Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 170abcaa authored by Sugar Zhang's avatar Sugar Zhang Committed by Mark Brown
Browse files

ASoC: rockchip: i2s: configure the sdio pins' iomux mode



There are 3 i2s sdio pins, which iomux mode is as follows:

 - sdi3_sdo1
 - sdi2_sdo2
 - sdi1_sdo3

we need to configure these pins' iomux mode via the GRF register
when use multi channel playback/capture.

Signed-off-by: default avatarSugar Zhang <sugar.zhang@rock-chips.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 1a695a90
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -23,6 +23,11 @@ Required properties:
- rockchip,playback-channels: max playback channels, if not set, 8 channels default.
- rockchip,capture-channels: max capture channels, if not set, 2 channels default.

Required properties for controller which support multi channels
playback/capture:

- rockchip,grf: the phandle of the syscon node for GRF register.

Example for rk3288 I2S controller:

i2s@ff890000 {
+58 −9
Original line number Diff line number Diff line
@@ -11,8 +11,10 @@
 */

#include <linux/module.h>
#include <linux/mfd/syscon.h>
#include <linux/delay.h>
#include <linux/of_gpio.h>
#include <linux/of_device.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
@@ -23,6 +25,11 @@

#define DRV_NAME "rockchip-i2s"

struct rk_i2s_pins {
	u32 reg_offset;
	u32 shift;
};

struct rk_i2s_dev {
	struct device *dev;

@@ -33,6 +40,7 @@ struct rk_i2s_dev {
	struct snd_dmaengine_dai_dma_data playback_dma_data;

	struct regmap *regmap;
	struct regmap *grf;

/*
 * Used to indicate the tx/rx status.
@@ -42,6 +50,7 @@ struct rk_i2s_dev {
	bool tx_start;
	bool rx_start;
	bool is_master_mode;
	const struct rk_i2s_pins *pins;
};

static int i2s_runtime_suspend(struct device *dev)
@@ -300,6 +309,30 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
				   I2S_TXCR_VDW_MASK | I2S_TXCR_CSR_MASK,
				   val);

	if (!IS_ERR(i2s->grf) && i2s->pins) {
		regmap_read(i2s->regmap, I2S_TXCR, &val);
		val &= I2S_TXCR_CSR_MASK;

		switch (val) {
		case I2S_CHN_4:
			val = I2S_IO_4CH_OUT_6CH_IN;
			break;
		case I2S_CHN_6:
			val = I2S_IO_6CH_OUT_4CH_IN;
			break;
		case I2S_CHN_8:
			val = I2S_IO_8CH_OUT_2CH_IN;
			break;
		default:
			val = I2S_IO_2CH_OUT_8CH_IN;
			break;
		}

		val <<= i2s->pins->shift;
		val |= (I2S_IO_DIRECTION_MASK << i2s->pins->shift) << 16;
		regmap_write(i2s->grf, i2s->pins->reg_offset, 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,
@@ -485,9 +518,23 @@ static const struct regmap_config rockchip_i2s_regmap_config = {
	.cache_type = REGCACHE_FLAT,
};

static const struct rk_i2s_pins rk3399_i2s_pins = {
	.reg_offset = 0xe220,
	.shift = 11,
};

static const struct of_device_id rockchip_i2s_match[] = {
	{ .compatible = "rockchip,rk3066-i2s", },
	{ .compatible = "rockchip,rk3188-i2s", },
	{ .compatible = "rockchip,rk3288-i2s", },
	{ .compatible = "rockchip,rk3399-i2s", .data = &rk3399_i2s_pins },
	{},
};

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 resource *res;
@@ -501,6 +548,17 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
		return -ENOMEM;
	}

	i2s->dev = &pdev->dev;

	i2s->grf = syscon_regmap_lookup_by_phandle(node, "rockchip,grf");
	if (!IS_ERR(i2s->grf)) {
		of_id = of_match_device(rockchip_i2s_match, &pdev->dev);
		if (!of_id || !of_id->data)
			return -EINVAL;

		i2s->pins = of_id->data;
	}

	/* try to prepare related clocks */
	i2s->hclk = devm_clk_get(&pdev->dev, "i2s_hclk");
	if (IS_ERR(i2s->hclk)) {
@@ -540,7 +598,6 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
	i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
	i2s->capture_dma_data.maxburst = 4;

	i2s->dev = &pdev->dev;
	dev_set_drvdata(&pdev->dev, i2s);

	pm_runtime_enable(&pdev->dev);
@@ -606,14 +663,6 @@ static int rockchip_i2s_remove(struct platform_device *pdev)
	return 0;
}

static const struct of_device_id rockchip_i2s_match[] = {
	{ .compatible = "rockchip,rk3066-i2s", },
	{ .compatible = "rockchip,rk3188-i2s", },
	{ .compatible = "rockchip,rk3288-i2s", },
	{ .compatible = "rockchip,rk3399-i2s", },
	{},
};

static const struct dev_pm_ops rockchip_i2s_pm_ops = {
	SET_RUNTIME_PM_OPS(i2s_runtime_suspend, i2s_runtime_resume,
			   NULL)
+7 −0
Original line number Diff line number Diff line
@@ -236,4 +236,11 @@ enum {
#define I2S_TXDR	(0x0024)
#define I2S_RXDR	(0x0028)

/* io direction cfg register */
#define I2S_IO_DIRECTION_MASK	(7)
#define I2S_IO_8CH_OUT_2CH_IN	(0)
#define I2S_IO_6CH_OUT_4CH_IN	(4)
#define I2S_IO_4CH_OUT_6CH_IN	(6)
#define I2S_IO_2CH_OUT_8CH_IN	(7)

#endif /* _ROCKCHIP_IIS_H */