• 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_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);