123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458 |
- /*
- * Copyright (c) 2006-2022, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2022-11-26 GuEe-GUI first version
- */
- #include "dev_pin_dm.h"
- static rt_size_t pin_total_nr = 0;
- static RT_DEFINE_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;
- gpio->ops->pin_irq_enable(&gpio->parent, pirq->hwirq, 0);
- }
- static void pin_dm_irq_unmask(struct rt_pic_irq *pirq)
- {
- struct rt_device_pin *gpio = pirq->pic->priv_data;
- gpio->ops->pin_irq_enable(&gpio->parent, pirq->hwirq, 1);
- }
- static rt_err_t pin_dm_irq_set_triger_mode(struct rt_pic_irq *pirq, rt_uint32_t mode)
- {
- rt_uint8_t pin_mode;
- struct rt_device_pin *gpio = pirq->pic->priv_data;
- switch (mode)
- {
- case RT_IRQ_MODE_EDGE_RISING:
- pin_mode = PIN_IRQ_MODE_RISING;
- break;
- case RT_IRQ_MODE_EDGE_FALLING:
- pin_mode = PIN_IRQ_MODE_FALLING;
- break;
- case RT_IRQ_MODE_EDGE_BOTH:
- pin_mode = PIN_IRQ_MODE_RISING_FALLING;
- break;
- case RT_IRQ_MODE_LEVEL_HIGH:
- pin_mode = PIN_IRQ_MODE_HIGH_LEVEL;
- break;
- case RT_IRQ_MODE_LEVEL_LOW:
- pin_mode = PIN_IRQ_MODE_LOW_LEVEL;
- break;
- default:
- return -RT_ENOSYS;
- }
- return gpio->ops->pin_irq_mode(&gpio->parent, pirq->hwirq, pin_mode);
- }
- static int pin_dm_irq_map(struct rt_pic *pic, int hwirq, rt_uint32_t mode)
- {
- int irq = -1;
- struct rt_device_pin *gpio = pic->priv_data;
- struct rt_pic_irq *pirq = rt_pic_find_irq(pic, hwirq);
- if (pirq)
- {
- irq = rt_pic_config_irq(pic, hwirq, hwirq);
- if (irq >= 0)
- {
- rt_pic_cascade(pirq, gpio->irqchip.irq);
- rt_pic_irq_set_triger_mode(irq, 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)
- {
- rt_err_t err = RT_EOK;
- if (args->args_count == 2)
- {
- out_pirq->hwirq = args->args[0];
- out_pirq->mode = args->args[1] & RT_IRQ_MODE_MASK;
- }
- else
- {
- err = -RT_EINVAL;
- }
- return err;
- }
- const static struct rt_pic_ops pin_dm_ops =
- {
- .name = "GPIO",
- .irq_enable = pin_dm_irq_mask,
- .irq_disable = pin_dm_irq_unmask,
- .irq_mask = pin_dm_irq_mask,
- .irq_unmask = pin_dm_irq_unmask,
- .irq_set_triger_mode = pin_dm_irq_set_triger_mode,
- .irq_map = pin_dm_irq_map,
- .irq_parse = pin_dm_irq_parse,
- };
- rt_err_t pin_pic_handle_isr(struct rt_device_pin *gpio, rt_base_t pin)
- {
- rt_err_t err;
- if (gpio)
- {
- rt_ubase_t pin_index = pin;
- struct rt_pin_irqchip *irqchip = &gpio->irqchip;
- 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_index);
- if (pirq->irq >= 0)
- {
- err = rt_pic_handle_isr(pirq);
- }
- else
- {
- err = -RT_EINVAL;
- }
- legacy_isr = &gpio->legacy_isr[pin_index];
- if (legacy_isr->hdr)
- {
- legacy_isr->hdr(legacy_isr->args);
- }
- }
- else
- {
- err = -RT_EINVAL;
- }
- }
- else
- {
- err = -RT_EINVAL;
- }
- return err;
- }
- 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;
- irqchip->irq = pin_irq;
- if (!gpio->pin_nr)
- {
- return -RT_EINVAL;
- }
- gpio->legacy_isr = rt_calloc(gpio->pin_nr, sizeof(*gpio->legacy_isr));
- if (!gpio->legacy_isr)
- {
- 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
- {
- err = -RT_EINVAL;
- }
- return err;
- }
- 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)
- {
- rt_ssize_t res = -RT_ENOSYS;
- RT_ASSERT(dev != RT_NULL);
- #ifdef RT_USING_OFW
- if (dev->ofw_node)
- {
- res = rt_ofw_get_named_pin(dev->ofw_node, propname, index, out_mode, out_value);
- }
- else
- {
- res = -RT_EINVAL;
- }
- #endif /* RT_USING_OFW */
- return res;
- }
- rt_ssize_t rt_pin_get_named_pin_count(struct rt_device *dev, const char *propname)
- {
- rt_ssize_t count = -RT_ENOSYS;
- RT_ASSERT(dev != RT_NULL);
- #ifdef RT_USING_OFW
- if (dev->ofw_node)
- {
- count = rt_ofw_get_named_pin_count(dev->ofw_node, propname);
- }
- else
- {
- count = -RT_EINVAL;
- }
- #endif /* RT_USING_OFW */
- return count;
- }
|