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