1 /* Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved.
2
3 * Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in
4 * the the People's Republic of China and other countries.
5 * All Allwinner Technology Co.,Ltd. trademarks are used with permission.
6
7 * DISCLAIMER
8 * THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT.
9 * IF YOU NEED TO INTEGRATE THIRD PARTY¡¯S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.)
10 * IN ALLWINNERS¡¯SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN
11 * ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES.
12 * ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS
13 * COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE.
14 * YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY¡¯S TECHNOLOGY.
15
16
17 * THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT
18 * PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND,
19 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING
20 * THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE
21 * OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22 * IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29 * OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31 #include <hal_interrupt.h>
32 #include <hal_clk.h>
33 #include <sunxi_hal_gpadc.h>
34 #include <hal_reset.h>
35
36 hal_gpadc_t hal_gpadc;
37
38 #if defined(CONFIG_SOC_SUN20IW1)
hal_gpadc_clk_init(hal_gpadc_t * gpadc)39 static hal_gpadc_status_t hal_gpadc_clk_init(hal_gpadc_t *gpadc)
40 {
41 hal_clk_type_t clk_type = HAL_SUNXI_CCU;
42 hal_clk_id_t gpadc_clk_id = gpadc->bus_clk;
43 hal_clk_t mclk;
44
45 hal_reset_type_t reset_type = HAL_SUNXI_RESET;
46 hal_reset_id_t gpadc_reset_id = gpadc->rst_clk;
47 struct reset_control *reset;
48
49 mclk = hal_clock_get(clk_type, gpadc_clk_id);
50 if(hal_clock_enable(mclk))
51 {
52 GPADC_ERR("gpadc clk enable failed!\n");
53 return GPADC_ERROR;
54 }
55 gpadc->mbus_clk = mclk;
56
57 reset = hal_reset_control_get(reset_type, gpadc_reset_id);
58 if (hal_reset_control_deassert(reset))
59 {
60 GPADC_ERR("gpadc reset deassert failed!\n");
61 return GPADC_ERROR;
62 }
63 hal_reset_control_put(reset);
64 return GPADC_OK;
65 }
66 #else
hal_gpadc_clk_init(hal_gpadc_t * gpadc)67 static hal_gpadc_status_t hal_gpadc_clk_init(hal_gpadc_t *gpadc)
68 {
69 #if !defined(CONFIG_ARCH_SUN8IW18P1)
70 if (hal_clk_set_parent(gpadc->mclk, gpadc->pclk))
71 {
72 GPADC_ERR("[gpadc] clk set parent failed!");
73 return GPADC_ERROR;
74 }
75 #endif
76 if (hal_clock_enable(gpadc->mclk))
77 {
78 GPADC_ERR("[gpadc] clk enable mclk failed!");
79 return GPADC_ERROR;
80 }
81
82 return GPADC_OK;
83 }
84 #endif
85
gpadc_channel_check_valid(hal_gpadc_channel_t channal)86 static int gpadc_channel_check_valid(hal_gpadc_channel_t channal)
87 {
88 hal_gpadc_t *gpadc = &hal_gpadc;
89
90 return channal < gpadc->channel_num ? 0 : -1 ;
91 }
92
gpadc_channel_select(hal_gpadc_channel_t channal)93 static void gpadc_channel_select(hal_gpadc_channel_t channal)
94 {
95 uint32_t reg_val;
96 hal_gpadc_t *gpadc = &hal_gpadc;
97
98 reg_val = readl((unsigned long)(gpadc->reg_base) + GP_CS_EN_REG);
99 reg_val |= (0x01 << channal);
100 writel(reg_val, (unsigned long)(gpadc->reg_base) + GP_CS_EN_REG);
101
102 }
103
gpadc_channel_deselect(hal_gpadc_channel_t channal)104 static void gpadc_channel_deselect(hal_gpadc_channel_t channal)
105 {
106 uint32_t reg_val;
107 hal_gpadc_t *gpadc = &hal_gpadc;
108
109 reg_val = readl((unsigned long)(gpadc->reg_base) + GP_CS_EN_REG);
110 reg_val &= ~(0x01 << channal);
111 writel(reg_val, (unsigned long)(gpadc->reg_base) + GP_CS_EN_REG);
112
113 }
114
gpadc_compare_select(hal_gpadc_channel_t channal)115 static void gpadc_compare_select(hal_gpadc_channel_t channal)
116 {
117 uint32_t reg_val;
118 hal_gpadc_t *gpadc = &hal_gpadc;
119
120 reg_val = readl((unsigned long)(gpadc->reg_base) + GP_CS_EN_REG);
121 reg_val |= (GP_CH0_CMP_EN << channal);
122 writel(reg_val, (unsigned long)(gpadc->reg_base) + GP_CS_EN_REG);
123
124 }
125
gpadc_compare_deselect(hal_gpadc_channel_t channal)126 static void gpadc_compare_deselect(hal_gpadc_channel_t channal)
127 {
128 uint32_t reg_val;
129 hal_gpadc_t *gpadc = &hal_gpadc;
130
131 reg_val = readl((unsigned long)(gpadc->reg_base) + GP_CTRL_REG);
132 reg_val &= ~(GP_CH0_CMP_EN << channal);
133 writel(reg_val, (unsigned long)(gpadc->reg_base) + GP_CTRL_REG);
134
135 }
136
gpadc_channel_enable_lowirq(hal_gpadc_channel_t channal)137 static void gpadc_channel_enable_lowirq(hal_gpadc_channel_t channal)
138 {
139 uint32_t reg_val;
140 hal_gpadc_t *gpadc = &hal_gpadc;
141
142 reg_val = readl((unsigned long)(gpadc->reg_base) + GP_DATAL_INTC_REG);
143 reg_val |= (0x01 << channal);
144 writel(reg_val, (unsigned long)(gpadc->reg_base) + GP_DATAL_INTC_REG);
145 }
146
gpadc_channel_disable_lowirq(hal_gpadc_channel_t channal)147 static void gpadc_channel_disable_lowirq(hal_gpadc_channel_t channal)
148 {
149 uint32_t reg_val;
150 hal_gpadc_t *gpadc = &hal_gpadc;
151
152 reg_val = readl((unsigned long)(gpadc->reg_base) + GP_DATAL_INTC_REG);
153 reg_val &= ~(0x01 << channal);
154 writel(reg_val, (unsigned long)(gpadc->reg_base) + GP_DATAL_INTC_REG);
155 }
156
gpadc_channel_compare_lowdata(hal_gpadc_channel_t channal,uint32_t low_uv)157 static void gpadc_channel_compare_lowdata(hal_gpadc_channel_t channal,
158 uint32_t low_uv)
159 {
160 uint32_t reg_val = 0, low = 0, unit = 0;
161 hal_gpadc_t *gpadc = &hal_gpadc;
162
163 /* analog voltage range 0~1.8v, 12bits sample rate, unit=1.8v/(2^12) */
164 unit = VOL_RANGE / 4096; /* 12bits sample rate */
165 low = low_uv / unit;
166 if (low > VOL_VALUE_MASK)
167 {
168 low = VOL_VALUE_MASK;
169 }
170
171 reg_val = readl((unsigned long)(gpadc->reg_base) + GP_CH0_CMP_DATA_REG + 4 * channal);
172 reg_val &= ~VOL_VALUE_MASK;
173 reg_val |= (low & VOL_VALUE_MASK);
174 writel(reg_val, (unsigned long)(gpadc->reg_base) + GP_CH0_CMP_DATA_REG + 4 * channal);
175
176 }
177
gpadc_channel_enable_highirq(hal_gpadc_channel_t channal)178 static void gpadc_channel_enable_highirq(hal_gpadc_channel_t channal)
179 {
180 uint32_t reg_val;
181 hal_gpadc_t *gpadc = &hal_gpadc;
182
183 reg_val = readl((unsigned long)(gpadc->reg_base) + GP_DATAH_INTC_REG);
184 reg_val |= (1 << channal);
185 writel(reg_val, (unsigned long)(gpadc->reg_base) + GP_DATAH_INTC_REG);
186
187 }
188
gpadc_channel_disable_highirq(hal_gpadc_channel_t channal)189 static void gpadc_channel_disable_highirq(hal_gpadc_channel_t channal)
190 {
191 uint32_t reg_val;
192 hal_gpadc_t *gpadc = &hal_gpadc;
193
194 reg_val = readl((unsigned long)(gpadc->reg_base) + GP_DATAH_INTC_REG);
195 reg_val &= ~(1 << channal);
196 writel(reg_val, (unsigned long)(gpadc->reg_base) + GP_DATAH_INTC_REG);
197
198 }
199
gpadc_channel_compare_highdata(hal_gpadc_channel_t channal,uint32_t hig_uv)200 static void gpadc_channel_compare_highdata(hal_gpadc_channel_t channal,
201 uint32_t hig_uv)
202 {
203 uint32_t reg_val = 0, hig_val = 0, unit_val = 0;
204 hal_gpadc_t *gpadc = &hal_gpadc;
205
206 /* anolog voltage range 0~1.8v, 12bits sample rate, unit=1.8v/(2^12) */
207 unit_val = VOL_RANGE / 4096; /* 12bits sample rate */
208 hig_val = hig_uv / unit_val;
209
210 if (hig_val > VOL_VALUE_MASK)
211 {
212 hig_val = VOL_VALUE_MASK;
213 }
214
215 reg_val = readl((unsigned long)(gpadc->reg_base) + GP_CH0_CMP_DATA_REG + 4 * channal);
216 reg_val &= ~(VOL_VALUE_MASK << 16);
217 reg_val |= (hig_val & VOL_VALUE_MASK) << 16;
218 writel(reg_val, (unsigned long)(gpadc->reg_base) + GP_CH0_CMP_DATA_REG + 4 * channal);
219
220 }
221
222 /* clk_in: source clock, round_clk: sample rate */
gpadc_sample_rate_set(uint32_t reg_base,uint32_t clk_in,uint32_t round_clk)223 static void gpadc_sample_rate_set(uint32_t reg_base, uint32_t clk_in,
224 uint32_t round_clk)
225 {
226 uint32_t div, reg_val;
227 if (round_clk > clk_in)
228 {
229 GPADC_ERR("invalid round clk!");
230 }
231 div = clk_in / round_clk - 1 ;
232 reg_val = readl((unsigned long)(reg_base) + GP_SR_REG);
233 reg_val &= ~GP_SR_CON;
234 reg_val |= (div << 16);
235 writel(reg_val, (unsigned long)(reg_base) + GP_SR_REG);
236 }
237
gpadc_calibration_enable(uint32_t reg_base)238 static void gpadc_calibration_enable(uint32_t reg_base)
239 {
240 uint32_t reg_val;
241 reg_val = readl((unsigned long)(reg_base) + GP_CTRL_REG);
242 reg_val |= GP_CALI_EN;
243 writel(reg_val, (unsigned long)(reg_base) + GP_CTRL_REG);
244 }
245
gpadc_mode_select(uint32_t reg_base,enum gp_select_mode mode)246 static void gpadc_mode_select(uint32_t reg_base,
247 enum gp_select_mode mode)
248 {
249 uint32_t reg_val;
250
251 reg_val = readl((unsigned long)(reg_base) + GP_CTRL_REG);
252 reg_val &= ~GP_MODE_SELECT;
253 reg_val |= (mode << 18);
254 writel(reg_val, (unsigned long)(reg_base) + GP_CTRL_REG);
255 }
256
257 /* enable gpadc function, true:enable, false:disable */
gpadc_enable(uint32_t reg_base)258 static void gpadc_enable(uint32_t reg_base)
259 {
260 uint32_t reg_val = 0;
261
262 reg_val = readl((unsigned long)(reg_base) + GP_CTRL_REG);
263 reg_val |= GP_ADC_EN;
264 writel(reg_val, (unsigned long)(reg_base) + GP_CTRL_REG);
265 }
266
267 /* enable gpadc function, true:enable, false:disable */
gpadc_disable(uint32_t reg_base)268 static void gpadc_disable(uint32_t reg_base)
269 {
270 uint32_t reg_val = 0;
271
272 reg_val = readl((unsigned long)(reg_base) + GP_CTRL_REG);
273 reg_val &= ~GP_ADC_EN;
274 writel(reg_val, (unsigned long)(reg_base) + GP_CTRL_REG);
275 }
276
gpadc_read_channel_irq_enable(uint32_t reg_base)277 static uint32_t gpadc_read_channel_irq_enable(uint32_t reg_base)
278 {
279 return readl((unsigned long)(reg_base) + GP_DATA_INTC_REG);
280 }
281
gpadc_read_channel_lowirq_enable(uint32_t reg_base)282 static uint32_t gpadc_read_channel_lowirq_enable(uint32_t reg_base)
283 {
284 return readl((unsigned long)(reg_base) + GP_DATAL_INTC_REG);
285 }
286
gpadc_read_channel_highirq_enable(uint32_t reg_base)287 static uint32_t gpadc_read_channel_highirq_enable(uint32_t reg_base)
288 {
289 return readl((unsigned long)(reg_base) + GP_DATAH_INTC_REG);
290 }
291
gpadc_channel_irq_status(uint32_t reg_base)292 static uint32_t gpadc_channel_irq_status(uint32_t reg_base)
293 {
294 return readl((unsigned long)(reg_base) + GP_DATA_INTS_REG);
295 }
296
gpadc_channel_clear_irq(uint32_t reg_base,uint32_t flags)297 static void gpadc_channel_clear_irq(uint32_t reg_base, uint32_t flags)
298 {
299 writel(flags, (unsigned long)(reg_base) + GP_DATA_INTS_REG);
300 }
301
gpadc_channel_lowirq_status(uint32_t reg_base)302 static uint32_t gpadc_channel_lowirq_status(uint32_t reg_base)
303 {
304 return readl((unsigned long)(reg_base) + GP_DATAL_INTS_REG);
305 }
306
gpadc_channel_clear_lowirq(uint32_t reg_base,uint32_t flags)307 static void gpadc_channel_clear_lowirq(uint32_t reg_base, uint32_t flags)
308 {
309 writel(flags, (unsigned long)(reg_base) + GP_DATAL_INTS_REG);
310 }
311
gpadc_channel_highirq_status(uint32_t reg_base)312 static uint32_t gpadc_channel_highirq_status(uint32_t reg_base)
313 {
314 return readl((unsigned long)(reg_base) + GP_DATAH_INTS_REG);
315 }
316
gpadc_channel_clear_highirq(uint32_t reg_base,uint32_t flags)317 static void gpadc_channel_clear_highirq(uint32_t reg_base, uint32_t flags)
318 {
319 writel(flags, (unsigned long)(reg_base) + GP_DATAH_INTS_REG);
320 }
321
gpadc_read_data(uint32_t reg_base,hal_gpadc_channel_t channal)322 static int gpadc_read_data(uint32_t reg_base, hal_gpadc_channel_t channal)
323 {
324 return readl((unsigned long)(reg_base) + GP_CH0_DATA_REG + 4 * channal) & GP_CH_DATA_MASK;
325 }
326
hal_gpadc_callback(uint32_t data_type,uint32_t data)327 int hal_gpadc_callback(uint32_t data_type, uint32_t data)
328 {
329 GPADC_INFO("gpadc interrupt, data_type is %ld", data_type);
330 return 0;
331 }
332
gpadc_handler(int irq,void * dev)333 static irqreturn_t gpadc_handler(int irq, void *dev)
334 {
335 hal_gpadc_t *gpadc = (hal_gpadc_t *)dev;
336
337 uint32_t reg_val, reg_low, reg_high;
338 uint32_t reg_enable, reg_enable_low, reg_enable_high;
339 uint32_t i, data = 0;
340
341 reg_enable = gpadc_read_channel_irq_enable(gpadc->reg_base);
342 reg_enable_low = gpadc_read_channel_lowirq_enable(gpadc->reg_base);
343 reg_enable_high = gpadc_read_channel_highirq_enable(gpadc->reg_base);
344
345 reg_val = gpadc_channel_irq_status(gpadc->reg_base);
346 gpadc_channel_clear_irq(gpadc->reg_base, reg_val);
347 reg_low = gpadc_channel_lowirq_status(gpadc->reg_base);
348 gpadc_channel_clear_lowirq(gpadc->reg_base, reg_val);
349 reg_high = gpadc_channel_highirq_status(gpadc->reg_base);
350 gpadc_channel_clear_highirq(gpadc->reg_base, reg_val);
351
352 for (i = 0; i < gpadc->channel_num; i++)
353 {
354 if (reg_low & (1 << i) & reg_enable_low)
355 {
356 data = gpadc_read_data(gpadc->reg_base, i);
357 gpadc_channel_enable_highirq(i);
358
359 if (gpadc->callback[i])
360 {
361 gpadc->callback[i](GPADC_DOWN, data);
362 }
363 }
364
365 if (reg_high & (1 << i) & reg_enable_high)
366 {
367 gpadc_channel_disable_highirq(i);
368 gpadc->callback[i](GPADC_UP, data);
369 }
370 }
371
372 return 0;
373 }
374
hal_gpadc_register_callback(hal_gpadc_channel_t channal,gpadc_callback_t user_callback)375 hal_gpadc_status_t hal_gpadc_register_callback(hal_gpadc_channel_t channal,
376 gpadc_callback_t user_callback)
377 {
378 hal_gpadc_t *gpadc = &hal_gpadc;
379
380 if (gpadc_channel_check_valid(channal))
381 {
382 return GPADC_CHANNEL_ERROR;
383 }
384
385 if (user_callback == NULL)
386 {
387 return GPADC_ERROR;
388 }
389
390 gpadc->callback[channal] = user_callback;
391
392 return GPADC_OK;
393 }
394
hal_gpadc_channel_init(hal_gpadc_channel_t channal)395 hal_gpadc_status_t hal_gpadc_channel_init(hal_gpadc_channel_t channal)
396 {
397 hal_gpadc_t *gpadc = &hal_gpadc;
398
399 if (gpadc_channel_check_valid(channal))
400 {
401 return GPADC_CHANNEL_ERROR;
402 }
403
404 gpadc_channel_select(channal);
405 gpadc_compare_select(channal);
406 gpadc_channel_enable_lowirq(channal);
407 gpadc_channel_compare_lowdata(channal, COMPARE_LOWDATA);
408 gpadc_channel_compare_highdata(channal, COMPARE_HIGDATA);
409
410 return GPADC_OK;
411 }
412
hal_gpadc_channel_exit(hal_gpadc_channel_t channal)413 hal_gpadc_status_t hal_gpadc_channel_exit(hal_gpadc_channel_t channal)
414 {
415 hal_gpadc_t *gpadc = &hal_gpadc;
416
417 if (gpadc_channel_check_valid(channal))
418 {
419 return GPADC_CHANNEL_ERROR;
420 }
421
422 gpadc_channel_deselect(channal);
423 gpadc_compare_deselect(channal);
424 gpadc_channel_disable_lowirq(channal);
425
426 return GPADC_OK;
427 }
428
hal_gpadc_setup(hal_gpadc_t * gpadc)429 static void hal_gpadc_setup(hal_gpadc_t *gpadc)
430 {
431 uint8_t i;
432
433 gpadc->reg_base = GPADC_BASE;
434 gpadc->channel_num = CHANNEL_NUM;
435 gpadc->irq_num = SUNXI_GPADC_IRQ;
436 gpadc->sample_rate = DEFAULT_SR;
437 #if defined(CONFIG_SOC_SUN20IW1)
438 gpadc->bus_clk = CLK_BUS_GPADC;
439 gpadc->rst_clk = RST_BUS_GPADC;
440 #else
441 gpadc->pclk = HAL_CLK_SRC_HOSC24M;
442 gpadc->mclk = HAL_CLK_PERIPH_GPADC;
443 #endif
444 gpadc->mode = GP_CONTINUOUS_MODE;
445
446 for (i = 0; i < gpadc->channel_num; i++)
447 {
448 gpadc->callback[i] = hal_gpadc_callback;
449 }
450 };
451
hal_gpadc_init(void)452 int hal_gpadc_init(void)
453 {
454 hal_gpadc_t *gpadc = &hal_gpadc;
455
456
457 hal_gpadc_setup(gpadc);
458
459 if (hal_gpadc_clk_init(gpadc))
460 {
461 GPADC_ERR("gpadc init clk error");
462 return GPADC_CLK_ERROR;
463 }
464
465 GPADC_INFO("gpadc set sample rate");
466 gpadc_sample_rate_set(gpadc->reg_base, OSC_24MHZ, gpadc->sample_rate);
467
468 if (request_irq(gpadc->irq_num, gpadc_handler, IRQF_NO_SUSPEND, "gpadc", gpadc))
469 {
470 return GPADC_IRQ_ERROR;
471 }
472
473 enable_irq(gpadc->irq_num);
474
475 GPADC_INFO("gpadc enable calibration");
476 gpadc_calibration_enable(gpadc->reg_base);
477 gpadc_mode_select(gpadc->reg_base, gpadc->mode);
478 gpadc_enable(gpadc->reg_base);
479
480 return GPADC_OK;
481 }
482
hal_gpadc_deinit(void)483 hal_gpadc_status_t hal_gpadc_deinit(void)
484 {
485 disable_irq(hal_gpadc.irq_num);
486 #if defined(CONFIG_SOC_SUN20IW1)
487 hal_clock_disable(hal_gpadc.mbus_clk);
488 #else
489 hal_clock_disable(hal_gpadc.mclk);
490 #endif
491 return GPADC_OK;
492 }
493
494 //device_initcall(hal_gpadc_init);
495