2008-10-08 15:41:43 +04:00
/*
* Pinmuxed GPIO support for SuperH .
*
* Copyright ( C ) 2008 Magnus Damm
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*/
2010-10-03 22:54:56 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2008-10-08 15:41:43 +04:00
# include <linux/errno.h>
# include <linux/kernel.h>
# include <linux/list.h>
# include <linux/module.h>
# include <linux/clk.h>
# include <linux/err.h>
# include <linux/io.h>
# include <linux/irq.h>
# include <linux/bitops.h>
# include <linux/gpio.h>
2011-12-09 07:14:27 +04:00
# include <linux/slab.h>
# include <linux/ioport.h>
static void pfc_iounmap ( struct pinmux_info * pip )
{
int k ;
for ( k = 0 ; k < pip - > num_resources ; k + + )
if ( pip - > window [ k ] . virt )
iounmap ( pip - > window [ k ] . virt ) ;
kfree ( pip - > window ) ;
pip - > window = NULL ;
}
static int pfc_ioremap ( struct pinmux_info * pip )
{
struct resource * res ;
int k ;
if ( ! pip - > num_resources )
return 0 ;
pip - > window = kzalloc ( pip - > num_resources * sizeof ( * pip - > window ) ,
GFP_NOWAIT ) ;
if ( ! pip - > window )
goto err1 ;
for ( k = 0 ; k < pip - > num_resources ; k + + ) {
res = pip - > resource + k ;
WARN_ON ( resource_type ( res ) ! = IORESOURCE_MEM ) ;
pip - > window [ k ] . phys = res - > start ;
pip - > window [ k ] . size = resource_size ( res ) ;
pip - > window [ k ] . virt = ioremap_nocache ( res - > start ,
resource_size ( res ) ) ;
if ( ! pip - > window [ k ] . virt )
goto err2 ;
}
return 0 ;
err2 :
pfc_iounmap ( pip ) ;
err1 :
return - 1 ;
}
static void __iomem * pfc_phys_to_virt ( struct pinmux_info * pip ,
unsigned long address )
{
struct pfc_window * window ;
int k ;
/* scan through physical windows and convert address */
for ( k = 0 ; k < pip - > num_resources ; k + + ) {
window = pip - > window + k ;
if ( address < window - > phys )
continue ;
if ( address > = ( window - > phys + window - > size ) )
continue ;
return window - > virt + ( address - window - > phys ) ;
}
/* no windows defined, register must be 1:1 mapped virt:phys */
return ( void __iomem * ) address ;
}
2008-10-08 15:41:43 +04:00
static int enum_in_range ( pinmux_enum_t enum_id , struct pinmux_range * r )
{
if ( enum_id < r - > begin )
return 0 ;
if ( enum_id > r - > end )
return 0 ;
return 1 ;
}
2011-12-09 07:14:27 +04:00
static unsigned long gpio_read_raw_reg ( void __iomem * mapped_reg ,
2008-12-25 12:17:26 +03:00
unsigned long reg_width )
{
switch ( reg_width ) {
case 8 :
2011-12-09 07:14:27 +04:00
return ioread8 ( mapped_reg ) ;
2008-12-25 12:17:26 +03:00
case 16 :
2011-12-09 07:14:27 +04:00
return ioread16 ( mapped_reg ) ;
2008-12-25 12:17:26 +03:00
case 32 :
2011-12-09 07:14:27 +04:00
return ioread32 ( mapped_reg ) ;
2008-12-25 12:17:26 +03:00
}
BUG ( ) ;
return 0 ;
}
2011-12-09 07:14:27 +04:00
static void gpio_write_raw_reg ( void __iomem * mapped_reg ,
2008-12-25 12:17:26 +03:00
unsigned long reg_width ,
unsigned long data )
{
switch ( reg_width ) {
case 8 :
2011-12-09 07:14:27 +04:00
iowrite8 ( data , mapped_reg ) ;
2008-12-25 12:17:26 +03:00
return ;
case 16 :
2011-12-09 07:14:27 +04:00
iowrite16 ( data , mapped_reg ) ;
2008-12-25 12:17:26 +03:00
return ;
case 32 :
2011-12-09 07:14:27 +04:00
iowrite32 ( data , mapped_reg ) ;
2008-12-25 12:17:26 +03:00
return ;
}
BUG ( ) ;
}
2011-12-13 20:00:37 +04:00
static int gpio_read_bit ( struct pinmux_data_reg * dr ,
unsigned long in_pos )
{
unsigned long pos ;
pos = dr - > reg_width - ( in_pos + 1 ) ;
pr_debug ( " read_bit: addr = %lx, pos = %ld, "
" r_width = %ld \n " , dr - > reg , pos , dr - > reg_width ) ;
return ( gpio_read_raw_reg ( dr - > mapped_reg , dr - > reg_width ) > > pos ) & 1 ;
}
2008-12-25 12:17:26 +03:00
static void gpio_write_bit ( struct pinmux_data_reg * dr ,
unsigned long in_pos , unsigned long value )
{
unsigned long pos ;
pos = dr - > reg_width - ( in_pos + 1 ) ;
2009-12-09 09:51:27 +03:00
pr_debug ( " write_bit addr = %lx, value = %d, pos = %ld, "
2009-11-30 06:15:04 +03:00
" r_width = %ld \n " ,
dr - > reg , ! ! value , pos , dr - > reg_width ) ;
2008-12-25 12:17:26 +03:00
if ( value )
set_bit ( pos , & dr - > reg_shadow ) ;
else
clear_bit ( pos , & dr - > reg_shadow ) ;
2011-12-09 07:14:27 +04:00
gpio_write_raw_reg ( dr - > mapped_reg , dr - > reg_width , dr - > reg_shadow ) ;
2008-12-25 12:17:26 +03:00
}
2011-12-13 20:00:55 +04:00
static void config_reg_helper ( struct pinmux_info * gpioc ,
struct pinmux_cfg_reg * crp ,
unsigned long in_pos ,
void __iomem * * mapped_regp ,
unsigned long * maskp ,
unsigned long * posp )
2008-10-08 15:41:43 +04:00
{
2011-12-13 20:01:05 +04:00
int k ;
2011-12-13 20:00:55 +04:00
* mapped_regp = pfc_phys_to_virt ( gpioc , crp - > reg ) ;
2008-10-08 15:41:43 +04:00
2011-12-13 20:01:05 +04:00
if ( crp - > field_width ) {
* maskp = ( 1 < < crp - > field_width ) - 1 ;
* posp = crp - > reg_width - ( ( in_pos + 1 ) * crp - > field_width ) ;
} else {
* maskp = ( 1 < < crp - > var_field_width [ in_pos ] ) - 1 ;
* posp = crp - > reg_width ;
for ( k = 0 ; k < = in_pos ; k + + )
* posp - = crp - > var_field_width [ k ] ;
}
2011-12-13 20:00:55 +04:00
}
static int read_config_reg ( struct pinmux_info * gpioc ,
struct pinmux_cfg_reg * crp ,
unsigned long field )
{
void __iomem * mapped_reg ;
unsigned long mask , pos ;
config_reg_helper ( gpioc , crp , field , & mapped_reg , & mask , & pos ) ;
2008-10-08 15:41:43 +04:00
2011-12-13 20:00:55 +04:00
pr_debug ( " read_reg: addr = %lx, field = %ld, "
2009-11-30 06:15:04 +03:00
" r_width = %ld, f_width = %ld \n " ,
2011-12-13 20:00:55 +04:00
crp - > reg , field , crp - > reg_width , crp - > field_width ) ;
2008-10-08 15:41:43 +04:00
2011-12-13 20:00:55 +04:00
return ( gpio_read_raw_reg ( mapped_reg , crp - > reg_width ) > > pos ) & mask ;
2008-12-25 12:17:18 +03:00
}
2011-12-13 20:00:55 +04:00
static void write_config_reg ( struct pinmux_info * gpioc ,
struct pinmux_cfg_reg * crp ,
unsigned long field , unsigned long value )
2008-12-25 12:17:18 +03:00
{
2011-12-13 20:00:55 +04:00
void __iomem * mapped_reg ;
2011-12-13 20:01:14 +04:00
unsigned long mask , pos , data ;
2008-12-25 12:17:18 +03:00
2011-12-13 20:00:55 +04:00
config_reg_helper ( gpioc , crp , field , & mapped_reg , & mask , & pos ) ;
2008-10-08 15:41:43 +04:00
2011-12-13 20:00:55 +04:00
pr_debug ( " write_reg addr = %lx, value = %ld, field = %ld, "
2009-11-30 06:15:04 +03:00
" r_width = %ld, f_width = %ld \n " ,
2011-12-13 20:00:55 +04:00
crp - > reg , value , field , crp - > reg_width , crp - > field_width ) ;
2008-12-25 12:17:18 +03:00
mask = ~ ( mask < < pos ) ;
value = value < < pos ;
2008-10-08 15:41:43 +04:00
2011-12-13 20:01:14 +04:00
data = gpio_read_raw_reg ( mapped_reg , crp - > reg_width ) ;
data & = mask ;
data | = value ;
if ( gpioc - > unlock_reg )
gpio_write_raw_reg ( pfc_phys_to_virt ( gpioc , gpioc - > unlock_reg ) ,
32 , ~ data ) ;
gpio_write_raw_reg ( mapped_reg , crp - > reg_width , data ) ;
2008-10-08 15:41:43 +04:00
}
2008-12-25 12:17:09 +03:00
static int setup_data_reg ( struct pinmux_info * gpioc , unsigned gpio )
2008-10-08 15:41:43 +04:00
{
2008-12-25 12:17:09 +03:00
struct pinmux_gpio * gpiop = & gpioc - > gpios [ gpio ] ;
2008-10-08 15:41:43 +04:00
struct pinmux_data_reg * data_reg ;
int k , n ;
2008-12-25 12:17:09 +03:00
if ( ! enum_in_range ( gpiop - > enum_id , & gpioc - > data ) )
2008-10-08 15:41:43 +04:00
return - 1 ;
k = 0 ;
while ( 1 ) {
data_reg = gpioc - > data_regs + k ;
if ( ! data_reg - > reg_width )
break ;
2011-12-09 07:14:27 +04:00
data_reg - > mapped_reg = pfc_phys_to_virt ( gpioc , data_reg - > reg ) ;
2008-10-08 15:41:43 +04:00
for ( n = 0 ; n < data_reg - > reg_width ; n + + ) {
2008-12-25 12:17:09 +03:00
if ( data_reg - > enum_ids [ n ] = = gpiop - > enum_id ) {
gpiop - > flags & = ~ PINMUX_FLAG_DREG ;
gpiop - > flags | = ( k < < PINMUX_FLAG_DREG_SHIFT ) ;
gpiop - > flags & = ~ PINMUX_FLAG_DBIT ;
gpiop - > flags | = ( n < < PINMUX_FLAG_DBIT_SHIFT ) ;
2008-10-08 15:41:43 +04:00
return 0 ;
}
}
k + + ;
}
2008-12-25 12:17:09 +03:00
BUG ( ) ;
2008-10-08 15:41:43 +04:00
return - 1 ;
}
2008-12-25 12:17:26 +03:00
static void setup_data_regs ( struct pinmux_info * gpioc )
{
struct pinmux_data_reg * drp ;
int k ;
for ( k = gpioc - > first_gpio ; k < = gpioc - > last_gpio ; k + + )
setup_data_reg ( gpioc , k ) ;
k = 0 ;
while ( 1 ) {
drp = gpioc - > data_regs + k ;
if ( ! drp - > reg_width )
break ;
2011-12-09 07:14:27 +04:00
drp - > reg_shadow = gpio_read_raw_reg ( drp - > mapped_reg ,
drp - > reg_width ) ;
2008-12-25 12:17:26 +03:00
k + + ;
}
}
2008-12-25 12:17:09 +03:00
static int get_data_reg ( struct pinmux_info * gpioc , unsigned gpio ,
struct pinmux_data_reg * * drp , int * bitp )
{
struct pinmux_gpio * gpiop = & gpioc - > gpios [ gpio ] ;
int k , n ;
if ( ! enum_in_range ( gpiop - > enum_id , & gpioc - > data ) )
return - 1 ;
k = ( gpiop - > flags & PINMUX_FLAG_DREG ) > > PINMUX_FLAG_DREG_SHIFT ;
n = ( gpiop - > flags & PINMUX_FLAG_DBIT ) > > PINMUX_FLAG_DBIT_SHIFT ;
* drp = gpioc - > data_regs + k ;
* bitp = n ;
return 0 ;
}
2008-10-08 15:41:43 +04:00
static int get_config_reg ( struct pinmux_info * gpioc , pinmux_enum_t enum_id ,
2011-12-13 20:00:46 +04:00
struct pinmux_cfg_reg * * crp ,
int * fieldp , int * valuep ,
2008-10-08 15:41:43 +04:00
unsigned long * * cntp )
{
struct pinmux_cfg_reg * config_reg ;
2011-12-13 20:01:05 +04:00
unsigned long r_width , f_width , curr_width , ncomb ;
int k , m , n , pos , bit_pos ;
2008-10-08 15:41:43 +04:00
k = 0 ;
while ( 1 ) {
config_reg = gpioc - > cfg_regs + k ;
r_width = config_reg - > reg_width ;
f_width = config_reg - > field_width ;
if ( ! r_width )
break ;
2011-12-13 20:01:05 +04:00
pos = 0 ;
m = 0 ;
for ( bit_pos = 0 ; bit_pos < r_width ; bit_pos + = curr_width ) {
if ( f_width )
curr_width = f_width ;
else
curr_width = config_reg - > var_field_width [ m ] ;
ncomb = 1 < < curr_width ;
for ( n = 0 ; n < ncomb ; n + + ) {
if ( config_reg - > enum_ids [ pos + n ] = = enum_id ) {
* crp = config_reg ;
* fieldp = m ;
* valuep = n ;
* cntp = & config_reg - > cnt [ m ] ;
return 0 ;
}
2008-10-08 15:41:43 +04:00
}
2011-12-13 20:01:05 +04:00
pos + = ncomb ;
m + + ;
2008-10-08 15:41:43 +04:00
}
k + + ;
}
return - 1 ;
}
static int get_gpio_enum_id ( struct pinmux_info * gpioc , unsigned gpio ,
int pos , pinmux_enum_t * enum_idp )
{
pinmux_enum_t enum_id = gpioc - > gpios [ gpio ] . enum_id ;
pinmux_enum_t * data = gpioc - > gpio_data ;
int k ;
if ( ! enum_in_range ( enum_id , & gpioc - > data ) ) {
if ( ! enum_in_range ( enum_id , & gpioc - > mark ) ) {
pr_err ( " non data/mark enum_id for gpio %d \n " , gpio ) ;
return - 1 ;
}
}
if ( pos ) {
* enum_idp = data [ pos + 1 ] ;
return pos + 1 ;
}
for ( k = 0 ; k < gpioc - > gpio_data_size ; k + + ) {
if ( data [ k ] = = enum_id ) {
* enum_idp = data [ k + 1 ] ;
return k + 1 ;
}
}
pr_err ( " cannot locate data/mark enum_id for gpio %d \n " , gpio ) ;
return - 1 ;
}
enum { GPIO_CFG_DRYRUN , GPIO_CFG_REQ , GPIO_CFG_FREE } ;
2008-12-25 12:17:18 +03:00
static int pinmux_config_gpio ( struct pinmux_info * gpioc , unsigned gpio ,
int pinmux_type , int cfg_mode )
2008-10-08 15:41:43 +04:00
{
struct pinmux_cfg_reg * cr = NULL ;
pinmux_enum_t enum_id ;
struct pinmux_range * range ;
2011-12-13 20:00:46 +04:00
int in_range , pos , field , value ;
2008-10-08 15:41:43 +04:00
unsigned long * cntp ;
switch ( pinmux_type ) {
case PINMUX_TYPE_FUNCTION :
range = NULL ;
break ;
case PINMUX_TYPE_OUTPUT :
range = & gpioc - > output ;
break ;
case PINMUX_TYPE_INPUT :
range = & gpioc - > input ;
break ;
case PINMUX_TYPE_INPUT_PULLUP :
range = & gpioc - > input_pu ;
break ;
case PINMUX_TYPE_INPUT_PULLDOWN :
range = & gpioc - > input_pd ;
break ;
default :
goto out_err ;
}
pos = 0 ;
enum_id = 0 ;
2011-12-13 20:00:46 +04:00
field = 0 ;
value = 0 ;
2008-10-08 15:41:43 +04:00
while ( 1 ) {
pos = get_gpio_enum_id ( gpioc , gpio , pos , & enum_id ) ;
if ( pos < = 0 )
goto out_err ;
if ( ! enum_id )
break ;
2010-01-19 16:52:28 +03:00
/* first check if this is a function enum */
2008-10-08 15:41:43 +04:00
in_range = enum_in_range ( enum_id , & gpioc - > function ) ;
2010-01-19 16:52:28 +03:00
if ( ! in_range ) {
/* not a function enum */
if ( range ) {
/*
* other range exists , so this pin is
* a regular GPIO pin that now is being
* bound to a specific direction .
*
* for this case we only allow function enums
* and the enums that match the other range .
*/
in_range = enum_in_range ( enum_id , range ) ;
/*
* special case pass through for fixed
* input - only or output - only pins without
* function enum register association .
*/
if ( in_range & & enum_id = = range - > force )
continue ;
} else {
/*
* no other range exists , so this pin
* must then be of the function type .
*
* allow function type pins to select
* any combination of function / in / out
* in their MARK lists .
*/
in_range = 1 ;
}
2008-10-22 13:29:17 +04:00
}
2008-10-08 15:41:43 +04:00
if ( ! in_range )
continue ;
2011-12-13 20:00:46 +04:00
if ( get_config_reg ( gpioc , enum_id , & cr ,
& field , & value , & cntp ) ! = 0 )
2008-10-08 15:41:43 +04:00
goto out_err ;
switch ( cfg_mode ) {
case GPIO_CFG_DRYRUN :
2011-12-13 20:00:55 +04:00
if ( ! * cntp | |
( read_config_reg ( gpioc , cr , field ) ! = value ) )
2008-10-08 15:41:43 +04:00
continue ;
break ;
case GPIO_CFG_REQ :
2011-12-13 20:00:46 +04:00
write_config_reg ( gpioc , cr , field , value ) ;
2008-10-08 15:41:43 +04:00
* cntp = * cntp + 1 ;
break ;
case GPIO_CFG_FREE :
* cntp = * cntp - 1 ;
break ;
}
}
return 0 ;
out_err :
return - 1 ;
}
static DEFINE_SPINLOCK ( gpio_lock ) ;
2008-12-25 12:17:34 +03:00
static struct pinmux_info * chip_to_pinmux ( struct gpio_chip * chip )
2008-10-08 15:41:43 +04:00
{
2008-12-25 12:17:34 +03:00
return container_of ( chip , struct pinmux_info , chip ) ;
}
static int sh_gpio_request ( struct gpio_chip * chip , unsigned offset )
{
struct pinmux_info * gpioc = chip_to_pinmux ( chip ) ;
2008-10-08 15:41:43 +04:00
struct pinmux_data_reg * dummy ;
unsigned long flags ;
int i , ret , pinmux_type ;
ret = - EINVAL ;
if ( ! gpioc )
goto err_out ;
spin_lock_irqsave ( & gpio_lock , flags ) ;
2008-12-25 12:17:34 +03:00
if ( ( gpioc - > gpios [ offset ] . flags & PINMUX_FLAG_TYPE ) ! = PINMUX_TYPE_NONE )
2008-10-08 15:41:43 +04:00
goto err_unlock ;
/* setup pin function here if no data is associated with pin */
2008-12-25 12:17:34 +03:00
if ( get_data_reg ( gpioc , offset , & dummy , & i ) ! = 0 )
2008-10-08 15:41:43 +04:00
pinmux_type = PINMUX_TYPE_FUNCTION ;
else
pinmux_type = PINMUX_TYPE_GPIO ;
if ( pinmux_type = = PINMUX_TYPE_FUNCTION ) {
2008-12-25 12:17:34 +03:00
if ( pinmux_config_gpio ( gpioc , offset ,
2008-10-08 15:41:43 +04:00
pinmux_type ,
GPIO_CFG_DRYRUN ) ! = 0 )
goto err_unlock ;
2008-12-25 12:17:34 +03:00
if ( pinmux_config_gpio ( gpioc , offset ,
2008-10-08 15:41:43 +04:00
pinmux_type ,
GPIO_CFG_REQ ) ! = 0 )
BUG ( ) ;
}
2008-12-25 12:17:34 +03:00
gpioc - > gpios [ offset ] . flags & = ~ PINMUX_FLAG_TYPE ;
gpioc - > gpios [ offset ] . flags | = pinmux_type ;
2008-10-08 15:41:43 +04:00
ret = 0 ;
err_unlock :
spin_unlock_irqrestore ( & gpio_lock , flags ) ;
err_out :
return ret ;
}
2008-12-25 12:17:34 +03:00
static void sh_gpio_free ( struct gpio_chip * chip , unsigned offset )
2008-10-08 15:41:43 +04:00
{
2008-12-25 12:17:34 +03:00
struct pinmux_info * gpioc = chip_to_pinmux ( chip ) ;
2008-10-08 15:41:43 +04:00
unsigned long flags ;
int pinmux_type ;
if ( ! gpioc )
return ;
spin_lock_irqsave ( & gpio_lock , flags ) ;
2008-12-25 12:17:34 +03:00
pinmux_type = gpioc - > gpios [ offset ] . flags & PINMUX_FLAG_TYPE ;
pinmux_config_gpio ( gpioc , offset , pinmux_type , GPIO_CFG_FREE ) ;
gpioc - > gpios [ offset ] . flags & = ~ PINMUX_FLAG_TYPE ;
gpioc - > gpios [ offset ] . flags | = PINMUX_TYPE_NONE ;
2008-10-08 15:41:43 +04:00
spin_unlock_irqrestore ( & gpio_lock , flags ) ;
}
static int pinmux_direction ( struct pinmux_info * gpioc ,
unsigned gpio , int new_pinmux_type )
{
2008-12-25 12:17:18 +03:00
int pinmux_type ;
int ret = - EINVAL ;
if ( ! gpioc )
goto err_out ;
2008-10-08 15:41:43 +04:00
pinmux_type = gpioc - > gpios [ gpio ] . flags & PINMUX_FLAG_TYPE ;
switch ( pinmux_type ) {
case PINMUX_TYPE_GPIO :
break ;
case PINMUX_TYPE_OUTPUT :
case PINMUX_TYPE_INPUT :
case PINMUX_TYPE_INPUT_PULLUP :
case PINMUX_TYPE_INPUT_PULLDOWN :
pinmux_config_gpio ( gpioc , gpio , pinmux_type , GPIO_CFG_FREE ) ;
break ;
default :
goto err_out ;
}
if ( pinmux_config_gpio ( gpioc , gpio ,
new_pinmux_type ,
GPIO_CFG_DRYRUN ) ! = 0 )
goto err_out ;
if ( pinmux_config_gpio ( gpioc , gpio ,
new_pinmux_type ,
GPIO_CFG_REQ ) ! = 0 )
BUG ( ) ;
2008-12-25 12:17:09 +03:00
gpioc - > gpios [ gpio ] . flags & = ~ PINMUX_FLAG_TYPE ;
gpioc - > gpios [ gpio ] . flags | = new_pinmux_type ;
2008-10-08 15:41:43 +04:00
ret = 0 ;
err_out :
return ret ;
}
2008-12-25 12:17:34 +03:00
static int sh_gpio_direction_input ( struct gpio_chip * chip , unsigned offset )
2008-10-08 15:41:43 +04:00
{
2008-12-25 12:17:34 +03:00
struct pinmux_info * gpioc = chip_to_pinmux ( chip ) ;
2008-10-08 15:41:43 +04:00
unsigned long flags ;
2008-12-25 12:17:18 +03:00
int ret ;
2008-10-08 15:41:43 +04:00
spin_lock_irqsave ( & gpio_lock , flags ) ;
2008-12-25 12:17:34 +03:00
ret = pinmux_direction ( gpioc , offset , PINMUX_TYPE_INPUT ) ;
2008-10-08 15:41:43 +04:00
spin_unlock_irqrestore ( & gpio_lock , flags ) ;
2008-12-25 12:17:18 +03:00
2008-10-08 15:41:43 +04:00
return ret ;
}
2008-12-25 12:17:34 +03:00
static void sh_gpio_set_value ( struct pinmux_info * gpioc ,
2008-12-25 12:17:18 +03:00
unsigned gpio , int value )
2008-10-08 15:41:43 +04:00
{
struct pinmux_data_reg * dr = NULL ;
int bit = 0 ;
2008-12-25 12:17:18 +03:00
if ( ! gpioc | | get_data_reg ( gpioc , gpio , & dr , & bit ) ! = 0 )
2008-10-08 15:41:43 +04:00
BUG ( ) ;
else
2008-12-25 12:17:26 +03:00
gpio_write_bit ( dr , bit , value ) ;
2008-10-08 15:41:43 +04:00
}
2008-12-25 12:17:34 +03:00
static int sh_gpio_direction_output ( struct gpio_chip * chip , unsigned offset ,
int value )
2008-10-08 15:41:43 +04:00
{
2008-12-25 12:17:34 +03:00
struct pinmux_info * gpioc = chip_to_pinmux ( chip ) ;
2008-10-08 15:41:43 +04:00
unsigned long flags ;
2008-12-25 12:17:18 +03:00
int ret ;
2008-10-08 15:41:43 +04:00
2008-12-25 12:17:34 +03:00
sh_gpio_set_value ( gpioc , offset , value ) ;
2008-12-25 12:17:26 +03:00
spin_lock_irqsave ( & gpio_lock , flags ) ;
2008-12-25 12:17:34 +03:00
ret = pinmux_direction ( gpioc , offset , PINMUX_TYPE_OUTPUT ) ;
2008-10-08 15:41:43 +04:00
spin_unlock_irqrestore ( & gpio_lock , flags ) ;
2008-12-25 12:17:18 +03:00
2008-10-08 15:41:43 +04:00
return ret ;
}
2008-12-25 12:17:34 +03:00
static int sh_gpio_get_value ( struct pinmux_info * gpioc , unsigned gpio )
2008-10-08 15:41:43 +04:00
{
2008-12-25 12:17:18 +03:00
struct pinmux_data_reg * dr = NULL ;
int bit = 0 ;
2008-10-08 15:41:43 +04:00
2010-10-04 00:15:20 +04:00
if ( ! gpioc | | get_data_reg ( gpioc , gpio , & dr , & bit ) ! = 0 )
return - EINVAL ;
2008-10-08 15:41:43 +04:00
2011-12-13 20:00:37 +04:00
return gpio_read_bit ( dr , bit ) ;
2008-12-25 12:17:18 +03:00
}
2008-12-25 12:17:34 +03:00
static int sh_gpio_get ( struct gpio_chip * chip , unsigned offset )
2008-12-25 12:17:18 +03:00
{
2008-12-25 12:17:34 +03:00
return sh_gpio_get_value ( chip_to_pinmux ( chip ) , offset ) ;
2008-10-08 15:41:43 +04:00
}
2008-12-25 12:17:34 +03:00
static void sh_gpio_set ( struct gpio_chip * chip , unsigned offset , int value )
2008-10-08 15:41:43 +04:00
{
2008-12-25 12:17:34 +03:00
sh_gpio_set_value ( chip_to_pinmux ( chip ) , offset , value ) ;
2008-10-08 15:41:43 +04:00
}
2011-09-28 11:50:58 +04:00
static int sh_gpio_to_irq ( struct gpio_chip * chip , unsigned offset )
{
struct pinmux_info * gpioc = chip_to_pinmux ( chip ) ;
pinmux_enum_t enum_id ;
pinmux_enum_t * enum_ids ;
int i , k , pos ;
pos = 0 ;
enum_id = 0 ;
while ( 1 ) {
pos = get_gpio_enum_id ( gpioc , offset , pos , & enum_id ) ;
if ( pos < = 0 | | ! enum_id )
break ;
for ( i = 0 ; i < gpioc - > gpio_irq_size ; i + + ) {
enum_ids = gpioc - > gpio_irq [ i ] . enum_ids ;
for ( k = 0 ; enum_ids [ k ] ; k + + ) {
if ( enum_ids [ k ] = = enum_id )
return gpioc - > gpio_irq [ i ] . irq ;
}
}
}
return - ENOSYS ;
}
2008-10-08 15:41:43 +04:00
int register_pinmux ( struct pinmux_info * pip )
{
2008-12-25 12:17:34 +03:00
struct gpio_chip * chip = & pip - > chip ;
2011-12-09 07:14:27 +04:00
int ret ;
2008-12-25 12:17:34 +03:00
2010-10-03 22:54:56 +04:00
pr_info ( " %s handling gpio %d -> %d \n " ,
2008-10-08 15:41:43 +04:00
pip - > name , pip - > first_gpio , pip - > last_gpio ) ;
2011-12-09 07:14:27 +04:00
ret = pfc_ioremap ( pip ) ;
if ( ret < 0 )
return ret ;
2008-12-25 12:17:34 +03:00
setup_data_regs ( pip ) ;
chip - > request = sh_gpio_request ;
chip - > free = sh_gpio_free ;
chip - > direction_input = sh_gpio_direction_input ;
chip - > get = sh_gpio_get ;
chip - > direction_output = sh_gpio_direction_output ;
chip - > set = sh_gpio_set ;
2011-09-28 11:50:58 +04:00
chip - > to_irq = sh_gpio_to_irq ;
2008-12-25 12:17:34 +03:00
WARN_ON ( pip - > first_gpio ! = 0 ) ; /* needs testing */
chip - > label = pip - > name ;
chip - > owner = THIS_MODULE ;
chip - > base = pip - > first_gpio ;
chip - > ngpio = ( pip - > last_gpio - pip - > first_gpio ) + 1 ;
2011-12-09 07:14:27 +04:00
ret = gpiochip_add ( chip ) ;
if ( ret < 0 )
pfc_iounmap ( pip ) ;
return ret ;
2008-10-08 15:41:43 +04:00
}
2010-10-03 22:54:56 +04:00
int unregister_pinmux ( struct pinmux_info * pip )
{
pr_info ( " %s deregistering \n " , pip - > name ) ;
2011-12-09 07:14:27 +04:00
pfc_iounmap ( pip ) ;
2010-10-03 22:54:56 +04:00
return gpiochip_remove ( & pip - > chip ) ;
}