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_host.h"
24 #include "audio_control.h"
25 #include "audio_dai_if.h"
26 #include "audio_dai_base.h"
27 #include "audio_driver_log.h"
28 #include "audio_stream_dispatch.h"
29 #include "osal_io.h"
30 #include "rk3588_audio_common.h"
31 #include "audio_platform_base.h"
32 #include "rk3588_dai_ops.h"
33 #include "rk3588_dai_linux.h"
34
35 #define HDF_LOG_TAG rk3588_dai_linux
36
37 #define DRV_NAME "rockchip-i2s-tdm"
38
rockchip_i2s_tdm_wr_reg(struct device * dev,unsigned int reg)39 static bool rockchip_i2s_tdm_wr_reg(struct device *dev, unsigned int reg)
40 {
41 switch (reg) {
42 case I2S_TXCR:
43 case I2S_RXCR:
44 case I2S_CKR:
45 case I2S_DMACR:
46 case I2S_INTCR:
47 case I2S_XFER:
48 case I2S_CLR:
49 case I2S_TXDR:
50 case I2S_TDM_TXCR:
51 case I2S_TDM_RXCR:
52 case I2S_CLKDIV:
53 return true;
54 default:
55 return false;
56 }
57 }
58
rockchip_i2s_tdm_rd_reg(struct device * dev,unsigned int reg)59 static bool rockchip_i2s_tdm_rd_reg(struct device *dev, unsigned int reg)
60 {
61 switch (reg) {
62 case I2S_TXCR:
63 case I2S_RXCR:
64 case I2S_CKR:
65 case I2S_DMACR:
66 case I2S_INTCR:
67 case I2S_XFER:
68 case I2S_CLR:
69 case I2S_TXDR:
70 case I2S_RXDR:
71 case I2S_TXFIFOLR:
72 case I2S_INTSR:
73 case I2S_RXFIFOLR:
74 case I2S_TDM_TXCR:
75 case I2S_TDM_RXCR:
76 case I2S_CLKDIV:
77 return true;
78 default:
79 return false;
80 }
81 }
82
rockchip_i2s_tdm_volatile_reg(struct device * dev,unsigned int reg)83 static bool rockchip_i2s_tdm_volatile_reg(struct device *dev, unsigned int reg)
84 {
85 switch (reg) {
86 case I2S_TXFIFOLR:
87 case I2S_INTSR:
88 case I2S_CLR:
89 case I2S_TXDR:
90 case I2S_RXDR:
91 case I2S_RXFIFOLR:
92 return true;
93 default:
94 return false;
95 }
96 }
97
rockchip_i2s_tdm_precious_reg(struct device * dev,unsigned int reg)98 static bool rockchip_i2s_tdm_precious_reg(struct device *dev, unsigned int reg)
99 {
100 switch (reg) {
101 case I2S_RXDR:
102 return true;
103 default:
104 return false;
105 }
106 }
107
108 static const struct reg_default rockchip_i2s_tdm_reg_defaults[] = {
109 {0x00, 0x7200000f},
110 {0x04, 0x01c8000f},
111 {0x08, 0x00001f1f},
112 {0x10, 0x001f0000},
113 {0x14, 0x01f00000},
114 {0x30, 0x00003eff},
115 {0x34, 0x00003eff},
116 {0x38, 0x00000707},
117 };
118
119 static const struct regmap_config rockchip_i2s_tdm_regmap_config = {
120 .reg_bits = 32,
121 .reg_stride = 4,
122 .val_bits = 32,
123 .max_register = I2S_CLKDIV,
124 .reg_defaults = rockchip_i2s_tdm_reg_defaults,
125 .num_reg_defaults = ARRAY_SIZE(rockchip_i2s_tdm_reg_defaults),
126 .writeable_reg = rockchip_i2s_tdm_wr_reg,
127 .readable_reg = rockchip_i2s_tdm_rd_reg,
128 .volatile_reg = rockchip_i2s_tdm_volatile_reg,
129 .precious_reg = rockchip_i2s_tdm_precious_reg,
130 .cache_type = REGCACHE_FLAT,
131 };
132
133 static const struct of_device_id rockchip_i2s_tdm_match[] = {
134 { .compatible = "rockchip,rk3588-i2s-tdm", },
135 {},
136 };
137
138 #if 0
139 static int of_i2s_resetid_get(struct device_node *node,
140 const char *id)
141 {
142 struct of_phandle_args args;
143 int index = 0;
144 int ret;
145
146 if (id)
147 index = of_property_match_string(node,
148 "reset-names", id);
149 ret = of_parse_phandle_with_args(node, "resets", "#reset-cells",
150 index, &args);
151 if (ret)
152 return ret;
153
154 return args.args[0];
155 }
156 #endif
157
i2s_tdm_runtime_suspend(struct rk3588_i2s_tdm_dev * i2s_tdm)158 static int i2s_tdm_runtime_suspend(struct rk3588_i2s_tdm_dev *i2s_tdm)
159 {
160 regcache_cache_only(i2s_tdm->regmap, true);
161 if (!IS_ERR(i2s_tdm->mclk_tx))
162 clk_disable_unprepare(i2s_tdm->mclk_tx);
163 if (!IS_ERR(i2s_tdm->mclk_rx))
164 clk_disable_unprepare(i2s_tdm->mclk_rx);
165 return 0;
166 }
rockchip_i2s_tdm_probe(struct platform_device * pdev)167 static int rockchip_i2s_tdm_probe(struct platform_device *pdev)
168 {
169 struct device_node *node = pdev->dev.of_node;
170 //struct device_node *cru_node;
171 const struct of_device_id *of_id;
172 struct rk3588_i2s_tdm_dev *i2s_tdm;
173 //struct snd_soc_dai_driver *soc_dai;
174 struct resource *res;
175 void __iomem *regs;
176 //bool sync;
177 int ret;
178 int val;
179 struct device *temp_i2s_dev;
180
181
182 temp_i2s_dev = &pdev->dev;
183 if (strcmp(dev_name(temp_i2s_dev), "fe470000.i2s") != 0) {
184 AUDIO_DRIVER_LOG_INFO("failed dmaDevice->name %s ", dev_name(temp_i2s_dev));
185 return 0;
186 }
187 AUDIO_DEVICE_LOG_DEBUG("match dmaDevice->name %s ", dev_name(temp_i2s_dev));
188 i2s_tdm = devm_kzalloc(&pdev->dev, sizeof(*i2s_tdm), GFP_KERNEL);
189 if (!i2s_tdm)
190 return -ENOMEM;
191
192 i2s_tdm->dev = &pdev->dev;
193 of_id = of_match_device(rockchip_i2s_tdm_match, &pdev->dev);
194 if (!of_id)
195 return -EINVAL;
196
197 spin_lock_init(&i2s_tdm->lock);
198 i2s_tdm->soc_data = (const struct rk_i2s_soc_data *)of_id->data;
199
200 i2s_tdm->bclk_fs = 64;
201 if (!of_property_read_u32(node, "rockchip,bclk-fs", &val)) {
202 if ((val >= 32) && (val % 2 == 0))
203 i2s_tdm->bclk_fs = val;
204 }
205
206 i2s_tdm->clk_trcm = I2S_CKR_TRCM_TXRX;
207 if (!of_property_read_u32(node, "rockchip,clk-trcm", &val)) {
208 if (val >= 0 && val <= 2) {
209 i2s_tdm->clk_trcm = val << I2S_CKR_TRCM_SHIFT;
210 // if (i2s_tdm->clk_trcm)
211 // soc_dai->symmetric_rates = 1;
212 }
213 }
214
215 i2s_tdm->tdm_fsync_half_frame =
216 of_property_read_bool(node, "rockchip,tdm-fsync-half-frame");
217
218
219 i2s_tdm->grf = syscon_regmap_lookup_by_phandle(node, "rockchip,grf");
220
221 // sync = of_device_is_compatible(node, "rockchip,px30-i2s-tdm") ||
222 // of_device_is_compatible(node, "rockchip,rk1808-i2s-tdm") ||
223 // of_device_is_compatible(node, "rockchip,rk3308-i2s-tdm");
224
225 // if (i2s_tdm->clk_trcm && sync) {
226 // cru_node = of_parse_phandle(node, "rockchip,cru", 0);
227 // i2s_tdm->cru_base = of_iomap(cru_node, 0);
228 // if (!i2s_tdm->cru_base)
229 // return -ENOENT;
230
231 // i2s_tdm->tx_reset_id = of_i2s_resetid_get(node, "tx-m");
232 // i2s_tdm->rx_reset_id = of_i2s_resetid_get(node, "rx-m");
233 // }
234
235 i2s_tdm->tx_reset = devm_reset_control_get(&pdev->dev, "tx-m");
236 if (IS_ERR(i2s_tdm->tx_reset)) {
237 ret = PTR_ERR(i2s_tdm->tx_reset);
238 if (ret != -ENOENT)
239 return ret;
240 }
241
242 i2s_tdm->rx_reset = devm_reset_control_get(&pdev->dev, "rx-m");
243 if (IS_ERR(i2s_tdm->rx_reset)) {
244 ret = PTR_ERR(i2s_tdm->rx_reset);
245 if (ret != -ENOENT)
246 return ret;
247 }
248
249 i2s_tdm->hclk = devm_clk_get(&pdev->dev, "hclk");
250 if (IS_ERR(i2s_tdm->hclk))
251 return PTR_ERR(i2s_tdm->hclk);
252
253 ret = clk_prepare_enable(i2s_tdm->hclk);
254 if (ret)
255 return ret;
256
257 i2s_tdm->mclk_tx = devm_clk_get(&pdev->dev, "mclk_tx");
258 if (IS_ERR(i2s_tdm->mclk_tx))
259 return PTR_ERR(i2s_tdm->mclk_tx);
260
261 i2s_tdm->mclk_rx = devm_clk_get(&pdev->dev, "mclk_rx");
262 if (IS_ERR(i2s_tdm->mclk_rx))
263 return PTR_ERR(i2s_tdm->mclk_rx);
264
265 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
266 regs = devm_ioremap_resource(&pdev->dev, res);
267 if (IS_ERR(regs))
268 return PTR_ERR(regs);
269
270 i2s_tdm->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
271 &rockchip_i2s_tdm_regmap_config);
272 if (IS_ERR(i2s_tdm->regmap))
273 return PTR_ERR(i2s_tdm->regmap);
274
275 atomic_set(&i2s_tdm->refcount, 0);
276 dev_set_drvdata(&pdev->dev, i2s_tdm);
277
278 regmap_update_bits(i2s_tdm->regmap, I2S_DMACR, I2S_DMACR_TDL_MASK,
279 I2S_DMACR_TDL(16));
280 regmap_update_bits(i2s_tdm->regmap, I2S_DMACR, I2S_DMACR_RDL_MASK,
281 I2S_DMACR_RDL(16));
282 regmap_update_bits(i2s_tdm->regmap, I2S_CKR,
283 I2S_CKR_TRCM_MASK, i2s_tdm->clk_trcm);
284
285 return 0;
286 }
287
rockchip_i2s_tdm_remove(struct platform_device * pdev)288 static int rockchip_i2s_tdm_remove(struct platform_device *pdev)
289 {
290 struct rk3588_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(&pdev->dev);
291
292 i2s_tdm_runtime_suspend(i2s_tdm);
293
294 if (!IS_ERR(i2s_tdm->mclk_tx))
295 clk_prepare_enable(i2s_tdm->mclk_tx);
296 if (!IS_ERR(i2s_tdm->mclk_rx))
297 clk_prepare_enable(i2s_tdm->mclk_rx);
298 if (!IS_ERR(i2s_tdm->hclk))
299 clk_disable_unprepare(i2s_tdm->hclk);
300
301 return 0;
302 }
303
304
305
306 static struct platform_driver rockchip_i2s_tdm_driver = {
307 .probe = rockchip_i2s_tdm_probe,
308 .remove = rockchip_i2s_tdm_remove,
309 .driver = {
310 .name = DRV_NAME,
311 .of_match_table = of_match_ptr(rockchip_i2s_tdm_match),
312 .pm = NULL,
313 },
314 };
315 module_platform_driver(rockchip_i2s_tdm_driver);