2010-11-25 08:21:48 +03:00
/* linux/arch/arm/mach-s5p64x0/gpiolib.c
2010-01-19 09:31:17 +03:00
*
2010-09-08 11:23:05 +04:00
* Copyright ( c ) 2009 - 2010 Samsung Electronics Co . , Ltd .
* http : //www.samsung.com
2010-01-19 09:31:17 +03:00
*
2010-09-08 11:23:05 +04:00
* S5P64X0 - GPIOlib support
2010-01-19 09:31:17 +03:00
*
* 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 .
2010-09-08 11:23:05 +04:00
*/
2010-01-19 09:31:17 +03:00
# include <linux/kernel.h>
# include <linux/irq.h>
# include <linux/io.h>
2010-08-05 02:54:49 +04:00
# include <linux/gpio.h>
2010-01-19 09:31:17 +03:00
# include <mach/map.h>
# include <mach/regs-gpio.h>
2010-11-25 08:17:01 +03:00
# include <mach/regs-clock.h>
2010-08-05 02:54:49 +04:00
2011-08-19 21:30:08 +04:00
# include <plat/cpu.h>
2010-01-19 09:31:17 +03:00
# include <plat/gpio-core.h>
# include <plat/gpio-cfg.h>
# include <plat/gpio-cfg-helpers.h>
2010-09-08 11:23:05 +04:00
/*
* S5P6440 GPIO bank summary :
*
* Bank GPIOs Style SlpCon ExtInt Group
* A 6 4 Bit Yes 1
* B 7 4 Bit Yes 1
* C 8 4 Bit Yes 2
* F 2 2 Bit Yes 4 [ 1 ]
* G 7 4 Bit Yes 5
* H 10 4 Bit [ 2 ] Yes 6
* I 16 2 Bit Yes None
* J 12 2 Bit Yes None
* N 16 2 Bit No IRQ_EINT
* P 8 2 Bit Yes 8
* R 15 4 Bit [ 2 ] Yes 8
*
2010-11-25 08:17:01 +03:00
* S5P6450 GPIO bank summary :
*
* Bank GPIOs Style SlpCon ExtInt Group
* A 6 4 Bit Yes 1
* B 7 4 Bit Yes 1
* C 8 4 Bit Yes 2
* D 8 4 Bit Yes None
* F 2 2 Bit Yes None
* G 14 4 Bit [ 2 ] Yes 5
* H 10 4 Bit [ 2 ] Yes 6
* I 16 2 Bit Yes None
* J 12 2 Bit Yes None
* K 5 4 Bit Yes None
* N 16 2 Bit No IRQ_EINT
* P 11 2 Bit Yes 8
* Q 14 2 Bit Yes None
* R 15 4 Bit [ 2 ] Yes None
* S 8 2 Bit Yes None
*
2010-09-08 11:23:05 +04:00
* [ 1 ] BANKF pins 14 , 15 do not form part of the external interrupt sources
* [ 2 ] BANK has two control registers , GPxCON0 and GPxCON1
*/
2010-01-19 09:31:17 +03:00
2010-09-08 11:23:05 +04:00
static int s5p64x0_gpiolib_rbank_4bit2_input ( struct gpio_chip * chip ,
2010-01-19 09:31:17 +03:00
unsigned int offset )
{
struct s3c_gpio_chip * ourchip = to_s3c_gpio ( chip ) ;
void __iomem * base = ourchip - > base ;
void __iomem * regcon = base ;
unsigned long con ;
2010-05-19 11:31:49 +04:00
unsigned long flags ;
2010-01-19 09:31:17 +03:00
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 ;
}
2010-05-19 11:31:49 +04:00
s3c_gpio_lock ( ourchip , flags ) ;
2010-01-19 09:31:17 +03:00
con = __raw_readl ( regcon ) ;
con & = ~ ( 0xf < < con_4bit_shift ( offset ) ) ;
__raw_writel ( con , regcon ) ;
2010-05-19 11:31:49 +04:00
s3c_gpio_unlock ( ourchip , flags ) ;
2010-01-19 09:31:17 +03:00
return 0 ;
}
2010-09-08 11:23:05 +04:00
static int s5p64x0_gpiolib_rbank_4bit2_output ( struct gpio_chip * chip ,
2010-01-19 09:31:17 +03:00
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 ;
2010-05-19 11:31:49 +04:00
unsigned long flags ;
2010-01-19 09:31:17 +03:00
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 ;
}
2010-05-19 11:31:49 +04:00
s3c_gpio_lock ( ourchip , flags ) ;
2010-01-19 09:31:17 +03:00
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 ) ;
2010-05-19 11:31:49 +04:00
s3c_gpio_unlock ( ourchip , flags ) ;
2010-01-19 09:31:17 +03:00
return 0 ;
}
2010-09-08 11:23:05 +04:00
int s5p64x0_gpio_setcfg_4bit_rbank ( struct s3c_gpio_chip * chip ,
2010-01-19 09:31:17 +03:00
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 ;
}
2010-09-08 11:23:05 +04:00
static struct s3c_gpio_cfg s5p64x0_gpio_cfgs [ ] = {
2010-01-19 09:31:17 +03:00
{
. cfg_eint = 0 ,
} , {
. cfg_eint = 7 ,
} , {
. cfg_eint = 3 ,
2010-09-08 11:23:05 +04:00
. set_config = s5p64x0_gpio_setcfg_4bit_rbank ,
2010-01-19 09:31:17 +03:00
} , {
. cfg_eint = 0 ,
. set_config = s3c_gpio_setcfg_s3c24xx ,
2010-05-06 05:27:16 +04:00
. get_config = s3c_gpio_getcfg_s3c24xx ,
2010-01-19 09:31:17 +03:00
} , {
. cfg_eint = 2 ,
. set_config = s3c_gpio_setcfg_s3c24xx ,
2010-05-06 05:27:16 +04:00
. get_config = s3c_gpio_getcfg_s3c24xx ,
2010-01-19 09:31:17 +03:00
} , {
. cfg_eint = 3 ,
. set_config = s3c_gpio_setcfg_s3c24xx ,
2010-05-06 05:27:16 +04:00
. get_config = s3c_gpio_getcfg_s3c24xx ,
2010-01-19 09:31:17 +03:00
} ,
} ;
static struct s3c_gpio_chip s5p6440_gpio_4bit [ ] = {
{
2010-11-25 08:17:01 +03:00
. base = S5P64X0_GPA_BASE ,
2010-09-08 11:23:05 +04:00
. config = & s5p64x0_gpio_cfgs [ 1 ] ,
2010-01-19 09:31:17 +03:00
. chip = {
. base = S5P6440_GPA ( 0 ) ,
. ngpio = S5P6440_GPIO_A_NR ,
. label = " GPA " ,
} ,
} , {
2010-11-25 08:17:01 +03:00
. base = S5P64X0_GPB_BASE ,
2010-09-08 11:23:05 +04:00
. config = & s5p64x0_gpio_cfgs [ 1 ] ,
2010-01-19 09:31:17 +03:00
. chip = {
. base = S5P6440_GPB ( 0 ) ,
. ngpio = S5P6440_GPIO_B_NR ,
. label = " GPB " ,
} ,
} , {
2010-11-25 08:17:01 +03:00
. base = S5P64X0_GPC_BASE ,
2010-09-08 11:23:05 +04:00
. config = & s5p64x0_gpio_cfgs [ 1 ] ,
2010-01-19 09:31:17 +03:00
. chip = {
. base = S5P6440_GPC ( 0 ) ,
. ngpio = S5P6440_GPIO_C_NR ,
. label = " GPC " ,
} ,
} , {
2010-11-25 08:17:01 +03:00
. base = S5P64X0_GPG_BASE ,
2010-09-08 11:23:05 +04:00
. config = & s5p64x0_gpio_cfgs [ 1 ] ,
2010-01-19 09:31:17 +03:00
. chip = {
. base = S5P6440_GPG ( 0 ) ,
. ngpio = S5P6440_GPIO_G_NR ,
. label = " GPG " ,
} ,
} ,
} ;
static struct s3c_gpio_chip s5p6440_gpio_4bit2 [ ] = {
{
2010-11-25 08:17:01 +03:00
. base = S5P64X0_GPH_BASE + 0x4 ,
2010-09-08 11:23:05 +04:00
. config = & s5p64x0_gpio_cfgs [ 1 ] ,
2010-01-19 09:31:17 +03:00
. chip = {
. base = S5P6440_GPH ( 0 ) ,
. ngpio = S5P6440_GPIO_H_NR ,
. label = " GPH " ,
} ,
} ,
} ;
2010-09-08 11:23:05 +04:00
static struct s3c_gpio_chip s5p6440_gpio_rbank_4bit2 [ ] = {
2010-01-19 09:31:17 +03:00
{
2010-11-25 08:17:01 +03:00
. base = S5P64X0_GPR_BASE + 0x4 ,
2010-09-08 11:23:05 +04:00
. config = & s5p64x0_gpio_cfgs [ 2 ] ,
2010-01-19 09:31:17 +03:00
. chip = {
. base = S5P6440_GPR ( 0 ) ,
. ngpio = S5P6440_GPIO_R_NR ,
. label = " GPR " ,
} ,
} ,
} ;
static struct s3c_gpio_chip s5p6440_gpio_2bit [ ] = {
{
2010-11-25 08:17:01 +03:00
. base = S5P64X0_GPF_BASE ,
2010-09-08 11:23:05 +04:00
. config = & s5p64x0_gpio_cfgs [ 5 ] ,
2010-01-19 09:31:17 +03:00
. chip = {
. base = S5P6440_GPF ( 0 ) ,
. ngpio = S5P6440_GPIO_F_NR ,
. label = " GPF " ,
} ,
} , {
2010-11-25 08:17:01 +03:00
. base = S5P64X0_GPI_BASE ,
2010-09-08 11:23:05 +04:00
. config = & s5p64x0_gpio_cfgs [ 3 ] ,
2010-01-19 09:31:17 +03:00
. chip = {
. base = S5P6440_GPI ( 0 ) ,
. ngpio = S5P6440_GPIO_I_NR ,
. label = " GPI " ,
} ,
} , {
2010-11-25 08:17:01 +03:00
. base = S5P64X0_GPJ_BASE ,
2010-09-08 11:23:05 +04:00
. config = & s5p64x0_gpio_cfgs [ 3 ] ,
2010-01-19 09:31:17 +03:00
. chip = {
. base = S5P6440_GPJ ( 0 ) ,
. ngpio = S5P6440_GPIO_J_NR ,
. label = " GPJ " ,
} ,
} , {
2010-11-25 08:17:01 +03:00
. base = S5P64X0_GPN_BASE ,
2010-09-08 11:23:05 +04:00
. config = & s5p64x0_gpio_cfgs [ 4 ] ,
2010-01-19 09:31:17 +03:00
. chip = {
. base = S5P6440_GPN ( 0 ) ,
. ngpio = S5P6440_GPIO_N_NR ,
. label = " GPN " ,
} ,
} , {
2010-11-25 08:17:01 +03:00
. base = S5P64X0_GPP_BASE ,
2010-09-08 11:23:05 +04:00
. config = & s5p64x0_gpio_cfgs [ 5 ] ,
2010-01-19 09:31:17 +03:00
. chip = {
. base = S5P6440_GPP ( 0 ) ,
. ngpio = S5P6440_GPIO_P_NR ,
. label = " GPP " ,
} ,
} ,
} ;
2010-11-25 08:17:01 +03:00
static struct s3c_gpio_chip s5p6450_gpio_4bit [ ] = {
{
. base = S5P64X0_GPA_BASE ,
. config = & s5p64x0_gpio_cfgs [ 1 ] ,
. chip = {
. base = S5P6450_GPA ( 0 ) ,
. ngpio = S5P6450_GPIO_A_NR ,
. label = " GPA " ,
} ,
} , {
. base = S5P64X0_GPB_BASE ,
. config = & s5p64x0_gpio_cfgs [ 1 ] ,
. chip = {
. base = S5P6450_GPB ( 0 ) ,
. ngpio = S5P6450_GPIO_B_NR ,
. label = " GPB " ,
} ,
} , {
. base = S5P64X0_GPC_BASE ,
. config = & s5p64x0_gpio_cfgs [ 1 ] ,
. chip = {
. base = S5P6450_GPC ( 0 ) ,
. ngpio = S5P6450_GPIO_C_NR ,
. label = " GPC " ,
} ,
} , {
. base = S5P6450_GPD_BASE ,
. config = & s5p64x0_gpio_cfgs [ 1 ] ,
. chip = {
. base = S5P6450_GPD ( 0 ) ,
. ngpio = S5P6450_GPIO_D_NR ,
. label = " GPD " ,
} ,
} , {
. base = S5P6450_GPK_BASE ,
. config = & s5p64x0_gpio_cfgs [ 1 ] ,
. chip = {
. base = S5P6450_GPK ( 0 ) ,
. ngpio = S5P6450_GPIO_K_NR ,
. label = " GPK " ,
} ,
} ,
} ;
static struct s3c_gpio_chip s5p6450_gpio_4bit2 [ ] = {
{
. base = S5P64X0_GPG_BASE + 0x4 ,
. config = & s5p64x0_gpio_cfgs [ 1 ] ,
. chip = {
. base = S5P6450_GPG ( 0 ) ,
. ngpio = S5P6450_GPIO_G_NR ,
. label = " GPG " ,
} ,
} , {
. base = S5P64X0_GPH_BASE + 0x4 ,
. config = & s5p64x0_gpio_cfgs [ 1 ] ,
. chip = {
. base = S5P6450_GPH ( 0 ) ,
. ngpio = S5P6450_GPIO_H_NR ,
. label = " GPH " ,
} ,
} ,
} ;
static struct s3c_gpio_chip s5p6450_gpio_rbank_4bit2 [ ] = {
{
. base = S5P64X0_GPR_BASE + 0x4 ,
. config = & s5p64x0_gpio_cfgs [ 2 ] ,
. chip = {
. base = S5P6450_GPR ( 0 ) ,
. ngpio = S5P6450_GPIO_R_NR ,
. label = " GPR " ,
} ,
} ,
} ;
static struct s3c_gpio_chip s5p6450_gpio_2bit [ ] = {
{
. base = S5P64X0_GPF_BASE ,
. config = & s5p64x0_gpio_cfgs [ 5 ] ,
. chip = {
. base = S5P6450_GPF ( 0 ) ,
. ngpio = S5P6450_GPIO_F_NR ,
. label = " GPF " ,
} ,
} , {
. base = S5P64X0_GPI_BASE ,
. config = & s5p64x0_gpio_cfgs [ 3 ] ,
. chip = {
. base = S5P6450_GPI ( 0 ) ,
. ngpio = S5P6450_GPIO_I_NR ,
. label = " GPI " ,
} ,
} , {
. base = S5P64X0_GPJ_BASE ,
. config = & s5p64x0_gpio_cfgs [ 3 ] ,
. chip = {
. base = S5P6450_GPJ ( 0 ) ,
. ngpio = S5P6450_GPIO_J_NR ,
. label = " GPJ " ,
} ,
} , {
. base = S5P64X0_GPN_BASE ,
. config = & s5p64x0_gpio_cfgs [ 4 ] ,
. chip = {
. base = S5P6450_GPN ( 0 ) ,
. ngpio = S5P6450_GPIO_N_NR ,
. label = " GPN " ,
} ,
} , {
. base = S5P64X0_GPP_BASE ,
. config = & s5p64x0_gpio_cfgs [ 5 ] ,
. chip = {
. base = S5P6450_GPP ( 0 ) ,
. ngpio = S5P6450_GPIO_P_NR ,
. label = " GPP " ,
} ,
} , {
. base = S5P6450_GPQ_BASE ,
. config = & s5p64x0_gpio_cfgs [ 4 ] ,
. chip = {
. base = S5P6450_GPQ ( 0 ) ,
. ngpio = S5P6450_GPIO_Q_NR ,
. label = " GPQ " ,
} ,
} , {
. base = S5P6450_GPS_BASE ,
. config = & s5p64x0_gpio_cfgs [ 5 ] ,
. chip = {
. base = S5P6450_GPS ( 0 ) ,
. ngpio = S5P6450_GPIO_S_NR ,
. label = " GPS " ,
} ,
} ,
} ;
2010-09-08 11:23:05 +04:00
void __init s5p64x0_gpiolib_set_cfg ( struct s3c_gpio_cfg * chipcfg , int nr_chips )
2010-01-19 09:31:17 +03:00
{
for ( ; nr_chips > 0 ; nr_chips - - , chipcfg + + ) {
if ( ! chipcfg - > set_config )
chipcfg - > set_config = s3c_gpio_setcfg_s3c64xx_4bit ;
2010-05-06 05:27:16 +04:00
if ( ! chipcfg - > get_config )
chipcfg - > get_config = s3c_gpio_getcfg_s3c64xx_4bit ;
2010-01-19 09:31:17 +03:00
if ( ! chipcfg - > set_pull )
chipcfg - > set_pull = s3c_gpio_setpull_updown ;
if ( ! chipcfg - > get_pull )
chipcfg - > get_pull = s3c_gpio_getpull_updown ;
}
}
2010-09-08 11:23:05 +04:00
static void __init s5p64x0_gpio_add_rbank_4bit2 ( struct s3c_gpio_chip * chip ,
2010-01-19 09:31:17 +03:00
int nr_chips )
{
for ( ; nr_chips > 0 ; nr_chips - - , chip + + ) {
2010-09-08 11:23:05 +04:00
chip - > chip . direction_input = s5p64x0_gpiolib_rbank_4bit2_input ;
2010-01-19 09:31:17 +03:00
chip - > chip . direction_output =
2010-09-08 11:23:05 +04:00
s5p64x0_gpiolib_rbank_4bit2_output ;
2010-01-19 09:31:17 +03:00
s3c_gpiolib_add ( chip ) ;
}
}
2010-11-25 08:17:01 +03:00
static int __init s5p64x0_gpiolib_init ( void )
2010-01-19 09:31:17 +03:00
{
2010-09-08 11:23:05 +04:00
s5p64x0_gpiolib_set_cfg ( s5p64x0_gpio_cfgs ,
ARRAY_SIZE ( s5p64x0_gpio_cfgs ) ) ;
2010-11-25 08:17:01 +03:00
2011-08-19 21:30:08 +04:00
if ( soc_is_s5p6450 ( ) ) {
2010-11-24 05:00:16 +03:00
samsung_gpiolib_add_2bit_chips ( s5p6450_gpio_2bit ,
ARRAY_SIZE ( s5p6450_gpio_2bit ) ) ;
2010-01-19 09:31:17 +03:00
2010-11-25 08:17:01 +03:00
samsung_gpiolib_add_4bit_chips ( s5p6450_gpio_4bit ,
ARRAY_SIZE ( s5p6450_gpio_4bit ) ) ;
2010-01-19 09:31:17 +03:00
2010-11-25 08:17:01 +03:00
samsung_gpiolib_add_4bit2_chips ( s5p6450_gpio_4bit2 ,
ARRAY_SIZE ( s5p6450_gpio_4bit2 ) ) ;
2010-01-19 09:31:17 +03:00
2010-11-25 08:17:01 +03:00
s5p64x0_gpio_add_rbank_4bit2 ( s5p6450_gpio_rbank_4bit2 ,
ARRAY_SIZE ( s5p6450_gpio_rbank_4bit2 ) ) ;
} else {
2010-11-24 05:00:16 +03:00
samsung_gpiolib_add_2bit_chips ( s5p6440_gpio_2bit ,
ARRAY_SIZE ( s5p6440_gpio_2bit ) ) ;
2010-01-19 09:31:17 +03:00
2010-11-25 08:17:01 +03:00
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 ) ) ;
s5p64x0_gpio_add_rbank_4bit2 ( s5p6440_gpio_rbank_4bit2 ,
ARRAY_SIZE ( s5p6440_gpio_rbank_4bit2 ) ) ;
}
2010-01-19 09:31:17 +03:00
return 0 ;
}
2010-12-03 14:45:48 +03:00
core_initcall ( s5p64x0_gpiolib_init ) ;