• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Winner Microelectronics Co., Ltd. All rights reserved.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 /**
17  * @file wm_gpio.c
18  *
19  * @brief GPIO Driver Module
20  *
21  * @author dave
22  *
23  * Copyright (c) 2014 Winner Microelectronics Co., Ltd.
24  */
25 #include "wm_gpio.h"
26 #include "wm_regs.h"
27 #include "wm_irq.h"
28 #include "wm_osal.h"
29 #include "tls_common.h"
30 
31 struct gpio_irq_context {
32     tls_gpio_irq_callback callback;
33     void *arg;
34 };
35 
36 static struct gpio_irq_context gpio_context[WM_IO_PB_31 - WM_IO_PA_00 + 1] = {{0, 0}};
37 
GPIOA_IRQHandler(void)38 ATTRIBUTE_ISR void GPIOA_IRQHandler(void)
39 {
40     u8  i     = 0;
41     u8  found = 0;
42     u32 reg   = 0;
43     csi_kernel_intrpt_enter();
44 
45     reg = tls_reg_read32(HR_GPIO_MIS);
46 
47     for (i = 0; i <= WM_IO_PA_15; i++) {
48         if (reg & BIT(i)) {
49             found = 1;
50             break;
51         }
52     }
53 
54     if (found) {
55         if (gpio_context[i].callback != NULL)
56             gpio_context[i].callback(gpio_context[i].arg);
57     }
58     csi_kernel_intrpt_exit();
59 }
60 
GPIOB_IRQHandler(void)61 ATTRIBUTE_ISR void GPIOB_IRQHandler(void)
62 {
63     u8  i     = 0;
64     u8  found = 0;
65     u32 reg   = 0;
66     csi_kernel_intrpt_enter();
67     reg = tls_reg_read32(HR_GPIO_MIS + TLS_IO_AB_OFFSET);
68 
69     for (i = WM_IO_PB_00; i <= WM_IO_PB_31; i++) {
70         if (reg & BIT(i - WM_IO_PB_00)) {
71             found = 1;
72             break;
73         }
74     }
75 
76     if (found) {
77         if (gpio_context[i].callback != NULL)
78             gpio_context[i].callback(gpio_context[i].arg);
79     }
80     csi_kernel_intrpt_exit();
81 }
82 
83 /**
84  * @brief          This function is used to config gpio function
85  *
86  * @param[in]      gpio_pin    gpio pin num
87  * @param[in]      dir         gpio direction
88  * @param[in]      attr        gpio attribute
89  *
90  * @return         None
91  *
92  * @note
93  */
tls_gpio_cfg(enum tls_io_name gpio_pin,enum tls_gpio_dir dir,enum tls_gpio_attr attr)94 void tls_gpio_cfg(enum tls_io_name gpio_pin, enum tls_gpio_dir dir, enum tls_gpio_attr attr)
95 {
96     u8    pin;
97     u16 offset;
98 
99     if (gpio_pin >= WM_IO_PB_00) {
100         pin    = gpio_pin - WM_IO_PB_00;
101         offset = TLS_IO_AB_OFFSET;
102     } else {
103         pin    = gpio_pin;
104         offset = 0;
105     }
106 
107     /* enable gpio function */
108     tls_io_cfg_set(gpio_pin, WM_IO_OPT5_GPIO);
109 
110     /* gpio direction */
111     if (WM_GPIO_DIR_OUTPUT == dir)
112         tls_reg_write32(HR_GPIO_DIR + offset, tls_reg_read32(HR_GPIO_DIR + offset) | BIT(pin));      /* 1 set output */
113     else if (WM_GPIO_DIR_INPUT == dir)
114         tls_reg_write32(HR_GPIO_DIR + offset, tls_reg_read32(HR_GPIO_DIR + offset) & (~BIT(pin)));     /* 0 set input */
115 
116     /* gpio attribute */
117     if (WM_GPIO_ATTR_FLOATING == attr) {
118         /* 1 disable pullup */
119         tls_reg_write32(HR_GPIO_PULLUP_EN + offset, tls_reg_read32(HR_GPIO_PULLUP_EN + offset) | BIT(pin));
120         /* 1 disable pulldown */
121         tls_reg_write32(HR_GPIO_PULLDOWN_EN + offset, tls_reg_read32(HR_GPIO_PULLDOWN_EN + offset)&(~BIT(pin)));
122     }
123     if (WM_GPIO_ATTR_PULLHIGH == attr) {
124         /* 0 enable pullup */
125         tls_reg_write32(HR_GPIO_PULLUP_EN + offset, tls_reg_read32(HR_GPIO_PULLUP_EN + offset) & (~BIT(pin)));
126         /* 0 disable pulldown */
127         tls_reg_write32(HR_GPIO_PULLDOWN_EN + offset, tls_reg_read32(HR_GPIO_PULLDOWN_EN + offset) &(~BIT(pin)));
128     }
129 
130     if (WM_GPIO_ATTR_PULLLOW == attr) {
131         /* 0 disable pullup */
132         tls_reg_write32(HR_GPIO_PULLUP_EN + offset, tls_reg_read32(HR_GPIO_PULLUP_EN + offset) | BIT(pin));
133         /* 1 disable pulldown */
134         tls_reg_write32(HR_GPIO_PULLDOWN_EN + offset, tls_reg_read32(HR_GPIO_PULLDOWN_EN + offset) | BIT(pin));
135     }
136 }
137 
138 /**
139  * @brief          This function is used to read gpio status
140  *
141  * @param[in]      gpio_pin    gpio pin num
142  *
143  * @retval         0     power level is low
144  * @retval         1     power level is high
145  *
146  * @note           None
147  */
tls_gpio_read(enum tls_io_name gpio_pin)148 u8 tls_gpio_read(enum tls_io_name gpio_pin)
149 {
150     u32 reg_en;
151     u32 reg;
152     u8  pin;
153     u16 offset;
154 
155     if (gpio_pin >= WM_IO_PB_00) {
156         pin    = gpio_pin - WM_IO_PB_00;
157         offset = TLS_IO_AB_OFFSET;
158     } else {
159         pin    = gpio_pin;
160         offset = 0;
161     }
162 
163     reg_en = tls_reg_read32(HR_GPIO_DATA_EN + offset);
164     tls_reg_write32(HR_GPIO_DATA_EN + offset, reg_en | (1 << pin));
165     reg = tls_reg_read32(HR_GPIO_DATA + offset);
166     tls_reg_write32(HR_GPIO_DATA_EN + offset, reg_en);
167     if (reg & (0x1 << pin))
168         return 1;
169     else
170         return 0;
171 }
172 
173 /**
174  * @brief          This function is used to modify gpio status
175  *
176  * @param[in]      gpio_pin    gpio pin num
177  * @param[in]      value       power level
178  *                             0: low  power level
179  *                                1: high power level
180  *
181  * @return         None
182  *
183  * @note           None
184  */
tls_gpio_write(enum tls_io_name gpio_pin,u8 value)185 void tls_gpio_write(enum tls_io_name gpio_pin, u8 value)
186 {
187     u32 cpu_sr = 0;
188     u32 reg;
189     u32    reg_en;
190     u8  pin;
191     u16 offset;
192 
193     if (gpio_pin >= WM_IO_PB_00) {
194         pin    = gpio_pin - WM_IO_PB_00;
195         offset = TLS_IO_AB_OFFSET;
196     } else {
197         pin    = gpio_pin;
198         offset = 0;
199     }
200 
201     cpu_sr = tls_os_set_critical();
202 
203     reg_en = tls_reg_read32(HR_GPIO_DATA_EN + offset);
204     tls_reg_write32(HR_GPIO_DATA_EN + offset, reg_en | (1 << pin));
205 
206     reg = tls_reg_read32(HR_GPIO_DATA + offset);
207     if (value)
208         tls_reg_write32(HR_GPIO_DATA + offset, reg |  (1 << pin));    /* write high */
209     else
210         tls_reg_write32(HR_GPIO_DATA + offset, reg & (~(1 << pin))); /* write low */
211 
212     tls_reg_write32(HR_GPIO_DATA_EN + offset, reg_en);
213 
214     tls_os_release_critical(cpu_sr);
215 }
216 
217 /**
218  * @brief          This function is used to config gpio interrupt
219  *
220  * @param[in]      gpio_pin    gpio pin num
221  * @param[in]      mode        interrupt trigger type
222  *
223  * @return         None
224  *
225  * @note           None
226  */
tls_gpio_irq_enable(enum tls_io_name gpio_pin,enum tls_gpio_irq_trig mode)227 void tls_gpio_irq_enable(enum tls_io_name gpio_pin, enum tls_gpio_irq_trig mode)
228 {
229     u32 reg;
230     u8  pin;
231     u16 offset;
232     u8  vec_no;
233 
234     if (gpio_pin >= WM_IO_PB_00) {
235         pin    = gpio_pin - WM_IO_PB_00;
236         offset = TLS_IO_AB_OFFSET;
237         vec_no = GPIOB_IRQn;
238     } else {
239         pin    = gpio_pin;
240         offset = 0;
241         vec_no = GPIOA_IRQn;
242     }
243 
244     switch (mode) {
245         case WM_GPIO_IRQ_TRIG_RISING_EDGE:
246             reg = tls_reg_read32(HR_GPIO_IS + offset);
247             reg &= (~(0x1 << pin));
248         //   TLS_DBGPRT_INFO("\r\nrising edge is ret=%x\r\n",reg);
249             tls_reg_write32(HR_GPIO_IS + offset, reg);        /* 0 edge trigger */
250             reg = tls_reg_read32(HR_GPIO_IBE + offset);
251             reg &= (~(0x1 << pin));
252         //   TLS_DBGPRT_INFO("\r\nrising edge ibe ret=%x\r\n",reg);
253             tls_reg_write32(HR_GPIO_IBE + offset, reg);    /* 0 edge trigger */
254             reg = tls_reg_read32(HR_GPIO_IEV + offset);
255             reg |= (0x1 << pin);
256         //   TLS_DBGPRT_INFO("\r\nrising edge iev ret=%x\r\n",reg);
257             tls_reg_write32(HR_GPIO_IEV + offset, reg);    /* 1 rising edge trigger */
258             break;
259         case WM_GPIO_IRQ_TRIG_FALLING_EDGE:
260             reg = tls_reg_read32(HR_GPIO_IS + offset);
261             reg &= (~(0x1 << pin));
262         //   TLS_DBGPRT_INFO("\falling edge is ret=%x\n",reg);
263             tls_reg_write32(HR_GPIO_IS + offset, reg);        /* 0 edge trigger */
264             reg = tls_reg_read32(HR_GPIO_IBE + offset);
265             reg &= (~(0x1 << pin));
266         //   TLS_DBGPRT_INFO("\falling edge ibe ret=%x\n",reg);
267             tls_reg_write32(HR_GPIO_IBE + offset, reg);    /* 0 edge trigger */
268             reg = tls_reg_read32(HR_GPIO_IEV + offset);
269             reg &= (~(0x1 << pin));
270         //   TLS_DBGPRT_INFO("\falling edge iev ret=%x\n",reg);
271             tls_reg_write32(HR_GPIO_IEV + offset, reg);    /* 0 falling edge trigger */
272             break;
273         case WM_GPIO_IRQ_TRIG_DOUBLE_EDGE:
274             reg = tls_reg_read32(HR_GPIO_IS + offset);
275             tls_reg_write32(HR_GPIO_IS + offset, reg & (~(0x1 << pin)));    /* 0 edge trigger */
276             reg = tls_reg_read32(HR_GPIO_IBE + offset);
277             tls_reg_write32(HR_GPIO_IBE + offset, reg | (0x1 << pin));       /* 1 double edge trigger */
278             break;
279         case WM_GPIO_IRQ_TRIG_HIGH_LEVEL:
280             reg = tls_reg_read32(HR_GPIO_IS + offset);
281             tls_reg_write32(HR_GPIO_IS + offset, reg | (0x1 << pin));        /* 1 level trigger */
282             reg = tls_reg_read32(HR_GPIO_IEV + offset);
283             tls_reg_write32(HR_GPIO_IEV + offset, reg | (0x1 << pin));        /* 1 high level trigger */
284             break;
285         case WM_GPIO_IRQ_TRIG_LOW_LEVEL:
286             reg = tls_reg_read32(HR_GPIO_IS + offset);
287             tls_reg_write32(HR_GPIO_IS + offset, reg | (0x1 << pin));        /* 1 level trigger */
288             reg = tls_reg_read32(HR_GPIO_IEV + offset);
289             tls_reg_write32(HR_GPIO_IEV + offset, reg & (~(0x1 << pin)));    /* 0 low level trigger */
290             break;
291     }
292 
293     reg = tls_reg_read32(HR_GPIO_IE + offset);
294     reg |= (0x1 << pin);
295     tls_reg_write32(HR_GPIO_IE + offset, reg);        /* enable interrupt */
296 
297     tls_irq_enable(vec_no);
298 }
299 
300 /**
301  * @brief          This function is used to disable gpio interrupt
302  *
303  * @param[in]      gpio_pin    gpio pin num
304  *
305  * @return         None
306  *
307  * @note           None
308  */
tls_gpio_irq_disable(enum tls_io_name gpio_pin)309 void tls_gpio_irq_disable(enum tls_io_name gpio_pin)
310 {
311     u32 reg;
312     u8  pin;
313     u16 offset;
314 
315     if (gpio_pin >= WM_IO_PB_00) {
316         pin    = gpio_pin - WM_IO_PB_00;
317         offset = TLS_IO_AB_OFFSET;
318         reg = tls_reg_read32(HR_GPIO_IE + offset);
319         tls_reg_write32(HR_GPIO_IE + offset, reg & (~(0x1 << pin)));    /* disable interrupt */
320         reg = reg&(~(0x1 << pin));
321         if (reg == 0) {
322             tls_irq_disable(GPIOB_IRQn);
323         }
324     } else {
325         pin    = gpio_pin;
326         offset = 0;
327         reg = tls_reg_read32(HR_GPIO_IE + offset);
328         tls_reg_write32(HR_GPIO_IE + offset, reg & (~(0x1 << pin)));    /* disable interrupt */
329         reg = (reg&(~(0x1 << pin)))&0xFFFF;
330         if (reg == 0) {
331             tls_irq_disable(GPIOA_IRQn);
332         }
333     }
334 }
335 
336 /**
337  * @brief          This function is used to get gpio interrupt status
338  *
339  * @param[in]      gpio_pin    gpio pin num
340  *
341  * @retval         0     no interrupt happened
342  * @retval         1     interrupt happened
343  *
344  * @note           None
345  */
tls_get_gpio_irq_status(enum tls_io_name gpio_pin)346 u8 tls_get_gpio_irq_status(enum tls_io_name gpio_pin)
347 {
348     u32 reg;
349     u8  pin;
350     u16 offset;
351 
352     if (gpio_pin >= WM_IO_PB_00) {
353         pin    = gpio_pin - WM_IO_PB_00;
354         offset = TLS_IO_AB_OFFSET;
355     } else {
356         pin    = gpio_pin;
357         offset = 0;
358     }
359 
360     reg = tls_reg_read32(HR_GPIO_RIS + offset);
361     if (reg & (0x1 << pin))
362         return    1;
363     else
364         return    0;
365 }
366 
367 /**
368  * @brief          This function is used to clear gpio interrupt flag
369  *
370  * @param[in]      gpio_pin    gpio pin num
371  *
372  * @return         None
373  *
374  * @note           None
375  */
tls_clr_gpio_irq_status(enum tls_io_name gpio_pin)376 void tls_clr_gpio_irq_status(enum tls_io_name gpio_pin)
377 {
378     u8  pin;
379     u16 offset;
380 
381     if (gpio_pin >= WM_IO_PB_00) {
382         pin    = gpio_pin - WM_IO_PB_00;
383         offset = TLS_IO_AB_OFFSET;
384     } else {
385         pin    = gpio_pin;
386         offset = 0;
387     }
388 
389     tls_reg_write32(HR_GPIO_IC + offset, (0x1 << pin));        /* 1 clear interrupt status */
390 }
391 
392 /**
393  * @brief          This function is used to register gpio interrupt
394  *
395  * @param[in]      gpio_pin    gpio pin num
396  * @param[in]      callback    the gpio interrupt call back function
397  * @param[in]      arg         parammeter for the callback
398  *
399  * @return         None
400  *
401  * @note
402  * gpio callback function is called in interrupt,
403  * so can not operate the critical data in the callback fuuction,
404  * recommendation to send messages to other tasks to operate it.
405  */
tls_gpio_isr_register(enum tls_io_name gpio_pin,tls_gpio_irq_callback callback,void * arg)406 void tls_gpio_isr_register(enum tls_io_name gpio_pin,
407                            tls_gpio_irq_callback callback,
408                            void *arg)
409 {
410     gpio_context[gpio_pin].callback = callback;
411     gpio_context[gpio_pin].arg = arg;
412 }