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