2010-01-11 15:10:08 +03:00
/*
* Regulators driver for Maxim max8925
*
* Copyright ( C ) 2009 Marvell International Ltd .
* Haojian Zhuang < haojian . zhuang @ 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/kernel.h>
2011-07-18 00:28:23 +04:00
# include <linux/module.h>
2010-01-11 15:10:08 +03:00
# include <linux/init.h>
# include <linux/err.h>
# include <linux/i2c.h>
# include <linux/platform_device.h>
# include <linux/regulator/driver.h>
# include <linux/regulator/machine.h>
# include <linux/mfd/max8925.h>
2012-11-07 14:09:53 +04:00
# include <linux/of.h>
# include <linux/regulator/of_regulator.h>
2010-01-11 15:10:08 +03:00
# define SD1_DVM_VMIN 850000
# define SD1_DVM_VMAX 1000000
# define SD1_DVM_STEP 50000
# define SD1_DVM_SHIFT 5 /* SDCTL1 bit5 */
# define SD1_DVM_EN 6 /* SDV1 bit 6 */
2012-01-04 11:12:04 +04:00
/* bit definitions in LDO control registers */
# define LDO_SEQ_I2C 0x7 /* Power U/D by i2c */
# define LDO_SEQ_MASK 0x7 /* Power U/D sequence mask */
# define LDO_SEQ_SHIFT 2 /* Power U/D sequence offset */
# define LDO_I2C_EN 0x1 /* Enable by i2c */
# define LDO_I2C_EN_MASK 0x1 /* Enable mask by i2c */
# define LDO_I2C_EN_SHIFT 0 /* Enable offset by i2c */
2011-04-18 18:04:09 +04:00
2010-01-11 15:10:08 +03:00
struct max8925_regulator_info {
struct regulator_desc desc ;
struct i2c_client * i2c ;
int vol_reg ;
int enable_reg ;
} ;
2012-05-14 06:36:40 +04:00
static int max8925_set_voltage_sel ( struct regulator_dev * rdev ,
unsigned int selector )
2010-01-11 15:10:08 +03:00
{
struct max8925_regulator_info * info = rdev_get_drvdata ( rdev ) ;
2012-05-14 06:36:40 +04:00
unsigned char mask = rdev - > desc - > n_voltages - 1 ;
2010-01-11 15:10:08 +03:00
2012-05-14 06:36:40 +04:00
return max8925_set_bits ( info - > i2c , info - > vol_reg , mask , selector ) ;
2010-01-11 15:10:08 +03:00
}
2012-05-14 06:34:50 +04:00
static int max8925_get_voltage_sel ( struct regulator_dev * rdev )
2010-01-11 15:10:08 +03:00
{
struct max8925_regulator_info * info = rdev_get_drvdata ( rdev ) ;
unsigned char data , mask ;
int ret ;
ret = max8925_reg_read ( info - > i2c , info - > vol_reg ) ;
if ( ret < 0 )
return ret ;
2012-04-02 05:16:08 +04:00
mask = rdev - > desc - > n_voltages - 1 ;
data = ret & mask ;
2010-01-11 15:10:08 +03:00
2012-05-14 06:34:50 +04:00
return data ;
2010-01-11 15:10:08 +03:00
}
static int max8925_enable ( struct regulator_dev * rdev )
{
struct max8925_regulator_info * info = rdev_get_drvdata ( rdev ) ;
return max8925_set_bits ( info - > i2c , info - > enable_reg ,
2012-01-04 11:12:04 +04:00
LDO_SEQ_MASK < < LDO_SEQ_SHIFT |
LDO_I2C_EN_MASK < < LDO_I2C_EN_SHIFT ,
LDO_SEQ_I2C < < LDO_SEQ_SHIFT |
LDO_I2C_EN < < LDO_I2C_EN_SHIFT ) ;
2010-01-11 15:10:08 +03:00
}
static int max8925_disable ( struct regulator_dev * rdev )
{
struct max8925_regulator_info * info = rdev_get_drvdata ( rdev ) ;
return max8925_set_bits ( info - > i2c , info - > enable_reg ,
2012-01-04 11:12:04 +04:00
LDO_SEQ_MASK < < LDO_SEQ_SHIFT |
LDO_I2C_EN_MASK < < LDO_I2C_EN_SHIFT ,
LDO_SEQ_I2C < < LDO_SEQ_SHIFT ) ;
2010-01-11 15:10:08 +03:00
}
static int max8925_is_enabled ( struct regulator_dev * rdev )
{
struct max8925_regulator_info * info = rdev_get_drvdata ( rdev ) ;
2012-01-04 11:12:04 +04:00
int ldo_seq , ret ;
2010-01-11 15:10:08 +03:00
2010-04-06 14:19:15 +04:00
ret = max8925_reg_read ( info - > i2c , info - > enable_reg ) ;
2010-01-11 15:10:08 +03:00
if ( ret < 0 )
return ret ;
2012-01-04 11:12:04 +04:00
ldo_seq = ( ret > > LDO_SEQ_SHIFT ) & LDO_SEQ_MASK ;
if ( ldo_seq ! = LDO_SEQ_I2C )
return 1 ;
else
return ret & ( LDO_I2C_EN_MASK < < LDO_I2C_EN_SHIFT ) ;
2010-01-11 15:10:08 +03:00
}
static int max8925_set_dvm_voltage ( struct regulator_dev * rdev , int uV )
{
struct max8925_regulator_info * info = rdev_get_drvdata ( rdev ) ;
unsigned char data , mask ;
if ( uV < SD1_DVM_VMIN | | uV > SD1_DVM_VMAX )
return - EINVAL ;
2012-03-13 12:09:28 +04:00
data = DIV_ROUND_UP ( uV - SD1_DVM_VMIN , SD1_DVM_STEP ) ;
2010-01-11 15:10:08 +03:00
data < < = SD1_DVM_SHIFT ;
mask = 3 < < SD1_DVM_SHIFT ;
return max8925_set_bits ( info - > i2c , info - > enable_reg , mask , data ) ;
}
static int max8925_set_dvm_enable ( struct regulator_dev * rdev )
{
struct max8925_regulator_info * info = rdev_get_drvdata ( rdev ) ;
return max8925_set_bits ( info - > i2c , info - > vol_reg , 1 < < SD1_DVM_EN ,
1 < < SD1_DVM_EN ) ;
}
static int max8925_set_dvm_disable ( struct regulator_dev * rdev )
{
struct max8925_regulator_info * info = rdev_get_drvdata ( rdev ) ;
return max8925_set_bits ( info - > i2c , info - > vol_reg , 1 < < SD1_DVM_EN , 0 ) ;
}
static struct regulator_ops max8925_regulator_sdv_ops = {
2012-05-14 06:36:40 +04:00
. map_voltage = regulator_map_voltage_linear ,
2012-05-14 06:35:40 +04:00
. list_voltage = regulator_list_voltage_linear ,
2012-05-14 06:36:40 +04:00
. set_voltage_sel = max8925_set_voltage_sel ,
2012-05-14 06:34:50 +04:00
. get_voltage_sel = max8925_get_voltage_sel ,
2010-01-11 15:10:08 +03:00
. enable = max8925_enable ,
. disable = max8925_disable ,
. is_enabled = max8925_is_enabled ,
. set_suspend_voltage = max8925_set_dvm_voltage ,
. set_suspend_enable = max8925_set_dvm_enable ,
. set_suspend_disable = max8925_set_dvm_disable ,
} ;
static struct regulator_ops max8925_regulator_ldo_ops = {
2012-05-14 06:36:40 +04:00
. map_voltage = regulator_map_voltage_linear ,
2012-05-14 06:35:40 +04:00
. list_voltage = regulator_list_voltage_linear ,
2012-05-14 06:36:40 +04:00
. set_voltage_sel = max8925_set_voltage_sel ,
2012-05-14 06:34:50 +04:00
. get_voltage_sel = max8925_get_voltage_sel ,
2010-01-11 15:10:08 +03:00
. enable = max8925_enable ,
. disable = max8925_disable ,
. is_enabled = max8925_is_enabled ,
} ;
# define MAX8925_SDV(_id, min, max, step) \
{ \
. desc = { \
. name = " SDV " # _id , \
. ops = & max8925_regulator_sdv_ops , \
. type = REGULATOR_VOLTAGE , \
. id = MAX8925_ID_SD # # _id , \
. owner = THIS_MODULE , \
2012-04-02 05:16:08 +04:00
. n_voltages = 64 , \
2012-05-14 06:35:40 +04:00
. min_uV = min * 1000 , \
. uV_step = step * 1000 , \
2010-01-11 15:10:08 +03:00
} , \
. vol_reg = MAX8925_SDV # # _id , \
. enable_reg = MAX8925_SDCTL # # _id , \
}
# define MAX8925_LDO(_id, min, max, step) \
{ \
. desc = { \
. name = " LDO " # _id , \
. ops = & max8925_regulator_ldo_ops , \
. type = REGULATOR_VOLTAGE , \
. id = MAX8925_ID_LDO # # _id , \
. owner = THIS_MODULE , \
2012-04-02 05:16:08 +04:00
. n_voltages = 64 , \
2012-05-14 06:35:40 +04:00
. min_uV = min * 1000 , \
. uV_step = step * 1000 , \
2010-01-11 15:10:08 +03:00
} , \
. vol_reg = MAX8925_LDOVOUT # # _id , \
. enable_reg = MAX8925_LDOCTL # # _id , \
}
2012-11-07 14:09:53 +04:00
# ifdef CONFIG_OF
static struct of_regulator_match max8925_regulator_matches [ ] = {
{ . name = " SDV1 " , } ,
{ . name = " SDV2 " , } ,
{ . name = " SDV3 " , } ,
{ . name = " LDO1 " , } ,
{ . name = " LDO2 " , } ,
{ . name = " LDO3 " , } ,
{ . name = " LDO4 " , } ,
{ . name = " LDO5 " , } ,
{ . name = " LDO6 " , } ,
{ . name = " LDO7 " , } ,
{ . name = " LDO8 " , } ,
{ . name = " LDO9 " , } ,
{ . name = " LDO10 " , } ,
{ . name = " LDO11 " , } ,
{ . name = " LDO12 " , } ,
{ . name = " LDO13 " , } ,
{ . name = " LDO14 " , } ,
{ . name = " LDO15 " , } ,
{ . name = " LDO16 " , } ,
{ . name = " LDO17 " , } ,
{ . name = " LDO18 " , } ,
{ . name = " LDO19 " , } ,
{ . name = " LDO20 " , } ,
} ;
# endif
2010-01-11 15:10:08 +03:00
static struct max8925_regulator_info max8925_regulator_info [ ] = {
MAX8925_SDV ( 1 , 637.5 , 1425 , 12.5 ) ,
MAX8925_SDV ( 2 , 650 , 2225 , 25 ) ,
MAX8925_SDV ( 3 , 750 , 3900 , 50 ) ,
MAX8925_LDO ( 1 , 750 , 3900 , 50 ) ,
MAX8925_LDO ( 2 , 650 , 2250 , 25 ) ,
MAX8925_LDO ( 3 , 650 , 2250 , 25 ) ,
MAX8925_LDO ( 4 , 750 , 3900 , 50 ) ,
MAX8925_LDO ( 5 , 750 , 3900 , 50 ) ,
MAX8925_LDO ( 6 , 750 , 3900 , 50 ) ,
MAX8925_LDO ( 7 , 750 , 3900 , 50 ) ,
MAX8925_LDO ( 8 , 750 , 3900 , 50 ) ,
MAX8925_LDO ( 9 , 750 , 3900 , 50 ) ,
MAX8925_LDO ( 10 , 750 , 3900 , 50 ) ,
MAX8925_LDO ( 11 , 750 , 3900 , 50 ) ,
MAX8925_LDO ( 12 , 750 , 3900 , 50 ) ,
MAX8925_LDO ( 13 , 750 , 3900 , 50 ) ,
MAX8925_LDO ( 14 , 750 , 3900 , 50 ) ,
MAX8925_LDO ( 15 , 750 , 3900 , 50 ) ,
MAX8925_LDO ( 16 , 750 , 3900 , 50 ) ,
MAX8925_LDO ( 17 , 650 , 2250 , 25 ) ,
MAX8925_LDO ( 18 , 650 , 2250 , 25 ) ,
MAX8925_LDO ( 19 , 750 , 3900 , 50 ) ,
MAX8925_LDO ( 20 , 750 , 3900 , 50 ) ,
} ;
2012-11-07 14:09:53 +04:00
# ifdef CONFIG_OF
static int max8925_regulator_dt_init ( struct platform_device * pdev ,
struct regulator_config * config ,
int ridx )
{
struct device_node * nproot , * np ;
int rcount ;
2014-03-18 14:23:03 +04:00
2014-09-10 07:50:39 +04:00
nproot = pdev - > dev . parent - > of_node ;
2012-11-07 14:09:53 +04:00
if ( ! nproot )
return - ENODEV ;
2014-02-14 15:49:51 +04:00
np = of_get_child_by_name ( nproot , " regulators " ) ;
2012-11-07 14:09:53 +04:00
if ( ! np ) {
dev_err ( & pdev - > dev , " failed to find regulators node \n " ) ;
return - ENODEV ;
}
rcount = of_regulator_match ( & pdev - > dev , np ,
& max8925_regulator_matches [ ridx ] , 1 ) ;
2013-01-27 17:16:56 +04:00
of_node_put ( np ) ;
2012-11-07 14:09:53 +04:00
if ( rcount < 0 )
2014-02-18 14:41:01 +04:00
return rcount ;
2012-11-07 14:09:53 +04:00
config - > init_data = max8925_regulator_matches [ ridx ] . init_data ;
config - > of_node = max8925_regulator_matches [ ridx ] . of_node ;
return 0 ;
}
# else
2013-02-15 16:36:06 +04:00
# define max8925_regulator_dt_init(x, y, z) (-1)
2012-11-07 14:09:53 +04:00
# endif
2012-11-19 22:22:22 +04:00
static int max8925_regulator_probe ( struct platform_device * pdev )
2010-01-11 15:10:08 +03:00
{
struct max8925_chip * chip = dev_get_drvdata ( pdev - > dev . parent ) ;
2013-07-30 12:20:47 +04:00
struct regulator_init_data * pdata = dev_get_platdata ( & pdev - > dev ) ;
2012-04-04 03:50:22 +04:00
struct regulator_config config = { } ;
2010-02-24 10:38:55 +03:00
struct max8925_regulator_info * ri ;
2012-09-17 08:19:05 +04:00
struct resource * res ;
2010-01-11 15:10:08 +03:00
struct regulator_dev * rdev ;
2012-11-07 14:09:53 +04:00
int i , regulator_idx ;
2010-01-11 15:10:08 +03:00
2012-09-17 08:19:05 +04:00
res = platform_get_resource ( pdev , IORESOURCE_REG , 0 ) ;
if ( ! res ) {
dev_err ( & pdev - > dev , " No REG resource! \n " ) ;
return - EINVAL ;
}
for ( i = 0 ; i < ARRAY_SIZE ( max8925_regulator_info ) ; i + + ) {
ri = & max8925_regulator_info [ i ] ;
2012-11-07 14:09:53 +04:00
if ( ri - > vol_reg = = res - > start ) {
regulator_idx = i ;
2012-09-17 08:19:05 +04:00
break ;
2012-11-07 14:09:53 +04:00
}
2012-09-17 08:19:05 +04:00
}
2012-11-07 14:09:53 +04:00
2012-09-17 08:19:05 +04:00
if ( i = = ARRAY_SIZE ( max8925_regulator_info ) ) {
dev_err ( & pdev - > dev , " Failed to find regulator %llu \n " ,
( unsigned long long ) res - > start ) ;
2010-01-11 15:10:08 +03:00
return - EINVAL ;
}
ri - > i2c = chip - > i2c ;
2012-04-04 03:50:22 +04:00
config . dev = & pdev - > dev ;
config . driver_data = ri ;
2013-02-15 16:36:06 +04:00
if ( max8925_regulator_dt_init ( pdev , & config , regulator_idx ) )
2012-11-07 14:09:53 +04:00
if ( pdata )
config . init_data = pdata ;
2013-09-30 04:56:24 +04:00
rdev = devm_regulator_register ( & pdev - > dev , & ri - > desc , & config ) ;
2010-01-11 15:10:08 +03:00
if ( IS_ERR ( rdev ) ) {
dev_err ( & pdev - > dev , " failed to register regulator %s \n " ,
ri - > desc . name ) ;
return PTR_ERR ( rdev ) ;
}
platform_set_drvdata ( pdev , rdev ) ;
return 0 ;
}
static struct platform_driver max8925_regulator_driver = {
. driver = {
. name = " max8925-regulator " ,
} ,
. probe = max8925_regulator_probe ,
} ;
static int __init max8925_regulator_init ( void )
{
return platform_driver_register ( & max8925_regulator_driver ) ;
}
subsys_initcall ( max8925_regulator_init ) ;
static void __exit max8925_regulator_exit ( void )
{
platform_driver_unregister ( & max8925_regulator_driver ) ;
}
module_exit ( max8925_regulator_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Haojian Zhuang <haojian.zhuang@marvell.com> " ) ;
MODULE_DESCRIPTION ( " Regulator Driver for Maxim 8925 PMIC " ) ;
MODULE_ALIAS ( " platform:max8925-regulator " ) ;