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