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