2012-09-08 14:52:18 +04:00
/*
* FAN53555 Fairchild Digitally Programmable TinyBuck Regulator Driver .
*
* Supported Part Numbers :
* FAN53555UC00X / 01 X / 03 X / 04 X / 05 X
*
* Copyright ( c ) 2012 Marvell Technology Ltd .
* Yunfan Zhang < yfzhang @ marvell . com >
*
* This package 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 .
*
*/
# include <linux/module.h>
# include <linux/param.h>
# include <linux/err.h>
# include <linux/platform_device.h>
# include <linux/regulator/driver.h>
# include <linux/regulator/machine.h>
# include <linux/i2c.h>
# include <linux/slab.h>
# include <linux/regmap.h>
# include <linux/regulator/fan53555.h>
/* Voltage setting */
# define FAN53555_VSEL0 0x00
# define FAN53555_VSEL1 0x01
/* Control register */
# define FAN53555_CONTROL 0x02
/* IC Type */
# define FAN53555_ID1 0x03
/* IC mask version */
# define FAN53555_ID2 0x04
/* Monitor register */
# define FAN53555_MONITOR 0x05
/* VSEL bit definitions */
# define VSEL_BUCK_EN (1 << 7)
# define VSEL_MODE (1 << 6)
# define VSEL_NSEL_MASK 0x3F
/* Chip ID and Verison */
# define DIE_ID 0x0F /* ID1 */
# define DIE_REV 0x0F /* ID2 */
/* Control bit definitions */
# define CTL_OUTPUT_DISCHG (1 << 7)
# define CTL_SLEW_MASK (0x7 << 4)
# define CTL_SLEW_SHIFT 4
# define CTL_RESET (1 << 2)
# define FAN53555_NVOLTAGES 64 /* Numbers of voltages */
/* IC Type */
enum {
FAN53555_CHIP_ID_00 = 0 ,
FAN53555_CHIP_ID_01 ,
FAN53555_CHIP_ID_02 ,
FAN53555_CHIP_ID_03 ,
FAN53555_CHIP_ID_04 ,
FAN53555_CHIP_ID_05 ,
} ;
struct fan53555_device_info {
struct regmap * regmap ;
struct device * dev ;
struct regulator_desc desc ;
struct regulator_dev * rdev ;
struct regulator_init_data * regulator ;
/* IC Type and Rev */
int chip_id ;
int chip_rev ;
/* Voltage setting register */
unsigned int vol_reg ;
unsigned int sleep_reg ;
/* Voltage range and step(linear) */
unsigned int vsel_min ;
unsigned int vsel_step ;
/* Voltage slew rate limiting */
unsigned int slew_rate ;
/* Sleep voltage cache */
unsigned int sleep_vol_cache ;
} ;
static int fan53555_set_suspend_voltage ( struct regulator_dev * rdev , int uV )
{
struct fan53555_device_info * di = rdev_get_drvdata ( rdev ) ;
int ret ;
if ( di - > sleep_vol_cache = = uV )
return 0 ;
ret = regulator_map_voltage_linear ( rdev , uV , uV ) ;
if ( ret < 0 )
return - EINVAL ;
ret = regmap_update_bits ( di - > regmap , di - > sleep_reg ,
VSEL_NSEL_MASK , ret ) ;
if ( ret < 0 )
return - EINVAL ;
/* Cache the sleep voltage setting.
* Might not be the real voltage which is rounded */
di - > sleep_vol_cache = uV ;
return 0 ;
}
static int fan53555_set_mode ( struct regulator_dev * rdev , unsigned int mode )
{
struct fan53555_device_info * di = rdev_get_drvdata ( rdev ) ;
switch ( mode ) {
case REGULATOR_MODE_FAST :
regmap_update_bits ( di - > regmap , di - > vol_reg ,
VSEL_MODE , VSEL_MODE ) ;
break ;
case REGULATOR_MODE_NORMAL :
regmap_update_bits ( di - > regmap , di - > vol_reg , VSEL_MODE , 0 ) ;
break ;
default :
return - EINVAL ;
}
return 0 ;
}
static unsigned int fan53555_get_mode ( struct regulator_dev * rdev )
{
struct fan53555_device_info * di = rdev_get_drvdata ( rdev ) ;
unsigned int val ;
int ret = 0 ;
ret = regmap_read ( di - > regmap , di - > vol_reg , & val ) ;
if ( ret < 0 )
return ret ;
if ( val & VSEL_MODE )
return REGULATOR_MODE_FAST ;
else
return REGULATOR_MODE_NORMAL ;
}
static struct regulator_ops fan53555_regulator_ops = {
. set_voltage_sel = regulator_set_voltage_sel_regmap ,
. get_voltage_sel = regulator_get_voltage_sel_regmap ,
. map_voltage = regulator_map_voltage_linear ,
. list_voltage = regulator_list_voltage_linear ,
. set_suspend_voltage = fan53555_set_suspend_voltage ,
. enable = regulator_enable_regmap ,
. disable = regulator_disable_regmap ,
. is_enabled = regulator_is_enabled_regmap ,
. set_mode = fan53555_set_mode ,
. get_mode = fan53555_get_mode ,
} ;
/* For 00,01,03,05 options:
* VOUT = 0.60 V + NSELx * 10 mV , from 0.60 to 1.23 V .
* For 04 option :
* VOUT = 0.603 V + NSELx * 12.826 mV , from 0.603 to 1.411 V .
* */
static int fan53555_device_setup ( struct fan53555_device_info * di ,
struct fan53555_platform_data * pdata )
{
unsigned int reg , data , mask ;
/* Setup voltage control register */
switch ( pdata - > sleep_vsel_id ) {
case FAN53555_VSEL_ID_0 :
di - > sleep_reg = FAN53555_VSEL0 ;
di - > vol_reg = FAN53555_VSEL1 ;
break ;
case FAN53555_VSEL_ID_1 :
di - > sleep_reg = FAN53555_VSEL1 ;
di - > vol_reg = FAN53555_VSEL0 ;
break ;
default :
dev_err ( di - > dev , " Invalid VSEL ID! \n " ) ;
return - EINVAL ;
}
/* Init voltage range and step */
switch ( di - > chip_id ) {
case FAN53555_CHIP_ID_00 :
case FAN53555_CHIP_ID_01 :
case FAN53555_CHIP_ID_03 :
case FAN53555_CHIP_ID_05 :
di - > vsel_min = 600000 ;
di - > vsel_step = 10000 ;
break ;
case FAN53555_CHIP_ID_04 :
di - > vsel_min = 603000 ;
di - > vsel_step = 12826 ;
break ;
default :
dev_err ( di - > dev ,
" Chip ID[%d] \n not supported! \n " , di - > chip_id ) ;
return - EINVAL ;
}
/* Init slew rate */
if ( pdata - > slew_rate & 0x7 )
di - > slew_rate = pdata - > slew_rate ;
else
di - > slew_rate = FAN53555_SLEW_RATE_64MV ;
reg = FAN53555_CONTROL ;
data = di - > slew_rate < < CTL_SLEW_SHIFT ;
mask = CTL_SLEW_MASK ;
return regmap_update_bits ( di - > regmap , reg , mask , data ) ;
}
static int fan53555_regulator_register ( struct fan53555_device_info * di ,
struct regulator_config * config )
{
struct regulator_desc * rdesc = & di - > desc ;
rdesc - > name = " fan53555-reg " ;
rdesc - > ops = & fan53555_regulator_ops ;
rdesc - > type = REGULATOR_VOLTAGE ;
rdesc - > n_voltages = FAN53555_NVOLTAGES ;
rdesc - > enable_reg = di - > vol_reg ;
rdesc - > enable_mask = VSEL_BUCK_EN ;
rdesc - > min_uV = di - > vsel_min ;
rdesc - > uV_step = di - > vsel_step ;
rdesc - > vsel_reg = di - > vol_reg ;
rdesc - > vsel_mask = VSEL_NSEL_MASK ;
rdesc - > owner = THIS_MODULE ;
2013-09-03 10:27:56 +04:00
di - > rdev = devm_regulator_register ( di - > dev , & di - > desc , config ) ;
2013-07-15 05:50:32 +04:00
return PTR_ERR_OR_ZERO ( di - > rdev ) ;
2012-09-08 14:52:18 +04:00
}
static struct regmap_config fan53555_regmap_config = {
. reg_bits = 8 ,
. val_bits = 8 ,
} ;
2012-11-19 22:22:22 +04:00
static int fan53555_regulator_probe ( struct i2c_client * client ,
2012-09-08 14:52:18 +04:00
const struct i2c_device_id * id )
{
struct fan53555_device_info * di ;
struct fan53555_platform_data * pdata ;
struct regulator_config config = { } ;
unsigned int val ;
int ret ;
2013-07-30 12:20:47 +04:00
pdata = dev_get_platdata ( & client - > dev ) ;
2012-09-08 14:52:18 +04:00
if ( ! pdata | | ! pdata - > regulator ) {
dev_err ( & client - > dev , " Platform data not found! \n " ) ;
return - ENODEV ;
}
di = devm_kzalloc ( & client - > dev , sizeof ( struct fan53555_device_info ) ,
GFP_KERNEL ) ;
if ( ! di ) {
dev_err ( & client - > dev , " Failed to allocate device info data! \n " ) ;
return - ENOMEM ;
}
di - > regmap = devm_regmap_init_i2c ( client , & fan53555_regmap_config ) ;
if ( IS_ERR ( di - > regmap ) ) {
dev_err ( & client - > dev , " Failed to allocate regmap! \n " ) ;
return PTR_ERR ( di - > regmap ) ;
}
di - > dev = & client - > dev ;
di - > regulator = pdata - > regulator ;
i2c_set_clientdata ( client , di ) ;
/* Get chip ID */
ret = regmap_read ( di - > regmap , FAN53555_ID1 , & val ) ;
if ( ret < 0 ) {
dev_err ( & client - > dev , " Failed to get chip ID! \n " ) ;
return - ENODEV ;
}
di - > chip_id = val & DIE_ID ;
/* Get chip revision */
ret = regmap_read ( di - > regmap , FAN53555_ID2 , & val ) ;
if ( ret < 0 ) {
dev_err ( & client - > dev , " Failed to get chip Rev! \n " ) ;
return - ENODEV ;
}
di - > chip_rev = val & DIE_REV ;
dev_info ( & client - > dev , " FAN53555 Option[%d] Rev[%d] Detected! \n " ,
di - > chip_id , di - > chip_rev ) ;
/* Device init */
ret = fan53555_device_setup ( di , pdata ) ;
if ( ret < 0 ) {
dev_err ( & client - > dev , " Failed to setup device! \n " ) ;
return ret ;
}
/* Register regulator */
config . dev = di - > dev ;
config . init_data = di - > regulator ;
config . regmap = di - > regmap ;
config . driver_data = di ;
ret = fan53555_regulator_register ( di , & config ) ;
if ( ret < 0 )
dev_err ( & client - > dev , " Failed to register regulator! \n " ) ;
return ret ;
}
static const struct i2c_device_id fan53555_id [ ] = {
{ " fan53555 " , - 1 } ,
{ } ,
} ;
static struct i2c_driver fan53555_regulator_driver = {
. driver = {
. name = " fan53555-regulator " ,
} ,
. probe = fan53555_regulator_probe ,
. id_table = fan53555_id ,
} ;
module_i2c_driver ( fan53555_regulator_driver ) ;
MODULE_AUTHOR ( " Yunfan Zhang <yfzhang@marvell.com> " ) ;
MODULE_DESCRIPTION ( " FAN53555 regulator driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;