2011-07-04 12:43:42 +04:00
/*
* linux / drivers / regulator / aat2870 - regulator . c
*
* Copyright ( c ) 2011 , NVIDIA Corporation .
* Author : Jin Park < jinyoungp @ nvidia . 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 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 .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA
* 02110 - 1301 USA
*/
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/err.h>
2011-07-30 08:13:09 +04:00
# include <linux/module.h>
2011-07-04 12:43:42 +04:00
# include <linux/slab.h>
# include <linux/delay.h>
# include <linux/platform_device.h>
# include <linux/regulator/driver.h>
# include <linux/regulator/machine.h>
# include <linux/mfd/aat2870.h>
struct aat2870_regulator {
2012-03-02 05:28:44 +04:00
struct aat2870_data * aat2870 ;
2011-07-04 12:43:42 +04:00
struct regulator_desc desc ;
const int * voltages ; /* uV */
int min_uV ;
int max_uV ;
u8 enable_addr ;
u8 enable_shift ;
u8 enable_mask ;
u8 voltage_addr ;
u8 voltage_shift ;
u8 voltage_mask ;
} ;
static int aat2870_ldo_list_voltage ( struct regulator_dev * rdev ,
unsigned selector )
{
struct aat2870_regulator * ri = rdev_get_drvdata ( rdev ) ;
return ri - > voltages [ selector ] ;
}
static int aat2870_ldo_set_voltage_sel ( struct regulator_dev * rdev ,
unsigned selector )
{
struct aat2870_regulator * ri = rdev_get_drvdata ( rdev ) ;
2012-03-02 05:28:44 +04:00
struct aat2870_data * aat2870 = ri - > aat2870 ;
2011-07-04 12:43:42 +04:00
return aat2870 - > update ( aat2870 , ri - > voltage_addr , ri - > voltage_mask ,
2011-11-28 10:07:48 +04:00
selector < < ri - > voltage_shift ) ;
2011-07-04 12:43:42 +04:00
}
static int aat2870_ldo_get_voltage_sel ( struct regulator_dev * rdev )
{
struct aat2870_regulator * ri = rdev_get_drvdata ( rdev ) ;
2012-03-02 05:28:44 +04:00
struct aat2870_data * aat2870 = ri - > aat2870 ;
2011-07-04 12:43:42 +04:00
u8 val ;
int ret ;
ret = aat2870 - > read ( aat2870 , ri - > voltage_addr , & val ) ;
if ( ret )
return ret ;
return ( val & ri - > voltage_mask ) > > ri - > voltage_shift ;
}
static int aat2870_ldo_enable ( struct regulator_dev * rdev )
{
struct aat2870_regulator * ri = rdev_get_drvdata ( rdev ) ;
2012-03-02 05:28:44 +04:00
struct aat2870_data * aat2870 = ri - > aat2870 ;
2011-07-04 12:43:42 +04:00
return aat2870 - > update ( aat2870 , ri - > enable_addr , ri - > enable_mask ,
ri - > enable_mask ) ;
}
static int aat2870_ldo_disable ( struct regulator_dev * rdev )
{
struct aat2870_regulator * ri = rdev_get_drvdata ( rdev ) ;
2012-03-02 05:28:44 +04:00
struct aat2870_data * aat2870 = ri - > aat2870 ;
2011-07-04 12:43:42 +04:00
return aat2870 - > update ( aat2870 , ri - > enable_addr , ri - > enable_mask , 0 ) ;
}
static int aat2870_ldo_is_enabled ( struct regulator_dev * rdev )
{
struct aat2870_regulator * ri = rdev_get_drvdata ( rdev ) ;
2012-03-02 05:28:44 +04:00
struct aat2870_data * aat2870 = ri - > aat2870 ;
2011-07-04 12:43:42 +04:00
u8 val ;
int ret ;
ret = aat2870 - > read ( aat2870 , ri - > enable_addr , & val ) ;
if ( ret )
return ret ;
return val & ri - > enable_mask ? 1 : 0 ;
}
static struct regulator_ops aat2870_ldo_ops = {
. list_voltage = aat2870_ldo_list_voltage ,
. set_voltage_sel = aat2870_ldo_set_voltage_sel ,
. get_voltage_sel = aat2870_ldo_get_voltage_sel ,
. enable = aat2870_ldo_enable ,
. disable = aat2870_ldo_disable ,
. is_enabled = aat2870_ldo_is_enabled ,
} ;
static const int aat2870_ldo_voltages [ ] = {
1200000 , 1300000 , 1500000 , 1600000 ,
1800000 , 2000000 , 2200000 , 2500000 ,
2600000 , 2700000 , 2800000 , 2900000 ,
3000000 , 3100000 , 3200000 , 3300000 ,
} ;
# define AAT2870_LDO(ids) \
{ \
. desc = { \
. name = # ids , \
. id = AAT2870_ID_ # # ids , \
. n_voltages = ARRAY_SIZE ( aat2870_ldo_voltages ) , \
. ops = & aat2870_ldo_ops , \
. type = REGULATOR_VOLTAGE , \
. owner = THIS_MODULE , \
} , \
. voltages = aat2870_ldo_voltages , \
. min_uV = 1200000 , \
. max_uV = 3300000 , \
}
static struct aat2870_regulator aat2870_regulators [ ] = {
AAT2870_LDO ( LDOA ) ,
AAT2870_LDO ( LDOB ) ,
AAT2870_LDO ( LDOC ) ,
AAT2870_LDO ( LDOD ) ,
} ;
static struct aat2870_regulator * aat2870_get_regulator ( int id )
{
struct aat2870_regulator * ri = NULL ;
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( aat2870_regulators ) ; i + + ) {
ri = & aat2870_regulators [ i ] ;
if ( ri - > desc . id = = id )
break ;
}
2011-11-28 10:06:31 +04:00
if ( i = = ARRAY_SIZE ( aat2870_regulators ) )
2011-07-04 12:43:42 +04:00
return NULL ;
ri - > enable_addr = AAT2870_LDO_EN ;
ri - > enable_shift = id - AAT2870_ID_LDOA ;
ri - > enable_mask = 0x1 < < ri - > enable_shift ;
ri - > voltage_addr = ( id - AAT2870_ID_LDOA ) / 2 ?
AAT2870_LDO_CD : AAT2870_LDO_AB ;
ri - > voltage_shift = ( id - AAT2870_ID_LDOA ) % 2 ? 0 : 4 ;
ri - > voltage_mask = 0xF < < ri - > voltage_shift ;
return ri ;
}
static int aat2870_regulator_probe ( struct platform_device * pdev )
{
struct aat2870_regulator * ri ;
struct regulator_dev * rdev ;
ri = aat2870_get_regulator ( pdev - > id ) ;
if ( ! ri ) {
dev_err ( & pdev - > dev , " Invalid device ID, %d \n " , pdev - > id ) ;
return - EINVAL ;
}
2012-03-02 05:28:44 +04:00
ri - > aat2870 = dev_get_drvdata ( pdev - > dev . parent ) ;
2011-07-04 12:43:42 +04:00
rdev = regulator_register ( & ri - > desc , & pdev - > dev ,
2011-11-18 15:17:19 +04:00
pdev - > dev . platform_data , ri , NULL ) ;
2011-07-04 12:43:42 +04: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 int __devexit aat2870_regulator_remove ( struct platform_device * pdev )
{
struct regulator_dev * rdev = platform_get_drvdata ( pdev ) ;
regulator_unregister ( rdev ) ;
return 0 ;
}
static struct platform_driver aat2870_regulator_driver = {
. driver = {
. name = " aat2870-regulator " ,
. owner = THIS_MODULE ,
} ,
. probe = aat2870_regulator_probe ,
. remove = __devexit_p ( aat2870_regulator_remove ) ,
} ;
static int __init aat2870_regulator_init ( void )
{
return platform_driver_register ( & aat2870_regulator_driver ) ;
}
subsys_initcall ( aat2870_regulator_init ) ;
static void __exit aat2870_regulator_exit ( void )
{
platform_driver_unregister ( & aat2870_regulator_driver ) ;
}
module_exit ( aat2870_regulator_exit ) ;
MODULE_DESCRIPTION ( " AnalogicTech AAT2870 Regulator " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Jin Park <jinyoungp@nvidia.com> " ) ;