--- /dev/null
-#define GPIO_REG(x) (*(volatile u32 *)(GPIO_REGS_VIRT + (x)))
+ /*
+ * Written by Philipp Zabel <philipp.zabel@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+ #ifndef __MACH_PXA_GPIO_PXA_H
+ #define __MACH_PXA_GPIO_PXA_H
+
+ #include <mach/irqs.h>
+ #include <mach/hardware.h>
+
+ #define GPIO_REGS_VIRT io_p2v(0x40E00000)
+
+ #define BANK_OFF(n) (((n) < 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2))
++#define GPIO_REG(x) (GPIO_REGS_VIRT + (x))
+
+ /* GPIO Pin Level Registers */
+ #define GPLR0 GPIO_REG(BANK_OFF(0) + 0x00)
+ #define GPLR1 GPIO_REG(BANK_OFF(1) + 0x00)
+ #define GPLR2 GPIO_REG(BANK_OFF(2) + 0x00)
+ #define GPLR3 GPIO_REG(BANK_OFF(3) + 0x00)
+
+ /* GPIO Pin Direction Registers */
+ #define GPDR0 GPIO_REG(BANK_OFF(0) + 0x0c)
+ #define GPDR1 GPIO_REG(BANK_OFF(1) + 0x0c)
+ #define GPDR2 GPIO_REG(BANK_OFF(2) + 0x0c)
+ #define GPDR3 GPIO_REG(BANK_OFF(3) + 0x0c)
+
+ /* GPIO Pin Output Set Registers */
+ #define GPSR0 GPIO_REG(BANK_OFF(0) + 0x18)
+ #define GPSR1 GPIO_REG(BANK_OFF(1) + 0x18)
+ #define GPSR2 GPIO_REG(BANK_OFF(2) + 0x18)
+ #define GPSR3 GPIO_REG(BANK_OFF(3) + 0x18)
+
+ /* GPIO Pin Output Clear Registers */
+ #define GPCR0 GPIO_REG(BANK_OFF(0) + 0x24)
+ #define GPCR1 GPIO_REG(BANK_OFF(1) + 0x24)
+ #define GPCR2 GPIO_REG(BANK_OFF(2) + 0x24)
+ #define GPCR3 GPIO_REG(BANK_OFF(3) + 0x24)
+
+ /* GPIO Rising Edge Detect Registers */
+ #define GRER0 GPIO_REG(BANK_OFF(0) + 0x30)
+ #define GRER1 GPIO_REG(BANK_OFF(1) + 0x30)
+ #define GRER2 GPIO_REG(BANK_OFF(2) + 0x30)
+ #define GRER3 GPIO_REG(BANK_OFF(3) + 0x30)
+
+ /* GPIO Falling Edge Detect Registers */
+ #define GFER0 GPIO_REG(BANK_OFF(0) + 0x3c)
+ #define GFER1 GPIO_REG(BANK_OFF(1) + 0x3c)
+ #define GFER2 GPIO_REG(BANK_OFF(2) + 0x3c)
+ #define GFER3 GPIO_REG(BANK_OFF(3) + 0x3c)
+
+ /* GPIO Edge Detect Status Registers */
+ #define GEDR0 GPIO_REG(BANK_OFF(0) + 0x48)
+ #define GEDR1 GPIO_REG(BANK_OFF(1) + 0x48)
+ #define GEDR2 GPIO_REG(BANK_OFF(2) + 0x48)
+ #define GEDR3 GPIO_REG(BANK_OFF(3) + 0x48)
+
+ /* GPIO Alternate Function Select Registers */
+ #define GAFR0_L GPIO_REG(0x0054)
+ #define GAFR0_U GPIO_REG(0x0058)
+ #define GAFR1_L GPIO_REG(0x005C)
+ #define GAFR1_U GPIO_REG(0x0060)
+ #define GAFR2_L GPIO_REG(0x0064)
+ #define GAFR2_U GPIO_REG(0x0068)
+ #define GAFR3_L GPIO_REG(0x006C)
+ #define GAFR3_U GPIO_REG(0x0070)
+
+ /* More handy macros. The argument is a literal GPIO number. */
+
+ #define GPIO_bit(x) (1 << ((x) & 0x1f))
+
+ #define GPLR(x) GPIO_REG(BANK_OFF((x) >> 5) + 0x00)
+ #define GPDR(x) GPIO_REG(BANK_OFF((x) >> 5) + 0x0c)
+ #define GPSR(x) GPIO_REG(BANK_OFF((x) >> 5) + 0x18)
+ #define GPCR(x) GPIO_REG(BANK_OFF((x) >> 5) + 0x24)
+ #define GRER(x) GPIO_REG(BANK_OFF((x) >> 5) + 0x30)
+ #define GFER(x) GPIO_REG(BANK_OFF((x) >> 5) + 0x3c)
+ #define GEDR(x) GPIO_REG(BANK_OFF((x) >> 5) + 0x48)
+ #define GAFR(x) GPIO_REG(0x54 + (((x) & 0x70) >> 2))
+
+
+ #define NR_BUILTIN_GPIO PXA_GPIO_IRQ_NUM
+
+ #define gpio_to_bank(gpio) ((gpio) >> 5)
+
+ #ifdef CONFIG_CPU_PXA26x
+ /* GPIO86/87/88/89 on PXA26x have their direction bits in GPDR2 inverted,
+ * as well as their Alternate Function value being '1' for GPIO in GAFRx.
+ */
+ static inline int __gpio_is_inverted(unsigned gpio)
+ {
+ return cpu_is_pxa25x() && gpio > 85;
+ }
+ #else
+ static inline int __gpio_is_inverted(unsigned gpio) { return 0; }
+ #endif
+
+ /*
+ * On PXA25x and PXA27x, GAFRx and GPDRx together decide the alternate
+ * function of a GPIO, and GPDRx cannot be altered once configured. It
+ * is attributed as "occupied" here (I know this terminology isn't
+ * accurate, you are welcome to propose a better one :-)
+ */
+ static inline int __gpio_is_occupied(unsigned gpio)
+ {
+ if (cpu_is_pxa27x() || cpu_is_pxa25x()) {
+ int af = (GAFR(gpio) >> ((gpio & 0xf) * 2)) & 0x3;
+ int dir = GPDR(gpio) & GPIO_bit(gpio);
+
+ if (__gpio_is_inverted(gpio))
+ return af != 1 || dir == 0;
+ else
+ return af != 0 || dir != 0;
+ } else
+ return GPDR(gpio) & GPIO_bit(gpio);
+ }
+
+ #include <plat/gpio-pxa.h>
+ #endif /* __MACH_PXA_GPIO_PXA_H */
--- /dev/null
- chips[i].regbase = (void __iomem *)GPIO_BANK(i);
+ /*
+ * linux/arch/arm/plat-pxa/gpio.c
+ *
+ * Generic PXA GPIO handling
+ *
+ * Author: Nicolas Pitre
+ * Created: Jun 15, 2001
+ * Copyright: MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+ #include <linux/gpio.h>
+ #include <linux/init.h>
+ #include <linux/irq.h>
+ #include <linux/io.h>
+ #include <linux/syscore_ops.h>
+ #include <linux/slab.h>
+
+ #include <mach/gpio-pxa.h>
+
+ int pxa_last_gpio;
+
+ struct pxa_gpio_chip {
+ struct gpio_chip chip;
+ void __iomem *regbase;
+ char label[10];
+
+ unsigned long irq_mask;
+ unsigned long irq_edge_rise;
+ unsigned long irq_edge_fall;
+
+ #ifdef CONFIG_PM
+ unsigned long saved_gplr;
+ unsigned long saved_gpdr;
+ unsigned long saved_grer;
+ unsigned long saved_gfer;
+ #endif
+ };
+
+ static DEFINE_SPINLOCK(gpio_lock);
+ static struct pxa_gpio_chip *pxa_gpio_chips;
+
+ #define for_each_gpio_chip(i, c) \
+ for (i = 0, c = &pxa_gpio_chips[0]; i <= pxa_last_gpio; i += 32, c++)
+
+ static inline void __iomem *gpio_chip_base(struct gpio_chip *c)
+ {
+ return container_of(c, struct pxa_gpio_chip, chip)->regbase;
+ }
+
+ static inline struct pxa_gpio_chip *gpio_to_pxachip(unsigned gpio)
+ {
+ return &pxa_gpio_chips[gpio_to_bank(gpio)];
+ }
+
+ static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+ {
+ void __iomem *base = gpio_chip_base(chip);
+ uint32_t value, mask = 1 << offset;
+ unsigned long flags;
+
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ value = __raw_readl(base + GPDR_OFFSET);
+ if (__gpio_is_inverted(chip->base + offset))
+ value |= mask;
+ else
+ value &= ~mask;
+ __raw_writel(value, base + GPDR_OFFSET);
+
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ return 0;
+ }
+
+ static int pxa_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+ {
+ void __iomem *base = gpio_chip_base(chip);
+ uint32_t tmp, mask = 1 << offset;
+ unsigned long flags;
+
+ __raw_writel(mask, base + (value ? GPSR_OFFSET : GPCR_OFFSET));
+
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ tmp = __raw_readl(base + GPDR_OFFSET);
+ if (__gpio_is_inverted(chip->base + offset))
+ tmp &= ~mask;
+ else
+ tmp |= mask;
+ __raw_writel(tmp, base + GPDR_OFFSET);
+
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ return 0;
+ }
+
+ static int pxa_gpio_get(struct gpio_chip *chip, unsigned offset)
+ {
+ return __raw_readl(gpio_chip_base(chip) + GPLR_OFFSET) & (1 << offset);
+ }
+
+ static void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+ {
+ __raw_writel(1 << offset, gpio_chip_base(chip) +
+ (value ? GPSR_OFFSET : GPCR_OFFSET));
+ }
+
+ static int __init pxa_init_gpio_chip(int gpio_end)
+ {
+ int i, gpio, nbanks = gpio_to_bank(gpio_end) + 1;
+ struct pxa_gpio_chip *chips;
+
+ chips = kzalloc(nbanks * sizeof(struct pxa_gpio_chip), GFP_KERNEL);
+ if (chips == NULL) {
+ pr_err("%s: failed to allocate GPIO chips\n", __func__);
+ return -ENOMEM;
+ }
+
+ for (i = 0, gpio = 0; i < nbanks; i++, gpio += 32) {
+ struct gpio_chip *c = &chips[i].chip;
+
+ sprintf(chips[i].label, "gpio-%d", i);
++ chips[i].regbase = GPIO_BANK(i);
+
+ c->base = gpio;
+ c->label = chips[i].label;
+
+ c->direction_input = pxa_gpio_direction_input;
+ c->direction_output = pxa_gpio_direction_output;
+ c->get = pxa_gpio_get;
+ c->set = pxa_gpio_set;
+
+ /* number of GPIOs on last bank may be less than 32 */
+ c->ngpio = (gpio + 31 > gpio_end) ? (gpio_end - gpio + 1) : 32;
+ gpiochip_add(c);
+ }
+ pxa_gpio_chips = chips;
+ return 0;
+ }
+
+ /* Update only those GRERx and GFERx edge detection register bits if those
+ * bits are set in c->irq_mask
+ */
+ static inline void update_edge_detect(struct pxa_gpio_chip *c)
+ {
+ uint32_t grer, gfer;
+
+ grer = __raw_readl(c->regbase + GRER_OFFSET) & ~c->irq_mask;
+ gfer = __raw_readl(c->regbase + GFER_OFFSET) & ~c->irq_mask;
+ grer |= c->irq_edge_rise & c->irq_mask;
+ gfer |= c->irq_edge_fall & c->irq_mask;
+ __raw_writel(grer, c->regbase + GRER_OFFSET);
+ __raw_writel(gfer, c->regbase + GFER_OFFSET);
+ }
+
+ static int pxa_gpio_irq_type(struct irq_data *d, unsigned int type)
+ {
+ struct pxa_gpio_chip *c;
+ int gpio = irq_to_gpio(d->irq);
+ unsigned long gpdr, mask = GPIO_bit(gpio);
+
+ c = gpio_to_pxachip(gpio);
+
+ if (type == IRQ_TYPE_PROBE) {
+ /* Don't mess with enabled GPIOs using preconfigured edges or
+ * GPIOs set to alternate function or to output during probe
+ */
+ if ((c->irq_edge_rise | c->irq_edge_fall) & GPIO_bit(gpio))
+ return 0;
+
+ if (__gpio_is_occupied(gpio))
+ return 0;
+
+ type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
+ }
+
+ gpdr = __raw_readl(c->regbase + GPDR_OFFSET);
+
+ if (__gpio_is_inverted(gpio))
+ __raw_writel(gpdr | mask, c->regbase + GPDR_OFFSET);
+ else
+ __raw_writel(gpdr & ~mask, c->regbase + GPDR_OFFSET);
+
+ if (type & IRQ_TYPE_EDGE_RISING)
+ c->irq_edge_rise |= mask;
+ else
+ c->irq_edge_rise &= ~mask;
+
+ if (type & IRQ_TYPE_EDGE_FALLING)
+ c->irq_edge_fall |= mask;
+ else
+ c->irq_edge_fall &= ~mask;
+
+ update_edge_detect(c);
+
+ pr_debug("%s: IRQ%d (GPIO%d) - edge%s%s\n", __func__, d->irq, gpio,
+ ((type & IRQ_TYPE_EDGE_RISING) ? " rising" : ""),
+ ((type & IRQ_TYPE_EDGE_FALLING) ? " falling" : ""));
+ return 0;
+ }
+
+ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc)
+ {
+ struct pxa_gpio_chip *c;
+ int loop, gpio, gpio_base, n;
+ unsigned long gedr;
+
+ do {
+ loop = 0;
+ for_each_gpio_chip(gpio, c) {
+ gpio_base = c->chip.base;
+
+ gedr = __raw_readl(c->regbase + GEDR_OFFSET);
+ gedr = gedr & c->irq_mask;
+ __raw_writel(gedr, c->regbase + GEDR_OFFSET);
+
+ n = find_first_bit(&gedr, BITS_PER_LONG);
+ while (n < BITS_PER_LONG) {
+ loop = 1;
+
+ generic_handle_irq(gpio_to_irq(gpio_base + n));
+ n = find_next_bit(&gedr, BITS_PER_LONG, n + 1);
+ }
+ }
+ } while (loop);
+ }
+
+ static void pxa_ack_muxed_gpio(struct irq_data *d)
+ {
+ int gpio = irq_to_gpio(d->irq);
+ struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
+
+ __raw_writel(GPIO_bit(gpio), c->regbase + GEDR_OFFSET);
+ }
+
+ static void pxa_mask_muxed_gpio(struct irq_data *d)
+ {
+ int gpio = irq_to_gpio(d->irq);
+ struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
+ uint32_t grer, gfer;
+
+ c->irq_mask &= ~GPIO_bit(gpio);
+
+ grer = __raw_readl(c->regbase + GRER_OFFSET) & ~GPIO_bit(gpio);
+ gfer = __raw_readl(c->regbase + GFER_OFFSET) & ~GPIO_bit(gpio);
+ __raw_writel(grer, c->regbase + GRER_OFFSET);
+ __raw_writel(gfer, c->regbase + GFER_OFFSET);
+ }
+
+ static void pxa_unmask_muxed_gpio(struct irq_data *d)
+ {
+ int gpio = irq_to_gpio(d->irq);
+ struct pxa_gpio_chip *c = gpio_to_pxachip(gpio);
+
+ c->irq_mask |= GPIO_bit(gpio);
+ update_edge_detect(c);
+ }
+
+ static struct irq_chip pxa_muxed_gpio_chip = {
+ .name = "GPIO",
+ .irq_ack = pxa_ack_muxed_gpio,
+ .irq_mask = pxa_mask_muxed_gpio,
+ .irq_unmask = pxa_unmask_muxed_gpio,
+ .irq_set_type = pxa_gpio_irq_type,
+ };
+
+ void __init pxa_init_gpio(int mux_irq, int start, int end, set_wake_t fn)
+ {
+ struct pxa_gpio_chip *c;
+ int gpio, irq;
+
+ pxa_last_gpio = end;
+
+ /* Initialize GPIO chips */
+ pxa_init_gpio_chip(end);
+
+ /* clear all GPIO edge detects */
+ for_each_gpio_chip(gpio, c) {
+ __raw_writel(0, c->regbase + GFER_OFFSET);
+ __raw_writel(0, c->regbase + GRER_OFFSET);
+ __raw_writel(~0,c->regbase + GEDR_OFFSET);
+ }
+
+ for (irq = gpio_to_irq(start); irq <= gpio_to_irq(end); irq++) {
+ irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
+ handle_edge_irq);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ }
+
+ /* Install handler for GPIO>=2 edge detect interrupts */
+ irq_set_chained_handler(mux_irq, pxa_gpio_demux_handler);
+ pxa_muxed_gpio_chip.irq_set_wake = fn;
+ }
+
+ #ifdef CONFIG_PM
+ static int pxa_gpio_suspend(void)
+ {
+ struct pxa_gpio_chip *c;
+ int gpio;
+
+ for_each_gpio_chip(gpio, c) {
+ c->saved_gplr = __raw_readl(c->regbase + GPLR_OFFSET);
+ c->saved_gpdr = __raw_readl(c->regbase + GPDR_OFFSET);
+ c->saved_grer = __raw_readl(c->regbase + GRER_OFFSET);
+ c->saved_gfer = __raw_readl(c->regbase + GFER_OFFSET);
+
+ /* Clear GPIO transition detect bits */
+ __raw_writel(0xffffffff, c->regbase + GEDR_OFFSET);
+ }
+ return 0;
+ }
+
+ static void pxa_gpio_resume(void)
+ {
+ struct pxa_gpio_chip *c;
+ int gpio;
+
+ for_each_gpio_chip(gpio, c) {
+ /* restore level with set/clear */
+ __raw_writel( c->saved_gplr, c->regbase + GPSR_OFFSET);
+ __raw_writel(~c->saved_gplr, c->regbase + GPCR_OFFSET);
+
+ __raw_writel(c->saved_grer, c->regbase + GRER_OFFSET);
+ __raw_writel(c->saved_gfer, c->regbase + GFER_OFFSET);
+ __raw_writel(c->saved_gpdr, c->regbase + GPDR_OFFSET);
+ }
+ }
+ #else
+ #define pxa_gpio_suspend NULL
+ #define pxa_gpio_resume NULL
+ #endif
+
+ struct syscore_ops pxa_gpio_syscore_ops = {
+ .suspend = pxa_gpio_suspend,
+ .resume = pxa_gpio_resume,
+ };