瀏覽代碼

[DM/FEATURE] Support virtual pin

1. There is only one GPIO device in System.
2. For Pin API input is pin number
3. Add sets pin debounce time API.

So we need a virtual pin for multi gpio chip.

Signed-off-by: GuEe-GUI <2991707448@qq.com>
GuEe-GUI 6 月之前
父節點
當前提交
e3340eca34

+ 17 - 0
components/drivers/include/drivers/dev_pin.h

@@ -89,6 +89,8 @@ struct rt_pin_irqchip
     int irq;
     rt_base_t pin_range[2];
 };
+
+struct rt_pin_irq_hdr;
 #endif /* RT_USING_DM */
 
 /**
@@ -98,7 +100,13 @@ struct rt_device_pin
 {
     struct rt_device parent;
 #ifdef RT_USING_DM
+    /* MUST keep the order member after parent */
     struct rt_pin_irqchip irqchip;
+    /* Fill by DM */
+    rt_base_t pin_start;
+    rt_size_t pin_nr;
+    rt_list_t list;
+    struct rt_pin_irq_hdr *legacy_isr;
 #endif /* RT_USING_DM */
     const struct rt_pin_ops *ops;
 };
@@ -212,6 +220,7 @@ struct rt_pin_ops
     rt_err_t (*pin_detach_irq)(struct rt_device *device, rt_base_t pin);
     rt_err_t (*pin_irq_enable)(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled);
     rt_base_t (*pin_get)(const char *name);
+    rt_err_t (*pin_debounce)(struct rt_device *device, rt_base_t pin, rt_uint32_t debounce);
 #ifdef RT_USING_DM
     rt_err_t (*pin_irq_mode)(struct rt_device *device, rt_base_t pin, rt_uint8_t mode);
     rt_ssize_t (*pin_parse)(struct rt_device *device, struct rt_ofw_cell_args *args, rt_uint32_t *flags);
@@ -284,6 +293,14 @@ rt_err_t rt_pin_detach_irq(rt_base_t pin);
  */
 rt_err_t rt_pin_irq_enable(rt_base_t pin, rt_uint8_t enabled);
 
+/**
+ * @brief set the pin's debounce time
+ * @param pin the pin number
+ * @param debounce time
+ * @return rt_err_t error code
+ */
+rt_err_t rt_pin_debounce(rt_base_t pin, rt_uint32_t debounce);
+
 #ifdef RT_USING_DM
 rt_ssize_t rt_pin_get_named_pin(struct rt_device *dev, const char *propname, int index,
         rt_uint8_t *out_mode, rt_uint8_t *out_value);

+ 10 - 0
components/drivers/pin/dev_pin.c

@@ -132,6 +132,16 @@ rt_err_t rt_pin_irq_enable(rt_base_t pin, rt_uint8_t enabled)
     return -RT_ENOSYS;
 }
 
+rt_err_t rt_pin_debounce(rt_base_t pin, rt_uint32_t debounce)
+{
+    RT_ASSERT(_hw_pin.ops != RT_NULL);
+    if (_hw_pin.ops->pin_debounce)
+    {
+        return _hw_pin.ops->pin_debounce(&_hw_pin.parent, pin, debounce);
+    }
+    return -RT_ENOSYS;
+}
+
 /* RT-Thread Hardware PIN APIs */
 void rt_pin_mode(rt_base_t pin, rt_uint8_t mode)
 {

+ 256 - 18
components/drivers/pin/dev_pin_dm.c

@@ -10,6 +10,227 @@
 
 #include "dev_pin_dm.h"
 
+static rt_size_t pin_total_nr = 0;
+static struct rt_spinlock pin_lock = {};
+static rt_list_t pin_nodes = RT_LIST_OBJECT_INIT(pin_nodes);
+
+static struct rt_device_pin *pin_device_find(rt_ubase_t pin)
+{
+    struct rt_device_pin *gpio = RT_NULL, *gpio_tmp;
+
+    rt_spin_lock(&pin_lock);
+
+    rt_list_for_each_entry(gpio_tmp, &pin_nodes, list)
+    {
+        if (pin >= gpio_tmp->pin_start &&
+            pin - gpio_tmp->pin_start < gpio_tmp->pin_nr)
+        {
+            gpio = gpio_tmp;
+            break;
+        }
+    }
+
+    rt_spin_unlock(&pin_lock);
+
+    return gpio;
+}
+
+static void pin_api_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode)
+{
+    struct rt_device_pin *gpio = pin_device_find(pin);
+
+    if (gpio && gpio->ops->pin_mode)
+    {
+        gpio->ops->pin_mode(&gpio->parent, pin - gpio->pin_start, mode);
+    }
+}
+
+static void pin_api_write(struct rt_device *device, rt_base_t pin, rt_uint8_t value)
+{
+    struct rt_device_pin *gpio = pin_device_find(pin);
+
+    if (gpio && gpio->ops->pin_write)
+    {
+        gpio->ops->pin_write(&gpio->parent, pin - gpio->pin_start, value);
+    }
+}
+
+static rt_ssize_t pin_api_read(struct rt_device *device, rt_base_t pin)
+{
+    struct rt_device_pin *gpio = pin_device_find(pin);
+
+    if (gpio && gpio->ops->pin_read)
+    {
+        return gpio->ops->pin_read(&gpio->parent, pin - gpio->pin_start);
+    }
+
+    return -RT_EINVAL;
+}
+
+static rt_err_t pin_api_attach_irq(struct rt_device *device, rt_base_t pin,
+        rt_uint8_t mode, void (*hdr)(void *args), void *args)
+{
+    struct rt_device_pin *gpio = pin_device_find(pin);
+
+    if (gpio)
+    {
+        rt_base_t pin_index = pin - gpio->pin_start;
+
+        if (!gpio->ops->pin_attach_irq)
+        {
+            rt_err_t err;
+            struct rt_pin_irq_hdr *legacy_isr;
+
+            if ((err = gpio->ops->pin_irq_mode(&gpio->parent, pin_index, mode)))
+            {
+                return err;
+            }
+
+            legacy_isr = &gpio->legacy_isr[pin_index];
+            legacy_isr->pin = pin_index;
+            legacy_isr->mode = mode;
+            legacy_isr->hdr = hdr;
+            legacy_isr->args = args;
+
+            return RT_EOK;
+        }
+        else
+        {
+            return gpio->ops->pin_attach_irq(&gpio->parent, pin_index, mode, hdr, args);
+        }
+    }
+
+    return -RT_EINVAL;
+}
+
+static rt_err_t pin_api_detach_irq(struct rt_device *device, rt_base_t pin)
+{
+    struct rt_device_pin *gpio = pin_device_find(pin);
+
+    if (gpio)
+    {
+        rt_base_t pin_index = pin - gpio->pin_start;
+
+        if (!gpio->ops->pin_detach_irq)
+        {
+            struct rt_pin_irq_hdr *legacy_isr;
+
+            legacy_isr = &gpio->legacy_isr[pin_index];
+            rt_memset(legacy_isr, 0, sizeof(*legacy_isr));
+
+            return RT_EOK;
+        }
+        else
+        {
+            return gpio->ops->pin_detach_irq(&gpio->parent, pin);
+        }
+    }
+
+    return -RT_EINVAL;
+}
+
+static rt_err_t pin_api_irq_enable(struct rt_device *device, rt_base_t pin,
+        rt_uint8_t enabled)
+{
+    struct rt_device_pin *gpio = pin_device_find(pin);
+
+    if (gpio && gpio->ops->pin_irq_enable)
+    {
+        return gpio->ops->pin_irq_enable(&gpio->parent, pin - gpio->pin_start, enabled);
+    }
+
+    return -RT_EINVAL;
+}
+
+static rt_base_t pin_api_get(const char *name)
+{
+    rt_base_t res = -RT_EINVAL;
+    struct rt_device_pin *gpio;
+
+    rt_spin_lock(&pin_lock);
+
+    rt_list_for_each_entry(gpio, &pin_nodes, list)
+    {
+        if (gpio->ops->pin_get && !(res = gpio->ops->pin_get(name)))
+        {
+            break;
+        }
+    }
+
+    rt_spin_unlock(&pin_lock);
+
+    return res;
+}
+
+static rt_err_t pin_api_debounce(struct rt_device *device, rt_base_t pin,
+        rt_uint32_t debounce)
+{
+    struct rt_device_pin *gpio = pin_device_find(pin);
+
+    if (gpio && gpio->ops->pin_debounce)
+    {
+        return gpio->ops->pin_debounce(&gpio->parent, pin - gpio->pin_start, debounce);
+    }
+
+    return -RT_EINVAL;
+}
+
+static rt_err_t pin_api_irq_mode(struct rt_device *device, rt_base_t pin,
+        rt_uint8_t mode)
+{
+    struct rt_device_pin *gpio = pin_device_find(pin);
+
+    if (gpio && gpio->ops->pin_irq_mode)
+    {
+        return gpio->ops->pin_irq_mode(&gpio->parent, pin - gpio->pin_start, mode);
+    }
+
+    return -RT_EINVAL;
+}
+
+static const struct rt_pin_ops pin_api_dm_ops =
+{
+    .pin_mode = pin_api_mode,
+    .pin_write = pin_api_write,
+    .pin_read = pin_api_read,
+    .pin_attach_irq = pin_api_attach_irq,
+    .pin_detach_irq = pin_api_detach_irq,
+    .pin_irq_enable = pin_api_irq_enable,
+    .pin_get = pin_api_get,
+    .pin_debounce = pin_api_debounce,
+    .pin_irq_mode = pin_api_irq_mode,
+};
+
+rt_err_t pin_api_init(struct rt_device_pin *gpio, rt_size_t pin_nr)
+{
+    rt_err_t err = RT_EOK;
+
+    if (!gpio || !gpio->ops)
+    {
+        return -RT_EINVAL;
+    }
+
+    rt_spin_lock(&pin_lock);
+
+    if (rt_list_isempty(&pin_nodes))
+    {
+        rt_spin_unlock(&pin_lock);
+        rt_device_pin_register("gpio", &pin_api_dm_ops, RT_NULL);
+        rt_spin_lock(&pin_lock);
+    }
+
+    gpio->pin_start = pin_total_nr;
+    gpio->pin_nr = pin_nr;
+    pin_total_nr += pin_nr;
+
+    rt_list_init(&gpio->list);
+    rt_list_insert_before(&pin_nodes, &gpio->list);
+
+    rt_spin_unlock(&pin_lock);
+
+    return err;
+}
+
 static void pin_dm_irq_mask(struct rt_pic_irq *pirq)
 {
     struct rt_device_pin *gpio = pirq->pic->priv_data;
@@ -78,7 +299,8 @@ static int pin_dm_irq_map(struct rt_pic *pic, int hwirq, rt_uint32_t mode)
     return irq;
 }
 
-static rt_err_t pin_dm_irq_parse(struct rt_pic *pic, struct rt_ofw_cell_args *args, struct rt_pic_irq *out_pirq)
+static rt_err_t pin_dm_irq_parse(struct rt_pic *pic,
+        struct rt_ofw_cell_args *args, struct rt_pic_irq *out_pirq)
 {
     rt_err_t err = RT_EOK;
 
@@ -95,7 +317,7 @@ static rt_err_t pin_dm_irq_parse(struct rt_pic *pic, struct rt_ofw_cell_args *ar
     return err;
 }
 
-static struct rt_pic_ops pin_dm_ops =
+const static struct rt_pic_ops pin_dm_ops =
 {
     .name = "GPIO",
     .irq_enable = pin_dm_irq_mask,
@@ -113,13 +335,15 @@ rt_err_t pin_pic_handle_isr(struct rt_device_pin *gpio, rt_base_t pin)
 
     if (gpio)
     {
+        rt_ubase_t pin_index = pin;
         struct rt_pin_irqchip *irqchip = &gpio->irqchip;
 
-        if (pin >= irqchip->pin_range[0] && pin <= irqchip->pin_range[1])
+        if (pin_index < gpio->pin_nr)
         {
             struct rt_pic_irq *pirq;
+            struct rt_pin_irq_hdr *legacy_isr;
 
-            pirq = rt_pic_find_irq(&irqchip->parent, pin - irqchip->pin_range[0]);
+            pirq = rt_pic_find_irq(&irqchip->parent, pin_index);
 
             if (pirq->irq >= 0)
             {
@@ -129,6 +353,13 @@ rt_err_t pin_pic_handle_isr(struct rt_device_pin *gpio, rt_base_t pin)
             {
                 err = -RT_EINVAL;
             }
+
+            legacy_isr = &gpio->legacy_isr[pin_index];
+
+            if (legacy_isr->hdr)
+            {
+                legacy_isr->hdr(legacy_isr->args);
+            }
         }
         else
         {
@@ -143,32 +374,39 @@ rt_err_t pin_pic_handle_isr(struct rt_device_pin *gpio, rt_base_t pin)
     return err;
 }
 
-rt_err_t pin_pic_init(struct rt_device_pin *gpio)
+rt_err_t pin_pic_init(struct rt_device_pin *gpio, int pin_irq)
 {
     rt_err_t err;
 
     if (gpio)
     {
         struct rt_pin_irqchip *irqchip = &gpio->irqchip;
+        struct rt_pic *pic = &irqchip->parent;
 
-        if (irqchip->pin_range[0] >= 0 && irqchip->pin_range[1] >= irqchip->pin_range[0])
+        irqchip->irq = pin_irq;
+
+        if (!gpio->pin_nr)
         {
-            struct rt_pic *pic = &irqchip->parent;
-            rt_size_t pin_nr = irqchip->pin_range[1] - irqchip->pin_range[0] + 1;
+            return -RT_EINVAL;
+        }
 
-            pic->priv_data = gpio;
-            pic->ops = &pin_dm_ops;
-            /* Make sure the type of gpio for pic */
-            gpio->parent.parent.type = RT_Object_Class_Device;
-            rt_pic_default_name(&irqchip->parent);
+        gpio->legacy_isr = rt_calloc(gpio->pin_nr, sizeof(*gpio->legacy_isr));
 
-            err = rt_pic_linear_irq(pic, pin_nr);
-            rt_pic_user_extends(pic);
-        }
-        else
+        if (!gpio->legacy_isr)
         {
-            err = -RT_EINVAL;
+            return -RT_ENOMEM;
         }
+
+        pic->priv_data = gpio;
+        pic->ops = &pin_dm_ops;
+        /* Make sure the type of gpio for pic */
+        gpio->parent.parent.type = RT_Object_Class_Device;
+        rt_pic_default_name(&irqchip->parent);
+
+        err = rt_pic_linear_irq(pic, gpio->pin_nr);
+        rt_pic_user_extends(pic);
+
+        err = RT_EOK;
     }
     else
     {

+ 3 - 1
components/drivers/pin/dev_pin_dm.h

@@ -15,7 +15,9 @@
 #include <rtthread.h>
 #include <rtdevice.h>
 
+rt_err_t pin_api_init(struct rt_device_pin *gpio, rt_size_t pin_nr);
+
+rt_err_t pin_pic_init(struct rt_device_pin *gpio, int pin_irq);
 rt_err_t pin_pic_handle_isr(struct rt_device_pin *gpio, rt_base_t pin);
-rt_err_t pin_pic_init(struct rt_device_pin *gpio);
 
 #endif /* __DEV_PIN_DM_H__ */

+ 12 - 6
components/drivers/pin/dev_pin_ofw.c

@@ -130,14 +130,20 @@ rt_ssize_t rt_ofw_get_named_pin(struct rt_ofw_node *np, const char *propname, in
 _out_converts:
     rt_ofw_node_put(pin_dev_np);
 
-    if (out_mode)
+    if (pin >= 0)
     {
-        *out_mode = mode;
-    }
+        /* Get virtual pin */
+        pin += pin_dev->pin_start;
 
-    if (out_value)
-    {
-        *out_value = value;
+        if (out_mode)
+        {
+            *out_mode = mode;
+        }
+
+        if (out_value)
+        {
+            *out_value = value;
+        }
     }
 
     return pin;