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