2008-10-31 16:14:34 +00:00
/* linux/arch/arm/plat-s3c/gpio-config.c
*
* Copyright 2008 Openmoko , Inc .
2010-05-06 10:27:16 +09:00
* Copyright 2008 - 2010 Simtec Electronics
2008-10-31 16:14:34 +00:00
* Ben Dooks < ben @ simtec . co . uk >
* http : //armlinux.simtec.co.uk/
*
* S3C series GPIO configuration core
*
* 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>
2009-03-10 23:21:48 +00:00
# include <linux/module.h>
2008-10-31 16:14:34 +00:00
# include <linux/gpio.h>
# include <linux/io.h>
2010-01-19 17:14:46 +09:00
# include <plat/gpio-core.h>
2008-10-31 16:14:34 +00:00
# include <plat/gpio-cfg.h>
# include <plat/gpio-cfg-helpers.h>
int s3c_gpio_cfgpin ( unsigned int pin , unsigned int config )
{
struct s3c_gpio_chip * chip = s3c_gpiolib_getchip ( pin ) ;
unsigned long flags ;
int offset ;
int ret ;
if ( ! chip )
return - EINVAL ;
offset = pin - chip - > chip . base ;
2010-05-06 15:42:23 +09:00
s3c_gpio_lock ( chip , flags ) ;
2008-10-31 16:14:34 +00:00
ret = s3c_gpio_do_setcfg ( chip , offset , config ) ;
2010-05-06 15:42:23 +09:00
s3c_gpio_unlock ( chip , flags ) ;
2008-10-31 16:14:34 +00:00
return ret ;
}
2009-03-10 23:21:48 +00:00
EXPORT_SYMBOL ( s3c_gpio_cfgpin ) ;
2008-10-31 16:14:34 +00:00
2010-10-01 13:37:13 +09:00
int s3c_gpio_cfgpin_range ( unsigned int start , unsigned int nr ,
unsigned int cfg )
{
int ret ;
for ( ; nr > 0 ; nr - - , start + + ) {
ret = s3c_gpio_cfgpin ( start , cfg ) ;
if ( ret ! = 0 )
return ret ;
}
return 0 ;
}
EXPORT_SYMBOL_GPL ( s3c_gpio_cfgpin_range ) ;
2010-10-01 16:34:34 +09:00
int s3c_gpio_cfgall_range ( unsigned int start , unsigned int nr ,
unsigned int cfg , s3c_gpio_pull_t pull )
{
int ret ;
for ( ; nr > 0 ; nr - - , start + + ) {
s3c_gpio_setpull ( start , pull ) ;
ret = s3c_gpio_cfgpin ( start , cfg ) ;
if ( ret ! = 0 )
return ret ;
}
return 0 ;
}
EXPORT_SYMBOL_GPL ( s3c_gpio_cfgall_range ) ;
2010-05-06 10:50:42 +09:00
unsigned s3c_gpio_getcfg ( unsigned int pin )
{
struct s3c_gpio_chip * chip = s3c_gpiolib_getchip ( pin ) ;
unsigned long flags ;
unsigned ret = 0 ;
int offset ;
if ( chip ) {
offset = pin - chip - > chip . base ;
2010-05-06 15:42:23 +09:00
s3c_gpio_lock ( chip , flags ) ;
2010-05-06 10:50:42 +09:00
ret = s3c_gpio_do_getcfg ( chip , offset ) ;
2010-05-06 15:42:23 +09:00
s3c_gpio_unlock ( chip , flags ) ;
2010-05-06 10:50:42 +09:00
}
return ret ;
}
EXPORT_SYMBOL ( s3c_gpio_getcfg ) ;
2008-10-31 16:14:34 +00:00
int s3c_gpio_setpull ( unsigned int pin , s3c_gpio_pull_t pull )
{
struct s3c_gpio_chip * chip = s3c_gpiolib_getchip ( pin ) ;
unsigned long flags ;
int offset , ret ;
if ( ! chip )
return - EINVAL ;
offset = pin - chip - > chip . base ;
2010-05-06 15:42:23 +09:00
s3c_gpio_lock ( chip , flags ) ;
2008-10-31 16:14:34 +00:00
ret = s3c_gpio_do_setpull ( chip , offset , pull ) ;
2010-05-06 15:42:23 +09:00
s3c_gpio_unlock ( chip , flags ) ;
2008-10-31 16:14:34 +00:00
return ret ;
}
2009-03-10 23:21:48 +00:00
EXPORT_SYMBOL ( s3c_gpio_setpull ) ;
2008-10-31 16:14:34 +00:00
2010-10-26 08:40:08 +09:00
s3c_gpio_pull_t s3c_gpio_getpull ( unsigned int pin )
{
struct s3c_gpio_chip * chip = s3c_gpiolib_getchip ( pin ) ;
unsigned long flags ;
int offset ;
u32 pup = 0 ;
if ( chip ) {
offset = pin - chip - > chip . base ;
s3c_gpio_lock ( chip , flags ) ;
pup = s3c_gpio_do_getpull ( chip , offset ) ;
s3c_gpio_unlock ( chip , flags ) ;
}
return ( __force s3c_gpio_pull_t ) pup ;
}
EXPORT_SYMBOL ( s3c_gpio_getpull ) ;
2008-10-31 16:14:34 +00:00
# ifdef CONFIG_S3C_GPIO_CFG_S3C24XX
2010-04-30 19:30:35 +09:00
int s3c_gpio_setcfg_s3c24xx_a ( struct s3c_gpio_chip * chip ,
unsigned int off , unsigned int cfg )
2008-10-31 16:14:34 +00:00
{
void __iomem * reg = chip - > base ;
unsigned int shift = off ;
u32 con ;
if ( s3c_gpio_is_cfg_special ( cfg ) ) {
cfg & = 0xf ;
/* Map output to 0, and SFN2 to 1 */
cfg - = 1 ;
if ( cfg > 1 )
return - EINVAL ;
cfg < < = shift ;
}
con = __raw_readl ( reg ) ;
con & = ~ ( 0x1 < < shift ) ;
con | = cfg ;
__raw_writel ( con , reg ) ;
return 0 ;
}
2010-05-06 10:27:16 +09:00
unsigned s3c_gpio_getcfg_s3c24xx_a ( struct s3c_gpio_chip * chip ,
unsigned int off )
{
u32 con ;
con = __raw_readl ( chip - > base ) ;
con > > = off ;
con & = 1 ;
con + + ;
return S3C_GPIO_SFN ( con ) ;
}
2008-10-31 16:14:34 +00:00
int s3c_gpio_setcfg_s3c24xx ( struct s3c_gpio_chip * chip ,
unsigned int off , unsigned int cfg )
{
void __iomem * reg = chip - > base ;
unsigned int shift = off * 2 ;
u32 con ;
if ( s3c_gpio_is_cfg_special ( cfg ) ) {
cfg & = 0xf ;
if ( cfg > 3 )
return - EINVAL ;
cfg < < = shift ;
}
con = __raw_readl ( reg ) ;
con & = ~ ( 0x3 < < shift ) ;
con | = cfg ;
__raw_writel ( con , reg ) ;
return 0 ;
}
2010-05-06 10:27:16 +09:00
unsigned int s3c_gpio_getcfg_s3c24xx ( struct s3c_gpio_chip * chip ,
unsigned int off )
{
u32 con ;
con = __raw_readl ( chip - > base ) ;
con > > = off * 2 ;
con & = 3 ;
/* this conversion works for IN and OUT as well as special mode */
return S3C_GPIO_SPECIAL ( con ) ;
}
2008-10-31 16:14:34 +00:00
# endif
# ifdef CONFIG_S3C_GPIO_CFG_S3C64XX
int s3c_gpio_setcfg_s3c64xx_4bit ( struct s3c_gpio_chip * chip ,
unsigned int off , unsigned int cfg )
{
void __iomem * reg = chip - > base ;
unsigned int shift = ( off & 7 ) * 4 ;
u32 con ;
2009-06-18 13:30:16 +02:00
if ( off < 8 & & chip - > chip . ngpio > 8 )
2008-10-31 16:14:34 +00:00
reg - = 4 ;
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-05-06 10:27:16 +09:00
unsigned s3c_gpio_getcfg_s3c64xx_4bit ( struct s3c_gpio_chip * chip ,
unsigned int off )
{
void __iomem * reg = chip - > base ;
unsigned int shift = ( off & 7 ) * 4 ;
u32 con ;
if ( off < 8 & & chip - > chip . ngpio > 8 )
reg - = 4 ;
con = __raw_readl ( reg ) ;
con > > = shift ;
con & = 0xf ;
/* this conversion works for IN and OUT as well as special mode */
return S3C_GPIO_SPECIAL ( con ) ;
}
2008-10-31 16:14:34 +00:00
# endif /* CONFIG_S3C_GPIO_CFG_S3C64XX */
# ifdef CONFIG_S3C_GPIO_PULL_UPDOWN
int s3c_gpio_setpull_updown ( struct s3c_gpio_chip * chip ,
unsigned int off , s3c_gpio_pull_t pull )
{
void __iomem * reg = chip - > base + 0x08 ;
int shift = off * 2 ;
u32 pup ;
pup = __raw_readl ( reg ) ;
pup & = ~ ( 3 < < shift ) ;
pup | = pull < < shift ;
__raw_writel ( pup , reg ) ;
return 0 ;
}
s3c_gpio_pull_t s3c_gpio_getpull_updown ( struct s3c_gpio_chip * chip ,
unsigned int off )
{
void __iomem * reg = chip - > base + 0x08 ;
int shift = off * 2 ;
u32 pup = __raw_readl ( reg ) ;
pup > > = shift ;
pup & = 0x3 ;
return ( __force s3c_gpio_pull_t ) pup ;
}
2011-01-06 13:04:33 +09:00
# ifdef CONFIG_S3C_GPIO_PULL_S3C2443
int s3c_gpio_setpull_s3c2443 ( struct s3c_gpio_chip * chip ,
unsigned int off , s3c_gpio_pull_t pull )
{
switch ( pull ) {
case S3C_GPIO_PULL_NONE :
pull = 0x01 ;
break ;
case S3C_GPIO_PULL_UP :
pull = 0x00 ;
break ;
case S3C_GPIO_PULL_DOWN :
pull = 0x02 ;
break ;
}
return s3c_gpio_setpull_updown ( chip , off , pull ) ;
}
s3c_gpio_pull_t s3c_gpio_getpull_s3c2443 ( struct s3c_gpio_chip * chip ,
unsigned int off )
{
s3c_gpio_pull_t pull ;
pull = s3c_gpio_getpull_updown ( chip , off ) ;
switch ( pull ) {
case 0x00 :
pull = S3C_GPIO_PULL_UP ;
break ;
case 0x01 :
case 0x03 :
pull = S3C_GPIO_PULL_NONE ;
break ;
case 0x02 :
pull = S3C_GPIO_PULL_DOWN ;
break ;
}
return pull ;
}
# endif
2008-10-31 16:14:34 +00:00
# endif
2010-05-03 14:39:45 +09:00
2010-12-01 08:29:23 +02:00
# if defined(CONFIG_S3C_GPIO_PULL_UP) || defined(CONFIG_S3C_GPIO_PULL_DOWN)
static int s3c_gpio_setpull_1 ( struct s3c_gpio_chip * chip ,
unsigned int off , s3c_gpio_pull_t pull ,
s3c_gpio_pull_t updown )
2010-05-03 14:39:45 +09:00
{
void __iomem * reg = chip - > base + 0x08 ;
u32 pup = __raw_readl ( reg ) ;
2010-12-01 08:29:23 +02:00
if ( pull = = updown )
2010-05-03 14:39:45 +09:00
pup & = ~ ( 1 < < off ) ;
2010-12-01 08:29:23 +02:00
else if ( pull = = S3C_GPIO_PULL_NONE )
2010-05-03 14:39:45 +09:00
pup | = ( 1 < < off ) ;
else
return - EINVAL ;
__raw_writel ( pup , reg ) ;
return 0 ;
}
2010-12-01 08:29:23 +02:00
static s3c_gpio_pull_t s3c_gpio_getpull_1 ( struct s3c_gpio_chip * chip ,
unsigned int off , s3c_gpio_pull_t updown )
2010-05-03 14:39:45 +09:00
{
void __iomem * reg = chip - > base + 0x08 ;
u32 pup = __raw_readl ( reg ) ;
pup & = ( 1 < < off ) ;
2010-12-01 08:29:23 +02:00
return pup ? S3C_GPIO_PULL_NONE : updown ;
}
# endif /* CONFIG_S3C_GPIO_PULL_UP || CONFIG_S3C_GPIO_PULL_DOWN */
# ifdef CONFIG_S3C_GPIO_PULL_UP
s3c_gpio_pull_t s3c_gpio_getpull_1up ( struct s3c_gpio_chip * chip ,
unsigned int off )
{
return s3c_gpio_getpull_1 ( chip , off , S3C_GPIO_PULL_UP ) ;
}
int s3c_gpio_setpull_1up ( struct s3c_gpio_chip * chip ,
unsigned int off , s3c_gpio_pull_t pull )
{
return s3c_gpio_setpull_1 ( chip , off , pull , S3C_GPIO_PULL_UP ) ;
2010-05-03 14:39:45 +09:00
}
# endif /* CONFIG_S3C_GPIO_PULL_UP */
2010-12-01 08:29:23 +02:00
# ifdef CONFIG_S3C_GPIO_PULL_DOWN
s3c_gpio_pull_t s3c_gpio_getpull_1down ( struct s3c_gpio_chip * chip ,
unsigned int off )
{
return s3c_gpio_getpull_1 ( chip , off , S3C_GPIO_PULL_DOWN ) ;
}
int s3c_gpio_setpull_1down ( struct s3c_gpio_chip * chip ,
unsigned int off , s3c_gpio_pull_t pull )
{
return s3c_gpio_setpull_1 ( chip , off , pull , S3C_GPIO_PULL_DOWN ) ;
}
# endif /* CONFIG_S3C_GPIO_PULL_DOWN */
2010-05-18 12:23:36 +02:00
# ifdef CONFIG_S5P_GPIO_DRVSTR
s5p_gpio_drvstr_t s5p_gpio_get_drvstr ( unsigned int pin )
{
struct s3c_gpio_chip * chip = s3c_gpiolib_getchip ( pin ) ;
unsigned int off ;
void __iomem * reg ;
int shift ;
u32 drvstr ;
if ( ! chip )
return - EINVAL ;
2010-08-30 12:07:58 +09:00
off = pin - chip - > chip . base ;
2010-05-18 12:23:36 +02:00
shift = off * 2 ;
reg = chip - > base + 0x0C ;
drvstr = __raw_readl ( reg ) ;
drvstr = drvstr > > shift ;
2010-08-30 12:07:58 +09:00
drvstr & = 0x3 ;
2010-05-18 12:23:36 +02:00
return ( __force s5p_gpio_drvstr_t ) drvstr ;
}
EXPORT_SYMBOL ( s5p_gpio_get_drvstr ) ;
int s5p_gpio_set_drvstr ( unsigned int pin , s5p_gpio_drvstr_t drvstr )
{
struct s3c_gpio_chip * chip = s3c_gpiolib_getchip ( pin ) ;
unsigned int off ;
void __iomem * reg ;
int shift ;
u32 tmp ;
if ( ! chip )
return - EINVAL ;
2010-08-30 12:07:58 +09:00
off = pin - chip - > chip . base ;
2010-05-18 12:23:36 +02:00
shift = off * 2 ;
reg = chip - > base + 0x0C ;
tmp = __raw_readl ( reg ) ;
2010-08-30 12:07:58 +09:00
tmp & = ~ ( 0x3 < < shift ) ;
2010-05-18 12:23:36 +02:00
tmp | = drvstr < < shift ;
__raw_writel ( tmp , reg ) ;
return 0 ;
}
EXPORT_SYMBOL ( s5p_gpio_set_drvstr ) ;
# endif /* CONFIG_S5P_GPIO_DRVSTR */