• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 Bestechnic (Shanghai) Co., Ltd. All rights reserved.
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 "hal_gpio.h"
12 #include "hal_iomux.h"
13 #include "hdf_log.h"
14 #include "osal_irq.h"
15 #ifdef LOSCFG_DRIVERS_HDF_CONFIG_MACRO
16 #include "hcs_macro.h"
17 #include "hdf_config_macro.h"
18 #else
19 #include "device_resource_if.h"
20 #endif
21 
22 #define HDF_LOG_TAG GPIO_BES
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 pin;
47     uint32_t realPin;
48     uint32_t config;
49     uint32_t pinNum;
50     uint32_t type; /**< Type of the input event EV_KEY */
51     uint32_t code; /**< Specific code item of the input event KEY_POWER*/
52     unsigned long physBase;
53 };
54 
55 enum GpioDeviceState {
56     GPIO_DEVICE_UNINITIALIZED = 0x0u,
57     GPIO_DEVICE_INITIALIZED = 0x1u,
58 };
59 
60 struct GpioDevice {
61     uint8_t port; /* gpio port */
62     struct GpioResource resource;
63     enum GPIO_CONFIG config; /* gpio config */
64 };
65 
66 typedef int32_t (*oem_gpio_irq_handler_t)(uint16_t gpio, void *data);
67 
68 #define DECIMALNUM 10
69 #define OCTALNUM 8
70 
71 static struct GpioCntlr g_gpioCntlr;
72 
73 enum HAL_GPIO_PIN_T g_gpioPinReflectionMap[HAL_GPIO_PIN_LED_NUM] = {0};
74 
75 static struct HAL_GPIO_IRQ_CFG_T g_gpioIrqCfg[HAL_GPIO_PIN_LED_NUM] = {0};
76 
OemGpioIrqHdl(enum HAL_GPIO_PIN_T pin)77 static void OemGpioIrqHdl(enum HAL_GPIO_PIN_T pin)
78 {
79     if (pin >= HAL_GPIO_PIN_LED_NUM) {
80         HDF_LOGE("%s %d, error pin:%d", __func__, __LINE__, pin);
81         return;
82     }
83     for (size_t i = 0; i < HAL_GPIO_PIN_LED_NUM; i++) {
84         if (pin == (enum HAL_GPIO_PIN_T)g_gpioPinReflectionMap[i]) {
85             GpioCntlrIrqCallback(&g_gpioCntlr, i);
86             return;
87         }
88     }
89 }
90 
91 /* dispatch */
GpioDispatch(struct HdfDeviceIoClient * client,int cmdId,struct HdfSBuf * data,struct HdfSBuf * reply)92 int32_t GpioDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply)
93 {
94     (void)cmdId;
95     if (client == NULL || client->device == NULL || data == NULL || reply == NULL) {
96         HDF_LOGE("%s: client or client->device is NULL", __func__);
97         return HDF_ERR_INVALID_PARAM;
98     }
99     return HDF_SUCCESS;
100 }
101 
102 /* HdfDriverEntry method definitions */
103 static int32_t GpioDriverInit(struct HdfDeviceObject *device);
104 static void GpioDriverRelease(struct HdfDeviceObject *device);
105 
106 /* HdfDriverEntry definitions */
107 struct HdfDriverEntry g_GpioDriverEntry = {
108     .moduleVersion = 1,
109     .moduleName = "BES_GPIO_MODULE_HDF",
110     .Init = GpioDriverInit,
111     .Release = GpioDriverRelease,
112 };
113 HDF_INIT(g_GpioDriverEntry);
114 
115 /* GpioMethod method definitions */
116 static int32_t GpioDevWrite(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t val);
117 static int32_t GpioDevRead(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t *val);
118 static int32_t GpioDevSetDir(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t dir);
119 static int32_t GpioDevGetDir(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t *dir);
120 static int32_t GpioDevSetIrq(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t mode);
121 static int32_t GpioDevUnSetIrq(struct GpioCntlr *cntlr, uint16_t gpio);
122 static int32_t GpioDevEnableIrq(struct GpioCntlr *cntlr, uint16_t gpio);
123 static int32_t GpioDevDisableIrq(struct GpioCntlr *cntlr, uint16_t gpio);
124 /* GpioMethod definitions */
125 struct GpioMethod g_GpioCntlrMethod = {
126     .request = NULL,
127     .release = NULL,
128     .write = GpioDevWrite,
129     .read = GpioDevRead,
130     .setDir = GpioDevSetDir,
131     .getDir = GpioDevGetDir,
132     .toIrq = NULL,
133     .setIrq = GpioDevSetIrq,
134     .unsetIrq = GpioDevUnSetIrq,
135     .enableIrq = GpioDevEnableIrq,
136     .disableIrq = GpioDevDisableIrq,
137 };
138 
InitGpioDevice(const struct GpioDevice * device)139 static int InitGpioDevice(const struct GpioDevice *device)
140 {
141     struct HAL_IOMUX_PIN_FUNCTION_MAP gpioCfg;
142     if (device == NULL) {
143         HDF_LOGE("%s: device is NULL", __func__);
144         return HDF_ERR_INVALID_PARAM;
145     }
146     gpioCfg.pin = device->port;
147     gpioCfg.function = HAL_IOMUX_FUNC_AS_GPIO;
148     gpioCfg.volt = HAL_IOMUX_PIN_VOLTAGE_VIO;
149 
150     if ((device->config == OUTPUT_PUSH_PULL) || (device->config == OUTPUT_OPEN_DRAIN_PULL_UP) ||
151         (device->config == INPUT_PULL_UP) || (device->config == IRQ_MODE)) {
152         gpioCfg.pull_sel = HAL_IOMUX_PIN_PULLUP_ENABLE;
153     } else if ((device->config == INPUT_PULL_DOWN)) {
154         gpioCfg.pull_sel = HAL_IOMUX_PIN_PULLDOWN_ENABLE;
155     } else {
156         gpioCfg.pull_sel = HAL_IOMUX_PIN_NOPULL;
157     }
158 
159     hal_iomux_init(&gpioCfg, 1);
160 
161     return HDF_SUCCESS;
162 }
163 #ifdef LOSCFG_DRIVERS_HDF_CONFIG_MACRO
164 #define PLATFORM_GPIO_CONFIG HCS_NODE(HCS_NODE(HCS_ROOT, platform), gpio_config)
GetGpioDeviceResource(struct GpioDevice * device)165 static uint32_t GetGpioDeviceResource(struct GpioDevice *device)
166 {
167     uint32_t relPin;
168     int32_t ret;
169     struct GpioResource *resource = NULL;
170     if (device == NULL) {
171         HDF_LOGE("%s: device is NULL", __func__);
172         return HDF_ERR_INVALID_PARAM;
173     }
174     resource = &device->resource;
175     if (resource == NULL) {
176         HDF_LOGE("%s: resource is NULL", __func__);
177         return HDF_ERR_INVALID_OBJECT;
178     }
179     resource->pinNum = HCS_PROP(PLATFORM_GPIO_CONFIG, pinNum);
180     uint32_t pins[] = HCS_ARRAYS(HCS_NODE(PLATFORM_GPIO_CONFIG, pin));
181     uint32_t realPins[] = HCS_ARRAYS(HCS_NODE(PLATFORM_GPIO_CONFIG, realPin));
182     uint32_t configs[] = HCS_ARRAYS(HCS_NODE(PLATFORM_GPIO_CONFIG, config));
183     for (size_t i = 0; i < resource->pinNum; i++) {
184         resource->pin = pins[i];
185         resource->realPin = realPins[i];
186         resource->config = configs[i];
187 
188         relPin = resource->realPin / DECIMALNUM * OCTALNUM + resource->realPin % DECIMALNUM;
189         g_gpioPinReflectionMap[resource->pin] = relPin;
190         device->config = resource->config;
191         resource->pin = relPin;
192         device->port = relPin;
193 
194         ret = InitGpioDevice(device);
195         if (ret != HDF_SUCCESS) {
196             HDF_LOGE("InitGpioDevice FAIL\r\n");
197             return HDF_FAILURE;
198         }
199     }
200 
201     return HDF_SUCCESS;
202 }
203 #else
GetGpioDeviceResource(struct GpioDevice * device,const struct DeviceResourceNode * resourceNode)204 static uint32_t GetGpioDeviceResource(
205     struct GpioDevice *device, const struct DeviceResourceNode *resourceNode)
206 {
207     uint32_t relPin;
208     int32_t ret;
209     struct GpioResource *resource = NULL;
210     struct DeviceResourceIface *dri = NULL;
211     if (device == NULL || resourceNode == NULL) {
212         HDF_LOGE("%s: device is NULL", __func__);
213         return HDF_ERR_INVALID_PARAM;
214     }
215     resource = &device->resource;
216     if (resource == NULL) {
217         HDF_LOGE("%s: resource is NULL", __func__);
218         return HDF_ERR_INVALID_OBJECT;
219     }
220     dri = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
221     if (dri == NULL || dri->GetUint32 == NULL) {
222         HDF_LOGE("DeviceResourceIface is invalid");
223         return HDF_ERR_INVALID_OBJECT;
224     }
225 
226     if (dri->GetUint32(resourceNode, "pinNum", &resource->pinNum, 0) != HDF_SUCCESS) {
227         HDF_LOGE("gpio config read pinNum fail");
228         return HDF_FAILURE;
229     }
230 
231     for (size_t i = 0; i < resource->pinNum; i++) {
232         if (dri->GetUint32ArrayElem(resourceNode, "pin", i, &resource->pin, 0) != HDF_SUCCESS) {
233             HDF_LOGE("gpio config read pin fail");
234             return HDF_FAILURE;
235         }
236 
237         if (dri->GetUint32ArrayElem(resourceNode, "realPin", i, &resource->realPin, 0) != HDF_SUCCESS) {
238             HDF_LOGE("gpio config read realPin fail");
239             return HDF_FAILURE;
240         }
241 
242         if (dri->GetUint32ArrayElem(resourceNode, "config", i, &resource->config, 0) != HDF_SUCCESS) {
243             HDF_LOGE("gpio config read config fail");
244             return HDF_FAILURE;
245         }
246 
247         relPin = resource->realPin / DECIMALNUM * OCTALNUM + resource->realPin % DECIMALNUM;
248         g_gpioPinReflectionMap[resource->pin] = relPin;
249         device->config = resource->config;
250         resource->pin = relPin;
251         device->port = relPin;
252 
253         ret = InitGpioDevice(device);
254         if (ret != HDF_SUCCESS) {
255             HDF_LOGE("InitGpioDevice FAIL\r\n");
256             return HDF_FAILURE;
257         }
258     }
259     return HDF_SUCCESS;
260 }
261 #endif
262 
AttachGpioDevice(struct GpioCntlr * gpioCntlr,const struct HdfDeviceObject * device)263 static int32_t AttachGpioDevice(struct GpioCntlr *gpioCntlr, const struct HdfDeviceObject *device)
264 {
265     int32_t ret;
266 
267     struct GpioDevice *gpioDevice = NULL;
268 #ifdef LOSCFG_DRIVERS_HDF_CONFIG_MACRO
269     if (device == NULL) {
270 #else
271     if (device == NULL || device->property == NULL) {
272 #endif
273         HDF_LOGE("%s: param is NULL", __func__);
274         return HDF_ERR_INVALID_PARAM;
275     }
276 
277     gpioDevice = (struct GpioDevice *)OsalMemAlloc(sizeof(struct GpioDevice));
278     if (gpioDevice == NULL) {
279         HDF_LOGE("%s: OsalMemAlloc gpioDevice error", __func__);
280         return HDF_ERR_MALLOC_FAIL;
281     }
282 #ifdef LOSCFG_DRIVERS_HDF_CONFIG_MACRO
283     ret = GetGpioDeviceResource(gpioDevice);
284 #else
285     ret = GetGpioDeviceResource(gpioDevice, device->property);
286 #endif
287     if (ret != HDF_SUCCESS) {
288         OsalMemFree(gpioDevice);
289         return HDF_FAILURE;
290     }
291 
292     gpioCntlr->count = gpioDevice->resource.pinNum;
293     gpioCntlr->priv = (void *)gpioDevice;
294     return HDF_SUCCESS;
295 }
296 
297 static int32_t GpioDriverInit(struct HdfDeviceObject *device)
298 {
299     int32_t ret;
300     struct GpioCntlr *gpioCntlr = NULL;
301 
302     if (device == NULL) {
303         HDF_LOGE("%s: device is NULL", __func__);
304         return HDF_ERR_INVALID_PARAM;
305     }
306 
307     ret = PlatformDeviceBind(&g_gpioCntlr.device, device);
308     if (ret != HDF_SUCCESS) {
309         HDF_LOGE("%s: bind hdf device failed:%d", __func__, ret);
310         return ret;
311     }
312 
313     gpioCntlr = GpioCntlrFromHdfDev(device);
314     if (gpioCntlr == NULL) {
315         HDF_LOGE("GpioCntlrFromHdfDev fail\r\n");
316         return HDF_DEV_ERR_NO_DEVICE_SERVICE;
317     }
318 
319     ret = AttachGpioDevice(gpioCntlr, device); // GpioCntlr add GpioDevice to priv
320     if (ret != HDF_SUCCESS) {
321         HDF_LOGE("AttachGpioDevice fail\r\n");
322         return HDF_DEV_ERR_ATTACHDEV_FAIL;
323     }
324 
325     gpioCntlr->ops = &g_GpioCntlrMethod; // register callback
326     ret = GpioCntlrAdd(gpioCntlr);
327     if (ret != HDF_SUCCESS) {
328         HDF_LOGE("GpioCntlrAdd fail %d\r\n", gpioCntlr->start);
329         return HDF_FAILURE;
330     }
331     return HDF_SUCCESS;
332 }
333 
334 static void GpioDriverRelease(struct HdfDeviceObject *device)
335 {
336     struct GpioCntlr *gpioCntlr = NULL;
337 
338     if (device == NULL) {
339         HDF_LOGE("%s: device is NULL", __func__);
340         return;
341     }
342 
343     gpioCntlr = GpioCntlrFromHdfDev(device);
344     if (gpioCntlr == NULL) {
345         HDF_LOGE("GpioCntlrFromHdfDev fail\r\n");
346         return;
347     }
348 
349     gpioCntlr->ops = NULL;
350     OsalMemFree(gpioCntlr->priv);
351     gpioCntlr->count = 0;
352 }
353 
354 /* dev api */
355 static int32_t GpioDevWrite(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t val)
356 {
357     (void)cntlr;
358     uint16_t halGpio = g_gpioPinReflectionMap[gpio];
359     if ((enum HAL_GPIO_PIN_T)halGpio >= HAL_GPIO_PIN_LED_NUM) {
360         HDF_LOGE("%s %d, error pin:%d", __func__, __LINE__, halGpio);
361         return HDF_ERR_NOT_SUPPORT;
362     }
363 
364     hal_gpio_pin_set_dir((enum HAL_GPIO_PIN_T)halGpio, HAL_GPIO_DIR_OUT, val);
365 
366     return HDF_SUCCESS;
367 }
368 
369 static int32_t GpioDevRead(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t *val)
370 {
371     (void)cntlr;
372     uint16_t value;
373     uint16_t halGpio = g_gpioPinReflectionMap[gpio];
374     if ((enum HAL_GPIO_PIN_T)halGpio >= HAL_GPIO_PIN_LED_NUM) {
375         HDF_LOGE("%s %d, error pin:%hu", __func__, __LINE__, halGpio);
376         return HDF_ERR_NOT_SUPPORT;
377     }
378 
379     value = (uint16_t)hal_gpio_pin_get_val((enum HAL_GPIO_PIN_T)halGpio);
380     *val = value;
381 
382     return HDF_SUCCESS;
383 }
384 
385 static int32_t GpioDevSetDir(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t dir)
386 {
387     (void)cntlr;
388     uint16_t halGpio = g_gpioPinReflectionMap[gpio];
389     if ((enum HAL_GPIO_PIN_T)halGpio >= HAL_GPIO_PIN_LED_NUM) {
390         HDF_LOGE("%s %d, error pin:%hu", __func__, __LINE__, halGpio);
391         return HDF_ERR_NOT_SUPPORT;
392     }
393 
394     hal_gpio_pin_set_dir((enum HAL_GPIO_PIN_T)halGpio, (enum HAL_GPIO_DIR_T)dir, 0);
395 
396     return HDF_SUCCESS;
397 }
398 
399 static int32_t GpioDevGetDir(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t *dir)
400 {
401     (void)cntlr;
402     uint16_t value;
403     uint16_t halGpio = g_gpioPinReflectionMap[gpio];
404     if ((enum HAL_GPIO_PIN_T)halGpio >= HAL_GPIO_PIN_LED_NUM) {
405         HDF_LOGE("%s %d, error pin:%hu", __func__, __LINE__, gpio);
406         return HDF_ERR_NOT_SUPPORT;
407     }
408 
409     value = (uint16_t)hal_gpio_pin_get_dir((enum HAL_GPIO_PIN_T)halGpio);
410     *dir = value;
411 
412     return HDF_SUCCESS;
413 }
414 
415 static int32_t GpioDevSetIrq(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t mode)
416 {
417     (void)cntlr;
418     enum HAL_GPIO_PIN_T pin = (enum HAL_GPIO_PIN_T)g_gpioPinReflectionMap[gpio];
419     if (pin >= HAL_GPIO_PIN_LED_NUM) {
420         HDF_LOGE("%s %d, error pin:%d", __func__, __LINE__, pin);
421         return HDF_ERR_NOT_SUPPORT;
422     }
423 
424     if ((mode == OSAL_IRQF_TRIGGER_RISING) || (mode == OSAL_IRQF_TRIGGER_FALLING)) {
425         g_gpioIrqCfg[pin].irq_type = HAL_GPIO_IRQ_TYPE_EDGE_SENSITIVE;
426     } else if ((mode == OSAL_IRQF_TRIGGER_HIGH) || (mode == OSAL_IRQF_TRIGGER_LOW)) {
427         g_gpioIrqCfg[pin].irq_type = HAL_GPIO_IRQ_TYPE_LEVEL_SENSITIVE;
428     } else {
429         HDF_LOGE("%s %d, error mode:%hu", __func__, __LINE__, mode);
430         return HDF_ERR_NOT_SUPPORT;
431     }
432 
433     g_gpioIrqCfg[pin].irq_polarity = mode;
434 
435     return HDF_SUCCESS;
436 }
437 
438 static int32_t GpioDevUnSetIrq(struct GpioCntlr *cntlr, uint16_t gpio)
439 {
440     (void)cntlr;
441     enum HAL_GPIO_PIN_T pin = (enum HAL_GPIO_PIN_T)g_gpioPinReflectionMap[gpio];
442     if (pin >= HAL_GPIO_PIN_LED_NUM) {
443         HDF_LOGE("%s %d, error pin:%d", __func__, __LINE__, pin);
444         return HDF_ERR_NOT_SUPPORT;
445     }
446 
447     return HDF_SUCCESS;
448 }
449 
450 static int32_t GpioDevEnableIrq(struct GpioCntlr *cntlr, uint16_t gpio)
451 {
452     (void)cntlr;
453     struct HAL_GPIO_IRQ_CFG_T gpioCfg;
454     uint16_t halGpio = (enum HAL_GPIO_PIN_T)g_gpioPinReflectionMap[gpio];
455     if ((enum HAL_GPIO_PIN_T)halGpio >= HAL_GPIO_PIN_LED_NUM) {
456         HDF_LOGE("%s %d, error pin:%d", __func__, __LINE__, (enum HAL_GPIO_PIN_T)halGpio);
457         return HDF_ERR_NOT_SUPPORT;
458     }
459 
460     hal_gpio_pin_set_dir((enum HAL_GPIO_PIN_T)halGpio, HAL_GPIO_DIR_IN, 0);
461 
462     gpioCfg.irq_enable = true;
463     gpioCfg.irq_debounce = true;
464     gpioCfg.irq_polarity = g_gpioIrqCfg[(enum HAL_GPIO_PIN_T)halGpio].irq_polarity;
465     gpioCfg.irq_handler = OemGpioIrqHdl;
466     gpioCfg.irq_type = g_gpioIrqCfg[(enum HAL_GPIO_PIN_T)halGpio].irq_type;
467     g_gpioIrqCfg[halGpio] = gpioCfg;
468 
469     hal_gpio_setup_irq((enum HAL_GPIO_PIN_T)halGpio, &gpioCfg);
470 
471     return HDF_SUCCESS;
472 }
473 
474 static int32_t GpioDevDisableIrq(struct GpioCntlr *cntlr, uint16_t gpio)
475 {
476     (void)cntlr;
477     uint16_t halGpio = (enum HAL_GPIO_PIN_T)g_gpioPinReflectionMap[gpio];
478     if ((enum HAL_GPIO_PIN_T)halGpio >= HAL_GPIO_PIN_LED_NUM) {
479         HDF_LOGE("%s %d, error pin:%d", __func__, __LINE__, halGpio);
480         return HDF_ERR_NOT_SUPPORT;
481     }
482 
483     const struct HAL_GPIO_IRQ_CFG_T gpioCfg = {
484         .irq_enable = false,
485         .irq_debounce = false,
486         .irq_polarity = HAL_GPIO_IRQ_POLARITY_LOW_FALLING,
487         .irq_handler = NULL,
488         .irq_type = HAL_GPIO_IRQ_TYPE_EDGE_SENSITIVE,
489     };
490 
491     hal_gpio_setup_irq((enum HAL_GPIO_PIN_T)halGpio, &gpioCfg);
492 
493     return HDF_SUCCESS;
494 }
495