Merge v2.6.37-rc8 into powerpc/next
[pandora-kernel.git] / arch / powerpc / sysdev / mpc8xxx_gpio.c
index c0ea05e..c48cd81 100644 (file)
@@ -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>
  *
  *
  * 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_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;
 
 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;
         */
        u32 data;
        struct irq_host *irq;
+       void *of_dev_id_data;
 };
 
 static inline u32 mpc8xxx_gpio2mask(unsigned int gpio)
 };
 
 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;
 }
 
        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,
 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)
 {
 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);
        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,
 };
 
        .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;
 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;
 
        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;
 
        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 */
        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;
 
 {
        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);
 
        for_each_compatible_node(np, NULL, "fsl,qoriq-gpio")
                mpc8xxx_add_controller(np);
 
        for_each_compatible_node(np, NULL, "fsl,qoriq-gpio")