2008-07-03 14:24:25 +04:00
/* linux/arch/arm/plat-s3c24xx/gpiolib.c
*
* Copyright ( c ) 2008 Simtec Electronics
* http : //armlinux.simtec.co.uk/
* Ben Dooks < ben @ simtec . co . uk >
*
* S3C24XX GPIOlib support
*
* 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 .
*/
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/module.h>
# include <linux/interrupt.h>
# include <linux/ioport.h>
# include <linux/io.h>
# include <linux/gpio.h>
2008-08-05 19:14:15 +04:00
# include <mach/hardware.h>
2008-07-03 14:24:25 +04:00
# include <asm/irq.h>
2008-08-05 19:14:15 +04:00
# include <mach/regs-gpio.h>
2008-07-03 14:24:25 +04:00
struct s3c24xx_gpio_chip {
struct gpio_chip chip ;
void __iomem * base ;
} ;
static inline struct s3c24xx_gpio_chip * to_s3c_chip ( struct gpio_chip * gpc )
{
return container_of ( gpc , struct s3c24xx_gpio_chip , chip ) ;
}
/* these routines are exported for use by other parts of the platform
* and system support , but are not intended to be used directly by the
* drivers themsevles .
*/
2008-08-27 01:54:03 +04:00
static int s3c24xx_gpiolib_input ( struct gpio_chip * chip , unsigned offset )
2008-07-03 14:24:25 +04:00
{
struct s3c24xx_gpio_chip * ourchip = to_s3c_chip ( chip ) ;
void __iomem * base = ourchip - > base ;
unsigned long flags ;
unsigned long con ;
local_irq_save ( flags ) ;
con = __raw_readl ( base + 0x00 ) ;
con & = ~ ( 3 < < ( offset * 2 ) ) ;
con | = ( S3C2410_GPIO_OUTPUT & 0xf ) < < ( offset * 2 ) ;
__raw_writel ( con , base + 0x00 ) ;
local_irq_restore ( flags ) ;
return 0 ;
}
2008-08-27 01:54:03 +04:00
static int s3c24xx_gpiolib_output ( struct gpio_chip * chip ,
2008-07-03 14:24:25 +04:00
unsigned offset , int value )
{
struct s3c24xx_gpio_chip * ourchip = to_s3c_chip ( chip ) ;
void __iomem * base = ourchip - > base ;
unsigned long flags ;
unsigned long dat ;
unsigned long con ;
local_irq_save ( flags ) ;
dat = __raw_readl ( base + 0x04 ) ;
dat & = ~ ( 1 < < offset ) ;
if ( value )
dat | = 1 < < offset ;
__raw_writel ( dat , base + 0x04 ) ;
con = __raw_readl ( base + 0x00 ) ;
con & = ~ ( 3 < < ( offset * 2 ) ) ;
con | = ( S3C2410_GPIO_OUTPUT & 0xf ) < < ( offset * 2 ) ;
__raw_writel ( con , base + 0x00 ) ;
__raw_writel ( dat , base + 0x04 ) ;
local_irq_restore ( flags ) ;
return 0 ;
}
2008-08-27 01:54:03 +04:00
static void s3c24xx_gpiolib_set ( struct gpio_chip * chip ,
unsigned offset , int value )
2008-07-03 14:24:25 +04:00
{
struct s3c24xx_gpio_chip * ourchip = to_s3c_chip ( chip ) ;
void __iomem * base = ourchip - > base ;
unsigned long flags ;
unsigned long dat ;
local_irq_save ( flags ) ;
dat = __raw_readl ( base + 0x04 ) ;
dat & = ~ ( 1 < < offset ) ;
if ( value )
dat | = 1 < < offset ;
__raw_writel ( dat , base + 0x04 ) ;
local_irq_restore ( flags ) ;
}
2008-08-27 01:54:03 +04:00
static int s3c24xx_gpiolib_get ( struct gpio_chip * chip , unsigned offset )
2008-07-03 14:24:25 +04:00
{
struct s3c24xx_gpio_chip * ourchip = to_s3c_chip ( chip ) ;
unsigned long val ;
val = __raw_readl ( ourchip - > base + 0x04 ) ;
val > > = offset ;
val & = 1 ;
return val ;
}
static int s3c24xx_gpiolib_banka_input ( struct gpio_chip * chip , unsigned offset )
{
return - EINVAL ;
}
static int s3c24xx_gpiolib_banka_output ( struct gpio_chip * chip ,
unsigned offset , int value )
{
struct s3c24xx_gpio_chip * ourchip = to_s3c_chip ( chip ) ;
void __iomem * base = ourchip - > base ;
unsigned long flags ;
unsigned long dat ;
unsigned long con ;
local_irq_save ( flags ) ;
con = __raw_readl ( base + 0x00 ) ;
dat = __raw_readl ( base + 0x04 ) ;
dat & = ~ ( 1 < < offset ) ;
if ( value )
dat | = 1 < < offset ;
__raw_writel ( dat , base + 0x04 ) ;
con & = ~ ( 1 < < offset ) ;
__raw_writel ( con , base + 0x00 ) ;
__raw_writel ( dat , base + 0x04 ) ;
local_irq_restore ( flags ) ;
return 0 ;
}
2008-08-27 01:54:03 +04:00
static struct s3c24xx_gpio_chip gpios [ ] = {
2008-07-03 14:24:25 +04:00
[ 0 ] = {
. base = S3C24XX_GPIO_BASE ( S3C2410_GPA0 ) ,
. chip = {
. base = S3C2410_GPA0 ,
. owner = THIS_MODULE ,
. label = " GPIOA " ,
. ngpio = 24 ,
. direction_input = s3c24xx_gpiolib_banka_input ,
. direction_output = s3c24xx_gpiolib_banka_output ,
} ,
} ,
[ 1 ] = {
. base = S3C24XX_GPIO_BASE ( S3C2410_GPB0 ) ,
. chip = {
. base = S3C2410_GPB0 ,
. owner = THIS_MODULE ,
. label = " GPIOB " ,
. ngpio = 16 ,
} ,
} ,
[ 2 ] = {
. base = S3C24XX_GPIO_BASE ( S3C2410_GPC0 ) ,
. chip = {
. base = S3C2410_GPC0 ,
. owner = THIS_MODULE ,
. label = " GPIOC " ,
. ngpio = 16 ,
} ,
} ,
[ 3 ] = {
. base = S3C24XX_GPIO_BASE ( S3C2410_GPD0 ) ,
. chip = {
. base = S3C2410_GPD0 ,
. owner = THIS_MODULE ,
. label = " GPIOD " ,
. ngpio = 16 ,
} ,
} ,
[ 4 ] = {
. base = S3C24XX_GPIO_BASE ( S3C2410_GPE0 ) ,
. chip = {
. base = S3C2410_GPE0 ,
. label = " GPIOE " ,
. owner = THIS_MODULE ,
. ngpio = 16 ,
} ,
} ,
[ 5 ] = {
. base = S3C24XX_GPIO_BASE ( S3C2410_GPF0 ) ,
. chip = {
. base = S3C2410_GPF0 ,
. owner = THIS_MODULE ,
. label = " GPIOF " ,
. ngpio = 8 ,
} ,
} ,
[ 6 ] = {
. base = S3C24XX_GPIO_BASE ( S3C2410_GPG0 ) ,
. chip = {
. base = S3C2410_GPG0 ,
. owner = THIS_MODULE ,
. label = " GPIOG " ,
. ngpio = 10 ,
} ,
} ,
} ;
2008-10-31 19:14:27 +03:00
static __init void s3c24xx_gpiolib_add ( struct s3c24xx_gpio_chip * chip )
{
struct gpio_chip * gc = & chip - > chip ;
BUG_ON ( ! chip - > base ) ;
BUG_ON ( ! gc - > label ) ;
BUG_ON ( ! gc - > ngpio ) ;
if ( ! gc - > direction_input )
gc - > direction_input = s3c24xx_gpiolib_input ;
if ( ! gc - > direction_output )
gc - > direction_output = s3c24xx_gpiolib_output ;
if ( ! gc - > set )
gc - > set = s3c24xx_gpiolib_set ;
if ( ! gc - > get )
gc - > get = s3c24xx_gpiolib_get ;
/* gpiochip_add() prints own failure message on error. */
gpiochip_add ( gc ) ;
}
2008-07-03 14:24:25 +04:00
static __init int s3c24xx_gpiolib_init ( void )
{
struct s3c24xx_gpio_chip * chip = gpios ;
int gpn ;
for ( gpn = 0 ; gpn < ARRAY_SIZE ( gpios ) ; gpn + + , chip + + )
2008-10-31 19:14:27 +03:00
s3c24xx_gpiolib_add ( chip ) ;
2008-07-03 14:24:25 +04:00
return 0 ;
}
arch_initcall ( s3c24xx_gpiolib_init ) ;