• 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 #include "osal_mem.h"
11 #include "platform_core.h"
12 #include "securec.h"
13 
14 #define HDF_LOG_TAG gpio_manager
15 
16 #define MAX_CNT_PER_CNTLR          1024
17 
GpioCntlrCheckStart(struct GpioCntlr * cntlr,struct DListHead * list)18 static int32_t GpioCntlrCheckStart(struct GpioCntlr *cntlr, struct DListHead *list)
19 {
20     uint16_t freeStart;
21     uint16_t freeCount;
22     struct PlatformDevice *iterLast = NULL;
23     struct PlatformDevice *iterCur = NULL;
24     struct PlatformDevice *tmp = NULL;
25     struct GpioCntlr *cntlrCur = NULL;
26     struct GpioCntlr *cntlrLast = NULL;
27 
28     DLIST_FOR_EACH_ENTRY_SAFE(iterCur, tmp, list, struct PlatformDevice, node) {
29         cntlrCur = CONTAINER_OF(iterCur, struct GpioCntlr, device);
30         cntlrLast = CONTAINER_OF(iterLast, struct GpioCntlr, device);
31         if (cntlrLast == NULL) {
32             freeStart = 0;
33             freeCount = cntlrCur->start;
34         } else {
35             freeStart = cntlrLast->start + cntlrLast->count;
36             freeCount = cntlrCur->start - freeStart;
37         }
38 
39         if (cntlr->start < freeStart) {
40             HDF_LOGE("%s: start:%hu not available(freeStart:%hu, freeCount:%hu)",
41                 __func__, cntlr->start, freeStart, freeCount);
42             return HDF_PLT_RSC_NOT_AVL;
43         }
44 
45         if ((cntlr->start + cntlr->count) <= (freeStart + freeCount)) {
46             return HDF_SUCCESS;
47         }
48         cntlrLast = cntlrCur;
49     }
50     if (cntlrLast == NULL) { // empty list
51         return HDF_SUCCESS;
52     }
53     if (cntlr->start >= (cntlrLast->start + cntlrLast->count)) {
54         return HDF_SUCCESS;
55     }
56     HDF_LOGE("%s: start:%hu(%hu) not available(lastStart:%hu, lastCount:%hu)",
57         __func__, cntlr->start, cntlr->count, cntlrLast->start, cntlrLast->count);
58     return GPIO_NUM_MAX;
59 }
60 
GpioManagerAdd(struct PlatformManager * manager,struct PlatformDevice * device)61 static int32_t GpioManagerAdd(struct PlatformManager *manager, struct PlatformDevice *device)
62 {
63     int32_t ret;
64     struct GpioCntlr *cntlr = CONTAINER_OF(device, struct GpioCntlr, device);
65 
66     ret = GpioCntlrCheckStart(cntlr, &manager->devices);
67     if (ret != HDF_SUCCESS) {
68         HDF_LOGE("%s: start:%hu(%hu) invalid:%d", __func__, cntlr->start, cntlr->count, ret);
69         return HDF_ERR_INVALID_PARAM;
70     }
71 
72     DListInsertTail(&device->node, &manager->devices);
73     PLAT_LOGI("%s: start:%hu count:%hu added success", __func__, cntlr->start, cntlr->count);
74     return HDF_SUCCESS;
75 }
76 
GpioManagerDel(struct PlatformManager * manager,struct PlatformDevice * device)77 static int32_t GpioManagerDel(struct PlatformManager *manager, struct PlatformDevice *device)
78 {
79     (void)manager;
80     if (!DListIsEmpty(&device->node)) {
81         DListRemove(&device->node);
82     }
83     return HDF_SUCCESS;
84 }
85 
GpioManagerGet(void)86 struct PlatformManager *GpioManagerGet(void)
87 {
88     static struct PlatformManager *manager = NULL;
89 
90     if (manager == NULL) {
91         manager = PlatformManagerGet(PLATFORM_MODULE_GPIO);
92         if (manager != NULL) {
93             manager->add = GpioManagerAdd;
94             manager->del = GpioManagerDel;
95         }
96     }
97     return manager;
98 }
99 
GpioInfosFree(struct GpioCntlr * cntlr)100 static inline void GpioInfosFree(struct GpioCntlr *cntlr)
101 {
102     if (cntlr->isAutoAlloced) {
103         OsalMemFree(cntlr->ginfos);
104         cntlr->ginfos = NULL;
105         cntlr->isAutoAlloced = false;
106     }
107 }
108 
GpioCntlrCreateGpioInfos(struct GpioCntlr * cntlr)109 static int32_t GpioCntlrCreateGpioInfos(struct GpioCntlr *cntlr)
110 {
111     int32_t ret;
112     uint16_t i;
113     static uint16_t groupNum = 0;
114 
115     if (cntlr->ginfos == NULL) {
116         cntlr->ginfos = OsalMemCalloc(sizeof(*cntlr->ginfos) * cntlr->count);
117         if (cntlr->ginfos == NULL) {
118             HDF_LOGE("%s: gpio ginfos is NULL", __func__);
119             return HDF_ERR_MALLOC_FAIL;
120         }
121         cntlr->isAutoAlloced = true;
122     }
123 
124     for (i = 0; i < cntlr->count; i++) {
125         cntlr->ginfos[i].cntlr = cntlr;
126         if (strlen(cntlr->ginfos[i].name) == 0) {
127             if (snprintf_s(cntlr->ginfos[i].name, GPIO_NAME_LEN, GPIO_NAME_LEN - 1,
128                 "GPIO%hu_%hu", groupNum, i) < 0) {
129                 HDF_LOGE("%s:default format gpio name failed", __func__);
130                 ret = HDF_PLT_ERR_OS_API;
131                 goto ERROR_EXIT;
132             }
133         }
134         (void)OsalSpinInit(&cntlr->ginfos[i].spin);
135     }
136     groupNum++;
137     return HDF_SUCCESS;
138 
139 ERROR_EXIT:
140     while (i-- > 0) {
141         (void)OsalSpinDestroy(&cntlr->ginfos[i].spin);
142     }
143 
144     OsalMemFree(cntlr->ginfos);
145     cntlr->ginfos = NULL;
146 
147     return ret;
148 }
149 
GpioCntlrDestroyGpioInfos(struct GpioCntlr * cntlr)150 static void GpioCntlrDestroyGpioInfos(struct GpioCntlr *cntlr)
151 {
152     uint16_t i;
153     struct GpioIrqRecord *irqRecord = NULL;
154 
155     for (i = 0; i < cntlr->count; i++) {
156         irqRecord = cntlr->ginfos[i].irqRecord;
157         if (irqRecord != NULL) {
158             GpioIrqRecordDestroy(irqRecord);
159         }
160         (void)OsalSpinDestroy(&cntlr->ginfos[i].spin);
161     }
162     GpioInfosFree(cntlr);
163 }
164 
GpioCntlrAdd(struct GpioCntlr * cntlr)165 int32_t GpioCntlrAdd(struct GpioCntlr *cntlr)
166 {
167     int32_t ret;
168 
169     if (cntlr == NULL) {
170         HDF_LOGE("%s: cntlr is NULL!", __func__);
171         return HDF_ERR_INVALID_OBJECT;
172     }
173 
174     if (cntlr->ops == NULL) {
175         HDF_LOGE("%s: no ops supplied!", __func__);
176         return HDF_ERR_INVALID_OBJECT;
177     }
178 
179     if (cntlr->count == 0 || cntlr->count >= MAX_CNT_PER_CNTLR) {
180         HDF_LOGE("%s: invalid gpio count:%hu", __func__, cntlr->count);
181         return HDF_ERR_INVALID_PARAM;
182     }
183 
184     ret = GpioCntlrCreateGpioInfos(cntlr);
185     if (ret != HDF_SUCCESS) {
186         HDF_LOGE("%s: failed to creat gpio infos:%d", __func__, ret);
187         return ret;
188     }
189     cntlr->device.manager = GpioManagerGet();
190     ret = PlatformDeviceAdd(&cntlr->device);
191     if (ret != HDF_SUCCESS) {
192         HDF_LOGE("%s: failed to add device:%d", __func__, ret);
193         GpioCntlrDestroyGpioInfos(cntlr);
194         return ret;
195     }
196 
197     return HDF_SUCCESS;
198 }
199 
GpioCntlrRemove(struct GpioCntlr * cntlr)200 void GpioCntlrRemove(struct GpioCntlr *cntlr)
201 {
202     if (cntlr == NULL) {
203         return;
204     }
205 
206     PlatformDeviceDel(&cntlr->device);
207 
208     if (cntlr->ginfos == NULL) {
209         return;
210     }
211 
212     GpioCntlrDestroyGpioInfos(cntlr);
213 }
214 
GpioCntlrFindMatch(struct PlatformDevice * device,void * data)215 static bool GpioCntlrFindMatch(struct PlatformDevice *device, void *data)
216 {
217     uint16_t gpio = (uint16_t)(uintptr_t)data;
218     struct GpioCntlr *cntlr = CONTAINER_OF(device, struct GpioCntlr, device);
219 
220     if (gpio >= cntlr->start && gpio < (cntlr->start + cntlr->count)) {
221         return true;
222     }
223     return false;
224 }
225 
GpioCntlrGetByGpio(uint16_t gpio)226 struct GpioCntlr *GpioCntlrGetByGpio(uint16_t gpio)
227 {
228     struct PlatformManager *gpioMgr = NULL;
229     struct PlatformDevice *device = NULL;
230 
231     gpioMgr = GpioManagerGet();
232     if (gpioMgr == NULL) {
233         HDF_LOGE("%s: failed to get gpio manager", __func__);
234         return NULL;
235     }
236 
237     device = PlatformManagerFindDevice(gpioMgr, (void *)(uintptr_t)gpio, GpioCntlrFindMatch);
238     if (device == NULL) {
239         HDF_LOGE("%s: gpio %hu is not in any controllers!", __func__, gpio);
240         return NULL;
241     }
242     return CONTAINER_OF(device, struct GpioCntlr, device);
243 }
244 
GpioCntlrFindMatchByName(struct PlatformDevice * device,void * data)245 static bool GpioCntlrFindMatchByName(struct PlatformDevice *device, void *data)
246 {
247     uint32_t index;
248     char *tmpName = (char *)data;
249     struct GpioCntlr *cntlr = NULL;
250 
251     cntlr = CONTAINER_OF(device, struct GpioCntlr, device);
252     if (cntlr == NULL) {
253         HDF_LOGE("%s: cntlr is NULL!", __func__);
254         return false;
255     }
256 
257     for (index = 0; index < cntlr->count; index++) {
258         if (strcmp(cntlr->ginfos[index].name, tmpName) == 0) {
259             return true;
260         }
261     }
262     return false;
263 }
264 
GpioCntlrGetByGpioName(const char * gpioName)265 struct GpioCntlr *GpioCntlrGetByGpioName(const char *gpioName)
266 {
267     struct PlatformManager *gpioMgr = NULL;
268     struct PlatformDevice *device = NULL;
269 
270     gpioMgr = GpioManagerGet();
271     if (gpioMgr == NULL) {
272         HDF_LOGE("%s: failed to get gpio manager", __func__);
273         return NULL;
274     }
275 
276     device = PlatformManagerFindDevice(gpioMgr, (void *)gpioName, GpioCntlrFindMatchByName);
277     if (device == NULL) {
278         HDF_LOGE("%s: gpio %s is not in any controllers!", __func__, gpioName);
279         return NULL;
280     }
281     return CONTAINER_OF(device, struct GpioCntlr, device);
282 }
283