diff options
Diffstat (limited to 'arch/arm/mach-s5p6440/gpio.c')
| -rw-r--r-- | arch/arm/mach-s5p6440/gpio.c | 322 | 
1 files changed, 322 insertions, 0 deletions
diff --git a/arch/arm/mach-s5p6440/gpio.c b/arch/arm/mach-s5p6440/gpio.c new file mode 100644 index 00000000000..b0ea741177a --- /dev/null +++ b/arch/arm/mach-s5p6440/gpio.c @@ -0,0 +1,322 @@ +/* arch/arm/mach-s5p6440/gpio.c + * + * Copyright (c) 2009 Samsung Electronics Co., Ltd. + * 		http://www.samsung.com/ + * + * S5P6440 - 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 <mach/map.h> +#include <mach/gpio.h> +#include <mach/regs-gpio.h> +#include <plat/gpio-core.h> +#include <plat/gpio-cfg.h> +#include <plat/gpio-cfg-helpers.h> + +/* GPIO bank summary: +* +* Bank	GPIOs	Style	SlpCon	ExtInt Group +* A	6	4Bit	Yes	1 +* B	7	4Bit	Yes	1 +* C	8	4Bit	Yes	2 +* F	2	2Bit	Yes	4 [1] +* G	7	4Bit	Yes	5 +* H	10	4Bit[2]	Yes	6 +* I	16	2Bit	Yes	None +* J	12	2Bit	Yes	None +* N	16	2Bit	No	IRQ_EINT +* P	8	2Bit	Yes	8 +* R	15	4Bit[2]	Yes	8 +* +* [1] BANKF pins 14,15 do not form part of the external interrupt sources +* [2] BANK has two control registers, GPxCON0 and GPxCON1 +*/ + +static int s5p6440_gpiolib_rbank_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; + +	switch (offset) { +	case 6: +		offset += 1; +	case 0: +	case 1: +	case 2: +	case 3: +	case 4: +	case 5: +		regcon -= 4; +		break; +	default: +		offset -= 7; +		break; +	} + +	con = __raw_readl(regcon); +	con &= ~(0xf << con_4bit_shift(offset)); +	__raw_writel(con, regcon); + +	return 0; +} + +static int s5p6440_gpiolib_rbank_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; + +	switch (con_offset) { +	case 6: +		con_offset += 1; +	case 0: +	case 1: +	case 2: +	case 3: +	case 4: +	case 5: +		regcon -= 4; +		break; +	default: +		con_offset -= 7; +		break; +	} + +	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(con, regcon); +	__raw_writel(dat, base + GPIODAT_OFF); + +	return 0; +} + +int s5p6440_gpio_setcfg_4bit_rbank(struct s3c_gpio_chip *chip, +				   unsigned int off, unsigned int cfg) +{ +	void __iomem *reg = chip->base; +	unsigned int shift; +	u32 con; + +	switch (off) { +	case 0: +	case 1: +	case 2: +	case 3: +	case 4: +	case 5: +		shift = (off & 7) * 4; +		reg -= 4; +		break; +	case 6: +		shift = ((off + 1) & 7) * 4; +		reg -= 4; +	default: +		shift = ((off + 1) & 7) * 4; +		break; +	} + +	if (s3c_gpio_is_cfg_special(cfg)) { +		cfg &= 0xf; +		cfg <<= shift; +	} + +	con = __raw_readl(reg); +	con &= ~(0xf << shift); +	con |= cfg; +	__raw_writel(con, reg); + +	return 0; +} + +static struct s3c_gpio_cfg s5p6440_gpio_cfgs[] = { +	{ +		.cfg_eint	= 0, +	}, { +		.cfg_eint	= 7, +	}, { +		.cfg_eint	= 3, +		.set_config	= s5p6440_gpio_setcfg_4bit_rbank, +	}, { +		.cfg_eint	= 0, +		.set_config	= s3c_gpio_setcfg_s3c24xx, +	}, { +		.cfg_eint	= 2, +		.set_config	= s3c_gpio_setcfg_s3c24xx, +	}, { +		.cfg_eint	= 3, +		.set_config	= s3c_gpio_setcfg_s3c24xx, +	}, +}; + +static struct s3c_gpio_chip s5p6440_gpio_4bit[] = { +	{ +		.base	= S5P6440_GPA_BASE, +		.config	= &s5p6440_gpio_cfgs[1], +		.chip	= { +			.base	= S5P6440_GPA(0), +			.ngpio	= S5P6440_GPIO_A_NR, +			.label	= "GPA", +		}, +	}, { +		.base	= S5P6440_GPB_BASE, +		.config	= &s5p6440_gpio_cfgs[1], +		.chip	= { +			.base	= S5P6440_GPB(0), +			.ngpio	= S5P6440_GPIO_B_NR, +			.label	= "GPB", +		}, +	}, { +		.base	= S5P6440_GPC_BASE, +		.config	= &s5p6440_gpio_cfgs[1], +		.chip	= { +			.base	= S5P6440_GPC(0), +			.ngpio	= S5P6440_GPIO_C_NR, +			.label	= "GPC", +		}, +	}, { +		.base	= S5P6440_GPG_BASE, +		.config	= &s5p6440_gpio_cfgs[1], +		.chip	= { +			.base	= S5P6440_GPG(0), +			.ngpio	= S5P6440_GPIO_G_NR, +			.label	= "GPG", +		}, +	}, +}; + +static struct s3c_gpio_chip s5p6440_gpio_4bit2[] = { +	{ +		.base	= S5P6440_GPH_BASE + 0x4, +		.config	= &s5p6440_gpio_cfgs[1], +		.chip	= { +			.base	= S5P6440_GPH(0), +			.ngpio	= S5P6440_GPIO_H_NR, +			.label	= "GPH", +		}, +	}, +}; + +static struct s3c_gpio_chip gpio_rbank_4bit2[] = { +	{ +		.base	= S5P6440_GPR_BASE + 0x4, +		.config	= &s5p6440_gpio_cfgs[2], +		.chip	= { +			.base	= S5P6440_GPR(0), +			.ngpio	= S5P6440_GPIO_R_NR, +			.label	= "GPR", +		}, +	}, +}; + +static struct s3c_gpio_chip s5p6440_gpio_2bit[] = { +	{ +		.base	= S5P6440_GPF_BASE, +		.config	= &s5p6440_gpio_cfgs[5], +		.chip	= { +			.base	= S5P6440_GPF(0), +			.ngpio	= S5P6440_GPIO_F_NR, +			.label	= "GPF", +		}, +	}, { +		.base	= S5P6440_GPI_BASE, +		.config	= &s5p6440_gpio_cfgs[3], +		.chip	= { +			.base	= S5P6440_GPI(0), +			.ngpio	= S5P6440_GPIO_I_NR, +			.label	= "GPI", +		}, +	}, { +		.base	= S5P6440_GPJ_BASE, +		.config	= &s5p6440_gpio_cfgs[3], +		.chip	= { +			.base	= S5P6440_GPJ(0), +			.ngpio	= S5P6440_GPIO_J_NR, +			.label	= "GPJ", +		}, +	}, { +		.base	= S5P6440_GPN_BASE, +		.config	= &s5p6440_gpio_cfgs[4], +		.chip	= { +			.base	= S5P6440_GPN(0), +			.ngpio	= S5P6440_GPIO_N_NR, +			.label	= "GPN", +		}, +	}, { +		.base	= S5P6440_GPP_BASE, +		.config	= &s5p6440_gpio_cfgs[5], +		.chip	= { +			.base	= S5P6440_GPP(0), +			.ngpio	= S5P6440_GPIO_P_NR, +			.label	= "GPP", +		}, +	}, +}; + +void __init s5p6440_gpiolib_set_cfg(struct s3c_gpio_cfg *chipcfg, int nr_chips) +{ +	for (; nr_chips > 0; nr_chips--, chipcfg++) { +		if (!chipcfg->set_config) +			chipcfg->set_config	= s3c_gpio_setcfg_s3c64xx_4bit; +		if (!chipcfg->set_pull) +			chipcfg->set_pull	= s3c_gpio_setpull_updown; +		if (!chipcfg->get_pull) +			chipcfg->get_pull	= s3c_gpio_getpull_updown; +	} +} + +static void __init s5p6440_gpio_add_rbank_4bit2(struct s3c_gpio_chip *chip, +						int nr_chips) +{ +	for (; nr_chips > 0; nr_chips--, chip++) { +		chip->chip.direction_input = s5p6440_gpiolib_rbank_4bit2_input; +		chip->chip.direction_output = +					s5p6440_gpiolib_rbank_4bit2_output; +		s3c_gpiolib_add(chip); +	} +} + +static int __init s5p6440_gpiolib_init(void) +{ +	struct s3c_gpio_chip *chips = s5p6440_gpio_2bit; +	int nr_chips = ARRAY_SIZE(s5p6440_gpio_2bit); + +	s5p6440_gpiolib_set_cfg(s5p6440_gpio_cfgs, +				ARRAY_SIZE(s5p6440_gpio_cfgs)); + +	for (; nr_chips > 0; nr_chips--, chips++) +		s3c_gpiolib_add(chips); + +	samsung_gpiolib_add_4bit_chips(s5p6440_gpio_4bit, +				ARRAY_SIZE(s5p6440_gpio_4bit)); + +	samsung_gpiolib_add_4bit2_chips(s5p6440_gpio_4bit2, +				ARRAY_SIZE(s5p6440_gpio_4bit2)); + +	s5p6440_gpio_add_rbank_4bit2(gpio_rbank_4bit2, +				ARRAY_SIZE(gpio_rbank_4bit2)); + +	return 0; +} +arch_initcall(s5p6440_gpiolib_init);  |