• 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 #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("GpioCntlrCheckStart: start:%hu not available(freeStart:%hu, freeCount:%hu)",
41                 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("GpioCntlrCheckStart: start:%hu(%hu) not available(lastStart:%hu, lastCount:%hu)",
57         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("GpioManagerAdd: start:%hu(%hu) invalid:%d!", cntlr->start, cntlr->count, ret);
69         return HDF_ERR_INVALID_PARAM;
70     }
71 
72     DListInsertTail(&device->node, &manager->devices);
73     PLAT_LOGI("GpioManagerAdd: start:%hu count:%hu added success!", 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("GpioCntlrCreateGpioInfos: gpio ginfos is null!");
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("GpioCntlrCreateGpioInfos: default format gpio name fail!");
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("GpioCntlrAdd: cntlr is null!");
171         return HDF_ERR_INVALID_OBJECT;
172     }
173 
174     if (cntlr->ops == NULL) {
175         HDF_LOGE("GpioCntlrAdd: no ops supplied!");
176         return HDF_ERR_INVALID_OBJECT;
177     }
178 
179     if (cntlr->count == 0 || cntlr->count >= MAX_CNT_PER_CNTLR) {
180         HDF_LOGE("GpioCntlrAdd: invalid gpio count:%hu!", cntlr->count);
181         return HDF_ERR_INVALID_PARAM;
182     }
183 
184     ret = GpioCntlrCreateGpioInfos(cntlr);
185     if (ret != HDF_SUCCESS) {
186         HDF_LOGE("GpioCntlrAdd: fail to creat gpio infos:%d!", ret);
187         return ret;
188     }
189     cntlr->device.manager = GpioManagerGet();
190     ret = PlatformDeviceAdd(&cntlr->device);
191     if (ret != HDF_SUCCESS) {
192         HDF_LOGE("GpioCntlrAdd: fail to add device:%d!", 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         HDF_LOGE("GpioCntlrRemove: cntlr is null!");
204         return;
205     }
206 
207     PlatformDeviceDel(&cntlr->device);
208 
209     if (cntlr->ginfos == NULL) {
210         HDF_LOGE("GpioCntlrRemove: ginfos is null!");
211         return;
212     }
213 
214     GpioCntlrDestroyGpioInfos(cntlr);
215 }
216 
GpioCntlrFindMatch(struct PlatformDevice * device,void * data)217 static bool GpioCntlrFindMatch(struct PlatformDevice *device, void *data)
218 {
219     uint16_t gpio = (uint16_t)(uintptr_t)data;
220     struct GpioCntlr *cntlr = CONTAINER_OF(device, struct GpioCntlr, device);
221 
222     if (gpio >= cntlr->start && gpio < (cntlr->start + cntlr->count)) {
223         return true;
224     }
225     return false;
226 }
227 
GpioCntlrGetByGpio(uint16_t gpio)228 struct GpioCntlr *GpioCntlrGetByGpio(uint16_t gpio)
229 {
230     struct PlatformManager *gpioMgr = NULL;
231     struct PlatformDevice *device = NULL;
232 
233     gpioMgr = GpioManagerGet();
234     if (gpioMgr == NULL) {
235         HDF_LOGE("GpioCntlrGetByGpio: fail to get gpio manager!");
236         return NULL;
237     }
238 
239     device = PlatformManagerFindDevice(gpioMgr, (void *)(uintptr_t)gpio, GpioCntlrFindMatch);
240     if (device == NULL) {
241         HDF_LOGE("GpioCntlrGetByGpio: gpio %hu is not in any controllers!", gpio);
242         return NULL;
243     }
244     return CONTAINER_OF(device, struct GpioCntlr, device);
245 }
246 
GpioCntlrFindMatchByName(struct PlatformDevice * device,void * data)247 static bool GpioCntlrFindMatchByName(struct PlatformDevice *device, void *data)
248 {
249     uint32_t index;
250     char *tmpName = (char *)data;
251     struct GpioCntlr *cntlr = NULL;
252 
253     cntlr = CONTAINER_OF(device, struct GpioCntlr, device);
254     if (cntlr == NULL) {
255         HDF_LOGE("GpioCntlrFindMatchByName: cntlr is null!");
256         return false;
257     }
258 
259     for (index = 0; index < cntlr->count; index++) {
260         if (strcmp(cntlr->ginfos[index].name, tmpName) == 0) {
261             return true;
262         }
263     }
264     return false;
265 }
266 
GpioCntlrGetByGpioName(const char * gpioName)267 struct GpioCntlr *GpioCntlrGetByGpioName(const char *gpioName)
268 {
269     struct PlatformManager *gpioMgr = NULL;
270     struct PlatformDevice *device = NULL;
271 
272     gpioMgr = GpioManagerGet();
273     if (gpioMgr == NULL) {
274         HDF_LOGE("GpioCntlrGetByGpioName: fail to get gpio manager!");
275         return NULL;
276     }
277 
278     device = PlatformManagerFindDevice(gpioMgr, (void *)gpioName, GpioCntlrFindMatchByName);
279     if (device == NULL) {
280         HDF_LOGE("GpioCntlrGetByGpioName: gpio %s is not in any controllers!", gpioName);
281         return NULL;
282     }
283     return CONTAINER_OF(device, struct GpioCntlr, device);
284 }
285