/* * 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 #include #include #include #include #include #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); } }