aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/da7219.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/da7219.c')
-rw-r--r--sound/soc/codecs/da7219.c116
1 files changed, 73 insertions, 43 deletions
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index b1df4bb36105..121a8190f93e 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -1376,11 +1376,7 @@ static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
return -EINVAL;
}
- /* By default 64 BCLKs per WCLK is supported */
- dai_clk_mode |= DA7219_DAI_BCLKS_PER_WCLK_64;
-
snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE,
- DA7219_DAI_BCLKS_PER_WCLK_MASK |
DA7219_DAI_CLK_POL_MASK | DA7219_DAI_WCLK_POL_MASK,
dai_clk_mode);
snd_soc_component_update_bits(component, DA7219_DAI_CTRL, DA7219_DAI_FORMAT_MASK,
@@ -1395,69 +1391,83 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai,
{
struct snd_soc_component *component = dai->component;
struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
- u8 dai_bclks_per_wclk;
- __le16 offset;
+ unsigned int ch_mask;
+ u8 dai_bclks_per_wclk, slot_offset;
+ u16 offset;
+ __le16 dai_offset;
u32 frame_size;
- /* No channels enabled so disable TDM, revert to 64-bit frames */
+ /* No channels enabled so disable TDM */
if (!tx_mask) {
snd_soc_component_update_bits(component, DA7219_DAI_TDM_CTRL,
DA7219_DAI_TDM_CH_EN_MASK |
DA7219_DAI_TDM_MODE_EN_MASK, 0);
- snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE,
- DA7219_DAI_BCLKS_PER_WCLK_MASK,
- DA7219_DAI_BCLKS_PER_WCLK_64);
+ da7219->tdm_en = false;
return 0;
}
/* Check we have valid slots */
- if (fls(tx_mask) > DA7219_DAI_TDM_MAX_SLOTS) {
- dev_err(component->dev, "Invalid number of slots, max = %d\n",
+ slot_offset = ffs(tx_mask) - 1;
+ ch_mask = (tx_mask >> slot_offset);
+ if (fls(ch_mask) > DA7219_DAI_TDM_MAX_SLOTS) {
+ dev_err(component->dev,
+ "Invalid number of slots, max = %d\n",
DA7219_DAI_TDM_MAX_SLOTS);
return -EINVAL;
}
- /* Check we have a valid offset given */
- if (rx_mask > DA7219_DAI_OFFSET_MAX) {
- dev_err(component->dev, "Invalid slot offset, max = %d\n",
- DA7219_DAI_OFFSET_MAX);
+ /*
+ * Ensure we have a valid offset into the frame, based on slot width
+ * and slot offset of first slot we're interested in.
+ */
+ offset = slot_offset * slot_width;
+ if (offset > DA7219_DAI_OFFSET_MAX) {
+ dev_err(component->dev, "Invalid frame offset %d\n", offset);
return -EINVAL;
}
- /* Calculate & validate frame size based on slot info provided. */
- frame_size = slots * slot_width;
- switch (frame_size) {
- case 32:
- dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_32;
- break;
- case 64:
- dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_64;
- break;
- case 128:
- dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_128;
- break;
- case 256:
- dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_256;
- break;
- default:
- dev_err(component->dev, "Invalid frame size %d\n", frame_size);
- return -EINVAL;
- }
+ /*
+ * If we're master, calculate & validate frame size based on slot info
+ * provided as we have a limited set of rates available.
+ */
+ if (da7219->master) {
+ frame_size = slots * slot_width;
+ switch (frame_size) {
+ case 32:
+ dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_32;
+ break;
+ case 64:
+ dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_64;
+ break;
+ case 128:
+ dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_128;
+ break;
+ case 256:
+ dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_256;
+ break;
+ default:
+ dev_err(component->dev, "Invalid frame size %d\n",
+ frame_size);
+ return -EINVAL;
+ }
- snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE,
- DA7219_DAI_BCLKS_PER_WCLK_MASK,
- dai_bclks_per_wclk);
+ snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE,
+ DA7219_DAI_BCLKS_PER_WCLK_MASK,
+ dai_bclks_per_wclk);
+ }
- offset = cpu_to_le16(rx_mask);
+ dai_offset = cpu_to_le16(offset);
regmap_bulk_write(da7219->regmap, DA7219_DAI_OFFSET_LOWER,
- &offset, sizeof(offset));
+ &dai_offset, sizeof(dai_offset));
snd_soc_component_update_bits(component, DA7219_DAI_TDM_CTRL,
DA7219_DAI_TDM_CH_EN_MASK |
DA7219_DAI_TDM_MODE_EN_MASK,
- (tx_mask << DA7219_DAI_TDM_CH_EN_SHIFT) |
+ (ch_mask << DA7219_DAI_TDM_CH_EN_SHIFT) |
DA7219_DAI_TDM_MODE_EN_MASK);
+ da7219->tdm_en = true;
+
return 0;
}
@@ -1466,10 +1476,13 @@ static int da7219_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
- u8 dai_ctrl = 0, fs;
+ struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
+ u8 dai_ctrl = 0, dai_bclks_per_wclk = 0, fs;
unsigned int channels;
+ int word_len = params_width(params);
+ int frame_size;
- switch (params_width(params)) {
+ switch (word_len) {
case 16:
dai_ctrl |= DA7219_DAI_WORD_LENGTH_S16_LE;
break;
@@ -1533,6 +1546,23 @@ static int da7219_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
+ /*
+ * If we're master, then we have a limited set of BCLK rates we
+ * support. For slave mode this isn't the case and the codec can detect
+ * the BCLK rate automatically.
+ */
+ if (da7219->master && !da7219->tdm_en) {
+ frame_size = word_len * 2;
+ if (frame_size <= 32)
+ dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_32;
+ else
+ dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_64;
+
+ snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE,
+ DA7219_DAI_BCLKS_PER_WCLK_MASK,
+ dai_bclks_per_wclk);
+ }
+
snd_soc_component_update_bits(component, DA7219_DAI_CTRL,
DA7219_DAI_WORD_LENGTH_MASK |
DA7219_DAI_CH_NUM_MASK,