2012-06-20 12:29:04 +04:00
/*
* SuperH Pin Function Controller GPIO driver .
*
* Copyright ( C ) 2008 Magnus Damm
* Copyright ( C ) 2009 - 2012 Paul Mundt
*
* 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 .
*/
2012-12-16 02:50:47 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME " gpio: " fmt
2012-06-20 12:29:04 +04:00
# include <linux/init.h>
# include <linux/gpio.h>
# include <linux/slab.h>
# include <linux/spinlock.h>
# include <linux/module.h>
2012-07-10 07:08:14 +04:00
# include <linux/pinctrl/consumer.h>
2012-08-28 21:54:42 +04:00
# include <linux/sh_pfc.h>
2012-06-20 12:29:04 +04:00
2012-12-16 02:50:44 +04:00
# include "core.h"
2012-06-20 12:29:04 +04:00
struct sh_pfc_chip {
struct sh_pfc * pfc ;
struct gpio_chip gpio_chip ;
} ;
static struct sh_pfc_chip * gpio_to_pfc_chip ( struct gpio_chip * gc )
{
return container_of ( gc , struct sh_pfc_chip , gpio_chip ) ;
}
static struct sh_pfc * gpio_to_pfc ( struct gpio_chip * gc )
{
return gpio_to_pfc_chip ( gc ) - > pfc ;
}
static int sh_gpio_request ( struct gpio_chip * gc , unsigned offset )
{
2012-07-10 07:08:14 +04:00
return pinctrl_request_gpio ( offset ) ;
2012-06-20 12:29:04 +04:00
}
static void sh_gpio_free ( struct gpio_chip * gc , unsigned offset )
{
2012-07-10 07:08:14 +04:00
pinctrl_free_gpio ( offset ) ;
2012-06-20 12:29:04 +04:00
}
static void sh_gpio_set_value ( struct sh_pfc * pfc , unsigned gpio , int value )
{
struct pinmux_data_reg * dr = NULL ;
int bit = 0 ;
if ( ! pfc | | sh_pfc_get_data_reg ( pfc , gpio , & dr , & bit ) ! = 0 )
BUG ( ) ;
else
sh_pfc_write_bit ( dr , bit , value ) ;
}
static int sh_gpio_get_value ( struct sh_pfc * pfc , unsigned gpio )
{
struct pinmux_data_reg * dr = NULL ;
int bit = 0 ;
if ( ! pfc | | sh_pfc_get_data_reg ( pfc , gpio , & dr , & bit ) ! = 0 )
return - EINVAL ;
return sh_pfc_read_bit ( dr , bit ) ;
}
2012-07-10 07:08:14 +04:00
static int sh_gpio_direction_input ( struct gpio_chip * gc , unsigned offset )
{
return pinctrl_gpio_direction_input ( offset ) ;
}
static int sh_gpio_direction_output ( struct gpio_chip * gc , unsigned offset ,
int value )
{
sh_gpio_set_value ( gpio_to_pfc ( gc ) , offset , value ) ;
return pinctrl_gpio_direction_output ( offset ) ;
}
2012-06-20 12:29:04 +04:00
static int sh_gpio_get ( struct gpio_chip * gc , unsigned offset )
{
return sh_gpio_get_value ( gpio_to_pfc ( gc ) , offset ) ;
}
static void sh_gpio_set ( struct gpio_chip * gc , unsigned offset , int value )
{
sh_gpio_set_value ( gpio_to_pfc ( gc ) , offset , value ) ;
}
static int sh_gpio_to_irq ( struct gpio_chip * gc , unsigned offset )
{
struct sh_pfc * pfc = gpio_to_pfc ( gc ) ;
pinmux_enum_t enum_id ;
pinmux_enum_t * enum_ids ;
int i , k , pos ;
pos = 0 ;
enum_id = 0 ;
while ( 1 ) {
pos = sh_pfc_gpio_to_enum ( pfc , offset , pos , & enum_id ) ;
if ( pos < = 0 | | ! enum_id )
break ;
2012-12-16 02:50:43 +04:00
for ( i = 0 ; i < pfc - > pdata - > gpio_irq_size ; i + + ) {
enum_ids = pfc - > pdata - > gpio_irq [ i ] . enum_ids ;
2012-06-20 12:29:04 +04:00
for ( k = 0 ; enum_ids [ k ] ; k + + ) {
if ( enum_ids [ k ] = = enum_id )
2012-12-16 02:50:43 +04:00
return pfc - > pdata - > gpio_irq [ i ] . irq ;
2012-06-20 12:29:04 +04:00
}
}
}
return - ENOSYS ;
}
static void sh_pfc_gpio_setup ( struct sh_pfc_chip * chip )
{
struct sh_pfc * pfc = chip - > pfc ;
struct gpio_chip * gc = & chip - > gpio_chip ;
gc - > request = sh_gpio_request ;
gc - > free = sh_gpio_free ;
gc - > direction_input = sh_gpio_direction_input ;
gc - > get = sh_gpio_get ;
gc - > direction_output = sh_gpio_direction_output ;
gc - > set = sh_gpio_set ;
gc - > to_irq = sh_gpio_to_irq ;
2012-12-16 02:50:43 +04:00
WARN_ON ( pfc - > pdata - > first_gpio ! = 0 ) ; /* needs testing */
2012-06-20 12:29:04 +04:00
2012-12-16 02:50:43 +04:00
gc - > label = pfc - > pdata - > name ;
2012-06-20 12:29:04 +04:00
gc - > owner = THIS_MODULE ;
2012-12-16 02:50:43 +04:00
gc - > base = pfc - > pdata - > first_gpio ;
gc - > ngpio = ( pfc - > pdata - > last_gpio - pfc - > pdata - > first_gpio ) + 1 ;
2012-06-20 12:29:04 +04:00
}
int sh_pfc_register_gpiochip ( struct sh_pfc * pfc )
{
struct sh_pfc_chip * chip ;
int ret ;
chip = kzalloc ( sizeof ( struct sh_pfc_chip ) , GFP_KERNEL ) ;
if ( unlikely ( ! chip ) )
return - ENOMEM ;
chip - > pfc = pfc ;
sh_pfc_gpio_setup ( chip ) ;
ret = gpiochip_add ( & chip - > gpio_chip ) ;
2012-12-16 02:50:46 +04:00
if ( unlikely ( ret < 0 ) ) {
2012-06-20 12:29:04 +04:00
kfree ( chip ) ;
2012-12-16 02:50:46 +04:00
return ret ;
}
pfc - > gpio = chip ;
2012-06-20 12:29:04 +04:00
pr_info ( " %s handling gpio %d -> %d \n " ,
2012-12-16 02:50:43 +04:00
pfc - > pdata - > name , pfc - > pdata - > first_gpio ,
pfc - > pdata - > last_gpio ) ;
2012-06-20 12:29:04 +04:00
return 0 ;
}
2012-12-16 02:50:46 +04:00
int sh_pfc_unregister_gpiochip ( struct sh_pfc * pfc )
2012-06-20 12:29:04 +04:00
{
2012-12-16 02:50:46 +04:00
struct sh_pfc_chip * chip = pfc - > gpio ;
2012-06-20 12:29:04 +04:00
int ret ;
ret = gpiochip_remove ( & chip - > gpio_chip ) ;
if ( unlikely ( ret < 0 ) )
return ret ;
kfree ( chip ) ;
2012-12-16 02:50:46 +04:00
pfc - > gpio = NULL ;
2012-06-20 12:29:04 +04:00
return 0 ;
}