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