mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-09 23:39:18 +00:00
Merge series "Patches to update for rockchip i2s" from Sugar Zhang <sugar.zhang@rock-chips.com>:
These patches fixup or update for rockchip i2s. Changes in v3: - Drop property 'rockchip,playback-only', 'rockchip,capture-only'. Implement it by 'dma-names' of DT instead. Changes in v2: - split property trcm into single 'trcm-sync-tx-only' and 'trcm-sync-rx-only' suggested by Nicolas. - split property trcm into single 'trcm-sync-tx-only' and 'trcm-sync-rx-only' suggested by Nicolas. - drop change-id Sugar Zhang (12): ASoC: rockchip: i2s: Add support for set bclk ratio ASoC: rockchip: i2s: Fixup clk div error ASoC: rockchip: i2s: Improve dma data transfer efficiency ASoC: rockchip: i2s: Fix regmap_ops hang ASoC: rockchip: i2s: Fix concurrency between tx/rx ASoC: rockchip: i2s: Reset the controller if soft reset failed ASoC: dt-bindings: rockchip: Document reset property for i2s ASoC: rockchip: i2s: Make playback/capture optional ASoC: rockchip: i2s: Add compatible for more SoCs ASoC: dt-bindings: rockchip: Add compatible strings for more SoCs ASoC: rockchip: i2s: Add support for frame inversion ASoC: dt-bindings: rockchip: i2s: Document property TRCM Xiaotan Luo (1): ASoC: rockchip: i2s: Fixup config for DAIFMT_DSP_A/B Xing Zheng (1): ASoC: rockchip: i2s: Add support for TRCM property .../devicetree/bindings/sound/rockchip-i2s.yaml | 19 ++ sound/soc/rockchip/rockchip_i2s.c | 278 +++++++++++++++------ sound/soc/rockchip/rockchip_i2s.h | 10 +- 3 files changed, 224 insertions(+), 83 deletions(-) -- 2.7.4
This commit is contained in:
commit
515b436be2
@ -20,7 +20,9 @@ properties:
|
||||
- items:
|
||||
- enum:
|
||||
- rockchip,px30-i2s
|
||||
- rockchip,rk1808-i2s
|
||||
- rockchip,rk3036-i2s
|
||||
- rockchip,rk3128-i2s
|
||||
- rockchip,rk3188-i2s
|
||||
- rockchip,rk3228-i2s
|
||||
- rockchip,rk3288-i2s
|
||||
@ -29,6 +31,7 @@ properties:
|
||||
- rockchip,rk3366-i2s
|
||||
- rockchip,rk3368-i2s
|
||||
- rockchip,rk3399-i2s
|
||||
- rockchip,rv1126-i2s
|
||||
- const: rockchip,rk3066-i2s
|
||||
|
||||
reg:
|
||||
@ -61,6 +64,14 @@ properties:
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: reset-m
|
||||
- const: reset-h
|
||||
|
||||
resets:
|
||||
maxItems: 2
|
||||
|
||||
rockchip,capture-channels:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
default: 2
|
||||
|
@ -40,6 +40,9 @@ struct rk_i2s_dev {
|
||||
struct regmap *regmap;
|
||||
struct regmap *grf;
|
||||
|
||||
bool has_capture;
|
||||
bool has_playback;
|
||||
|
||||
/*
|
||||
* Used to indicate the tx/rx status.
|
||||
* I2S controller hopes to start the tx and rx together,
|
||||
@ -49,6 +52,7 @@ struct rk_i2s_dev {
|
||||
bool rx_start;
|
||||
bool is_master_mode;
|
||||
const struct rk_i2s_pins *pins;
|
||||
unsigned int bclk_ratio;
|
||||
};
|
||||
|
||||
static int i2s_runtime_suspend(struct device *dev)
|
||||
@ -186,7 +190,9 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
|
||||
{
|
||||
struct rk_i2s_dev *i2s = to_info(cpu_dai);
|
||||
unsigned int mask = 0, val = 0;
|
||||
int ret = 0;
|
||||
|
||||
pm_runtime_get_sync(cpu_dai->dev);
|
||||
mask = I2S_CKR_MSS_MASK;
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
@ -199,21 +205,37 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
|
||||
i2s->is_master_mode = false;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto err_pm_put;
|
||||
}
|
||||
|
||||
regmap_update_bits(i2s->regmap, I2S_CKR, mask, val);
|
||||
|
||||
mask = I2S_CKR_CKP_MASK;
|
||||
mask = I2S_CKR_CKP_MASK | I2S_CKR_TLP_MASK | I2S_CKR_RLP_MASK;
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
val = I2S_CKR_CKP_NEG;
|
||||
val = I2S_CKR_CKP_NORMAL |
|
||||
I2S_CKR_TLP_NORMAL |
|
||||
I2S_CKR_RLP_NORMAL;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_NB_IF:
|
||||
val = I2S_CKR_CKP_NORMAL |
|
||||
I2S_CKR_TLP_INVERTED |
|
||||
I2S_CKR_RLP_INVERTED;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF:
|
||||
val = I2S_CKR_CKP_POS;
|
||||
val = I2S_CKR_CKP_INVERTED |
|
||||
I2S_CKR_TLP_NORMAL |
|
||||
I2S_CKR_RLP_NORMAL;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_IF:
|
||||
val = I2S_CKR_CKP_INVERTED |
|
||||
I2S_CKR_TLP_INVERTED |
|
||||
I2S_CKR_RLP_INVERTED;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto err_pm_put;
|
||||
}
|
||||
|
||||
regmap_update_bits(i2s->regmap, I2S_CKR, mask, val);
|
||||
@ -229,14 +251,15 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
val = I2S_TXCR_IBM_NORMAL;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A: /* PCM no delay mode */
|
||||
val = I2S_TXCR_TFS_PCM;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_B: /* PCM delay 1 mode */
|
||||
case SND_SOC_DAIFMT_DSP_A: /* PCM delay 1 bit mode */
|
||||
val = I2S_TXCR_TFS_PCM | I2S_TXCR_PBM_MODE(1);
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_B: /* PCM no delay mode */
|
||||
val = I2S_TXCR_TFS_PCM;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto err_pm_put;
|
||||
}
|
||||
|
||||
regmap_update_bits(i2s->regmap, I2S_TXCR, mask, val);
|
||||
@ -252,19 +275,23 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
val = I2S_RXCR_IBM_NORMAL;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A: /* PCM no delay mode */
|
||||
val = I2S_RXCR_TFS_PCM;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_B: /* PCM delay 1 mode */
|
||||
case SND_SOC_DAIFMT_DSP_A: /* PCM delay 1 bit mode */
|
||||
val = I2S_RXCR_TFS_PCM | I2S_RXCR_PBM_MODE(1);
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_B: /* PCM no delay mode */
|
||||
val = I2S_RXCR_TFS_PCM;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto err_pm_put;
|
||||
}
|
||||
|
||||
regmap_update_bits(i2s->regmap, I2S_RXCR, mask, val);
|
||||
|
||||
return 0;
|
||||
err_pm_put:
|
||||
pm_runtime_put(cpu_dai->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
|
||||
@ -278,11 +305,11 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
|
||||
|
||||
if (i2s->is_master_mode) {
|
||||
mclk_rate = clk_get_rate(i2s->mclk);
|
||||
bclk_rate = 2 * 32 * params_rate(params);
|
||||
if (bclk_rate == 0 || mclk_rate % bclk_rate)
|
||||
bclk_rate = i2s->bclk_ratio * params_rate(params);
|
||||
if (!bclk_rate)
|
||||
return -EINVAL;
|
||||
|
||||
div_bclk = mclk_rate / bclk_rate;
|
||||
div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate);
|
||||
div_lrck = bclk_rate / params_rate(params);
|
||||
regmap_update_bits(i2s->regmap, I2S_CKR,
|
||||
I2S_CKR_MDIV_MASK,
|
||||
@ -413,6 +440,16 @@ static int rockchip_i2s_trigger(struct snd_pcm_substream *substream,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rockchip_i2s_set_bclk_ratio(struct snd_soc_dai *dai,
|
||||
unsigned int ratio)
|
||||
{
|
||||
struct rk_i2s_dev *i2s = to_info(dai);
|
||||
|
||||
i2s->bclk_ratio = ratio;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rockchip_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
|
||||
unsigned int freq, int dir)
|
||||
{
|
||||
@ -433,14 +470,16 @@ static int rockchip_i2s_dai_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct rk_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
dai->capture_dma_data = &i2s->capture_dma_data;
|
||||
dai->playback_dma_data = &i2s->playback_dma_data;
|
||||
snd_soc_dai_init_dma_data(dai,
|
||||
i2s->has_playback ? &i2s->playback_dma_data : NULL,
|
||||
i2s->has_capture ? &i2s->capture_dma_data : NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = {
|
||||
.hw_params = rockchip_i2s_hw_params,
|
||||
.set_bclk_ratio = rockchip_i2s_set_bclk_ratio,
|
||||
.set_sysclk = rockchip_i2s_set_sysclk,
|
||||
.set_fmt = rockchip_i2s_set_fmt,
|
||||
.trigger = rockchip_i2s_trigger,
|
||||
@ -448,28 +487,6 @@ static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = {
|
||||
|
||||
static struct snd_soc_dai_driver rockchip_i2s_dai = {
|
||||
.probe = rockchip_i2s_dai_probe,
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = SNDRV_PCM_RATE_8000_192000,
|
||||
.formats = (SNDRV_PCM_FMTBIT_S8 |
|
||||
SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S20_3LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE),
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = SNDRV_PCM_RATE_8000_192000,
|
||||
.formats = (SNDRV_PCM_FMTBIT_S8 |
|
||||
SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S20_3LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE),
|
||||
},
|
||||
.ops = &rockchip_i2s_dai_ops,
|
||||
.symmetric_rate = 1,
|
||||
};
|
||||
@ -567,23 +584,101 @@ static const struct rk_i2s_pins rk3399_i2s_pins = {
|
||||
};
|
||||
|
||||
static const struct of_device_id rockchip_i2s_match[] __maybe_unused = {
|
||||
{ .compatible = "rockchip,px30-i2s", },
|
||||
{ .compatible = "rockchip,rk1808-i2s", },
|
||||
{ .compatible = "rockchip,rk3036-i2s", },
|
||||
{ .compatible = "rockchip,rk3066-i2s", },
|
||||
{ .compatible = "rockchip,rk3128-i2s", },
|
||||
{ .compatible = "rockchip,rk3188-i2s", },
|
||||
{ .compatible = "rockchip,rk3228-i2s", },
|
||||
{ .compatible = "rockchip,rk3288-i2s", },
|
||||
{ .compatible = "rockchip,rk3308-i2s", },
|
||||
{ .compatible = "rockchip,rk3328-i2s", },
|
||||
{ .compatible = "rockchip,rk3366-i2s", },
|
||||
{ .compatible = "rockchip,rk3368-i2s", },
|
||||
{ .compatible = "rockchip,rk3399-i2s", .data = &rk3399_i2s_pins },
|
||||
{ .compatible = "rockchip,rv1126-i2s", },
|
||||
{},
|
||||
};
|
||||
|
||||
static int rockchip_i2s_init_dai(struct rk_i2s_dev *i2s, struct resource *res,
|
||||
struct snd_soc_dai_driver **dp)
|
||||
{
|
||||
struct device_node *node = i2s->dev->of_node;
|
||||
struct snd_soc_dai_driver *dai;
|
||||
struct property *dma_names;
|
||||
const char *dma_name;
|
||||
unsigned int val;
|
||||
|
||||
of_property_for_each_string(node, "dma-names", dma_names, dma_name) {
|
||||
if (!strcmp(dma_name, "tx"))
|
||||
i2s->has_playback = true;
|
||||
if (!strcmp(dma_name, "rx"))
|
||||
i2s->has_capture = true;
|
||||
}
|
||||
|
||||
dai = devm_kmemdup(i2s->dev, &rockchip_i2s_dai,
|
||||
sizeof(*dai), GFP_KERNEL);
|
||||
if (!dai)
|
||||
return -ENOMEM;
|
||||
|
||||
if (i2s->has_playback) {
|
||||
dai->playback.stream_name = "Playback";
|
||||
dai->playback.channels_min = 2;
|
||||
dai->playback.channels_max = 8;
|
||||
dai->playback.rates = SNDRV_PCM_RATE_8000_192000;
|
||||
dai->playback.formats = SNDRV_PCM_FMTBIT_S8 |
|
||||
SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S20_3LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE;
|
||||
|
||||
i2s->playback_dma_data.addr = res->start + I2S_TXDR;
|
||||
i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
i2s->playback_dma_data.maxburst = 8;
|
||||
|
||||
if (!of_property_read_u32(node, "rockchip,playback-channels", &val)) {
|
||||
if (val >= 2 && val <= 8)
|
||||
dai->playback.channels_max = val;
|
||||
}
|
||||
}
|
||||
|
||||
if (i2s->has_capture) {
|
||||
dai->capture.stream_name = "Capture";
|
||||
dai->capture.channels_min = 2;
|
||||
dai->capture.channels_max = 8;
|
||||
dai->capture.rates = SNDRV_PCM_RATE_8000_192000;
|
||||
dai->capture.formats = SNDRV_PCM_FMTBIT_S8 |
|
||||
SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S20_3LE |
|
||||
SNDRV_PCM_FMTBIT_S24_LE |
|
||||
SNDRV_PCM_FMTBIT_S32_LE;
|
||||
|
||||
i2s->capture_dma_data.addr = res->start + I2S_RXDR;
|
||||
i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
i2s->capture_dma_data.maxburst = 8;
|
||||
|
||||
if (!of_property_read_u32(node, "rockchip,capture-channels", &val)) {
|
||||
if (val >= 2 && val <= 8)
|
||||
dai->capture.channels_max = val;
|
||||
}
|
||||
}
|
||||
|
||||
if (dp)
|
||||
*dp = dai;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rockchip_i2s_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
const struct of_device_id *of_id;
|
||||
struct rk_i2s_dev *i2s;
|
||||
struct snd_soc_dai_driver *soc_dai;
|
||||
struct snd_soc_dai_driver *dai;
|
||||
struct resource *res;
|
||||
void __iomem *regs;
|
||||
int ret;
|
||||
int val;
|
||||
|
||||
i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
|
||||
if (!i2s)
|
||||
@ -630,13 +725,7 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(i2s->regmap);
|
||||
}
|
||||
|
||||
i2s->playback_dma_data.addr = res->start + I2S_TXDR;
|
||||
i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
i2s->playback_dma_data.maxburst = 4;
|
||||
|
||||
i2s->capture_dma_data.addr = res->start + I2S_RXDR;
|
||||
i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
i2s->capture_dma_data.maxburst = 4;
|
||||
i2s->bclk_ratio = 64;
|
||||
|
||||
dev_set_drvdata(&pdev->dev, i2s);
|
||||
|
||||
@ -647,26 +736,13 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
|
||||
goto err_pm_disable;
|
||||
}
|
||||
|
||||
soc_dai = devm_kmemdup(&pdev->dev, &rockchip_i2s_dai,
|
||||
sizeof(*soc_dai), GFP_KERNEL);
|
||||
if (!soc_dai) {
|
||||
ret = -ENOMEM;
|
||||
ret = rockchip_i2s_init_dai(i2s, res, &dai);
|
||||
if (ret)
|
||||
goto err_pm_disable;
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(node, "rockchip,playback-channels", &val)) {
|
||||
if (val >= 2 && val <= 8)
|
||||
soc_dai->playback.channels_max = val;
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(node, "rockchip,capture-channels", &val)) {
|
||||
if (val >= 2 && val <= 8)
|
||||
soc_dai->capture.channels_max = val;
|
||||
}
|
||||
|
||||
ret = devm_snd_soc_register_component(&pdev->dev,
|
||||
&rockchip_i2s_component,
|
||||
soc_dai, 1);
|
||||
dai, 1);
|
||||
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Could not register DAI\n");
|
||||
|
@ -88,15 +88,17 @@
|
||||
#define I2S_CKR_MSS_SLAVE (1 << I2S_CKR_MSS_SHIFT)
|
||||
#define I2S_CKR_MSS_MASK (1 << I2S_CKR_MSS_SHIFT)
|
||||
#define I2S_CKR_CKP_SHIFT 26
|
||||
#define I2S_CKR_CKP_NEG (0 << I2S_CKR_CKP_SHIFT)
|
||||
#define I2S_CKR_CKP_POS (1 << I2S_CKR_CKP_SHIFT)
|
||||
#define I2S_CKR_CKP_NORMAL (0 << I2S_CKR_CKP_SHIFT)
|
||||
#define I2S_CKR_CKP_INVERTED (1 << I2S_CKR_CKP_SHIFT)
|
||||
#define I2S_CKR_CKP_MASK (1 << I2S_CKR_CKP_SHIFT)
|
||||
#define I2S_CKR_RLP_SHIFT 25
|
||||
#define I2S_CKR_RLP_NORMAL (0 << I2S_CKR_RLP_SHIFT)
|
||||
#define I2S_CKR_RLP_OPPSITE (1 << I2S_CKR_RLP_SHIFT)
|
||||
#define I2S_CKR_RLP_INVERTED (1 << I2S_CKR_RLP_SHIFT)
|
||||
#define I2S_CKR_RLP_MASK (1 << I2S_CKR_RLP_SHIFT)
|
||||
#define I2S_CKR_TLP_SHIFT 24
|
||||
#define I2S_CKR_TLP_NORMAL (0 << I2S_CKR_TLP_SHIFT)
|
||||
#define I2S_CKR_TLP_OPPSITE (1 << I2S_CKR_TLP_SHIFT)
|
||||
#define I2S_CKR_TLP_INVERTED (1 << I2S_CKR_TLP_SHIFT)
|
||||
#define I2S_CKR_TLP_MASK (1 << I2S_CKR_TLP_SHIFT)
|
||||
#define I2S_CKR_MDIV_SHIFT 16
|
||||
#define I2S_CKR_MDIV(x) ((x - 1) << I2S_CKR_MDIV_SHIFT)
|
||||
#define I2S_CKR_MDIV_MASK (0xff << I2S_CKR_MDIV_SHIFT)
|
||||
|
Loading…
x
Reference in New Issue
Block a user