فهرست منبع

[bsp][cv1800b] Add gpio driver for cv1800b (#8158)

xiunian 1 سال پیش
والد
کامیت
53801fc4ab
2فایلهای تغییر یافته به همراه351 افزوده شده و 0 حذف شده
  1. 336 0
      bsp/cv1800b/drivers/drv_gpio.c
  2. 15 0
      bsp/cv1800b/drivers/drv_gpio.h

+ 336 - 0
bsp/cv1800b/drivers/drv_gpio.c

@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2023/10/19     xiunian      first version
+ */
+#include <rthw.h>
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <board.h>
+#include <ioremap.h>
+
+#ifdef RT_USING_PIN
+#include "drv_gpio.h"
+
+#define GPIO_SWPORTA_DR     0x00
+#define GPIO_SWPORTA_DDR    0x04
+
+#define GPIO_INTEN          0x30
+#define GPIO_INTTYPE_LEVEL  0x38
+#define GPIO_INT_POLARITY   0x3c
+#define GPIO_INTSTATUS      0x40
+#define GPIO_PORTA_EOI      0x4c
+
+#define GPIO_EXT_PORTA      0x50
+
+#define DWAPB_DRIVER_NAME   "gpio-dwapb"
+
+#define DWAPB_GPIOA_BASE    0x03020000
+#define DWAPB_GPIOE_BASE    0x05021000
+
+#define DWAPB_GPIO_SIZE     0x1000
+#define DWAPB_GPIOA_IRQNUM  0x3c
+#define DWAPB_GPIOE_IRQNUM  0x46
+
+#define DWAPB_GPIO_PORT_NR  5
+#define DWAPB_GPIO_NR       32
+
+#define PIN_NUM(port, no)   (((((port) & 0xFu) << 8) | ((no) & 0xFFu)))
+#define PIN_PORT(pin)       ((uint8_t)(((pin) >> 8) & 0xFu))
+#define PIN_NO(pin)         ((uint8_t)((pin) & 0xFFu))
+
+#define BIT(x)              (1UL << (x))
+
+rt_inline rt_uint32_t dwapb_read32(rt_ubase_t addr)
+{
+    return HWREG32(addr);
+}
+
+rt_inline void dwapb_write32(rt_ubase_t addr, rt_uint32_t value)
+{
+    HWREG32(addr) = value;
+}
+
+static rt_ubase_t dwapb_gpio_base = DWAPB_GPIOA_BASE;
+static rt_ubase_t dwapb_gpio_base_e = DWAPB_GPIOE_BASE;
+
+static struct dwapb_event
+{
+    void (*(hdr[DWAPB_GPIO_NR]))(void *args);
+    void *args[DWAPB_GPIO_NR];
+    rt_uint8_t is_both_edge[DWAPB_GPIO_NR];
+} _dwapb_events[DWAPB_GPIO_PORT_NR];
+
+static void dwapb_toggle_trigger(rt_uint8_t port, rt_uint8_t bit)
+{
+    rt_uint8_t val;
+    rt_ubase_t base_addr;
+    rt_uint32_t pol;
+
+    base_addr = (port == 4 ? dwapb_gpio_base_e : (dwapb_gpio_base + DWAPB_GPIO_SIZE * port));
+
+    pol = dwapb_read32(base_addr + GPIO_INT_POLARITY);
+    /* Just read the current value right out of the data register */
+    val = (rt_uint8_t)((dwapb_read32(base_addr + GPIO_EXT_PORTA) >> (bit)) & 1);
+
+    if (val)
+        pol &= ~BIT(bit);
+    else
+        pol |= BIT(bit);
+
+    dwapb_write32(base_addr + GPIO_INT_POLARITY, pol);
+}
+
+static void dwapb_pin_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode)
+{
+    rt_uint8_t bit, port;
+    rt_ubase_t base_addr;
+    rt_uint32_t reg_val;
+
+    bit = PIN_NO(pin);
+    port = PIN_PORT(pin);
+    base_addr = (port == 4 ? dwapb_gpio_base_e : (dwapb_gpio_base + DWAPB_GPIO_SIZE * port));
+
+    reg_val = dwapb_read32(base_addr + GPIO_SWPORTA_DDR);
+    switch (mode)
+    {
+    case PIN_MODE_OUTPUT:
+        reg_val |= BIT(bit);
+        break;
+    case PIN_MODE_INPUT:
+        reg_val &= ~BIT(bit);
+        break;
+    }
+
+    dwapb_write32(base_addr + GPIO_SWPORTA_DDR, reg_val);
+}
+
+static void dwapb_pin_write(struct rt_device *device, rt_base_t pin, rt_uint8_t value)
+{
+    rt_uint8_t bit, port;
+    rt_ubase_t base_addr;
+    rt_uint32_t reg_val;
+
+    bit = PIN_NO(pin);
+    port = PIN_PORT(pin);
+    base_addr = (port == 4 ? dwapb_gpio_base_e : (dwapb_gpio_base + DWAPB_GPIO_SIZE * port));
+
+    reg_val = dwapb_read32(base_addr + GPIO_SWPORTA_DR);
+    reg_val = (value ? (reg_val | BIT(bit)) : (reg_val & (~BIT(bit))));
+    dwapb_write32(base_addr + GPIO_SWPORTA_DR, reg_val);
+}
+
+static rt_int8_t dwapb_pin_read(struct rt_device *device, rt_base_t pin)
+{
+    rt_uint8_t bit, port;
+    rt_ubase_t base_addr;
+
+    bit = PIN_NO(pin);
+    port = PIN_PORT(pin);
+    base_addr = (port == 4 ? dwapb_gpio_base_e : (dwapb_gpio_base + DWAPB_GPIO_SIZE * port));
+
+    rt_uint32_t reg_val = dwapb_read32(GPIO_EXT_PORTA + base_addr);
+    return ((reg_val >> (bit)) & 1);
+}
+
+static rt_base_t dwapb_pin_get(const char *name)
+{
+    rt_base_t pin = 0;
+    int port_num, pin_num = 0;
+    int i, name_len;
+
+    name_len = rt_strlen(name);
+
+    if ((name_len < 2) || (name_len > 3))
+    {
+        goto out;
+    }
+
+    if ((name[0] >= 'A') && (name[0] <= 'E'))
+    {
+        port_num = (int)(name[0] - 'A');
+    }
+    else
+    {
+        goto out;
+    }
+
+    for (i = 1; i < name_len; i++)
+    {
+        pin_num *= 10;
+        pin_num += name[i] - '0';
+    }
+
+    pin = PIN_NUM(port_num, pin_num);
+
+    return pin;
+out:
+    rt_kprintf("xy   x:A~E  y:0~31, e.g. C24\n");
+    return -RT_EINVAL;
+}
+
+static rt_err_t dwapb_pin_attach_irq(struct rt_device *device, rt_base_t pin, rt_uint8_t mode, void (*hdr)(void *args), void *args)
+{
+    rt_uint8_t bit, port;
+    rt_ubase_t base_addr;
+    rt_uint32_t it_val, ip_val;
+
+    bit = PIN_NO(pin);
+    port = PIN_PORT(pin);
+
+    base_addr = (port == 4 ? dwapb_gpio_base_e : (dwapb_gpio_base + DWAPB_GPIO_SIZE * port));
+
+    it_val = dwapb_read32(base_addr + GPIO_INTTYPE_LEVEL);
+    ip_val = dwapb_read32(base_addr + GPIO_INT_POLARITY);
+
+    if (mode == PIN_IRQ_MODE_HIGH_LEVEL || mode == PIN_IRQ_MODE_LOW_LEVEL)
+    {
+        rt_bool_t polarity = (mode == PIN_IRQ_MODE_HIGH_LEVEL);
+
+        /* Enable level detection */
+        it_val = (it_val & (~BIT(bit)));
+        /* Select polarity */
+        ip_val = (polarity ? (ip_val | BIT(bit)) : (ip_val & (~BIT(bit))));
+    }
+    else if (mode == PIN_IRQ_MODE_RISING_FALLING)
+    {
+        /* Disable level detection */
+        it_val = (it_val | BIT(bit));
+        /* Select both edges */
+        dwapb_toggle_trigger(port, bit);
+    }
+    else if (mode == PIN_IRQ_MODE_RISING || mode == PIN_IRQ_MODE_FALLING)
+    {
+        rt_bool_t rising = (mode == PIN_IRQ_MODE_RISING);
+
+        /* Disable level detection */
+        it_val = (it_val | BIT(bit));
+        /* Select edge */
+        ip_val = (rising ? (ip_val | BIT(bit)) : (ip_val & (~BIT(bit))));
+    }
+    else
+    {
+        /* No trigger: disable everything */
+        it_val = (it_val & (~BIT(bit)));
+        ip_val = (ip_val & (~BIT(bit)));
+    }
+
+    dwapb_write32(base_addr + GPIO_INTTYPE_LEVEL, it_val);
+    if (mode != PIN_IRQ_MODE_RISING_FALLING)
+        dwapb_write32(base_addr + GPIO_INT_POLARITY, ip_val);
+
+    _dwapb_events[PIN_PORT(pin)].hdr[PIN_NO(pin)] = hdr;
+    _dwapb_events[PIN_PORT(pin)].args[PIN_NO(pin)] = args;
+    _dwapb_events[PIN_PORT(pin)].is_both_edge[PIN_NO(pin)] = (mode == PIN_IRQ_MODE_RISING_FALLING);
+
+    return RT_EOK;
+}
+
+static rt_err_t dwapb_pin_detach_irq(struct rt_device *device, rt_base_t pin)
+{
+    _dwapb_events[PIN_PORT(pin)].hdr[PIN_NO(pin)] = RT_NULL;
+    _dwapb_events[PIN_PORT(pin)].args[PIN_NO(pin)] = RT_NULL;
+    _dwapb_events[PIN_PORT(pin)].is_both_edge[PIN_NO(pin)] = 0;
+
+    return RT_EOK;
+}
+
+static rt_err_t dwapb_pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled)
+{
+    rt_uint8_t bit, port;
+    rt_ubase_t base_addr;
+
+    bit = PIN_NO(pin);
+    port = PIN_PORT(pin);
+    base_addr = (port == 4 ? dwapb_gpio_base_e : (dwapb_gpio_base + DWAPB_GPIO_SIZE * port));
+
+    rt_uint32_t reg_val = dwapb_read32(base_addr + GPIO_INTEN);
+    reg_val = (enabled ? (reg_val | BIT(bit)) : (reg_val & (~BIT(bit))));
+    dwapb_write32(base_addr + GPIO_INTEN, reg_val);
+
+    return RT_EOK;
+}
+
+static const struct rt_pin_ops _dwapb_ops =
+{
+    dwapb_pin_mode,
+    dwapb_pin_write,
+    dwapb_pin_read,
+    dwapb_pin_attach_irq,
+    dwapb_pin_detach_irq,
+    dwapb_pin_irq_enable,
+    dwapb_pin_get,
+};
+
+static void rt_hw_gpio_isr(int irqno, void *param)
+{
+    rt_uint8_t port;
+    rt_ubase_t base_addr;
+    rt_uint32_t pending, mask;
+
+    mask = 0;
+    port = (irqno == DWAPB_GPIOE_IRQNUM ? 4 : (irqno - DWAPB_GPIOA_IRQNUM));
+
+    base_addr = (port == 4 ? dwapb_gpio_base_e : (dwapb_gpio_base + DWAPB_GPIO_SIZE * port));
+    pending = dwapb_read32(base_addr + GPIO_INTSTATUS);
+
+    if (pending)
+    {
+        rt_base_t bit;
+
+        for (bit = 0; bit < DWAPB_GPIO_NR; ++bit)
+        {
+            if (pending & BIT(bit))
+            {
+                mask = (mask | (BIT(bit)));
+
+                if (_dwapb_events[port].hdr[bit] != RT_NULL)
+                {
+                    _dwapb_events[port].hdr[bit](_dwapb_events[port].args[bit]);
+                }
+
+                if (_dwapb_events[port].is_both_edge[bit]) {
+                    dwapb_toggle_trigger(port, bit);
+                }
+            }
+        }
+    }
+
+    dwapb_write32(base_addr + GPIO_PORTA_EOI, mask);
+}
+
+int rt_hw_gpio_init(void)
+{
+#ifdef RT_USING_LWP
+#define BSP_IOREMAP_GPIO_DEVICE(no)     \
+    rt_ioremap((void *)(DWAPB_GPIOA_BASE + (no) * DWAPB_GPIO_SIZE), DWAPB_GPIO_SIZE);
+
+    dwapb_gpio_base = (rt_size_t)BSP_IOREMAP_GPIO_DEVICE(0);
+    BSP_IOREMAP_GPIO_DEVICE(1);
+    BSP_IOREMAP_GPIO_DEVICE(2);
+    BSP_IOREMAP_GPIO_DEVICE(3);
+    dwapb_gpio_base_e = (rt_size_t)rt_ioremap((void *)DWAPB_GPIOE_BASE, DWAPB_GPIO_SIZE);
+#endif
+
+    rt_device_pin_register("gpio", &_dwapb_ops, RT_NULL);
+
+#define INT_INSTALL_GPIO_DEVICE(no)     \
+    rt_hw_interrupt_install(DWAPB_GPIOA_IRQNUM + (no), rt_hw_gpio_isr, RT_NULL, "gpio");    \
+    rt_hw_interrupt_umask(DWAPB_GPIOA_IRQNUM + (no));
+
+    INT_INSTALL_GPIO_DEVICE(0);
+    INT_INSTALL_GPIO_DEVICE(1);
+    INT_INSTALL_GPIO_DEVICE(2);
+    INT_INSTALL_GPIO_DEVICE(3);
+
+    rt_hw_interrupt_install(DWAPB_GPIOE_IRQNUM, rt_hw_gpio_isr, RT_NULL, "gpio");
+    rt_hw_interrupt_umask(DWAPB_GPIOE_IRQNUM);
+    return 0;
+}
+INIT_DEVICE_EXPORT(rt_hw_gpio_init);
+
+#endif /* RT_USING_PIN */

+ 15 - 0
bsp/cv1800b/drivers/drv_gpio.h

@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2023/10/19     xiunian      first version
+ */
+#ifndef DRV_GPIO_H__
+#define DRV_GPIO_H__
+
+int rt_hw_gpio_init(void);
+
+#endif