1 /*
2 * Copyright (c) 2020-2021 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 PLAT_LOGE("GpioCntlrCheckStart: start:%u not available(freeStart:%u, freeCount:%u)",
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 PLAT_LOGE("GpioCntlrCheckStart: start:%u(%u) not available(lastStart:%u, lastCount:%u)",
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 PLAT_LOGE("GpioManagerAdd: start:%u(%u) 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:%u count:%u 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 if (!DListIsEmpty(&device->node)) {
80 DListRemove(&device->node);
81 }
82 return HDF_SUCCESS;
83 }
84
GpioManagerGet(void)85 struct PlatformManager *GpioManagerGet(void)
86 {
87 static struct PlatformManager *manager = NULL;
88
89 if (manager == NULL) {
90 manager = PlatformManagerGet(PLATFORM_MODULE_GPIO);
91 if (manager != NULL) {
92 manager->add = GpioManagerAdd;
93 manager->del = GpioManagerDel;
94 }
95 }
96 return manager;
97 }
98
GpioCntlrCreateGpioInfos(struct GpioCntlr * cntlr)99 static int32_t GpioCntlrCreateGpioInfos(struct GpioCntlr *cntlr)
100 {
101 int32_t ret;
102 uint16_t i;
103
104 cntlr->ginfos = OsalMemCalloc(sizeof(*cntlr->ginfos) * cntlr->count);
105 if (cntlr->ginfos == NULL) {
106 return HDF_ERR_MALLOC_FAIL;
107 }
108 for (i = 0; i < cntlr->count; i++) {
109 cntlr->ginfos[i].cntlr = cntlr;
110 if (snprintf_s(cntlr->ginfos[i].name, GPIO_NAME_LEN, GPIO_NAME_LEN - 1,
111 "GPIO%u+%u", cntlr->start, i) < 0) {
112 PLAT_LOGE("GpioCntlrCreateGpioInfos: format gpio name fail");
113 ret = HDF_PLT_ERR_OS_API;
114 goto ERROR_EXIT;
115 }
116 (void)OsalSpinInit(&cntlr->ginfos[i].spin);
117 }
118 return HDF_SUCCESS;
119
120 ERROR_EXIT:
121 while (i-- > 0) {
122 (void)OsalSpinDestroy(&cntlr->ginfos[i].spin);
123 }
124 OsalMemFree(cntlr->ginfos);
125 return ret;
126 }
127
GpioCntlrDestroyGpioInfos(struct GpioCntlr * cntlr)128 static void GpioCntlrDestroyGpioInfos(struct GpioCntlr *cntlr)
129 {
130 uint16_t i;
131 struct GpioIrqRecord *irqRecord = NULL;
132
133 for (i = 0; i < cntlr->count; i++) {
134 irqRecord = cntlr->ginfos[i].irqRecord;
135 if (irqRecord != NULL) {
136 GpioIrqRecordDestroy(irqRecord);
137 }
138 (void)OsalSpinDestroy(&cntlr->ginfos[i].spin);
139 }
140 OsalMemFree(cntlr->ginfos);
141 cntlr->ginfos = NULL;
142 }
143
GpioCntlrAdd(struct GpioCntlr * cntlr)144 int32_t GpioCntlrAdd(struct GpioCntlr *cntlr)
145 {
146 int32_t ret;
147
148 if (cntlr == NULL) {
149 return HDF_ERR_INVALID_OBJECT;
150 }
151
152 if (cntlr->ops == NULL) {
153 PLAT_LOGE("GpioCntlrAdd: no ops supplied!");
154 return HDF_ERR_INVALID_OBJECT;
155 }
156
157 if (cntlr->count == 0 || cntlr->count >= MAX_CNT_PER_CNTLR) {
158 PLAT_LOGE("GpioCntlrAdd: invalid gpio count:%u", cntlr->count);
159 return HDF_ERR_INVALID_PARAM;
160 }
161
162 ret = GpioCntlrCreateGpioInfos(cntlr);
163 if (ret != HDF_SUCCESS) {
164 return ret;
165 }
166 cntlr->device.manager = GpioManagerGet();
167 ret = PlatformDeviceAdd(&cntlr->device);
168 if (ret != HDF_SUCCESS) {
169 GpioCntlrDestroyGpioInfos(cntlr);
170 return ret;
171 }
172
173 return HDF_SUCCESS;
174 }
175
GpioCntlrRemove(struct GpioCntlr * cntlr)176 void GpioCntlrRemove(struct GpioCntlr *cntlr)
177 {
178 if (cntlr == NULL) {
179 return;
180 }
181
182 PlatformDeviceDel(&cntlr->device);
183
184 if (cntlr->ginfos == NULL) {
185 return;
186 }
187
188 GpioCntlrDestroyGpioInfos(cntlr);
189 }
190
GpioCntlrFindMatch(struct PlatformDevice * device,void * data)191 static bool GpioCntlrFindMatch(struct PlatformDevice *device, void *data)
192 {
193 uint16_t gpio = (uint16_t)(uintptr_t)data;
194 struct GpioCntlr *cntlr = CONTAINER_OF(device, struct GpioCntlr, device);
195
196 if (gpio >= cntlr->start && gpio < (cntlr->start + cntlr->count)) {
197 return true;
198 }
199 return false;
200 }
201
GpioCntlrGetByGpio(uint16_t gpio)202 struct GpioCntlr *GpioCntlrGetByGpio(uint16_t gpio)
203 {
204 struct PlatformManager *gpioMgr = NULL;
205 struct PlatformDevice *device = NULL;
206
207 gpioMgr = GpioManagerGet();
208 if (gpioMgr == NULL) {
209 PLAT_LOGE("GpioCntlrGetByGpio: get gpio manager failed");
210 return NULL;
211 }
212
213 device = PlatformManagerFindDevice(gpioMgr, (void *)(uintptr_t)gpio, GpioCntlrFindMatch);
214 if (device == NULL) {
215 PLAT_LOGE("GpioCntlrGetByGpio: gpio %u not in any controllers!", gpio);
216 return NULL;
217 }
218 return CONTAINER_OF(device, struct GpioCntlr, device);
219 }
220