• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020-2023 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("GpioCntlrWrite: cntlr is null!");
42         return HDF_ERR_INVALID_OBJECT;
43     }
44     if (cntlr->ops == NULL || cntlr->ops->write == NULL) {
45         HDF_LOGE("GpioCntlrWrite: ops or write is null!");
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("GpioCntlrRead: cntlr is null!");
56         return HDF_ERR_INVALID_OBJECT;
57     }
58     if (cntlr->ops == NULL || cntlr->ops->read == NULL) {
59         HDF_LOGE("GpioCntlrRead: ops or read is null!");
60         return HDF_ERR_NOT_SUPPORT;
61     }
62     if (val == NULL) {
63         HDF_LOGE("GpioCntlrRead: val is null!");
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("GpioCntlrSetDir: cntlr is null!");
74         return HDF_ERR_INVALID_OBJECT;
75     }
76     if (cntlr->ops == NULL || cntlr->ops->setDir == NULL) {
77         HDF_LOGE("GpioCntlrSetDir: ops or setDir is null!");
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("GpioCntlrGetDir: cntlr is null!");
88         return HDF_ERR_INVALID_OBJECT;
89     }
90     if (cntlr->ops == NULL || cntlr->ops->getDir == NULL) {
91         HDF_LOGE("GpioCntlrGetDir: ops or getDir is null!");
92         return HDF_ERR_NOT_SUPPORT;
93     }
94     if (dir == NULL) {
95         HDF_LOGE("GpioCntlrGetDir: dir is null!");
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("GpioCntlrToIrq: cntlr is null!");
106         return HDF_ERR_INVALID_OBJECT;
107     }
108     if (cntlr->ops == NULL || cntlr->ops->toIrq == NULL) {
109         HDF_LOGE("GpioCntlrToIrq: ops or toIrq is null!");
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("GpioCntlrIrqCallback: invalid cntlr(ginfos) or loal num:%hu!", local);
123         return;
124     }
125     ginfo = &cntlr->ginfos[local];
126     if (ginfo == NULL) {
127         HDF_LOGW("GpioCntlrIrqCallback: ginfo null(start:%hu, local:%hu)", cntlr->start, local);
128         return;
129     }
130 
131     GpioInfoLock(ginfo);
132     irqRecord = ginfo->irqRecord;
133 
134     if (irqRecord == NULL) {
135         HDF_LOGW("GpioCntlrIrqCallback: irq not set (start:%hu, local:%hu)", 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     if (irqRecord == NULL) {
150         HDF_LOGI("GpioCntlrIrqThreadHandler: irqRecord is null!");
151         return HDF_FAILURE;
152     }
153     while (true) {
154         ret = OsalSemWait(&irqRecord->sem, HDF_WAIT_FOREVER);
155         if (irqRecord->removed) {
156             break;
157         }
158         if (ret != HDF_SUCCESS) {
159             continue;
160         }
161         if (irqRecord->btmFunc != NULL) {
162             (void)irqRecord->btmFunc(irqRecord->global, irqRecord->irqData);
163         }
164     }
165     (void)OsalSpinLockIrqSave(&irqRecord->spin, &irqSave);
166     (void)OsalSpinUnlockIrqRestore(&irqRecord->spin, &irqSave); // last post done
167     HDF_LOGI("GpioCntlrIrqThreadHandler: gpio(%hu) thread exit!", irqRecord->global);
168     (void)OsalSemDestroy(&irqRecord->sem);
169     (void)OsalSpinDestroy(&irqRecord->spin);
170     (void)OsalThreadDestroy(&irqRecord->thread);
171     OsalMemFree(irqRecord);
172     return HDF_SUCCESS;
173 }
174 
GpioCntlrSetIrqInner(struct GpioInfo * ginfo,struct GpioIrqRecord * irqRecord)175 static int32_t GpioCntlrSetIrqInner(struct GpioInfo *ginfo, struct GpioIrqRecord *irqRecord)
176 {
177     int32_t ret;
178     uint16_t local = GpioInfoToLocal(ginfo);
179     struct GpioCntlr *cntlr = ginfo->cntlr;
180 
181     if (cntlr == NULL) {
182         HDF_LOGE("GpioCntlrSetIrqInner: cntlr is null!");
183         return HDF_ERR_INVALID_PARAM;
184     }
185     GpioInfoLock(ginfo);
186 
187     if (ginfo->irqRecord != NULL) {
188         GpioInfoUnlock(ginfo);
189         HDF_LOGE("GpioCntlrSetIrqInner: gpio(%hu+%hu) irq already set!", cntlr->start, local);
190         return HDF_ERR_NOT_SUPPORT;
191     }
192 
193     ginfo->irqRecord = irqRecord;
194     GpioInfoUnlock(ginfo);
195     ret = cntlr->ops->setIrq(cntlr, local, irqRecord->mode);
196     if (ret != HDF_SUCCESS) {
197         GpioInfoLock(ginfo);
198         HDF_LOGE("GpioCntlrSetIrqInner: gpio fail to setIrq!");
199         ginfo->irqRecord = NULL;
200         GpioInfoUnlock(ginfo);
201     }
202     return ret;
203 }
204 
GpioIrqRecordCreate(struct GpioInfo * ginfo,uint16_t mode,GpioIrqFunc func,void * arg,struct GpioIrqRecord ** new)205 static int32_t GpioIrqRecordCreate(struct GpioInfo *ginfo, uint16_t mode, GpioIrqFunc func, void *arg,
206     struct GpioIrqRecord **new)
207 {
208     int32_t ret;
209     struct GpioIrqRecord *irqRecord = NULL;
210     struct OsalThreadParam cfg;
211 
212     irqRecord = (struct GpioIrqRecord *)OsalMemCalloc(sizeof(*irqRecord));
213     if (irqRecord == NULL) {
214         HDF_LOGE("GpioIrqRecordCreate: fail to calloc for irqRecord!");
215         return HDF_ERR_MALLOC_FAIL;
216     }
217     irqRecord->removed = false;
218     irqRecord->mode = mode;
219     irqRecord->irqFunc = ((mode & GPIO_IRQ_USING_THREAD) == 0) ? func : NULL;
220     irqRecord->btmFunc = ((mode & GPIO_IRQ_USING_THREAD) != 0) ? func : NULL;
221     irqRecord->irqData = arg;
222     irqRecord->global = GpioInfoToGlobal(ginfo);
223     if (irqRecord->btmFunc != NULL) {
224         ret = OsalThreadCreate(&irqRecord->thread, GpioCntlrIrqThreadHandler, irqRecord);
225         if (ret != HDF_SUCCESS) {
226             OsalMemFree(irqRecord);
227             HDF_LOGE("GpioIrqRecordCreate: fail to create irq thread, ret: %d!", ret);
228             return ret;
229         }
230         (void)OsalSpinInit(&irqRecord->spin);
231         (void)OsalSemInit(&irqRecord->sem, 0);
232         cfg.name = (char *)ginfo->name;
233         cfg.priority = OSAL_THREAD_PRI_HIGHEST;
234         cfg.stackSize = GPIO_IRQ_STACK_SIZE;
235         ret = OsalThreadStart(&irqRecord->thread, &cfg);
236         if (ret != HDF_SUCCESS) {
237             (void)OsalSemDestroy(&irqRecord->sem);
238             (void)OsalSpinDestroy(&irqRecord->spin);
239             (void)OsalThreadDestroy(&irqRecord->thread);
240             OsalMemFree(irqRecord);
241             HDF_LOGE("GpioIrqRecordCreate: fail to start irq thread, ret: %d!", ret);
242             return ret;
243         }
244         HDF_LOGI("GpioIrqRecordCreate: gpio(%hu) thread started!", GpioInfoToGlobal(ginfo));
245     }
246 
247     *new = irqRecord;
248     return HDF_SUCCESS;
249 }
250 
GpioCntlrSetIrq(struct GpioCntlr * cntlr,uint16_t local,uint16_t mode,GpioIrqFunc func,void * arg)251 int32_t GpioCntlrSetIrq(struct GpioCntlr *cntlr, uint16_t local, uint16_t mode, GpioIrqFunc func, void *arg)
252 {
253     int32_t ret;
254     struct GpioInfo *ginfo = NULL;
255     struct GpioIrqRecord *irqRecord = NULL;
256 
257     if (cntlr == NULL || cntlr->ginfos == NULL) {
258         HDF_LOGE("GpioCntlrSetIrq: cntlr or ginfos is null!");
259         return HDF_ERR_INVALID_OBJECT;
260     }
261     if (local >= cntlr->count || func == NULL) {
262         HDF_LOGE("GpioCntlrSetIrq: local is invalid or func is null!");
263         return HDF_ERR_INVALID_PARAM;
264     }
265     if (cntlr->ops == NULL || cntlr->ops->setIrq == NULL) {
266         HDF_LOGE("GpioCntlrSetIrq: ops or setIrq is null!");
267         return HDF_ERR_NOT_SUPPORT;
268     }
269 
270     ginfo = &cntlr->ginfos[local];
271     ret = GpioIrqRecordCreate(ginfo, mode, func, arg, &irqRecord);
272     if (ret != HDF_SUCCESS) {
273         HDF_LOGE("GpioCntlrSetIrq: fail to create irq record, ret: %d!", ret);
274         return ret;
275     }
276 
277     ret = GpioCntlrSetIrqInner(ginfo, irqRecord);
278     if (ret != HDF_SUCCESS) {
279         HDF_LOGE("GpioCntlrSetIrq: fail to set irq inner, ret: %d!", ret);
280         GpioIrqRecordDestroy(irqRecord);
281     }
282     return ret;
283 }
284 
GpioCntlrUnsetIrq(struct GpioCntlr * cntlr,uint16_t local,void * arg)285 int32_t GpioCntlrUnsetIrq(struct GpioCntlr *cntlr, uint16_t local, void *arg)
286 {
287     int32_t ret;
288     struct GpioInfo *ginfo = NULL;
289     struct GpioIrqRecord *irqRecord = NULL;
290 
291     if (cntlr == NULL || cntlr->ginfos == NULL) {
292         HDF_LOGE("GpioCntlrUnsetIrq: cntlr or ginfos is null!");
293         return HDF_ERR_INVALID_OBJECT;
294     }
295     if (local >= cntlr->count) {
296         HDF_LOGE("GpioCntlrUnsetIrq: local is invalid!");
297         return HDF_ERR_INVALID_PARAM;
298     }
299     if (cntlr->ops == NULL || cntlr->ops->unsetIrq == NULL) {
300         HDF_LOGE("GpioCntlrUnsetIrq: ops or unsetIrq is null!");
301         return HDF_ERR_NOT_SUPPORT;
302     }
303 
304     ginfo = &cntlr->ginfos[local];
305     GpioInfoLock(ginfo);
306     if (ginfo->irqRecord == NULL) {
307         GpioInfoUnlock(ginfo);
308         HDF_LOGE("GpioCntlrUnsetIrq: gpio(%hu+%hu) irq not set yet!", cntlr->start, local);
309         return HDF_ERR_NOT_SUPPORT;
310     }
311     irqRecord = ginfo->irqRecord;
312     if (arg != irqRecord->irqData) {
313         GpioInfoUnlock(ginfo);
314         HDF_LOGE("GpioCntlrUnsetIrq: gpio(%hu+%hu) arg not match!", cntlr->start, local);
315         return HDF_ERR_INVALID_PARAM;
316     }
317     ret = cntlr->ops->unsetIrq(cntlr, local);
318     if (ret == HDF_SUCCESS) {
319         ginfo->irqRecord = NULL;
320     }
321     GpioInfoUnlock(ginfo);
322 
323     if (ret == HDF_SUCCESS) {
324         GpioIrqRecordDestroy(irqRecord);
325     }
326     return ret;
327 }
328 
GpioCntlrEnableIrq(struct GpioCntlr * cntlr,uint16_t local)329 int32_t GpioCntlrEnableIrq(struct GpioCntlr *cntlr, uint16_t local)
330 {
331     if (cntlr == NULL) {
332         HDF_LOGE("GpioCntlrEnableIrq: cntlr is null!");
333         return HDF_ERR_INVALID_OBJECT;
334     }
335     if (cntlr->ops == NULL || cntlr->ops->enableIrq == NULL) {
336         HDF_LOGE("GpioCntlrEnableIrq: ops or enableIrq is null!");
337         return HDF_ERR_NOT_SUPPORT;
338     }
339 
340     return cntlr->ops->enableIrq(cntlr, local);
341 }
342 
GpioCntlrDisableIrq(struct GpioCntlr * cntlr,uint16_t local)343 int32_t GpioCntlrDisableIrq(struct GpioCntlr *cntlr, uint16_t local)
344 {
345     if (cntlr == NULL) {
346         HDF_LOGE("GpioCntlrDisableIrq: cntlr is null!");
347         return HDF_ERR_INVALID_OBJECT;
348     }
349     if (cntlr->ops == NULL || cntlr->ops->disableIrq == NULL) {
350         HDF_LOGE("GpioCntlrDisableIrq: ops or disableIrq is null!");
351         return HDF_ERR_NOT_SUPPORT;
352     }
353 
354     return cntlr->ops->disableIrq(cntlr, local);
355 }
356 
GpioCntlrGetNumByGpioName(struct GpioCntlr * cntlr,const char * gpioName)357 int32_t GpioCntlrGetNumByGpioName(struct GpioCntlr *cntlr, const char *gpioName)
358 {
359     uint16_t index;
360 
361     if (cntlr == NULL) {
362         HDF_LOGE("GpioCntlrGetNumByGpioName: cntlr is null!");
363         return HDF_ERR_INVALID_OBJECT;
364     }
365 
366     if (gpioName == NULL || strlen(gpioName) > GPIO_NAME_LEN) {
367         HDF_LOGE("GpioCntlrGetNumByGpioName: gpioName is null or gpioName len out of range!");
368         return HDF_ERR_INVALID_OBJECT;
369     }
370 
371     for (index = 0; index < cntlr->count; index++) {
372         if (strcmp(cntlr->ginfos[index].name, gpioName) == 0) {
373             HDF_LOGD("GpioCntlrGetNumByGpioName: gpioName:%s get gpio number: %d success!", gpioName,
374                 (int32_t)(cntlr->start + index));
375             return (int32_t)(cntlr->start + index);
376         }
377     }
378     HDF_LOGE("GpioCntlrGetNumByGpioName: gpioName:%s fail to get gpio number!", gpioName);
379     return HDF_FAILURE;
380 }
381