summaryrefslogtreecommitdiffstats
path: root/kernel/sound/soc/rockchip/rockchip_i2s.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/sound/soc/rockchip/rockchip_i2s.c')
-rw-r--r--kernel/sound/soc/rockchip/rockchip_i2s.c56
1 files changed, 48 insertions, 8 deletions
diff --git a/kernel/sound/soc/rockchip/rockchip_i2s.c b/kernel/sound/soc/rockchip/rockchip_i2s.c
index acb5be53b..58ee64594 100644
--- a/kernel/sound/soc/rockchip/rockchip_i2s.c
+++ b/kernel/sound/soc/rockchip/rockchip_i2s.c
@@ -226,6 +226,7 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct rk_i2s_dev *i2s = to_info(dai);
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
unsigned int val = 0;
switch (params_format(params)) {
@@ -245,13 +246,46 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- regmap_update_bits(i2s->regmap, I2S_TXCR, I2S_TXCR_VDW_MASK, val);
- regmap_update_bits(i2s->regmap, I2S_RXCR, I2S_RXCR_VDW_MASK, val);
+ switch (params_channels(params)) {
+ case 8:
+ val |= I2S_CHN_8;
+ break;
+ case 6:
+ val |= I2S_CHN_6;
+ break;
+ case 4:
+ val |= I2S_CHN_4;
+ break;
+ case 2:
+ val |= I2S_CHN_2;
+ break;
+ default:
+ dev_err(i2s->dev, "invalid channel: %d\n",
+ params_channels(params));
+ return -EINVAL;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ regmap_update_bits(i2s->regmap, I2S_RXCR,
+ I2S_RXCR_VDW_MASK | I2S_RXCR_CSR_MASK,
+ val);
+ else
+ regmap_update_bits(i2s->regmap, I2S_TXCR,
+ I2S_TXCR_VDW_MASK | I2S_TXCR_CSR_MASK,
+ val);
+
regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_TDL_MASK,
I2S_DMACR_TDL(16));
regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_RDL_MASK,
I2S_DMACR_RDL(16));
+ val = I2S_CKR_TRCM_TXRX;
+ if (dai->driver->symmetric_rates || rtd->dai_link->symmetric_rates)
+ val = I2S_CKR_TRCM_TXSHARE;
+
+ regmap_update_bits(i2s->regmap, I2S_CKR,
+ I2S_CKR_TRCM_MASK,
+ val);
return 0;
}
@@ -415,10 +449,12 @@ static const struct regmap_config rockchip_i2s_regmap_config = {
static int rockchip_i2s_probe(struct platform_device *pdev)
{
+ struct device_node *node = pdev->dev.of_node;
struct rk_i2s_dev *i2s;
struct resource *res;
void __iomem *regs;
int ret;
+ int val;
i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
if (!i2s) {
@@ -475,6 +511,14 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
goto err_pm_disable;
}
+ /* refine capture channels */
+ if (!of_property_read_u32(node, "rockchip,capture-channels", &val)) {
+ if (val >= 2 && val <= 8)
+ rockchip_i2s_dai.capture.channels_max = val;
+ else
+ rockchip_i2s_dai.capture.channels_max = 2;
+ }
+
ret = devm_snd_soc_register_component(&pdev->dev,
&rockchip_i2s_component,
&rockchip_i2s_dai, 1);
@@ -483,16 +527,14 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
goto err_suspend;
}
- ret = snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+ ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
if (ret) {
dev_err(&pdev->dev, "Could not register PCM\n");
- goto err_pcm_register;
+ return ret;
}
return 0;
-err_pcm_register:
- snd_dmaengine_pcm_unregister(&pdev->dev);
err_suspend:
if (!pm_runtime_status_suspended(&pdev->dev))
i2s_runtime_suspend(&pdev->dev);
@@ -512,8 +554,6 @@ static int rockchip_i2s_remove(struct platform_device *pdev)
clk_disable_unprepare(i2s->mclk);
clk_disable_unprepare(i2s->hclk);
- snd_dmaengine_pcm_unregister(&pdev->dev);
- snd_soc_unregister_component(&pdev->dev);
return 0;
}