diff options
Diffstat (limited to 'drivers/gpio/gpio-mpc8xxx.c')
-rw-r--r-- | drivers/gpio/gpio-mpc8xxx.c | 70 |
1 files changed, 58 insertions, 12 deletions
diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index c8673a5d9412..604dfec353a1 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -22,6 +22,7 @@ #include <linux/irq.h> #include <linux/gpio/driver.h> #include <linux/bitops.h> +#include <linux/interrupt.h> #define MPC8XXX_GPIO_PINS 32 @@ -32,6 +33,7 @@ #define GPIO_IMR 0x10 #define GPIO_ICR 0x14 #define GPIO_ICR2 0x18 +#define GPIO_IBE 0x18 struct mpc8xxx_gpio_chip { struct gpio_chip gc; @@ -45,6 +47,27 @@ struct mpc8xxx_gpio_chip { unsigned int irqn; }; +/* The GPIO Input Buffer Enable register(GPIO_IBE) is used to + * control the input enable of each individual GPIO port. + * When an individual GPIO port’s direction is set to + * input (GPIO_GPDIR[DRn=0]), the associated input enable must be + * set (GPIOxGPIE[IEn]=1) to propagate the port value to the GPIO + * Data Register. + */ +static int ls1028a_gpio_dir_in_init(struct gpio_chip *gc) +{ + unsigned long flags; + struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc); + + spin_lock_irqsave(&gc->bgpio_lock, flags); + + gc->write_reg(mpc8xxx_gc->regs + GPIO_IBE, 0xffffffff); + + spin_unlock_irqrestore(&gc->bgpio_lock, flags); + + return 0; +} + /* * This hardware has a big endian bit assignment such that GPIO line 0 is * connected to bit 31, line 1 to bit 30 ... line 31 to bit 0. @@ -105,20 +128,19 @@ static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset) return -ENXIO; } -static void mpc8xxx_gpio_irq_cascade(struct irq_desc *desc) +static irqreturn_t mpc8xxx_gpio_irq_cascade(int irq, void *data) { - struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_desc_get_handler_data(desc); - struct irq_chip *chip = irq_desc_get_chip(desc); + struct mpc8xxx_gpio_chip *mpc8xxx_gc = data; struct gpio_chip *gc = &mpc8xxx_gc->gc; - unsigned int mask; + unsigned long mask; + int i; mask = gc->read_reg(mpc8xxx_gc->regs + GPIO_IER) & gc->read_reg(mpc8xxx_gc->regs + GPIO_IMR); - if (mask) - generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq, - 32 - ffs(mask))); - if (chip->irq_eoi) - chip->irq_eoi(&desc->irq_data); + for_each_set_bit(i, &mask, 32) + generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq, 31 - i)); + + return IRQ_HANDLED; } static void mpc8xxx_irq_unmask(struct irq_data *d) @@ -261,6 +283,7 @@ static const struct irq_domain_ops mpc8xxx_gpio_irq_ops = { }; struct mpc8xxx_gpio_devtype { + int (*gpio_dir_in_init)(struct gpio_chip *chip); int (*gpio_dir_out)(struct gpio_chip *, unsigned int, int); int (*gpio_get)(struct gpio_chip *, unsigned int); int (*irq_set_type)(struct irq_data *, unsigned int); @@ -271,6 +294,11 @@ static const struct mpc8xxx_gpio_devtype mpc512x_gpio_devtype = { .irq_set_type = mpc512x_irq_set_type, }; +static const struct mpc8xxx_gpio_devtype ls1028a_gpio_devtype = { + .gpio_dir_in_init = ls1028a_gpio_dir_in_init, + .irq_set_type = mpc8xxx_irq_set_type, +}; + static const struct mpc8xxx_gpio_devtype mpc5125_gpio_devtype = { .gpio_dir_out = mpc5125_gpio_dir_out, .irq_set_type = mpc512x_irq_set_type, @@ -291,6 +319,8 @@ static const struct of_device_id mpc8xxx_gpio_ids[] = { { .compatible = "fsl,mpc5121-gpio", .data = &mpc512x_gpio_devtype, }, { .compatible = "fsl,mpc5125-gpio", .data = &mpc5125_gpio_devtype, }, { .compatible = "fsl,pq3-gpio", }, + { .compatible = "fsl,ls1028a-gpio", .data = &ls1028a_gpio_devtype, }, + { .compatible = "fsl,ls1088a-gpio", .data = &ls1028a_gpio_devtype, }, { .compatible = "fsl,qoriq-gpio", }, {} }; @@ -317,6 +347,7 @@ static int mpc8xxx_probe(struct platform_device *pdev) return -ENOMEM; gc = &mpc8xxx_gc->gc; + gc->parent = &pdev->dev; if (of_property_read_bool(np, "little-endian")) { ret = bgpio_init(gc, &pdev->dev, 4, @@ -348,7 +379,8 @@ static int mpc8xxx_probe(struct platform_device *pdev) * It's assumed that only a single type of gpio controller is available * on the current machine, so overwriting global data is fine. */ - mpc8xxx_irq_chip.irq_set_type = devtype->irq_set_type; + if (devtype->irq_set_type) + mpc8xxx_irq_chip.irq_set_type = devtype->irq_set_type; if (devtype->gpio_dir_out) gc->direction_output = devtype->gpio_dir_out; @@ -357,6 +389,9 @@ static int mpc8xxx_probe(struct platform_device *pdev) gc->to_irq = mpc8xxx_gpio_to_irq; + if (of_device_is_compatible(np, "fsl,qoriq-gpio")) + gc->write_reg(mpc8xxx_gc->regs + GPIO_IBE, 0xffffffff); + ret = gpiochip_add_data(gc, mpc8xxx_gc); if (ret) { pr_err("%pOF: GPIO chip registration failed with status %d\n", @@ -376,9 +411,20 @@ static int mpc8xxx_probe(struct platform_device *pdev) /* ack and mask all irqs */ gc->write_reg(mpc8xxx_gc->regs + GPIO_IER, 0xffffffff); gc->write_reg(mpc8xxx_gc->regs + GPIO_IMR, 0); + /* enable input buffer */ + if (devtype->gpio_dir_in_init) + devtype->gpio_dir_in_init(gc); + + ret = devm_request_irq(&pdev->dev, mpc8xxx_gc->irqn, + mpc8xxx_gpio_irq_cascade, + IRQF_NO_THREAD | IRQF_SHARED, "gpio-cascade", + mpc8xxx_gc); + if (ret) { + dev_err(&pdev->dev, "%s: failed to devm_request_irq(%d), ret = %d\n", + np->full_name, mpc8xxx_gc->irqn, ret); + goto err; + } - irq_set_chained_handler_and_data(mpc8xxx_gc->irqn, - mpc8xxx_gpio_irq_cascade, mpc8xxx_gc); return 0; err: iounmap(mpc8xxx_gc->regs); |