aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2012-11-20 07:20:34 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-11-20 20:40:23 -0500
commit363589bf110aa0352a203112af16685dd9cb56c1 (patch)
tree9a5a4e18e1899d0a1ed16c7ba901e1e866571576
parent0aa5e47d1f3b395c4d2540a28ee37694466ee19b (diff)
ASoC: kirkwood-i2s: add support for external clock rates
This is part of a patch found in Rabeeh Khoury's git tree for the cubox, and cleaned up by me. Some platforms provide an external clock which can be used to allow other sample rates to be selected. Provide support for this. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r--sound/soc/kirkwood/kirkwood-i2s.c70
-rw-r--r--sound/soc/kirkwood/kirkwood.h8
2 files changed, 69 insertions, 9 deletions
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c
index 823ef1e71d19..d3629d5927e9 100644
--- a/sound/soc/kirkwood/kirkwood-i2s.c
+++ b/sound/soc/kirkwood/kirkwood-i2s.c
@@ -99,6 +99,29 @@ static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate)
99 } while (value == 0); 99 } while (value == 0);
100} 100}
101 101
102static void kirkwood_set_rate(struct snd_soc_dai *dai,
103 struct kirkwood_dma_data *priv, unsigned long rate)
104{
105 uint32_t clks_ctrl;
106
107 if (rate == 44100 || rate == 48000 || rate == 96000) {
108 /* use internal dco for supported rates */
109 dev_dbg(dai->dev, "%s: dco set rate = %lu\n",
110 __func__, rate);
111 kirkwood_set_dco(priv->io, rate);
112
113 clks_ctrl = KIRKWOOD_MCLK_SOURCE_DCO;
114 } else if (!IS_ERR(priv->extclk)) {
115 /* use optional external clk for other rates */
116 dev_dbg(dai->dev, "%s: extclk set rate = %lu -> %lu\n",
117 __func__, rate, 256 * rate);
118 clk_set_rate(priv->extclk, 256 * rate);
119
120 clks_ctrl = KIRKWOOD_MCLK_SOURCE_EXTCLK;
121 }
122 writel(clks_ctrl, priv->io + KIRKWOOD_CLOCKS_CTRL);
123}
124
102static int kirkwood_i2s_startup(struct snd_pcm_substream *substream, 125static int kirkwood_i2s_startup(struct snd_pcm_substream *substream,
103 struct snd_soc_dai *dai) 126 struct snd_soc_dai *dai)
104{ 127{
@@ -123,8 +146,7 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
123 i2s_reg = KIRKWOOD_I2S_RECCTL; 146 i2s_reg = KIRKWOOD_I2S_RECCTL;
124 } 147 }
125 148
126 /* set dco conf */ 149 kirkwood_set_rate(dai, priv, params_rate(params));
127 kirkwood_set_dco(priv->io, params_rate(params));
128 150
129 i2s_value = readl(priv->io+i2s_reg); 151 i2s_value = readl(priv->io+i2s_reg);
130 i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK; 152 i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK;
@@ -396,21 +418,45 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai = {
396 .channels_min = 1, 418 .channels_min = 1,
397 .channels_max = 2, 419 .channels_max = 2,
398 .rates = KIRKWOOD_I2S_RATES, 420 .rates = KIRKWOOD_I2S_RATES,
399 .formats = KIRKWOOD_I2S_FORMATS,}, 421 .formats = KIRKWOOD_I2S_FORMATS,
422 },
400 .capture = { 423 .capture = {
401 .channels_min = 1, 424 .channels_min = 1,
402 .channels_max = 2, 425 .channels_max = 2,
403 .rates = KIRKWOOD_I2S_RATES, 426 .rates = KIRKWOOD_I2S_RATES,
404 .formats = KIRKWOOD_I2S_FORMATS,}, 427 .formats = KIRKWOOD_I2S_FORMATS,
428 },
429 .ops = &kirkwood_i2s_dai_ops,
430};
431
432static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = {
433 .probe = kirkwood_i2s_probe,
434 .remove = kirkwood_i2s_remove,
435 .playback = {
436 .channels_min = 1,
437 .channels_max = 2,
438 .rates = SNDRV_PCM_RATE_8000_192000 |
439 SNDRV_PCM_RATE_CONTINUOUS |
440 SNDRV_PCM_RATE_KNOT,
441 .formats = KIRKWOOD_I2S_FORMATS,
442 },
443 .capture = {
444 .channels_min = 1,
445 .channels_max = 2,
446 .rates = SNDRV_PCM_RATE_8000_192000 |
447 SNDRV_PCM_RATE_CONTINUOUS |
448 SNDRV_PCM_RATE_KNOT,
449 .formats = KIRKWOOD_I2S_FORMATS,
450 },
405 .ops = &kirkwood_i2s_dai_ops, 451 .ops = &kirkwood_i2s_dai_ops,
406}; 452};
407 453
408static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev) 454static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
409{ 455{
410 struct resource *mem; 456 struct kirkwood_asoc_platform_data *data = pdev->dev.platform_data;
411 struct kirkwood_asoc_platform_data *data = 457 struct snd_soc_dai_driver *soc_dai = &kirkwood_i2s_dai;
412 pdev->dev.platform_data;
413 struct kirkwood_dma_data *priv; 458 struct kirkwood_dma_data *priv;
459 struct resource *mem;
414 int err; 460 int err;
415 461
416 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 462 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
@@ -480,11 +526,15 @@ static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
480 priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_128; 526 priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_128;
481 } 527 }
482 528
483 err = snd_soc_register_dai(&pdev->dev, &kirkwood_i2s_dai); 529 err = snd_soc_register_dai(&pdev->dev, soc_dai);
484 if (!err) 530 if (!err)
485 return 0; 531 return 0;
486 dev_err(&pdev->dev, "snd_soc_register_dai failed\n"); 532 dev_err(&pdev->dev, "snd_soc_register_dai failed\n");
487 533
534 if (!IS_ERR(priv->extclk)) {
535 clk_disable_unprepare(priv->extclk);
536 clk_put(priv->extclk);
537 }
488 clk_disable_unprepare(priv->clk); 538 clk_disable_unprepare(priv->clk);
489 539
490 return err; 540 return err;
@@ -496,6 +546,10 @@ static __devexit int kirkwood_i2s_dev_remove(struct platform_device *pdev)
496 546
497 snd_soc_unregister_dai(&pdev->dev); 547 snd_soc_unregister_dai(&pdev->dev);
498 548
549 if (!IS_ERR(priv->extclk)) {
550 clk_disable_unprepare(priv->extclk);
551 clk_put(priv->extclk);
552 }
499 clk_disable_unprepare(priv->clk); 553 clk_disable_unprepare(priv->clk);
500 554
501 return 0; 555 return 0;
diff --git a/sound/soc/kirkwood/kirkwood.h b/sound/soc/kirkwood/kirkwood.h
index 6e3b14ac24f5..4d92637ddb3f 100644
--- a/sound/soc/kirkwood/kirkwood.h
+++ b/sound/soc/kirkwood/kirkwood.h
@@ -77,6 +77,11 @@
77#define KIRKWOOD_DCO_SPCR_STATUS 0x120c 77#define KIRKWOOD_DCO_SPCR_STATUS 0x120c
78#define KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK (1<<16) 78#define KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK (1<<16)
79 79
80#define KIRKWOOD_CLOCKS_CTRL 0x1230
81#define KIRKWOOD_MCLK_SOURCE_MASK (3<<0)
82#define KIRKWOOD_MCLK_SOURCE_DCO (0<<0)
83#define KIRKWOOD_MCLK_SOURCE_EXTCLK (3<<0)
84
80#define KIRKWOOD_ERR_CAUSE 0x1300 85#define KIRKWOOD_ERR_CAUSE 0x1300
81#define KIRKWOOD_ERR_MASK 0x1304 86#define KIRKWOOD_ERR_MASK 0x1304
82 87
@@ -120,11 +125,12 @@
120 125
121struct kirkwood_dma_data { 126struct kirkwood_dma_data {
122 void __iomem *io; 127 void __iomem *io;
128 struct clk *clk;
129 struct clk *extclk;
123 uint32_t ctl_play; 130 uint32_t ctl_play;
124 uint32_t ctl_rec; 131 uint32_t ctl_rec;
125 int irq; 132 int irq;
126 int burst; 133 int burst;
127 struct clk *clk;
128}; 134};
129 135
130#endif 136#endif