2013-03-28 20:11:01 +04:00
/*
* Copyright ( C ) ST - Ericsson SA 2010
*
* License Terms : GNU General Public License v2
*
* Authors : Bengt Jonsson < bengt . g . jonsson @ stericsson . com >
*
* This file is based on drivers / regulator / ab8500 . c
*
* AB8500 external regulators
*
* ab8500 - ext supports the following regulators :
* - VextSupply3
*/
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/err.h>
# include <linux/module.h>
2013-06-07 20:11:27 +04:00
# include <linux/of.h>
2013-03-28 20:11:01 +04:00
# include <linux/platform_device.h>
# include <linux/regulator/driver.h>
# include <linux/regulator/machine.h>
2013-06-07 20:11:27 +04:00
# include <linux/regulator/of_regulator.h>
2013-03-28 20:11:01 +04:00
# include <linux/mfd/abx500.h>
# include <linux/mfd/abx500/ab8500.h>
# include <linux/regulator/ab8500.h>
/**
* struct ab8500_ext_regulator_info - ab8500 regulator information
* @ dev : device pointer
* @ desc : regulator description
* @ rdev : regulator device
2013-03-28 20:11:06 +04:00
* @ cfg : regulator configuration ( extension of regulator FW configuration )
2013-03-28 20:11:01 +04:00
* @ update_bank : bank to control on / off
* @ update_reg : register to control on / off
* @ update_mask : mask to enable / disable and set mode of regulator
* @ update_val : bits holding the regulator current mode
2013-03-28 20:11:06 +04:00
* @ update_val_hp : bits to set EN pin active ( LPn pin deactive )
2013-03-28 20:11:01 +04:00
* normally this means high power mode
2013-03-28 20:11:06 +04:00
* @ update_val_lp : bits to set EN pin active and LPn pin active
* normally this means low power mode
* @ update_val_hw : bits to set regulator pins in HW control
* SysClkReq pins and logic will choose mode
2013-03-28 20:11:01 +04:00
*/
struct ab8500_ext_regulator_info {
struct device * dev ;
struct regulator_desc desc ;
struct regulator_dev * rdev ;
2013-03-28 20:11:06 +04:00
struct ab8500_ext_regulator_cfg * cfg ;
2013-03-28 20:11:01 +04:00
u8 update_bank ;
u8 update_reg ;
u8 update_mask ;
u8 update_val ;
2013-03-28 20:11:06 +04:00
u8 update_val_hp ;
u8 update_val_lp ;
u8 update_val_hw ;
2013-03-28 20:11:01 +04:00
} ;
2013-04-16 19:33:00 +04:00
static int ab8500_ext_regulator_enable ( struct regulator_dev * rdev )
2013-03-28 20:11:01 +04:00
{
int ret ;
2013-04-16 19:33:00 +04:00
struct ab8500_ext_regulator_info * info = rdev_get_drvdata ( rdev ) ;
u8 regval ;
2013-03-28 20:11:01 +04:00
2013-04-16 19:33:00 +04:00
if ( info = = NULL ) {
dev_err ( rdev_get_dev ( rdev ) , " regulator info null pointer \n " ) ;
return - EINVAL ;
}
2013-03-28 20:11:06 +04:00
/*
* To satisfy both HW high power request and SW request , the regulator
* must be on in high power .
*/
if ( info - > cfg & & info - > cfg - > hwreq )
2013-04-16 19:33:00 +04:00
regval = info - > update_val_hp ;
else
regval = info - > update_val ;
2013-03-28 20:11:01 +04:00
ret = abx500_mask_and_set_register_interruptible ( info - > dev ,
info - > update_bank , info - > update_reg ,
2013-04-16 19:33:00 +04:00
info - > update_mask , regval ) ;
2013-04-02 16:56:16 +04:00
if ( ret < 0 ) {
2013-03-28 20:11:01 +04:00
dev_err ( rdev_get_dev ( info - > rdev ) ,
" couldn't set enable bits for regulator \n " ) ;
2013-04-02 16:56:16 +04:00
return ret ;
}
2013-03-28 20:11:01 +04:00
2013-04-16 19:33:00 +04:00
dev_dbg ( rdev_get_dev ( rdev ) ,
" %s-enable (bank, reg, mask, value): 0x%02x, 0x%02x, 0x%02x, 0x%02x \n " ,
info - > desc . name , info - > update_bank , info - > update_reg ,
info - > update_mask , regval ) ;
return 0 ;
2013-03-28 20:11:01 +04:00
}
2013-04-16 19:33:00 +04:00
static int ab8500_ext_regulator_disable ( struct regulator_dev * rdev )
2013-03-28 20:11:01 +04:00
{
int ret ;
struct ab8500_ext_regulator_info * info = rdev_get_drvdata ( rdev ) ;
2013-03-28 20:11:06 +04:00
u8 regval ;
2013-03-28 20:11:01 +04:00
if ( info = = NULL ) {
dev_err ( rdev_get_dev ( rdev ) , " regulator info null pointer \n " ) ;
return - EINVAL ;
}
2013-03-28 20:11:06 +04:00
/*
* Set the regulator in HW request mode if configured
*/
if ( info - > cfg & & info - > cfg - > hwreq )
2013-04-16 19:33:00 +04:00
regval = info - > update_val_hw ;
else
regval = 0 ;
2013-03-28 20:11:06 +04:00
2013-03-28 20:11:01 +04:00
ret = abx500_mask_and_set_register_interruptible ( info - > dev ,
info - > update_bank , info - > update_reg ,
2013-04-16 19:33:00 +04:00
info - > update_mask , regval ) ;
2013-04-02 16:56:16 +04:00
if ( ret < 0 ) {
2013-03-28 20:11:01 +04:00
dev_err ( rdev_get_dev ( info - > rdev ) ,
" couldn't set disable bits for regulator \n " ) ;
2013-04-02 16:56:16 +04:00
return ret ;
}
2013-03-28 20:11:01 +04:00
dev_dbg ( rdev_get_dev ( rdev ) , " %s-disable (bank, reg, mask, value): "
" 0x%02x, 0x%02x, 0x%02x, 0x%02x \n " ,
info - > desc . name , info - > update_bank , info - > update_reg ,
2013-03-28 20:11:06 +04:00
info - > update_mask , regval ) ;
2013-03-28 20:11:01 +04:00
2013-04-16 19:33:00 +04:00
return 0 ;
2013-03-28 20:11:01 +04:00
}
static int ab8500_ext_regulator_is_enabled ( struct regulator_dev * rdev )
{
int ret ;
struct ab8500_ext_regulator_info * info = rdev_get_drvdata ( rdev ) ;
u8 regval ;
if ( info = = NULL ) {
dev_err ( rdev_get_dev ( rdev ) , " regulator info null pointer \n " ) ;
return - EINVAL ;
}
ret = abx500_get_register_interruptible ( info - > dev ,
info - > update_bank , info - > update_reg , & regval ) ;
if ( ret < 0 ) {
dev_err ( rdev_get_dev ( rdev ) ,
" couldn't read 0x%x register \n " , info - > update_reg ) ;
return ret ;
}
dev_dbg ( rdev_get_dev ( rdev ) , " %s-is_enabled (bank, reg, mask, value): "
" 0x%02x, 0x%02x, 0x%02x, 0x%02x \n " ,
info - > desc . name , info - > update_bank , info - > update_reg ,
info - > update_mask , regval ) ;
2013-03-28 20:11:06 +04:00
if ( ( ( regval & info - > update_mask ) = = info - > update_val_lp ) | |
( ( regval & info - > update_mask ) = = info - > update_val_hp ) )
2013-04-07 19:13:39 +04:00
return 1 ;
2013-03-28 20:11:01 +04:00
else
2013-04-07 19:13:39 +04:00
return 0 ;
2013-03-28 20:11:01 +04:00
}
static int ab8500_ext_regulator_set_mode ( struct regulator_dev * rdev ,
unsigned int mode )
{
int ret = 0 ;
struct ab8500_ext_regulator_info * info = rdev_get_drvdata ( rdev ) ;
2013-04-16 19:29:12 +04:00
u8 regval ;
2013-03-28 20:11:01 +04:00
if ( info = = NULL ) {
dev_err ( rdev_get_dev ( rdev ) , " regulator info null pointer \n " ) ;
return - EINVAL ;
}
switch ( mode ) {
case REGULATOR_MODE_NORMAL :
2013-04-16 19:29:12 +04:00
regval = info - > update_val_hp ;
2013-03-28 20:11:01 +04:00
break ;
case REGULATOR_MODE_IDLE :
2013-04-16 19:29:12 +04:00
regval = info - > update_val_lp ;
2013-03-28 20:11:01 +04:00
break ;
default :
return - EINVAL ;
}
2013-04-16 19:29:12 +04:00
/* If regulator is enabled and info->cfg->hwreq is set, the regulator
must be on in high power , so we don ' t need to write the register with
the same value .
*/
if ( ab8500_ext_regulator_is_enabled ( rdev ) & &
! ( info - > cfg & & info - > cfg - > hwreq ) ) {
ret = abx500_mask_and_set_register_interruptible ( info - > dev ,
info - > update_bank , info - > update_reg ,
info - > update_mask , regval ) ;
if ( ret < 0 ) {
2013-03-28 20:11:01 +04:00
dev_err ( rdev_get_dev ( rdev ) ,
" Could not set regulator mode. \n " ) ;
2013-04-16 19:29:12 +04:00
return ret ;
}
2013-03-28 20:11:01 +04:00
dev_dbg ( rdev_get_dev ( rdev ) ,
" %s-set_mode (bank, reg, mask, value): "
" 0x%x, 0x%x, 0x%x, 0x%x \n " ,
info - > desc . name , info - > update_bank , info - > update_reg ,
info - > update_mask , regval ) ;
}
2013-04-16 19:29:12 +04:00
info - > update_val = regval ;
return 0 ;
2013-03-28 20:11:01 +04:00
}
static unsigned int ab8500_ext_regulator_get_mode ( struct regulator_dev * rdev )
{
struct ab8500_ext_regulator_info * info = rdev_get_drvdata ( rdev ) ;
int ret ;
if ( info = = NULL ) {
dev_err ( rdev_get_dev ( rdev ) , " regulator info null pointer \n " ) ;
return - EINVAL ;
}
if ( info - > update_val = = info - > update_val_hp )
ret = REGULATOR_MODE_NORMAL ;
else if ( info - > update_val = = info - > update_val_lp )
ret = REGULATOR_MODE_IDLE ;
else
ret = - EINVAL ;
return ret ;
}
2013-06-07 20:11:25 +04:00
static int ab8500_ext_set_voltage ( struct regulator_dev * rdev , int min_uV ,
int max_uV , unsigned * selector )
{
struct regulation_constraints * regu_constraints = rdev - > constraints ;
if ( ! regu_constraints ) {
dev_err ( rdev_get_dev ( rdev ) , " No regulator constraints \n " ) ;
return - EINVAL ;
}
if ( regu_constraints - > min_uV = = min_uV & &
regu_constraints - > max_uV = = max_uV )
return 0 ;
dev_err ( rdev_get_dev ( rdev ) ,
" Requested min %duV max %duV != constrained min %duV max %duV \n " ,
min_uV , max_uV ,
regu_constraints - > min_uV , regu_constraints - > max_uV ) ;
return - EINVAL ;
}
2013-03-28 20:11:01 +04:00
static int ab8500_ext_list_voltage ( struct regulator_dev * rdev ,
unsigned selector )
{
struct regulation_constraints * regu_constraints = rdev - > constraints ;
if ( regu_constraints = = NULL ) {
dev_err ( rdev_get_dev ( rdev ) , " regulator constraints null pointer \n " ) ;
return - EINVAL ;
}
/* return the uV for the fixed regulators */
if ( regu_constraints - > min_uV & & regu_constraints - > max_uV ) {
if ( regu_constraints - > min_uV = = regu_constraints - > max_uV )
return regu_constraints - > min_uV ;
}
return - EINVAL ;
}
static struct regulator_ops ab8500_ext_regulator_ops = {
. enable = ab8500_ext_regulator_enable ,
. disable = ab8500_ext_regulator_disable ,
. is_enabled = ab8500_ext_regulator_is_enabled ,
. set_mode = ab8500_ext_regulator_set_mode ,
. get_mode = ab8500_ext_regulator_get_mode ,
2013-06-07 20:11:25 +04:00
. set_voltage = ab8500_ext_set_voltage ,
2013-03-28 20:11:01 +04:00
. list_voltage = ab8500_ext_list_voltage ,
} ;
static struct ab8500_ext_regulator_info
ab8500_ext_regulator_info [ AB8500_NUM_EXT_REGULATORS ] = {
[ AB8500_EXT_SUPPLY1 ] = {
. desc = {
. name = " VEXTSUPPLY1 " ,
. ops = & ab8500_ext_regulator_ops ,
. type = REGULATOR_VOLTAGE ,
. id = AB8500_EXT_SUPPLY1 ,
. owner = THIS_MODULE ,
. n_voltages = 1 ,
} ,
. update_bank = 0x04 ,
. update_reg = 0x08 ,
. update_mask = 0x03 ,
. update_val = 0x01 ,
. update_val_hp = 0x01 ,
. update_val_lp = 0x03 ,
. update_val_hw = 0x02 ,
} ,
[ AB8500_EXT_SUPPLY2 ] = {
. desc = {
. name = " VEXTSUPPLY2 " ,
. ops = & ab8500_ext_regulator_ops ,
. type = REGULATOR_VOLTAGE ,
. id = AB8500_EXT_SUPPLY2 ,
. owner = THIS_MODULE ,
. n_voltages = 1 ,
} ,
. update_bank = 0x04 ,
. update_reg = 0x08 ,
. update_mask = 0x0c ,
. update_val = 0x04 ,
. update_val_hp = 0x04 ,
. update_val_lp = 0x0c ,
. update_val_hw = 0x08 ,
} ,
[ AB8500_EXT_SUPPLY3 ] = {
. desc = {
. name = " VEXTSUPPLY3 " ,
. ops = & ab8500_ext_regulator_ops ,
. type = REGULATOR_VOLTAGE ,
. id = AB8500_EXT_SUPPLY3 ,
. owner = THIS_MODULE ,
. n_voltages = 1 ,
} ,
. update_bank = 0x04 ,
. update_reg = 0x08 ,
. update_mask = 0x30 ,
. update_val = 0x10 ,
2013-03-28 20:11:06 +04:00
. update_val_hp = 0x10 ,
. update_val_lp = 0x30 ,
. update_val_hw = 0x20 ,
2013-03-28 20:11:01 +04:00
} ,
} ;
2013-06-07 20:11:27 +04:00
static struct of_regulator_match ab8500_ext_regulator_match [ ] = {
{ . name = " ab8500_ext1 " , . driver_data = ( void * ) AB8500_EXT_SUPPLY1 , } ,
{ . name = " ab8500_ext2 " , . driver_data = ( void * ) AB8500_EXT_SUPPLY2 , } ,
{ . name = " ab8500_ext3 " , . driver_data = ( void * ) AB8500_EXT_SUPPLY3 , } ,
} ;
2013-06-26 08:43:37 +04:00
static int ab8500_ext_regulator_probe ( struct platform_device * pdev )
2013-03-28 20:11:01 +04:00
{
struct ab8500 * ab8500 = dev_get_drvdata ( pdev - > dev . parent ) ;
struct ab8500_platform_data * ppdata ;
struct ab8500_regulator_platform_data * pdata ;
2013-06-07 20:11:27 +04:00
struct device_node * np = pdev - > dev . of_node ;
2013-03-28 20:11:01 +04:00
struct regulator_config config = { } ;
int i , err ;
2013-06-07 20:11:27 +04:00
if ( np ) {
err = of_regulator_match ( & pdev - > dev , np ,
ab8500_ext_regulator_match ,
ARRAY_SIZE ( ab8500_ext_regulator_match ) ) ;
if ( err < 0 ) {
dev_err ( & pdev - > dev ,
" Error parsing regulator init data: %d \n " , err ) ;
return err ;
}
}
2013-03-28 20:11:01 +04:00
if ( ! ab8500 ) {
dev_err ( & pdev - > dev , " null mfd parent \n " ) ;
return - EINVAL ;
}
2013-06-07 20:11:27 +04:00
2013-03-28 20:11:01 +04:00
ppdata = dev_get_platdata ( ab8500 - > dev ) ;
if ( ! ppdata ) {
dev_err ( & pdev - > dev , " null parent pdata \n " ) ;
return - EINVAL ;
}
pdata = ppdata - > regulator ;
if ( ! pdata ) {
dev_err ( & pdev - > dev , " null pdata \n " ) ;
return - EINVAL ;
}
/* make sure the platform data has the correct size */
if ( pdata - > num_ext_regulator ! = ARRAY_SIZE ( ab8500_ext_regulator_info ) ) {
dev_err ( & pdev - > dev , " Configuration error: size mismatch. \n " ) ;
return - EINVAL ;
}
/* check for AB8500 2.x */
2013-03-28 20:11:13 +04:00
if ( is_ab8500_2p0_or_earlier ( ab8500 ) ) {
2013-03-28 20:11:01 +04:00
struct ab8500_ext_regulator_info * info ;
/* VextSupply3LPn is inverted on AB8500 2.x */
info = & ab8500_ext_regulator_info [ AB8500_EXT_SUPPLY3 ] ;
info - > update_val = 0x30 ;
2013-03-28 20:11:06 +04:00
info - > update_val_hp = 0x30 ;
info - > update_val_lp = 0x10 ;
2013-03-28 20:11:01 +04:00
}
/* register all regulators */
for ( i = 0 ; i < ARRAY_SIZE ( ab8500_ext_regulator_info ) ; i + + ) {
struct ab8500_ext_regulator_info * info = NULL ;
/* assign per-regulator data */
info = & ab8500_ext_regulator_info [ i ] ;
info - > dev = & pdev - > dev ;
2013-03-28 20:11:06 +04:00
info - > cfg = ( struct ab8500_ext_regulator_cfg * )
pdata - > ext_regulator [ i ] . driver_data ;
2013-03-28 20:11:01 +04:00
config . dev = & pdev - > dev ;
config . driver_data = info ;
2013-06-07 20:11:27 +04:00
config . of_node = ab8500_ext_regulator_match [ i ] . of_node ;
config . init_data = ( np ) ?
ab8500_ext_regulator_match [ i ] . init_data :
& pdata - > ext_regulator [ i ] ;
2013-03-28 20:11:01 +04:00
/* register regulator with framework */
2013-09-30 04:52:37 +04:00
info - > rdev = devm_regulator_register ( & pdev - > dev , & info - > desc ,
& config ) ;
2013-03-28 20:11:01 +04:00
if ( IS_ERR ( info - > rdev ) ) {
err = PTR_ERR ( info - > rdev ) ;
dev_err ( & pdev - > dev , " failed to register regulator %s \n " ,
info - > desc . name ) ;
return err ;
}
dev_dbg ( rdev_get_dev ( info - > rdev ) ,
" %s-probed \n " , info - > desc . name ) ;
}
return 0 ;
}
2013-06-07 20:11:26 +04:00
static struct platform_driver ab8500_ext_regulator_driver = {
. probe = ab8500_ext_regulator_probe ,
. driver = {
. name = " ab8500-ext-regulator " ,
} ,
} ;
static int __init ab8500_ext_regulator_init ( void )
{
int ret ;
ret = platform_driver_register ( & ab8500_ext_regulator_driver ) ;
if ( ret )
pr_err ( " Failed to register ab8500 ext regulator: %d \n " , ret ) ;
return ret ;
}
subsys_initcall ( ab8500_ext_regulator_init ) ;
static void __exit ab8500_ext_regulator_exit ( void )
{
platform_driver_unregister ( & ab8500_ext_regulator_driver ) ;
2013-03-28 20:11:01 +04:00
}
2013-06-07 20:11:26 +04:00
module_exit ( ab8500_ext_regulator_exit ) ;
2013-03-28 20:11:01 +04:00
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_AUTHOR ( " Bengt Jonsson <bengt.g.jonsson@stericsson.com> " ) ;
MODULE_DESCRIPTION ( " AB8500 external regulator driver " ) ;
MODULE_ALIAS ( " platform:ab8500-ext-regulator " ) ;