|
@@ -99,6 +99,29 @@ static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate)
|
|
|
} while (value == 0);
|
|
|
}
|
|
|
|
|
|
+static void kirkwood_set_rate(struct snd_soc_dai *dai,
|
|
|
+ struct kirkwood_dma_data *priv, unsigned long rate)
|
|
|
+{
|
|
|
+ uint32_t clks_ctrl;
|
|
|
+
|
|
|
+ if (rate == 44100 || rate == 48000 || rate == 96000) {
|
|
|
+ /* use internal dco for supported rates */
|
|
|
+ dev_dbg(dai->dev, "%s: dco set rate = %lu\n",
|
|
|
+ __func__, rate);
|
|
|
+ kirkwood_set_dco(priv->io, rate);
|
|
|
+
|
|
|
+ clks_ctrl = KIRKWOOD_MCLK_SOURCE_DCO;
|
|
|
+ } else if (!IS_ERR(priv->extclk)) {
|
|
|
+ /* use optional external clk for other rates */
|
|
|
+ dev_dbg(dai->dev, "%s: extclk set rate = %lu -> %lu\n",
|
|
|
+ __func__, rate, 256 * rate);
|
|
|
+ clk_set_rate(priv->extclk, 256 * rate);
|
|
|
+
|
|
|
+ clks_ctrl = KIRKWOOD_MCLK_SOURCE_EXTCLK;
|
|
|
+ }
|
|
|
+ writel(clks_ctrl, priv->io + KIRKWOOD_CLOCKS_CTRL);
|
|
|
+}
|
|
|
+
|
|
|
static int kirkwood_i2s_startup(struct snd_pcm_substream *substream,
|
|
|
struct snd_soc_dai *dai)
|
|
|
{
|
|
@@ -123,8 +146,7 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
|
|
|
i2s_reg = KIRKWOOD_I2S_RECCTL;
|
|
|
}
|
|
|
|
|
|
- /* set dco conf */
|
|
|
- kirkwood_set_dco(priv->io, params_rate(params));
|
|
|
+ kirkwood_set_rate(dai, priv, params_rate(params));
|
|
|
|
|
|
i2s_value = readl(priv->io+i2s_reg);
|
|
|
i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK;
|
|
@@ -396,21 +418,45 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai = {
|
|
|
.channels_min = 1,
|
|
|
.channels_max = 2,
|
|
|
.rates = KIRKWOOD_I2S_RATES,
|
|
|
- .formats = KIRKWOOD_I2S_FORMATS,},
|
|
|
+ .formats = KIRKWOOD_I2S_FORMATS,
|
|
|
+ },
|
|
|
.capture = {
|
|
|
.channels_min = 1,
|
|
|
.channels_max = 2,
|
|
|
.rates = KIRKWOOD_I2S_RATES,
|
|
|
- .formats = KIRKWOOD_I2S_FORMATS,},
|
|
|
+ .formats = KIRKWOOD_I2S_FORMATS,
|
|
|
+ },
|
|
|
+ .ops = &kirkwood_i2s_dai_ops,
|
|
|
+};
|
|
|
+
|
|
|
+static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = {
|
|
|
+ .probe = kirkwood_i2s_probe,
|
|
|
+ .remove = kirkwood_i2s_remove,
|
|
|
+ .playback = {
|
|
|
+ .channels_min = 1,
|
|
|
+ .channels_max = 2,
|
|
|
+ .rates = SNDRV_PCM_RATE_8000_192000 |
|
|
|
+ SNDRV_PCM_RATE_CONTINUOUS |
|
|
|
+ SNDRV_PCM_RATE_KNOT,
|
|
|
+ .formats = KIRKWOOD_I2S_FORMATS,
|
|
|
+ },
|
|
|
+ .capture = {
|
|
|
+ .channels_min = 1,
|
|
|
+ .channels_max = 2,
|
|
|
+ .rates = SNDRV_PCM_RATE_8000_192000 |
|
|
|
+ SNDRV_PCM_RATE_CONTINUOUS |
|
|
|
+ SNDRV_PCM_RATE_KNOT,
|
|
|
+ .formats = KIRKWOOD_I2S_FORMATS,
|
|
|
+ },
|
|
|
.ops = &kirkwood_i2s_dai_ops,
|
|
|
};
|
|
|
|
|
|
static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
|
|
|
{
|
|
|
- struct resource *mem;
|
|
|
- struct kirkwood_asoc_platform_data *data =
|
|
|
- pdev->dev.platform_data;
|
|
|
+ struct kirkwood_asoc_platform_data *data = pdev->dev.platform_data;
|
|
|
+ struct snd_soc_dai_driver *soc_dai = &kirkwood_i2s_dai;
|
|
|
struct kirkwood_dma_data *priv;
|
|
|
+ struct resource *mem;
|
|
|
int err;
|
|
|
|
|
|
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
|
@@ -480,11 +526,15 @@ static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
|
|
|
priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_128;
|
|
|
}
|
|
|
|
|
|
- err = snd_soc_register_dai(&pdev->dev, &kirkwood_i2s_dai);
|
|
|
+ err = snd_soc_register_dai(&pdev->dev, soc_dai);
|
|
|
if (!err)
|
|
|
return 0;
|
|
|
dev_err(&pdev->dev, "snd_soc_register_dai failed\n");
|
|
|
|
|
|
+ if (!IS_ERR(priv->extclk)) {
|
|
|
+ clk_disable_unprepare(priv->extclk);
|
|
|
+ clk_put(priv->extclk);
|
|
|
+ }
|
|
|
clk_disable_unprepare(priv->clk);
|
|
|
|
|
|
return err;
|
|
@@ -496,6 +546,10 @@ static __devexit int kirkwood_i2s_dev_remove(struct platform_device *pdev)
|
|
|
|
|
|
snd_soc_unregister_dai(&pdev->dev);
|
|
|
|
|
|
+ if (!IS_ERR(priv->extclk)) {
|
|
|
+ clk_disable_unprepare(priv->extclk);
|
|
|
+ clk_put(priv->extclk);
|
|
|
+ }
|
|
|
clk_disable_unprepare(priv->clk);
|
|
|
|
|
|
return 0;
|