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