1 /*
2  * Copyright (c) 2022 Jiangsu Hoperun Software Co., Ltd.
3  *
4  * This file 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 <stdlib.h>
10 #include "gpio_core.h"
11 #include "gpio_if.h"
12 #include "device_resource_if.h"
13 #include "osal_irq.h"
14 #include "hdf_log.h"
15 #include "wm_io.h"
16 #include "wm_gpio.h"
17 
18 #define DECIMALNUM 10
19 #define OCTALNUM 8
20 
21 #define HDF_LOG_TAG gpioDriver
22 #define WM_IO_MAX_GPIO_PIN_NUM 48
23 
24 /*
25  * Pin configuration
26  */
27 enum GPIO_CONFIG {
28     ANALOG_MODE,               /* Used as a function pin, input and output analog */
29     IRQ_MODE,                  /* Used to trigger interrupt */
30     INPUT_PULL_UP,             /* Input with an internal pull-up resistor - use with devices
31                                   that actively drive the signal low - e.g. button connected to ground */
32     INPUT_PULL_DOWN,           /* Input with an internal pull-down resistor - use with devices
33                                   that actively drive the signal high - e.g. button connected to a power rail */
34     INPUT_HIGH_IMPEDANCE,      /* Input - must always be driven, either actively or by an external pullup resistor */
35     OUTPUT_PUSH_PULL,          /* Output actively driven high and actively driven low -
36                                   must not be connected to other active outputs - e.g. LED output */
37     OUTPUT_OPEN_DRAIN_NO_PULL, /* Output actively driven low but is high-impedance when set high -
38                                   can be connected to other open-drain/open-collector outputs.
39                                   Needs an external pull-up resistor */
40     OUTPUT_OPEN_DRAIN_PULL_UP, /* Output actively driven low and is pulled high
41                                   with an internal resistor when set high -
42                                   can be connected to other open-drain/open-collector outputs. */
43 };
44 
45 struct GpioResource {
46     uint32_t groupNum;
47     uint32_t realPin;
48     uint32_t config;
49     uint32_t pinNum;
50 };
51 
52 struct GpioDevice {
53     uint8_t port; /* gpio port */
54     struct GpioResource resource;
55     enum GPIO_CONFIG config; /* gpio config */
56 };
57 
58 typedef void (* tls_gpio_pin_orq_handler)(enum tls_io_name pin);
59 
60 static struct GpioCntlr gpioCntlr;
61 struct wmGpioIrqHandler {
62     uint8_t port;
63 };
64 
65 enum tls_io_name g_gpioPinReflectionMap[WM_IO_MAX_GPIO_PIN_NUM] = {0};
66 static struct wmGpioIrqHandler g_wmGpioIrqHandler[WM_IO_MAX_GPIO_PIN_NUM] = {0};
67 enum tls_gpio_irq_trig g_gpioIrqCfg[WM_IO_MAX_GPIO_PIN_NUM] = {0};
68 
GpioIrqHdl()69 static GpioIrqFunc GpioIrqHdl()
70 {
71     uint16_t ret;
72 
73     for (size_t i = 0; i < WM_IO_MAX_GPIO_PIN_NUM; i++) {
74         ret = tls_get_gpio_irq_status(g_wmGpioIrqHandler[i].port);
75         if ((enum tls_io_name)g_gpioPinReflectionMap[i] && (ret != 0)) {
76             GpioCntlrIrqCallback(&gpioCntlr, i);
77             return HDF_SUCCESS;
78         }
79     }
80 }
81 
82 /* dispatch */
GpioDispatch(struct HdfDeviceIoClient * client,int cmdId,struct HdfSBuf * data,struct HdfSBuf * reply)83 int32_t GpioDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply)
84 {
85     (void)cmdId;
86     if (client == NULL || client->device == NULL || data == NULL || reply == NULL) {
87         HDF_LOGE("%s: client or client->device is NULL", __func__);
88         return HDF_ERR_INVALID_PARAM;
89     }
90     return HDF_SUCCESS;
91 }
92 
93 /* GpioMethod method definitions */
94 static int32_t GpioDevWrite(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t val);
95 static int32_t GpioDevRead(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t *val);
96 static int32_t GpioDevSetDir(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t dir);
97 static int32_t GpioDevSetIrq(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t mode);
98 static int32_t GpioDevUnSetIrq(struct GpioCntlr *cntlr, uint16_t gpio);
99 static int32_t GpioDevEnableIrq(struct GpioCntlr *cntlr, uint16_t gpio);
100 static int32_t GpioDevDisableIrq(struct GpioCntlr *cntlr, uint16_t gpio);
101 /* GpioMethod definitions */
102 struct GpioMethod g_GpioCntlrMethod = {
103     .request = NULL,
104     .release = NULL,
105     .write = GpioDevWrite,
106     .read = GpioDevRead,
107     .setDir = GpioDevSetDir,
108     .getDir = NULL,
109     .toIrq = NULL,
110     .setIrq = GpioDevSetIrq,
111     .unsetIrq = GpioDevUnSetIrq,
112     .enableIrq = GpioDevEnableIrq,
113     .disableIrq = GpioDevDisableIrq,
114 };
115 
116 /* dev api */
GpioDevWrite(struct GpioCntlr * cntlr,uint16_t gpio,uint16_t val)117 static int32_t GpioDevWrite(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t val)
118 {
119     uint16_t wmGpio;
120 
121     (void)cntlr;
122     if (gpio >= WM_IO_MAX_GPIO_PIN_NUM) {
123         HDF_LOGE("%s %d, error gpio:%hu", __func__, __LINE__, gpio);
124         return HDF_ERR_NOT_SUPPORT;
125     }
126     wmGpio= g_gpioPinReflectionMap[gpio];
127 
128     tls_gpio_write((enum tls_io_name)wmGpio, val);
129     return HDF_SUCCESS;
130 }
131 
GpioDevRead(struct GpioCntlr * cntlr,uint16_t gpio,uint16_t * val)132 static int32_t GpioDevRead(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t *val)
133 {
134     uint16_t value;
135     uint16_t wmGpio;
136 
137     (void)cntlr;
138     if (gpio >= WM_IO_MAX_GPIO_PIN_NUM) {
139         HDF_LOGE("%s %d, error gpio:%hu", __func__, __LINE__, gpio);
140         return HDF_ERR_NOT_SUPPORT;
141     }
142     wmGpio = g_gpioPinReflectionMap[gpio];
143 
144     value = tls_gpio_read((enum tls_io_name)wmGpio);
145     *val = value;
146     return HDF_SUCCESS;
147 }
148 
GpioDevSetDir(struct GpioCntlr * cntlr,uint16_t gpio,uint16_t dir)149 static int32_t GpioDevSetDir(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t dir)
150 {
151     uint16_t wmGpio;
152 
153     (void)cntlr;
154     if (gpio >= WM_IO_MAX_GPIO_PIN_NUM) {
155         HDF_LOGE("%s %d, error gpio:%hu", __func__, __LINE__, gpio);
156         return HDF_ERR_NOT_SUPPORT;
157     }
158     wmGpio = g_gpioPinReflectionMap[gpio];
159 
160     switch (dir) {
161         case GPIO_DIR_OUT:
162             dir = WM_GPIO_DIR_OUTPUT;
163             break;
164         case GPIO_DIR_IN:
165             dir = WM_GPIO_DIR_INPUT;
166             break;
167         default:
168             HDF_LOGE("%s: invalid dir", __func__);
169             return HDF_ERR_INVALID_PARAM;
170     }
171 
172     tls_gpio_cfg((enum tls_io_name)wmGpio, (enum tls_gpio_dir)dir, WM_GPIO_ATTR_FLOATING);
173 
174     return HDF_SUCCESS;
175 }
176 
GpioDevSetIrq(struct GpioCntlr * cntlr,uint16_t gpio,uint16_t mode)177 static int32_t GpioDevSetIrq(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t mode)
178 {
179     uint16_t wmGpio;
180 
181     (void)cntlr;
182     if (gpio >= WM_IO_MAX_GPIO_PIN_NUM) {
183         HDF_LOGE("%s %d, error gpio:%hu", __func__, __LINE__, gpio);
184         return HDF_ERR_NOT_SUPPORT;
185     }
186     wmGpio= g_gpioPinReflectionMap[gpio];
187 
188     g_wmGpioIrqHandler[wmGpio].port = gpio;
189     tls_gpio_isr_register((enum tls_io_name)wmGpio, (tls_gpio_irq_callback)GpioIrqHdl, NULL);
190 
191     switch (mode) {
192         case OSAL_IRQF_TRIGGER_RISING:
193             g_gpioIrqCfg[wmGpio] = WM_GPIO_IRQ_TRIG_RISING_EDGE;
194             break;
195         case OSAL_IRQF_TRIGGER_FALLING:
196             g_gpioIrqCfg[wmGpio] = WM_GPIO_IRQ_TRIG_FALLING_EDGE;
197             break;
198         case OSAL_IRQF_TRIGGER_HIGH:
199             g_gpioIrqCfg[wmGpio] = WM_GPIO_IRQ_TRIG_HIGH_LEVEL;
200             break;
201         case OSAL_IRQF_TRIGGER_LOW:
202             g_gpioIrqCfg[wmGpio] = WM_GPIO_IRQ_TRIG_LOW_LEVEL;
203             break;
204         default:
205             HDF_LOGE("%s: invalid mode", __func__);
206             return HDF_ERR_INVALID_PARAM;
207     }
208 
209     return HDF_SUCCESS;
210 }
211 
GpioDevUnSetIrq(struct GpioCntlr * cntlr,uint16_t gpio)212 static int32_t GpioDevUnSetIrq(struct GpioCntlr *cntlr, uint16_t gpio)
213 {
214     uint16_t wmGpio;
215 
216     (void)cntlr;
217     if (gpio >= WM_IO_MAX_GPIO_PIN_NUM) {
218         HDF_LOGE("%s %d, error gpio:%hu", __func__, __LINE__, gpio);
219         return HDF_ERR_NOT_SUPPORT;
220     }
221     wmGpio= g_gpioPinReflectionMap[gpio];
222     return HDF_SUCCESS;
223 }
224 
GpioDevEnableIrq(struct GpioCntlr * cntlr,uint16_t gpio)225 static int32_t GpioDevEnableIrq(struct GpioCntlr *cntlr, uint16_t gpio)
226 {
227     uint16_t wmGpio;
228 
229     (void)cntlr;
230     if (gpio >= WM_IO_MAX_GPIO_PIN_NUM) {
231         HDF_LOGE("%s %d, error gpio:%hu", __func__, __LINE__, gpio);
232         return HDF_ERR_NOT_SUPPORT;
233     }
234     wmGpio= g_gpioPinReflectionMap[gpio];
235 
236     // config gpio interrupt
237     tls_gpio_irq_enable((enum tls_io_name)wmGpio, g_gpioIrqCfg[wmGpio]);
238     return HDF_SUCCESS;
239 }
240 
GpioDevDisableIrq(struct GpioCntlr * cntlr,uint16_t gpio)241 static int32_t GpioDevDisableIrq(struct GpioCntlr *cntlr, uint16_t gpio)
242 {
243     uint16_t wmGpio;
244 
245     (void)cntlr;
246     if (gpio >= WM_IO_MAX_GPIO_PIN_NUM) {
247         HDF_LOGE("%s %d, error gpio:%hu", __func__, __LINE__, gpio);
248         return HDF_ERR_NOT_SUPPORT;
249     }
250     wmGpio= g_gpioPinReflectionMap[gpio];
251 
252     tls_gpio_irq_disable((enum tls_io_name)wmGpio);
253     return HDF_SUCCESS;
254 }
255 
GetGpioDeviceResource(struct GpioDevice * device,const struct DeviceResourceNode * resourceNode)256 static uint32_t GetGpioDeviceResource(struct GpioDevice *device, const struct DeviceResourceNode *resourceNode)
257 {
258     struct GpioResource *resource = NULL;
259     struct DeviceResourceIface *dri = NULL;
260 
261     if (device == NULL || resourceNode == NULL) {
262         HDF_LOGE("%s: device is NULL", __func__);
263         return HDF_ERR_INVALID_PARAM;
264     }
265     resource = &device->resource;
266     if (resource == NULL) {
267         HDF_LOGE("%s: resource is NULL", __func__);
268         return HDF_ERR_INVALID_OBJECT;
269     }
270     dri = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
271     if (dri == NULL || dri->GetUint32 == NULL || dri->GetUint32ArrayElem == NULL) {
272         HDF_LOGE("DeviceResourceIface is invalid");
273         return HDF_ERR_INVALID_OBJECT;
274     }
275 
276     if (dri->GetUint32(resourceNode, "groupNum", &resource->groupNum, 0) != HDF_SUCCESS) {
277         HDF_LOGE("gpio config read groupNum fail");
278         return HDF_FAILURE;
279     }
280 
281     if (dri->GetUint32(resourceNode, "pinNum", &resource->pinNum, 0) != HDF_SUCCESS) {
282         HDF_LOGE("gpio config read pinNum fail");
283         return HDF_FAILURE;
284     }
285 
286     for (size_t i = 0; i < resource->groupNum; i++) {
287         if (dri->GetUint32ArrayElem(resourceNode, "config", i, &resource->config, 0) != HDF_SUCCESS) {
288             HDF_LOGE("gpio config read config fail");
289             return HDF_FAILURE;
290         }
291     }
292     device->config = resource->config;
293     return HDF_SUCCESS;
294 }
295 
AttachGpioDevice(struct GpioCntlr * gpioCntlr,const struct HdfDeviceObject * device)296 static int32_t AttachGpioDevice(struct GpioCntlr *gpioCntlr, const struct HdfDeviceObject *device)
297 {
298     int32_t ret;
299 
300     struct GpioDevice *gpioDevice = NULL;
301     if (device == NULL || device->property == NULL) {
302         HDF_LOGE("%s: property is NULL", __func__);
303         return HDF_ERR_INVALID_PARAM;
304     }
305 
306     gpioDevice = (struct GpioDevice *)OsalMemAlloc(sizeof(struct GpioDevice));
307     if (gpioDevice == NULL) {
308         HDF_LOGE("%s: OsalMemAlloc gpioDevice error", __func__);
309         return HDF_ERR_MALLOC_FAIL;
310     }
311 
312     ret = GetGpioDeviceResource(gpioDevice, device->property);
313     if (ret != HDF_SUCCESS) {
314         (void)OsalMemFree(gpioDevice);
315         return HDF_FAILURE;
316     }
317 
318     gpioCntlr->count = gpioDevice->resource.pinNum;
319 
320     return HDF_SUCCESS;
321 }
322 
GpioDriverInit(struct HdfDeviceObject * device)323 static int32_t GpioDriverInit(struct HdfDeviceObject *device)
324 {
325     int32_t ret;
326     struct GpioCntlr *gpioCntlr = NULL;
327 
328     if (device == NULL) {
329         HDF_LOGE("%s: device is NULL", __func__);
330         return HDF_ERR_INVALID_PARAM;
331     }
332 
333     gpioCntlr = GpioCntlrFromHdfDev(device);
334     if (gpioCntlr == NULL) {
335         HDF_LOGE("GpioCntlrFromHdfDev fail\r\n");
336         return HDF_DEV_ERR_NO_DEVICE_SERVICE;
337     }
338 
339     ret = AttachGpioDevice(gpioCntlr, device); // GpioCntlr add GpioDevice to priv
340     if (ret != HDF_SUCCESS) {
341         HDF_LOGE("AttachGpioDevice fail\r\n");
342         return HDF_DEV_ERR_ATTACHDEV_FAIL;
343     }
344 
345     gpioCntlr->ops = &g_GpioCntlrMethod; // register callback
346     ret = GpioCntlrAdd(gpioCntlr);
347     if (ret != HDF_SUCCESS) {
348         HDF_LOGE("GpioCntlrAdd fail %d\r\n", gpioCntlr->start);
349         return HDF_FAILURE;
350     }
351     return HDF_SUCCESS;
352 }
353 
GpioDriverBind(struct HdfDeviceObject * device)354 static int32_t GpioDriverBind(struct HdfDeviceObject *device)
355 {
356     if (device == NULL) {
357         HDF_LOGE("Sample device object is null!");
358         return HDF_ERR_INVALID_PARAM;
359     }
360 
361     gpioCntlr.device.hdfDev = device;
362     device->service = gpioCntlr.device.hdfDev;
363 
364     return HDF_SUCCESS;
365 }
366 
GpioDriverRelease(struct HdfDeviceObject * device)367 static void GpioDriverRelease(struct HdfDeviceObject *device)
368 {
369     struct GpioCntlr *gpioCntlr = NULL;
370 
371     if (device == NULL) {
372         HDF_LOGE("%s: device is NULL", __func__);
373         return;
374     }
375 
376     gpioCntlr = GpioCntlrFromHdfDev(device);
377     if (gpioCntlr == NULL) {
378         HDF_LOGE("%s: host is NULL", __func__);
379         return;
380     }
381 
382     gpioCntlr->ops = NULL;
383     OsalMemFree(gpioCntlr);
384 }
385 
386 /* HdfDriverEntry definitions */
387 struct HdfDriverEntry g_GpioDriverEntry = {
388     .moduleVersion = 1,
389     .moduleName = "WM_GPIO_MODULE_HDF",
390     .Bind = GpioDriverBind,
391     .Init = GpioDriverInit,
392     .Release = GpioDriverRelease,
393 };
394 HDF_INIT(g_GpioDriverEntry);
395