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