Merge branch 'gpio/next' of git://git.secretlab.ca/git/linux-2.6
* 'gpio/next' of git://git.secretlab.ca/git/linux-2.6: gpio/pch_gpio: Support new device ML7223 gpio: make gpio_{request,free}_array gpio array parameter const GPIO: OMAP: move to drivers/gpio GPIO: OMAP: move register offset defines into <plat/gpio.h> gpio: Convert gpio_is_valid to return bool gpio: Move the s5pc100 GPIO to drivers/gpio gpio: Move the s5pv210 GPIO to drivers/gpio gpio: Move the exynos4 GPIO to drivers/gpio gpio: Move to Samsung common GPIO library to drivers/gpio gpio/nomadik: add function to read GPIO pull down status gpio/nomadik: show all pins in debug gpio: move Nomadik GPIO driver to drivers/gpio gpio: move U300 GPIO driver to drivers/gpio langwell_gpio: add runtime pm support gpio/pca953x: Add support for pca9574 and pca9575 devices gpio/cs5535: Show explicit dependency between gpio_cs5535 and mfd_cs5535
This commit is contained in:
@@ -86,6 +86,30 @@ config GPIO_IT8761E
|
||||
help
|
||||
Say yes here to support GPIO functionality of IT8761E super I/O chip.
|
||||
|
||||
config GPIO_EXYNOS4
|
||||
bool "Samsung Exynos4 GPIO library support"
|
||||
default y if CPU_EXYNOS4210
|
||||
help
|
||||
Say yes here to support Samsung Exynos4 series SoCs GPIO library
|
||||
|
||||
config GPIO_PLAT_SAMSUNG
|
||||
bool "Samsung SoCs GPIO library support"
|
||||
default y if SAMSUNG_GPIOLIB_4BIT
|
||||
help
|
||||
Say yes here to support Samsung SoCs GPIO library
|
||||
|
||||
config GPIO_S5PC100
|
||||
bool "Samsung S5PC100 GPIO library support"
|
||||
default y if CPU_S5PC100
|
||||
help
|
||||
Say yes here to support Samsung S5PC100 SoCs GPIO library
|
||||
|
||||
config GPIO_S5PV210
|
||||
bool "Samsung S5PV210/S5PC110 GPIO library support"
|
||||
default y if CPU_S5PV210
|
||||
help
|
||||
Say yes here to support Samsung S5PV210/S5PC110 SoCs GPIO library
|
||||
|
||||
config GPIO_PL061
|
||||
bool "PrimeCell PL061 GPIO support"
|
||||
depends on ARM_AMBA
|
||||
@@ -303,7 +327,7 @@ comment "PCI GPIO expanders:"
|
||||
|
||||
config GPIO_CS5535
|
||||
tristate "AMD CS5535/CS5536 GPIO support"
|
||||
depends on PCI && X86 && !CS5535_GPIO
|
||||
depends on PCI && X86 && !CS5535_GPIO && MFD_CS5535
|
||||
help
|
||||
The AMD CS5535 and CS5536 southbridges support 28 GPIO pins that
|
||||
can be used for quite a number of things. The CS5535/6 is found on
|
||||
@@ -334,13 +358,19 @@ config GPIO_LANGWELL
|
||||
Say Y here to support Intel Langwell/Penwell GPIO.
|
||||
|
||||
config GPIO_PCH
|
||||
tristate "PCH GPIO of Intel Topcliff"
|
||||
tristate "Intel EG20T PCH / OKI SEMICONDUCTOR ML7223 IOH GPIO"
|
||||
depends on PCI && X86
|
||||
help
|
||||
This driver is for PCH(Platform controller Hub) GPIO of Intel Topcliff
|
||||
which is an IOH(Input/Output Hub) for x86 embedded processor.
|
||||
This driver can access PCH GPIO device.
|
||||
|
||||
This driver also can be used for OKI SEMICONDUCTOR IOH(Input/
|
||||
Output Hub), ML7223.
|
||||
ML7223 IOH is for MP(Media Phone) use.
|
||||
ML7223 is companion chip for Intel Atom E6xx series.
|
||||
ML7223 is completely compatible for Intel EG20T PCH.
|
||||
|
||||
config GPIO_ML_IOH
|
||||
tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support"
|
||||
depends on PCI
|
||||
|
@@ -8,6 +8,10 @@ obj-$(CONFIG_GPIO_ADP5520) += adp5520-gpio.o
|
||||
obj-$(CONFIG_GPIO_ADP5588) += adp5588-gpio.o
|
||||
obj-$(CONFIG_GPIO_BASIC_MMIO_CORE) += basic_mmio_gpio.o
|
||||
obj-$(CONFIG_GPIO_BASIC_MMIO) += basic_mmio_gpio.o
|
||||
obj-$(CONFIG_GPIO_EXYNOS4) += gpio-exynos4.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_GPIO_LANGWELL) += langwell_gpio.o
|
||||
obj-$(CONFIG_GPIO_MAX730X) += max730x.o
|
||||
obj-$(CONFIG_GPIO_MAX7300) += max7300.o
|
||||
@@ -16,6 +20,7 @@ obj-$(CONFIG_GPIO_MAX732X) += max732x.o
|
||||
obj-$(CONFIG_GPIO_MC33880) += mc33880.o
|
||||
obj-$(CONFIG_GPIO_MCP23S08) += mcp23s08.o
|
||||
obj-$(CONFIG_GPIO_74X164) += 74x164.o
|
||||
obj-$(CONFIG_ARCH_OMAP) += gpio-omap.o
|
||||
obj-$(CONFIG_GPIO_PCA953X) += pca953x.o
|
||||
obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o
|
||||
obj-$(CONFIG_GPIO_PCH) += pch_gpio.o
|
||||
@@ -34,6 +39,8 @@ obj-$(CONFIG_GPIO_WM831X) += wm831x-gpio.o
|
||||
obj-$(CONFIG_GPIO_WM8350) += wm8350-gpiolib.o
|
||||
obj-$(CONFIG_GPIO_WM8994) += wm8994-gpio.o
|
||||
obj-$(CONFIG_GPIO_SCH) += sch_gpio.o
|
||||
obj-$(CONFIG_MACH_U300) += gpio-u300.o
|
||||
obj-$(CONFIG_PLAT_NOMADIK) += gpio-nomadik.o
|
||||
obj-$(CONFIG_GPIO_RDC321X) += rdc321x-gpio.o
|
||||
obj-$(CONFIG_GPIO_JANZ_TTL) += janz-ttl.o
|
||||
obj-$(CONFIG_GPIO_SX150X) += sx150x.o
|
||||
|
365
drivers/gpio/gpio-exynos4.c
Normal file
365
drivers/gpio/gpio-exynos4.c
Normal file
@@ -0,0 +1,365 @@
|
||||
/* linux/arch/arm/mach-exynos4/gpiolib.c
|
||||
*
|
||||
* Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* EXYNOS4 - GPIOlib support
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <mach/map.h>
|
||||
|
||||
#include <plat/gpio-core.h>
|
||||
#include <plat/gpio-cfg.h>
|
||||
#include <plat/gpio-cfg-helpers.h>
|
||||
|
||||
static struct s3c_gpio_cfg gpio_cfg = {
|
||||
.set_config = s3c_gpio_setcfg_s3c64xx_4bit,
|
||||
.set_pull = s3c_gpio_setpull_updown,
|
||||
.get_pull = s3c_gpio_getpull_updown,
|
||||
};
|
||||
|
||||
static struct s3c_gpio_cfg gpio_cfg_noint = {
|
||||
.set_config = s3c_gpio_setcfg_s3c64xx_4bit,
|
||||
.set_pull = s3c_gpio_setpull_updown,
|
||||
.get_pull = s3c_gpio_getpull_updown,
|
||||
};
|
||||
|
||||
/*
|
||||
* Following are the gpio banks in v310.
|
||||
*
|
||||
* The 'config' member when left to NULL, is initialized to the default
|
||||
* structure gpio_cfg in the init function below.
|
||||
*
|
||||
* The 'base' member is also initialized in the init function below.
|
||||
* Note: The initialization of 'base' member of s3c_gpio_chip structure
|
||||
* uses the above macro and depends on the banks being listed in order here.
|
||||
*/
|
||||
static struct s3c_gpio_chip exynos4_gpio_part1_4bit[] = {
|
||||
{
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPA0(0),
|
||||
.ngpio = EXYNOS4_GPIO_A0_NR,
|
||||
.label = "GPA0",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPA1(0),
|
||||
.ngpio = EXYNOS4_GPIO_A1_NR,
|
||||
.label = "GPA1",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPB(0),
|
||||
.ngpio = EXYNOS4_GPIO_B_NR,
|
||||
.label = "GPB",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPC0(0),
|
||||
.ngpio = EXYNOS4_GPIO_C0_NR,
|
||||
.label = "GPC0",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPC1(0),
|
||||
.ngpio = EXYNOS4_GPIO_C1_NR,
|
||||
.label = "GPC1",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPD0(0),
|
||||
.ngpio = EXYNOS4_GPIO_D0_NR,
|
||||
.label = "GPD0",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPD1(0),
|
||||
.ngpio = EXYNOS4_GPIO_D1_NR,
|
||||
.label = "GPD1",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPE0(0),
|
||||
.ngpio = EXYNOS4_GPIO_E0_NR,
|
||||
.label = "GPE0",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPE1(0),
|
||||
.ngpio = EXYNOS4_GPIO_E1_NR,
|
||||
.label = "GPE1",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPE2(0),
|
||||
.ngpio = EXYNOS4_GPIO_E2_NR,
|
||||
.label = "GPE2",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPE3(0),
|
||||
.ngpio = EXYNOS4_GPIO_E3_NR,
|
||||
.label = "GPE3",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPE4(0),
|
||||
.ngpio = EXYNOS4_GPIO_E4_NR,
|
||||
.label = "GPE4",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPF0(0),
|
||||
.ngpio = EXYNOS4_GPIO_F0_NR,
|
||||
.label = "GPF0",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPF1(0),
|
||||
.ngpio = EXYNOS4_GPIO_F1_NR,
|
||||
.label = "GPF1",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPF2(0),
|
||||
.ngpio = EXYNOS4_GPIO_F2_NR,
|
||||
.label = "GPF2",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPF3(0),
|
||||
.ngpio = EXYNOS4_GPIO_F3_NR,
|
||||
.label = "GPF3",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct s3c_gpio_chip exynos4_gpio_part2_4bit[] = {
|
||||
{
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPJ0(0),
|
||||
.ngpio = EXYNOS4_GPIO_J0_NR,
|
||||
.label = "GPJ0",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPJ1(0),
|
||||
.ngpio = EXYNOS4_GPIO_J1_NR,
|
||||
.label = "GPJ1",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPK0(0),
|
||||
.ngpio = EXYNOS4_GPIO_K0_NR,
|
||||
.label = "GPK0",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPK1(0),
|
||||
.ngpio = EXYNOS4_GPIO_K1_NR,
|
||||
.label = "GPK1",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPK2(0),
|
||||
.ngpio = EXYNOS4_GPIO_K2_NR,
|
||||
.label = "GPK2",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPK3(0),
|
||||
.ngpio = EXYNOS4_GPIO_K3_NR,
|
||||
.label = "GPK3",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPL0(0),
|
||||
.ngpio = EXYNOS4_GPIO_L0_NR,
|
||||
.label = "GPL0",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPL1(0),
|
||||
.ngpio = EXYNOS4_GPIO_L1_NR,
|
||||
.label = "GPL1",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPL2(0),
|
||||
.ngpio = EXYNOS4_GPIO_L2_NR,
|
||||
.label = "GPL2",
|
||||
},
|
||||
}, {
|
||||
.config = &gpio_cfg_noint,
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPY0(0),
|
||||
.ngpio = EXYNOS4_GPIO_Y0_NR,
|
||||
.label = "GPY0",
|
||||
},
|
||||
}, {
|
||||
.config = &gpio_cfg_noint,
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPY1(0),
|
||||
.ngpio = EXYNOS4_GPIO_Y1_NR,
|
||||
.label = "GPY1",
|
||||
},
|
||||
}, {
|
||||
.config = &gpio_cfg_noint,
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPY2(0),
|
||||
.ngpio = EXYNOS4_GPIO_Y2_NR,
|
||||
.label = "GPY2",
|
||||
},
|
||||
}, {
|
||||
.config = &gpio_cfg_noint,
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPY3(0),
|
||||
.ngpio = EXYNOS4_GPIO_Y3_NR,
|
||||
.label = "GPY3",
|
||||
},
|
||||
}, {
|
||||
.config = &gpio_cfg_noint,
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPY4(0),
|
||||
.ngpio = EXYNOS4_GPIO_Y4_NR,
|
||||
.label = "GPY4",
|
||||
},
|
||||
}, {
|
||||
.config = &gpio_cfg_noint,
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPY5(0),
|
||||
.ngpio = EXYNOS4_GPIO_Y5_NR,
|
||||
.label = "GPY5",
|
||||
},
|
||||
}, {
|
||||
.config = &gpio_cfg_noint,
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPY6(0),
|
||||
.ngpio = EXYNOS4_GPIO_Y6_NR,
|
||||
.label = "GPY6",
|
||||
},
|
||||
}, {
|
||||
.base = (S5P_VA_GPIO2 + 0xC00),
|
||||
.config = &gpio_cfg_noint,
|
||||
.irq_base = IRQ_EINT(0),
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPX0(0),
|
||||
.ngpio = EXYNOS4_GPIO_X0_NR,
|
||||
.label = "GPX0",
|
||||
.to_irq = samsung_gpiolib_to_irq,
|
||||
},
|
||||
}, {
|
||||
.base = (S5P_VA_GPIO2 + 0xC20),
|
||||
.config = &gpio_cfg_noint,
|
||||
.irq_base = IRQ_EINT(8),
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPX1(0),
|
||||
.ngpio = EXYNOS4_GPIO_X1_NR,
|
||||
.label = "GPX1",
|
||||
.to_irq = samsung_gpiolib_to_irq,
|
||||
},
|
||||
}, {
|
||||
.base = (S5P_VA_GPIO2 + 0xC40),
|
||||
.config = &gpio_cfg_noint,
|
||||
.irq_base = IRQ_EINT(16),
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPX2(0),
|
||||
.ngpio = EXYNOS4_GPIO_X2_NR,
|
||||
.label = "GPX2",
|
||||
.to_irq = samsung_gpiolib_to_irq,
|
||||
},
|
||||
}, {
|
||||
.base = (S5P_VA_GPIO2 + 0xC60),
|
||||
.config = &gpio_cfg_noint,
|
||||
.irq_base = IRQ_EINT(24),
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPX3(0),
|
||||
.ngpio = EXYNOS4_GPIO_X3_NR,
|
||||
.label = "GPX3",
|
||||
.to_irq = samsung_gpiolib_to_irq,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct s3c_gpio_chip exynos4_gpio_part3_4bit[] = {
|
||||
{
|
||||
.chip = {
|
||||
.base = EXYNOS4_GPZ(0),
|
||||
.ngpio = EXYNOS4_GPIO_Z_NR,
|
||||
.label = "GPZ",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static __init int exynos4_gpiolib_init(void)
|
||||
{
|
||||
struct s3c_gpio_chip *chip;
|
||||
int i;
|
||||
int group = 0;
|
||||
int nr_chips;
|
||||
|
||||
/* GPIO part 1 */
|
||||
|
||||
chip = exynos4_gpio_part1_4bit;
|
||||
nr_chips = ARRAY_SIZE(exynos4_gpio_part1_4bit);
|
||||
|
||||
for (i = 0; i < nr_chips; i++, chip++) {
|
||||
if (chip->config == NULL) {
|
||||
chip->config = &gpio_cfg;
|
||||
/* Assign the GPIO interrupt group */
|
||||
chip->group = group++;
|
||||
}
|
||||
if (chip->base == NULL)
|
||||
chip->base = S5P_VA_GPIO1 + (i) * 0x20;
|
||||
}
|
||||
|
||||
samsung_gpiolib_add_4bit_chips(exynos4_gpio_part1_4bit, nr_chips);
|
||||
|
||||
/* GPIO part 2 */
|
||||
|
||||
chip = exynos4_gpio_part2_4bit;
|
||||
nr_chips = ARRAY_SIZE(exynos4_gpio_part2_4bit);
|
||||
|
||||
for (i = 0; i < nr_chips; i++, chip++) {
|
||||
if (chip->config == NULL) {
|
||||
chip->config = &gpio_cfg;
|
||||
/* Assign the GPIO interrupt group */
|
||||
chip->group = group++;
|
||||
}
|
||||
if (chip->base == NULL)
|
||||
chip->base = S5P_VA_GPIO2 + (i) * 0x20;
|
||||
}
|
||||
|
||||
samsung_gpiolib_add_4bit_chips(exynos4_gpio_part2_4bit, nr_chips);
|
||||
|
||||
/* GPIO part 3 */
|
||||
|
||||
chip = exynos4_gpio_part3_4bit;
|
||||
nr_chips = ARRAY_SIZE(exynos4_gpio_part3_4bit);
|
||||
|
||||
for (i = 0; i < nr_chips; i++, chip++) {
|
||||
if (chip->config == NULL) {
|
||||
chip->config = &gpio_cfg;
|
||||
/* Assign the GPIO interrupt group */
|
||||
chip->group = group++;
|
||||
}
|
||||
if (chip->base == NULL)
|
||||
chip->base = S5P_VA_GPIO3 + (i) * 0x20;
|
||||
}
|
||||
|
||||
samsung_gpiolib_add_4bit_chips(exynos4_gpio_part3_4bit, nr_chips);
|
||||
s5p_register_gpioint_bank(IRQ_GPIO_XA, 0, IRQ_GPIO1_NR_GROUPS);
|
||||
s5p_register_gpioint_bank(IRQ_GPIO_XB, IRQ_GPIO1_NR_GROUPS, IRQ_GPIO2_NR_GROUPS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
core_initcall(exynos4_gpiolib_init);
|
1069
drivers/gpio/gpio-nomadik.c
Normal file
1069
drivers/gpio/gpio-nomadik.c
Normal file
Diff onderdrukt omdat het te groot bestand
Laad Diff
2007
drivers/gpio/gpio-omap.c
Normal file
2007
drivers/gpio/gpio-omap.c
Normal file
Diff onderdrukt omdat het te groot bestand
Laad Diff
206
drivers/gpio/gpio-plat-samsung.c
Normal file
206
drivers/gpio/gpio-plat-samsung.c
Normal file
@@ -0,0 +1,206 @@
|
||||
/* arch/arm/plat-samsung/gpiolib.c
|
||||
*
|
||||
* Copyright 2008 Openmoko, Inc.
|
||||
* Copyright 2008 Simtec Electronics
|
||||
* Ben Dooks <ben@simtec.co.uk>
|
||||
* http://armlinux.simtec.co.uk/
|
||||
*
|
||||
* Copyright (c) 2009 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com/
|
||||
*
|
||||
* SAMSUNG - GPIOlib support
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <plat/gpio-core.h>
|
||||
#include <plat/gpio-cfg.h>
|
||||
#include <plat/gpio-cfg-helpers.h>
|
||||
|
||||
#ifndef DEBUG_GPIO
|
||||
#define gpio_dbg(x...) do { } while (0)
|
||||
#else
|
||||
#define gpio_dbg(x...) printk(KERN_DEBUG x)
|
||||
#endif
|
||||
|
||||
/* The samsung_gpiolib_4bit routines are to control the gpio banks where
|
||||
* the gpio configuration register (GPxCON) has 4 bits per GPIO, as the
|
||||
* following example:
|
||||
*
|
||||
* base + 0x00: Control register, 4 bits per gpio
|
||||
* gpio n: 4 bits starting at (4*n)
|
||||
* 0000 = input, 0001 = output, others mean special-function
|
||||
* base + 0x04: Data register, 1 bit per gpio
|
||||
* bit n: data bit n
|
||||
*
|
||||
* Note, since the data register is one bit per gpio and is at base + 0x4
|
||||
* we can use s3c_gpiolib_get and s3c_gpiolib_set to change the state of
|
||||
* the output.
|
||||
*/
|
||||
|
||||
static int samsung_gpiolib_4bit_input(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
|
||||
void __iomem *base = ourchip->base;
|
||||
unsigned long con;
|
||||
|
||||
con = __raw_readl(base + GPIOCON_OFF);
|
||||
con &= ~(0xf << con_4bit_shift(offset));
|
||||
__raw_writel(con, base + GPIOCON_OFF);
|
||||
|
||||
gpio_dbg("%s: %p: CON now %08lx\n", __func__, base, con);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int samsung_gpiolib_4bit_output(struct gpio_chip *chip,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
|
||||
void __iomem *base = ourchip->base;
|
||||
unsigned long con;
|
||||
unsigned long dat;
|
||||
|
||||
con = __raw_readl(base + GPIOCON_OFF);
|
||||
con &= ~(0xf << con_4bit_shift(offset));
|
||||
con |= 0x1 << con_4bit_shift(offset);
|
||||
|
||||
dat = __raw_readl(base + GPIODAT_OFF);
|
||||
|
||||
if (value)
|
||||
dat |= 1 << offset;
|
||||
else
|
||||
dat &= ~(1 << offset);
|
||||
|
||||
__raw_writel(dat, base + GPIODAT_OFF);
|
||||
__raw_writel(con, base + GPIOCON_OFF);
|
||||
__raw_writel(dat, base + GPIODAT_OFF);
|
||||
|
||||
gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The next set of routines are for the case where the GPIO configuration
|
||||
* registers are 4 bits per GPIO but there is more than one register (the
|
||||
* bank has more than 8 GPIOs.
|
||||
*
|
||||
* This case is the similar to the 4 bit case, but the registers are as
|
||||
* follows:
|
||||
*
|
||||
* base + 0x00: Control register, 4 bits per gpio (lower 8 GPIOs)
|
||||
* gpio n: 4 bits starting at (4*n)
|
||||
* 0000 = input, 0001 = output, others mean special-function
|
||||
* base + 0x04: Control register, 4 bits per gpio (up to 8 additions GPIOs)
|
||||
* gpio n: 4 bits starting at (4*n)
|
||||
* 0000 = input, 0001 = output, others mean special-function
|
||||
* base + 0x08: Data register, 1 bit per gpio
|
||||
* bit n: data bit n
|
||||
*
|
||||
* To allow us to use the s3c_gpiolib_get and s3c_gpiolib_set routines we
|
||||
* store the 'base + 0x4' address so that these routines see the data
|
||||
* register at ourchip->base + 0x04.
|
||||
*/
|
||||
|
||||
static int samsung_gpiolib_4bit2_input(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
|
||||
void __iomem *base = ourchip->base;
|
||||
void __iomem *regcon = base;
|
||||
unsigned long con;
|
||||
|
||||
if (offset > 7)
|
||||
offset -= 8;
|
||||
else
|
||||
regcon -= 4;
|
||||
|
||||
con = __raw_readl(regcon);
|
||||
con &= ~(0xf << con_4bit_shift(offset));
|
||||
__raw_writel(con, regcon);
|
||||
|
||||
gpio_dbg("%s: %p: CON %08lx\n", __func__, base, con);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int samsung_gpiolib_4bit2_output(struct gpio_chip *chip,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
|
||||
void __iomem *base = ourchip->base;
|
||||
void __iomem *regcon = base;
|
||||
unsigned long con;
|
||||
unsigned long dat;
|
||||
unsigned con_offset = offset;
|
||||
|
||||
if (con_offset > 7)
|
||||
con_offset -= 8;
|
||||
else
|
||||
regcon -= 4;
|
||||
|
||||
con = __raw_readl(regcon);
|
||||
con &= ~(0xf << con_4bit_shift(con_offset));
|
||||
con |= 0x1 << con_4bit_shift(con_offset);
|
||||
|
||||
dat = __raw_readl(base + GPIODAT_OFF);
|
||||
|
||||
if (value)
|
||||
dat |= 1 << offset;
|
||||
else
|
||||
dat &= ~(1 << offset);
|
||||
|
||||
__raw_writel(dat, base + GPIODAT_OFF);
|
||||
__raw_writel(con, regcon);
|
||||
__raw_writel(dat, base + GPIODAT_OFF);
|
||||
|
||||
gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __init samsung_gpiolib_add_4bit(struct s3c_gpio_chip *chip)
|
||||
{
|
||||
chip->chip.direction_input = samsung_gpiolib_4bit_input;
|
||||
chip->chip.direction_output = samsung_gpiolib_4bit_output;
|
||||
chip->pm = __gpio_pm(&s3c_gpio_pm_4bit);
|
||||
}
|
||||
|
||||
void __init samsung_gpiolib_add_4bit2(struct s3c_gpio_chip *chip)
|
||||
{
|
||||
chip->chip.direction_input = samsung_gpiolib_4bit2_input;
|
||||
chip->chip.direction_output = samsung_gpiolib_4bit2_output;
|
||||
chip->pm = __gpio_pm(&s3c_gpio_pm_4bit);
|
||||
}
|
||||
|
||||
void __init samsung_gpiolib_add_4bit_chips(struct s3c_gpio_chip *chip,
|
||||
int nr_chips)
|
||||
{
|
||||
for (; nr_chips > 0; nr_chips--, chip++) {
|
||||
samsung_gpiolib_add_4bit(chip);
|
||||
s3c_gpiolib_add(chip);
|
||||
}
|
||||
}
|
||||
|
||||
void __init samsung_gpiolib_add_4bit2_chips(struct s3c_gpio_chip *chip,
|
||||
int nr_chips)
|
||||
{
|
||||
for (; nr_chips > 0; nr_chips--, chip++) {
|
||||
samsung_gpiolib_add_4bit2(chip);
|
||||
s3c_gpiolib_add(chip);
|
||||
}
|
||||
}
|
||||
|
||||
void __init samsung_gpiolib_add_2bit_chips(struct s3c_gpio_chip *chip,
|
||||
int nr_chips)
|
||||
{
|
||||
for (; nr_chips > 0; nr_chips--, chip++)
|
||||
s3c_gpiolib_add(chip);
|
||||
}
|
355
drivers/gpio/gpio-s5pc100.c
Normal file
355
drivers/gpio/gpio-s5pc100.c
Normal file
@@ -0,0 +1,355 @@
|
||||
/* linux/arch/arm/mach-s5pc100/gpiolib.c
|
||||
*
|
||||
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Copyright 2009 Samsung Electronics Co
|
||||
* Kyungmin Park <kyungmin.park@samsung.com>
|
||||
*
|
||||
* S5PC100 - GPIOlib support
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <mach/map.h>
|
||||
#include <mach/regs-gpio.h>
|
||||
|
||||
#include <plat/gpio-core.h>
|
||||
#include <plat/gpio-cfg.h>
|
||||
#include <plat/gpio-cfg-helpers.h>
|
||||
|
||||
/* S5PC100 GPIO bank summary:
|
||||
*
|
||||
* Bank GPIOs Style INT Type
|
||||
* A0 8 4Bit GPIO_INT0
|
||||
* A1 5 4Bit GPIO_INT1
|
||||
* B 8 4Bit GPIO_INT2
|
||||
* C 5 4Bit GPIO_INT3
|
||||
* D 7 4Bit GPIO_INT4
|
||||
* E0 8 4Bit GPIO_INT5
|
||||
* E1 6 4Bit GPIO_INT6
|
||||
* F0 8 4Bit GPIO_INT7
|
||||
* F1 8 4Bit GPIO_INT8
|
||||
* F2 8 4Bit GPIO_INT9
|
||||
* F3 4 4Bit GPIO_INT10
|
||||
* G0 8 4Bit GPIO_INT11
|
||||
* G1 3 4Bit GPIO_INT12
|
||||
* G2 7 4Bit GPIO_INT13
|
||||
* G3 7 4Bit GPIO_INT14
|
||||
* H0 8 4Bit WKUP_INT
|
||||
* H1 8 4Bit WKUP_INT
|
||||
* H2 8 4Bit WKUP_INT
|
||||
* H3 8 4Bit WKUP_INT
|
||||
* I 8 4Bit GPIO_INT15
|
||||
* J0 8 4Bit GPIO_INT16
|
||||
* J1 5 4Bit GPIO_INT17
|
||||
* J2 8 4Bit GPIO_INT18
|
||||
* J3 8 4Bit GPIO_INT19
|
||||
* J4 4 4Bit GPIO_INT20
|
||||
* K0 8 4Bit None
|
||||
* K1 6 4Bit None
|
||||
* K2 8 4Bit None
|
||||
* K3 8 4Bit None
|
||||
* L0 8 4Bit None
|
||||
* L1 8 4Bit None
|
||||
* L2 8 4Bit None
|
||||
* L3 8 4Bit None
|
||||
*/
|
||||
|
||||
static struct s3c_gpio_cfg gpio_cfg = {
|
||||
.set_config = s3c_gpio_setcfg_s3c64xx_4bit,
|
||||
.set_pull = s3c_gpio_setpull_updown,
|
||||
.get_pull = s3c_gpio_getpull_updown,
|
||||
};
|
||||
|
||||
static struct s3c_gpio_cfg gpio_cfg_eint = {
|
||||
.cfg_eint = 0xf,
|
||||
.set_config = s3c_gpio_setcfg_s3c64xx_4bit,
|
||||
.set_pull = s3c_gpio_setpull_updown,
|
||||
.get_pull = s3c_gpio_getpull_updown,
|
||||
};
|
||||
|
||||
static struct s3c_gpio_cfg gpio_cfg_noint = {
|
||||
.set_config = s3c_gpio_setcfg_s3c64xx_4bit,
|
||||
.set_pull = s3c_gpio_setpull_updown,
|
||||
.get_pull = s3c_gpio_getpull_updown,
|
||||
};
|
||||
|
||||
/*
|
||||
* GPIO bank's base address given the index of the bank in the
|
||||
* list of all gpio banks.
|
||||
*/
|
||||
#define S5PC100_BANK_BASE(bank_nr) (S5P_VA_GPIO + ((bank_nr) * 0x20))
|
||||
|
||||
/*
|
||||
* Following are the gpio banks in S5PC100.
|
||||
*
|
||||
* The 'config' member when left to NULL, is initialized to the default
|
||||
* structure gpio_cfg in the init function below.
|
||||
*
|
||||
* The 'base' member is also initialized in the init function below.
|
||||
* Note: The initialization of 'base' member of s3c_gpio_chip structure
|
||||
* uses the above macro and depends on the banks being listed in order here.
|
||||
*/
|
||||
static struct s3c_gpio_chip s5pc100_gpio_chips[] = {
|
||||
{
|
||||
.chip = {
|
||||
.base = S5PC100_GPA0(0),
|
||||
.ngpio = S5PC100_GPIO_A0_NR,
|
||||
.label = "GPA0",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PC100_GPA1(0),
|
||||
.ngpio = S5PC100_GPIO_A1_NR,
|
||||
.label = "GPA1",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PC100_GPB(0),
|
||||
.ngpio = S5PC100_GPIO_B_NR,
|
||||
.label = "GPB",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PC100_GPC(0),
|
||||
.ngpio = S5PC100_GPIO_C_NR,
|
||||
.label = "GPC",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PC100_GPD(0),
|
||||
.ngpio = S5PC100_GPIO_D_NR,
|
||||
.label = "GPD",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PC100_GPE0(0),
|
||||
.ngpio = S5PC100_GPIO_E0_NR,
|
||||
.label = "GPE0",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PC100_GPE1(0),
|
||||
.ngpio = S5PC100_GPIO_E1_NR,
|
||||
.label = "GPE1",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PC100_GPF0(0),
|
||||
.ngpio = S5PC100_GPIO_F0_NR,
|
||||
.label = "GPF0",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PC100_GPF1(0),
|
||||
.ngpio = S5PC100_GPIO_F1_NR,
|
||||
.label = "GPF1",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PC100_GPF2(0),
|
||||
.ngpio = S5PC100_GPIO_F2_NR,
|
||||
.label = "GPF2",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PC100_GPF3(0),
|
||||
.ngpio = S5PC100_GPIO_F3_NR,
|
||||
.label = "GPF3",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PC100_GPG0(0),
|
||||
.ngpio = S5PC100_GPIO_G0_NR,
|
||||
.label = "GPG0",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PC100_GPG1(0),
|
||||
.ngpio = S5PC100_GPIO_G1_NR,
|
||||
.label = "GPG1",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PC100_GPG2(0),
|
||||
.ngpio = S5PC100_GPIO_G2_NR,
|
||||
.label = "GPG2",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PC100_GPG3(0),
|
||||
.ngpio = S5PC100_GPIO_G3_NR,
|
||||
.label = "GPG3",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PC100_GPI(0),
|
||||
.ngpio = S5PC100_GPIO_I_NR,
|
||||
.label = "GPI",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PC100_GPJ0(0),
|
||||
.ngpio = S5PC100_GPIO_J0_NR,
|
||||
.label = "GPJ0",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PC100_GPJ1(0),
|
||||
.ngpio = S5PC100_GPIO_J1_NR,
|
||||
.label = "GPJ1",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PC100_GPJ2(0),
|
||||
.ngpio = S5PC100_GPIO_J2_NR,
|
||||
.label = "GPJ2",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PC100_GPJ3(0),
|
||||
.ngpio = S5PC100_GPIO_J3_NR,
|
||||
.label = "GPJ3",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PC100_GPJ4(0),
|
||||
.ngpio = S5PC100_GPIO_J4_NR,
|
||||
.label = "GPJ4",
|
||||
},
|
||||
}, {
|
||||
.config = &gpio_cfg_noint,
|
||||
.chip = {
|
||||
.base = S5PC100_GPK0(0),
|
||||
.ngpio = S5PC100_GPIO_K0_NR,
|
||||
.label = "GPK0",
|
||||
},
|
||||
}, {
|
||||
.config = &gpio_cfg_noint,
|
||||
.chip = {
|
||||
.base = S5PC100_GPK1(0),
|
||||
.ngpio = S5PC100_GPIO_K1_NR,
|
||||
.label = "GPK1",
|
||||
},
|
||||
}, {
|
||||
.config = &gpio_cfg_noint,
|
||||
.chip = {
|
||||
.base = S5PC100_GPK2(0),
|
||||
.ngpio = S5PC100_GPIO_K2_NR,
|
||||
.label = "GPK2",
|
||||
},
|
||||
}, {
|
||||
.config = &gpio_cfg_noint,
|
||||
.chip = {
|
||||
.base = S5PC100_GPK3(0),
|
||||
.ngpio = S5PC100_GPIO_K3_NR,
|
||||
.label = "GPK3",
|
||||
},
|
||||
}, {
|
||||
.config = &gpio_cfg_noint,
|
||||
.chip = {
|
||||
.base = S5PC100_GPL0(0),
|
||||
.ngpio = S5PC100_GPIO_L0_NR,
|
||||
.label = "GPL0",
|
||||
},
|
||||
}, {
|
||||
.config = &gpio_cfg_noint,
|
||||
.chip = {
|
||||
.base = S5PC100_GPL1(0),
|
||||
.ngpio = S5PC100_GPIO_L1_NR,
|
||||
.label = "GPL1",
|
||||
},
|
||||
}, {
|
||||
.config = &gpio_cfg_noint,
|
||||
.chip = {
|
||||
.base = S5PC100_GPL2(0),
|
||||
.ngpio = S5PC100_GPIO_L2_NR,
|
||||
.label = "GPL2",
|
||||
},
|
||||
}, {
|
||||
.config = &gpio_cfg_noint,
|
||||
.chip = {
|
||||
.base = S5PC100_GPL3(0),
|
||||
.ngpio = S5PC100_GPIO_L3_NR,
|
||||
.label = "GPL3",
|
||||
},
|
||||
}, {
|
||||
.config = &gpio_cfg_noint,
|
||||
.chip = {
|
||||
.base = S5PC100_GPL4(0),
|
||||
.ngpio = S5PC100_GPIO_L4_NR,
|
||||
.label = "GPL4",
|
||||
},
|
||||
}, {
|
||||
.base = (S5P_VA_GPIO + 0xC00),
|
||||
.config = &gpio_cfg_eint,
|
||||
.irq_base = IRQ_EINT(0),
|
||||
.chip = {
|
||||
.base = S5PC100_GPH0(0),
|
||||
.ngpio = S5PC100_GPIO_H0_NR,
|
||||
.label = "GPH0",
|
||||
.to_irq = samsung_gpiolib_to_irq,
|
||||
},
|
||||
}, {
|
||||
.base = (S5P_VA_GPIO + 0xC20),
|
||||
.config = &gpio_cfg_eint,
|
||||
.irq_base = IRQ_EINT(8),
|
||||
.chip = {
|
||||
.base = S5PC100_GPH1(0),
|
||||
.ngpio = S5PC100_GPIO_H1_NR,
|
||||
.label = "GPH1",
|
||||
.to_irq = samsung_gpiolib_to_irq,
|
||||
},
|
||||
}, {
|
||||
.base = (S5P_VA_GPIO + 0xC40),
|
||||
.config = &gpio_cfg_eint,
|
||||
.irq_base = IRQ_EINT(16),
|
||||
.chip = {
|
||||
.base = S5PC100_GPH2(0),
|
||||
.ngpio = S5PC100_GPIO_H2_NR,
|
||||
.label = "GPH2",
|
||||
.to_irq = samsung_gpiolib_to_irq,
|
||||
},
|
||||
}, {
|
||||
.base = (S5P_VA_GPIO + 0xC60),
|
||||
.config = &gpio_cfg_eint,
|
||||
.irq_base = IRQ_EINT(24),
|
||||
.chip = {
|
||||
.base = S5PC100_GPH3(0),
|
||||
.ngpio = S5PC100_GPIO_H3_NR,
|
||||
.label = "GPH3",
|
||||
.to_irq = samsung_gpiolib_to_irq,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static __init int s5pc100_gpiolib_init(void)
|
||||
{
|
||||
struct s3c_gpio_chip *chip = s5pc100_gpio_chips;
|
||||
int nr_chips = ARRAY_SIZE(s5pc100_gpio_chips);
|
||||
int gpioint_group = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nr_chips; i++, chip++) {
|
||||
if (chip->config == NULL) {
|
||||
chip->config = &gpio_cfg;
|
||||
chip->group = gpioint_group++;
|
||||
}
|
||||
if (chip->base == NULL)
|
||||
chip->base = S5PC100_BANK_BASE(i);
|
||||
}
|
||||
|
||||
samsung_gpiolib_add_4bit_chips(s5pc100_gpio_chips, nr_chips);
|
||||
s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
core_initcall(s5pc100_gpiolib_init);
|
288
drivers/gpio/gpio-s5pv210.c
Normal file
288
drivers/gpio/gpio-s5pv210.c
Normal file
@@ -0,0 +1,288 @@
|
||||
/* linux/arch/arm/mach-s5pv210/gpiolib.c
|
||||
*
|
||||
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com/
|
||||
*
|
||||
* S5PV210 - GPIOlib support
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <plat/gpio-core.h>
|
||||
#include <plat/gpio-cfg.h>
|
||||
#include <plat/gpio-cfg-helpers.h>
|
||||
#include <mach/map.h>
|
||||
|
||||
static struct s3c_gpio_cfg gpio_cfg = {
|
||||
.set_config = s3c_gpio_setcfg_s3c64xx_4bit,
|
||||
.set_pull = s3c_gpio_setpull_updown,
|
||||
.get_pull = s3c_gpio_getpull_updown,
|
||||
};
|
||||
|
||||
static struct s3c_gpio_cfg gpio_cfg_noint = {
|
||||
.set_config = s3c_gpio_setcfg_s3c64xx_4bit,
|
||||
.set_pull = s3c_gpio_setpull_updown,
|
||||
.get_pull = s3c_gpio_getpull_updown,
|
||||
};
|
||||
|
||||
/* GPIO bank's base address given the index of the bank in the
|
||||
* list of all gpio banks.
|
||||
*/
|
||||
#define S5PV210_BANK_BASE(bank_nr) (S5P_VA_GPIO + ((bank_nr) * 0x20))
|
||||
|
||||
/*
|
||||
* Following are the gpio banks in v210.
|
||||
*
|
||||
* The 'config' member when left to NULL, is initialized to the default
|
||||
* structure gpio_cfg in the init function below.
|
||||
*
|
||||
* The 'base' member is also initialized in the init function below.
|
||||
* Note: The initialization of 'base' member of s3c_gpio_chip structure
|
||||
* uses the above macro and depends on the banks being listed in order here.
|
||||
*/
|
||||
static struct s3c_gpio_chip s5pv210_gpio_4bit[] = {
|
||||
{
|
||||
.chip = {
|
||||
.base = S5PV210_GPA0(0),
|
||||
.ngpio = S5PV210_GPIO_A0_NR,
|
||||
.label = "GPA0",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PV210_GPA1(0),
|
||||
.ngpio = S5PV210_GPIO_A1_NR,
|
||||
.label = "GPA1",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PV210_GPB(0),
|
||||
.ngpio = S5PV210_GPIO_B_NR,
|
||||
.label = "GPB",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PV210_GPC0(0),
|
||||
.ngpio = S5PV210_GPIO_C0_NR,
|
||||
.label = "GPC0",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PV210_GPC1(0),
|
||||
.ngpio = S5PV210_GPIO_C1_NR,
|
||||
.label = "GPC1",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PV210_GPD0(0),
|
||||
.ngpio = S5PV210_GPIO_D0_NR,
|
||||
.label = "GPD0",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PV210_GPD1(0),
|
||||
.ngpio = S5PV210_GPIO_D1_NR,
|
||||
.label = "GPD1",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PV210_GPE0(0),
|
||||
.ngpio = S5PV210_GPIO_E0_NR,
|
||||
.label = "GPE0",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PV210_GPE1(0),
|
||||
.ngpio = S5PV210_GPIO_E1_NR,
|
||||
.label = "GPE1",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PV210_GPF0(0),
|
||||
.ngpio = S5PV210_GPIO_F0_NR,
|
||||
.label = "GPF0",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PV210_GPF1(0),
|
||||
.ngpio = S5PV210_GPIO_F1_NR,
|
||||
.label = "GPF1",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PV210_GPF2(0),
|
||||
.ngpio = S5PV210_GPIO_F2_NR,
|
||||
.label = "GPF2",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PV210_GPF3(0),
|
||||
.ngpio = S5PV210_GPIO_F3_NR,
|
||||
.label = "GPF3",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PV210_GPG0(0),
|
||||
.ngpio = S5PV210_GPIO_G0_NR,
|
||||
.label = "GPG0",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PV210_GPG1(0),
|
||||
.ngpio = S5PV210_GPIO_G1_NR,
|
||||
.label = "GPG1",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PV210_GPG2(0),
|
||||
.ngpio = S5PV210_GPIO_G2_NR,
|
||||
.label = "GPG2",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PV210_GPG3(0),
|
||||
.ngpio = S5PV210_GPIO_G3_NR,
|
||||
.label = "GPG3",
|
||||
},
|
||||
}, {
|
||||
.config = &gpio_cfg_noint,
|
||||
.chip = {
|
||||
.base = S5PV210_GPI(0),
|
||||
.ngpio = S5PV210_GPIO_I_NR,
|
||||
.label = "GPI",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PV210_GPJ0(0),
|
||||
.ngpio = S5PV210_GPIO_J0_NR,
|
||||
.label = "GPJ0",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PV210_GPJ1(0),
|
||||
.ngpio = S5PV210_GPIO_J1_NR,
|
||||
.label = "GPJ1",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PV210_GPJ2(0),
|
||||
.ngpio = S5PV210_GPIO_J2_NR,
|
||||
.label = "GPJ2",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PV210_GPJ3(0),
|
||||
.ngpio = S5PV210_GPIO_J3_NR,
|
||||
.label = "GPJ3",
|
||||
},
|
||||
}, {
|
||||
.chip = {
|
||||
.base = S5PV210_GPJ4(0),
|
||||
.ngpio = S5PV210_GPIO_J4_NR,
|
||||
.label = "GPJ4",
|
||||
},
|
||||
}, {
|
||||
.config = &gpio_cfg_noint,
|
||||
.chip = {
|
||||
.base = S5PV210_MP01(0),
|
||||
.ngpio = S5PV210_GPIO_MP01_NR,
|
||||
.label = "MP01",
|
||||
},
|
||||
}, {
|
||||
.config = &gpio_cfg_noint,
|
||||
.chip = {
|
||||
.base = S5PV210_MP02(0),
|
||||
.ngpio = S5PV210_GPIO_MP02_NR,
|
||||
.label = "MP02",
|
||||
},
|
||||
}, {
|
||||
.config = &gpio_cfg_noint,
|
||||
.chip = {
|
||||
.base = S5PV210_MP03(0),
|
||||
.ngpio = S5PV210_GPIO_MP03_NR,
|
||||
.label = "MP03",
|
||||
},
|
||||
}, {
|
||||
.config = &gpio_cfg_noint,
|
||||
.chip = {
|
||||
.base = S5PV210_MP04(0),
|
||||
.ngpio = S5PV210_GPIO_MP04_NR,
|
||||
.label = "MP04",
|
||||
},
|
||||
}, {
|
||||
.config = &gpio_cfg_noint,
|
||||
.chip = {
|
||||
.base = S5PV210_MP05(0),
|
||||
.ngpio = S5PV210_GPIO_MP05_NR,
|
||||
.label = "MP05",
|
||||
},
|
||||
}, {
|
||||
.base = (S5P_VA_GPIO + 0xC00),
|
||||
.config = &gpio_cfg_noint,
|
||||
.irq_base = IRQ_EINT(0),
|
||||
.chip = {
|
||||
.base = S5PV210_GPH0(0),
|
||||
.ngpio = S5PV210_GPIO_H0_NR,
|
||||
.label = "GPH0",
|
||||
.to_irq = samsung_gpiolib_to_irq,
|
||||
},
|
||||
}, {
|
||||
.base = (S5P_VA_GPIO + 0xC20),
|
||||
.config = &gpio_cfg_noint,
|
||||
.irq_base = IRQ_EINT(8),
|
||||
.chip = {
|
||||
.base = S5PV210_GPH1(0),
|
||||
.ngpio = S5PV210_GPIO_H1_NR,
|
||||
.label = "GPH1",
|
||||
.to_irq = samsung_gpiolib_to_irq,
|
||||
},
|
||||
}, {
|
||||
.base = (S5P_VA_GPIO + 0xC40),
|
||||
.config = &gpio_cfg_noint,
|
||||
.irq_base = IRQ_EINT(16),
|
||||
.chip = {
|
||||
.base = S5PV210_GPH2(0),
|
||||
.ngpio = S5PV210_GPIO_H2_NR,
|
||||
.label = "GPH2",
|
||||
.to_irq = samsung_gpiolib_to_irq,
|
||||
},
|
||||
}, {
|
||||
.base = (S5P_VA_GPIO + 0xC60),
|
||||
.config = &gpio_cfg_noint,
|
||||
.irq_base = IRQ_EINT(24),
|
||||
.chip = {
|
||||
.base = S5PV210_GPH3(0),
|
||||
.ngpio = S5PV210_GPIO_H3_NR,
|
||||
.label = "GPH3",
|
||||
.to_irq = samsung_gpiolib_to_irq,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static __init int s5pv210_gpiolib_init(void)
|
||||
{
|
||||
struct s3c_gpio_chip *chip = s5pv210_gpio_4bit;
|
||||
int nr_chips = ARRAY_SIZE(s5pv210_gpio_4bit);
|
||||
int gpioint_group = 0;
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < nr_chips; i++, chip++) {
|
||||
if (chip->config == NULL) {
|
||||
chip->config = &gpio_cfg;
|
||||
chip->group = gpioint_group++;
|
||||
}
|
||||
if (chip->base == NULL)
|
||||
chip->base = S5PV210_BANK_BASE(i);
|
||||
}
|
||||
|
||||
samsung_gpiolib_add_4bit_chips(s5pv210_gpio_4bit, nr_chips);
|
||||
s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
core_initcall(s5pv210_gpiolib_init);
|
700
drivers/gpio/gpio-u300.c
Normal file
700
drivers/gpio/gpio-u300.c
Normal file
@@ -0,0 +1,700 @@
|
||||
/*
|
||||
*
|
||||
* arch/arm/mach-u300/gpio.c
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2007-2009 ST-Ericsson AB
|
||||
* License terms: GNU General Public License (GPL) version 2
|
||||
* U300 GPIO module.
|
||||
* This can driver either of the two basic GPIO cores
|
||||
* available in the U300 platforms:
|
||||
* COH 901 335 - Used in DB3150 (U300 1.0) and DB3200 (U330 1.0)
|
||||
* COH 901 571/3 - Used in DB3210 (U365 2.0) and DB3350 (U335 1.0)
|
||||
* Notice that you also have inline macros in <asm-arch/gpio.h>
|
||||
* Author: Linus Walleij <linus.walleij@stericsson.com>
|
||||
* Author: Jonas Aaberg <jonas.aberg@stericsson.com>
|
||||
*
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
/* Reference to GPIO block clock */
|
||||
static struct clk *clk;
|
||||
|
||||
/* Memory resource */
|
||||
static struct resource *memres;
|
||||
static void __iomem *virtbase;
|
||||
static struct device *gpiodev;
|
||||
|
||||
struct u300_gpio_port {
|
||||
const char *name;
|
||||
int irq;
|
||||
int number;
|
||||
};
|
||||
|
||||
|
||||
static struct u300_gpio_port gpio_ports[] = {
|
||||
{
|
||||
.name = "gpio0",
|
||||
.number = 0,
|
||||
},
|
||||
{
|
||||
.name = "gpio1",
|
||||
.number = 1,
|
||||
},
|
||||
{
|
||||
.name = "gpio2",
|
||||
.number = 2,
|
||||
},
|
||||
#ifdef U300_COH901571_3
|
||||
{
|
||||
.name = "gpio3",
|
||||
.number = 3,
|
||||
},
|
||||
{
|
||||
.name = "gpio4",
|
||||
.number = 4,
|
||||
},
|
||||
#ifdef CONFIG_MACH_U300_BS335
|
||||
{
|
||||
.name = "gpio5",
|
||||
.number = 5,
|
||||
},
|
||||
{
|
||||
.name = "gpio6",
|
||||
.number = 6,
|
||||
},
|
||||
#endif
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
#ifdef U300_COH901571_3
|
||||
|
||||
/* Default input value */
|
||||
#define DEFAULT_OUTPUT_LOW 0
|
||||
#define DEFAULT_OUTPUT_HIGH 1
|
||||
|
||||
/* GPIO Pull-Up status */
|
||||
#define DISABLE_PULL_UP 0
|
||||
#define ENABLE_PULL_UP 1
|
||||
|
||||
#define GPIO_NOT_USED 0
|
||||
#define GPIO_IN 1
|
||||
#define GPIO_OUT 2
|
||||
|
||||
struct u300_gpio_configuration_data {
|
||||
unsigned char pin_usage;
|
||||
unsigned char default_output_value;
|
||||
unsigned char pull_up;
|
||||
};
|
||||
|
||||
/* Initial configuration */
|
||||
const struct u300_gpio_configuration_data
|
||||
u300_gpio_config[U300_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = {
|
||||
#ifdef CONFIG_MACH_U300_BS335
|
||||
/* Port 0, pins 0-7 */
|
||||
{
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_HIGH, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}
|
||||
},
|
||||
/* Port 1, pins 0-7 */
|
||||
{
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_HIGH, DISABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}
|
||||
},
|
||||
/* Port 2, pins 0-7 */
|
||||
{
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}
|
||||
},
|
||||
/* Port 3, pins 0-7 */
|
||||
{
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}
|
||||
},
|
||||
/* Port 4, pins 0-7 */
|
||||
{
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}
|
||||
},
|
||||
/* Port 5, pins 0-7 */
|
||||
{
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}
|
||||
},
|
||||
/* Port 6, pind 0-7 */
|
||||
{
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MACH_U300_BS365
|
||||
/* Port 0, pins 0-7 */
|
||||
{
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}
|
||||
},
|
||||
/* Port 1, pins 0-7 */
|
||||
{
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_HIGH, DISABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}
|
||||
},
|
||||
/* Port 2, pins 0-7 */
|
||||
{
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}
|
||||
},
|
||||
/* Port 3, pins 0-7 */
|
||||
{
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}
|
||||
},
|
||||
/* Port 4, pins 0-7 */
|
||||
{
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
|
||||
{GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
|
||||
/* These 4 pins doesn't exist on DB3210 */
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
|
||||
{GPIO_OUT, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
/* No users == we can power down GPIO */
|
||||
static int gpio_users;
|
||||
|
||||
struct gpio_struct {
|
||||
int (*callback)(void *);
|
||||
void *data;
|
||||
int users;
|
||||
};
|
||||
|
||||
static struct gpio_struct gpio_pin[U300_GPIO_MAX];
|
||||
|
||||
/*
|
||||
* Let drivers register callback in order to get notified when there is
|
||||
* an interrupt on the gpio pin
|
||||
*/
|
||||
int gpio_register_callback(unsigned gpio, int (*func)(void *arg), void *data)
|
||||
{
|
||||
if (gpio_pin[gpio].callback)
|
||||
dev_warn(gpiodev, "%s: WARNING: callback already "
|
||||
"registered for gpio pin#%d\n", __func__, gpio);
|
||||
gpio_pin[gpio].callback = func;
|
||||
gpio_pin[gpio].data = data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_register_callback);
|
||||
|
||||
int gpio_unregister_callback(unsigned gpio)
|
||||
{
|
||||
if (!gpio_pin[gpio].callback)
|
||||
dev_warn(gpiodev, "%s: WARNING: callback already "
|
||||
"unregistered for gpio pin#%d\n", __func__, gpio);
|
||||
gpio_pin[gpio].callback = NULL;
|
||||
gpio_pin[gpio].data = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_unregister_callback);
|
||||
|
||||
/* Non-zero means valid */
|
||||
int gpio_is_valid(int number)
|
||||
{
|
||||
if (number >= 0 &&
|
||||
number < (U300_GPIO_NUM_PORTS * U300_GPIO_PINS_PER_PORT))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_is_valid);
|
||||
|
||||
int gpio_request(unsigned gpio, const char *label)
|
||||
{
|
||||
if (gpio_pin[gpio].users)
|
||||
return -EINVAL;
|
||||
else
|
||||
gpio_pin[gpio].users++;
|
||||
|
||||
gpio_users++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_request);
|
||||
|
||||
void gpio_free(unsigned gpio)
|
||||
{
|
||||
gpio_users--;
|
||||
gpio_pin[gpio].users--;
|
||||
if (unlikely(gpio_pin[gpio].users < 0)) {
|
||||
dev_warn(gpiodev, "warning: gpio#%d release mismatch\n",
|
||||
gpio);
|
||||
gpio_pin[gpio].users = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_free);
|
||||
|
||||
/* This returns zero or nonzero */
|
||||
int gpio_get_value(unsigned gpio)
|
||||
{
|
||||
return readl(virtbase + U300_GPIO_PXPDIR +
|
||||
PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING) & (1 << (gpio & 0x07));
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_get_value);
|
||||
|
||||
/*
|
||||
* We hope that the compiler will optimize away the unused branch
|
||||
* in case "value" is a constant
|
||||
*/
|
||||
void gpio_set_value(unsigned gpio, int value)
|
||||
{
|
||||
u32 val;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
if (value) {
|
||||
/* set */
|
||||
val = readl(virtbase + U300_GPIO_PXPDOR +
|
||||
PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING)
|
||||
& (1 << (gpio & 0x07));
|
||||
writel(val | (1 << (gpio & 0x07)), virtbase +
|
||||
U300_GPIO_PXPDOR +
|
||||
PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING);
|
||||
} else {
|
||||
/* clear */
|
||||
val = readl(virtbase + U300_GPIO_PXPDOR +
|
||||
PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING)
|
||||
& (1 << (gpio & 0x07));
|
||||
writel(val & ~(1 << (gpio & 0x07)), virtbase +
|
||||
U300_GPIO_PXPDOR +
|
||||
PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING);
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_set_value);
|
||||
|
||||
int gpio_direction_input(unsigned gpio)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
if (gpio > U300_GPIO_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
local_irq_save(flags);
|
||||
val = readl(virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) *
|
||||
U300_GPIO_PORTX_SPACING);
|
||||
/* Mask out this pin*/
|
||||
val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << ((gpio & 0x07) << 1));
|
||||
/* This is not needed since it sets the bits to zero.*/
|
||||
/* val |= (U300_GPIO_PXPCR_PIN_MODE_INPUT << (gpio*2)); */
|
||||
writel(val, virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) *
|
||||
U300_GPIO_PORTX_SPACING);
|
||||
local_irq_restore(flags);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_direction_input);
|
||||
|
||||
int gpio_direction_output(unsigned gpio, int value)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
if (gpio > U300_GPIO_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
local_irq_save(flags);
|
||||
val = readl(virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) *
|
||||
U300_GPIO_PORTX_SPACING);
|
||||
/* Mask out this pin */
|
||||
val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << ((gpio & 0x07) << 1));
|
||||
/*
|
||||
* FIXME: configure for push/pull, open drain or open source per pin
|
||||
* in setup. The current driver will only support push/pull.
|
||||
*/
|
||||
val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL
|
||||
<< ((gpio & 0x07) << 1));
|
||||
writel(val, virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) *
|
||||
U300_GPIO_PORTX_SPACING);
|
||||
gpio_set_value(gpio, value);
|
||||
local_irq_restore(flags);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_direction_output);
|
||||
|
||||
/*
|
||||
* Enable an IRQ, edge is rising edge (!= 0) or falling edge (==0).
|
||||
*/
|
||||
void enable_irq_on_gpio_pin(unsigned gpio, int edge)
|
||||
{
|
||||
u32 val;
|
||||
unsigned long flags;
|
||||
local_irq_save(flags);
|
||||
|
||||
val = readl(virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) *
|
||||
U300_GPIO_PORTX_SPACING);
|
||||
val |= (1 << (gpio & 0x07));
|
||||
writel(val, virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) *
|
||||
U300_GPIO_PORTX_SPACING);
|
||||
val = readl(virtbase + U300_GPIO_PXICR + PIN_TO_PORT(gpio) *
|
||||
U300_GPIO_PORTX_SPACING);
|
||||
if (edge)
|
||||
val |= (1 << (gpio & 0x07));
|
||||
else
|
||||
val &= ~(1 << (gpio & 0x07));
|
||||
writel(val, virtbase + U300_GPIO_PXICR + PIN_TO_PORT(gpio) *
|
||||
U300_GPIO_PORTX_SPACING);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
EXPORT_SYMBOL(enable_irq_on_gpio_pin);
|
||||
|
||||
void disable_irq_on_gpio_pin(unsigned gpio)
|
||||
{
|
||||
u32 val;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
val = readl(virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) *
|
||||
U300_GPIO_PORTX_SPACING);
|
||||
val &= ~(1 << (gpio & 0x07));
|
||||
writel(val, virtbase + U300_GPIO_PXIEN + PIN_TO_PORT(gpio) *
|
||||
U300_GPIO_PORTX_SPACING);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
EXPORT_SYMBOL(disable_irq_on_gpio_pin);
|
||||
|
||||
/* Enable (value == 0) or disable (value == 1) internal pullup */
|
||||
void gpio_pullup(unsigned gpio, int value)
|
||||
{
|
||||
u32 val;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
if (value) {
|
||||
val = readl(virtbase + U300_GPIO_PXPER + PIN_TO_PORT(gpio) *
|
||||
U300_GPIO_PORTX_SPACING);
|
||||
writel(val | (1 << (gpio & 0x07)), virtbase + U300_GPIO_PXPER +
|
||||
PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING);
|
||||
} else {
|
||||
val = readl(virtbase + U300_GPIO_PXPER + PIN_TO_PORT(gpio) *
|
||||
U300_GPIO_PORTX_SPACING);
|
||||
writel(val & ~(1 << (gpio & 0x07)), virtbase + U300_GPIO_PXPER +
|
||||
PIN_TO_PORT(gpio) * U300_GPIO_PORTX_SPACING);
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_pullup);
|
||||
|
||||
static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct u300_gpio_port *port = dev_id;
|
||||
u32 val;
|
||||
int pin;
|
||||
|
||||
/* Read event register */
|
||||
val = readl(virtbase + U300_GPIO_PXIEV + port->number *
|
||||
U300_GPIO_PORTX_SPACING);
|
||||
/* Mask with enable register */
|
||||
val &= readl(virtbase + U300_GPIO_PXIEV + port->number *
|
||||
U300_GPIO_PORTX_SPACING);
|
||||
/* Mask relevant bits */
|
||||
val &= U300_GPIO_PXIEV_ALL_IRQ_EVENT_MASK;
|
||||
/* ACK IRQ (clear event) */
|
||||
writel(val, virtbase + U300_GPIO_PXIEV + port->number *
|
||||
U300_GPIO_PORTX_SPACING);
|
||||
/* Print message */
|
||||
while (val != 0) {
|
||||
unsigned gpio;
|
||||
|
||||
pin = __ffs(val);
|
||||
/* mask off this pin */
|
||||
val &= ~(1 << pin);
|
||||
gpio = (port->number << 3) + pin;
|
||||
|
||||
if (gpio_pin[gpio].callback)
|
||||
(void)gpio_pin[gpio].callback(gpio_pin[gpio].data);
|
||||
else
|
||||
dev_dbg(gpiodev, "stray GPIO IRQ on line %d\n",
|
||||
gpio);
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void gpio_set_initial_values(void)
|
||||
{
|
||||
#ifdef U300_COH901571_3
|
||||
int i, j;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
/* Write default values to all pins */
|
||||
for (i = 0; i < U300_GPIO_NUM_PORTS; i++) {
|
||||
val = 0;
|
||||
for (j = 0; j < 8; j++)
|
||||
val |= (u32) (u300_gpio_config[i][j].default_output_value != DEFAULT_OUTPUT_LOW) << j;
|
||||
local_irq_save(flags);
|
||||
writel(val, virtbase + U300_GPIO_PXPDOR + i * U300_GPIO_PORTX_SPACING);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Put all pins that are set to either 'GPIO_OUT' or 'GPIO_NOT_USED'
|
||||
* to output and 'GPIO_IN' to input for each port. And initialize
|
||||
* default value on outputs.
|
||||
*/
|
||||
for (i = 0; i < U300_GPIO_NUM_PORTS; i++) {
|
||||
for (j = 0; j < U300_GPIO_PINS_PER_PORT; j++) {
|
||||
local_irq_save(flags);
|
||||
val = readl(virtbase + U300_GPIO_PXPCR +
|
||||
i * U300_GPIO_PORTX_SPACING);
|
||||
/* Mask out this pin */
|
||||
val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << (j << 1));
|
||||
|
||||
if (u300_gpio_config[i][j].pin_usage != GPIO_IN)
|
||||
val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL << (j << 1));
|
||||
writel(val, virtbase + U300_GPIO_PXPCR +
|
||||
i * U300_GPIO_PORTX_SPACING);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable or disable the internal pull-ups in the GPIO ASIC block */
|
||||
for (i = 0; i < U300_GPIO_MAX; i++) {
|
||||
val = 0;
|
||||
for (j = 0; j < 8; j++)
|
||||
val |= (u32)((u300_gpio_config[i][j].pull_up == DISABLE_PULL_UP) << j);
|
||||
local_irq_save(flags);
|
||||
writel(val, virtbase + U300_GPIO_PXPER + i * U300_GPIO_PORTX_SPACING);
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int __init gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
u32 val;
|
||||
int err = 0;
|
||||
int i;
|
||||
int num_irqs;
|
||||
|
||||
gpiodev = &pdev->dev;
|
||||
memset(gpio_pin, 0, sizeof(gpio_pin));
|
||||
|
||||
/* Get GPIO clock */
|
||||
clk = clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(clk)) {
|
||||
err = PTR_ERR(clk);
|
||||
dev_err(gpiodev, "could not get GPIO clock\n");
|
||||
goto err_no_clk;
|
||||
}
|
||||
err = clk_enable(clk);
|
||||
if (err) {
|
||||
dev_err(gpiodev, "could not enable GPIO clock\n");
|
||||
goto err_no_clk_enable;
|
||||
}
|
||||
|
||||
memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!memres)
|
||||
goto err_no_resource;
|
||||
|
||||
if (request_mem_region(memres->start, memres->end - memres->start, "GPIO Controller")
|
||||
== NULL) {
|
||||
err = -ENODEV;
|
||||
goto err_no_ioregion;
|
||||
}
|
||||
|
||||
virtbase = ioremap(memres->start, resource_size(memres));
|
||||
if (!virtbase) {
|
||||
err = -ENOMEM;
|
||||
goto err_no_ioremap;
|
||||
}
|
||||
dev_info(gpiodev, "remapped 0x%08x to %p\n",
|
||||
memres->start, virtbase);
|
||||
|
||||
#ifdef U300_COH901335
|
||||
dev_info(gpiodev, "initializing GPIO Controller COH 901 335\n");
|
||||
/* Turn on the GPIO block */
|
||||
writel(U300_GPIO_CR_BLOCK_CLOCK_ENABLE, virtbase + U300_GPIO_CR);
|
||||
#endif
|
||||
|
||||
#ifdef U300_COH901571_3
|
||||
dev_info(gpiodev, "initializing GPIO Controller COH 901 571/3\n");
|
||||
val = readl(virtbase + U300_GPIO_CR);
|
||||
dev_info(gpiodev, "COH901571/3 block version: %d, " \
|
||||
"number of cores: %d\n",
|
||||
((val & 0x0000FE00) >> 9),
|
||||
((val & 0x000001FC) >> 2));
|
||||
writel(U300_GPIO_CR_BLOCK_CLKRQ_ENABLE, virtbase + U300_GPIO_CR);
|
||||
#endif
|
||||
|
||||
gpio_set_initial_values();
|
||||
|
||||
for (num_irqs = 0 ; num_irqs < U300_GPIO_NUM_PORTS; num_irqs++) {
|
||||
|
||||
gpio_ports[num_irqs].irq =
|
||||
platform_get_irq_byname(pdev,
|
||||
gpio_ports[num_irqs].name);
|
||||
|
||||
err = request_irq(gpio_ports[num_irqs].irq,
|
||||
gpio_irq_handler, IRQF_DISABLED,
|
||||
gpio_ports[num_irqs].name,
|
||||
&gpio_ports[num_irqs]);
|
||||
if (err) {
|
||||
dev_err(gpiodev, "cannot allocate IRQ for %s!\n",
|
||||
gpio_ports[num_irqs].name);
|
||||
goto err_no_irq;
|
||||
}
|
||||
/* Turns off PortX_irq_force */
|
||||
writel(0x0, virtbase + U300_GPIO_PXIFR +
|
||||
num_irqs * U300_GPIO_PORTX_SPACING);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_no_irq:
|
||||
for (i = 0; i < num_irqs; i++)
|
||||
free_irq(gpio_ports[i].irq, &gpio_ports[i]);
|
||||
iounmap(virtbase);
|
||||
err_no_ioremap:
|
||||
release_mem_region(memres->start, memres->end - memres->start);
|
||||
err_no_ioregion:
|
||||
err_no_resource:
|
||||
clk_disable(clk);
|
||||
err_no_clk_enable:
|
||||
clk_put(clk);
|
||||
err_no_clk:
|
||||
dev_info(gpiodev, "module ERROR:%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __exit gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Turn off the GPIO block */
|
||||
writel(0x00000000U, virtbase + U300_GPIO_CR);
|
||||
for (i = 0 ; i < U300_GPIO_NUM_PORTS; i++)
|
||||
free_irq(gpio_ports[i].irq, &gpio_ports[i]);
|
||||
iounmap(virtbase);
|
||||
release_mem_region(memres->start, memres->end - memres->start);
|
||||
clk_disable(clk);
|
||||
clk_put(clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver gpio_driver = {
|
||||
.driver = {
|
||||
.name = "u300-gpio",
|
||||
},
|
||||
.remove = __exit_p(gpio_remove),
|
||||
};
|
||||
|
||||
|
||||
static int __init u300_gpio_init(void)
|
||||
{
|
||||
return platform_driver_probe(&gpio_driver, gpio_probe);
|
||||
}
|
||||
|
||||
static void __exit u300_gpio_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&gpio_driver);
|
||||
}
|
||||
|
||||
arch_initcall(u300_gpio_init);
|
||||
module_exit(u300_gpio_exit);
|
||||
|
||||
MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
|
||||
|
||||
#ifdef U300_COH901571_3
|
||||
MODULE_DESCRIPTION("ST-Ericsson AB COH 901 571/3 GPIO driver");
|
||||
#endif
|
||||
|
||||
#ifdef U300_COH901335
|
||||
MODULE_DESCRIPTION("ST-Ericsson AB COH 901 335 GPIO driver");
|
||||
#endif
|
||||
|
||||
MODULE_LICENSE("GPL");
|
@@ -1296,7 +1296,7 @@ EXPORT_SYMBOL_GPL(gpio_request_one);
|
||||
* @array: array of the 'struct gpio'
|
||||
* @num: how many GPIOs in the array
|
||||
*/
|
||||
int gpio_request_array(struct gpio *array, size_t num)
|
||||
int gpio_request_array(const struct gpio *array, size_t num)
|
||||
{
|
||||
int i, err;
|
||||
|
||||
@@ -1319,7 +1319,7 @@ EXPORT_SYMBOL_GPL(gpio_request_array);
|
||||
* @array: array of the 'struct gpio'
|
||||
* @num: how many GPIOs in the array
|
||||
*/
|
||||
void gpio_free_array(struct gpio *array, size_t num)
|
||||
void gpio_free_array(const struct gpio *array, size_t num)
|
||||
{
|
||||
while (num--)
|
||||
gpio_free((array++)->gpio);
|
||||
|
@@ -33,6 +33,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
/*
|
||||
* Langwell chip has 64 pins and thus there are 2 32bit registers to control
|
||||
@@ -63,6 +64,7 @@ struct lnw_gpio {
|
||||
void *reg_base;
|
||||
spinlock_t lock;
|
||||
unsigned irq_base;
|
||||
struct pci_dev *pdev;
|
||||
};
|
||||
|
||||
static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset,
|
||||
@@ -104,11 +106,18 @@ static int lnw_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||
u32 value;
|
||||
unsigned long flags;
|
||||
|
||||
if (lnw->pdev)
|
||||
pm_runtime_get(&lnw->pdev->dev);
|
||||
|
||||
spin_lock_irqsave(&lnw->lock, flags);
|
||||
value = readl(gpdr);
|
||||
value &= ~BIT(offset % 32);
|
||||
writel(value, gpdr);
|
||||
spin_unlock_irqrestore(&lnw->lock, flags);
|
||||
|
||||
if (lnw->pdev)
|
||||
pm_runtime_put(&lnw->pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -120,11 +129,19 @@ static int lnw_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned long flags;
|
||||
|
||||
lnw_gpio_set(chip, offset, value);
|
||||
|
||||
if (lnw->pdev)
|
||||
pm_runtime_get(&lnw->pdev->dev);
|
||||
|
||||
spin_lock_irqsave(&lnw->lock, flags);
|
||||
value = readl(gpdr);
|
||||
value |= BIT(offset % 32);
|
||||
writel(value, gpdr);
|
||||
spin_unlock_irqrestore(&lnw->lock, flags);
|
||||
|
||||
if (lnw->pdev)
|
||||
pm_runtime_put(&lnw->pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -145,6 +162,10 @@ static int lnw_irq_type(struct irq_data *d, unsigned type)
|
||||
|
||||
if (gpio >= lnw->chip.ngpio)
|
||||
return -EINVAL;
|
||||
|
||||
if (lnw->pdev)
|
||||
pm_runtime_get(&lnw->pdev->dev);
|
||||
|
||||
spin_lock_irqsave(&lnw->lock, flags);
|
||||
if (type & IRQ_TYPE_EDGE_RISING)
|
||||
value = readl(grer) | BIT(gpio % 32);
|
||||
@@ -159,6 +180,9 @@ static int lnw_irq_type(struct irq_data *d, unsigned type)
|
||||
writel(value, gfer);
|
||||
spin_unlock_irqrestore(&lnw->lock, flags);
|
||||
|
||||
if (lnw->pdev)
|
||||
pm_runtime_put(&lnw->pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -211,6 +235,39 @@ static void lnw_irq_handler(unsigned irq, struct irq_desc *desc)
|
||||
chip->irq_eoi(data);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int lnw_gpio_runtime_resume(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lnw_gpio_runtime_suspend(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lnw_gpio_runtime_idle(struct device *dev)
|
||||
{
|
||||
int err = pm_schedule_suspend(dev, 500);
|
||||
|
||||
if (!err)
|
||||
return 0;
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
#else
|
||||
#define lnw_gpio_runtime_suspend NULL
|
||||
#define lnw_gpio_runtime_resume NULL
|
||||
#define lnw_gpio_runtime_idle NULL
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops lnw_gpio_pm_ops = {
|
||||
.runtime_suspend = lnw_gpio_runtime_suspend,
|
||||
.runtime_resume = lnw_gpio_runtime_resume,
|
||||
.runtime_idle = lnw_gpio_runtime_idle,
|
||||
};
|
||||
|
||||
static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
@@ -270,6 +327,7 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
|
||||
lnw->chip.base = gpio_base;
|
||||
lnw->chip.ngpio = id->driver_data;
|
||||
lnw->chip.can_sleep = 0;
|
||||
lnw->pdev = pdev;
|
||||
pci_set_drvdata(pdev, lnw);
|
||||
retval = gpiochip_add(&lnw->chip);
|
||||
if (retval) {
|
||||
@@ -285,6 +343,10 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
|
||||
}
|
||||
|
||||
spin_lock_init(&lnw->lock);
|
||||
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
pm_runtime_allow(&pdev->dev);
|
||||
|
||||
goto done;
|
||||
err5:
|
||||
kfree(lnw);
|
||||
@@ -302,6 +364,9 @@ static struct pci_driver lnw_gpio_driver = {
|
||||
.name = "langwell_gpio",
|
||||
.id_table = lnw_gpio_ids,
|
||||
.probe = lnw_gpio_probe,
|
||||
.driver = {
|
||||
.pm = &lnw_gpio_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
|
@@ -24,33 +24,46 @@
|
||||
#include <linux/of_gpio.h>
|
||||
#endif
|
||||
|
||||
#define PCA953X_INPUT 0
|
||||
#define PCA953X_OUTPUT 1
|
||||
#define PCA953X_INVERT 2
|
||||
#define PCA953X_DIRECTION 3
|
||||
#define PCA953X_INPUT 0
|
||||
#define PCA953X_OUTPUT 1
|
||||
#define PCA953X_INVERT 2
|
||||
#define PCA953X_DIRECTION 3
|
||||
|
||||
#define PCA953X_GPIOS 0x00FF
|
||||
#define PCA953X_INT 0x0100
|
||||
#define PCA957X_IN 0
|
||||
#define PCA957X_INVRT 1
|
||||
#define PCA957X_BKEN 2
|
||||
#define PCA957X_PUPD 3
|
||||
#define PCA957X_CFG 4
|
||||
#define PCA957X_OUT 5
|
||||
#define PCA957X_MSK 6
|
||||
#define PCA957X_INTS 7
|
||||
|
||||
#define PCA_GPIO_MASK 0x00FF
|
||||
#define PCA_INT 0x0100
|
||||
#define PCA953X_TYPE 0x1000
|
||||
#define PCA957X_TYPE 0x2000
|
||||
|
||||
static const struct i2c_device_id pca953x_id[] = {
|
||||
{ "pca9534", 8 | PCA953X_INT, },
|
||||
{ "pca9535", 16 | PCA953X_INT, },
|
||||
{ "pca9536", 4, },
|
||||
{ "pca9537", 4 | PCA953X_INT, },
|
||||
{ "pca9538", 8 | PCA953X_INT, },
|
||||
{ "pca9539", 16 | PCA953X_INT, },
|
||||
{ "pca9554", 8 | PCA953X_INT, },
|
||||
{ "pca9555", 16 | PCA953X_INT, },
|
||||
{ "pca9556", 8, },
|
||||
{ "pca9557", 8, },
|
||||
{ "pca9534", 8 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "pca9535", 16 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "pca9536", 4 | PCA953X_TYPE, },
|
||||
{ "pca9537", 4 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "pca9538", 8 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "pca9539", 16 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "pca9554", 8 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "pca9555", 16 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "pca9556", 8 | PCA953X_TYPE, },
|
||||
{ "pca9557", 8 | PCA953X_TYPE, },
|
||||
{ "pca9574", 8 | PCA957X_TYPE | PCA_INT, },
|
||||
{ "pca9575", 16 | PCA957X_TYPE | PCA_INT, },
|
||||
|
||||
{ "max7310", 8, },
|
||||
{ "max7312", 16 | PCA953X_INT, },
|
||||
{ "max7313", 16 | PCA953X_INT, },
|
||||
{ "max7315", 8 | PCA953X_INT, },
|
||||
{ "pca6107", 8 | PCA953X_INT, },
|
||||
{ "tca6408", 8 | PCA953X_INT, },
|
||||
{ "tca6416", 16 | PCA953X_INT, },
|
||||
{ "max7310", 8 | PCA953X_TYPE, },
|
||||
{ "max7312", 16 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "max7313", 16 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "max7315", 8 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "pca6107", 8 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "tca6408", 8 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "tca6416", 16 | PCA953X_TYPE | PCA_INT, },
|
||||
/* NYET: { "tca6424", 24, }, */
|
||||
{ }
|
||||
};
|
||||
@@ -75,16 +88,32 @@ struct pca953x_chip {
|
||||
struct pca953x_platform_data *dyn_pdata;
|
||||
struct gpio_chip gpio_chip;
|
||||
const char *const *names;
|
||||
int chip_type;
|
||||
};
|
||||
|
||||
static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val)
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
if (chip->gpio_chip.ngpio <= 8)
|
||||
ret = i2c_smbus_write_byte_data(chip->client, reg, val);
|
||||
else
|
||||
ret = i2c_smbus_write_word_data(chip->client, reg << 1, val);
|
||||
else {
|
||||
switch (chip->chip_type) {
|
||||
case PCA953X_TYPE:
|
||||
ret = i2c_smbus_write_word_data(chip->client,
|
||||
reg << 1, val);
|
||||
break;
|
||||
case PCA957X_TYPE:
|
||||
ret = i2c_smbus_write_byte_data(chip->client, reg << 1,
|
||||
val & 0xff);
|
||||
if (ret < 0)
|
||||
break;
|
||||
ret = i2c_smbus_write_byte_data(chip->client,
|
||||
(reg << 1) + 1,
|
||||
(val & 0xff00) >> 8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&chip->client->dev, "failed writing register\n");
|
||||
@@ -116,13 +145,22 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
|
||||
{
|
||||
struct pca953x_chip *chip;
|
||||
uint16_t reg_val;
|
||||
int ret;
|
||||
int ret, offset = 0;
|
||||
|
||||
chip = container_of(gc, struct pca953x_chip, gpio_chip);
|
||||
|
||||
mutex_lock(&chip->i2c_lock);
|
||||
reg_val = chip->reg_direction | (1u << off);
|
||||
ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val);
|
||||
|
||||
switch (chip->chip_type) {
|
||||
case PCA953X_TYPE:
|
||||
offset = PCA953X_DIRECTION;
|
||||
break;
|
||||
case PCA957X_TYPE:
|
||||
offset = PCA957X_CFG;
|
||||
break;
|
||||
}
|
||||
ret = pca953x_write_reg(chip, offset, reg_val);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
@@ -138,7 +176,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
|
||||
{
|
||||
struct pca953x_chip *chip;
|
||||
uint16_t reg_val;
|
||||
int ret;
|
||||
int ret, offset = 0;
|
||||
|
||||
chip = container_of(gc, struct pca953x_chip, gpio_chip);
|
||||
|
||||
@@ -149,7 +187,15 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
|
||||
else
|
||||
reg_val = chip->reg_output & ~(1u << off);
|
||||
|
||||
ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val);
|
||||
switch (chip->chip_type) {
|
||||
case PCA953X_TYPE:
|
||||
offset = PCA953X_OUTPUT;
|
||||
break;
|
||||
case PCA957X_TYPE:
|
||||
offset = PCA957X_OUT;
|
||||
break;
|
||||
}
|
||||
ret = pca953x_write_reg(chip, offset, reg_val);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
@@ -157,7 +203,15 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
|
||||
|
||||
/* then direction */
|
||||
reg_val = chip->reg_direction & ~(1u << off);
|
||||
ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val);
|
||||
switch (chip->chip_type) {
|
||||
case PCA953X_TYPE:
|
||||
offset = PCA953X_DIRECTION;
|
||||
break;
|
||||
case PCA957X_TYPE:
|
||||
offset = PCA957X_CFG;
|
||||
break;
|
||||
}
|
||||
ret = pca953x_write_reg(chip, offset, reg_val);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
@@ -172,12 +226,20 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
|
||||
{
|
||||
struct pca953x_chip *chip;
|
||||
uint16_t reg_val;
|
||||
int ret;
|
||||
int ret, offset = 0;
|
||||
|
||||
chip = container_of(gc, struct pca953x_chip, gpio_chip);
|
||||
|
||||
mutex_lock(&chip->i2c_lock);
|
||||
ret = pca953x_read_reg(chip, PCA953X_INPUT, ®_val);
|
||||
switch (chip->chip_type) {
|
||||
case PCA953X_TYPE:
|
||||
offset = PCA953X_INPUT;
|
||||
break;
|
||||
case PCA957X_TYPE:
|
||||
offset = PCA957X_IN;
|
||||
break;
|
||||
}
|
||||
ret = pca953x_read_reg(chip, offset, ®_val);
|
||||
mutex_unlock(&chip->i2c_lock);
|
||||
if (ret < 0) {
|
||||
/* NOTE: diagnostic already emitted; that's all we should
|
||||
@@ -194,7 +256,7 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
|
||||
{
|
||||
struct pca953x_chip *chip;
|
||||
uint16_t reg_val;
|
||||
int ret;
|
||||
int ret, offset = 0;
|
||||
|
||||
chip = container_of(gc, struct pca953x_chip, gpio_chip);
|
||||
|
||||
@@ -204,7 +266,15 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
|
||||
else
|
||||
reg_val = chip->reg_output & ~(1u << off);
|
||||
|
||||
ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val);
|
||||
switch (chip->chip_type) {
|
||||
case PCA953X_TYPE:
|
||||
offset = PCA953X_OUTPUT;
|
||||
break;
|
||||
case PCA957X_TYPE:
|
||||
offset = PCA957X_OUT;
|
||||
break;
|
||||
}
|
||||
ret = pca953x_write_reg(chip, offset, reg_val);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
@@ -322,9 +392,17 @@ static uint16_t pca953x_irq_pending(struct pca953x_chip *chip)
|
||||
uint16_t old_stat;
|
||||
uint16_t pending;
|
||||
uint16_t trigger;
|
||||
int ret;
|
||||
int ret, offset = 0;
|
||||
|
||||
ret = pca953x_read_reg(chip, PCA953X_INPUT, &cur_stat);
|
||||
switch (chip->chip_type) {
|
||||
case PCA953X_TYPE:
|
||||
offset = PCA953X_INPUT;
|
||||
break;
|
||||
case PCA957X_TYPE:
|
||||
offset = PCA957X_IN;
|
||||
break;
|
||||
}
|
||||
ret = pca953x_read_reg(chip, offset, &cur_stat);
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
@@ -372,14 +450,21 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
|
||||
{
|
||||
struct i2c_client *client = chip->client;
|
||||
struct pca953x_platform_data *pdata = client->dev.platform_data;
|
||||
int ret;
|
||||
int ret, offset = 0;
|
||||
|
||||
if (pdata->irq_base != -1
|
||||
&& (id->driver_data & PCA953X_INT)) {
|
||||
&& (id->driver_data & PCA_INT)) {
|
||||
int lvl;
|
||||
|
||||
ret = pca953x_read_reg(chip, PCA953X_INPUT,
|
||||
&chip->irq_stat);
|
||||
switch (chip->chip_type) {
|
||||
case PCA953X_TYPE:
|
||||
offset = PCA953X_INPUT;
|
||||
break;
|
||||
case PCA957X_TYPE:
|
||||
offset = PCA957X_IN;
|
||||
break;
|
||||
}
|
||||
ret = pca953x_read_reg(chip, offset, &chip->irq_stat);
|
||||
if (ret)
|
||||
goto out_failed;
|
||||
|
||||
@@ -439,7 +524,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
|
||||
struct i2c_client *client = chip->client;
|
||||
struct pca953x_platform_data *pdata = client->dev.platform_data;
|
||||
|
||||
if (pdata->irq_base != -1 && (id->driver_data & PCA953X_INT))
|
||||
if (pdata->irq_base != -1 && (id->driver_data & PCA_INT))
|
||||
dev_warn(&client->dev, "interrupt support not compiled in\n");
|
||||
|
||||
return 0;
|
||||
@@ -499,12 +584,65 @@ pca953x_get_alt_pdata(struct i2c_client *client)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __devinit device_pca953x_init(struct pca953x_chip *chip, int invert)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = pca953x_read_reg(chip, PCA953X_DIRECTION,
|
||||
&chip->reg_direction);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* set platform specific polarity inversion */
|
||||
ret = pca953x_write_reg(chip, PCA953X_INVERT, invert);
|
||||
if (ret)
|
||||
goto out;
|
||||
return 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devinit device_pca957x_init(struct pca953x_chip *chip, int invert)
|
||||
{
|
||||
int ret;
|
||||
uint16_t val = 0;
|
||||
|
||||
/* Let every port in proper state, that could save power */
|
||||
pca953x_write_reg(chip, PCA957X_PUPD, 0x0);
|
||||
pca953x_write_reg(chip, PCA957X_CFG, 0xffff);
|
||||
pca953x_write_reg(chip, PCA957X_OUT, 0x0);
|
||||
|
||||
ret = pca953x_read_reg(chip, PCA957X_IN, &val);
|
||||
if (ret)
|
||||
goto out;
|
||||
ret = pca953x_read_reg(chip, PCA957X_OUT, &chip->reg_output);
|
||||
if (ret)
|
||||
goto out;
|
||||
ret = pca953x_read_reg(chip, PCA957X_CFG, &chip->reg_direction);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* set platform specific polarity inversion */
|
||||
pca953x_write_reg(chip, PCA957X_INVRT, invert);
|
||||
|
||||
/* To enable register 6, 7 to controll pull up and pull down */
|
||||
pca953x_write_reg(chip, PCA957X_BKEN, 0x202);
|
||||
|
||||
return 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devinit pca953x_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct pca953x_platform_data *pdata;
|
||||
struct pca953x_chip *chip;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL);
|
||||
if (chip == NULL)
|
||||
@@ -531,25 +669,20 @@ static int __devinit pca953x_probe(struct i2c_client *client,
|
||||
chip->gpio_start = pdata->gpio_base;
|
||||
|
||||
chip->names = pdata->names;
|
||||
chip->chip_type = id->driver_data & (PCA953X_TYPE | PCA957X_TYPE);
|
||||
|
||||
mutex_init(&chip->i2c_lock);
|
||||
|
||||
/* initialize cached registers from their original values.
|
||||
* we can't share this chip with another i2c master.
|
||||
*/
|
||||
pca953x_setup_gpio(chip, id->driver_data & PCA953X_GPIOS);
|
||||
pca953x_setup_gpio(chip, id->driver_data & PCA_GPIO_MASK);
|
||||
|
||||
ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output);
|
||||
if (ret)
|
||||
goto out_failed;
|
||||
|
||||
ret = pca953x_read_reg(chip, PCA953X_DIRECTION, &chip->reg_direction);
|
||||
if (ret)
|
||||
goto out_failed;
|
||||
|
||||
/* set platform specific polarity inversion */
|
||||
ret = pca953x_write_reg(chip, PCA953X_INVERT, pdata->invert);
|
||||
if (ret)
|
||||
if (chip->chip_type == PCA953X_TYPE)
|
||||
device_pca953x_init(chip, pdata->invert);
|
||||
else if (chip->chip_type == PCA957X_TYPE)
|
||||
device_pca957x_init(chip, pdata->invert);
|
||||
else
|
||||
goto out_failed;
|
||||
|
||||
ret = pca953x_irq_setup(chip, id);
|
||||
|
@@ -283,8 +283,10 @@ static int pch_gpio_resume(struct pci_dev *pdev)
|
||||
#define pch_gpio_resume NULL
|
||||
#endif
|
||||
|
||||
#define PCI_VENDOR_ID_ROHM 0x10DB
|
||||
static DEFINE_PCI_DEVICE_TABLE(pch_gpio_pcidev_id) = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8803) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8014) },
|
||||
{ 0, }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, pch_gpio_pcidev_id);
|
||||
|
Verwijs in nieuw issue
Block a user