|
@@ -10,6 +10,227 @@
|
|
|
|
|
|
#include "dev_pin_dm.h"
|
|
#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)
|
|
static void pin_dm_irq_mask(struct rt_pic_irq *pirq)
|
|
{
|
|
{
|
|
struct rt_device_pin *gpio = pirq->pic->priv_data;
|
|
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;
|
|
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;
|
|
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;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
-static struct rt_pic_ops pin_dm_ops =
|
|
|
|
|
|
+const static struct rt_pic_ops pin_dm_ops =
|
|
{
|
|
{
|
|
.name = "GPIO",
|
|
.name = "GPIO",
|
|
.irq_enable = pin_dm_irq_mask,
|
|
.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)
|
|
if (gpio)
|
|
{
|
|
{
|
|
|
|
+ rt_ubase_t pin_index = pin;
|
|
struct rt_pin_irqchip *irqchip = &gpio->irqchip;
|
|
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_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)
|
|
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;
|
|
err = -RT_EINVAL;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ legacy_isr = &gpio->legacy_isr[pin_index];
|
|
|
|
+
|
|
|
|
+ if (legacy_isr->hdr)
|
|
|
|
+ {
|
|
|
|
+ legacy_isr->hdr(legacy_isr->args);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
else
|
|
else
|
|
{
|
|
{
|
|
@@ -143,32 +374,39 @@ rt_err_t pin_pic_handle_isr(struct rt_device_pin *gpio, rt_base_t pin)
|
|
return err;
|
|
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;
|
|
rt_err_t err;
|
|
|
|
|
|
if (gpio)
|
|
if (gpio)
|
|
{
|
|
{
|
|
struct rt_pin_irqchip *irqchip = &gpio->irqchip;
|
|
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
|
|
else
|
|
{
|
|
{
|