Merge branch 'next/fixes' into next/cleanup
Conflicts: arch/arm/mach-mxs/include/mach/gpio.h arch/arm/plat-mxc/include/mach/gpio.h drivers/video/omap/lcd_apollon.c drivers/video/omap/lcd_ldp.c drivers/video/omap/lcd_overo.c
This commit is contained in:
@@ -178,6 +178,15 @@ config GPIO_SCH
|
||||
The Intel Tunnel Creek processor has 5 GPIOs powered by the
|
||||
core power rail and 9 from suspend power supply.
|
||||
|
||||
config GPIO_U300
|
||||
bool "ST-Ericsson U300 COH 901 335/571 GPIO"
|
||||
depends on GPIOLIB && ARCH_U300
|
||||
help
|
||||
Say yes here to support GPIO interface on ST-Ericsson U300.
|
||||
The names of the two IP block variants supported are
|
||||
COH 901 335 and COH 901 571/3. They contain 3, 5 or 7
|
||||
ports of 8 GPIO pins each.
|
||||
|
||||
config GPIO_VX855
|
||||
tristate "VIA VX855/VX875 GPIO"
|
||||
depends on MFD_SUPPORT && PCI
|
||||
|
@@ -14,11 +14,14 @@ obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o
|
||||
obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
|
||||
obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
|
||||
obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o
|
||||
obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o
|
||||
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
|
||||
obj-$(CONFIG_GPIO_EXYNOS4) += gpio-exynos4.o
|
||||
obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o
|
||||
obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o
|
||||
obj-$(CONFIG_MACH_KS8695) += gpio-ks8695.o
|
||||
obj-$(CONFIG_GPIO_LANGWELL) += gpio-langwell.o
|
||||
obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o
|
||||
obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o
|
||||
obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o
|
||||
obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o
|
||||
@@ -37,18 +40,20 @@ obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o
|
||||
obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o
|
||||
obj-$(CONFIG_GPIO_PCH) += gpio-pch.o
|
||||
obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o
|
||||
obj-$(CONFIG_PLAT_PXA) += gpio-pxa.o
|
||||
obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o
|
||||
|
||||
obj-$(CONFIG_GPIO_PLAT_SAMSUNG) += gpio-plat-samsung.o
|
||||
obj-$(CONFIG_GPIO_S5PC100) += gpio-s5pc100.o
|
||||
obj-$(CONFIG_GPIO_S5PV210) += gpio-s5pv210.o
|
||||
|
||||
obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o
|
||||
obj-$(CONFIG_GPIO_SCH) += gpio-sch.o
|
||||
obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
|
||||
obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o
|
||||
obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o
|
||||
obj-$(CONFIG_ARCH_TEGRA) += gpio-tegra.o
|
||||
obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o
|
||||
obj-$(CONFIG_ARCH_DAVINCI_TNETV107X) += gpio-tnetv107x.o
|
||||
obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o
|
||||
obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o
|
||||
obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o
|
||||
|
455
drivers/gpio/gpio-davinci.c
Normal file
455
drivers/gpio/gpio-davinci.c
Normal file
@@ -0,0 +1,455 @@
|
||||
/*
|
||||
* TI DaVinci GPIO Support
|
||||
*
|
||||
* Copyright (c) 2006-2007 David Brownell
|
||||
* Copyright (c) 2007, MontaVista Software, Inc. <source@mvista.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.
|
||||
*/
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <asm/mach/irq.h>
|
||||
|
||||
struct davinci_gpio_regs {
|
||||
u32 dir;
|
||||
u32 out_data;
|
||||
u32 set_data;
|
||||
u32 clr_data;
|
||||
u32 in_data;
|
||||
u32 set_rising;
|
||||
u32 clr_rising;
|
||||
u32 set_falling;
|
||||
u32 clr_falling;
|
||||
u32 intstat;
|
||||
};
|
||||
|
||||
#define chip2controller(chip) \
|
||||
container_of(chip, struct davinci_gpio_controller, chip)
|
||||
|
||||
static struct davinci_gpio_controller chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)];
|
||||
static void __iomem *gpio_base;
|
||||
|
||||
static struct davinci_gpio_regs __iomem __init *gpio2regs(unsigned gpio)
|
||||
{
|
||||
void __iomem *ptr;
|
||||
|
||||
if (gpio < 32 * 1)
|
||||
ptr = gpio_base + 0x10;
|
||||
else if (gpio < 32 * 2)
|
||||
ptr = gpio_base + 0x38;
|
||||
else if (gpio < 32 * 3)
|
||||
ptr = gpio_base + 0x60;
|
||||
else if (gpio < 32 * 4)
|
||||
ptr = gpio_base + 0x88;
|
||||
else if (gpio < 32 * 5)
|
||||
ptr = gpio_base + 0xb0;
|
||||
else
|
||||
ptr = NULL;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static inline struct davinci_gpio_regs __iomem *irq2regs(int irq)
|
||||
{
|
||||
struct davinci_gpio_regs __iomem *g;
|
||||
|
||||
g = (__force struct davinci_gpio_regs __iomem *)irq_get_chip_data(irq);
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
static int __init davinci_gpio_irq_setup(void);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/* board setup code *MUST* setup pinmux and enable the GPIO clock. */
|
||||
static inline int __davinci_direction(struct gpio_chip *chip,
|
||||
unsigned offset, bool out, int value)
|
||||
{
|
||||
struct davinci_gpio_controller *d = chip2controller(chip);
|
||||
struct davinci_gpio_regs __iomem *g = d->regs;
|
||||
unsigned long flags;
|
||||
u32 temp;
|
||||
u32 mask = 1 << offset;
|
||||
|
||||
spin_lock_irqsave(&d->lock, flags);
|
||||
temp = __raw_readl(&g->dir);
|
||||
if (out) {
|
||||
temp &= ~mask;
|
||||
__raw_writel(mask, value ? &g->set_data : &g->clr_data);
|
||||
} else {
|
||||
temp |= mask;
|
||||
}
|
||||
__raw_writel(temp, &g->dir);
|
||||
spin_unlock_irqrestore(&d->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int davinci_direction_in(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return __davinci_direction(chip, offset, false, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
davinci_direction_out(struct gpio_chip *chip, unsigned offset, int value)
|
||||
{
|
||||
return __davinci_direction(chip, offset, true, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the pin's value (works even if it's set up as output);
|
||||
* returns zero/nonzero.
|
||||
*
|
||||
* Note that changes are synched to the GPIO clock, so reading values back
|
||||
* right after you've set them may give old values.
|
||||
*/
|
||||
static int davinci_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct davinci_gpio_controller *d = chip2controller(chip);
|
||||
struct davinci_gpio_regs __iomem *g = d->regs;
|
||||
|
||||
return (1 << offset) & __raw_readl(&g->in_data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Assuming the pin is muxed as a gpio output, set its output value.
|
||||
*/
|
||||
static void
|
||||
davinci_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||
{
|
||||
struct davinci_gpio_controller *d = chip2controller(chip);
|
||||
struct davinci_gpio_regs __iomem *g = d->regs;
|
||||
|
||||
__raw_writel((1 << offset), value ? &g->set_data : &g->clr_data);
|
||||
}
|
||||
|
||||
static int __init davinci_gpio_setup(void)
|
||||
{
|
||||
int i, base;
|
||||
unsigned ngpio;
|
||||
struct davinci_soc_info *soc_info = &davinci_soc_info;
|
||||
struct davinci_gpio_regs *regs;
|
||||
|
||||
if (soc_info->gpio_type != GPIO_TYPE_DAVINCI)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* The gpio banks conceptually expose a segmented bitmap,
|
||||
* and "ngpio" is one more than the largest zero-based
|
||||
* bit index that's valid.
|
||||
*/
|
||||
ngpio = soc_info->gpio_num;
|
||||
if (ngpio == 0) {
|
||||
pr_err("GPIO setup: how many GPIOs?\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (WARN_ON(DAVINCI_N_GPIO < ngpio))
|
||||
ngpio = DAVINCI_N_GPIO;
|
||||
|
||||
gpio_base = ioremap(soc_info->gpio_base, SZ_4K);
|
||||
if (WARN_ON(!gpio_base))
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0, base = 0; base < ngpio; i++, base += 32) {
|
||||
chips[i].chip.label = "DaVinci";
|
||||
|
||||
chips[i].chip.direction_input = davinci_direction_in;
|
||||
chips[i].chip.get = davinci_gpio_get;
|
||||
chips[i].chip.direction_output = davinci_direction_out;
|
||||
chips[i].chip.set = davinci_gpio_set;
|
||||
|
||||
chips[i].chip.base = base;
|
||||
chips[i].chip.ngpio = ngpio - base;
|
||||
if (chips[i].chip.ngpio > 32)
|
||||
chips[i].chip.ngpio = 32;
|
||||
|
||||
spin_lock_init(&chips[i].lock);
|
||||
|
||||
regs = gpio2regs(base);
|
||||
chips[i].regs = regs;
|
||||
chips[i].set_data = ®s->set_data;
|
||||
chips[i].clr_data = ®s->clr_data;
|
||||
chips[i].in_data = ®s->in_data;
|
||||
|
||||
gpiochip_add(&chips[i].chip);
|
||||
}
|
||||
|
||||
soc_info->gpio_ctlrs = chips;
|
||||
soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32);
|
||||
|
||||
davinci_gpio_irq_setup();
|
||||
return 0;
|
||||
}
|
||||
pure_initcall(davinci_gpio_setup);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/*
|
||||
* We expect irqs will normally be set up as input pins, but they can also be
|
||||
* used as output pins ... which is convenient for testing.
|
||||
*
|
||||
* NOTE: The first few GPIOs also have direct INTC hookups in addition
|
||||
* to their GPIOBNK0 irq, with a bit less overhead.
|
||||
*
|
||||
* All those INTC hookups (direct, plus several IRQ banks) can also
|
||||
* serve as EDMA event triggers.
|
||||
*/
|
||||
|
||||
static void gpio_irq_disable(struct irq_data *d)
|
||||
{
|
||||
struct davinci_gpio_regs __iomem *g = irq2regs(d->irq);
|
||||
u32 mask = (u32) irq_data_get_irq_handler_data(d);
|
||||
|
||||
__raw_writel(mask, &g->clr_falling);
|
||||
__raw_writel(mask, &g->clr_rising);
|
||||
}
|
||||
|
||||
static void gpio_irq_enable(struct irq_data *d)
|
||||
{
|
||||
struct davinci_gpio_regs __iomem *g = irq2regs(d->irq);
|
||||
u32 mask = (u32) irq_data_get_irq_handler_data(d);
|
||||
unsigned status = irqd_get_trigger_type(d);
|
||||
|
||||
status &= IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING;
|
||||
if (!status)
|
||||
status = IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING;
|
||||
|
||||
if (status & IRQ_TYPE_EDGE_FALLING)
|
||||
__raw_writel(mask, &g->set_falling);
|
||||
if (status & IRQ_TYPE_EDGE_RISING)
|
||||
__raw_writel(mask, &g->set_rising);
|
||||
}
|
||||
|
||||
static int gpio_irq_type(struct irq_data *d, unsigned trigger)
|
||||
{
|
||||
if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_chip gpio_irqchip = {
|
||||
.name = "GPIO",
|
||||
.irq_enable = gpio_irq_enable,
|
||||
.irq_disable = gpio_irq_disable,
|
||||
.irq_set_type = gpio_irq_type,
|
||||
.flags = IRQCHIP_SET_TYPE_MASKED,
|
||||
};
|
||||
|
||||
static void
|
||||
gpio_irq_handler(unsigned irq, struct irq_desc *desc)
|
||||
{
|
||||
struct davinci_gpio_regs __iomem *g;
|
||||
u32 mask = 0xffff;
|
||||
struct davinci_gpio_controller *d;
|
||||
|
||||
d = (struct davinci_gpio_controller *)irq_desc_get_handler_data(desc);
|
||||
g = (struct davinci_gpio_regs __iomem *)d->regs;
|
||||
|
||||
/* we only care about one bank */
|
||||
if (irq & 1)
|
||||
mask <<= 16;
|
||||
|
||||
/* temporarily mask (level sensitive) parent IRQ */
|
||||
desc->irq_data.chip->irq_mask(&desc->irq_data);
|
||||
desc->irq_data.chip->irq_ack(&desc->irq_data);
|
||||
while (1) {
|
||||
u32 status;
|
||||
int n;
|
||||
int res;
|
||||
|
||||
/* ack any irqs */
|
||||
status = __raw_readl(&g->intstat) & mask;
|
||||
if (!status)
|
||||
break;
|
||||
__raw_writel(status, &g->intstat);
|
||||
|
||||
/* now demux them to the right lowlevel handler */
|
||||
n = d->irq_base;
|
||||
if (irq & 1) {
|
||||
n += 16;
|
||||
status >>= 16;
|
||||
}
|
||||
|
||||
while (status) {
|
||||
res = ffs(status);
|
||||
n += res;
|
||||
generic_handle_irq(n - 1);
|
||||
status >>= res;
|
||||
}
|
||||
}
|
||||
desc->irq_data.chip->irq_unmask(&desc->irq_data);
|
||||
/* now it may re-trigger */
|
||||
}
|
||||
|
||||
static int gpio_to_irq_banked(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct davinci_gpio_controller *d = chip2controller(chip);
|
||||
|
||||
if (d->irq_base >= 0)
|
||||
return d->irq_base + offset;
|
||||
else
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct davinci_soc_info *soc_info = &davinci_soc_info;
|
||||
|
||||
/* NOTE: we assume for now that only irqs in the first gpio_chip
|
||||
* can provide direct-mapped IRQs to AINTC (up to 32 GPIOs).
|
||||
*/
|
||||
if (offset < soc_info->gpio_unbanked)
|
||||
return soc_info->gpio_irq + offset;
|
||||
else
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int gpio_irq_type_unbanked(struct irq_data *d, unsigned trigger)
|
||||
{
|
||||
struct davinci_gpio_regs __iomem *g = irq2regs(d->irq);
|
||||
u32 mask = (u32) irq_data_get_irq_handler_data(d);
|
||||
|
||||
if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
|
||||
return -EINVAL;
|
||||
|
||||
__raw_writel(mask, (trigger & IRQ_TYPE_EDGE_FALLING)
|
||||
? &g->set_falling : &g->clr_falling);
|
||||
__raw_writel(mask, (trigger & IRQ_TYPE_EDGE_RISING)
|
||||
? &g->set_rising : &g->clr_rising);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: for suspend/resume, probably best to make a platform_device with
|
||||
* suspend_late/resume_resume calls hooking into results of the set_wake()
|
||||
* calls ... so if no gpios are wakeup events the clock can be disabled,
|
||||
* with outputs left at previously set levels, and so that VDD3P3V.IOPWDN0
|
||||
* (dm6446) can be set appropriately for GPIOV33 pins.
|
||||
*/
|
||||
|
||||
static int __init davinci_gpio_irq_setup(void)
|
||||
{
|
||||
unsigned gpio, irq, bank;
|
||||
struct clk *clk;
|
||||
u32 binten = 0;
|
||||
unsigned ngpio, bank_irq;
|
||||
struct davinci_soc_info *soc_info = &davinci_soc_info;
|
||||
struct davinci_gpio_regs __iomem *g;
|
||||
|
||||
ngpio = soc_info->gpio_num;
|
||||
|
||||
bank_irq = soc_info->gpio_irq;
|
||||
if (bank_irq == 0) {
|
||||
printk(KERN_ERR "Don't know first GPIO bank IRQ.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
clk = clk_get(NULL, "gpio");
|
||||
if (IS_ERR(clk)) {
|
||||
printk(KERN_ERR "Error %ld getting gpio clock?\n",
|
||||
PTR_ERR(clk));
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
clk_enable(clk);
|
||||
|
||||
/* Arrange gpio_to_irq() support, handling either direct IRQs or
|
||||
* banked IRQs. Having GPIOs in the first GPIO bank use direct
|
||||
* IRQs, while the others use banked IRQs, would need some setup
|
||||
* tweaks to recognize hardware which can do that.
|
||||
*/
|
||||
for (gpio = 0, bank = 0; gpio < ngpio; bank++, gpio += 32) {
|
||||
chips[bank].chip.to_irq = gpio_to_irq_banked;
|
||||
chips[bank].irq_base = soc_info->gpio_unbanked
|
||||
? -EINVAL
|
||||
: (soc_info->intc_irq_num + gpio);
|
||||
}
|
||||
|
||||
/*
|
||||
* AINTC can handle direct/unbanked IRQs for GPIOs, with the GPIO
|
||||
* controller only handling trigger modes. We currently assume no
|
||||
* IRQ mux conflicts; gpio_irq_type_unbanked() is only for GPIOs.
|
||||
*/
|
||||
if (soc_info->gpio_unbanked) {
|
||||
static struct irq_chip gpio_irqchip_unbanked;
|
||||
|
||||
/* pass "bank 0" GPIO IRQs to AINTC */
|
||||
chips[0].chip.to_irq = gpio_to_irq_unbanked;
|
||||
binten = BIT(0);
|
||||
|
||||
/* AINTC handles mask/unmask; GPIO handles triggering */
|
||||
irq = bank_irq;
|
||||
gpio_irqchip_unbanked = *irq_get_chip(irq);
|
||||
gpio_irqchip_unbanked.name = "GPIO-AINTC";
|
||||
gpio_irqchip_unbanked.irq_set_type = gpio_irq_type_unbanked;
|
||||
|
||||
/* default trigger: both edges */
|
||||
g = gpio2regs(0);
|
||||
__raw_writel(~0, &g->set_falling);
|
||||
__raw_writel(~0, &g->set_rising);
|
||||
|
||||
/* set the direct IRQs up to use that irqchip */
|
||||
for (gpio = 0; gpio < soc_info->gpio_unbanked; gpio++, irq++) {
|
||||
irq_set_chip(irq, &gpio_irqchip_unbanked);
|
||||
irq_set_handler_data(irq, (void *)__gpio_mask(gpio));
|
||||
irq_set_chip_data(irq, (__force void *)g);
|
||||
irq_set_status_flags(irq, IRQ_TYPE_EDGE_BOTH);
|
||||
}
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Or, AINTC can handle IRQs for banks of 16 GPIO IRQs, which we
|
||||
* then chain through our own handler.
|
||||
*/
|
||||
for (gpio = 0, irq = gpio_to_irq(0), bank = 0;
|
||||
gpio < ngpio;
|
||||
bank++, bank_irq++) {
|
||||
unsigned i;
|
||||
|
||||
/* disabled by default, enabled only as needed */
|
||||
g = gpio2regs(gpio);
|
||||
__raw_writel(~0, &g->clr_falling);
|
||||
__raw_writel(~0, &g->clr_rising);
|
||||
|
||||
/* set up all irqs in this bank */
|
||||
irq_set_chained_handler(bank_irq, gpio_irq_handler);
|
||||
|
||||
/*
|
||||
* Each chip handles 32 gpios, and each irq bank consists of 16
|
||||
* gpio irqs. Pass the irq bank's corresponding controller to
|
||||
* the chained irq handler.
|
||||
*/
|
||||
irq_set_handler_data(bank_irq, &chips[gpio / 32]);
|
||||
|
||||
for (i = 0; i < 16 && gpio < ngpio; i++, irq++, gpio++) {
|
||||
irq_set_chip(irq, &gpio_irqchip);
|
||||
irq_set_chip_data(irq, (__force void *)g);
|
||||
irq_set_handler_data(irq, (void *)__gpio_mask(gpio));
|
||||
irq_set_handler(irq, handle_simple_irq);
|
||||
set_irq_flags(irq, IRQF_VALID);
|
||||
}
|
||||
|
||||
binten |= BIT(bank);
|
||||
}
|
||||
|
||||
done:
|
||||
/* BINTEN -- per-bank interrupt enable. genirq would also let these
|
||||
* bits be set/cleared dynamically.
|
||||
*/
|
||||
__raw_writel(binten, gpio_base + 0x08);
|
||||
|
||||
printk(KERN_INFO "DaVinci: %d gpio irqs\n", irq - gpio_to_irq(0));
|
||||
|
||||
return 0;
|
||||
}
|
@@ -23,6 +23,9 @@
|
||||
#include <linux/basic_mmio_gpio.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/gpio-ep93xx.h>
|
||||
|
||||
#define irq_to_gpio(irq) ((irq) - gpio_to_irq(0))
|
||||
|
||||
struct ep93xx_gpio {
|
||||
void __iomem *mmio_base;
|
||||
@@ -307,6 +310,21 @@ static int ep93xx_gpio_set_debounce(struct gpio_chip *chip,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Map GPIO A0..A7 (0..7) to irq 64..71,
|
||||
* B0..B7 (7..15) to irq 72..79, and
|
||||
* F0..F7 (16..24) to irq 80..87.
|
||||
*/
|
||||
static int ep93xx_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
int gpio = chip->base + offset;
|
||||
|
||||
if (gpio > EP93XX_GPIO_LINE_MAX_IRQ)
|
||||
return -EINVAL;
|
||||
|
||||
return 64 + gpio;
|
||||
}
|
||||
|
||||
static int ep93xx_gpio_add_bank(struct bgpio_chip *bgc, struct device *dev,
|
||||
void __iomem *mmio_base, struct ep93xx_gpio_bank *bank)
|
||||
{
|
||||
@@ -321,8 +339,10 @@ static int ep93xx_gpio_add_bank(struct bgpio_chip *bgc, struct device *dev,
|
||||
bgc->gc.label = bank->label;
|
||||
bgc->gc.base = bank->base;
|
||||
|
||||
if (bank->has_debounce)
|
||||
if (bank->has_debounce) {
|
||||
bgc->gc.set_debounce = ep93xx_gpio_set_debounce;
|
||||
bgc->gc.to_irq = ep93xx_gpio_to_irq;
|
||||
}
|
||||
|
||||
return gpiochip_add(&bgc->gc);
|
||||
}
|
||||
|
319
drivers/gpio/gpio-ks8695.c
Normal file
319
drivers/gpio/gpio-ks8695.c
Normal file
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
* arch/arm/mach-ks8695/gpio.c
|
||||
*
|
||||
* Copyright (C) 2006 Andrew Victor
|
||||
* Updated to GPIOLIB, Copyright 2008 Simtec Electronics
|
||||
* Daniel Silverstone <dsilvers@simtec.co.uk>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/mach/irq.h>
|
||||
|
||||
#include <mach/regs-gpio.h>
|
||||
#include <mach/gpio-ks8695.h>
|
||||
|
||||
/*
|
||||
* Configure a GPIO line for either GPIO function, or its internal
|
||||
* function (Interrupt, Timer, etc).
|
||||
*/
|
||||
static void ks8695_gpio_mode(unsigned int pin, short gpio)
|
||||
{
|
||||
unsigned int enable[] = { IOPC_IOEINT0EN, IOPC_IOEINT1EN, IOPC_IOEINT2EN, IOPC_IOEINT3EN, IOPC_IOTIM0EN, IOPC_IOTIM1EN };
|
||||
unsigned long x, flags;
|
||||
|
||||
if (pin > KS8695_GPIO_5) /* only GPIO 0..5 have internal functions */
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPC);
|
||||
if (gpio) /* GPIO: set bit to 0 */
|
||||
x &= ~enable[pin];
|
||||
else /* Internal function: set bit to 1 */
|
||||
x |= enable[pin];
|
||||
__raw_writel(x, KS8695_GPIO_VA + KS8695_IOPC);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
|
||||
static unsigned short gpio_irq[] = { KS8695_IRQ_EXTERN0, KS8695_IRQ_EXTERN1, KS8695_IRQ_EXTERN2, KS8695_IRQ_EXTERN3 };
|
||||
|
||||
/*
|
||||
* Configure GPIO pin as external interrupt source.
|
||||
*/
|
||||
int ks8695_gpio_interrupt(unsigned int pin, unsigned int type)
|
||||
{
|
||||
unsigned long x, flags;
|
||||
|
||||
if (pin > KS8695_GPIO_3) /* only GPIO 0..3 can generate IRQ */
|
||||
return -EINVAL;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
/* set pin as input */
|
||||
x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
|
||||
x &= ~IOPM(pin);
|
||||
__raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM);
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
/* Set IRQ triggering type */
|
||||
irq_set_irq_type(gpio_irq[pin], type);
|
||||
|
||||
/* enable interrupt mode */
|
||||
ks8695_gpio_mode(pin, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ks8695_gpio_interrupt);
|
||||
|
||||
|
||||
|
||||
/* .... Generic GPIO interface .............................................. */
|
||||
|
||||
/*
|
||||
* Configure the GPIO line as an input.
|
||||
*/
|
||||
static int ks8695_gpio_direction_input(struct gpio_chip *gc, unsigned int pin)
|
||||
{
|
||||
unsigned long x, flags;
|
||||
|
||||
if (pin > KS8695_GPIO_15)
|
||||
return -EINVAL;
|
||||
|
||||
/* set pin to GPIO mode */
|
||||
ks8695_gpio_mode(pin, 1);
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
/* set pin as input */
|
||||
x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
|
||||
x &= ~IOPM(pin);
|
||||
__raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM);
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Configure the GPIO line as an output, with default state.
|
||||
*/
|
||||
static int ks8695_gpio_direction_output(struct gpio_chip *gc,
|
||||
unsigned int pin, int state)
|
||||
{
|
||||
unsigned long x, flags;
|
||||
|
||||
if (pin > KS8695_GPIO_15)
|
||||
return -EINVAL;
|
||||
|
||||
/* set pin to GPIO mode */
|
||||
ks8695_gpio_mode(pin, 1);
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
/* set line state */
|
||||
x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
|
||||
if (state)
|
||||
x |= IOPD(pin);
|
||||
else
|
||||
x &= ~IOPD(pin);
|
||||
__raw_writel(x, KS8695_GPIO_VA + KS8695_IOPD);
|
||||
|
||||
/* set pin as output */
|
||||
x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
|
||||
x |= IOPM(pin);
|
||||
__raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM);
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set the state of an output GPIO line.
|
||||
*/
|
||||
static void ks8695_gpio_set_value(struct gpio_chip *gc,
|
||||
unsigned int pin, int state)
|
||||
{
|
||||
unsigned long x, flags;
|
||||
|
||||
if (pin > KS8695_GPIO_15)
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
/* set output line state */
|
||||
x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
|
||||
if (state)
|
||||
x |= IOPD(pin);
|
||||
else
|
||||
x &= ~IOPD(pin);
|
||||
__raw_writel(x, KS8695_GPIO_VA + KS8695_IOPD);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read the state of a GPIO line.
|
||||
*/
|
||||
static int ks8695_gpio_get_value(struct gpio_chip *gc, unsigned int pin)
|
||||
{
|
||||
unsigned long x;
|
||||
|
||||
if (pin > KS8695_GPIO_15)
|
||||
return -EINVAL;
|
||||
|
||||
x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
|
||||
return (x & IOPD(pin)) != 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Map GPIO line to IRQ number.
|
||||
*/
|
||||
static int ks8695_gpio_to_irq(struct gpio_chip *gc, unsigned int pin)
|
||||
{
|
||||
if (pin > KS8695_GPIO_3) /* only GPIO 0..3 can generate IRQ */
|
||||
return -EINVAL;
|
||||
|
||||
return gpio_irq[pin];
|
||||
}
|
||||
|
||||
/*
|
||||
* Map IRQ number to GPIO line.
|
||||
*/
|
||||
int irq_to_gpio(unsigned int irq)
|
||||
{
|
||||
if ((irq < KS8695_IRQ_EXTERN0) || (irq > KS8695_IRQ_EXTERN3))
|
||||
return -EINVAL;
|
||||
|
||||
return (irq - KS8695_IRQ_EXTERN0);
|
||||
}
|
||||
EXPORT_SYMBOL(irq_to_gpio);
|
||||
|
||||
/* GPIOLIB interface */
|
||||
|
||||
static struct gpio_chip ks8695_gpio_chip = {
|
||||
.label = "KS8695",
|
||||
.direction_input = ks8695_gpio_direction_input,
|
||||
.direction_output = ks8695_gpio_direction_output,
|
||||
.get = ks8695_gpio_get_value,
|
||||
.set = ks8695_gpio_set_value,
|
||||
.to_irq = ks8695_gpio_to_irq,
|
||||
.base = 0,
|
||||
.ngpio = 16,
|
||||
.can_sleep = 0,
|
||||
};
|
||||
|
||||
/* Register the GPIOs */
|
||||
void ks8695_register_gpios(void)
|
||||
{
|
||||
if (gpiochip_add(&ks8695_gpio_chip))
|
||||
printk(KERN_ERR "Unable to register core GPIOs\n");
|
||||
}
|
||||
|
||||
/* .... Debug interface ..................................................... */
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
||||
static int ks8695_gpio_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
unsigned int enable[] = { IOPC_IOEINT0EN, IOPC_IOEINT1EN, IOPC_IOEINT2EN, IOPC_IOEINT3EN, IOPC_IOTIM0EN, IOPC_IOTIM1EN };
|
||||
unsigned int intmask[] = { IOPC_IOEINT0TM, IOPC_IOEINT1TM, IOPC_IOEINT2TM, IOPC_IOEINT3TM };
|
||||
unsigned long mode, ctrl, data;
|
||||
int i;
|
||||
|
||||
mode = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
|
||||
ctrl = __raw_readl(KS8695_GPIO_VA + KS8695_IOPC);
|
||||
data = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
|
||||
|
||||
seq_printf(s, "Pin\tI/O\tFunction\tState\n\n");
|
||||
|
||||
for (i = KS8695_GPIO_0; i <= KS8695_GPIO_15 ; i++) {
|
||||
seq_printf(s, "%i:\t", i);
|
||||
|
||||
seq_printf(s, "%s\t", (mode & IOPM(i)) ? "Output" : "Input");
|
||||
|
||||
if (i <= KS8695_GPIO_3) {
|
||||
if (ctrl & enable[i]) {
|
||||
seq_printf(s, "EXT%i ", i);
|
||||
|
||||
switch ((ctrl & intmask[i]) >> (4 * i)) {
|
||||
case IOPC_TM_LOW:
|
||||
seq_printf(s, "(Low)"); break;
|
||||
case IOPC_TM_HIGH:
|
||||
seq_printf(s, "(High)"); break;
|
||||
case IOPC_TM_RISING:
|
||||
seq_printf(s, "(Rising)"); break;
|
||||
case IOPC_TM_FALLING:
|
||||
seq_printf(s, "(Falling)"); break;
|
||||
case IOPC_TM_EDGE:
|
||||
seq_printf(s, "(Edges)"); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
seq_printf(s, "GPIO\t");
|
||||
}
|
||||
else if (i <= KS8695_GPIO_5) {
|
||||
if (ctrl & enable[i])
|
||||
seq_printf(s, "TOUT%i\t", i - KS8695_GPIO_4);
|
||||
else
|
||||
seq_printf(s, "GPIO\t");
|
||||
}
|
||||
else
|
||||
seq_printf(s, "GPIO\t");
|
||||
|
||||
seq_printf(s, "\t");
|
||||
|
||||
seq_printf(s, "%i\n", (data & IOPD(i)) ? 1 : 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ks8695_gpio_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, ks8695_gpio_show, NULL);
|
||||
}
|
||||
|
||||
static const struct file_operations ks8695_gpio_operations = {
|
||||
.open = ks8695_gpio_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int __init ks8695_gpio_debugfs_init(void)
|
||||
{
|
||||
/* /sys/kernel/debug/ks8695_gpio */
|
||||
(void) debugfs_create_file("ks8695_gpio", S_IFREG | S_IRUGO, NULL, NULL, &ks8695_gpio_operations);
|
||||
return 0;
|
||||
}
|
||||
postcore_initcall(ks8695_gpio_debugfs_init);
|
||||
|
||||
#endif
|
446
drivers/gpio/gpio-lpc32xx.c
Normal file
446
drivers/gpio/gpio-lpc32xx.c
Normal file
@@ -0,0 +1,446 @@
|
||||
/*
|
||||
* arch/arm/mach-lpc32xx/gpiolib.c
|
||||
*
|
||||
* Author: Kevin Wells <kevin.wells@nxp.com>
|
||||
*
|
||||
* Copyright (C) 2010 NXP Semiconductors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/platform.h>
|
||||
#include <mach/gpio-lpc32xx.h>
|
||||
|
||||
#define LPC32XX_GPIO_P3_INP_STATE _GPREG(0x000)
|
||||
#define LPC32XX_GPIO_P3_OUTP_SET _GPREG(0x004)
|
||||
#define LPC32XX_GPIO_P3_OUTP_CLR _GPREG(0x008)
|
||||
#define LPC32XX_GPIO_P3_OUTP_STATE _GPREG(0x00C)
|
||||
#define LPC32XX_GPIO_P2_DIR_SET _GPREG(0x010)
|
||||
#define LPC32XX_GPIO_P2_DIR_CLR _GPREG(0x014)
|
||||
#define LPC32XX_GPIO_P2_DIR_STATE _GPREG(0x018)
|
||||
#define LPC32XX_GPIO_P2_INP_STATE _GPREG(0x01C)
|
||||
#define LPC32XX_GPIO_P2_OUTP_SET _GPREG(0x020)
|
||||
#define LPC32XX_GPIO_P2_OUTP_CLR _GPREG(0x024)
|
||||
#define LPC32XX_GPIO_P2_MUX_SET _GPREG(0x028)
|
||||
#define LPC32XX_GPIO_P2_MUX_CLR _GPREG(0x02C)
|
||||
#define LPC32XX_GPIO_P2_MUX_STATE _GPREG(0x030)
|
||||
#define LPC32XX_GPIO_P0_INP_STATE _GPREG(0x040)
|
||||
#define LPC32XX_GPIO_P0_OUTP_SET _GPREG(0x044)
|
||||
#define LPC32XX_GPIO_P0_OUTP_CLR _GPREG(0x048)
|
||||
#define LPC32XX_GPIO_P0_OUTP_STATE _GPREG(0x04C)
|
||||
#define LPC32XX_GPIO_P0_DIR_SET _GPREG(0x050)
|
||||
#define LPC32XX_GPIO_P0_DIR_CLR _GPREG(0x054)
|
||||
#define LPC32XX_GPIO_P0_DIR_STATE _GPREG(0x058)
|
||||
#define LPC32XX_GPIO_P1_INP_STATE _GPREG(0x060)
|
||||
#define LPC32XX_GPIO_P1_OUTP_SET _GPREG(0x064)
|
||||
#define LPC32XX_GPIO_P1_OUTP_CLR _GPREG(0x068)
|
||||
#define LPC32XX_GPIO_P1_OUTP_STATE _GPREG(0x06C)
|
||||
#define LPC32XX_GPIO_P1_DIR_SET _GPREG(0x070)
|
||||
#define LPC32XX_GPIO_P1_DIR_CLR _GPREG(0x074)
|
||||
#define LPC32XX_GPIO_P1_DIR_STATE _GPREG(0x078)
|
||||
|
||||
#define GPIO012_PIN_TO_BIT(x) (1 << (x))
|
||||
#define GPIO3_PIN_TO_BIT(x) (1 << ((x) + 25))
|
||||
#define GPO3_PIN_TO_BIT(x) (1 << (x))
|
||||
#define GPIO012_PIN_IN_SEL(x, y) (((x) >> (y)) & 1)
|
||||
#define GPIO3_PIN_IN_SHIFT(x) ((x) == 5 ? 24 : 10 + (x))
|
||||
#define GPIO3_PIN_IN_SEL(x, y) ((x) >> GPIO3_PIN_IN_SHIFT(y))
|
||||
#define GPIO3_PIN5_IN_SEL(x) (((x) >> 24) & 1)
|
||||
#define GPI3_PIN_IN_SEL(x, y) (((x) >> (y)) & 1)
|
||||
|
||||
struct gpio_regs {
|
||||
void __iomem *inp_state;
|
||||
void __iomem *outp_set;
|
||||
void __iomem *outp_clr;
|
||||
void __iomem *dir_set;
|
||||
void __iomem *dir_clr;
|
||||
};
|
||||
|
||||
/*
|
||||
* GPIO names
|
||||
*/
|
||||
static const char *gpio_p0_names[LPC32XX_GPIO_P0_MAX] = {
|
||||
"p0.0", "p0.1", "p0.2", "p0.3",
|
||||
"p0.4", "p0.5", "p0.6", "p0.7"
|
||||
};
|
||||
|
||||
static const char *gpio_p1_names[LPC32XX_GPIO_P1_MAX] = {
|
||||
"p1.0", "p1.1", "p1.2", "p1.3",
|
||||
"p1.4", "p1.5", "p1.6", "p1.7",
|
||||
"p1.8", "p1.9", "p1.10", "p1.11",
|
||||
"p1.12", "p1.13", "p1.14", "p1.15",
|
||||
"p1.16", "p1.17", "p1.18", "p1.19",
|
||||
"p1.20", "p1.21", "p1.22", "p1.23",
|
||||
};
|
||||
|
||||
static const char *gpio_p2_names[LPC32XX_GPIO_P2_MAX] = {
|
||||
"p2.0", "p2.1", "p2.2", "p2.3",
|
||||
"p2.4", "p2.5", "p2.6", "p2.7",
|
||||
"p2.8", "p2.9", "p2.10", "p2.11",
|
||||
"p2.12"
|
||||
};
|
||||
|
||||
static const char *gpio_p3_names[LPC32XX_GPIO_P3_MAX] = {
|
||||
"gpi000", "gpio01", "gpio02", "gpio03",
|
||||
"gpio04", "gpio05"
|
||||
};
|
||||
|
||||
static const char *gpi_p3_names[LPC32XX_GPI_P3_MAX] = {
|
||||
"gpi00", "gpi01", "gpi02", "gpi03",
|
||||
"gpi04", "gpi05", "gpi06", "gpi07",
|
||||
"gpi08", "gpi09", NULL, NULL,
|
||||
NULL, NULL, NULL, "gpi15",
|
||||
"gpi16", "gpi17", "gpi18", "gpi19",
|
||||
"gpi20", "gpi21", "gpi22", "gpi23",
|
||||
"gpi24", "gpi25", "gpi26", "gpi27"
|
||||
};
|
||||
|
||||
static const char *gpo_p3_names[LPC32XX_GPO_P3_MAX] = {
|
||||
"gpo00", "gpo01", "gpo02", "gpo03",
|
||||
"gpo04", "gpo05", "gpo06", "gpo07",
|
||||
"gpo08", "gpo09", "gpo10", "gpo11",
|
||||
"gpo12", "gpo13", "gpo14", "gpo15",
|
||||
"gpo16", "gpo17", "gpo18", "gpo19",
|
||||
"gpo20", "gpo21", "gpo22", "gpo23"
|
||||
};
|
||||
|
||||
static struct gpio_regs gpio_grp_regs_p0 = {
|
||||
.inp_state = LPC32XX_GPIO_P0_INP_STATE,
|
||||
.outp_set = LPC32XX_GPIO_P0_OUTP_SET,
|
||||
.outp_clr = LPC32XX_GPIO_P0_OUTP_CLR,
|
||||
.dir_set = LPC32XX_GPIO_P0_DIR_SET,
|
||||
.dir_clr = LPC32XX_GPIO_P0_DIR_CLR,
|
||||
};
|
||||
|
||||
static struct gpio_regs gpio_grp_regs_p1 = {
|
||||
.inp_state = LPC32XX_GPIO_P1_INP_STATE,
|
||||
.outp_set = LPC32XX_GPIO_P1_OUTP_SET,
|
||||
.outp_clr = LPC32XX_GPIO_P1_OUTP_CLR,
|
||||
.dir_set = LPC32XX_GPIO_P1_DIR_SET,
|
||||
.dir_clr = LPC32XX_GPIO_P1_DIR_CLR,
|
||||
};
|
||||
|
||||
static struct gpio_regs gpio_grp_regs_p2 = {
|
||||
.inp_state = LPC32XX_GPIO_P2_INP_STATE,
|
||||
.outp_set = LPC32XX_GPIO_P2_OUTP_SET,
|
||||
.outp_clr = LPC32XX_GPIO_P2_OUTP_CLR,
|
||||
.dir_set = LPC32XX_GPIO_P2_DIR_SET,
|
||||
.dir_clr = LPC32XX_GPIO_P2_DIR_CLR,
|
||||
};
|
||||
|
||||
static struct gpio_regs gpio_grp_regs_p3 = {
|
||||
.inp_state = LPC32XX_GPIO_P3_INP_STATE,
|
||||
.outp_set = LPC32XX_GPIO_P3_OUTP_SET,
|
||||
.outp_clr = LPC32XX_GPIO_P3_OUTP_CLR,
|
||||
.dir_set = LPC32XX_GPIO_P2_DIR_SET,
|
||||
.dir_clr = LPC32XX_GPIO_P2_DIR_CLR,
|
||||
};
|
||||
|
||||
struct lpc32xx_gpio_chip {
|
||||
struct gpio_chip chip;
|
||||
struct gpio_regs *gpio_grp;
|
||||
};
|
||||
|
||||
static inline struct lpc32xx_gpio_chip *to_lpc32xx_gpio(
|
||||
struct gpio_chip *gpc)
|
||||
{
|
||||
return container_of(gpc, struct lpc32xx_gpio_chip, chip);
|
||||
}
|
||||
|
||||
static void __set_gpio_dir_p012(struct lpc32xx_gpio_chip *group,
|
||||
unsigned pin, int input)
|
||||
{
|
||||
if (input)
|
||||
__raw_writel(GPIO012_PIN_TO_BIT(pin),
|
||||
group->gpio_grp->dir_clr);
|
||||
else
|
||||
__raw_writel(GPIO012_PIN_TO_BIT(pin),
|
||||
group->gpio_grp->dir_set);
|
||||
}
|
||||
|
||||
static void __set_gpio_dir_p3(struct lpc32xx_gpio_chip *group,
|
||||
unsigned pin, int input)
|
||||
{
|
||||
u32 u = GPIO3_PIN_TO_BIT(pin);
|
||||
|
||||
if (input)
|
||||
__raw_writel(u, group->gpio_grp->dir_clr);
|
||||
else
|
||||
__raw_writel(u, group->gpio_grp->dir_set);
|
||||
}
|
||||
|
||||
static void __set_gpio_level_p012(struct lpc32xx_gpio_chip *group,
|
||||
unsigned pin, int high)
|
||||
{
|
||||
if (high)
|
||||
__raw_writel(GPIO012_PIN_TO_BIT(pin),
|
||||
group->gpio_grp->outp_set);
|
||||
else
|
||||
__raw_writel(GPIO012_PIN_TO_BIT(pin),
|
||||
group->gpio_grp->outp_clr);
|
||||
}
|
||||
|
||||
static void __set_gpio_level_p3(struct lpc32xx_gpio_chip *group,
|
||||
unsigned pin, int high)
|
||||
{
|
||||
u32 u = GPIO3_PIN_TO_BIT(pin);
|
||||
|
||||
if (high)
|
||||
__raw_writel(u, group->gpio_grp->outp_set);
|
||||
else
|
||||
__raw_writel(u, group->gpio_grp->outp_clr);
|
||||
}
|
||||
|
||||
static void __set_gpo_level_p3(struct lpc32xx_gpio_chip *group,
|
||||
unsigned pin, int high)
|
||||
{
|
||||
if (high)
|
||||
__raw_writel(GPO3_PIN_TO_BIT(pin), group->gpio_grp->outp_set);
|
||||
else
|
||||
__raw_writel(GPO3_PIN_TO_BIT(pin), group->gpio_grp->outp_clr);
|
||||
}
|
||||
|
||||
static int __get_gpio_state_p012(struct lpc32xx_gpio_chip *group,
|
||||
unsigned pin)
|
||||
{
|
||||
return GPIO012_PIN_IN_SEL(__raw_readl(group->gpio_grp->inp_state),
|
||||
pin);
|
||||
}
|
||||
|
||||
static int __get_gpio_state_p3(struct lpc32xx_gpio_chip *group,
|
||||
unsigned pin)
|
||||
{
|
||||
int state = __raw_readl(group->gpio_grp->inp_state);
|
||||
|
||||
/*
|
||||
* P3 GPIO pin input mapping is not contiguous, GPIOP3-0..4 is mapped
|
||||
* to bits 10..14, while GPIOP3-5 is mapped to bit 24.
|
||||
*/
|
||||
return GPIO3_PIN_IN_SEL(state, pin);
|
||||
}
|
||||
|
||||
static int __get_gpi_state_p3(struct lpc32xx_gpio_chip *group,
|
||||
unsigned pin)
|
||||
{
|
||||
return GPI3_PIN_IN_SEL(__raw_readl(group->gpio_grp->inp_state), pin);
|
||||
}
|
||||
|
||||
/*
|
||||
* GENERIC_GPIO primitives.
|
||||
*/
|
||||
static int lpc32xx_gpio_dir_input_p012(struct gpio_chip *chip,
|
||||
unsigned pin)
|
||||
{
|
||||
struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
|
||||
|
||||
__set_gpio_dir_p012(group, pin, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpc32xx_gpio_dir_input_p3(struct gpio_chip *chip,
|
||||
unsigned pin)
|
||||
{
|
||||
struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
|
||||
|
||||
__set_gpio_dir_p3(group, pin, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpc32xx_gpio_dir_in_always(struct gpio_chip *chip,
|
||||
unsigned pin)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpc32xx_gpio_get_value_p012(struct gpio_chip *chip, unsigned pin)
|
||||
{
|
||||
struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
|
||||
|
||||
return __get_gpio_state_p012(group, pin);
|
||||
}
|
||||
|
||||
static int lpc32xx_gpio_get_value_p3(struct gpio_chip *chip, unsigned pin)
|
||||
{
|
||||
struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
|
||||
|
||||
return __get_gpio_state_p3(group, pin);
|
||||
}
|
||||
|
||||
static int lpc32xx_gpi_get_value(struct gpio_chip *chip, unsigned pin)
|
||||
{
|
||||
struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
|
||||
|
||||
return __get_gpi_state_p3(group, pin);
|
||||
}
|
||||
|
||||
static int lpc32xx_gpio_dir_output_p012(struct gpio_chip *chip, unsigned pin,
|
||||
int value)
|
||||
{
|
||||
struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
|
||||
|
||||
__set_gpio_dir_p012(group, pin, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpc32xx_gpio_dir_output_p3(struct gpio_chip *chip, unsigned pin,
|
||||
int value)
|
||||
{
|
||||
struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
|
||||
|
||||
__set_gpio_dir_p3(group, pin, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpc32xx_gpio_dir_out_always(struct gpio_chip *chip, unsigned pin,
|
||||
int value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lpc32xx_gpio_set_value_p012(struct gpio_chip *chip, unsigned pin,
|
||||
int value)
|
||||
{
|
||||
struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
|
||||
|
||||
__set_gpio_level_p012(group, pin, value);
|
||||
}
|
||||
|
||||
static void lpc32xx_gpio_set_value_p3(struct gpio_chip *chip, unsigned pin,
|
||||
int value)
|
||||
{
|
||||
struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
|
||||
|
||||
__set_gpio_level_p3(group, pin, value);
|
||||
}
|
||||
|
||||
static void lpc32xx_gpo_set_value(struct gpio_chip *chip, unsigned pin,
|
||||
int value)
|
||||
{
|
||||
struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
|
||||
|
||||
__set_gpo_level_p3(group, pin, value);
|
||||
}
|
||||
|
||||
static int lpc32xx_gpio_request(struct gpio_chip *chip, unsigned pin)
|
||||
{
|
||||
if (pin < chip->ngpio)
|
||||
return 0;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = {
|
||||
{
|
||||
.chip = {
|
||||
.label = "gpio_p0",
|
||||
.direction_input = lpc32xx_gpio_dir_input_p012,
|
||||
.get = lpc32xx_gpio_get_value_p012,
|
||||
.direction_output = lpc32xx_gpio_dir_output_p012,
|
||||
.set = lpc32xx_gpio_set_value_p012,
|
||||
.request = lpc32xx_gpio_request,
|
||||
.base = LPC32XX_GPIO_P0_GRP,
|
||||
.ngpio = LPC32XX_GPIO_P0_MAX,
|
||||
.names = gpio_p0_names,
|
||||
.can_sleep = 0,
|
||||
},
|
||||
.gpio_grp = &gpio_grp_regs_p0,
|
||||
},
|
||||
{
|
||||
.chip = {
|
||||
.label = "gpio_p1",
|
||||
.direction_input = lpc32xx_gpio_dir_input_p012,
|
||||
.get = lpc32xx_gpio_get_value_p012,
|
||||
.direction_output = lpc32xx_gpio_dir_output_p012,
|
||||
.set = lpc32xx_gpio_set_value_p012,
|
||||
.request = lpc32xx_gpio_request,
|
||||
.base = LPC32XX_GPIO_P1_GRP,
|
||||
.ngpio = LPC32XX_GPIO_P1_MAX,
|
||||
.names = gpio_p1_names,
|
||||
.can_sleep = 0,
|
||||
},
|
||||
.gpio_grp = &gpio_grp_regs_p1,
|
||||
},
|
||||
{
|
||||
.chip = {
|
||||
.label = "gpio_p2",
|
||||
.direction_input = lpc32xx_gpio_dir_input_p012,
|
||||
.get = lpc32xx_gpio_get_value_p012,
|
||||
.direction_output = lpc32xx_gpio_dir_output_p012,
|
||||
.set = lpc32xx_gpio_set_value_p012,
|
||||
.request = lpc32xx_gpio_request,
|
||||
.base = LPC32XX_GPIO_P2_GRP,
|
||||
.ngpio = LPC32XX_GPIO_P2_MAX,
|
||||
.names = gpio_p2_names,
|
||||
.can_sleep = 0,
|
||||
},
|
||||
.gpio_grp = &gpio_grp_regs_p2,
|
||||
},
|
||||
{
|
||||
.chip = {
|
||||
.label = "gpio_p3",
|
||||
.direction_input = lpc32xx_gpio_dir_input_p3,
|
||||
.get = lpc32xx_gpio_get_value_p3,
|
||||
.direction_output = lpc32xx_gpio_dir_output_p3,
|
||||
.set = lpc32xx_gpio_set_value_p3,
|
||||
.request = lpc32xx_gpio_request,
|
||||
.base = LPC32XX_GPIO_P3_GRP,
|
||||
.ngpio = LPC32XX_GPIO_P3_MAX,
|
||||
.names = gpio_p3_names,
|
||||
.can_sleep = 0,
|
||||
},
|
||||
.gpio_grp = &gpio_grp_regs_p3,
|
||||
},
|
||||
{
|
||||
.chip = {
|
||||
.label = "gpi_p3",
|
||||
.direction_input = lpc32xx_gpio_dir_in_always,
|
||||
.get = lpc32xx_gpi_get_value,
|
||||
.request = lpc32xx_gpio_request,
|
||||
.base = LPC32XX_GPI_P3_GRP,
|
||||
.ngpio = LPC32XX_GPI_P3_MAX,
|
||||
.names = gpi_p3_names,
|
||||
.can_sleep = 0,
|
||||
},
|
||||
.gpio_grp = &gpio_grp_regs_p3,
|
||||
},
|
||||
{
|
||||
.chip = {
|
||||
.label = "gpo_p3",
|
||||
.direction_output = lpc32xx_gpio_dir_out_always,
|
||||
.set = lpc32xx_gpo_set_value,
|
||||
.request = lpc32xx_gpio_request,
|
||||
.base = LPC32XX_GPO_P3_GRP,
|
||||
.ngpio = LPC32XX_GPO_P3_MAX,
|
||||
.names = gpo_p3_names,
|
||||
.can_sleep = 0,
|
||||
},
|
||||
.gpio_grp = &gpio_grp_regs_p3,
|
||||
},
|
||||
};
|
||||
|
||||
void __init lpc32xx_gpio_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(lpc32xx_gpiochip); i++)
|
||||
gpiochip_add(&lpc32xx_gpiochip[i].chip);
|
||||
}
|
@@ -27,8 +27,9 @@
|
||||
#include <asm/mach/irq.h>
|
||||
|
||||
#include <plat/pincfg.h>
|
||||
#include <plat/gpio-nomadik.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <asm/gpio.h>
|
||||
|
||||
/*
|
||||
* The GPIO module in the Nomadik family of Systems-on-Chip is an
|
||||
|
@@ -25,7 +25,7 @@
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/irq.h>
|
||||
#include <mach/irqs.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/mach/irq.h>
|
||||
|
||||
struct gpio_bank {
|
||||
|
338
drivers/gpio/gpio-pxa.c
Normal file
338
drivers/gpio/gpio-pxa.c
Normal file
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
* 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,
|
||||
};
|
63
drivers/gpio/gpio-sa1100.c
Normal file
63
drivers/gpio/gpio-sa1100.c
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* linux/arch/arm/mach-sa1100/gpio.c
|
||||
*
|
||||
* Generic SA-1100 GPIO handling
|
||||
*
|
||||
* 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/module.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
|
||||
static int sa1100_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return GPLR & GPIO_GPIO(offset);
|
||||
}
|
||||
|
||||
static void sa1100_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||
{
|
||||
if (value)
|
||||
GPSR = GPIO_GPIO(offset);
|
||||
else
|
||||
GPCR = GPIO_GPIO(offset);
|
||||
}
|
||||
|
||||
static int sa1100_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
GPDR &= ~GPIO_GPIO(offset);
|
||||
local_irq_restore(flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sa1100_direction_output(struct gpio_chip *chip, unsigned offset, int value)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
sa1100_gpio_set(chip, offset, value);
|
||||
GPDR |= GPIO_GPIO(offset);
|
||||
local_irq_restore(flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct gpio_chip sa1100_gpio_chip = {
|
||||
.label = "gpio",
|
||||
.direction_input = sa1100_direction_input,
|
||||
.direction_output = sa1100_direction_output,
|
||||
.set = sa1100_gpio_set,
|
||||
.get = sa1100_gpio_get,
|
||||
.base = 0,
|
||||
.ngpio = GPIO_MAX + 1,
|
||||
};
|
||||
|
||||
void __init sa1100_init_gpio(void)
|
||||
{
|
||||
gpiochip_add(&sa1100_gpio_chip);
|
||||
}
|
@@ -27,6 +27,7 @@
|
||||
|
||||
#include <asm/mach/irq.h>
|
||||
|
||||
#include <mach/gpio-tegra.h>
|
||||
#include <mach/iomap.h>
|
||||
#include <mach/suspend.h>
|
||||
|
||||
@@ -134,7 +135,10 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return TEGRA_GPIO_TO_IRQ(offset);
|
||||
}
|
||||
|
||||
static struct gpio_chip tegra_gpio_chip = {
|
||||
.label = "tegra-gpio",
|
||||
@@ -142,6 +146,7 @@ static struct gpio_chip tegra_gpio_chip = {
|
||||
.get = tegra_gpio_get,
|
||||
.direction_output = tegra_gpio_direction_output,
|
||||
.set = tegra_gpio_set,
|
||||
.to_irq = tegra_gpio_to_irq,
|
||||
.base = 0,
|
||||
.ngpio = TEGRA_NR_GPIOS,
|
||||
};
|
||||
@@ -331,6 +336,7 @@ static struct lock_class_key gpio_lock_class;
|
||||
static int __init tegra_gpio_init(void)
|
||||
{
|
||||
struct tegra_gpio_bank *bank;
|
||||
int gpio;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
@@ -352,14 +358,17 @@ static int __init tegra_gpio_init(void)
|
||||
|
||||
gpiochip_add(&tegra_gpio_chip);
|
||||
|
||||
for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + TEGRA_NR_GPIOS); i++) {
|
||||
bank = &tegra_gpio_banks[GPIO_BANK(irq_to_gpio(i))];
|
||||
for (gpio = 0; gpio < TEGRA_NR_GPIOS; gpio++) {
|
||||
int irq = TEGRA_GPIO_TO_IRQ(gpio);
|
||||
/* No validity check; all Tegra GPIOs are valid IRQs */
|
||||
|
||||
irq_set_lockdep_class(i, &gpio_lock_class);
|
||||
irq_set_chip_data(i, bank);
|
||||
irq_set_chip_and_handler(i, &tegra_gpio_irq_chip,
|
||||
bank = &tegra_gpio_banks[GPIO_BANK(gpio)];
|
||||
|
||||
irq_set_lockdep_class(irq, &gpio_lock_class);
|
||||
irq_set_chip_data(irq, bank);
|
||||
irq_set_chip_and_handler(irq, &tegra_gpio_irq_chip,
|
||||
handle_simple_irq);
|
||||
set_irq_flags(i, IRQF_VALID);
|
||||
set_irq_flags(irq, IRQF_VALID);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) {
|
||||
|
205
drivers/gpio/gpio-tnetv107x.c
Normal file
205
drivers/gpio/gpio-tnetv107x.c
Normal file
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Texas Instruments TNETV107X GPIO Controller
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments
|
||||
*
|
||||
* 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 version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <mach/common.h>
|
||||
#include <mach/tnetv107x.h>
|
||||
|
||||
struct tnetv107x_gpio_regs {
|
||||
u32 idver;
|
||||
u32 data_in[3];
|
||||
u32 data_out[3];
|
||||
u32 direction[3];
|
||||
u32 enable[3];
|
||||
};
|
||||
|
||||
#define gpio_reg_index(gpio) ((gpio) >> 5)
|
||||
#define gpio_reg_bit(gpio) BIT((gpio) & 0x1f)
|
||||
|
||||
#define gpio_reg_rmw(reg, mask, val) \
|
||||
__raw_writel((__raw_readl(reg) & ~(mask)) | (val), (reg))
|
||||
|
||||
#define gpio_reg_set_bit(reg, gpio) \
|
||||
gpio_reg_rmw((reg) + gpio_reg_index(gpio), 0, gpio_reg_bit(gpio))
|
||||
|
||||
#define gpio_reg_clear_bit(reg, gpio) \
|
||||
gpio_reg_rmw((reg) + gpio_reg_index(gpio), gpio_reg_bit(gpio), 0)
|
||||
|
||||
#define gpio_reg_get_bit(reg, gpio) \
|
||||
(__raw_readl((reg) + gpio_reg_index(gpio)) & gpio_reg_bit(gpio))
|
||||
|
||||
#define chip2controller(chip) \
|
||||
container_of(chip, struct davinci_gpio_controller, chip)
|
||||
|
||||
#define TNETV107X_GPIO_CTLRS DIV_ROUND_UP(TNETV107X_N_GPIO, 32)
|
||||
|
||||
static struct davinci_gpio_controller chips[TNETV107X_GPIO_CTLRS];
|
||||
|
||||
static int tnetv107x_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct davinci_gpio_controller *ctlr = chip2controller(chip);
|
||||
struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
|
||||
unsigned gpio = chip->base + offset;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ctlr->lock, flags);
|
||||
|
||||
gpio_reg_set_bit(regs->enable, gpio);
|
||||
|
||||
spin_unlock_irqrestore(&ctlr->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tnetv107x_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct davinci_gpio_controller *ctlr = chip2controller(chip);
|
||||
struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
|
||||
unsigned gpio = chip->base + offset;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ctlr->lock, flags);
|
||||
|
||||
gpio_reg_clear_bit(regs->enable, gpio);
|
||||
|
||||
spin_unlock_irqrestore(&ctlr->lock, flags);
|
||||
}
|
||||
|
||||
static int tnetv107x_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct davinci_gpio_controller *ctlr = chip2controller(chip);
|
||||
struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
|
||||
unsigned gpio = chip->base + offset;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ctlr->lock, flags);
|
||||
|
||||
gpio_reg_set_bit(regs->direction, gpio);
|
||||
|
||||
spin_unlock_irqrestore(&ctlr->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tnetv107x_gpio_dir_out(struct gpio_chip *chip,
|
||||
unsigned offset, int value)
|
||||
{
|
||||
struct davinci_gpio_controller *ctlr = chip2controller(chip);
|
||||
struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
|
||||
unsigned gpio = chip->base + offset;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ctlr->lock, flags);
|
||||
|
||||
if (value)
|
||||
gpio_reg_set_bit(regs->data_out, gpio);
|
||||
else
|
||||
gpio_reg_clear_bit(regs->data_out, gpio);
|
||||
|
||||
gpio_reg_clear_bit(regs->direction, gpio);
|
||||
|
||||
spin_unlock_irqrestore(&ctlr->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tnetv107x_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct davinci_gpio_controller *ctlr = chip2controller(chip);
|
||||
struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
|
||||
unsigned gpio = chip->base + offset;
|
||||
int ret;
|
||||
|
||||
ret = gpio_reg_get_bit(regs->data_in, gpio);
|
||||
|
||||
return ret ? 1 : 0;
|
||||
}
|
||||
|
||||
static void tnetv107x_gpio_set(struct gpio_chip *chip,
|
||||
unsigned offset, int value)
|
||||
{
|
||||
struct davinci_gpio_controller *ctlr = chip2controller(chip);
|
||||
struct tnetv107x_gpio_regs __iomem *regs = ctlr->regs;
|
||||
unsigned gpio = chip->base + offset;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ctlr->lock, flags);
|
||||
|
||||
if (value)
|
||||
gpio_reg_set_bit(regs->data_out, gpio);
|
||||
else
|
||||
gpio_reg_clear_bit(regs->data_out, gpio);
|
||||
|
||||
spin_unlock_irqrestore(&ctlr->lock, flags);
|
||||
}
|
||||
|
||||
static int __init tnetv107x_gpio_setup(void)
|
||||
{
|
||||
int i, base;
|
||||
unsigned ngpio;
|
||||
struct davinci_soc_info *soc_info = &davinci_soc_info;
|
||||
struct tnetv107x_gpio_regs *regs;
|
||||
struct davinci_gpio_controller *ctlr;
|
||||
|
||||
if (soc_info->gpio_type != GPIO_TYPE_TNETV107X)
|
||||
return 0;
|
||||
|
||||
ngpio = soc_info->gpio_num;
|
||||
if (ngpio == 0) {
|
||||
pr_err("GPIO setup: how many GPIOs?\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (WARN_ON(TNETV107X_N_GPIO < ngpio))
|
||||
ngpio = TNETV107X_N_GPIO;
|
||||
|
||||
regs = ioremap(soc_info->gpio_base, SZ_4K);
|
||||
if (WARN_ON(!regs))
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0, base = 0; base < ngpio; i++, base += 32) {
|
||||
ctlr = &chips[i];
|
||||
|
||||
ctlr->chip.label = "tnetv107x";
|
||||
ctlr->chip.can_sleep = 0;
|
||||
ctlr->chip.base = base;
|
||||
ctlr->chip.ngpio = ngpio - base;
|
||||
if (ctlr->chip.ngpio > 32)
|
||||
ctlr->chip.ngpio = 32;
|
||||
|
||||
ctlr->chip.request = tnetv107x_gpio_request;
|
||||
ctlr->chip.free = tnetv107x_gpio_free;
|
||||
ctlr->chip.direction_input = tnetv107x_gpio_dir_in;
|
||||
ctlr->chip.get = tnetv107x_gpio_get;
|
||||
ctlr->chip.direction_output = tnetv107x_gpio_dir_out;
|
||||
ctlr->chip.set = tnetv107x_gpio_set;
|
||||
|
||||
spin_lock_init(&ctlr->lock);
|
||||
|
||||
ctlr->regs = regs;
|
||||
ctlr->set_data = ®s->data_out[i];
|
||||
ctlr->clr_data = ®s->data_out[i];
|
||||
ctlr->in_data = ®s->data_in[i];
|
||||
|
||||
gpiochip_add(&ctlr->chip);
|
||||
}
|
||||
|
||||
soc_info->gpio_ctlrs = chips;
|
||||
soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32);
|
||||
return 0;
|
||||
}
|
||||
pure_initcall(tnetv107x_gpio_setup);
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user