summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Thomson <Adam.Thomson.Opensource@diasemi.com>2019-02-14 05:13:30 -0500
committerMark Brown <broonie@kernel.org>2019-02-14 09:49:59 -0500
commit541ccdc113f000d51858ee7e135889e4096a3316 (patch)
treeca89e1e5da86831586d8dfe45bb13487764b0fc6
parent9fd729542cf4aff3c70b8e5be6f510e6722bc369 (diff)
ASoC: da7219: Update TDM usage to be more flexible
The previous implementatation was restrictive with regards to BCLK rates for slave mode where the driver would not allow rates the codec couldn't provide itself as clock master. The codec is able to automatically determine and handle whatever rate is provided so this restriction isn't necessary for slave mode. The code was also flawed with regards to setting of the frame offset as using rx_mask to explicitly set the offset has the knock on effect of impacting the min and max channels for the codec, in soc_pcm_hw_params() through the call to soc_pcm_codec_params_fixup(). With this update, the driver now only limits frame size if codec is clock master, and dynamically determines the BCLK offset relating to WCLK using the tx_mask for slot offset along with the slot width provided. Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/codecs/da7219.c80
1 files changed, 47 insertions, 33 deletions
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c
index c599aa9f609b..121a8190f93e 100644
--- a/sound/soc/codecs/da7219.c
+++ b/sound/soc/codecs/da7219.c
@@ -1391,8 +1391,10 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai,
1391{ 1391{
1392 struct snd_soc_component *component = dai->component; 1392 struct snd_soc_component *component = dai->component;
1393 struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component); 1393 struct da7219_priv *da7219 = snd_soc_component_get_drvdata(component);
1394 u8 dai_bclks_per_wclk; 1394 unsigned int ch_mask;
1395 __le16 offset; 1395 u8 dai_bclks_per_wclk, slot_offset;
1396 u16 offset;
1397 __le16 dai_offset;
1396 u32 frame_size; 1398 u32 frame_size;
1397 1399
1398 /* No channels enabled so disable TDM */ 1400 /* No channels enabled so disable TDM */
@@ -1405,51 +1407,63 @@ static int da7219_set_dai_tdm_slot(struct snd_soc_dai *dai,
1405 } 1407 }
1406 1408
1407 /* Check we have valid slots */ 1409 /* Check we have valid slots */
1408 if (fls(tx_mask) > DA7219_DAI_TDM_MAX_SLOTS) { 1410 slot_offset = ffs(tx_mask) - 1;
1409 dev_err(component->dev, "Invalid number of slots, max = %d\n", 1411 ch_mask = (tx_mask >> slot_offset);
1412 if (fls(ch_mask) > DA7219_DAI_TDM_MAX_SLOTS) {
1413 dev_err(component->dev,
1414 "Invalid number of slots, max = %d\n",
1410 DA7219_DAI_TDM_MAX_SLOTS); 1415 DA7219_DAI_TDM_MAX_SLOTS);
1411 return -EINVAL; 1416 return -EINVAL;
1412 } 1417 }
1413 1418
1414 /* Check we have a valid offset given */ 1419 /*
1415 if (rx_mask > DA7219_DAI_OFFSET_MAX) { 1420 * Ensure we have a valid offset into the frame, based on slot width
1416 dev_err(component->dev, "Invalid slot offset, max = %d\n", 1421 * and slot offset of first slot we're interested in.
1417 DA7219_DAI_OFFSET_MAX); 1422 */
1423 offset = slot_offset * slot_width;
1424 if (offset > DA7219_DAI_OFFSET_MAX) {
1425 dev_err(component->dev, "Invalid frame offset %d\n", offset);
1418 return -EINVAL; 1426 return -EINVAL;
1419 } 1427 }
1420 1428
1421 /* Calculate & validate frame size based on slot info provided. */ 1429 /*
1422 frame_size = slots * slot_width; 1430 * If we're master, calculate & validate frame size based on slot info
1423 switch (frame_size) { 1431 * provided as we have a limited set of rates available.
1424 case 32: 1432 */
1425 dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_32; 1433 if (da7219->master) {
1426 break; 1434 frame_size = slots * slot_width;
1427 case 64: 1435 switch (frame_size) {
1428 dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_64; 1436 case 32:
1429 break; 1437 dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_32;
1430 case 128: 1438 break;
1431 dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_128; 1439 case 64:
1432 break; 1440 dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_64;
1433 case 256: 1441 break;
1434 dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_256; 1442 case 128:
1435 break; 1443 dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_128;
1436 default: 1444 break;
1437 dev_err(component->dev, "Invalid frame size %d\n", frame_size); 1445 case 256:
1438 return -EINVAL; 1446 dai_bclks_per_wclk = DA7219_DAI_BCLKS_PER_WCLK_256;
1439 } 1447 break;
1448 default:
1449 dev_err(component->dev, "Invalid frame size %d\n",
1450 frame_size);
1451 return -EINVAL;
1452 }
1440 1453
1441 snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE, 1454 snd_soc_component_update_bits(component, DA7219_DAI_CLK_MODE,
1442 DA7219_DAI_BCLKS_PER_WCLK_MASK, 1455 DA7219_DAI_BCLKS_PER_WCLK_MASK,
1443 dai_bclks_per_wclk); 1456 dai_bclks_per_wclk);
1457 }
1444 1458
1445 offset = cpu_to_le16(rx_mask); 1459 dai_offset = cpu_to_le16(offset);
1446 regmap_bulk_write(da7219->regmap, DA7219_DAI_OFFSET_LOWER, 1460 regmap_bulk_write(da7219->regmap, DA7219_DAI_OFFSET_LOWER,
1447 &offset, sizeof(offset)); 1461 &dai_offset, sizeof(dai_offset));
1448 1462
1449 snd_soc_component_update_bits(component, DA7219_DAI_TDM_CTRL, 1463 snd_soc_component_update_bits(component, DA7219_DAI_TDM_CTRL,
1450 DA7219_DAI_TDM_CH_EN_MASK | 1464 DA7219_DAI_TDM_CH_EN_MASK |
1451 DA7219_DAI_TDM_MODE_EN_MASK, 1465 DA7219_DAI_TDM_MODE_EN_MASK,
1452 (tx_mask << DA7219_DAI_TDM_CH_EN_SHIFT) | 1466 (ch_mask << DA7219_DAI_TDM_CH_EN_SHIFT) |
1453 DA7219_DAI_TDM_MODE_EN_MASK); 1467 DA7219_DAI_TDM_MODE_EN_MASK);
1454 1468
1455 da7219->tdm_en = true; 1469 da7219->tdm_en = true;