devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/4] Support regulator ON/OFF by PMIC state machine.
@ 2020-09-03 18:37 Matti Vaittinen
  2020-09-03 18:38 ` [PATCH 1/4] regulator: bd718x7 initialize regulator config only once Matti Vaittinen
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Matti Vaittinen @ 2020-09-03 18:37 UTC (permalink / raw)
  To: mazziesaccount
  Cc: Liam Girdwood, Mark Brown, Rob Herring, Matti Vaittinen,
	linux-kernel, devicetree, linux-power

Support regulator enable/disable via BD718(37/47/50) PMIC state machine.

The ROHM BD718(37/47/50) PMICs are mainly used for powering i.MX8 based
systems. On some setups the i.MX8 SoC uses a IO line to suspend the
system. These PMICs support this via PMIC internal HW state machine
which can be toggled for example by the PMIC_STBY_REQ IO-pin.

Regulators can be controlled either by this state machine or by SW via
I2C. This patch series allows mixed control model by adding a
device-tree property which is intended to be used to leave some of the
regulators under HW state machine control while allowing other to be
still controlled using the driver. The driver can also be used to set
voltages levels for all regulators no matter if enable/disable state is
controlled by SW or HW.

---

Matti Vaittinen (4):
  regulator: bd718x7 initialize regulator config only once
  dt-bindings: regulator: bd71837: add property for omitting ON/OFF
    control
  dt-bindings: regulator: bd71847: add property for omitting ON/OFF
    control
  regulator: bd718x7 fix regulator states at SUSPEND

 .../regulator/rohm,bd71837-regulator.yaml     |  11 +
 .../regulator/rohm,bd71847-regulator.yaml     |  11 +
 drivers/regulator/bd718x7-regulator.c         | 422 +++++++++++-------
 3 files changed, 293 insertions(+), 151 deletions(-)

-- 
2.21.0


-- 
Matti Vaittinen, Linux device drivers
ROHM Semiconductors, Finland SWDC
Kiviharjunlenkki 1E
90220 OULU
FINLAND

~~~ "I don't think so," said Rene Descartes. Just then he vanished ~~~
Simon says - in Latin please.
~~~ "non cogito me" dixit Rene Descarte, deinde evanescavit ~~~
Thanks to Simon Glass for the translation =] 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/4] regulator: bd718x7 initialize regulator config only once
  2020-09-03 18:37 [PATCH 0/4] Support regulator ON/OFF by PMIC state machine Matti Vaittinen
@ 2020-09-03 18:38 ` Matti Vaittinen
  2020-09-03 18:38 ` [PATCH 2/4] dt-bindings: regulator: bd71837: add property for omitting ON/OFF control Matti Vaittinen
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Matti Vaittinen @ 2020-09-03 18:38 UTC (permalink / raw)
  To: mazziesaccount
  Cc: Liam Girdwood, Mark Brown, Rob Herring, Matti Vaittinen,
	linux-kernel, devicetree, linux-power

The BD718x7 driver initialized common configs for all regulators.
Simplify initialization by moving the initialization of common configs
out of the loop.

Signed-off-by: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
---
 drivers/regulator/bd718x7-regulator.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/regulator/bd718x7-regulator.c b/drivers/regulator/bd718x7-regulator.c
index 7b311389f925..a72031595b9e 100644
--- a/drivers/regulator/bd718x7-regulator.c
+++ b/drivers/regulator/bd718x7-regulator.c
@@ -1319,6 +1319,9 @@ static int bd718xx_probe(struct platform_device *pdev)
 		}
 	}
 
+	config.dev = pdev->dev.parent;
+	config.regmap = mfd->chip.regmap;
+
 	for (i = 0; i < num_reg_data; i++) {
 
 		const struct regulator_desc *desc;
@@ -1328,8 +1331,6 @@ static int bd718xx_probe(struct platform_device *pdev)
 		r = &reg_data[i];
 		desc = &r->desc;
 
-		config.dev = pdev->dev.parent;
-		config.regmap = mfd->chip.regmap;
 
 		rdev = devm_regulator_register(&pdev->dev, desc, &config);
 		if (IS_ERR(rdev)) {
-- 
2.21.0


-- 
Matti Vaittinen, Linux device drivers
ROHM Semiconductors, Finland SWDC
Kiviharjunlenkki 1E
90220 OULU
FINLAND

~~~ "I don't think so," said Rene Descartes. Just then he vanished ~~~
Simon says - in Latin please.
~~~ "non cogito me" dixit Rene Descarte, deinde evanescavit ~~~
Thanks to Simon Glass for the translation =] 

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/4] dt-bindings: regulator: bd71837: add property for omitting ON/OFF control
  2020-09-03 18:37 [PATCH 0/4] Support regulator ON/OFF by PMIC state machine Matti Vaittinen
  2020-09-03 18:38 ` [PATCH 1/4] regulator: bd718x7 initialize regulator config only once Matti Vaittinen
@ 2020-09-03 18:38 ` Matti Vaittinen
  2020-09-03 18:38 ` [PATCH 3/4] dt-bindings: regulator: bd71847: " Matti Vaittinen
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Matti Vaittinen @ 2020-09-03 18:38 UTC (permalink / raw)
  To: mazziesaccount
  Cc: Liam Girdwood, Mark Brown, Rob Herring, Matti Vaittinen,
	linux-kernel, devicetree, linux-power

The BD718(37/47/50) regulator enable states can be controlled either by SW
or by PMIC internal state machine.

On some systems mixture of SW and HW state machine controlled regulators is
needed.

Specifically, some SoCs signal SUSPEND state change to PMIC via
STBY_REQ line. Now there are setups that expect certain regulators then to
be disabled (by PMIC state machine) while other regulators should stay
enabled (regardless of HW state => SW control required).

Add a new device-tree property "rohm,no-regulator-enable-control" which can
be used to leave regulator(s) under HW state machine control.

Signed-off-by: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
---
 .../bindings/regulator/rohm,bd71837-regulator.yaml    | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/Documentation/devicetree/bindings/regulator/rohm,bd71837-regulator.yaml b/Documentation/devicetree/bindings/regulator/rohm,bd71837-regulator.yaml
index 19d9408d9c3b..f5e31196a646 100644
--- a/Documentation/devicetree/bindings/regulator/rohm,bd71837-regulator.yaml
+++ b/Documentation/devicetree/bindings/regulator/rohm,bd71837-regulator.yaml
@@ -93,6 +93,17 @@ patternProperties:
         # ----------------------------------------------------------------
         # rest | not supported   | not supported    | not supported
 
+      # BD71837 power outputs can either be controlled by the PMIC internal
+      # hardware state machine or by software. If you need regulators to be
+      # turned ON/OFF for example based on PMIC_STBY_REQ line (which toggles
+      # PMIC HW state machine) - then you should set this property.
+      # Tradeoff is that then SW can't control the ON/OFF state for this
+      # regulator (other than invoking a PMIC state change).
+      rohm,no-regulator-enable-control:
+        description: |
+          Enable/Disable control of this regulator must be left to the
+          PMIC hardware state machine.
+        type: boolean
 
     required:
       - regulator-name
-- 
2.21.0


-- 
Matti Vaittinen, Linux device drivers
ROHM Semiconductors, Finland SWDC
Kiviharjunlenkki 1E
90220 OULU
FINLAND

~~~ "I don't think so," said Rene Descartes. Just then he vanished ~~~
Simon says - in Latin please.
~~~ "non cogito me" dixit Rene Descarte, deinde evanescavit ~~~
Thanks to Simon Glass for the translation =] 

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/4] dt-bindings: regulator: bd71847: add property for omitting ON/OFF control
  2020-09-03 18:37 [PATCH 0/4] Support regulator ON/OFF by PMIC state machine Matti Vaittinen
  2020-09-03 18:38 ` [PATCH 1/4] regulator: bd718x7 initialize regulator config only once Matti Vaittinen
  2020-09-03 18:38 ` [PATCH 2/4] dt-bindings: regulator: bd71837: add property for omitting ON/OFF control Matti Vaittinen
@ 2020-09-03 18:38 ` Matti Vaittinen
  2020-09-03 18:39 ` [PATCH 4/4] regulator: bd718x7 fix regulator states at SUSPEND Matti Vaittinen
  2020-09-04 10:03 ` [PATCH 0/4] Support regulator ON/OFF by PMIC state machine Mark Brown
  4 siblings, 0 replies; 6+ messages in thread
From: Matti Vaittinen @ 2020-09-03 18:38 UTC (permalink / raw)
  To: mazziesaccount
  Cc: Liam Girdwood, Mark Brown, Rob Herring, Matti Vaittinen,
	linux-kernel, devicetree, linux-power

The BD718(37/47/50) regulator enable states can be controlled either by SW
or by PMIC internal state machine.

On some systems mixture of SW and HW state machine controlled regulators is
needed.

Specifically, some SoCs signal SUSPEND state change to PMIC via
STBY_REQ line. Now there are setups that expect certain regulators then to
be disabled (by PMIC state machine) while other regulators should stay
enabled (regardless of HW state => SW control required).

Add a new device-tree property "rohm,no-regulator-enable-control" which can
be used to leave regulator(s) under HW state machine control.

Signed-off-by: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
---
 .../bindings/regulator/rohm,bd71847-regulator.yaml    | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/Documentation/devicetree/bindings/regulator/rohm,bd71847-regulator.yaml b/Documentation/devicetree/bindings/regulator/rohm,bd71847-regulator.yaml
index 07256a4b50b9..eeac32cd15d6 100644
--- a/Documentation/devicetree/bindings/regulator/rohm,bd71847-regulator.yaml
+++ b/Documentation/devicetree/bindings/regulator/rohm,bd71847-regulator.yaml
@@ -88,6 +88,17 @@ patternProperties:
         # ----------------------------------------------------------------
         # rest | not supported   | not supported    | not supported
 
+      # BD718(47/50) power outputs can either be controlled by the PMIC internal
+      # hardware state machine or by software. If you need regulators to be
+      # turned ON/OFF for example based on PMIC_STBY_REQ line (which toggles
+      # PMIC HW state machine) - then you should set this property.
+      # Tradeoff is that then SW can't control the ON/OFF state for this
+      # regulator (other than invoking a PMIC state change).
+      rohm,no-regulator-enable-control:
+        description: |
+          Enable/Disable control of this regulator must be left to the
+          PMIC hardware state machine.
+        type: boolean
     required:
       - regulator-name
 
-- 
2.21.0


-- 
Matti Vaittinen, Linux device drivers
ROHM Semiconductors, Finland SWDC
Kiviharjunlenkki 1E
90220 OULU
FINLAND

~~~ "I don't think so," said Rene Descartes. Just then he vanished ~~~
Simon says - in Latin please.
~~~ "non cogito me" dixit Rene Descarte, deinde evanescavit ~~~
Thanks to Simon Glass for the translation =] 

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 4/4] regulator: bd718x7 fix regulator states at SUSPEND
  2020-09-03 18:37 [PATCH 0/4] Support regulator ON/OFF by PMIC state machine Matti Vaittinen
                   ` (2 preceding siblings ...)
  2020-09-03 18:38 ` [PATCH 3/4] dt-bindings: regulator: bd71847: " Matti Vaittinen
@ 2020-09-03 18:39 ` Matti Vaittinen
  2020-09-04 10:03 ` [PATCH 0/4] Support regulator ON/OFF by PMIC state machine Mark Brown
  4 siblings, 0 replies; 6+ messages in thread
From: Matti Vaittinen @ 2020-09-03 18:39 UTC (permalink / raw)
  To: mazziesaccount
  Cc: Liam Girdwood, Mark Brown, Rob Herring, Matti Vaittinen,
	linux-kernel, devicetree, linux-power

The BD718(37/47/50) regulator enable states can be controlled
either by SW or by PMIC internal state machine. The bd718x7
driver has not supported leaving the regulators under HW state
machine control (except for cases where this is required to
avoid boot-up problems due to critical regulators being turned
OFF at reset when SNVS used as reset state).

On some systems this is undesirable as there now are setups where
mixture of SW and HW state machine controlled regulators is needed.

Specifically, some SoCs signal SUSPEND state change to PMIC via
STBY_REQ line. Now there are setups that expect certain regulators
then to be disabled (by PMIC state machine) while other regulators
should stay enabled (regardless of HW state => SW control required).

Add support for a new device-tree property
"rohm,no-regulator-enable-control" which can be used to leave
regulator(s) under HW state machine control.

Signed-off-by: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
---
 drivers/regulator/bd718x7-regulator.c | 417 +++++++++++++++++---------
 1 file changed, 268 insertions(+), 149 deletions(-)

diff --git a/drivers/regulator/bd718x7-regulator.c b/drivers/regulator/bd718x7-regulator.c
index a72031595b9e..159c917b9c4c 100644
--- a/drivers/regulator/bd718x7-regulator.c
+++ b/drivers/regulator/bd718x7-regulator.c
@@ -15,6 +15,39 @@
 #include <linux/regulator/of_regulator.h>
 #include <linux/slab.h>
 
+/*
+ * BD718(37/47/50) have two "enable control modes". ON/OFF can either be
+ * controlled by software - or by PMIC internal HW state machine. Whether
+ * regulator should be under SW or HW control can be defined from device-tree.
+ * Let's provide separate ops for regulators to use depending on the "enable
+ * control mode".
+ */
+#define BD718XX_HWOPNAME(swopname) swopname##_hwcontrol
+
+#define BD718XX_OPS(name, _list_voltage, _map_voltage, _set_voltage_sel, \
+		   _get_voltage_sel, _set_voltage_time_sel, _set_ramp_delay) \
+static const struct regulator_ops name = {			\
+	.enable = regulator_enable_regmap,			\
+	.disable = regulator_disable_regmap,			\
+	.is_enabled = regulator_is_enabled_regmap,		\
+	.list_voltage = (_list_voltage),			\
+	.map_voltage = (_map_voltage),				\
+	.set_voltage_sel = (_set_voltage_sel),			\
+	.get_voltage_sel = (_get_voltage_sel),			\
+	.set_voltage_time_sel = (_set_voltage_time_sel),	\
+	.set_ramp_delay = (_set_ramp_delay),			\
+};								\
+								\
+static const struct regulator_ops BD718XX_HWOPNAME(name) = {	\
+	.is_enabled = always_enabled_by_hwstate,		\
+	.list_voltage = (_list_voltage),			\
+	.map_voltage = (_map_voltage),				\
+	.set_voltage_sel = (_set_voltage_sel),			\
+	.get_voltage_sel = (_get_voltage_sel),			\
+	.set_voltage_time_sel = (_set_voltage_time_sel),	\
+	.set_ramp_delay = (_set_ramp_delay),			\
+}								\
+
 /*
  * BUCK1/2/3/4
  * BUCK1RAMPRATE[1:0] BUCK1 DVS ramp rate setting
@@ -55,6 +88,38 @@ static int bd718xx_buck1234_set_ramp_delay(struct regulator_dev *rdev,
 				  BUCK_RAMPRATE_MASK, ramp_value << 6);
 }
 
+/* These functions are used when regulators are under HW state machine control.
+ * We assume PMIC is in RUN state because SW running and able to query the
+ * status. Most of the regulators have fixed ON or OFF state at RUN/IDLE so for
+ * them we just return a constant. BD71837 BUCK3 and BUCK4 are exceptions as
+ * they support configuring the ON/OFF state for RUN.
+ *
+ * Note for next hacker - these PMICs have a register where the HW state can be
+ * read. If assuming RUN appears to be false in your use-case - you can
+ * implement state reading (although that is not going to be atomic) before
+ * returning the enable state.
+ */
+static int always_enabled_by_hwstate(struct regulator_dev *rdev)
+{
+	return 1;
+}
+
+static int never_enabled_by_hwstate(struct regulator_dev *rdev)
+{
+	return 0;
+}
+
+static int bd71837_get_buck34_enable_hwctrl(struct regulator_dev *rdev)
+{
+	int ret;
+	unsigned int val;
+
+	ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val);
+	if (ret)
+		return ret;
+
+	return !!(BD718XX_BUCK_RUN_ON & val);
+}
 /*
  * On BD71837 (not on BD71847, BD71850, ...)
  * Bucks 1 to 4 support DVS. PWM mode is used when voltage is changed.
@@ -71,7 +136,7 @@ static int bd718xx_buck1234_set_ramp_delay(struct regulator_dev *rdev,
 static int bd71837_set_voltage_sel_restricted(struct regulator_dev *rdev,
 						    unsigned int sel)
 {
-	if (regulator_is_enabled_regmap(rdev))
+	if (rdev->desc->ops->is_enabled(rdev))
 		return -EBUSY;
 
 	return regulator_set_voltage_sel_regmap(rdev, sel);
@@ -113,7 +178,7 @@ static int voltage_change_prepare(struct regulator_dev *rdev, unsigned int sel,
 	int ret;
 
 	*mask = 0;
-	if (regulator_is_enabled_regmap(rdev)) {
+	if (rdev->desc->ops->is_enabled(rdev)) {
 		int now, new;
 
 		now = rdev->desc->ops->get_voltage_sel(rdev);
@@ -195,133 +260,90 @@ static int bd718xx_set_voltage_sel_pickable_restricted(
 static int bd71837_set_voltage_sel_pickable_restricted(
 		struct regulator_dev *rdev, unsigned int sel)
 {
-	if (regulator_is_enabled_regmap(rdev))
+	if (rdev->desc->ops->is_enabled(rdev))
 		return -EBUSY;
 
 	return regulator_set_voltage_sel_pickable_regmap(rdev, sel);
 }
 
-static const struct regulator_ops bd718xx_pickable_range_ldo_ops = {
-	.enable = regulator_enable_regmap,
-	.disable = regulator_disable_regmap,
-	.is_enabled = regulator_is_enabled_regmap,
+/*
+ * OPS common for BD71847 and BD71850
+ */
+BD718XX_OPS(bd718xx_pickable_range_ldo_ops,
+	    regulator_list_voltage_pickable_linear_range, NULL,
+	    bd718xx_set_voltage_sel_pickable_restricted,
+	    regulator_get_voltage_sel_pickable_regmap, NULL, NULL);
+
+/* BD71847 and BD71850 LDO 5 is by default OFF at RUN state */
+static const struct regulator_ops bd718xx_ldo5_ops_hwstate = {
+	.is_enabled = never_enabled_by_hwstate,
 	.list_voltage = regulator_list_voltage_pickable_linear_range,
 	.set_voltage_sel = bd718xx_set_voltage_sel_pickable_restricted,
 	.get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
-
 };
 
-static const struct regulator_ops bd71837_pickable_range_ldo_ops = {
-	.enable = regulator_enable_regmap,
-	.disable = regulator_disable_regmap,
-	.is_enabled = regulator_is_enabled_regmap,
-	.list_voltage = regulator_list_voltage_pickable_linear_range,
-	.set_voltage_sel = bd71837_set_voltage_sel_pickable_restricted,
-	.get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
-};
-
-static const struct regulator_ops bd718xx_pickable_range_buck_ops = {
-	.enable = regulator_enable_regmap,
-	.disable = regulator_disable_regmap,
-	.is_enabled = regulator_is_enabled_regmap,
-	.list_voltage = regulator_list_voltage_pickable_linear_range,
-	.set_voltage_sel = regulator_set_voltage_sel_pickable_regmap,
-	.get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
-	.set_voltage_time_sel = regulator_set_voltage_time_sel,
-};
+BD718XX_OPS(bd718xx_pickable_range_buck_ops,
+	    regulator_list_voltage_pickable_linear_range, NULL,
+	    regulator_set_voltage_sel_pickable_regmap,
+	    regulator_get_voltage_sel_pickable_regmap,
+	    regulator_set_voltage_time_sel, NULL);
 
-static const struct regulator_ops bd71837_pickable_range_buck_ops = {
-	.enable = regulator_enable_regmap,
-	.disable = regulator_disable_regmap,
-	.is_enabled = regulator_is_enabled_regmap,
-	.list_voltage = regulator_list_voltage_pickable_linear_range,
-	.set_voltage_sel = bd71837_set_voltage_sel_pickable_restricted,
-	.get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
-	.set_voltage_time_sel = regulator_set_voltage_time_sel,
-};
-
-static const struct regulator_ops bd71837_ldo_regulator_ops = {
-	.enable = regulator_enable_regmap,
-	.disable = regulator_disable_regmap,
-	.is_enabled = regulator_is_enabled_regmap,
-	.list_voltage = regulator_list_voltage_linear_range,
-	.set_voltage_sel = bd71837_set_voltage_sel_restricted,
-	.get_voltage_sel = regulator_get_voltage_sel_regmap,
-};
+BD718XX_OPS(bd718xx_ldo_regulator_ops, regulator_list_voltage_linear_range,
+	    NULL, bd718xx_set_voltage_sel_restricted,
+	    regulator_get_voltage_sel_regmap, NULL, NULL);
 
-static const struct regulator_ops bd718xx_ldo_regulator_ops = {
-	.enable = regulator_enable_regmap,
-	.disable = regulator_disable_regmap,
-	.is_enabled = regulator_is_enabled_regmap,
-	.list_voltage = regulator_list_voltage_linear_range,
-	.set_voltage_sel = bd718xx_set_voltage_sel_restricted,
-	.get_voltage_sel = regulator_get_voltage_sel_regmap,
-};
+BD718XX_OPS(bd718xx_ldo_regulator_nolinear_ops, regulator_list_voltage_table,
+	    NULL, bd718xx_set_voltage_sel_restricted,
+	    regulator_get_voltage_sel_regmap, NULL, NULL);
 
-static const struct regulator_ops bd71837_ldo_regulator_nolinear_ops = {
-	.enable = regulator_enable_regmap,
-	.disable = regulator_disable_regmap,
-	.is_enabled = regulator_is_enabled_regmap,
-	.list_voltage = regulator_list_voltage_table,
-	.set_voltage_sel = bd71837_set_voltage_sel_restricted,
-	.get_voltage_sel = regulator_get_voltage_sel_regmap,
-};
+BD718XX_OPS(bd718xx_buck_regulator_ops, regulator_list_voltage_linear_range,
+	    NULL, regulator_set_voltage_sel_regmap,
+	    regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel,
+	    NULL);
 
-static const struct regulator_ops bd718xx_ldo_regulator_nolinear_ops = {
-	.enable = regulator_enable_regmap,
-	.disable = regulator_disable_regmap,
-	.is_enabled = regulator_is_enabled_regmap,
-	.list_voltage = regulator_list_voltage_table,
-	.set_voltage_sel = bd718xx_set_voltage_sel_restricted,
-	.get_voltage_sel = regulator_get_voltage_sel_regmap,
-};
+BD718XX_OPS(bd718xx_buck_regulator_nolinear_ops, regulator_list_voltage_table,
+	    regulator_map_voltage_ascend, regulator_set_voltage_sel_regmap,
+	    regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel,
+	    NULL);
 
-static const struct regulator_ops bd718xx_buck_regulator_ops = {
-	.enable = regulator_enable_regmap,
-	.disable = regulator_disable_regmap,
-	.is_enabled = regulator_is_enabled_regmap,
-	.list_voltage = regulator_list_voltage_linear_range,
-	.set_voltage_sel = regulator_set_voltage_sel_regmap,
-	.get_voltage_sel = regulator_get_voltage_sel_regmap,
-	.set_voltage_time_sel = regulator_set_voltage_time_sel,
-};
-
-static const struct regulator_ops bd71837_buck_regulator_ops = {
-	.enable = regulator_enable_regmap,
-	.disable = regulator_disable_regmap,
-	.is_enabled = regulator_is_enabled_regmap,
-	.list_voltage = regulator_list_voltage_linear_range,
-	.set_voltage_sel = bd71837_set_voltage_sel_restricted,
-	.get_voltage_sel = regulator_get_voltage_sel_regmap,
-	.set_voltage_time_sel = regulator_set_voltage_time_sel,
-};
-
-static const struct regulator_ops bd718xx_buck_regulator_nolinear_ops = {
-	.enable = regulator_enable_regmap,
-	.disable = regulator_disable_regmap,
-	.is_enabled = regulator_is_enabled_regmap,
-	.list_voltage = regulator_list_voltage_table,
-	.map_voltage = regulator_map_voltage_ascend,
-	.set_voltage_sel = regulator_set_voltage_sel_regmap,
-	.get_voltage_sel = regulator_get_voltage_sel_regmap,
-	.set_voltage_time_sel = regulator_set_voltage_time_sel,
-};
-
-static const struct regulator_ops bd71837_buck_regulator_nolinear_ops = {
-	.enable = regulator_enable_regmap,
-	.disable = regulator_disable_regmap,
-	.is_enabled = regulator_is_enabled_regmap,
-	.list_voltage = regulator_list_voltage_table,
-	.map_voltage = regulator_map_voltage_ascend,
-	.set_voltage_sel = bd718xx_set_voltage_sel_restricted,
-	.get_voltage_sel = regulator_get_voltage_sel_regmap,
-	.set_voltage_time_sel = regulator_set_voltage_time_sel,
-};
-
-static const struct regulator_ops bd718xx_dvs_buck_regulator_ops = {
-	.enable = regulator_enable_regmap,
-	.disable = regulator_disable_regmap,
-	.is_enabled = regulator_is_enabled_regmap,
+/*
+ * OPS for BD71837
+ */
+BD718XX_OPS(bd71837_pickable_range_ldo_ops,
+	    regulator_list_voltage_pickable_linear_range, NULL,
+	    bd71837_set_voltage_sel_pickable_restricted,
+	    regulator_get_voltage_sel_pickable_regmap, NULL, NULL);
+
+BD718XX_OPS(bd71837_pickable_range_buck_ops,
+	    regulator_list_voltage_pickable_linear_range, NULL,
+	    bd71837_set_voltage_sel_pickable_restricted,
+	    regulator_get_voltage_sel_pickable_regmap,
+	    regulator_set_voltage_time_sel, NULL);
+
+BD718XX_OPS(bd71837_ldo_regulator_ops, regulator_list_voltage_linear_range,
+	    NULL, bd71837_set_voltage_sel_restricted,
+	    regulator_get_voltage_sel_regmap, NULL, NULL);
+
+BD718XX_OPS(bd71837_ldo_regulator_nolinear_ops, regulator_list_voltage_table,
+	    NULL, bd71837_set_voltage_sel_restricted,
+	    regulator_get_voltage_sel_regmap, NULL, NULL);
+
+BD718XX_OPS(bd71837_buck_regulator_ops, regulator_list_voltage_linear_range,
+	    NULL, bd71837_set_voltage_sel_restricted,
+	    regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel,
+	    NULL);
+
+BD718XX_OPS(bd71837_buck_regulator_nolinear_ops, regulator_list_voltage_table,
+	    regulator_map_voltage_ascend, bd718xx_set_voltage_sel_restricted,
+	    regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel,
+	    NULL);
+/*
+ * BD71837 bucks 3 and 4 support defining their enable/disable state also
+ * when buck enable state is under HW state machine control. In that case the
+ * bit [2] in CTRL register is used to indicate if regulator should be ON.
+ */
+static const struct regulator_ops bd71837_buck34_ops_hwctrl = {
+	.is_enabled = bd71837_get_buck34_enable_hwctrl,
 	.list_voltage = regulator_list_voltage_linear_range,
 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
@@ -329,6 +351,14 @@ static const struct regulator_ops bd718xx_dvs_buck_regulator_ops = {
 	.set_ramp_delay = bd718xx_buck1234_set_ramp_delay,
 };
 
+/*
+ * OPS for all of the ICs - BD718(37/47/50)
+ */
+BD718XX_OPS(bd718xx_dvs_buck_regulator_ops, regulator_list_voltage_linear_range,
+	    NULL, regulator_set_voltage_sel_regmap,
+	    regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel,
+	    bd718xx_buck1234_set_ramp_delay);
+
 /*
  * BD71837 BUCK1/2/3/4
  * BD71847 BUCK1/2
@@ -543,14 +573,37 @@ static int buck_set_hw_dvs_levels(struct device_node *np,
 	return rohm_regulator_set_dvs_levels(&data->dvs, np, desc, cfg->regmap);
 }
 
-static const struct bd718xx_regulator_data bd71847_regulators[] = {
+const struct regulator_ops *bd71847_swcontrol_ops[] = {
+	&bd718xx_dvs_buck_regulator_ops, &bd718xx_dvs_buck_regulator_ops,
+	&bd718xx_pickable_range_buck_ops, &bd718xx_pickable_range_buck_ops,
+	&bd718xx_buck_regulator_nolinear_ops, &bd718xx_buck_regulator_ops,
+	&bd718xx_pickable_range_ldo_ops, &bd718xx_ldo_regulator_nolinear_ops,
+	&bd718xx_ldo_regulator_ops, &bd718xx_ldo_regulator_ops,
+	&bd718xx_pickable_range_ldo_ops, &bd718xx_ldo_regulator_ops,
+};
+
+const struct regulator_ops *bd71847_hwcontrol_ops[] = {
+	&BD718XX_HWOPNAME(bd718xx_dvs_buck_regulator_ops),
+	&BD718XX_HWOPNAME(bd718xx_dvs_buck_regulator_ops),
+	&BD718XX_HWOPNAME(bd718xx_pickable_range_buck_ops),
+	&BD718XX_HWOPNAME(bd718xx_pickable_range_buck_ops),
+	&BD718XX_HWOPNAME(bd718xx_buck_regulator_nolinear_ops),
+	&BD718XX_HWOPNAME(bd718xx_buck_regulator_ops),
+	&BD718XX_HWOPNAME(bd718xx_pickable_range_ldo_ops),
+	&BD718XX_HWOPNAME(bd718xx_ldo_regulator_nolinear_ops),
+	&BD718XX_HWOPNAME(bd718xx_ldo_regulator_ops),
+	&BD718XX_HWOPNAME(bd718xx_ldo_regulator_ops),
+	&bd718xx_ldo5_ops_hwstate,
+	&BD718XX_HWOPNAME(bd718xx_ldo_regulator_ops),
+};
+
+static struct bd718xx_regulator_data bd71847_regulators[] = {
 	{
 		.desc = {
 			.name = "buck1",
 			.of_match = of_match_ptr("BUCK1"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_BUCK1,
-			.ops = &bd718xx_dvs_buck_regulator_ops,
 			.type = REGULATOR_VOLTAGE,
 			.n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM,
 			.linear_ranges = bd718xx_dvs_buck_volts,
@@ -585,7 +638,6 @@ static const struct bd718xx_regulator_data bd71847_regulators[] = {
 			.of_match = of_match_ptr("BUCK2"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_BUCK2,
-			.ops = &bd718xx_dvs_buck_regulator_ops,
 			.type = REGULATOR_VOLTAGE,
 			.n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM,
 			.linear_ranges = bd718xx_dvs_buck_volts,
@@ -616,7 +668,6 @@ static const struct bd718xx_regulator_data bd71847_regulators[] = {
 			.of_match = of_match_ptr("BUCK3"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_BUCK3,
-			.ops = &bd718xx_pickable_range_buck_ops,
 			.type = REGULATOR_VOLTAGE,
 			.n_voltages = BD71847_BUCK3_VOLTAGE_NUM,
 			.linear_ranges = bd71847_buck3_volts,
@@ -643,7 +694,6 @@ static const struct bd718xx_regulator_data bd71847_regulators[] = {
 			.of_match = of_match_ptr("BUCK4"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_BUCK4,
-			.ops = &bd718xx_pickable_range_buck_ops,
 			.type = REGULATOR_VOLTAGE,
 			.n_voltages = BD71847_BUCK4_VOLTAGE_NUM,
 			.linear_ranges = bd71847_buck4_volts,
@@ -670,7 +720,6 @@ static const struct bd718xx_regulator_data bd71847_regulators[] = {
 			.of_match = of_match_ptr("BUCK5"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_BUCK5,
-			.ops = &bd718xx_buck_regulator_nolinear_ops,
 			.type = REGULATOR_VOLTAGE,
 			.volt_table = &bd718xx_3rd_nodvs_buck_volts[0],
 			.n_voltages = ARRAY_SIZE(bd718xx_3rd_nodvs_buck_volts),
@@ -692,7 +741,6 @@ static const struct bd718xx_regulator_data bd71847_regulators[] = {
 			.of_match = of_match_ptr("BUCK6"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_BUCK6,
-			.ops = &bd718xx_buck_regulator_ops,
 			.type = REGULATOR_VOLTAGE,
 			.n_voltages = BD718XX_4TH_NODVS_BUCK_VOLTAGE_NUM,
 			.linear_ranges = bd718xx_4th_nodvs_buck_volts,
@@ -716,7 +764,6 @@ static const struct bd718xx_regulator_data bd71847_regulators[] = {
 			.of_match = of_match_ptr("LDO1"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_LDO1,
-			.ops = &bd718xx_pickable_range_ldo_ops,
 			.type = REGULATOR_VOLTAGE,
 			.n_voltages = BD718XX_LDO1_VOLTAGE_NUM,
 			.linear_ranges = bd718xx_ldo1_volts,
@@ -742,7 +789,6 @@ static const struct bd718xx_regulator_data bd71847_regulators[] = {
 			.of_match = of_match_ptr("LDO2"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_LDO2,
-			.ops = &bd718xx_ldo_regulator_nolinear_ops,
 			.type = REGULATOR_VOLTAGE,
 			.volt_table = &ldo_2_volts[0],
 			.vsel_reg = BD718XX_REG_LDO2_VOLT,
@@ -764,7 +810,6 @@ static const struct bd718xx_regulator_data bd71847_regulators[] = {
 			.of_match = of_match_ptr("LDO3"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_LDO3,
-			.ops = &bd718xx_ldo_regulator_ops,
 			.type = REGULATOR_VOLTAGE,
 			.n_voltages = BD718XX_LDO3_VOLTAGE_NUM,
 			.linear_ranges = bd718xx_ldo3_volts,
@@ -787,7 +832,6 @@ static const struct bd718xx_regulator_data bd71847_regulators[] = {
 			.of_match = of_match_ptr("LDO4"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_LDO4,
-			.ops = &bd718xx_ldo_regulator_ops,
 			.type = REGULATOR_VOLTAGE,
 			.n_voltages = BD718XX_LDO4_VOLTAGE_NUM,
 			.linear_ranges = bd718xx_ldo4_volts,
@@ -810,7 +854,6 @@ static const struct bd718xx_regulator_data bd71847_regulators[] = {
 			.of_match = of_match_ptr("LDO5"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_LDO5,
-			.ops = &bd718xx_pickable_range_ldo_ops,
 			.type = REGULATOR_VOLTAGE,
 			.n_voltages = BD71847_LDO5_VOLTAGE_NUM,
 			.linear_ranges = bd71847_ldo5_volts,
@@ -836,7 +879,6 @@ static const struct bd718xx_regulator_data bd71847_regulators[] = {
 			.of_match = of_match_ptr("LDO6"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_LDO6,
-			.ops = &bd718xx_ldo_regulator_ops,
 			.type = REGULATOR_VOLTAGE,
 			.n_voltages = BD718XX_LDO6_VOLTAGE_NUM,
 			.linear_ranges = bd718xx_ldo6_volts,
@@ -857,14 +899,41 @@ static const struct bd718xx_regulator_data bd71847_regulators[] = {
 	},
 };
 
-static const struct bd718xx_regulator_data bd71837_regulators[] = {
+const struct regulator_ops *bd71837_swcontrol_ops[] = {
+	&bd718xx_dvs_buck_regulator_ops, &bd718xx_dvs_buck_regulator_ops,
+	&bd718xx_dvs_buck_regulator_ops, &bd718xx_dvs_buck_regulator_ops,
+	&bd71837_pickable_range_buck_ops, &bd71837_buck_regulator_ops,
+	&bd71837_buck_regulator_nolinear_ops, &bd71837_buck_regulator_ops,
+	&bd71837_pickable_range_ldo_ops, &bd71837_ldo_regulator_nolinear_ops,
+	&bd71837_ldo_regulator_ops, &bd71837_ldo_regulator_ops,
+	&bd71837_ldo_regulator_ops, &bd71837_ldo_regulator_ops,
+	&bd71837_ldo_regulator_ops,
+};
+
+const struct regulator_ops *bd71837_hwcontrol_ops[] = {
+	&BD718XX_HWOPNAME(bd718xx_dvs_buck_regulator_ops),
+	&BD718XX_HWOPNAME(bd718xx_dvs_buck_regulator_ops),
+	&bd71837_buck34_ops_hwctrl, &bd71837_buck34_ops_hwctrl,
+	&BD718XX_HWOPNAME(bd71837_pickable_range_buck_ops),
+	&BD718XX_HWOPNAME(bd71837_buck_regulator_ops),
+	&BD718XX_HWOPNAME(bd71837_buck_regulator_nolinear_ops),
+	&BD718XX_HWOPNAME(bd71837_buck_regulator_ops),
+	&BD718XX_HWOPNAME(bd71837_pickable_range_ldo_ops),
+	&BD718XX_HWOPNAME(bd71837_ldo_regulator_nolinear_ops),
+	&BD718XX_HWOPNAME(bd71837_ldo_regulator_ops),
+	&BD718XX_HWOPNAME(bd71837_ldo_regulator_ops),
+	&BD718XX_HWOPNAME(bd71837_ldo_regulator_ops),
+	&BD718XX_HWOPNAME(bd71837_ldo_regulator_ops),
+	&BD718XX_HWOPNAME(bd71837_ldo_regulator_ops),
+};
+
+static struct bd718xx_regulator_data bd71837_regulators[] = {
 	{
 		.desc = {
 			.name = "buck1",
 			.of_match = of_match_ptr("BUCK1"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_BUCK1,
-			.ops = &bd718xx_dvs_buck_regulator_ops,
 			.type = REGULATOR_VOLTAGE,
 			.n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM,
 			.linear_ranges = bd718xx_dvs_buck_volts,
@@ -898,7 +967,6 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
 			.of_match = of_match_ptr("BUCK2"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_BUCK2,
-			.ops = &bd718xx_dvs_buck_regulator_ops,
 			.type = REGULATOR_VOLTAGE,
 			.n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM,
 			.linear_ranges = bd718xx_dvs_buck_volts,
@@ -929,7 +997,6 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
 			.of_match = of_match_ptr("BUCK3"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_BUCK3,
-			.ops = &bd718xx_dvs_buck_regulator_ops,
 			.type = REGULATOR_VOLTAGE,
 			.n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM,
 			.linear_ranges = bd718xx_dvs_buck_volts,
@@ -958,7 +1025,6 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
 			.of_match = of_match_ptr("BUCK4"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_BUCK4,
-			.ops = &bd718xx_dvs_buck_regulator_ops,
 			.type = REGULATOR_VOLTAGE,
 			.n_voltages = BD718XX_DVS_BUCK_VOLTAGE_NUM,
 			.linear_ranges = bd718xx_dvs_buck_volts,
@@ -987,7 +1053,6 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
 			.of_match = of_match_ptr("BUCK5"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_BUCK5,
-			.ops = &bd71837_pickable_range_buck_ops,
 			.type = REGULATOR_VOLTAGE,
 			.n_voltages = BD71837_BUCK5_VOLTAGE_NUM,
 			.linear_ranges = bd71837_buck5_volts,
@@ -1014,7 +1079,6 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
 			.of_match = of_match_ptr("BUCK6"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_BUCK6,
-			.ops = &bd71837_buck_regulator_ops,
 			.type = REGULATOR_VOLTAGE,
 			.n_voltages = BD71837_BUCK6_VOLTAGE_NUM,
 			.linear_ranges = bd71837_buck6_volts,
@@ -1038,7 +1102,6 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
 			.of_match = of_match_ptr("BUCK7"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_BUCK7,
-			.ops = &bd71837_buck_regulator_nolinear_ops,
 			.type = REGULATOR_VOLTAGE,
 			.volt_table = &bd718xx_3rd_nodvs_buck_volts[0],
 			.n_voltages = ARRAY_SIZE(bd718xx_3rd_nodvs_buck_volts),
@@ -1060,7 +1123,6 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
 			.of_match = of_match_ptr("BUCK8"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_BUCK8,
-			.ops = &bd71837_buck_regulator_ops,
 			.type = REGULATOR_VOLTAGE,
 			.n_voltages = BD718XX_4TH_NODVS_BUCK_VOLTAGE_NUM,
 			.linear_ranges = bd718xx_4th_nodvs_buck_volts,
@@ -1084,7 +1146,6 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
 			.of_match = of_match_ptr("LDO1"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_LDO1,
-			.ops = &bd71837_pickable_range_ldo_ops,
 			.type = REGULATOR_VOLTAGE,
 			.n_voltages = BD718XX_LDO1_VOLTAGE_NUM,
 			.linear_ranges = bd718xx_ldo1_volts,
@@ -1110,7 +1171,6 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
 			.of_match = of_match_ptr("LDO2"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_LDO2,
-			.ops = &bd71837_ldo_regulator_nolinear_ops,
 			.type = REGULATOR_VOLTAGE,
 			.volt_table = &ldo_2_volts[0],
 			.vsel_reg = BD718XX_REG_LDO2_VOLT,
@@ -1132,7 +1192,6 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
 			.of_match = of_match_ptr("LDO3"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_LDO3,
-			.ops = &bd71837_ldo_regulator_ops,
 			.type = REGULATOR_VOLTAGE,
 			.n_voltages = BD718XX_LDO3_VOLTAGE_NUM,
 			.linear_ranges = bd718xx_ldo3_volts,
@@ -1155,7 +1214,6 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
 			.of_match = of_match_ptr("LDO4"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_LDO4,
-			.ops = &bd71837_ldo_regulator_ops,
 			.type = REGULATOR_VOLTAGE,
 			.n_voltages = BD718XX_LDO4_VOLTAGE_NUM,
 			.linear_ranges = bd718xx_ldo4_volts,
@@ -1178,7 +1236,6 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
 			.of_match = of_match_ptr("LDO5"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_LDO5,
-			.ops = &bd71837_ldo_regulator_ops,
 			.type = REGULATOR_VOLTAGE,
 			.n_voltages = BD71837_LDO5_VOLTAGE_NUM,
 			.linear_ranges = bd71837_ldo5_volts,
@@ -1205,7 +1262,6 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
 			.of_match = of_match_ptr("LDO6"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_LDO6,
-			.ops = &bd71837_ldo_regulator_ops,
 			.type = REGULATOR_VOLTAGE,
 			.n_voltages = BD718XX_LDO6_VOLTAGE_NUM,
 			.linear_ranges = bd718xx_ldo6_volts,
@@ -1232,7 +1288,6 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
 			.of_match = of_match_ptr("LDO7"),
 			.regulators_node = of_match_ptr("regulators"),
 			.id = BD718XX_LDO7,
-			.ops = &bd71837_ldo_regulator_ops,
 			.type = REGULATOR_VOLTAGE,
 			.n_voltages = BD71837_LDO7_VOLTAGE_NUM,
 			.linear_ranges = bd71837_ldo7_volts,
@@ -1251,15 +1306,57 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
 	},
 };
 
+static void mark_hw_controlled(struct device *dev, struct device_node *np,
+			       struct bd718xx_regulator_data *reg_data,
+			       unsigned int num_reg_data, int *info)
+{
+	int i;
+
+	for (i = 1; i <= num_reg_data; i++) {
+		if (!of_node_name_eq(np, reg_data[i-1].desc.of_match))
+			continue;
+
+		*info |= 1 << (i - 1);
+		dev_dbg(dev, "regulator %d runlevel controlled\n", i);
+		return;
+	}
+	dev_warn(dev, "Bad regulator node\n");
+}
+
+static int get_hw_controlled_regulators(struct device *dev,
+					struct bd718xx_regulator_data *reg_data,
+					unsigned int num_reg_data, int *info)
+{
+	struct device_node *np;
+	struct device_node *nproot = dev->of_node;
+	const char *prop = "rohm,no-regulator-enable-control";
+
+	*info = 0;
+
+	nproot = of_get_child_by_name(nproot, "regulators");
+	if (!nproot) {
+		dev_err(dev, "failed to find regulators node\n");
+		return -ENODEV;
+	}
+	for_each_child_of_node(nproot, np)
+		if (of_property_read_bool(np, prop))
+			mark_hw_controlled(dev, np, reg_data, num_reg_data,
+					   info);
+
+	of_node_put(nproot);
+	return 0;
+}
+
 static int bd718xx_probe(struct platform_device *pdev)
 {
 	struct bd718xx *mfd;
 	struct regulator_config config = { 0 };
-	int i, j, err;
+	int i, j, err, omit_enable;
 	bool use_snvs;
-	const struct bd718xx_regulator_data *reg_data;
+	struct bd718xx_regulator_data *reg_data;
 	unsigned int num_reg_data;
 	enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data;
+	const struct regulator_ops **swops, **hwops;
 
 	mfd = dev_get_drvdata(pdev->dev.parent);
 	if (!mfd) {
@@ -1272,10 +1369,14 @@ static int bd718xx_probe(struct platform_device *pdev)
 	case ROHM_CHIP_TYPE_BD71837:
 		reg_data = bd71837_regulators;
 		num_reg_data = ARRAY_SIZE(bd71837_regulators);
+		swops = &bd71837_swcontrol_ops[0];
+		hwops = &bd71837_hwcontrol_ops[0];
 		break;
 	case ROHM_CHIP_TYPE_BD71847:
 		reg_data = bd71847_regulators;
 		num_reg_data = ARRAY_SIZE(bd71847_regulators);
+		swops = &bd71847_swcontrol_ops[0];
+		hwops = &bd71847_hwcontrol_ops[0];
 		break;
 	default:
 		dev_err(&pdev->dev, "Unsupported chip type\n");
@@ -1321,16 +1422,33 @@ static int bd718xx_probe(struct platform_device *pdev)
 
 	config.dev = pdev->dev.parent;
 	config.regmap = mfd->chip.regmap;
+	/*
+	 * There are cases when we want to leave the enable-control for
+	 * the HW state machine and use this driver only for voltage control.
+	 * One special case is when we use PMIC_STBY_REQ line from SoC to PMIC
+	 * in order to set the system to SUSPEND state.
+	 *
+	 * If regulator is taken under SW control the regulator state will not
+	 * be affected by PMIC state machine - Eg. regulator is likely to stay
+	 * on even in SUSPEND
+	 */
+	get_hw_controlled_regulators(pdev->dev.parent, reg_data, num_reg_data,
+				     &omit_enable);
 
 	for (i = 0; i < num_reg_data; i++) {
 
-		const struct regulator_desc *desc;
+		struct regulator_desc *desc;
 		struct regulator_dev *rdev;
-		const struct bd718xx_regulator_data *r;
+		struct bd718xx_regulator_data *r;
+		int no_enable_control = omit_enable & (1 << i);
 
 		r = &reg_data[i];
 		desc = &r->desc;
 
+		if (no_enable_control)
+			desc->ops = hwops[i];
+		else
+			desc->ops = swops[i];
 
 		rdev = devm_regulator_register(&pdev->dev, desc, &config);
 		if (IS_ERR(rdev)) {
@@ -1357,8 +1475,9 @@ static int bd718xx_probe(struct platform_device *pdev)
 		 * enable SW control for crucial regulators if snvs state is
 		 * used
 		 */
-		if (!use_snvs || !rdev->constraints->always_on ||
-		    !rdev->constraints->boot_on) {
+		if (!no_enable_control && (!use_snvs ||
+		    !rdev->constraints->always_on ||
+		    !rdev->constraints->boot_on)) {
 			err = regmap_update_bits(mfd->chip.regmap, r->init.reg,
 						 r->init.mask, r->init.val);
 			if (err) {
-- 
2.21.0


-- 
Matti Vaittinen, Linux device drivers
ROHM Semiconductors, Finland SWDC
Kiviharjunlenkki 1E
90220 OULU
FINLAND

~~~ "I don't think so," said Rene Descartes. Just then he vanished ~~~
Simon says - in Latin please.
~~~ "non cogito me" dixit Rene Descarte, deinde evanescavit ~~~
Thanks to Simon Glass for the translation =] 

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 0/4] Support regulator ON/OFF by PMIC state machine.
  2020-09-03 18:37 [PATCH 0/4] Support regulator ON/OFF by PMIC state machine Matti Vaittinen
                   ` (3 preceding siblings ...)
  2020-09-03 18:39 ` [PATCH 4/4] regulator: bd718x7 fix regulator states at SUSPEND Matti Vaittinen
@ 2020-09-04 10:03 ` Mark Brown
  4 siblings, 0 replies; 6+ messages in thread
From: Mark Brown @ 2020-09-04 10:03 UTC (permalink / raw)
  To: Matti Vaittinen, mazziesaccount
  Cc: Liam Girdwood, devicetree, linux-kernel, Rob Herring, linux-power

On Thu, 3 Sep 2020 21:37:51 +0300, Matti Vaittinen wrote:
> Support regulator enable/disable via BD718(37/47/50) PMIC state machine.
> 
> The ROHM BD718(37/47/50) PMICs are mainly used for powering i.MX8 based
> systems. On some setups the i.MX8 SoC uses a IO line to suspend the
> system. These PMICs support this via PMIC internal HW state machine
> which can be toggled for example by the PMIC_STBY_REQ IO-pin.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git for-next

Thanks!

[1/4] regulator: bd718x7 initialize regulator config only once
      commit: df9db2541a82ec18c474942a93729420d37fac81
[2/4] regulator: bd71837: add property for omitting ON/OFF control
      commit: 4788c692bec76dc33c646a07a4aaf7e2dd60091e
[3/4] regulator: bd71847: add property for omitting ON/OFF control
      commit: 6656d4462c7ac5ca0bc5d5a8a91a8c98f0fd1409
[4/4] regulator: bd718x7 fix regulator states at SUSPEND
      commit: 1d848d681c4d4e148193b699a6e5f222e8621519

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2020-09-04 10:04 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-03 18:37 [PATCH 0/4] Support regulator ON/OFF by PMIC state machine Matti Vaittinen
2020-09-03 18:38 ` [PATCH 1/4] regulator: bd718x7 initialize regulator config only once Matti Vaittinen
2020-09-03 18:38 ` [PATCH 2/4] dt-bindings: regulator: bd71837: add property for omitting ON/OFF control Matti Vaittinen
2020-09-03 18:38 ` [PATCH 3/4] dt-bindings: regulator: bd71847: " Matti Vaittinen
2020-09-03 18:39 ` [PATCH 4/4] regulator: bd718x7 fix regulator states at SUSPEND Matti Vaittinen
2020-09-04 10:03 ` [PATCH 0/4] Support regulator ON/OFF by PMIC state machine Mark Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).