blob: 66e035e60aa1007953e38dea4d7a8c64c0b090ce [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Support for asr auxadc driver
4 *
5 * Copyright 2023 ASR Microelectronics (Shanghai) Co., Ltd.
6 *
7 */
8#include <linux/module.h>
9#include <linux/platform_device.h>
10#include <linux/clk.h>
11#include <linux/delay.h>
12#include <linux/err.h>
13#include <linux/io.h>
14#include <linux/clk.h>
15#include <linux/of.h>
16#include <linux/uaccess.h>
17#include <linux/mfd/88pm80x.h>
18#include <linux/cputype.h>
19#include <soc/asr/addr-map.h>
20
21#define APBS_REG_12 (0x12c)
22#define APBS_REG_3 (0x108)
23
24#define AUX_REG_BASE_OFFSET (0x80)
25#define AUX_REG_DATA (0x80 - AUX_REG_BASE_OFFSET)
26#define AUX_INT_CLR_REG (0xF0 - AUX_REG_BASE_OFFSET)
27#define AUX_INT_STS_REG (0xA0 - AUX_REG_BASE_OFFSET)
28
29#define OLD_AUXADC_REG_CTRL (0x0)
30#define OLD_AUXADC_REG_CFG (0x4)
31#define OLD_AUXADC_REG_INT_STATUS (0x8)
32#define OLD_AUXADC_REG_ADCTIME_CTRL (0xC)
33#define OLD_AUXADC_REG_DATA (0x10)
34#define OLD_AUXADC_REG_CTRL2 (0x70)
35
36
37struct asr_auxadc_fusedata {
38 u16 auxadc_gain_offset;
39 u16 auxadc_gain_error;
40 u16 fuse_bits;
41 u16 fuse_mask_all;
42 u16 fuse_mask_data;
43};
44
45struct asr_auxadc {
46 struct device *dev;
47 struct clk *clk;
48 void __iomem *base;
49 void __iomem *adc_ctrl_reg;
50 struct asr_auxadc_fusedata fuse_data;
51};
52DEFINE_MUTEX(asr_auxadc_lock);
53static struct asr_auxadc *g_auxadc;
54extern int extern_get_auxadc_fusedata(u16 *gain_offset, u16 *gain_error);
55
56static int asr_auxadc_fusedata_init(struct asr_auxadc *asr_auxadc)
57{
58 extern_get_auxadc_fusedata(&asr_auxadc->fuse_data.auxadc_gain_offset,
59 &asr_auxadc->fuse_data.auxadc_gain_error);
60 if (cpu_is_asr1828() || cpu_is_asr1901() || cpu_is_asr1906()) {
61 asr_auxadc->fuse_data.fuse_bits = 12;
62 asr_auxadc->fuse_data.fuse_mask_data = 0x7ff;
63 asr_auxadc->fuse_data.fuse_mask_all = 0xfff;
64 } else {
65 asr_auxadc->fuse_data.fuse_bits = 5;
66 asr_auxadc->fuse_data.fuse_mask_data = 0xf;
67 asr_auxadc->fuse_data.fuse_mask_all = 0x1f;
68 }
69
70 pr_info("auxadc fusedata: %03x %03x\n",
71 asr_auxadc->fuse_data.auxadc_gain_offset,
72 asr_auxadc->fuse_data.auxadc_gain_error);
73
74 return 0;
75}
76
77static int asr_auxadc_base_init(struct asr_auxadc *asr_auxadc)
78{
79 u32 value;
80 void __iomem *apbs_base = regs_addr_get_va(REGS_ADDR_APBS);
81
82 if (cpu_is_asr1828() || cpu_is_asr1903())
83 g_auxadc->adc_ctrl_reg = apbs_base + APBS_REG_3;
84 else
85 g_auxadc->adc_ctrl_reg = apbs_base + APBS_REG_12;
86
87 if (cpu_is_asr1806()) {
88 value = readl(g_auxadc->adc_ctrl_reg);
89 value &= ~(0xffff0000);
90 value |= (0x1060 << 16); /* clk div4 and 2clk sample delay */
91 writel(value, g_auxadc->adc_ctrl_reg);
92 } else if (cpu_is_asr1903() || cpu_is_asr1828()) {
93 value = readl(g_auxadc->adc_ctrl_reg);
94 value |= (0x1 << 22);
95 if (cpu_is_asr1828())
96 value |= (0x3 << 24);
97 writel(value, g_auxadc->adc_ctrl_reg);
98 } else if (cpu_is_asr1901() || cpu_is_asr1906()) {
99 value = readl(asr_auxadc->base + OLD_AUXADC_REG_CFG);
100 value &= ~(0x1 << 19);
101 writel(value, asr_auxadc->base + OLD_AUXADC_REG_CFG);
102 }
103
104 return 0;
105}
106
107static ssize_t auxadc_debug_read(struct file *file, char __user *userbuf,
108 size_t count, loff_t *ppos)
109{
110 unsigned int len = 0;
111 char *buf;
112 ssize_t ret;
113
114 if (*ppos)
115 return 0;
116
117 buf = kzalloc(128, GFP_KERNEL);
118 if (!buf) {
119 pr_err("Cannot allocate buffer!\n");
120 return -ENOMEM;
121 }
122
123 len += sprintf(buf + len, "adc1: %04d\n", extern_get_auxadc_volt(ASR_AUXADC1));
124 len += sprintf(buf + len, "adc2: %04d\n", extern_get_auxadc_volt(ASR_AUXADC2));
125 len += sprintf(buf + len, "adc3: %04d\n", extern_get_auxadc_volt(ASR_AUXADC3));
126 len += sprintf(buf + len, "adc4: %04d\n", extern_get_auxadc_volt(ASR_AUXADC4));
127 len += sprintf(buf + len, "adc5: %04d\n", extern_get_auxadc_volt(ASR_AUXADC5));
128
129 ret = simple_read_from_buffer(userbuf, count, ppos, buf, len);
130 kfree(buf);
131 return ret;
132}
133
134static const struct file_operations auxadc_debug_ops = {
135 .owner = THIS_MODULE,
136 .open = simple_open,
137 .read = auxadc_debug_read,
138 .write = NULL,
139};
140
141static int asr_auxadc_debugfs_init(struct asr_auxadc *asr_auxadc)
142{
143 struct dentry *auxadc_entry;
144
145 auxadc_entry = debugfs_create_file("auxadc", S_IRUGO | S_IFREG,
146 NULL, (void *)asr_auxadc, &auxadc_debug_ops);
147
148 if (auxadc_entry == NULL) {
149 dev_err(g_auxadc->dev, "create auxadc debugfs error!\n");
150 return -ENOENT;
151 }
152
153 return 0;
154}
155
156int __extern_get_old_auxadc_volt(int adc_id)
157{
158 u32 value;
159 u8 adc_channel;
160 int timeout, out_value, raw_value = 0;
161 void __iomem *base = g_auxadc->base;
162 int nr_avg = 0, sample_index = 0, nr_total_samples = (16 + 2);
163 int raw_min = 0xfffffff, raw_max = 0;
164
165 adc_channel = (adc_id - ASR_AUXADC1) & 0xf;
166
167 might_sleep();
168 mutex_lock(&asr_auxadc_lock);
169 /* step 1. powerup adc */
170 value = readl(base + OLD_AUXADC_REG_CTRL2);
171 value |= (0x1 << 6);
172 writel(value, base + OLD_AUXADC_REG_CTRL2);
173 udelay(20);
174
175 /* step 2. clear CTRL and INT STATUS */
176 while (sample_index < nr_total_samples) {
177 writel(0x0, base + OLD_AUXADC_REG_CTRL);
178 writel(0x3ff, base + OLD_AUXADC_REG_INT_STATUS);
179
180 usleep_range(50,50);
181 /* step 3. start SOC */
182 value = readl(base + OLD_AUXADC_REG_CTRL);
183 value |= (0x1 | (0x1 << (adc_channel + 1)) | (0x1 << (adc_channel + 16)));
184 writel(value, base + OLD_AUXADC_REG_CTRL);
185
186 /* step 4. polling int status */
187 timeout = 10000;
188 while ((readl(base + OLD_AUXADC_REG_INT_STATUS) == 0) && timeout--)
189 ndelay(100);
190
191 if (timeout <= 0) {
192 dev_err(g_auxadc->dev, "aux adc%d timeout: 0x%x 0x%x\n",
193 adc_channel, readl(base + OLD_AUXADC_REG_CTRL), readl(base + OLD_AUXADC_REG_CFG));
194 out_value = -EINVAL;
195 goto err_out;
196 }
197
198 if (sample_index >= 2) {
199 out_value = readl(base + OLD_AUXADC_REG_DATA + (adc_channel << 2)) & 0xFFF;
200 if (raw_min > out_value)
201 raw_min = out_value;
202 if (raw_max < out_value)
203 raw_max = out_value;
204 raw_value += out_value;
205 nr_avg++;
206 }
207 sample_index++;
208 }
209
210 raw_value -= (raw_max + raw_min);
211 raw_value = raw_value / (nr_avg - 2);
212
213 pr_debug("timeout: %d, raw_value: %x 0x%x\n", timeout, raw_value, readl(g_auxadc->base + OLD_AUXADC_REG_INT_STATUS));
214
215 if ((0x1 << 11) & g_auxadc->fuse_data.auxadc_gain_error)
216 raw_value = raw_value * (16384 - (1 * ((0x1 << 12) - ((g_auxadc->fuse_data.auxadc_gain_error & 0xfff)))));
217 else
218 raw_value = raw_value * (16384 + (1 * (g_auxadc->fuse_data.auxadc_gain_error & 0x7ff)));
219
220 raw_value = ((raw_value * 24) >> 12) * 50;
221
222 if ((0x1 << 11) & g_auxadc->fuse_data.auxadc_gain_offset)
223 raw_value = raw_value - (328 * ((0x1 << 12) - (g_auxadc->fuse_data.auxadc_gain_offset & 0xfff)));
224 else
225 raw_value = raw_value + (328 * (g_auxadc->fuse_data.auxadc_gain_offset & 0x7ff));
226
227 if (raw_value < 0) {
228 pr_info("aux neg: %d\n", raw_value);
229 raw_value = 0;
230 }
231 out_value = (raw_value >> 14);
232
233err_out:
234 writel(0x0, base + OLD_AUXADC_REG_CTRL);
235 writel(0x3ff, base + OLD_AUXADC_REG_INT_STATUS);
236 /* power off adc */
237 value = readl(base + OLD_AUXADC_REG_CTRL2);
238 value &= ~(0x1 << 6);
239 writel(value, base + OLD_AUXADC_REG_CTRL2);
240 mutex_unlock(&asr_auxadc_lock);
241
242 return out_value;
243}
244
245int asr1828_calc_adc_val(int raw_value)
246{
247 int div_value;
248
249 if ((0x1 << (g_auxadc->fuse_data.fuse_bits - 1)) & g_auxadc->fuse_data.auxadc_gain_offset)
250 raw_value = raw_value + ((0x1 << g_auxadc->fuse_data.fuse_bits) - (g_auxadc->fuse_data.auxadc_gain_offset & g_auxadc->fuse_data.fuse_mask_all));
251 else
252 raw_value = raw_value - ((g_auxadc->fuse_data.auxadc_gain_offset & g_auxadc->fuse_data.fuse_mask_data));
253
254 if ((0x1 << (g_auxadc->fuse_data.fuse_bits - 1)) & g_auxadc->fuse_data.auxadc_gain_error)
255 div_value = (4800 + (((0x1 << g_auxadc->fuse_data.fuse_bits) - ((g_auxadc->fuse_data.auxadc_gain_error & g_auxadc->fuse_data.fuse_mask_all)))));
256 else
257 div_value = (4800 - ((g_auxadc->fuse_data.auxadc_gain_error & g_auxadc->fuse_data.fuse_mask_data)));
258
259 raw_value = (raw_value * 4800 * 60) >> 12;
260
261 raw_value = (raw_value * 20) / div_value;
262
263 if (raw_value < 0) {
264 pr_info("aux neg: %d\n", raw_value);
265 raw_value = 0;
266 }
267
268 return raw_value;
269}
270
271int __extern_get_new_auxadc_volt(int adc_id)
272{
273 u32 value;
274 u8 adc_channel;
275 int timeout, out_value, raw_value = 0;
276 int nr_avg = 0, sample_index = 0, nr_total_samples = (3 + 16);
277 int raw_min = 0xfffffff, raw_max = 0;
278
279 might_sleep();
280 mutex_lock(&asr_auxadc_lock);
281 /* step 1. powerup adc*/
282 value = readl(g_auxadc->adc_ctrl_reg);
283 if (value == 0)
284 BUG();
285 value |= (0x1 << 8);
286 writel(value, g_auxadc->adc_ctrl_reg);
287
288 if (cpu_is_asr1828())
289 udelay(20);
290
291 adc_channel = (adc_id - ASR_AUXADC1 + 1) & 0x1f;
292
293 while (sample_index < nr_total_samples) {
294 /*
295 * step 2. set adc channel, clr soc and continous mode
296 * clear INT STATUS
297 */
298 value = readl(g_auxadc->adc_ctrl_reg);
299 if (value == 0)
300 BUG();
301 value &= ~(0x7F << 9);
302 value |= (adc_channel << 11);
303 writel(value, g_auxadc->adc_ctrl_reg);
304
305 usleep_range(50,50);
306 if (!cpu_is_asr1828())
307 writel(0x1, g_auxadc->base + AUX_INT_CLR_REG);
308
309 /* clear the data reg */
310 if (cpu_is_asr1828())
311 writel(0x0, g_auxadc->base + AUX_REG_DATA + (0 << 2));
312
313 /* step 3. set soc */
314 value = readl(g_auxadc->adc_ctrl_reg);
315 if (value == 0)
316 BUG();
317 value |= (0x1 << 9);
318 writel(value, g_auxadc->adc_ctrl_reg);
319
320 if (cpu_is_asr1828()) {
321 /* step 4. polling adc value */
322 timeout = 200;
323 while (((readl(g_auxadc->base + AUX_REG_DATA + (0 << 2)) & 0xFFF0000) == 0) && (timeout--))
324 ndelay(100);
325 if (timeout <= 0) {
326 printk(KERN_DEBUG "aux adc%d timeout\n", adc_channel);
327 }
328 } else {
329 /* step 4. polling int status */
330 timeout = 10000;
331 while ((readl(g_auxadc->base + AUX_INT_STS_REG) == 0) && timeout--)
332 ndelay(100);
333
334 if (timeout <= 0) {
335 dev_err(g_auxadc->dev, "aux adc%d timeout: 0x%x\n",
336 adc_channel, readl(g_auxadc->adc_ctrl_reg));
337 out_value = -EINVAL;
338 goto err_out;
339 }
340 }
341
342 if (sample_index >= 3) {
343 if (cpu_is_asr1828())
344 out_value = (readl(g_auxadc->base + AUX_REG_DATA + (0 << 2)) >> 16) & 0xFFF;
345 else
346 out_value = readl(g_auxadc->base + AUX_REG_DATA + (0 << 2)) & 0xFFF;
347 if (raw_min > out_value)
348 raw_min = out_value;
349 if (raw_max < out_value)
350 raw_max = out_value;
351 raw_value += out_value;
352 nr_avg++;
353 }
354 sample_index++;
355 }
356 raw_value -= (raw_max + raw_min);
357 raw_value = raw_value / (nr_avg - 2);
358
359 pr_debug("timeout: %d, raw_value: %x 0x%x\n", timeout, raw_value, readl(g_auxadc->base + AUX_INT_STS_REG));
360
361 if (cpu_is_asr1828()) {
362 out_value = asr1828_calc_adc_val(raw_value);
363 goto err_out;
364 }
365
366 if ((0x1 << (g_auxadc->fuse_data.fuse_bits - 1)) & g_auxadc->fuse_data.auxadc_gain_error)
367 raw_value = raw_value * (6000 - (10 * ((0x1 << g_auxadc->fuse_data.fuse_bits) - ((g_auxadc->fuse_data.auxadc_gain_error & g_auxadc->fuse_data.fuse_mask_all)))));
368 else
369 raw_value = raw_value * (6000 + (10 * (g_auxadc->fuse_data.auxadc_gain_error & g_auxadc->fuse_data.fuse_mask_data)));
370
371 if ((0x1 << (g_auxadc->fuse_data.fuse_bits - 1)) & g_auxadc->fuse_data.auxadc_gain_offset)
372 raw_value = raw_value - (12000 * ((0x1 << g_auxadc->fuse_data.fuse_bits) - (g_auxadc->fuse_data.auxadc_gain_offset & g_auxadc->fuse_data.fuse_mask_all)));
373 else
374 raw_value = raw_value + (12000 * (g_auxadc->fuse_data.auxadc_gain_offset & g_auxadc->fuse_data.fuse_mask_data));
375
376 if (raw_value < 0) {
377 pr_info("aux neg: %d\n", raw_value);
378 raw_value = 0;
379 }
380 out_value = (raw_value >> 12) / 5;
381
382err_out:
383 if (!cpu_is_asr1828())
384 writel(0x1, g_auxadc->base + AUX_INT_CLR_REG);
385 /* power off adc */
386 value = readl(g_auxadc->adc_ctrl_reg);
387 if (value == 0)
388 BUG();
389 value &= ~(0xff << 8);
390 writel(value, g_auxadc->adc_ctrl_reg);
391 mutex_unlock(&asr_auxadc_lock);
392
393 return out_value;
394}
395
396int extern_get_auxadc_volt(int adc_id)
397{
398 if (cpu_is_asr1806() || cpu_is_asr1903() || cpu_is_asr1828())
399 return __extern_get_new_auxadc_volt(adc_id);
400 else if (cpu_is_asr1901() || cpu_is_asr1906())
401 return __extern_get_old_auxadc_volt(adc_id);
402 else {
403 pr_err("auxadc not supported\n");
404 return -EINVAL;
405 }
406}
407
408static int asr_auxadc_probe(struct platform_device *pdev)
409{
410 struct asr_auxadc *asr_auxadc;
411 struct device *dev = &pdev->dev;
412 struct resource *res;
413 int ret = 0;
414
415 asr_auxadc = devm_kzalloc(dev, sizeof(*asr_auxadc), GFP_KERNEL);
416 if (!asr_auxadc)
417 return -ENOMEM;
418
419 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
420 asr_auxadc->base = ioremap(res->start, resource_size(res));
421 if (IS_ERR(asr_auxadc->base)) {
422 dev_err(&pdev->dev, "asr_auxadc base error\n");
423 return PTR_ERR(asr_auxadc->base);
424 }
425 asr_auxadc->clk = devm_clk_get(&pdev->dev, NULL);
426 if (IS_ERR(asr_auxadc->clk)) {
427 dev_err(&pdev->dev, "asr_auxadc clk error\n");
428 return PTR_ERR(asr_auxadc->clk);
429 }
430 clk_prepare_enable(asr_auxadc->clk);
431 asr_auxadc->dev = &pdev->dev;
432 g_auxadc = asr_auxadc;
433 ret = asr_auxadc_fusedata_init(asr_auxadc);
434 asr_auxadc_base_init(asr_auxadc);
435 asr_auxadc_debugfs_init(asr_auxadc);
436 platform_set_drvdata(pdev, asr_auxadc);
437
438 dev_info(&pdev->dev, "auxadc done\n");
439
440 return ret;
441}
442
443static int asr_auxadc_remove(struct platform_device *pdev)
444{
445 struct asr_auxadc *asr_auxadc = platform_get_drvdata(pdev);
446 platform_set_drvdata(pdev, NULL);
447 kfree(asr_auxadc);
448
449 return 0;
450}
451
452#ifdef CONFIG_OF
453static const struct of_device_id asr_auxadc_id_table[] = {
454 { .compatible = "asr,auxadc" },
455 {}
456};
457MODULE_DEVICE_TABLE(of, asr_auxadc_id_table);
458#endif
459
460static struct platform_driver asr_auxadc_driver = {
461 .probe = asr_auxadc_probe,
462 .remove = asr_auxadc_remove,
463 .driver = {
464 .name = "asr-auxadc",
465 .owner = THIS_MODULE,
466#ifdef CONFIG_OF
467 .of_match_table = of_match_ptr(asr_auxadc_id_table),
468#endif
469 },
470};
471
472static int __init asr_auxadc_init(void)
473{
474 return platform_driver_register(&asr_auxadc_driver);
475}
476
477static void __exit asr_auxadc_exit(void)
478{
479 platform_driver_unregister(&asr_auxadc_driver);
480}
481
482arch_initcall(asr_auxadc_init);
483module_exit(asr_auxadc_exit);
484
485MODULE_DESCRIPTION("ASR AUXADC DRIVER");
486MODULE_LICENSE("GPL");
487MODULE_ALIAS("platform:asr-auxadc");