• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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