2010-08-11 03:11:04 +04:00
/*
* Core driver for TI TPS6586x PMIC family
*
* Copyright ( c ) 2010 CompuLab Ltd .
* Mike Rapoport < mike @ compulab . co . il >
*
* Based on da903x . c .
* Copyright ( C ) 2008 Compulab , Ltd .
* Mike Rapoport < mike @ compulab . co . il >
* Copyright ( C ) 2006 - 2008 Marvell International Ltd .
* Eric Miao < eric . miao @ marvell . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
2010-09-20 02:18:27 +04:00
# include <linux/interrupt.h>
# include <linux/irq.h>
2010-08-11 03:11:04 +04:00
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/mutex.h>
# include <linux/slab.h>
# include <linux/gpio.h>
# include <linux/i2c.h>
# include <linux/mfd/core.h>
# include <linux/mfd/tps6586x.h>
/* GPIO control registers */
# define TPS6586X_GPIOSET1 0x5d
# define TPS6586X_GPIOSET2 0x5e
2010-09-20 02:18:27 +04:00
/* interrupt control registers */
# define TPS6586X_INT_ACK1 0xb5
# define TPS6586X_INT_ACK2 0xb6
# define TPS6586X_INT_ACK3 0xb7
# define TPS6586X_INT_ACK4 0xb8
/* interrupt mask registers */
# define TPS6586X_INT_MASK1 0xb0
# define TPS6586X_INT_MASK2 0xb1
# define TPS6586X_INT_MASK3 0xb2
# define TPS6586X_INT_MASK4 0xb3
# define TPS6586X_INT_MASK5 0xb4
2010-08-11 03:11:04 +04:00
/* device id */
# define TPS6586X_VERSIONCRC 0xcd
2010-09-20 02:18:27 +04:00
struct tps6586x_irq_data {
u8 mask_reg ;
u8 mask_mask ;
} ;
# define TPS6586X_IRQ(_reg, _mask) \
{ \
. mask_reg = ( _reg ) - TPS6586X_INT_MASK1 , \
. mask_mask = ( _mask ) , \
}
static const struct tps6586x_irq_data tps6586x_irqs [ ] = {
[ TPS6586X_INT_PLDO_0 ] = TPS6586X_IRQ ( TPS6586X_INT_MASK1 , 1 < < 0 ) ,
[ TPS6586X_INT_PLDO_1 ] = TPS6586X_IRQ ( TPS6586X_INT_MASK1 , 1 < < 1 ) ,
[ TPS6586X_INT_PLDO_2 ] = TPS6586X_IRQ ( TPS6586X_INT_MASK1 , 1 < < 2 ) ,
[ TPS6586X_INT_PLDO_3 ] = TPS6586X_IRQ ( TPS6586X_INT_MASK1 , 1 < < 3 ) ,
[ TPS6586X_INT_PLDO_4 ] = TPS6586X_IRQ ( TPS6586X_INT_MASK1 , 1 < < 4 ) ,
[ TPS6586X_INT_PLDO_5 ] = TPS6586X_IRQ ( TPS6586X_INT_MASK1 , 1 < < 5 ) ,
[ TPS6586X_INT_PLDO_6 ] = TPS6586X_IRQ ( TPS6586X_INT_MASK1 , 1 < < 6 ) ,
[ TPS6586X_INT_PLDO_7 ] = TPS6586X_IRQ ( TPS6586X_INT_MASK1 , 1 < < 7 ) ,
[ TPS6586X_INT_COMP_DET ] = TPS6586X_IRQ ( TPS6586X_INT_MASK4 , 1 < < 0 ) ,
[ TPS6586X_INT_ADC ] = TPS6586X_IRQ ( TPS6586X_INT_MASK2 , 1 < < 1 ) ,
[ TPS6586X_INT_PLDO_8 ] = TPS6586X_IRQ ( TPS6586X_INT_MASK2 , 1 < < 2 ) ,
[ TPS6586X_INT_PLDO_9 ] = TPS6586X_IRQ ( TPS6586X_INT_MASK2 , 1 < < 3 ) ,
[ TPS6586X_INT_PSM_0 ] = TPS6586X_IRQ ( TPS6586X_INT_MASK2 , 1 < < 4 ) ,
[ TPS6586X_INT_PSM_1 ] = TPS6586X_IRQ ( TPS6586X_INT_MASK2 , 1 < < 5 ) ,
[ TPS6586X_INT_PSM_2 ] = TPS6586X_IRQ ( TPS6586X_INT_MASK2 , 1 < < 6 ) ,
[ TPS6586X_INT_PSM_3 ] = TPS6586X_IRQ ( TPS6586X_INT_MASK2 , 1 < < 7 ) ,
[ TPS6586X_INT_RTC_ALM1 ] = TPS6586X_IRQ ( TPS6586X_INT_MASK5 , 1 < < 4 ) ,
[ TPS6586X_INT_ACUSB_OVP ] = TPS6586X_IRQ ( TPS6586X_INT_MASK5 , 0x03 ) ,
[ TPS6586X_INT_USB_DET ] = TPS6586X_IRQ ( TPS6586X_INT_MASK5 , 1 < < 2 ) ,
[ TPS6586X_INT_AC_DET ] = TPS6586X_IRQ ( TPS6586X_INT_MASK5 , 1 < < 3 ) ,
[ TPS6586X_INT_BAT_DET ] = TPS6586X_IRQ ( TPS6586X_INT_MASK3 , 1 < < 0 ) ,
[ TPS6586X_INT_CHG_STAT ] = TPS6586X_IRQ ( TPS6586X_INT_MASK4 , 0xfc ) ,
[ TPS6586X_INT_CHG_TEMP ] = TPS6586X_IRQ ( TPS6586X_INT_MASK3 , 0x06 ) ,
[ TPS6586X_INT_PP ] = TPS6586X_IRQ ( TPS6586X_INT_MASK3 , 0xf0 ) ,
[ TPS6586X_INT_RESUME ] = TPS6586X_IRQ ( TPS6586X_INT_MASK5 , 1 < < 5 ) ,
[ TPS6586X_INT_LOW_SYS ] = TPS6586X_IRQ ( TPS6586X_INT_MASK5 , 1 < < 6 ) ,
[ TPS6586X_INT_RTC_ALM2 ] = TPS6586X_IRQ ( TPS6586X_INT_MASK4 , 1 < < 1 ) ,
} ;
2010-08-11 03:11:04 +04:00
struct tps6586x {
struct mutex lock ;
struct device * dev ;
struct i2c_client * client ;
struct gpio_chip gpio ;
2010-09-20 02:18:27 +04:00
struct irq_chip irq_chip ;
struct mutex irq_lock ;
int irq_base ;
u32 irq_en ;
u8 mask_cache [ 5 ] ;
u8 mask_reg [ 5 ] ;
2010-08-11 03:11:04 +04:00
} ;
static inline int __tps6586x_read ( struct i2c_client * client ,
int reg , uint8_t * val )
{
int ret ;
ret = i2c_smbus_read_byte_data ( client , reg ) ;
if ( ret < 0 ) {
dev_err ( & client - > dev , " failed reading at 0x%02x \n " , reg ) ;
return ret ;
}
* val = ( uint8_t ) ret ;
return 0 ;
}
static inline int __tps6586x_reads ( struct i2c_client * client , int reg ,
int len , uint8_t * val )
{
int ret ;
ret = i2c_smbus_read_i2c_block_data ( client , reg , len , val ) ;
if ( ret < 0 ) {
dev_err ( & client - > dev , " failed reading from 0x%02x \n " , reg ) ;
return ret ;
}
return 0 ;
}
static inline int __tps6586x_write ( struct i2c_client * client ,
int reg , uint8_t val )
{
int ret ;
ret = i2c_smbus_write_byte_data ( client , reg , val ) ;
if ( ret < 0 ) {
dev_err ( & client - > dev , " failed writing 0x%02x to 0x%02x \n " ,
val , reg ) ;
return ret ;
}
return 0 ;
}
static inline int __tps6586x_writes ( struct i2c_client * client , int reg ,
int len , uint8_t * val )
{
2011-02-24 07:48:13 +03:00
int ret , i ;
2010-08-11 03:11:04 +04:00
2011-02-24 07:48:13 +03:00
for ( i = 0 ; i < len ; i + + ) {
ret = __tps6586x_write ( client , reg + i , * ( val + i ) ) ;
if ( ret < 0 )
return ret ;
2010-08-11 03:11:04 +04:00
}
return 0 ;
}
int tps6586x_write ( struct device * dev , int reg , uint8_t val )
{
return __tps6586x_write ( to_i2c_client ( dev ) , reg , val ) ;
}
EXPORT_SYMBOL_GPL ( tps6586x_write ) ;
int tps6586x_writes ( struct device * dev , int reg , int len , uint8_t * val )
{
return __tps6586x_writes ( to_i2c_client ( dev ) , reg , len , val ) ;
}
EXPORT_SYMBOL_GPL ( tps6586x_writes ) ;
int tps6586x_read ( struct device * dev , int reg , uint8_t * val )
{
return __tps6586x_read ( to_i2c_client ( dev ) , reg , val ) ;
}
EXPORT_SYMBOL_GPL ( tps6586x_read ) ;
int tps6586x_reads ( struct device * dev , int reg , int len , uint8_t * val )
{
return __tps6586x_reads ( to_i2c_client ( dev ) , reg , len , val ) ;
}
EXPORT_SYMBOL_GPL ( tps6586x_reads ) ;
int tps6586x_set_bits ( struct device * dev , int reg , uint8_t bit_mask )
{
struct tps6586x * tps6586x = dev_get_drvdata ( dev ) ;
uint8_t reg_val ;
int ret = 0 ;
mutex_lock ( & tps6586x - > lock ) ;
ret = __tps6586x_read ( to_i2c_client ( dev ) , reg , & reg_val ) ;
if ( ret )
goto out ;
2011-10-31 10:24:30 +04:00
if ( ( reg_val & bit_mask ) ! = bit_mask ) {
2010-08-11 03:11:04 +04:00
reg_val | = bit_mask ;
ret = __tps6586x_write ( to_i2c_client ( dev ) , reg , reg_val ) ;
}
out :
mutex_unlock ( & tps6586x - > lock ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( tps6586x_set_bits ) ;
int tps6586x_clr_bits ( struct device * dev , int reg , uint8_t bit_mask )
{
struct tps6586x * tps6586x = dev_get_drvdata ( dev ) ;
uint8_t reg_val ;
int ret = 0 ;
mutex_lock ( & tps6586x - > lock ) ;
ret = __tps6586x_read ( to_i2c_client ( dev ) , reg , & reg_val ) ;
if ( ret )
goto out ;
if ( reg_val & bit_mask ) {
reg_val & = ~ bit_mask ;
ret = __tps6586x_write ( to_i2c_client ( dev ) , reg , reg_val ) ;
}
out :
mutex_unlock ( & tps6586x - > lock ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( tps6586x_clr_bits ) ;
int tps6586x_update ( struct device * dev , int reg , uint8_t val , uint8_t mask )
{
struct tps6586x * tps6586x = dev_get_drvdata ( dev ) ;
uint8_t reg_val ;
int ret = 0 ;
mutex_lock ( & tps6586x - > lock ) ;
ret = __tps6586x_read ( tps6586x - > client , reg , & reg_val ) ;
if ( ret )
goto out ;
if ( ( reg_val & mask ) ! = val ) {
reg_val = ( reg_val & ~ mask ) | val ;
ret = __tps6586x_write ( tps6586x - > client , reg , reg_val ) ;
}
out :
mutex_unlock ( & tps6586x - > lock ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( tps6586x_update ) ;
static int tps6586x_gpio_get ( struct gpio_chip * gc , unsigned offset )
{
struct tps6586x * tps6586x = container_of ( gc , struct tps6586x , gpio ) ;
uint8_t val ;
int ret ;
ret = __tps6586x_read ( tps6586x - > client , TPS6586X_GPIOSET2 , & val ) ;
if ( ret )
return ret ;
return ! ! ( val & ( 1 < < offset ) ) ;
}
static void tps6586x_gpio_set ( struct gpio_chip * chip , unsigned offset ,
int value )
{
struct tps6586x * tps6586x = container_of ( chip , struct tps6586x , gpio ) ;
2011-04-12 18:55:58 +04:00
tps6586x_update ( tps6586x - > dev , TPS6586X_GPIOSET2 ,
value < < offset , 1 < < offset ) ;
2010-08-11 03:11:04 +04:00
}
static int tps6586x_gpio_output ( struct gpio_chip * gc , unsigned offset ,
int value )
{
struct tps6586x * tps6586x = container_of ( gc , struct tps6586x , gpio ) ;
uint8_t val , mask ;
tps6586x_gpio_set ( gc , offset , value ) ;
val = 0x1 < < ( offset * 2 ) ;
mask = 0x3 < < ( offset * 2 ) ;
return tps6586x_update ( tps6586x - > dev , TPS6586X_GPIOSET1 , val , mask ) ;
}
2011-01-31 19:31:49 +03:00
static int tps6586x_gpio_init ( struct tps6586x * tps6586x , int gpio_base )
2010-08-11 03:11:04 +04:00
{
if ( ! gpio_base )
2011-01-31 19:31:49 +03:00
return 0 ;
2010-08-11 03:11:04 +04:00
tps6586x - > gpio . owner = THIS_MODULE ;
tps6586x - > gpio . label = tps6586x - > client - > name ;
tps6586x - > gpio . dev = tps6586x - > dev ;
tps6586x - > gpio . base = gpio_base ;
tps6586x - > gpio . ngpio = 4 ;
tps6586x - > gpio . can_sleep = 1 ;
/* FIXME: add handling of GPIOs as dedicated inputs */
tps6586x - > gpio . direction_output = tps6586x_gpio_output ;
tps6586x - > gpio . set = tps6586x_gpio_set ;
tps6586x - > gpio . get = tps6586x_gpio_get ;
2011-01-31 19:31:49 +03:00
return gpiochip_add ( & tps6586x - > gpio ) ;
2010-08-11 03:11:04 +04:00
}
static int __remove_subdev ( struct device * dev , void * unused )
{
platform_device_unregister ( to_platform_device ( dev ) ) ;
return 0 ;
}
static int tps6586x_remove_subdevs ( struct tps6586x * tps6586x )
{
return device_for_each_child ( tps6586x - > dev , NULL , __remove_subdev ) ;
}
2010-12-12 15:39:28 +03:00
static void tps6586x_irq_lock ( struct irq_data * data )
2010-09-20 02:18:27 +04:00
{
2010-12-12 15:39:28 +03:00
struct tps6586x * tps6586x = irq_data_get_irq_chip_data ( data ) ;
2010-09-20 02:18:27 +04:00
mutex_lock ( & tps6586x - > irq_lock ) ;
}
2010-12-12 15:39:28 +03:00
static void tps6586x_irq_enable ( struct irq_data * irq_data )
2010-09-20 02:18:27 +04:00
{
2010-12-12 15:39:28 +03:00
struct tps6586x * tps6586x = irq_data_get_irq_chip_data ( irq_data ) ;
unsigned int __irq = irq_data - > irq - tps6586x - > irq_base ;
2010-09-20 02:18:27 +04:00
const struct tps6586x_irq_data * data = & tps6586x_irqs [ __irq ] ;
tps6586x - > mask_reg [ data - > mask_reg ] & = ~ data - > mask_mask ;
tps6586x - > irq_en | = ( 1 < < __irq ) ;
}
2010-12-12 15:39:28 +03:00
static void tps6586x_irq_disable ( struct irq_data * irq_data )
2010-09-20 02:18:27 +04:00
{
2010-12-12 15:39:28 +03:00
struct tps6586x * tps6586x = irq_data_get_irq_chip_data ( irq_data ) ;
2010-09-20 02:18:27 +04:00
2010-12-12 15:39:28 +03:00
unsigned int __irq = irq_data - > irq - tps6586x - > irq_base ;
2010-09-20 02:18:27 +04:00
const struct tps6586x_irq_data * data = & tps6586x_irqs [ __irq ] ;
tps6586x - > mask_reg [ data - > mask_reg ] | = data - > mask_mask ;
tps6586x - > irq_en & = ~ ( 1 < < __irq ) ;
}
2010-12-12 15:39:28 +03:00
static void tps6586x_irq_sync_unlock ( struct irq_data * data )
2010-09-20 02:18:27 +04:00
{
2010-12-12 15:39:28 +03:00
struct tps6586x * tps6586x = irq_data_get_irq_chip_data ( data ) ;
2010-09-20 02:18:27 +04:00
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( tps6586x - > mask_reg ) ; i + + ) {
if ( tps6586x - > mask_reg [ i ] ! = tps6586x - > mask_cache [ i ] ) {
if ( ! WARN_ON ( tps6586x_write ( tps6586x - > dev ,
TPS6586X_INT_MASK1 + i ,
tps6586x - > mask_reg [ i ] ) ) )
tps6586x - > mask_cache [ i ] = tps6586x - > mask_reg [ i ] ;
}
}
mutex_unlock ( & tps6586x - > irq_lock ) ;
}
static irqreturn_t tps6586x_irq ( int irq , void * data )
{
struct tps6586x * tps6586x = data ;
u32 acks ;
int ret = 0 ;
ret = tps6586x_reads ( tps6586x - > dev , TPS6586X_INT_ACK1 ,
sizeof ( acks ) , ( uint8_t * ) & acks ) ;
if ( ret < 0 ) {
dev_err ( tps6586x - > dev , " failed to read interrupt status \n " ) ;
return IRQ_NONE ;
}
acks = le32_to_cpu ( acks ) ;
while ( acks ) {
int i = __ffs ( acks ) ;
if ( tps6586x - > irq_en & ( 1 < < i ) )
handle_nested_irq ( tps6586x - > irq_base + i ) ;
acks & = ~ ( 1 < < i ) ;
}
return IRQ_HANDLED ;
}
static int __devinit tps6586x_irq_init ( struct tps6586x * tps6586x , int irq ,
int irq_base )
{
int i , ret ;
u8 tmp [ 4 ] ;
if ( ! irq_base ) {
dev_warn ( tps6586x - > dev , " No interrupt support on IRQ base \n " ) ;
return - EINVAL ;
}
mutex_init ( & tps6586x - > irq_lock ) ;
for ( i = 0 ; i < 5 ; i + + ) {
tps6586x - > mask_cache [ i ] = 0xff ;
tps6586x - > mask_reg [ i ] = 0xff ;
tps6586x_write ( tps6586x - > dev , TPS6586X_INT_MASK1 + i , 0xff ) ;
}
tps6586x_reads ( tps6586x - > dev , TPS6586X_INT_ACK1 , sizeof ( tmp ) , tmp ) ;
tps6586x - > irq_base = irq_base ;
tps6586x - > irq_chip . name = " tps6586x " ;
2010-12-12 15:39:28 +03:00
tps6586x - > irq_chip . irq_enable = tps6586x_irq_enable ;
tps6586x - > irq_chip . irq_disable = tps6586x_irq_disable ;
tps6586x - > irq_chip . irq_bus_lock = tps6586x_irq_lock ;
tps6586x - > irq_chip . irq_bus_sync_unlock = tps6586x_irq_sync_unlock ;
2010-09-20 02:18:27 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( tps6586x_irqs ) ; i + + ) {
int __irq = i + tps6586x - > irq_base ;
2011-03-25 14:12:32 +03:00
irq_set_chip_data ( __irq , tps6586x ) ;
irq_set_chip_and_handler ( __irq , & tps6586x - > irq_chip ,
2010-09-20 02:18:27 +04:00
handle_simple_irq ) ;
2011-03-25 14:12:32 +03:00
irq_set_nested_thread ( __irq , 1 ) ;
2010-09-20 02:18:27 +04:00
# ifdef CONFIG_ARM
set_irq_flags ( __irq , IRQF_VALID ) ;
# endif
}
ret = request_threaded_irq ( irq , NULL , tps6586x_irq , IRQF_ONESHOT ,
" tps6586x " , tps6586x ) ;
if ( ! ret ) {
device_init_wakeup ( tps6586x - > dev , 1 ) ;
enable_irq_wake ( irq ) ;
}
return ret ;
}
2010-08-11 03:11:04 +04:00
static int __devinit tps6586x_add_subdevs ( struct tps6586x * tps6586x ,
struct tps6586x_platform_data * pdata )
{
struct tps6586x_subdev_info * subdev ;
struct platform_device * pdev ;
int i , ret = 0 ;
for ( i = 0 ; i < pdata - > num_subdevs ; i + + ) {
subdev = & pdata - > subdevs [ i ] ;
pdev = platform_device_alloc ( subdev - > name , subdev - > id ) ;
2010-08-24 09:47:22 +04:00
if ( ! pdev ) {
ret = - ENOMEM ;
goto failed ;
}
2010-08-11 03:11:04 +04:00
pdev - > dev . parent = tps6586x - > dev ;
pdev - > dev . platform_data = subdev - > platform_data ;
ret = platform_device_add ( pdev ) ;
2010-08-24 09:47:22 +04:00
if ( ret ) {
platform_device_put ( pdev ) ;
2010-08-11 03:11:04 +04:00
goto failed ;
2010-08-24 09:47:22 +04:00
}
2010-08-11 03:11:04 +04:00
}
return 0 ;
failed :
tps6586x_remove_subdevs ( tps6586x ) ;
return ret ;
}
static int __devinit tps6586x_i2c_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
{
struct tps6586x_platform_data * pdata = client - > dev . platform_data ;
struct tps6586x * tps6586x ;
int ret ;
if ( ! pdata ) {
dev_err ( & client - > dev , " tps6586x requires platform data \n " ) ;
return - ENOTSUPP ;
}
ret = i2c_smbus_read_byte_data ( client , TPS6586X_VERSIONCRC ) ;
if ( ret < 0 ) {
dev_err ( & client - > dev , " Chip ID read failed: %d \n " , ret ) ;
return - EIO ;
}
2010-12-09 20:30:11 +03:00
dev_info ( & client - > dev , " VERSIONCRC is %02x \n " , ret ) ;
2010-08-11 03:11:04 +04:00
tps6586x = kzalloc ( sizeof ( struct tps6586x ) , GFP_KERNEL ) ;
if ( tps6586x = = NULL )
return - ENOMEM ;
tps6586x - > client = client ;
tps6586x - > dev = & client - > dev ;
i2c_set_clientdata ( client , tps6586x ) ;
mutex_init ( & tps6586x - > lock ) ;
2010-09-20 02:18:27 +04:00
if ( client - > irq ) {
ret = tps6586x_irq_init ( tps6586x , client - > irq ,
pdata - > irq_base ) ;
if ( ret ) {
dev_err ( & client - > dev , " IRQ init failed: %d \n " , ret ) ;
goto err_irq_init ;
}
}
2011-01-31 19:31:49 +03:00
ret = tps6586x_gpio_init ( tps6586x , pdata - > gpio_base ) ;
if ( ret ) {
dev_err ( & client - > dev , " GPIO registration failed: %d \n " , ret ) ;
goto err_gpio_init ;
}
2010-08-11 03:11:04 +04:00
ret = tps6586x_add_subdevs ( tps6586x , pdata ) ;
if ( ret ) {
dev_err ( & client - > dev , " add devices failed: %d \n " , ret ) ;
goto err_add_devs ;
}
return 0 ;
err_add_devs :
2011-01-31 19:31:49 +03:00
if ( pdata - > gpio_base ) {
ret = gpiochip_remove ( & tps6586x - > gpio ) ;
if ( ret )
dev_err ( & client - > dev , " Can't remove gpio chip: %d \n " ,
ret ) ;
}
err_gpio_init :
2010-09-20 02:18:27 +04:00
if ( client - > irq )
free_irq ( client - > irq , tps6586x ) ;
err_irq_init :
2010-08-11 03:11:04 +04:00
kfree ( tps6586x ) ;
return ret ;
}
static int __devexit tps6586x_i2c_remove ( struct i2c_client * client )
{
2010-08-24 11:18:58 +04:00
struct tps6586x * tps6586x = i2c_get_clientdata ( client ) ;
struct tps6586x_platform_data * pdata = client - > dev . platform_data ;
int ret ;
2010-09-20 02:18:27 +04:00
if ( client - > irq )
free_irq ( client - > irq , tps6586x ) ;
2010-08-24 11:18:58 +04:00
if ( pdata - > gpio_base ) {
ret = gpiochip_remove ( & tps6586x - > gpio ) ;
if ( ret )
dev_err ( & client - > dev , " Can't remove gpio chip: %d \n " ,
ret ) ;
}
tps6586x_remove_subdevs ( tps6586x ) ;
kfree ( tps6586x ) ;
2010-08-11 03:11:04 +04:00
return 0 ;
}
static const struct i2c_device_id tps6586x_id_table [ ] = {
{ " tps6586x " , 0 } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( i2c , tps6586x_id_table ) ;
static struct i2c_driver tps6586x_driver = {
. driver = {
. name = " tps6586x " ,
. owner = THIS_MODULE ,
} ,
. probe = tps6586x_i2c_probe ,
. remove = __devexit_p ( tps6586x_i2c_remove ) ,
. id_table = tps6586x_id_table ,
} ;
static int __init tps6586x_init ( void )
{
return i2c_add_driver ( & tps6586x_driver ) ;
}
subsys_initcall ( tps6586x_init ) ;
static void __exit tps6586x_exit ( void )
{
i2c_del_driver ( & tps6586x_driver ) ;
}
module_exit ( tps6586x_exit ) ;
MODULE_DESCRIPTION ( " TPS6586X core driver " ) ;
MODULE_AUTHOR ( " Mike Rapoport <mike@compulab.co.il> " ) ;
MODULE_LICENSE ( " GPL " ) ;