2021-07-09 18:40:36 +03:00
// SPDX-License-Identifier: GPL-2.0+
# include <linux/bitops.h>
# include <linux/delay.h>
# include <linux/gpio/consumer.h>
# include <linux/i2c.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/mutex.h>
# include <linux/regmap.h>
# include <linux/regulator/driver.h>
enum {
RTQ6752_IDX_PAVDD = 0 ,
RTQ6752_IDX_NAVDD = 1 ,
RTQ6752_IDX_MAX
} ;
# define RTQ6752_REG_PAVDD 0x00
# define RTQ6752_REG_NAVDD 0x01
# define RTQ6752_REG_PAVDDONDLY 0x07
2021-07-14 05:36:10 +03:00
# define RTQ6752_REG_PAVDDSSTIME 0x08
2021-07-09 18:40:36 +03:00
# define RTQ6752_REG_NAVDDONDLY 0x0D
# define RTQ6752_REG_NAVDDSSTIME 0x0E
# define RTQ6752_REG_OPTION1 0x12
# define RTQ6752_REG_CHSWITCH 0x16
# define RTQ6752_REG_FAULT 0x1D
# define RTQ6752_VOUT_MASK GENMASK(5, 0)
# define RTQ6752_NAVDDEN_MASK BIT(3)
# define RTQ6752_PAVDDEN_MASK BIT(0)
# define RTQ6752_PAVDDAD_MASK BIT(4)
# define RTQ6752_NAVDDAD_MASK BIT(3)
# define RTQ6752_PAVDDF_MASK BIT(3)
# define RTQ6752_NAVDDF_MASK BIT(0)
# define RTQ6752_ENABLE_MASK (BIT(RTQ6752_IDX_MAX) - 1)
# define RTQ6752_VOUT_MINUV 5000000
# define RTQ6752_VOUT_STEPUV 50000
# define RTQ6752_VOUT_NUM 47
# define RTQ6752_I2CRDY_TIMEUS 1000
# define RTQ6752_MINSS_TIMEUS 5000
struct rtq6752_priv {
struct regmap * regmap ;
struct gpio_desc * enable_gpio ;
struct mutex lock ;
unsigned char enable_flag ;
} ;
static int rtq6752_set_vdd_enable ( struct regulator_dev * rdev )
{
struct rtq6752_priv * priv = rdev_get_drvdata ( rdev ) ;
int rid = rdev_get_id ( rdev ) , ret ;
mutex_lock ( & priv - > lock ) ;
2021-09-14 17:20:49 +03:00
if ( ! priv - > enable_flag ) {
if ( priv - > enable_gpio ) {
gpiod_set_value ( priv - > enable_gpio , 1 ) ;
2021-07-09 18:40:36 +03:00
2021-09-14 17:20:49 +03:00
usleep_range ( RTQ6752_I2CRDY_TIMEUS ,
RTQ6752_I2CRDY_TIMEUS + 100 ) ;
}
2021-07-09 18:40:36 +03:00
regcache_cache_only ( priv - > regmap , false ) ;
ret = regcache_sync ( priv - > regmap ) ;
if ( ret ) {
mutex_unlock ( & priv - > lock ) ;
return ret ;
}
}
priv - > enable_flag | = BIT ( rid ) ;
mutex_unlock ( & priv - > lock ) ;
return regulator_enable_regmap ( rdev ) ;
}
static int rtq6752_set_vdd_disable ( struct regulator_dev * rdev )
{
struct rtq6752_priv * priv = rdev_get_drvdata ( rdev ) ;
int rid = rdev_get_id ( rdev ) , ret ;
ret = regulator_disable_regmap ( rdev ) ;
if ( ret )
return ret ;
mutex_lock ( & priv - > lock ) ;
priv - > enable_flag & = ~ BIT ( rid ) ;
2021-07-16 06:55:46 +03:00
if ( ! priv - > enable_flag ) {
2021-07-09 18:40:36 +03:00
regcache_cache_only ( priv - > regmap , true ) ;
regcache_mark_dirty ( priv - > regmap ) ;
2021-09-14 17:20:49 +03:00
if ( priv - > enable_gpio )
gpiod_set_value ( priv - > enable_gpio , 0 ) ;
2021-07-16 06:55:46 +03:00
2021-09-14 17:20:49 +03:00
}
2021-07-09 18:40:36 +03:00
mutex_unlock ( & priv - > lock ) ;
return 0 ;
}
static int rtq6752_get_error_flags ( struct regulator_dev * rdev ,
unsigned int * flags )
{
unsigned int val , events = 0 ;
const unsigned int fault_mask [ ] = {
RTQ6752_PAVDDF_MASK , RTQ6752_NAVDDF_MASK } ;
int rid = rdev_get_id ( rdev ) , ret ;
ret = regmap_read ( rdev - > regmap , RTQ6752_REG_FAULT , & val ) ;
if ( ret )
return ret ;
if ( val & fault_mask [ rid ] )
events = REGULATOR_ERROR_REGULATION_OUT ;
* flags = events ;
return 0 ;
}
static const struct regulator_ops rtq6752_regulator_ops = {
. list_voltage = regulator_list_voltage_linear ,
. set_voltage_sel = regulator_set_voltage_sel_regmap ,
. get_voltage_sel = regulator_get_voltage_sel_regmap ,
. enable = rtq6752_set_vdd_enable ,
. disable = rtq6752_set_vdd_disable ,
. is_enabled = regulator_is_enabled_regmap ,
. set_active_discharge = regulator_set_active_discharge_regmap ,
. get_error_flags = rtq6752_get_error_flags ,
} ;
static const struct regulator_desc rtq6752_regulator_descs [ ] = {
{
. name = " rtq6752-pavdd " ,
. of_match = of_match_ptr ( " pavdd " ) ,
. regulators_node = of_match_ptr ( " regulators " ) ,
. id = RTQ6752_IDX_PAVDD ,
. n_voltages = RTQ6752_VOUT_NUM ,
. ops = & rtq6752_regulator_ops ,
. owner = THIS_MODULE ,
. min_uV = RTQ6752_VOUT_MINUV ,
. uV_step = RTQ6752_VOUT_STEPUV ,
. enable_time = RTQ6752_MINSS_TIMEUS ,
. vsel_reg = RTQ6752_REG_PAVDD ,
. vsel_mask = RTQ6752_VOUT_MASK ,
. enable_reg = RTQ6752_REG_CHSWITCH ,
. enable_mask = RTQ6752_PAVDDEN_MASK ,
. active_discharge_reg = RTQ6752_REG_OPTION1 ,
. active_discharge_mask = RTQ6752_PAVDDAD_MASK ,
. active_discharge_off = RTQ6752_PAVDDAD_MASK ,
} ,
{
. name = " rtq6752-navdd " ,
. of_match = of_match_ptr ( " navdd " ) ,
. regulators_node = of_match_ptr ( " regulators " ) ,
. id = RTQ6752_IDX_NAVDD ,
. n_voltages = RTQ6752_VOUT_NUM ,
. ops = & rtq6752_regulator_ops ,
. owner = THIS_MODULE ,
. min_uV = RTQ6752_VOUT_MINUV ,
. uV_step = RTQ6752_VOUT_STEPUV ,
. enable_time = RTQ6752_MINSS_TIMEUS ,
. vsel_reg = RTQ6752_REG_NAVDD ,
. vsel_mask = RTQ6752_VOUT_MASK ,
. enable_reg = RTQ6752_REG_CHSWITCH ,
. enable_mask = RTQ6752_NAVDDEN_MASK ,
. active_discharge_reg = RTQ6752_REG_OPTION1 ,
. active_discharge_mask = RTQ6752_NAVDDAD_MASK ,
. active_discharge_off = RTQ6752_NAVDDAD_MASK ,
}
} ;
static int rtq6752_init_device_properties ( struct rtq6752_priv * priv )
{
u8 raw_vals [ ] = { 0 , 0 } ;
int ret ;
/* Configure PAVDD on and softstart delay time to the minimum */
ret = regmap_raw_write ( priv - > regmap , RTQ6752_REG_PAVDDONDLY , raw_vals ,
ARRAY_SIZE ( raw_vals ) ) ;
if ( ret )
return ret ;
/* Configure NAVDD on and softstart delay time to the minimum */
return regmap_raw_write ( priv - > regmap , RTQ6752_REG_NAVDDONDLY , raw_vals ,
ARRAY_SIZE ( raw_vals ) ) ;
}
static bool rtq6752_is_volatile_reg ( struct device * dev , unsigned int reg )
{
if ( reg = = RTQ6752_REG_FAULT )
return true ;
return false ;
}
static const struct reg_default rtq6752_reg_defaults [ ] = {
{ RTQ6752_REG_PAVDD , 0x14 } ,
{ RTQ6752_REG_NAVDD , 0x14 } ,
{ RTQ6752_REG_PAVDDONDLY , 0x01 } ,
{ RTQ6752_REG_PAVDDSSTIME , 0x01 } ,
{ RTQ6752_REG_NAVDDONDLY , 0x01 } ,
{ RTQ6752_REG_NAVDDSSTIME , 0x01 } ,
{ RTQ6752_REG_OPTION1 , 0x07 } ,
{ RTQ6752_REG_CHSWITCH , 0x29 } ,
} ;
static const struct regmap_config rtq6752_regmap_config = {
. reg_bits = 8 ,
. val_bits = 8 ,
. cache_type = REGCACHE_RBTREE ,
. max_register = RTQ6752_REG_FAULT ,
. reg_defaults = rtq6752_reg_defaults ,
. num_reg_defaults = ARRAY_SIZE ( rtq6752_reg_defaults ) ,
. volatile_reg = rtq6752_is_volatile_reg ,
} ;
static int rtq6752_probe ( struct i2c_client * i2c )
{
struct rtq6752_priv * priv ;
struct regulator_config reg_cfg = { } ;
struct regulator_dev * rdev ;
int i , ret ;
priv = devm_kzalloc ( & i2c - > dev , sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv )
return - ENOMEM ;
mutex_init ( & priv - > lock ) ;
priv - > enable_gpio = devm_gpiod_get_optional ( & i2c - > dev , " enable " ,
GPIOD_OUT_HIGH ) ;
if ( IS_ERR ( priv - > enable_gpio ) ) {
dev_err ( & i2c - > dev , " Failed to get 'enable' gpio \n " ) ;
return PTR_ERR ( priv - > enable_gpio ) ;
}
usleep_range ( RTQ6752_I2CRDY_TIMEUS , RTQ6752_I2CRDY_TIMEUS + 100 ) ;
/* Default EN pin to high, PAVDD and NAVDD will be on */
priv - > enable_flag = RTQ6752_ENABLE_MASK ;
priv - > regmap = devm_regmap_init_i2c ( i2c , & rtq6752_regmap_config ) ;
if ( IS_ERR ( priv - > regmap ) ) {
dev_err ( & i2c - > dev , " Failed to init regmap \n " ) ;
return PTR_ERR ( priv - > regmap ) ;
}
ret = rtq6752_init_device_properties ( priv ) ;
if ( ret ) {
dev_err ( & i2c - > dev , " Failed to init device properties \n " ) ;
return ret ;
}
reg_cfg . dev = & i2c - > dev ;
reg_cfg . regmap = priv - > regmap ;
reg_cfg . driver_data = priv ;
for ( i = 0 ; i < ARRAY_SIZE ( rtq6752_regulator_descs ) ; i + + ) {
rdev = devm_regulator_register ( & i2c - > dev ,
rtq6752_regulator_descs + i ,
& reg_cfg ) ;
if ( IS_ERR ( rdev ) ) {
dev_err ( & i2c - > dev , " Failed to init %d regulator \n " , i ) ;
return PTR_ERR ( rdev ) ;
}
}
return 0 ;
}
static const struct of_device_id __maybe_unused rtq6752_device_table [ ] = {
{ . compatible = " richtek,rtq6752 " , } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , rtq6752_device_table ) ;
static struct i2c_driver rtq6752_driver = {
. driver = {
. name = " rtq6752 " ,
. of_match_table = rtq6752_device_table ,
} ,
. probe_new = rtq6752_probe ,
} ;
module_i2c_driver ( rtq6752_driver ) ;
2021-07-14 05:36:10 +03:00
MODULE_AUTHOR ( " ChiYuan Huang <cy_huang@richtek.com> " ) ;
2021-07-09 18:40:36 +03:00
MODULE_DESCRIPTION ( " Richtek RTQ6752 Regulator Driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;