diff mbox series

[v3,05/13] regulator: qcom_spmi: Add support for new regulator types

Message ID 20220731223736.1036286-6-iskren.chernev@gmail.com (mailing list archive)
State Superseded
Headers show
Series PM6125 regulator support | expand

Commit Message

Iskren Chernev July 31, 2022, 10:37 p.m. UTC
Add support for some regulator types that are missing in this driver, all
belonging to the FTSMPS426 register layout.  This is done in preparation
for adding support for the PM6125 PMIC.

Although these regulators conform to ftsmps426 (common 2) layout, their
modes are slightly offset (BYPASS, RETENTION and LPM values are one lower).

Also, slew rate for the FTS regulator is computed in a simpler way.

The inspiration for the magic constants was taken from [1]

[1]: https://source.codeaurora.org/quic/la/kernel/msm-5.4/commit/?h=kernel.lnx.5.4.r1-rel&id=d1220daeffaa440ffff0a8c47322eb0033bf54f5

Signed-off-by: Adam Skladowski <a39.skl@gmail.com>
Signed-off-by: Iskren Chernev <iskren.chernev@gmail.com>
---
 drivers/regulator/qcom_spmi-regulator.c | 138 ++++++++++++++++++++++++
 1 file changed, 138 insertions(+)

Comments

kernel test robot Aug. 1, 2022, 3:53 a.m. UTC | #1
Hi Iskren,

I love your patch! Yet something to improve:

[auto build test ERROR on broonie-regulator/for-next]
[also build test ERROR on next-20220728]
[cannot apply to krzk-dt/for-next linus/master v5.19]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Iskren-Chernev/PM6125-regulator-support/20220801-064059
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git for-next
config: arm64-buildonly-randconfig-r005-20220731 (https://download.01.org/0day-ci/archive/20220801/202208011110.Bms4zAP4-lkp@intel.com/config)
compiler: clang version 16.0.0 (https://github.com/llvm/llvm-project 52cd00cabf479aa7eb6dbb063b7ba41ea57bce9e)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install arm64 cross compiling tool for clang build
        # apt-get install binutils-aarch64-linux-gnu
        # https://github.com/intel-lab-lkp/linux/commit/3758c84ef9cec75fc09a3463506782d3179fe480
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Iskren-Chernev/PM6125-regulator-support/20220801-064059
        git checkout 3758c84ef9cec75fc09a3463506782d3179fe480
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm64 SHELL=/bin/bash drivers/regulator/

If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> drivers/regulator/qcom_spmi-regulator.c:1565:15: error: incompatible function pointer types initializing 'unsigned int (*)(struct regulator_dev *)' with an expression of type 'int (struct regulator_dev *, unsigned int)' [-Werror,-Wincompatible-function-pointer-types]
           .get_mode               = spmi_regulator_ftsmps3_get_mode,
                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   1 error generated.


vim +1565 drivers/regulator/qcom_spmi-regulator.c

  1554	
  1555	static const struct regulator_ops spmi_ftsmps3_ops = {
  1556		.enable			= regulator_enable_regmap,
  1557		.disable		= regulator_disable_regmap,
  1558		.is_enabled		= regulator_is_enabled_regmap,
  1559		.set_voltage_sel	= spmi_regulator_ftsmps426_set_voltage,
  1560		.set_voltage_time_sel	= spmi_regulator_set_voltage_time_sel,
  1561		.get_voltage_sel	= spmi_regulator_ftsmps426_get_voltage,
  1562		.map_voltage		= spmi_regulator_single_map_voltage,
  1563		.list_voltage		= spmi_regulator_common_list_voltage,
  1564		.set_mode		= spmi_regulator_ftsmps3_set_mode,
> 1565		.get_mode		= spmi_regulator_ftsmps3_get_mode,
  1566		.set_load		= spmi_regulator_common_set_load,
  1567		.set_pull_down		= spmi_regulator_common_set_pull_down,
  1568	};
  1569
Krzysztof Kozlowski Aug. 2, 2022, 10:46 a.m. UTC | #2
On 01/08/2022 00:37, Iskren Chernev wrote:
> Add support for some regulator types that are missing in this driver, all
> belonging to the FTSMPS426 register layout.  This is done in preparation
> for adding support for the PM6125 PMIC.
> 
> Although these regulators conform to ftsmps426 (common 2) layout, their
> modes are slightly offset (BYPASS, RETENTION and LPM values are one lower).
> 
> Also, slew rate for the FTS regulator is computed in a simpler way.
> 
> The inspiration for the magic constants was taken from [1]
> 
> [1]: https://source.codeaurora.org/quic/la/kernel/msm-5.4/commit/?h=kernel.lnx.5.4.r1-rel&id=d1220daeffaa440ffff0a8c47322eb0033bf54f5
> 
> Signed-off-by: Adam Skladowski <a39.skl@gmail.com>
> Signed-off-by: Iskren Chernev <iskren.chernev@gmail.com>
> ---
>  drivers/regulator/qcom_spmi-regulator.c | 138 ++++++++++++++++++++++++
>  1 file changed, 138 insertions(+)
> 
> diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c
> index a2d0292a92fd..50c8ee01e0ad 100644
> --- a/drivers/regulator/qcom_spmi-regulator.c
> +++ b/drivers/regulator/qcom_spmi-regulator.c
> @@ -99,6 +99,8 @@ enum spmi_regulator_logical_type {
>  	SPMI_REGULATOR_LOGICAL_TYPE_ULT_LDO,
>  	SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS426,
>  	SPMI_REGULATOR_LOGICAL_TYPE_HFS430,
> +	SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS3,
> +	SPMI_REGULATOR_LOGICAL_TYPE_LDO_510,
>  };
>  
>  enum spmi_regulator_type {
> @@ -166,6 +168,16 @@ enum spmi_regulator_subtype {
>  	SPMI_REGULATOR_SUBTYPE_HFS430		= 0x0a,
>  	SPMI_REGULATOR_SUBTYPE_HT_P150		= 0x35,
>  	SPMI_REGULATOR_SUBTYPE_HT_P600		= 0x3d,
> +	SPMI_REGULATOR_SUBTYPE_FTSMPS_510	= 0x0b,
> +	SPMI_REGULATOR_SUBTYPE_LV_P150_510	= 0x71,
> +	SPMI_REGULATOR_SUBTYPE_LV_P300_510	= 0x72,
> +	SPMI_REGULATOR_SUBTYPE_LV_P600_510	= 0x73,
> +	SPMI_REGULATOR_SUBTYPE_N300_510		= 0x6a,
> +	SPMI_REGULATOR_SUBTYPE_N600_510		= 0x6b,
> +	SPMI_REGULATOR_SUBTYPE_N1200_510	= 0x6c,
> +	SPMI_REGULATOR_SUBTYPE_MV_P50_510	= 0x7a,
> +	SPMI_REGULATOR_SUBTYPE_MV_P150_510	= 0x7b,
> +	SPMI_REGULATOR_SUBTYPE_MV_P600_510	= 0x7d,
>  };
>  
>  enum spmi_common_regulator_registers {
> @@ -193,6 +205,14 @@ enum spmi_ftsmps426_regulator_registers {
>  	SPMI_FTSMPS426_REG_VOLTAGE_ULS_MSB	= 0x69,
>  };
>  
> +/*
> + * Third common register layout
> + */
> +enum spmi_ftsmps3_regulator_registers {
> +	SPMI_FTSMPS3_REG_STEP_CTRL		= 0x3c,
> +};
> +
> +

Just one blank line.

>  enum spmi_vs_registers {
>  	SPMI_VS_REG_OCP				= 0x4a,
>  	SPMI_VS_REG_SOFT_START			= 0x4c,
> @@ -260,6 +280,15 @@ enum spmi_common_control_register_index {
>  
>  #define SPMI_FTSMPS426_MODE_MASK		0x07
>  
> +/* Third common regulator mode register values */
> +#define SPMI_FTSMPS3_MODE_BYPASS_MASK		2
> +#define SPMI_FTSMPS3_MODE_RETENTION_MASK	3
> +#define SPMI_FTSMPS3_MODE_LPM_MASK		4
> +#define SPMI_FTSMPS3_MODE_AUTO_MASK		6
> +#define SPMI_FTSMPS3_MODE_HPM_MASK		7
> +
> +#define SPMI_FTSMPS3_MODE_MASK			0x07
> +
>  /* Common regulator pull down control register layout */
>  #define SPMI_COMMON_PULL_DOWN_ENABLE_MASK	0x80
>  
> @@ -305,6 +334,9 @@ enum spmi_common_control_register_index {
>  #define SPMI_FTSMPS_STEP_MARGIN_NUM	4
>  #define SPMI_FTSMPS_STEP_MARGIN_DEN	5
>  
> +/* slew_rate has units of uV/us. */
> +#define SPMI_FTSMPS3_SLEW_RATE_38p4 38400
> +
>  #define SPMI_FTSMPS426_STEP_CTRL_DELAY_MASK	0x03
>  #define SPMI_FTSMPS426_STEP_CTRL_DELAY_SHIFT	0
>  
> @@ -554,6 +586,14 @@ static struct spmi_voltage_range ht_p600_ranges[] = {
>  	SPMI_VOLTAGE_RANGE(0, 1704000, 1704000, 1896000, 1896000, 8000),
>  };
>  
> +static struct spmi_voltage_range nldo_510_ranges[] = {
> +	SPMI_VOLTAGE_RANGE(0, 320000, 320000, 1304000, 1304000, 8000),
> +};
> +
> +static struct spmi_voltage_range ftsmps510_ranges[] = {
> +	SPMI_VOLTAGE_RANGE(0, 300000, 300000, 1372000, 1372000, 4000),
> +};
> +
>  static DEFINE_SPMI_SET_POINTS(pldo);
>  static DEFINE_SPMI_SET_POINTS(nldo1);
>  static DEFINE_SPMI_SET_POINTS(nldo2);
> @@ -576,6 +616,8 @@ static DEFINE_SPMI_SET_POINTS(ht_nldo);
>  static DEFINE_SPMI_SET_POINTS(hfs430);
>  static DEFINE_SPMI_SET_POINTS(ht_p150);
>  static DEFINE_SPMI_SET_POINTS(ht_p600);
> +static DEFINE_SPMI_SET_POINTS(nldo_510);
> +static DEFINE_SPMI_SET_POINTS(ftsmps510);
>  
>  static inline int spmi_vreg_read(struct spmi_regulator *vreg, u16 addr, u8 *buf,
>  				 int len)
> @@ -1062,6 +1104,24 @@ static unsigned int spmi_regulator_ftsmps426_get_mode(struct regulator_dev *rdev
>  	}
>  }
>  
> +static int
> +spmi_regulator_ftsmps3_get_mode(struct regulator_dev *rdev, unsigned int mode)
> +{
> +	struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
> +	u8 reg;
> +
> +	spmi_vreg_read(vreg, SPMI_COMMON_REG_MODE, &reg, 1);
> +
> +	switch (reg) {
> +	case SPMI_FTSMPS3_MODE_HPM_MASK:
> +		return REGULATOR_MODE_NORMAL;
> +	case SPMI_FTSMPS3_MODE_AUTO_MASK:
> +		return REGULATOR_MODE_FAST;
> +	default:
> +		return REGULATOR_MODE_IDLE;
> +	}
> +}
> +
>  static int
>  spmi_regulator_common_set_mode(struct regulator_dev *rdev, unsigned int mode)
>  {
> @@ -1108,6 +1168,33 @@ spmi_regulator_ftsmps426_set_mode(struct regulator_dev *rdev, unsigned int mode)
>  	return spmi_vreg_update_bits(vreg, SPMI_COMMON_REG_MODE, val, mask);
>  }
>  
> +static int
> +spmi_regulator_ftsmps3_set_mode(struct regulator_dev *rdev, unsigned int mode)
> +{
> +	struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
> +	u8 mask = SPMI_FTSMPS3_MODE_MASK;
> +	u8 val;
> +
> +	switch (mode) {
> +	case REGULATOR_MODE_NORMAL:
> +		val = SPMI_FTSMPS3_MODE_HPM_MASK;
> +		break;
> +	case REGULATOR_MODE_FAST:
> +		val = SPMI_FTSMPS3_MODE_AUTO_MASK;
> +		break;
> +	case REGULATOR_MODE_IDLE:
> +		val = vreg->logical_type ==
> +				SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS3 ?
> +			SPMI_FTSMPS3_MODE_RETENTION_MASK :
> +			SPMI_FTSMPS3_MODE_LPM_MASK;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return spmi_vreg_update_bits(vreg, SPMI_COMMON_REG_MODE, val, mask);
> +}
> +
>  static int
>  spmi_regulator_common_set_load(struct regulator_dev *rdev, int load_uA)
>  {
> @@ -1465,6 +1552,21 @@ static const struct regulator_ops spmi_hfs430_ops = {
>  	.get_mode		= spmi_regulator_ftsmps426_get_mode,
>  };
>  
> +static const struct regulator_ops spmi_ftsmps3_ops = {
> +	.enable			= regulator_enable_regmap,
> +	.disable		= regulator_disable_regmap,
> +	.is_enabled		= regulator_is_enabled_regmap,
> +	.set_voltage_sel	= spmi_regulator_ftsmps426_set_voltage,
> +	.set_voltage_time_sel	= spmi_regulator_set_voltage_time_sel,
> +	.get_voltage_sel	= spmi_regulator_ftsmps426_get_voltage,
> +	.map_voltage		= spmi_regulator_single_map_voltage,
> +	.list_voltage		= spmi_regulator_common_list_voltage,
> +	.set_mode		= spmi_regulator_ftsmps3_set_mode,
> +	.get_mode		= spmi_regulator_ftsmps3_get_mode,
> +	.set_load		= spmi_regulator_common_set_load,
> +	.set_pull_down		= spmi_regulator_common_set_pull_down,
> +};
> +
>  /* Maximum possible digital major revision value */
>  #define INF 0xFF
>  
> @@ -1549,6 +1651,16 @@ static const struct spmi_regulator_mapping supported_regulators[] = {
>  	SPMI_VREG(ULT_LDO, P300,     0, INF, ULT_LDO, ult_ldo, ult_pldo, 10000),
>  	SPMI_VREG(ULT_LDO, P150,     0, INF, ULT_LDO, ult_ldo, ult_pldo, 10000),
>  	SPMI_VREG(ULT_LDO, P50,     0, INF, ULT_LDO, ult_ldo, ult_pldo, 5000),
> +	SPMI_VREG(LDO, LV_P150_510, 0, INF, LDO_510, ftsmps3, ht_lvpldo, 10000),
> +	SPMI_VREG(LDO, LV_P300_510, 0, INF, LDO_510, ftsmps3, ht_lvpldo, 10000),
> +	SPMI_VREG(LDO, LV_P600_510, 0, INF, LDO_510, ftsmps3, ht_lvpldo, 10000),
> +	SPMI_VREG(LDO, MV_P50_510,  0, INF, LDO_510, ftsmps3, pldo660, 10000),
> +	SPMI_VREG(LDO, MV_P150_510, 0, INF, LDO_510, ftsmps3, pldo660, 10000),
> +	SPMI_VREG(LDO, MV_P600_510, 0, INF, LDO_510, ftsmps3, pldo660, 10000),
> +	SPMI_VREG(LDO, N300_510,    0, INF, LDO_510, ftsmps3, nldo_510, 10000),
> +	SPMI_VREG(LDO, N600_510,    0, INF, LDO_510, ftsmps3, nldo_510, 10000),
> +	SPMI_VREG(LDO, N1200_510,   0, INF, LDO_510, ftsmps3, nldo_510, 10000),
> +	SPMI_VREG(FTS, FTSMPS_510,  0, INF, FTSMPS3, ftsmps3, ftsmps510, 100000),
>  };
>  
>  static void spmi_calculate_num_voltages(struct spmi_voltage_set_points *points)
> @@ -1696,6 +1808,27 @@ static int spmi_regulator_init_slew_rate_ftsmps426(struct spmi_regulator *vreg,
>  	return ret;
>  }
>  
> +static int spmi_regulator_init_slew_rate_ftsmps3(struct spmi_regulator *vreg)
> +{
> +	int ret;
> +	u8 reg = 0;
> +	int delay;
> +
> +	ret = spmi_vreg_read(vreg, SPMI_FTSMPS3_REG_STEP_CTRL, &reg, 1);
> +	if (ret) {
> +		dev_err(vreg->dev, "spmi read failed, ret=%d\n", ret);
> +		return ret;
> +	}
> +
> +	delay = reg & SPMI_FTSMPS426_STEP_CTRL_DELAY_MASK;
> +	delay >>= SPMI_FTSMPS426_STEP_CTRL_DELAY_SHIFT;
> +
> +

Drop two blank lines.


Best regards,
Krzysztof
Mark Brown Aug. 2, 2022, 1:17 p.m. UTC | #3
On Tue, Aug 02, 2022 at 12:46:48PM +0200, Krzysztof Kozlowski wrote:
> On 01/08/2022 00:37, Iskren Chernev wrote:

> > +/*
> > + * Third common register layout
> > + */
> > +enum spmi_ftsmps3_regulator_registers {
> > +	SPMI_FTSMPS3_REG_STEP_CTRL		= 0x3c,
> > +};
> > +
> > +
> 
> Just one blank line.

Please delete unneeded context from mails when replying.  Doing this
makes it much easier to find your reply in the message, helping ensure
it won't be missed by people scrolling through the irrelevant quoted
material.
diff mbox series

Patch

diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c
index a2d0292a92fd..50c8ee01e0ad 100644
--- a/drivers/regulator/qcom_spmi-regulator.c
+++ b/drivers/regulator/qcom_spmi-regulator.c
@@ -99,6 +99,8 @@  enum spmi_regulator_logical_type {
 	SPMI_REGULATOR_LOGICAL_TYPE_ULT_LDO,
 	SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS426,
 	SPMI_REGULATOR_LOGICAL_TYPE_HFS430,
+	SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS3,
+	SPMI_REGULATOR_LOGICAL_TYPE_LDO_510,
 };
 
 enum spmi_regulator_type {
@@ -166,6 +168,16 @@  enum spmi_regulator_subtype {
 	SPMI_REGULATOR_SUBTYPE_HFS430		= 0x0a,
 	SPMI_REGULATOR_SUBTYPE_HT_P150		= 0x35,
 	SPMI_REGULATOR_SUBTYPE_HT_P600		= 0x3d,
+	SPMI_REGULATOR_SUBTYPE_FTSMPS_510	= 0x0b,
+	SPMI_REGULATOR_SUBTYPE_LV_P150_510	= 0x71,
+	SPMI_REGULATOR_SUBTYPE_LV_P300_510	= 0x72,
+	SPMI_REGULATOR_SUBTYPE_LV_P600_510	= 0x73,
+	SPMI_REGULATOR_SUBTYPE_N300_510		= 0x6a,
+	SPMI_REGULATOR_SUBTYPE_N600_510		= 0x6b,
+	SPMI_REGULATOR_SUBTYPE_N1200_510	= 0x6c,
+	SPMI_REGULATOR_SUBTYPE_MV_P50_510	= 0x7a,
+	SPMI_REGULATOR_SUBTYPE_MV_P150_510	= 0x7b,
+	SPMI_REGULATOR_SUBTYPE_MV_P600_510	= 0x7d,
 };
 
 enum spmi_common_regulator_registers {
@@ -193,6 +205,14 @@  enum spmi_ftsmps426_regulator_registers {
 	SPMI_FTSMPS426_REG_VOLTAGE_ULS_MSB	= 0x69,
 };
 
+/*
+ * Third common register layout
+ */
+enum spmi_ftsmps3_regulator_registers {
+	SPMI_FTSMPS3_REG_STEP_CTRL		= 0x3c,
+};
+
+
 enum spmi_vs_registers {
 	SPMI_VS_REG_OCP				= 0x4a,
 	SPMI_VS_REG_SOFT_START			= 0x4c,
@@ -260,6 +280,15 @@  enum spmi_common_control_register_index {
 
 #define SPMI_FTSMPS426_MODE_MASK		0x07
 
+/* Third common regulator mode register values */
+#define SPMI_FTSMPS3_MODE_BYPASS_MASK		2
+#define SPMI_FTSMPS3_MODE_RETENTION_MASK	3
+#define SPMI_FTSMPS3_MODE_LPM_MASK		4
+#define SPMI_FTSMPS3_MODE_AUTO_MASK		6
+#define SPMI_FTSMPS3_MODE_HPM_MASK		7
+
+#define SPMI_FTSMPS3_MODE_MASK			0x07
+
 /* Common regulator pull down control register layout */
 #define SPMI_COMMON_PULL_DOWN_ENABLE_MASK	0x80
 
@@ -305,6 +334,9 @@  enum spmi_common_control_register_index {
 #define SPMI_FTSMPS_STEP_MARGIN_NUM	4
 #define SPMI_FTSMPS_STEP_MARGIN_DEN	5
 
+/* slew_rate has units of uV/us. */
+#define SPMI_FTSMPS3_SLEW_RATE_38p4 38400
+
 #define SPMI_FTSMPS426_STEP_CTRL_DELAY_MASK	0x03
 #define SPMI_FTSMPS426_STEP_CTRL_DELAY_SHIFT	0
 
@@ -554,6 +586,14 @@  static struct spmi_voltage_range ht_p600_ranges[] = {
 	SPMI_VOLTAGE_RANGE(0, 1704000, 1704000, 1896000, 1896000, 8000),
 };
 
+static struct spmi_voltage_range nldo_510_ranges[] = {
+	SPMI_VOLTAGE_RANGE(0, 320000, 320000, 1304000, 1304000, 8000),
+};
+
+static struct spmi_voltage_range ftsmps510_ranges[] = {
+	SPMI_VOLTAGE_RANGE(0, 300000, 300000, 1372000, 1372000, 4000),
+};
+
 static DEFINE_SPMI_SET_POINTS(pldo);
 static DEFINE_SPMI_SET_POINTS(nldo1);
 static DEFINE_SPMI_SET_POINTS(nldo2);
@@ -576,6 +616,8 @@  static DEFINE_SPMI_SET_POINTS(ht_nldo);
 static DEFINE_SPMI_SET_POINTS(hfs430);
 static DEFINE_SPMI_SET_POINTS(ht_p150);
 static DEFINE_SPMI_SET_POINTS(ht_p600);
+static DEFINE_SPMI_SET_POINTS(nldo_510);
+static DEFINE_SPMI_SET_POINTS(ftsmps510);
 
 static inline int spmi_vreg_read(struct spmi_regulator *vreg, u16 addr, u8 *buf,
 				 int len)
@@ -1062,6 +1104,24 @@  static unsigned int spmi_regulator_ftsmps426_get_mode(struct regulator_dev *rdev
 	}
 }
 
+static int
+spmi_regulator_ftsmps3_get_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
+	u8 reg;
+
+	spmi_vreg_read(vreg, SPMI_COMMON_REG_MODE, &reg, 1);
+
+	switch (reg) {
+	case SPMI_FTSMPS3_MODE_HPM_MASK:
+		return REGULATOR_MODE_NORMAL;
+	case SPMI_FTSMPS3_MODE_AUTO_MASK:
+		return REGULATOR_MODE_FAST;
+	default:
+		return REGULATOR_MODE_IDLE;
+	}
+}
+
 static int
 spmi_regulator_common_set_mode(struct regulator_dev *rdev, unsigned int mode)
 {
@@ -1108,6 +1168,33 @@  spmi_regulator_ftsmps426_set_mode(struct regulator_dev *rdev, unsigned int mode)
 	return spmi_vreg_update_bits(vreg, SPMI_COMMON_REG_MODE, val, mask);
 }
 
+static int
+spmi_regulator_ftsmps3_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+	struct spmi_regulator *vreg = rdev_get_drvdata(rdev);
+	u8 mask = SPMI_FTSMPS3_MODE_MASK;
+	u8 val;
+
+	switch (mode) {
+	case REGULATOR_MODE_NORMAL:
+		val = SPMI_FTSMPS3_MODE_HPM_MASK;
+		break;
+	case REGULATOR_MODE_FAST:
+		val = SPMI_FTSMPS3_MODE_AUTO_MASK;
+		break;
+	case REGULATOR_MODE_IDLE:
+		val = vreg->logical_type ==
+				SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS3 ?
+			SPMI_FTSMPS3_MODE_RETENTION_MASK :
+			SPMI_FTSMPS3_MODE_LPM_MASK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return spmi_vreg_update_bits(vreg, SPMI_COMMON_REG_MODE, val, mask);
+}
+
 static int
 spmi_regulator_common_set_load(struct regulator_dev *rdev, int load_uA)
 {
@@ -1465,6 +1552,21 @@  static const struct regulator_ops spmi_hfs430_ops = {
 	.get_mode		= spmi_regulator_ftsmps426_get_mode,
 };
 
+static const struct regulator_ops spmi_ftsmps3_ops = {
+	.enable			= regulator_enable_regmap,
+	.disable		= regulator_disable_regmap,
+	.is_enabled		= regulator_is_enabled_regmap,
+	.set_voltage_sel	= spmi_regulator_ftsmps426_set_voltage,
+	.set_voltage_time_sel	= spmi_regulator_set_voltage_time_sel,
+	.get_voltage_sel	= spmi_regulator_ftsmps426_get_voltage,
+	.map_voltage		= spmi_regulator_single_map_voltage,
+	.list_voltage		= spmi_regulator_common_list_voltage,
+	.set_mode		= spmi_regulator_ftsmps3_set_mode,
+	.get_mode		= spmi_regulator_ftsmps3_get_mode,
+	.set_load		= spmi_regulator_common_set_load,
+	.set_pull_down		= spmi_regulator_common_set_pull_down,
+};
+
 /* Maximum possible digital major revision value */
 #define INF 0xFF
 
@@ -1549,6 +1651,16 @@  static const struct spmi_regulator_mapping supported_regulators[] = {
 	SPMI_VREG(ULT_LDO, P300,     0, INF, ULT_LDO, ult_ldo, ult_pldo, 10000),
 	SPMI_VREG(ULT_LDO, P150,     0, INF, ULT_LDO, ult_ldo, ult_pldo, 10000),
 	SPMI_VREG(ULT_LDO, P50,     0, INF, ULT_LDO, ult_ldo, ult_pldo, 5000),
+	SPMI_VREG(LDO, LV_P150_510, 0, INF, LDO_510, ftsmps3, ht_lvpldo, 10000),
+	SPMI_VREG(LDO, LV_P300_510, 0, INF, LDO_510, ftsmps3, ht_lvpldo, 10000),
+	SPMI_VREG(LDO, LV_P600_510, 0, INF, LDO_510, ftsmps3, ht_lvpldo, 10000),
+	SPMI_VREG(LDO, MV_P50_510,  0, INF, LDO_510, ftsmps3, pldo660, 10000),
+	SPMI_VREG(LDO, MV_P150_510, 0, INF, LDO_510, ftsmps3, pldo660, 10000),
+	SPMI_VREG(LDO, MV_P600_510, 0, INF, LDO_510, ftsmps3, pldo660, 10000),
+	SPMI_VREG(LDO, N300_510,    0, INF, LDO_510, ftsmps3, nldo_510, 10000),
+	SPMI_VREG(LDO, N600_510,    0, INF, LDO_510, ftsmps3, nldo_510, 10000),
+	SPMI_VREG(LDO, N1200_510,   0, INF, LDO_510, ftsmps3, nldo_510, 10000),
+	SPMI_VREG(FTS, FTSMPS_510,  0, INF, FTSMPS3, ftsmps3, ftsmps510, 100000),
 };
 
 static void spmi_calculate_num_voltages(struct spmi_voltage_set_points *points)
@@ -1696,6 +1808,27 @@  static int spmi_regulator_init_slew_rate_ftsmps426(struct spmi_regulator *vreg,
 	return ret;
 }
 
+static int spmi_regulator_init_slew_rate_ftsmps3(struct spmi_regulator *vreg)
+{
+	int ret;
+	u8 reg = 0;
+	int delay;
+
+	ret = spmi_vreg_read(vreg, SPMI_FTSMPS3_REG_STEP_CTRL, &reg, 1);
+	if (ret) {
+		dev_err(vreg->dev, "spmi read failed, ret=%d\n", ret);
+		return ret;
+	}
+
+	delay = reg & SPMI_FTSMPS426_STEP_CTRL_DELAY_MASK;
+	delay >>= SPMI_FTSMPS426_STEP_CTRL_DELAY_SHIFT;
+
+
+	vreg->slew_rate = SPMI_FTSMPS3_SLEW_RATE_38p4 >> delay;
+
+	return ret;
+}
+
 static int spmi_regulator_init_registers(struct spmi_regulator *vreg,
 				const struct spmi_regulator_init_data *data)
 {
@@ -1846,6 +1979,11 @@  static int spmi_regulator_of_parse(struct device_node *node,
 		if (ret)
 			return ret;
 		break;
+	case SPMI_REGULATOR_LOGICAL_TYPE_FTSMPS3:
+		ret = spmi_regulator_init_slew_rate_ftsmps3(vreg);
+		if (ret)
+			return ret;
+		break;
 	default:
 		break;
 	}