Unverified Commit 515b436b authored by Mark Brown's avatar Mark Brown
Browse files

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
parents dac825b6 917f0771
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -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
+144 −68
Original line number Diff line number Diff line
@@ -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");
+6 −4
Original line number Diff line number Diff line
@@ -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)