1 /*
2 * Copyright (C) 2021 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include "hi_adc.h"
20 #include "hi_osal.h"
21 #include "hi_adc_hal.h"
22
23 #ifndef NULL
24 #define NULL ((void *)0)
25 #endif
26
27 #define OSDRV_MODULE_VERSION_STRING "HISI_LSADC"
28
29 #define lsadc_print(fmt, ...) osal_printk("Func:%s, Line:%d, "fmt"\n", __FUNCTION__, __LINE__, ##__VA_ARGS__)
30
31 #define lsadc_addr_offset(x) (LSADC_BASE_ADDR + (x))
32
33 #define HISI_LSADC_CONFIG 0x00
34 #define HISI_LSADC_GLITCH 0x04
35 #define HISI_LSADC_TIMESCAN 0x08
36 #define HISI_LSADC_INTEN 0x10
37 #define HISI_LSADC_INTSTATUS 0x14
38 #define HISI_LSADC_INTCLR 0x18
39 #define HISI_LSADC_START 0x1C
40 #define HISI_LSADC_STOP 0x20
41 #define HISI_LSADC_ACTBIT 0x24
42 #define HISI_LSADC_CHNDATA 0x2C
43
44 volatile void *g_lsadc_reg_base = NULL;
45 unsigned int g_lsadc_irq = LSADC_IRQ_ID;
46 static osal_spinlock_t g_lsadc_lock;
47 static int g_need_iounmap = 0;
48
49 #define lsadc_vir_addr(x) ((uintptr_t)g_lsadc_reg_base + (x) - LSADC_BASE_ADDR)
50 #define lsadc_writel(v, x) osal_writel(v, lsadc_vir_addr(lsadc_addr_offset(x)))
51 #define lsadc_readl(x) osal_readl(lsadc_vir_addr(lsadc_addr_offset(x)))
52
lsadc_reg_write(unsigned long value,unsigned long mask,unsigned long addr)53 static inline void lsadc_reg_write(unsigned long value, unsigned long mask, unsigned long addr)
54 {
55 unsigned long t;
56
57 t = lsadc_readl(addr);
58 t &= ~mask;
59 t |= value & mask;
60 lsadc_writel(t, addr);
61 }
62
write_reg32(unsigned int value,unsigned int mask,const void * addr)63 static void write_reg32(unsigned int value, unsigned int mask, const void *addr)
64 {
65 unsigned int t;
66
67 t = osal_readl((void *)addr);
68 t &= ~mask;
69 t |= value & mask;
70 osal_writel(t, (void *)addr);
71 }
72
hilsadc_open(void * private_data)73 static int hilsadc_open(void *private_data)
74 {
75 hi_adc_unused(private_data);
76
77 lsadc_reg_write(0 << 15, 1 << 15, HISI_LSADC_CONFIG); /* 15: unreset analog circuit [15] */
78 return 0;
79 }
80
hilsadc_release(void * private_data)81 static int hilsadc_release(void *private_data)
82 {
83 hi_adc_unused(private_data);
84
85 lsadc_reg_write(1 << 15, 1 << 15, HISI_LSADC_CONFIG); /* 15: reset analog circuit [15] */
86 return 0;
87 }
88
89 /*
90 * 0: single scanning mode
91 * 1: continuous scanning mode
92 * The filter glitch is already enable, only the continuous mode has a filter glitch, and the single mode is invalid.
93 */
lsadc_model_select(int value)94 static int lsadc_model_select(int value)
95 {
96 unsigned int val;
97 unsigned long flag;
98
99 val = (unsigned int)value;
100 if ((val != 0) && (val != 1)) {
101 lsadc_print("error value:%x\n", val);
102 return -1;
103 }
104
105 osal_spin_lock_irqsave(&g_lsadc_lock, &flag);
106 lsadc_reg_write(val << 13, 1 << 13, HISI_LSADC_CONFIG); /* 13: [13] bit */
107 if (val == 1) {
108 lsadc_reg_write(0xc << 20, 0xc << 20, HISI_LSADC_CONFIG); /* 20, 0xc: [23:20] bits */
109
110 lsadc_writel(GLITCH, HISI_LSADC_GLITCH); /* glitch_sample, must > 0 */
111 lsadc_writel(TIME_SCAN, HISI_LSADC_TIMESCAN); /* time_scan, must > 20 */
112
113 lsadc_reg_write(0 << 17, 0 << 17, HISI_LSADC_CONFIG); /* 17: [17] bit set glitch not bypass */
114 } else {
115 lsadc_reg_write(1 << 17, 1 << 17, HISI_LSADC_CONFIG); /* 17: [17] bit set glitch bypass */
116 }
117 osal_spin_unlock_irqrestore(&g_lsadc_lock, &flag);
118
119 return 0;
120 }
121
lsadc_chn_valid(int chn,int enable)122 static int lsadc_chn_valid(int chn, int enable)
123 {
124 unsigned long flag;
125 unsigned long value;
126
127 osal_spin_lock_irqsave(&g_lsadc_lock, &flag);
128 value = enable ? 1 : 0;
129 switch (chn) {
130 case 0: /* chn 0 */
131 lsadc_reg_write(value << 8, 1 << 8, HISI_LSADC_CONFIG); /* 8: [8] bit for chn 0 */
132 break;
133 case 1: /* chn 1 */
134 lsadc_reg_write(value << 9, 1 << 9, HISI_LSADC_CONFIG); /* 9: [9] bit for chn 1 */
135 break;
136 #if (LSADC_MAX_CHN_NUM == 4)
137 case 2: /* chn 2 */
138 lsadc_reg_write(value << 10, 1 << 10, HISI_LSADC_CONFIG); /* 10: [10] bit for chn 2 */
139 break;
140 case 3: /* chn 3 */
141 lsadc_reg_write(value << 11, 1 << 11, HISI_LSADC_CONFIG); /* 11: [11] bit for chn 3 */
142 break;
143 #endif
144 default:
145 osal_spin_unlock_irqrestore(&g_lsadc_lock, &flag);
146 lsadc_print("error chn:%d\n", chn);
147 return -1;
148 }
149 osal_spin_unlock_irqrestore(&g_lsadc_lock, &flag);
150
151 return 0;
152 }
153
lsadc_enable_clock(void)154 static int lsadc_enable_clock(void)
155 {
156 void *lsadc_crg_addr = NULL;
157
158 lsadc_crg_addr = osal_ioremap(LSADC_CRG_ADDR, (unsigned long)LSADC_CLOCK_REG_LENGTH);
159 if (lsadc_crg_addr == NULL) {
160 return -1;
161 }
162
163 write_reg32(0x1 << ADC_BIT, 0x1 << ADC_BIT, lsadc_crg_addr); /* 0x1: [1] bit for clock control */
164
165 osal_iounmap((void *)lsadc_crg_addr, (unsigned long)LSADC_CLOCK_REG_LENGTH);
166
167 return 0;
168 }
169
lsadc_disable_clock(void)170 static void lsadc_disable_clock(void)
171 {
172 void *lsadc_crg_addr = NULL;
173
174 lsadc_crg_addr = osal_ioremap(LSADC_CRG_ADDR, (unsigned long)LSADC_CLOCK_REG_LENGTH);
175 if (lsadc_crg_addr == NULL) {
176 return;
177 }
178
179 write_reg32(0x0 << ADC_BIT, 0x1 << ADC_BIT, lsadc_crg_addr); /* 0x1: [1] bit for clock control */
180
181 osal_iounmap((void *)lsadc_crg_addr, (unsigned long)LSADC_CLOCK_REG_LENGTH);
182 }
183
lsadc_start(void)184 static int lsadc_start(void)
185 {
186 unsigned long flag;
187 osal_spin_lock_irqsave(&g_lsadc_lock, &flag);
188
189 #ifdef ENABLE_ADC_IRQ
190 lsadc_reg_write(1, 1, HISI_LSADC_INTEN); /* int enable */
191 #endif
192
193 lsadc_reg_write(1, 1, HISI_LSADC_START); /* start */
194
195 osal_spin_unlock_irqrestore(&g_lsadc_lock, &flag);
196
197 return 0;
198 }
199
lsadc_stop(void)200 static int lsadc_stop(void)
201 {
202 unsigned long flag;
203 osal_spin_lock_irqsave(&g_lsadc_lock, &flag);
204
205 lsadc_reg_write(1, 1, HISI_LSADC_STOP); /* 1: [1] bit for adc control, stop adc */
206
207 #ifdef ENABLE_ADC_IRQ
208 lsadc_reg_write(0, 1, HISI_LSADC_INTEN); /* 1: [1] bit for int enable control, disable int */
209 #endif
210
211 osal_spin_unlock_irqrestore(&g_lsadc_lock, &flag);
212
213 return 0;
214 }
215
lsadc_get_chn_value(unsigned int chn)216 static int lsadc_get_chn_value(unsigned int chn)
217 {
218 if (chn >= LSADC_MAX_CHN_NUM) {
219 lsadc_print("error chn:%u\n", chn);
220 return -1;
221 }
222
223 return lsadc_readl(HISI_LSADC_CHNDATA + (chn << 2)); /* 2: each chn has 4 bytes int data, so shift left 2 bits */
224 }
225
226 #ifdef ENABLE_ADC_IRQ
lsadc_irq_proc(int irq,void * dev_id)227 static int lsadc_irq_proc(int irq, void *dev_id)
228 {
229 unsigned int intstate;
230 int chn_value;
231 unsigned int chn;
232 unsigned long flag;
233 osal_spin_lock_irqsave(&g_lsadc_lock, &flag);
234
235 intstate = lsadc_readl(HISI_LSADC_INTSTATUS);
236 lsadc_reg_write(LSADC_CHN_MASK, LSADC_CHN_MASK, HISI_LSADC_INTCLR); /* clr int flag all */
237
238 osal_spin_unlock_irqrestore(&g_lsadc_lock, &flag);
239
240 for (chn = 0; chn < LSADC_MAX_CHN_NUM; chn++) {
241 if (intstate & (1 << chn)) {
242 chn_value = lsadc_get_chn_value(chn);
243 lsadc_print("chn[%u] value:%d\n", chn, chn_value);
244 }
245 }
246
247 /* do what you want to do in irq */
248 return OSAL_IRQ_HANDLED;
249 }
250 #endif
251
hilsadc_ioctl(unsigned int cmd,unsigned long arg,void * private_data)252 static long hilsadc_ioctl(unsigned int cmd, unsigned long arg, void *private_data)
253 {
254 int ret = -1;
255 if (arg == 0) {
256 return ret;
257 }
258 int param;
259 hi_adc_unused(private_data);
260
261 switch (cmd) {
262 case LSADC_IOC_MODEL_SEL:
263 param = *(int *)(uintptr_t)arg;
264 ret = lsadc_model_select(param);
265 break;
266
267 case LSADC_IOC_CHN_ENABLE:
268 param = *(int *)(uintptr_t)arg;
269 ret = lsadc_chn_valid(param, 1);
270 break;
271
272 case LSADC_IOC_CHN_DISABLE:
273 param = *(int *)(uintptr_t)arg;
274 ret = lsadc_chn_valid(param, 0);
275 break;
276
277 case LSADC_IOC_START:
278 ret = lsadc_start();
279 break;
280
281 case LSADC_IOC_STOP:
282 ret = lsadc_stop();
283 break;
284
285 case LSADC_IOC_GET_CHNVAL:
286 param = *(int *)(uintptr_t)arg;
287 ret = lsadc_get_chn_value(param);
288 break;
289
290 default:
291 lsadc_print("error cmd:%08x\n", cmd);
292 ret = -1;
293 break;
294 }
295
296 return ret;
297 }
298
299 static struct osal_fileops g_hi_lsadc_fops = {
300 .open = hilsadc_open,
301 .release = hilsadc_release,
302 .unlocked_ioctl = hilsadc_ioctl,
303 };
304
305 static osal_dev_t *g_lsadc_device = NULL;
306
lsadc_init(void)307 int lsadc_init(void)
308 {
309 if (g_lsadc_reg_base == NULL) {
310 g_lsadc_reg_base = (volatile void *)osal_ioremap(LSADC_BASE_ADDR, 0x100); /* 0x100: ADC reg length */
311 if (g_lsadc_reg_base == NULL) {
312 lsadc_print("lsadc ioremap error.\n");
313 return -1;
314 }
315 g_need_iounmap = 1;
316 }
317
318 #ifdef ENABLE_ADC_IRQ
319 if (g_lsadc_irq <= 0) {
320 g_lsadc_irq = LSADC_IRQ_ID;
321 }
322
323 if (osal_request_irq(g_lsadc_irq, lsadc_irq_proc, 0, "hi_lsadc", &g_hi_lsadc_fops) != 0) {
324 lsadc_print("lsadc request irq error.\n");
325 goto requeset_irq_fail;
326 }
327 #endif
328
329 osal_spin_lock_init(&g_lsadc_lock);
330
331 g_lsadc_device = osal_createdev("hi_lsadc");
332 g_lsadc_device->minor = 255; /* dev_minor 255 */
333 g_lsadc_device->fops = &g_hi_lsadc_fops;
334 if (osal_registerdevice(g_lsadc_device) != 0) {
335 lsadc_print("lsadc register device error.\n");
336 goto register_device_fail;
337 }
338
339 if (lsadc_enable_clock() != 0) {
340 lsadc_print("lsadc enable clock error.\n");
341 goto enable_clock_fail;
342 }
343 osal_printk("hi_lsadc init ok. ver=%s, %s.\n", __DATE__, __TIME__);
344
345 return 0;
346
347 enable_clock_fail:
348 osal_deregisterdevice(g_lsadc_device);
349 register_device_fail:
350 osal_destroydev(g_lsadc_device);
351 osal_spin_lock_destroy(&g_lsadc_lock);
352
353 #ifdef ENABLE_ADC_IRQ
354 osal_free_irq(g_lsadc_irq, &g_hi_lsadc_fops);
355 requeset_irq_fail:
356 #endif
357
358 if (g_need_iounmap) {
359 osal_iounmap((void *)g_lsadc_reg_base, (unsigned long)LSADC_CLOCK_REG_LENGTH);
360 g_need_iounmap = 0;
361 g_lsadc_reg_base = NULL;
362 }
363
364 return -1;
365 }
366
lsadc_exit(void)367 void lsadc_exit(void)
368 {
369 #ifdef ENABLE_ADC_IRQ
370 osal_free_irq(g_lsadc_irq, &g_hi_lsadc_fops);
371 #endif
372
373 osal_spin_lock_destroy(&g_lsadc_lock);
374
375 osal_deregisterdevice(g_lsadc_device);
376 osal_destroydev(g_lsadc_device);
377 if (g_need_iounmap) {
378 osal_iounmap((void *)g_lsadc_reg_base, (unsigned long)LSADC_CLOCK_REG_LENGTH);
379 g_need_iounmap = 0;
380 g_lsadc_reg_base = NULL;
381 }
382
383 lsadc_disable_clock();
384 osal_printk("hi_lsadc exit ok.\n");
385 }
386