2010-06-04 07:46:04 +04:00
/*
* Voltage and current regulation for AD5398 and AD5821
*
* Copyright 2010 Analog Devices Inc .
*
* Enter bugs at http : //blackfin.uclinux.org/
*
* Licensed under the GPL - 2 or later .
*/
# include <linux/module.h>
# include <linux/err.h>
# include <linux/i2c.h>
# include <linux/slab.h>
# include <linux/platform_device.h>
# include <linux/regulator/driver.h>
# include <linux/regulator/machine.h>
# define AD5398_CURRENT_EN_MASK 0x8000
struct ad5398_chip_info {
struct i2c_client * client ;
int min_uA ;
int max_uA ;
unsigned int current_level ;
unsigned int current_mask ;
unsigned int current_offset ;
2010-09-01 06:29:18 +04:00
struct regulator_dev * rdev ;
2010-06-04 07:46:04 +04:00
} ;
static int ad5398_calc_current ( struct ad5398_chip_info * chip ,
unsigned selector )
{
unsigned range_uA = chip - > max_uA - chip - > min_uA ;
return chip - > min_uA + ( selector * range_uA / chip - > current_level ) ;
}
static int ad5398_read_reg ( struct i2c_client * client , unsigned short * data )
{
unsigned short val ;
int ret ;
ret = i2c_master_recv ( client , ( char * ) & val , 2 ) ;
if ( ret < 0 ) {
dev_err ( & client - > dev , " I2C read error \n " ) ;
return ret ;
}
* data = be16_to_cpu ( val ) ;
return ret ;
}
static int ad5398_write_reg ( struct i2c_client * client , const unsigned short data )
{
unsigned short val ;
int ret ;
val = cpu_to_be16 ( data ) ;
ret = i2c_master_send ( client , ( char * ) & val , 2 ) ;
2016-02-11 13:17:03 +03:00
if ( ret ! = 2 ) {
2010-06-04 07:46:04 +04:00
dev_err ( & client - > dev , " I2C write error \n " ) ;
2016-02-11 13:17:03 +03:00
return ret < 0 ? ret : - EIO ;
}
2010-06-04 07:46:04 +04:00
2016-02-11 13:17:03 +03:00
return 0 ;
2010-06-04 07:46:04 +04:00
}
static int ad5398_get_current_limit ( struct regulator_dev * rdev )
{
struct ad5398_chip_info * chip = rdev_get_drvdata ( rdev ) ;
struct i2c_client * client = chip - > client ;
unsigned short data ;
int ret ;
ret = ad5398_read_reg ( client , & data ) ;
if ( ret < 0 )
return ret ;
ret = ( data & chip - > current_mask ) > > chip - > current_offset ;
return ad5398_calc_current ( chip , ret ) ;
}
static int ad5398_set_current_limit ( struct regulator_dev * rdev , int min_uA , int max_uA )
{
struct ad5398_chip_info * chip = rdev_get_drvdata ( rdev ) ;
struct i2c_client * client = chip - > client ;
unsigned range_uA = chip - > max_uA - chip - > min_uA ;
unsigned selector ;
unsigned short data ;
int ret ;
2012-07-04 07:55:07 +04:00
if ( min_uA < chip - > min_uA )
min_uA = chip - > min_uA ;
if ( max_uA > chip - > max_uA )
max_uA = chip - > max_uA ;
if ( min_uA > chip - > max_uA | | max_uA < chip - > min_uA )
2010-06-04 07:46:04 +04:00
return - EINVAL ;
2012-03-02 12:20:54 +04:00
selector = DIV_ROUND_UP ( ( min_uA - chip - > min_uA ) * chip - > current_level ,
range_uA ) ;
2010-06-04 07:46:04 +04:00
if ( ad5398_calc_current ( chip , selector ) > max_uA )
return - EINVAL ;
2012-03-27 06:08:25 +04:00
dev_dbg ( & client - > dev , " changing current %duA \n " ,
ad5398_calc_current ( chip , selector ) ) ;
2010-06-04 07:46:04 +04:00
/* read chip enable bit */
ret = ad5398_read_reg ( client , & data ) ;
if ( ret < 0 )
return ret ;
/* prepare register data */
selector = ( selector < < chip - > current_offset ) & chip - > current_mask ;
data = ( unsigned short ) selector | ( data & AD5398_CURRENT_EN_MASK ) ;
/* write the new current value back as well as enable bit */
ret = ad5398_write_reg ( client , data ) ;
return ret ;
}
static int ad5398_is_enabled ( struct regulator_dev * rdev )
{
struct ad5398_chip_info * chip = rdev_get_drvdata ( rdev ) ;
struct i2c_client * client = chip - > client ;
unsigned short data ;
int ret ;
ret = ad5398_read_reg ( client , & data ) ;
if ( ret < 0 )
return ret ;
if ( data & AD5398_CURRENT_EN_MASK )
return 1 ;
else
return 0 ;
}
static int ad5398_enable ( struct regulator_dev * rdev )
{
struct ad5398_chip_info * chip = rdev_get_drvdata ( rdev ) ;
struct i2c_client * client = chip - > client ;
unsigned short data ;
int ret ;
ret = ad5398_read_reg ( client , & data ) ;
if ( ret < 0 )
return ret ;
if ( data & AD5398_CURRENT_EN_MASK )
return 0 ;
data | = AD5398_CURRENT_EN_MASK ;
ret = ad5398_write_reg ( client , data ) ;
return ret ;
}
static int ad5398_disable ( struct regulator_dev * rdev )
{
struct ad5398_chip_info * chip = rdev_get_drvdata ( rdev ) ;
struct i2c_client * client = chip - > client ;
unsigned short data ;
int ret ;
ret = ad5398_read_reg ( client , & data ) ;
if ( ret < 0 )
return ret ;
if ( ! ( data & AD5398_CURRENT_EN_MASK ) )
return 0 ;
data & = ~ AD5398_CURRENT_EN_MASK ;
ret = ad5398_write_reg ( client , data ) ;
return ret ;
}
static struct regulator_ops ad5398_ops = {
. get_current_limit = ad5398_get_current_limit ,
. set_current_limit = ad5398_set_current_limit ,
. enable = ad5398_enable ,
. disable = ad5398_disable ,
. is_enabled = ad5398_is_enabled ,
} ;
2012-04-05 07:56:56 +04:00
static const struct regulator_desc ad5398_reg = {
2010-06-04 07:46:04 +04:00
. name = " isink " ,
. id = 0 ,
. ops = & ad5398_ops ,
. type = REGULATOR_CURRENT ,
. owner = THIS_MODULE ,
} ;
struct ad5398_current_data_format {
int current_bits ;
int current_offset ;
int min_uA ;
int max_uA ;
} ;
static const struct ad5398_current_data_format df_10_4_120 = { 10 , 4 , 0 , 120000 } ;
static const struct i2c_device_id ad5398_id [ ] = {
{ " ad5398 " , ( kernel_ulong_t ) & df_10_4_120 } ,
{ " ad5821 " , ( kernel_ulong_t ) & df_10_4_120 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , ad5398_id ) ;
2012-11-19 22:22:22 +04:00
static int ad5398_probe ( struct i2c_client * client ,
2010-06-04 07:46:04 +04:00
const struct i2c_device_id * id )
{
2013-07-30 12:20:47 +04:00
struct regulator_init_data * init_data = dev_get_platdata ( & client - > dev ) ;
2012-04-04 03:50:22 +04:00
struct regulator_config config = { } ;
2010-06-04 07:46:04 +04:00
struct ad5398_chip_info * chip ;
const struct ad5398_current_data_format * df =
( struct ad5398_current_data_format * ) id - > driver_data ;
if ( ! init_data )
return - EINVAL ;
2012-03-27 06:09:42 +04:00
chip = devm_kzalloc ( & client - > dev , sizeof ( * chip ) , GFP_KERNEL ) ;
2010-06-04 07:46:04 +04:00
if ( ! chip )
return - ENOMEM ;
2012-04-04 03:50:22 +04:00
config . dev = & client - > dev ;
config . init_data = init_data ;
config . driver_data = chip ;
2010-06-04 07:46:04 +04:00
chip - > client = client ;
chip - > min_uA = df - > min_uA ;
chip - > max_uA = df - > max_uA ;
chip - > current_level = 1 < < df - > current_bits ;
chip - > current_offset = df - > current_offset ;
chip - > current_mask = ( chip - > current_level - 1 ) < < chip - > current_offset ;
2013-09-03 10:20:25 +04:00
chip - > rdev = devm_regulator_register ( & client - > dev , & ad5398_reg ,
& config ) ;
2010-09-01 06:29:18 +04:00
if ( IS_ERR ( chip - > rdev ) ) {
2010-06-04 07:46:04 +04:00
dev_err ( & client - > dev , " failed to register %s %s \n " ,
id - > name , ad5398_reg . name ) ;
2013-09-03 10:20:25 +04:00
return PTR_ERR ( chip - > rdev ) ;
2010-06-04 07:46:04 +04:00
}
i2c_set_clientdata ( client , chip ) ;
dev_dbg ( & client - > dev , " %s regulator driver is registered. \n " , id - > name ) ;
return 0 ;
}
static struct i2c_driver ad5398_driver = {
. probe = ad5398_probe ,
. driver = {
. name = " ad5398 " ,
} ,
. id_table = ad5398_id ,
} ;
static int __init ad5398_init ( void )
{
return i2c_add_driver ( & ad5398_driver ) ;
}
2010-06-10 12:50:20 +04:00
subsys_initcall ( ad5398_init ) ;
2010-06-04 07:46:04 +04:00
static void __exit ad5398_exit ( void )
{
i2c_del_driver ( & ad5398_driver ) ;
}
module_exit ( ad5398_exit ) ;
MODULE_DESCRIPTION ( " AD5398 and AD5821 current regulator driver " ) ;
MODULE_AUTHOR ( " Sonic Zhang " ) ;
MODULE_LICENSE ( " GPL " ) ;