aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/layerscape/patches-4.4/8042-drivers-gpio-Port-gpio-driver-to-support-layerscape-.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/layerscape/patches-4.4/8042-drivers-gpio-Port-gpio-driver-to-support-layerscape-.patch')
-rw-r--r--target/linux/layerscape/patches-4.4/8042-drivers-gpio-Port-gpio-driver-to-support-layerscape-.patch289
1 files changed, 289 insertions, 0 deletions
diff --git a/target/linux/layerscape/patches-4.4/8042-drivers-gpio-Port-gpio-driver-to-support-layerscape-.patch b/target/linux/layerscape/patches-4.4/8042-drivers-gpio-Port-gpio-driver-to-support-layerscape-.patch
new file mode 100644
index 0000000000..101f4505fe
--- /dev/null
+++ b/target/linux/layerscape/patches-4.4/8042-drivers-gpio-Port-gpio-driver-to-support-layerscape-.patch
@@ -0,0 +1,289 @@
+From c2d0a12b5cfa61e43494483f5d1ee466b4998830 Mon Sep 17 00:00:00 2001
+From: Liu Gang <Gang.Liu@nxp.com>
+Date: Thu, 14 Jan 2016 19:48:09 +0800
+Subject: [PATCH 42/70] drivers/gpio: Port gpio driver to support layerscape
+ platform
+
+Layerscape has the same ip block/controller as
+GPIO on powerpc platform(MPC8XXX).
+
+So use portable i/o accessors, as in_be32/out_be32
+accessors are Power architecture specific whereas
+ioread32/iowrite32 and ioread32be/iowrite32be are
+available in other architectures.
+
+Layerscape GPIO controller's registers may be big
+or little endian, so the code needs to get the
+endian property from DTB, then make additional
+functions to fit right register read/write
+operations.
+
+Currently the code can support ls2080a GPIO with
+little endian registers. And it can also work well
+on other layerscape platform with big endian GPIO
+registers.
+
+Signed-off-by: Liu Gang <Gang.Liu@nxp.com>
+---
+ drivers/gpio/Kconfig | 7 ++--
+ drivers/gpio/gpio-mpc8xxx.c | 87 +++++++++++++++++++++++++++++++------------
+ 2 files changed, 68 insertions(+), 26 deletions(-)
+
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -281,12 +281,13 @@ config GPIO_MPC5200
+ depends on PPC_MPC52xx
+
+ config GPIO_MPC8XXX
+- bool "MPC512x/MPC8xxx GPIO support"
++ bool "MPC512x/MPC8xxx/QorIQ GPIO support"
+ depends on PPC_MPC512x || PPC_MPC831x || PPC_MPC834x || PPC_MPC837x || \
+- FSL_SOC_BOOKE || PPC_86xx
++ FSL_SOC_BOOKE || PPC_86xx || ARCH_LAYERSCAPE || ARM || \
++ COMPILE_TEST
+ help
+ Say Y here if you're going to use hardware that connects to the
+- MPC512x/831x/834x/837x/8572/8610 GPIOs.
++ MPC512x/831x/834x/837x/8572/8610/QorIQ GPIOs.
+
+ config GPIO_MVEBU
+ def_bool y
+--- a/drivers/gpio/gpio-mpc8xxx.c
++++ b/drivers/gpio/gpio-mpc8xxx.c
+@@ -1,5 +1,5 @@
+ /*
+- * GPIOs on MPC512x/8349/8572/8610 and compatible
++ * GPIOs on MPC512x/8349/8572/8610/QorIQ and compatible
+ *
+ * Copyright (C) 2008 Peter Korsgaard <jacmet@sunsite.dk>
+ *
+@@ -19,6 +19,7 @@
+ #include <linux/gpio.h>
+ #include <linux/slab.h>
+ #include <linux/irq.h>
++#include <linux/irqdomain.h>
+
+ #define MPC8XXX_GPIO_PINS 32
+
+@@ -44,6 +45,27 @@ struct mpc8xxx_gpio_chip {
+ const void *of_dev_id_data;
+ };
+
++static bool gpio_little_endian;
++static inline u32 gpio_in32(void __iomem *addr)
++{
++ u32 val;
++
++ if (gpio_little_endian)
++ val = ioread32(addr);
++ else
++ val = ioread32be(addr);
++
++ return val;
++}
++
++static inline void gpio_out32(u32 val, void __iomem *addr)
++{
++ if (gpio_little_endian)
++ iowrite32(val, addr);
++ else
++ iowrite32be(val, addr);
++}
++
+ static inline u32 mpc8xxx_gpio2mask(unsigned int gpio)
+ {
+ return 1u << (MPC8XXX_GPIO_PINS - 1 - gpio);
+@@ -59,9 +81,17 @@ static void mpc8xxx_gpio_save_regs(struc
+ {
+ struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+
+- mpc8xxx_gc->data = in_be32(mm->regs + GPIO_DAT);
++ mpc8xxx_gc->data = gpio_in32(mm->regs + GPIO_DAT);
+ }
+
++/* Generic set and clear bits accessor ports */
++#define bgpio_setbits32(_addr, _v) \
++ gpio_out32(gpio_in32(_addr) | (_v), (_addr))
++#define bgpio_clrbits32(_addr, _v) \
++ gpio_out32(gpio_in32(_addr) & ~(_v), (_addr))
++#define bgpio_clrsetbits32(addr, clear, set) \
++ gpio_out32((gpio_in32(addr) & ~(clear)) | (set), (addr))
++
+ /* Workaround GPIO 1 errata on MPC8572/MPC8536. The status of GPIOs
+ * defined as output cannot be determined by reading GPDAT register,
+ * so we use shadow data register instead. The status of input pins
+@@ -74,9 +104,9 @@ static int mpc8572_gpio_get(struct gpio_
+ struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+ u32 out_mask, out_shadow;
+
+- out_mask = in_be32(mm->regs + GPIO_DIR);
++ out_mask = gpio_in32(mm->regs + GPIO_DIR);
+
+- val = in_be32(mm->regs + GPIO_DAT) & ~out_mask;
++ val = gpio_in32(mm->regs + GPIO_DAT) & ~out_mask;
+ out_shadow = mpc8xxx_gc->data & out_mask;
+
+ return (val | out_shadow) & mpc8xxx_gpio2mask(gpio);
+@@ -86,7 +116,7 @@ static int mpc8xxx_gpio_get(struct gpio_
+ {
+ struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
+
+- return in_be32(mm->regs + GPIO_DAT) & mpc8xxx_gpio2mask(gpio);
++ return gpio_in32(mm->regs + GPIO_DAT) & mpc8xxx_gpio2mask(gpio);
+ }
+
+ static void mpc8xxx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+@@ -102,7 +132,7 @@ static void mpc8xxx_gpio_set(struct gpio
+ else
+ mpc8xxx_gc->data &= ~mpc8xxx_gpio2mask(gpio);
+
+- out_be32(mm->regs + GPIO_DAT, mpc8xxx_gc->data);
++ gpio_out32(mpc8xxx_gc->data, mm->regs + GPIO_DAT);
+
+ raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+ }
+@@ -128,7 +158,7 @@ static void mpc8xxx_gpio_set_multiple(st
+ }
+ }
+
+- out_be32(mm->regs + GPIO_DAT, mpc8xxx_gc->data);
++ gpio_out32(mpc8xxx_gc->data, mm->regs + GPIO_DAT);
+
+ raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+ }
+@@ -141,7 +171,7 @@ static int mpc8xxx_gpio_dir_in(struct gp
+
+ raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+
+- clrbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio));
++ bgpio_clrbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio));
+
+ raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+
+@@ -158,7 +188,7 @@ static int mpc8xxx_gpio_dir_out(struct g
+
+ raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+
+- setbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio));
++ bgpio_setbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio));
+
+ raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+
+@@ -201,7 +231,8 @@ static void mpc8xxx_gpio_irq_cascade(str
+ struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
+ unsigned int mask;
+
+- mask = in_be32(mm->regs + GPIO_IER) & in_be32(mm->regs + GPIO_IMR);
++ mask = gpio_in32(mm->regs + GPIO_IER)
++ & gpio_in32(mm->regs + GPIO_IMR);
+ if (mask)
+ generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq,
+ 32 - ffs(mask)));
+@@ -217,7 +248,8 @@ static void mpc8xxx_irq_unmask(struct ir
+
+ raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+
+- setbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
++ bgpio_setbits32(mm->regs + GPIO_IMR,
++ mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
+
+ raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+ }
+@@ -230,7 +262,8 @@ static void mpc8xxx_irq_mask(struct irq_
+
+ raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+
+- clrbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
++ bgpio_clrbits32(mm->regs + GPIO_IMR,
++ mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
+
+ raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+ }
+@@ -240,7 +273,7 @@ static void mpc8xxx_irq_ack(struct irq_d
+ struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
+ struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
+
+- out_be32(mm->regs + GPIO_IER, mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
++ gpio_out32(mpc8xxx_gpio2mask(irqd_to_hwirq(d)), mm->regs + GPIO_IER);
+ }
+
+ static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)
+@@ -252,15 +285,15 @@ static int mpc8xxx_irq_set_type(struct i
+ switch (flow_type) {
+ case IRQ_TYPE_EDGE_FALLING:
+ raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+- setbits32(mm->regs + GPIO_ICR,
+- mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
++ bgpio_setbits32(mm->regs + GPIO_ICR,
++ mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
+ raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+ break;
+
+ case IRQ_TYPE_EDGE_BOTH:
+ raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+- clrbits32(mm->regs + GPIO_ICR,
+- mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
++ bgpio_clrbits32(mm->regs + GPIO_ICR,
++ mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
+ raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+ break;
+
+@@ -292,20 +325,20 @@ static int mpc512x_irq_set_type(struct i
+ case IRQ_TYPE_EDGE_FALLING:
+ case IRQ_TYPE_LEVEL_LOW:
+ raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+- clrsetbits_be32(reg, 3 << shift, 2 << shift);
++ bgpio_clrsetbits32(reg, 3 << shift, 2 << shift);
+ raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+ break;
+
+ case IRQ_TYPE_EDGE_RISING:
+ case IRQ_TYPE_LEVEL_HIGH:
+ raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+- clrsetbits_be32(reg, 3 << shift, 1 << shift);
++ bgpio_clrsetbits32(reg, 3 << shift, 1 << shift);
+ raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+ break;
+
+ case IRQ_TYPE_EDGE_BOTH:
+ raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+- clrbits32(reg, 3 << shift);
++ bgpio_clrbits32(reg, 3 << shift);
+ raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+ break;
+
+@@ -398,6 +431,14 @@ static int mpc8xxx_probe(struct platform
+ mm_gc = &mpc8xxx_gc->mm_gc;
+ gc = &mm_gc->gc;
+
++ if (of_property_read_bool(np, "little-endian")) {
++ gpio_little_endian = true;
++ dev_dbg(&pdev->dev, "GPIO REGISTERS are LITTLE endian\n");
++ } else {
++ gpio_little_endian = false;
++ dev_dbg(&pdev->dev, "GPIO REGISTERS are BIG endian\n");
++ }
++
+ mm_gc->save_regs = mpc8xxx_gpio_save_regs;
+ gc->ngpio = MPC8XXX_GPIO_PINS;
+ gc->direction_input = mpc8xxx_gpio_dir_in;
+@@ -422,7 +463,7 @@ static int mpc8xxx_probe(struct platform
+ return ret;
+
+ mpc8xxx_gc->irqn = irq_of_parse_and_map(np, 0);
+- if (mpc8xxx_gc->irqn == NO_IRQ)
++ if (mpc8xxx_gc->irqn == 0)
+ return 0;
+
+ mpc8xxx_gc->irq = irq_domain_add_linear(np, MPC8XXX_GPIO_PINS,
+@@ -435,8 +476,8 @@ static int mpc8xxx_probe(struct platform
+ mpc8xxx_gc->of_dev_id_data = id->data;
+
+ /* ack and mask all irqs */
+- out_be32(mm_gc->regs + GPIO_IER, 0xffffffff);
+- out_be32(mm_gc->regs + GPIO_IMR, 0);
++ gpio_out32(0xffffffff, mm_gc->regs + GPIO_IER);
++ gpio_out32(0, mm_gc->regs + GPIO_IMR);
+
+ irq_set_chained_handler_and_data(mpc8xxx_gc->irqn,
+ mpc8xxx_gpio_irq_cascade, mpc8xxx_gc);