2005-04-16 15:20:36 -07:00
/* linux/arch/arm/mach-s3c2410/gpio.c
*
* Copyright ( c ) 2004 - 2005 Simtec Electronics
* Ben Dooks < ben @ simtec . co . uk >
*
2006-10-30 02:27:45 +01:00
* S3C24XX GPIO support
2005-04-16 15:20:36 -07:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2006-09-20 20:54:54 +01:00
*/
2005-04-16 15:20:36 -07:00
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/module.h>
# include <linux/interrupt.h>
# include <linux/ioport.h>
# include <asm/hardware.h>
# include <asm/irq.h>
# include <asm/io.h>
# include <asm/arch/regs-gpio.h>
void s3c2410_gpio_cfgpin ( unsigned int pin , unsigned int function )
{
2006-02-01 21:24:23 +00:00
void __iomem * base = S3C24XX_GPIO_BASE ( pin ) ;
2005-04-16 15:20:36 -07:00
unsigned long mask ;
unsigned long con ;
unsigned long flags ;
if ( pin < S3C2410_GPIO_BANKB ) {
mask = 1 < < S3C2410_GPIO_OFFSET ( pin ) ;
} else {
mask = 3 < < S3C2410_GPIO_OFFSET ( pin ) * 2 ;
}
2005-10-28 15:26:41 +01:00
switch ( function ) {
case S3C2410_GPIO_LEAVE :
mask = 0 ;
function = 0 ;
break ;
case S3C2410_GPIO_INPUT :
case S3C2410_GPIO_OUTPUT :
case S3C2410_GPIO_SFN2 :
case S3C2410_GPIO_SFN3 :
if ( pin < S3C2410_GPIO_BANKB ) {
2007-01-16 12:33:35 +01:00
function - = 1 ;
2005-10-28 15:26:41 +01:00
function & = 1 ;
function < < = S3C2410_GPIO_OFFSET ( pin ) ;
} else {
function & = 3 ;
function < < = S3C2410_GPIO_OFFSET ( pin ) * 2 ;
}
}
/* modify the specified register wwith IRQs off */
2005-04-16 15:20:36 -07:00
local_irq_save ( flags ) ;
con = __raw_readl ( base + 0x00 ) ;
con & = ~ mask ;
con | = function ;
__raw_writel ( con , base + 0x00 ) ;
local_irq_restore ( flags ) ;
}
EXPORT_SYMBOL ( s3c2410_gpio_cfgpin ) ;
unsigned int s3c2410_gpio_getcfg ( unsigned int pin )
{
2006-02-01 21:24:23 +00:00
void __iomem * base = S3C24XX_GPIO_BASE ( pin ) ;
2005-04-16 15:20:36 -07:00
unsigned long mask ;
if ( pin < S3C2410_GPIO_BANKB ) {
mask = 1 < < S3C2410_GPIO_OFFSET ( pin ) ;
} else {
mask = 3 < < S3C2410_GPIO_OFFSET ( pin ) * 2 ;
}
return __raw_readl ( base ) & mask ;
}
EXPORT_SYMBOL ( s3c2410_gpio_getcfg ) ;
void s3c2410_gpio_pullup ( unsigned int pin , unsigned int to )
{
2006-02-01 21:24:23 +00:00
void __iomem * base = S3C24XX_GPIO_BASE ( pin ) ;
2005-04-16 15:20:36 -07:00
unsigned long offs = S3C2410_GPIO_OFFSET ( pin ) ;
unsigned long flags ;
unsigned long up ;
if ( pin < S3C2410_GPIO_BANKB )
return ;
local_irq_save ( flags ) ;
up = __raw_readl ( base + 0x08 ) ;
up & = ~ ( 1L < < offs ) ;
up | = to < < offs ;
__raw_writel ( up , base + 0x08 ) ;
local_irq_restore ( flags ) ;
}
EXPORT_SYMBOL ( s3c2410_gpio_pullup ) ;
void s3c2410_gpio_setpin ( unsigned int pin , unsigned int to )
{
2006-02-01 21:24:23 +00:00
void __iomem * base = S3C24XX_GPIO_BASE ( pin ) ;
2005-04-16 15:20:36 -07:00
unsigned long offs = S3C2410_GPIO_OFFSET ( pin ) ;
unsigned long flags ;
unsigned long dat ;
local_irq_save ( flags ) ;
dat = __raw_readl ( base + 0x04 ) ;
dat & = ~ ( 1 < < offs ) ;
dat | = to < < offs ;
__raw_writel ( dat , base + 0x04 ) ;
local_irq_restore ( flags ) ;
}
EXPORT_SYMBOL ( s3c2410_gpio_setpin ) ;
unsigned int s3c2410_gpio_getpin ( unsigned int pin )
{
2006-02-01 21:24:23 +00:00
void __iomem * base = S3C24XX_GPIO_BASE ( pin ) ;
2005-04-16 15:20:36 -07:00
unsigned long offs = S3C2410_GPIO_OFFSET ( pin ) ;
return __raw_readl ( base + 0x04 ) & ( 1 < < offs ) ;
}
EXPORT_SYMBOL ( s3c2410_gpio_getpin ) ;
unsigned int s3c2410_modify_misccr ( unsigned int clear , unsigned int change )
{
unsigned long flags ;
unsigned long misccr ;
local_irq_save ( flags ) ;
2006-02-01 21:24:23 +00:00
misccr = __raw_readl ( S3C24XX_MISCCR ) ;
2005-04-16 15:20:36 -07:00
misccr & = ~ clear ;
misccr ^ = change ;
2006-02-01 21:24:23 +00:00
__raw_writel ( misccr , S3C24XX_MISCCR ) ;
2005-04-16 15:20:36 -07:00
local_irq_restore ( flags ) ;
return misccr ;
}
EXPORT_SYMBOL ( s3c2410_modify_misccr ) ;
2006-10-30 02:27:45 +01:00
int s3c2410_gpio_getirq ( unsigned int pin )
{
if ( pin < S3C2410_GPF0 | | pin > S3C2410_GPG15 )
return - 1 ; /* not valid interrupts */
if ( pin < S3C2410_GPG0 & & pin > S3C2410_GPF7 )
return - 1 ; /* not valid pin */
if ( pin < S3C2410_GPF4 )
return ( pin - S3C2410_GPF0 ) + IRQ_EINT0 ;
if ( pin < S3C2410_GPG0 )
return ( pin - S3C2410_GPF4 ) + IRQ_EINT4 ;
return ( pin - S3C2410_GPG0 ) + IRQ_EINT8 ;
}
EXPORT_SYMBOL ( s3c2410_gpio_getirq ) ;