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