aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/sunxi/sun4i-i2s.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/sunxi/sun4i-i2s.c')
-rw-r--r--sound/soc/sunxi/sun4i-i2s.c105
1 files changed, 87 insertions, 18 deletions
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 687a8f83dbe5..f24d19526603 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -93,6 +93,9 @@ struct sun4i_i2s {
93 struct clk *mod_clk; 93 struct clk *mod_clk;
94 struct regmap *regmap; 94 struct regmap *regmap;
95 95
96 unsigned int mclk_freq;
97
98 struct snd_dmaengine_dai_dma_data capture_dma_data;
96 struct snd_dmaengine_dai_dma_data playback_dma_data; 99 struct snd_dmaengine_dai_dma_data playback_dma_data;
97}; 100};
98 101
@@ -157,14 +160,24 @@ static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s,
157} 160}
158 161
159static int sun4i_i2s_oversample_rates[] = { 128, 192, 256, 384, 512, 768 }; 162static int sun4i_i2s_oversample_rates[] = { 128, 192, 256, 384, 512, 768 };
163static bool sun4i_i2s_oversample_is_valid(unsigned int oversample)
164{
165 int i;
166
167 for (i = 0; i < ARRAY_SIZE(sun4i_i2s_oversample_rates); i++)
168 if (sun4i_i2s_oversample_rates[i] == oversample)
169 return true;
170
171 return false;
172}
160 173
161static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s, 174static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
162 unsigned int rate, 175 unsigned int rate,
163 unsigned int word_size) 176 unsigned int word_size)
164{ 177{
165 unsigned int clk_rate; 178 unsigned int oversample_rate, clk_rate;
166 int bclk_div, mclk_div; 179 int bclk_div, mclk_div;
167 int ret, i; 180 int ret;
168 181
169 switch (rate) { 182 switch (rate) {
170 case 176400: 183 case 176400:
@@ -196,21 +209,18 @@ static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
196 if (ret) 209 if (ret)
197 return ret; 210 return ret;
198 211
199 /* Always favor the highest oversampling rate */ 212 oversample_rate = i2s->mclk_freq / rate;
200 for (i = (ARRAY_SIZE(sun4i_i2s_oversample_rates) - 1); i >= 0; i--) { 213 if (!sun4i_i2s_oversample_is_valid(oversample_rate))
201 unsigned int oversample_rate = sun4i_i2s_oversample_rates[i]; 214 return -EINVAL;
202
203 bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate,
204 word_size);
205 mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate,
206 clk_rate,
207 rate);
208 215
209 if ((bclk_div >= 0) && (mclk_div >= 0)) 216 bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate,
210 break; 217 word_size);
211 } 218 if (bclk_div < 0)
219 return -EINVAL;
212 220
213 if ((bclk_div < 0) || (mclk_div < 0)) 221 mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate,
222 clk_rate, rate);
223 if (mclk_div < 0)
214 return -EINVAL; 224 return -EINVAL;
215 225
216 regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG, 226 regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG,
@@ -341,6 +351,27 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
341 return 0; 351 return 0;
342} 352}
343 353
354static void sun4i_i2s_start_capture(struct sun4i_i2s *i2s)
355{
356 /* Flush RX FIFO */
357 regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
358 SUN4I_I2S_FIFO_CTRL_FLUSH_RX,
359 SUN4I_I2S_FIFO_CTRL_FLUSH_RX);
360
361 /* Clear RX counter */
362 regmap_write(i2s->regmap, SUN4I_I2S_RX_CNT_REG, 0);
363
364 /* Enable RX Block */
365 regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
366 SUN4I_I2S_CTRL_RX_EN,
367 SUN4I_I2S_CTRL_RX_EN);
368
369 /* Enable RX DRQ */
370 regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG,
371 SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN,
372 SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN);
373}
374
344static void sun4i_i2s_start_playback(struct sun4i_i2s *i2s) 375static void sun4i_i2s_start_playback(struct sun4i_i2s *i2s)
345{ 376{
346 /* Flush TX FIFO */ 377 /* Flush TX FIFO */
@@ -362,6 +393,18 @@ static void sun4i_i2s_start_playback(struct sun4i_i2s *i2s)
362 SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN); 393 SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN);
363} 394}
364 395
396static void sun4i_i2s_stop_capture(struct sun4i_i2s *i2s)
397{
398 /* Disable RX Block */
399 regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
400 SUN4I_I2S_CTRL_RX_EN,
401 0);
402
403 /* Disable RX DRQ */
404 regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG,
405 SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN,
406 0);
407}
365 408
366static void sun4i_i2s_stop_playback(struct sun4i_i2s *i2s) 409static void sun4i_i2s_stop_playback(struct sun4i_i2s *i2s)
367{ 410{
@@ -388,7 +431,7 @@ static int sun4i_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
388 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 431 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
389 sun4i_i2s_start_playback(i2s); 432 sun4i_i2s_start_playback(i2s);
390 else 433 else
391 return -EINVAL; 434 sun4i_i2s_start_capture(i2s);
392 break; 435 break;
393 436
394 case SNDRV_PCM_TRIGGER_STOP: 437 case SNDRV_PCM_TRIGGER_STOP:
@@ -397,7 +440,7 @@ static int sun4i_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
397 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 440 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
398 sun4i_i2s_stop_playback(i2s); 441 sun4i_i2s_stop_playback(i2s);
399 else 442 else
400 return -EINVAL; 443 sun4i_i2s_stop_capture(i2s);
401 break; 444 break;
402 445
403 default: 446 default:
@@ -447,9 +490,23 @@ static void sun4i_i2s_shutdown(struct snd_pcm_substream *substream,
447 regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG, 0); 490 regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG, 0);
448} 491}
449 492
493static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
494 unsigned int freq, int dir)
495{
496 struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
497
498 if (clk_id != 0)
499 return -EINVAL;
500
501 i2s->mclk_freq = freq;
502
503 return 0;
504}
505
450static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { 506static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = {
451 .hw_params = sun4i_i2s_hw_params, 507 .hw_params = sun4i_i2s_hw_params,
452 .set_fmt = sun4i_i2s_set_fmt, 508 .set_fmt = sun4i_i2s_set_fmt,
509 .set_sysclk = sun4i_i2s_set_sysclk,
453 .shutdown = sun4i_i2s_shutdown, 510 .shutdown = sun4i_i2s_shutdown,
454 .startup = sun4i_i2s_startup, 511 .startup = sun4i_i2s_startup,
455 .trigger = sun4i_i2s_trigger, 512 .trigger = sun4i_i2s_trigger,
@@ -459,7 +516,9 @@ static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai)
459{ 516{
460 struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); 517 struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
461 518
462 snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data, NULL); 519 snd_soc_dai_init_dma_data(dai,
520 &i2s->playback_dma_data,
521 &i2s->capture_dma_data);
463 522
464 snd_soc_dai_set_drvdata(dai, i2s); 523 snd_soc_dai_set_drvdata(dai, i2s);
465 524
@@ -468,6 +527,13 @@ static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai)
468 527
469static struct snd_soc_dai_driver sun4i_i2s_dai = { 528static struct snd_soc_dai_driver sun4i_i2s_dai = {
470 .probe = sun4i_i2s_dai_probe, 529 .probe = sun4i_i2s_dai_probe,
530 .capture = {
531 .stream_name = "Capture",
532 .channels_min = 2,
533 .channels_max = 2,
534 .rates = SNDRV_PCM_RATE_8000_192000,
535 .formats = SNDRV_PCM_FMTBIT_S16_LE,
536 },
471 .playback = { 537 .playback = {
472 .stream_name = "Playback", 538 .stream_name = "Playback",
473 .channels_min = 2, 539 .channels_min = 2,
@@ -630,6 +696,9 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
630 i2s->playback_dma_data.addr = res->start + SUN4I_I2S_FIFO_TX_REG; 696 i2s->playback_dma_data.addr = res->start + SUN4I_I2S_FIFO_TX_REG;
631 i2s->playback_dma_data.maxburst = 4; 697 i2s->playback_dma_data.maxburst = 4;
632 698
699 i2s->capture_dma_data.addr = res->start + SUN4I_I2S_FIFO_RX_REG;
700 i2s->capture_dma_data.maxburst = 4;
701
633 pm_runtime_enable(&pdev->dev); 702 pm_runtime_enable(&pdev->dev);
634 if (!pm_runtime_enabled(&pdev->dev)) { 703 if (!pm_runtime_enabled(&pdev->dev)) {
635 ret = sun4i_i2s_runtime_resume(&pdev->dev); 704 ret = sun4i_i2s_runtime_resume(&pdev->dev);