[PATCH v4] powerpc/mpc8xxx_gpio.c: extend the driver to support mpc512x gpios

Grant Likely grant.likely at secretlab.ca
Mon Aug 9 16:20:54 EST 2010


On Sun, Aug 8, 2010 at 11:58 PM, Anatolij Gustschin <agust at denx.de> wrote:
> The GPIO controller of MPC512x is slightly different from
> 8xxx GPIO controllers. The register interface is the same
> except the external interrupt control register. The MPC512x
> GPIO controller differentiates between four interrupt event
> types and therefore provides two interrupt control registers,
> GPICR1 and GPICR2. GPIO[0:15] interrupt event types are
> configured in GPICR1 register, GPIO[16:31] - in GPICR2 register.
>
> This patch adds MPC512x speciffic set_type() callback and
> updates config file and comments. Additionally the gpio chip
> registration function is changed to use for_each_matching_node()
> preventing multiple registration if a node claimes compatibility
> with another gpio controller type.
>
> Signed-off-by: Anatolij Gustschin <agust at denx.de>
> ---
> v4:
>  - undo function merging as it was wrong
>  - fix commit message

Looks good, thanks.  I'll pick it up after the merge window closes in
prep for 2.6.27

g.

>
> v3:
>  - merge mpc8xxx_add_controller() into mpc8xxx_add_gpiochips()
>  - do not use of_node's data field for set type hook,
>    use added void data pointer in the gpio chip struct
>    instead.
>
> v2:
>  - add patch description
>  - use match table data to set irq set_type hook as
>   recommended
>  - refactor to use for_each_matching_node() in
>   mpc8xxx_add_gpiochips() as suggested by Grant
>
>  arch/powerpc/platforms/Kconfig     |    7 ++-
>  arch/powerpc/sysdev/mpc8xxx_gpio.c |   75 ++++++++++++++++++++++++++++++++----
>  2 files changed, 71 insertions(+), 11 deletions(-)
>
> diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
> index d1663db..471115a 100644
> --- a/arch/powerpc/platforms/Kconfig
> +++ b/arch/powerpc/platforms/Kconfig
> @@ -304,13 +304,14 @@ config OF_RTC
>  source "arch/powerpc/sysdev/bestcomm/Kconfig"
>
>  config MPC8xxx_GPIO
> -       bool "MPC8xxx GPIO support"
> -       depends on PPC_MPC831x || PPC_MPC834x || PPC_MPC837x || FSL_SOC_BOOKE || PPC_86xx
> +       bool "MPC512x/MPC8xxx GPIO support"
> +       depends on PPC_MPC512x || PPC_MPC831x || PPC_MPC834x || PPC_MPC837x || \
> +                  FSL_SOC_BOOKE || PPC_86xx
>        select GENERIC_GPIO
>        select ARCH_REQUIRE_GPIOLIB
>        help
>          Say Y here if you're going to use hardware that connects to the
> -         MPC831x/834x/837x/8572/8610 GPIOs.
> +         MPC512x/831x/834x/837x/8572/8610 GPIOs.
>
>  config SIMPLE_GPIO
>        bool "Support for simple, memory-mapped GPIO controllers"
> diff --git a/arch/powerpc/sysdev/mpc8xxx_gpio.c b/arch/powerpc/sysdev/mpc8xxx_gpio.c
> index 2b69084..3649939 100644
> --- a/arch/powerpc/sysdev/mpc8xxx_gpio.c
> +++ b/arch/powerpc/sysdev/mpc8xxx_gpio.c
> @@ -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 at 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;
> --
> 1.7.0.4
>
>



-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.


More information about the Linuxppc-dev mailing list