diff options
author | Maxime Ripard <maxime.ripard@bootlin.com> | 2019-08-19 15:25:27 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2019-08-21 08:11:55 -0400 |
commit | 137befe19f310400a8b20fd8a4ce8c4141aafde0 (patch) | |
tree | 34a5774aed4b1ab401619e8923899faeb956ff84 /sound | |
parent | c26a8841119826badc8d358a4266880f83359f26 (diff) |
ASoC: sun4i-i2s: Add support for TDM slots
The i2s controller supports TDM, for up to 8 slots. Let's support the TDM
API.
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Link: https://lore.kernel.org/r/26392af30b3e7b31ee48d5b867d45be8675db046.1566242458.git-series.maxime.ripard@bootlin.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/sunxi/sun4i-i2s.c | 40 |
1 files changed, 34 insertions, 6 deletions
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 9e691baee1e8..8326b8cfa569 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c | |||
@@ -168,6 +168,8 @@ struct sun4i_i2s { | |||
168 | struct reset_control *rst; | 168 | struct reset_control *rst; |
169 | 169 | ||
170 | unsigned int mclk_freq; | 170 | unsigned int mclk_freq; |
171 | unsigned int slots; | ||
172 | unsigned int slot_width; | ||
171 | 173 | ||
172 | struct snd_dmaengine_dai_dma_data capture_dma_data; | 174 | struct snd_dmaengine_dai_dma_data capture_dma_data; |
173 | struct snd_dmaengine_dai_dma_data playback_dma_data; | 175 | struct snd_dmaengine_dai_dma_data playback_dma_data; |
@@ -287,7 +289,7 @@ static bool sun4i_i2s_oversample_is_valid(unsigned int oversample) | |||
287 | 289 | ||
288 | static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, | 290 | static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, |
289 | unsigned int rate, | 291 | unsigned int rate, |
290 | unsigned int channels, | 292 | unsigned int slots, |
291 | unsigned int word_size) | 293 | unsigned int word_size) |
292 | { | 294 | { |
293 | struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); | 295 | struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); |
@@ -335,7 +337,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, | |||
335 | 337 | ||
336 | bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s); | 338 | bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s); |
337 | bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate, | 339 | bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate, |
338 | rate, channels, word_size); | 340 | rate, slots, word_size); |
339 | if (bclk_div < 0) { | 341 | if (bclk_div < 0) { |
340 | dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div); | 342 | dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div); |
341 | return -EINVAL; | 343 | return -EINVAL; |
@@ -419,6 +421,10 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, | |||
419 | const struct snd_pcm_hw_params *params) | 421 | const struct snd_pcm_hw_params *params) |
420 | { | 422 | { |
421 | unsigned int channels = params_channels(params); | 423 | unsigned int channels = params_channels(params); |
424 | unsigned int slots = channels; | ||
425 | |||
426 | if (i2s->slots) | ||
427 | slots = i2s->slots; | ||
422 | 428 | ||
423 | /* Map the channels for playback and capture */ | 429 | /* Map the channels for playback and capture */ |
424 | regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210); | 430 | regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210); |
@@ -428,7 +434,6 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, | |||
428 | regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, | 434 | regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, |
429 | SUN4I_I2S_CHAN_SEL_MASK, | 435 | SUN4I_I2S_CHAN_SEL_MASK, |
430 | SUN4I_I2S_CHAN_SEL(channels)); | 436 | SUN4I_I2S_CHAN_SEL(channels)); |
431 | |||
432 | regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, | 437 | regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, |
433 | SUN4I_I2S_CHAN_SEL_MASK, | 438 | SUN4I_I2S_CHAN_SEL_MASK, |
434 | SUN4I_I2S_CHAN_SEL(channels)); | 439 | SUN4I_I2S_CHAN_SEL(channels)); |
@@ -452,10 +457,18 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, | |||
452 | struct snd_soc_dai *dai) | 457 | struct snd_soc_dai *dai) |
453 | { | 458 | { |
454 | struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); | 459 | struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); |
460 | unsigned int word_size = params_width(params); | ||
455 | unsigned int channels = params_channels(params); | 461 | unsigned int channels = params_channels(params); |
462 | unsigned int slots = channels; | ||
456 | int ret, sr, wss; | 463 | int ret, sr, wss; |
457 | u32 width; | 464 | u32 width; |
458 | 465 | ||
466 | if (i2s->slots) | ||
467 | slots = i2s->slots; | ||
468 | |||
469 | if (i2s->slot_width) | ||
470 | word_size = i2s->slot_width; | ||
471 | |||
459 | ret = i2s->variant->set_chan_cfg(i2s, params); | 472 | ret = i2s->variant->set_chan_cfg(i2s, params); |
460 | if (ret < 0) { | 473 | if (ret < 0) { |
461 | dev_err(dai->dev, "Invalid channel configuration\n"); | 474 | dev_err(dai->dev, "Invalid channel configuration\n"); |
@@ -477,15 +490,14 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, | |||
477 | if (sr < 0) | 490 | if (sr < 0) |
478 | return -EINVAL; | 491 | return -EINVAL; |
479 | 492 | ||
480 | wss = i2s->variant->get_wss(i2s, params_width(params)); | 493 | wss = i2s->variant->get_wss(i2s, word_size); |
481 | if (wss < 0) | 494 | if (wss < 0) |
482 | return -EINVAL; | 495 | return -EINVAL; |
483 | 496 | ||
484 | regmap_field_write(i2s->field_fmt_wss, wss); | 497 | regmap_field_write(i2s->field_fmt_wss, wss); |
485 | regmap_field_write(i2s->field_fmt_sr, sr); | 498 | regmap_field_write(i2s->field_fmt_sr, sr); |
486 | 499 | ||
487 | return sun4i_i2s_set_clk_rate(dai, params_rate(params), | 500 | return sun4i_i2s_set_clk_rate(dai, params_rate(params), slots, word_size); |
488 | channels, params_width(params)); | ||
489 | } | 501 | } |
490 | 502 | ||
491 | static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, | 503 | static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, |
@@ -785,10 +797,26 @@ static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, | |||
785 | return 0; | 797 | return 0; |
786 | } | 798 | } |
787 | 799 | ||
800 | static int sun4i_i2s_set_tdm_slot(struct snd_soc_dai *dai, | ||
801 | unsigned int tx_mask, unsigned int rx_mask, | ||
802 | int slots, int slot_width) | ||
803 | { | ||
804 | struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); | ||
805 | |||
806 | if (slots > 8) | ||
807 | return -EINVAL; | ||
808 | |||
809 | i2s->slots = slots; | ||
810 | i2s->slot_width = slot_width; | ||
811 | |||
812 | return 0; | ||
813 | } | ||
814 | |||
788 | static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { | 815 | static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { |
789 | .hw_params = sun4i_i2s_hw_params, | 816 | .hw_params = sun4i_i2s_hw_params, |
790 | .set_fmt = sun4i_i2s_set_fmt, | 817 | .set_fmt = sun4i_i2s_set_fmt, |
791 | .set_sysclk = sun4i_i2s_set_sysclk, | 818 | .set_sysclk = sun4i_i2s_set_sysclk, |
819 | .set_tdm_slot = sun4i_i2s_set_tdm_slot, | ||
792 | .trigger = sun4i_i2s_trigger, | 820 | .trigger = sun4i_i2s_trigger, |
793 | }; | 821 | }; |
794 | 822 | ||