2014-04-11 13:38:10 +04:00
/*
* AXP20x regulators driver .
*
* Copyright ( C ) 2013 Carlo Caione < carlo @ caione . org >
*
* This file is subject to the terms and conditions of the GNU General
* Public License . See the file " COPYING " in the main directory of this
* archive for more details .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
# include <linux/err.h>
# include <linux/init.h>
# include <linux/module.h>
# include <linux/of.h>
# include <linux/of_device.h>
# include <linux/platform_device.h>
# include <linux/regmap.h>
# include <linux/mfd/axp20x.h>
# include <linux/regulator/driver.h>
# include <linux/regulator/of_regulator.h>
# define AXP20X_IO_ENABLED 0x03
# define AXP20X_IO_DISABLED 0x07
2015-12-22 12:08:06 +03:00
# define AXP22X_IO_ENABLED 0x03
# define AXP22X_IO_DISABLED 0x04
2015-04-10 07:09:04 +03:00
2014-04-11 13:38:10 +04:00
# define AXP20X_WORKMODE_DCDC2_MASK BIT(2)
# define AXP20X_WORKMODE_DCDC3_MASK BIT(1)
2015-04-10 07:09:04 +03:00
# define AXP22X_WORKMODE_DCDCX_MASK(x) BIT(x)
2014-04-11 13:38:10 +04:00
# define AXP20X_FREQ_DCDC_MASK 0x0f
2016-06-03 19:59:44 +03:00
# define AXP22X_MISC_N_VBUSEN_FUNC BIT(4)
2015-04-10 07:09:03 +03:00
# define AXP_DESC_IO(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
_vmask , _ereg , _emask , _enable_val , _disable_val ) \
[ _family # # _ # # _id ] = { \
2016-02-15 13:31:22 +03:00
. name = ( _match ) , \
2014-04-11 13:38:10 +04:00
. supply_name = ( _supply ) , \
2015-01-09 19:23:43 +03:00
. of_match = of_match_ptr ( _match ) , \
. regulators_node = of_match_ptr ( " regulators " ) , \
2014-04-11 13:38:10 +04:00
. type = REGULATOR_VOLTAGE , \
2015-04-10 07:09:03 +03:00
. id = _family # # _ # # _id , \
2014-04-11 13:38:10 +04:00
. n_voltages = ( ( ( _max ) - ( _min ) ) / ( _step ) + 1 ) , \
. owner = THIS_MODULE , \
. min_uV = ( _min ) * 1000 , \
. uV_step = ( _step ) * 1000 , \
. vsel_reg = ( _vreg ) , \
. vsel_mask = ( _vmask ) , \
. enable_reg = ( _ereg ) , \
. enable_mask = ( _emask ) , \
. enable_val = ( _enable_val ) , \
. disable_val = ( _disable_val ) , \
. ops = & axp20x_ops , \
}
2015-04-10 07:09:03 +03:00
# define AXP_DESC(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
_vmask , _ereg , _emask ) \
[ _family # # _ # # _id ] = { \
2016-02-15 13:31:22 +03:00
. name = ( _match ) , \
2014-04-11 13:38:10 +04:00
. supply_name = ( _supply ) , \
2015-01-09 19:23:43 +03:00
. of_match = of_match_ptr ( _match ) , \
. regulators_node = of_match_ptr ( " regulators " ) , \
2014-04-11 13:38:10 +04:00
. type = REGULATOR_VOLTAGE , \
2015-04-10 07:09:03 +03:00
. id = _family # # _ # # _id , \
2014-04-11 13:38:10 +04:00
. n_voltages = ( ( ( _max ) - ( _min ) ) / ( _step ) + 1 ) , \
. owner = THIS_MODULE , \
. min_uV = ( _min ) * 1000 , \
. uV_step = ( _step ) * 1000 , \
. vsel_reg = ( _vreg ) , \
. vsel_mask = ( _vmask ) , \
. enable_reg = ( _ereg ) , \
. enable_mask = ( _emask ) , \
. ops = & axp20x_ops , \
}
2016-02-02 13:27:37 +03:00
# define AXP_DESC_SW(_family, _id, _match, _supply, _ereg, _emask) \
2015-04-10 07:09:04 +03:00
[ _family # # _ # # _id ] = { \
2016-02-15 13:31:22 +03:00
. name = ( _match ) , \
2015-04-10 07:09:04 +03:00
. supply_name = ( _supply ) , \
. of_match = of_match_ptr ( _match ) , \
. regulators_node = of_match_ptr ( " regulators " ) , \
. type = REGULATOR_VOLTAGE , \
. id = _family # # _ # # _id , \
. owner = THIS_MODULE , \
. enable_reg = ( _ereg ) , \
. enable_mask = ( _emask ) , \
. ops = & axp20x_ops_sw , \
}
2015-04-10 07:09:03 +03:00
# define AXP_DESC_FIXED(_family, _id, _match, _supply, _volt) \
[ _family # # _ # # _id ] = { \
2016-02-15 13:31:22 +03:00
. name = ( _match ) , \
2014-04-11 13:38:10 +04:00
. supply_name = ( _supply ) , \
2015-01-09 19:23:43 +03:00
. of_match = of_match_ptr ( _match ) , \
. regulators_node = of_match_ptr ( " regulators " ) , \
2014-04-11 13:38:10 +04:00
. type = REGULATOR_VOLTAGE , \
2015-04-10 07:09:03 +03:00
. id = _family # # _ # # _id , \
2014-04-11 13:38:10 +04:00
. n_voltages = 1 , \
. owner = THIS_MODULE , \
. min_uV = ( _volt ) * 1000 , \
. ops = & axp20x_ops_fixed \
}
2016-02-02 13:27:38 +03:00
# define AXP_DESC_RANGES(_family, _id, _match, _supply, _ranges, _n_voltages, \
_vreg , _vmask , _ereg , _emask ) \
2015-04-10 07:09:03 +03:00
[ _family # # _ # # _id ] = { \
2016-02-15 13:31:22 +03:00
. name = ( _match ) , \
2014-04-11 13:38:10 +04:00
. supply_name = ( _supply ) , \
2015-01-09 19:23:43 +03:00
. of_match = of_match_ptr ( _match ) , \
. regulators_node = of_match_ptr ( " regulators " ) , \
2014-04-11 13:38:10 +04:00
. type = REGULATOR_VOLTAGE , \
2015-04-10 07:09:03 +03:00
. id = _family # # _ # # _id , \
2016-02-02 13:27:38 +03:00
. n_voltages = ( _n_voltages ) , \
2014-04-11 13:38:10 +04:00
. owner = THIS_MODULE , \
. vsel_reg = ( _vreg ) , \
. vsel_mask = ( _vmask ) , \
. enable_reg = ( _ereg ) , \
. enable_mask = ( _emask ) , \
2016-02-02 13:27:38 +03:00
. linear_ranges = ( _ranges ) , \
. n_linear_ranges = ARRAY_SIZE ( _ranges ) , \
. ops = & axp20x_ops_range , \
2014-04-11 13:38:10 +04:00
}
static struct regulator_ops axp20x_ops_fixed = {
. list_voltage = regulator_list_voltage_linear ,
} ;
2016-02-02 13:27:38 +03:00
static struct regulator_ops axp20x_ops_range = {
2014-04-11 13:38:10 +04:00
. set_voltage_sel = regulator_set_voltage_sel_regmap ,
. get_voltage_sel = regulator_get_voltage_sel_regmap ,
2016-02-02 13:27:38 +03:00
. list_voltage = regulator_list_voltage_linear_range ,
2014-04-11 13:38:10 +04:00
. enable = regulator_enable_regmap ,
. disable = regulator_disable_regmap ,
. is_enabled = regulator_is_enabled_regmap ,
} ;
static struct regulator_ops axp20x_ops = {
. set_voltage_sel = regulator_set_voltage_sel_regmap ,
. get_voltage_sel = regulator_get_voltage_sel_regmap ,
. list_voltage = regulator_list_voltage_linear ,
. enable = regulator_enable_regmap ,
. disable = regulator_disable_regmap ,
. is_enabled = regulator_is_enabled_regmap ,
} ;
2015-04-10 07:09:04 +03:00
static struct regulator_ops axp20x_ops_sw = {
. enable = regulator_enable_regmap ,
. disable = regulator_disable_regmap ,
. is_enabled = regulator_is_enabled_regmap ,
} ;
2016-02-02 13:27:38 +03:00
static const struct regulator_linear_range axp20x_ldo4_ranges [ ] = {
REGULATOR_LINEAR_RANGE ( 1250000 , 0x0 , 0x0 , 0 ) ,
REGULATOR_LINEAR_RANGE ( 1300000 , 0x1 , 0x8 , 100000 ) ,
2016-04-26 17:00:51 +03:00
REGULATOR_LINEAR_RANGE ( 2500000 , 0x9 , 0x9 , 0 ) ,
REGULATOR_LINEAR_RANGE ( 2700000 , 0xa , 0xb , 100000 ) ,
REGULATOR_LINEAR_RANGE ( 3000000 , 0xc , 0xf , 100000 ) ,
2016-02-02 13:27:38 +03:00
} ;
2014-04-11 13:38:10 +04:00
static const struct regulator_desc axp20x_regulators [ ] = {
2015-04-10 07:09:03 +03:00
AXP_DESC ( AXP20X , DCDC2 , " dcdc2 " , " vin2 " , 700 , 2275 , 25 ,
AXP20X_DCDC2_V_OUT , 0x3f , AXP20X_PWR_OUT_CTRL , 0x10 ) ,
AXP_DESC ( AXP20X , DCDC3 , " dcdc3 " , " vin3 " , 700 , 3500 , 25 ,
AXP20X_DCDC3_V_OUT , 0x7f , AXP20X_PWR_OUT_CTRL , 0x02 ) ,
AXP_DESC_FIXED ( AXP20X , LDO1 , " ldo1 " , " acin " , 1300 ) ,
AXP_DESC ( AXP20X , LDO2 , " ldo2 " , " ldo24in " , 1800 , 3300 , 100 ,
AXP20X_LDO24_V_OUT , 0xf0 , AXP20X_PWR_OUT_CTRL , 0x04 ) ,
AXP_DESC ( AXP20X , LDO3 , " ldo3 " , " ldo3in " , 700 , 3500 , 25 ,
AXP20X_LDO3_V_OUT , 0x7f , AXP20X_PWR_OUT_CTRL , 0x40 ) ,
2016-02-02 13:27:38 +03:00
AXP_DESC_RANGES ( AXP20X , LDO4 , " ldo4 " , " ldo24in " , axp20x_ldo4_ranges ,
16 , AXP20X_LDO24_V_OUT , 0x0f , AXP20X_PWR_OUT_CTRL ,
0x08 ) ,
2015-04-10 07:09:03 +03:00
AXP_DESC_IO ( AXP20X , LDO5 , " ldo5 " , " ldo5in " , 1800 , 3300 , 100 ,
AXP20X_LDO5_V_OUT , 0xf0 , AXP20X_GPIO0_CTRL , 0x07 ,
AXP20X_IO_ENABLED , AXP20X_IO_DISABLED ) ,
2014-04-11 13:38:10 +04:00
} ;
2015-04-10 07:09:04 +03:00
static const struct regulator_desc axp22x_regulators [ ] = {
AXP_DESC ( AXP22X , DCDC1 , " dcdc1 " , " vin1 " , 1600 , 3400 , 100 ,
AXP22X_DCDC1_V_OUT , 0x1f , AXP22X_PWR_OUT_CTRL1 , BIT ( 1 ) ) ,
AXP_DESC ( AXP22X , DCDC2 , " dcdc2 " , " vin2 " , 600 , 1540 , 20 ,
AXP22X_DCDC2_V_OUT , 0x3f , AXP22X_PWR_OUT_CTRL1 , BIT ( 2 ) ) ,
AXP_DESC ( AXP22X , DCDC3 , " dcdc3 " , " vin3 " , 600 , 1860 , 20 ,
AXP22X_DCDC3_V_OUT , 0x3f , AXP22X_PWR_OUT_CTRL1 , BIT ( 3 ) ) ,
AXP_DESC ( AXP22X , DCDC4 , " dcdc4 " , " vin4 " , 600 , 1540 , 20 ,
2015-09-26 16:21:12 +03:00
AXP22X_DCDC4_V_OUT , 0x3f , AXP22X_PWR_OUT_CTRL1 , BIT ( 4 ) ) ,
2015-04-10 07:09:04 +03:00
AXP_DESC ( AXP22X , DCDC5 , " dcdc5 " , " vin5 " , 1000 , 2550 , 50 ,
2015-09-26 16:21:12 +03:00
AXP22X_DCDC5_V_OUT , 0x1f , AXP22X_PWR_OUT_CTRL1 , BIT ( 5 ) ) ,
2015-04-10 07:09:04 +03:00
/* secondary switchable output of DCDC1 */
2016-02-02 13:27:37 +03:00
AXP_DESC_SW ( AXP22X , DC1SW , " dc1sw " , NULL , AXP22X_PWR_OUT_CTRL2 ,
BIT ( 7 ) ) ,
2015-04-10 07:09:04 +03:00
/* LDO regulator internally chained to DCDC5 */
2015-09-30 09:39:46 +03:00
AXP_DESC ( AXP22X , DC5LDO , " dc5ldo " , NULL , 700 , 1400 , 100 ,
2015-04-10 07:09:04 +03:00
AXP22X_DC5LDO_V_OUT , 0x7 , AXP22X_PWR_OUT_CTRL1 , BIT ( 0 ) ) ,
AXP_DESC ( AXP22X , ALDO1 , " aldo1 " , " aldoin " , 700 , 3300 , 100 ,
AXP22X_ALDO1_V_OUT , 0x1f , AXP22X_PWR_OUT_CTRL1 , BIT ( 6 ) ) ,
AXP_DESC ( AXP22X , ALDO2 , " aldo2 " , " aldoin " , 700 , 3300 , 100 ,
AXP22X_ALDO2_V_OUT , 0x1f , AXP22X_PWR_OUT_CTRL1 , BIT ( 7 ) ) ,
AXP_DESC ( AXP22X , ALDO3 , " aldo3 " , " aldoin " , 700 , 3300 , 100 ,
AXP22X_ALDO3_V_OUT , 0x1f , AXP22X_PWR_OUT_CTRL3 , BIT ( 7 ) ) ,
AXP_DESC ( AXP22X , DLDO1 , " dldo1 " , " dldoin " , 700 , 3300 , 100 ,
AXP22X_DLDO1_V_OUT , 0x1f , AXP22X_PWR_OUT_CTRL2 , BIT ( 3 ) ) ,
AXP_DESC ( AXP22X , DLDO2 , " dldo2 " , " dldoin " , 700 , 3300 , 100 ,
AXP22X_DLDO2_V_OUT , 0x1f , AXP22X_PWR_OUT_CTRL2 , BIT ( 4 ) ) ,
AXP_DESC ( AXP22X , DLDO3 , " dldo3 " , " dldoin " , 700 , 3300 , 100 ,
AXP22X_DLDO3_V_OUT , 0x1f , AXP22X_PWR_OUT_CTRL2 , BIT ( 5 ) ) ,
AXP_DESC ( AXP22X , DLDO4 , " dldo4 " , " dldoin " , 700 , 3300 , 100 ,
AXP22X_DLDO4_V_OUT , 0x1f , AXP22X_PWR_OUT_CTRL2 , BIT ( 6 ) ) ,
AXP_DESC ( AXP22X , ELDO1 , " eldo1 " , " eldoin " , 700 , 3300 , 100 ,
AXP22X_ELDO1_V_OUT , 0x1f , AXP22X_PWR_OUT_CTRL2 , BIT ( 0 ) ) ,
AXP_DESC ( AXP22X , ELDO2 , " eldo2 " , " eldoin " , 700 , 3300 , 100 ,
AXP22X_ELDO2_V_OUT , 0x1f , AXP22X_PWR_OUT_CTRL2 , BIT ( 1 ) ) ,
AXP_DESC ( AXP22X , ELDO3 , " eldo3 " , " eldoin " , 700 , 3300 , 100 ,
AXP22X_ELDO3_V_OUT , 0x1f , AXP22X_PWR_OUT_CTRL2 , BIT ( 2 ) ) ,
2016-04-27 21:38:44 +03:00
/* Note the datasheet only guarantees reliable operation up to
* 3.3 V , this needs to be enforced via dts provided constraints */
AXP_DESC_IO ( AXP22X , LDO_IO0 , " ldo_io0 " , " ips " , 700 , 3800 , 100 ,
2015-04-10 07:09:04 +03:00
AXP22X_LDO_IO0_V_OUT , 0x1f , AXP20X_GPIO0_CTRL , 0x07 ,
AXP22X_IO_ENABLED , AXP22X_IO_DISABLED ) ,
2016-04-27 21:38:44 +03:00
/* Note the datasheet only guarantees reliable operation up to
* 3.3 V , this needs to be enforced via dts provided constraints */
AXP_DESC_IO ( AXP22X , LDO_IO1 , " ldo_io1 " , " ips " , 700 , 3800 , 100 ,
2015-04-10 07:09:04 +03:00
AXP22X_LDO_IO1_V_OUT , 0x1f , AXP20X_GPIO1_CTRL , 0x07 ,
AXP22X_IO_ENABLED , AXP22X_IO_DISABLED ) ,
AXP_DESC_FIXED ( AXP22X , RTC_LDO , " rtc_ldo " , " ips " , 3000 ) ,
} ;
2016-06-03 19:59:44 +03:00
static const struct regulator_desc axp22x_drivevbus_regulator = {
. name = " drivevbus " ,
. supply_name = " drivevbus " ,
. of_match = of_match_ptr ( " drivevbus " ) ,
. regulators_node = of_match_ptr ( " regulators " ) ,
. type = REGULATOR_VOLTAGE ,
. owner = THIS_MODULE ,
. enable_reg = AXP20X_VBUS_IPSOUT_MGMT ,
. enable_mask = BIT ( 2 ) ,
. ops = & axp20x_ops_sw ,
} ;
2016-05-31 19:23:19 +03:00
static const struct regulator_linear_range axp809_dcdc4_ranges [ ] = {
REGULATOR_LINEAR_RANGE ( 600000 , 0x0 , 0x2f , 20000 ) ,
REGULATOR_LINEAR_RANGE ( 1800000 , 0x30 , 0x38 , 100000 ) ,
} ;
static const struct regulator_linear_range axp809_dldo1_ranges [ ] = {
REGULATOR_LINEAR_RANGE ( 700000 , 0x0 , 0x1a , 100000 ) ,
REGULATOR_LINEAR_RANGE ( 3400000 , 0x1b , 0x1f , 200000 ) ,
} ;
static const struct regulator_desc axp809_regulators [ ] = {
AXP_DESC ( AXP809 , DCDC1 , " dcdc1 " , " vin1 " , 1600 , 3400 , 100 ,
AXP22X_DCDC1_V_OUT , 0x1f , AXP22X_PWR_OUT_CTRL1 , BIT ( 1 ) ) ,
AXP_DESC ( AXP809 , DCDC2 , " dcdc2 " , " vin2 " , 600 , 1540 , 20 ,
AXP22X_DCDC2_V_OUT , 0x3f , AXP22X_PWR_OUT_CTRL1 , BIT ( 2 ) ) ,
AXP_DESC ( AXP809 , DCDC3 , " dcdc3 " , " vin3 " , 600 , 1860 , 20 ,
AXP22X_DCDC3_V_OUT , 0x3f , AXP22X_PWR_OUT_CTRL1 , BIT ( 3 ) ) ,
AXP_DESC_RANGES ( AXP809 , DCDC4 , " dcdc4 " , " vin4 " , axp809_dcdc4_ranges ,
57 , AXP22X_DCDC4_V_OUT , 0x3f , AXP22X_PWR_OUT_CTRL1 ,
BIT ( 4 ) ) ,
AXP_DESC ( AXP809 , DCDC5 , " dcdc5 " , " vin5 " , 1000 , 2550 , 50 ,
AXP22X_DCDC5_V_OUT , 0x1f , AXP22X_PWR_OUT_CTRL1 , BIT ( 5 ) ) ,
/* secondary switchable output of DCDC1 */
AXP_DESC_SW ( AXP809 , DC1SW , " dc1sw " , NULL , AXP22X_PWR_OUT_CTRL2 ,
BIT ( 7 ) ) ,
/* LDO regulator internally chained to DCDC5 */
AXP_DESC ( AXP809 , DC5LDO , " dc5ldo " , NULL , 700 , 1400 , 100 ,
AXP22X_DC5LDO_V_OUT , 0x7 , AXP22X_PWR_OUT_CTRL1 , BIT ( 0 ) ) ,
AXP_DESC ( AXP809 , ALDO1 , " aldo1 " , " aldoin " , 700 , 3300 , 100 ,
AXP22X_ALDO1_V_OUT , 0x1f , AXP22X_PWR_OUT_CTRL1 , BIT ( 6 ) ) ,
AXP_DESC ( AXP809 , ALDO2 , " aldo2 " , " aldoin " , 700 , 3300 , 100 ,
AXP22X_ALDO2_V_OUT , 0x1f , AXP22X_PWR_OUT_CTRL1 , BIT ( 7 ) ) ,
AXP_DESC ( AXP809 , ALDO3 , " aldo3 " , " aldoin " , 700 , 3300 , 100 ,
AXP22X_ALDO3_V_OUT , 0x1f , AXP22X_PWR_OUT_CTRL2 , BIT ( 5 ) ) ,
AXP_DESC_RANGES ( AXP809 , DLDO1 , " dldo1 " , " dldoin " , axp809_dldo1_ranges ,
32 , AXP22X_DLDO1_V_OUT , 0x1f , AXP22X_PWR_OUT_CTRL2 ,
BIT ( 3 ) ) ,
AXP_DESC ( AXP809 , DLDO2 , " dldo2 " , " dldoin " , 700 , 3300 , 100 ,
AXP22X_DLDO2_V_OUT , 0x1f , AXP22X_PWR_OUT_CTRL2 , BIT ( 4 ) ) ,
AXP_DESC ( AXP809 , ELDO1 , " eldo1 " , " eldoin " , 700 , 3300 , 100 ,
AXP22X_ELDO1_V_OUT , 0x1f , AXP22X_PWR_OUT_CTRL2 , BIT ( 0 ) ) ,
AXP_DESC ( AXP809 , ELDO2 , " eldo2 " , " eldoin " , 700 , 3300 , 100 ,
AXP22X_ELDO2_V_OUT , 0x1f , AXP22X_PWR_OUT_CTRL2 , BIT ( 1 ) ) ,
AXP_DESC ( AXP809 , ELDO3 , " eldo3 " , " eldoin " , 700 , 3300 , 100 ,
AXP22X_ELDO3_V_OUT , 0x1f , AXP22X_PWR_OUT_CTRL2 , BIT ( 2 ) ) ,
AXP_DESC_IO ( AXP809 , LDO_IO0 , " ldo_io0 " , " ips " , 700 , 3300 , 100 ,
AXP22X_LDO_IO0_V_OUT , 0x1f , AXP20X_GPIO0_CTRL , 0x07 ,
AXP22X_IO_ENABLED , AXP22X_IO_DISABLED ) ,
AXP_DESC_IO ( AXP809 , LDO_IO1 , " ldo_io1 " , " ips " , 700 , 3300 , 100 ,
AXP22X_LDO_IO1_V_OUT , 0x1f , AXP20X_GPIO1_CTRL , 0x07 ,
AXP22X_IO_ENABLED , AXP22X_IO_DISABLED ) ,
AXP_DESC_FIXED ( AXP809 , RTC_LDO , " rtc_ldo " , " ips " , 1800 ) ,
AXP_DESC_SW ( AXP809 , SW , " sw " , " swin " , AXP22X_PWR_OUT_CTRL2 , BIT ( 6 ) ) ,
} ;
2014-04-11 13:38:10 +04:00
static int axp20x_set_dcdc_freq ( struct platform_device * pdev , u32 dcdcfreq )
{
struct axp20x_dev * axp20x = dev_get_drvdata ( pdev - > dev . parent ) ;
2015-04-10 07:09:03 +03:00
u32 min , max , def , step ;
switch ( axp20x - > variant ) {
case AXP202_ID :
case AXP209_ID :
min = 750 ;
max = 1875 ;
def = 1500 ;
step = 75 ;
break ;
2015-04-10 07:09:04 +03:00
case AXP221_ID :
2016-02-12 05:02:45 +03:00
case AXP223_ID :
2016-05-31 19:23:19 +03:00
case AXP809_ID :
2015-04-10 07:09:04 +03:00
min = 1800 ;
max = 4050 ;
def = 3000 ;
step = 150 ;
break ;
2015-04-10 07:09:03 +03:00
default :
dev_err ( & pdev - > dev ,
" Setting DCDC frequency for unsupported AXP variant \n " ) ;
return - EINVAL ;
}
if ( dcdcfreq = = 0 )
dcdcfreq = def ;
2014-04-11 13:38:10 +04:00
2015-04-10 07:09:03 +03:00
if ( dcdcfreq < min ) {
dcdcfreq = min ;
dev_warn ( & pdev - > dev , " DCDC frequency too low. Set to %ukHz \n " ,
min ) ;
2014-04-11 13:38:10 +04:00
}
2015-04-10 07:09:03 +03:00
if ( dcdcfreq > max ) {
dcdcfreq = max ;
dev_warn ( & pdev - > dev , " DCDC frequency too high. Set to %ukHz \n " ,
max ) ;
2014-04-11 13:38:10 +04:00
}
2015-04-10 07:09:03 +03:00
dcdcfreq = ( dcdcfreq - min ) / step ;
2014-04-11 13:38:10 +04:00
return regmap_update_bits ( axp20x - > regmap , AXP20X_DCDC_FREQ ,
AXP20X_FREQ_DCDC_MASK , dcdcfreq ) ;
}
static int axp20x_regulator_parse_dt ( struct platform_device * pdev )
{
struct device_node * np , * regulators ;
int ret ;
2015-04-10 07:09:03 +03:00
u32 dcdcfreq = 0 ;
2014-04-11 13:38:10 +04:00
np = of_node_get ( pdev - > dev . parent - > of_node ) ;
if ( ! np )
return 0 ;
2014-05-19 12:25:30 +04:00
regulators = of_get_child_by_name ( np , " regulators " ) ;
2014-04-11 13:38:10 +04:00
if ( ! regulators ) {
dev_warn ( & pdev - > dev , " regulators node not found \n " ) ;
} else {
of_property_read_u32 ( regulators , " x-powers,dcdc-freq " , & dcdcfreq ) ;
ret = axp20x_set_dcdc_freq ( pdev , dcdcfreq ) ;
if ( ret < 0 ) {
dev_err ( & pdev - > dev , " Error setting dcdc frequency: %d \n " , ret ) ;
return ret ;
}
of_node_put ( regulators ) ;
}
return 0 ;
}
static int axp20x_set_dcdc_workmode ( struct regulator_dev * rdev , int id , u32 workmode )
{
2015-04-10 07:09:03 +03:00
struct axp20x_dev * axp20x = rdev_get_drvdata ( rdev ) ;
unsigned int mask ;
2014-04-11 13:38:10 +04:00
2015-04-10 07:09:03 +03:00
switch ( axp20x - > variant ) {
case AXP202_ID :
case AXP209_ID :
if ( ( id ! = AXP20X_DCDC2 ) & & ( id ! = AXP20X_DCDC3 ) )
return - EINVAL ;
mask = AXP20X_WORKMODE_DCDC2_MASK ;
if ( id = = AXP20X_DCDC3 )
mask = AXP20X_WORKMODE_DCDC3_MASK ;
2014-04-11 13:38:10 +04:00
2015-04-10 07:09:03 +03:00
workmode < < = ffs ( mask ) - 1 ;
break ;
2014-04-11 13:38:10 +04:00
2015-04-10 07:09:04 +03:00
case AXP221_ID :
2016-02-12 05:02:45 +03:00
case AXP223_ID :
2016-05-31 19:23:19 +03:00
case AXP809_ID :
2015-04-10 07:09:04 +03:00
if ( id < AXP22X_DCDC1 | | id > AXP22X_DCDC5 )
return - EINVAL ;
mask = AXP22X_WORKMODE_DCDCX_MASK ( id - AXP22X_DCDC1 ) ;
workmode < < = id - AXP22X_DCDC1 ;
break ;
2015-04-10 07:09:03 +03:00
default :
/* should not happen */
WARN_ON ( 1 ) ;
return - EINVAL ;
}
2014-04-11 13:38:10 +04:00
return regmap_update_bits ( rdev - > regmap , AXP20X_DCDC_MODE , mask , workmode ) ;
}
static int axp20x_regulator_probe ( struct platform_device * pdev )
{
struct regulator_dev * rdev ;
struct axp20x_dev * axp20x = dev_get_drvdata ( pdev - > dev . parent ) ;
2015-04-10 07:09:03 +03:00
const struct regulator_desc * regulators ;
2015-01-09 19:23:44 +03:00
struct regulator_config config = {
. dev = pdev - > dev . parent ,
. regmap = axp20x - > regmap ,
2015-04-10 07:09:03 +03:00
. driver_data = axp20x ,
2015-01-09 19:23:44 +03:00
} ;
2015-04-10 07:09:03 +03:00
int ret , i , nregulators ;
2014-04-11 13:38:10 +04:00
u32 workmode ;
2016-05-31 19:23:19 +03:00
const char * dcdc1_name = axp22x_regulators [ AXP22X_DCDC1 ] . name ;
const char * dcdc5_name = axp22x_regulators [ AXP22X_DCDC5 ] . name ;
2016-06-03 19:59:44 +03:00
bool drivevbus = false ;
2014-04-11 13:38:10 +04:00
2015-04-10 07:09:03 +03:00
switch ( axp20x - > variant ) {
case AXP202_ID :
case AXP209_ID :
regulators = axp20x_regulators ;
nregulators = AXP20X_REG_ID_MAX ;
break ;
2015-04-10 07:09:04 +03:00
case AXP221_ID :
2016-02-12 05:02:45 +03:00
case AXP223_ID :
2015-04-10 07:09:04 +03:00
regulators = axp22x_regulators ;
nregulators = AXP22X_REG_ID_MAX ;
2016-06-03 19:59:44 +03:00
drivevbus = of_property_read_bool ( pdev - > dev . parent - > of_node ,
" x-powers,drive-vbus-en " ) ;
2015-04-10 07:09:04 +03:00
break ;
2016-05-31 19:23:19 +03:00
case AXP809_ID :
regulators = axp809_regulators ;
nregulators = AXP809_REG_ID_MAX ;
break ;
2015-04-10 07:09:03 +03:00
default :
dev_err ( & pdev - > dev , " Unsupported AXP variant: %ld \n " ,
axp20x - > variant ) ;
return - EINVAL ;
}
2015-01-09 19:23:44 +03:00
/* This only sets the dcdc freq. Ignore any errors */
axp20x_regulator_parse_dt ( pdev ) ;
2014-04-11 13:38:10 +04:00
2015-04-10 07:09:03 +03:00
for ( i = 0 ; i < nregulators ; i + + ) {
2015-09-30 09:39:46 +03:00
const struct regulator_desc * desc = & regulators [ i ] ;
struct regulator_desc * new_desc ;
/*
* Regulators DC1SW and DC5LDO are connected internally ,
* so we have to handle their supply names separately .
*
* We always register the regulators in proper sequence ,
* so the supply names are correctly read . See the last
* part of this loop to see where we save the DT defined
* name .
*/
2016-05-31 19:23:19 +03:00
if ( ( regulators = = axp22x_regulators & & i = = AXP22X_DC1SW ) | |
( regulators = = axp809_regulators & & i = = AXP809_DC1SW ) ) {
new_desc = devm_kzalloc ( & pdev - > dev , sizeof ( * desc ) ,
GFP_KERNEL ) ;
* new_desc = regulators [ i ] ;
new_desc - > supply_name = dcdc1_name ;
desc = new_desc ;
}
if ( ( regulators = = axp22x_regulators & & i = = AXP22X_DC5LDO ) | |
( regulators = = axp809_regulators & & i = = AXP809_DC5LDO ) ) {
new_desc = devm_kzalloc ( & pdev - > dev , sizeof ( * desc ) ,
GFP_KERNEL ) ;
* new_desc = regulators [ i ] ;
new_desc - > supply_name = dcdc5_name ;
desc = new_desc ;
2015-09-30 09:39:46 +03:00
}
rdev = devm_regulator_register ( & pdev - > dev , desc , & config ) ;
2014-04-11 13:38:10 +04:00
if ( IS_ERR ( rdev ) ) {
dev_err ( & pdev - > dev , " Failed to register %s \n " ,
2015-04-10 07:09:03 +03:00
regulators [ i ] . name ) ;
2014-04-11 13:38:10 +04:00
return PTR_ERR ( rdev ) ;
}
2015-01-09 19:23:44 +03:00
ret = of_property_read_u32 ( rdev - > dev . of_node ,
" x-powers,dcdc-workmode " ,
2014-04-11 13:38:10 +04:00
& workmode ) ;
if ( ! ret ) {
if ( axp20x_set_dcdc_workmode ( rdev , i , workmode ) )
dev_err ( & pdev - > dev , " Failed to set workmode on %s \n " ,
2015-04-10 07:09:03 +03:00
rdev - > desc - > name ) ;
2014-04-11 13:38:10 +04:00
}
2015-09-30 09:39:46 +03:00
/*
* Save AXP22X DCDC1 / DCDC5 regulator names for later .
*/
2016-05-31 19:23:19 +03:00
if ( ( regulators = = axp22x_regulators & & i = = AXP22X_DCDC1 ) | |
( regulators = = axp809_regulators & & i = = AXP809_DCDC1 ) )
of_property_read_string ( rdev - > dev . of_node ,
" regulator-name " ,
& dcdc1_name ) ;
if ( ( regulators = = axp22x_regulators & & i = = AXP22X_DCDC5 ) | |
( regulators = = axp809_regulators & & i = = AXP809_DCDC5 ) )
of_property_read_string ( rdev - > dev . of_node ,
" regulator-name " ,
& dcdc5_name ) ;
2014-04-11 13:38:10 +04:00
}
2016-06-03 19:59:44 +03:00
if ( drivevbus ) {
/* Change N_VBUSEN sense pin to DRIVEVBUS output pin */
regmap_update_bits ( axp20x - > regmap , AXP20X_OVER_TMP ,
AXP22X_MISC_N_VBUSEN_FUNC , 0 ) ;
rdev = devm_regulator_register ( & pdev - > dev ,
& axp22x_drivevbus_regulator ,
& config ) ;
if ( IS_ERR ( rdev ) ) {
dev_err ( & pdev - > dev , " Failed to register drivevbus \n " ) ;
return PTR_ERR ( rdev ) ;
}
}
2014-04-11 13:38:10 +04:00
return 0 ;
}
static struct platform_driver axp20x_regulator_driver = {
. probe = axp20x_regulator_probe ,
. driver = {
. name = " axp20x-regulator " ,
} ,
} ;
module_platform_driver ( axp20x_regulator_driver ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_AUTHOR ( " Carlo Caione <carlo@caione.org> " ) ;
MODULE_DESCRIPTION ( " Regulator Driver for AXP20X PMIC " ) ;
2015-08-01 20:13:25 +03:00
MODULE_ALIAS ( " platform:axp20x-regulator " ) ;