2018-08-07 19:18:25 +03:00
// SPDX-License-Identifier: GPL-2.0+
//
// max77693.c - Regulator driver for the Maxim 77693 and 77843
//
// Copyright (C) 2013-2015 Samsung Electronics
// Jonghwa Lee <jonghwa3.lee@samsung.com>
// Krzysztof Kozlowski <krzk@kernel.org>
//
// This driver is based on max77686.c
2013-06-25 05:08:38 +04:00
# include <linux/err.h>
# include <linux/slab.h>
# include <linux/platform_device.h>
# include <linux/module.h>
# include <linux/export.h>
# include <linux/regulator/driver.h>
# include <linux/regulator/machine.h>
# include <linux/mfd/max77693.h>
2015-07-15 15:59:50 +03:00
# include <linux/mfd/max77693-common.h>
2013-06-25 05:08:38 +04:00
# include <linux/mfd/max77693-private.h>
2015-07-15 15:59:54 +03:00
# include <linux/mfd/max77843-private.h>
2013-06-25 05:08:38 +04:00
# include <linux/regulator/of_regulator.h>
2014-05-21 10:52:47 +04:00
# include <linux/regmap.h>
2013-06-25 05:08:38 +04:00
2015-07-15 15:59:54 +03:00
/*
* ID for MAX77843 regulators .
* There is no need for such for MAX77693 .
*/
enum max77843_regulator_type {
MAX77843_SAFEOUT1 = 0 ,
MAX77843_SAFEOUT2 ,
MAX77843_CHARGER ,
MAX77843_NUM ,
} ;
/* Register differences between chargers: MAX77693 and MAX77843 */
2015-07-15 15:59:49 +03:00
struct chg_reg_data {
unsigned int linear_reg ;
unsigned int linear_mask ;
unsigned int uA_step ;
unsigned int min_sel ;
} ;
2013-06-25 05:08:38 +04:00
/*
2015-07-15 15:59:54 +03:00
* MAX77693 CHARGER regulator - Min : 20 mA , Max : 2580 mA , step : 20 mA
2013-06-25 05:08:38 +04:00
* 0x00 , 0x01 , 0x2 , 0x03 = 60 mA
* 0x04 ~ 0x7E = ( 60 + ( X - 3 ) * 20 ) mA
2015-07-15 15:59:54 +03:00
* Actually for MAX77693 the driver manipulates the maximum input current ,
* not the fast charge current ( output ) . This should be fixed .
*
* On MAX77843 the calculation formula is the same ( except values ) .
* Fortunately it properly manipulates the fast charge current .
2013-06-25 05:08:38 +04:00
*/
static int max77693_chg_get_current_limit ( struct regulator_dev * rdev )
{
2015-07-15 15:59:49 +03:00
const struct chg_reg_data * reg_data = rdev_get_drvdata ( rdev ) ;
2013-06-25 05:08:38 +04:00
unsigned int chg_min_uA = rdev - > constraints - > min_uA ;
unsigned int chg_max_uA = rdev - > constraints - > max_uA ;
2014-05-21 10:52:47 +04:00
unsigned int reg , sel ;
2013-06-25 05:08:38 +04:00
unsigned int val ;
int ret ;
2015-07-15 15:59:49 +03:00
ret = regmap_read ( rdev - > regmap , reg_data - > linear_reg , & reg ) ;
2013-06-25 05:08:38 +04:00
if ( ret < 0 )
return ret ;
2015-07-15 15:59:49 +03:00
sel = reg & reg_data - > linear_mask ;
2013-06-25 05:08:38 +04:00
/* the first four codes for charger current are all 60mA */
2015-07-15 15:59:49 +03:00
if ( sel < = reg_data - > min_sel )
2013-06-25 05:08:38 +04:00
sel = 0 ;
else
2015-07-15 15:59:49 +03:00
sel - = reg_data - > min_sel ;
2013-06-25 05:08:38 +04:00
2015-07-15 15:59:49 +03:00
val = chg_min_uA + reg_data - > uA_step * sel ;
2013-06-25 05:08:38 +04:00
if ( val > chg_max_uA )
return - EINVAL ;
return val ;
}
static int max77693_chg_set_current_limit ( struct regulator_dev * rdev ,
int min_uA , int max_uA )
{
2015-07-15 15:59:49 +03:00
const struct chg_reg_data * reg_data = rdev_get_drvdata ( rdev ) ;
2013-06-25 05:08:38 +04:00
unsigned int chg_min_uA = rdev - > constraints - > min_uA ;
int sel = 0 ;
2015-07-15 15:59:49 +03:00
while ( chg_min_uA + reg_data - > uA_step * sel < min_uA )
2013-06-25 05:08:38 +04:00
sel + + ;
2015-07-15 15:59:49 +03:00
if ( chg_min_uA + reg_data - > uA_step * sel > max_uA )
2013-06-25 05:08:38 +04:00
return - EINVAL ;
/* the first four codes for charger current are all 60mA */
2015-07-15 15:59:49 +03:00
sel + = reg_data - > min_sel ;
2013-06-25 05:08:38 +04:00
2015-07-15 15:59:49 +03:00
return regmap_write ( rdev - > regmap , reg_data - > linear_reg , sel ) ;
2013-06-25 05:08:38 +04:00
}
/* end of CHARGER regulator ops */
2015-07-15 15:59:54 +03:00
/* Returns regmap suitable for given regulator on chosen device */
static struct regmap * max77693_get_regmap ( enum max77693_types type ,
struct max77693_dev * max77693 ,
int reg_id )
{
if ( type = = TYPE_MAX77693 )
return max77693 - > regmap ;
/* Else: TYPE_MAX77843 */
switch ( reg_id ) {
case MAX77843_SAFEOUT1 :
case MAX77843_SAFEOUT2 :
return max77693 - > regmap ;
case MAX77843_CHARGER :
return max77693 - > regmap_chg ;
default :
return max77693 - > regmap ;
}
}
2013-06-25 05:08:38 +04:00
static const unsigned int max77693_safeout_table [ ] = {
4850000 ,
4900000 ,
4950000 ,
3300000 ,
} ;
2017-01-28 17:24:09 +03:00
static const struct regulator_ops max77693_safeout_ops = {
2013-06-25 05:08:38 +04:00
. list_voltage = regulator_list_voltage_table ,
. is_enabled = regulator_is_enabled_regmap ,
. enable = regulator_enable_regmap ,
. disable = regulator_disable_regmap ,
. get_voltage_sel = regulator_get_voltage_sel_regmap ,
. set_voltage_sel = regulator_set_voltage_sel_regmap ,
} ;
2017-03-11 22:01:19 +03:00
static const struct regulator_ops max77693_charger_ops = {
2015-04-29 13:58:28 +03:00
. is_enabled = regulator_is_enabled_regmap ,
2013-06-25 05:08:38 +04:00
. enable = regulator_enable_regmap ,
. disable = regulator_disable_regmap ,
. get_current_limit = max77693_chg_get_current_limit ,
. set_current_limit = max77693_chg_set_current_limit ,
} ;
2015-07-15 15:59:54 +03:00
# define max77693_regulator_desc_esafeout(_num) { \
2013-06-25 05:08:38 +04:00
. name = " ESAFEOUT " # _num , \
. id = MAX77693_ESAFEOUT # # _num , \
2015-03-26 13:35:58 +03:00
. of_match = of_match_ptr ( " ESAFEOUT " # _num ) , \
. regulators_node = of_match_ptr ( " regulators " ) , \
2013-06-25 05:08:38 +04:00
. n_voltages = 4 , \
. ops = & max77693_safeout_ops , \
. type = REGULATOR_VOLTAGE , \
2013-12-24 17:37:50 +04:00
. owner = THIS_MODULE , \
2013-06-25 05:08:38 +04:00
. volt_table = max77693_safeout_table , \
. vsel_reg = MAX77693_CHG_REG_SAFEOUT_CTRL , \
. vsel_mask = SAFEOUT_CTRL_SAFEOUT # # _num # # _MASK , \
. enable_reg = MAX77693_CHG_REG_SAFEOUT_CTRL , \
. enable_mask = SAFEOUT_CTRL_ENSAFEOUT # # _num # # _MASK , \
}
2015-07-15 15:59:54 +03:00
static const struct regulator_desc max77693_supported_regulators [ ] = {
max77693_regulator_desc_esafeout ( 1 ) ,
max77693_regulator_desc_esafeout ( 2 ) ,
2013-06-25 05:08:38 +04:00
{
. name = " CHARGER " ,
. id = MAX77693_CHARGER ,
2015-03-26 13:35:58 +03:00
. of_match = of_match_ptr ( " CHARGER " ) ,
. regulators_node = of_match_ptr ( " regulators " ) ,
2013-06-25 05:08:38 +04:00
. ops = & max77693_charger_ops ,
. type = REGULATOR_CURRENT ,
. owner = THIS_MODULE ,
. enable_reg = MAX77693_CHG_REG_CHG_CNFG_00 ,
. enable_mask = CHG_CNFG_00_CHG_MASK |
CHG_CNFG_00_BUCK_MASK ,
2015-04-29 13:58:28 +03:00
. enable_val = CHG_CNFG_00_CHG_MASK | CHG_CNFG_00_BUCK_MASK ,
2013-06-25 05:08:38 +04:00
} ,
} ;
2015-07-15 15:59:49 +03:00
static const struct chg_reg_data max77693_chg_reg_data = {
. linear_reg = MAX77693_CHG_REG_CHG_CNFG_09 ,
. linear_mask = CHG_CNFG_09_CHGIN_ILIM_MASK ,
. uA_step = 20000 ,
. min_sel = 3 ,
} ;
2015-07-15 15:59:54 +03:00
# define max77843_regulator_desc_esafeout(num) { \
. name = " SAFEOUT " # num , \
. id = MAX77843_SAFEOUT # # num , \
. ops = & max77693_safeout_ops , \
. of_match = of_match_ptr ( " SAFEOUT " # num ) , \
. regulators_node = of_match_ptr ( " regulators " ) , \
. type = REGULATOR_VOLTAGE , \
. owner = THIS_MODULE , \
. n_voltages = ARRAY_SIZE ( max77693_safeout_table ) , \
. volt_table = max77693_safeout_table , \
. enable_reg = MAX77843_SYS_REG_SAFEOUTCTRL , \
. enable_mask = MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT # # num , \
. vsel_reg = MAX77843_SYS_REG_SAFEOUTCTRL , \
. vsel_mask = MAX77843_REG_SAFEOUTCTRL_SAFEOUT # # num # # _MASK , \
}
static const struct regulator_desc max77843_supported_regulators [ ] = {
[ MAX77843_SAFEOUT1 ] = max77843_regulator_desc_esafeout ( 1 ) ,
[ MAX77843_SAFEOUT2 ] = max77843_regulator_desc_esafeout ( 2 ) ,
[ MAX77843_CHARGER ] = {
. name = " CHARGER " ,
. id = MAX77843_CHARGER ,
. ops = & max77693_charger_ops ,
. of_match = of_match_ptr ( " CHARGER " ) ,
. regulators_node = of_match_ptr ( " regulators " ) ,
. type = REGULATOR_CURRENT ,
. owner = THIS_MODULE ,
. enable_reg = MAX77843_CHG_REG_CHG_CNFG_00 ,
. enable_mask = MAX77843_CHG_MASK ,
. enable_val = MAX77843_CHG_MASK ,
} ,
} ;
static const struct chg_reg_data max77843_chg_reg_data = {
. linear_reg = MAX77843_CHG_REG_CHG_CNFG_02 ,
. linear_mask = MAX77843_CHG_FAST_CHG_CURRENT_MASK ,
. uA_step = MAX77843_CHG_FAST_CHG_CURRENT_STEP ,
. min_sel = 2 ,
} ;
2013-06-25 05:08:38 +04:00
static int max77693_pmic_probe ( struct platform_device * pdev )
{
2015-07-15 15:59:54 +03:00
enum max77693_types type = platform_get_device_id ( pdev ) - > driver_data ;
2013-06-25 05:08:38 +04:00
struct max77693_dev * iodev = dev_get_drvdata ( pdev - > dev . parent ) ;
2015-07-15 15:59:54 +03:00
const struct regulator_desc * regulators ;
unsigned int regulators_size ;
2015-03-26 13:35:58 +03:00
int i ;
2014-11-03 17:07:05 +03:00
struct regulator_config config = { } ;
2013-06-25 05:08:38 +04:00
2015-03-26 13:35:58 +03:00
config . dev = iodev - > dev ;
2013-06-25 05:08:38 +04:00
2015-07-15 15:59:54 +03:00
switch ( type ) {
case TYPE_MAX77693 :
regulators = max77693_supported_regulators ;
regulators_size = ARRAY_SIZE ( max77693_supported_regulators ) ;
config . driver_data = ( void * ) & max77693_chg_reg_data ;
break ;
case TYPE_MAX77843 :
regulators = max77843_supported_regulators ;
regulators_size = ARRAY_SIZE ( max77843_supported_regulators ) ;
config . driver_data = ( void * ) & max77843_chg_reg_data ;
break ;
default :
dev_err ( & pdev - > dev , " Unsupported device type: %u \n " , type ) ;
return - ENODEV ;
}
for ( i = 0 ; i < regulators_size ; i + + ) {
2014-03-10 12:32:46 +04:00
struct regulator_dev * rdev ;
2013-06-25 05:08:38 +04:00
2015-07-15 15:59:54 +03:00
config . regmap = max77693_get_regmap ( type , iodev ,
regulators [ i ] . id ) ;
2014-03-10 12:32:46 +04:00
rdev = devm_regulator_register ( & pdev - > dev ,
2015-03-26 13:35:58 +03:00
& regulators [ i ] , & config ) ;
2014-03-10 12:32:46 +04:00
if ( IS_ERR ( rdev ) ) {
dev_err ( & pdev - > dev ,
2015-03-26 13:35:58 +03:00
" Failed to initialize regulator-%d \n " , i ) ;
2014-03-10 12:32:46 +04:00
return PTR_ERR ( rdev ) ;
2013-06-25 05:08:38 +04:00
}
}
return 0 ;
}
static const struct platform_device_id max77693_pmic_id [ ] = {
2015-07-15 15:59:49 +03:00
{ " max77693-pmic " , TYPE_MAX77693 } ,
2015-07-15 15:59:54 +03:00
{ " max77843-regulator " , TYPE_MAX77843 } ,
2013-06-25 05:08:38 +04:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( platform , max77693_pmic_id ) ;
static struct platform_driver max77693_pmic_driver = {
. driver = {
. name = " max77693-pmic " ,
} ,
. probe = max77693_pmic_probe ,
. id_table = max77693_pmic_id ,
} ;
2015-08-21 15:38:39 +03:00
static int __init max77693_pmic_init ( void )
{
return platform_driver_register ( & max77693_pmic_driver ) ;
}
subsys_initcall ( max77693_pmic_init ) ;
static void __exit max77693_pmic_cleanup ( void )
{
platform_driver_unregister ( & max77693_pmic_driver ) ;
}
module_exit ( max77693_pmic_cleanup ) ;
2013-06-25 05:08:38 +04:00
2015-07-15 15:59:54 +03:00
MODULE_DESCRIPTION ( " MAXIM 77693/77843 regulator driver " ) ;
2013-06-25 05:08:38 +04:00
MODULE_AUTHOR ( " Jonghwa Lee <jonghwa3.lee@samsung.com> " ) ;
2016-08-17 15:07:46 +03:00
MODULE_AUTHOR ( " Krzysztof Kozlowski <krzk@kernel.org> " ) ;
2013-06-25 05:08:38 +04:00
MODULE_LICENSE ( " GPL " ) ;