18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * linux/sound/soc/m8m/hi6210_i2s.c - I2S IP driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2015 Linaro, Ltd
68c2ecf20Sopenharmony_ci * Author: Andy Green <andy.green@linaro.org>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * This driver only deals with S2 interface (BT)
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/init.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/device.h>
148c2ecf20Sopenharmony_ci#include <linux/delay.h>
158c2ecf20Sopenharmony_ci#include <linux/clk.h>
168c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
178c2ecf20Sopenharmony_ci#include <linux/io.h>
188c2ecf20Sopenharmony_ci#include <linux/gpio.h>
198c2ecf20Sopenharmony_ci#include <sound/core.h>
208c2ecf20Sopenharmony_ci#include <sound/pcm.h>
218c2ecf20Sopenharmony_ci#include <sound/pcm_params.h>
228c2ecf20Sopenharmony_ci#include <sound/dmaengine_pcm.h>
238c2ecf20Sopenharmony_ci#include <sound/initval.h>
248c2ecf20Sopenharmony_ci#include <sound/soc.h>
258c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
268c2ecf20Sopenharmony_ci#include <linux/reset.h>
278c2ecf20Sopenharmony_ci#include <linux/of_address.h>
288c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
298c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h>
308c2ecf20Sopenharmony_ci#include <linux/reset-controller.h>
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#include "hi6210-i2s.h"
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistruct hi6210_i2s {
358c2ecf20Sopenharmony_ci	struct device *dev;
368c2ecf20Sopenharmony_ci	struct reset_control *rc;
378c2ecf20Sopenharmony_ci	struct clk *clk[8];
388c2ecf20Sopenharmony_ci	int clocks;
398c2ecf20Sopenharmony_ci	struct snd_soc_dai_driver dai;
408c2ecf20Sopenharmony_ci	void __iomem *base;
418c2ecf20Sopenharmony_ci	struct regmap *sysctrl;
428c2ecf20Sopenharmony_ci	phys_addr_t base_phys;
438c2ecf20Sopenharmony_ci	struct snd_dmaengine_dai_dma_data dma_data[2];
448c2ecf20Sopenharmony_ci	int clk_rate;
458c2ecf20Sopenharmony_ci	spinlock_t lock;
468c2ecf20Sopenharmony_ci	int rate;
478c2ecf20Sopenharmony_ci	int format;
488c2ecf20Sopenharmony_ci	u8 bits;
498c2ecf20Sopenharmony_ci	u8 channels;
508c2ecf20Sopenharmony_ci	u8 id;
518c2ecf20Sopenharmony_ci	u8 channel_length;
528c2ecf20Sopenharmony_ci	u8 use;
538c2ecf20Sopenharmony_ci	u32 master:1;
548c2ecf20Sopenharmony_ci	u32 status:1;
558c2ecf20Sopenharmony_ci};
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci#define SC_PERIPH_CLKEN1	0x210
588c2ecf20Sopenharmony_ci#define SC_PERIPH_CLKDIS1	0x214
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci#define SC_PERIPH_CLKEN3	0x230
618c2ecf20Sopenharmony_ci#define SC_PERIPH_CLKDIS3	0x234
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci#define SC_PERIPH_CLKEN12	0x270
648c2ecf20Sopenharmony_ci#define SC_PERIPH_CLKDIS12	0x274
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci#define SC_PERIPH_RSTEN1	0x310
678c2ecf20Sopenharmony_ci#define SC_PERIPH_RSTDIS1	0x314
688c2ecf20Sopenharmony_ci#define SC_PERIPH_RSTSTAT1	0x318
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci#define SC_PERIPH_RSTEN2	0x320
718c2ecf20Sopenharmony_ci#define SC_PERIPH_RSTDIS2	0x324
728c2ecf20Sopenharmony_ci#define SC_PERIPH_RSTSTAT2	0x328
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci#define SOC_PMCTRL_BBPPLLALIAS	0x48
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cienum {
778c2ecf20Sopenharmony_ci	CLK_DACODEC,
788c2ecf20Sopenharmony_ci	CLK_I2S_BASE,
798c2ecf20Sopenharmony_ci};
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic inline void hi6210_write_reg(struct hi6210_i2s *i2s, int reg, u32 val)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	writel(val, i2s->base + reg);
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic inline u32 hi6210_read_reg(struct hi6210_i2s *i2s, int reg)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	return readl(i2s->base + reg);
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistatic int hi6210_i2s_startup(struct snd_pcm_substream *substream,
928c2ecf20Sopenharmony_ci			      struct snd_soc_dai *cpu_dai)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
958c2ecf20Sopenharmony_ci	int ret, n;
968c2ecf20Sopenharmony_ci	u32 val;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	/* deassert reset on ABB */
998c2ecf20Sopenharmony_ci	regmap_read(i2s->sysctrl, SC_PERIPH_RSTSTAT2, &val);
1008c2ecf20Sopenharmony_ci	if (val & BIT(4))
1018c2ecf20Sopenharmony_ci		regmap_write(i2s->sysctrl, SC_PERIPH_RSTDIS2, BIT(4));
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	for (n = 0; n < i2s->clocks; n++) {
1048c2ecf20Sopenharmony_ci		ret = clk_prepare_enable(i2s->clk[n]);
1058c2ecf20Sopenharmony_ci		if (ret)
1068c2ecf20Sopenharmony_ci			goto err_unprepare_clk;
1078c2ecf20Sopenharmony_ci	}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	ret = clk_set_rate(i2s->clk[CLK_I2S_BASE], 49152000);
1108c2ecf20Sopenharmony_ci	if (ret) {
1118c2ecf20Sopenharmony_ci		dev_err(i2s->dev, "%s: setting 49.152MHz base rate failed %d\n",
1128c2ecf20Sopenharmony_ci			__func__, ret);
1138c2ecf20Sopenharmony_ci		goto err_unprepare_clk;
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	/* enable clock before frequency division */
1178c2ecf20Sopenharmony_ci	regmap_write(i2s->sysctrl, SC_PERIPH_CLKEN12, BIT(9));
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	/* enable codec working clock / == "codec bus clock" */
1208c2ecf20Sopenharmony_ci	regmap_write(i2s->sysctrl, SC_PERIPH_CLKEN1, BIT(5));
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	/* deassert reset on codec / interface clock / working clock */
1238c2ecf20Sopenharmony_ci	regmap_write(i2s->sysctrl, SC_PERIPH_RSTEN1, BIT(5));
1248c2ecf20Sopenharmony_ci	regmap_write(i2s->sysctrl, SC_PERIPH_RSTDIS1, BIT(5));
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	/* not interested in i2s irqs */
1278c2ecf20Sopenharmony_ci	val = hi6210_read_reg(i2s, HII2S_CODEC_IRQ_MASK);
1288c2ecf20Sopenharmony_ci	val |= 0x3f;
1298c2ecf20Sopenharmony_ci	hi6210_write_reg(i2s, HII2S_CODEC_IRQ_MASK, val);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	/* reset the stereo downlink fifo */
1338c2ecf20Sopenharmony_ci	val = hi6210_read_reg(i2s, HII2S_APB_AFIFO_CFG_1);
1348c2ecf20Sopenharmony_ci	val |= (BIT(5) | BIT(4));
1358c2ecf20Sopenharmony_ci	hi6210_write_reg(i2s, HII2S_APB_AFIFO_CFG_1, val);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	val = hi6210_read_reg(i2s, HII2S_APB_AFIFO_CFG_1);
1388c2ecf20Sopenharmony_ci	val &= ~(BIT(5) | BIT(4));
1398c2ecf20Sopenharmony_ci	hi6210_write_reg(i2s, HII2S_APB_AFIFO_CFG_1, val);
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	val = hi6210_read_reg(i2s, HII2S_SW_RST_N);
1438c2ecf20Sopenharmony_ci	val &= ~(HII2S_SW_RST_N__ST_DL_WORDLEN_MASK <<
1448c2ecf20Sopenharmony_ci			HII2S_SW_RST_N__ST_DL_WORDLEN_SHIFT);
1458c2ecf20Sopenharmony_ci	val |= (HII2S_BITS_16 << HII2S_SW_RST_N__ST_DL_WORDLEN_SHIFT);
1468c2ecf20Sopenharmony_ci	hi6210_write_reg(i2s, HII2S_SW_RST_N, val);
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	val = hi6210_read_reg(i2s, HII2S_MISC_CFG);
1498c2ecf20Sopenharmony_ci	/* mux 11/12 = APB not i2s */
1508c2ecf20Sopenharmony_ci	val &= ~HII2S_MISC_CFG__ST_DL_TEST_SEL;
1518c2ecf20Sopenharmony_ci	/* BT R ch  0 = mixer op of DACR ch */
1528c2ecf20Sopenharmony_ci	val &= ~HII2S_MISC_CFG__S2_DOUT_RIGHT_SEL;
1538c2ecf20Sopenharmony_ci	val &= ~HII2S_MISC_CFG__S2_DOUT_TEST_SEL;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	val |= HII2S_MISC_CFG__S2_DOUT_RIGHT_SEL;
1568c2ecf20Sopenharmony_ci	/* BT L ch = 1 = mux 7 = "mixer output of DACL */
1578c2ecf20Sopenharmony_ci	val |= HII2S_MISC_CFG__S2_DOUT_TEST_SEL;
1588c2ecf20Sopenharmony_ci	hi6210_write_reg(i2s, HII2S_MISC_CFG, val);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	val = hi6210_read_reg(i2s, HII2S_SW_RST_N);
1618c2ecf20Sopenharmony_ci	val |= HII2S_SW_RST_N__SW_RST_N;
1628c2ecf20Sopenharmony_ci	hi6210_write_reg(i2s, HII2S_SW_RST_N, val);
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	return 0;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cierr_unprepare_clk:
1678c2ecf20Sopenharmony_ci	while (n--)
1688c2ecf20Sopenharmony_ci		clk_disable_unprepare(i2s->clk[n]);
1698c2ecf20Sopenharmony_ci	return ret;
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_cistatic void hi6210_i2s_shutdown(struct snd_pcm_substream *substream,
1738c2ecf20Sopenharmony_ci				struct snd_soc_dai *cpu_dai)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
1768c2ecf20Sopenharmony_ci	int n;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	for (n = 0; n < i2s->clocks; n++)
1798c2ecf20Sopenharmony_ci		clk_disable_unprepare(i2s->clk[n]);
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	regmap_write(i2s->sysctrl, SC_PERIPH_RSTEN1, BIT(5));
1828c2ecf20Sopenharmony_ci}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistatic void hi6210_i2s_txctrl(struct snd_soc_dai *cpu_dai, int on)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
1878c2ecf20Sopenharmony_ci	u32 val;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	spin_lock(&i2s->lock);
1908c2ecf20Sopenharmony_ci	if (on) {
1918c2ecf20Sopenharmony_ci		/* enable S2 TX */
1928c2ecf20Sopenharmony_ci		val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
1938c2ecf20Sopenharmony_ci		val |= HII2S_I2S_CFG__S2_IF_TX_EN;
1948c2ecf20Sopenharmony_ci		hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
1958c2ecf20Sopenharmony_ci	} else {
1968c2ecf20Sopenharmony_ci		/* disable S2 TX */
1978c2ecf20Sopenharmony_ci		val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
1988c2ecf20Sopenharmony_ci		val &= ~HII2S_I2S_CFG__S2_IF_TX_EN;
1998c2ecf20Sopenharmony_ci		hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
2008c2ecf20Sopenharmony_ci	}
2018c2ecf20Sopenharmony_ci	spin_unlock(&i2s->lock);
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic void hi6210_i2s_rxctrl(struct snd_soc_dai *cpu_dai, int on)
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
2078c2ecf20Sopenharmony_ci	u32 val;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	spin_lock(&i2s->lock);
2108c2ecf20Sopenharmony_ci	if (on) {
2118c2ecf20Sopenharmony_ci		val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
2128c2ecf20Sopenharmony_ci		val |= HII2S_I2S_CFG__S2_IF_RX_EN;
2138c2ecf20Sopenharmony_ci		hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
2148c2ecf20Sopenharmony_ci	} else {
2158c2ecf20Sopenharmony_ci		val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
2168c2ecf20Sopenharmony_ci		val &= ~HII2S_I2S_CFG__S2_IF_RX_EN;
2178c2ecf20Sopenharmony_ci		hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
2188c2ecf20Sopenharmony_ci	}
2198c2ecf20Sopenharmony_ci	spin_unlock(&i2s->lock);
2208c2ecf20Sopenharmony_ci}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_cistatic int hi6210_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
2238c2ecf20Sopenharmony_ci{
2248c2ecf20Sopenharmony_ci	struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	/*
2278c2ecf20Sopenharmony_ci	 * We don't actually set the hardware until the hw_params
2288c2ecf20Sopenharmony_ci	 * call, but we need to validate the user input here.
2298c2ecf20Sopenharmony_ci	 */
2308c2ecf20Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
2318c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_CBM_CFM:
2328c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_CBS_CFS:
2338c2ecf20Sopenharmony_ci		break;
2348c2ecf20Sopenharmony_ci	default:
2358c2ecf20Sopenharmony_ci		return -EINVAL;
2368c2ecf20Sopenharmony_ci	}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
2398c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_I2S:
2408c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_LEFT_J:
2418c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_RIGHT_J:
2428c2ecf20Sopenharmony_ci		break;
2438c2ecf20Sopenharmony_ci	default:
2448c2ecf20Sopenharmony_ci		return -EINVAL;
2458c2ecf20Sopenharmony_ci	}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	i2s->format = fmt;
2488c2ecf20Sopenharmony_ci	i2s->master = (i2s->format & SND_SOC_DAIFMT_MASTER_MASK) ==
2498c2ecf20Sopenharmony_ci		      SND_SOC_DAIFMT_CBS_CFS;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	return 0;
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cistatic int hi6210_i2s_hw_params(struct snd_pcm_substream *substream,
2558c2ecf20Sopenharmony_ci			    struct snd_pcm_hw_params *params,
2568c2ecf20Sopenharmony_ci			    struct snd_soc_dai *cpu_dai)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
2598c2ecf20Sopenharmony_ci	u32 bits = 0, rate = 0, signed_data = 0, fmt = 0;
2608c2ecf20Sopenharmony_ci	u32 val;
2618c2ecf20Sopenharmony_ci	struct snd_dmaengine_dai_dma_data *dma_data;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	switch (params_format(params)) {
2648c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_U16_LE:
2658c2ecf20Sopenharmony_ci		signed_data = HII2S_I2S_CFG__S2_CODEC_DATA_FORMAT;
2668c2ecf20Sopenharmony_ci		fallthrough;
2678c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_S16_LE:
2688c2ecf20Sopenharmony_ci		bits = HII2S_BITS_16;
2698c2ecf20Sopenharmony_ci		break;
2708c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_U24_LE:
2718c2ecf20Sopenharmony_ci		signed_data = HII2S_I2S_CFG__S2_CODEC_DATA_FORMAT;
2728c2ecf20Sopenharmony_ci		fallthrough;
2738c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_S24_LE:
2748c2ecf20Sopenharmony_ci		bits = HII2S_BITS_24;
2758c2ecf20Sopenharmony_ci		break;
2768c2ecf20Sopenharmony_ci	default:
2778c2ecf20Sopenharmony_ci		dev_err(cpu_dai->dev, "Bad format\n");
2788c2ecf20Sopenharmony_ci		return -EINVAL;
2798c2ecf20Sopenharmony_ci	}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	switch (params_rate(params)) {
2838c2ecf20Sopenharmony_ci	case 8000:
2848c2ecf20Sopenharmony_ci		rate = HII2S_FS_RATE_8KHZ;
2858c2ecf20Sopenharmony_ci		break;
2868c2ecf20Sopenharmony_ci	case 16000:
2878c2ecf20Sopenharmony_ci		rate = HII2S_FS_RATE_16KHZ;
2888c2ecf20Sopenharmony_ci		break;
2898c2ecf20Sopenharmony_ci	case 32000:
2908c2ecf20Sopenharmony_ci		rate = HII2S_FS_RATE_32KHZ;
2918c2ecf20Sopenharmony_ci		break;
2928c2ecf20Sopenharmony_ci	case 48000:
2938c2ecf20Sopenharmony_ci		rate = HII2S_FS_RATE_48KHZ;
2948c2ecf20Sopenharmony_ci		break;
2958c2ecf20Sopenharmony_ci	case 96000:
2968c2ecf20Sopenharmony_ci		rate = HII2S_FS_RATE_96KHZ;
2978c2ecf20Sopenharmony_ci		break;
2988c2ecf20Sopenharmony_ci	case 192000:
2998c2ecf20Sopenharmony_ci		rate = HII2S_FS_RATE_192KHZ;
3008c2ecf20Sopenharmony_ci		break;
3018c2ecf20Sopenharmony_ci	default:
3028c2ecf20Sopenharmony_ci		dev_err(cpu_dai->dev, "Bad rate: %d\n", params_rate(params));
3038c2ecf20Sopenharmony_ci		return -EINVAL;
3048c2ecf20Sopenharmony_ci	}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	if (!(params_channels(params))) {
3078c2ecf20Sopenharmony_ci		dev_err(cpu_dai->dev, "Bad channels\n");
3088c2ecf20Sopenharmony_ci		return -EINVAL;
3098c2ecf20Sopenharmony_ci	}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	switch (bits) {
3148c2ecf20Sopenharmony_ci	case HII2S_BITS_24:
3158c2ecf20Sopenharmony_ci		i2s->bits = 32;
3168c2ecf20Sopenharmony_ci		dma_data->addr_width = 3;
3178c2ecf20Sopenharmony_ci		break;
3188c2ecf20Sopenharmony_ci	default:
3198c2ecf20Sopenharmony_ci		i2s->bits = 16;
3208c2ecf20Sopenharmony_ci		dma_data->addr_width = 2;
3218c2ecf20Sopenharmony_ci		break;
3228c2ecf20Sopenharmony_ci	}
3238c2ecf20Sopenharmony_ci	i2s->rate = params_rate(params);
3248c2ecf20Sopenharmony_ci	i2s->channels = params_channels(params);
3258c2ecf20Sopenharmony_ci	i2s->channel_length = i2s->channels * i2s->bits;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	val = hi6210_read_reg(i2s, HII2S_ST_DL_FIFO_TH_CFG);
3288c2ecf20Sopenharmony_ci	val &= ~((HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AEMPTY_MASK <<
3298c2ecf20Sopenharmony_ci			HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AEMPTY_SHIFT) |
3308c2ecf20Sopenharmony_ci		(HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AFULL_MASK <<
3318c2ecf20Sopenharmony_ci			HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AFULL_SHIFT) |
3328c2ecf20Sopenharmony_ci		(HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AEMPTY_MASK <<
3338c2ecf20Sopenharmony_ci			HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AEMPTY_SHIFT) |
3348c2ecf20Sopenharmony_ci		(HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AFULL_MASK <<
3358c2ecf20Sopenharmony_ci			HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AFULL_SHIFT));
3368c2ecf20Sopenharmony_ci	val |= ((16 << HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AEMPTY_SHIFT) |
3378c2ecf20Sopenharmony_ci		(30 << HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AFULL_SHIFT) |
3388c2ecf20Sopenharmony_ci		(16 << HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AEMPTY_SHIFT) |
3398c2ecf20Sopenharmony_ci		(30 << HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AFULL_SHIFT));
3408c2ecf20Sopenharmony_ci	hi6210_write_reg(i2s, HII2S_ST_DL_FIFO_TH_CFG, val);
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	val = hi6210_read_reg(i2s, HII2S_IF_CLK_EN_CFG);
3448c2ecf20Sopenharmony_ci	val |= (BIT(19) | BIT(18) | BIT(17) |
3458c2ecf20Sopenharmony_ci		HII2S_IF_CLK_EN_CFG__S2_IF_CLK_EN |
3468c2ecf20Sopenharmony_ci		HII2S_IF_CLK_EN_CFG__S2_OL_MIXER_EN |
3478c2ecf20Sopenharmony_ci		HII2S_IF_CLK_EN_CFG__S2_OL_SRC_EN |
3488c2ecf20Sopenharmony_ci		HII2S_IF_CLK_EN_CFG__ST_DL_R_EN |
3498c2ecf20Sopenharmony_ci		HII2S_IF_CLK_EN_CFG__ST_DL_L_EN);
3508c2ecf20Sopenharmony_ci	hi6210_write_reg(i2s, HII2S_IF_CLK_EN_CFG, val);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	val = hi6210_read_reg(i2s, HII2S_DIG_FILTER_CLK_EN_CFG);
3548c2ecf20Sopenharmony_ci	val &= ~(HII2S_DIG_FILTER_CLK_EN_CFG__DACR_SDM_EN |
3558c2ecf20Sopenharmony_ci		 HII2S_DIG_FILTER_CLK_EN_CFG__DACR_HBF2I_EN |
3568c2ecf20Sopenharmony_ci		 HII2S_DIG_FILTER_CLK_EN_CFG__DACR_AGC_EN |
3578c2ecf20Sopenharmony_ci		 HII2S_DIG_FILTER_CLK_EN_CFG__DACL_SDM_EN |
3588c2ecf20Sopenharmony_ci		 HII2S_DIG_FILTER_CLK_EN_CFG__DACL_HBF2I_EN |
3598c2ecf20Sopenharmony_ci		 HII2S_DIG_FILTER_CLK_EN_CFG__DACL_AGC_EN);
3608c2ecf20Sopenharmony_ci	val |= (HII2S_DIG_FILTER_CLK_EN_CFG__DACR_MIXER_EN |
3618c2ecf20Sopenharmony_ci		HII2S_DIG_FILTER_CLK_EN_CFG__DACL_MIXER_EN);
3628c2ecf20Sopenharmony_ci	hi6210_write_reg(i2s, HII2S_DIG_FILTER_CLK_EN_CFG, val);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	val = hi6210_read_reg(i2s, HII2S_DIG_FILTER_MODULE_CFG);
3668c2ecf20Sopenharmony_ci	val &= ~(HII2S_DIG_FILTER_MODULE_CFG__DACR_MIXER_IN2_MUTE |
3678c2ecf20Sopenharmony_ci		 HII2S_DIG_FILTER_MODULE_CFG__DACL_MIXER_IN2_MUTE);
3688c2ecf20Sopenharmony_ci	hi6210_write_reg(i2s, HII2S_DIG_FILTER_MODULE_CFG, val);
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	val = hi6210_read_reg(i2s, HII2S_MUX_TOP_MODULE_CFG);
3718c2ecf20Sopenharmony_ci	val &= ~(HII2S_MUX_TOP_MODULE_CFG__S2_OL_MIXER_IN1_MUTE |
3728c2ecf20Sopenharmony_ci		 HII2S_MUX_TOP_MODULE_CFG__S2_OL_MIXER_IN2_MUTE |
3738c2ecf20Sopenharmony_ci		 HII2S_MUX_TOP_MODULE_CFG__VOICE_DLINK_MIXER_IN1_MUTE |
3748c2ecf20Sopenharmony_ci		 HII2S_MUX_TOP_MODULE_CFG__VOICE_DLINK_MIXER_IN2_MUTE);
3758c2ecf20Sopenharmony_ci	hi6210_write_reg(i2s, HII2S_MUX_TOP_MODULE_CFG, val);
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	switch (i2s->format & SND_SOC_DAIFMT_MASTER_MASK) {
3798c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_CBM_CFM:
3808c2ecf20Sopenharmony_ci		i2s->master = false;
3818c2ecf20Sopenharmony_ci		val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
3828c2ecf20Sopenharmony_ci		val |= HII2S_I2S_CFG__S2_MST_SLV;
3838c2ecf20Sopenharmony_ci		hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
3848c2ecf20Sopenharmony_ci		break;
3858c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_CBS_CFS:
3868c2ecf20Sopenharmony_ci		i2s->master = true;
3878c2ecf20Sopenharmony_ci		val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
3888c2ecf20Sopenharmony_ci		val &= ~HII2S_I2S_CFG__S2_MST_SLV;
3898c2ecf20Sopenharmony_ci		hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
3908c2ecf20Sopenharmony_ci		break;
3918c2ecf20Sopenharmony_ci	default:
3928c2ecf20Sopenharmony_ci		WARN_ONCE(1, "Invalid i2s->fmt MASTER_MASK. This shouldn't happen\n");
3938c2ecf20Sopenharmony_ci		return -EINVAL;
3948c2ecf20Sopenharmony_ci	}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) {
3978c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_I2S:
3988c2ecf20Sopenharmony_ci		fmt = HII2S_FORMAT_I2S;
3998c2ecf20Sopenharmony_ci		break;
4008c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_LEFT_J:
4018c2ecf20Sopenharmony_ci		fmt = HII2S_FORMAT_LEFT_JUST;
4028c2ecf20Sopenharmony_ci		break;
4038c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_RIGHT_J:
4048c2ecf20Sopenharmony_ci		fmt = HII2S_FORMAT_RIGHT_JUST;
4058c2ecf20Sopenharmony_ci		break;
4068c2ecf20Sopenharmony_ci	default:
4078c2ecf20Sopenharmony_ci		WARN_ONCE(1, "Invalid i2s->fmt FORMAT_MASK. This shouldn't happen\n");
4088c2ecf20Sopenharmony_ci		return -EINVAL;
4098c2ecf20Sopenharmony_ci	}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
4128c2ecf20Sopenharmony_ci	val &= ~(HII2S_I2S_CFG__S2_FUNC_MODE_MASK <<
4138c2ecf20Sopenharmony_ci			HII2S_I2S_CFG__S2_FUNC_MODE_SHIFT);
4148c2ecf20Sopenharmony_ci	val |= fmt << HII2S_I2S_CFG__S2_FUNC_MODE_SHIFT;
4158c2ecf20Sopenharmony_ci	hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	val = hi6210_read_reg(i2s, HII2S_CLK_SEL);
4198c2ecf20Sopenharmony_ci	val &= ~(HII2S_CLK_SEL__I2S_BT_FM_SEL | /* BT gets the I2S */
4208c2ecf20Sopenharmony_ci			HII2S_CLK_SEL__EXT_12_288MHZ_SEL);
4218c2ecf20Sopenharmony_ci	hi6210_write_reg(i2s, HII2S_CLK_SEL, val);
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	dma_data->maxburst = 2;
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
4268c2ecf20Sopenharmony_ci		dma_data->addr = i2s->base_phys + HII2S_ST_DL_CHANNEL;
4278c2ecf20Sopenharmony_ci	else
4288c2ecf20Sopenharmony_ci		dma_data->addr = i2s->base_phys + HII2S_STEREO_UPLINK_CHANNEL;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	switch (i2s->channels) {
4318c2ecf20Sopenharmony_ci	case 1:
4328c2ecf20Sopenharmony_ci		val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
4338c2ecf20Sopenharmony_ci		val |= HII2S_I2S_CFG__S2_FRAME_MODE;
4348c2ecf20Sopenharmony_ci		hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
4358c2ecf20Sopenharmony_ci		break;
4368c2ecf20Sopenharmony_ci	default:
4378c2ecf20Sopenharmony_ci		val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
4388c2ecf20Sopenharmony_ci		val &= ~HII2S_I2S_CFG__S2_FRAME_MODE;
4398c2ecf20Sopenharmony_ci		hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
4408c2ecf20Sopenharmony_ci		break;
4418c2ecf20Sopenharmony_ci	}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	/* clear loopback, set signed type and word length */
4448c2ecf20Sopenharmony_ci	val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
4458c2ecf20Sopenharmony_ci	val &= ~HII2S_I2S_CFG__S2_CODEC_DATA_FORMAT;
4468c2ecf20Sopenharmony_ci	val &= ~(HII2S_I2S_CFG__S2_CODEC_IO_WORDLENGTH_MASK <<
4478c2ecf20Sopenharmony_ci			HII2S_I2S_CFG__S2_CODEC_IO_WORDLENGTH_SHIFT);
4488c2ecf20Sopenharmony_ci	val &= ~(HII2S_I2S_CFG__S2_DIRECT_LOOP_MASK <<
4498c2ecf20Sopenharmony_ci			HII2S_I2S_CFG__S2_DIRECT_LOOP_SHIFT);
4508c2ecf20Sopenharmony_ci	val |= signed_data;
4518c2ecf20Sopenharmony_ci	val |= (bits << HII2S_I2S_CFG__S2_CODEC_IO_WORDLENGTH_SHIFT);
4528c2ecf20Sopenharmony_ci	hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	if (!i2s->master)
4568c2ecf20Sopenharmony_ci		return 0;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	/* set DAC and related units to correct rate */
4598c2ecf20Sopenharmony_ci	val = hi6210_read_reg(i2s, HII2S_FS_CFG);
4608c2ecf20Sopenharmony_ci	val &= ~(HII2S_FS_CFG__FS_S2_MASK << HII2S_FS_CFG__FS_S2_SHIFT);
4618c2ecf20Sopenharmony_ci	val &= ~(HII2S_FS_CFG__FS_DACLR_MASK << HII2S_FS_CFG__FS_DACLR_SHIFT);
4628c2ecf20Sopenharmony_ci	val &= ~(HII2S_FS_CFG__FS_ST_DL_R_MASK <<
4638c2ecf20Sopenharmony_ci					HII2S_FS_CFG__FS_ST_DL_R_SHIFT);
4648c2ecf20Sopenharmony_ci	val &= ~(HII2S_FS_CFG__FS_ST_DL_L_MASK <<
4658c2ecf20Sopenharmony_ci					HII2S_FS_CFG__FS_ST_DL_L_SHIFT);
4668c2ecf20Sopenharmony_ci	val |= (rate << HII2S_FS_CFG__FS_S2_SHIFT);
4678c2ecf20Sopenharmony_ci	val |= (rate << HII2S_FS_CFG__FS_DACLR_SHIFT);
4688c2ecf20Sopenharmony_ci	val |= (rate << HII2S_FS_CFG__FS_ST_DL_R_SHIFT);
4698c2ecf20Sopenharmony_ci	val |= (rate << HII2S_FS_CFG__FS_ST_DL_L_SHIFT);
4708c2ecf20Sopenharmony_ci	hi6210_write_reg(i2s, HII2S_FS_CFG, val);
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	return 0;
4738c2ecf20Sopenharmony_ci}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_cistatic int hi6210_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
4768c2ecf20Sopenharmony_ci			  struct snd_soc_dai *cpu_dai)
4778c2ecf20Sopenharmony_ci{
4788c2ecf20Sopenharmony_ci	pr_debug("%s\n", __func__);
4798c2ecf20Sopenharmony_ci	switch (cmd) {
4808c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
4818c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
4828c2ecf20Sopenharmony_ci		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
4838c2ecf20Sopenharmony_ci			hi6210_i2s_rxctrl(cpu_dai, 1);
4848c2ecf20Sopenharmony_ci		else
4858c2ecf20Sopenharmony_ci			hi6210_i2s_txctrl(cpu_dai, 1);
4868c2ecf20Sopenharmony_ci		break;
4878c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
4888c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
4898c2ecf20Sopenharmony_ci		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
4908c2ecf20Sopenharmony_ci			hi6210_i2s_rxctrl(cpu_dai, 0);
4918c2ecf20Sopenharmony_ci		else
4928c2ecf20Sopenharmony_ci			hi6210_i2s_txctrl(cpu_dai, 0);
4938c2ecf20Sopenharmony_ci		break;
4948c2ecf20Sopenharmony_ci	default:
4958c2ecf20Sopenharmony_ci		dev_err(cpu_dai->dev, "unknown cmd\n");
4968c2ecf20Sopenharmony_ci		return -EINVAL;
4978c2ecf20Sopenharmony_ci	}
4988c2ecf20Sopenharmony_ci	return 0;
4998c2ecf20Sopenharmony_ci}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_cistatic int hi6210_i2s_dai_probe(struct snd_soc_dai *dai)
5028c2ecf20Sopenharmony_ci{
5038c2ecf20Sopenharmony_ci	struct hi6210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	snd_soc_dai_init_dma_data(dai,
5068c2ecf20Sopenharmony_ci				  &i2s->dma_data[SNDRV_PCM_STREAM_PLAYBACK],
5078c2ecf20Sopenharmony_ci				  &i2s->dma_data[SNDRV_PCM_STREAM_CAPTURE]);
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	return 0;
5108c2ecf20Sopenharmony_ci}
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops hi6210_i2s_dai_ops = {
5148c2ecf20Sopenharmony_ci	.trigger	= hi6210_i2s_trigger,
5158c2ecf20Sopenharmony_ci	.hw_params	= hi6210_i2s_hw_params,
5168c2ecf20Sopenharmony_ci	.set_fmt	= hi6210_i2s_set_fmt,
5178c2ecf20Sopenharmony_ci	.startup	= hi6210_i2s_startup,
5188c2ecf20Sopenharmony_ci	.shutdown	= hi6210_i2s_shutdown,
5198c2ecf20Sopenharmony_ci};
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_driver hi6210_i2s_dai_init = {
5228c2ecf20Sopenharmony_ci	.probe		= hi6210_i2s_dai_probe,
5238c2ecf20Sopenharmony_ci	.playback = {
5248c2ecf20Sopenharmony_ci		.channels_min = 2,
5258c2ecf20Sopenharmony_ci		.channels_max = 2,
5268c2ecf20Sopenharmony_ci		.formats = SNDRV_PCM_FMTBIT_S16_LE |
5278c2ecf20Sopenharmony_ci			   SNDRV_PCM_FMTBIT_U16_LE,
5288c2ecf20Sopenharmony_ci		.rates = SNDRV_PCM_RATE_48000,
5298c2ecf20Sopenharmony_ci	},
5308c2ecf20Sopenharmony_ci	.capture = {
5318c2ecf20Sopenharmony_ci		.channels_min = 2,
5328c2ecf20Sopenharmony_ci		.channels_max = 2,
5338c2ecf20Sopenharmony_ci		.formats = SNDRV_PCM_FMTBIT_S16_LE |
5348c2ecf20Sopenharmony_ci			   SNDRV_PCM_FMTBIT_U16_LE,
5358c2ecf20Sopenharmony_ci		.rates = SNDRV_PCM_RATE_48000,
5368c2ecf20Sopenharmony_ci	},
5378c2ecf20Sopenharmony_ci	.ops = &hi6210_i2s_dai_ops,
5388c2ecf20Sopenharmony_ci};
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver hi6210_i2s_i2s_comp = {
5418c2ecf20Sopenharmony_ci	.name = "hi6210_i2s-i2s",
5428c2ecf20Sopenharmony_ci};
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_cistatic int hi6210_i2s_probe(struct platform_device *pdev)
5458c2ecf20Sopenharmony_ci{
5468c2ecf20Sopenharmony_ci	struct device_node *node = pdev->dev.of_node;
5478c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
5488c2ecf20Sopenharmony_ci	struct hi6210_i2s *i2s;
5498c2ecf20Sopenharmony_ci	struct resource *res;
5508c2ecf20Sopenharmony_ci	int ret;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);
5538c2ecf20Sopenharmony_ci	if (!i2s)
5548c2ecf20Sopenharmony_ci		return -ENOMEM;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	i2s->dev = dev;
5578c2ecf20Sopenharmony_ci	spin_lock_init(&i2s->lock);
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
5608c2ecf20Sopenharmony_ci	i2s->base = devm_ioremap_resource(dev, res);
5618c2ecf20Sopenharmony_ci	if (IS_ERR(i2s->base))
5628c2ecf20Sopenharmony_ci		return PTR_ERR(i2s->base);
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	i2s->base_phys = (phys_addr_t)res->start;
5658c2ecf20Sopenharmony_ci	i2s->dai = hi6210_i2s_dai_init;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	dev_set_drvdata(dev, i2s);
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	i2s->sysctrl = syscon_regmap_lookup_by_phandle(node,
5708c2ecf20Sopenharmony_ci						"hisilicon,sysctrl-syscon");
5718c2ecf20Sopenharmony_ci	if (IS_ERR(i2s->sysctrl))
5728c2ecf20Sopenharmony_ci		return PTR_ERR(i2s->sysctrl);
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	i2s->clk[CLK_DACODEC] = devm_clk_get(dev, "dacodec");
5758c2ecf20Sopenharmony_ci	if (IS_ERR(i2s->clk[CLK_DACODEC]))
5768c2ecf20Sopenharmony_ci		return PTR_ERR(i2s->clk[CLK_DACODEC]);
5778c2ecf20Sopenharmony_ci	i2s->clocks++;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	i2s->clk[CLK_I2S_BASE] = devm_clk_get(dev, "i2s-base");
5808c2ecf20Sopenharmony_ci	if (IS_ERR(i2s->clk[CLK_I2S_BASE]))
5818c2ecf20Sopenharmony_ci		return PTR_ERR(i2s->clk[CLK_I2S_BASE]);
5828c2ecf20Sopenharmony_ci	i2s->clocks++;
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0);
5858c2ecf20Sopenharmony_ci	if (ret)
5868c2ecf20Sopenharmony_ci		return ret;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	ret = devm_snd_soc_register_component(dev, &hi6210_i2s_i2s_comp,
5898c2ecf20Sopenharmony_ci					 &i2s->dai, 1);
5908c2ecf20Sopenharmony_ci	return ret;
5918c2ecf20Sopenharmony_ci}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_cistatic const struct of_device_id hi6210_i2s_dt_ids[] = {
5948c2ecf20Sopenharmony_ci	{ .compatible = "hisilicon,hi6210-i2s" },
5958c2ecf20Sopenharmony_ci	{ /* sentinel */ }
5968c2ecf20Sopenharmony_ci};
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, hi6210_i2s_dt_ids);
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_cistatic struct platform_driver hi6210_i2s_driver = {
6018c2ecf20Sopenharmony_ci	.probe = hi6210_i2s_probe,
6028c2ecf20Sopenharmony_ci	.driver = {
6038c2ecf20Sopenharmony_ci		.name = "hi6210_i2s",
6048c2ecf20Sopenharmony_ci		.of_match_table = hi6210_i2s_dt_ids,
6058c2ecf20Sopenharmony_ci	},
6068c2ecf20Sopenharmony_ci};
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_cimodule_platform_driver(hi6210_i2s_driver);
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Hisilicon HI6210 I2S driver");
6118c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andy Green <andy.green@linaro.org>");
6128c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
613