2013-07-18 07:07:03 +04:00
/*
* Regulators driver for Marvell 88 PM800
*
* Copyright ( C ) 2012 Marvell International Ltd .
* Joseph ( Yossi ) Hanin < yhanin @ marvell . com >
* Yi Zhang < yizhang @ marvell . 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 .
*/
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/init.h>
# include <linux/err.h>
# include <linux/regmap.h>
# include <linux/regulator/driver.h>
# include <linux/regulator/machine.h>
# include <linux/mfd/88pm80x.h>
# include <linux/delay.h>
# include <linux/io.h>
# include <linux/of.h>
# include <linux/regulator/of_regulator.h>
/* LDO1 with DVC[0..3] */
# define PM800_LDO1_VOUT (0x08) /* VOUT1 */
# define PM800_LDO1_VOUT_2 (0x09)
# define PM800_LDO1_VOUT_3 (0x0A)
# define PM800_LDO2_VOUT (0x0B)
# define PM800_LDO3_VOUT (0x0C)
# define PM800_LDO4_VOUT (0x0D)
# define PM800_LDO5_VOUT (0x0E)
# define PM800_LDO6_VOUT (0x0F)
# define PM800_LDO7_VOUT (0x10)
# define PM800_LDO8_VOUT (0x11)
# define PM800_LDO9_VOUT (0x12)
# define PM800_LDO10_VOUT (0x13)
# define PM800_LDO11_VOUT (0x14)
# define PM800_LDO12_VOUT (0x15)
# define PM800_LDO13_VOUT (0x16)
# define PM800_LDO14_VOUT (0x17)
# define PM800_LDO15_VOUT (0x18)
# define PM800_LDO16_VOUT (0x19)
# define PM800_LDO17_VOUT (0x1A)
# define PM800_LDO18_VOUT (0x1B)
# define PM800_LDO19_VOUT (0x1C)
/* BUCK1 with DVC[0..3] */
# define PM800_BUCK1 (0x3C)
# define PM800_BUCK1_1 (0x3D)
# define PM800_BUCK1_2 (0x3E)
# define PM800_BUCK1_3 (0x3F)
# define PM800_BUCK2 (0x40)
# define PM800_BUCK3 (0x41)
# define PM800_BUCK4 (0x42)
# define PM800_BUCK4_1 (0x43)
# define PM800_BUCK4_2 (0x44)
# define PM800_BUCK4_3 (0x45)
# define PM800_BUCK5 (0x46)
# define PM800_BUCK_ENA (0x50)
# define PM800_LDO_ENA1_1 (0x51)
# define PM800_LDO_ENA1_2 (0x52)
# define PM800_LDO_ENA1_3 (0x53)
# define PM800_LDO_ENA2_1 (0x56)
# define PM800_LDO_ENA2_2 (0x57)
# define PM800_LDO_ENA2_3 (0x58)
# define PM800_BUCK1_MISC1 (0x78)
# define PM800_BUCK3_MISC1 (0x7E)
# define PM800_BUCK4_MISC1 (0x81)
# define PM800_BUCK5_MISC1 (0x84)
struct pm800_regulator_info {
struct regulator_desc desc ;
int max_ua ;
} ;
struct pm800_regulators {
struct pm80x_chip * chip ;
struct regmap * map ;
} ;
/*
* vreg - the buck regs string .
* ereg - the string for the enable register .
* ebit - the bit number in the enable register .
* amax - the current
* Buck has 2 kinds of voltage steps . It is easy to find voltage by ranges ,
* not the constant voltage table .
2013-07-19 09:06:22 +04:00
* n_volt - Number of available selectors
2013-07-18 07:07:03 +04:00
*/
2015-07-16 21:16:56 +03:00
# define PM800_BUCK(match, vreg, ereg, ebit, amax, volt_ranges, n_volt) \
2013-07-18 07:07:03 +04:00
{ \
. desc = { \
2015-07-16 21:16:54 +03:00
. name = # vreg , \
2015-07-16 21:16:56 +03:00
. of_match = of_match_ptr ( # match ) , \
. regulators_node = of_match_ptr ( " regulators " ) , \
2015-07-16 21:16:54 +03:00
. ops = & pm800_volt_range_ops , \
. type = REGULATOR_VOLTAGE , \
. id = PM800_ID_ # # vreg , \
. owner = THIS_MODULE , \
2013-07-19 09:06:22 +04:00
. n_voltages = n_volt , \
2013-07-18 07:07:03 +04:00
. linear_ranges = volt_ranges , \
. n_linear_ranges = ARRAY_SIZE ( volt_ranges ) , \
. vsel_reg = PM800_ # # vreg , \
. vsel_mask = 0x7f , \
. enable_reg = PM800_ # # ereg , \
. enable_mask = 1 < < ( ebit ) , \
} , \
2015-07-16 21:16:54 +03:00
. max_ua = ( amax ) , \
2013-07-18 07:07:03 +04:00
}
/*
* vreg - the LDO regs string
* ereg - the string for the enable register .
* ebit - the bit number in the enable register .
* amax - the current
* volt_table - the LDO voltage table
* For all the LDOes , there are too many ranges . Using volt_table will be
* simpler and faster .
*/
2015-07-16 21:16:56 +03:00
# define PM800_LDO(match, vreg, ereg, ebit, amax, ldo_volt_table) \
2013-07-18 07:07:03 +04:00
{ \
. desc = { \
2015-07-16 21:16:54 +03:00
. name = # vreg , \
2015-07-16 21:16:56 +03:00
. of_match = of_match_ptr ( # match ) , \
. regulators_node = of_match_ptr ( " regulators " ) , \
2015-07-16 21:16:54 +03:00
. ops = & pm800_volt_table_ops , \
. type = REGULATOR_VOLTAGE , \
. id = PM800_ID_ # # vreg , \
. owner = THIS_MODULE , \
. n_voltages = ARRAY_SIZE ( ldo_volt_table ) , \
. vsel_reg = PM800_ # # vreg # # _VOUT , \
2015-07-17 14:42:48 +03:00
. vsel_mask = 0xf , \
2015-07-16 21:16:54 +03:00
. enable_reg = PM800_ # # ereg , \
. enable_mask = 1 < < ( ebit ) , \
. volt_table = ldo_volt_table , \
2013-07-18 07:07:03 +04:00
} , \
2015-07-16 21:16:54 +03:00
. max_ua = ( amax ) , \
2013-07-18 07:07:03 +04:00
}
/* Ranges are sorted in ascending order. */
static const struct regulator_linear_range buck1_volt_range [ ] = {
2013-10-11 05:32:18 +04:00
REGULATOR_LINEAR_RANGE ( 600000 , 0 , 0x4f , 12500 ) ,
REGULATOR_LINEAR_RANGE ( 1600000 , 0x50 , 0x54 , 50000 ) ,
2013-07-18 07:07:03 +04:00
} ;
/* BUCK 2~5 have same ranges. */
static const struct regulator_linear_range buck2_5_volt_range [ ] = {
2013-10-11 05:32:18 +04:00
REGULATOR_LINEAR_RANGE ( 600000 , 0 , 0x4f , 12500 ) ,
REGULATOR_LINEAR_RANGE ( 1600000 , 0x50 , 0x72 , 50000 ) ,
2013-07-18 07:07:03 +04:00
} ;
static const unsigned int ldo1_volt_table [ ] = {
600000 , 650000 , 700000 , 750000 , 800000 , 850000 , 900000 , 950000 ,
1000000 , 1050000 , 1100000 , 1150000 , 1200000 , 1300000 , 1400000 , 1500000 ,
} ;
static const unsigned int ldo2_volt_table [ ] = {
1700000 , 1800000 , 1900000 , 2000000 , 2100000 , 2500000 , 2700000 , 2800000 ,
} ;
/* LDO 3~17 have same voltage table. */
static const unsigned int ldo3_17_volt_table [ ] = {
1200000 , 1250000 , 1700000 , 1800000 , 1850000 , 1900000 , 2500000 , 2600000 ,
2700000 , 2750000 , 2800000 , 2850000 , 2900000 , 3000000 , 3100000 , 3300000 ,
} ;
/* LDO 18~19 have same voltage table. */
static const unsigned int ldo18_19_volt_table [ ] = {
1700000 , 1800000 , 1900000 , 2500000 , 2800000 , 2900000 , 3100000 , 3300000 ,
} ;
static int pm800_get_current_limit ( struct regulator_dev * rdev )
{
struct pm800_regulator_info * info = rdev_get_drvdata ( rdev ) ;
return info - > max_ua ;
}
2017-01-28 16:23:18 +03:00
static const struct regulator_ops pm800_volt_range_ops = {
2015-07-16 21:16:54 +03:00
. list_voltage = regulator_list_voltage_linear_range ,
. map_voltage = regulator_map_voltage_linear_range ,
. set_voltage_sel = regulator_set_voltage_sel_regmap ,
. get_voltage_sel = regulator_get_voltage_sel_regmap ,
. enable = regulator_enable_regmap ,
. disable = regulator_disable_regmap ,
. is_enabled = regulator_is_enabled_regmap ,
. get_current_limit = pm800_get_current_limit ,
2013-07-18 07:07:03 +04:00
} ;
2017-01-28 16:23:18 +03:00
static const struct regulator_ops pm800_volt_table_ops = {
2015-07-16 21:16:54 +03:00
. list_voltage = regulator_list_voltage_table ,
. map_voltage = regulator_map_voltage_iterate ,
. set_voltage_sel = regulator_set_voltage_sel_regmap ,
. get_voltage_sel = regulator_get_voltage_sel_regmap ,
. enable = regulator_enable_regmap ,
. disable = regulator_disable_regmap ,
. is_enabled = regulator_is_enabled_regmap ,
. get_current_limit = pm800_get_current_limit ,
2013-07-18 07:07:03 +04:00
} ;
/* The array is indexed by id(PM800_ID_XXX) */
static struct pm800_regulator_info pm800_regulator_info [ ] = {
2015-07-16 21:16:56 +03:00
PM800_BUCK ( buck1 , BUCK1 , BUCK_ENA , 0 , 3000000 , buck1_volt_range , 0x55 ) ,
PM800_BUCK ( buck2 , BUCK2 , BUCK_ENA , 1 , 1200000 , buck2_5_volt_range , 0x73 ) ,
PM800_BUCK ( buck3 , BUCK3 , BUCK_ENA , 2 , 1200000 , buck2_5_volt_range , 0x73 ) ,
PM800_BUCK ( buck4 , BUCK4 , BUCK_ENA , 3 , 1200000 , buck2_5_volt_range , 0x73 ) ,
PM800_BUCK ( buck5 , BUCK5 , BUCK_ENA , 4 , 1200000 , buck2_5_volt_range , 0x73 ) ,
PM800_LDO ( ldo1 , LDO1 , LDO_ENA1_1 , 0 , 200000 , ldo1_volt_table ) ,
PM800_LDO ( ldo2 , LDO2 , LDO_ENA1_1 , 1 , 10000 , ldo2_volt_table ) ,
PM800_LDO ( ldo3 , LDO3 , LDO_ENA1_1 , 2 , 300000 , ldo3_17_volt_table ) ,
PM800_LDO ( ldo4 , LDO4 , LDO_ENA1_1 , 3 , 300000 , ldo3_17_volt_table ) ,
PM800_LDO ( ldo5 , LDO5 , LDO_ENA1_1 , 4 , 300000 , ldo3_17_volt_table ) ,
PM800_LDO ( ldo6 , LDO6 , LDO_ENA1_1 , 5 , 300000 , ldo3_17_volt_table ) ,
PM800_LDO ( ldo7 , LDO7 , LDO_ENA1_1 , 6 , 300000 , ldo3_17_volt_table ) ,
PM800_LDO ( ldo8 , LDO8 , LDO_ENA1_1 , 7 , 300000 , ldo3_17_volt_table ) ,
PM800_LDO ( ldo9 , LDO9 , LDO_ENA1_2 , 0 , 300000 , ldo3_17_volt_table ) ,
PM800_LDO ( ldo10 , LDO10 , LDO_ENA1_2 , 1 , 300000 , ldo3_17_volt_table ) ,
PM800_LDO ( ldo11 , LDO11 , LDO_ENA1_2 , 2 , 300000 , ldo3_17_volt_table ) ,
PM800_LDO ( ldo12 , LDO12 , LDO_ENA1_2 , 3 , 300000 , ldo3_17_volt_table ) ,
PM800_LDO ( ldo13 , LDO13 , LDO_ENA1_2 , 4 , 300000 , ldo3_17_volt_table ) ,
PM800_LDO ( ldo14 , LDO14 , LDO_ENA1_2 , 5 , 300000 , ldo3_17_volt_table ) ,
PM800_LDO ( ldo15 , LDO15 , LDO_ENA1_2 , 6 , 300000 , ldo3_17_volt_table ) ,
PM800_LDO ( ldo16 , LDO16 , LDO_ENA1_2 , 7 , 300000 , ldo3_17_volt_table ) ,
PM800_LDO ( ldo17 , LDO17 , LDO_ENA1_3 , 0 , 300000 , ldo3_17_volt_table ) ,
PM800_LDO ( ldo18 , LDO18 , LDO_ENA1_3 , 1 , 200000 , ldo18_19_volt_table ) ,
PM800_LDO ( ldo19 , LDO19 , LDO_ENA1_3 , 2 , 200000 , ldo18_19_volt_table ) ,
2013-07-18 07:07:03 +04:00
} ;
static int pm800_regulator_probe ( struct platform_device * pdev )
{
struct pm80x_chip * chip = dev_get_drvdata ( pdev - > dev . parent ) ;
2013-07-30 12:20:47 +04:00
struct pm80x_platform_data * pdata = dev_get_platdata ( pdev - > dev . parent ) ;
2013-07-18 07:07:03 +04:00
struct pm800_regulators * pm800_data ;
struct regulator_config config = { } ;
struct regulator_init_data * init_data ;
int i , ret ;
2015-07-16 21:16:56 +03:00
if ( pdata & & pdata - > num_regulators ) {
2013-07-18 07:07:03 +04:00
unsigned int count = 0 ;
2013-08-04 05:23:28 +04:00
/* Check whether num_regulator is valid. */
2013-08-14 20:14:03 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( pdata - > regulators ) ; i + + ) {
2013-08-04 05:23:28 +04:00
if ( pdata - > regulators [ i ] )
count + + ;
}
2013-07-18 07:07:03 +04:00
if ( count ! = pdata - > num_regulators )
return - EINVAL ;
}
pm800_data = devm_kzalloc ( & pdev - > dev , sizeof ( * pm800_data ) ,
GFP_KERNEL ) ;
2014-02-18 14:41:07 +04:00
if ( ! pm800_data )
2013-07-18 07:07:03 +04:00
return - ENOMEM ;
pm800_data - > map = chip - > subchip - > regmap_power ;
pm800_data - > chip = chip ;
platform_set_drvdata ( pdev , pm800_data ) ;
2015-07-16 21:16:56 +03:00
config . dev = chip - > dev ;
config . regmap = pm800_data - > map ;
2013-07-18 07:07:03 +04:00
for ( i = 0 ; i < PM800_ID_RG_MAX ; i + + ) {
2015-07-16 21:16:55 +03:00
struct regulator_dev * regulator ;
2015-07-16 21:16:56 +03:00
if ( pdata & & pdata - > num_regulators ) {
2013-07-18 07:07:03 +04:00
init_data = pdata - > regulators [ i ] ;
2015-07-16 21:16:56 +03:00
if ( ! init_data )
continue ;
config . init_data = init_data ;
}
config . driver_data = & pm800_regulator_info [ i ] ;
2013-07-18 07:07:03 +04:00
2015-07-16 21:16:55 +03:00
regulator = devm_regulator_register ( & pdev - > dev ,
2015-07-16 21:16:56 +03:00
& pm800_regulator_info [ i ] . desc , & config ) ;
2015-07-16 21:16:55 +03:00
if ( IS_ERR ( regulator ) ) {
ret = PTR_ERR ( regulator ) ;
2013-07-18 07:07:03 +04:00
dev_err ( & pdev - > dev , " Failed to register %s \n " ,
2015-07-16 21:16:56 +03:00
pm800_regulator_info [ i ] . desc . name ) ;
2013-07-18 07:07:03 +04:00
return ret ;
}
}
return 0 ;
}
static struct platform_driver pm800_regulator_driver = {
. driver = {
. name = " 88pm80x-regulator " ,
} ,
. probe = pm800_regulator_probe ,
} ;
module_platform_driver ( pm800_regulator_driver ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Joseph(Yossi) Hanin <yhanin@marvell.com> " ) ;
MODULE_DESCRIPTION ( " Regulator Driver for Marvell 88PM800 PMIC " ) ;
MODULE_ALIAS ( " platform:88pm800-regulator " ) ;