162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/* sound/soc/rockchip/rockchip_i2s.c
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * ALSA SoC Audio Layer - Rockchip I2S Controller driver
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (c) 2014 Rockchip Electronics Co. Ltd.
762306a36Sopenharmony_ci * Author: Jianqun <jay.xu@rock-chips.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
1262306a36Sopenharmony_ci#include <linux/delay.h>
1362306a36Sopenharmony_ci#include <linux/of_gpio.h>
1462306a36Sopenharmony_ci#include <linux/of_device.h>
1562306a36Sopenharmony_ci#include <linux/clk.h>
1662306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h>
1762306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1862306a36Sopenharmony_ci#include <linux/regmap.h>
1962306a36Sopenharmony_ci#include <linux/spinlock.h>
2062306a36Sopenharmony_ci#include <sound/pcm_params.h>
2162306a36Sopenharmony_ci#include <sound/dmaengine_pcm.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include "rockchip_i2s.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define DRV_NAME "rockchip-i2s"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistruct rk_i2s_pins {
2862306a36Sopenharmony_ci	u32 reg_offset;
2962306a36Sopenharmony_ci	u32 shift;
3062306a36Sopenharmony_ci};
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistruct rk_i2s_dev {
3362306a36Sopenharmony_ci	struct device *dev;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	struct clk *hclk;
3662306a36Sopenharmony_ci	struct clk *mclk;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	struct snd_dmaengine_dai_dma_data capture_dma_data;
3962306a36Sopenharmony_ci	struct snd_dmaengine_dai_dma_data playback_dma_data;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	struct regmap *regmap;
4262306a36Sopenharmony_ci	struct regmap *grf;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	bool has_capture;
4562306a36Sopenharmony_ci	bool has_playback;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/*
4862306a36Sopenharmony_ci * Used to indicate the tx/rx status.
4962306a36Sopenharmony_ci * I2S controller hopes to start the tx and rx together,
5062306a36Sopenharmony_ci * also to stop them when they are both try to stop.
5162306a36Sopenharmony_ci*/
5262306a36Sopenharmony_ci	bool tx_start;
5362306a36Sopenharmony_ci	bool rx_start;
5462306a36Sopenharmony_ci	bool is_master_mode;
5562306a36Sopenharmony_ci	const struct rk_i2s_pins *pins;
5662306a36Sopenharmony_ci	unsigned int bclk_ratio;
5762306a36Sopenharmony_ci	spinlock_t lock; /* tx/rx lock */
5862306a36Sopenharmony_ci	struct pinctrl *pinctrl;
5962306a36Sopenharmony_ci	struct pinctrl_state *bclk_on;
6062306a36Sopenharmony_ci	struct pinctrl_state *bclk_off;
6162306a36Sopenharmony_ci};
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic int i2s_pinctrl_select_bclk_on(struct rk_i2s_dev *i2s)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	int ret = 0;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	if (!IS_ERR(i2s->pinctrl) && !IS_ERR_OR_NULL(i2s->bclk_on))
6862306a36Sopenharmony_ci		ret = pinctrl_select_state(i2s->pinctrl, i2s->bclk_on);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	if (ret)
7162306a36Sopenharmony_ci		dev_err(i2s->dev, "bclk enable failed %d\n", ret);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	return ret;
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic int i2s_pinctrl_select_bclk_off(struct rk_i2s_dev *i2s)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	int ret = 0;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	if (!IS_ERR(i2s->pinctrl) && !IS_ERR_OR_NULL(i2s->bclk_off))
8262306a36Sopenharmony_ci		ret = pinctrl_select_state(i2s->pinctrl, i2s->bclk_off);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	if (ret)
8562306a36Sopenharmony_ci		dev_err(i2s->dev, "bclk disable failed %d\n", ret);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	return ret;
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic int i2s_runtime_suspend(struct device *dev)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	struct rk_i2s_dev *i2s = dev_get_drvdata(dev);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	regcache_cache_only(i2s->regmap, true);
9562306a36Sopenharmony_ci	clk_disable_unprepare(i2s->mclk);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	return 0;
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic int i2s_runtime_resume(struct device *dev)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	struct rk_i2s_dev *i2s = dev_get_drvdata(dev);
10362306a36Sopenharmony_ci	int ret;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	ret = clk_prepare_enable(i2s->mclk);
10662306a36Sopenharmony_ci	if (ret) {
10762306a36Sopenharmony_ci		dev_err(i2s->dev, "clock enable failed %d\n", ret);
10862306a36Sopenharmony_ci		return ret;
10962306a36Sopenharmony_ci	}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	regcache_cache_only(i2s->regmap, false);
11262306a36Sopenharmony_ci	regcache_mark_dirty(i2s->regmap);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	ret = regcache_sync(i2s->regmap);
11562306a36Sopenharmony_ci	if (ret)
11662306a36Sopenharmony_ci		clk_disable_unprepare(i2s->mclk);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	return ret;
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic inline struct rk_i2s_dev *to_info(struct snd_soc_dai *dai)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	return snd_soc_dai_get_drvdata(dai);
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic int rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	unsigned int val = 0;
12962306a36Sopenharmony_ci	int ret = 0;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	spin_lock(&i2s->lock);
13262306a36Sopenharmony_ci	if (on) {
13362306a36Sopenharmony_ci		ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
13462306a36Sopenharmony_ci					 I2S_DMACR_TDE_ENABLE,
13562306a36Sopenharmony_ci					 I2S_DMACR_TDE_ENABLE);
13662306a36Sopenharmony_ci		if (ret < 0)
13762306a36Sopenharmony_ci			goto end;
13862306a36Sopenharmony_ci		ret = regmap_update_bits(i2s->regmap, I2S_XFER,
13962306a36Sopenharmony_ci					 I2S_XFER_TXS_START | I2S_XFER_RXS_START,
14062306a36Sopenharmony_ci					 I2S_XFER_TXS_START | I2S_XFER_RXS_START);
14162306a36Sopenharmony_ci		if (ret < 0)
14262306a36Sopenharmony_ci			goto end;
14362306a36Sopenharmony_ci		i2s->tx_start = true;
14462306a36Sopenharmony_ci	} else {
14562306a36Sopenharmony_ci		i2s->tx_start = false;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci		ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
14862306a36Sopenharmony_ci					 I2S_DMACR_TDE_ENABLE,
14962306a36Sopenharmony_ci					 I2S_DMACR_TDE_DISABLE);
15062306a36Sopenharmony_ci		if (ret < 0)
15162306a36Sopenharmony_ci			goto end;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci		if (!i2s->rx_start) {
15462306a36Sopenharmony_ci			ret = regmap_update_bits(i2s->regmap, I2S_XFER,
15562306a36Sopenharmony_ci						 I2S_XFER_TXS_START | I2S_XFER_RXS_START,
15662306a36Sopenharmony_ci						 I2S_XFER_TXS_STOP | I2S_XFER_RXS_STOP);
15762306a36Sopenharmony_ci			if (ret < 0)
15862306a36Sopenharmony_ci				goto end;
15962306a36Sopenharmony_ci			udelay(150);
16062306a36Sopenharmony_ci			ret = regmap_update_bits(i2s->regmap, I2S_CLR,
16162306a36Sopenharmony_ci						 I2S_CLR_TXC | I2S_CLR_RXC,
16262306a36Sopenharmony_ci						 I2S_CLR_TXC | I2S_CLR_RXC);
16362306a36Sopenharmony_ci			if (ret < 0)
16462306a36Sopenharmony_ci				goto end;
16562306a36Sopenharmony_ci			ret = regmap_read_poll_timeout_atomic(i2s->regmap,
16662306a36Sopenharmony_ci							      I2S_CLR,
16762306a36Sopenharmony_ci							      val,
16862306a36Sopenharmony_ci							      val == 0,
16962306a36Sopenharmony_ci							      20,
17062306a36Sopenharmony_ci							      200);
17162306a36Sopenharmony_ci			if (ret < 0)
17262306a36Sopenharmony_ci				dev_warn(i2s->dev, "fail to clear: %d\n", ret);
17362306a36Sopenharmony_ci		}
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ciend:
17662306a36Sopenharmony_ci	spin_unlock(&i2s->lock);
17762306a36Sopenharmony_ci	if (ret < 0)
17862306a36Sopenharmony_ci		dev_err(i2s->dev, "lrclk update failed\n");
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	return ret;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic int rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	unsigned int val = 0;
18662306a36Sopenharmony_ci	int ret = 0;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	spin_lock(&i2s->lock);
18962306a36Sopenharmony_ci	if (on) {
19062306a36Sopenharmony_ci		ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
19162306a36Sopenharmony_ci					 I2S_DMACR_RDE_ENABLE,
19262306a36Sopenharmony_ci					 I2S_DMACR_RDE_ENABLE);
19362306a36Sopenharmony_ci		if (ret < 0)
19462306a36Sopenharmony_ci			goto end;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci		ret = regmap_update_bits(i2s->regmap, I2S_XFER,
19762306a36Sopenharmony_ci					 I2S_XFER_TXS_START | I2S_XFER_RXS_START,
19862306a36Sopenharmony_ci					 I2S_XFER_TXS_START | I2S_XFER_RXS_START);
19962306a36Sopenharmony_ci		if (ret < 0)
20062306a36Sopenharmony_ci			goto end;
20162306a36Sopenharmony_ci		i2s->rx_start = true;
20262306a36Sopenharmony_ci	} else {
20362306a36Sopenharmony_ci		i2s->rx_start = false;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci		ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
20662306a36Sopenharmony_ci					 I2S_DMACR_RDE_ENABLE,
20762306a36Sopenharmony_ci					 I2S_DMACR_RDE_DISABLE);
20862306a36Sopenharmony_ci		if (ret < 0)
20962306a36Sopenharmony_ci			goto end;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci		if (!i2s->tx_start) {
21262306a36Sopenharmony_ci			ret = regmap_update_bits(i2s->regmap, I2S_XFER,
21362306a36Sopenharmony_ci						 I2S_XFER_TXS_START | I2S_XFER_RXS_START,
21462306a36Sopenharmony_ci						 I2S_XFER_TXS_STOP | I2S_XFER_RXS_STOP);
21562306a36Sopenharmony_ci			if (ret < 0)
21662306a36Sopenharmony_ci				goto end;
21762306a36Sopenharmony_ci			udelay(150);
21862306a36Sopenharmony_ci			ret = regmap_update_bits(i2s->regmap, I2S_CLR,
21962306a36Sopenharmony_ci						 I2S_CLR_TXC | I2S_CLR_RXC,
22062306a36Sopenharmony_ci						 I2S_CLR_TXC | I2S_CLR_RXC);
22162306a36Sopenharmony_ci			if (ret < 0)
22262306a36Sopenharmony_ci				goto end;
22362306a36Sopenharmony_ci			ret = regmap_read_poll_timeout_atomic(i2s->regmap,
22462306a36Sopenharmony_ci							      I2S_CLR,
22562306a36Sopenharmony_ci							      val,
22662306a36Sopenharmony_ci							      val == 0,
22762306a36Sopenharmony_ci							      20,
22862306a36Sopenharmony_ci							      200);
22962306a36Sopenharmony_ci			if (ret < 0)
23062306a36Sopenharmony_ci				dev_warn(i2s->dev, "fail to clear: %d\n", ret);
23162306a36Sopenharmony_ci		}
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ciend:
23462306a36Sopenharmony_ci	spin_unlock(&i2s->lock);
23562306a36Sopenharmony_ci	if (ret < 0)
23662306a36Sopenharmony_ci		dev_err(i2s->dev, "lrclk update failed\n");
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	return ret;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
24262306a36Sopenharmony_ci				unsigned int fmt)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	struct rk_i2s_dev *i2s = to_info(cpu_dai);
24562306a36Sopenharmony_ci	unsigned int mask = 0, val = 0;
24662306a36Sopenharmony_ci	int ret = 0;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	pm_runtime_get_sync(cpu_dai->dev);
24962306a36Sopenharmony_ci	mask = I2S_CKR_MSS_MASK;
25062306a36Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
25162306a36Sopenharmony_ci	case SND_SOC_DAIFMT_BP_FP:
25262306a36Sopenharmony_ci		/* Set source clock in Master mode */
25362306a36Sopenharmony_ci		val = I2S_CKR_MSS_MASTER;
25462306a36Sopenharmony_ci		i2s->is_master_mode = true;
25562306a36Sopenharmony_ci		break;
25662306a36Sopenharmony_ci	case SND_SOC_DAIFMT_BC_FC:
25762306a36Sopenharmony_ci		val = I2S_CKR_MSS_SLAVE;
25862306a36Sopenharmony_ci		i2s->is_master_mode = false;
25962306a36Sopenharmony_ci		break;
26062306a36Sopenharmony_ci	default:
26162306a36Sopenharmony_ci		ret = -EINVAL;
26262306a36Sopenharmony_ci		goto err_pm_put;
26362306a36Sopenharmony_ci	}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	regmap_update_bits(i2s->regmap, I2S_CKR, mask, val);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	mask = I2S_CKR_CKP_MASK | I2S_CKR_TLP_MASK | I2S_CKR_RLP_MASK;
26862306a36Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
26962306a36Sopenharmony_ci	case SND_SOC_DAIFMT_NB_NF:
27062306a36Sopenharmony_ci		val = I2S_CKR_CKP_NORMAL |
27162306a36Sopenharmony_ci		      I2S_CKR_TLP_NORMAL |
27262306a36Sopenharmony_ci		      I2S_CKR_RLP_NORMAL;
27362306a36Sopenharmony_ci		break;
27462306a36Sopenharmony_ci	case SND_SOC_DAIFMT_NB_IF:
27562306a36Sopenharmony_ci		val = I2S_CKR_CKP_NORMAL |
27662306a36Sopenharmony_ci		      I2S_CKR_TLP_INVERTED |
27762306a36Sopenharmony_ci		      I2S_CKR_RLP_INVERTED;
27862306a36Sopenharmony_ci		break;
27962306a36Sopenharmony_ci	case SND_SOC_DAIFMT_IB_NF:
28062306a36Sopenharmony_ci		val = I2S_CKR_CKP_INVERTED |
28162306a36Sopenharmony_ci		      I2S_CKR_TLP_NORMAL |
28262306a36Sopenharmony_ci		      I2S_CKR_RLP_NORMAL;
28362306a36Sopenharmony_ci		break;
28462306a36Sopenharmony_ci	case SND_SOC_DAIFMT_IB_IF:
28562306a36Sopenharmony_ci		val = I2S_CKR_CKP_INVERTED |
28662306a36Sopenharmony_ci		      I2S_CKR_TLP_INVERTED |
28762306a36Sopenharmony_ci		      I2S_CKR_RLP_INVERTED;
28862306a36Sopenharmony_ci		break;
28962306a36Sopenharmony_ci	default:
29062306a36Sopenharmony_ci		ret = -EINVAL;
29162306a36Sopenharmony_ci		goto err_pm_put;
29262306a36Sopenharmony_ci	}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	regmap_update_bits(i2s->regmap, I2S_CKR, mask, val);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	mask = I2S_TXCR_IBM_MASK | I2S_TXCR_TFS_MASK | I2S_TXCR_PBM_MASK;
29762306a36Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
29862306a36Sopenharmony_ci	case SND_SOC_DAIFMT_RIGHT_J:
29962306a36Sopenharmony_ci		val = I2S_TXCR_IBM_RSJM;
30062306a36Sopenharmony_ci		break;
30162306a36Sopenharmony_ci	case SND_SOC_DAIFMT_LEFT_J:
30262306a36Sopenharmony_ci		val = I2S_TXCR_IBM_LSJM;
30362306a36Sopenharmony_ci		break;
30462306a36Sopenharmony_ci	case SND_SOC_DAIFMT_I2S:
30562306a36Sopenharmony_ci		val = I2S_TXCR_IBM_NORMAL;
30662306a36Sopenharmony_ci		break;
30762306a36Sopenharmony_ci	case SND_SOC_DAIFMT_DSP_A: /* PCM delay 1 bit mode */
30862306a36Sopenharmony_ci		val = I2S_TXCR_TFS_PCM | I2S_TXCR_PBM_MODE(1);
30962306a36Sopenharmony_ci		break;
31062306a36Sopenharmony_ci	case SND_SOC_DAIFMT_DSP_B: /* PCM no delay mode */
31162306a36Sopenharmony_ci		val = I2S_TXCR_TFS_PCM;
31262306a36Sopenharmony_ci		break;
31362306a36Sopenharmony_ci	default:
31462306a36Sopenharmony_ci		ret = -EINVAL;
31562306a36Sopenharmony_ci		goto err_pm_put;
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	regmap_update_bits(i2s->regmap, I2S_TXCR, mask, val);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	mask = I2S_RXCR_IBM_MASK | I2S_RXCR_TFS_MASK | I2S_RXCR_PBM_MASK;
32162306a36Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
32262306a36Sopenharmony_ci	case SND_SOC_DAIFMT_RIGHT_J:
32362306a36Sopenharmony_ci		val = I2S_RXCR_IBM_RSJM;
32462306a36Sopenharmony_ci		break;
32562306a36Sopenharmony_ci	case SND_SOC_DAIFMT_LEFT_J:
32662306a36Sopenharmony_ci		val = I2S_RXCR_IBM_LSJM;
32762306a36Sopenharmony_ci		break;
32862306a36Sopenharmony_ci	case SND_SOC_DAIFMT_I2S:
32962306a36Sopenharmony_ci		val = I2S_RXCR_IBM_NORMAL;
33062306a36Sopenharmony_ci		break;
33162306a36Sopenharmony_ci	case SND_SOC_DAIFMT_DSP_A: /* PCM delay 1 bit mode */
33262306a36Sopenharmony_ci		val = I2S_RXCR_TFS_PCM | I2S_RXCR_PBM_MODE(1);
33362306a36Sopenharmony_ci		break;
33462306a36Sopenharmony_ci	case SND_SOC_DAIFMT_DSP_B: /* PCM no delay mode */
33562306a36Sopenharmony_ci		val = I2S_RXCR_TFS_PCM;
33662306a36Sopenharmony_ci		break;
33762306a36Sopenharmony_ci	default:
33862306a36Sopenharmony_ci		ret = -EINVAL;
33962306a36Sopenharmony_ci		goto err_pm_put;
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	regmap_update_bits(i2s->regmap, I2S_RXCR, mask, val);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cierr_pm_put:
34562306a36Sopenharmony_ci	pm_runtime_put(cpu_dai->dev);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	return ret;
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_cistatic int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
35162306a36Sopenharmony_ci				  struct snd_pcm_hw_params *params,
35262306a36Sopenharmony_ci				  struct snd_soc_dai *dai)
35362306a36Sopenharmony_ci{
35462306a36Sopenharmony_ci	struct rk_i2s_dev *i2s = to_info(dai);
35562306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
35662306a36Sopenharmony_ci	unsigned int val = 0;
35762306a36Sopenharmony_ci	unsigned int mclk_rate, bclk_rate, div_bclk, div_lrck;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	if (i2s->is_master_mode) {
36062306a36Sopenharmony_ci		mclk_rate = clk_get_rate(i2s->mclk);
36162306a36Sopenharmony_ci		bclk_rate = i2s->bclk_ratio * params_rate(params);
36262306a36Sopenharmony_ci		if (!bclk_rate)
36362306a36Sopenharmony_ci			return -EINVAL;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci		div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate);
36662306a36Sopenharmony_ci		div_lrck = bclk_rate / params_rate(params);
36762306a36Sopenharmony_ci		regmap_update_bits(i2s->regmap, I2S_CKR,
36862306a36Sopenharmony_ci				   I2S_CKR_MDIV_MASK,
36962306a36Sopenharmony_ci				   I2S_CKR_MDIV(div_bclk));
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci		regmap_update_bits(i2s->regmap, I2S_CKR,
37262306a36Sopenharmony_ci				   I2S_CKR_TSD_MASK |
37362306a36Sopenharmony_ci				   I2S_CKR_RSD_MASK,
37462306a36Sopenharmony_ci				   I2S_CKR_TSD(div_lrck) |
37562306a36Sopenharmony_ci				   I2S_CKR_RSD(div_lrck));
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	switch (params_format(params)) {
37962306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_S8:
38062306a36Sopenharmony_ci		val |= I2S_TXCR_VDW(8);
38162306a36Sopenharmony_ci		break;
38262306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_S16_LE:
38362306a36Sopenharmony_ci		val |= I2S_TXCR_VDW(16);
38462306a36Sopenharmony_ci		break;
38562306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_S20_3LE:
38662306a36Sopenharmony_ci		val |= I2S_TXCR_VDW(20);
38762306a36Sopenharmony_ci		break;
38862306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_S24_LE:
38962306a36Sopenharmony_ci		val |= I2S_TXCR_VDW(24);
39062306a36Sopenharmony_ci		break;
39162306a36Sopenharmony_ci	case SNDRV_PCM_FORMAT_S32_LE:
39262306a36Sopenharmony_ci		val |= I2S_TXCR_VDW(32);
39362306a36Sopenharmony_ci		break;
39462306a36Sopenharmony_ci	default:
39562306a36Sopenharmony_ci		return -EINVAL;
39662306a36Sopenharmony_ci	}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	switch (params_channels(params)) {
39962306a36Sopenharmony_ci	case 8:
40062306a36Sopenharmony_ci		val |= I2S_CHN_8;
40162306a36Sopenharmony_ci		break;
40262306a36Sopenharmony_ci	case 6:
40362306a36Sopenharmony_ci		val |= I2S_CHN_6;
40462306a36Sopenharmony_ci		break;
40562306a36Sopenharmony_ci	case 4:
40662306a36Sopenharmony_ci		val |= I2S_CHN_4;
40762306a36Sopenharmony_ci		break;
40862306a36Sopenharmony_ci	case 2:
40962306a36Sopenharmony_ci		val |= I2S_CHN_2;
41062306a36Sopenharmony_ci		break;
41162306a36Sopenharmony_ci	default:
41262306a36Sopenharmony_ci		dev_err(i2s->dev, "invalid channel: %d\n",
41362306a36Sopenharmony_ci			params_channels(params));
41462306a36Sopenharmony_ci		return -EINVAL;
41562306a36Sopenharmony_ci	}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
41862306a36Sopenharmony_ci		regmap_update_bits(i2s->regmap, I2S_RXCR,
41962306a36Sopenharmony_ci				   I2S_RXCR_VDW_MASK | I2S_RXCR_CSR_MASK,
42062306a36Sopenharmony_ci				   val);
42162306a36Sopenharmony_ci	else
42262306a36Sopenharmony_ci		regmap_update_bits(i2s->regmap, I2S_TXCR,
42362306a36Sopenharmony_ci				   I2S_TXCR_VDW_MASK | I2S_TXCR_CSR_MASK,
42462306a36Sopenharmony_ci				   val);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	if (!IS_ERR(i2s->grf) && i2s->pins) {
42762306a36Sopenharmony_ci		regmap_read(i2s->regmap, I2S_TXCR, &val);
42862306a36Sopenharmony_ci		val &= I2S_TXCR_CSR_MASK;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci		switch (val) {
43162306a36Sopenharmony_ci		case I2S_CHN_4:
43262306a36Sopenharmony_ci			val = I2S_IO_4CH_OUT_6CH_IN;
43362306a36Sopenharmony_ci			break;
43462306a36Sopenharmony_ci		case I2S_CHN_6:
43562306a36Sopenharmony_ci			val = I2S_IO_6CH_OUT_4CH_IN;
43662306a36Sopenharmony_ci			break;
43762306a36Sopenharmony_ci		case I2S_CHN_8:
43862306a36Sopenharmony_ci			val = I2S_IO_8CH_OUT_2CH_IN;
43962306a36Sopenharmony_ci			break;
44062306a36Sopenharmony_ci		default:
44162306a36Sopenharmony_ci			val = I2S_IO_2CH_OUT_8CH_IN;
44262306a36Sopenharmony_ci			break;
44362306a36Sopenharmony_ci		}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci		val <<= i2s->pins->shift;
44662306a36Sopenharmony_ci		val |= (I2S_IO_DIRECTION_MASK << i2s->pins->shift) << 16;
44762306a36Sopenharmony_ci		regmap_write(i2s->grf, i2s->pins->reg_offset, val);
44862306a36Sopenharmony_ci	}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_TDL_MASK,
45162306a36Sopenharmony_ci			   I2S_DMACR_TDL(16));
45262306a36Sopenharmony_ci	regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_RDL_MASK,
45362306a36Sopenharmony_ci			   I2S_DMACR_RDL(16));
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	val = I2S_CKR_TRCM_TXRX;
45662306a36Sopenharmony_ci	if (dai->driver->symmetric_rate && rtd->dai_link->symmetric_rate)
45762306a36Sopenharmony_ci		val = I2S_CKR_TRCM_TXONLY;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	regmap_update_bits(i2s->regmap, I2S_CKR,
46062306a36Sopenharmony_ci			   I2S_CKR_TRCM_MASK,
46162306a36Sopenharmony_ci			   val);
46262306a36Sopenharmony_ci	return 0;
46362306a36Sopenharmony_ci}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_cistatic int rockchip_i2s_trigger(struct snd_pcm_substream *substream,
46662306a36Sopenharmony_ci				int cmd, struct snd_soc_dai *dai)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	struct rk_i2s_dev *i2s = to_info(dai);
46962306a36Sopenharmony_ci	int ret = 0;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	switch (cmd) {
47262306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
47362306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_RESUME:
47462306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
47562306a36Sopenharmony_ci		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
47662306a36Sopenharmony_ci			ret = rockchip_snd_rxctrl(i2s, 1);
47762306a36Sopenharmony_ci		else
47862306a36Sopenharmony_ci			ret = rockchip_snd_txctrl(i2s, 1);
47962306a36Sopenharmony_ci		if (ret < 0)
48062306a36Sopenharmony_ci			return ret;
48162306a36Sopenharmony_ci		i2s_pinctrl_select_bclk_on(i2s);
48262306a36Sopenharmony_ci		break;
48362306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_SUSPEND:
48462306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
48562306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
48662306a36Sopenharmony_ci		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
48762306a36Sopenharmony_ci			if (!i2s->tx_start)
48862306a36Sopenharmony_ci				i2s_pinctrl_select_bclk_off(i2s);
48962306a36Sopenharmony_ci			ret = rockchip_snd_rxctrl(i2s, 0);
49062306a36Sopenharmony_ci		} else {
49162306a36Sopenharmony_ci			if (!i2s->rx_start)
49262306a36Sopenharmony_ci				i2s_pinctrl_select_bclk_off(i2s);
49362306a36Sopenharmony_ci			ret = rockchip_snd_txctrl(i2s, 0);
49462306a36Sopenharmony_ci		}
49562306a36Sopenharmony_ci		break;
49662306a36Sopenharmony_ci	default:
49762306a36Sopenharmony_ci		ret = -EINVAL;
49862306a36Sopenharmony_ci		break;
49962306a36Sopenharmony_ci	}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	return ret;
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_cistatic int rockchip_i2s_set_bclk_ratio(struct snd_soc_dai *dai,
50562306a36Sopenharmony_ci				       unsigned int ratio)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	struct rk_i2s_dev *i2s = to_info(dai);
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	i2s->bclk_ratio = ratio;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	return 0;
51262306a36Sopenharmony_ci}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_cistatic int rockchip_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
51562306a36Sopenharmony_ci				   unsigned int freq, int dir)
51662306a36Sopenharmony_ci{
51762306a36Sopenharmony_ci	struct rk_i2s_dev *i2s = to_info(cpu_dai);
51862306a36Sopenharmony_ci	int ret;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	if (freq == 0)
52162306a36Sopenharmony_ci		return 0;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	ret = clk_set_rate(i2s->mclk, freq);
52462306a36Sopenharmony_ci	if (ret)
52562306a36Sopenharmony_ci		dev_err(i2s->dev, "Fail to set mclk %d\n", ret);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	return ret;
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_cistatic int rockchip_i2s_dai_probe(struct snd_soc_dai *dai)
53162306a36Sopenharmony_ci{
53262306a36Sopenharmony_ci	struct rk_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai);
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	snd_soc_dai_init_dma_data(dai,
53562306a36Sopenharmony_ci		i2s->has_playback ? &i2s->playback_dma_data : NULL,
53662306a36Sopenharmony_ci		i2s->has_capture  ? &i2s->capture_dma_data  : NULL);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	return 0;
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cistatic const struct snd_soc_dai_ops rockchip_i2s_dai_ops = {
54262306a36Sopenharmony_ci	.probe = rockchip_i2s_dai_probe,
54362306a36Sopenharmony_ci	.hw_params = rockchip_i2s_hw_params,
54462306a36Sopenharmony_ci	.set_bclk_ratio	= rockchip_i2s_set_bclk_ratio,
54562306a36Sopenharmony_ci	.set_sysclk = rockchip_i2s_set_sysclk,
54662306a36Sopenharmony_ci	.set_fmt = rockchip_i2s_set_fmt,
54762306a36Sopenharmony_ci	.trigger = rockchip_i2s_trigger,
54862306a36Sopenharmony_ci};
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_cistatic struct snd_soc_dai_driver rockchip_i2s_dai = {
55162306a36Sopenharmony_ci	.ops = &rockchip_i2s_dai_ops,
55262306a36Sopenharmony_ci	.symmetric_rate = 1,
55362306a36Sopenharmony_ci};
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_cistatic const struct snd_soc_component_driver rockchip_i2s_component = {
55662306a36Sopenharmony_ci	.name = DRV_NAME,
55762306a36Sopenharmony_ci	.legacy_dai_naming = 1,
55862306a36Sopenharmony_ci};
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_cistatic bool rockchip_i2s_wr_reg(struct device *dev, unsigned int reg)
56162306a36Sopenharmony_ci{
56262306a36Sopenharmony_ci	switch (reg) {
56362306a36Sopenharmony_ci	case I2S_TXCR:
56462306a36Sopenharmony_ci	case I2S_RXCR:
56562306a36Sopenharmony_ci	case I2S_CKR:
56662306a36Sopenharmony_ci	case I2S_DMACR:
56762306a36Sopenharmony_ci	case I2S_INTCR:
56862306a36Sopenharmony_ci	case I2S_XFER:
56962306a36Sopenharmony_ci	case I2S_CLR:
57062306a36Sopenharmony_ci	case I2S_TXDR:
57162306a36Sopenharmony_ci		return true;
57262306a36Sopenharmony_ci	default:
57362306a36Sopenharmony_ci		return false;
57462306a36Sopenharmony_ci	}
57562306a36Sopenharmony_ci}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_cistatic bool rockchip_i2s_rd_reg(struct device *dev, unsigned int reg)
57862306a36Sopenharmony_ci{
57962306a36Sopenharmony_ci	switch (reg) {
58062306a36Sopenharmony_ci	case I2S_TXCR:
58162306a36Sopenharmony_ci	case I2S_RXCR:
58262306a36Sopenharmony_ci	case I2S_CKR:
58362306a36Sopenharmony_ci	case I2S_DMACR:
58462306a36Sopenharmony_ci	case I2S_INTCR:
58562306a36Sopenharmony_ci	case I2S_XFER:
58662306a36Sopenharmony_ci	case I2S_CLR:
58762306a36Sopenharmony_ci	case I2S_TXDR:
58862306a36Sopenharmony_ci	case I2S_RXDR:
58962306a36Sopenharmony_ci	case I2S_FIFOLR:
59062306a36Sopenharmony_ci	case I2S_INTSR:
59162306a36Sopenharmony_ci		return true;
59262306a36Sopenharmony_ci	default:
59362306a36Sopenharmony_ci		return false;
59462306a36Sopenharmony_ci	}
59562306a36Sopenharmony_ci}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_cistatic bool rockchip_i2s_volatile_reg(struct device *dev, unsigned int reg)
59862306a36Sopenharmony_ci{
59962306a36Sopenharmony_ci	switch (reg) {
60062306a36Sopenharmony_ci	case I2S_INTSR:
60162306a36Sopenharmony_ci	case I2S_CLR:
60262306a36Sopenharmony_ci	case I2S_FIFOLR:
60362306a36Sopenharmony_ci	case I2S_TXDR:
60462306a36Sopenharmony_ci	case I2S_RXDR:
60562306a36Sopenharmony_ci		return true;
60662306a36Sopenharmony_ci	default:
60762306a36Sopenharmony_ci		return false;
60862306a36Sopenharmony_ci	}
60962306a36Sopenharmony_ci}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_cistatic bool rockchip_i2s_precious_reg(struct device *dev, unsigned int reg)
61262306a36Sopenharmony_ci{
61362306a36Sopenharmony_ci	switch (reg) {
61462306a36Sopenharmony_ci	case I2S_RXDR:
61562306a36Sopenharmony_ci		return true;
61662306a36Sopenharmony_ci	default:
61762306a36Sopenharmony_ci		return false;
61862306a36Sopenharmony_ci	}
61962306a36Sopenharmony_ci}
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_cistatic const struct reg_default rockchip_i2s_reg_defaults[] = {
62262306a36Sopenharmony_ci	{0x00, 0x0000000f},
62362306a36Sopenharmony_ci	{0x04, 0x0000000f},
62462306a36Sopenharmony_ci	{0x08, 0x00071f1f},
62562306a36Sopenharmony_ci	{0x10, 0x001f0000},
62662306a36Sopenharmony_ci	{0x14, 0x01f00000},
62762306a36Sopenharmony_ci};
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_cistatic const struct regmap_config rockchip_i2s_regmap_config = {
63062306a36Sopenharmony_ci	.reg_bits = 32,
63162306a36Sopenharmony_ci	.reg_stride = 4,
63262306a36Sopenharmony_ci	.val_bits = 32,
63362306a36Sopenharmony_ci	.max_register = I2S_RXDR,
63462306a36Sopenharmony_ci	.reg_defaults = rockchip_i2s_reg_defaults,
63562306a36Sopenharmony_ci	.num_reg_defaults = ARRAY_SIZE(rockchip_i2s_reg_defaults),
63662306a36Sopenharmony_ci	.writeable_reg = rockchip_i2s_wr_reg,
63762306a36Sopenharmony_ci	.readable_reg = rockchip_i2s_rd_reg,
63862306a36Sopenharmony_ci	.volatile_reg = rockchip_i2s_volatile_reg,
63962306a36Sopenharmony_ci	.precious_reg = rockchip_i2s_precious_reg,
64062306a36Sopenharmony_ci	.cache_type = REGCACHE_FLAT,
64162306a36Sopenharmony_ci};
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_cistatic const struct rk_i2s_pins rk3399_i2s_pins = {
64462306a36Sopenharmony_ci	.reg_offset = 0xe220,
64562306a36Sopenharmony_ci	.shift = 11,
64662306a36Sopenharmony_ci};
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_cistatic const struct of_device_id rockchip_i2s_match[] __maybe_unused = {
64962306a36Sopenharmony_ci	{ .compatible = "rockchip,px30-i2s", },
65062306a36Sopenharmony_ci	{ .compatible = "rockchip,rk1808-i2s", },
65162306a36Sopenharmony_ci	{ .compatible = "rockchip,rk3036-i2s", },
65262306a36Sopenharmony_ci	{ .compatible = "rockchip,rk3066-i2s", },
65362306a36Sopenharmony_ci	{ .compatible = "rockchip,rk3128-i2s", },
65462306a36Sopenharmony_ci	{ .compatible = "rockchip,rk3188-i2s", },
65562306a36Sopenharmony_ci	{ .compatible = "rockchip,rk3228-i2s", },
65662306a36Sopenharmony_ci	{ .compatible = "rockchip,rk3288-i2s", },
65762306a36Sopenharmony_ci	{ .compatible = "rockchip,rk3308-i2s", },
65862306a36Sopenharmony_ci	{ .compatible = "rockchip,rk3328-i2s", },
65962306a36Sopenharmony_ci	{ .compatible = "rockchip,rk3366-i2s", },
66062306a36Sopenharmony_ci	{ .compatible = "rockchip,rk3368-i2s", },
66162306a36Sopenharmony_ci	{ .compatible = "rockchip,rk3399-i2s", .data = &rk3399_i2s_pins },
66262306a36Sopenharmony_ci	{ .compatible = "rockchip,rk3588-i2s", },
66362306a36Sopenharmony_ci	{ .compatible = "rockchip,rv1126-i2s", },
66462306a36Sopenharmony_ci	{},
66562306a36Sopenharmony_ci};
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_cistatic int rockchip_i2s_init_dai(struct rk_i2s_dev *i2s, struct resource *res,
66862306a36Sopenharmony_ci				 struct snd_soc_dai_driver **dp)
66962306a36Sopenharmony_ci{
67062306a36Sopenharmony_ci	struct device_node *node = i2s->dev->of_node;
67162306a36Sopenharmony_ci	struct snd_soc_dai_driver *dai;
67262306a36Sopenharmony_ci	struct property *dma_names;
67362306a36Sopenharmony_ci	const char *dma_name;
67462306a36Sopenharmony_ci	unsigned int val;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	of_property_for_each_string(node, "dma-names", dma_names, dma_name) {
67762306a36Sopenharmony_ci		if (!strcmp(dma_name, "tx"))
67862306a36Sopenharmony_ci			i2s->has_playback = true;
67962306a36Sopenharmony_ci		if (!strcmp(dma_name, "rx"))
68062306a36Sopenharmony_ci			i2s->has_capture = true;
68162306a36Sopenharmony_ci	}
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	dai = devm_kmemdup(i2s->dev, &rockchip_i2s_dai,
68462306a36Sopenharmony_ci			   sizeof(*dai), GFP_KERNEL);
68562306a36Sopenharmony_ci	if (!dai)
68662306a36Sopenharmony_ci		return -ENOMEM;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	if (i2s->has_playback) {
68962306a36Sopenharmony_ci		dai->playback.stream_name = "Playback";
69062306a36Sopenharmony_ci		dai->playback.channels_min = 2;
69162306a36Sopenharmony_ci		dai->playback.channels_max = 8;
69262306a36Sopenharmony_ci		dai->playback.rates = SNDRV_PCM_RATE_8000_192000;
69362306a36Sopenharmony_ci		dai->playback.formats = SNDRV_PCM_FMTBIT_S8 |
69462306a36Sopenharmony_ci					SNDRV_PCM_FMTBIT_S16_LE |
69562306a36Sopenharmony_ci					SNDRV_PCM_FMTBIT_S20_3LE |
69662306a36Sopenharmony_ci					SNDRV_PCM_FMTBIT_S24_LE |
69762306a36Sopenharmony_ci					SNDRV_PCM_FMTBIT_S32_LE;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci		i2s->playback_dma_data.addr = res->start + I2S_TXDR;
70062306a36Sopenharmony_ci		i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
70162306a36Sopenharmony_ci		i2s->playback_dma_data.maxburst = 8;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci		if (!of_property_read_u32(node, "rockchip,playback-channels", &val)) {
70462306a36Sopenharmony_ci			if (val >= 2 && val <= 8)
70562306a36Sopenharmony_ci				dai->playback.channels_max = val;
70662306a36Sopenharmony_ci		}
70762306a36Sopenharmony_ci	}
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	if (i2s->has_capture) {
71062306a36Sopenharmony_ci		dai->capture.stream_name = "Capture";
71162306a36Sopenharmony_ci		dai->capture.channels_min = 2;
71262306a36Sopenharmony_ci		dai->capture.channels_max = 8;
71362306a36Sopenharmony_ci		dai->capture.rates = SNDRV_PCM_RATE_8000_192000;
71462306a36Sopenharmony_ci		dai->capture.formats = SNDRV_PCM_FMTBIT_S8 |
71562306a36Sopenharmony_ci				       SNDRV_PCM_FMTBIT_S16_LE |
71662306a36Sopenharmony_ci				       SNDRV_PCM_FMTBIT_S20_3LE |
71762306a36Sopenharmony_ci				       SNDRV_PCM_FMTBIT_S24_LE |
71862306a36Sopenharmony_ci				       SNDRV_PCM_FMTBIT_S32_LE;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci		i2s->capture_dma_data.addr = res->start + I2S_RXDR;
72162306a36Sopenharmony_ci		i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
72262306a36Sopenharmony_ci		i2s->capture_dma_data.maxburst = 8;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci		if (!of_property_read_u32(node, "rockchip,capture-channels", &val)) {
72562306a36Sopenharmony_ci			if (val >= 2 && val <= 8)
72662306a36Sopenharmony_ci				dai->capture.channels_max = val;
72762306a36Sopenharmony_ci		}
72862306a36Sopenharmony_ci	}
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	if (dp)
73162306a36Sopenharmony_ci		*dp = dai;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	return 0;
73462306a36Sopenharmony_ci}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_cistatic int rockchip_i2s_probe(struct platform_device *pdev)
73762306a36Sopenharmony_ci{
73862306a36Sopenharmony_ci	struct device_node *node = pdev->dev.of_node;
73962306a36Sopenharmony_ci	const struct of_device_id *of_id;
74062306a36Sopenharmony_ci	struct rk_i2s_dev *i2s;
74162306a36Sopenharmony_ci	struct snd_soc_dai_driver *dai;
74262306a36Sopenharmony_ci	struct resource *res;
74362306a36Sopenharmony_ci	void __iomem *regs;
74462306a36Sopenharmony_ci	int ret;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
74762306a36Sopenharmony_ci	if (!i2s)
74862306a36Sopenharmony_ci		return -ENOMEM;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	spin_lock_init(&i2s->lock);
75162306a36Sopenharmony_ci	i2s->dev = &pdev->dev;
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	i2s->grf = syscon_regmap_lookup_by_phandle(node, "rockchip,grf");
75462306a36Sopenharmony_ci	if (!IS_ERR(i2s->grf)) {
75562306a36Sopenharmony_ci		of_id = of_match_device(rockchip_i2s_match, &pdev->dev);
75662306a36Sopenharmony_ci		if (!of_id || !of_id->data)
75762306a36Sopenharmony_ci			return -EINVAL;
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci		i2s->pins = of_id->data;
76062306a36Sopenharmony_ci	}
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	/* try to prepare related clocks */
76362306a36Sopenharmony_ci	i2s->hclk = devm_clk_get(&pdev->dev, "i2s_hclk");
76462306a36Sopenharmony_ci	if (IS_ERR(i2s->hclk)) {
76562306a36Sopenharmony_ci		dev_err(&pdev->dev, "Can't retrieve i2s bus clock\n");
76662306a36Sopenharmony_ci		return PTR_ERR(i2s->hclk);
76762306a36Sopenharmony_ci	}
76862306a36Sopenharmony_ci	ret = clk_prepare_enable(i2s->hclk);
76962306a36Sopenharmony_ci	if (ret) {
77062306a36Sopenharmony_ci		dev_err(i2s->dev, "hclock enable failed %d\n", ret);
77162306a36Sopenharmony_ci		return ret;
77262306a36Sopenharmony_ci	}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	i2s->mclk = devm_clk_get(&pdev->dev, "i2s_clk");
77562306a36Sopenharmony_ci	if (IS_ERR(i2s->mclk)) {
77662306a36Sopenharmony_ci		dev_err(&pdev->dev, "Can't retrieve i2s master clock\n");
77762306a36Sopenharmony_ci		ret = PTR_ERR(i2s->mclk);
77862306a36Sopenharmony_ci		goto err_clk;
77962306a36Sopenharmony_ci	}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
78262306a36Sopenharmony_ci	if (IS_ERR(regs)) {
78362306a36Sopenharmony_ci		ret = PTR_ERR(regs);
78462306a36Sopenharmony_ci		goto err_clk;
78562306a36Sopenharmony_ci	}
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
78862306a36Sopenharmony_ci					    &rockchip_i2s_regmap_config);
78962306a36Sopenharmony_ci	if (IS_ERR(i2s->regmap)) {
79062306a36Sopenharmony_ci		dev_err(&pdev->dev,
79162306a36Sopenharmony_ci			"Failed to initialise managed register map\n");
79262306a36Sopenharmony_ci		ret = PTR_ERR(i2s->regmap);
79362306a36Sopenharmony_ci		goto err_clk;
79462306a36Sopenharmony_ci	}
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	i2s->bclk_ratio = 64;
79762306a36Sopenharmony_ci	i2s->pinctrl = devm_pinctrl_get(&pdev->dev);
79862306a36Sopenharmony_ci	if (!IS_ERR(i2s->pinctrl)) {
79962306a36Sopenharmony_ci		i2s->bclk_on = pinctrl_lookup_state(i2s->pinctrl, "bclk_on");
80062306a36Sopenharmony_ci		if (!IS_ERR_OR_NULL(i2s->bclk_on)) {
80162306a36Sopenharmony_ci			i2s->bclk_off = pinctrl_lookup_state(i2s->pinctrl, "bclk_off");
80262306a36Sopenharmony_ci			if (IS_ERR_OR_NULL(i2s->bclk_off)) {
80362306a36Sopenharmony_ci				dev_err(&pdev->dev, "failed to find i2s bclk_off\n");
80462306a36Sopenharmony_ci				ret = -EINVAL;
80562306a36Sopenharmony_ci				goto err_clk;
80662306a36Sopenharmony_ci			}
80762306a36Sopenharmony_ci		}
80862306a36Sopenharmony_ci	} else {
80962306a36Sopenharmony_ci		dev_dbg(&pdev->dev, "failed to find i2s pinctrl\n");
81062306a36Sopenharmony_ci	}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	i2s_pinctrl_select_bclk_off(i2s);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	dev_set_drvdata(&pdev->dev, i2s);
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
81762306a36Sopenharmony_ci	if (!pm_runtime_enabled(&pdev->dev)) {
81862306a36Sopenharmony_ci		ret = i2s_runtime_resume(&pdev->dev);
81962306a36Sopenharmony_ci		if (ret)
82062306a36Sopenharmony_ci			goto err_pm_disable;
82162306a36Sopenharmony_ci	}
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	ret = rockchip_i2s_init_dai(i2s, res, &dai);
82462306a36Sopenharmony_ci	if (ret)
82562306a36Sopenharmony_ci		goto err_pm_disable;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	ret = devm_snd_soc_register_component(&pdev->dev,
82862306a36Sopenharmony_ci					      &rockchip_i2s_component,
82962306a36Sopenharmony_ci					      dai, 1);
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	if (ret) {
83262306a36Sopenharmony_ci		dev_err(&pdev->dev, "Could not register DAI\n");
83362306a36Sopenharmony_ci		goto err_suspend;
83462306a36Sopenharmony_ci	}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
83762306a36Sopenharmony_ci	if (ret) {
83862306a36Sopenharmony_ci		dev_err(&pdev->dev, "Could not register PCM\n");
83962306a36Sopenharmony_ci		goto err_suspend;
84062306a36Sopenharmony_ci	}
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	return 0;
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_cierr_suspend:
84562306a36Sopenharmony_ci	if (!pm_runtime_status_suspended(&pdev->dev))
84662306a36Sopenharmony_ci		i2s_runtime_suspend(&pdev->dev);
84762306a36Sopenharmony_cierr_pm_disable:
84862306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
84962306a36Sopenharmony_cierr_clk:
85062306a36Sopenharmony_ci	clk_disable_unprepare(i2s->hclk);
85162306a36Sopenharmony_ci	return ret;
85262306a36Sopenharmony_ci}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_cistatic void rockchip_i2s_remove(struct platform_device *pdev)
85562306a36Sopenharmony_ci{
85662306a36Sopenharmony_ci	struct rk_i2s_dev *i2s = dev_get_drvdata(&pdev->dev);
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
85962306a36Sopenharmony_ci	if (!pm_runtime_status_suspended(&pdev->dev))
86062306a36Sopenharmony_ci		i2s_runtime_suspend(&pdev->dev);
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	clk_disable_unprepare(i2s->hclk);
86362306a36Sopenharmony_ci}
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_cistatic const struct dev_pm_ops rockchip_i2s_pm_ops = {
86662306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(i2s_runtime_suspend, i2s_runtime_resume,
86762306a36Sopenharmony_ci			   NULL)
86862306a36Sopenharmony_ci};
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_cistatic struct platform_driver rockchip_i2s_driver = {
87162306a36Sopenharmony_ci	.probe = rockchip_i2s_probe,
87262306a36Sopenharmony_ci	.remove_new = rockchip_i2s_remove,
87362306a36Sopenharmony_ci	.driver = {
87462306a36Sopenharmony_ci		.name = DRV_NAME,
87562306a36Sopenharmony_ci		.of_match_table = of_match_ptr(rockchip_i2s_match),
87662306a36Sopenharmony_ci		.pm = &rockchip_i2s_pm_ops,
87762306a36Sopenharmony_ci	},
87862306a36Sopenharmony_ci};
87962306a36Sopenharmony_cimodule_platform_driver(rockchip_i2s_driver);
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ciMODULE_DESCRIPTION("ROCKCHIP IIS ASoC Interface");
88262306a36Sopenharmony_ciMODULE_AUTHOR("jianqun <jay.xu@rock-chips.com>");
88362306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
88462306a36Sopenharmony_ciMODULE_ALIAS("platform:" DRV_NAME);
88562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, rockchip_i2s_match);
886