2010-05-18 20:51:20 +04:00
/*
* Texas Instruments TNETV107X GPIO Controller
*
* Copyright ( C ) 2010 Texas Instruments
*
* 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 version 2.
*
* This program is distributed " as is " WITHOUT ANY WARRANTY of any
* kind , whether express or implied ; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/gpio.h>
2013-08-18 09:19:03 +04:00
# include <linux/platform_data/gpio-davinci.h>
2010-05-18 20:51:20 +04:00
# include <mach/common.h>
# include <mach/tnetv107x.h>
struct tnetv107x_gpio_regs {
u32 idver ;
u32 data_in [ 3 ] ;
u32 data_out [ 3 ] ;
u32 direction [ 3 ] ;
u32 enable [ 3 ] ;
} ;
# define gpio_reg_index(gpio) ((gpio) >> 5)
# define gpio_reg_bit(gpio) BIT((gpio) & 0x1f)
# define gpio_reg_rmw(reg, mask, val) \
__raw_writel ( ( __raw_readl ( reg ) & ~ ( mask ) ) | ( val ) , ( reg ) )
# define gpio_reg_set_bit(reg, gpio) \
gpio_reg_rmw ( ( reg ) + gpio_reg_index ( gpio ) , 0 , gpio_reg_bit ( gpio ) )
# define gpio_reg_clear_bit(reg, gpio) \
gpio_reg_rmw ( ( reg ) + gpio_reg_index ( gpio ) , gpio_reg_bit ( gpio ) , 0 )
# define gpio_reg_get_bit(reg, gpio) \
( __raw_readl ( ( reg ) + gpio_reg_index ( gpio ) ) & gpio_reg_bit ( gpio ) )
# define chip2controller(chip) \
container_of ( chip , struct davinci_gpio_controller , chip )
# define TNETV107X_GPIO_CTLRS DIV_ROUND_UP(TNETV107X_N_GPIO, 32)
static struct davinci_gpio_controller chips [ TNETV107X_GPIO_CTLRS ] ;
static int tnetv107x_gpio_request ( struct gpio_chip * chip , unsigned offset )
{
struct davinci_gpio_controller * ctlr = chip2controller ( chip ) ;
struct tnetv107x_gpio_regs __iomem * regs = ctlr - > regs ;
unsigned gpio = chip - > base + offset ;
unsigned long flags ;
spin_lock_irqsave ( & ctlr - > lock , flags ) ;
2011-01-26 01:05:26 +03:00
gpio_reg_set_bit ( regs - > enable , gpio ) ;
2010-05-18 20:51:20 +04:00
spin_unlock_irqrestore ( & ctlr - > lock , flags ) ;
return 0 ;
}
static void tnetv107x_gpio_free ( struct gpio_chip * chip , unsigned offset )
{
struct davinci_gpio_controller * ctlr = chip2controller ( chip ) ;
struct tnetv107x_gpio_regs __iomem * regs = ctlr - > regs ;
unsigned gpio = chip - > base + offset ;
unsigned long flags ;
spin_lock_irqsave ( & ctlr - > lock , flags ) ;
2011-01-26 01:05:26 +03:00
gpio_reg_clear_bit ( regs - > enable , gpio ) ;
2010-05-18 20:51:20 +04:00
spin_unlock_irqrestore ( & ctlr - > lock , flags ) ;
}
static int tnetv107x_gpio_dir_in ( struct gpio_chip * chip , unsigned offset )
{
struct davinci_gpio_controller * ctlr = chip2controller ( chip ) ;
struct tnetv107x_gpio_regs __iomem * regs = ctlr - > regs ;
unsigned gpio = chip - > base + offset ;
unsigned long flags ;
spin_lock_irqsave ( & ctlr - > lock , flags ) ;
2011-01-26 01:05:26 +03:00
gpio_reg_set_bit ( regs - > direction , gpio ) ;
2010-05-18 20:51:20 +04:00
spin_unlock_irqrestore ( & ctlr - > lock , flags ) ;
return 0 ;
}
static int tnetv107x_gpio_dir_out ( struct gpio_chip * chip ,
unsigned offset , int value )
{
struct davinci_gpio_controller * ctlr = chip2controller ( chip ) ;
struct tnetv107x_gpio_regs __iomem * regs = ctlr - > regs ;
unsigned gpio = chip - > base + offset ;
unsigned long flags ;
spin_lock_irqsave ( & ctlr - > lock , flags ) ;
if ( value )
2011-01-26 01:05:26 +03:00
gpio_reg_set_bit ( regs - > data_out , gpio ) ;
2010-05-18 20:51:20 +04:00
else
2011-01-26 01:05:26 +03:00
gpio_reg_clear_bit ( regs - > data_out , gpio ) ;
2010-05-18 20:51:20 +04:00
2011-01-26 01:05:26 +03:00
gpio_reg_clear_bit ( regs - > direction , gpio ) ;
2010-05-18 20:51:20 +04:00
spin_unlock_irqrestore ( & ctlr - > lock , flags ) ;
return 0 ;
}
static int tnetv107x_gpio_get ( struct gpio_chip * chip , unsigned offset )
{
struct davinci_gpio_controller * ctlr = chip2controller ( chip ) ;
struct tnetv107x_gpio_regs __iomem * regs = ctlr - > regs ;
unsigned gpio = chip - > base + offset ;
int ret ;
2011-01-26 01:05:26 +03:00
ret = gpio_reg_get_bit ( regs - > data_in , gpio ) ;
2010-05-18 20:51:20 +04:00
return ret ? 1 : 0 ;
}
static void tnetv107x_gpio_set ( struct gpio_chip * chip ,
unsigned offset , int value )
{
struct davinci_gpio_controller * ctlr = chip2controller ( chip ) ;
struct tnetv107x_gpio_regs __iomem * regs = ctlr - > regs ;
unsigned gpio = chip - > base + offset ;
unsigned long flags ;
spin_lock_irqsave ( & ctlr - > lock , flags ) ;
if ( value )
2011-01-26 01:05:26 +03:00
gpio_reg_set_bit ( regs - > data_out , gpio ) ;
2010-05-18 20:51:20 +04:00
else
2011-01-26 01:05:26 +03:00
gpio_reg_clear_bit ( regs - > data_out , gpio ) ;
2010-05-18 20:51:20 +04:00
spin_unlock_irqrestore ( & ctlr - > lock , flags ) ;
}
static int __init tnetv107x_gpio_setup ( void )
{
int i , base ;
unsigned ngpio ;
struct davinci_soc_info * soc_info = & davinci_soc_info ;
struct tnetv107x_gpio_regs * regs ;
struct davinci_gpio_controller * ctlr ;
if ( soc_info - > gpio_type ! = GPIO_TYPE_TNETV107X )
return 0 ;
ngpio = soc_info - > gpio_num ;
if ( ngpio = = 0 ) {
pr_err ( " GPIO setup: how many GPIOs? \n " ) ;
return - EINVAL ;
}
if ( WARN_ON ( TNETV107X_N_GPIO < ngpio ) )
ngpio = TNETV107X_N_GPIO ;
regs = ioremap ( soc_info - > gpio_base , SZ_4K ) ;
if ( WARN_ON ( ! regs ) )
return - EINVAL ;
for ( i = 0 , base = 0 ; base < ngpio ; i + + , base + = 32 ) {
ctlr = & chips [ i ] ;
ctlr - > chip . label = " tnetv107x " ;
ctlr - > chip . can_sleep = 0 ;
ctlr - > chip . base = base ;
ctlr - > chip . ngpio = ngpio - base ;
if ( ctlr - > chip . ngpio > 32 )
ctlr - > chip . ngpio = 32 ;
ctlr - > chip . request = tnetv107x_gpio_request ;
ctlr - > chip . free = tnetv107x_gpio_free ;
ctlr - > chip . direction_input = tnetv107x_gpio_dir_in ;
ctlr - > chip . get = tnetv107x_gpio_get ;
ctlr - > chip . direction_output = tnetv107x_gpio_dir_out ;
ctlr - > chip . set = tnetv107x_gpio_set ;
spin_lock_init ( & ctlr - > lock ) ;
ctlr - > regs = regs ;
ctlr - > set_data = & regs - > data_out [ i ] ;
ctlr - > clr_data = & regs - > data_out [ i ] ;
ctlr - > in_data = & regs - > data_in [ i ] ;
gpiochip_add ( & ctlr - > chip ) ;
}
soc_info - > gpio_ctlrs = chips ;
soc_info - > gpio_ctlrs_num = DIV_ROUND_UP ( ngpio , 32 ) ;
return 0 ;
}
pure_initcall ( tnetv107x_gpio_setup ) ;