2011-05-03 01:19:46 +04:00
/*
* tps65910 . c - - TI TPS6591x
*
* 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/module.h>
# include <linux/moduleparam.h>
# include <linux/init.h>
2012-02-21 16:51:34 +04:00
# include <linux/err.h>
2011-05-03 01:19:46 +04:00
# include <linux/slab.h>
# include <linux/i2c.h>
# include <linux/gpio.h>
# include <linux/mfd/core.h>
2012-02-21 16:51:34 +04:00
# include <linux/regmap.h>
2011-05-03 01:19:46 +04:00
# include <linux/mfd/tps65910.h>
static struct mfd_cell tps65910s [ ] = {
{
. name = " tps65910-pmic " ,
} ,
{
. name = " tps65910-rtc " ,
} ,
{
. name = " tps65910-power " ,
} ,
} ;
static int tps65910_i2c_read ( struct tps65910 * tps65910 , u8 reg ,
int bytes , void * dest )
{
2012-02-21 16:51:34 +04:00
return regmap_bulk_read ( tps65910 - > regmap , reg , dest , bytes ) ;
2011-05-03 01:19:46 +04:00
}
static int tps65910_i2c_write ( struct tps65910 * tps65910 , u8 reg ,
2012-02-21 16:51:34 +04:00
int bytes , void * src )
2011-05-03 01:19:46 +04:00
{
2012-02-21 16:51:34 +04:00
return regmap_bulk_write ( tps65910 - > regmap , reg , src , bytes ) ;
2011-05-03 01:19:46 +04:00
}
int tps65910_set_bits ( struct tps65910 * tps65910 , u8 reg , u8 mask )
{
2012-02-21 16:51:34 +04:00
return regmap_update_bits ( tps65910 - > regmap , reg , mask , mask ) ;
2011-05-03 01:19:46 +04:00
}
EXPORT_SYMBOL_GPL ( tps65910_set_bits ) ;
int tps65910_clear_bits ( struct tps65910 * tps65910 , u8 reg , u8 mask )
{
2012-02-21 16:51:34 +04:00
return regmap_update_bits ( tps65910 - > regmap , reg , mask , 0 ) ;
2011-05-03 01:19:46 +04:00
}
EXPORT_SYMBOL_GPL ( tps65910_clear_bits ) ;
2012-02-21 16:51:34 +04:00
static bool is_volatile_reg ( struct device * dev , unsigned int reg )
{
struct tps65910 * tps65910 = dev_get_drvdata ( dev ) ;
/*
* Caching all regulator registers .
* All regualator register address range is same for
* TPS65910 and TPS65911
*/
if ( ( reg > = TPS65910_VIO ) & & ( reg < = TPS65910_VDAC ) ) {
/* Check for non-existing register */
if ( tps65910_chip_id ( tps65910 ) = = TPS65910 )
if ( ( reg = = TPS65911_VDDCTRL_OP ) | |
( reg = = TPS65911_VDDCTRL_SR ) )
return true ;
return false ;
}
return true ;
}
2012-03-07 17:16:05 +04:00
static const struct regmap_config tps65910_regmap_config = {
2012-02-21 16:51:34 +04:00
. reg_bits = 8 ,
. val_bits = 8 ,
. volatile_reg = is_volatile_reg ,
. max_register = TPS65910_MAX_REGISTER ,
. num_reg_defaults_raw = TPS65910_MAX_REGISTER ,
. cache_type = REGCACHE_RBTREE ,
} ;
2011-05-03 01:19:46 +04:00
static int tps65910_i2c_probe ( struct i2c_client * i2c ,
const struct i2c_device_id * id )
{
struct tps65910 * tps65910 ;
2011-05-03 01:19:52 +04:00
struct tps65910_board * pmic_plat_data ;
2011-05-03 01:20:04 +04:00
struct tps65910_platform_data * init_data ;
2011-05-03 01:19:46 +04:00
int ret = 0 ;
2011-05-03 01:19:52 +04:00
pmic_plat_data = dev_get_platdata ( & i2c - > dev ) ;
if ( ! pmic_plat_data )
return - EINVAL ;
2011-05-03 01:20:04 +04:00
init_data = kzalloc ( sizeof ( struct tps65910_platform_data ) , GFP_KERNEL ) ;
if ( init_data = = NULL )
return - ENOMEM ;
2011-05-03 01:19:46 +04:00
tps65910 = kzalloc ( sizeof ( struct tps65910 ) , GFP_KERNEL ) ;
2011-07-06 02:29:07 +04:00
if ( tps65910 = = NULL ) {
kfree ( init_data ) ;
2011-05-03 01:19:46 +04:00
return - ENOMEM ;
2011-07-06 02:29:07 +04:00
}
2011-05-03 01:19:46 +04:00
i2c_set_clientdata ( i2c , tps65910 ) ;
tps65910 - > dev = & i2c - > dev ;
tps65910 - > i2c_client = i2c ;
2011-05-17 03:34:59 +04:00
tps65910 - > id = id - > driver_data ;
2011-05-03 01:19:46 +04:00
tps65910 - > read = tps65910_i2c_read ;
tps65910 - > write = tps65910_i2c_write ;
mutex_init ( & tps65910 - > io_mutex ) ;
2012-03-07 17:16:05 +04:00
tps65910 - > regmap = regmap_init_i2c ( i2c , & tps65910_regmap_config ) ;
2012-02-21 16:51:34 +04:00
if ( IS_ERR ( tps65910 - > regmap ) ) {
ret = PTR_ERR ( tps65910 - > regmap ) ;
dev_err ( & i2c - > dev , " regmap initialization failed: %d \n " , ret ) ;
goto regmap_err ;
}
2011-05-03 01:19:46 +04:00
ret = mfd_add_devices ( tps65910 - > dev , - 1 ,
tps65910s , ARRAY_SIZE ( tps65910s ) ,
NULL , 0 ) ;
if ( ret < 0 )
goto err ;
2011-07-14 01:22:26 +04:00
init_data - > irq = pmic_plat_data - > irq ;
2012-01-18 18:49:16 +04:00
init_data - > irq_base = pmic_plat_data - > irq_base ;
2011-07-14 01:22:26 +04:00
2011-05-03 01:19:52 +04:00
tps65910_gpio_init ( tps65910 , pmic_plat_data - > gpio_base ) ;
2011-12-14 14:35:35 +04:00
tps65910_irq_init ( tps65910 , init_data - > irq , init_data ) ;
2011-05-03 01:20:04 +04:00
2011-07-06 02:29:07 +04:00
kfree ( init_data ) ;
2011-05-03 01:19:46 +04:00
return ret ;
err :
2012-02-21 16:51:34 +04:00
regmap_exit ( tps65910 - > regmap ) ;
regmap_err :
2011-05-03 01:19:46 +04:00
kfree ( tps65910 ) ;
2011-07-06 02:29:07 +04:00
kfree ( init_data ) ;
2011-05-03 01:19:46 +04:00
return ret ;
}
static int tps65910_i2c_remove ( struct i2c_client * i2c )
{
struct tps65910 * tps65910 = i2c_get_clientdata ( i2c ) ;
2011-06-20 14:47:55 +04:00
tps65910_irq_exit ( tps65910 ) ;
2011-12-14 14:35:35 +04:00
mfd_remove_devices ( tps65910 - > dev ) ;
2012-02-21 16:51:34 +04:00
regmap_exit ( tps65910 - > regmap ) ;
2011-05-03 01:19:46 +04:00
kfree ( tps65910 ) ;
return 0 ;
}
static const struct i2c_device_id tps65910_i2c_id [ ] = {
2011-05-17 03:34:59 +04:00
{ " tps65910 " , TPS65910 } ,
{ " tps65911 " , TPS65911 } ,
2011-05-03 01:19:46 +04:00
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , tps65910_i2c_id ) ;
static struct i2c_driver tps65910_i2c_driver = {
. driver = {
. name = " tps65910 " ,
. owner = THIS_MODULE ,
} ,
. probe = tps65910_i2c_probe ,
. remove = tps65910_i2c_remove ,
. id_table = tps65910_i2c_id ,
} ;
static int __init tps65910_i2c_init ( void )
{
return i2c_add_driver ( & tps65910_i2c_driver ) ;
}
/* init early so consumer devices can complete system boot */
subsys_initcall ( tps65910_i2c_init ) ;
static void __exit tps65910_i2c_exit ( void )
{
i2c_del_driver ( & tps65910_i2c_driver ) ;
}
module_exit ( tps65910_i2c_exit ) ;
MODULE_AUTHOR ( " Graeme Gregory <gg@slimlogic.co.uk> " ) ;
MODULE_AUTHOR ( " Jorge Eduardo Candelaria <jedu@slimlogic.co.uk> " ) ;
MODULE_DESCRIPTION ( " TPS6591x chip family multi-function driver " ) ;
MODULE_LICENSE ( " GPL " ) ;