/* * Copyright (c) 2022 Jiangsu Hoperun Software Co., Ltd. * * This file is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * See the LICENSE file in the root of this repository for complete details. */ #include #include "gpio_core.h" #include "gpio_if.h" #include "device_resource_if.h" #include "osal_irq.h" #include "hdf_core_log.h" #include "wm_io.h" #include "wm_gpio.h" #define DECIMALNUM 10 #define OCTALNUM 8 #define HDF_LOG_TAG gpioDriver #define WM_IO_MAX_GPIO_PIN_NUM 48 /* * Pin configuration */ enum GPIO_CONFIG { ANALOG_MODE, /* Used as a function pin, input and output analog */ IRQ_MODE, /* Used to trigger interrupt */ INPUT_PULL_UP, /* Input with an internal pull-up resistor - use with devices that actively drive the signal low - e.g. button connected to ground */ INPUT_PULL_DOWN, /* Input with an internal pull-down resistor - use with devices that actively drive the signal high - e.g. button connected to a power rail */ INPUT_HIGH_IMPEDANCE, /* Input - must always be driven, either actively or by an external pullup resistor */ OUTPUT_PUSH_PULL, /* Output actively driven high and actively driven low - must not be connected to other active outputs - e.g. LED output */ OUTPUT_OPEN_DRAIN_NO_PULL, /* Output actively driven low but is high-impedance when set high - can be connected to other open-drain/open-collector outputs. Needs an external pull-up resistor */ OUTPUT_OPEN_DRAIN_PULL_UP, /* Output actively driven low and is pulled high with an internal resistor when set high - can be connected to other open-drain/open-collector outputs. */ }; struct GpioResource { uint32_t groupNum; uint32_t realPin; uint32_t config; uint32_t pinNum; }; struct GpioDevice { uint8_t port; /* gpio port */ struct GpioResource resource; enum GPIO_CONFIG config; /* gpio config */ }; typedef void (* tls_gpio_pin_orq_handler)(enum tls_io_name pin); static struct GpioCntlr gpioCntlr; struct wmGpioIrqHandler { uint8_t port; }; enum tls_io_name g_gpioPinReflectionMap[WM_IO_MAX_GPIO_PIN_NUM] = {0}; static struct wmGpioIrqHandler g_wmGpioIrqHandler[WM_IO_MAX_GPIO_PIN_NUM] = {0}; enum tls_gpio_irq_trig g_gpioIrqCfg[WM_IO_MAX_GPIO_PIN_NUM] = {0}; static GpioIrqFunc GpioIrqHdl() { uint16_t ret; for (size_t i = 0; i < WM_IO_MAX_GPIO_PIN_NUM; i++) { ret = tls_get_gpio_irq_status(g_wmGpioIrqHandler[i].port); if ((enum tls_io_name)g_gpioPinReflectionMap[i] && (ret != 0)) { GpioCntlrIrqCallback(&gpioCntlr, i); return HDF_SUCCESS; } } } /* dispatch */ int32_t GpioDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data, struct HdfSBuf *reply) { (void)cmdId; if (client == NULL || client->device == NULL || data == NULL || reply == NULL) { HDF_LOGE("%s: client or client->device is NULL", __func__); return HDF_ERR_INVALID_PARAM; } return HDF_SUCCESS; } /* GpioMethod method definitions */ static int32_t GpioDevWrite(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t val); static int32_t GpioDevRead(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t *val); static int32_t GpioDevSetDir(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t dir); static int32_t GpioDevSetIrq(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t mode); static int32_t GpioDevUnSetIrq(struct GpioCntlr *cntlr, uint16_t gpio); static int32_t GpioDevEnableIrq(struct GpioCntlr *cntlr, uint16_t gpio); static int32_t GpioDevDisableIrq(struct GpioCntlr *cntlr, uint16_t gpio); /* GpioMethod definitions */ struct GpioMethod g_GpioCntlrMethod = { .request = NULL, .release = NULL, .write = GpioDevWrite, .read = GpioDevRead, .setDir = GpioDevSetDir, .getDir = NULL, .toIrq = NULL, .setIrq = GpioDevSetIrq, .unsetIrq = GpioDevUnSetIrq, .enableIrq = GpioDevEnableIrq, .disableIrq = GpioDevDisableIrq, }; /* dev api */ static int32_t GpioDevWrite(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t val) { uint16_t wmGpio; (void)cntlr; if (gpio >= WM_IO_MAX_GPIO_PIN_NUM) { HDF_LOGE("%s %d, error gpio:%hu", __func__, __LINE__, gpio); return HDF_ERR_NOT_SUPPORT; } wmGpio= g_gpioPinReflectionMap[gpio]; tls_gpio_write((enum tls_io_name)wmGpio, val); return HDF_SUCCESS; } static int32_t GpioDevRead(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t *val) { uint16_t value; uint16_t wmGpio; (void)cntlr; if (gpio >= WM_IO_MAX_GPIO_PIN_NUM) { HDF_LOGE("%s %d, error gpio:%hu", __func__, __LINE__, gpio); return HDF_ERR_NOT_SUPPORT; } wmGpio = g_gpioPinReflectionMap[gpio]; value = tls_gpio_read((enum tls_io_name)wmGpio); *val = value; return HDF_SUCCESS; } static int32_t GpioDevSetDir(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t dir) { uint16_t wmGpio; (void)cntlr; if (gpio >= WM_IO_MAX_GPIO_PIN_NUM) { HDF_LOGE("%s %d, error gpio:%hu", __func__, __LINE__, gpio); return HDF_ERR_NOT_SUPPORT; } wmGpio = g_gpioPinReflectionMap[gpio]; switch (dir) { case GPIO_DIR_OUT: dir = WM_GPIO_DIR_OUTPUT; break; case GPIO_DIR_IN: dir = WM_GPIO_DIR_INPUT; break; default: HDF_LOGE("%s: invalid dir", __func__); return HDF_ERR_INVALID_PARAM; } tls_gpio_cfg((enum tls_io_name)wmGpio, (enum tls_gpio_dir)dir, WM_GPIO_ATTR_FLOATING); return HDF_SUCCESS; } static int32_t GpioDevSetIrq(struct GpioCntlr *cntlr, uint16_t gpio, uint16_t mode) { uint16_t wmGpio; (void)cntlr; if (gpio >= WM_IO_MAX_GPIO_PIN_NUM) { HDF_LOGE("%s %d, error gpio:%hu", __func__, __LINE__, gpio); return HDF_ERR_NOT_SUPPORT; } wmGpio= g_gpioPinReflectionMap[gpio]; g_wmGpioIrqHandler[wmGpio].port = gpio; tls_gpio_isr_register((enum tls_io_name)wmGpio, (tls_gpio_irq_callback)GpioIrqHdl, NULL); switch (mode) { case OSAL_IRQF_TRIGGER_RISING: g_gpioIrqCfg[wmGpio] = WM_GPIO_IRQ_TRIG_RISING_EDGE; break; case OSAL_IRQF_TRIGGER_FALLING: g_gpioIrqCfg[wmGpio] = WM_GPIO_IRQ_TRIG_FALLING_EDGE; break; case OSAL_IRQF_TRIGGER_HIGH: g_gpioIrqCfg[wmGpio] = WM_GPIO_IRQ_TRIG_HIGH_LEVEL; break; case OSAL_IRQF_TRIGGER_LOW: g_gpioIrqCfg[wmGpio] = WM_GPIO_IRQ_TRIG_LOW_LEVEL; break; default: HDF_LOGE("%s: invalid mode", __func__); return HDF_ERR_INVALID_PARAM; } return HDF_SUCCESS; } static int32_t GpioDevUnSetIrq(struct GpioCntlr *cntlr, uint16_t gpio) { uint16_t wmGpio; (void)cntlr; if (gpio >= WM_IO_MAX_GPIO_PIN_NUM) { HDF_LOGE("%s %d, error gpio:%hu", __func__, __LINE__, gpio); return HDF_ERR_NOT_SUPPORT; } wmGpio= g_gpioPinReflectionMap[gpio]; return HDF_SUCCESS; } static int32_t GpioDevEnableIrq(struct GpioCntlr *cntlr, uint16_t gpio) { uint16_t wmGpio; (void)cntlr; if (gpio >= WM_IO_MAX_GPIO_PIN_NUM) { HDF_LOGE("%s %d, error gpio:%hu", __func__, __LINE__, gpio); return HDF_ERR_NOT_SUPPORT; } wmGpio= g_gpioPinReflectionMap[gpio]; // config gpio interrupt tls_gpio_irq_enable((enum tls_io_name)wmGpio, g_gpioIrqCfg[wmGpio]); return HDF_SUCCESS; } static int32_t GpioDevDisableIrq(struct GpioCntlr *cntlr, uint16_t gpio) { uint16_t wmGpio; (void)cntlr; if (gpio >= WM_IO_MAX_GPIO_PIN_NUM) { HDF_LOGE("%s %d, error gpio:%hu", __func__, __LINE__, gpio); return HDF_ERR_NOT_SUPPORT; } wmGpio= g_gpioPinReflectionMap[gpio]; tls_gpio_irq_disable((enum tls_io_name)wmGpio); return HDF_SUCCESS; } static uint32_t GetGpioDeviceResource(struct GpioDevice *device, const struct DeviceResourceNode *resourceNode) { struct GpioResource *resource = NULL; struct DeviceResourceIface *dri = NULL; if (device == NULL || resourceNode == NULL) { HDF_LOGE("%s: device is NULL", __func__); return HDF_ERR_INVALID_PARAM; } resource = &device->resource; if (resource == NULL) { HDF_LOGE("%s: resource is NULL", __func__); return HDF_ERR_INVALID_OBJECT; } dri = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); if (dri == NULL || dri->GetUint32 == NULL || dri->GetUint32ArrayElem == NULL) { HDF_LOGE("DeviceResourceIface is invalid"); return HDF_ERR_INVALID_OBJECT; } if (dri->GetUint32(resourceNode, "groupNum", &resource->groupNum, 0) != HDF_SUCCESS) { HDF_LOGE("gpio config read groupNum fail"); return HDF_FAILURE; } if (dri->GetUint32(resourceNode, "pinNum", &resource->pinNum, 0) != HDF_SUCCESS) { HDF_LOGE("gpio config read pinNum fail"); return HDF_FAILURE; } for (size_t i = 0; i < resource->groupNum; i++) { if (dri->GetUint32ArrayElem(resourceNode, "config", i, &resource->config, 0) != HDF_SUCCESS) { HDF_LOGE("gpio config read config fail"); return HDF_FAILURE; } } device->config = resource->config; return HDF_SUCCESS; } static int32_t AttachGpioDevice(struct GpioCntlr *gpioCntlr, const struct HdfDeviceObject *device) { int32_t ret; struct GpioDevice *gpioDevice = NULL; if (device == NULL || device->property == NULL) { HDF_LOGE("%s: property is NULL", __func__); return HDF_ERR_INVALID_PARAM; } gpioDevice = (struct GpioDevice *)OsalMemAlloc(sizeof(struct GpioDevice)); if (gpioDevice == NULL) { HDF_LOGE("%s: OsalMemAlloc gpioDevice error", __func__); return HDF_ERR_MALLOC_FAIL; } ret = GetGpioDeviceResource(gpioDevice, device->property); if (ret != HDF_SUCCESS) { (void)OsalMemFree(gpioDevice); return HDF_FAILURE; } gpioCntlr->count = gpioDevice->resource.pinNum; return HDF_SUCCESS; } static int32_t GpioDriverInit(struct HdfDeviceObject *device) { int32_t ret; struct GpioCntlr *gpioCntlr = NULL; if (device == NULL) { HDF_LOGE("%s: device is NULL", __func__); return HDF_ERR_INVALID_PARAM; } gpioCntlr = GpioCntlrFromHdfDev(device); if (gpioCntlr == NULL) { HDF_LOGE("GpioCntlrFromHdfDev fail\r\n"); return HDF_DEV_ERR_NO_DEVICE_SERVICE; } ret = AttachGpioDevice(gpioCntlr, device); // GpioCntlr add GpioDevice to priv if (ret != HDF_SUCCESS) { HDF_LOGE("AttachGpioDevice fail\r\n"); return HDF_DEV_ERR_ATTACHDEV_FAIL; } gpioCntlr->ops = &g_GpioCntlrMethod; // register callback ret = GpioCntlrAdd(gpioCntlr); if (ret != HDF_SUCCESS) { HDF_LOGE("GpioCntlrAdd fail %d\r\n", gpioCntlr->start); return HDF_FAILURE; } return HDF_SUCCESS; } static int32_t GpioDriverBind(struct HdfDeviceObject *device) { if (device == NULL) { HDF_LOGE("Sample device object is null!"); return HDF_ERR_INVALID_PARAM; } gpioCntlr.device.hdfDev = device; device->service = gpioCntlr.device.hdfDev; return HDF_SUCCESS; } static void GpioDriverRelease(struct HdfDeviceObject *device) { struct GpioCntlr *gpioCntlr = NULL; if (device == NULL) { HDF_LOGE("%s: device is NULL", __func__); return; } gpioCntlr = GpioCntlrFromHdfDev(device); if (gpioCntlr == NULL) { HDF_LOGE("%s: host is NULL", __func__); return; } gpioCntlr->ops = NULL; OsalMemFree(gpioCntlr); } /* HdfDriverEntry definitions */ struct HdfDriverEntry g_GpioDriverEntry = { .moduleVersion = 1, .moduleName = "WM_GPIO_MODULE_HDF", .Bind = GpioDriverBind, .Init = GpioDriverInit, .Release = GpioDriverRelease, }; HDF_INIT(g_GpioDriverEntry);