2010-08-20 09:43:56 +04:00
/*
* max8952 . c - Voltage and current regulation for the Maxim 8952
*
* Copyright ( C ) 2010 Samsung Electronics
* MyungJoo Ham < myungjoo . ham @ samsung . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* 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 . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/i2c.h>
# include <linux/err.h>
# include <linux/platform_device.h>
# include <linux/regulator/driver.h>
# include <linux/regulator/max8952.h>
# include <linux/gpio.h>
# include <linux/io.h>
2013-04-04 20:17:20 +04:00
# include <linux/of.h>
# include <linux/of_gpio.h>
# include <linux/regulator/of_regulator.h>
2010-08-20 09:43:56 +04:00
# include <linux/slab.h>
/* Registers */
enum {
MAX8952_REG_MODE0 ,
MAX8952_REG_MODE1 ,
MAX8952_REG_MODE2 ,
MAX8952_REG_MODE3 ,
MAX8952_REG_CONTROL ,
MAX8952_REG_SYNC ,
MAX8952_REG_RAMP ,
MAX8952_REG_CHIP_ID1 ,
MAX8952_REG_CHIP_ID2 ,
} ;
struct max8952_data {
struct i2c_client * client ;
struct max8952_platform_data * pdata ;
bool vid0 ;
bool vid1 ;
} ;
static int max8952_read_reg ( struct max8952_data * max8952 , u8 reg )
{
int ret = i2c_smbus_read_byte_data ( max8952 - > client , reg ) ;
2014-03-18 14:23:04 +04:00
2010-08-20 09:43:56 +04:00
if ( ret > 0 )
ret & = 0xff ;
return ret ;
}
static int max8952_write_reg ( struct max8952_data * max8952 ,
u8 reg , u8 value )
{
return i2c_smbus_write_byte_data ( max8952 - > client , reg , value ) ;
}
static int max8952_list_voltage ( struct regulator_dev * rdev ,
unsigned int selector )
{
struct max8952_data * max8952 = rdev_get_drvdata ( rdev ) ;
if ( rdev_get_id ( rdev ) ! = 0 )
return - EINVAL ;
2012-04-20 14:36:14 +04:00
return ( max8952 - > pdata - > dvs_mode [ selector ] * 10 + 770 ) * 1000 ;
2010-08-20 09:43:56 +04:00
}
2012-04-20 14:36:14 +04:00
static int max8952_get_voltage_sel ( struct regulator_dev * rdev )
2010-08-20 09:43:56 +04:00
{
struct max8952_data * max8952 = rdev_get_drvdata ( rdev ) ;
u8 vid = 0 ;
if ( max8952 - > vid0 )
vid + = 1 ;
if ( max8952 - > vid1 )
vid + = 2 ;
2012-04-20 14:36:14 +04:00
return vid ;
2010-08-20 09:43:56 +04:00
}
2012-03-26 05:20:58 +04:00
static int max8952_set_voltage_sel ( struct regulator_dev * rdev ,
unsigned selector )
2010-08-20 09:43:56 +04:00
{
struct max8952_data * max8952 = rdev_get_drvdata ( rdev ) ;
if ( ! gpio_is_valid ( max8952 - > pdata - > gpio_vid0 ) | |
2011-06-15 12:54:12 +04:00
! gpio_is_valid ( max8952 - > pdata - > gpio_vid1 ) ) {
2010-08-20 09:43:56 +04:00
/* DVS not supported */
return - EPERM ;
}
2012-03-26 05:20:58 +04:00
max8952 - > vid0 = selector & 0x1 ;
max8952 - > vid1 = ( selector > > 1 ) & 0x1 ;
gpio_set_value ( max8952 - > pdata - > gpio_vid0 , max8952 - > vid0 ) ;
gpio_set_value ( max8952 - > pdata - > gpio_vid1 , max8952 - > vid1 ) ;
2010-08-20 09:43:56 +04:00
return 0 ;
}
2017-01-28 17:51:04 +03:00
static const struct regulator_ops max8952_ops = {
2010-08-20 09:43:56 +04:00
. list_voltage = max8952_list_voltage ,
2012-04-20 14:36:14 +04:00
. get_voltage_sel = max8952_get_voltage_sel ,
2012-03-26 05:20:58 +04:00
. set_voltage_sel = max8952_set_voltage_sel ,
2010-08-20 09:43:56 +04:00
} ;
2012-04-06 04:29:49 +04:00
static const struct regulator_desc regulator = {
2010-08-20 09:43:56 +04:00
. name = " MAX8952_VOUT " ,
. id = 0 ,
. n_voltages = MAX8952_NUM_DVS_MODE ,
. ops = & max8952_ops ,
. type = REGULATOR_VOLTAGE ,
. owner = THIS_MODULE ,
} ;
2013-04-04 20:17:20 +04:00
# ifdef CONFIG_OF
2014-05-07 12:06:34 +04:00
static const struct of_device_id max8952_dt_match [ ] = {
2013-04-04 20:17:20 +04:00
{ . compatible = " maxim,max8952 " } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , max8952_dt_match ) ;
static struct max8952_platform_data * max8952_parse_dt ( struct device * dev )
{
struct max8952_platform_data * pd ;
struct device_node * np = dev - > of_node ;
int ret ;
int i ;
pd = devm_kzalloc ( dev , sizeof ( * pd ) , GFP_KERNEL ) ;
2014-02-20 12:53:08 +04:00
if ( ! pd )
2013-04-04 20:17:20 +04:00
return NULL ;
pd - > gpio_vid0 = of_get_named_gpio ( np , " max8952,vid-gpios " , 0 ) ;
pd - > gpio_vid1 = of_get_named_gpio ( np , " max8952,vid-gpios " , 1 ) ;
pd - > gpio_en = of_get_named_gpio ( np , " max8952,en-gpio " , 0 ) ;
if ( of_property_read_u32 ( np , " max8952,default-mode " , & pd - > default_mode ) )
dev_warn ( dev , " Default mode not specified, assuming 0 \n " ) ;
ret = of_property_read_u32_array ( np , " max8952,dvs-mode-microvolt " ,
pd - > dvs_mode , ARRAY_SIZE ( pd - > dvs_mode ) ) ;
if ( ret ) {
dev_err ( dev , " max8952,dvs-mode-microvolt property not specified " ) ;
return NULL ;
}
for ( i = 0 ; i < ARRAY_SIZE ( pd - > dvs_mode ) ; + + i ) {
if ( pd - > dvs_mode [ i ] < 770000 | | pd - > dvs_mode [ i ] > 1400000 ) {
dev_err ( dev , " DVS voltage %d out of range \n " , i ) ;
return NULL ;
}
pd - > dvs_mode [ i ] = ( pd - > dvs_mode [ i ] - 770000 ) / 10000 ;
}
if ( of_property_read_u32 ( np , " max8952,sync-freq " , & pd - > sync_freq ) )
dev_warn ( dev , " max8952,sync-freq property not specified, defaulting to 26MHz \n " ) ;
if ( of_property_read_u32 ( np , " max8952,ramp-speed " , & pd - > ramp_speed ) )
dev_warn ( dev , " max8952,ramp-speed property not specified, defaulting to 32mV/us \n " ) ;
2014-11-10 16:43:53 +03:00
pd - > reg_data = of_get_regulator_init_data ( dev , np , & regulator ) ;
2013-04-04 20:17:20 +04:00
if ( ! pd - > reg_data ) {
dev_err ( dev , " Failed to parse regulator init data \n " ) ;
return NULL ;
}
return pd ;
}
# else
static struct max8952_platform_data * max8952_parse_dt ( struct device * dev )
{
return NULL ;
}
# endif
2012-11-19 22:22:22 +04:00
static int max8952_pmic_probe ( struct i2c_client * client ,
2010-08-20 09:43:56 +04:00
const struct i2c_device_id * i2c_id )
{
struct i2c_adapter * adapter = to_i2c_adapter ( client - > dev . parent ) ;
2013-07-30 12:20:47 +04:00
struct max8952_platform_data * pdata = dev_get_platdata ( & client - > dev ) ;
2012-04-04 03:50:22 +04:00
struct regulator_config config = { } ;
2010-08-20 09:43:56 +04:00
struct max8952_data * max8952 ;
2014-03-10 12:32:50 +04:00
struct regulator_dev * rdev ;
2010-08-20 09:43:56 +04:00
int ret = 0 , err = 0 ;
2013-04-04 20:17:20 +04:00
if ( client - > dev . of_node )
pdata = max8952_parse_dt ( & client - > dev ) ;
2010-08-20 09:43:56 +04:00
if ( ! pdata ) {
dev_err ( & client - > dev , " Require the platform data \n " ) ;
return - EINVAL ;
}
if ( ! i2c_check_functionality ( adapter , I2C_FUNC_SMBUS_BYTE ) )
return - EIO ;
2012-05-16 08:50:47 +04:00
max8952 = devm_kzalloc ( & client - > dev , sizeof ( struct max8952_data ) ,
GFP_KERNEL ) ;
2010-08-20 09:43:56 +04:00
if ( ! max8952 )
return - ENOMEM ;
max8952 - > client = client ;
max8952 - > pdata = pdata ;
2014-03-10 12:32:50 +04:00
config . dev = & client - > dev ;
2013-04-04 20:17:19 +04:00
config . init_data = pdata - > reg_data ;
2012-04-04 03:50:22 +04:00
config . driver_data = max8952 ;
2013-04-25 18:15:21 +04:00
config . of_node = client - > dev . of_node ;
2012-04-04 03:50:22 +04:00
2012-07-10 02:10:12 +04:00
config . ena_gpio = pdata - > gpio_en ;
2014-11-03 21:12:04 +03:00
if ( client - > dev . of_node )
config . ena_gpio_initialized = true ;
2013-04-04 20:17:19 +04:00
if ( pdata - > reg_data - > constraints . boot_on )
2012-07-10 02:10:12 +04:00
config . ena_gpio_flags | = GPIOF_OUT_INIT_HIGH ;
2014-03-10 12:32:50 +04:00
rdev = devm_regulator_register ( & client - > dev , & regulator , & config ) ;
if ( IS_ERR ( rdev ) ) {
ret = PTR_ERR ( rdev ) ;
dev_err ( & client - > dev , " regulator init failed (%d) \n " , ret ) ;
2012-05-16 08:50:47 +04:00
return ret ;
2010-10-25 06:11:07 +04:00
}
2010-08-20 09:43:56 +04:00
2012-03-15 04:47:48 +04:00
max8952 - > vid0 = pdata - > default_mode & 0x1 ;
max8952 - > vid1 = ( pdata - > default_mode > > 1 ) & 0x1 ;
2010-08-20 09:43:56 +04:00
if ( gpio_is_valid ( pdata - > gpio_vid0 ) & &
gpio_is_valid ( pdata - > gpio_vid1 ) ) {
2014-06-16 06:12:25 +04:00
unsigned long gpio_flags ;
gpio_flags = max8952 - > vid0 ?
GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW ;
if ( devm_gpio_request_one ( & client - > dev , pdata - > gpio_vid0 ,
gpio_flags , " MAX8952 VID0 " ) )
2010-08-20 09:43:56 +04:00
err = 1 ;
2014-06-16 06:12:25 +04:00
gpio_flags = max8952 - > vid1 ?
GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW ;
if ( devm_gpio_request_one ( & client - > dev , pdata - > gpio_vid1 ,
gpio_flags , " MAX8952 VID1 " ) )
2010-08-20 09:43:56 +04:00
err = 2 ;
} else
err = 3 ;
if ( err ) {
2014-03-10 12:32:50 +04:00
dev_warn ( & client - > dev , " VID0/1 gpio invalid: "
2011-03-31 05:57:33 +04:00
" DVS not available. \n " ) ;
2010-08-20 09:43:56 +04:00
max8952 - > vid0 = 0 ;
max8952 - > vid1 = 0 ;
/* Mark invalid */
pdata - > gpio_vid0 = - 1 ;
pdata - > gpio_vid1 = - 1 ;
/* Disable Pulldown of EN only */
max8952_write_reg ( max8952 , MAX8952_REG_CONTROL , 0x60 ) ;
2014-03-10 12:32:50 +04:00
dev_err ( & client - > dev , " DVS modes disabled because VID0 and VID1 "
2010-08-20 09:43:56 +04:00
" do not have proper controls. \n " ) ;
} else {
/*
* Disable Pulldown on EN , VID0 , VID1 to reduce
* leakage current of MAX8952 assuming that MAX8952
* is turned on ( EN = = 1 ) . Note that without having VID0 / 1
* properly connected , turning pulldown off can be
* problematic . Thus , turn this off only when they are
* controllable by GPIO .
*/
max8952_write_reg ( max8952 , MAX8952_REG_CONTROL , 0x0 ) ;
}
max8952_write_reg ( max8952 , MAX8952_REG_MODE0 ,
( max8952_read_reg ( max8952 ,
MAX8952_REG_MODE0 ) & 0xC0 ) |
( pdata - > dvs_mode [ 0 ] & 0x3F ) ) ;
max8952_write_reg ( max8952 , MAX8952_REG_MODE1 ,
( max8952_read_reg ( max8952 ,
MAX8952_REG_MODE1 ) & 0xC0 ) |
( pdata - > dvs_mode [ 1 ] & 0x3F ) ) ;
max8952_write_reg ( max8952 , MAX8952_REG_MODE2 ,
( max8952_read_reg ( max8952 ,
MAX8952_REG_MODE2 ) & 0xC0 ) |
( pdata - > dvs_mode [ 2 ] & 0x3F ) ) ;
max8952_write_reg ( max8952 , MAX8952_REG_MODE3 ,
( max8952_read_reg ( max8952 ,
MAX8952_REG_MODE3 ) & 0xC0 ) |
( pdata - > dvs_mode [ 3 ] & 0x3F ) ) ;
max8952_write_reg ( max8952 , MAX8952_REG_SYNC ,
( max8952_read_reg ( max8952 , MAX8952_REG_SYNC ) & 0x3F ) |
( ( pdata - > sync_freq & 0x3 ) < < 6 ) ) ;
max8952_write_reg ( max8952 , MAX8952_REG_RAMP ,
( max8952_read_reg ( max8952 , MAX8952_REG_RAMP ) & 0x1F ) |
( ( pdata - > ramp_speed & 0x7 ) < < 5 ) ) ;
i2c_set_clientdata ( client , max8952 ) ;
2010-10-25 06:11:07 +04:00
return 0 ;
2010-08-20 09:43:56 +04:00
}
static const struct i2c_device_id max8952_ids [ ] = {
{ " max8952 " , 0 } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( i2c , max8952_ids ) ;
static struct i2c_driver max8952_pmic_driver = {
. probe = max8952_pmic_probe ,
. driver = {
. name = " max8952 " ,
2013-04-04 20:17:20 +04:00
. of_match_table = of_match_ptr ( max8952_dt_match ) ,
2010-08-20 09:43:56 +04:00
} ,
. id_table = max8952_ids ,
} ;
static int __init max8952_pmic_init ( void )
{
return i2c_add_driver ( & max8952_pmic_driver ) ;
}
subsys_initcall ( max8952_pmic_init ) ;
static void __exit max8952_pmic_exit ( void )
{
i2c_del_driver ( & max8952_pmic_driver ) ;
}
module_exit ( max8952_pmic_exit ) ;
MODULE_DESCRIPTION ( " MAXIM 8952 voltage regulator driver " ) ;
MODULE_AUTHOR ( " MyungJoo Ham <myungjoo.ham@samsung.com> " ) ;
MODULE_LICENSE ( " GPL " ) ;