2020-08-17 09:10:45 +02:00
// SPDX-License-Identifier: GPL-2.0
2021-01-21 08:18:06 +01:00
//
// Device driver for regulators in Hisi IC
//
// Copyright (c) 2013 Linaro Ltd.
// Copyright (c) 2011 Hisilicon.
2021-01-21 08:18:11 +01:00
// Copyright (c) 2020-2021 Huawei Technologies Co., Ltd
2021-01-21 08:18:06 +01:00
//
// Guodong Xu <guodong.xu@linaro.org>
2020-08-17 09:10:42 +02:00
2021-01-21 08:18:07 +01:00
# include <linux/delay.h>
2020-08-17 09:10:59 +02:00
# include <linux/mfd/hi6421-spmi-pmic.h>
# include <linux/module.h>
# include <linux/platform_device.h>
2021-01-29 20:51:47 +01:00
# include <linux/regmap.h>
2020-08-17 09:10:42 +02:00
# include <linux/regulator/driver.h>
# include <linux/spmi.h>
2021-01-21 08:18:07 +01:00
struct hi6421_spmi_reg_info {
struct regulator_desc desc ;
u8 eco_mode_mask ;
u32 eco_uA ;
2020-08-17 09:10:42 +02:00
2021-01-21 08:18:09 +01:00
/* Serialize regulator enable logic */
struct mutex enable_mutex ;
} ;
2020-08-17 09:10:42 +02:00
2021-01-21 08:18:07 +01:00
static const unsigned int ldo3_voltages [ ] = {
1500000 , 1550000 , 1600000 , 1650000 ,
1700000 , 1725000 , 1750000 , 1775000 ,
1800000 , 1825000 , 1850000 , 1875000 ,
1900000 , 1925000 , 1950000 , 2000000
} ;
static const unsigned int ldo4_voltages [ ] = {
1725000 , 1750000 , 1775000 , 1800000 ,
1825000 , 1850000 , 1875000 , 1900000
} ;
static const unsigned int ldo9_voltages [ ] = {
1750000 , 1800000 , 1825000 , 2800000 ,
2850000 , 2950000 , 3000000 , 3300000
} ;
static const unsigned int ldo15_voltages [ ] = {
1800000 , 1850000 , 2400000 , 2600000 ,
2700000 , 2850000 , 2950000 , 3000000
} ;
static const unsigned int ldo17_voltages [ ] = {
2500000 , 2600000 , 2700000 , 2800000 ,
3000000 , 3100000 , 3200000 , 3300000
} ;
static const unsigned int ldo34_voltages [ ] = {
2600000 , 2700000 , 2800000 , 2900000 ,
3000000 , 3100000 , 3200000 , 3300000
} ;
2021-01-21 08:18:13 +01:00
/**
* HI6421V600_LDO ( ) - specify a LDO power line
* @ _id : LDO id name string
* @ vtable : voltage table
* @ ereg : enable register
* @ emask : enable mask
* @ vreg : voltage select register
* @ odelay : off / on delay time in uS
* @ etime : enable time in uS
* @ ecomask : eco mode mask
* @ ecoamp : eco mode load uppler limit in uA
2020-08-17 09:10:42 +02:00
*/
2021-01-21 08:18:07 +01:00
# define HI6421V600_LDO(_id, vtable, ereg, emask, vreg, \
odelay , etime , ecomask , ecoamp ) \
[ HI6421V600_ # # _id ] = { \
. desc = { \
. name = # _id , \
. of_match = of_match_ptr ( # _id ) , \
. regulators_node = of_match_ptr ( " regulators " ) , \
. ops = & hi6421_spmi_ldo_rops , \
. type = REGULATOR_VOLTAGE , \
. id = HI6421V600_ # # _id , \
. owner = THIS_MODULE , \
. volt_table = vtable , \
. n_voltages = ARRAY_SIZE ( vtable ) , \
. vsel_mask = ( 1 < < ( ARRAY_SIZE ( vtable ) - 1 ) ) - 1 , \
. vsel_reg = vreg , \
. enable_reg = ereg , \
. enable_mask = emask , \
. enable_time = etime , \
. ramp_delay = etime , \
. off_on_delay = odelay , \
} , \
. eco_mode_mask = ecomask , \
. eco_uA = ecoamp , \
}
2020-08-17 09:10:42 +02:00
2020-08-17 09:10:51 +02:00
static int hi6421_spmi_regulator_enable ( struct regulator_dev * rdev )
2020-08-17 09:10:42 +02:00
{
2021-01-21 08:18:07 +01:00
struct hi6421_spmi_reg_info * sreg = rdev_get_drvdata ( rdev ) ;
2021-01-21 08:18:10 +01:00
int ret ;
2020-08-17 09:10:42 +02:00
/* cannot enable more than one regulator at one time */
2021-01-21 08:18:09 +01:00
mutex_lock ( & sreg - > enable_mutex ) ;
2020-08-17 09:10:44 +02:00
2021-04-30 16:55:55 +08:00
ret = regmap_update_bits ( rdev - > regmap , rdev - > desc - > enable_reg ,
2021-01-29 20:51:47 +01:00
rdev - > desc - > enable_mask ,
2021-02-09 13:49:34 +05:30
rdev - > desc - > enable_mask ) ;
2020-08-17 09:10:42 +02:00
2021-01-21 08:18:12 +01:00
/* Avoid powering up multiple devices at the same time */
usleep_range ( rdev - > desc - > off_on_delay , rdev - > desc - > off_on_delay + 60 ) ;
2021-01-21 08:18:09 +01:00
mutex_unlock ( & sreg - > enable_mutex ) ;
2020-08-17 09:10:42 +02:00
2021-01-21 08:18:10 +01:00
return ret ;
2020-08-17 09:10:42 +02:00
}
2020-08-17 09:10:51 +02:00
static unsigned int hi6421_spmi_regulator_get_mode ( struct regulator_dev * rdev )
2020-08-17 09:10:42 +02:00
{
2021-01-21 08:18:07 +01:00
struct hi6421_spmi_reg_info * sreg = rdev_get_drvdata ( rdev ) ;
2020-08-17 09:10:59 +02:00
u32 reg_val ;
2020-08-17 09:10:42 +02:00
2021-04-30 16:55:55 +08:00
regmap_read ( rdev - > regmap , rdev - > desc - > enable_reg , & reg_val ) ;
2020-08-17 09:10:42 +02:00
2020-08-17 09:10:47 +02:00
if ( reg_val & sreg - > eco_mode_mask )
2021-01-21 08:18:08 +01:00
return REGULATOR_MODE_IDLE ;
2020-08-17 09:10:48 +02:00
2021-01-21 08:18:08 +01:00
return REGULATOR_MODE_NORMAL ;
2020-08-17 09:10:42 +02:00
}
2020-08-17 09:10:51 +02:00
static int hi6421_spmi_regulator_set_mode ( struct regulator_dev * rdev ,
2020-08-17 09:10:57 +02:00
unsigned int mode )
2020-08-17 09:10:42 +02:00
{
2021-01-21 08:18:07 +01:00
struct hi6421_spmi_reg_info * sreg = rdev_get_drvdata ( rdev ) ;
2020-08-17 09:10:49 +02:00
u32 val ;
2020-08-17 09:10:42 +02:00
switch ( mode ) {
case REGULATOR_MODE_NORMAL :
2020-08-17 09:10:49 +02:00
val = 0 ;
2020-08-17 09:10:42 +02:00
break ;
case REGULATOR_MODE_IDLE :
2020-08-17 09:10:49 +02:00
val = sreg - > eco_mode_mask < < ( ffs ( sreg - > eco_mode_mask ) - 1 ) ;
2020-08-17 09:10:42 +02:00
break ;
default :
return - EINVAL ;
}
2021-04-30 16:55:55 +08:00
return regmap_update_bits ( rdev - > regmap , rdev - > desc - > enable_reg ,
2021-01-29 20:51:47 +01:00
sreg - > eco_mode_mask , val ) ;
2020-08-17 09:10:42 +02:00
}
2020-08-17 09:10:57 +02:00
static unsigned int
hi6421_spmi_regulator_get_optimum_mode ( struct regulator_dev * rdev ,
int input_uV , int output_uV ,
int load_uA )
2020-08-17 09:10:42 +02:00
{
2021-01-21 08:18:07 +01:00
struct hi6421_spmi_reg_info * sreg = rdev_get_drvdata ( rdev ) ;
2020-08-17 09:10:42 +02:00
2021-01-21 08:18:14 +01:00
if ( ! sreg - > eco_uA | | ( ( unsigned int ) load_uA > sreg - > eco_uA ) )
2020-08-17 09:10:42 +02:00
return REGULATOR_MODE_NORMAL ;
2020-08-17 09:10:59 +02:00
return REGULATOR_MODE_IDLE ;
2020-08-17 09:10:42 +02:00
}
2020-08-17 09:10:59 +02:00
static const struct regulator_ops hi6421_spmi_ldo_rops = {
2021-01-29 20:51:48 +01:00
. is_enabled = regulator_is_enabled_regmap ,
2020-08-17 09:10:51 +02:00
. enable = hi6421_spmi_regulator_enable ,
2021-04-30 16:55:55 +08:00
. disable = regulator_disable_regmap ,
2020-08-17 09:10:42 +02:00
. list_voltage = regulator_list_voltage_table ,
2021-06-10 21:41:28 +08:00
. map_voltage = regulator_map_voltage_ascend ,
2021-01-29 20:51:48 +01:00
. get_voltage_sel = regulator_get_voltage_sel_regmap ,
. set_voltage_sel = regulator_set_voltage_sel_regmap ,
2020-08-17 09:10:51 +02:00
. get_mode = hi6421_spmi_regulator_get_mode ,
. set_mode = hi6421_spmi_regulator_set_mode ,
. get_optimum_mode = hi6421_spmi_regulator_get_optimum_mode ,
2020-08-17 09:10:42 +02:00
} ;
2021-01-21 08:18:07 +01:00
/* HI6421v600 regulators with known registers */
enum hi6421_spmi_regulator_id {
HI6421V600_LDO3 ,
HI6421V600_LDO4 ,
HI6421V600_LDO9 ,
HI6421V600_LDO15 ,
HI6421V600_LDO16 ,
HI6421V600_LDO17 ,
HI6421V600_LDO33 ,
HI6421V600_LDO34 ,
} ;
2020-08-17 09:10:59 +02:00
2021-01-21 08:18:07 +01:00
static struct hi6421_spmi_reg_info regulator_info [ ] = {
HI6421V600_LDO ( LDO3 , ldo3_voltages ,
0x16 , 0x01 , 0x51 ,
20000 , 120 ,
0 , 0 ) ,
HI6421V600_LDO ( LDO4 , ldo4_voltages ,
0x17 , 0x01 , 0x52 ,
20000 , 120 ,
0x10 , 10000 ) ,
HI6421V600_LDO ( LDO9 , ldo9_voltages ,
0x1c , 0x01 , 0x57 ,
20000 , 360 ,
0x10 , 10000 ) ,
HI6421V600_LDO ( LDO15 , ldo15_voltages ,
0x21 , 0x01 , 0x5c ,
20000 , 360 ,
0x10 , 10000 ) ,
HI6421V600_LDO ( LDO16 , ldo15_voltages ,
0x22 , 0x01 , 0x5d ,
20000 , 360 ,
0x10 , 10000 ) ,
HI6421V600_LDO ( LDO17 , ldo17_voltages ,
0x23 , 0x01 , 0x5e ,
20000 , 120 ,
0x10 , 10000 ) ,
HI6421V600_LDO ( LDO33 , ldo17_voltages ,
0x32 , 0x01 , 0x6d ,
20000 , 120 ,
0 , 0 ) ,
HI6421V600_LDO ( LDO34 , ldo34_voltages ,
0x33 , 0x01 , 0x6e ,
20000 , 120 ,
0 , 0 ) ,
} ;
2020-08-17 09:10:42 +02:00
2020-08-17 09:10:51 +02:00
static int hi6421_spmi_regulator_probe ( struct platform_device * pdev )
2020-08-17 09:10:42 +02:00
{
2020-08-17 09:10:46 +02:00
struct device * pmic_dev = pdev - > dev . parent ;
2021-01-21 08:18:07 +01:00
struct regulator_config config = { } ;
struct hi6421_spmi_reg_info * sreg ;
struct hi6421_spmi_reg_info * info ;
struct device * dev = & pdev - > dev ;
2020-08-17 09:10:51 +02:00
struct hi6421_spmi_pmic * pmic ;
2021-01-21 08:18:07 +01:00
struct regulator_dev * rdev ;
int i ;
2020-08-17 09:10:46 +02:00
/*
* This driver is meant to be called by hi6421 - spmi - core ,
* which should first set drvdata . If this doesn ' t happen , hit
* a warn on and return .
*/
pmic = dev_get_drvdata ( pmic_dev ) ;
if ( WARN_ON ( ! pmic ) )
return - ENODEV ;
2021-01-21 08:18:07 +01:00
sreg = devm_kzalloc ( dev , sizeof ( * sreg ) , GFP_KERNEL ) ;
if ( ! sreg )
return - ENOMEM ;
2020-08-17 09:10:42 +02:00
2021-01-21 08:18:09 +01:00
mutex_init ( & sreg - > enable_mutex ) ;
2020-08-17 09:10:42 +02:00
2021-01-21 08:18:07 +01:00
for ( i = 0 ; i < ARRAY_SIZE ( regulator_info ) ; i + + ) {
info = & regulator_info [ i ] ;
2020-08-17 09:10:42 +02:00
2021-01-21 08:18:07 +01:00
config . dev = pdev - > dev . parent ;
config . driver_data = sreg ;
2021-01-29 20:51:49 +01:00
config . regmap = pmic - > regmap ;
2020-08-17 09:10:42 +02:00
2021-01-21 08:18:07 +01:00
rdev = devm_regulator_register ( dev , & info - > desc , & config ) ;
if ( IS_ERR ( rdev ) ) {
dev_err ( dev , " failed to register %s \n " ,
info - > desc . name ) ;
return PTR_ERR ( rdev ) ;
}
}
2020-08-17 09:10:42 +02:00
return 0 ;
}
2021-01-21 08:18:07 +01:00
static const struct platform_device_id hi6421_spmi_regulator_table [ ] = {
2020-08-17 09:10:46 +02:00
{ . name = " hi6421v600-regulator " } ,
{ } ,
} ;
2021-01-21 08:18:07 +01:00
MODULE_DEVICE_TABLE ( platform , hi6421_spmi_regulator_table ) ;
2020-08-17 09:10:46 +02:00
2021-01-21 08:18:07 +01:00
static struct platform_driver hi6421_spmi_regulator_driver = {
. id_table = hi6421_spmi_regulator_table ,
2020-08-17 09:10:42 +02:00
. driver = {
2021-01-21 08:18:10 +01:00
. name = " hi6421v600-regulator " ,
2020-08-17 09:10:42 +02:00
} ,
2020-08-17 09:10:51 +02:00
. probe = hi6421_spmi_regulator_probe ,
2020-08-17 09:10:42 +02:00
} ;
2021-01-21 08:18:07 +01:00
module_platform_driver ( hi6421_spmi_regulator_driver ) ;
2020-08-17 09:10:42 +02:00
2021-01-21 08:18:10 +01:00
MODULE_DESCRIPTION ( " Hi6421v600 SPMI regulator driver " ) ;
2020-08-17 09:10:42 +02:00
MODULE_LICENSE ( " GPL v2 " ) ;