• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020-2022 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 #ifdef __LITEOS_M__
11 #include "los_interrupt.h"
12 #endif
13 #include "osal_mem.h"
14 #include "platform_core.h"
15 
16 #define HDF_LOG_TAG gpio_core
17 
18 #define GPIO_IRQ_STACK_SIZE        10000
19 
GpioInfoLock(struct GpioInfo * ginfo)20 static inline void GpioInfoLock(struct GpioInfo *ginfo)
21 {
22 #ifndef __LITEOS_M__
23     (void)OsalSpinLockIrqSave(&ginfo->spin, &ginfo->irqSave);
24 #else
25     ginfo->irqSave = LOS_IntLock();
26 #endif
27 }
28 
GpioInfoUnlock(struct GpioInfo * ginfo)29 static inline void GpioInfoUnlock(struct GpioInfo *ginfo)
30 {
31 #ifndef __LITEOS_M__
32     (void)OsalSpinUnlockIrqRestore(&ginfo->spin, &ginfo->irqSave);
33 #else
34     LOS_IntRestore(ginfo->irqSave);
35 #endif
36 }
37 
GpioCntlrWrite(struct GpioCntlr * cntlr,uint16_t local,uint16_t val)38 int32_t GpioCntlrWrite(struct GpioCntlr *cntlr, uint16_t local, uint16_t val)
39 {
40     if (cntlr == NULL) {
41         HDF_LOGE("%s: cntlr is NULL!", __func__);
42         return HDF_ERR_INVALID_OBJECT;
43     }
44     if (cntlr->ops == NULL || cntlr->ops->write == NULL) {
45         HDF_LOGE("%s: ops or write is NULL!", __func__);
46         return HDF_ERR_NOT_SUPPORT;
47     }
48 
49     return cntlr->ops->write(cntlr, local, val);
50 }
51 
GpioCntlrRead(struct GpioCntlr * cntlr,uint16_t local,uint16_t * val)52 int32_t GpioCntlrRead(struct GpioCntlr *cntlr, uint16_t local, uint16_t *val)
53 {
54     if (cntlr == NULL) {
55         HDF_LOGE("%s: cntlr is NULL!", __func__);
56         return HDF_ERR_INVALID_OBJECT;
57     }
58     if (cntlr->ops == NULL || cntlr->ops->read == NULL) {
59         HDF_LOGE("%s: ops or read is NULL!", __func__);
60         return HDF_ERR_NOT_SUPPORT;
61     }
62     if (val == NULL) {
63         HDF_LOGE("%s: val is NULL!", __func__);
64         return HDF_ERR_INVALID_PARAM;
65     }
66 
67     return cntlr->ops->read(cntlr, local, val);
68 }
69 
GpioCntlrSetDir(struct GpioCntlr * cntlr,uint16_t local,uint16_t dir)70 int32_t GpioCntlrSetDir(struct GpioCntlr *cntlr, uint16_t local, uint16_t dir)
71 {
72     if (cntlr == NULL) {
73         HDF_LOGE("%s: cntlr is NULL!", __func__);
74         return HDF_ERR_INVALID_OBJECT;
75     }
76     if (cntlr->ops == NULL || cntlr->ops->setDir == NULL) {
77         HDF_LOGE("%s: ops or setDir is NULL!", __func__);
78         return HDF_ERR_NOT_SUPPORT;
79     }
80 
81     return cntlr->ops->setDir(cntlr, local, dir);
82 }
83 
GpioCntlrGetDir(struct GpioCntlr * cntlr,uint16_t local,uint16_t * dir)84 int32_t GpioCntlrGetDir(struct GpioCntlr *cntlr, uint16_t local, uint16_t *dir)
85 {
86     if (cntlr == NULL) {
87         HDF_LOGE("%s: cntlr is NULL!", __func__);
88         return HDF_ERR_INVALID_OBJECT;
89     }
90     if (cntlr->ops == NULL || cntlr->ops->getDir == NULL) {
91         HDF_LOGE("%s: ops or getDir is NULL!", __func__);
92         return HDF_ERR_NOT_SUPPORT;
93     }
94     if (dir == NULL) {
95         HDF_LOGE("%s: dir is NULL!", __func__);
96         return HDF_ERR_INVALID_PARAM;
97     }
98 
99     return cntlr->ops->getDir(cntlr, local, dir);
100 }
101 
GpioCntlrToIrq(struct GpioCntlr * cntlr,uint16_t local,uint16_t * irq)102 int32_t GpioCntlrToIrq(struct GpioCntlr *cntlr, uint16_t local, uint16_t *irq)
103 {
104     if (cntlr == NULL) {
105         HDF_LOGE("%s: cntlr is NULL!", __func__);
106         return HDF_ERR_INVALID_OBJECT;
107     }
108     if (cntlr->ops == NULL || cntlr->ops->toIrq == NULL) {
109         HDF_LOGE("%s: ops or toIrq is NULL!", __func__);
110         return HDF_ERR_NOT_SUPPORT;
111     }
112 
113     return cntlr->ops->toIrq(cntlr, local, irq);
114 }
115 
GpioCntlrIrqCallback(struct GpioCntlr * cntlr,uint16_t local)116 void GpioCntlrIrqCallback(struct GpioCntlr *cntlr, uint16_t local)
117 {
118     struct GpioInfo *ginfo = NULL;
119     struct GpioIrqRecord *irqRecord = NULL;
120 
121     if (cntlr == NULL || cntlr->ginfos == NULL || local >= cntlr->count) {
122         HDF_LOGW("%s: invalid cntlr(ginfos) or loal num:%hu!", __func__, local);
123         return;
124     }
125     ginfo = &cntlr->ginfos[local];
126     if (ginfo == NULL) {
127         HDF_LOGW("%s: ginfo null(start:%hu, local:%hu)", __func__, cntlr->start, local);
128         return;
129     }
130 
131     GpioInfoLock(ginfo);
132     irqRecord = ginfo->irqRecord;
133 
134     if (irqRecord == NULL) {
135         HDF_LOGW("%s: irq not set (start:%hu, local:%hu)", __func__, cntlr->start, local);
136         GpioInfoUnlock(ginfo);
137         return;
138     }
139     GpioIrqRecordTrigger(irqRecord);
140     GpioInfoUnlock(ginfo);
141 }
142 
GpioCntlrIrqThreadHandler(void * data)143 static int32_t GpioCntlrIrqThreadHandler(void *data)
144 {
145     int32_t ret;
146     uint32_t irqSave;
147     struct GpioIrqRecord *irqRecord = (struct GpioIrqRecord *)data;
148 
149     while (true) {
150         ret = OsalSemWait(&irqRecord->sem, HDF_WAIT_FOREVER);
151         if (irqRecord->removed) {
152             break;
153         }
154         if (ret != HDF_SUCCESS) {
155             continue;
156         }
157         if (irqRecord->btmFunc != NULL) {
158             (void)irqRecord->btmFunc(irqRecord->global, irqRecord->irqData);
159         }
160     }
161     (void)OsalSpinLockIrqSave(&irqRecord->spin, &irqSave);
162     (void)OsalSpinUnlockIrqRestore(&irqRecord->spin, &irqSave); // last post done
163     HDF_LOGI("%s: gpio(%hu) thread exit!", __func__, irqRecord->global);
164     (void)OsalSemDestroy(&irqRecord->sem);
165     (void)OsalSpinDestroy(&irqRecord->spin);
166     (void)OsalThreadDestroy(&irqRecord->thread);
167     OsalMemFree(irqRecord);
168     return HDF_SUCCESS;
169 }
170 
GpioCntlrSetIrqInner(struct GpioInfo * ginfo,struct GpioIrqRecord * irqRecord)171 static int32_t GpioCntlrSetIrqInner(struct GpioInfo *ginfo, struct GpioIrqRecord *irqRecord)
172 {
173     int32_t ret;
174     uint16_t local = GpioInfoToLocal(ginfo);
175     struct GpioCntlr *cntlr = ginfo->cntlr;
176 
177     if (cntlr == NULL) {
178         HDF_LOGE("%s: cntlr is NULL!", __func__);
179         return HDF_ERR_INVALID_PARAM;
180     }
181     GpioInfoLock(ginfo);
182 
183     if (ginfo->irqRecord != NULL) {
184         GpioInfoUnlock(ginfo);
185         HDF_LOGE("%s: gpio(%hu+%hu) irq already set!", __func__, cntlr->start, local);
186         return HDF_ERR_NOT_SUPPORT;
187     }
188 
189     ginfo->irqRecord = irqRecord;
190     GpioInfoUnlock(ginfo);
191     ret = cntlr->ops->setIrq(cntlr, local, irqRecord->mode);
192     if (ret != HDF_SUCCESS) {
193         GpioInfoLock(ginfo);
194         HDF_LOGE("%s: gpio failed to setIrq!", __func__);
195         ginfo->irqRecord = NULL;
196         GpioInfoUnlock(ginfo);
197     }
198     return ret;
199 }
200 
GpioIrqRecordCreate(struct GpioInfo * ginfo,uint16_t mode,GpioIrqFunc func,void * arg,struct GpioIrqRecord ** new)201 static int32_t GpioIrqRecordCreate(struct GpioInfo *ginfo, uint16_t mode, GpioIrqFunc func, void *arg,
202     struct GpioIrqRecord **new)
203 {
204     int32_t ret;
205     struct GpioIrqRecord *irqRecord = NULL;
206     struct OsalThreadParam cfg;
207 
208     irqRecord = (struct GpioIrqRecord *)OsalMemCalloc(sizeof(*irqRecord));
209     if (irqRecord == NULL) {
210         HDF_LOGE("%s: failed to calloc for irqRecord!", __func__);
211         return HDF_ERR_MALLOC_FAIL;
212     }
213     irqRecord->removed = false;
214     irqRecord->mode = mode;
215     irqRecord->irqFunc = ((mode & GPIO_IRQ_USING_THREAD) == 0) ? func : NULL;
216     irqRecord->btmFunc = ((mode & GPIO_IRQ_USING_THREAD) != 0) ? func : NULL;
217     irqRecord->irqData = arg;
218     irqRecord->global = GpioInfoToGlobal(ginfo);
219     if (irqRecord->btmFunc != NULL) {
220         ret = OsalThreadCreate(&irqRecord->thread, GpioCntlrIrqThreadHandler, irqRecord);
221         if (ret != HDF_SUCCESS) {
222             OsalMemFree(irqRecord);
223             HDF_LOGE("%s: failed to create irq thread:%d!", __func__, ret);
224             return ret;
225         }
226         (void)OsalSpinInit(&irqRecord->spin);
227         (void)OsalSemInit(&irqRecord->sem, 0);
228         cfg.name = (char *)ginfo->name;
229         cfg.priority = OSAL_THREAD_PRI_HIGHEST;
230         cfg.stackSize = GPIO_IRQ_STACK_SIZE;
231         ret = OsalThreadStart(&irqRecord->thread, &cfg);
232         if (ret != HDF_SUCCESS) {
233             (void)OsalSemDestroy(&irqRecord->sem);
234             (void)OsalSpinDestroy(&irqRecord->spin);
235             (void)OsalThreadDestroy(&irqRecord->thread);
236             OsalMemFree(irqRecord);
237             HDF_LOGE("%s: failed to start irq thread:%d!", __func__, ret);
238             return ret;
239         }
240         HDF_LOGI("%s: gpio(%hu) thread started!", __func__, GpioInfoToGlobal(ginfo));
241     }
242 
243     *new = irqRecord;
244     return HDF_SUCCESS;
245 }
246 
GpioCntlrSetIrq(struct GpioCntlr * cntlr,uint16_t local,uint16_t mode,GpioIrqFunc func,void * arg)247 int32_t GpioCntlrSetIrq(struct GpioCntlr *cntlr, uint16_t local, uint16_t mode, GpioIrqFunc func, void *arg)
248 {
249     int32_t ret;
250     struct GpioInfo *ginfo = NULL;
251     struct GpioIrqRecord *irqRecord = NULL;
252 
253     if (cntlr == NULL || cntlr->ginfos == NULL) {
254         HDF_LOGE("%s: cntlr or ginfos is NULL!", __func__);
255         return HDF_ERR_INVALID_OBJECT;
256     }
257     if (local >= cntlr->count || func == NULL) {
258         HDF_LOGE("%s: local is invalid or func is NULL!", __func__);
259         return HDF_ERR_INVALID_PARAM;
260     }
261     if (cntlr->ops == NULL || cntlr->ops->setIrq == NULL) {
262         HDF_LOGE("%s: ops or setIrq is NULL!", __func__);
263         return HDF_ERR_NOT_SUPPORT;
264     }
265 
266     ginfo = &cntlr->ginfos[local];
267     ret = GpioIrqRecordCreate(ginfo, mode, func, arg, &irqRecord);
268     if (ret != HDF_SUCCESS) {
269         HDF_LOGE("%s: failed to create irq record:%d!", __func__, ret);
270         return ret;
271     }
272 
273     ret = GpioCntlrSetIrqInner(ginfo, irqRecord);
274     if (ret != HDF_SUCCESS) {
275         HDF_LOGE("%s: failed to set irq inner:%d!", __func__, ret);
276         GpioIrqRecordDestroy(irqRecord);
277     }
278     return ret;
279 }
280 
GpioCntlrUnsetIrq(struct GpioCntlr * cntlr,uint16_t local,void * arg)281 int32_t GpioCntlrUnsetIrq(struct GpioCntlr *cntlr, uint16_t local, void *arg)
282 {
283     int32_t ret;
284     struct GpioInfo *ginfo = NULL;
285     struct GpioIrqRecord *irqRecord = NULL;
286 
287     if (cntlr == NULL || cntlr->ginfos == NULL) {
288         HDF_LOGE("%s: cntlr or ginfos is NULL!", __func__);
289         return HDF_ERR_INVALID_OBJECT;
290     }
291     if (local >= cntlr->count) {
292         HDF_LOGE("%s: local is invalid!", __func__);
293         return HDF_ERR_INVALID_PARAM;
294     }
295     if (cntlr->ops == NULL || cntlr->ops->unsetIrq == NULL) {
296         HDF_LOGE("%s: ops or unsetIrq is NULL!", __func__);
297         return HDF_ERR_NOT_SUPPORT;
298     }
299 
300     ginfo = &cntlr->ginfos[local];
301     GpioInfoLock(ginfo);
302     if (ginfo->irqRecord == NULL) {
303         GpioInfoUnlock(ginfo);
304         HDF_LOGE("%s: gpio(%hu+%hu) irq not set yet!", __func__, cntlr->start, local);
305         return HDF_ERR_NOT_SUPPORT;
306     }
307     irqRecord = ginfo->irqRecord;
308     if (arg != irqRecord->irqData) {
309         GpioInfoUnlock(ginfo);
310         HDF_LOGE("%s: gpio(%hu+%hu) arg not match!", __func__, cntlr->start, local);
311         return HDF_ERR_INVALID_PARAM;
312     }
313     ret = cntlr->ops->unsetIrq(cntlr, local);
314     if (ret == HDF_SUCCESS) {
315         ginfo->irqRecord = NULL;
316     }
317     GpioInfoUnlock(ginfo);
318 
319     if (ret == HDF_SUCCESS) {
320         GpioIrqRecordDestroy(irqRecord);
321     }
322     return ret;
323 }
324 
GpioCntlrEnableIrq(struct GpioCntlr * cntlr,uint16_t local)325 int32_t GpioCntlrEnableIrq(struct GpioCntlr *cntlr, uint16_t local)
326 {
327     if (cntlr == NULL) {
328         HDF_LOGE("%s: cntlr is NULL!", __func__);
329         return HDF_ERR_INVALID_OBJECT;
330     }
331     if (cntlr->ops == NULL || cntlr->ops->enableIrq == NULL) {
332         HDF_LOGE("%s: ops or enableIrq is NULL!", __func__);
333         return HDF_ERR_NOT_SUPPORT;
334     }
335 
336     return cntlr->ops->enableIrq(cntlr, local);
337 }
338 
GpioCntlrDisableIrq(struct GpioCntlr * cntlr,uint16_t local)339 int32_t GpioCntlrDisableIrq(struct GpioCntlr *cntlr, uint16_t local)
340 {
341     if (cntlr == NULL) {
342         HDF_LOGE("%s: cntlr is NULL!", __func__);
343         return HDF_ERR_INVALID_OBJECT;
344     }
345     if (cntlr->ops == NULL || cntlr->ops->disableIrq == NULL) {
346         HDF_LOGE("%s: ops or disableIrq is NULL!", __func__);
347         return HDF_ERR_NOT_SUPPORT;
348     }
349 
350     return cntlr->ops->disableIrq(cntlr, local);
351 }
352 
GpioCntlrGetNumByGpioName(struct GpioCntlr * cntlr,const char * gpioName)353 int32_t GpioCntlrGetNumByGpioName(struct GpioCntlr *cntlr, const char *gpioName)
354 {
355     uint32_t index;
356 
357     if (cntlr == NULL) {
358         HDF_LOGE("%s: cntlr is NULL!", __func__);
359         return HDF_ERR_INVALID_OBJECT;
360     }
361 
362     if (gpioName == NULL || strlen(gpioName) > GPIO_NAME_LEN) {
363         HDF_LOGE("%s: gpioName is NULL or gpioName len out of range!", __func__);
364         return HDF_ERR_INVALID_OBJECT;
365     }
366 
367     for (index = 0; index < cntlr->count; index++) {
368         if (strcmp(cntlr->ginfos[index].name, gpioName) == 0) {
369             HDF_LOGD("%s: gpioName:%s get gpio number: %u success!", __func__, gpioName, index);
370             return cntlr->start + index;
371         }
372     }
373     HDF_LOGE("%s: gpioName:%s failed to get gpio number!", __func__, gpioName);
374     return HDF_FAILURE;
375 }
376