xref: /linux/sound/soc/hisilicon/hi6210-i2s.c (revision 06d07429858317ded2db7986113a9e0129cd599b)
18e8e69d6SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
20bf750f4SAndy Green /*
30bf750f4SAndy Green  * linux/sound/soc/m8m/hi6210_i2s.c - I2S IP driver
40bf750f4SAndy Green  *
50bf750f4SAndy Green  * Copyright (C) 2015 Linaro, Ltd
60bf750f4SAndy Green  * Author: Andy Green <andy.green@linaro.org>
70bf750f4SAndy Green  *
80bf750f4SAndy Green  * This driver only deals with S2 interface (BT)
90bf750f4SAndy Green  */
100bf750f4SAndy Green 
110bf750f4SAndy Green #include <linux/init.h>
120bf750f4SAndy Green #include <linux/module.h>
130bf750f4SAndy Green #include <linux/device.h>
140bf750f4SAndy Green #include <linux/delay.h>
150bf750f4SAndy Green #include <linux/clk.h>
160bf750f4SAndy Green #include <linux/jiffies.h>
170bf750f4SAndy Green #include <linux/io.h>
180bf750f4SAndy Green #include <sound/core.h>
190bf750f4SAndy Green #include <sound/pcm.h>
200bf750f4SAndy Green #include <sound/pcm_params.h>
210bf750f4SAndy Green #include <sound/dmaengine_pcm.h>
220bf750f4SAndy Green #include <sound/initval.h>
230bf750f4SAndy Green #include <sound/soc.h>
240bf750f4SAndy Green #include <linux/interrupt.h>
250bf750f4SAndy Green #include <linux/reset.h>
260bf750f4SAndy Green #include <linux/of_address.h>
270bf750f4SAndy Green #include <linux/of_irq.h>
280bf750f4SAndy Green #include <linux/mfd/syscon.h>
290bf750f4SAndy Green #include <linux/reset-controller.h>
300bf750f4SAndy Green 
310bf750f4SAndy Green #include "hi6210-i2s.h"
320bf750f4SAndy Green 
330bf750f4SAndy Green struct hi6210_i2s {
340bf750f4SAndy Green 	struct device *dev;
350bf750f4SAndy Green 	struct reset_control *rc;
360bf750f4SAndy Green 	struct clk *clk[8];
370bf750f4SAndy Green 	int clocks;
380bf750f4SAndy Green 	struct snd_soc_dai_driver dai;
390bf750f4SAndy Green 	void __iomem *base;
400bf750f4SAndy Green 	struct regmap *sysctrl;
410bf750f4SAndy Green 	phys_addr_t base_phys;
420bf750f4SAndy Green 	struct snd_dmaengine_dai_dma_data dma_data[2];
430bf750f4SAndy Green 	int clk_rate;
440bf750f4SAndy Green 	spinlock_t lock;
450bf750f4SAndy Green 	int rate;
460bf750f4SAndy Green 	int format;
470bf750f4SAndy Green 	u8 bits;
480bf750f4SAndy Green 	u8 channels;
490bf750f4SAndy Green 	u8 id;
500bf750f4SAndy Green 	u8 channel_length;
510bf750f4SAndy Green 	u8 use;
520bf750f4SAndy Green 	u32 master:1;
530bf750f4SAndy Green 	u32 status:1;
540bf750f4SAndy Green };
550bf750f4SAndy Green 
560bf750f4SAndy Green #define SC_PERIPH_CLKEN1	0x210
570bf750f4SAndy Green #define SC_PERIPH_CLKDIS1	0x214
580bf750f4SAndy Green 
590bf750f4SAndy Green #define SC_PERIPH_CLKEN3	0x230
600bf750f4SAndy Green #define SC_PERIPH_CLKDIS3	0x234
610bf750f4SAndy Green 
620bf750f4SAndy Green #define SC_PERIPH_CLKEN12	0x270
630bf750f4SAndy Green #define SC_PERIPH_CLKDIS12	0x274
640bf750f4SAndy Green 
650bf750f4SAndy Green #define SC_PERIPH_RSTEN1	0x310
660bf750f4SAndy Green #define SC_PERIPH_RSTDIS1	0x314
670bf750f4SAndy Green #define SC_PERIPH_RSTSTAT1	0x318
680bf750f4SAndy Green 
690bf750f4SAndy Green #define SC_PERIPH_RSTEN2	0x320
700bf750f4SAndy Green #define SC_PERIPH_RSTDIS2	0x324
710bf750f4SAndy Green #define SC_PERIPH_RSTSTAT2	0x328
720bf750f4SAndy Green 
730bf750f4SAndy Green #define SOC_PMCTRL_BBPPLLALIAS	0x48
740bf750f4SAndy Green 
750bf750f4SAndy Green enum {
760bf750f4SAndy Green 	CLK_DACODEC,
770bf750f4SAndy Green 	CLK_I2S_BASE,
780bf750f4SAndy Green };
790bf750f4SAndy Green 
hi6210_write_reg(struct hi6210_i2s * i2s,int reg,u32 val)800bf750f4SAndy Green static inline void hi6210_write_reg(struct hi6210_i2s *i2s, int reg, u32 val)
810bf750f4SAndy Green {
820bf750f4SAndy Green 	writel(val, i2s->base + reg);
830bf750f4SAndy Green }
840bf750f4SAndy Green 
hi6210_read_reg(struct hi6210_i2s * i2s,int reg)850bf750f4SAndy Green static inline u32 hi6210_read_reg(struct hi6210_i2s *i2s, int reg)
860bf750f4SAndy Green {
870bf750f4SAndy Green 	return readl(i2s->base + reg);
880bf750f4SAndy Green }
890bf750f4SAndy Green 
hi6210_i2s_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * cpu_dai)902a54e845STakashi Sakamoto static int hi6210_i2s_startup(struct snd_pcm_substream *substream,
910bf750f4SAndy Green 			      struct snd_soc_dai *cpu_dai)
920bf750f4SAndy Green {
930bf750f4SAndy Green 	struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
940bf750f4SAndy Green 	int ret, n;
950bf750f4SAndy Green 	u32 val;
960bf750f4SAndy Green 
970bf750f4SAndy Green 	/* deassert reset on ABB */
980bf750f4SAndy Green 	regmap_read(i2s->sysctrl, SC_PERIPH_RSTSTAT2, &val);
990bf750f4SAndy Green 	if (val & BIT(4))
1000bf750f4SAndy Green 		regmap_write(i2s->sysctrl, SC_PERIPH_RSTDIS2, BIT(4));
1010bf750f4SAndy Green 
1020bf750f4SAndy Green 	for (n = 0; n < i2s->clocks; n++) {
1030bf750f4SAndy Green 		ret = clk_prepare_enable(i2s->clk[n]);
104375904e3SYang Yingliang 		if (ret)
105375904e3SYang Yingliang 			goto err_unprepare_clk;
1060bf750f4SAndy Green 	}
1070bf750f4SAndy Green 
1080bf750f4SAndy Green 	ret = clk_set_rate(i2s->clk[CLK_I2S_BASE], 49152000);
1090bf750f4SAndy Green 	if (ret) {
1100bf750f4SAndy Green 		dev_err(i2s->dev, "%s: setting 49.152MHz base rate failed %d\n",
1110bf750f4SAndy Green 			__func__, ret);
112375904e3SYang Yingliang 		goto err_unprepare_clk;
1130bf750f4SAndy Green 	}
1140bf750f4SAndy Green 
1150bf750f4SAndy Green 	/* enable clock before frequency division */
1160bf750f4SAndy Green 	regmap_write(i2s->sysctrl, SC_PERIPH_CLKEN12, BIT(9));
1170bf750f4SAndy Green 
1180bf750f4SAndy Green 	/* enable codec working clock / == "codec bus clock" */
1190bf750f4SAndy Green 	regmap_write(i2s->sysctrl, SC_PERIPH_CLKEN1, BIT(5));
1200bf750f4SAndy Green 
1210bf750f4SAndy Green 	/* deassert reset on codec / interface clock / working clock */
1220bf750f4SAndy Green 	regmap_write(i2s->sysctrl, SC_PERIPH_RSTEN1, BIT(5));
1230bf750f4SAndy Green 	regmap_write(i2s->sysctrl, SC_PERIPH_RSTDIS1, BIT(5));
1240bf750f4SAndy Green 
1250bf750f4SAndy Green 	/* not interested in i2s irqs */
1260bf750f4SAndy Green 	val = hi6210_read_reg(i2s, HII2S_CODEC_IRQ_MASK);
1270bf750f4SAndy Green 	val |= 0x3f;
1280bf750f4SAndy Green 	hi6210_write_reg(i2s, HII2S_CODEC_IRQ_MASK, val);
1290bf750f4SAndy Green 
1300bf750f4SAndy Green 
1310bf750f4SAndy Green 	/* reset the stereo downlink fifo */
1320bf750f4SAndy Green 	val = hi6210_read_reg(i2s, HII2S_APB_AFIFO_CFG_1);
1330bf750f4SAndy Green 	val |= (BIT(5) | BIT(4));
1340bf750f4SAndy Green 	hi6210_write_reg(i2s, HII2S_APB_AFIFO_CFG_1, val);
1350bf750f4SAndy Green 
1360bf750f4SAndy Green 	val = hi6210_read_reg(i2s, HII2S_APB_AFIFO_CFG_1);
1370bf750f4SAndy Green 	val &= ~(BIT(5) | BIT(4));
1380bf750f4SAndy Green 	hi6210_write_reg(i2s, HII2S_APB_AFIFO_CFG_1, val);
1390bf750f4SAndy Green 
1400bf750f4SAndy Green 
1410bf750f4SAndy Green 	val = hi6210_read_reg(i2s, HII2S_SW_RST_N);
1420bf750f4SAndy Green 	val &= ~(HII2S_SW_RST_N__ST_DL_WORDLEN_MASK <<
1430bf750f4SAndy Green 			HII2S_SW_RST_N__ST_DL_WORDLEN_SHIFT);
1440bf750f4SAndy Green 	val |= (HII2S_BITS_16 << HII2S_SW_RST_N__ST_DL_WORDLEN_SHIFT);
1450bf750f4SAndy Green 	hi6210_write_reg(i2s, HII2S_SW_RST_N, val);
1460bf750f4SAndy Green 
1470bf750f4SAndy Green 	val = hi6210_read_reg(i2s, HII2S_MISC_CFG);
1480bf750f4SAndy Green 	/* mux 11/12 = APB not i2s */
1490bf750f4SAndy Green 	val &= ~HII2S_MISC_CFG__ST_DL_TEST_SEL;
1500bf750f4SAndy Green 	/* BT R ch  0 = mixer op of DACR ch */
1510bf750f4SAndy Green 	val &= ~HII2S_MISC_CFG__S2_DOUT_RIGHT_SEL;
1520bf750f4SAndy Green 	val &= ~HII2S_MISC_CFG__S2_DOUT_TEST_SEL;
1530bf750f4SAndy Green 
1540bf750f4SAndy Green 	val |= HII2S_MISC_CFG__S2_DOUT_RIGHT_SEL;
1550bf750f4SAndy Green 	/* BT L ch = 1 = mux 7 = "mixer output of DACL */
1560bf750f4SAndy Green 	val |= HII2S_MISC_CFG__S2_DOUT_TEST_SEL;
1570bf750f4SAndy Green 	hi6210_write_reg(i2s, HII2S_MISC_CFG, val);
1580bf750f4SAndy Green 
1590bf750f4SAndy Green 	val = hi6210_read_reg(i2s, HII2S_SW_RST_N);
1600bf750f4SAndy Green 	val |= HII2S_SW_RST_N__SW_RST_N;
1610bf750f4SAndy Green 	hi6210_write_reg(i2s, HII2S_SW_RST_N, val);
1620bf750f4SAndy Green 
1630bf750f4SAndy Green 	return 0;
164375904e3SYang Yingliang 
165375904e3SYang Yingliang err_unprepare_clk:
166375904e3SYang Yingliang 	while (n--)
167375904e3SYang Yingliang 		clk_disable_unprepare(i2s->clk[n]);
168375904e3SYang Yingliang 	return ret;
1690bf750f4SAndy Green }
1702a54e845STakashi Sakamoto 
hi6210_i2s_shutdown(struct snd_pcm_substream * substream,struct snd_soc_dai * cpu_dai)1712a54e845STakashi Sakamoto static void hi6210_i2s_shutdown(struct snd_pcm_substream *substream,
1720bf750f4SAndy Green 				struct snd_soc_dai *cpu_dai)
1730bf750f4SAndy Green {
1740bf750f4SAndy Green 	struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
1750bf750f4SAndy Green 	int n;
1760bf750f4SAndy Green 
1770bf750f4SAndy Green 	for (n = 0; n < i2s->clocks; n++)
1780bf750f4SAndy Green 		clk_disable_unprepare(i2s->clk[n]);
1790bf750f4SAndy Green 
1800bf750f4SAndy Green 	regmap_write(i2s->sysctrl, SC_PERIPH_RSTEN1, BIT(5));
1810bf750f4SAndy Green }
1820bf750f4SAndy Green 
hi6210_i2s_txctrl(struct snd_soc_dai * cpu_dai,int on)1830bf750f4SAndy Green static void hi6210_i2s_txctrl(struct snd_soc_dai *cpu_dai, int on)
1840bf750f4SAndy Green {
1850bf750f4SAndy Green 	struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
1860bf750f4SAndy Green 	u32 val;
1870bf750f4SAndy Green 
1880bf750f4SAndy Green 	spin_lock(&i2s->lock);
1890bf750f4SAndy Green 	if (on) {
1900bf750f4SAndy Green 		/* enable S2 TX */
1910bf750f4SAndy Green 		val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
1920bf750f4SAndy Green 		val |= HII2S_I2S_CFG__S2_IF_TX_EN;
1930bf750f4SAndy Green 		hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
1940bf750f4SAndy Green 	} else {
1950bf750f4SAndy Green 		/* disable S2 TX */
1960bf750f4SAndy Green 		val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
1970bf750f4SAndy Green 		val &= ~HII2S_I2S_CFG__S2_IF_TX_EN;
1980bf750f4SAndy Green 		hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
1990bf750f4SAndy Green 	}
2000bf750f4SAndy Green 	spin_unlock(&i2s->lock);
2010bf750f4SAndy Green }
2020bf750f4SAndy Green 
hi6210_i2s_rxctrl(struct snd_soc_dai * cpu_dai,int on)2030bf750f4SAndy Green static void hi6210_i2s_rxctrl(struct snd_soc_dai *cpu_dai, int on)
2040bf750f4SAndy Green {
2050bf750f4SAndy Green 	struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
2060bf750f4SAndy Green 	u32 val;
2070bf750f4SAndy Green 
2080bf750f4SAndy Green 	spin_lock(&i2s->lock);
2090bf750f4SAndy Green 	if (on) {
2100bf750f4SAndy Green 		val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
2110bf750f4SAndy Green 		val |= HII2S_I2S_CFG__S2_IF_RX_EN;
2120bf750f4SAndy Green 		hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
2130bf750f4SAndy Green 	} else {
2140bf750f4SAndy Green 		val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
2150bf750f4SAndy Green 		val &= ~HII2S_I2S_CFG__S2_IF_RX_EN;
2160bf750f4SAndy Green 		hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
2170bf750f4SAndy Green 	}
2180bf750f4SAndy Green 	spin_unlock(&i2s->lock);
2190bf750f4SAndy Green }
2200bf750f4SAndy Green 
hi6210_i2s_set_fmt(struct snd_soc_dai * cpu_dai,unsigned int fmt)2210bf750f4SAndy Green static int hi6210_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
2220bf750f4SAndy Green {
2230bf750f4SAndy Green 	struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
2240bf750f4SAndy Green 
2250bf750f4SAndy Green 	/*
2260bf750f4SAndy Green 	 * We don't actually set the hardware until the hw_params
2270bf750f4SAndy Green 	 * call, but we need to validate the user input here.
2280bf750f4SAndy Green 	 */
2290f362524SCharles Keepax 	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
2300f362524SCharles Keepax 	case SND_SOC_DAIFMT_BC_FC:
2310f362524SCharles Keepax 	case SND_SOC_DAIFMT_BP_FP:
2320bf750f4SAndy Green 		break;
2330bf750f4SAndy Green 	default:
2340bf750f4SAndy Green 		return -EINVAL;
2350bf750f4SAndy Green 	}
2360bf750f4SAndy Green 
2370bf750f4SAndy Green 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
2380bf750f4SAndy Green 	case SND_SOC_DAIFMT_I2S:
2390bf750f4SAndy Green 	case SND_SOC_DAIFMT_LEFT_J:
2400bf750f4SAndy Green 	case SND_SOC_DAIFMT_RIGHT_J:
2410bf750f4SAndy Green 		break;
2420bf750f4SAndy Green 	default:
2430bf750f4SAndy Green 		return -EINVAL;
2440bf750f4SAndy Green 	}
2450bf750f4SAndy Green 
2460bf750f4SAndy Green 	i2s->format = fmt;
2470f362524SCharles Keepax 	i2s->master = (i2s->format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) ==
2480f362524SCharles Keepax 		      SND_SOC_DAIFMT_BP_FP;
2490bf750f4SAndy Green 
2500bf750f4SAndy Green 	return 0;
2510bf750f4SAndy Green }
2520bf750f4SAndy Green 
hi6210_i2s_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * cpu_dai)2530bf750f4SAndy Green static int hi6210_i2s_hw_params(struct snd_pcm_substream *substream,
2540bf750f4SAndy Green 			    struct snd_pcm_hw_params *params,
2550bf750f4SAndy Green 			    struct snd_soc_dai *cpu_dai)
2560bf750f4SAndy Green {
2570bf750f4SAndy Green 	struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
2580bf750f4SAndy Green 	u32 bits = 0, rate = 0, signed_data = 0, fmt = 0;
2590bf750f4SAndy Green 	u32 val;
2600bf750f4SAndy Green 	struct snd_dmaengine_dai_dma_data *dma_data;
2610bf750f4SAndy Green 
2620bf750f4SAndy Green 	switch (params_format(params)) {
2630bf750f4SAndy Green 	case SNDRV_PCM_FORMAT_U16_LE:
2640bf750f4SAndy Green 		signed_data = HII2S_I2S_CFG__S2_CODEC_DATA_FORMAT;
265df561f66SGustavo A. R. Silva 		fallthrough;
2660bf750f4SAndy Green 	case SNDRV_PCM_FORMAT_S16_LE:
2670bf750f4SAndy Green 		bits = HII2S_BITS_16;
2680bf750f4SAndy Green 		break;
2690bf750f4SAndy Green 	case SNDRV_PCM_FORMAT_U24_LE:
2700bf750f4SAndy Green 		signed_data = HII2S_I2S_CFG__S2_CODEC_DATA_FORMAT;
271df561f66SGustavo A. R. Silva 		fallthrough;
2720bf750f4SAndy Green 	case SNDRV_PCM_FORMAT_S24_LE:
2730bf750f4SAndy Green 		bits = HII2S_BITS_24;
2740bf750f4SAndy Green 		break;
2750bf750f4SAndy Green 	default:
2760bf750f4SAndy Green 		dev_err(cpu_dai->dev, "Bad format\n");
2770bf750f4SAndy Green 		return -EINVAL;
2780bf750f4SAndy Green 	}
2790bf750f4SAndy Green 
2800bf750f4SAndy Green 
2810bf750f4SAndy Green 	switch (params_rate(params)) {
2820bf750f4SAndy Green 	case 8000:
2830bf750f4SAndy Green 		rate = HII2S_FS_RATE_8KHZ;
2840bf750f4SAndy Green 		break;
2850bf750f4SAndy Green 	case 16000:
2860bf750f4SAndy Green 		rate = HII2S_FS_RATE_16KHZ;
2870bf750f4SAndy Green 		break;
2880bf750f4SAndy Green 	case 32000:
2890bf750f4SAndy Green 		rate = HII2S_FS_RATE_32KHZ;
2900bf750f4SAndy Green 		break;
2910bf750f4SAndy Green 	case 48000:
2920bf750f4SAndy Green 		rate = HII2S_FS_RATE_48KHZ;
2930bf750f4SAndy Green 		break;
2940bf750f4SAndy Green 	case 96000:
2950bf750f4SAndy Green 		rate = HII2S_FS_RATE_96KHZ;
2960bf750f4SAndy Green 		break;
2970bf750f4SAndy Green 	case 192000:
2980bf750f4SAndy Green 		rate = HII2S_FS_RATE_192KHZ;
2990bf750f4SAndy Green 		break;
3000bf750f4SAndy Green 	default:
3010bf750f4SAndy Green 		dev_err(cpu_dai->dev, "Bad rate: %d\n", params_rate(params));
3020bf750f4SAndy Green 		return -EINVAL;
3030bf750f4SAndy Green 	}
3040bf750f4SAndy Green 
3050bf750f4SAndy Green 	if (!(params_channels(params))) {
3060bf750f4SAndy Green 		dev_err(cpu_dai->dev, "Bad channels\n");
3070bf750f4SAndy Green 		return -EINVAL;
3080bf750f4SAndy Green 	}
3090bf750f4SAndy Green 
3100bf750f4SAndy Green 	dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);
3110bf750f4SAndy Green 
3120bf750f4SAndy Green 	switch (bits) {
3130bf750f4SAndy Green 	case HII2S_BITS_24:
3140bf750f4SAndy Green 		i2s->bits = 32;
3150bf750f4SAndy Green 		dma_data->addr_width = 3;
3160bf750f4SAndy Green 		break;
3170bf750f4SAndy Green 	default:
3180bf750f4SAndy Green 		i2s->bits = 16;
3190bf750f4SAndy Green 		dma_data->addr_width = 2;
32016c1c089SJohn Stultz 		break;
3210bf750f4SAndy Green 	}
3220bf750f4SAndy Green 	i2s->rate = params_rate(params);
3230bf750f4SAndy Green 	i2s->channels = params_channels(params);
3240bf750f4SAndy Green 	i2s->channel_length = i2s->channels * i2s->bits;
3250bf750f4SAndy Green 
3260bf750f4SAndy Green 	val = hi6210_read_reg(i2s, HII2S_ST_DL_FIFO_TH_CFG);
3270bf750f4SAndy Green 	val &= ~((HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AEMPTY_MASK <<
3280bf750f4SAndy Green 			HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AEMPTY_SHIFT) |
3290bf750f4SAndy Green 		(HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AFULL_MASK <<
3300bf750f4SAndy Green 			HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AFULL_SHIFT) |
3310bf750f4SAndy Green 		(HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AEMPTY_MASK <<
3320bf750f4SAndy Green 			HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AEMPTY_SHIFT) |
3330bf750f4SAndy Green 		(HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AFULL_MASK <<
3340bf750f4SAndy Green 			HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AFULL_SHIFT));
3350bf750f4SAndy Green 	val |= ((16 << HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AEMPTY_SHIFT) |
3360bf750f4SAndy Green 		(30 << HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AFULL_SHIFT) |
3370bf750f4SAndy Green 		(16 << HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AEMPTY_SHIFT) |
3380bf750f4SAndy Green 		(30 << HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AFULL_SHIFT));
3390bf750f4SAndy Green 	hi6210_write_reg(i2s, HII2S_ST_DL_FIFO_TH_CFG, val);
3400bf750f4SAndy Green 
3410bf750f4SAndy Green 
3420bf750f4SAndy Green 	val = hi6210_read_reg(i2s, HII2S_IF_CLK_EN_CFG);
3430bf750f4SAndy Green 	val |= (BIT(19) | BIT(18) | BIT(17) |
3440bf750f4SAndy Green 		HII2S_IF_CLK_EN_CFG__S2_IF_CLK_EN |
3450bf750f4SAndy Green 		HII2S_IF_CLK_EN_CFG__S2_OL_MIXER_EN |
3460bf750f4SAndy Green 		HII2S_IF_CLK_EN_CFG__S2_OL_SRC_EN |
3470bf750f4SAndy Green 		HII2S_IF_CLK_EN_CFG__ST_DL_R_EN |
3480bf750f4SAndy Green 		HII2S_IF_CLK_EN_CFG__ST_DL_L_EN);
3490bf750f4SAndy Green 	hi6210_write_reg(i2s, HII2S_IF_CLK_EN_CFG, val);
3500bf750f4SAndy Green 
3510bf750f4SAndy Green 
3520bf750f4SAndy Green 	val = hi6210_read_reg(i2s, HII2S_DIG_FILTER_CLK_EN_CFG);
3530bf750f4SAndy Green 	val &= ~(HII2S_DIG_FILTER_CLK_EN_CFG__DACR_SDM_EN |
3540bf750f4SAndy Green 		 HII2S_DIG_FILTER_CLK_EN_CFG__DACR_HBF2I_EN |
3550bf750f4SAndy Green 		 HII2S_DIG_FILTER_CLK_EN_CFG__DACR_AGC_EN |
3560bf750f4SAndy Green 		 HII2S_DIG_FILTER_CLK_EN_CFG__DACL_SDM_EN |
3570bf750f4SAndy Green 		 HII2S_DIG_FILTER_CLK_EN_CFG__DACL_HBF2I_EN |
3580bf750f4SAndy Green 		 HII2S_DIG_FILTER_CLK_EN_CFG__DACL_AGC_EN);
3590bf750f4SAndy Green 	val |= (HII2S_DIG_FILTER_CLK_EN_CFG__DACR_MIXER_EN |
3600bf750f4SAndy Green 		HII2S_DIG_FILTER_CLK_EN_CFG__DACL_MIXER_EN);
3610bf750f4SAndy Green 	hi6210_write_reg(i2s, HII2S_DIG_FILTER_CLK_EN_CFG, val);
3620bf750f4SAndy Green 
3630bf750f4SAndy Green 
3640bf750f4SAndy Green 	val = hi6210_read_reg(i2s, HII2S_DIG_FILTER_MODULE_CFG);
3650bf750f4SAndy Green 	val &= ~(HII2S_DIG_FILTER_MODULE_CFG__DACR_MIXER_IN2_MUTE |
3660bf750f4SAndy Green 		 HII2S_DIG_FILTER_MODULE_CFG__DACL_MIXER_IN2_MUTE);
3670bf750f4SAndy Green 	hi6210_write_reg(i2s, HII2S_DIG_FILTER_MODULE_CFG, val);
3680bf750f4SAndy Green 
3690bf750f4SAndy Green 	val = hi6210_read_reg(i2s, HII2S_MUX_TOP_MODULE_CFG);
3700bf750f4SAndy Green 	val &= ~(HII2S_MUX_TOP_MODULE_CFG__S2_OL_MIXER_IN1_MUTE |
3710bf750f4SAndy Green 		 HII2S_MUX_TOP_MODULE_CFG__S2_OL_MIXER_IN2_MUTE |
3720bf750f4SAndy Green 		 HII2S_MUX_TOP_MODULE_CFG__VOICE_DLINK_MIXER_IN1_MUTE |
3730bf750f4SAndy Green 		 HII2S_MUX_TOP_MODULE_CFG__VOICE_DLINK_MIXER_IN2_MUTE);
3740bf750f4SAndy Green 	hi6210_write_reg(i2s, HII2S_MUX_TOP_MODULE_CFG, val);
3750bf750f4SAndy Green 
3760bf750f4SAndy Green 
3770f362524SCharles Keepax 	switch (i2s->format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
3780f362524SCharles Keepax 	case SND_SOC_DAIFMT_BC_FC:
3790bf750f4SAndy Green 		i2s->master = false;
3800bf750f4SAndy Green 		val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
3810bf750f4SAndy Green 		val |= HII2S_I2S_CFG__S2_MST_SLV;
3820bf750f4SAndy Green 		hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
3830bf750f4SAndy Green 		break;
3840f362524SCharles Keepax 	case SND_SOC_DAIFMT_BP_FP:
3850bf750f4SAndy Green 		i2s->master = true;
3860bf750f4SAndy Green 		val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
3870bf750f4SAndy Green 		val &= ~HII2S_I2S_CFG__S2_MST_SLV;
3880bf750f4SAndy Green 		hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
3890bf750f4SAndy Green 		break;
3900bf750f4SAndy Green 	default:
3910f362524SCharles Keepax 		WARN_ONCE(1, "Invalid i2s->fmt CLOCK_PROVIDER_MASK. This shouldn't happen\n");
392da13d746SJohn Stultz 		return -EINVAL;
3930bf750f4SAndy Green 	}
3940bf750f4SAndy Green 
3950bf750f4SAndy Green 	switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) {
3960bf750f4SAndy Green 	case SND_SOC_DAIFMT_I2S:
3970bf750f4SAndy Green 		fmt = HII2S_FORMAT_I2S;
3980bf750f4SAndy Green 		break;
3990bf750f4SAndy Green 	case SND_SOC_DAIFMT_LEFT_J:
4000bf750f4SAndy Green 		fmt = HII2S_FORMAT_LEFT_JUST;
4010bf750f4SAndy Green 		break;
4020bf750f4SAndy Green 	case SND_SOC_DAIFMT_RIGHT_J:
4030bf750f4SAndy Green 		fmt = HII2S_FORMAT_RIGHT_JUST;
4040bf750f4SAndy Green 		break;
4050bf750f4SAndy Green 	default:
4060bf750f4SAndy Green 		WARN_ONCE(1, "Invalid i2s->fmt FORMAT_MASK. This shouldn't happen\n");
407da13d746SJohn Stultz 		return -EINVAL;
4080bf750f4SAndy Green 	}
4090bf750f4SAndy Green 
4100bf750f4SAndy Green 	val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
4110bf750f4SAndy Green 	val &= ~(HII2S_I2S_CFG__S2_FUNC_MODE_MASK <<
4120bf750f4SAndy Green 			HII2S_I2S_CFG__S2_FUNC_MODE_SHIFT);
4130bf750f4SAndy Green 	val |= fmt << HII2S_I2S_CFG__S2_FUNC_MODE_SHIFT;
4140bf750f4SAndy Green 	hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
4150bf750f4SAndy Green 
4160bf750f4SAndy Green 
4170bf750f4SAndy Green 	val = hi6210_read_reg(i2s, HII2S_CLK_SEL);
4180bf750f4SAndy Green 	val &= ~(HII2S_CLK_SEL__I2S_BT_FM_SEL | /* BT gets the I2S */
4190bf750f4SAndy Green 			HII2S_CLK_SEL__EXT_12_288MHZ_SEL);
4200bf750f4SAndy Green 	hi6210_write_reg(i2s, HII2S_CLK_SEL, val);
4210bf750f4SAndy Green 
4220bf750f4SAndy Green 	dma_data->maxburst = 2;
4230bf750f4SAndy Green 
4240bf750f4SAndy Green 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
4250bf750f4SAndy Green 		dma_data->addr = i2s->base_phys + HII2S_ST_DL_CHANNEL;
4260bf750f4SAndy Green 	else
4270bf750f4SAndy Green 		dma_data->addr = i2s->base_phys + HII2S_STEREO_UPLINK_CHANNEL;
4280bf750f4SAndy Green 
4290bf750f4SAndy Green 	switch (i2s->channels) {
4300bf750f4SAndy Green 	case 1:
4310bf750f4SAndy Green 		val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
4320bf750f4SAndy Green 		val |= HII2S_I2S_CFG__S2_FRAME_MODE;
4330bf750f4SAndy Green 		hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
4340bf750f4SAndy Green 		break;
4350bf750f4SAndy Green 	default:
4360bf750f4SAndy Green 		val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
4370bf750f4SAndy Green 		val &= ~HII2S_I2S_CFG__S2_FRAME_MODE;
4380bf750f4SAndy Green 		hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
43916c1c089SJohn Stultz 		break;
4400bf750f4SAndy Green 	}
4410bf750f4SAndy Green 
4420bf750f4SAndy Green 	/* clear loopback, set signed type and word length */
4430bf750f4SAndy Green 	val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
4440bf750f4SAndy Green 	val &= ~HII2S_I2S_CFG__S2_CODEC_DATA_FORMAT;
4450bf750f4SAndy Green 	val &= ~(HII2S_I2S_CFG__S2_CODEC_IO_WORDLENGTH_MASK <<
4460bf750f4SAndy Green 			HII2S_I2S_CFG__S2_CODEC_IO_WORDLENGTH_SHIFT);
4470bf750f4SAndy Green 	val &= ~(HII2S_I2S_CFG__S2_DIRECT_LOOP_MASK <<
4480bf750f4SAndy Green 			HII2S_I2S_CFG__S2_DIRECT_LOOP_SHIFT);
4490bf750f4SAndy Green 	val |= signed_data;
4500bf750f4SAndy Green 	val |= (bits << HII2S_I2S_CFG__S2_CODEC_IO_WORDLENGTH_SHIFT);
4510bf750f4SAndy Green 	hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
4520bf750f4SAndy Green 
4530bf750f4SAndy Green 
4540bf750f4SAndy Green 	if (!i2s->master)
4550bf750f4SAndy Green 		return 0;
4560bf750f4SAndy Green 
4570bf750f4SAndy Green 	/* set DAC and related units to correct rate */
4580bf750f4SAndy Green 	val = hi6210_read_reg(i2s, HII2S_FS_CFG);
4590bf750f4SAndy Green 	val &= ~(HII2S_FS_CFG__FS_S2_MASK << HII2S_FS_CFG__FS_S2_SHIFT);
4600bf750f4SAndy Green 	val &= ~(HII2S_FS_CFG__FS_DACLR_MASK << HII2S_FS_CFG__FS_DACLR_SHIFT);
4610bf750f4SAndy Green 	val &= ~(HII2S_FS_CFG__FS_ST_DL_R_MASK <<
4620bf750f4SAndy Green 					HII2S_FS_CFG__FS_ST_DL_R_SHIFT);
4630bf750f4SAndy Green 	val &= ~(HII2S_FS_CFG__FS_ST_DL_L_MASK <<
4640bf750f4SAndy Green 					HII2S_FS_CFG__FS_ST_DL_L_SHIFT);
4650bf750f4SAndy Green 	val |= (rate << HII2S_FS_CFG__FS_S2_SHIFT);
4660bf750f4SAndy Green 	val |= (rate << HII2S_FS_CFG__FS_DACLR_SHIFT);
4670bf750f4SAndy Green 	val |= (rate << HII2S_FS_CFG__FS_ST_DL_R_SHIFT);
4680bf750f4SAndy Green 	val |= (rate << HII2S_FS_CFG__FS_ST_DL_L_SHIFT);
4690bf750f4SAndy Green 	hi6210_write_reg(i2s, HII2S_FS_CFG, val);
4700bf750f4SAndy Green 
4710bf750f4SAndy Green 	return 0;
4720bf750f4SAndy Green }
4730bf750f4SAndy Green 
hi6210_i2s_trigger(struct snd_pcm_substream * substream,int cmd,struct snd_soc_dai * cpu_dai)4740bf750f4SAndy Green static int hi6210_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
4750bf750f4SAndy Green 			  struct snd_soc_dai *cpu_dai)
4760bf750f4SAndy Green {
4770bf750f4SAndy Green 	pr_debug("%s\n", __func__);
4780bf750f4SAndy Green 	switch (cmd) {
4790bf750f4SAndy Green 	case SNDRV_PCM_TRIGGER_START:
4800bf750f4SAndy Green 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
4810bf750f4SAndy Green 		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
4820bf750f4SAndy Green 			hi6210_i2s_rxctrl(cpu_dai, 1);
4830bf750f4SAndy Green 		else
4840bf750f4SAndy Green 			hi6210_i2s_txctrl(cpu_dai, 1);
4850bf750f4SAndy Green 		break;
4860bf750f4SAndy Green 	case SNDRV_PCM_TRIGGER_STOP:
4870bf750f4SAndy Green 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
4880bf750f4SAndy Green 		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
4890bf750f4SAndy Green 			hi6210_i2s_rxctrl(cpu_dai, 0);
4900bf750f4SAndy Green 		else
4910bf750f4SAndy Green 			hi6210_i2s_txctrl(cpu_dai, 0);
4920bf750f4SAndy Green 		break;
4930bf750f4SAndy Green 	default:
4942b8eae79SColin Ian King 		dev_err(cpu_dai->dev, "unknown cmd\n");
4950bf750f4SAndy Green 		return -EINVAL;
4960bf750f4SAndy Green 	}
4970bf750f4SAndy Green 	return 0;
4980bf750f4SAndy Green }
4990bf750f4SAndy Green 
hi6210_i2s_dai_probe(struct snd_soc_dai * dai)5000bf750f4SAndy Green static int hi6210_i2s_dai_probe(struct snd_soc_dai *dai)
5010bf750f4SAndy Green {
5020bf750f4SAndy Green 	struct hi6210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
5030bf750f4SAndy Green 
5040bf750f4SAndy Green 	snd_soc_dai_init_dma_data(dai,
5050bf750f4SAndy Green 				  &i2s->dma_data[SNDRV_PCM_STREAM_PLAYBACK],
5060bf750f4SAndy Green 				  &i2s->dma_data[SNDRV_PCM_STREAM_CAPTURE]);
5070bf750f4SAndy Green 
5080bf750f4SAndy Green 	return 0;
5090bf750f4SAndy Green }
5100bf750f4SAndy Green 
5110bf750f4SAndy Green 
51294372fceSGustavo A. R. Silva static const struct snd_soc_dai_ops hi6210_i2s_dai_ops = {
513*4f1ec3daSKuninori Morimoto 	.probe		= hi6210_i2s_dai_probe,
5140bf750f4SAndy Green 	.trigger	= hi6210_i2s_trigger,
5150bf750f4SAndy Green 	.hw_params	= hi6210_i2s_hw_params,
516b9a79728SCharles Keepax 	.set_fmt	= hi6210_i2s_set_fmt,
5170bf750f4SAndy Green 	.startup	= hi6210_i2s_startup,
5180bf750f4SAndy Green 	.shutdown	= hi6210_i2s_shutdown,
5190bf750f4SAndy Green };
5200bf750f4SAndy Green 
5212a54e845STakashi Sakamoto static const struct snd_soc_dai_driver hi6210_i2s_dai_init = {
5220bf750f4SAndy Green 	.playback = {
5230bf750f4SAndy Green 		.channels_min = 2,
5240bf750f4SAndy Green 		.channels_max = 2,
5250bf750f4SAndy Green 		.formats = SNDRV_PCM_FMTBIT_S16_LE |
5260bf750f4SAndy Green 			   SNDRV_PCM_FMTBIT_U16_LE,
5270bf750f4SAndy Green 		.rates = SNDRV_PCM_RATE_48000,
5280bf750f4SAndy Green 	},
5290bf750f4SAndy Green 	.capture = {
5300bf750f4SAndy Green 		.channels_min = 2,
5310bf750f4SAndy Green 		.channels_max = 2,
5320bf750f4SAndy Green 		.formats = SNDRV_PCM_FMTBIT_S16_LE |
5330bf750f4SAndy Green 			   SNDRV_PCM_FMTBIT_U16_LE,
5340bf750f4SAndy Green 		.rates = SNDRV_PCM_RATE_48000,
5350bf750f4SAndy Green 	},
5360bf750f4SAndy Green 	.ops = &hi6210_i2s_dai_ops,
5370bf750f4SAndy Green };
5380bf750f4SAndy Green 
5390bf750f4SAndy Green static const struct snd_soc_component_driver hi6210_i2s_i2s_comp = {
5400bf750f4SAndy Green 	.name = "hi6210_i2s-i2s",
541bf6dacb7SCharles Keepax 	.legacy_dai_naming = 1,
5420bf750f4SAndy Green };
5430bf750f4SAndy Green 
hi6210_i2s_probe(struct platform_device * pdev)5440bf750f4SAndy Green static int hi6210_i2s_probe(struct platform_device *pdev)
5450bf750f4SAndy Green {
5460bf750f4SAndy Green 	struct device_node *node = pdev->dev.of_node;
5470bf750f4SAndy Green 	struct device *dev = &pdev->dev;
5480bf750f4SAndy Green 	struct hi6210_i2s *i2s;
5490bf750f4SAndy Green 	struct resource *res;
5500bf750f4SAndy Green 	int ret;
5510bf750f4SAndy Green 
55277060f4fSTang Bin 	i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);
5530bf750f4SAndy Green 	if (!i2s)
5540bf750f4SAndy Green 		return -ENOMEM;
5550bf750f4SAndy Green 
5560bf750f4SAndy Green 	i2s->dev = dev;
5570bf750f4SAndy Green 	spin_lock_init(&i2s->lock);
5580bf750f4SAndy Green 
559afc3a0b4SYang Yingliang 	i2s->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
5600bf750f4SAndy Green 	if (IS_ERR(i2s->base))
5610bf750f4SAndy Green 		return PTR_ERR(i2s->base);
5620bf750f4SAndy Green 
5630bf750f4SAndy Green 	i2s->base_phys = (phys_addr_t)res->start;
5640bf750f4SAndy Green 	i2s->dai = hi6210_i2s_dai_init;
5650bf750f4SAndy Green 
56677060f4fSTang Bin 	dev_set_drvdata(dev, i2s);
5670bf750f4SAndy Green 
5680bf750f4SAndy Green 	i2s->sysctrl = syscon_regmap_lookup_by_phandle(node,
5690bf750f4SAndy Green 						"hisilicon,sysctrl-syscon");
5700bf750f4SAndy Green 	if (IS_ERR(i2s->sysctrl))
5710bf750f4SAndy Green 		return PTR_ERR(i2s->sysctrl);
5720bf750f4SAndy Green 
57377060f4fSTang Bin 	i2s->clk[CLK_DACODEC] = devm_clk_get(dev, "dacodec");
574e782ddbbSTang Bin 	if (IS_ERR(i2s->clk[CLK_DACODEC]))
5750bf750f4SAndy Green 		return PTR_ERR(i2s->clk[CLK_DACODEC]);
5760bf750f4SAndy Green 	i2s->clocks++;
5770bf750f4SAndy Green 
57877060f4fSTang Bin 	i2s->clk[CLK_I2S_BASE] = devm_clk_get(dev, "i2s-base");
579e782ddbbSTang Bin 	if (IS_ERR(i2s->clk[CLK_I2S_BASE]))
5800bf750f4SAndy Green 		return PTR_ERR(i2s->clk[CLK_I2S_BASE]);
5810bf750f4SAndy Green 	i2s->clocks++;
5820bf750f4SAndy Green 
58377060f4fSTang Bin 	ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0);
5840bf750f4SAndy Green 	if (ret)
5850bf750f4SAndy Green 		return ret;
5860bf750f4SAndy Green 
58777060f4fSTang Bin 	ret = devm_snd_soc_register_component(dev, &hi6210_i2s_i2s_comp,
5880bf750f4SAndy Green 					 &i2s->dai, 1);
5890bf750f4SAndy Green 	return ret;
5900bf750f4SAndy Green }
5910bf750f4SAndy Green 
5920bf750f4SAndy Green static const struct of_device_id hi6210_i2s_dt_ids[] = {
5930bf750f4SAndy Green 	{ .compatible = "hisilicon,hi6210-i2s" },
5940bf750f4SAndy Green 	{ /* sentinel */ }
5950bf750f4SAndy Green };
5960bf750f4SAndy Green 
5970bf750f4SAndy Green MODULE_DEVICE_TABLE(of, hi6210_i2s_dt_ids);
5980bf750f4SAndy Green 
5990bf750f4SAndy Green static struct platform_driver hi6210_i2s_driver = {
6000bf750f4SAndy Green 	.probe = hi6210_i2s_probe,
6010bf750f4SAndy Green 	.driver = {
6020bf750f4SAndy Green 		.name = "hi6210_i2s",
6030bf750f4SAndy Green 		.of_match_table = hi6210_i2s_dt_ids,
6040bf750f4SAndy Green 	},
6050bf750f4SAndy Green };
6060bf750f4SAndy Green 
6070bf750f4SAndy Green module_platform_driver(hi6210_i2s_driver);
6080bf750f4SAndy Green 
6090bf750f4SAndy Green MODULE_DESCRIPTION("Hisilicon HI6210 I2S driver");
6100bf750f4SAndy Green MODULE_AUTHOR("Andy Green <andy.green@linaro.org>");
6110bf750f4SAndy Green MODULE_LICENSE("GPL");
612