1 /*
2 * Copyright (C) 2022 HiHope Open Source Organization .
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #include <sound/pcm_params.h>
10 #include <sound/dmaengine_pcm.h>
11 #include <linux/module.h>
12 #include <linux/mfd/syscon.h>
13 #include <linux/delay.h>
14 #include <linux/of_gpio.h>
15 #include <linux/of_device.h>
16 #include <linux/of_address.h>
17 #include <linux/clk.h>
18 #include <linux/clk/rockchip.h>
19 #include <linux/pm_runtime.h>
20 #include <linux/regmap.h>
21 #include <linux/reset.h>
22 #include <linux/spinlock.h>
23
24 #include "audio_driver_log.h"
25 #include "rk3568_dai_linux.h"
26
27 #define DRV_NAME "rockchip-i2s-tdm"
28
29 struct txrx_config {
30 u32 addr;
31 u32 reg;
32 u32 txonly;
33 u32 rxonly;
34 };
35 struct rk_i2s_soc_data {
36 u32 softrst_offset;
37 u32 grf_reg_offset;
38 u32 grf_shift;
39 int config_count;
40 const struct txrx_config *configs;
41 int (*init)(struct device *dev, u32 addr);
42 };
43
44 static const struct txrx_config rk3568_txrx_config[] = {
45 // base addr, reg, txonly, rxonly
46 { 0xfe410000, 0x504, RK3568_I2S1_CLK_TXONLY, RK3568_I2S1_CLK_RXONLY },
47 };
48
common_soc_init(struct device * dev,u32 addr)49 static int common_soc_init(struct device *dev, u32 addr)
50 {
51 struct rk3568_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(dev);
52 AUDIO_DEVICE_LOG_DEBUG("i2s_tdm addr = %p ", i2s_tdm);
53 regmap_write(i2s_tdm->grf, rk3568_txrx_config[0].reg, rk3568_txrx_config[0].txonly);
54 return 0;
55 }
56
57 static const struct rk_i2s_soc_data rk3568_i2s_soc_data = {
58 .softrst_offset = 0x0400, // offset
59 .configs = rk3568_txrx_config,
60 .config_count = 1,
61 .init = common_soc_init,
62 };
63 static const struct of_device_id rockchip_i2s_tdm_match[] = {
64
65 { .compatible = "rockchip,rk3568-i2s-tdm", .data = &rk3568_i2s_soc_data },
66 {},
67 };
rockchip_i2s_tdm_wr_reg(struct device * dev,unsigned int reg)68 static bool rockchip_i2s_tdm_wr_reg(struct device *dev, unsigned int reg)
69 {
70 switch (reg) {
71 case I2S_TXCR:
72 case I2S_RXCR:
73 case I2S_CKR:
74 case I2S_DMACR:
75 case I2S_INTCR:
76 case I2S_XFER:
77 case I2S_CLR:
78 case I2S_TXDR:
79 case I2S_TDM_TXCR:
80 case I2S_TDM_RXCR:
81 case I2S_CLKDIV:
82 return true;
83 default:
84 return false;
85 }
86 }
87
rockchip_i2s_tdm_rd_reg(struct device * dev,unsigned int reg)88 static bool rockchip_i2s_tdm_rd_reg(struct device *dev, unsigned int reg)
89 {
90 switch (reg) {
91 case I2S_TXCR:
92 case I2S_RXCR:
93 case I2S_CKR:
94 case I2S_DMACR:
95 case I2S_INTCR:
96 case I2S_XFER:
97 case I2S_CLR:
98 case I2S_TXDR:
99 case I2S_RXDR:
100 case I2S_TXFIFOLR:
101 case I2S_INTSR:
102 case I2S_RXFIFOLR:
103 case I2S_TDM_TXCR:
104 case I2S_TDM_RXCR:
105 case I2S_CLKDIV:
106 return true;
107 default:
108 return false;
109 }
110 }
111
rockchip_i2s_tdm_volatile_reg(struct device * dev,unsigned int reg)112 static bool rockchip_i2s_tdm_volatile_reg(struct device *dev, unsigned int reg)
113 {
114 switch (reg) {
115 case I2S_TXFIFOLR:
116 case I2S_INTSR:
117 case I2S_CLR:
118 case I2S_TXDR:
119 case I2S_RXDR:
120 case I2S_RXFIFOLR:
121 return true;
122 default:
123 return false;
124 }
125 }
126
rockchip_i2s_tdm_precious_reg(struct device * dev,unsigned int reg)127 static bool rockchip_i2s_tdm_precious_reg(struct device *dev, unsigned int reg)
128 {
129 switch (reg) {
130 case I2S_RXDR:
131 return true;
132 default:
133 return false;
134 }
135 }
136
137 // regs init value map
138 static const struct reg_default rockchip_i2s_tdm_reg_defaults[] = {
139 {0x00, 0x7200000f},
140 {0x04, 0x01c8000f},
141 {0x08, 0x00001f1f},
142 {0x10, 0x001f0000},
143 {0x14, 0x01f00000},
144 {0x30, 0x00003eff},
145 {0x34, 0x00003eff},
146 {0x38, 0x00000707},
147 };
148
149 static const struct regmap_config rockchip_i2s_tdm_regmap_config = {
150 .reg_bits = 32,
151 .reg_stride = 4,
152 .val_bits = 32,
153 .max_register = I2S_CLKDIV,
154 .reg_defaults = rockchip_i2s_tdm_reg_defaults,
155 .num_reg_defaults = ARRAY_SIZE(rockchip_i2s_tdm_reg_defaults),
156 .writeable_reg = rockchip_i2s_tdm_wr_reg,
157 .readable_reg = rockchip_i2s_tdm_rd_reg,
158 .volatile_reg = rockchip_i2s_tdm_volatile_reg,
159 .precious_reg = rockchip_i2s_tdm_precious_reg,
160 .cache_type = REGCACHE_FLAT,
161 };
162
i2s_tdm_runtime_suspend(struct rk3568_i2s_tdm_dev * i2s_tdm)163 static int i2s_tdm_runtime_suspend(struct rk3568_i2s_tdm_dev *i2s_tdm)
164 {
165 regcache_cache_only(i2s_tdm->regmap, true);
166 if (!IS_ERR(i2s_tdm->mclk_tx))
167 clk_disable_unprepare(i2s_tdm->mclk_tx);
168 if (!IS_ERR(i2s_tdm->mclk_rx))
169 clk_disable_unprepare(i2s_tdm->mclk_rx);
170 return 0;
171 }
172
i2s_tdm_runtime_resume(struct rk3568_i2s_tdm_dev * i2s_tdm)173 static int i2s_tdm_runtime_resume(struct rk3568_i2s_tdm_dev *i2s_tdm)
174 {
175 int ret;
176 if (!IS_ERR(i2s_tdm->mclk_tx))
177 clk_prepare_enable(i2s_tdm->mclk_tx);
178 if (!IS_ERR(i2s_tdm->mclk_rx))
179 clk_prepare_enable(i2s_tdm->mclk_rx);
180
181 regcache_cache_only(i2s_tdm->regmap, false);
182 regcache_mark_dirty(i2s_tdm->regmap);
183
184 ret = regcache_sync(i2s_tdm->regmap);
185 if (ret) {
186 if (!IS_ERR(i2s_tdm->mclk_tx))
187 clk_disable_unprepare(i2s_tdm->mclk_tx);
188 if (!IS_ERR(i2s_tdm->mclk_rx))
189 clk_disable_unprepare(i2s_tdm->mclk_rx);
190 }
191 return ret;
192 }
193
rockchip_i2s_tdm_probe(struct platform_device * pdev)194 static int rockchip_i2s_tdm_probe(struct platform_device *pdev)
195 {
196 struct device_node *node = pdev->dev.of_node;
197 const struct of_device_id *of_id;
198 struct rk3568_i2s_tdm_dev *i2s_tdm;
199 struct resource *res;
200 struct device *temp_i2s_dev;
201
202 int ret;
203 int val;
204 AUDIO_DEVICE_LOG_INFO("enter ");
205 temp_i2s_dev = &pdev->dev;
206 AUDIO_DEVICE_LOG_DEBUG("dmaDevice->name %s ", dev_name(temp_i2s_dev));
207 i2s_tdm = devm_kzalloc(&pdev->dev, sizeof(*i2s_tdm), GFP_KERNEL);
208 if (!i2s_tdm) {
209 return -ENOMEM;
210 }
211 i2s_tdm->dev = &pdev->dev;
212
213 of_id = of_match_device(rockchip_i2s_tdm_match, &pdev->dev);
214 if (!of_id || !of_id->data) {
215 return -EINVAL;
216 }
217
218 spin_lock_init(&i2s_tdm->lock);
219 i2s_tdm->soc_data = (const struct rk_i2s_soc_data *)of_id->data;
220
221 i2s_tdm->bclk_fs = 64; // default-freq div factor is 64
222 if (!of_property_read_u32(node, "rockchip,bclk-fs", &val)) {
223 if ((val >= 32) && (val % 2 == 0)) // min-freq div factor is 32, and it is an integer multiple of 2
224 i2s_tdm->bclk_fs = val;
225 }
226
227 i2s_tdm->clk_trcm = I2S_CKR_TRCM_TXRX;
228 if (!of_property_read_u32(node, "rockchip,clk-trcm", &val)) {
229 if (val >= 0 && val <= 2) { // clk-trcm factor should between 0 and 2
230 i2s_tdm->clk_trcm = val << I2S_CKR_TRCM_SHIFT;
231 }
232 }
233
234 i2s_tdm->tdm_fsync_half_frame =
235 of_property_read_bool(node, "rockchip,tdm-fsync-half-frame");
236
237 i2s_tdm->grf = syscon_regmap_lookup_by_phandle(node, "rockchip,grf");
238 if (IS_ERR(i2s_tdm->grf)) {
239 return PTR_ERR(i2s_tdm->grf);
240 }
241
242 i2s_tdm->tx_reset = devm_reset_control_get(&pdev->dev, "tx-m");
243 if (IS_ERR(i2s_tdm->tx_reset)) {
244 ret = PTR_ERR(i2s_tdm->tx_reset);
245 if (ret != -ENOENT) {
246 return ret;
247 }
248 }
249
250 i2s_tdm->rx_reset = devm_reset_control_get(&pdev->dev, "rx-m");
251 if (IS_ERR(i2s_tdm->rx_reset)) {
252 ret = PTR_ERR(i2s_tdm->rx_reset);
253 if (ret != -ENOENT) {
254 return ret;
255 }
256 }
257
258 i2s_tdm->hclk = devm_clk_get(&pdev->dev, "hclk");
259 if (IS_ERR(i2s_tdm->hclk)) {
260 return PTR_ERR(i2s_tdm->hclk);
261 }
262
263 ret = clk_prepare_enable(i2s_tdm->hclk);
264 if (ret) {
265 return ret;
266 }
267
268 i2s_tdm->mclk_tx = devm_clk_get(&pdev->dev, "mclk_tx");
269 if (IS_ERR(i2s_tdm->mclk_tx)) {
270 return PTR_ERR(i2s_tdm->mclk_tx);
271 }
272
273 i2s_tdm->mclk_rx = devm_clk_get(&pdev->dev, "mclk_rx");
274 if (IS_ERR(i2s_tdm->mclk_rx)) {
275 return PTR_ERR(i2s_tdm->mclk_rx);
276 }
277
278 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
279
280 i2s_tdm->regmap = devm_regmap_init_mmio(&pdev->dev, devm_ioremap_resource(&pdev->dev, res),
281 &rockchip_i2s_tdm_regmap_config);
282 if (IS_ERR(i2s_tdm->regmap)) {
283 return PTR_ERR(i2s_tdm->regmap);
284 }
285
286 atomic_set(&i2s_tdm->refcount, 0);
287 dev_set_drvdata(&pdev->dev, i2s_tdm);
288
289 ret = i2s_tdm_runtime_resume(i2s_tdm);
290 if (ret) {
291 return ret;
292 }
293
294 regmap_update_bits(i2s_tdm->regmap, I2S_DMACR, I2S_DMACR_TDL_MASK,
295 I2S_DMACR_TDL(16)); // Transmit Data Level MASK with 16bit
296 regmap_update_bits(i2s_tdm->regmap, I2S_DMACR, I2S_DMACR_RDL_MASK,
297 I2S_DMACR_RDL(16)); // Receive Data Level MASK with 16bit
298 regmap_update_bits(i2s_tdm->regmap, I2S_CKR,
299 I2S_CKR_TRCM_MASK, i2s_tdm->clk_trcm);
300 return 0;
301 }
302
rockchip_i2s_tdm_remove(struct platform_device * pdev)303 static int rockchip_i2s_tdm_remove(struct platform_device *pdev)
304 {
305 struct rk3568_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(&pdev->dev);
306
307 i2s_tdm_runtime_suspend(i2s_tdm);
308
309 if (!IS_ERR(i2s_tdm->mclk_tx))
310 clk_prepare_enable(i2s_tdm->mclk_tx);
311 if (!IS_ERR(i2s_tdm->mclk_rx))
312 clk_prepare_enable(i2s_tdm->mclk_rx);
313 if (!IS_ERR(i2s_tdm->hclk))
314 clk_disable_unprepare(i2s_tdm->hclk);
315
316 return 0;
317 }
318
319 static struct platform_driver rockchip_i2s_tdm_driver = {
320 .probe = rockchip_i2s_tdm_probe,
321 .remove = rockchip_i2s_tdm_remove,
322 .driver = {
323 .name = DRV_NAME,
324 .of_match_table = of_match_ptr(rockchip_i2s_tdm_match),
325 .pm = NULL,
326 },
327 };
328 module_platform_driver(rockchip_i2s_tdm_driver);
329