|  | /* | 
|  | *  linux/arch/arm/mach-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/init.h> | 
|  | #include <linux/module.h> | 
|  |  | 
|  | #include <asm/gpio.h> | 
|  | #include <asm/hardware.h> | 
|  | #include <asm/io.h> | 
|  | #include <asm/arch/pxa-regs.h> | 
|  |  | 
|  | #include "generic.h" | 
|  |  | 
|  |  | 
|  | struct pxa_gpio_chip { | 
|  | struct gpio_chip chip; | 
|  | void __iomem     *regbase; | 
|  | }; | 
|  |  | 
|  | int pxa_last_gpio; | 
|  |  | 
|  | /* | 
|  | * Configure pins for GPIO or other functions | 
|  | */ | 
|  | int pxa_gpio_mode(int gpio_mode) | 
|  | { | 
|  | unsigned long flags; | 
|  | int gpio = gpio_mode & GPIO_MD_MASK_NR; | 
|  | int fn = (gpio_mode & GPIO_MD_MASK_FN) >> 8; | 
|  | int gafr; | 
|  |  | 
|  | if (gpio > pxa_last_gpio) | 
|  | return -EINVAL; | 
|  |  | 
|  | local_irq_save(flags); | 
|  | if (gpio_mode & GPIO_DFLT_LOW) | 
|  | GPCR(gpio) = GPIO_bit(gpio); | 
|  | else if (gpio_mode & GPIO_DFLT_HIGH) | 
|  | GPSR(gpio) = GPIO_bit(gpio); | 
|  | if (gpio_mode & GPIO_MD_MASK_DIR) | 
|  | GPDR(gpio) |= GPIO_bit(gpio); | 
|  | else | 
|  | GPDR(gpio) &= ~GPIO_bit(gpio); | 
|  | gafr = GAFR(gpio) & ~(0x3 << (((gpio) & 0xf)*2)); | 
|  | GAFR(gpio) = gafr |  (fn  << (((gpio) & 0xf)*2)); | 
|  | local_irq_restore(flags); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  | EXPORT_SYMBOL(pxa_gpio_mode); | 
|  |  | 
|  | static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | 
|  | { | 
|  | unsigned long        flags; | 
|  | u32                  mask = 1 << offset; | 
|  | u32                  value; | 
|  | struct pxa_gpio_chip *pxa; | 
|  | void __iomem         *gpdr; | 
|  |  | 
|  | pxa = container_of(chip, struct pxa_gpio_chip, chip); | 
|  | gpdr = pxa->regbase + GPDR_OFFSET; | 
|  | local_irq_save(flags); | 
|  | value = __raw_readl(gpdr); | 
|  | value &= ~mask; | 
|  | __raw_writel(value, gpdr); | 
|  | local_irq_restore(flags); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int pxa_gpio_direction_output(struct gpio_chip *chip, | 
|  | unsigned offset, int value) | 
|  | { | 
|  | unsigned long        flags; | 
|  | u32                  mask = 1 << offset; | 
|  | u32                  tmp; | 
|  | struct pxa_gpio_chip *pxa; | 
|  | void __iomem         *gpdr; | 
|  |  | 
|  | pxa = container_of(chip, struct pxa_gpio_chip, chip); | 
|  | __raw_writel(mask, | 
|  | pxa->regbase + (value ? GPSR_OFFSET : GPCR_OFFSET)); | 
|  | gpdr = pxa->regbase + GPDR_OFFSET; | 
|  | local_irq_save(flags); | 
|  | tmp = __raw_readl(gpdr); | 
|  | tmp |= mask; | 
|  | __raw_writel(tmp, gpdr); | 
|  | local_irq_restore(flags); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Return GPIO level | 
|  | */ | 
|  | static int pxa_gpio_get(struct gpio_chip *chip, unsigned offset) | 
|  | { | 
|  | u32                  mask = 1 << offset; | 
|  | struct pxa_gpio_chip *pxa; | 
|  |  | 
|  | pxa = container_of(chip, struct pxa_gpio_chip, chip); | 
|  | return __raw_readl(pxa->regbase + GPLR_OFFSET) & mask; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Set output GPIO level | 
|  | */ | 
|  | static void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | 
|  | { | 
|  | u32                  mask = 1 << offset; | 
|  | struct pxa_gpio_chip *pxa; | 
|  |  | 
|  | pxa = container_of(chip, struct pxa_gpio_chip, chip); | 
|  |  | 
|  | if (value) | 
|  | __raw_writel(mask, pxa->regbase + GPSR_OFFSET); | 
|  | else | 
|  | __raw_writel(mask, pxa->regbase + GPCR_OFFSET); | 
|  | } | 
|  |  | 
|  | static struct pxa_gpio_chip pxa_gpio_chip[] = { | 
|  | [0] = { | 
|  | .regbase = GPIO0_BASE, | 
|  | .chip = { | 
|  | .label            = "gpio-0", | 
|  | .direction_input  = pxa_gpio_direction_input, | 
|  | .direction_output = pxa_gpio_direction_output, | 
|  | .get              = pxa_gpio_get, | 
|  | .set              = pxa_gpio_set, | 
|  | .base             = 0, | 
|  | .ngpio            = 32, | 
|  | }, | 
|  | }, | 
|  | [1] = { | 
|  | .regbase = GPIO1_BASE, | 
|  | .chip = { | 
|  | .label            = "gpio-1", | 
|  | .direction_input  = pxa_gpio_direction_input, | 
|  | .direction_output = pxa_gpio_direction_output, | 
|  | .get              = pxa_gpio_get, | 
|  | .set              = pxa_gpio_set, | 
|  | .base             = 32, | 
|  | .ngpio            = 32, | 
|  | }, | 
|  | }, | 
|  | [2] = { | 
|  | .regbase = GPIO2_BASE, | 
|  | .chip = { | 
|  | .label            = "gpio-2", | 
|  | .direction_input  = pxa_gpio_direction_input, | 
|  | .direction_output = pxa_gpio_direction_output, | 
|  | .get              = pxa_gpio_get, | 
|  | .set              = pxa_gpio_set, | 
|  | .base             = 64, | 
|  | .ngpio            = 32, /* 21 for PXA25x */ | 
|  | }, | 
|  | }, | 
|  | #if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) | 
|  | [3] = { | 
|  | .regbase = GPIO3_BASE, | 
|  | .chip = { | 
|  | .label            = "gpio-3", | 
|  | .direction_input  = pxa_gpio_direction_input, | 
|  | .direction_output = pxa_gpio_direction_output, | 
|  | .get              = pxa_gpio_get, | 
|  | .set              = pxa_gpio_set, | 
|  | .base             = 96, | 
|  | .ngpio            = 32, | 
|  | }, | 
|  | }, | 
|  | #endif | 
|  | }; | 
|  |  | 
|  | void __init pxa_init_gpio(int gpio_nr) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | /* add a GPIO chip for each register bank. | 
|  | * the last PXA25x register only contains 21 GPIOs | 
|  | */ | 
|  | for (i = 0; i < gpio_nr; i += 32) { | 
|  | if (i+32 > gpio_nr) | 
|  | pxa_gpio_chip[i/32].chip.ngpio = gpio_nr - i; | 
|  | gpiochip_add(&pxa_gpio_chip[i/32].chip); | 
|  | } | 
|  | } |