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