2020-01-20 16:44:45 +03:00
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2020 ROHM Semiconductors
# include <linux/errno.h>
# include <linux/mfd/rohm-generic.h>
# include <linux/module.h>
# include <linux/of.h>
# include <linux/regmap.h>
# include <linux/regulator/driver.h>
static int set_dvs_level ( const struct regulator_desc * desc ,
struct device_node * np , struct regmap * regmap ,
char * prop , unsigned int reg , unsigned int mask ,
unsigned int omask , unsigned int oreg )
{
int ret , i ;
uint32_t uv ;
ret = of_property_read_u32 ( np , prop , & uv ) ;
if ( ret ) {
if ( ret ! = - EINVAL )
return ret ;
return 0 ;
}
2021-04-05 14:43:26 +03:00
/* If voltage is set to 0 => disable */
2020-01-20 16:44:45 +03:00
if ( uv = = 0 ) {
if ( omask )
return regmap_update_bits ( regmap , oreg , omask , 0 ) ;
}
2021-04-05 14:43:26 +03:00
/* Some setups don't allow setting own voltage but do allow enabling */
if ( ! mask ) {
if ( omask )
return regmap_update_bits ( regmap , oreg , omask , omask ) ;
return - EINVAL ;
}
2020-01-20 16:44:45 +03:00
for ( i = 0 ; i < desc - > n_voltages ; i + + ) {
2021-04-05 14:43:26 +03:00
/* NOTE to next hacker - Does not support pickable ranges */
if ( desc - > linear_range_selectors )
return - EINVAL ;
if ( desc - > n_linear_ranges )
ret = regulator_desc_list_voltage_linear_range ( desc , i ) ;
else
ret = regulator_desc_list_voltage_linear ( desc , i ) ;
2020-01-20 16:44:45 +03:00
if ( ret < 0 )
continue ;
if ( ret = = uv ) {
i < < = ffs ( desc - > vsel_mask ) - 1 ;
ret = regmap_update_bits ( regmap , reg , mask , i ) ;
if ( omask & & ! ret )
ret = regmap_update_bits ( regmap , oreg , omask ,
omask ) ;
break ;
}
}
return ret ;
}
int rohm_regulator_set_dvs_levels ( const struct rohm_dvs_config * dvs ,
struct device_node * np ,
const struct regulator_desc * desc ,
struct regmap * regmap )
{
int i , ret = 0 ;
char * prop ;
unsigned int reg , mask , omask , oreg = desc - > enable_reg ;
2021-02-12 11:00:23 +03:00
for ( i = 0 ; i < ROHM_DVS_LEVEL_VALID_AMOUNT & & ! ret ; i + + ) {
int bit ;
bit = BIT ( i ) ;
if ( dvs - > level_map & bit ) {
switch ( bit ) {
2020-01-20 16:44:45 +03:00
case ROHM_DVS_LEVEL_RUN :
prop = " rohm,dvs-run-voltage " ;
reg = dvs - > run_reg ;
mask = dvs - > run_mask ;
omask = dvs - > run_on_mask ;
break ;
case ROHM_DVS_LEVEL_IDLE :
prop = " rohm,dvs-idle-voltage " ;
reg = dvs - > idle_reg ;
mask = dvs - > idle_mask ;
omask = dvs - > idle_on_mask ;
break ;
case ROHM_DVS_LEVEL_SUSPEND :
prop = " rohm,dvs-suspend-voltage " ;
reg = dvs - > suspend_reg ;
mask = dvs - > suspend_mask ;
omask = dvs - > suspend_on_mask ;
break ;
case ROHM_DVS_LEVEL_LPSR :
prop = " rohm,dvs-lpsr-voltage " ;
reg = dvs - > lpsr_reg ;
mask = dvs - > lpsr_mask ;
omask = dvs - > lpsr_on_mask ;
break ;
2021-04-05 14:43:44 +03:00
case ROHM_DVS_LEVEL_SNVS :
prop = " rohm,dvs-snvs-voltage " ;
reg = dvs - > snvs_reg ;
mask = dvs - > snvs_mask ;
omask = dvs - > snvs_on_mask ;
break ;
2020-01-20 16:44:45 +03:00
default :
return - EINVAL ;
}
ret = set_dvs_level ( desc , np , regmap , prop , reg , mask ,
omask , oreg ) ;
}
}
return ret ;
}
EXPORT_SYMBOL ( rohm_regulator_set_dvs_levels ) ;
2021-11-18 14:48:47 +03:00
/*
* Few ROHM PMIC ICs have constrains on voltage changing :
* BD71837 - only buck 1 - 4 voltages can be changed when they are enabled .
* Other bucks and all LDOs must be disabled when voltage is changed .
* BD96801 - LDO voltage levels can be changed when LDOs are disabled .
*/
int rohm_regulator_set_voltage_sel_restricted ( struct regulator_dev * rdev ,
unsigned int sel )
{
if ( rdev - > desc - > ops - > is_enabled ( rdev ) )
return - EBUSY ;
return regulator_set_voltage_sel_regmap ( rdev , sel ) ;
}
EXPORT_SYMBOL_GPL ( rohm_regulator_set_voltage_sel_restricted ) ;
2020-01-20 16:44:45 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_AUTHOR ( " Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com> " ) ;
MODULE_DESCRIPTION ( " Generic helpers for ROHM PMIC regulator drivers " ) ;