xref: /rk3399_rockchip-uboot/drivers/sound/rockchip-i2s.c (revision 69ab2873d7dfde4d3bde450cbbcd415ad5a6a883)
1*69ab2873SSugar Zhang // SPDX-License-Identifier:     GPL-2.0+
2*69ab2873SSugar Zhang /*
3*69ab2873SSugar Zhang  * (C) Copyright 2018 Rockchip Electronics Co., Ltd
4*69ab2873SSugar Zhang  */
5*69ab2873SSugar Zhang 
6*69ab2873SSugar Zhang #include <clk.h>
7*69ab2873SSugar Zhang #include <common.h>
8*69ab2873SSugar Zhang #include <dm.h>
9*69ab2873SSugar Zhang #include <errno.h>
10*69ab2873SSugar Zhang #include <malloc.h>
11*69ab2873SSugar Zhang #include <asm/io.h>
12*69ab2873SSugar Zhang #include <sound.h>
13*69ab2873SSugar Zhang #include "rockchip-i2s.h"
14*69ab2873SSugar Zhang 
15*69ab2873SSugar Zhang #define I2S_FIFO_LENGTH (31)
16*69ab2873SSugar Zhang 
17*69ab2873SSugar Zhang struct rk_i2s_dev {
18*69ab2873SSugar Zhang 	void *regbase;
19*69ab2873SSugar Zhang 	struct clk mclk;
20*69ab2873SSugar Zhang };
21*69ab2873SSugar Zhang 
i2s_reg_readl(struct rk_i2s_dev * dev,u32 offset)22*69ab2873SSugar Zhang static inline u32 i2s_reg_readl(struct rk_i2s_dev *dev, u32 offset)
23*69ab2873SSugar Zhang {
24*69ab2873SSugar Zhang 	return readl(dev->regbase + offset);
25*69ab2873SSugar Zhang }
26*69ab2873SSugar Zhang 
i2s_reg_writel(struct rk_i2s_dev * dev,u32 offset,u32 val)27*69ab2873SSugar Zhang static inline void i2s_reg_writel(struct rk_i2s_dev *dev, u32 offset, u32 val)
28*69ab2873SSugar Zhang {
29*69ab2873SSugar Zhang 	writel(val, dev->regbase + offset);
30*69ab2873SSugar Zhang }
31*69ab2873SSugar Zhang 
i2s_reg_update_bits(struct rk_i2s_dev * dev,u32 offset,u32 mask,u32 val)32*69ab2873SSugar Zhang static inline void i2s_reg_update_bits(struct rk_i2s_dev *dev, u32 offset,
33*69ab2873SSugar Zhang 				       u32 mask, u32 val)
34*69ab2873SSugar Zhang {
35*69ab2873SSugar Zhang 	u32 tmp, orig;
36*69ab2873SSugar Zhang 
37*69ab2873SSugar Zhang 	orig = readl(dev->regbase + offset);
38*69ab2873SSugar Zhang 
39*69ab2873SSugar Zhang 	tmp = orig & ~mask;
40*69ab2873SSugar Zhang 	tmp |= val & mask;
41*69ab2873SSugar Zhang 
42*69ab2873SSugar Zhang 	if (tmp != orig)
43*69ab2873SSugar Zhang 		writel(tmp, dev->regbase + offset);
44*69ab2873SSugar Zhang }
45*69ab2873SSugar Zhang 
dump_regs(struct rk_i2s_dev * dev)46*69ab2873SSugar Zhang static void dump_regs(struct rk_i2s_dev *dev)
47*69ab2873SSugar Zhang {
48*69ab2873SSugar Zhang 	int i = 0;
49*69ab2873SSugar Zhang 
50*69ab2873SSugar Zhang 	for (i = 0; i <= I2S_RXDR; i += 4)
51*69ab2873SSugar Zhang 		debug("0x%02x: 0x%08x\n", i, readl(dev->regbase + i));
52*69ab2873SSugar Zhang }
53*69ab2873SSugar Zhang 
rk_i2s_hw_params(struct udevice * udev,unsigned int samplerate,unsigned int fmt,unsigned int channels)54*69ab2873SSugar Zhang static int rk_i2s_hw_params(struct udevice *udev, unsigned int samplerate,
55*69ab2873SSugar Zhang 			    unsigned int fmt, unsigned int channels)
56*69ab2873SSugar Zhang {
57*69ab2873SSugar Zhang 	struct rk_i2s_dev *dev = dev_get_priv(udev);
58*69ab2873SSugar Zhang 
59*69ab2873SSugar Zhang 	/* set fmt */
60*69ab2873SSugar Zhang 	i2s_reg_update_bits(dev, I2S_CKR,
61*69ab2873SSugar Zhang 			    I2S_CKR_MSS_MASK, I2S_CKR_MSS_MASTER);
62*69ab2873SSugar Zhang 	i2s_reg_update_bits(dev, I2S_TXCR,
63*69ab2873SSugar Zhang 			    I2S_TXCR_IBM_MASK, I2S_TXCR_IBM_NORMAL);
64*69ab2873SSugar Zhang 	i2s_reg_update_bits(dev, I2S_RXCR,
65*69ab2873SSugar Zhang 			    I2S_RXCR_IBM_MASK, I2S_RXCR_IBM_NORMAL);
66*69ab2873SSugar Zhang 	/* set div */
67*69ab2873SSugar Zhang 	i2s_reg_update_bits(dev, I2S_CKR,
68*69ab2873SSugar Zhang 			    I2S_CKR_TSD_MASK | I2S_CKR_RSD_MASK,
69*69ab2873SSugar Zhang 			    I2S_CKR_TSD(64) | I2S_CKR_RSD(64));
70*69ab2873SSugar Zhang 	i2s_reg_update_bits(dev, I2S_CKR,
71*69ab2873SSugar Zhang 			    I2S_CKR_MDIV_MASK, I2S_CKR_MDIV(4));
72*69ab2873SSugar Zhang 	/* set hwparams */
73*69ab2873SSugar Zhang 	i2s_reg_update_bits(dev, I2S_TXCR,
74*69ab2873SSugar Zhang 			    I2S_TXCR_VDW_MASK |
75*69ab2873SSugar Zhang 			    I2S_TXCR_CSR_MASK,
76*69ab2873SSugar Zhang 			    I2S_TXCR_VDW(16) |
77*69ab2873SSugar Zhang 			    I2S_TXCR_CHN_2);
78*69ab2873SSugar Zhang 	i2s_reg_update_bits(dev, I2S_RXCR,
79*69ab2873SSugar Zhang 			    I2S_RXCR_CSR_MASK |
80*69ab2873SSugar Zhang 			    I2S_RXCR_VDW_MASK,
81*69ab2873SSugar Zhang 			    I2S_TXCR_VDW(16) |
82*69ab2873SSugar Zhang 			    I2S_TXCR_CHN_2);
83*69ab2873SSugar Zhang 	i2s_reg_update_bits(dev, I2S_DMACR,
84*69ab2873SSugar Zhang 			    I2S_DMACR_TDL_MASK | I2S_DMACR_RDL_MASK,
85*69ab2873SSugar Zhang 			    I2S_DMACR_TDL(16) | I2S_DMACR_RDL(16));
86*69ab2873SSugar Zhang 
87*69ab2873SSugar Zhang 	return 0;
88*69ab2873SSugar Zhang }
89*69ab2873SSugar Zhang 
rk_i2s_txctrl(struct rk_i2s_dev * dev,int on)90*69ab2873SSugar Zhang static void rk_i2s_txctrl(struct rk_i2s_dev *dev, int on)
91*69ab2873SSugar Zhang {
92*69ab2873SSugar Zhang 	if (on) {
93*69ab2873SSugar Zhang 		i2s_reg_update_bits(dev, I2S_XFER,
94*69ab2873SSugar Zhang 				    I2S_XFER_TXS_MASK | I2S_XFER_RXS_MASK,
95*69ab2873SSugar Zhang 				    I2S_XFER_TXS_START | I2S_XFER_RXS_START);
96*69ab2873SSugar Zhang 	} else {
97*69ab2873SSugar Zhang 		i2s_reg_update_bits(dev, I2S_XFER,
98*69ab2873SSugar Zhang 				    I2S_XFER_TXS_MASK |
99*69ab2873SSugar Zhang 				    I2S_XFER_RXS_MASK,
100*69ab2873SSugar Zhang 				    I2S_XFER_TXS_STOP |
101*69ab2873SSugar Zhang 				    I2S_XFER_RXS_STOP);
102*69ab2873SSugar Zhang 
103*69ab2873SSugar Zhang 		i2s_reg_update_bits(dev, I2S_CLR,
104*69ab2873SSugar Zhang 				    I2S_CLR_TXC_MASK | I2S_CLR_RXC_MASK,
105*69ab2873SSugar Zhang 				    I2S_CLR_TXC | I2S_CLR_RXC);
106*69ab2873SSugar Zhang 	}
107*69ab2873SSugar Zhang }
108*69ab2873SSugar Zhang 
rk_i2s_transfer_tx_data(struct udevice * udev,unsigned int * data,unsigned long data_size)109*69ab2873SSugar Zhang static int rk_i2s_transfer_tx_data(struct udevice *udev, unsigned int *data,
110*69ab2873SSugar Zhang 				   unsigned long data_size)
111*69ab2873SSugar Zhang {
112*69ab2873SSugar Zhang 	struct rk_i2s_dev *dev = dev_get_priv(udev);
113*69ab2873SSugar Zhang 	u32 val;
114*69ab2873SSugar Zhang 
115*69ab2873SSugar Zhang 	if (data_size < I2S_FIFO_LENGTH) {
116*69ab2873SSugar Zhang 		debug("%s : invalid data size\n", __func__);
117*69ab2873SSugar Zhang 		return -EINVAL;
118*69ab2873SSugar Zhang 	}
119*69ab2873SSugar Zhang 
120*69ab2873SSugar Zhang 	rk_i2s_txctrl(dev, 1);
121*69ab2873SSugar Zhang 	while (data_size > 0) {
122*69ab2873SSugar Zhang 		val = i2s_reg_readl(dev, I2S_FIFOLR);
123*69ab2873SSugar Zhang 		if (val < I2S_FIFO_LENGTH) {
124*69ab2873SSugar Zhang 			i2s_reg_writel(dev, I2S_TXDR, *data++);
125*69ab2873SSugar Zhang 			data_size--;
126*69ab2873SSugar Zhang 		}
127*69ab2873SSugar Zhang 	}
128*69ab2873SSugar Zhang 
129*69ab2873SSugar Zhang 	return 0;
130*69ab2873SSugar Zhang }
131*69ab2873SSugar Zhang 
rk_i2s_set_sysclk(struct udevice * dev,unsigned int freq)132*69ab2873SSugar Zhang static int rk_i2s_set_sysclk(struct udevice *dev, unsigned int freq)
133*69ab2873SSugar Zhang {
134*69ab2873SSugar Zhang 	struct rk_i2s_dev *i2s = dev_get_priv(dev);
135*69ab2873SSugar Zhang 
136*69ab2873SSugar Zhang 	clk_set_rate(&i2s->mclk, freq);
137*69ab2873SSugar Zhang 
138*69ab2873SSugar Zhang 	return 0;
139*69ab2873SSugar Zhang }
140*69ab2873SSugar Zhang 
141*69ab2873SSugar Zhang static const struct snd_soc_dai_ops rockchip_i2s_ops = {
142*69ab2873SSugar Zhang 	.hw_params = rk_i2s_hw_params,
143*69ab2873SSugar Zhang 	.set_sysclk = rk_i2s_set_sysclk,
144*69ab2873SSugar Zhang 	.transfer = rk_i2s_transfer_tx_data,
145*69ab2873SSugar Zhang };
146*69ab2873SSugar Zhang 
rockchip_i2s_probe(struct udevice * dev)147*69ab2873SSugar Zhang static int rockchip_i2s_probe(struct udevice *dev)
148*69ab2873SSugar Zhang {
149*69ab2873SSugar Zhang 	struct rk_i2s_dev *i2s = dev_get_priv(dev);
150*69ab2873SSugar Zhang 	int ret;
151*69ab2873SSugar Zhang 
152*69ab2873SSugar Zhang 	i2s->regbase = dev_read_addr_ptr(dev);
153*69ab2873SSugar Zhang 
154*69ab2873SSugar Zhang 	ret = clk_get_by_name(dev, "i2s_clk", &i2s->mclk);
155*69ab2873SSugar Zhang 	if (ret) {
156*69ab2873SSugar Zhang 		printf("%s get i2s mclk fail!\n", __func__);
157*69ab2873SSugar Zhang 		return -EINVAL;
158*69ab2873SSugar Zhang 	}
159*69ab2873SSugar Zhang 
160*69ab2873SSugar Zhang 	dump_regs(i2s);
161*69ab2873SSugar Zhang 	return 0;
162*69ab2873SSugar Zhang }
163*69ab2873SSugar Zhang 
164*69ab2873SSugar Zhang static const struct udevice_id rockchip_i2s_ids[] = {
165*69ab2873SSugar Zhang 	{ .compatible = "rockchip,px30-i2s", },
166*69ab2873SSugar Zhang 	{ .compatible = "rockchip,rk3036-i2s", },
167*69ab2873SSugar Zhang 	{ .compatible = "rockchip,rk3066-i2s", },
168*69ab2873SSugar Zhang 	{ .compatible = "rockchip,rk3128-i2s", },
169*69ab2873SSugar Zhang 	{ .compatible = "rockchip,rk3188-i2s", },
170*69ab2873SSugar Zhang 	{ .compatible = "rockchip,rk3288-i2s", },
171*69ab2873SSugar Zhang 	{ .compatible = "rockchip,rk3328-i2s", },
172*69ab2873SSugar Zhang 	{ .compatible = "rockchip,rk3368-i2s", },
173*69ab2873SSugar Zhang 	{ .compatible = "rockchip,rk3399-i2s", },
174*69ab2873SSugar Zhang 	{ }
175*69ab2873SSugar Zhang };
176*69ab2873SSugar Zhang 
177*69ab2873SSugar Zhang U_BOOT_DRIVER(rockchip_i2s) = {
178*69ab2873SSugar Zhang 	.name = "rockchip_i2s",
179*69ab2873SSugar Zhang 	.id = UCLASS_I2S,
180*69ab2873SSugar Zhang 	.of_match = rockchip_i2s_ids,
181*69ab2873SSugar Zhang 	.probe = rockchip_i2s_probe,
182*69ab2873SSugar Zhang 	.priv_auto_alloc_size = sizeof(struct rk_i2s_dev),
183*69ab2873SSugar Zhang 	.ops = &rockchip_i2s_ops,
184*69ab2873SSugar Zhang };
185*69ab2873SSugar Zhang 
186*69ab2873SSugar Zhang UCLASS_DRIVER(i2s) = {
187*69ab2873SSugar Zhang 	.id = UCLASS_I2S,
188*69ab2873SSugar Zhang 	.name = "i2s_bus",
189*69ab2873SSugar Zhang };
190