• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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