2011-05-03 01:19:52 +04:00
/*
2011-06-05 04:38:28 +04:00
* TI TPS6591x GPIO driver
2011-05-03 01:19:52 +04:00
*
* Copyright 2010 Texas Instruments Inc .
*
* Author : Graeme Gregory < gg @ slimlogic . co . uk >
* Author : Jorge Eduardo Candelaria jedu @ slimlogic . co . uk >
*
* 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 .
*
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/errno.h>
# include <linux/gpio.h>
# include <linux/i2c.h>
2012-05-11 20:18:27 +04:00
# include <linux/platform_device.h>
2011-05-03 01:19:52 +04:00
# include <linux/mfd/tps65910.h>
2012-05-19 00:31:43 +04:00
# include <linux/of_device.h>
2011-05-03 01:19:52 +04:00
2012-05-11 20:18:27 +04:00
struct tps65910_gpio {
struct gpio_chip gpio_chip ;
struct tps65910 * tps65910 ;
} ;
static inline struct tps65910_gpio * to_tps65910_gpio ( struct gpio_chip * chip )
{
return container_of ( chip , struct tps65910_gpio , gpio_chip ) ;
}
2011-05-03 01:19:52 +04:00
static int tps65910_gpio_get ( struct gpio_chip * gc , unsigned offset )
{
2012-05-11 20:18:27 +04:00
struct tps65910_gpio * tps65910_gpio = to_tps65910_gpio ( gc ) ;
struct tps65910 * tps65910 = tps65910_gpio - > tps65910 ;
2012-05-08 22:42:38 +04:00
unsigned int val ;
2011-05-03 01:19:52 +04:00
2012-05-08 22:42:38 +04:00
tps65910_reg_read ( tps65910 , TPS65910_GPIO0 + offset , & val ) ;
2011-05-03 01:19:52 +04:00
2011-05-17 03:35:42 +04:00
if ( val & GPIO_STS_MASK )
2011-05-03 01:19:52 +04:00
return 1 ;
return 0 ;
}
static void tps65910_gpio_set ( struct gpio_chip * gc , unsigned offset ,
int value )
{
2012-05-11 20:18:27 +04:00
struct tps65910_gpio * tps65910_gpio = to_tps65910_gpio ( gc ) ;
struct tps65910 * tps65910 = tps65910_gpio - > tps65910 ;
2011-05-03 01:19:52 +04:00
if ( value )
2012-05-08 22:42:38 +04:00
tps65910_reg_set_bits ( tps65910 , TPS65910_GPIO0 + offset ,
2011-05-17 03:35:42 +04:00
GPIO_SET_MASK ) ;
2011-05-03 01:19:52 +04:00
else
2012-05-08 22:42:38 +04:00
tps65910_reg_clear_bits ( tps65910 , TPS65910_GPIO0 + offset ,
2011-05-17 03:35:42 +04:00
GPIO_SET_MASK ) ;
2011-05-03 01:19:52 +04:00
}
static int tps65910_gpio_output ( struct gpio_chip * gc , unsigned offset ,
int value )
{
2012-05-11 20:18:27 +04:00
struct tps65910_gpio * tps65910_gpio = to_tps65910_gpio ( gc ) ;
struct tps65910 * tps65910 = tps65910_gpio - > tps65910 ;
2011-05-03 01:19:52 +04:00
/* Set the initial value */
2012-01-18 18:37:35 +04:00
tps65910_gpio_set ( gc , offset , value ) ;
2011-05-03 01:19:52 +04:00
2012-05-08 22:42:38 +04:00
return tps65910_reg_set_bits ( tps65910 , TPS65910_GPIO0 + offset ,
2011-05-17 03:35:42 +04:00
GPIO_CFG_MASK ) ;
2011-05-03 01:19:52 +04:00
}
static int tps65910_gpio_input ( struct gpio_chip * gc , unsigned offset )
{
2012-05-11 20:18:27 +04:00
struct tps65910_gpio * tps65910_gpio = to_tps65910_gpio ( gc ) ;
struct tps65910 * tps65910 = tps65910_gpio - > tps65910 ;
2011-05-03 01:19:52 +04:00
2012-05-08 22:42:38 +04:00
return tps65910_reg_clear_bits ( tps65910 , TPS65910_GPIO0 + offset ,
2011-05-17 03:35:42 +04:00
GPIO_CFG_MASK ) ;
2011-05-03 01:19:52 +04:00
}
2012-05-19 00:31:43 +04:00
# ifdef CONFIG_OF
static struct tps65910_board * tps65910_parse_dt_for_gpio ( struct device * dev ,
struct tps65910 * tps65910 , int chip_ngpio )
{
struct tps65910_board * tps65910_board = tps65910 - > of_plat_data ;
unsigned int prop_array [ TPS6591X_MAX_NUM_GPIO ] ;
int ngpio = min ( chip_ngpio , TPS6591X_MAX_NUM_GPIO ) ;
int ret ;
int idx ;
tps65910_board - > gpio_base = - 1 ;
ret = of_property_read_u32_array ( tps65910 - > dev - > of_node ,
" ti,en-gpio-sleep " , prop_array , ngpio ) ;
if ( ret < 0 ) {
dev_dbg ( dev , " ti,en-gpio-sleep not specified \n " ) ;
return tps65910_board ;
}
for ( idx = 0 ; idx < ngpio ; idx + + )
tps65910_board - > en_gpio_sleep [ idx ] = ( prop_array [ idx ] ! = 0 ) ;
return tps65910_board ;
}
# else
static struct tps65910_board * tps65910_parse_dt_for_gpio ( struct device * dev ,
struct tps65910 * tps65910 , int chip_ngpio )
{
return NULL ;
}
# endif
2012-11-19 22:22:34 +04:00
static int tps65910_gpio_probe ( struct platform_device * pdev )
2011-05-03 01:19:52 +04:00
{
2012-05-11 20:18:27 +04:00
struct tps65910 * tps65910 = dev_get_drvdata ( pdev - > dev . parent ) ;
struct tps65910_board * pdata = dev_get_platdata ( tps65910 - > dev ) ;
struct tps65910_gpio * tps65910_gpio ;
2011-05-03 01:19:52 +04:00
int ret ;
2012-05-11 20:18:27 +04:00
int i ;
tps65910_gpio = devm_kzalloc ( & pdev - > dev ,
sizeof ( * tps65910_gpio ) , GFP_KERNEL ) ;
if ( ! tps65910_gpio ) {
dev_err ( & pdev - > dev , " Could not allocate tps65910_gpio \n " ) ;
return - ENOMEM ;
}
2011-05-03 01:19:52 +04:00
2012-05-11 20:18:27 +04:00
tps65910_gpio - > tps65910 = tps65910 ;
2011-05-03 01:19:52 +04:00
2012-05-11 20:18:27 +04:00
tps65910_gpio - > gpio_chip . owner = THIS_MODULE ;
tps65910_gpio - > gpio_chip . label = tps65910 - > i2c_client - > name ;
2011-05-17 03:35:42 +04:00
switch ( tps65910_chip_id ( tps65910 ) ) {
case TPS65910 :
2012-05-11 20:18:27 +04:00
tps65910_gpio - > gpio_chip . ngpio = TPS65910_NUM_GPIO ;
2011-07-06 06:08:27 +04:00
break ;
2011-05-17 03:35:42 +04:00
case TPS65911 :
2012-05-11 20:18:27 +04:00
tps65910_gpio - > gpio_chip . ngpio = TPS65911_NUM_GPIO ;
2011-07-06 06:08:27 +04:00
break ;
2011-05-17 03:35:42 +04:00
default :
2012-05-11 20:18:27 +04:00
return - EINVAL ;
2011-05-17 03:35:42 +04:00
}
2012-05-11 20:18:27 +04:00
tps65910_gpio - > gpio_chip . can_sleep = 1 ;
tps65910_gpio - > gpio_chip . direction_input = tps65910_gpio_input ;
tps65910_gpio - > gpio_chip . direction_output = tps65910_gpio_output ;
tps65910_gpio - > gpio_chip . set = tps65910_gpio_set ;
tps65910_gpio - > gpio_chip . get = tps65910_gpio_get ;
tps65910_gpio - > gpio_chip . dev = & pdev - > dev ;
2012-07-10 09:16:34 +04:00
# ifdef CONFIG_OF_GPIO
2012-07-04 19:06:45 +04:00
tps65910_gpio - > gpio_chip . of_node = tps65910 - > dev - > of_node ;
2012-07-10 09:16:34 +04:00
# endif
2012-05-11 20:18:27 +04:00
if ( pdata & & pdata - > gpio_base )
tps65910_gpio - > gpio_chip . base = pdata - > gpio_base ;
else
tps65910_gpio - > gpio_chip . base = - 1 ;
2012-05-19 00:31:43 +04:00
if ( ! pdata & & tps65910 - > dev - > of_node )
pdata = tps65910_parse_dt_for_gpio ( & pdev - > dev , tps65910 ,
tps65910_gpio - > gpio_chip . ngpio ) ;
2012-05-11 20:18:27 +04:00
if ( ! pdata )
goto skip_init ;
/* Configure sleep control for gpios if provided */
for ( i = 0 ; i < tps65910_gpio - > gpio_chip . ngpio ; + + i ) {
if ( ! pdata - > en_gpio_sleep [ i ] )
continue ;
ret = tps65910_reg_set_bits ( tps65910 ,
TPS65910_GPIO0 + i , GPIO_SLEEP_MASK ) ;
if ( ret < 0 )
dev_warn ( tps65910 - > dev ,
" GPIO Sleep setting failed with err %d \n " , ret ) ;
}
skip_init :
ret = gpiochip_add ( & tps65910_gpio - > gpio_chip ) ;
if ( ret < 0 ) {
dev_err ( & pdev - > dev , " Could not register gpiochip, %d \n " , ret ) ;
return ret ;
2012-02-01 10:39:04 +04:00
}
2012-05-11 20:18:27 +04:00
platform_set_drvdata ( pdev , tps65910_gpio ) ;
2011-05-03 01:19:52 +04:00
2012-05-11 20:18:27 +04:00
return ret ;
2011-05-03 01:19:52 +04:00
}
2012-05-11 20:18:27 +04:00
2012-11-19 22:25:50 +04:00
static int tps65910_gpio_remove ( struct platform_device * pdev )
2012-05-11 20:18:27 +04:00
{
struct tps65910_gpio * tps65910_gpio = platform_get_drvdata ( pdev ) ;
return gpiochip_remove ( & tps65910_gpio - > gpio_chip ) ;
}
static struct platform_driver tps65910_gpio_driver = {
. driver . name = " tps65910-gpio " ,
. driver . owner = THIS_MODULE ,
. probe = tps65910_gpio_probe ,
2012-11-19 22:20:08 +04:00
. remove = tps65910_gpio_remove ,
2012-05-11 20:18:27 +04:00
} ;
static int __init tps65910_gpio_init ( void )
{
return platform_driver_register ( & tps65910_gpio_driver ) ;
}
subsys_initcall ( tps65910_gpio_init ) ;
static void __exit tps65910_gpio_exit ( void )
{
platform_driver_unregister ( & tps65910_gpio_driver ) ;
}
module_exit ( tps65910_gpio_exit ) ;
MODULE_AUTHOR ( " Graeme Gregory <gg@slimlogic.co.uk> " ) ;
MODULE_AUTHOR ( " Jorge Eduardo Candelaria jedu@slimlogic.co.uk> " ) ;
MODULE_DESCRIPTION ( " GPIO interface for TPS65910/TPS6511 PMICs " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_ALIAS ( " platform:tps65910-gpio " ) ;