2014-02-06 09:50:13 +04:00
/*
* tps65218 - regulator . c
*
* Regulator driver for TPS65218 PMIC
*
* Copyright ( C ) 2014 Texas Instruments Incorporated - http : //www.ti.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 .
*
* This program is distributed " as is " WITHOUT ANY WARRANTY of any
* kind , whether expressed or implied ; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License version 2 for more details .
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/device.h>
# include <linux/init.h>
# include <linux/err.h>
# include <linux/platform_device.h>
# include <linux/of_device.h>
2016-09-19 10:39:02 +03:00
# include <linux/regmap.h>
2014-02-06 09:50:13 +04:00
# include <linux/regulator/of_regulator.h>
# include <linux/regulator/driver.h>
# include <linux/regulator/machine.h>
# include <linux/mfd/tps65218.h>
2015-11-25 14:59:04 +03:00
enum tps65218_regulators { DCDC1 , DCDC2 , DCDC3 , DCDC4 ,
DCDC5 , DCDC6 , LDO1 , LS3 } ;
2014-02-06 09:50:13 +04:00
2016-09-19 10:39:06 +03:00
# define TPS65218_REGULATOR(_name, _of, _id, _type, _ops, _n, _vr, _vm, _er, \
_em , _cr , _cm , _lr , _nlr , _delay , _fuv , _sr , _sm ) \
2014-02-06 09:50:13 +04:00
{ \
. name = _name , \
2016-09-19 10:39:06 +03:00
. of_match = _of , \
2014-02-06 09:50:13 +04:00
. id = _id , \
. ops = & _ops , \
. n_voltages = _n , \
2015-11-25 14:59:04 +03:00
. type = _type , \
2014-02-06 09:50:13 +04:00
. owner = THIS_MODULE , \
. vsel_reg = _vr , \
. vsel_mask = _vm , \
2015-11-25 14:59:04 +03:00
. csel_reg = _cr , \
. csel_mask = _cm , \
2014-02-06 09:50:13 +04:00
. enable_reg = _er , \
. enable_mask = _em , \
2014-07-08 23:09:13 +04:00
. volt_table = NULL , \
2014-02-06 09:50:13 +04:00
. linear_ranges = _lr , \
. n_linear_ranges = _nlr , \
2014-05-22 05:26:47 +04:00
. ramp_delay = _delay , \
2016-06-24 11:28:08 +03:00
. fixed_uV = _fuv , \
. bypass_reg = _sr , \
. bypass_mask = _sm , \
2014-02-06 09:50:13 +04:00
} \
static const struct regulator_linear_range dcdc1_dcdc2_ranges [ ] = {
REGULATOR_LINEAR_RANGE ( 850000 , 0x0 , 0x32 , 10000 ) ,
REGULATOR_LINEAR_RANGE ( 1375000 , 0x33 , 0x3f , 25000 ) ,
} ;
static const struct regulator_linear_range ldo1_dcdc3_ranges [ ] = {
REGULATOR_LINEAR_RANGE ( 900000 , 0x0 , 0x1a , 25000 ) ,
REGULATOR_LINEAR_RANGE ( 1600000 , 0x1b , 0x3f , 50000 ) ,
} ;
static const struct regulator_linear_range dcdc4_ranges [ ] = {
REGULATOR_LINEAR_RANGE ( 1175000 , 0x0 , 0xf , 25000 ) ,
2014-07-08 23:09:12 +04:00
REGULATOR_LINEAR_RANGE ( 1600000 , 0x10 , 0x34 , 50000 ) ,
2014-02-06 09:50:13 +04:00
} ;
static int tps65218_pmic_set_voltage_sel ( struct regulator_dev * dev ,
unsigned selector )
{
int ret ;
struct tps65218 * tps = rdev_get_drvdata ( dev ) ;
unsigned int rid = rdev_get_id ( dev ) ;
/* Set the voltage based on vsel value and write protect level is 2 */
ret = tps65218_set_bits ( tps , dev - > desc - > vsel_reg , dev - > desc - > vsel_mask ,
selector , TPS65218_PROTECT_L1 ) ;
/* Set GO bit for DCDC1/2 to initiate voltage transistion */
switch ( rid ) {
case TPS65218_DCDC_1 :
case TPS65218_DCDC_2 :
ret = tps65218_set_bits ( tps , TPS65218_REG_CONTRL_SLEW_RATE ,
TPS65218_SLEW_RATE_GO ,
TPS65218_SLEW_RATE_GO ,
TPS65218_PROTECT_L1 ) ;
break ;
}
return ret ;
}
static int tps65218_pmic_enable ( struct regulator_dev * dev )
{
struct tps65218 * tps = rdev_get_drvdata ( dev ) ;
2014-06-24 12:29:16 +04:00
int rid = rdev_get_id ( dev ) ;
2014-02-06 09:50:13 +04:00
if ( rid < TPS65218_DCDC_1 | | rid > TPS65218_LDO_1 )
return - EINVAL ;
/* Enable the regulator and password protection is level 1 */
return tps65218_set_bits ( tps , dev - > desc - > enable_reg ,
dev - > desc - > enable_mask , dev - > desc - > enable_mask ,
TPS65218_PROTECT_L1 ) ;
}
static int tps65218_pmic_disable ( struct regulator_dev * dev )
{
struct tps65218 * tps = rdev_get_drvdata ( dev ) ;
2014-06-24 12:29:16 +04:00
int rid = rdev_get_id ( dev ) ;
2014-02-06 09:50:13 +04:00
if ( rid < TPS65218_DCDC_1 | | rid > TPS65218_LDO_1 )
return - EINVAL ;
/* Disable the regulator and password protection is level 1 */
return tps65218_clear_bits ( tps , dev - > desc - > enable_reg ,
dev - > desc - > enable_mask , TPS65218_PROTECT_L1 ) ;
}
2016-06-24 11:28:08 +03:00
static int tps65218_pmic_set_suspend_enable ( struct regulator_dev * dev )
{
struct tps65218 * tps = rdev_get_drvdata ( dev ) ;
unsigned int rid = rdev_get_id ( dev ) ;
if ( rid < TPS65218_DCDC_1 | | rid > TPS65218_LDO_1 )
return - EINVAL ;
return tps65218_clear_bits ( tps , dev - > desc - > bypass_reg ,
dev - > desc - > bypass_mask ,
TPS65218_PROTECT_L1 ) ;
}
static int tps65218_pmic_set_suspend_disable ( struct regulator_dev * dev )
{
struct tps65218 * tps = rdev_get_drvdata ( dev ) ;
unsigned int rid = rdev_get_id ( dev ) ;
if ( rid < TPS65218_DCDC_1 | | rid > TPS65218_LDO_1 )
return - EINVAL ;
2016-08-10 15:23:55 +03:00
/*
* Certain revisions of TPS65218 will need to have DCDC3 regulator
* enabled always , otherwise an immediate system reboot will occur
* during poweroff .
*/
if ( rid = = TPS65218_DCDC_3 & & tps - > rev = = TPS65218_REV_2_1 )
return 0 ;
2016-09-19 10:39:06 +03:00
if ( ! tps - > strobes [ rid ] ) {
2016-06-24 11:28:09 +03:00
if ( rid = = TPS65218_DCDC_3 )
tps - > info [ rid ] - > strobe = 3 ;
else
return - EINVAL ;
}
2016-06-24 11:28:08 +03:00
return tps65218_set_bits ( tps , dev - > desc - > bypass_reg ,
dev - > desc - > bypass_mask ,
2016-09-19 10:39:06 +03:00
tps - > strobes [ rid ] , TPS65218_PROTECT_L1 ) ;
2016-06-24 11:28:08 +03:00
}
2014-02-06 09:50:13 +04:00
/* Operations permitted on DCDC1, DCDC2 */
static struct regulator_ops tps65218_dcdc12_ops = {
. is_enabled = regulator_is_enabled_regmap ,
. enable = tps65218_pmic_enable ,
. disable = tps65218_pmic_disable ,
. get_voltage_sel = regulator_get_voltage_sel_regmap ,
. set_voltage_sel = tps65218_pmic_set_voltage_sel ,
. list_voltage = regulator_list_voltage_linear_range ,
. map_voltage = regulator_map_voltage_linear_range ,
2014-05-22 05:26:47 +04:00
. set_voltage_time_sel = regulator_set_voltage_time_sel ,
2016-06-24 11:28:08 +03:00
. set_suspend_enable = tps65218_pmic_set_suspend_enable ,
. set_suspend_disable = tps65218_pmic_set_suspend_disable ,
2014-02-06 09:50:13 +04:00
} ;
/* Operations permitted on DCDC3, DCDC4 and LDO1 */
static struct regulator_ops tps65218_ldo1_dcdc34_ops = {
. is_enabled = regulator_is_enabled_regmap ,
. enable = tps65218_pmic_enable ,
. disable = tps65218_pmic_disable ,
. get_voltage_sel = regulator_get_voltage_sel_regmap ,
. set_voltage_sel = tps65218_pmic_set_voltage_sel ,
. list_voltage = regulator_list_voltage_linear_range ,
. map_voltage = regulator_map_voltage_linear_range ,
2016-06-24 11:28:08 +03:00
. set_suspend_enable = tps65218_pmic_set_suspend_enable ,
. set_suspend_disable = tps65218_pmic_set_suspend_disable ,
2014-02-06 09:50:13 +04:00
} ;
2015-11-25 14:59:04 +03:00
static const int ls3_currents [ ] = { 100 , 200 , 500 , 1000 } ;
static int tps65218_pmic_set_input_current_lim ( struct regulator_dev * dev ,
int lim_uA )
{
unsigned int index = 0 ;
unsigned int num_currents = ARRAY_SIZE ( ls3_currents ) ;
struct tps65218 * tps = rdev_get_drvdata ( dev ) ;
while ( index < num_currents & & ls3_currents [ index ] ! = lim_uA )
index + + ;
if ( index = = num_currents )
return - EINVAL ;
return tps65218_set_bits ( tps , dev - > desc - > csel_reg , dev - > desc - > csel_mask ,
index < < 2 , TPS65218_PROTECT_L1 ) ;
}
static int tps65218_pmic_set_current_limit ( struct regulator_dev * dev ,
int min_uA , int max_uA )
{
int index = 0 ;
unsigned int num_currents = ARRAY_SIZE ( ls3_currents ) ;
struct tps65218 * tps = rdev_get_drvdata ( dev ) ;
while ( index < num_currents & & ls3_currents [ index ] < max_uA )
index + + ;
index - - ;
if ( index < 0 | | ls3_currents [ index ] < min_uA )
return - EINVAL ;
return tps65218_set_bits ( tps , dev - > desc - > csel_reg , dev - > desc - > csel_mask ,
index < < 2 , TPS65218_PROTECT_L1 ) ;
}
static int tps65218_pmic_get_current_limit ( struct regulator_dev * dev )
{
int retval ;
unsigned int index ;
struct tps65218 * tps = rdev_get_drvdata ( dev ) ;
2016-09-19 10:39:02 +03:00
retval = regmap_read ( tps - > regmap , dev - > desc - > csel_reg , & index ) ;
2015-11-25 14:59:04 +03:00
if ( retval < 0 )
return retval ;
index = ( index & dev - > desc - > csel_mask ) > > 2 ;
return ls3_currents [ index ] ;
}
static struct regulator_ops tps65218_ls3_ops = {
. is_enabled = regulator_is_enabled_regmap ,
. enable = tps65218_pmic_enable ,
. disable = tps65218_pmic_disable ,
. set_input_current_limit = tps65218_pmic_set_input_current_lim ,
. set_current_limit = tps65218_pmic_set_current_limit ,
. get_current_limit = tps65218_pmic_get_current_limit ,
} ;
2014-02-06 09:50:13 +04:00
/* Operations permitted on DCDC5, DCDC6 */
static struct regulator_ops tps65218_dcdc56_pmic_ops = {
. is_enabled = regulator_is_enabled_regmap ,
. enable = tps65218_pmic_enable ,
. disable = tps65218_pmic_disable ,
2016-06-24 11:28:08 +03:00
. set_suspend_enable = tps65218_pmic_set_suspend_enable ,
. set_suspend_disable = tps65218_pmic_set_suspend_disable ,
2014-02-06 09:50:13 +04:00
} ;
static const struct regulator_desc regulators [ ] = {
2016-09-19 10:39:06 +03:00
TPS65218_REGULATOR ( " DCDC1 " , " regulator-dcdc1 " , TPS65218_DCDC_1 ,
REGULATOR_VOLTAGE , tps65218_dcdc12_ops , 64 ,
TPS65218_REG_CONTROL_DCDC1 ,
2015-11-25 14:59:04 +03:00
TPS65218_CONTROL_DCDC1_MASK , TPS65218_REG_ENABLE1 ,
TPS65218_ENABLE1_DC1_EN , 0 , 0 , dcdc1_dcdc2_ranges ,
2016-06-24 11:28:08 +03:00
2 , 4000 , 0 , TPS65218_REG_SEQ3 ,
TPS65218_SEQ3_DC1_SEQ_MASK ) ,
2016-09-19 10:39:06 +03:00
TPS65218_REGULATOR ( " DCDC2 " , " regulator-dcdc2 " , TPS65218_DCDC_2 ,
REGULATOR_VOLTAGE , tps65218_dcdc12_ops , 64 ,
TPS65218_REG_CONTROL_DCDC2 ,
2015-11-25 14:59:04 +03:00
TPS65218_CONTROL_DCDC2_MASK , TPS65218_REG_ENABLE1 ,
TPS65218_ENABLE1_DC2_EN , 0 , 0 , dcdc1_dcdc2_ranges ,
2016-06-24 11:28:08 +03:00
2 , 4000 , 0 , TPS65218_REG_SEQ3 ,
TPS65218_SEQ3_DC2_SEQ_MASK ) ,
2016-09-19 10:39:06 +03:00
TPS65218_REGULATOR ( " DCDC3 " , " regulator-dcdc3 " , TPS65218_DCDC_3 ,
REGULATOR_VOLTAGE , tps65218_ldo1_dcdc34_ops , 64 ,
2015-11-25 14:59:04 +03:00
TPS65218_REG_CONTROL_DCDC3 ,
2014-02-06 09:50:13 +04:00
TPS65218_CONTROL_DCDC3_MASK , TPS65218_REG_ENABLE1 ,
2015-11-25 14:59:04 +03:00
TPS65218_ENABLE1_DC3_EN , 0 , 0 , ldo1_dcdc3_ranges , 2 ,
2016-06-24 11:28:08 +03:00
0 , 0 , TPS65218_REG_SEQ4 , TPS65218_SEQ4_DC3_SEQ_MASK ) ,
2016-09-19 10:39:06 +03:00
TPS65218_REGULATOR ( " DCDC4 " , " regulator-dcdc4 " , TPS65218_DCDC_4 ,
REGULATOR_VOLTAGE , tps65218_ldo1_dcdc34_ops , 53 ,
2015-11-25 14:59:04 +03:00
TPS65218_REG_CONTROL_DCDC4 ,
TPS65218_CONTROL_DCDC4_MASK , TPS65218_REG_ENABLE1 ,
TPS65218_ENABLE1_DC4_EN , 0 , 0 , dcdc4_ranges , 2 ,
2016-06-24 11:28:08 +03:00
0 , 0 , TPS65218_REG_SEQ4 , TPS65218_SEQ4_DC4_SEQ_MASK ) ,
2016-09-19 10:39:06 +03:00
TPS65218_REGULATOR ( " DCDC5 " , " regulator-dcdc5 " , TPS65218_DCDC_5 ,
REGULATOR_VOLTAGE , tps65218_dcdc56_pmic_ops , 1 , - 1 ,
- 1 , TPS65218_REG_ENABLE1 , TPS65218_ENABLE1_DC5_EN , 0 ,
0 , NULL , 0 , 0 , 1000000 , TPS65218_REG_SEQ5 ,
2016-06-24 11:28:08 +03:00
TPS65218_SEQ5_DC5_SEQ_MASK ) ,
2016-09-19 10:39:06 +03:00
TPS65218_REGULATOR ( " DCDC6 " , " regulator-dcdc6 " , TPS65218_DCDC_6 ,
REGULATOR_VOLTAGE , tps65218_dcdc56_pmic_ops , 1 , - 1 ,
- 1 , TPS65218_REG_ENABLE1 , TPS65218_ENABLE1_DC6_EN , 0 ,
0 , NULL , 0 , 0 , 1800000 , TPS65218_REG_SEQ5 ,
2016-06-24 11:28:08 +03:00
TPS65218_SEQ5_DC6_SEQ_MASK ) ,
2016-09-19 10:39:06 +03:00
TPS65218_REGULATOR ( " LDO1 " , " regulator-ldo1 " , TPS65218_LDO_1 ,
REGULATOR_VOLTAGE , tps65218_ldo1_dcdc34_ops , 64 ,
2014-06-18 19:17:48 +04:00
TPS65218_REG_CONTROL_LDO1 ,
2014-02-06 09:50:13 +04:00
TPS65218_CONTROL_LDO1_MASK , TPS65218_REG_ENABLE2 ,
2015-11-25 14:59:04 +03:00
TPS65218_ENABLE2_LDO1_EN , 0 , 0 , ldo1_dcdc3_ranges ,
2016-06-24 11:28:08 +03:00
2 , 0 , 0 , TPS65218_REG_SEQ6 ,
TPS65218_SEQ6_LDO1_SEQ_MASK ) ,
2016-09-19 10:39:06 +03:00
TPS65218_REGULATOR ( " LS3 " , " regulator-ls3 " , TPS65218_LS_3 ,
REGULATOR_CURRENT , tps65218_ls3_ops , 0 , 0 , 0 ,
TPS65218_REG_ENABLE2 , TPS65218_ENABLE2_LS3_EN ,
TPS65218_REG_CONFIG2 , TPS65218_CONFIG2_LS3ILIM_MASK ,
NULL , 0 , 0 , 0 , 0 , 0 ) ,
2014-02-06 09:50:13 +04:00
} ;
static int tps65218_regulator_probe ( struct platform_device * pdev )
{
struct tps65218 * tps = dev_get_drvdata ( pdev - > dev . parent ) ;
struct regulator_dev * rdev ;
struct regulator_config config = { } ;
2016-09-19 10:39:06 +03:00
int i , ret ;
2016-06-24 11:28:08 +03:00
unsigned int val ;
2014-02-06 09:50:13 +04:00
config . dev = & pdev - > dev ;
2016-09-19 10:39:06 +03:00
config . dev - > of_node = tps - > dev - > of_node ;
2014-02-06 09:50:13 +04:00
config . driver_data = tps ;
config . regmap = tps - > regmap ;
2016-09-19 10:39:06 +03:00
/* Allocate memory for strobes */
tps - > strobes = devm_kzalloc ( & pdev - > dev , sizeof ( u8 ) *
TPS65218_NUM_REGULATOR , GFP_KERNEL ) ;
2014-02-06 09:50:13 +04:00
2016-09-19 10:39:06 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( regulators ) ; i + + ) {
rdev = devm_regulator_register ( & pdev - > dev , & regulators [ i ] ,
& config ) ;
if ( IS_ERR ( rdev ) ) {
dev_err ( tps - > dev , " failed to register %s regulator \n " ,
pdev - > name ) ;
return PTR_ERR ( rdev ) ;
}
2016-06-24 11:28:08 +03:00
2016-09-19 10:39:06 +03:00
ret = regmap_read ( tps - > regmap , regulators [ i ] . bypass_reg , & val ) ;
if ( ret )
return ret ;
tps - > strobes [ i ] = val & regulators [ i ] . bypass_mask ;
}
2016-06-24 11:28:08 +03:00
2014-02-06 09:50:13 +04:00
return 0 ;
}
2016-09-19 10:39:06 +03:00
static const struct platform_device_id tps65218_regulator_id_table [ ] = {
{ " tps65218-regulator " , } ,
{ /* sentinel */ }
} ;
MODULE_DEVICE_TABLE ( platform , tps65218_regulator_id_table ) ;
2014-02-06 09:50:13 +04:00
static struct platform_driver tps65218_regulator_driver = {
. driver = {
. name = " tps65218-pmic " ,
} ,
. probe = tps65218_regulator_probe ,
2016-09-19 10:39:06 +03:00
. id_table = tps65218_regulator_id_table ,
2014-02-06 09:50:13 +04:00
} ;
module_platform_driver ( tps65218_regulator_driver ) ;
MODULE_AUTHOR ( " J Keerthy <j-keerthy@ti.com> " ) ;
MODULE_DESCRIPTION ( " TPS65218 voltage regulator driver " ) ;
MODULE_ALIAS ( " platform:tps65218-pmic " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;