• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
3  *
4  * HDF is dual licensed: you can use it either under the terms of
5  * the GPL, or the BSD license, at your option.
6  * See the LICENSE file in the root of this repository for complete details.
7  */
8 
9 #include "gpio/gpio_core.h"
10 #include "osal_mem.h"
11 #include "platform_core.h"
12 
13 #define HDF_LOG_TAG gpio_core
14 
15 #define GPIO_IRQ_STACK_SIZE        10000
16 
GpioInfoLock(struct GpioInfo * ginfo)17 static inline void GpioInfoLock(struct GpioInfo *ginfo)
18 {
19     (void)OsalSpinLockIrqSave(&ginfo->spin, &ginfo->irqSave);
20 }
21 
GpioInfoUnlock(struct GpioInfo * ginfo)22 static inline void GpioInfoUnlock(struct GpioInfo *ginfo)
23 {
24     (void)OsalSpinUnlockIrqRestore(&ginfo->spin, &ginfo->irqSave);
25 }
26 
GpioCntlrWrite(struct GpioCntlr * cntlr,uint16_t local,uint16_t val)27 int32_t GpioCntlrWrite(struct GpioCntlr *cntlr, uint16_t local, uint16_t val)
28 {
29     if (cntlr == NULL) {
30         return HDF_ERR_INVALID_OBJECT;
31     }
32     if (cntlr->ops == NULL || cntlr->ops->write == NULL) {
33         return HDF_ERR_NOT_SUPPORT;
34     }
35 
36     return cntlr->ops->write(cntlr, local, val);
37 }
38 
GpioCntlrRead(struct GpioCntlr * cntlr,uint16_t local,uint16_t * val)39 int32_t GpioCntlrRead(struct GpioCntlr *cntlr, uint16_t local, uint16_t *val)
40 {
41     if (cntlr == NULL) {
42         return HDF_ERR_INVALID_OBJECT;
43     }
44     if (cntlr->ops == NULL || cntlr->ops->read == NULL) {
45         return HDF_ERR_NOT_SUPPORT;
46     }
47     if (val == NULL) {
48         return HDF_ERR_INVALID_PARAM;
49     }
50 
51     return cntlr->ops->read(cntlr, local, val);
52 }
53 
GpioCntlrSetDir(struct GpioCntlr * cntlr,uint16_t local,uint16_t dir)54 int32_t GpioCntlrSetDir(struct GpioCntlr *cntlr, uint16_t local, uint16_t dir)
55 {
56     if (cntlr == NULL) {
57         return HDF_ERR_INVALID_OBJECT;
58     }
59     if (cntlr->ops == NULL || cntlr->ops->setDir == NULL) {
60         return HDF_ERR_NOT_SUPPORT;
61     }
62 
63     return cntlr->ops->setDir(cntlr, local, dir);
64 }
65 
GpioCntlrGetDir(struct GpioCntlr * cntlr,uint16_t local,uint16_t * dir)66 int32_t GpioCntlrGetDir(struct GpioCntlr *cntlr, uint16_t local, uint16_t *dir)
67 {
68     if (cntlr == NULL) {
69         return HDF_ERR_INVALID_OBJECT;
70     }
71     if (cntlr->ops == NULL || cntlr->ops->getDir == NULL) {
72         return HDF_ERR_NOT_SUPPORT;
73     }
74     if (dir == NULL) {
75         return HDF_ERR_INVALID_PARAM;
76     }
77 
78     return cntlr->ops->getDir(cntlr, local, dir);
79 }
80 
GpioCntlrToIrq(struct GpioCntlr * cntlr,uint16_t local,uint16_t * irq)81 int32_t GpioCntlrToIrq(struct GpioCntlr *cntlr, uint16_t local, uint16_t *irq)
82 {
83     if (cntlr == NULL) {
84         return HDF_ERR_INVALID_OBJECT;
85     }
86     if (cntlr->ops == NULL || cntlr->ops->toIrq == NULL) {
87         return HDF_ERR_NOT_SUPPORT;
88     }
89 
90     return cntlr->ops->toIrq(cntlr, local, irq);
91 }
92 
GpioCntlrIrqCallback(struct GpioCntlr * cntlr,uint16_t local)93 void GpioCntlrIrqCallback(struct GpioCntlr *cntlr, uint16_t local)
94 {
95     struct GpioInfo *ginfo = NULL;
96     struct GpioIrqRecord *irqRecord = NULL;
97 
98     if (cntlr == NULL || cntlr->ginfos == NULL || local >= cntlr->count) {
99         PLAT_LOGW("GpioCntlrIrqCallback: invalid cntlr(ginfos) or loal num:%u!", local);
100         return;
101     }
102     ginfo = &cntlr->ginfos[local];
103     if (ginfo == NULL) {
104         PLAT_LOGW("GpioCntlrIrqCallback: ginfo null(start:%u, local:%u)", cntlr->start, local);
105         return;
106     }
107 
108     GpioInfoLock(ginfo);
109     irqRecord = ginfo->irqRecord;
110 
111     if (irqRecord == NULL) {
112         PLAT_LOGW("GpioCntlrIrqCallback: irq not set (start:%u, local:%u)", cntlr->start, local);
113         GpioInfoUnlock(ginfo);
114         return;
115     }
116     GpioIrqRecordTrigger(irqRecord);
117     GpioInfoUnlock(ginfo);
118 }
119 
GpioCntlrIrqThreadHandler(void * data)120 static int32_t GpioCntlrIrqThreadHandler(void *data)
121 {
122     int32_t ret;
123     uint32_t irqSave;
124     struct GpioIrqRecord *irqRecord = (struct GpioIrqRecord *)data;
125 
126     while (true) {
127         ret = OsalSemWait(&irqRecord->sem, HDF_WAIT_FOREVER);
128         if (irqRecord->removed) {
129             break;
130         }
131         if (ret != HDF_SUCCESS) {
132             continue;
133         }
134         if (irqRecord->btmFunc != NULL) {
135             (void)irqRecord->btmFunc(irqRecord->global, irqRecord->irqData);
136         }
137     }
138     (void)OsalSpinLockIrqSave(&irqRecord->spin, &irqSave);
139     (void)OsalSpinUnlockIrqRestore(&irqRecord->spin, &irqSave); // last post done
140     PLAT_LOGI("GpioCntlrIrqThreadHandler: gpio(%u) thread exit", irqRecord->global);
141     (void)OsalSemDestroy(&irqRecord->sem);
142     (void)OsalSpinDestroy(&irqRecord->spin);
143     (void)OsalThreadDestroy(&irqRecord->thread);
144     OsalMemFree(irqRecord);
145     return HDF_SUCCESS;
146 }
147 
GpioCntlrSetIrqInner(struct GpioInfo * ginfo,struct GpioIrqRecord * irqRecord)148 static int32_t GpioCntlrSetIrqInner(struct GpioInfo *ginfo, struct GpioIrqRecord *irqRecord)
149 {
150     int32_t ret;
151     uint16_t local = GpioInfoToLocal(ginfo);
152     struct GpioCntlr *cntlr = ginfo->cntlr;
153 
154     if (cntlr == NULL) {
155         PLAT_LOGE("GpioCntlrSetIrqInner: cntlr is NULL");
156         return HDF_ERR_INVALID_PARAM;
157     }
158     GpioInfoLock(ginfo);
159 
160     if (ginfo->irqRecord != NULL) {
161         GpioInfoUnlock(ginfo);
162         PLAT_LOGE("GpioCntlrSetIrqInner: gpio(%u+%u) irq already set", cntlr->start, local);
163         return HDF_ERR_NOT_SUPPORT;
164     }
165 
166     ginfo->irqRecord = irqRecord;
167     GpioInfoUnlock(ginfo);
168     ret = cntlr->ops->setIrq(cntlr, local, irqRecord->mode);
169     if (ret != HDF_SUCCESS) {
170         GpioInfoLock(ginfo);
171         PLAT_LOGE("GpioCntlrSetIrqInner: gpio setIrq fail");
172         ginfo->irqRecord = NULL;
173         GpioInfoUnlock(ginfo);
174     }
175     return ret;
176 }
177 
GpioIrqRecordCreate(struct GpioInfo * ginfo,uint16_t mode,GpioIrqFunc func,void * arg,struct GpioIrqRecord ** new)178 static int32_t GpioIrqRecordCreate(struct GpioInfo *ginfo, uint16_t mode, GpioIrqFunc func, void *arg,
179     struct GpioIrqRecord **new)
180 {
181     int32_t ret;
182     struct GpioIrqRecord *irqRecord = NULL;
183     struct OsalThreadParam cfg;
184 
185     irqRecord = (struct GpioIrqRecord *)OsalMemCalloc(sizeof(*irqRecord));
186     if (irqRecord == NULL) {
187         PLAT_LOGE("GpioIrqRecordCreate: alloc irq record failed");
188         return HDF_ERR_MALLOC_FAIL;
189     }
190     irqRecord->removed = false;
191     irqRecord->mode = mode;
192     irqRecord->irqFunc = ((mode & GPIO_IRQ_USING_THREAD) == 0) ? func : NULL;
193     irqRecord->btmFunc = ((mode & GPIO_IRQ_USING_THREAD) != 0) ? func : NULL;
194     irqRecord->irqData = arg;
195     irqRecord->global = GpioInfoToGlobal(ginfo);
196     if (irqRecord->btmFunc != NULL) {
197         ret = OsalThreadCreate(&irqRecord->thread, GpioCntlrIrqThreadHandler, irqRecord);
198         if (ret != HDF_SUCCESS) {
199             OsalMemFree(irqRecord);
200             PLAT_LOGE("GpioIrqRecordCreate: create irq thread failed:%d", ret);
201             return ret;
202         }
203         (void)OsalSpinInit(&irqRecord->spin);
204         (void)OsalSemInit(&irqRecord->sem, 0);
205         cfg.name = (char *)ginfo->name;
206         cfg.priority = OSAL_THREAD_PRI_HIGHEST;
207         cfg.stackSize = GPIO_IRQ_STACK_SIZE;
208         ret = OsalThreadStart(&irqRecord->thread, &cfg);
209         if (ret != HDF_SUCCESS) {
210             (void)OsalSemDestroy(&irqRecord->sem);
211             (void)OsalSpinDestroy(&irqRecord->spin);
212             (void)OsalThreadDestroy(&irqRecord->thread);
213             OsalMemFree(irqRecord);
214             PLAT_LOGE("GpioIrqRecordCreate: start irq thread failed:%d", ret);
215             return ret;
216         }
217         PLAT_LOGI("GpioIrqRecordCreate: gpio(%u) thread started", GpioInfoToGlobal(ginfo));
218     }
219 
220     *new = irqRecord;
221     return HDF_SUCCESS;
222 }
223 
GpioCntlrSetIrq(struct GpioCntlr * cntlr,uint16_t local,uint16_t mode,GpioIrqFunc func,void * arg)224 int32_t GpioCntlrSetIrq(struct GpioCntlr *cntlr, uint16_t local, uint16_t mode, GpioIrqFunc func, void *arg)
225 {
226     int32_t ret;
227     struct GpioInfo *ginfo = NULL;
228     struct GpioIrqRecord *irqRecord = NULL;
229 
230     if (cntlr == NULL || cntlr->ginfos == NULL) {
231         return HDF_ERR_INVALID_OBJECT;
232     }
233     if (local >= cntlr->count || func == NULL) {
234         return HDF_ERR_INVALID_PARAM;
235     }
236     if (cntlr->ops == NULL || cntlr->ops->setIrq == NULL) {
237         return HDF_ERR_NOT_SUPPORT;
238     }
239 
240     ginfo = &cntlr->ginfos[local];
241     ret = GpioIrqRecordCreate(ginfo, mode, func, arg, &irqRecord);
242     if (ret != HDF_SUCCESS) {
243         PLAT_LOGE("GpioCntlrSetIrq: create irq record failed:%d", ret);
244         return ret;
245     }
246 
247     ret = GpioCntlrSetIrqInner(ginfo, irqRecord);
248     if (ret != HDF_SUCCESS) {
249         GpioIrqRecordDestroy(irqRecord);
250     }
251     return ret;
252 }
253 
GpioCntlrUnsetIrq(struct GpioCntlr * cntlr,uint16_t local,void * arg)254 int32_t GpioCntlrUnsetIrq(struct GpioCntlr *cntlr, uint16_t local, void *arg)
255 {
256     int32_t ret;
257     struct GpioInfo *ginfo = NULL;
258     struct GpioIrqRecord *irqRecord = NULL;
259 
260     if (cntlr == NULL || cntlr->ginfos == NULL) {
261         return HDF_ERR_INVALID_OBJECT;
262     }
263     if (local >= cntlr->count) {
264         return HDF_ERR_INVALID_PARAM;
265     }
266     if (cntlr->ops == NULL || cntlr->ops->unsetIrq == NULL) {
267         return HDF_ERR_NOT_SUPPORT;
268     }
269 
270     ginfo = &cntlr->ginfos[local];
271     GpioInfoLock(ginfo);
272     if (ginfo->irqRecord == NULL) {
273         GpioInfoUnlock(ginfo);
274         PLAT_LOGE("GpioCntlrUnsetIrq: gpio(%u+%u) irq not set yet", cntlr->start, local);
275         return HDF_ERR_NOT_SUPPORT;
276     }
277     irqRecord = ginfo->irqRecord;
278     if (arg != irqRecord->irqData) {
279         GpioInfoUnlock(ginfo);
280         PLAT_LOGE("GpioCntlrUnsetIrq: gpio(%u+%u) arg not match", cntlr->start, local);
281         return HDF_ERR_INVALID_PARAM;
282     }
283     ret = cntlr->ops->unsetIrq(cntlr, local);
284     if (ret == HDF_SUCCESS) {
285         ginfo->irqRecord = NULL;
286     }
287     GpioInfoUnlock(ginfo);
288 
289     if (ret == HDF_SUCCESS) {
290         GpioIrqRecordDestroy(irqRecord);
291     }
292     return ret;
293 }
294 
GpioCntlrEnableIrq(struct GpioCntlr * cntlr,uint16_t local)295 int32_t GpioCntlrEnableIrq(struct GpioCntlr *cntlr, uint16_t local)
296 {
297     if (cntlr == NULL) {
298         return HDF_ERR_INVALID_OBJECT;
299     }
300     if (cntlr->ops == NULL || cntlr->ops->enableIrq == NULL) {
301         return HDF_ERR_NOT_SUPPORT;
302     }
303 
304     return cntlr->ops->enableIrq(cntlr, local);
305 }
306 
GpioCntlrDisableIrq(struct GpioCntlr * cntlr,uint16_t local)307 int32_t GpioCntlrDisableIrq(struct GpioCntlr *cntlr, uint16_t local)
308 {
309     if (cntlr == NULL) {
310         return HDF_ERR_INVALID_OBJECT;
311     }
312     if (cntlr->ops == NULL || cntlr->ops->disableIrq == NULL) {
313         return HDF_ERR_NOT_SUPPORT;
314     }
315 
316     return cntlr->ops->disableIrq(cntlr, local);
317 }
318