diff --git a/components/drivers/include/drivers/dev_pin.h b/components/drivers/include/drivers/dev_pin.h index e6ed7b6e83e..b1705ae6ddd 100644 --- a/components/drivers/include/drivers/dev_pin.h +++ b/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); diff --git a/components/drivers/pin/Kconfig b/components/drivers/pin/Kconfig index 24a2c02bf8c..2520897834b 100755 --- a/components/drivers/pin/Kconfig +++ b/components/drivers/pin/Kconfig @@ -1,3 +1,7 @@ menuconfig RT_USING_PIN bool "Using Generic GPIO device drivers" default y + +if RT_USING_PIN + osource "$(SOC_DM_PIN_DIR)/Kconfig" +endif diff --git a/components/drivers/pin/dev_pin.c b/components/drivers/pin/dev_pin.c index ddea62ff0e8..4403557b205 100644 --- a/components/drivers/pin/dev_pin.c +++ b/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) { diff --git a/components/drivers/pin/dev_pin_dm.c b/components/drivers/pin/dev_pin_dm.c index d7714c5a754..90cca94d226 100644 --- a/components/drivers/pin/dev_pin_dm.c +++ b/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 { diff --git a/components/drivers/pin/dev_pin_dm.h b/components/drivers/pin/dev_pin_dm.h index c85d93ca415..09374cab5cd 100644 --- a/components/drivers/pin/dev_pin_dm.h +++ b/components/drivers/pin/dev_pin_dm.h @@ -15,7 +15,9 @@ #include #include +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__ */ diff --git a/components/drivers/pin/dev_pin_ofw.c b/components/drivers/pin/dev_pin_ofw.c index d42cd83076e..fbf053811db 100644 --- a/components/drivers/pin/dev_pin_ofw.c +++ b/components/drivers/pin/dev_pin_ofw.c @@ -59,6 +59,12 @@ rt_ssize_t rt_ofw_get_named_pin(struct rt_ofw_node *np, const char *propname, in } pin_dev_np = pin_args.data; + + if (!rt_ofw_data(pin_dev_np)) + { + rt_platform_ofw_request(pin_dev_np); + } + pin_dev = rt_ofw_data(pin_dev_np); if (!pin_dev) @@ -111,11 +117,11 @@ rt_ssize_t rt_ofw_get_named_pin(struct rt_ofw_node *np, const char *propname, in if (out_value) { - if (flags == (PIN_ACTIVE_HIGH | PIN_PUSH_PULL)) + if ((flags & 1) == PIN_ACTIVE_HIGH) { value = PIN_HIGH; } - else if (flags == (PIN_ACTIVE_LOW | PIN_PUSH_PULL)) + else if ((flags & 1) == PIN_ACTIVE_LOW) { value = PIN_LOW; } @@ -124,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; @@ -142,7 +154,7 @@ rt_ssize_t rt_ofw_get_named_pin_count(struct rt_ofw_node *np, const char *propna char gpios_name[64]; rt_ssize_t count = 0; - if (!np || !propname) + if (!np) { return -RT_EINVAL; }