|
@@ -1,5 +1,5 @@
|
|
|
/*
|
|
|
- * GPIOs on MPC8349/8572/8610 and compatible
|
|
|
+ * GPIOs on MPC512x/8349/8572/8610 and compatible
|
|
|
*
|
|
|
* Copyright (C) 2008 Peter Korsgaard <jacmet@sunsite.dk>
|
|
|
*
|
|
@@ -26,6 +26,7 @@
|
|
|
#define GPIO_IER 0x0c
|
|
|
#define GPIO_IMR 0x10
|
|
|
#define GPIO_ICR 0x14
|
|
|
+#define GPIO_ICR2 0x18
|
|
|
|
|
|
struct mpc8xxx_gpio_chip {
|
|
|
struct of_mm_gpio_chip mm_gc;
|
|
@@ -37,6 +38,7 @@ struct mpc8xxx_gpio_chip {
|
|
|
*/
|
|
|
u32 data;
|
|
|
struct irq_host *irq;
|
|
|
+ void *of_dev_id_data;
|
|
|
};
|
|
|
|
|
|
static inline u32 mpc8xxx_gpio2mask(unsigned int gpio)
|
|
@@ -215,6 +217,51 @@ static int mpc8xxx_irq_set_type(unsigned int virq, unsigned int flow_type)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int mpc512x_irq_set_type(unsigned int virq, unsigned int flow_type)
|
|
|
+{
|
|
|
+ struct mpc8xxx_gpio_chip *mpc8xxx_gc = get_irq_chip_data(virq);
|
|
|
+ struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
|
|
|
+ unsigned long gpio = virq_to_hw(virq);
|
|
|
+ void __iomem *reg;
|
|
|
+ unsigned int shift;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ if (gpio < 16) {
|
|
|
+ reg = mm->regs + GPIO_ICR;
|
|
|
+ shift = (15 - gpio) * 2;
|
|
|
+ } else {
|
|
|
+ reg = mm->regs + GPIO_ICR2;
|
|
|
+ shift = (15 - (gpio % 16)) * 2;
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (flow_type) {
|
|
|
+ case IRQ_TYPE_EDGE_FALLING:
|
|
|
+ case IRQ_TYPE_LEVEL_LOW:
|
|
|
+ spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
|
|
|
+ clrsetbits_be32(reg, 3 << shift, 2 << shift);
|
|
|
+ spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case IRQ_TYPE_EDGE_RISING:
|
|
|
+ case IRQ_TYPE_LEVEL_HIGH:
|
|
|
+ spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
|
|
|
+ clrsetbits_be32(reg, 3 << shift, 1 << shift);
|
|
|
+ spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case IRQ_TYPE_EDGE_BOTH:
|
|
|
+ spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
|
|
|
+ clrbits32(reg, 3 << shift);
|
|
|
+ spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static struct irq_chip mpc8xxx_irq_chip = {
|
|
|
.name = "mpc8xxx-gpio",
|
|
|
.unmask = mpc8xxx_irq_unmask,
|
|
@@ -226,6 +273,11 @@ static struct irq_chip mpc8xxx_irq_chip = {
|
|
|
static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq,
|
|
|
irq_hw_number_t hw)
|
|
|
{
|
|
|
+ struct mpc8xxx_gpio_chip *mpc8xxx_gc = h->host_data;
|
|
|
+
|
|
|
+ if (mpc8xxx_gc->of_dev_id_data)
|
|
|
+ mpc8xxx_irq_chip.set_type = mpc8xxx_gc->of_dev_id_data;
|
|
|
+
|
|
|
set_irq_chip_data(virq, h->host_data);
|
|
|
set_irq_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq);
|
|
|
set_irq_type(virq, IRQ_TYPE_NONE);
|
|
@@ -253,11 +305,20 @@ static struct irq_host_ops mpc8xxx_gpio_irq_ops = {
|
|
|
.xlate = mpc8xxx_gpio_irq_xlate,
|
|
|
};
|
|
|
|
|
|
+static struct of_device_id mpc8xxx_gpio_ids[] __initdata = {
|
|
|
+ { .compatible = "fsl,mpc8349-gpio", },
|
|
|
+ { .compatible = "fsl,mpc8572-gpio", },
|
|
|
+ { .compatible = "fsl,mpc8610-gpio", },
|
|
|
+ { .compatible = "fsl,mpc5121-gpio", .data = mpc512x_irq_set_type, },
|
|
|
+ {}
|
|
|
+};
|
|
|
+
|
|
|
static void __init mpc8xxx_add_controller(struct device_node *np)
|
|
|
{
|
|
|
struct mpc8xxx_gpio_chip *mpc8xxx_gc;
|
|
|
struct of_mm_gpio_chip *mm_gc;
|
|
|
struct gpio_chip *gc;
|
|
|
+ const struct of_device_id *id;
|
|
|
unsigned hwirq;
|
|
|
int ret;
|
|
|
|
|
@@ -297,6 +358,10 @@ static void __init mpc8xxx_add_controller(struct device_node *np)
|
|
|
if (!mpc8xxx_gc->irq)
|
|
|
goto skip_irq;
|
|
|
|
|
|
+ id = of_match_node(mpc8xxx_gpio_ids, np);
|
|
|
+ if (id)
|
|
|
+ mpc8xxx_gc->of_dev_id_data = id->data;
|
|
|
+
|
|
|
mpc8xxx_gc->irq->host_data = mpc8xxx_gc;
|
|
|
|
|
|
/* ack and mask all irqs */
|
|
@@ -321,13 +386,7 @@ static int __init mpc8xxx_add_gpiochips(void)
|
|
|
{
|
|
|
struct device_node *np;
|
|
|
|
|
|
- for_each_compatible_node(np, NULL, "fsl,mpc8349-gpio")
|
|
|
- mpc8xxx_add_controller(np);
|
|
|
-
|
|
|
- for_each_compatible_node(np, NULL, "fsl,mpc8572-gpio")
|
|
|
- mpc8xxx_add_controller(np);
|
|
|
-
|
|
|
- for_each_compatible_node(np, NULL, "fsl,mpc8610-gpio")
|
|
|
+ for_each_matching_node(np, mpc8xxx_gpio_ids)
|
|
|
mpc8xxx_add_controller(np);
|
|
|
|
|
|
return 0;
|