[PATCH v8 10/10] MAINTAINERS: Add reviewer for regulator irq_helpers

2021-04-19 Thread Matti Vaittinen
Add a reviewer entry for the regulator irq_helpers.

Signed-off-by: Matti Vaittinen 
---
Changelog:
 v7 - onwards
  - no changes
 v6:
  - New patch
---
 MAINTAINERS | 4 
 1 file changed, 4 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 7fdc513392f4..c917d85feccd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19228,6 +19228,10 @@ F: include/dt-bindings/regulator/
 F: include/linux/regulator/
 K: regulator_get_optional
 
+VOLTAGE AND CURRENT REGULATOR IRQ HELPERS
+R: Matti Vaittinen 
+F: drivers/regulator/irq_helpers.c
+
 VRF
 M: David Ahern 
 L: net...@vger.kernel.org
-- 
2.25.4


-- 
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 =] 


[PATCH v8 09/10] regulator: bd9576: Fix the driver name in id table

2021-04-19 Thread Matti Vaittinen
Driver name was changed in MFD cell:
https://lore.kernel.org/lkml/560b9748094392493ebf7af11b6cc558776c4fd5.1613031055.git.matti.vaitti...@fi.rohmeurope.com/
Fix the ID table to match this.

Signed-off-by: Matti Vaittinen 
---
No changes since RFC-v2
---
 drivers/regulator/bd9576-regulator.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/regulator/bd9576-regulator.c 
b/drivers/regulator/bd9576-regulator.c
index 0d55d383d2aa..aeb816cf9ad3 100644
--- a/drivers/regulator/bd9576-regulator.c
+++ b/drivers/regulator/bd9576-regulator.c
@@ -1117,8 +1117,8 @@ static int bd957x_probe(struct platform_device *pdev)
 }
 
 static const struct platform_device_id bd957x_pmic_id[] = {
-   { "bd9573-pmic", ROHM_CHIP_TYPE_BD9573 },
-   { "bd9576-pmic", ROHM_CHIP_TYPE_BD9576 },
+   { "bd9573-regulator", ROHM_CHIP_TYPE_BD9573 },
+   { "bd9576-regulator", ROHM_CHIP_TYPE_BD9576 },
{ },
 };
 MODULE_DEVICE_TABLE(platform, bd957x_pmic_id);
-- 
2.25.4


-- 
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 =] 


[PATCH v8 08/10] regulator: bd9576: Support error reporting

2021-04-19 Thread Matti Vaittinen
BD9573 and BD9576 support set of "protection" interrupts for "fatal"
issues. Those lead to SOC reset as PMIC shuts the power outputs. Thus
there is no relevant IRQ handling for them.

Few "detection" interrupts were added to the BD9576 with the idea that
SOC could take some recovery-action before error gets unrecoverable.

Add support for over and under voltage detection for Vout1 ... Vout4
and VoutL1. Add over-current detection for VoutS1 and finally a
thermal warning (common for all regulators) which alerts 30 C
before temperature reaches the thermal shutdown point. This way
consumer drivers can build error-recovery mechanisms.

Unfortunately the BD9576 interrupt logic was not re-evaluated. IRQs
are not designed to be properly acknowleged - and IRQ line is kept
active for whole duration of error condition (in comparison to
informing only about state change).

Signed-off-by: Matti Vaittinen 
---
No changes since RFC-v3
---
 drivers/regulator/bd9576-regulator.c | 1056 ++
 1 file changed, 929 insertions(+), 127 deletions(-)

diff --git a/drivers/regulator/bd9576-regulator.c 
b/drivers/regulator/bd9576-regulator.c
index a8b5832a5a1b..0d55d383d2aa 100644
--- a/drivers/regulator/bd9576-regulator.c
+++ b/drivers/regulator/bd9576-regulator.c
@@ -2,10 +2,10 @@
 // Copyright (C) 2020 ROHM Semiconductors
 // ROHM BD9576MUF/BD9573MUF regulator driver
 
-#include 
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -16,11 +16,18 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 
 #define BD957X_VOUTS1_VOLT 330
 #define BD957X_VOUTS4_BASE_VOLT103
 #define BD957X_VOUTS34_NUM_VOLT32
 
+#define BD9576_THERM_IRQ_MASK_TW   BIT(5)
+#define BD9576_xVD_IRQ_MASK_VOUTL1 BIT(5)
+#define BD9576_UVD_IRQ_MASK_VOUTS1_OCW BIT(6)
+#define BD9576_xVD_IRQ_MASK_VOUT1TO4   0x0F
+
 static int vout1_volt_table[] = {500, 490, 480, 470, 460,
 450, 450, 450, 500, 510,
 520, 530, 540, 550, 550,
@@ -36,9 +43,85 @@ static int voutl1_volt_table[] = {250, 254, 258, 
262, 266,
  242, 238, 234, 230, 226,
  222};
 
+static const struct linear_range vout1_xvd_ranges[] = {
+   REGULATOR_LINEAR_RANGE(225000, 0x01, 0x2b, 0),
+   REGULATOR_LINEAR_RANGE(225000, 0x2c, 0x54, 5000),
+   REGULATOR_LINEAR_RANGE(425000, 0x55, 0x7f, 0),
+};
+
+static const struct linear_range vout234_xvd_ranges[] = {
+   REGULATOR_LINEAR_RANGE(17000, 0x01, 0x0f, 0),
+   REGULATOR_LINEAR_RANGE(17000, 0x10, 0x6d, 1000),
+   REGULATOR_LINEAR_RANGE(11, 0x6e, 0x7f, 0),
+};
+
+static const struct linear_range voutL1_xvd_ranges[] = {
+   REGULATOR_LINEAR_RANGE(34000, 0x01, 0x0f, 0),
+   REGULATOR_LINEAR_RANGE(34000, 0x10, 0x6d, 2000),
+   REGULATOR_LINEAR_RANGE(22, 0x6e, 0x7f, 0),
+};
+
+static struct linear_range voutS1_ocw_ranges_internal[] = {
+   REGULATOR_LINEAR_RANGE(20, 0x01, 0x04, 0),
+   REGULATOR_LINEAR_RANGE(25, 0x05, 0x18, 5),
+   REGULATOR_LINEAR_RANGE(120, 0x19, 0x3f, 0),
+};
+
+static struct linear_range voutS1_ocw_ranges[] = {
+   REGULATOR_LINEAR_RANGE(5, 0x01, 0x04, 0),
+   REGULATOR_LINEAR_RANGE(6, 0x05, 0x18, 1),
+   REGULATOR_LINEAR_RANGE(25, 0x19, 0x3f, 0),
+};
+
+static struct linear_range voutS1_ocp_ranges_internal[] = {
+   REGULATOR_LINEAR_RANGE(30, 0x01, 0x06, 0),
+   REGULATOR_LINEAR_RANGE(35, 0x7, 0x1b, 5),
+   REGULATOR_LINEAR_RANGE(135, 0x1c, 0x3f, 0),
+};
+
+static struct linear_range voutS1_ocp_ranges[] = {
+   REGULATOR_LINEAR_RANGE(7, 0x01, 0x06, 0),
+   REGULATOR_LINEAR_RANGE(8, 0x7, 0x1b, 1),
+   REGULATOR_LINEAR_RANGE(28, 0x1c, 0x3f, 0),
+};
+
 struct bd957x_regulator_data {
struct regulator_desc desc;
int base_voltage;
+   struct regulator_dev *rdev;
+   int ovd_notif;
+   int uvd_notif;
+   int temp_notif;
+   int ovd_err;
+   int uvd_err;
+   int temp_err;
+   const struct linear_range *xvd_ranges;
+   int num_xvd_ranges;
+   bool oc_supported;
+   unsigned int ovd_reg;
+   unsigned int uvd_reg;
+   unsigned int xvd_mask;
+   unsigned int ocp_reg;
+   unsigned int ocp_mask;
+   unsigned int ocw_reg;
+   unsigned int ocw_mask;
+   unsigned int ocw_rfet;
+};
+
+#define BD9576_NUM_REGULATORS 6
+#define BD9576_NUM_OVD_REGULATORS 5
+
+struct bd957x_data {
+   struct bd957x_regulator_data regulator_data[BD9576_NUM_REGULATORS];
+   struct regmap *regmap;
+   struct delayed_work therm_irq_suppress;
+   struct delayed_work ovd_irq_suppress;
+   struct delayed_work uvd_irq_suppress;
+   unsigned int therm_irq;
+   unsigned int ovd_irq

[PATCH v8 07/10] dt-bindings: regulator: bd9576 add FET ON-resistance for OCW

2021-04-19 Thread Matti Vaittinen
BD9576MUF provides over-current protection and detection. Current is
measured as voltage loss over external FET. Allow specifying FET's on
resistance so current monitoring limits can be converted to voltages.

Signed-off-by: Matti Vaittinen 
Reviewed-by: Rob Herring 

---
v5 onwards:
  - No changes
v4:
  - Fixed the description indentiation
---
 .../bindings/regulator/rohm,bd9576-regulator.yaml   | 6 ++
 1 file changed, 6 insertions(+)

diff --git 
a/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml 
b/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml
index b6515a0cee62..7cb74cc8c5d9 100644
--- a/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml
+++ b/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml
@@ -27,6 +27,12 @@ patternProperties:
   Properties for single regulator.
 $ref: "regulator.yaml#"
 
+properties:
+  rohm,ocw-fet-ron-micro-ohms:
+description: |
+  External FET's ON-resistance. Required if VoutS1 OCP/OCW is
+  to be set.
+
 required:
   - regulator-name
 
-- 
2.25.4


-- 
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 =] 


[PATCH v8 06/10] regulator: add property parsing and callbacks to set protection limits

2021-04-19 Thread Matti Vaittinen
Add DT property parsing code and setting callback for regulator over/under
voltage, over-current and temperature error limits.

Signed-off-by: Matti Vaittinen 
---
No changes since RFC-v3
---
 drivers/regulator/core.c  | 122 +-
 drivers/regulator/of_regulator.c  |  58 ++
 drivers/regulator/qcom-labibb-regulator.c |  10 +-
 drivers/regulator/qcom_spmi-regulator.c   |   6 +-
 drivers/regulator/stpmic1_regulator.c |  20 +++-
 include/linux/regulator/driver.h  |  41 +++-
 include/linux/regulator/machine.h |  26 +
 7 files changed, 274 insertions(+), 9 deletions(-)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 0c45814aabea..88926c407b02 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1312,6 +1312,52 @@ static int machine_constraints_current(struct 
regulator_dev *rdev,
 
 static int _regulator_do_enable(struct regulator_dev *rdev);
 
+static int notif_set_limit(struct regulator_dev *rdev,
+  int (*set)(struct regulator_dev *, int, int, bool),
+  int limit, int severity)
+{
+   bool enable;
+
+   if (limit == REGULATOR_NOTIF_LIMIT_DISABLE) {
+   enable = false;
+   limit = 0;
+   } else {
+   enable = true;
+   }
+
+   if (limit == REGULATOR_NOTIF_LIMIT_ENABLE)
+   limit = 0;
+
+   return set(rdev, limit, severity, enable);
+}
+
+static int handle_notify_limits(struct regulator_dev *rdev,
+   int (*set)(struct regulator_dev *, int, int, bool),
+   struct notification_limit *limits)
+{
+   int ret = 0;
+
+   if (!set)
+   return -EOPNOTSUPP;
+
+   if (limits->prot)
+   ret = notif_set_limit(rdev, set, limits->prot,
+ REGULATOR_SEVERITY_PROT);
+   if (ret)
+   return ret;
+
+   if (limits->err)
+   ret = notif_set_limit(rdev, set, limits->err,
+ REGULATOR_SEVERITY_ERR);
+   if (ret)
+   return ret;
+
+   if (limits->warn)
+   ret = notif_set_limit(rdev, set, limits->warn,
+ REGULATOR_SEVERITY_WARN);
+
+   return ret;
+}
 /**
  * set_machine_constraints - sets regulator constraints
  * @rdev: regulator source
@@ -1397,9 +1443,27 @@ static int set_machine_constraints(struct regulator_dev 
*rdev)
}
}
 
+   /*
+* Existing logic does not warn if over_current_protection is given as
+* a constraint but driver does not support that. I think we should
+* warn about this type of issues as it is possible someone changes
+* PMIC on board to another type - and the another PMIC's driver does
+* not support setting protection. Board composer may happily believe
+* the DT limits are respected - especially if the new PMIC HW also
+* supports protection but the driver does not. I won't change the logic
+* without hearing more experienced opinion on this though.
+*
+* If warning is seen as a good idea then we can merge handling the
+* over-curret protection and detection and get rid of this special
+* handling.
+*/
if (rdev->constraints->over_current_protection
&& ops->set_over_current_protection) {
-   ret = ops->set_over_current_protection(rdev);
+   int lim = rdev->constraints->over_curr_limits.prot;
+
+   ret = ops->set_over_current_protection(rdev, lim,
+  REGULATOR_SEVERITY_PROT,
+  true);
if (ret < 0) {
rdev_err(rdev, "failed to set over current protection: 
%pe\n",
 ERR_PTR(ret));
@@ -1407,6 +1471,62 @@ static int set_machine_constraints(struct regulator_dev 
*rdev)
}
}
 
+   if (rdev->constraints->over_current_detection)
+   ret = handle_notify_limits(rdev,
+  ops->set_over_current_protection,
+  
>constraints->over_curr_limits);
+   if (ret) {
+   if (ret != -EOPNOTSUPP) {
+   rdev_err(rdev, "failed to set over current limits: 
%pe\n",
+ERR_PTR(ret));
+   return ret;
+   }
+   rdev_warn(rdev,
+ "IC does not support requested over-current 
limits\n");
+   }
+
+   if (rdev->constraints->over_voltage_detection)
+   ret = handle_notify_limits(rdev,
+  ops->se

[PATCH v8 05/10] regulator: IRQ based event/error notification helpers

2021-04-19 Thread Matti Vaittinen
Provide helper function for IC's implementing regulator notifications
when an IRQ fires. The helper also works for IRQs which can not be acked.
Helper can be set to disable the IRQ at handler and then re-enabling it
on delayed work later. The helper also adds regulator_get_error_flags()
errors in cache for the duration of IRQ disabling.

Signed-off-by: Matti Vaittinen 
Reviewed-by: Andy Shevchenko 

---
v8 onwards:
 - No changes since v7
v7 (mostly more fixes pointed by Andy)
 - fix regulator error_flags query
 - grammar/typos
 - do not BUG() but attempt to shut-down the system
 - use BITS_PER_TYPE()
v6 (fix issues noted by Andy):
 - remove unnecessary variable
 - use BIT(foo) instead of 1 << foo
 - use devm_add_action_or_reset()
 - do not check the irq parameter validity, leave that to
   request_threaded_irq()
 - put resource-managed function in devres.c
 - fix the kerneldocs for the new IRQ helpers
v5:
 - fix the pr_emerg print
v4:
 - Comment block styling
 - Added prints to point the potential HW failure before BUG()
 - Corrected typo from kerneldoc
 - added missing newlines
---
 drivers/regulator/Makefile   |   2 +-
 drivers/regulator/core.c |  29 ++-
 drivers/regulator/devres.c   |  52 
 drivers/regulator/irq_helpers.c  | 394 +++
 include/linux/regulator/driver.h | 135 +++
 5 files changed, 604 insertions(+), 8 deletions(-)
 create mode 100644 drivers/regulator/irq_helpers.c

diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 44d2f8bf4b74..e25f1c2d6c9b 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -4,7 +4,7 @@
 #
 
 
-obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o devres.o
+obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o devres.o 
irq_helpers.o
 obj-$(CONFIG_OF) += of_regulator.o
 obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
 obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 16114aea099a..0c45814aabea 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -4388,22 +4388,36 @@ unsigned int regulator_get_mode(struct regulator 
*regulator)
 }
 EXPORT_SYMBOL_GPL(regulator_get_mode);
 
+static int rdev_get_cached_err_flags(struct regulator_dev *rdev)
+{
+   int ret = 0;
+
+   if (rdev->use_cached_err) {
+   spin_lock(>err_lock);
+   ret = rdev->cached_err;
+   spin_unlock(>err_lock);
+   }
+   return ret;
+}
+
 static int _regulator_get_error_flags(struct regulator_dev *rdev,
unsigned int *flags)
 {
-   int ret;
+   int cached_flags, ret = 0;
 
regulator_lock(rdev);
 
-   /* sanity check */
-   if (!rdev->desc->ops->get_error_flags) {
+   cached_flags = rdev_get_cached_err_flags(rdev);
+
+   if (rdev->desc->ops->get_error_flags)
+   ret = rdev->desc->ops->get_error_flags(rdev, flags);
+   else if (!rdev->use_cached_err)
ret = -EINVAL;
-   goto out;
-   }
 
-   ret = rdev->desc->ops->get_error_flags(rdev, flags);
-out:
+   *flags |= cached_flags;
+
regulator_unlock(rdev);
+
return ret;
 }
 
@@ -5236,6 +5250,7 @@ regulator_register(const struct regulator_desc 
*regulator_desc,
goto rinse;
}
device_initialize(>dev);
+   spin_lock_init(>err_lock);
 
/*
 * Duplicate the config so the driver could override it after
diff --git a/drivers/regulator/devres.c b/drivers/regulator/devres.c
index 3091210889e3..a8de0aa88bad 100644
--- a/drivers/regulator/devres.c
+++ b/drivers/regulator/devres.c
@@ -481,3 +481,55 @@ void devm_regulator_unregister_notifier(struct regulator 
*regulator,
WARN_ON(rc);
 }
 EXPORT_SYMBOL_GPL(devm_regulator_unregister_notifier);
+
+static void regulator_irq_helper_drop(void *res)
+{
+   regulator_irq_helper_cancel();
+}
+
+/**
+ * devm_regulator_irq_helper - resource managed registration of IRQ based
+ * regulator event/error notifier
+ *
+ * @dev:   device to which lifetime the helper's lifetime is
+ * bound.
+ * @d: IRQ helper descriptor.
+ * @irq:   IRQ used to inform events/errors to be notified.
+ * @irq_flags: Extra IRQ flags to be OR'ed with the default
+ * IRQF_ONESHOT when requesting the (threaded) irq.
+ * @common_errs:   Errors which can be flagged by this IRQ for all rdevs.
+ * When IRQ is re-enabled these errors will be cleared
+ * from all associated regulators
+ * @per_rdev_errs: Optional error flag array describing errors specific
+ * for only some of the regulators. These errors will be
+ * or'ed with common errors. If this is given the

[PATCH v8 04/10] regulator: add warning flags

2021-04-19 Thread Matti Vaittinen
Add 'warning' level events and error flags to regulator core.
Current regulator core notifications are used to inform consumers
about errors where HW is misbehaving in such way it is assumed to
be broken/unrecoverable.

There are PMICs which are designed for system(s) that may have use
for regulator indications sent before HW is damaged so that some
board/consumer specific recovery-event can be performed while
continuing most of the normal operations.

Add new WARNING level events and notifications to be used for
that purpose.

Signed-off-by: Matti Vaittinen 
---
No changes since RFC-v2
---
 include/linux/regulator/consumer.h | 14 ++
 1 file changed, 14 insertions(+)

diff --git a/include/linux/regulator/consumer.h 
b/include/linux/regulator/consumer.h
index 20e84a84fb77..f72ca73631be 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -119,6 +119,16 @@ struct regulator_dev;
 #define REGULATOR_EVENT_PRE_DISABLE0x400
 #define REGULATOR_EVENT_ABORT_DISABLE  0x800
 #define REGULATOR_EVENT_ENABLE 0x1000
+/*
+ * Following notifications should be emitted only if detected condition
+ * is such that the HW is likely to still be working but consumers should
+ * take a recovery action to prevent problems esacalating into errors.
+ */
+#define REGULATOR_EVENT_UNDER_VOLTAGE_WARN 0x2000
+#define REGULATOR_EVENT_OVER_CURRENT_WARN  0x4000
+#define REGULATOR_EVENT_OVER_VOLTAGE_WARN  0x8000
+#define REGULATOR_EVENT_OVER_TEMP_WARN 0x1
+#define REGULATOR_EVENT_WARN_MASK  0x1E000
 
 /*
  * Regulator errors that can be queried using regulator_get_error_flags
@@ -138,6 +148,10 @@ struct regulator_dev;
 #define REGULATOR_ERROR_FAIL   BIT(4)
 #define REGULATOR_ERROR_OVER_TEMP  BIT(5)
 
+#define REGULATOR_ERROR_UNDER_VOLTAGE_WARN BIT(6)
+#define REGULATOR_ERROR_OVER_CURRENT_WARN  BIT(7)
+#define REGULATOR_ERROR_OVER_VOLTAGE_WARN  BIT(8)
+#define REGULATOR_ERROR_OVER_TEMP_WARN BIT(9)
 
 /**
  * struct pre_voltage_change_data - Data sent with PRE_VOLTAGE_CHANGE event
-- 
2.25.4


-- 
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 =] 


[PATCH v8 03/10] thermal: Use generic HW-protection shutdown API

2021-04-19 Thread Matti Vaittinen
The hardware shutdown function was exported from kernel/reboot for
other subsystems to use. Logic is copied from the thermal_core. The
protection mutex is replaced by an atomic_t to allow calls also from
an IRQ context.

Use the exported API instead of implementing own just for the
thermal_core.

Signed-off-by: Matti Vaittinen 

---
Changelog:
v8:
 - new patch (change added in v7, splitted in own patch at v8)

Use the exported API instead
---
 drivers/thermal/thermal_core.c | 63 +++---
 1 file changed, 4 insertions(+), 59 deletions(-)

diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 996c038f83a4..b1444845af38 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -36,10 +36,8 @@ static LIST_HEAD(thermal_governor_list);
 
 static DEFINE_MUTEX(thermal_list_lock);
 static DEFINE_MUTEX(thermal_governor_lock);
-static DEFINE_MUTEX(poweroff_lock);
 
 static atomic_t in_suspend;
-static bool power_off_triggered;
 
 static struct thermal_governor *def_governor;
 
@@ -327,70 +325,18 @@ static void handle_non_critical_trips(struct 
thermal_zone_device *tz, int trip)
   def_governor->throttle(tz, trip);
 }
 
-/**
- * thermal_emergency_poweroff_func - emergency poweroff work after a known 
delay
- * @work: work_struct associated with the emergency poweroff function
- *
- * This function is called in very critical situations to force
- * a kernel poweroff after a configurable timeout value.
- */
-static void thermal_emergency_poweroff_func(struct work_struct *work)
-{
-   /*
-* We have reached here after the emergency thermal shutdown
-* Waiting period has expired. This means orderly_poweroff has
-* not been able to shut off the system for some reason.
-* Try to shut down the system immediately using kernel_power_off
-* if populated
-*/
-   WARN(1, "Attempting kernel_power_off: Temperature too high\n");
-   kernel_power_off();
-
-   /*
-* Worst of the worst case trigger emergency restart
-*/
-   WARN(1, "Attempting emergency_restart: Temperature too high\n");
-   emergency_restart();
-}
-
-static DECLARE_DELAYED_WORK(thermal_emergency_poweroff_work,
-   thermal_emergency_poweroff_func);
-
-/**
- * thermal_emergency_poweroff - Trigger an emergency system poweroff
- *
- * This may be called from any critical situation to trigger a system shutdown
- * after a known period of time. By default this is not scheduled.
- */
-static void thermal_emergency_poweroff(void)
+void thermal_zone_device_critical(struct thermal_zone_device *tz)
 {
-   int poweroff_delay_ms = CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS;
/*
 * poweroff_delay_ms must be a carefully profiled positive value.
-* Its a must for thermal_emergency_poweroff_work to be scheduled
+* Its a must for forced_emergency_poweroff_work to be scheduled.
 */
-   if (poweroff_delay_ms <= 0)
-   return;
-   schedule_delayed_work(_emergency_poweroff_work,
- msecs_to_jiffies(poweroff_delay_ms));
-}
+   int poweroff_delay_ms = CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS;
 
-void thermal_zone_device_critical(struct thermal_zone_device *tz)
-{
dev_emerg(>device, "%s: critical temperature reached, "
  "shutting down\n", tz->type);
 
-   mutex_lock(_lock);
-   if (!power_off_triggered) {
-   /*
-* Queue a backup emergency shutdown in the event of
-* orderly_poweroff failure
-*/
-   thermal_emergency_poweroff();
-   orderly_poweroff(true);
-   power_off_triggered = true;
-   }
-   mutex_unlock(_lock);
+   hw_protection_shutdown("Temperature too high", poweroff_delay_ms);
 }
 EXPORT_SYMBOL(thermal_zone_device_critical);
 
@@ -1549,7 +1495,6 @@ static int __init thermal_init(void)
ida_destroy(_cdev_ida);
mutex_destroy(_list_lock);
mutex_destroy(_governor_lock);
-   mutex_destroy(_lock);
return result;
 }
 postcore_initcall(thermal_init);
-- 
2.25.4


-- 
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 =] 


[PATCH v8 02/10] reboot: Add hardware protection power-off

2021-04-19 Thread Matti Vaittinen
There can be few cases when we need to shut-down the system in order to
protect the hardware. Currently this is done at east by the thermal core
when temperature raises over certain limit.

Some PMICs can also generate interrupts for example for over-current or
over-voltage, voltage drops, short-circuit, ... etc. On some systems
these are a sign of hardware failure and only thing to do is try to
protect the rest of the hardware by shutting down the system.

Add shut-down logic which can be used by all subsystems instead of
implementing the shutdown in each subsystem. The logic is stolen from
thermal_core with difference of using atomic_t instead of a mutex in
order to allow calls directly from IRQ context.

Signed-off-by: Matti Vaittinen 

---

Changelog:
v8: (changes suggested by Daniel Lezcano)
 - replace a protection implemented by a flag + spin_lock_irqsave() with
   simple atomic_dec_and_test().
 - Split thermal-core changes and adding the new API to separate patches
v7:
 - New patch
---
 include/linux/reboot.h |  1 +
 kernel/reboot.c| 80 ++
 2 files changed, 81 insertions(+)

diff --git a/include/linux/reboot.h b/include/linux/reboot.h
index 3734cd8f38a8..af907a3d68d1 100644
--- a/include/linux/reboot.h
+++ b/include/linux/reboot.h
@@ -79,6 +79,7 @@ extern char poweroff_cmd[POWEROFF_CMD_PATH_LEN];
 
 extern void orderly_poweroff(bool force);
 extern void orderly_reboot(void);
+void hw_protection_shutdown(const char *reason, int ms_until_forced);
 
 /*
  * Emergency restart, callable from an interrupt handler.
diff --git a/kernel/reboot.c b/kernel/reboot.c
index a6ad5eb2fa73..5da8c80a2647 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -7,6 +7,7 @@
 
 #define pr_fmt(fmt)"reboot: " fmt
 
+#include 
 #include 
 #include 
 #include 
@@ -518,6 +519,85 @@ void orderly_reboot(void)
 }
 EXPORT_SYMBOL_GPL(orderly_reboot);
 
+/**
+ * hw_failure_emergency_poweroff_func - emergency poweroff work after a known 
delay
+ * @work: work_struct associated with the emergency poweroff function
+ *
+ * This function is called in very critical situations to force
+ * a kernel poweroff after a configurable timeout value.
+ */
+static void hw_failure_emergency_poweroff_func(struct work_struct *work)
+{
+   /*
+* We have reached here after the emergency shutdown waiting period has
+* expired. This means orderly_poweroff has not been able to shut off
+* the system for some reason.
+*
+* Try to shut down the system immediately using kernel_power_off
+* if populated
+*/
+   WARN(1, "Hardware protection timed-out. Trying forced poweroff\n");
+   kernel_power_off();
+
+   /*
+* Worst of the worst case trigger emergency restart
+*/
+   WARN(1,
+"Hardware protection shutdown failed. Trying emergency restart\n");
+   emergency_restart();
+}
+
+static DECLARE_DELAYED_WORK(hw_failure_emergency_poweroff_work,
+   hw_failure_emergency_poweroff_func);
+
+/**
+ * hw_failure_emergency_poweroff - Trigger an emergency system poweroff
+ *
+ * This may be called from any critical situation to trigger a system shutdown
+ * after a given period of time. If time is negative this is not scheduled.
+ */
+static void hw_failure_emergency_poweroff(int poweroff_delay_ms)
+{
+   if (poweroff_delay_ms <= 0)
+   return;
+   schedule_delayed_work(_failure_emergency_poweroff_work,
+ msecs_to_jiffies(poweroff_delay_ms));
+}
+
+/**
+ * hw_protection_shutdown - Trigger an emergency system poweroff
+ *
+ * @reason:Reason of emergency shutdown to be printed.
+ * @ms_until_forced:   Time to wait for orderly shutdown before tiggering a
+ * forced shudown. Negative value disables the forced
+ * shutdown.
+ *
+ * Initiate an emergency system shutdown in order to protect hardware from
+ * further damage. Usage examples include a thermal protection or a voltage or
+ * current regulator failures.
+ * NOTE: The request is ignored if protection shutdown is already pending even
+ * if the previous request has given a large timeout for forced shutdown.
+ * Can be called from any context.
+ */
+void hw_protection_shutdown(const char *reason, int ms_until_forced)
+{
+   static atomic_t allow_proceed = ATOMIC_INIT(1);
+
+   pr_emerg("HARDWARE PROTECTION shutdown (%s)\n", reason);
+
+   /* Shutdown should be initiated only once. */
+   if (!atomic_dec_and_test(_proceed))
+   return;
+
+   /*
+* Queue a backup emergency shutdown in the event of
+* orderly_poweroff failure
+*/
+   hw_failure_emergency_poweroff(ms_until_forced);
+   orderly_poweroff(true);
+}
+EXPORT_SYMBOL_GPL(hw_protection_shutdown);
+
 static int __init reboot_setup(char *str)
 {
for (;;) {
-- 
2.25.4


-- 

[PATCH v8 01/10] dt_bindings: Add protection limit properties

2021-04-19 Thread Matti Vaittinen
Support specifying protection/error/warning limits for regulator
over current, over temperature and over/under voltage.

Most of the PMICs support only "protection" feature but few
setups do also support error/warning level indications.

On many ICs most of the protection limits can't actually be set.
But for example the ampere limit for over-current protection on ROHM
BD9576 can be configured - or feature can be completely disabled.

Provide limit setting for all protections/errors for the sake of
the completeness and do that using own properties for all so that
not all users would need to set all levels when only one or few are
supported.

Signed-off-by: Matti Vaittinen 
Reviewed-by: Rob Herring 

---
No changes since RFC-v2
---
 .../bindings/regulator/regulator.yaml | 82 +++
 1 file changed, 82 insertions(+)

diff --git a/Documentation/devicetree/bindings/regulator/regulator.yaml 
b/Documentation/devicetree/bindings/regulator/regulator.yaml
index 6d0bc9cd4040..a6ae9ecae5cc 100644
--- a/Documentation/devicetree/bindings/regulator/regulator.yaml
+++ b/Documentation/devicetree/bindings/regulator/regulator.yaml
@@ -117,6 +117,88 @@ properties:
 description: Enable over current protection.
 type: boolean
 
+  regulator-oc-protection-microamp:
+description: Set over current protection limit. This is a limit where
+  hardware performs emergency shutdown. Zero can be passed to disable
+  protection and value '1' indicates that protection should be enabled but
+  limit setting can be omitted.
+
+  regulator-oc-error-microamp:
+description: Set over current error limit. This is a limit where part of
+  the hardware propably is malfunctional and damage prevention is 
requested.
+  Zero can be passed to disable error detection and value '1' indicates
+  that detection should be enabled but limit setting can be omitted.
+
+  regulator-oc-warn-microamp:
+description: Set over current warning limit. This is a limit where hardware
+  is assumed still to be functional but approaching limit where it gets
+  damaged. Recovery actions should be initiated. Zero can be passed to
+  disable detection and value '1' indicates that detection should
+  be enabled but limit setting can be omitted.
+
+  regulator-ov-protection-microvolt:
+description: Set over voltage protection limit. This is a limit where
+  hardware performs emergency shutdown. Zero can be passed to disable
+  protection and value '1' indicates that protection should be enabled but
+  limit setting can be omitted. Limit is given as microvolt offset from
+  voltage set to regulator.
+
+  regulator-ov-error-microvolt:
+description: Set over voltage error limit. This is a limit where part of
+  the hardware propably is malfunctional and damage prevention is requested
+  Zero can be passed to disable error detection and value '1' indicates
+  that detection should be enabled but limit setting can be omitted. Limit
+  is given as microvolt offset from voltage set to regulator.
+
+  regulator-ov-warn-microvolt:
+description: Set over voltage warning limit. This is a limit where hardware
+  is assumed still to be functional but approaching limit where it gets
+  damaged. Recovery actions should be initiated. Zero can be passed to
+  disable detection and value '1' indicates that detection should
+  be enabled but limit setting can be omitted. Limit is given as microvolt
+  offset from voltage set to regulator.
+
+  regulator-uv-protection-microvolt:
+description: Set over under voltage protection limit. This is a limit where
+  hardware performs emergency shutdown. Zero can be passed to disable
+  protection and value '1' indicates that protection should be enabled but
+  limit setting can be omitted. Limit is given as microvolt offset from
+  voltage set to regulator.
+
+  regulator-uv-error-microvolt:
+description: Set under voltage error limit. This is a limit where part of
+  the hardware propably is malfunctional and damage prevention is requested
+  Zero can be passed to disable error detection and value '1' indicates
+  that detection should be enabled but limit setting can be omitted. Limit
+  is given as microvolt offset from voltage set to regulator.
+
+  regulator-uv-warn-microvolt:
+description: Set over under voltage warning limit. This is a limit where
+  hardware is assumed still to be functional but approaching limit where
+  it gets damaged. Recovery actions should be initiated. Zero can be passed
+  to disable detection and value '1' indicates that detection should
+  be enabled but limit setting can be omitted. Limit is given as microvolt
+  offset from voltage set to regulator.
+
+  regulator-temp-protection-kelvin:
+description: Set over temperature protection limit. This is a limit where
+  hardware performs emergenc

[PATCH v8 00/10] Extend regulator notification support

2021-04-19 Thread Matti Vaittinen
2 + BD9576 series
  - Split devm variant of delayed wq to own series
  Regulator framework:
  - Provide non devm variant of IRQ notification helpers
  - shorten dt-property names as suggested by Rob
  - unconditionally call map_event in IRQ handling and require it to be
populated
  BD9576 regulators:
  - change the FET resistance property to micro-ohms
  - fix voltage computation in OC limit setting

--

Matti Vaittinen (10):
  dt_bindings: Add protection limit properties
  reboot: Add hardware protection power-off
  thermal: Use generic HW-protection shutdown API
  regulator: add warning flags
  regulator: IRQ based event/error notification helpers
  regulator: add property parsing and callbacks to set protection limits
  dt-bindings: regulator: bd9576 add FET ON-resistance for OCW
  regulator: bd9576: Support error reporting
  regulator: bd9576: Fix the driver name in id table
  MAINTAINERS: Add reviewer for regulator irq_helpers

 .../bindings/regulator/regulator.yaml |   82 ++
 .../regulator/rohm,bd9576-regulator.yaml  |6 +
 MAINTAINERS   |4 +
 drivers/regulator/Makefile|2 +-
 drivers/regulator/bd9576-regulator.c  | 1060 +++--
 drivers/regulator/core.c  |  151 ++-
 drivers/regulator/devres.c|   52 +
 drivers/regulator/irq_helpers.c   |  394 ++
 drivers/regulator/of_regulator.c  |   58 +
 drivers/regulator/qcom-labibb-regulator.c |   10 +-
 drivers/regulator/qcom_spmi-regulator.c   |6 +-
 drivers/regulator/stpmic1_regulator.c |   20 +-
 drivers/thermal/thermal_core.c|   63 +-
 include/linux/reboot.h|1 +
 include/linux/regulator/consumer.h|   14 +
 include/linux/regulator/driver.h  |  176 ++-
 include/linux/regulator/machine.h |   26 +
 kernel/reboot.c   |   80 ++
 18 files changed, 2000 insertions(+), 205 deletions(-)
 create mode 100644 drivers/regulator/irq_helpers.c


base-commit: d434405aaab7d0ebc516b68a8fc4100922d7f5ef
-- 
2.25.4


-- 
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 =] 


Re: [PATCH v7 2/9] reboot: thermal: Export hardware protection shutdown

2021-04-17 Thread Matti Vaittinen
Hi Daniel,

Thank you for the review. Much appreciated!

On Sat, 2021-04-17 at 07:32 +0200, Daniel Lezcano wrote:
> On 14/04/2021 07:52, Matti Vaittinen wrote:
> > Thermal core contains a logic for safety shutdown. System is
> > attempted to
> > be powered off if temperature exceeds safety limits.
> > 
> > Currently this can be also utilized by regulator subsystem as a
> > final
> > protection measure if PMICs report dangerous over-voltage, over-
> > current or
> > over-temperature and if per regulator counter measures fail or do
> > not
> > exist.
> > 
> > Move this logic to kernel/reboot.c and export the functionality for
> > other
> > subsystems to use. Also replace the mutex with a spinlock to allow
> > using
> > the function from any context.
> > 
> > Also the EMIF bus code has implemented a safety shut-down. EMIF
> > does not
> > attempt orderly_poweroff at all. Thus the EMIF code is not
> > converted to use
> > this new function.
> > 
> > Signed-off-by: Matti Vaittinen 
> > ---
> > Changelog
> >  v7:
> >   - new patch
> > 
> > Please note - this patch has received only a minimal amount of
> > testing.
> > (The new API call was tested to shut-down my system at driver probe
> > but
> > no odd corner-cases have been tested).
> > 
> > Any testing for thermal shutdown is appreciated.
> > ---
> >  drivers/thermal/thermal_core.c | 63 ++---
> >  include/linux/reboot.h |  1 +
> >  kernel/reboot.c| 86
> > ++
> 
> Please send a patch implementing the reboot/shutdown and then another
> one replacing the thermal shutdown code by a call to the new API.

I guess your suggestion makes sense. That way if the change causes any
problems in thermal-core it can be reverted without impacting other
potential users of this API. My original thinking was that this was
more of an move of functionality than adding an API. Having the move as
one patch makes sense as it shows where the code came from.

> 
> >  3 files changed, 91 insertions(+), 59 deletions(-)
> > 
> > diff --git a/drivers/thermal/thermal_core.c
> > b/drivers/thermal/thermal_core.c
> > index 996c038f83a4..b1444845af38 100644
> > --- a/drivers/thermal/thermal_core.c
> > +++ b/drivers/thermal/thermal_core.c
> > @@ -36,10 +36,8 @@ static LIST_HEAD(thermal_governor_list);
> >  
> > 

...

> > +static bool prot_power_off_triggered;
> > +static DEFINE_SPINLOCK(poweroff_lock);
> > +
> > +/**
> > + * hw_protection_shutdown - Trigger an emergency system poweroff
> > + *
> > + * @reason:Reason of emergency shutdown to be
> > printed.
> > + * @ms_until_forced:   Time to wait for orderly shutdown
> > before tiggering a
> > + * forced shudown. Negative value disables the
> > forced
> > + * shutdown.
> > + *
> > + * Initiate an emergency system shutdown in order to protect
> > hardware from
> > + * further damage. Usage examples include a thermal protection or
> > a voltage or
> > + * current regulator failures.
> > + * NOTE: The request is ignored if protection shutdown is already
> > pending even
> > + * if the previous request has given a large timeout for forced
> > shutdown.
> > + * Can be called from any context.
> > + */
> > +void hw_protection_shutdown(const char *reason, int
> > ms_until_forced)
> > +{
> > +   unsigned long flags;
> > +
> > +   pr_emerg("HARDWARE PROTECTION shutdown (%s)\n", reason);
> > +
> > +   spin_lock_irqsave(_lock, flags);
> > +   if (prot_power_off_triggered) {
> > +   spin_unlock(_lock);
> 
> Why not spin_unlock_irqrestore() ?
> 

Well spotted It for sure must be spin_unlock_irqrestore. My bad.

> > +   return;
> > +   }
> > +   prot_power_off_triggered = true;
> > +   spin_unlock_irqrestore(_lock, flags);
> 
> Why not take the spin_lock definitively for all the procedure ?
> 
> eg.
> 
> {
>   ...
> 
>   pr_emerg( ... );
> 
>   if (spin_trylock())
>   return;
> 
>   hw_failure_emergency_poweroff(ms_until_forced);
> 
>   orderly_poweroff(true);
> }
> 
> No need of prot_power_off_triggered and the spin_lock can be declared
> static inside the function.

I think this makes perfect sense. My thinking just jammed to replacing
the mutex thermal-core used with a spin-lock using similar logic. I
guess this could even be just an atomic cmpxchg (or equivalent, I don't
remember what atomic abstractions we have) just to return if function
has been previously executed. Well, the spin_trylock() should work just
fine as far as I can say. So - thanks.


Best Regards
Matti Vaittinen



[PATCH v7 9/9] MAINTAINERS: Add reviewer for regulator irq_helpers

2021-04-14 Thread Matti Vaittinen
Add a reviewer entry for the regulator irq_helpers.

Signed-off-by: Matti Vaittinen 
---
Changelog:
 v6:
  - New patch
---
 MAINTAINERS | 4 
 1 file changed, 4 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 7fdc513392f4..c917d85feccd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19228,6 +19228,10 @@ F: include/dt-bindings/regulator/
 F: include/linux/regulator/
 K: regulator_get_optional
 
+VOLTAGE AND CURRENT REGULATOR IRQ HELPERS
+R: Matti Vaittinen 
+F: drivers/regulator/irq_helpers.c
+
 VRF
 M: David Ahern 
 L: net...@vger.kernel.org
-- 
2.25.4


-- 
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 =] 


[PATCH v7 8/9] regulator: bd9576: Fix the driver name in id table

2021-04-14 Thread Matti Vaittinen
Driver name was changed in MFD cell:
https://lore.kernel.org/lkml/560b9748094392493ebf7af11b6cc558776c4fd5.1613031055.git.matti.vaitti...@fi.rohmeurope.com/
Fix the ID table to match this.

Signed-off-by: Matti Vaittinen 
---
No changes since RFC-v2
---
 drivers/regulator/bd9576-regulator.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/regulator/bd9576-regulator.c 
b/drivers/regulator/bd9576-regulator.c
index 0d55d383d2aa..aeb816cf9ad3 100644
--- a/drivers/regulator/bd9576-regulator.c
+++ b/drivers/regulator/bd9576-regulator.c
@@ -1117,8 +1117,8 @@ static int bd957x_probe(struct platform_device *pdev)
 }
 
 static const struct platform_device_id bd957x_pmic_id[] = {
-   { "bd9573-pmic", ROHM_CHIP_TYPE_BD9573 },
-   { "bd9576-pmic", ROHM_CHIP_TYPE_BD9576 },
+   { "bd9573-regulator", ROHM_CHIP_TYPE_BD9573 },
+   { "bd9576-regulator", ROHM_CHIP_TYPE_BD9576 },
{ },
 };
 MODULE_DEVICE_TABLE(platform, bd957x_pmic_id);
-- 
2.25.4


-- 
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 =] 


[PATCH v7 6/9] dt-bindings: regulator: bd9576 add FET ON-resistance for OCW

2021-04-14 Thread Matti Vaittinen
BD9576MUF provides over-current protection and detection. Current is
measured as voltage loss over external FET. Allow specifying FET's on
resistance so current monitoring limits can be converted to voltages.

Signed-off-by: Matti Vaittinen 
Reviewed-by: Rob Herring 
---
v5 onwards:
  - No changes
v4:
  - Fixed the description indentiation
---
 .../bindings/regulator/rohm,bd9576-regulator.yaml   | 6 ++
 1 file changed, 6 insertions(+)

diff --git 
a/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml 
b/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml
index b6515a0cee62..7cb74cc8c5d9 100644
--- a/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml
+++ b/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml
@@ -27,6 +27,12 @@ patternProperties:
   Properties for single regulator.
 $ref: "regulator.yaml#"
 
+properties:
+  rohm,ocw-fet-ron-micro-ohms:
+description: |
+  External FET's ON-resistance. Required if VoutS1 OCP/OCW is
+  to be set.
+
 required:
   - regulator-name
 
-- 
2.25.4


-- 
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 =] 


[PATCH v7 7/9] regulator: bd9576: Support error reporting

2021-04-14 Thread Matti Vaittinen
BD9573 and BD9576 support set of "protection" interrupts for "fatal"
issues. Those lead to SOC reset as PMIC shuts the power outputs. Thus
there is no relevant IRQ handling for them.

Few "detection" interrupts were added to the BD9576 with the idea that
SOC could take some recovery-action before error gets unrecoverable.

Add support for over and under voltage detection for Vout1 ... Vout4
and VoutL1. Add over-current detection for VoutS1 and finally a
thermal warning (common for all regulators) which alerts 30 C
before temperature reaches the thermal shutdown point. This way
consumer drivers can build error-recovery mechanisms.

Unfortunately the BD9576 interrupt logic was not re-evaluated. IRQs
are not designed to be properly acknowleged - and IRQ line is kept
active for whole duration of error condition (in comparison to
informing only about state change).

Signed-off-by: Matti Vaittinen 
---
No changes since RFC-v3
---
 drivers/regulator/bd9576-regulator.c | 1056 ++
 1 file changed, 929 insertions(+), 127 deletions(-)

diff --git a/drivers/regulator/bd9576-regulator.c 
b/drivers/regulator/bd9576-regulator.c
index a8b5832a5a1b..0d55d383d2aa 100644
--- a/drivers/regulator/bd9576-regulator.c
+++ b/drivers/regulator/bd9576-regulator.c
@@ -2,10 +2,10 @@
 // Copyright (C) 2020 ROHM Semiconductors
 // ROHM BD9576MUF/BD9573MUF regulator driver
 
-#include 
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -16,11 +16,18 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 
 #define BD957X_VOUTS1_VOLT 330
 #define BD957X_VOUTS4_BASE_VOLT103
 #define BD957X_VOUTS34_NUM_VOLT32
 
+#define BD9576_THERM_IRQ_MASK_TW   BIT(5)
+#define BD9576_xVD_IRQ_MASK_VOUTL1 BIT(5)
+#define BD9576_UVD_IRQ_MASK_VOUTS1_OCW BIT(6)
+#define BD9576_xVD_IRQ_MASK_VOUT1TO4   0x0F
+
 static int vout1_volt_table[] = {500, 490, 480, 470, 460,
 450, 450, 450, 500, 510,
 520, 530, 540, 550, 550,
@@ -36,9 +43,85 @@ static int voutl1_volt_table[] = {250, 254, 258, 
262, 266,
  242, 238, 234, 230, 226,
  222};
 
+static const struct linear_range vout1_xvd_ranges[] = {
+   REGULATOR_LINEAR_RANGE(225000, 0x01, 0x2b, 0),
+   REGULATOR_LINEAR_RANGE(225000, 0x2c, 0x54, 5000),
+   REGULATOR_LINEAR_RANGE(425000, 0x55, 0x7f, 0),
+};
+
+static const struct linear_range vout234_xvd_ranges[] = {
+   REGULATOR_LINEAR_RANGE(17000, 0x01, 0x0f, 0),
+   REGULATOR_LINEAR_RANGE(17000, 0x10, 0x6d, 1000),
+   REGULATOR_LINEAR_RANGE(11, 0x6e, 0x7f, 0),
+};
+
+static const struct linear_range voutL1_xvd_ranges[] = {
+   REGULATOR_LINEAR_RANGE(34000, 0x01, 0x0f, 0),
+   REGULATOR_LINEAR_RANGE(34000, 0x10, 0x6d, 2000),
+   REGULATOR_LINEAR_RANGE(22, 0x6e, 0x7f, 0),
+};
+
+static struct linear_range voutS1_ocw_ranges_internal[] = {
+   REGULATOR_LINEAR_RANGE(20, 0x01, 0x04, 0),
+   REGULATOR_LINEAR_RANGE(25, 0x05, 0x18, 5),
+   REGULATOR_LINEAR_RANGE(120, 0x19, 0x3f, 0),
+};
+
+static struct linear_range voutS1_ocw_ranges[] = {
+   REGULATOR_LINEAR_RANGE(5, 0x01, 0x04, 0),
+   REGULATOR_LINEAR_RANGE(6, 0x05, 0x18, 1),
+   REGULATOR_LINEAR_RANGE(25, 0x19, 0x3f, 0),
+};
+
+static struct linear_range voutS1_ocp_ranges_internal[] = {
+   REGULATOR_LINEAR_RANGE(30, 0x01, 0x06, 0),
+   REGULATOR_LINEAR_RANGE(35, 0x7, 0x1b, 5),
+   REGULATOR_LINEAR_RANGE(135, 0x1c, 0x3f, 0),
+};
+
+static struct linear_range voutS1_ocp_ranges[] = {
+   REGULATOR_LINEAR_RANGE(7, 0x01, 0x06, 0),
+   REGULATOR_LINEAR_RANGE(8, 0x7, 0x1b, 1),
+   REGULATOR_LINEAR_RANGE(28, 0x1c, 0x3f, 0),
+};
+
 struct bd957x_regulator_data {
struct regulator_desc desc;
int base_voltage;
+   struct regulator_dev *rdev;
+   int ovd_notif;
+   int uvd_notif;
+   int temp_notif;
+   int ovd_err;
+   int uvd_err;
+   int temp_err;
+   const struct linear_range *xvd_ranges;
+   int num_xvd_ranges;
+   bool oc_supported;
+   unsigned int ovd_reg;
+   unsigned int uvd_reg;
+   unsigned int xvd_mask;
+   unsigned int ocp_reg;
+   unsigned int ocp_mask;
+   unsigned int ocw_reg;
+   unsigned int ocw_mask;
+   unsigned int ocw_rfet;
+};
+
+#define BD9576_NUM_REGULATORS 6
+#define BD9576_NUM_OVD_REGULATORS 5
+
+struct bd957x_data {
+   struct bd957x_regulator_data regulator_data[BD9576_NUM_REGULATORS];
+   struct regmap *regmap;
+   struct delayed_work therm_irq_suppress;
+   struct delayed_work ovd_irq_suppress;
+   struct delayed_work uvd_irq_suppress;
+   unsigned int therm_irq;
+   unsigned int ovd_irq

[PATCH v7 4/9] regulator: IRQ based event/error notification helpers

2021-04-14 Thread Matti Vaittinen
Provide helper function for IC's implementing regulator notifications
when an IRQ fires. The helper also works for IRQs which can not be acked.
Helper can be set to disable the IRQ at handler and then re-enabling it
on delayed work later. The helper also adds regulator_get_error_flags()
errors in cache for the duration of IRQ disabling.

Signed-off-by: Matti Vaittinen 
Reviewed-by: Andy Shevchenko 

---

As a note - here we just define 10 sec time-limit for orderly_poweroff()
to shut-down the system. I believe this is better than the original
BUG() - but still sub-optimal as the required shut-down time should be
profiled for each system. Thermal core uses KConfig to give the time. I
don't like that either as it requires system specific compilation.
Perhaps the device-tree would be one option - although this is something
that might warrant a user-space configuration option.

Anyways, I hope that can be improved later - it is still just kind of a
backup of a backup of a backup :)

v7 (mostly more fixes pointed by Andy)
 - fix regulator error_flags query
 - grammar/typos
 - do not BUG() but attempt to shut-down the system
 - use BITS_PER_TYPE()
v6 (fix issues noted by Andy):
 - remove unnecessary variable
 - use BIT(foo) instead of 1 << foo
 - use devm_add_action_or_reset()
 - do not check the irq parameter validity, leave that to
   request_threaded_irq()
 - put resource-managed function in devres.c
 - fix the kerneldocs for the new IRQ helpers
v5:
 - fix the pr_emerg print
v4:
 - Comment block styling
 - Added prints to point the potential HW failure before BUG()
 - Corrected typo from kerneldoc
 - added missing newlines
---
 drivers/regulator/Makefile   |   2 +-
 drivers/regulator/core.c |  29 ++-
 drivers/regulator/devres.c   |  52 
 drivers/regulator/irq_helpers.c  | 394 +++
 include/linux/regulator/driver.h | 135 +++
 5 files changed, 604 insertions(+), 8 deletions(-)
 create mode 100644 drivers/regulator/irq_helpers.c

diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 44d2f8bf4b74..e25f1c2d6c9b 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -4,7 +4,7 @@
 #
 
 
-obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o devres.o
+obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o devres.o 
irq_helpers.o
 obj-$(CONFIG_OF) += of_regulator.o
 obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
 obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 16114aea099a..0c45814aabea 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -4388,22 +4388,36 @@ unsigned int regulator_get_mode(struct regulator 
*regulator)
 }
 EXPORT_SYMBOL_GPL(regulator_get_mode);
 
+static int rdev_get_cached_err_flags(struct regulator_dev *rdev)
+{
+   int ret = 0;
+
+   if (rdev->use_cached_err) {
+   spin_lock(>err_lock);
+   ret = rdev->cached_err;
+   spin_unlock(>err_lock);
+   }
+   return ret;
+}
+
 static int _regulator_get_error_flags(struct regulator_dev *rdev,
unsigned int *flags)
 {
-   int ret;
+   int cached_flags, ret = 0;
 
regulator_lock(rdev);
 
-   /* sanity check */
-   if (!rdev->desc->ops->get_error_flags) {
+   cached_flags = rdev_get_cached_err_flags(rdev);
+
+   if (rdev->desc->ops->get_error_flags)
+   ret = rdev->desc->ops->get_error_flags(rdev, flags);
+   else if (!rdev->use_cached_err)
ret = -EINVAL;
-   goto out;
-   }
 
-   ret = rdev->desc->ops->get_error_flags(rdev, flags);
-out:
+   *flags |= cached_flags;
+
regulator_unlock(rdev);
+
return ret;
 }
 
@@ -5236,6 +5250,7 @@ regulator_register(const struct regulator_desc 
*regulator_desc,
goto rinse;
}
device_initialize(>dev);
+   spin_lock_init(>err_lock);
 
/*
 * Duplicate the config so the driver could override it after
diff --git a/drivers/regulator/devres.c b/drivers/regulator/devres.c
index 3091210889e3..a8de0aa88bad 100644
--- a/drivers/regulator/devres.c
+++ b/drivers/regulator/devres.c
@@ -481,3 +481,55 @@ void devm_regulator_unregister_notifier(struct regulator 
*regulator,
WARN_ON(rc);
 }
 EXPORT_SYMBOL_GPL(devm_regulator_unregister_notifier);
+
+static void regulator_irq_helper_drop(void *res)
+{
+   regulator_irq_helper_cancel();
+}
+
+/**
+ * devm_regulator_irq_helper - resource managed registration of IRQ based
+ * regulator event/error notifier
+ *
+ * @dev:   device to which lifetime the helper's lifetime is
+ * bound.
+ * @d: IRQ helper descriptor.
+ * @irq:   IRQ used to inform events/errors to be notified.
+ * @

[PATCH v7 5/9] regulator: add property parsing and callbacks to set protection limits

2021-04-14 Thread Matti Vaittinen
Add DT property parsing code and setting callback for regulator over/under
voltage, over-current and temperature error limits.

Signed-off-by: Matti Vaittinen 
---
No changes since RFC-v3
---
 drivers/regulator/core.c  | 122 +-
 drivers/regulator/of_regulator.c  |  58 ++
 drivers/regulator/qcom-labibb-regulator.c |  10 +-
 drivers/regulator/qcom_spmi-regulator.c   |   6 +-
 drivers/regulator/stpmic1_regulator.c |  20 +++-
 include/linux/regulator/driver.h  |  41 +++-
 include/linux/regulator/machine.h |  26 +
 7 files changed, 274 insertions(+), 9 deletions(-)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 0c45814aabea..88926c407b02 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1312,6 +1312,52 @@ static int machine_constraints_current(struct 
regulator_dev *rdev,
 
 static int _regulator_do_enable(struct regulator_dev *rdev);
 
+static int notif_set_limit(struct regulator_dev *rdev,
+  int (*set)(struct regulator_dev *, int, int, bool),
+  int limit, int severity)
+{
+   bool enable;
+
+   if (limit == REGULATOR_NOTIF_LIMIT_DISABLE) {
+   enable = false;
+   limit = 0;
+   } else {
+   enable = true;
+   }
+
+   if (limit == REGULATOR_NOTIF_LIMIT_ENABLE)
+   limit = 0;
+
+   return set(rdev, limit, severity, enable);
+}
+
+static int handle_notify_limits(struct regulator_dev *rdev,
+   int (*set)(struct regulator_dev *, int, int, bool),
+   struct notification_limit *limits)
+{
+   int ret = 0;
+
+   if (!set)
+   return -EOPNOTSUPP;
+
+   if (limits->prot)
+   ret = notif_set_limit(rdev, set, limits->prot,
+ REGULATOR_SEVERITY_PROT);
+   if (ret)
+   return ret;
+
+   if (limits->err)
+   ret = notif_set_limit(rdev, set, limits->err,
+ REGULATOR_SEVERITY_ERR);
+   if (ret)
+   return ret;
+
+   if (limits->warn)
+   ret = notif_set_limit(rdev, set, limits->warn,
+ REGULATOR_SEVERITY_WARN);
+
+   return ret;
+}
 /**
  * set_machine_constraints - sets regulator constraints
  * @rdev: regulator source
@@ -1397,9 +1443,27 @@ static int set_machine_constraints(struct regulator_dev 
*rdev)
}
}
 
+   /*
+* Existing logic does not warn if over_current_protection is given as
+* a constraint but driver does not support that. I think we should
+* warn about this type of issues as it is possible someone changes
+* PMIC on board to another type - and the another PMIC's driver does
+* not support setting protection. Board composer may happily believe
+* the DT limits are respected - especially if the new PMIC HW also
+* supports protection but the driver does not. I won't change the logic
+* without hearing more experienced opinion on this though.
+*
+* If warning is seen as a good idea then we can merge handling the
+* over-curret protection and detection and get rid of this special
+* handling.
+*/
if (rdev->constraints->over_current_protection
&& ops->set_over_current_protection) {
-   ret = ops->set_over_current_protection(rdev);
+   int lim = rdev->constraints->over_curr_limits.prot;
+
+   ret = ops->set_over_current_protection(rdev, lim,
+  REGULATOR_SEVERITY_PROT,
+  true);
if (ret < 0) {
rdev_err(rdev, "failed to set over current protection: 
%pe\n",
 ERR_PTR(ret));
@@ -1407,6 +1471,62 @@ static int set_machine_constraints(struct regulator_dev 
*rdev)
}
}
 
+   if (rdev->constraints->over_current_detection)
+   ret = handle_notify_limits(rdev,
+  ops->set_over_current_protection,
+  
>constraints->over_curr_limits);
+   if (ret) {
+   if (ret != -EOPNOTSUPP) {
+   rdev_err(rdev, "failed to set over current limits: 
%pe\n",
+ERR_PTR(ret));
+   return ret;
+   }
+   rdev_warn(rdev,
+ "IC does not support requested over-current 
limits\n");
+   }
+
+   if (rdev->constraints->over_voltage_detection)
+   ret = handle_notify_limits(rdev,
+  ops->se

[PATCH v7 3/9] regulator: add warning flags

2021-04-13 Thread Matti Vaittinen
Add 'warning' level events and error flags to regulator core.
Current regulator core notifications are used to inform consumers
about errors where HW is misbehaving in such way it is assumed to
be broken/unrecoverable.

There are PMICs which are designed for system(s) that may have use
for regulator indications sent before HW is damaged so that some
board/consumer specific recovery-event can be performed while
continuing most of the normal operations.

Add new WARNING level events and notifications to be used for
that purpose.

Signed-off-by: Matti Vaittinen 
---
No changes since RFC-v2
---
 include/linux/regulator/consumer.h | 14 ++
 1 file changed, 14 insertions(+)

diff --git a/include/linux/regulator/consumer.h 
b/include/linux/regulator/consumer.h
index 20e84a84fb77..f72ca73631be 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -119,6 +119,16 @@ struct regulator_dev;
 #define REGULATOR_EVENT_PRE_DISABLE0x400
 #define REGULATOR_EVENT_ABORT_DISABLE  0x800
 #define REGULATOR_EVENT_ENABLE 0x1000
+/*
+ * Following notifications should be emitted only if detected condition
+ * is such that the HW is likely to still be working but consumers should
+ * take a recovery action to prevent problems esacalating into errors.
+ */
+#define REGULATOR_EVENT_UNDER_VOLTAGE_WARN 0x2000
+#define REGULATOR_EVENT_OVER_CURRENT_WARN  0x4000
+#define REGULATOR_EVENT_OVER_VOLTAGE_WARN  0x8000
+#define REGULATOR_EVENT_OVER_TEMP_WARN 0x1
+#define REGULATOR_EVENT_WARN_MASK  0x1E000
 
 /*
  * Regulator errors that can be queried using regulator_get_error_flags
@@ -138,6 +148,10 @@ struct regulator_dev;
 #define REGULATOR_ERROR_FAIL   BIT(4)
 #define REGULATOR_ERROR_OVER_TEMP  BIT(5)
 
+#define REGULATOR_ERROR_UNDER_VOLTAGE_WARN BIT(6)
+#define REGULATOR_ERROR_OVER_CURRENT_WARN  BIT(7)
+#define REGULATOR_ERROR_OVER_VOLTAGE_WARN  BIT(8)
+#define REGULATOR_ERROR_OVER_TEMP_WARN BIT(9)
 
 /**
  * struct pre_voltage_change_data - Data sent with PRE_VOLTAGE_CHANGE event
-- 
2.25.4


-- 
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 =] 


[PATCH v7 2/9] reboot: thermal: Export hardware protection shutdown

2021-04-13 Thread Matti Vaittinen
Thermal core contains a logic for safety shutdown. System is attempted to
be powered off if temperature exceeds safety limits.

Currently this can be also utilized by regulator subsystem as a final
protection measure if PMICs report dangerous over-voltage, over-current or
over-temperature and if per regulator counter measures fail or do not
exist.

Move this logic to kernel/reboot.c and export the functionality for other
subsystems to use. Also replace the mutex with a spinlock to allow using
the function from any context.

Also the EMIF bus code has implemented a safety shut-down. EMIF does not
attempt orderly_poweroff at all. Thus the EMIF code is not converted to use
this new function.

Signed-off-by: Matti Vaittinen 
---
Changelog
 v7:
  - new patch

Please note - this patch has received only a minimal amount of testing.
(The new API call was tested to shut-down my system at driver probe but
no odd corner-cases have been tested).

Any testing for thermal shutdown is appreciated.
---
 drivers/thermal/thermal_core.c | 63 ++---
 include/linux/reboot.h |  1 +
 kernel/reboot.c| 86 ++
 3 files changed, 91 insertions(+), 59 deletions(-)

diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 996c038f83a4..b1444845af38 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -36,10 +36,8 @@ static LIST_HEAD(thermal_governor_list);
 
 static DEFINE_MUTEX(thermal_list_lock);
 static DEFINE_MUTEX(thermal_governor_lock);
-static DEFINE_MUTEX(poweroff_lock);
 
 static atomic_t in_suspend;
-static bool power_off_triggered;
 
 static struct thermal_governor *def_governor;
 
@@ -327,70 +325,18 @@ static void handle_non_critical_trips(struct 
thermal_zone_device *tz, int trip)
   def_governor->throttle(tz, trip);
 }
 
-/**
- * thermal_emergency_poweroff_func - emergency poweroff work after a known 
delay
- * @work: work_struct associated with the emergency poweroff function
- *
- * This function is called in very critical situations to force
- * a kernel poweroff after a configurable timeout value.
- */
-static void thermal_emergency_poweroff_func(struct work_struct *work)
-{
-   /*
-* We have reached here after the emergency thermal shutdown
-* Waiting period has expired. This means orderly_poweroff has
-* not been able to shut off the system for some reason.
-* Try to shut down the system immediately using kernel_power_off
-* if populated
-*/
-   WARN(1, "Attempting kernel_power_off: Temperature too high\n");
-   kernel_power_off();
-
-   /*
-* Worst of the worst case trigger emergency restart
-*/
-   WARN(1, "Attempting emergency_restart: Temperature too high\n");
-   emergency_restart();
-}
-
-static DECLARE_DELAYED_WORK(thermal_emergency_poweroff_work,
-   thermal_emergency_poweroff_func);
-
-/**
- * thermal_emergency_poweroff - Trigger an emergency system poweroff
- *
- * This may be called from any critical situation to trigger a system shutdown
- * after a known period of time. By default this is not scheduled.
- */
-static void thermal_emergency_poweroff(void)
+void thermal_zone_device_critical(struct thermal_zone_device *tz)
 {
-   int poweroff_delay_ms = CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS;
/*
 * poweroff_delay_ms must be a carefully profiled positive value.
-* Its a must for thermal_emergency_poweroff_work to be scheduled
+* Its a must for forced_emergency_poweroff_work to be scheduled.
 */
-   if (poweroff_delay_ms <= 0)
-   return;
-   schedule_delayed_work(_emergency_poweroff_work,
- msecs_to_jiffies(poweroff_delay_ms));
-}
+   int poweroff_delay_ms = CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS;
 
-void thermal_zone_device_critical(struct thermal_zone_device *tz)
-{
dev_emerg(>device, "%s: critical temperature reached, "
  "shutting down\n", tz->type);
 
-   mutex_lock(_lock);
-   if (!power_off_triggered) {
-   /*
-* Queue a backup emergency shutdown in the event of
-* orderly_poweroff failure
-*/
-   thermal_emergency_poweroff();
-   orderly_poweroff(true);
-   power_off_triggered = true;
-   }
-   mutex_unlock(_lock);
+   hw_protection_shutdown("Temperature too high", poweroff_delay_ms);
 }
 EXPORT_SYMBOL(thermal_zone_device_critical);
 
@@ -1549,7 +1495,6 @@ static int __init thermal_init(void)
ida_destroy(_cdev_ida);
mutex_destroy(_list_lock);
mutex_destroy(_governor_lock);
-   mutex_destroy(_lock);
return result;
 }
 postcore_initcall(thermal_init);
diff --git a/include/linux/reboot.h b/include/linux/

[PATCH v7 1/9] dt_bindings: Add protection limit properties

2021-04-13 Thread Matti Vaittinen
Support specifying protection/error/warning limits for regulator
over current, over temperature and over/under voltage.

Most of the PMICs support only "protection" feature but few
setups do also support error/warning level indications.

On many ICs most of the protection limits can't actually be set.
But for example the ampere limit for over-current protection on ROHM
BD9576 can be configured - or feature can be completely disabled.

Provide limit setting for all protections/errors for the sake of
the completeness and do that using own properties for all so that
not all users would need to set all levels when only one or few are
supported.

Signed-off-by: Matti Vaittinen 
Reviewed-by: Rob Herring 

---
No changes since RFC-v2
---
 .../bindings/regulator/regulator.yaml | 82 +++
 1 file changed, 82 insertions(+)

diff --git a/Documentation/devicetree/bindings/regulator/regulator.yaml 
b/Documentation/devicetree/bindings/regulator/regulator.yaml
index 6d0bc9cd4040..a6ae9ecae5cc 100644
--- a/Documentation/devicetree/bindings/regulator/regulator.yaml
+++ b/Documentation/devicetree/bindings/regulator/regulator.yaml
@@ -117,6 +117,88 @@ properties:
 description: Enable over current protection.
 type: boolean
 
+  regulator-oc-protection-microamp:
+description: Set over current protection limit. This is a limit where
+  hardware performs emergency shutdown. Zero can be passed to disable
+  protection and value '1' indicates that protection should be enabled but
+  limit setting can be omitted.
+
+  regulator-oc-error-microamp:
+description: Set over current error limit. This is a limit where part of
+  the hardware propably is malfunctional and damage prevention is 
requested.
+  Zero can be passed to disable error detection and value '1' indicates
+  that detection should be enabled but limit setting can be omitted.
+
+  regulator-oc-warn-microamp:
+description: Set over current warning limit. This is a limit where hardware
+  is assumed still to be functional but approaching limit where it gets
+  damaged. Recovery actions should be initiated. Zero can be passed to
+  disable detection and value '1' indicates that detection should
+  be enabled but limit setting can be omitted.
+
+  regulator-ov-protection-microvolt:
+description: Set over voltage protection limit. This is a limit where
+  hardware performs emergency shutdown. Zero can be passed to disable
+  protection and value '1' indicates that protection should be enabled but
+  limit setting can be omitted. Limit is given as microvolt offset from
+  voltage set to regulator.
+
+  regulator-ov-error-microvolt:
+description: Set over voltage error limit. This is a limit where part of
+  the hardware propably is malfunctional and damage prevention is requested
+  Zero can be passed to disable error detection and value '1' indicates
+  that detection should be enabled but limit setting can be omitted. Limit
+  is given as microvolt offset from voltage set to regulator.
+
+  regulator-ov-warn-microvolt:
+description: Set over voltage warning limit. This is a limit where hardware
+  is assumed still to be functional but approaching limit where it gets
+  damaged. Recovery actions should be initiated. Zero can be passed to
+  disable detection and value '1' indicates that detection should
+  be enabled but limit setting can be omitted. Limit is given as microvolt
+  offset from voltage set to regulator.
+
+  regulator-uv-protection-microvolt:
+description: Set over under voltage protection limit. This is a limit where
+  hardware performs emergency shutdown. Zero can be passed to disable
+  protection and value '1' indicates that protection should be enabled but
+  limit setting can be omitted. Limit is given as microvolt offset from
+  voltage set to regulator.
+
+  regulator-uv-error-microvolt:
+description: Set under voltage error limit. This is a limit where part of
+  the hardware propably is malfunctional and damage prevention is requested
+  Zero can be passed to disable error detection and value '1' indicates
+  that detection should be enabled but limit setting can be omitted. Limit
+  is given as microvolt offset from voltage set to regulator.
+
+  regulator-uv-warn-microvolt:
+description: Set over under voltage warning limit. This is a limit where
+  hardware is assumed still to be functional but approaching limit where
+  it gets damaged. Recovery actions should be initiated. Zero can be passed
+  to disable detection and value '1' indicates that detection should
+  be enabled but limit setting can be omitted. Limit is given as microvolt
+  offset from voltage set to regulator.
+
+  regulator-temp-protection-kelvin:
+description: Set over temperature protection limit. This is a limit where
+  hardware performs emergenc

[PATCH v7 0/9] Extend regulator notification support

2021-04-13 Thread Matti Vaittinen
nally call map_event in IRQ handling and require it to be
populated
  BD9576 regulators:
  - change the FET resistance property to micro-ohms
  - fix voltage computation in OC limit setting

--

Matti Vaittinen (9):
  dt_bindings: Add protection limit properties
  reboot: thermal: Export hardware protection shutdown
  regulator: add warning flags
  regulator: IRQ based event/error notification helpers
  regulator: add property parsing and callbacks to set protection limits
  dt-bindings: regulator: bd9576 add FET ON-resistance for OCW
  regulator: bd9576: Support error reporting
  regulator: bd9576: Fix the driver name in id table
  MAINTAINERS: Add reviewer for regulator irq_helpers

 .../bindings/regulator/regulator.yaml |   82 ++
 .../regulator/rohm,bd9576-regulator.yaml  |6 +
 MAINTAINERS   |4 +
 drivers/regulator/Makefile|2 +-
 drivers/regulator/bd9576-regulator.c  | 1060 +++--
 drivers/regulator/core.c  |  151 ++-
 drivers/regulator/devres.c|   52 +
 drivers/regulator/irq_helpers.c   |  394 ++
 drivers/regulator/of_regulator.c  |   58 +
 drivers/regulator/qcom-labibb-regulator.c |   10 +-
 drivers/regulator/qcom_spmi-regulator.c   |6 +-
 drivers/regulator/stpmic1_regulator.c |   20 +-
 drivers/thermal/thermal_core.c|   63 +-
 include/linux/reboot.h|1 +
 include/linux/regulator/consumer.h|   14 +
 include/linux/regulator/driver.h  |  176 ++-
 include/linux/regulator/machine.h |   26 +
 kernel/reboot.c   |   86 ++
 18 files changed, 2006 insertions(+), 205 deletions(-)
 create mode 100644 drivers/regulator/irq_helpers.c


base-commit: d434405aaab7d0ebc516b68a8fc4100922d7f5ef
-- 
2.25.4


-- 
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 =] 


Re: [PATCH v4 3/7] regulator: IRQ based event/error notification helpers

2021-04-12 Thread Matti Vaittinen


On Fri, 2021-04-09 at 10:08 +0300, Matti Vaittinen wrote:
> On Thu, 2021-04-08 at 20:20 -0700, Kees Cook wrote:
> > On Wed, Apr 07, 2021 at 03:50:15PM +0300, Andy Shevchenko wrote:
> > > On Wed, Apr 7, 2021 at 12:49 PM Vaittinen, Matti
> > >  wrote:
> > > > On Wed, 2021-04-07 at 12:10 +0300, Andy Shevchenko wrote:
> > > > > On Wed, Apr 7, 2021 at 8:02 AM Matti Vaittinen
> > > > >  wrote:
> > > > > > On Wed, 2021-04-07 at 01:44 +0300, Andy Shevchenko wrote:
> > > > > > > On Tuesday, April 6, 2021, Matti Vaittinen <
> > > > > > > matti.vaitti...@fi.rohmeurope.com> wrote:
> > > > > > > > +   BUG();
> > > > > > > > +}
> > 
> > This, though, are you sure you want to use BUG()? Linus gets upset
> > about
> > such things:
> > https://www.kernel.org/doc/html/latest/process/deprecated.html#bug-and-bug-on
> > 
> 
> I see. I am unsure of what would be the best action in the regulator
> case we are handling here. To give the context, we assume here a
> situation where power has gone out of regulation and the hardware is
> probably failing. First countermeasure to protect what is left of HW
> is
> to shut-down the failing regulator. BUG() was called here as a last
> resort if shutting the power via regulator interface was not
> implemented or working.
> 
> Eg, we try to take what ever last measure we can to minimize the HW
> damage - and BUG() was used for this in the qcom driver where I stole
> the idea. Judging the comment related to BUG() in asm-generic/bug.h
> 
> /*
>  * Don't use BUG() or BUG_ON() unless there's really no way out; one
>  
> * example might be detecting data structure corruption in the middle
>  *
> of an operation that can't be backed out of.  If the (sub)system
>  * can
> somehow continue operating, perhaps with reduced functionality,
>  * it's
> probably not BUG-worthy.
>  *
>  * If you're tempted to BUG(), think
> again:  is completely giving up
>  * really the *only* solution?  There
> are usually better options, where
>  * users don't need to reboot ASAP and
> can mostly shut down cleanly.
>  */
> https://elixir.bootlin.com/linux/v5.12-rc6/source/include/asm-generic/bug.h#L55
> 
> this really might be valid use-case.
> 
> To me the real question is what happens after the BUG() - and if
> there
> is any generic handling or if it is platform/board specific? Does it
> actually have any chance to save the HW?
> 
> Mark already pointed that we might need to figure a way to punt a
> "failing event" to the user-space to initiate better "safety
> shutdown".
> Such event does not currently exist so I think the main use-case here
> is to do logging and potentially prevent enabling any further actions
> in the failing HW.
> 
> So - any better suggestions?
> 

Maybe we should take same approach as is taken in thermal_core? Quoting
the thermal documentation:

"On an event of critical trip temperature crossing. Thermal
framework 
allows the system to shutdown gracefully by calling
orderly_poweroff().  
In the event of a failure of orderly_poweroff() to shut down the
system  
we are in danger of keeping the system alive at undesirably
high 
temperatures. To mitigate this high risk scenario we program a
work  
queue to fire after a pre-determined number of seconds to
start  
an emergency shutdown of the device using the
kernel_power_off() 
function. In case kernel_power_off() fails then
finally  
emergency_restart() is called in the worst case."

Maybe this 'hardware protection, in-kernel, emergency HW saving
shutdown' - logic, should be pulled out of thermal_core.c (or at least
exported) for (other parts like) the regulators to use?

I don't like the idea relying in the user-space to be in shape it can
handle the situation. I may be mistaken but I think a quick action
might be required. Hence the in-kernel handling does not sound so bad
to me.

I am open to all education and suggestions. Meanwhile I am planning to
just convert the BUG() to WARN(). I don't claim I know how BUG() is
implemented on each platform - but my understanding is that it does not
guarantee any power to be cut but just halts the calling process(?). I
guess this does not guarantee what happens next - maybe it even keeps
the power enabled and end up just deadlocking the system by reserved
locks? I think thermal guys have been pondering this scenario for
severe temperature protection shutdown so I would like to hear your
opinions.


Best Regards
Matti Vaittinen



Re: [RFC PATCH v3 1/3] regmap-irq: Extend sub-irq to support non-fixed reg strides

2021-04-12 Thread Matti Vaittinen
;chip->status_base, i);

How does this work with the case where we have many subregs pointed by
single main-status register bit? If I read this correctly, then the
chip->num_regs can be greater than amount of meaningful main-status
bits and thus greater than amount of map entries.

I don't have BD71828 or BD70528 at home so I haven't tested this. So
hopefully I misunderstand something - but if I don't, then this change
will break the existing main-IRQ functionality. I will visit the office
later this week and I'll see if I have a chance to test this - but I
hope you can check your change still supports the case where one main
status IRQ bit signals more than one sub-register with active IRQs.

Best Regards
Matti Vaittinen


--
Matti Vaittinen, Linux device drivers
ROHM Semiconductors, Finland SWDC
K
iviharjunlenkki 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 for the translation Simon)




Re: [PATCH v6 3/8] regulator: IRQ based event/error notification helpers

2021-04-08 Thread Matti Vaittinen
Hello Andy,

On Wed, 2021-04-07 at 16:21 +0300, Andy Shevchenko wrote:
> On Wed, Apr 7, 2021 at 1:04 PM Matti Vaittinen
>  wrote:
> > Provide helper function for IC's implementing regulator
> > notifications
> > when an IRQ fires. The helper also works for IRQs which can not be
> > acked.
> > Helper can be set to disable the IRQ at handler and then re-
> > enabling it
> > on delayed work later. The helper also adds
> > regulator_get_error_flags()
> > errors in cache for the duration of IRQ disabling.
> 
> Thanks for an update, my comments below. After addressing them, feel
> free to add
> Reviewed-by: Andy Shevchenko 

I (eventually) disagreed with couple of points here and haven't changed
those. Please see list below.

I still do think you did a really good job reviewing this - and you
should get the recognition from that work. Thus I'd nevertheless would
like to add your Reviewed-by to the next version. Please let me know if
you think it's ok. (I have the v7 ready but I'll wait until the next
Monday before sending it to see if this brings more discussion).

> > +/**
> > + * devm_regulator_irq_helper - resource managed registration of
> > IRQ based
> > + * regulator event/error notifier
> > + *
> > + * @dev:   device to which lifetime the helper's
> > lifetime is
> > + * bound.
> > + * @d: IRQ helper descriptor.
> > + * @irq:   IRQ used to inform events/errors to be
> > notified.
> > + * @irq_flags: Extra IRQ flags to be OR's with the default
> > IRQF_ONESHOT
> > + * when requesting the (threaded) irq.
> > + * @common_errs:   Errors which can be flagged by this IRQ for
> > all rdevs.
> > + * When IRQ is re-enabled these errors will be
> > cleared
> > + * from all associated regulators
> > + * @per_rdev_errs: Optional error flag array describing errors
> > specific
> > + * for only some of the regulators. These
> > errors will be
> > + * or'ed with common errors. If this is given
> > the array
> > + * should contain rdev_amount flags. Can be
> > set to NULL
> > + * if there is no regulator specific error
> > flags for this
> > + * IRQ.
> > + * @rdev:  Array of regulators associated with this
> > IRQ.
> > + * @rdev_amount:   Amount of regulators associated wit this
> > IRQ.
> 
> Can you describe, please, the return value meaning. It will be good
> also to move detailed descriptions (expectations?) of the fields to
> the Description section, here.

I added the return-value documentation as you suggested. For parameter
descriptions I still think the best and clearest place is in parameter
description.

> 
> > + */
> > +void *devm_regulator_irq_helper(struct device *dev,
> > +   const struct regulator_irq_desc *d,
> > int irq,
> > +   int irq_flags, int common_errs,
> > +   int *per_rdev_errs,
> > +   struct regulator_dev **rdev, int
> > rdev_amount)
> 
> I didn't get why you need the ** pointer instead of plain pointer.
> 

This I replied to earlier - I did change the parameter documentation a
bit to explain this:
"@rdev: Array of pointers to regulators associated with this IRQ"

> > +#include 
> > +#include 
> > +#include 
> 
> + Blank line? I would separate group of generic headers with
> particular to the subsystem

I haven't seen this practice in other parts of regulator subsystem (and
I personally fail to see the value).

> > +/**
> > + * struct regulator_irq_data - regulator error/notification status
> > date
> > + *
> > + * @states:Status structs for each of the associated
> > regulators.
> > + * @num_states:Amount of associated regulators.
> > + * @data:  Driver data pointer given at regulator_irq_desc.
> > + * @opaque:Value storage for IC driver. Core does not update
> > this. ICs
> > + * may want to store status register value here at
> > map_event and
> > + * compare contents at renable to see if new problems
> > have been
> 
> re-enable / reenable
> 
> > + * added to status. If that is the case it may be
> > desirable to
> > + * return REGULATOR_ERROR_CLEARED and not
> > REGULATOR_ERROR_ON to
> > + * allow IRQ fire again and to generate notifications
> > also for
> > + * the new issues.
> > + *
> > + * This structure is passed to map_event and renable for reporting
> > regulator
> 
> Ditto.

'renable' refers to the callback name. I tried to clarify that in
comments though.
"compare contents at 'renable' callback to see..." and "This structure
is passed to 'map_event' and 'renable' callbacks for..."

Best Regards
Matti Vaittinen



Re: [PATCH v6 3/8] regulator: IRQ based event/error notification helpers

2021-04-07 Thread Matti Vaittinen
Hello Andy, All.

On Wed, 2021-04-07 at 16:21 +0300, Andy Shevchenko wrote:
> On Wed, Apr 7, 2021 at 1:04 PM Matti Vaittinen
>  wrote:
> > Provide helper function for IC's implementing regulator
> > notifications
> > when an IRQ fires. The helper also works for IRQs which can not be
> > acked.
> > Helper can be set to disable the IRQ at handler and then re-
> > enabling it
> > on delayed work later. The helper also adds
> > regulator_get_error_flags()
> > errors in cache for the duration of IRQ disabling.
> 
> Thanks for an update, my comments below. After addressing them, feel
> free to add
> Reviewed-by: Andy Shevchenko 
> 
> > Signed-off-by: Matti Vaittinen 
> > 
> >  static int _regulator_get_error_flags(struct regulator_dev *rdev,
> > unsigned int *flags)
> >  {
> > -   int ret;
> > +   int ret, tmpret;
> > 
> > regulator_lock(rdev);
> > 
> > +   ret = rdev_get_cached_err_flags(rdev);
> > +
> > /* sanity check */
> > -   if (!rdev->desc->ops->get_error_flags) {
> > +   if (rdev->desc->ops->get_error_flags) {
> > +   tmpret = rdev->desc->ops->get_error_flags(rdev,
> > flags);
> > +   if (tmpret > 0)
> > +   ret |= tmpret;
> 
> Oh, I don't like this. Easy fix is to rename ret (okay, it's been
> used
> elsewhere, so adding then) to something meaningful, like error_flags,
> then you can easily understand that value should be positive and
> error
> codes are negative.

No wonder if this looks hairy. I think I have got this plain wrong. The
rdev_get_cached_err_flags() is not updating the flags. Looks like just
plain mistake from my side. I think I've mixed the returning flags via
parameter and return value. This must be fixed. Well spotted.


> + */
> > +void *devm_regulator_irq_helper(struct device *dev,
> > +   const struct regulator_irq_desc *d,
> > int irq,
> > +   int irq_flags, int common_errs,
> > +   int *per_rdev_errs,
> > +   struct regulator_dev **rdev, int
> > rdev_amount)
> 
> I didn't get why you need the ** pointer instead of plain pointer.

We have an array of pointers. And we give a pointer to the first
pointer. Maybe it's the lack of coffee but I don't see why a single
pointer would be correct? rdev structures are not in contagious memory,
pointers to rdevs are. So we need address of first pointer, right?
+#include 


> > +#include 
> > +#include 
> > +#include 
> 
> Not sure how this header is used. I haven't found any direct users of
> it. Perhaps you wanted interrupt.h?

Thanks. I think this specific header may be a leftover from first draft
where I thought I'll use named IRQs. The header was for
 of_irq_get_byname(). That ended up as a mess for everything else but
platform devices :) I'll check the headers, thanks.

> > +#include 
> > +#include 
> > +#include 
> 
> + Blank line? I would separate group of generic headers with
> particular to the subsystem

I don't see this being used in regulator subsystem - and to tell the
truth, I don't really see the value.

> > +#include 

...

> > +
> > +reread:
> > +   if (d->fatal_cnt && h->retry_cnt > d->fatal_cnt) {
> > +   if (d->die)
> > +   ret = d->die(rid);
> > +   else
> > +   die_loudly("Regulator HW failure? - no IC
> > recovery");
> > +
> > +   /*
> > +* If the 'last resort' IC recovery failed we will
> > have
> > +* nothing else left to do...
> > +*/
> > +   if (ret)
> > +   die_loudly("Regulator HW failure? - IC
> > recovery failed");
> 
> Looking at the above code this will be executed if and only if
> d->die() is defined, correct?
> In that case, why not
> 
> if (d->die) {
>   ret = ...
>   if (ret)
>rdev_die_loudly(...);
> } else
>rdev_die_loudly(...);
> 
> ?

I think this should simply be:

if (!d->die)
die_loudly("Regulator HW failure? - no IC recovery");

ret = d->die(rdev);
if (ret)
die_loudly(...);

...

> > +static void init_rdev_errors(struct regulator_irq *h)
> > +{
> > +   int i;
> > +
> > +   for (i = 0; i < h->rdata.num_states; i++) {
> > +   if (h->rdata.states[i].possible_errs)
> > +

[PATCH v6 8/8] MAINTAINERS: Add reviewer for regulator irq_helpers

2021-04-07 Thread Matti Vaittinen
Add a reviewer entry for the regulator irq_helpers.

Signed-off-by: Matti Vaittinen 
---
Changelog:
 v6:
  - New patch
---
 MAINTAINERS | 4 
 1 file changed, 4 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index c80ad735b384..8ed6af3e66f7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19211,6 +19211,10 @@ F: include/dt-bindings/regulator/
 F: include/linux/regulator/
 K: regulator_get_optional
 
+VOLTAGE AND CURRENT REGULATOR IRQ HELPERS
+R: Matti Vaittinen 
+F: drivers/regulator/irq_helpers.c
+
 VRF
 M: David Ahern 
 L: net...@vger.kernel.org
-- 
2.25.4


-- 
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 =] 


[PATCH v6 7/8] regulator: bd9576: Fix the driver name in id table

2021-04-07 Thread Matti Vaittinen
Driver name was changed in MFD cell:
https://lore.kernel.org/lkml/560b9748094392493ebf7af11b6cc558776c4fd5.1613031055.git.matti.vaitti...@fi.rohmeurope.com/
Fix the ID table to match this.

Signed-off-by: Matti Vaittinen 
---
Please note - this patch is not really related to the series. This
change is related to separate MFD driver change and was only added
as part of this series to avoid the conflicts.

No changes since RFC-v2
---
 drivers/regulator/bd9576-regulator.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/regulator/bd9576-regulator.c 
b/drivers/regulator/bd9576-regulator.c
index 0d55d383d2aa..aeb816cf9ad3 100644
--- a/drivers/regulator/bd9576-regulator.c
+++ b/drivers/regulator/bd9576-regulator.c
@@ -1117,8 +1117,8 @@ static int bd957x_probe(struct platform_device *pdev)
 }
 
 static const struct platform_device_id bd957x_pmic_id[] = {
-   { "bd9573-pmic", ROHM_CHIP_TYPE_BD9573 },
-   { "bd9576-pmic", ROHM_CHIP_TYPE_BD9576 },
+   { "bd9573-regulator", ROHM_CHIP_TYPE_BD9573 },
+   { "bd9576-regulator", ROHM_CHIP_TYPE_BD9576 },
{ },
 };
 MODULE_DEVICE_TABLE(platform, bd957x_pmic_id);
-- 
2.25.4


-- 
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 =] 


[PATCH v6 6/8] regulator: bd9576: Support error reporting

2021-04-07 Thread Matti Vaittinen
BD9573 and BD9576 support set of "protection" interrupts for "fatal"
issues. Those lead to SOC reset as PMIC shuts the power outputs. Thus
there is no relevant IRQ handling for them.

Few "detection" interrupts were added to the BD9576 with the idea that
SOC could take some recovery-action before error gets unrecoverable.

Add support for over and under voltage detection for Vout1 ... Vout4
and VoutL1. Add over-current detection for VoutS1 and finally a
thermal warning (common for all regulators) which alerts 30 C
before temperature reaches the thermal shutdown point. This way
consumer drivers can build error-recovery mechanisms.

Unfortunately the BD9576 interrupt logic was not re-evaluated. IRQs
are not designed to be properly acknowleged - and IRQ line is kept
active for whole duration of error condition (in comparison to
informing only about state change).

Signed-off-by: Matti Vaittinen 
---
No changes since RFC-v3
---
 drivers/regulator/bd9576-regulator.c | 1056 ++
 1 file changed, 929 insertions(+), 127 deletions(-)

diff --git a/drivers/regulator/bd9576-regulator.c 
b/drivers/regulator/bd9576-regulator.c
index a8b5832a5a1b..0d55d383d2aa 100644
--- a/drivers/regulator/bd9576-regulator.c
+++ b/drivers/regulator/bd9576-regulator.c
@@ -2,10 +2,10 @@
 // Copyright (C) 2020 ROHM Semiconductors
 // ROHM BD9576MUF/BD9573MUF regulator driver
 
-#include 
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -16,11 +16,18 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 
 #define BD957X_VOUTS1_VOLT 330
 #define BD957X_VOUTS4_BASE_VOLT103
 #define BD957X_VOUTS34_NUM_VOLT32
 
+#define BD9576_THERM_IRQ_MASK_TW   BIT(5)
+#define BD9576_xVD_IRQ_MASK_VOUTL1 BIT(5)
+#define BD9576_UVD_IRQ_MASK_VOUTS1_OCW BIT(6)
+#define BD9576_xVD_IRQ_MASK_VOUT1TO4   0x0F
+
 static int vout1_volt_table[] = {500, 490, 480, 470, 460,
 450, 450, 450, 500, 510,
 520, 530, 540, 550, 550,
@@ -36,9 +43,85 @@ static int voutl1_volt_table[] = {250, 254, 258, 
262, 266,
  242, 238, 234, 230, 226,
  222};
 
+static const struct linear_range vout1_xvd_ranges[] = {
+   REGULATOR_LINEAR_RANGE(225000, 0x01, 0x2b, 0),
+   REGULATOR_LINEAR_RANGE(225000, 0x2c, 0x54, 5000),
+   REGULATOR_LINEAR_RANGE(425000, 0x55, 0x7f, 0),
+};
+
+static const struct linear_range vout234_xvd_ranges[] = {
+   REGULATOR_LINEAR_RANGE(17000, 0x01, 0x0f, 0),
+   REGULATOR_LINEAR_RANGE(17000, 0x10, 0x6d, 1000),
+   REGULATOR_LINEAR_RANGE(11, 0x6e, 0x7f, 0),
+};
+
+static const struct linear_range voutL1_xvd_ranges[] = {
+   REGULATOR_LINEAR_RANGE(34000, 0x01, 0x0f, 0),
+   REGULATOR_LINEAR_RANGE(34000, 0x10, 0x6d, 2000),
+   REGULATOR_LINEAR_RANGE(22, 0x6e, 0x7f, 0),
+};
+
+static struct linear_range voutS1_ocw_ranges_internal[] = {
+   REGULATOR_LINEAR_RANGE(20, 0x01, 0x04, 0),
+   REGULATOR_LINEAR_RANGE(25, 0x05, 0x18, 5),
+   REGULATOR_LINEAR_RANGE(120, 0x19, 0x3f, 0),
+};
+
+static struct linear_range voutS1_ocw_ranges[] = {
+   REGULATOR_LINEAR_RANGE(5, 0x01, 0x04, 0),
+   REGULATOR_LINEAR_RANGE(6, 0x05, 0x18, 1),
+   REGULATOR_LINEAR_RANGE(25, 0x19, 0x3f, 0),
+};
+
+static struct linear_range voutS1_ocp_ranges_internal[] = {
+   REGULATOR_LINEAR_RANGE(30, 0x01, 0x06, 0),
+   REGULATOR_LINEAR_RANGE(35, 0x7, 0x1b, 5),
+   REGULATOR_LINEAR_RANGE(135, 0x1c, 0x3f, 0),
+};
+
+static struct linear_range voutS1_ocp_ranges[] = {
+   REGULATOR_LINEAR_RANGE(7, 0x01, 0x06, 0),
+   REGULATOR_LINEAR_RANGE(8, 0x7, 0x1b, 1),
+   REGULATOR_LINEAR_RANGE(28, 0x1c, 0x3f, 0),
+};
+
 struct bd957x_regulator_data {
struct regulator_desc desc;
int base_voltage;
+   struct regulator_dev *rdev;
+   int ovd_notif;
+   int uvd_notif;
+   int temp_notif;
+   int ovd_err;
+   int uvd_err;
+   int temp_err;
+   const struct linear_range *xvd_ranges;
+   int num_xvd_ranges;
+   bool oc_supported;
+   unsigned int ovd_reg;
+   unsigned int uvd_reg;
+   unsigned int xvd_mask;
+   unsigned int ocp_reg;
+   unsigned int ocp_mask;
+   unsigned int ocw_reg;
+   unsigned int ocw_mask;
+   unsigned int ocw_rfet;
+};
+
+#define BD9576_NUM_REGULATORS 6
+#define BD9576_NUM_OVD_REGULATORS 5
+
+struct bd957x_data {
+   struct bd957x_regulator_data regulator_data[BD9576_NUM_REGULATORS];
+   struct regmap *regmap;
+   struct delayed_work therm_irq_suppress;
+   struct delayed_work ovd_irq_suppress;
+   struct delayed_work uvd_irq_suppress;
+   unsigned int therm_irq;
+   unsigned int ovd_irq

[PATCH v6 5/8] dt-bindings: regulator: bd9576 add FET ON-resistance for OCW

2021-04-07 Thread Matti Vaittinen
BD9576MUF provides over-current protection and detection. Current is
measured as voltage loss over external FET. Allow specifying FET's on
resistance so current monitoring limits can be converted to voltages.

Signed-off-by: Matti Vaittinen 
---
v5 onwards:
  - No changes
v4:
  - Fixed the description indentiation
---
 .../bindings/regulator/rohm,bd9576-regulator.yaml   | 6 ++
 1 file changed, 6 insertions(+)

diff --git 
a/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml 
b/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml
index b6515a0cee62..7cb74cc8c5d9 100644
--- a/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml
+++ b/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml
@@ -27,6 +27,12 @@ patternProperties:
   Properties for single regulator.
 $ref: "regulator.yaml#"
 
+properties:
+  rohm,ocw-fet-ron-micro-ohms:
+description: |
+  External FET's ON-resistance. Required if VoutS1 OCP/OCW is
+  to be set.
+
 required:
   - regulator-name
 
-- 
2.25.4


-- 
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 =] 


[PATCH v6 4/8] regulator: add property parsing and callbacks to set protection limits

2021-04-07 Thread Matti Vaittinen
Add DT property parsing code and setting callback for regulator over/under
voltage, over-current and temperature error limits.

Signed-off-by: Matti Vaittinen 
---
No changes since RFC-v3
---
 drivers/regulator/core.c  | 122 +-
 drivers/regulator/of_regulator.c  |  58 ++
 drivers/regulator/qcom-labibb-regulator.c |  10 +-
 drivers/regulator/qcom_spmi-regulator.c   |   6 +-
 drivers/regulator/stpmic1_regulator.c |  20 +++-
 include/linux/regulator/driver.h  |  41 +++-
 include/linux/regulator/machine.h |  26 +
 7 files changed, 274 insertions(+), 9 deletions(-)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index fabc83288e1b..5a3b932dc8a5 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1312,6 +1312,52 @@ static int machine_constraints_current(struct 
regulator_dev *rdev,
 
 static int _regulator_do_enable(struct regulator_dev *rdev);
 
+static int notif_set_limit(struct regulator_dev *rdev,
+  int (*set)(struct regulator_dev *, int, int, bool),
+  int limit, int severity)
+{
+   bool enable;
+
+   if (limit == REGULATOR_NOTIF_LIMIT_DISABLE) {
+   enable = false;
+   limit = 0;
+   } else {
+   enable = true;
+   }
+
+   if (limit == REGULATOR_NOTIF_LIMIT_ENABLE)
+   limit = 0;
+
+   return set(rdev, limit, severity, enable);
+}
+
+static int handle_notify_limits(struct regulator_dev *rdev,
+   int (*set)(struct regulator_dev *, int, int, bool),
+   struct notification_limit *limits)
+{
+   int ret = 0;
+
+   if (!set)
+   return -EOPNOTSUPP;
+
+   if (limits->prot)
+   ret = notif_set_limit(rdev, set, limits->prot,
+ REGULATOR_SEVERITY_PROT);
+   if (ret)
+   return ret;
+
+   if (limits->err)
+   ret = notif_set_limit(rdev, set, limits->err,
+ REGULATOR_SEVERITY_ERR);
+   if (ret)
+   return ret;
+
+   if (limits->warn)
+   ret = notif_set_limit(rdev, set, limits->warn,
+ REGULATOR_SEVERITY_WARN);
+
+   return ret;
+}
 /**
  * set_machine_constraints - sets regulator constraints
  * @rdev: regulator source
@@ -1397,9 +1443,27 @@ static int set_machine_constraints(struct regulator_dev 
*rdev)
}
}
 
+   /*
+* Existing logic does not warn if over_current_protection is given as
+* a constraint but driver does not support that. I think we should
+* warn about this type of issues as it is possible someone changes
+* PMIC on board to another type - and the another PMIC's driver does
+* not support setting protection. Board composer may happily believe
+* the DT limits are respected - especially if the new PMIC HW also
+* supports protection but the driver does not. I won't change the logic
+* without hearing more experienced opinion on this though.
+*
+* If warning is seen as a good idea then we can merge handling the
+* over-curret protection and detection and get rid of this special
+* handling.
+*/
if (rdev->constraints->over_current_protection
&& ops->set_over_current_protection) {
-   ret = ops->set_over_current_protection(rdev);
+   int lim = rdev->constraints->over_curr_limits.prot;
+
+   ret = ops->set_over_current_protection(rdev, lim,
+  REGULATOR_SEVERITY_PROT,
+  true);
if (ret < 0) {
rdev_err(rdev, "failed to set over current protection: 
%pe\n",
 ERR_PTR(ret));
@@ -1407,6 +1471,62 @@ static int set_machine_constraints(struct regulator_dev 
*rdev)
}
}
 
+   if (rdev->constraints->over_current_detection)
+   ret = handle_notify_limits(rdev,
+  ops->set_over_current_protection,
+  
>constraints->over_curr_limits);
+   if (ret) {
+   if (ret != -EOPNOTSUPP) {
+   rdev_err(rdev, "failed to set over current limits: 
%pe\n",
+ERR_PTR(ret));
+   return ret;
+   }
+   rdev_warn(rdev,
+ "IC does not support requested over-current 
limits\n");
+   }
+
+   if (rdev->constraints->over_voltage_detection)
+   ret = handle_notify_limits(rdev,
+  ops->se

[PATCH v6 3/8] regulator: IRQ based event/error notification helpers

2021-04-07 Thread Matti Vaittinen
Provide helper function for IC's implementing regulator notifications
when an IRQ fires. The helper also works for IRQs which can not be acked.
Helper can be set to disable the IRQ at handler and then re-enabling it
on delayed work later. The helper also adds regulator_get_error_flags()
errors in cache for the duration of IRQ disabling.

Signed-off-by: Matti Vaittinen 

---
v6 (fix issues noted by Andy):
- remove unnecessary variable
- use BIT(foo) instead of 1 << foo
- use devm_add_action_or_reset()
- do not check the irq parameter validity, leave that to
  request_threaded_irq()
- put resource-managed function in devres.c
- fix the kerneldocs for the new IRQ helpers
v5:
 - fix the pr_emerg print
v4:
 - Comment block styling
 - Added prints to point the potential HW failure before BUG()
 - Corrected typo from kerneldoc
 - added missing newlines
---
 drivers/regulator/Makefile   |   2 +-
 drivers/regulator/core.c |  24 +-
 drivers/regulator/devres.c   |  49 
 drivers/regulator/irq_helpers.c  | 396 +++
 include/linux/regulator/driver.h | 135 +++
 5 files changed, 602 insertions(+), 4 deletions(-)
 create mode 100644 drivers/regulator/irq_helpers.c

diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 44d2f8bf4b74..e25f1c2d6c9b 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -4,7 +4,7 @@
 #
 
 
-obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o devres.o
+obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o devres.o 
irq_helpers.o
 obj-$(CONFIG_OF) += of_regulator.o
 obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
 obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 16114aea099a..fabc83288e1b 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -4388,20 +4388,37 @@ unsigned int regulator_get_mode(struct regulator 
*regulator)
 }
 EXPORT_SYMBOL_GPL(regulator_get_mode);
 
+static int rdev_get_cached_err_flags(struct regulator_dev *rdev)
+{
+   int ret = 0;
+
+   if (rdev->use_cached_err) {
+   spin_lock(>err_lock);
+   ret = rdev->cached_err;
+   spin_unlock(>err_lock);
+   }
+   return ret;
+}
+
 static int _regulator_get_error_flags(struct regulator_dev *rdev,
unsigned int *flags)
 {
-   int ret;
+   int ret, tmpret;
 
regulator_lock(rdev);
 
+   ret = rdev_get_cached_err_flags(rdev);
+
/* sanity check */
-   if (!rdev->desc->ops->get_error_flags) {
+   if (rdev->desc->ops->get_error_flags) {
+   tmpret = rdev->desc->ops->get_error_flags(rdev, flags);
+   if (tmpret > 0)
+   ret |= tmpret;
+   } else if (!rdev->use_cached_err) {
ret = -EINVAL;
goto out;
}
 
-   ret = rdev->desc->ops->get_error_flags(rdev, flags);
 out:
regulator_unlock(rdev);
return ret;
@@ -5236,6 +5253,7 @@ regulator_register(const struct regulator_desc 
*regulator_desc,
goto rinse;
}
device_initialize(>dev);
+   spin_lock_init(>err_lock);
 
/*
 * Duplicate the config so the driver could override it after
diff --git a/drivers/regulator/devres.c b/drivers/regulator/devres.c
index 3091210889e3..127262dcd3f7 100644
--- a/drivers/regulator/devres.c
+++ b/drivers/regulator/devres.c
@@ -481,3 +481,52 @@ void devm_regulator_unregister_notifier(struct regulator 
*regulator,
WARN_ON(rc);
 }
 EXPORT_SYMBOL_GPL(devm_regulator_unregister_notifier);
+
+static void regulator_irq_helper_drop(void *res)
+{
+   regulator_irq_helper_cancel();
+}
+
+/**
+ * devm_regulator_irq_helper - resource managed registration of IRQ based
+ * regulator event/error notifier
+ *
+ * @dev:   device to which lifetime the helper's lifetime is
+ * bound.
+ * @d: IRQ helper descriptor.
+ * @irq:   IRQ used to inform events/errors to be notified.
+ * @irq_flags: Extra IRQ flags to be OR's with the default IRQF_ONESHOT
+ * when requesting the (threaded) irq.
+ * @common_errs:   Errors which can be flagged by this IRQ for all rdevs.
+ * When IRQ is re-enabled these errors will be cleared
+ * from all associated regulators
+ * @per_rdev_errs: Optional error flag array describing errors specific
+ * for only some of the regulators. These errors will be
+ * or'ed with common errors. If this is given the array
+ * should contain rdev_amount flags. Can be set to NULL
+ * if there is no regulator specific error flags for this
+ * IRQ.
+ * @rdev:  

[PATCH v6 2/8] regulator: add warning flags

2021-04-07 Thread Matti Vaittinen
Add 'warning' level events and error flags to regulator core.
Current regulator core notifications are used to inform consumers
about errors where HW is misbehaving in such way it is assumed to
be broken/unrecoverable.

There are PMICs which are designed for system(s) that may have use
for regulator indications sent before HW is damaged so that some
board/consumer specific recovery-event can be performed while
continuing most of the normal operations.

Add new WARNING level events and notifications to be used for
that purpose.

Signed-off-by: Matti Vaittinen 
---
No changes since RFC-v2
---
 include/linux/regulator/consumer.h | 14 ++
 1 file changed, 14 insertions(+)

diff --git a/include/linux/regulator/consumer.h 
b/include/linux/regulator/consumer.h
index 20e84a84fb77..f72ca73631be 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -119,6 +119,16 @@ struct regulator_dev;
 #define REGULATOR_EVENT_PRE_DISABLE0x400
 #define REGULATOR_EVENT_ABORT_DISABLE  0x800
 #define REGULATOR_EVENT_ENABLE 0x1000
+/*
+ * Following notifications should be emitted only if detected condition
+ * is such that the HW is likely to still be working but consumers should
+ * take a recovery action to prevent problems esacalating into errors.
+ */
+#define REGULATOR_EVENT_UNDER_VOLTAGE_WARN 0x2000
+#define REGULATOR_EVENT_OVER_CURRENT_WARN  0x4000
+#define REGULATOR_EVENT_OVER_VOLTAGE_WARN  0x8000
+#define REGULATOR_EVENT_OVER_TEMP_WARN 0x1
+#define REGULATOR_EVENT_WARN_MASK  0x1E000
 
 /*
  * Regulator errors that can be queried using regulator_get_error_flags
@@ -138,6 +148,10 @@ struct regulator_dev;
 #define REGULATOR_ERROR_FAIL   BIT(4)
 #define REGULATOR_ERROR_OVER_TEMP  BIT(5)
 
+#define REGULATOR_ERROR_UNDER_VOLTAGE_WARN BIT(6)
+#define REGULATOR_ERROR_OVER_CURRENT_WARN  BIT(7)
+#define REGULATOR_ERROR_OVER_VOLTAGE_WARN  BIT(8)
+#define REGULATOR_ERROR_OVER_TEMP_WARN BIT(9)
 
 /**
  * struct pre_voltage_change_data - Data sent with PRE_VOLTAGE_CHANGE event
-- 
2.25.4


-- 
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 =] 


[PATCH v6 1/8] dt_bindings: Add protection limit properties

2021-04-07 Thread Matti Vaittinen
Support specifying protection/error/warning limits for regulator
over current, over temperature and over/under voltage.

Most of the PMICs support only "protection" feature but few
setups do also support error/warning level indications.

On many ICs most of the protection limits can't actually be set.
But for example the ampere limit for over-current protection on ROHM
BD9576 can be configured - or feature can be completely disabled.

Provide limit setting for all protections/errors for the sake of
the completeness and do that using own properties for all so that
not all users would need to set all levels when only one or few are
supported.

Signed-off-by: Matti Vaittinen 
Reviewed-by: Rob Herring 

---
No changes since RFC-v2
---
 .../bindings/regulator/regulator.yaml | 82 +++
 1 file changed, 82 insertions(+)

diff --git a/Documentation/devicetree/bindings/regulator/regulator.yaml 
b/Documentation/devicetree/bindings/regulator/regulator.yaml
index 6d0bc9cd4040..a6ae9ecae5cc 100644
--- a/Documentation/devicetree/bindings/regulator/regulator.yaml
+++ b/Documentation/devicetree/bindings/regulator/regulator.yaml
@@ -117,6 +117,88 @@ properties:
 description: Enable over current protection.
 type: boolean
 
+  regulator-oc-protection-microamp:
+description: Set over current protection limit. This is a limit where
+  hardware performs emergency shutdown. Zero can be passed to disable
+  protection and value '1' indicates that protection should be enabled but
+  limit setting can be omitted.
+
+  regulator-oc-error-microamp:
+description: Set over current error limit. This is a limit where part of
+  the hardware propably is malfunctional and damage prevention is 
requested.
+  Zero can be passed to disable error detection and value '1' indicates
+  that detection should be enabled but limit setting can be omitted.
+
+  regulator-oc-warn-microamp:
+description: Set over current warning limit. This is a limit where hardware
+  is assumed still to be functional but approaching limit where it gets
+  damaged. Recovery actions should be initiated. Zero can be passed to
+  disable detection and value '1' indicates that detection should
+  be enabled but limit setting can be omitted.
+
+  regulator-ov-protection-microvolt:
+description: Set over voltage protection limit. This is a limit where
+  hardware performs emergency shutdown. Zero can be passed to disable
+  protection and value '1' indicates that protection should be enabled but
+  limit setting can be omitted. Limit is given as microvolt offset from
+  voltage set to regulator.
+
+  regulator-ov-error-microvolt:
+description: Set over voltage error limit. This is a limit where part of
+  the hardware propably is malfunctional and damage prevention is requested
+  Zero can be passed to disable error detection and value '1' indicates
+  that detection should be enabled but limit setting can be omitted. Limit
+  is given as microvolt offset from voltage set to regulator.
+
+  regulator-ov-warn-microvolt:
+description: Set over voltage warning limit. This is a limit where hardware
+  is assumed still to be functional but approaching limit where it gets
+  damaged. Recovery actions should be initiated. Zero can be passed to
+  disable detection and value '1' indicates that detection should
+  be enabled but limit setting can be omitted. Limit is given as microvolt
+  offset from voltage set to regulator.
+
+  regulator-uv-protection-microvolt:
+description: Set over under voltage protection limit. This is a limit where
+  hardware performs emergency shutdown. Zero can be passed to disable
+  protection and value '1' indicates that protection should be enabled but
+  limit setting can be omitted. Limit is given as microvolt offset from
+  voltage set to regulator.
+
+  regulator-uv-error-microvolt:
+description: Set under voltage error limit. This is a limit where part of
+  the hardware propably is malfunctional and damage prevention is requested
+  Zero can be passed to disable error detection and value '1' indicates
+  that detection should be enabled but limit setting can be omitted. Limit
+  is given as microvolt offset from voltage set to regulator.
+
+  regulator-uv-warn-microvolt:
+description: Set over under voltage warning limit. This is a limit where
+  hardware is assumed still to be functional but approaching limit where
+  it gets damaged. Recovery actions should be initiated. Zero can be passed
+  to disable detection and value '1' indicates that detection should
+  be enabled but limit setting can be omitted. Limit is given as microvolt
+  offset from voltage set to regulator.
+
+  regulator-temp-protection-kelvin:
+description: Set over temperature protection limit. This is a limit where
+  hardware performs emergenc

[PATCH v6 0/8] Extend regulator notification support

2021-04-07 Thread Matti Vaittinen
Extend regulator notification support

This series extends the regulator notification and error flag support. Initial
discussion on the topic can be found here:
https://lore.kernel.org/lkml/6046836e22b8252983f08d5621c35ececb97820d.ca...@fi.rohmeurope.com/

This series is built on top of the BD9576MUF support patch series v9
which is currently in MFD tree at immutable branch ib-mfd-watchdog-5.13
https://lore.kernel.org/lkml/cover.1615219345.git.matti.vaitti...@fi.rohmeurope.com/
(The series should apply without those patches but there is compile time
dependency to definitions brought in at the last patch of the BD9576
series. This should be Ok though as there is a Kconfig dependency in
BD9576 regulator driver)

In a nutshell - the series adds:

1. WARNING level events/error flags. (Patch 2)
  Current regulator 'ERROR' event notifications for over/under
  voltage, over current and over temperature are used to indicate
  condition where monitored entity is so badly "off" that it actually
  indicates a hardware error which can not be recovered. The most
  typical hanling for that is believed to be a (graceful)
  system-shutdown. Here we add set of 'WARNING' level flags to allow
  sending notifications to consumers before things are 'that badly off'
  so that consumer drivers can implement recovery-actions.
2. Device-tree properties for specifying limit values. (Patches 1, 4)
  Add limits for above mentioned 'ERROR' and 'WARNING' levels (which
  send notifications to consumers) and also for a 'PROTECTION' level
  (which will be used to immediately shut-down the regulator(s) W/O
  informing consumer drivers. Typically implemented by hardware).
  Property parsing is implemented in regulator core which then calls
  callback operations for limit setting from the IC drivers. A
  warning is emitted if protection is requested by device tree but the
  underlying IC does not support configuring requested protection.
3. Helpers which can be registered by IC. (Patch 3)
  Target is to avoid implementing IRQ handling and IRQ storm protection
  in each IC driver. (Many of the ICs implementin these IRQs do not allow
  masking or acking the IRQ but keep the IRQ asserted for the whole
  duration of problem keeping the processor in IRQ handling loop).

The helper was attempted to be done so it could be used to implement
roughly same logic as is used in qcom-labibb regulator. This means
amongst other things a safety shut-down if IC registers are not readable.
Using these shut-down retry counters are optional. The idea is that the
helper could be also used by simpler ICs which do not provide status
register(s) which can be used to check if error is still active.

ICs which do not have such status register can simply omit the 'renable'
callback (and retry-counts etc) - and helper assumes the situation is Ok
and re-enables IRQ after given time period. If problem persists the
handler is ran again and another notification is sent - but at least the
delay allows processor to avoid IRQ loop.

Patch 6 takes this notification support in use at BD9576MUF.
Patch 7 is related to MFD change which is not really related to the RFC
here. It was added to this series in order to avoid potential conflicts.
Patch 8 adds a maintainers entry.

Changelog v6:
  Add MAINTAINERS entry
  Changes to IRQ notifiers
   - move devm functions to drivers/regulator/devres.c
   - drop irq validity check
   - use devm_add_action_or_reset()
   - fix styling issues
   - fix kerneldocs
Changelog v5:
   - Fix the badly formatted pr_emerg() call.
Changelog v4:
   - rebased on v5.12-rc6
   - dropped RFC
   - fix external FET DT-binding.
   - improve prints for cases when expecting HW failure.
   - styling and typos
Changelog v3:
  Regulator core:
   - Fix dangling pointer access at regulator_irq_helper()
  stpmic1_regulator:
   - fix function prototype (compile error)
  bd9576-regulator:
   - Update over current limits to what was given in new data-sheet
 (REV00K)
   - Allow over-current monitoring without external FET. Set limits to
 values given in data-sheet (REV00K).

Changelog v2:
  Generic:
  - rebase on v5.12-rc2 + BD9576 series
  - Split devm variant of delayed wq to own series
  Regulator framework:
  - Provide non devm variant of IRQ notification helpers
  - shorten dt-property names as suggested by Rob
  - unconditionally call map_event in IRQ handling and require it to be
populated
  BD9576 regulators:
  - change the FET resistance property to micro-ohms
  - fix voltage computation in OC limit setting

--

Matti Vaittinen (8):
  dt_bindings: Add protection limit properties
  regulator: add warning flags
  regulator: IRQ based event/error notification helpers
  regulator: add property parsing and callbacks to set protection limits
  dt-bindings: regulator: bd9576 add FET ON-resistance for OCW
  regulator: bd9576: Support error reporting
  regulator: bd9576: Fix the driver name in id table
  MAINTAINERS: Add reviewer for regulator i

Re: [PATCH v4 3/7] regulator: IRQ based event/error notification helpers

2021-04-06 Thread Matti Vaittinen
Morning Andy,

Thanks for the review! By the way, is it me or did your mail-client
spill this out using HTML?

On Wed, 2021-04-07 at 01:44 +0300, Andy Shevchenko wrote:
> On Tuesday, April 6, 2021, Matti Vaittinen <
> matti.vaitti...@fi.rohmeurope.com> wrote:

> > +static void die_loudly(const char *msg)
> > +{
> > +   pr_emerg(msg);
> 
> Oh là là, besides build bot complaints, this has serious security
> implications. Never do like this.
 
I'm not even trying to claim that was correct. And I did send a fixup -
sorry for this. I don't intend to do this again.

Now, when this is said - If you have a minute, please educate me.
Assuming we know all the callers and that all the callers use this as

die_loudly("foobarfoo\n");
- what is the exploit mechanism?

> > +   BUG();
> > +}
> > +


> > +/**
> > + * regulator_irq_helper - register IRQ based regulator event/error
> > notifier
> > + *
> > + * @dev:   device to which lifetime the helper's
> > lifetime is
> > + * bound.
> > + * @d: IRQ helper descriptor.
> > + * @irq:   IRQ used to inform events/errors to be
> > notified.
> > + * @irq_flags: Extra IRQ flags to be OR's with the default
> > IRQF_ONESHOT
> > + * when requesting the (threaded) irq.
> > + * @common_errs:   Errors which can be flagged by this IRQ for
> > all rdevs.
> > + * When IRQ is re-enabled these errors will be
> > cleared
> > + * from all associated regulators
> > + * @per_rdev_errs: Optional error flag array describing errors
> > specific
> > + * for only some of the regulators. These
> > errors will be
> > + * or'ed with common erros. If this is given
> > the array
> > + * should contain rdev_amount flags. Can be
> > set to NULL
> > + * if there is no regulator specific error
> > flags for this
> > + * IRQ.
> > + * @rdev:  Array of regulators associated with this
> > IRQ.
> > + * @rdev_amount:   Amount of regulators associated wit this
> > IRQ.
> > + */
> > +void *regulator_irq_helper(struct device *dev,
> > +   const struct regulator_irq_desc *d, int
> > irq,
> > +   int irq_flags, int common_errs, int
> > *per_rdev_errs,
> > +   struct regulator_dev **rdev, int
> > rdev_amount)
> > +{
> > +   struct regulator_irq *h;
> > +   int ret;
> > +
> > +   if (!rdev_amount || !d || !d->map_event || !d->name)
> > +   return ERR_PTR(-EINVAL);
> > +
> > +   if (irq <= 0) {
> > +   dev_err(dev, "No IRQ\n");
> > +   return ERR_PTR(-EINVAL);
> 
> Why shadowing error code? Negative IRQ is anything but “no IRQ”.

This was a good point. The irq is passed here as parameter. From this
function's perspective the negative irq is invalid parameter - we don't
know how the caller has obtained it. Print could show the value
contained in irq though.

Now that you pointed this out I am unsure if this check is needed here.
If we check it, then I still think we should report -EINVAL for invalid
parameter. Other option is to just call the request_threaded_irq() -
log the IRQ request failure and return what request_threaded_irq()
returns. Do you think that would make sense?

> > +
> > +/**
> > + * regulator_irq_helper_cancel - drop IRQ based regulator
> > event/error notifier
> > + *
> > + * @handle:Pointer to handle returned by a successful
> > call to
> > + * regulator_irq_helper(). Will be NULLed upon
> > return.
> > + *
> > + * The associated IRQ is released and work is cancelled when the
> > function
> > + * returns.
> > + */
> > +void regulator_irq_helper_cancel(void **handle)
> > +{
> > +   if (handle && *handle) {
> 
> Can handle ever be NULL here ? (Yes, I understand that you export
> this)

To tell the truth - I am not sure. I *guess* that if we allow this to
be NULL, then one *could* implement a driver for IC where IRQs are
optional, in a way that when IRQs are supported the pointer to handle
is valid, when IRQs aren't supported the pointer is NULL. (Why) do you
think we should skip the check?

>  
> > +   struct regulator_irq *h = *handle;
> > +
> > +   free_irq(h->irq, h);
> > +   if (h->de

[PATCH v5 7/7] regulator: bd9576: Fix the driver name in id table

2021-04-06 Thread Matti Vaittinen
Driver name was changed in MFD cell:
https://lore.kernel.org/lkml/560b9748094392493ebf7af11b6cc558776c4fd5.1613031055.git.matti.vaitti...@fi.rohmeurope.com/
Fix the ID table to match this.

Signed-off-by: Matti Vaittinen 
---
Please note - this patch is not really related to the series. This
change is related to separate MFD driver change and was only added
as part of this series to avoid the conflicts.

No changes since RFC-v2

 drivers/regulator/bd9576-regulator.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/regulator/bd9576-regulator.c 
b/drivers/regulator/bd9576-regulator.c
index 0d55d383d2aa..aeb816cf9ad3 100644
--- a/drivers/regulator/bd9576-regulator.c
+++ b/drivers/regulator/bd9576-regulator.c
@@ -1117,8 +1117,8 @@ static int bd957x_probe(struct platform_device *pdev)
 }
 
 static const struct platform_device_id bd957x_pmic_id[] = {
-   { "bd9573-pmic", ROHM_CHIP_TYPE_BD9573 },
-   { "bd9576-pmic", ROHM_CHIP_TYPE_BD9576 },
+   { "bd9573-regulator", ROHM_CHIP_TYPE_BD9573 },
+   { "bd9576-regulator", ROHM_CHIP_TYPE_BD9576 },
{ },
 };
 MODULE_DEVICE_TABLE(platform, bd957x_pmic_id);
-- 
2.25.4


-- 
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 =] 


[PATCH v5 6/7] regulator: bd9576: Support error reporting

2021-04-06 Thread Matti Vaittinen
BD9573 and BD9576 support set of "protection" interrupts for "fatal"
issues. Those lead to SOC reset as PMIC shuts the power outputs. Thus
there is no relevant IRQ handling for them.

Few "detection" interrupts were added to the BD9576 with the idea that
SOC could take some recovery-action before error gets unrecoverable.

Add support for over and under voltage detection for Vout1 ... Vout4
and VoutL1. Add over-current detection for VoutS1 and finally a
thermal warning (common for all regulators) which alerts 30 C
before temperature reaches the thermal shutdown point. This way
consumer drivers can build error-recovery mechanisms.

Unfortunately the BD9576 interrupt logic was not re-evaluated. IRQs
are not designed to be properly acknowleged - and IRQ line is kept
active for whole duration of error condition (in comparison to
informing only about state change).

Signed-off-by: Matti Vaittinen 
---
No changes since RFC-v3
 drivers/regulator/bd9576-regulator.c | 1056 ++

 1 file changed, 929 insertions(+), 127 deletions(-)

diff --git a/drivers/regulator/bd9576-regulator.c 
b/drivers/regulator/bd9576-regulator.c
index a8b5832a5a1b..0d55d383d2aa 100644
--- a/drivers/regulator/bd9576-regulator.c
+++ b/drivers/regulator/bd9576-regulator.c
@@ -2,10 +2,10 @@
 // Copyright (C) 2020 ROHM Semiconductors
 // ROHM BD9576MUF/BD9573MUF regulator driver
 
-#include 
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -16,11 +16,18 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 
 #define BD957X_VOUTS1_VOLT 330
 #define BD957X_VOUTS4_BASE_VOLT103
 #define BD957X_VOUTS34_NUM_VOLT32
 
+#define BD9576_THERM_IRQ_MASK_TW   BIT(5)
+#define BD9576_xVD_IRQ_MASK_VOUTL1 BIT(5)
+#define BD9576_UVD_IRQ_MASK_VOUTS1_OCW BIT(6)
+#define BD9576_xVD_IRQ_MASK_VOUT1TO4   0x0F
+
 static int vout1_volt_table[] = {500, 490, 480, 470, 460,
 450, 450, 450, 500, 510,
 520, 530, 540, 550, 550,
@@ -36,9 +43,85 @@ static int voutl1_volt_table[] = {250, 254, 258, 
262, 266,
  242, 238, 234, 230, 226,
  222};
 
+static const struct linear_range vout1_xvd_ranges[] = {
+   REGULATOR_LINEAR_RANGE(225000, 0x01, 0x2b, 0),
+   REGULATOR_LINEAR_RANGE(225000, 0x2c, 0x54, 5000),
+   REGULATOR_LINEAR_RANGE(425000, 0x55, 0x7f, 0),
+};
+
+static const struct linear_range vout234_xvd_ranges[] = {
+   REGULATOR_LINEAR_RANGE(17000, 0x01, 0x0f, 0),
+   REGULATOR_LINEAR_RANGE(17000, 0x10, 0x6d, 1000),
+   REGULATOR_LINEAR_RANGE(11, 0x6e, 0x7f, 0),
+};
+
+static const struct linear_range voutL1_xvd_ranges[] = {
+   REGULATOR_LINEAR_RANGE(34000, 0x01, 0x0f, 0),
+   REGULATOR_LINEAR_RANGE(34000, 0x10, 0x6d, 2000),
+   REGULATOR_LINEAR_RANGE(22, 0x6e, 0x7f, 0),
+};
+
+static struct linear_range voutS1_ocw_ranges_internal[] = {
+   REGULATOR_LINEAR_RANGE(20, 0x01, 0x04, 0),
+   REGULATOR_LINEAR_RANGE(25, 0x05, 0x18, 5),
+   REGULATOR_LINEAR_RANGE(120, 0x19, 0x3f, 0),
+};
+
+static struct linear_range voutS1_ocw_ranges[] = {
+   REGULATOR_LINEAR_RANGE(5, 0x01, 0x04, 0),
+   REGULATOR_LINEAR_RANGE(6, 0x05, 0x18, 1),
+   REGULATOR_LINEAR_RANGE(25, 0x19, 0x3f, 0),
+};
+
+static struct linear_range voutS1_ocp_ranges_internal[] = {
+   REGULATOR_LINEAR_RANGE(30, 0x01, 0x06, 0),
+   REGULATOR_LINEAR_RANGE(35, 0x7, 0x1b, 5),
+   REGULATOR_LINEAR_RANGE(135, 0x1c, 0x3f, 0),
+};
+
+static struct linear_range voutS1_ocp_ranges[] = {
+   REGULATOR_LINEAR_RANGE(7, 0x01, 0x06, 0),
+   REGULATOR_LINEAR_RANGE(8, 0x7, 0x1b, 1),
+   REGULATOR_LINEAR_RANGE(28, 0x1c, 0x3f, 0),
+};
+
 struct bd957x_regulator_data {
struct regulator_desc desc;
int base_voltage;
+   struct regulator_dev *rdev;
+   int ovd_notif;
+   int uvd_notif;
+   int temp_notif;
+   int ovd_err;
+   int uvd_err;
+   int temp_err;
+   const struct linear_range *xvd_ranges;
+   int num_xvd_ranges;
+   bool oc_supported;
+   unsigned int ovd_reg;
+   unsigned int uvd_reg;
+   unsigned int xvd_mask;
+   unsigned int ocp_reg;
+   unsigned int ocp_mask;
+   unsigned int ocw_reg;
+   unsigned int ocw_mask;
+   unsigned int ocw_rfet;
+};
+
+#define BD9576_NUM_REGULATORS 6
+#define BD9576_NUM_OVD_REGULATORS 5
+
+struct bd957x_data {
+   struct bd957x_regulator_data regulator_data[BD9576_NUM_REGULATORS];
+   struct regmap *regmap;
+   struct delayed_work therm_irq_suppress;
+   struct delayed_work ovd_irq_suppress;
+   struct delayed_work uvd_irq_suppress;
+   unsigned int therm_irq;
+   unsigned int ovd_irq

[PATCH v5 5/7] dt-bindings: regulator: bd9576 add FET ON-resistance for OCW

2021-04-06 Thread Matti Vaittinen
BD9576MUF provides over-current protection and detection. Current is
measured as voltage loss over external FET. Allow specifying FET's on
resistance so current monitoring limits can be converted to voltages.

Signed-off-by: Matti Vaittinen 
---
v5:
  - No changes
v4:
  - Fixed the description indentiation

 .../bindings/regulator/rohm,bd9576-regulator.yaml   | 6 ++
 1 file changed, 6 insertions(+)

diff --git 
a/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml 
b/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml
index b6515a0cee62..7cb74cc8c5d9 100644
--- a/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml
+++ b/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml
@@ -27,6 +27,12 @@ patternProperties:
   Properties for single regulator.
 $ref: "regulator.yaml#"
 
+properties:
+  rohm,ocw-fet-ron-micro-ohms:
+description: |
+  External FET's ON-resistance. Required if VoutS1 OCP/OCW is
+  to be set.
+
 required:
   - regulator-name
 
-- 
2.25.4


-- 
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 =] 


[PATCH v5 4/7] regulator: add property parsing and callbacks to set protection limits

2021-04-06 Thread Matti Vaittinen
Add DT property parsing code and setting callback for regulator over/under
voltage, over-current and temperature error limits.

Signed-off-by: Matti Vaittinen 
---
No changes since RFC-v3

 drivers/regulator/core.c  | 122 +-
 drivers/regulator/of_regulator.c  |  58 ++
 drivers/regulator/qcom-labibb-regulator.c |  10 +-
 drivers/regulator/qcom_spmi-regulator.c   |   6 +-
 drivers/regulator/stpmic1_regulator.c |  20 +++-
 include/linux/regulator/driver.h  |  41 +++-
 include/linux/regulator/machine.h |  26 +
 7 files changed, 274 insertions(+), 9 deletions(-)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index fabc83288e1b..5a3b932dc8a5 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1312,6 +1312,52 @@ static int machine_constraints_current(struct 
regulator_dev *rdev,
 
 static int _regulator_do_enable(struct regulator_dev *rdev);
 
+static int notif_set_limit(struct regulator_dev *rdev,
+  int (*set)(struct regulator_dev *, int, int, bool),
+  int limit, int severity)
+{
+   bool enable;
+
+   if (limit == REGULATOR_NOTIF_LIMIT_DISABLE) {
+   enable = false;
+   limit = 0;
+   } else {
+   enable = true;
+   }
+
+   if (limit == REGULATOR_NOTIF_LIMIT_ENABLE)
+   limit = 0;
+
+   return set(rdev, limit, severity, enable);
+}
+
+static int handle_notify_limits(struct regulator_dev *rdev,
+   int (*set)(struct regulator_dev *, int, int, bool),
+   struct notification_limit *limits)
+{
+   int ret = 0;
+
+   if (!set)
+   return -EOPNOTSUPP;
+
+   if (limits->prot)
+   ret = notif_set_limit(rdev, set, limits->prot,
+ REGULATOR_SEVERITY_PROT);
+   if (ret)
+   return ret;
+
+   if (limits->err)
+   ret = notif_set_limit(rdev, set, limits->err,
+ REGULATOR_SEVERITY_ERR);
+   if (ret)
+   return ret;
+
+   if (limits->warn)
+   ret = notif_set_limit(rdev, set, limits->warn,
+ REGULATOR_SEVERITY_WARN);
+
+   return ret;
+}
 /**
  * set_machine_constraints - sets regulator constraints
  * @rdev: regulator source
@@ -1397,9 +1443,27 @@ static int set_machine_constraints(struct regulator_dev 
*rdev)
}
}
 
+   /*
+* Existing logic does not warn if over_current_protection is given as
+* a constraint but driver does not support that. I think we should
+* warn about this type of issues as it is possible someone changes
+* PMIC on board to another type - and the another PMIC's driver does
+* not support setting protection. Board composer may happily believe
+* the DT limits are respected - especially if the new PMIC HW also
+* supports protection but the driver does not. I won't change the logic
+* without hearing more experienced opinion on this though.
+*
+* If warning is seen as a good idea then we can merge handling the
+* over-curret protection and detection and get rid of this special
+* handling.
+*/
if (rdev->constraints->over_current_protection
&& ops->set_over_current_protection) {
-   ret = ops->set_over_current_protection(rdev);
+   int lim = rdev->constraints->over_curr_limits.prot;
+
+   ret = ops->set_over_current_protection(rdev, lim,
+  REGULATOR_SEVERITY_PROT,
+  true);
if (ret < 0) {
rdev_err(rdev, "failed to set over current protection: 
%pe\n",
 ERR_PTR(ret));
@@ -1407,6 +1471,62 @@ static int set_machine_constraints(struct regulator_dev 
*rdev)
}
}
 
+   if (rdev->constraints->over_current_detection)
+   ret = handle_notify_limits(rdev,
+  ops->set_over_current_protection,
+  
>constraints->over_curr_limits);
+   if (ret) {
+   if (ret != -EOPNOTSUPP) {
+   rdev_err(rdev, "failed to set over current limits: 
%pe\n",
+ERR_PTR(ret));
+   return ret;
+   }
+   rdev_warn(rdev,
+ "IC does not support requested over-current 
limits\n");
+   }
+
+   if (rdev->constraints->over_voltage_detection)
+   ret = handle_notify_limits(rdev,
+  ops->se

[PATCH v5 3/7] regulator: IRQ based event/error notification helpers

2021-04-06 Thread Matti Vaittinen
Provide helper function for IC's implementing regulator notifications
when an IRQ fires. The helper also works for IRQs which can not be acked.
Helper can be set to disable the IRQ at handler and then re-enabling it
on delayed work later. The helper also adds regulator_get_error_flags()
errors in cache for the duration of IRQ disabling.

Signed-off-by: Matti Vaittinen 
---
v5:
 - fix the pr_emerg print
v4:
 - Comment block styling
 - Added prints to point the potential HW failure before BUG()
 - Corrected typo from kerneldoc
 - added missing newlines

 drivers/regulator/Makefile   |   2 +-
 drivers/regulator/core.c |  24 +-
 drivers/regulator/irq_helpers.c  | 432 +++
 include/linux/regulator/driver.h | 135 ++
 4 files changed, 589 insertions(+), 4 deletions(-)
 create mode 100644 drivers/regulator/irq_helpers.c

diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 44d2f8bf4b74..e25f1c2d6c9b 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -4,7 +4,7 @@
 #
 
 
-obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o devres.o
+obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o devres.o 
irq_helpers.o
 obj-$(CONFIG_OF) += of_regulator.o
 obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
 obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 16114aea099a..fabc83288e1b 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -4388,20 +4388,37 @@ unsigned int regulator_get_mode(struct regulator 
*regulator)
 }
 EXPORT_SYMBOL_GPL(regulator_get_mode);
 
+static int rdev_get_cached_err_flags(struct regulator_dev *rdev)
+{
+   int ret = 0;
+
+   if (rdev->use_cached_err) {
+   spin_lock(>err_lock);
+   ret = rdev->cached_err;
+   spin_unlock(>err_lock);
+   }
+   return ret;
+}
+
 static int _regulator_get_error_flags(struct regulator_dev *rdev,
unsigned int *flags)
 {
-   int ret;
+   int ret, tmpret;
 
regulator_lock(rdev);
 
+   ret = rdev_get_cached_err_flags(rdev);
+
/* sanity check */
-   if (!rdev->desc->ops->get_error_flags) {
+   if (rdev->desc->ops->get_error_flags) {
+   tmpret = rdev->desc->ops->get_error_flags(rdev, flags);
+   if (tmpret > 0)
+   ret |= tmpret;
+   } else if (!rdev->use_cached_err) {
ret = -EINVAL;
goto out;
}
 
-   ret = rdev->desc->ops->get_error_flags(rdev, flags);
 out:
regulator_unlock(rdev);
return ret;
@@ -5236,6 +5253,7 @@ regulator_register(const struct regulator_desc 
*regulator_desc,
goto rinse;
}
device_initialize(>dev);
+   spin_lock_init(>err_lock);
 
/*
 * Duplicate the config so the driver could override it after
diff --git a/drivers/regulator/irq_helpers.c b/drivers/regulator/irq_helpers.c
new file mode 100644
index ..868494904d61
--- /dev/null
+++ b/drivers/regulator/irq_helpers.c
@@ -0,0 +1,432 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2021 ROHM Semiconductors
+// regulator IRQ based event notification helpers
+//
+// Logic has been partially adapted from qcom-labibb driver.
+//
+// Author: Matti Vaittinen 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+struct regulator_irq {
+   struct regulator_irq_data rdata;
+   struct regulator_irq_desc desc;
+   int irq;
+   int retry_cnt;
+   struct delayed_work isr_work;
+};
+
+/*
+ * Should only be called from threaded handler to prevent potential deadlock
+ */
+static void rdev_flag_err(struct regulator_dev *rdev, int err)
+{
+   spin_lock(>err_lock);
+   rdev->cached_err |= err;
+   spin_unlock(>err_lock);
+}
+
+static void rdev_clear_err(struct regulator_dev *rdev, int err)
+{
+   spin_lock(>err_lock);
+   rdev->cached_err &= ~err;
+   spin_unlock(>err_lock);
+}
+
+static void die_loudly(const char *msg)
+{
+   pr_emerg("%s\n", msg);
+   BUG();
+}
+
+static void regulator_notifier_isr_work(struct work_struct *work)
+{
+   struct regulator_irq *h;
+   struct regulator_irq_desc *d;
+   struct regulator_irq_data *rid;
+   int ret = 0;
+   int tmo, i;
+   int num_rdevs;
+
+   h = container_of(work, struct regulator_irq,
+   isr_work.work);
+   d = >desc;
+   rid = >rdata;
+   num_rdevs = rid->num_states;
+
+reread:
+   if (d->fatal_cnt && h->retry_cnt > d->fatal_cnt) {
+   if (d->die)
+   ret = d->die(rid);
+   else
+   die_loudly("Re

[PATCH v5 2/7] regulator: add warning flags

2021-04-06 Thread Matti Vaittinen
Add 'warning' level events and error flags to regulator core.
Current regulator core notifications are used to inform consumers
about errors where HW is misbehaving in such way it is assumed to
be broken/unrecoverable.

There are PMICs which are designed for system(s) that may have use
for regulator indications sent before HW is damaged so that some
board/consumer specific recovery-event can be performed while
continuing most of the normal operations.

Add new WARNING level events and notifications to be used for
that purpose.

Signed-off-by: Matti Vaittinen 
---
No changes since RFC-v2

 include/linux/regulator/consumer.h | 14 ++
 1 file changed, 14 insertions(+)

diff --git a/include/linux/regulator/consumer.h 
b/include/linux/regulator/consumer.h
index 20e84a84fb77..f72ca73631be 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -119,6 +119,16 @@ struct regulator_dev;
 #define REGULATOR_EVENT_PRE_DISABLE0x400
 #define REGULATOR_EVENT_ABORT_DISABLE  0x800
 #define REGULATOR_EVENT_ENABLE 0x1000
+/*
+ * Following notifications should be emitted only if detected condition
+ * is such that the HW is likely to still be working but consumers should
+ * take a recovery action to prevent problems esacalating into errors.
+ */
+#define REGULATOR_EVENT_UNDER_VOLTAGE_WARN 0x2000
+#define REGULATOR_EVENT_OVER_CURRENT_WARN  0x4000
+#define REGULATOR_EVENT_OVER_VOLTAGE_WARN  0x8000
+#define REGULATOR_EVENT_OVER_TEMP_WARN 0x1
+#define REGULATOR_EVENT_WARN_MASK  0x1E000
 
 /*
  * Regulator errors that can be queried using regulator_get_error_flags
@@ -138,6 +148,10 @@ struct regulator_dev;
 #define REGULATOR_ERROR_FAIL   BIT(4)
 #define REGULATOR_ERROR_OVER_TEMP  BIT(5)
 
+#define REGULATOR_ERROR_UNDER_VOLTAGE_WARN BIT(6)
+#define REGULATOR_ERROR_OVER_CURRENT_WARN  BIT(7)
+#define REGULATOR_ERROR_OVER_VOLTAGE_WARN  BIT(8)
+#define REGULATOR_ERROR_OVER_TEMP_WARN BIT(9)
 
 /**
  * struct pre_voltage_change_data - Data sent with PRE_VOLTAGE_CHANGE event
-- 
2.25.4


-- 
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 =] 


[PATCH v5 1/7] dt_bindings: Add protection limit properties

2021-04-06 Thread Matti Vaittinen
Support specifying protection/error/warning limits for regulator
over current, over temperature and over/under voltage.

Most of the PMICs support only "protection" feature but few
setups do also support error/warning level indications.

On many ICs most of the protection limits can't actually be set.
But for example the ampere limit for over-current protection on ROHM
BD9576 can be configured - or feature can be completely disabled.

Provide limit setting for all protections/errors for the sake of
the completeness and do that using own properties for all so that
not all users would need to set all levels when only one or few are
supported.

Signed-off-by: Matti Vaittinen 
Reviewed-by: Rob Herring 

---
No changes since RFC-v2

 .../bindings/regulator/regulator.yaml | 82 +++
 1 file changed, 82 insertions(+)

diff --git a/Documentation/devicetree/bindings/regulator/regulator.yaml 
b/Documentation/devicetree/bindings/regulator/regulator.yaml
index 6d0bc9cd4040..a6ae9ecae5cc 100644
--- a/Documentation/devicetree/bindings/regulator/regulator.yaml
+++ b/Documentation/devicetree/bindings/regulator/regulator.yaml
@@ -117,6 +117,88 @@ properties:
 description: Enable over current protection.
 type: boolean
 
+  regulator-oc-protection-microamp:
+description: Set over current protection limit. This is a limit where
+  hardware performs emergency shutdown. Zero can be passed to disable
+  protection and value '1' indicates that protection should be enabled but
+  limit setting can be omitted.
+
+  regulator-oc-error-microamp:
+description: Set over current error limit. This is a limit where part of
+  the hardware propably is malfunctional and damage prevention is 
requested.
+  Zero can be passed to disable error detection and value '1' indicates
+  that detection should be enabled but limit setting can be omitted.
+
+  regulator-oc-warn-microamp:
+description: Set over current warning limit. This is a limit where hardware
+  is assumed still to be functional but approaching limit where it gets
+  damaged. Recovery actions should be initiated. Zero can be passed to
+  disable detection and value '1' indicates that detection should
+  be enabled but limit setting can be omitted.
+
+  regulator-ov-protection-microvolt:
+description: Set over voltage protection limit. This is a limit where
+  hardware performs emergency shutdown. Zero can be passed to disable
+  protection and value '1' indicates that protection should be enabled but
+  limit setting can be omitted. Limit is given as microvolt offset from
+  voltage set to regulator.
+
+  regulator-ov-error-microvolt:
+description: Set over voltage error limit. This is a limit where part of
+  the hardware propably is malfunctional and damage prevention is requested
+  Zero can be passed to disable error detection and value '1' indicates
+  that detection should be enabled but limit setting can be omitted. Limit
+  is given as microvolt offset from voltage set to regulator.
+
+  regulator-ov-warn-microvolt:
+description: Set over voltage warning limit. This is a limit where hardware
+  is assumed still to be functional but approaching limit where it gets
+  damaged. Recovery actions should be initiated. Zero can be passed to
+  disable detection and value '1' indicates that detection should
+  be enabled but limit setting can be omitted. Limit is given as microvolt
+  offset from voltage set to regulator.
+
+  regulator-uv-protection-microvolt:
+description: Set over under voltage protection limit. This is a limit where
+  hardware performs emergency shutdown. Zero can be passed to disable
+  protection and value '1' indicates that protection should be enabled but
+  limit setting can be omitted. Limit is given as microvolt offset from
+  voltage set to regulator.
+
+  regulator-uv-error-microvolt:
+description: Set under voltage error limit. This is a limit where part of
+  the hardware propably is malfunctional and damage prevention is requested
+  Zero can be passed to disable error detection and value '1' indicates
+  that detection should be enabled but limit setting can be omitted. Limit
+  is given as microvolt offset from voltage set to regulator.
+
+  regulator-uv-warn-microvolt:
+description: Set over under voltage warning limit. This is a limit where
+  hardware is assumed still to be functional but approaching limit where
+  it gets damaged. Recovery actions should be initiated. Zero can be passed
+  to disable detection and value '1' indicates that detection should
+  be enabled but limit setting can be omitted. Limit is given as microvolt
+  offset from voltage set to regulator.
+
+  regulator-temp-protection-kelvin:
+description: Set over temperature protection limit. This is a limit where
+  hardware performs emergency shut

[PATCH v5 0/7] Extend regulator notification support

2021-04-06 Thread Matti Vaittinen
Extend regulator notification support

This series extends the regulator notification and error flag support. Initial
discussion on the topic can be found here:
https://lore.kernel.org/lkml/6046836e22b8252983f08d5621c35ececb97820d.ca...@fi.rohmeurope.com/

This series is built on top of the BD9576MUF support patch series v9
which is currently in MFD tree at immutable branch ib-mfd-watchdog-5.13
https://lore.kernel.org/lkml/cover.1615219345.git.matti.vaitti...@fi.rohmeurope.com/
(The series should apply without those patches but there is compile time
dependency to definitions brought in at the last patch of the BD9576
series. This should be Ok though as there is a Kconfig dependency in
BD9576 regulator driver)

In a nutshell - the series adds:

1. WARNING level events/error flags. (Patch 2)
  Current regulator 'ERROR' event notifications for over/under
  voltage, over current and over temperature are used to indicate
  condition where monitored entity is so badly "off" that it actually
  indicates a hardware error which can not be recovered. The most
  typical hanling for that is believed to be a (graceful)
  system-shutdown. Here we add set of 'WARNING' level flags to allow
  sending notifications to consumers before things are 'that badly off'
  so that consumer drivers can implement recovery-actions.
2. Device-tree properties for specifying limit values. (Patches 1, 4)
  Add limits for above mentioned 'ERROR' and 'WARNING' levels (which
  send notifications to consumers) and also for a 'PROTECTION' level
  (which will be used to immediately shut-down the regulator(s) W/O
  informing consumer drivers. Typically implemented by hardware).
  Property parsing is implemented in regulator core which then calls
  callback operations for limit setting from the IC drivers. A
  warning is emitted if protection is requested by device tree but the
  underlying IC does not support configuring requested protection.
3. Helpers which can be registered by IC. (Patch 3)
  Target is to avoid implementing IRQ handling and IRQ storm protection
  in each IC driver. (Many of the ICs implementin these IRQs do not allow
  masking or acking the IRQ but keep the IRQ asserted for the whole
  duration of problem keeping the processor in IRQ handling loop).

The helper was attempted to be done so it could be used to implement
roughly same logic as is used in qcom-labibb regulator. This means
amongst other things a safety shut-down if IC registers are not readable.
Using these shut-down retry counters are optional. The idea is that the
helper could be also used by simpler ICs which do not provide status
register(s) which can be used to check if error is still active.

ICs which do not have such status register can simply omit the 'renable'
callback (and retry-counts etc) - and helper assumes the situation is Ok
and re-enables IRQ after given time period. If problem persists the
handler is ran again and another notification is sent - but at least the
delay allows processor to avoid IRQ loop.

Patch 6 takes this notification support in use at BD9576MUF.
Patch 7 is related to MFD change which is not really related to the RFC
here. It was added to this series in order to avoid potential conflicts.

Changelog v5:
   - Fix the badly formatted pr_emerg() call.
Changelog v4:
   - rebased on v5.12-rc6
   - dropped RFC
   - fix external FET DT-binding.
   - improve prints for cases when expecting HW failure.
   - styling and typos
Changelog v3:
  Regulator core:
   - Fix dangling pointer access at regulator_irq_helper()
  stpmic1_regulator:
   - fix function prototype (compile error)
  bd9576-regulator:
   - Update over current limits to what was given in new data-sheet
 (REV00K)
   - Allow over-current monitoring without external FET. Set limits to
 values given in data-sheet (REV00K).

Changelog v2:
  Generic:
  - rebase on v5.12-rc2 + BD9576 series
  - Split devm variant of delayed wq to own series
  Regulator framework:
  - Provide non devm variant of IRQ notification helpers
  - shorten dt-property names as suggested by Rob
  - unconditionally call map_event in IRQ handling and require it to be
populated
  BD9576 regulators:
  - change the FET resistance property to micro-ohms
  - fix voltage computation in OC limit setting

--

Matti Vaittinen (7):
  dt_bindings: Add protection limit properties
  regulator: add warning flags
  regulator: IRQ based event/error notification helpers
  regulator: add property parsing and callbacks to set protection limits
  dt-bindings: regulator: bd9576 add FET ON-resistance for OCW
  regulator: bd9576: Support error reporting
  regulator: bd9576: Fix the driver name in id table

 .../bindings/regulator/regulator.yaml |   82 ++
 .../regulator/rohm,bd9576-regulator.yaml  |6 +
 drivers/regulator/Makefile|2 +-
 drivers/regulator/bd9576-regulator.c  | 1060 +++--
 drivers/regulator/core.c  |  146 ++-
 drivers

Re: [PATCH v4 3/7] regulator: IRQ based event/error notification helpers

2021-04-06 Thread Matti Vaittinen


On Tue, 2021-04-06 at 18:27 +0800, kernel test robot wrote:
> If you fix the issue, kindly add following tag as appropriate
> Reported-by: kernel test robot 
> 
> All errors (new ones prefixed by >>):
> 
>In file included from include/linux/kernel.h:16,
> from arch/x86/include/asm/percpu.h:27,
> from arch/x86/include/asm/current.h:6,
> from include/linux/sched.h:12,
> from include/linux/ratelimit.h:6,
> from include/linux/dev_printk.h:16,
> from include/linux/device.h:15,
> from drivers/regulator/irq_helpers.c:10:
>drivers/regulator/irq_helpers.c: In function 'die_loudly':
> > > drivers/regulator/irq_helpers.c:46:11: error: expected ')' before
> > > 'msg'
>   46 |  pr_emerg(msg);
>  |   ^~~
>include/linux/printk.h:301:21: note: in definition of macro
> 'pr_fmt'
>  301 | #define pr_fmt(fmt) fmt
>  | ^~~
>drivers/regulator/irq_helpers.c:46:2: note: in expansion of macro
> 'pr_emerg'
>   46 |  pr_emerg(msg);
>  |  ^~~~

Ouch. Feeling stupid now.
I am sorry for the hassle folks. I'll fix this ASAP and resend.

> 
> vim +46 drivers/regulator/irq_helpers.c
> 
> 43
> 44static void die_loudly(const char *msg)
> 45{
>   > 46    pr_emerg(msg);
> 47BUG();
> 48}
> 49

Best Regards
Matti Vaittinen




[PATCH v4 7/7] regulator: bd9576: Fix the driver name in id table

2021-04-06 Thread Matti Vaittinen
Driver name was changed in MFD cell:
https://lore.kernel.org/lkml/560b9748094392493ebf7af11b6cc558776c4fd5.1613031055.git.matti.vaitti...@fi.rohmeurope.com/
Fix the ID table to match this.

Signed-off-by: Matti Vaittinen 
---
Please note - this patch is not really related to the series. This
change is related to separate MFD driver change and was only added
as part of this series to avoid the conflicts.

No changes since RFC-v2

 drivers/regulator/bd9576-regulator.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/regulator/bd9576-regulator.c 
b/drivers/regulator/bd9576-regulator.c
index 0d55d383d2aa..aeb816cf9ad3 100644
--- a/drivers/regulator/bd9576-regulator.c
+++ b/drivers/regulator/bd9576-regulator.c
@@ -1117,8 +1117,8 @@ static int bd957x_probe(struct platform_device *pdev)
 }
 
 static const struct platform_device_id bd957x_pmic_id[] = {
-   { "bd9573-pmic", ROHM_CHIP_TYPE_BD9573 },
-   { "bd9576-pmic", ROHM_CHIP_TYPE_BD9576 },
+   { "bd9573-regulator", ROHM_CHIP_TYPE_BD9573 },
+   { "bd9576-regulator", ROHM_CHIP_TYPE_BD9576 },
{ },
 };
 MODULE_DEVICE_TABLE(platform, bd957x_pmic_id);
-- 
2.25.4


-- 
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 =] 


[PATCH v4 6/7] regulator: bd9576: Support error reporting

2021-04-06 Thread Matti Vaittinen
BD9573 and BD9576 support set of "protection" interrupts for "fatal"
issues. Those lead to SOC reset as PMIC shuts the power outputs. Thus
there is no relevant IRQ handling for them.

Few "detection" interrupts were added to the BD9576 with the idea that
SOC could take some recovery-action before error gets unrecoverable.

Add support for over and under voltage detection for Vout1 ... Vout4
and VoutL1. Add over-current detection for VoutS1 and finally a
thermal warning (common for all regulators) which alerts 30 C
before temperature reaches the thermal shutdown point. This way
consumer drivers can build error-recovery mechanisms.

Unfortunately the BD9576 interrupt logic was not re-evaluated. IRQs
are not designed to be properly acknowleged - and IRQ line is kept
active for whole duration of error condition (in comparison to
informing only about state change).

Signed-off-by: Matti Vaittinen 
---
No changes since RFC-v3

 drivers/regulator/bd9576-regulator.c | 1056 ++
 1 file changed, 929 insertions(+), 127 deletions(-)

diff --git a/drivers/regulator/bd9576-regulator.c 
b/drivers/regulator/bd9576-regulator.c
index a8b5832a5a1b..0d55d383d2aa 100644
--- a/drivers/regulator/bd9576-regulator.c
+++ b/drivers/regulator/bd9576-regulator.c
@@ -2,10 +2,10 @@
 // Copyright (C) 2020 ROHM Semiconductors
 // ROHM BD9576MUF/BD9573MUF regulator driver
 
-#include 
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -16,11 +16,18 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 
 #define BD957X_VOUTS1_VOLT 330
 #define BD957X_VOUTS4_BASE_VOLT103
 #define BD957X_VOUTS34_NUM_VOLT32
 
+#define BD9576_THERM_IRQ_MASK_TW   BIT(5)
+#define BD9576_xVD_IRQ_MASK_VOUTL1 BIT(5)
+#define BD9576_UVD_IRQ_MASK_VOUTS1_OCW BIT(6)
+#define BD9576_xVD_IRQ_MASK_VOUT1TO4   0x0F
+
 static int vout1_volt_table[] = {500, 490, 480, 470, 460,
 450, 450, 450, 500, 510,
 520, 530, 540, 550, 550,
@@ -36,9 +43,85 @@ static int voutl1_volt_table[] = {250, 254, 258, 
262, 266,
  242, 238, 234, 230, 226,
  222};
 
+static const struct linear_range vout1_xvd_ranges[] = {
+   REGULATOR_LINEAR_RANGE(225000, 0x01, 0x2b, 0),
+   REGULATOR_LINEAR_RANGE(225000, 0x2c, 0x54, 5000),
+   REGULATOR_LINEAR_RANGE(425000, 0x55, 0x7f, 0),
+};
+
+static const struct linear_range vout234_xvd_ranges[] = {
+   REGULATOR_LINEAR_RANGE(17000, 0x01, 0x0f, 0),
+   REGULATOR_LINEAR_RANGE(17000, 0x10, 0x6d, 1000),
+   REGULATOR_LINEAR_RANGE(11, 0x6e, 0x7f, 0),
+};
+
+static const struct linear_range voutL1_xvd_ranges[] = {
+   REGULATOR_LINEAR_RANGE(34000, 0x01, 0x0f, 0),
+   REGULATOR_LINEAR_RANGE(34000, 0x10, 0x6d, 2000),
+   REGULATOR_LINEAR_RANGE(22, 0x6e, 0x7f, 0),
+};
+
+static struct linear_range voutS1_ocw_ranges_internal[] = {
+   REGULATOR_LINEAR_RANGE(20, 0x01, 0x04, 0),
+   REGULATOR_LINEAR_RANGE(25, 0x05, 0x18, 5),
+   REGULATOR_LINEAR_RANGE(120, 0x19, 0x3f, 0),
+};
+
+static struct linear_range voutS1_ocw_ranges[] = {
+   REGULATOR_LINEAR_RANGE(5, 0x01, 0x04, 0),
+   REGULATOR_LINEAR_RANGE(6, 0x05, 0x18, 1),
+   REGULATOR_LINEAR_RANGE(25, 0x19, 0x3f, 0),
+};
+
+static struct linear_range voutS1_ocp_ranges_internal[] = {
+   REGULATOR_LINEAR_RANGE(30, 0x01, 0x06, 0),
+   REGULATOR_LINEAR_RANGE(35, 0x7, 0x1b, 5),
+   REGULATOR_LINEAR_RANGE(135, 0x1c, 0x3f, 0),
+};
+
+static struct linear_range voutS1_ocp_ranges[] = {
+   REGULATOR_LINEAR_RANGE(7, 0x01, 0x06, 0),
+   REGULATOR_LINEAR_RANGE(8, 0x7, 0x1b, 1),
+   REGULATOR_LINEAR_RANGE(28, 0x1c, 0x3f, 0),
+};
+
 struct bd957x_regulator_data {
struct regulator_desc desc;
int base_voltage;
+   struct regulator_dev *rdev;
+   int ovd_notif;
+   int uvd_notif;
+   int temp_notif;
+   int ovd_err;
+   int uvd_err;
+   int temp_err;
+   const struct linear_range *xvd_ranges;
+   int num_xvd_ranges;
+   bool oc_supported;
+   unsigned int ovd_reg;
+   unsigned int uvd_reg;
+   unsigned int xvd_mask;
+   unsigned int ocp_reg;
+   unsigned int ocp_mask;
+   unsigned int ocw_reg;
+   unsigned int ocw_mask;
+   unsigned int ocw_rfet;
+};
+
+#define BD9576_NUM_REGULATORS 6
+#define BD9576_NUM_OVD_REGULATORS 5
+
+struct bd957x_data {
+   struct bd957x_regulator_data regulator_data[BD9576_NUM_REGULATORS];
+   struct regmap *regmap;
+   struct delayed_work therm_irq_suppress;
+   struct delayed_work ovd_irq_suppress;
+   struct delayed_work uvd_irq_suppress;
+   unsigned int therm_irq;
+   unsigned int ovd_irq

[PATCH v4 5/7] dt-bindings: regulator: bd9576 add FET ON-resistance for OCW

2021-04-06 Thread Matti Vaittinen
BD9576MUF provides over-current protection and detection. Current is
measured as voltage loss over external FET. Allow specifying FET's on
resistance so current monitoring limits can be converted to voltages.

Signed-off-by: Matti Vaittinen 
---
 .../bindings/regulator/rohm,bd9576-regulator.yaml   | 6 ++
 1 file changed, 6 insertions(+)
v4:
  - Fixed the description indentiation

diff --git 
a/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml 
b/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml
index b6515a0cee62..7cb74cc8c5d9 100644
--- a/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml
+++ b/Documentation/devicetree/bindings/regulator/rohm,bd9576-regulator.yaml
@@ -27,6 +27,12 @@ patternProperties:
   Properties for single regulator.
 $ref: "regulator.yaml#"
 
+properties:
+  rohm,ocw-fet-ron-micro-ohms:
+description: |
+  External FET's ON-resistance. Required if VoutS1 OCP/OCW is
+  to be set.
+
 required:
   - regulator-name
 
-- 
2.25.4


-- 
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 =] 


[PATCH v4 4/7] regulator: add property parsing and callbacks to set protection limits

2021-04-06 Thread Matti Vaittinen
Add DT property parsing code and setting callback for regulator over/under
voltage, over-current and temperature error limits.

Signed-off-by: Matti Vaittinen 
---
No changes since RFC-v3

 drivers/regulator/core.c  | 122 +-
 drivers/regulator/of_regulator.c  |  58 ++
 drivers/regulator/qcom-labibb-regulator.c |  10 +-
 drivers/regulator/qcom_spmi-regulator.c   |   6 +-
 drivers/regulator/stpmic1_regulator.c |  20 +++-
 include/linux/regulator/driver.h  |  41 +++-
 include/linux/regulator/machine.h |  26 +
 7 files changed, 274 insertions(+), 9 deletions(-)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index fabc83288e1b..5a3b932dc8a5 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1312,6 +1312,52 @@ static int machine_constraints_current(struct 
regulator_dev *rdev,
 
 static int _regulator_do_enable(struct regulator_dev *rdev);
 
+static int notif_set_limit(struct regulator_dev *rdev,
+  int (*set)(struct regulator_dev *, int, int, bool),
+  int limit, int severity)
+{
+   bool enable;
+
+   if (limit == REGULATOR_NOTIF_LIMIT_DISABLE) {
+   enable = false;
+   limit = 0;
+   } else {
+   enable = true;
+   }
+
+   if (limit == REGULATOR_NOTIF_LIMIT_ENABLE)
+   limit = 0;
+
+   return set(rdev, limit, severity, enable);
+}
+
+static int handle_notify_limits(struct regulator_dev *rdev,
+   int (*set)(struct regulator_dev *, int, int, bool),
+   struct notification_limit *limits)
+{
+   int ret = 0;
+
+   if (!set)
+   return -EOPNOTSUPP;
+
+   if (limits->prot)
+   ret = notif_set_limit(rdev, set, limits->prot,
+ REGULATOR_SEVERITY_PROT);
+   if (ret)
+   return ret;
+
+   if (limits->err)
+   ret = notif_set_limit(rdev, set, limits->err,
+ REGULATOR_SEVERITY_ERR);
+   if (ret)
+   return ret;
+
+   if (limits->warn)
+   ret = notif_set_limit(rdev, set, limits->warn,
+ REGULATOR_SEVERITY_WARN);
+
+   return ret;
+}
 /**
  * set_machine_constraints - sets regulator constraints
  * @rdev: regulator source
@@ -1397,9 +1443,27 @@ static int set_machine_constraints(struct regulator_dev 
*rdev)
}
}
 
+   /*
+* Existing logic does not warn if over_current_protection is given as
+* a constraint but driver does not support that. I think we should
+* warn about this type of issues as it is possible someone changes
+* PMIC on board to another type - and the another PMIC's driver does
+* not support setting protection. Board composer may happily believe
+* the DT limits are respected - especially if the new PMIC HW also
+* supports protection but the driver does not. I won't change the logic
+* without hearing more experienced opinion on this though.
+*
+* If warning is seen as a good idea then we can merge handling the
+* over-curret protection and detection and get rid of this special
+* handling.
+*/
if (rdev->constraints->over_current_protection
&& ops->set_over_current_protection) {
-   ret = ops->set_over_current_protection(rdev);
+   int lim = rdev->constraints->over_curr_limits.prot;
+
+   ret = ops->set_over_current_protection(rdev, lim,
+  REGULATOR_SEVERITY_PROT,
+  true);
if (ret < 0) {
rdev_err(rdev, "failed to set over current protection: 
%pe\n",
 ERR_PTR(ret));
@@ -1407,6 +1471,62 @@ static int set_machine_constraints(struct regulator_dev 
*rdev)
}
}
 
+   if (rdev->constraints->over_current_detection)
+   ret = handle_notify_limits(rdev,
+  ops->set_over_current_protection,
+  
>constraints->over_curr_limits);
+   if (ret) {
+   if (ret != -EOPNOTSUPP) {
+   rdev_err(rdev, "failed to set over current limits: 
%pe\n",
+ERR_PTR(ret));
+   return ret;
+   }
+   rdev_warn(rdev,
+ "IC does not support requested over-current 
limits\n");
+   }
+
+   if (rdev->constraints->over_voltage_detection)
+   ret = handle_notify_limits(rdev,
+  ops->se

[PATCH v4 3/7] regulator: IRQ based event/error notification helpers

2021-04-06 Thread Matti Vaittinen
Provide helper function for IC's implementing regulator notifications
when an IRQ fires. The helper also works for IRQs which can not be acked.
Helper can be set to disable the IRQ at handler and then re-enabling it
on delayed work later. The helper also adds regulator_get_error_flags()
errors in cache for the duration of IRQ disabling.

Signed-off-by: Matti Vaittinen 
---
Changes since v3:
 - Comment block styling
 - Added prints to point the potential HW failure before BUG()
 - Corrected typo from kerneldoc
 - added missing newlines

 drivers/regulator/Makefile   |   2 +-
 drivers/regulator/core.c |  24 +-
 drivers/regulator/irq_helpers.c  | 432 +++
 include/linux/regulator/driver.h | 135 ++
 4 files changed, 589 insertions(+), 4 deletions(-)
 create mode 100644 drivers/regulator/irq_helpers.c

diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 44d2f8bf4b74..e25f1c2d6c9b 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -4,7 +4,7 @@
 #
 
 
-obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o devres.o
+obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o devres.o 
irq_helpers.o
 obj-$(CONFIG_OF) += of_regulator.o
 obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
 obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 16114aea099a..fabc83288e1b 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -4388,20 +4388,37 @@ unsigned int regulator_get_mode(struct regulator 
*regulator)
 }
 EXPORT_SYMBOL_GPL(regulator_get_mode);
 
+static int rdev_get_cached_err_flags(struct regulator_dev *rdev)
+{
+   int ret = 0;
+
+   if (rdev->use_cached_err) {
+   spin_lock(>err_lock);
+   ret = rdev->cached_err;
+   spin_unlock(>err_lock);
+   }
+   return ret;
+}
+
 static int _regulator_get_error_flags(struct regulator_dev *rdev,
unsigned int *flags)
 {
-   int ret;
+   int ret, tmpret;
 
regulator_lock(rdev);
 
+   ret = rdev_get_cached_err_flags(rdev);
+
/* sanity check */
-   if (!rdev->desc->ops->get_error_flags) {
+   if (rdev->desc->ops->get_error_flags) {
+   tmpret = rdev->desc->ops->get_error_flags(rdev, flags);
+   if (tmpret > 0)
+   ret |= tmpret;
+   } else if (!rdev->use_cached_err) {
ret = -EINVAL;
goto out;
}
 
-   ret = rdev->desc->ops->get_error_flags(rdev, flags);
 out:
regulator_unlock(rdev);
return ret;
@@ -5236,6 +5253,7 @@ regulator_register(const struct regulator_desc 
*regulator_desc,
goto rinse;
}
device_initialize(>dev);
+   spin_lock_init(>err_lock);
 
/*
 * Duplicate the config so the driver could override it after
diff --git a/drivers/regulator/irq_helpers.c b/drivers/regulator/irq_helpers.c
new file mode 100644
index ..cc0c23c23b5f
--- /dev/null
+++ b/drivers/regulator/irq_helpers.c
@@ -0,0 +1,432 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2021 ROHM Semiconductors
+// regulator IRQ based event notification helpers
+//
+// Logic has been partially adapted from qcom-labibb driver.
+//
+// Author: Matti Vaittinen 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+struct regulator_irq {
+   struct regulator_irq_data rdata;
+   struct regulator_irq_desc desc;
+   int irq;
+   int retry_cnt;
+   struct delayed_work isr_work;
+};
+
+/*
+ * Should only be called from threaded handler to prevent potential deadlock
+ */
+static void rdev_flag_err(struct regulator_dev *rdev, int err)
+{
+   spin_lock(>err_lock);
+   rdev->cached_err |= err;
+   spin_unlock(>err_lock);
+}
+
+static void rdev_clear_err(struct regulator_dev *rdev, int err)
+{
+   spin_lock(>err_lock);
+   rdev->cached_err &= ~err;
+   spin_unlock(>err_lock);
+}
+
+static void die_loudly(const char *msg)
+{
+   pr_emerg(msg);
+   BUG();
+}
+
+static void regulator_notifier_isr_work(struct work_struct *work)
+{
+   struct regulator_irq *h;
+   struct regulator_irq_desc *d;
+   struct regulator_irq_data *rid;
+   int ret = 0;
+   int tmo, i;
+   int num_rdevs;
+
+   h = container_of(work, struct regulator_irq,
+   isr_work.work);
+   d = >desc;
+   rid = >rdata;
+   num_rdevs = rid->num_states;
+
+reread:
+   if (d->fatal_cnt && h->retry_cnt > d->fatal_cnt) {
+   if (d->die)
+   ret = d->die(rid);
+   else
+   die_loudly("Regulator HW failure? - no IC recovery\n");
+

[PATCH v4 2/7] regulator: add warning flags

2021-04-06 Thread Matti Vaittinen
Add 'warning' level events and error flags to regulator core.
Current regulator core notifications are used to inform consumers
about errors where HW is misbehaving in such way it is assumed to
be broken/unrecoverable.

There are PMICs which are designed for system(s) that may have use
for regulator indications sent before HW is damaged so that some
board/consumer specific recovery-event can be performed while
continuing most of the normal operations.

Add new WARNING level events and notifications to be used for
that purpose.

Signed-off-by: Matti Vaittinen 
---
No changes since RFC-v2

 include/linux/regulator/consumer.h | 14 ++
 1 file changed, 14 insertions(+)

diff --git a/include/linux/regulator/consumer.h 
b/include/linux/regulator/consumer.h
index 20e84a84fb77..f72ca73631be 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -119,6 +119,16 @@ struct regulator_dev;
 #define REGULATOR_EVENT_PRE_DISABLE0x400
 #define REGULATOR_EVENT_ABORT_DISABLE  0x800
 #define REGULATOR_EVENT_ENABLE 0x1000
+/*
+ * Following notifications should be emitted only if detected condition
+ * is such that the HW is likely to still be working but consumers should
+ * take a recovery action to prevent problems esacalating into errors.
+ */
+#define REGULATOR_EVENT_UNDER_VOLTAGE_WARN 0x2000
+#define REGULATOR_EVENT_OVER_CURRENT_WARN  0x4000
+#define REGULATOR_EVENT_OVER_VOLTAGE_WARN  0x8000
+#define REGULATOR_EVENT_OVER_TEMP_WARN 0x1
+#define REGULATOR_EVENT_WARN_MASK  0x1E000
 
 /*
  * Regulator errors that can be queried using regulator_get_error_flags
@@ -138,6 +148,10 @@ struct regulator_dev;
 #define REGULATOR_ERROR_FAIL   BIT(4)
 #define REGULATOR_ERROR_OVER_TEMP  BIT(5)
 
+#define REGULATOR_ERROR_UNDER_VOLTAGE_WARN BIT(6)
+#define REGULATOR_ERROR_OVER_CURRENT_WARN  BIT(7)
+#define REGULATOR_ERROR_OVER_VOLTAGE_WARN  BIT(8)
+#define REGULATOR_ERROR_OVER_TEMP_WARN BIT(9)
 
 /**
  * struct pre_voltage_change_data - Data sent with PRE_VOLTAGE_CHANGE event
-- 
2.25.4


-- 
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 =] 


[PATCH v4 1/7] dt_bindings: Add protection limit properties

2021-04-06 Thread Matti Vaittinen
Support specifying protection/error/warning limits for regulator
over current, over temperature and over/under voltage.

Most of the PMICs support only "protection" feature but few
setups do also support error/warning level indications.

On many ICs most of the protection limits can't actually be set.
But for example the ampere limit for over-current protection on ROHM
BD9576 can be configured - or feature can be completely disabled.

Provide limit setting for all protections/errors for the sake of
the completeness and do that using own properties for all so that
not all users would need to set all levels when only one or few are
supported.

Signed-off-by: Matti Vaittinen 
Reviewed-by: Rob Herring 
---
No changes since RFC-v2

 .../bindings/regulator/regulator.yaml | 82 +++
 1 file changed, 82 insertions(+)

diff --git a/Documentation/devicetree/bindings/regulator/regulator.yaml 
b/Documentation/devicetree/bindings/regulator/regulator.yaml
index 6d0bc9cd4040..a6ae9ecae5cc 100644
--- a/Documentation/devicetree/bindings/regulator/regulator.yaml
+++ b/Documentation/devicetree/bindings/regulator/regulator.yaml
@@ -117,6 +117,88 @@ properties:
 description: Enable over current protection.
 type: boolean
 
+  regulator-oc-protection-microamp:
+description: Set over current protection limit. This is a limit where
+  hardware performs emergency shutdown. Zero can be passed to disable
+  protection and value '1' indicates that protection should be enabled but
+  limit setting can be omitted.
+
+  regulator-oc-error-microamp:
+description: Set over current error limit. This is a limit where part of
+  the hardware propably is malfunctional and damage prevention is 
requested.
+  Zero can be passed to disable error detection and value '1' indicates
+  that detection should be enabled but limit setting can be omitted.
+
+  regulator-oc-warn-microamp:
+description: Set over current warning limit. This is a limit where hardware
+  is assumed still to be functional but approaching limit where it gets
+  damaged. Recovery actions should be initiated. Zero can be passed to
+  disable detection and value '1' indicates that detection should
+  be enabled but limit setting can be omitted.
+
+  regulator-ov-protection-microvolt:
+description: Set over voltage protection limit. This is a limit where
+  hardware performs emergency shutdown. Zero can be passed to disable
+  protection and value '1' indicates that protection should be enabled but
+  limit setting can be omitted. Limit is given as microvolt offset from
+  voltage set to regulator.
+
+  regulator-ov-error-microvolt:
+description: Set over voltage error limit. This is a limit where part of
+  the hardware propably is malfunctional and damage prevention is requested
+  Zero can be passed to disable error detection and value '1' indicates
+  that detection should be enabled but limit setting can be omitted. Limit
+  is given as microvolt offset from voltage set to regulator.
+
+  regulator-ov-warn-microvolt:
+description: Set over voltage warning limit. This is a limit where hardware
+  is assumed still to be functional but approaching limit where it gets
+  damaged. Recovery actions should be initiated. Zero can be passed to
+  disable detection and value '1' indicates that detection should
+  be enabled but limit setting can be omitted. Limit is given as microvolt
+  offset from voltage set to regulator.
+
+  regulator-uv-protection-microvolt:
+description: Set over under voltage protection limit. This is a limit where
+  hardware performs emergency shutdown. Zero can be passed to disable
+  protection and value '1' indicates that protection should be enabled but
+  limit setting can be omitted. Limit is given as microvolt offset from
+  voltage set to regulator.
+
+  regulator-uv-error-microvolt:
+description: Set under voltage error limit. This is a limit where part of
+  the hardware propably is malfunctional and damage prevention is requested
+  Zero can be passed to disable error detection and value '1' indicates
+  that detection should be enabled but limit setting can be omitted. Limit
+  is given as microvolt offset from voltage set to regulator.
+
+  regulator-uv-warn-microvolt:
+description: Set over under voltage warning limit. This is a limit where
+  hardware is assumed still to be functional but approaching limit where
+  it gets damaged. Recovery actions should be initiated. Zero can be passed
+  to disable detection and value '1' indicates that detection should
+  be enabled but limit setting can be omitted. Limit is given as microvolt
+  offset from voltage set to regulator.
+
+  regulator-temp-protection-kelvin:
+description: Set over temperature protection limit. This is a limit where
+  hardware performs emergency shut

[PATCH v4 0/7] Extend regulator notification support

2021-04-06 Thread Matti Vaittinen
Extend regulator notification support

This series extends the regulator notification and error flag support. Initial
discussion on the topic can be found here:
https://lore.kernel.org/lkml/6046836e22b8252983f08d5621c35ececb97820d.ca...@fi.rohmeurope.com/

This series is built on top of the BD9576MUF support patch series v9
which is currently in MFD tree at immutable branch ib-mfd-watchdog-5.13
https://lore.kernel.org/lkml/cover.1615219345.git.matti.vaitti...@fi.rohmeurope.com/
(The series should apply without those patches but there is compile time
dependency to definitions brought in at the last patch of the BD9576
series. This should be Ok though as there is a Kconfig dependency in
BD9576 regulator driver)

In a nutshell - the series adds:

1. WARNING level events/error flags. (Patch 2)
  Current regulator 'ERROR' event notifications for over/under
  voltage, over current and over temperature are used to indicate
  condition where monitored entity is so badly "off" that it actually
  indicates a hardware error which can not be recovered. The most
  typical hanling for that is believed to be a (graceful)
  system-shutdown. Here we add set of 'WARNING' level flags to allow
  sending notifications to consumers before things are 'that badly off'
  so that consumer drivers can implement recovery-actions.
2. Device-tree properties for specifying limit values. (Patches 1, 4)
  Add limits for above mentioned 'ERROR' and 'WARNING' levels (which
  send notifications to consumers) and also for a 'PROTECTION' level
  (which will be used to immediately shut-down the regulator(s) W/O
  informing consumer drivers. Typically implemented by hardware).
  Property parsing is implemented in regulator core which then calls
  callback operations for limit setting from the IC drivers. A
  warning is emitted if protection is requested by device tree but the
  underlying IC does not support configuring requested protection.
3. Helpers which can be registered by IC. (Patch 3)
  Target is to avoid implementing IRQ handling and IRQ storm protection
  in each IC driver. (Many of the ICs implementin these IRQs do not allow
  masking or acking the IRQ but keep the IRQ asserted for the whole
  duration of problem keeping the processor in IRQ handling loop).

The helper was attempted to be done so it could be used to implement
roughly same logic as is used in qcom-labibb regulator. This means
amongst other things a safety shut-down if IC registers are not readable.
Using these shut-down retry counters are optional. The idea is that the
helper could be also used by simpler ICs which do not provide status
register(s) which can be used to check if error is still active.

ICs which do not have such status register can simply omit the 'renable'
callback (and retry-counts etc) - and helper assumes the situation is Ok
and re-enables IRQ after given time period. If problem persists the
handler is ran again and another notification is sent - but at least the
delay allows processor to avoid IRQ loop.

Patch 6 takes this notification support in use at BD9576MUF.
Patch 7 is related to MFD change which is not really related to the RFC
here. It was added to this series in order to avoid potential conflicts.

Changelog v4:
   - rebased on v5.12-rc6
   - dropped RFC
   - fix external FET DT-binding.
   - improve prints for cases when expecting HW failure.
   - styling and typos
Changelog v3:
  Regulator core:
   - Fix dangling pointer access at regulator_irq_helper()
  stpmic1_regulator:
   - fix function prototype (compile error)
  bd9576-regulator:
   - Update over current limits to what was given in new data-sheet
 (REV00K)
   - Allow over-current monitoring without external FET. Set limits to
 values given in data-sheet (REV00K).

Changelog v2:
  Generic:
  - rebase on v5.12-rc2 + BD9576 series
  - Split devm variant of delayed wq to own series
  Regulator framework:
  - Provide non devm variant of IRQ notification helpers
  - shorten dt-property names as suggested by Rob
  - unconditionally call map_event in IRQ handling and require it to be
populated
  BD9576 regulators:
  - change the FET resistance property to micro-ohms
  - fix voltage computation in OC limit setting

--

Matti Vaittinen (7):
  dt_bindings: Add protection limit properties
  regulator: add warning flags
  regulator: IRQ based event/error notification helpers
  regulator: add property parsing and callbacks to set protection limits
  dt-bindings: regulator: bd9576 add FET ON-resistance for OCW
  regulator: bd9576: Support error reporting
  regulator: bd9576: Fix the driver name in id table

 .../bindings/regulator/regulator.yaml |   82 ++
 .../regulator/rohm,bd9576-regulator.yaml  |6 +
 drivers/regulator/Makefile|2 +-
 drivers/regulator/bd9576-regulator.c  | 1060 +++--
 drivers/regulator/core.c  |  146 ++-
 drivers/regulator/irq_helpers.c   |  431 +++
 drivers

[PATCH v6 16/16] MAINTAINERS: Add ROHM BD71815AGW

2021-04-05 Thread Matti Vaittinen
Add maintainer entries for ROHM BD71815AGW drivers.
New regulator and GPIO drivers were introduced for these PMICs.

Signed-off-by: Matti Vaittinen 
---
Changes since v3:
 - No changes
 MAINTAINERS | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index c80ad735b384..4176880a4eee 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15446,18 +15446,21 @@ F:
Documentation/devicetree/bindings/mfd/rohm,bd70528-pmic.txt
 F: Documentation/devicetree/bindings/regulator/rohm,bd70528-regulator.txt
 F: drivers/clk/clk-bd718x7.c
 F: drivers/gpio/gpio-bd70528.c
+F: drivers/gpio/gpio-bd71815.c
 F: drivers/gpio/gpio-bd71828.c
 F: drivers/mfd/rohm-bd70528.c
 F: drivers/mfd/rohm-bd71828.c
 F: drivers/mfd/rohm-bd718x7.c
 F: drivers/power/supply/bd70528-charger.c
 F: drivers/regulator/bd70528-regulator.c
+F: drivers/regulator/bd71815-regulator.c
 F: drivers/regulator/bd71828-regulator.c
 F: drivers/regulator/bd718x7-regulator.c
 F: drivers/regulator/rohm-regulator.c
 F: drivers/rtc/rtc-bd70528.c
 F: drivers/watchdog/bd70528_wdt.c
 F: include/linux/mfd/rohm-bd70528.h
+F: include/linux/mfd/rohm-bd71815.h
 F: include/linux/mfd/rohm-bd71828.h
 F: include/linux/mfd/rohm-bd718x7.h
 F: include/linux/mfd/rohm-generic.h
-- 
2.25.4


-- 
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 =] 


[PATCH v6 15/16] rtc: bd70528: Support RTC on ROHM BD71815

2021-04-05 Thread Matti Vaittinen
BD71815 contains similar RTC block as BD71828. Only the address offsets
seem different. Support also BD71815 RTC using rtc-bd70528.

Signed-off-by: Matti Vaittinen 
Acked-by: Alexandre Belloni 
---
Changes since v3:
 - No changes
 drivers/rtc/Kconfig   |  6 +++---
 drivers/rtc/rtc-bd70528.c | 45 ---
 2 files changed, 40 insertions(+), 11 deletions(-)

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index ce723dc54aa4..622af1314ece 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -501,11 +501,11 @@ config RTC_DRV_M41T80_WDT
  watchdog timer in the ST M41T60 and M41T80 RTC chips series.
 
 config RTC_DRV_BD70528
-   tristate "ROHM BD70528 PMIC RTC"
-   depends on MFD_ROHM_BD70528 && (BD70528_WATCHDOG || !BD70528_WATCHDOG)
+   tristate "ROHM BD70528, BD71815 and BD71828 PMIC RTC"
+   depends on MFD_ROHM_BD71828 || MFD_ROHM_BD70528 && (BD70528_WATCHDOG || 
!BD70528_WATCHDOG)
help
  If you say Y here you will get support for the RTC
- block on ROHM BD70528 and BD71828 Power Management IC.
+ block on ROHM BD70528, BD71815 and BD71828 Power Management IC.
 
  This driver can also be built as a module. If so, the module
  will be called rtc-bd70528.
diff --git a/drivers/rtc/rtc-bd70528.c b/drivers/rtc/rtc-bd70528.c
index fb4476bb5ab6..6454afca02a6 100644
--- a/drivers/rtc/rtc-bd70528.c
+++ b/drivers/rtc/rtc-bd70528.c
@@ -6,6 +6,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -13,6 +14,12 @@
 #include 
 #include 
 
+/*
+ * On BD71828 and BD71815 the ALM0 MASK is 14 bytes after the ALM0
+ * block start
+ */
+#define BD718XX_ALM_EN_OFFSET 14
+
 /*
  * We read regs RTC_SEC => RTC_YEAR
  * this struct is ordered according to chip registers.
@@ -55,6 +62,7 @@ struct bd70528_rtc {
struct regmap *regmap;
struct device *dev;
u8 reg_time_start;
+   u8 bd718xx_alm_block_start;
bool has_rtc_timers;
 };
 
@@ -236,8 +244,8 @@ static int bd71828_set_alarm(struct device *dev, struct 
rtc_wkalrm *a)
struct bd71828_rtc_alm alm;
struct bd70528_rtc *r = dev_get_drvdata(dev);
 
-   ret = regmap_bulk_read(r->regmap, BD71828_REG_RTC_ALM_START,
-  , sizeof(alm));
+   ret = regmap_bulk_read(r->regmap, r->bd718xx_alm_block_start, ,
+  sizeof(alm));
if (ret) {
dev_err(dev, "Failed to read alarm regs\n");
return ret;
@@ -250,8 +258,8 @@ static int bd71828_set_alarm(struct device *dev, struct 
rtc_wkalrm *a)
else
alm.alm_mask |= BD70528_MASK_ALM_EN;
 
-   ret = regmap_bulk_write(r->regmap, BD71828_REG_RTC_ALM_START,
-   , sizeof(alm));
+   ret = regmap_bulk_write(r->regmap, r->bd718xx_alm_block_start, ,
+   sizeof(alm));
if (ret)
dev_err(dev, "Failed to set alarm time\n");
 
@@ -311,8 +319,8 @@ static int bd71828_read_alarm(struct device *dev, struct 
rtc_wkalrm *a)
struct bd71828_rtc_alm alm;
struct bd70528_rtc *r = dev_get_drvdata(dev);
 
-   ret = regmap_bulk_read(r->regmap, BD71828_REG_RTC_ALM_START,
-  , sizeof(alm));
+   ret = regmap_bulk_read(r->regmap, r->bd718xx_alm_block_start, ,
+  sizeof(alm));
if (ret) {
dev_err(dev, "Failed to read alarm regs\n");
return ret;
@@ -453,8 +461,9 @@ static int bd71828_alm_enable(struct device *dev, unsigned 
int enabled)
if (!enabled)
enableval = 0;
 
-   ret = regmap_update_bits(r->regmap, BD71828_REG_RTC_ALM0_MASK,
-BD70528_MASK_ALM_EN, enableval);
+   ret = regmap_update_bits(r->regmap, r->bd718xx_alm_block_start +
+BD718XX_ALM_EN_OFFSET, BD70528_MASK_ALM_EN,
+enableval);
if (ret)
dev_err(dev, "Failed to change alarm state\n");
 
@@ -524,9 +533,28 @@ static int bd70528_probe(struct platform_device *pdev)
enable_main_irq = true;
rtc_ops = _rtc_ops;
break;
+   case ROHM_CHIP_TYPE_BD71815:
+   irq_name = "bd71815-rtc-alm-0";
+   bd_rtc->reg_time_start = BD71815_REG_RTC_START;
+
+   /*
+* See also BD718XX_ALM_EN_OFFSET:
+* This works for BD71828 and BD71815 as they have same offset
+* between ALM0 start and ALM0_MASK. If new ICs are to be
+* added this requires proper check as ALM0_MASK is not located
+* at the end of ALM0 block - but after all ALM blocks so if
+* amount of ALMs differ the offset to enable/

[PATCH v6 14/16] clk: bd718x7: Add support for clk gate on ROHM BD71815 PMIC

2021-04-05 Thread Matti Vaittinen
ROHM BD71815 also provide clk signal for RTC. Add control
for gating this clock.

Signed-off-by: Matti Vaittinen 
Reviewed-by: Stephen Boyd 
---
Changes since v3:
 - No changes
 drivers/clk/clk-bd718x7.c | 9 -
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/clk-bd718x7.c b/drivers/clk/clk-bd718x7.c
index 17d90e09f1c0..d9e70e506d18 100644
--- a/drivers/clk/clk-bd718x7.c
+++ b/drivers/clk/clk-bd718x7.c
@@ -13,6 +13,8 @@
 #include 
 
 /* clk control registers */
+/* BD71815 */
+#define BD71815_REG_OUT32K 0x1d
 /* BD70528 */
 #define BD70528_REG_OUT32K 0x2c
 /* BD71828 */
@@ -118,6 +120,10 @@ static int bd71837_clk_probe(struct platform_device *pdev)
c->reg = BD70528_REG_OUT32K;
c->mask = CLK_OUT_EN_MASK;
break;
+   case ROHM_CHIP_TYPE_BD71815:
+   c->reg = BD71815_REG_OUT32K;
+   c->mask = CLK_OUT_EN_MASK;
+   break;
default:
dev_err(>dev, "Unknown clk chip\n");
return -EINVAL;
@@ -146,6 +152,7 @@ static const struct platform_device_id bd718x7_clk_id[] = {
{ "bd71847-clk", ROHM_CHIP_TYPE_BD71847 },
{ "bd70528-clk", ROHM_CHIP_TYPE_BD70528 },
{ "bd71828-clk", ROHM_CHIP_TYPE_BD71828 },
+   { "bd71815-clk", ROHM_CHIP_TYPE_BD71815 },
{ },
 };
 MODULE_DEVICE_TABLE(platform, bd718x7_clk_id);
@@ -161,6 +168,6 @@ static struct platform_driver bd71837_clk = {
 module_platform_driver(bd71837_clk);
 
 MODULE_AUTHOR("Matti Vaittinen ");
-MODULE_DESCRIPTION("BD71837/BD71847/BD70528 chip clk driver");
+MODULE_DESCRIPTION("BD718(15/18/28/37/47/50) and BD70528 chip clk driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:bd718xx-clk");
-- 
2.25.4


-- 
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 =] 


[PATCH v6 13/16] regulator: Support ROHM BD71815 regulators

2021-04-05 Thread Matti Vaittinen
Support voltage control for regulators on ROHM BD71815 PMIC.

ROHM BD71815 contains 5 bucks, 7 LDOs and a boost (intended for LED).
Bucks 1 and 2 support HW state based voltage level and enable states. Other
regulators support HW state based enable states. All bucks and LDOs 1-5
allow voltage changes for RUN state and LDO4 can be enabled/disabled via
GPIO.

LDO3 does support changing between two predetermined voltages by using
a GPIO but this functionality is not included in this commit.

This work is derived from driver originally written by Tony Luo
 - although not much of original work is left.

Signed-off-by: Matti Vaittinen 
Acked-by: Mark Brown 
---
Changes since v4:
  - unify whole comment block to use c++ comments as was suggested by Mark
  - drop inclusion of machine.h
  - squash in the patch which made BD71815 to use generic ramp-delay as
generic ramp-delay support was added to the regulator tree.
 drivers/regulator/Kconfig |  11 +
 drivers/regulator/Makefile|   1 +
 drivers/regulator/bd71815-regulator.c | 652 ++
 3 files changed, 664 insertions(+)
 create mode 100644 drivers/regulator/bd71815-regulator.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 77c43134bc9e..6437348ce862 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -204,6 +204,17 @@ config REGULATOR_BD70528
  This driver can also be built as a module. If so, the module
  will be called bd70528-regulator.
 
+config REGULATOR_BD71815
+   tristate "ROHM BD71815 Power Regulator"
+   depends on MFD_ROHM_BD71828
+   help
+ This driver supports voltage regulators on ROHM BD71815 PMIC.
+ This will enable support for the software controllable buck
+ and LDO regulators and a current regulator for LEDs.
+
+ This driver can also be built as a module. If so, the module
+ will be called bd71815-regulator.
+
 config REGULATOR_BD71828
tristate "ROHM BD71828 Power Regulator"
depends on MFD_ROHM_BD71828
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 44d2f8bf4b74..c6f84a332fdd 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_REGULATOR_ATC260X) += atc260x-regulator.o
 obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o
 obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o
 obj-$(CONFIG_REGULATOR_BD70528) += bd70528-regulator.o
+obj-$(CONFIG_REGULATOR_BD71815)+= bd71815-regulator.o
 obj-$(CONFIG_REGULATOR_BD71828) += bd71828-regulator.o
 obj-$(CONFIG_REGULATOR_BD718XX) += bd718x7-regulator.o
 obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o
diff --git a/drivers/regulator/bd71815-regulator.c 
b/drivers/regulator/bd71815-regulator.c
new file mode 100644
index ..a4e8d5e36b40
--- /dev/null
+++ b/drivers/regulator/bd71815-regulator.c
@@ -0,0 +1,652 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright 2014 Embest Technology Co. Ltd. Inc.
+// bd71815-regulator.c ROHM BD71815 regulator driver
+//
+// Author: Tony Luo 
+//
+// Partially rewritten at 2021 by
+// Matti Vaittinen 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+struct bd71815_regulator {
+   struct regulator_desc desc;
+   const struct rohm_dvs_config *dvs;
+};
+
+struct bd71815_pmic {
+   struct bd71815_regulator descs[BD71815_REGULATOR_CNT];
+   struct regmap *regmap;
+   struct device *dev;
+   struct gpio_descs *gps;
+   struct regulator_dev *rdev[BD71815_REGULATOR_CNT];
+};
+
+static const int bd7181x_wled_currents[] = {
+   10, 20, 30, 50, 70, 100, 200, 300, 500, 700, 1000, 2000, 3000, 4000,
+   5000, 6000, 7000, 8000, 9000, 1, 11000, 12000, 13000, 14000, 15000,
+   16000, 17000, 18000, 19000, 2, 21000, 22000, 23000, 24000, 25000,
+};
+
+static const struct rohm_dvs_config buck1_dvs = {
+   .level_map  = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+ ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+   .run_reg= BD71815_REG_BUCK1_VOLT_H,
+   .run_mask   = BD71815_VOLT_MASK,
+   .run_on_mask= BD71815_BUCK_RUN_ON,
+   .snvs_on_mask   = BD71815_BUCK_SNVS_ON,
+   .suspend_reg= BD71815_REG_BUCK1_VOLT_L,
+   .suspend_mask   = BD71815_VOLT_MASK,
+   .suspend_on_mask= BD71815_BUCK_SUSP_ON,
+   .lpsr_reg   = BD71815_REG_BUCK1_VOLT_L,
+   .lpsr_mask  = BD71815_VOLT_MASK,
+   .lpsr_on_mask   = BD71815_BUCK_LPSR_ON,
+};
+
+static const struct rohm_dvs_config buck2_dvs = {
+   .level_map  = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+ ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LP

[PATCH v6 12/16] regulator: bd718x7, bd71828: Use ramp-delay helper

2021-04-05 Thread Matti Vaittinen
Use generic regamp ramp-delay helper function instead of implementing own.

Signed-off-by: Matti Vaittinen 
Acked-by: Mark Brown 
---
No changes since v4
 drivers/regulator/bd71828-regulator.c | 51 ---
 drivers/regulator/bd718x7-regulator.c | 60 ---
 2 files changed, 45 insertions(+), 66 deletions(-)

diff --git a/drivers/regulator/bd71828-regulator.c 
b/drivers/regulator/bd71828-regulator.c
index 6b12e963ed8f..a4f09a5a30ca 100644
--- a/drivers/regulator/bd71828-regulator.c
+++ b/drivers/regulator/bd71828-regulator.c
@@ -90,38 +90,7 @@ static const struct linear_range bd71828_ldo_volts[] = {
REGULATOR_LINEAR_RANGE(330, 0x32, 0x3f, 0),
 };
 
-static int bd71828_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
-{
-   unsigned int val;
-
-   switch (ramp_delay) {
-   case 1 ... 2500:
-   val = 0;
-   break;
-   case 2501 ... 5000:
-   val = 1;
-   break;
-   case 5001 ... 1:
-   val = 2;
-   break;
-   case 10001 ... 2:
-   val = 3;
-   break;
-   default:
-   val = 3;
-   dev_err(>dev,
-   "ramp_delay: %d not supported, setting 20mV/uS",
-ramp_delay);
-   }
-
-   /*
-* On BD71828 the ramp delay level control reg is at offset +2 to
-* enable reg
-*/
-   return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg + 2,
- BD71828_MASK_RAMP_DELAY,
- val << (ffs(BD71828_MASK_RAMP_DELAY) - 1));
-}
+static const unsigned int bd71828_ramp_delay[] = { 2500, 5000, 1, 2 };
 
 static int buck_set_hw_dvs_levels(struct device_node *np,
  const struct regulator_desc *desc,
@@ -185,7 +154,7 @@ static const struct regulator_ops bd71828_dvs_buck_ops = {
.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,
-   .set_ramp_delay = bd71828_set_ramp_delay,
+   .set_ramp_delay = regulator_set_ramp_delay_regmap,
 };
 
 static const struct regulator_ops bd71828_ldo_ops = {
@@ -219,6 +188,10 @@ static const struct bd71828_regulator_data bd71828_rdata[] 
= {
.enable_mask = BD71828_MASK_RUN_EN,
.vsel_reg = BD71828_REG_BUCK1_VOLT,
.vsel_mask = BD71828_MASK_BUCK1267_VOLT,
+   .ramp_delay_table = bd71828_ramp_delay,
+   .n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
+   .ramp_reg = BD71828_REG_BUCK1_MODE,
+   .ramp_mask = BD71828_MASK_RAMP_DELAY,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
@@ -261,6 +234,10 @@ static const struct bd71828_regulator_data bd71828_rdata[] 
= {
.enable_mask = BD71828_MASK_RUN_EN,
.vsel_reg = BD71828_REG_BUCK2_VOLT,
.vsel_mask = BD71828_MASK_BUCK1267_VOLT,
+   .ramp_delay_table = bd71828_ramp_delay,
+   .n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
+   .ramp_reg = BD71828_REG_BUCK2_MODE,
+   .ramp_mask = BD71828_MASK_RAMP_DELAY,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
@@ -421,6 +398,10 @@ static const struct bd71828_regulator_data bd71828_rdata[] 
= {
.enable_mask = BD71828_MASK_RUN_EN,
.vsel_reg = BD71828_REG_BUCK6_VOLT,
.vsel_mask = BD71828_MASK_BUCK1267_VOLT,
+   .ramp_delay_table = bd71828_ramp_delay,
+   .n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
+   .ramp_reg = BD71828_REG_BUCK6_MODE,
+   .ramp_mask = BD71828_MASK_RAMP_DELAY,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
@@ -458,6 +439,10 @@ static const struct bd71828_regulator_data bd71828_rdata[] 
= {
.enable_mask = BD71828_MASK_RUN_EN,
.vsel_reg = BD71828_REG_BUCK7_VOLT,
.vsel_mask = BD71828_MASK_BUCK1267_VOLT,
+   .ramp_delay_table = bd71828_ramp_delay,
+   .n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
+   .ramp_reg = BD71828_REG_BUCK7_MODE,
+   .ramp_mask = BD71828_MASK_RAMP_DELAY,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
diff --git

[PATCH v6 11/16] regulator: rohm-regulator: Support SNVS HW state.

2021-04-05 Thread Matti Vaittinen
The ROHM BD71815 supports setting voltage levels/regulator status
for HW-states "RUN", "SUSPEND", "LPSR" and "SNVS". Add DT parsing
helper also for SNVS state.

Signed-off-by: Matti Vaittinen 
Acked-for-MFD-by: Lee Jones 
Acked-by: Mark Brown 
---
Changes since v3:
 - No changes
 drivers/regulator/rohm-regulator.c | 6 ++
 include/linux/mfd/rohm-generic.h   | 6 +-
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/regulator/rohm-regulator.c 
b/drivers/regulator/rohm-regulator.c
index 63aabb8c7786..6e0d9c08ec1c 100644
--- a/drivers/regulator/rohm-regulator.c
+++ b/drivers/regulator/rohm-regulator.c
@@ -95,6 +95,12 @@ int rohm_regulator_set_dvs_levels(const struct 
rohm_dvs_config *dvs,
mask = dvs->lpsr_mask;
omask = dvs->lpsr_on_mask;
break;
+   case ROHM_DVS_LEVEL_SNVS:
+   prop = "rohm,dvs-snvs-voltage";
+   reg = dvs->snvs_reg;
+   mask = dvs->snvs_mask;
+   omask = dvs->snvs_on_mask;
+   break;
default:
return -EINVAL;
}
diff --git a/include/linux/mfd/rohm-generic.h b/include/linux/mfd/rohm-generic.h
index 9e2880e06950..a9144284cf6d 100644
--- a/include/linux/mfd/rohm-generic.h
+++ b/include/linux/mfd/rohm-generic.h
@@ -27,7 +27,8 @@ struct rohm_regmap_dev {
 #define ROHM_DVS_LEVEL_IDLEBIT(1)
 #define ROHM_DVS_LEVEL_SUSPEND BIT(2)
 #define ROHM_DVS_LEVEL_LPSRBIT(3)
-#define ROHM_DVS_LEVEL_VALID_AMOUNT4
+#define ROHM_DVS_LEVEL_SNVSBIT(4)
+#define ROHM_DVS_LEVEL_VALID_AMOUNT5
 #define ROHM_DVS_LEVEL_UNKNOWN 0
 
 /**
@@ -66,6 +67,9 @@ struct rohm_dvs_config {
unsigned int lpsr_reg;
unsigned int lpsr_mask;
unsigned int lpsr_on_mask;
+   unsigned int snvs_reg;
+   unsigned int snvs_mask;
+   unsigned int snvs_on_mask;
 };
 
 #if IS_ENABLED(CONFIG_REGULATOR_ROHM)
-- 
2.25.4


-- 
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 =] 


[PATCH v6 10/16] regulator: rohm-regulator: linear voltage support

2021-04-05 Thread Matti Vaittinen
The helper for obtaining HW-state based DVS voltage levels currently only
works for regulators using linear-ranges. Extend support to regulators with
simple linear mappings and add also proper error path if pickable-ranges
regulators call this.

Signed-off-by: Matti Vaittinen 
Acked-by: Mark Brown 
---
Changes since v3:
  - No changes
 drivers/regulator/rohm-regulator.c | 17 +++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/regulator/rohm-regulator.c 
b/drivers/regulator/rohm-regulator.c
index 5c558b153d55..63aabb8c7786 100644
--- a/drivers/regulator/rohm-regulator.c
+++ b/drivers/regulator/rohm-regulator.c
@@ -22,13 +22,26 @@ static int set_dvs_level(const struct regulator_desc *desc,
return ret;
return 0;
}
-
+   /* If voltage is set to 0 => disable */
if (uv == 0) {
if (omask)
return regmap_update_bits(regmap, oreg, omask, 0);
}
+   /* 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;
+   }
for (i = 0; i < desc->n_voltages; i++) {
-   ret = regulator_desc_list_voltage_linear_range(desc, i);
+   /* 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);
if (ret < 0)
continue;
if (ret == uv) {
-- 
2.25.4


-- 
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 =] 


[PATCH v6 09/16] gpio: support ROHM BD71815 GPOs

2021-04-05 Thread Matti Vaittinen
Support GPO(s) found from ROHM BD71815 power management IC. The IC has two
GPO pins but only one is properly documented in the data-sheet. The driver
exposes by default only the documented GPO. The second GPO is connected to
E5 pin and is marked as GND in the data-sheet. Control for this
undocumented pin can be enabled using a special DT property.

This driver is derived from work by Peter Yang 
although not so much of the original is left.

Signed-off-by: Matti Vaittinen 
Acked-by: Bartosz Golaszewski 
Acked-by: Linus Walleij 
---
Changes since v5:
 - more styling fixes
 - corrected commit message spelling
 - dropped error print as was suggested by Andy
 - dropped explicit setting of the .owner in driver struct

 drivers/gpio/Kconfig|  10 ++
 drivers/gpio/Makefile   |   1 +
 drivers/gpio/gpio-bd71815.c | 185 
 3 files changed, 196 insertions(+)
 create mode 100644 drivers/gpio/gpio-bd71815.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index e3607ec4c2e8..d3b3de514f6e 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -1105,6 +1105,16 @@ config GPIO_BD70528
  This driver can also be built as a module. If so, the module
  will be called gpio-bd70528.
 
+config GPIO_BD71815
+   tristate "ROHM BD71815 PMIC GPIO support"
+   depends on MFD_ROHM_BD71828
+   help
+ Support for GPO(s) on ROHM BD71815 PMIC. There are two GPOs
+ available on the ROHM PMIC.
+
+ This driver can also be built as a module. If so, the module
+ will be called gpio-bd71815.
+
 config GPIO_BD71828
tristate "ROHM BD71828 GPIO support"
depends on MFD_ROHM_BD71828
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index c58a90a3c3b1..4c12f31db31f 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_GPIO_ATH79)  += gpio-ath79.o
 obj-$(CONFIG_GPIO_BCM_KONA)+= gpio-bcm-kona.o
 obj-$(CONFIG_GPIO_BCM_XGS_IPROC)   += gpio-xgs-iproc.o
 obj-$(CONFIG_GPIO_BD70528) += gpio-bd70528.o
+obj-$(CONFIG_GPIO_BD71815) += gpio-bd71815.o
 obj-$(CONFIG_GPIO_BD71828) += gpio-bd71828.o
 obj-$(CONFIG_GPIO_BD9571MWV)   += gpio-bd9571mwv.o
 obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
diff --git a/drivers/gpio/gpio-bd71815.c b/drivers/gpio/gpio-bd71815.c
new file mode 100644
index ..d7dcb3395a77
--- /dev/null
+++ b/drivers/gpio/gpio-bd71815.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Support to GPOs on ROHM BD71815
+ * Copyright 2021 ROHM Semiconductors.
+ * Author: Matti Vaittinen 
+ *
+ * Copyright 2014 Embest Technology Co. Ltd. Inc.
+ * Author: yang...@embest-tech.com
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+/* For the BD71815 register definitions */
+#include 
+
+struct bd71815_gpio {
+   /* chip.parent points the MFD which provides DT node and regmap */
+   struct gpio_chip chip;
+   /* dev points to the platform device for devm and prints */
+   struct device *dev;
+   struct regmap *regmap;
+};
+
+static int bd71815gpo_get(struct gpio_chip *chip, unsigned int offset)
+{
+   struct bd71815_gpio *bd71815 = gpiochip_get_data(chip);
+   int ret, val;
+
+   ret = regmap_read(bd71815->regmap, BD71815_REG_GPO, );
+   if (ret)
+   return ret;
+
+   return (val >> offset) & 1;
+}
+
+static void bd71815gpo_set(struct gpio_chip *chip, unsigned int offset,
+  int value)
+{
+   struct bd71815_gpio *bd71815 = gpiochip_get_data(chip);
+   int ret, bit;
+
+   bit = BIT(offset);
+
+   if (value)
+   ret = regmap_set_bits(bd71815->regmap, BD71815_REG_GPO, bit);
+   else
+   ret = regmap_clear_bits(bd71815->regmap, BD71815_REG_GPO, bit);
+
+   if (ret)
+   dev_warn(bd71815->dev, "failed to toggle GPO\n");
+}
+
+static int bd71815_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+  unsigned long config)
+{
+   struct bd71815_gpio *bdgpio = gpiochip_get_data(chip);
+
+   switch (pinconf_to_config_param(config)) {
+   case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+   return regmap_update_bits(bdgpio->regmap,
+ BD71815_REG_GPO,
+ BD71815_GPIO_DRIVE_MASK << offset,
+ BD71815_GPIO_OPEN_DRAIN << offset);
+   case PIN_CONFIG_DRIVE_PUSH_PULL:
+   return regmap_update_bits(bdgpio->regmap,
+ BD71815_REG_GPO,
+ BD71815_GPIO_DRIVE_MASK << offset,
+ BD71815_GPIO_CMOS << offset);
+   default:
+   break;
+ 

[PATCH v6 08/16] mfd: Support for ROHM BD71815 PMIC core

2021-04-05 Thread Matti Vaittinen
Add core support for ROHM BD71815 Power Management IC.

The IC integrates regulators, a battery charger with a coulomb counter,
a real-time clock (RTC), clock gate and general-purpose outputs (GPO).

Signed-off-by: Matti Vaittinen 
Acked-for-MFD-by: Lee Jones 
---
No changes since v4
 drivers/mfd/Kconfig  |  15 +-
 drivers/mfd/rohm-bd71828.c   | 486 +++---
 include/linux/mfd/rohm-bd71815.h | 562 +++
 include/linux/mfd/rohm-bd71828.h |   3 +
 4 files changed, 933 insertions(+), 133 deletions(-)
 create mode 100644 include/linux/mfd/rohm-bd71815.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index b74efa469e90..60d9ae559f0a 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1975,19 +1975,20 @@ config MFD_ROHM_BD70528
  charger.
 
 config MFD_ROHM_BD71828
-   tristate "ROHM BD71828 Power Management IC"
+   tristate "ROHM BD71828 and BD71815 Power Management IC"
depends on I2C=y
depends on OF
select REGMAP_I2C
select REGMAP_IRQ
select MFD_CORE
help
- Select this option to get support for the ROHM BD71828 Power
- Management IC. BD71828GW is a single-chip power management IC for
- battery-powered portable devices. The IC integrates 7 buck
- converters, 7 LDOs, and a 1500 mA single-cell linear charger.
- Also included is a Coulomb counter, a real-time clock (RTC), and
- a 32.768 kHz clock gate.
+ Select this option to get support for the ROHM BD71828 and BD71815
+ Power Management ICs. BD71828GW and BD71815AGW are single-chip power
+ management ICs mainly for battery-powered portable devices.
+ The BD71828 integrates 7 buck converters and 7 LDOs. The BD71815
+ has 5 bucks, 7 LDOs, and a boost for driving LEDs. Both ICs provide
+ also a single-cell linear charger, a Coulomb counter, a real-time
+ clock (RTC), GPIOs and a 32.768 kHz clock gate.
 
 config MFD_STM32_LPTIMER
tristate "Support for STM32 Low-Power Timer"
diff --git a/drivers/mfd/rohm-bd71828.c b/drivers/mfd/rohm-bd71828.c
index 210261d026f2..714d9fcbf07b 100644
--- a/drivers/mfd/rohm-bd71828.c
+++ b/drivers/mfd/rohm-bd71828.c
@@ -2,7 +2,7 @@
 //
 // Copyright (C) 2019 ROHM Semiconductors
 //
-// ROHM BD71828 PMIC driver
+// ROHM BD71828/BD71815 PMIC driver
 
 #include 
 #include 
@@ -11,7 +11,9 @@
 #include 
 #include 
 #include 
+#include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -29,12 +31,84 @@ static struct gpio_keys_platform_data bd71828_powerkey_data 
= {
.name = "bd71828-pwrkey",
 };
 
-static const struct resource rtc_irqs[] = {
+static const struct resource bd71815_rtc_irqs[] = {
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC0, "bd71815-rtc-alm-0"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC1, "bd71815-rtc-alm-1"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC2, "bd71815-rtc-alm-2"),
+};
+
+static const struct resource bd71828_rtc_irqs[] = {
DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC0, "bd71828-rtc-alm-0"),
DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC1, "bd71828-rtc-alm-1"),
DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC2, "bd71828-rtc-alm-2"),
 };
 
+static struct resource bd71815_power_irqs[] = {
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_RMV, "bd71815-dcin-rmv"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_CLPS_OUT, "bd71815-clps-out"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_CLPS_IN, "bd71815-clps-in"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_OVP_RES, "bd71815-dcin-ovp-res"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_OVP_DET, "bd71815-dcin-ovp-det"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_MON_RES, "bd71815-dcin-mon-res"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_MON_DET, "bd71815-dcin-mon-det"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_UV_RES, "bd71815-vsys-uv-res"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_UV_DET, "bd71815-vsys-uv-det"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_LOW_RES, "bd71815-vsys-low-res"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_LOW_DET, "bd71815-vsys-low-det"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_MON_RES, "bd71815-vsys-mon-res"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_MON_RES, "bd71815-vsys-mon-det"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_WDG_TEMP, "bd71815-chg-wdg-temp"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_WDG_TIME, "bd71815-chg-wdg"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_RECHARGE_RES, "bd71815-rechg-res"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_RECHARGE_DET, "bd71815-rechg-det"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_RANGED_TEMP_TRANSITION, 
"bd71815-ranged-temp

[PATCH v6 07/16] mfd: Sort ROHM chip ID list for better readability

2021-04-05 Thread Matti Vaittinen
Sort the ID list so it is easier to see which ICs are present.

Signed-off-by: Matti Vaittinen 
Suggested-by: Lee Jones 
---
No changes since v4

 include/linux/mfd/rohm-generic.h | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/include/linux/mfd/rohm-generic.h b/include/linux/mfd/rohm-generic.h
index e107b4769101..9e2880e06950 100644
--- a/include/linux/mfd/rohm-generic.h
+++ b/include/linux/mfd/rohm-generic.h
@@ -8,13 +8,13 @@
 #include 
 
 enum rohm_chip_type {
-   ROHM_CHIP_TYPE_BD71837 = 0,
-   ROHM_CHIP_TYPE_BD71847,
+   ROHM_CHIP_TYPE_BD9571,
+   ROHM_CHIP_TYPE_BD9574,
ROHM_CHIP_TYPE_BD70528,
ROHM_CHIP_TYPE_BD71815,
ROHM_CHIP_TYPE_BD71828,
-   ROHM_CHIP_TYPE_BD9571,
-   ROHM_CHIP_TYPE_BD9574,
+   ROHM_CHIP_TYPE_BD71837,
+   ROHM_CHIP_TYPE_BD71847,
ROHM_CHIP_TYPE_AMOUNT
 };
 
-- 
2.25.4


-- 
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 =] 


[PATCH v6 06/16] mfd: Add ROHM BD71815 ID

2021-04-05 Thread Matti Vaittinen
Add chip ID for ROHM BD71815 and PMIC so that drivers can identify
this IC.

Signed-off-by: Matti Vaittinen 
Acked-for-MFD-by: Lee Jones 
---
No changes since v4

 include/linux/mfd/rohm-generic.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/linux/mfd/rohm-generic.h b/include/linux/mfd/rohm-generic.h
index 66f673c35303..e107b4769101 100644
--- a/include/linux/mfd/rohm-generic.h
+++ b/include/linux/mfd/rohm-generic.h
@@ -11,6 +11,7 @@ enum rohm_chip_type {
ROHM_CHIP_TYPE_BD71837 = 0,
ROHM_CHIP_TYPE_BD71847,
ROHM_CHIP_TYPE_BD70528,
+   ROHM_CHIP_TYPE_BD71815,
ROHM_CHIP_TYPE_BD71828,
ROHM_CHIP_TYPE_BD9571,
ROHM_CHIP_TYPE_BD9574,
-- 
2.25.4


-- 
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 =] 


[PATCH v6 05/16] dt_bindings: mfd: Add ROHM BD71815 PMIC

2021-04-05 Thread Matti Vaittinen
Document DT bindings for ROHM BD71815.

BD71815 is a single-chip power management IC mainly for battery-powered
portable devices. The IC integrates 5 bucks, 7 LDOs, a boost driver for
LED, a battery charger with a Coulomb counter, a real-time clock, a 32kHz
clock and two general-purpose outputs although only one is documented by
the data-sheet.

Signed-off-by: Matti Vaittinen 
Reviewed-by: Rob Herring 
---
No changes since v3
 .../bindings/mfd/rohm,bd71815-pmic.yaml   | 201 ++
 1 file changed, 201 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml

diff --git a/Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml 
b/Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml
new file mode 100644
index ..fe265bcab50d
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml
@@ -0,0 +1,201 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/rohm,bd71815-pmic.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ROHM BD71815 Power Management Integrated Circuit bindings
+
+maintainers:
+  - Matti Vaittinen 
+
+description: |
+  BD71815AGW is a single-chip power management ICs for battery-powered
+  portable devices. It integrates 5 buck converters, 8 LDOs, a boost driver
+  for LED and a 500 mA single-cell linear charger. Also included is a Coulomb
+  counter, a real-time clock (RTC), and a 32.768 kHz clock gate and two GPOs.
+
+properties:
+  compatible:
+const: rohm,bd71815
+
+  reg:
+description:
+  I2C slave address.
+maxItems: 1
+
+  interrupts:
+maxItems: 1
+
+  gpio-controller: true
+
+  "#gpio-cells":
+const: 2
+description: |
+  The first cell is the pin number and the second cell is used to specify
+  flags. See ../gpio/gpio.txt for more information.
+
+  clocks:
+maxItems: 1
+
+  "#clock-cells":
+const: 0
+
+  clock-output-names:
+const: bd71815-32k-out
+
+  rohm,clkout-open-drain:
+description: clk32kout mode. Set to 1 for "open-drain" or 0 for "cmos".
+$ref: "/schemas/types.yaml#/definitions/uint32"
+minimum: 0
+maximum: 1
+
+  rohm,charger-sense-resistor-ohms:
+minimum: 1000
+maximum: 5000
+description: |
+  BD71827 and BD71828 have SAR ADC for measuring charging currents.
+  External sense resistor (RSENSE in data sheet) should be used. If
+  something other but 30MOhm resistor is used the resistance value
+  should be given here in Ohms.
+default: 3000
+
+  regulators:
+$ref: ../regulator/rohm,bd71815-regulator.yaml
+description:
+  List of child nodes that specify the regulators.
+
+  gpio-reserved-ranges:
+description: |
+  Usage of BD71828 GPIO pins can be changed via OTP. This property can be
+  used to mark the pins which should not be configured for GPIO. Please see
+  the ../gpio/gpio.txt for more information.
+
+  rohm,enable-hidden-gpo:
+description: |
+  The BD71815 has undocumented GPO at pin E5. Pin is marked as GND at the
+  data-sheet as it's location in the middle of GND pins makes it hard to
+  use on PCB. If your board has managed to use this pin you can enable the
+  second GPO by defining this property. Dont enable this if you are unsure
+  about how the E5 pin is connected on your board.
+type: boolean
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - "#clock-cells"
+  - regulators
+  - gpio-controller
+  - "#gpio-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+#include 
+#include 
+i2c {
+#address-cells = <1>;
+#size-cells = <0>;
+pmic: pmic@4b {
+compatible = "rohm,bd71815";
+reg = <0x4b>;
+
+interrupt-parent = <>;
+interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
+
+clocks = < 0>;
+#clock-cells = <0>;
+clock-output-names = "bd71815-32k-out";
+
+gpio-controller;
+#gpio-cells = <2>;
+
+rohm,charger-sense-resistor-ohms = <1000>;
+
+regulators {
+buck1: buck1 {
+regulator-name = "buck1";
+regulator-min-microvolt = <80>;
+regulator-max-microvolt = <200>;
+regulator-always-on;
+regulator-ramp-delay = <1250>;
+rohm,dvs-run-voltage = <115>;
+rohm,dvs-suspend-voltage = <95>;
+};
+buck2: buck2 {
+regulator-name = "buck2";
+regulator-min-microvolt = <80>;
+regulator-max-microvolt

[PATCH v6 04/16] dt_bindings: regulator: Add ROHM BD71815 PMIC regulators

2021-04-05 Thread Matti Vaittinen
Add binding documentation for regulators on ROHM BD71815 PMIC.
5 bucks, 7 LDOs and a boost for LED.

Signed-off-by: Matti Vaittinen 
Reviewed-by: Rob Herring 
---
No Changes since v3
 .../regulator/rohm,bd71815-regulator.yaml | 116 ++
 1 file changed, 116 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/regulator/rohm,bd71815-regulator.yaml

diff --git 
a/Documentation/devicetree/bindings/regulator/rohm,bd71815-regulator.yaml 
b/Documentation/devicetree/bindings/regulator/rohm,bd71815-regulator.yaml
new file mode 100644
index ..7d0adb74a396
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/rohm,bd71815-regulator.yaml
@@ -0,0 +1,116 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/rohm,bd71815-regulator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ROHM BD71815 Power Management Integrated Circuit regulators
+
+maintainers:
+  - Matti Vaittinen 
+
+description: |
+  This module is part of the ROHM BD718215 MFD device. For more details
+  see Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml.
+
+  The regulator controller is represented as a sub-node of the PMIC node
+  on the device tree.
+
+  The valid names for BD71815 regulator nodes are
+  buck1, buck2, buck3, buck4, buck5,
+  ldo1, ldo2, ldo3, ldo4, ldo5,
+  ldodvref, ldolpsr, wled
+
+properties:
+  wled:
+type: object
+description:
+  properties for wled regulator
+$ref: regulator.yaml#
+
+properties:
+  regulator-name:
+const: wled
+
+patternProperties:
+  "^((ldo|buck)[1-5]|ldolpsr|ldodvref)$":
+type: object
+description:
+  Properties for single LDO/BUCK regulator.
+$ref: regulator.yaml#
+
+properties:
+  regulator-name:
+pattern: "^((ldo|buck)[1-5]|ldolpsr|ldodvref)$"
+description:
+  should be "ldo1", ..., "ldo5", "buck1", ..., "buck5" and "ldolpsr"
+  for ldolpsr regulator, "ldodvref" for ldodvref reglator.
+
+  rohm,vsel-gpios:
+description:
+  GPIO used to control ldo4 state (when ldo4 is controlled by GPIO).
+
+  rohm,dvs-run-voltage:
+description:
+  PMIC "RUN" state voltage in uV when PMIC HW states are used. See
+  comments below for bucks/LDOs which support this. 0 means
+  regulator should be disabled at RUN state.
+$ref: "/schemas/types.yaml#/definitions/uint32"
+minimum: 0
+maximum: 330
+
+  rohm,dvs-snvs-voltage:
+description:
+  Whether to keep regulator enabled at "SNVS" state or not.
+  0 means regulator should be disabled at SNVS state, non zero voltage
+  keeps regulator enabled. BD71815 does not change voltage level
+  when PMIC transitions to SNVS.SNVS voltage depends on the previous
+  state (from which the PMIC transitioned to SNVS).
+$ref: "/schemas/types.yaml#/definitions/uint32"
+minimum: 0
+maximum: 330
+
+  rohm,dvs-suspend-voltage:
+description:
+  PMIC "SUSPEND" state voltage in uV when PMIC HW states are used. See
+  comments below for bucks/LDOs which support this. 0 means
+  regulator should be disabled at SUSPEND state.
+$ref: "/schemas/types.yaml#/definitions/uint32"
+minimum: 0
+maximum: 330
+
+  rohm,dvs-lpsr-voltage:
+description:
+  PMIC "LPSR" state voltage in uV when PMIC HW states are used. See
+  comments below for bucks/LDOs which support this. 0 means
+  regulator should be disabled at LPSR state.
+$ref: "/schemas/types.yaml#/definitions/uint32"
+minimum: 0
+maximum: 330
+
+# Bucks 1 and 2 support giving separate voltages for operational states
+# (RUN /CLEAN according to data-sheet) and non operational states
+# (LPSR/SUSPEND). The voltage is automatically changed when HW
+# state changes. Omitting these properties from bucks 1 and 2 leave
+# buck voltages to not be toggled by HW state. Enable status may still
+# be toggled by state changes depending on HW default settings.
+#
+# Bucks 3-5 and ldos 1-5 support setting the RUN state voltage here.
+# Given RUN voltage is used at all states if regulator is enabled at
+# given state.
+# Values given for other states are regarded as enable/disable at
+# given state (see below).
+#
+# All regulators except WLED support specifying enable/disable status
+# for each of the HW states (RUN/SNVS/SUSPEND/LPSR). HW defaults can
+# be overridden by setting voltage to 0 (regulator disabled at given
+# state) or non-zero (regulator en

[PATCH v6 03/16] dt_bindings: bd71828: Add clock output mode

2021-04-05 Thread Matti Vaittinen
The BD71828 allows configuring the clk32kout pin mode to CMOS or
open-drain. Add device-tree property for specifying the preferred mode.

Signed-off-by: Matti Vaittinen 
Reviewed-by: Rob Herring 
---
No changes since v3
 .../devicetree/bindings/mfd/rohm,bd71828-pmic.yaml  | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml 
b/Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml
index 3a6a1a26e2b3..8380166d176c 100644
--- a/Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml
+++ b/Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml
@@ -44,6 +44,12 @@ properties:
   clock-output-names:
 const: bd71828-32k-out
 
+  rohm,clkout-open-drain:
+description: clk32kout mode. Set to 1 for "open-drain" or 0 for "cmos".
+$ref: "/schemas/types.yaml#/definitions/uint32"
+minimum: 0
+maximum: 1
+
   rohm,charger-sense-resistor-ohms:
 minimum: 1000
 maximum: 5000
-- 
2.25.4


-- 
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 =] 


[PATCH v6 01/16] rtc: bd70528: Do not require parent data

2021-04-05 Thread Matti Vaittinen
The ROHM BD71828 and BD71815 RTC drivers only need the regmap
pointer from parent. Regmap can be obtained via dev_get_regmap()
so do not require parent to populate driver data for that.

BD70528 on the other hand requires parent data to access the
watchdog so leave the parent data for BD70528 here for now.

Signed-off-by: Matti Vaittinen 
Acked-by: Alexandre Belloni 
---
No changes since v3

 drivers/rtc/rtc-bd70528.c | 67 ++-
 1 file changed, 31 insertions(+), 36 deletions(-)

diff --git a/drivers/rtc/rtc-bd70528.c b/drivers/rtc/rtc-bd70528.c
index 17cb67f5bf6e..fb4476bb5ab6 100644
--- a/drivers/rtc/rtc-bd70528.c
+++ b/drivers/rtc/rtc-bd70528.c
@@ -52,6 +52,7 @@ struct bd70528_rtc_alm {
 
 struct bd70528_rtc {
struct rohm_regmap_dev *parent;
+   struct regmap *regmap;
struct device *dev;
u8 reg_time_start;
bool has_rtc_timers;
@@ -234,9 +235,8 @@ static int bd71828_set_alarm(struct device *dev, struct 
rtc_wkalrm *a)
int ret;
struct bd71828_rtc_alm alm;
struct bd70528_rtc *r = dev_get_drvdata(dev);
-   struct rohm_regmap_dev *parent = r->parent;
 
-   ret = regmap_bulk_read(parent->regmap, BD71828_REG_RTC_ALM_START,
+   ret = regmap_bulk_read(r->regmap, BD71828_REG_RTC_ALM_START,
   , sizeof(alm));
if (ret) {
dev_err(dev, "Failed to read alarm regs\n");
@@ -250,7 +250,7 @@ static int bd71828_set_alarm(struct device *dev, struct 
rtc_wkalrm *a)
else
alm.alm_mask |= BD70528_MASK_ALM_EN;
 
-   ret = regmap_bulk_write(parent->regmap, BD71828_REG_RTC_ALM_START,
+   ret = regmap_bulk_write(r->regmap, BD71828_REG_RTC_ALM_START,
, sizeof(alm));
if (ret)
dev_err(dev, "Failed to set alarm time\n");
@@ -265,17 +265,16 @@ static int bd70528_set_alarm(struct device *dev, struct 
rtc_wkalrm *a)
struct bd70528_rtc_alm alm;
int ret;
struct bd70528_rtc *r = dev_get_drvdata(dev);
-   struct rohm_regmap_dev *parent = r->parent;
 
-   ret = regmap_bulk_read(parent->regmap, BD70528_REG_RTC_WAKE_START,
-  , sizeof(wake));
+   ret = regmap_bulk_read(r->regmap, BD70528_REG_RTC_WAKE_START, ,
+  sizeof(wake));
if (ret) {
dev_err(dev, "Failed to read wake regs\n");
return ret;
}
 
-   ret = regmap_bulk_read(parent->regmap, BD70528_REG_RTC_ALM_START,
-  , sizeof(alm));
+   ret = regmap_bulk_read(r->regmap, BD70528_REG_RTC_ALM_START, ,
+  sizeof(alm));
if (ret) {
dev_err(dev, "Failed to read alarm regs\n");
return ret;
@@ -292,15 +291,14 @@ static int bd70528_set_alarm(struct device *dev, struct 
rtc_wkalrm *a)
wake.ctrl &= ~BD70528_MASK_WAKE_EN;
}
 
-   ret = regmap_bulk_write(parent->regmap,
-   BD70528_REG_RTC_WAKE_START, ,
+   ret = regmap_bulk_write(r->regmap, BD70528_REG_RTC_WAKE_START, ,
sizeof(wake));
if (ret) {
dev_err(dev, "Failed to set wake time\n");
return ret;
}
-   ret = regmap_bulk_write(parent->regmap, BD70528_REG_RTC_ALM_START,
-   , sizeof(alm));
+   ret = regmap_bulk_write(r->regmap, BD70528_REG_RTC_ALM_START, ,
+   sizeof(alm));
if (ret)
dev_err(dev, "Failed to set alarm time\n");
 
@@ -312,9 +310,8 @@ static int bd71828_read_alarm(struct device *dev, struct 
rtc_wkalrm *a)
int ret;
struct bd71828_rtc_alm alm;
struct bd70528_rtc *r = dev_get_drvdata(dev);
-   struct rohm_regmap_dev *parent = r->parent;
 
-   ret = regmap_bulk_read(parent->regmap, BD71828_REG_RTC_ALM_START,
+   ret = regmap_bulk_read(r->regmap, BD71828_REG_RTC_ALM_START,
   , sizeof(alm));
if (ret) {
dev_err(dev, "Failed to read alarm regs\n");
@@ -336,10 +333,9 @@ static int bd70528_read_alarm(struct device *dev, struct 
rtc_wkalrm *a)
struct bd70528_rtc_alm alm;
int ret;
struct bd70528_rtc *r = dev_get_drvdata(dev);
-   struct rohm_regmap_dev *parent = r->parent;
 
-   ret = regmap_bulk_read(parent->regmap, BD70528_REG_RTC_ALM_START,
-  , sizeof(alm));
+   ret = regmap_bulk_read(r->regmap, BD70528_REG_RTC_ALM_START, ,
+  sizeof(alm));
if (ret) {
dev_err(dev, "Failed to read alarm regs\n");
return ret;
@@ -360,14 +356,12 @@ static int bd70528_set_time_locked(struct device *dev, 
st

[PATCH v6 02/16] mfd: bd718x7: simplify by cleaning unnecessary device data

2021-04-05 Thread Matti Vaittinen
Most ROHM PMIC sub-devices only use the regmap pointer from
parent device. They can obtain this by dev_get_regamap so in
most cases the MFD device does not need to allocate and populate
the driver data. Simplify drivers by removing this.

The BD70528 still needs the access to watchdog mutex so keep
rohm_regmap_dev in use on BD70528 RTC and WDG drivers for now.

Signed-off-by: Matti Vaittinen 
Acked-for-MFD-by: Lee Jones 
---
No changes since v3

 drivers/mfd/rohm-bd718x7.c   | 43 
 include/linux/mfd/rohm-bd718x7.h | 13 --
 2 files changed, 16 insertions(+), 40 deletions(-)

diff --git a/drivers/mfd/rohm-bd718x7.c b/drivers/mfd/rohm-bd718x7.c
index c32c1b6c98fa..bfd81f78beae 100644
--- a/drivers/mfd/rohm-bd718x7.c
+++ b/drivers/mfd/rohm-bd718x7.c
@@ -91,9 +91,9 @@ static const struct regmap_config bd718xx_regmap_config = {
.cache_type = REGCACHE_RBTREE,
 };
 
-static int bd718xx_init_press_duration(struct bd718xx *bd718xx)
+static int bd718xx_init_press_duration(struct regmap *regmap,
+  struct device *dev)
 {
-   struct device* dev = bd718xx->chip.dev;
u32 short_press_ms, long_press_ms;
u32 short_press_value, long_press_value;
int ret;
@@ -102,8 +102,7 @@ static int bd718xx_init_press_duration(struct bd718xx 
*bd718xx)
   _press_ms);
if (!ret) {
short_press_value = min(15u, (short_press_ms + 250) / 500);
-   ret = regmap_update_bits(bd718xx->chip.regmap,
-BD718XX_REG_PWRONCONFIG0,
+   ret = regmap_update_bits(regmap, BD718XX_REG_PWRONCONFIG0,
 BD718XX_PWRBTN_PRESS_DURATION_MASK,
 short_press_value);
if (ret) {
@@ -116,8 +115,7 @@ static int bd718xx_init_press_duration(struct bd718xx 
*bd718xx)
   _press_ms);
if (!ret) {
long_press_value = min(15u, (long_press_ms + 500) / 1000);
-   ret = regmap_update_bits(bd718xx->chip.regmap,
-BD718XX_REG_PWRONCONFIG1,
+   ret = regmap_update_bits(regmap, BD718XX_REG_PWRONCONFIG1,
 BD718XX_PWRBTN_PRESS_DURATION_MASK,
 long_press_value);
if (ret) {
@@ -132,7 +130,8 @@ static int bd718xx_init_press_duration(struct bd718xx 
*bd718xx)
 static int bd718xx_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
 {
-   struct bd718xx *bd718xx;
+   struct regmap *regmap;
+   struct regmap_irq_chip_data *irq_data;
int ret;
unsigned int chip_type;
struct mfd_cell *mfd;
@@ -142,13 +141,6 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c,
dev_err(>dev, "No IRQ configured\n");
return -EINVAL;
}
-
-   bd718xx = devm_kzalloc(>dev, sizeof(struct bd718xx), GFP_KERNEL);
-
-   if (!bd718xx)
-   return -ENOMEM;
-
-   bd718xx->chip_irq = i2c->irq;
chip_type = (unsigned int)(uintptr_t)
of_device_get_match_data(>dev);
switch (chip_type) {
@@ -164,29 +156,26 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c,
dev_err(>dev, "Unknown device type");
return -EINVAL;
}
-   bd718xx->chip.dev = >dev;
-   dev_set_drvdata(>dev, bd718xx);
 
-   bd718xx->chip.regmap = devm_regmap_init_i2c(i2c,
-   _regmap_config);
-   if (IS_ERR(bd718xx->chip.regmap)) {
+   regmap = devm_regmap_init_i2c(i2c, _regmap_config);
+   if (IS_ERR(regmap)) {
dev_err(>dev, "regmap initialization failed\n");
-   return PTR_ERR(bd718xx->chip.regmap);
+   return PTR_ERR(regmap);
}
 
-   ret = devm_regmap_add_irq_chip(>dev, bd718xx->chip.regmap,
-  bd718xx->chip_irq, IRQF_ONESHOT, 0,
-  _irq_chip, >irq_data);
+   ret = devm_regmap_add_irq_chip(>dev, regmap, i2c->irq,
+  IRQF_ONESHOT, 0, _irq_chip,
+  _data);
if (ret) {
dev_err(>dev, "Failed to add irq_chip\n");
return ret;
}
 
-   ret = bd718xx_init_press_duration(bd718xx);
+   ret = bd718xx_init_press_duration(regmap, >dev);
if (ret)
return ret;
 
-   ret = regmap_irq_get_virq(bd718xx->irq_data, BD718XX_INT_PWRBTN_S);
+   ret = regmap_irq_get_virq(irq_data, BD718XX_INT_PWRBTN_S);
 
if (ret < 0) {
dev_err(>dev, "Failed to get t

[PATCH v6 00/16] Support ROHM BD71815 PMIC

2021-04-05 Thread Matti Vaittinen
Patch series introducing support for ROHM BD71815 PMIC

ROHM BD71815 is a power management IC used in some battery powered
systems. It contains regulators, GPO(s), charger + coulomb counter, RTC
and a clock gate.

All regulators can be controlled via I2C. LDO4 can additionally be set to
be enabled/disabled by a GPIO. LDO3 voltage could be selected from two
voltages written into separate VSEL reisters using GPIO but this mode is
not supported by driver. On top of that the PMIC has the typical HW
state machine which is present also on many other ROHM PMICs.

IC contains two GPOs - but one of the GPOs is marked as GND in
data-sheet. Thus the driver by default only exposes one GPO. The second
GPO can be enabled by special DT property.

RTC is almost similar to what is on BD71828. For currently used features
only the register address offset to RTC block differs.

The charger driver is not included in this series. ROHM has a charger
driver with some fuel-gauging logig written in but this is not included
here. I am working on separating the logic from HW specific driver and
supporting both BD71815 and BD71828 chargers in separate patch series.

Changelog v6:
  Rebased on v5.12-rc6
  Regulator:
   - Fixed few minor issues pointer by Mark
   - Dropped the helper patches which were applied to regulator tree.
 Please note, there is compile-time dependency to those helpers so
 regulator helpers should be pulled in from:
 https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git
 tags/regulator-list-ramp-helpers
  GPIO:
   - Corrected change log spelling
   - Fixes some styling issues pointed by Andy.
Changelog v5:
  Regulator:
  - Added regmap helper for regulator ramp-delay and taken it in use
(patches 13, 14, 16 - they can be just dropped if ramp-delay helper is not
a good idea. Patch 15 implements old-fashioned ramp-delay)
  GPIO:
  - styling changes to GPIO (Mostly suggested by Andy)
  - implemented init_valid_mask (but can't count on it yet)
Changelog v4:
  - Sorted ROHM chip ID enum
  - Statcized DVS structures in regulator driver
  - Minor styling for regulator driver
  - rebased on v5.12-rc4
Changelog v3:
  - GPIO clean-up as suggested by Bartosz
  - MFD clean-up as suggested by Lee
  - clk-mode dt-binding handling in MFD driver corrected to reflect new
property values.
  - Dropped already applied patches
  - Rebased on v5.12-rc2
Changelog v2:
  - Rebased on top of v5.11-rc3
  - Added another "preliminary patch" which fixes HW-dvs voltage
handling (patch 1)
  - split regulator patch to two.
  - changed dt-binding patch ordering.
  regulators:
- staticized probe
- removed some unnecessary defines
- updated comments
- split rohm-regulator patch adding SNVS and supporting simple
  linear mapping into two - one adding support for mapping, other
  adding SNVS.
  GPIO:
- removed unnecessary headers
- clarified dev/parent->dev usage
- removed forgotten #define DEBUG
  dt-bindings:
- changed patch order to meet ref-dependencies
- added missing regulator nodes
- changed string property for clk mode to tristated
  MFD:
- header cleanups.
  CLK:
- fixed commit message

--

Matti Vaittinen (16):
  rtc: bd70528: Do not require parent data
  mfd: bd718x7: simplify by cleaning unnecessary device data
  dt_bindings: bd71828: Add clock output mode
  dt_bindings: regulator: Add ROHM BD71815 PMIC regulators
  dt_bindings: mfd: Add ROHM BD71815 PMIC
  mfd: Add ROHM BD71815 ID
  mfd: Sort ROHM chip ID list for better readability
  mfd: Support for ROHM BD71815 PMIC core
  gpio: support ROHM BD71815 GPOs
  regulator: rohm-regulator: linear voltage support
  regulator: rohm-regulator: Support SNVS HW state.
  regulator: bd718x7, bd71828: Use ramp-delay helper
  regulator: Support ROHM BD71815 regulators
  clk: bd718x7: Add support for clk gate on ROHM BD71815 PMIC
  rtc: bd70528: Support RTC on ROHM BD71815
  MAINTAINERS: Add ROHM BD71815AGW

 .../bindings/mfd/rohm,bd71815-pmic.yaml   | 201 ++
 .../bindings/mfd/rohm,bd71828-pmic.yaml   |   6 +
 .../regulator/rohm,bd71815-regulator.yaml | 116 
 MAINTAINERS   |   3 +
 drivers/clk/clk-bd718x7.c |   9 +-
 drivers/gpio/Kconfig  |  10 +
 drivers/gpio/Makefile |   1 +
 drivers/gpio/gpio-bd71815.c   | 185 +
 drivers/mfd/Kconfig   |  15 +-
 drivers/mfd/rohm-bd71828.c| 486 +
 drivers/mfd/rohm-bd718x7.c|  43 +-
 drivers/regulator/Kconfig |  11 +
 drivers/regulator/Makefile|   1 +
 drivers/regulator/bd71815-regulator.c | 652 ++
 drivers/regulator/bd71828-regulator.c |  51 +-
 drivers/regulator/bd718x7-regulator.c |  60 +-
 drivers/regulator/rohm-regulator.c|  23 +-
 driver

Re: [PATCH v5 16/19] regulator: bd71815: use ramp-delay helper

2021-04-04 Thread Matti Vaittinen


On Fri, 2021-04-02 at 20:02 +0100, Mark Brown wrote:
> On Mon, Mar 29, 2021 at 04:00:13PM +0300, Matti Vaittinen wrote:
> > Use generic regamp ramp-delay helper function instead of
> > implementing own.
> 
> This is patching something which was just added in the previous
> patch...
> 
> Acked-by: Mark Brown 

Correct. Reason was that I weren't sure if the idea of adding ramp-
delay helper was accepted. If it was seen as bad idea, then just
dropping this patch would have left the BD71815 with in-driver helper.

Best Regards
Matti Vaittinen



Re: [RFC PATCH v3 3/7] regulator: IRQ based event/error notification helpers

2021-04-04 Thread Matti Vaittinen


On Fri, 2021-04-02 at 18:11 +0100, Mark Brown wrote:
> On Thu, Mar 11, 2021 at 12:22:36PM +0200, Matti Vaittinen wrote:
> > +   if (d->fatal_cnt && h->retry_cnt > d->fatal_cnt) {
> > +   if (d->die)
> > +   ret = d->die(rid);
> > +   else
> > +   BUG();
> > +
> > +   /*
> > +* If the 'last resort' IC recovery failed we will have
> > +* nothing else left to do...
> > +*/
> > +   BUG_ON(ret);
> 
> This isn't good...  we should be trying to provide more system level
> handling of this, if nothing else it's quite possibly not a software
> bug
> here but rather a hardware failure.  An explicit message about what
> happened would be more likely to be understood as a hardware failure,

I do agree. I'll add a print in next version.

> and something which allows handling such as initiating a system
> shutdown
> would be good as well - I'm not sure if there's any existing
> mechanism
> to plumb userspace into, or perhaps some sort of policy configurable
> via
> sysfs.

I like the idea but don't know of such existing mechanism. The input
system power-key event is closest that comes to my mind - but I don't
think that would be quite right. Additionally, I am unsure what level
of user-space functionality can be expected to work? Maybe the severity
of configured notifications should be used to decide whether to do in-
kernel handling or to alert user-space. Anyways, that is something that
requires further pondering - I'd propose improving this later.

Best Regards
Matti Vaittinen



Re: [PATCH 1/2] gpio: sysfs: Obey valid_mask

2021-03-31 Thread Matti Vaittinen


On Wed, 2021-03-31 at 20:29 +0200, Bartosz Golaszewski wrote:
> On Wed, Mar 31, 2021 at 2:25 PM Andy Shevchenko
>  wrote:
> > On Wed, Mar 31, 2021 at 10:58 AM Bartosz Golaszewski
> >  wrote:
> > > On Mon, Mar 29, 2021 at 1:41 PM Matti Vaittinen
> > >  wrote:
> > > > Do not allow exporting GPIOs which are set invalid
> > > > by the driver's valid mask.
> > > > 
> > > > Fixes: 726cb3ba49692bdae6caff457755e7cdb432efa4
> > 
> > I have just noticed that this is invalid format for the Fixes tag
> > (luckily, haha, due to a blank line it's not recognized as a tag!).
> > 
> > Matti, I highly recommend to add in your .gitconfig file an alias:
> > one = show -s --pretty='format:%h (\"%s\")'
> > 
> > Bart, there are real Fixes tag issues from another series. I will
> > comment there as well to let an author know.
> > 
> > --
> 
> Eek, sorry I should have looked more carefully. I'll fix it in my
> tree.

Thanks for fixing this Bartosz.
Andy - well spotted. And the alias you pointed is something I've missed
:)

Sorry for the trouble! I should have used the correct tag format.

Thanks again!

Best Regards
Matti Vaittinen




Re: [PATCH v4 2/2] power: supply: mt6360_charger: add MT6360 charger support

2021-03-30 Thread Matti Vaittinen
t; MT6360_IPREC_SHFT);
> +}
> +
> +static int mt6360_charger_set_ieoc(struct mt6360_chg_info *mci,
> +const union power_supply_propval
> *val)
> +{
> + u8 sel;
> +
> + sel = mt6360_map_reg_sel(val->intval,
> +  MT6360_IEOC_MIN,
> +  MT6360_IEOC_MAX,
> +  MT6360_IEOC_STEP);

linear_ranges?

> + return regmap_update_bits(mci->regmap,
> +   MT6360_PMU_CHG_CTRL9,
> +   MT6360_IEOC_MASK,
> +   sel << MT6360_IEOC_SHFT);
> +}
> +
> +



> +static const struct regulator_ops mt6360_chg_otg_ops = {
> + .list_voltage = regulator_list_voltage_linear,
> + .enable = regulator_enable_regmap,
> + .disable = regulator_disable_regmap,
> + .is_enabled = regulator_is_enabled_regmap,
> + .set_voltage_sel = regulator_set_voltage_sel_regmap,
> + .get_voltage_sel = regulator_get_voltage_sel_regmap,
> +};
> +
> +static const struct regulator_desc mt6360_otg_rdesc = {
> + .of_match = "usb-otg-vbus",
> + .name = "usb-otg-vbus",
> + .ops = _chg_otg_ops,
> + .owner = THIS_MODULE,
> + .type = REGULATOR_VOLTAGE,
> + .min_uV = 4425000,
> + .uV_step = 25000,
> + .n_voltages = 57,
> + .vsel_reg = MT6360_PMU_CHG_CTRL5,
> + .vsel_mask = MT6360_VOBST_MASK,
> + .enable_reg = MT6360_PMU_CHG_CTRL1,
> + .enable_mask = MT6360_OPA_MODE_MASK,
> +};

Any particular reason why these are here and not in a regulator driver?

...

> +static int mt6360_charger_probe(struct platform_device *pdev)
> +{
> + struct mt6360_chg_info *mci;
> + struct power_supply_config charger_cfg = {};
> + struct regulator_config config = { };
> + int ret;
> +
> + mci = devm_kzalloc(>dev, sizeof(*mci), GFP_KERNEL);
> + if (!mci)
> + return -ENOMEM;
> +
> + ret = mt6360_parse_dt(pdev);
> + if (ret)
> + return dev_err_probe(>dev, ret, "Failed to parse
> dt\n");
> +
> + mci->dev = >dev;
> + mci->vinovp = 650;
> + mutex_init(>chgdet_lock);
> + platform_set_drvdata(pdev, mci);
> + INIT_WORK(>chrdet_work, _chrdet_work);
> +
> + mci->regmap = dev_get_regmap(pdev->dev.parent, NULL);
> + if (!mci->regmap)
> + return dev_err_probe(>dev, -ENODEV, "Failed to
> get parent regmap\n");
> +
> + ret = mt6360_apply_dt(pdev);
> + if (ret)
> + return dev_err_probe(>dev, ret, "Failed to apply
> dt\n");
> +
> + memcpy(>psy_desc, _charger_desc, sizeof(mci-
> >psy_desc));
> + mci->psy_desc.name = dev_name(>dev);
> + charger_cfg.drv_data = mci;
> + charger_cfg.of_node = pdev->dev.of_node;
> + mci->psy = devm_power_supply_register(>dev,
> +   >psy_desc,
> _cfg);
> + if (IS_ERR(mci->psy))
> + return dev_err_probe(>dev, PTR_ERR(mci->psy),
> +  "Failed to register power supply
> dev\n");
> +
> + ret = mt6360_chg_init_setting(mci);
> + if (ret)
> + return dev_err_probe(>dev, ret, "Failed to
> initial setting\n");
> +
> + schedule_work(>chrdet_work);

Is this work scheduled anywhere else? If not - why doing this in wq
context? If yes - does this wq need cancellation upon exit?

> +
> + ret = mt6360_chg_irq_register(pdev);
> + if (ret)
> + return dev_err_probe(>dev, ret, "Failed to
> register irqs\n");
> +
> + config.dev = >dev;
> + config.regmap = mci->regmap;
> + mci->otg_rdev = devm_regulator_register(>dev,
> _otg_rdesc,
> + );
> + if (IS_ERR(mci->otg_rdev))
> + return PTR_ERR(mci->otg_rdev);
> +
> + return 0;
> +}
> +

Best Regards
Matti Vaittinen



Re: [PATCH v5 09/19] gpio: support ROHM BD71815 GPOs

2021-03-30 Thread Matti Vaittinen
Hi Andy,

On Tue, 2021-03-30 at 13:11 +0300, Andy Shevchenko wrote:
> On Mon, Mar 29, 2021 at 3:58 PM Matti Vaittinen
>  wrote:
> > Support GPO(s) found from ROHM BD71815 power management IC. The IC
> > has two
> > GPO pins but only one is properly documented in data-sheet. The
> > driver
> 
> in the datasheet
> 
> > exposes by default only the documented GPO. The second GPO is
> > connected to
> > E5 pin and is marked as GND in data-sheet. Control for this
> > undocumented
> 
> in the datasheet
> 
> > pin can be enabled using a special DT property.
> > 
> > This driver is derived from work by Peter Yang <
> > yang...@embest-tech.com>
> > although not so much of original is left.
> 
> of the original
> 
> It seems you ignored my comments about the commit message. :-(

Sorry. I didn't do that by purpose. I forgot to reword commit.
Completely my bad.

> > +struct bd71815_gpio {
> > +   struct gpio_chip chip;
> > +   struct device *dev;
> 
> Wondering why you need this. Is it the same as chip.parent?
> 
> > +   struct regmap *regmap;
> > +};
> 
> ...
> 
> > +   int ret, bit;
> > +
> > +   bit = BIT(offset);
> 
> I prefer
>   int bit = BIT(offset);
>   int ret;
> but I think we already discussed that. OK.

Yes, we did.

> ...
> 
> > +   default:
> > +   break;
> > +   }
> > +   return -ENOTSUPP;
> 
> Here is a waste of line. Why break instead of direct return?

As we discussed last time, I do prefer functions which are supposed to
return a value, do so at the end of function. It's easier to read and
does not cause issues if someone changes switch to if-else or does
other modifications. IMO original is safer, reads better and does not
cause issues even with old compilers.

> ...
> 
> > +/* Template for GPIO chip */
> > +static const struct gpio_chip bd71815gpo_chip = {
> > +   .label  = "bd71815",
> > +   .owner  = THIS_MODULE,
> > +   .get= bd71815gpo_get,
> > +   .get_direction  = bd71815gpo_direction_get,
> > +   .set= bd71815gpo_set,
> > +   .set_config = bd71815_gpio_set_config,
> > +   .can_sleep  = 1,
> 
> Strictly speaking this should be true (boolean type value).

true.

> 
> > +};
> 
> ...
> 
> > +#define BD71815_TWO_GPIOS  0x3UL
> > +#define BD71815_ONE_GPIO   0x1UL
> 
> Are they masks? Can you use BIT() and GENMASK()?

Yes and yes. I personally prefer 0x3 over GENMASK() as for me the value
3 as bitmask is perfectly readable. But I know others may prefer using
GENMASK(). So yes, your comment is valid.

> > +/*
> > + * Sigh. The BD71815 and BD71817 were originally designed to
> > support two GPO
> > + * pins. At some point it was noticed the second GPO pin which is
> > the E5 pin
> > + * located at the center of IC is hard to use on PCB (due to the
> > location). It
> > + * was decided to not promote this second GPO and pin is marked as
> > GND in the
> 
> and the pin
> 
> > + * datasheet. The functionality is still there though! I guess
> > driving a GPO
> > + * connected to the ground is a bad idea. Thus we do not support
> > it by default.
> > + * OTOH - the original driver written by colleagues at Embest did
> > support
> > + * controlling this second GPO. It is thus possible this is used
> > in some of the
> > + * products.
> > + *
> > + * This driver does not by default support configuring this second
> > GPO
> > + * but allows using it by providing the DT property
> > + * "rohm,enable-hidden-gpo".
> > + */
> 

I am sorry. I think I missed this one too.

> ...
> 
> > +   /*
> > +* As writing of this the sysfs interface for GPIO control
> > does not
> > +* respect the valid_mask. Do not trust it but rather set
> > the ngpios
> > +* to 1 if "rohm,enable-hidden-gpo" is not given.
> > +*
> > +* This check can be removed later if the sysfs export is
> > fixed and
> > +* if the fix is backported.
> 
> So, mark this comment with the TODO/FIXME keyword?

I haven't used to use keywords like TODO/FIXME. Now that I think of it
I've seen a few FIXME comments in sources so perhaps I should start
using them where appropriate. I don't think it makes a big difference
here though as I expect to be reworking this in near future (I'll
revise ROHM PMIC GPIO drivers for reg

Re: [PATCH 2/2] gpiolib: Allow drivers to return EOPNOTSUPP from config

2021-03-29 Thread Matti Vaittinen
Morning Folks,

On Mon, 2021-03-29 at 16:30 +0300, Andy Shevchenko wrote:
> On Mon, Mar 29, 2021 at 03:20:07PM +0300, Matti Vaittinen wrote:
> > On Mon, 2021-03-29 at 14:59 +0300, Andy Shevchenko wrote:
> > > On Mon, Mar 29, 2021 at 2:43 PM Matti Vaittinen
> > >  wrote:
> > > > The checkpacth instructs to switch from ENOSUPP to EOPNOTSUPP.
> > > > > WARNING: ENOTSUPP is not a SUSV4 error code, prefer
> > > > > EOPNOTSUPP
> > > > 
> > > > Make the gpiolib allow drivers to return both so driver
> > > > developers
> > > > can avoid one of the checkpatch complaints.
> > > 
> > > Internally we are fine to use the ENOTSUPP.
> > > Checkpatch false positives there.
> > 
> > I agree. OTOH, the checkpatch check makes sense to user-visible
> > stuff.
> > Yet, the checkpatch has hard time guessing what is user-visible -
> > so it
> > probably is easiest to nag about all ENOTSUPP uses as it does now.
> > 
> > > I doubt we need this change. Rather checkpatch should rephrase
> > > this
> > > to
> > > point out that this is only applicable to _user-visible_ error
> > > path.
> > > Cc'ed Joe.
> > 
> > Yes, thanks for pulling Joe in.
> > 
> > Anyways, no matter what the warning says, all false positives are
> > annoying. I don't see why we should stay with ENOTSUPP in gpiolib?
> > (other than the burden of changing it).
> 
> For sake of the changing we are not changing the code.
No. But for the sake of making it better / more consistent :)

Anyway - after giving this second thought (thanks Andy for provoking me
to thinking this further) - I do agree with Andy that this particular
change is bad. More I think of this, less I like the idea of having two
separate return values to indicate the same thing. So we should support
only one which makes my patch terrible.

For the sake of consistency it would be cleaner to use same, single
value, for same error both inside the gpiolib and at user-interface.
That would be EOPNOTSUPP. As I said, having two separate error codes to
indicate same thing is confusing. Now the confusion is at the boundary
of gpiolib and user-land. Please educate me - is there difference in
the meaning of ENOTSUPP and EOPNOTSUPP or are they really indicating
the same thing? If yes, then yes - correct fix would be to use only one
and ditch the other. Whether the amount of work is such it is
practically worth is another topic - but that would be the right thing
to do (tm).

> 
> > But I have no strong opinion on this. All options I see have
> > downsides.
> > 
> > Accepting both ENOTSUPP and EOPNOTSUPP is the easy way to avoid
> > allowing checkpatch warnings - but I admit it isn't stylish.
> 
> I think the error code which is Linux kernel internal is for a
> reason.

If so, then the current checkpatch warning is even more questionable.

> 
> > Converting all ENOTSUPP cases inside gpiolib to EOPNOTSUPP is
> > teodious
> > although end result might be nicer.
> 
> Why? You still missed the justification except satisfying some tool
> that gives
> you false positives. We don't do that. It's the tool that has to be
> fixed /
> amended.
> 
> > Leaving it as is gives annoying false-positives to driver
> > developers.
> > 
> > My personal preference was this patch - others can have other view
> > like
> > Andy does. I'll leave this to community/maintainers to evaluate :)
> 
> This patch misses documentation fixes, for example.

Valid point.

> Also, do you suggest that we have to do the same in entire pin
> control
> subsystem?

After reading/writing this, I am unsure. This is why the discussion is
good :) I don't see why we should have two separate error codes for
same thing - but as you put it:

> I think the error code which is Linux kernel internal is for a
> reason.

not all of us thinks the same. So maybe I just don't get it? :)

Best Regards
Matti Vaittinen




[PATCH v5 19/19] MAINTAINERS: Add ROHM BD71815AGW

2021-03-29 Thread Matti Vaittinen
Add maintainer entries for ROHM BD71815AGW drivers.
New regulator and GPIO drivers were introduced for these PMICs.

Signed-off-by: Matti Vaittinen 
---
Changes since v3:
 - No changes
 MAINTAINERS | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 9e876927c60d..c251af6bfc03 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15452,18 +15452,21 @@ F:
Documentation/devicetree/bindings/mfd/rohm,bd70528-pmic.txt
 F: Documentation/devicetree/bindings/regulator/rohm,bd70528-regulator.txt
 F: drivers/clk/clk-bd718x7.c
 F: drivers/gpio/gpio-bd70528.c
+F: drivers/gpio/gpio-bd71815.c
 F: drivers/gpio/gpio-bd71828.c
 F: drivers/mfd/rohm-bd70528.c
 F: drivers/mfd/rohm-bd71828.c
 F: drivers/mfd/rohm-bd718x7.c
 F: drivers/power/supply/bd70528-charger.c
 F: drivers/regulator/bd70528-regulator.c
+F: drivers/regulator/bd71815-regulator.c
 F: drivers/regulator/bd71828-regulator.c
 F: drivers/regulator/bd718x7-regulator.c
 F: drivers/regulator/rohm-regulator.c
 F: drivers/rtc/rtc-bd70528.c
 F: drivers/watchdog/bd70528_wdt.c
 F: include/linux/mfd/rohm-bd70528.h
+F: include/linux/mfd/rohm-bd71815.h
 F: include/linux/mfd/rohm-bd71828.h
 F: include/linux/mfd/rohm-bd718x7.h
 F: include/linux/mfd/rohm-generic.h
-- 
2.25.4


-- 
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 =] 


[PATCH v5 18/19] rtc: bd70528: Support RTC on ROHM BD71815

2021-03-29 Thread Matti Vaittinen
BD71815 contains similar RTC block as BD71828. Only the address offsets
seem different. Support also BD71815 RTC using rtc-bd70528.

Signed-off-by: Matti Vaittinen 
Acked-by: Alexandre Belloni 
---
Changes since v3:
 - No changes
 drivers/rtc/Kconfig   |  6 +++---
 drivers/rtc/rtc-bd70528.c | 45 ---
 2 files changed, 40 insertions(+), 11 deletions(-)

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index ce723dc54aa4..622af1314ece 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -501,11 +501,11 @@ config RTC_DRV_M41T80_WDT
  watchdog timer in the ST M41T60 and M41T80 RTC chips series.
 
 config RTC_DRV_BD70528
-   tristate "ROHM BD70528 PMIC RTC"
-   depends on MFD_ROHM_BD70528 && (BD70528_WATCHDOG || !BD70528_WATCHDOG)
+   tristate "ROHM BD70528, BD71815 and BD71828 PMIC RTC"
+   depends on MFD_ROHM_BD71828 || MFD_ROHM_BD70528 && (BD70528_WATCHDOG || 
!BD70528_WATCHDOG)
help
  If you say Y here you will get support for the RTC
- block on ROHM BD70528 and BD71828 Power Management IC.
+ block on ROHM BD70528, BD71815 and BD71828 Power Management IC.
 
  This driver can also be built as a module. If so, the module
  will be called rtc-bd70528.
diff --git a/drivers/rtc/rtc-bd70528.c b/drivers/rtc/rtc-bd70528.c
index fb4476bb5ab6..6454afca02a6 100644
--- a/drivers/rtc/rtc-bd70528.c
+++ b/drivers/rtc/rtc-bd70528.c
@@ -6,6 +6,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -13,6 +14,12 @@
 #include 
 #include 
 
+/*
+ * On BD71828 and BD71815 the ALM0 MASK is 14 bytes after the ALM0
+ * block start
+ */
+#define BD718XX_ALM_EN_OFFSET 14
+
 /*
  * We read regs RTC_SEC => RTC_YEAR
  * this struct is ordered according to chip registers.
@@ -55,6 +62,7 @@ struct bd70528_rtc {
struct regmap *regmap;
struct device *dev;
u8 reg_time_start;
+   u8 bd718xx_alm_block_start;
bool has_rtc_timers;
 };
 
@@ -236,8 +244,8 @@ static int bd71828_set_alarm(struct device *dev, struct 
rtc_wkalrm *a)
struct bd71828_rtc_alm alm;
struct bd70528_rtc *r = dev_get_drvdata(dev);
 
-   ret = regmap_bulk_read(r->regmap, BD71828_REG_RTC_ALM_START,
-  , sizeof(alm));
+   ret = regmap_bulk_read(r->regmap, r->bd718xx_alm_block_start, ,
+  sizeof(alm));
if (ret) {
dev_err(dev, "Failed to read alarm regs\n");
return ret;
@@ -250,8 +258,8 @@ static int bd71828_set_alarm(struct device *dev, struct 
rtc_wkalrm *a)
else
alm.alm_mask |= BD70528_MASK_ALM_EN;
 
-   ret = regmap_bulk_write(r->regmap, BD71828_REG_RTC_ALM_START,
-   , sizeof(alm));
+   ret = regmap_bulk_write(r->regmap, r->bd718xx_alm_block_start, ,
+   sizeof(alm));
if (ret)
dev_err(dev, "Failed to set alarm time\n");
 
@@ -311,8 +319,8 @@ static int bd71828_read_alarm(struct device *dev, struct 
rtc_wkalrm *a)
struct bd71828_rtc_alm alm;
struct bd70528_rtc *r = dev_get_drvdata(dev);
 
-   ret = regmap_bulk_read(r->regmap, BD71828_REG_RTC_ALM_START,
-  , sizeof(alm));
+   ret = regmap_bulk_read(r->regmap, r->bd718xx_alm_block_start, ,
+  sizeof(alm));
if (ret) {
dev_err(dev, "Failed to read alarm regs\n");
return ret;
@@ -453,8 +461,9 @@ static int bd71828_alm_enable(struct device *dev, unsigned 
int enabled)
if (!enabled)
enableval = 0;
 
-   ret = regmap_update_bits(r->regmap, BD71828_REG_RTC_ALM0_MASK,
-BD70528_MASK_ALM_EN, enableval);
+   ret = regmap_update_bits(r->regmap, r->bd718xx_alm_block_start +
+BD718XX_ALM_EN_OFFSET, BD70528_MASK_ALM_EN,
+enableval);
if (ret)
dev_err(dev, "Failed to change alarm state\n");
 
@@ -524,9 +533,28 @@ static int bd70528_probe(struct platform_device *pdev)
enable_main_irq = true;
rtc_ops = _rtc_ops;
break;
+   case ROHM_CHIP_TYPE_BD71815:
+   irq_name = "bd71815-rtc-alm-0";
+   bd_rtc->reg_time_start = BD71815_REG_RTC_START;
+
+   /*
+* See also BD718XX_ALM_EN_OFFSET:
+* This works for BD71828 and BD71815 as they have same offset
+* between ALM0 start and ALM0_MASK. If new ICs are to be
+* added this requires proper check as ALM0_MASK is not located
+* at the end of ALM0 block - but after all ALM blocks so if
+* amount of ALMs differ the offset to enable/

[PATCH v5 17/19] clk: bd718x7: Add support for clk gate on ROHM BD71815 PMIC

2021-03-29 Thread Matti Vaittinen
ROHM BD71815 also provide clk signal for RTC. Add control
for gating this clock.

Signed-off-by: Matti Vaittinen 
Reviewed-by: Stephen Boyd 
---
Changes since v3:
 - No changes
 drivers/clk/clk-bd718x7.c | 9 -
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/clk-bd718x7.c b/drivers/clk/clk-bd718x7.c
index 17d90e09f1c0..d9e70e506d18 100644
--- a/drivers/clk/clk-bd718x7.c
+++ b/drivers/clk/clk-bd718x7.c
@@ -13,6 +13,8 @@
 #include 
 
 /* clk control registers */
+/* BD71815 */
+#define BD71815_REG_OUT32K 0x1d
 /* BD70528 */
 #define BD70528_REG_OUT32K 0x2c
 /* BD71828 */
@@ -118,6 +120,10 @@ static int bd71837_clk_probe(struct platform_device *pdev)
c->reg = BD70528_REG_OUT32K;
c->mask = CLK_OUT_EN_MASK;
break;
+   case ROHM_CHIP_TYPE_BD71815:
+   c->reg = BD71815_REG_OUT32K;
+   c->mask = CLK_OUT_EN_MASK;
+   break;
default:
dev_err(>dev, "Unknown clk chip\n");
return -EINVAL;
@@ -146,6 +152,7 @@ static const struct platform_device_id bd718x7_clk_id[] = {
{ "bd71847-clk", ROHM_CHIP_TYPE_BD71847 },
{ "bd70528-clk", ROHM_CHIP_TYPE_BD70528 },
{ "bd71828-clk", ROHM_CHIP_TYPE_BD71828 },
+   { "bd71815-clk", ROHM_CHIP_TYPE_BD71815 },
{ },
 };
 MODULE_DEVICE_TABLE(platform, bd718x7_clk_id);
@@ -161,6 +168,6 @@ static struct platform_driver bd71837_clk = {
 module_platform_driver(bd71837_clk);
 
 MODULE_AUTHOR("Matti Vaittinen ");
-MODULE_DESCRIPTION("BD71837/BD71847/BD70528 chip clk driver");
+MODULE_DESCRIPTION("BD718(15/18/28/37/47/50) and BD70528 chip clk driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:bd718xx-clk");
-- 
2.25.4


-- 
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 =] 


[PATCH v5 16/19] regulator: bd71815: use ramp-delay helper

2021-03-29 Thread Matti Vaittinen
Use generic regamp ramp-delay helper function instead of implementing own.

Signed-off-by: Matti Vaittinen 
---
Changes since v4:
 - new patch
 drivers/regulator/bd71815-regulator.c | 37 +--
 1 file changed, 6 insertions(+), 31 deletions(-)

diff --git a/drivers/regulator/bd71815-regulator.c 
b/drivers/regulator/bd71815-regulator.c
index b1448e34c629..00bab1307c14 100644
--- a/drivers/regulator/bd71815-regulator.c
+++ b/drivers/regulator/bd71815-regulator.c
@@ -264,36 +264,7 @@ static int buck12_set_hw_dvs_levels(struct device_node *np,
  * 10: 2.50mV/usec 10mV 4uS
  * 11: 1.25mV/usec 10mV 8uS
  */
-static int bd7181x_buck12_set_ramp_delay(struct regulator_dev *rdev,
-int ramp_delay)
-{
-   struct bd71815_pmic *pmic = rdev_get_drvdata(rdev);
-   int id = rdev->desc->id;
-   unsigned int ramp_value = BD71815_BUCK_RAMPRATE_10P00MV;
-
-   switch (ramp_delay) {
-   case 1 ... 1250:
-   ramp_value = BD71815_BUCK_RAMPRATE_1P25MV;
-   break;
-   case 1251 ... 2500:
-   ramp_value = BD71815_BUCK_RAMPRATE_2P50MV;
-   break;
-   case 2501 ... 5000:
-   ramp_value = BD71815_BUCK_RAMPRATE_5P00MV;
-   break;
-   case 5001 ... 1:
-   ramp_value = BD71815_BUCK_RAMPRATE_10P00MV;
-   break;
-   default:
-   ramp_value = BD71815_BUCK_RAMPRATE_10P00MV;
-   dev_err(pmic->dev,
-   "%s: ramp_delay: %d not supported, setting 
1mV//us\n",
-   rdev->desc->name, ramp_delay);
-   }
-
-   return regmap_update_bits(pmic->regmap, BD71815_REG_BUCK1_MODE + id*0x1,
-   BD71815_BUCK_RAMPRATE_MASK, ramp_value << 6);
-}
+static const unsigned int bd7181x_ramp_table[] = { 1250, 2500, 5000, 1 };
 
 static int bd7181x_led_set_current_limit(struct regulator_dev *rdev,
int min_uA, int max_uA)
@@ -429,7 +400,7 @@ static const struct regulator_ops 
bd7181x_buck12_regulator_ops = {
.set_voltage_sel = bd7181x_buck12_set_voltage_sel,
.get_voltage_sel = bd7181x_buck12_get_voltage_sel,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
-   .set_ramp_delay = bd7181x_buck12_set_ramp_delay,
+   .set_ramp_delay = regulator_set_ramp_delay_regmap,
 };
 
 static const struct regulator_ops bd7181x_led_regulator_ops = {
@@ -499,6 +470,10 @@ static const struct regulator_ops 
bd7181x_led_regulator_ops = {
.vsel_mask = 0x3f,  \
.enable_reg = (ereg),   \
.enable_mask = 0x04,\
+   .ramp_reg = (ereg), \
+   .ramp_mask = BD71815_BUCK_RAMPRATE_MASK,\
+   .ramp_delay_table = bd7181x_ramp_table, \
+   .n_ramp_values = ARRAY_SIZE(bd7181x_ramp_table),\
.of_parse_cb = buck12_set_hw_dvs_levels,\
},  \
.dvs = (_dvs),      \
-- 
2.25.4


-- 
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 =] 


[PATCH v5 13/19] regulator: Add regmap helper for ramp-delay setting

2021-03-29 Thread Matti Vaittinen
Quite a few regulator ICs do support setting ramp-delay by writing a value
matching the delay to a ramp-delay register.

Provide a simple helper for table-based delay setting.

Signed-off-by: Matti Vaittinen 
---
Changes since v4:
 - new patch
 drivers/regulator/helpers.c  | 65 
 include/linux/regulator/driver.h |  5 +++
 2 files changed, 70 insertions(+)

diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c
index 3e19ecbf7267..0e16e31c968f 100644
--- a/drivers/regulator/helpers.c
+++ b/drivers/regulator/helpers.c
@@ -901,3 +901,68 @@ bool regulator_is_equal(struct regulator *reg1, struct 
regulator *reg2)
return reg1->rdev == reg2->rdev;
 }
 EXPORT_SYMBOL_GPL(regulator_is_equal);
+
+static int find_closest_bigger(unsigned int target, const unsigned int *table,
+  unsigned int num_sel, unsigned int *sel)
+{
+   unsigned int s, tmp, max, maxsel = 0;
+   bool found = false;
+
+   max = table[0];
+
+   for (s = 0; s < num_sel; s++) {
+   if (table[s] > max) {
+   max = table[s];
+   maxsel = s;
+   }
+   if (table[s] >= target) {
+   if (!found || table[s] - target < tmp - target) {
+   tmp = table[s];
+   *sel = s;
+   found = true;
+   if (tmp == target)
+   break;
+   }
+   }
+   }
+
+   if (!found) {
+   *sel = maxsel;
+   return -EINVAL;
+   }
+
+   return 0;
+}
+
+/**
+ * regulator_set_ramp_delay_regmap - set_ramp_delay() helper
+ *
+ * @rdev: regulator to operate on
+ *
+ * Regulators that use regmap for their register I/O can set the ramp_reg
+ * and ramp_mask fields in their descriptor and then use this as their
+ * set_ramp_delay operation, saving some code.
+ */
+int regulator_set_ramp_delay_regmap(struct regulator_dev *rdev, int ramp_delay)
+{
+   int ret;
+   unsigned int sel;
+
+   if (!rdev->desc->n_ramp_values)
+   return -EINVAL;
+
+   ret = find_closest_bigger(ramp_delay, rdev->desc->ramp_delay_table,
+ rdev->desc->n_ramp_values, );
+
+   if (ret) {
+   dev_warn(rdev_get_dev(rdev),
+"Can't set ramp-delay %u, setting %u\n", ramp_delay,
+rdev->desc->ramp_delay_table[sel]);
+   }
+
+   sel <<= ffs(rdev->desc->ramp_mask) - 1;
+
+   return regmap_update_bits(rdev->regmap, rdev->desc->ramp_reg,
+ rdev->desc->ramp_mask, sel);
+}
+EXPORT_SYMBOL_GPL(regulator_set_ramp_delay_regmap);
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 39a540111645..597ed117086f 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -373,6 +373,10 @@ struct regulator_desc {
unsigned int pull_down_reg;
unsigned int pull_down_mask;
unsigned int pull_down_val_on;
+   unsigned int ramp_reg;
+   unsigned int ramp_mask;
+   const unsigned int *ramp_delay_table;
+   unsigned int n_ramp_values;
 
unsigned int enable_time;
 
@@ -535,6 +539,7 @@ int regulator_set_current_limit_regmap(struct regulator_dev 
*rdev,
   int min_uA, int max_uA);
 int regulator_get_current_limit_regmap(struct regulator_dev *rdev);
 void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data);
+int regulator_set_ramp_delay_regmap(struct regulator_dev *rdev, int 
ramp_delay);
 
 /*
  * Helper functions intended to be used by regulator drivers prior registering
-- 
2.25.4


-- 
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 =] 


[PATCH v5 15/19] regulator: Support ROHM BD71815 regulators

2021-03-29 Thread Matti Vaittinen
Support voltage control for regulators on ROHM BD71815 PMIC.

ROHM BD71815 contains 5 bucks, 7 LDOs and a boost (intended for LED).
Bucks 1 and 2 support HW state based voltage level and enable states. Other
regulators support HW state based enable states. All bucks and LDOs 1-5
allow voltage changes for RUN state and LDO4 can be enabled/disabled via
GPIO.

LDO3 does support changing between two predetermined voltages by using
a GPIO but this functionality is not included in this commit.

This work is derived from driver originally written by Tony Luo
 - although not much of original work is left.

Signed-off-by: Matti Vaittinen 
---
No changes since v4

 drivers/regulator/Kconfig |  11 +
 drivers/regulator/Makefile|   1 +
 drivers/regulator/bd71815-regulator.c | 676 ++
 3 files changed, 688 insertions(+)
 create mode 100644 drivers/regulator/bd71815-regulator.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 77c43134bc9e..6437348ce862 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -204,6 +204,17 @@ config REGULATOR_BD70528
  This driver can also be built as a module. If so, the module
  will be called bd70528-regulator.
 
+config REGULATOR_BD71815
+   tristate "ROHM BD71815 Power Regulator"
+   depends on MFD_ROHM_BD71828
+   help
+ This driver supports voltage regulators on ROHM BD71815 PMIC.
+ This will enable support for the software controllable buck
+ and LDO regulators and a current regulator for LEDs.
+
+ This driver can also be built as a module. If so, the module
+ will be called bd71815-regulator.
+
 config REGULATOR_BD71828
tristate "ROHM BD71828 Power Regulator"
depends on MFD_ROHM_BD71828
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 44d2f8bf4b74..c6f84a332fdd 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_REGULATOR_ATC260X) += atc260x-regulator.o
 obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o
 obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o
 obj-$(CONFIG_REGULATOR_BD70528) += bd70528-regulator.o
+obj-$(CONFIG_REGULATOR_BD71815)+= bd71815-regulator.o
 obj-$(CONFIG_REGULATOR_BD71828) += bd71828-regulator.o
 obj-$(CONFIG_REGULATOR_BD718XX) += bd718x7-regulator.o
 obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o
diff --git a/drivers/regulator/bd71815-regulator.c 
b/drivers/regulator/bd71815-regulator.c
new file mode 100644
index ..b1448e34c629
--- /dev/null
+++ b/drivers/regulator/bd71815-regulator.c
@@ -0,0 +1,676 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2014 Embest Technology Co. Ltd. Inc.
+ * bd71815-regulator.c ROHM BD71815 regulator driver
+ *
+ * Author: Tony Luo 
+ *
+ * Partially rewritten at 2021 by
+ * Matti Vaittinen 
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+struct bd71815_regulator {
+   struct regulator_desc desc;
+   const struct rohm_dvs_config *dvs;
+};
+
+struct bd71815_pmic {
+   struct bd71815_regulator descs[BD71815_REGULATOR_CNT];
+   struct regmap *regmap;
+   struct device *dev;
+   struct gpio_descs *gps;
+   struct regulator_dev *rdev[BD71815_REGULATOR_CNT];
+};
+
+static const int bd7181x_wled_currents[] = {
+   10, 20, 30, 50, 70, 100, 200, 300, 500, 700, 1000, 2000, 3000, 4000,
+   5000, 6000, 7000, 8000, 9000, 1, 11000, 12000, 13000, 14000, 15000,
+   16000, 17000, 18000, 19000, 2, 21000, 22000, 23000, 24000, 25000,
+};
+
+static const struct rohm_dvs_config buck1_dvs = {
+   .level_map  = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+ ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+   .run_reg= BD71815_REG_BUCK1_VOLT_H,
+   .run_mask   = BD71815_VOLT_MASK,
+   .run_on_mask= BD71815_BUCK_RUN_ON,
+   .snvs_on_mask   = BD71815_BUCK_SNVS_ON,
+   .suspend_reg= BD71815_REG_BUCK1_VOLT_L,
+   .suspend_mask   = BD71815_VOLT_MASK,
+   .suspend_on_mask= BD71815_BUCK_SUSP_ON,
+   .lpsr_reg   = BD71815_REG_BUCK1_VOLT_L,
+   .lpsr_mask  = BD71815_VOLT_MASK,
+   .lpsr_on_mask   = BD71815_BUCK_LPSR_ON,
+};
+
+static const struct rohm_dvs_config buck2_dvs = {
+   .level_map  = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
+ ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
+   .run_reg= BD71815_REG_BUCK2_VOLT_H,
+   .run_mask   = BD71815_VOLT_MASK,
+   .run_on_mask= BD71815_BUCK_RUN_ON,
+   .snvs_on_mask   = BD71815_BUCK_SNVS_ON,
+   .suspend_reg= BD71

[PATCH v5 14/19] regulator: bd718x7, bd71828: Use ramp-delay helper

2021-03-29 Thread Matti Vaittinen
Use generic regamp ramp-delay helper function instead of implementing own.

Signed-off-by: Matti Vaittinen 
---
Changes since v4:
 - new patch
 drivers/regulator/bd71828-regulator.c | 51 ---
 drivers/regulator/bd718x7-regulator.c | 60 ---
 2 files changed, 45 insertions(+), 66 deletions(-)

diff --git a/drivers/regulator/bd71828-regulator.c 
b/drivers/regulator/bd71828-regulator.c
index 6b12e963ed8f..a4f09a5a30ca 100644
--- a/drivers/regulator/bd71828-regulator.c
+++ b/drivers/regulator/bd71828-regulator.c
@@ -90,38 +90,7 @@ static const struct linear_range bd71828_ldo_volts[] = {
REGULATOR_LINEAR_RANGE(330, 0x32, 0x3f, 0),
 };
 
-static int bd71828_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
-{
-   unsigned int val;
-
-   switch (ramp_delay) {
-   case 1 ... 2500:
-   val = 0;
-   break;
-   case 2501 ... 5000:
-   val = 1;
-   break;
-   case 5001 ... 1:
-   val = 2;
-   break;
-   case 10001 ... 2:
-   val = 3;
-   break;
-   default:
-   val = 3;
-   dev_err(>dev,
-   "ramp_delay: %d not supported, setting 20mV/uS",
-ramp_delay);
-   }
-
-   /*
-* On BD71828 the ramp delay level control reg is at offset +2 to
-* enable reg
-*/
-   return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg + 2,
- BD71828_MASK_RAMP_DELAY,
- val << (ffs(BD71828_MASK_RAMP_DELAY) - 1));
-}
+static const unsigned int bd71828_ramp_delay[] = { 2500, 5000, 1, 2 };
 
 static int buck_set_hw_dvs_levels(struct device_node *np,
  const struct regulator_desc *desc,
@@ -185,7 +154,7 @@ static const struct regulator_ops bd71828_dvs_buck_ops = {
.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,
-   .set_ramp_delay = bd71828_set_ramp_delay,
+   .set_ramp_delay = regulator_set_ramp_delay_regmap,
 };
 
 static const struct regulator_ops bd71828_ldo_ops = {
@@ -219,6 +188,10 @@ static const struct bd71828_regulator_data bd71828_rdata[] 
= {
.enable_mask = BD71828_MASK_RUN_EN,
.vsel_reg = BD71828_REG_BUCK1_VOLT,
.vsel_mask = BD71828_MASK_BUCK1267_VOLT,
+   .ramp_delay_table = bd71828_ramp_delay,
+   .n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
+   .ramp_reg = BD71828_REG_BUCK1_MODE,
+   .ramp_mask = BD71828_MASK_RAMP_DELAY,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
@@ -261,6 +234,10 @@ static const struct bd71828_regulator_data bd71828_rdata[] 
= {
.enable_mask = BD71828_MASK_RUN_EN,
.vsel_reg = BD71828_REG_BUCK2_VOLT,
.vsel_mask = BD71828_MASK_BUCK1267_VOLT,
+   .ramp_delay_table = bd71828_ramp_delay,
+   .n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
+   .ramp_reg = BD71828_REG_BUCK2_MODE,
+   .ramp_mask = BD71828_MASK_RAMP_DELAY,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
@@ -421,6 +398,10 @@ static const struct bd71828_regulator_data bd71828_rdata[] 
= {
.enable_mask = BD71828_MASK_RUN_EN,
.vsel_reg = BD71828_REG_BUCK6_VOLT,
.vsel_mask = BD71828_MASK_BUCK1267_VOLT,
+   .ramp_delay_table = bd71828_ramp_delay,
+   .n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
+   .ramp_reg = BD71828_REG_BUCK6_MODE,
+   .ramp_mask = BD71828_MASK_RAMP_DELAY,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
@@ -458,6 +439,10 @@ static const struct bd71828_regulator_data bd71828_rdata[] 
= {
.enable_mask = BD71828_MASK_RUN_EN,
.vsel_reg = BD71828_REG_BUCK7_VOLT,
.vsel_mask = BD71828_MASK_BUCK1267_VOLT,
+   .ramp_delay_table = bd71828_ramp_delay,
+   .n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
+   .ramp_reg = BD71828_REG_BUCK7_MODE,
+   .ramp_mask = BD71828_MASK_RAMP_DELAY,
.owner = THIS_MODULE,
.of_parse_cb = buck_set_hw_dvs_levels,
},
diff --git a/drivers/regu

[PATCH v5 12/19] regulator: rohm-regulator: Support SNVS HW state.

2021-03-29 Thread Matti Vaittinen
The ROHM BD71815 supports setting voltage levels/regulator status
for HW-states "RUN", "SUSPEND", "LPSR" and "SNVS". Add DT parsing
helper also for SNVS state.

Signed-off-by: Matti Vaittinen 
Acked-for-MFD-by: Lee Jones 
---
Changes since v3:
 - No changes
 drivers/regulator/rohm-regulator.c | 6 ++
 include/linux/mfd/rohm-generic.h   | 6 +-
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/regulator/rohm-regulator.c 
b/drivers/regulator/rohm-regulator.c
index 63aabb8c7786..6e0d9c08ec1c 100644
--- a/drivers/regulator/rohm-regulator.c
+++ b/drivers/regulator/rohm-regulator.c
@@ -95,6 +95,12 @@ int rohm_regulator_set_dvs_levels(const struct 
rohm_dvs_config *dvs,
mask = dvs->lpsr_mask;
omask = dvs->lpsr_on_mask;
break;
+   case ROHM_DVS_LEVEL_SNVS:
+   prop = "rohm,dvs-snvs-voltage";
+   reg = dvs->snvs_reg;
+   mask = dvs->snvs_mask;
+   omask = dvs->snvs_on_mask;
+   break;
default:
return -EINVAL;
}
diff --git a/include/linux/mfd/rohm-generic.h b/include/linux/mfd/rohm-generic.h
index 9e2880e06950..a9144284cf6d 100644
--- a/include/linux/mfd/rohm-generic.h
+++ b/include/linux/mfd/rohm-generic.h
@@ -27,7 +27,8 @@ struct rohm_regmap_dev {
 #define ROHM_DVS_LEVEL_IDLEBIT(1)
 #define ROHM_DVS_LEVEL_SUSPEND BIT(2)
 #define ROHM_DVS_LEVEL_LPSRBIT(3)
-#define ROHM_DVS_LEVEL_VALID_AMOUNT4
+#define ROHM_DVS_LEVEL_SNVSBIT(4)
+#define ROHM_DVS_LEVEL_VALID_AMOUNT5
 #define ROHM_DVS_LEVEL_UNKNOWN 0
 
 /**
@@ -66,6 +67,9 @@ struct rohm_dvs_config {
unsigned int lpsr_reg;
unsigned int lpsr_mask;
unsigned int lpsr_on_mask;
+   unsigned int snvs_reg;
+   unsigned int snvs_mask;
+   unsigned int snvs_on_mask;
 };
 
 #if IS_ENABLED(CONFIG_REGULATOR_ROHM)
-- 
2.25.4


-- 
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 =] 


[PATCH v5 11/19] regulator: rohm-regulator: linear voltage support

2021-03-29 Thread Matti Vaittinen
The helper for obtaining HW-state based DVS voltage levels currently only
works for regulators using linear-ranges. Extend support to regulators with
simple linear mappings and add also proper error path if pickable-ranges
regulators call this.

Signed-off-by: Matti Vaittinen 
---
Changes since v3:
  - No changes
 drivers/regulator/rohm-regulator.c | 17 +++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/regulator/rohm-regulator.c 
b/drivers/regulator/rohm-regulator.c
index 5c558b153d55..63aabb8c7786 100644
--- a/drivers/regulator/rohm-regulator.c
+++ b/drivers/regulator/rohm-regulator.c
@@ -22,13 +22,26 @@ static int set_dvs_level(const struct regulator_desc *desc,
return ret;
return 0;
}
-
+   /* If voltage is set to 0 => disable */
if (uv == 0) {
if (omask)
return regmap_update_bits(regmap, oreg, omask, 0);
}
+   /* 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;
+   }
for (i = 0; i < desc->n_voltages; i++) {
-   ret = regulator_desc_list_voltage_linear_range(desc, i);
+   /* 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);
if (ret < 0)
continue;
if (ret == uv) {
-- 
2.25.4


-- 
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 =] 


[PATCH v5 10/19] regulator: helpers: Export helper voltage listing

2021-03-29 Thread Matti Vaittinen
Some drivers need to translate voltage values to selectors prior regulator
registration. Currently a regulator_desc based list_voltages helper is only
exported for regulators using the linear_ranges. Export similar helper also
for regulators using simple linear mapping.

Signed-off-by: Matti Vaittinen 
---
Changes since v3:
 - No changes
 drivers/regulator/helpers.c  | 36 +---
 include/linux/regulator/driver.h |  2 ++
 2 files changed, 30 insertions(+), 8 deletions(-)

diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c
index f42b394a0c46..3e19ecbf7267 100644
--- a/drivers/regulator/helpers.c
+++ b/drivers/regulator/helpers.c
@@ -508,6 +508,33 @@ int regulator_map_voltage_pickable_linear_range(struct 
regulator_dev *rdev,
 }
 EXPORT_SYMBOL_GPL(regulator_map_voltage_pickable_linear_range);
 
+/**
+ * regulator_desc_list_voltage_linear - List voltages with simple calculation
+ *
+ * @desc: Regulator desc for regulator which volatges are to be listed
+ * @selector: Selector to convert into a voltage
+ *
+ * Regulators with a simple linear mapping between voltages and
+ * selectors can set min_uV and uV_step in the regulator descriptor
+ * and then use this function prior regulator registration to list
+ * the voltages. This is useful when voltages need to be listed during
+ * device-tree parsing.
+ */
+int regulator_desc_list_voltage_linear(const struct regulator_desc *desc,
+  unsigned int selector)
+{
+   if (selector >= desc->n_voltages)
+   return -EINVAL;
+
+   if (selector < desc->linear_min_sel)
+   return 0;
+
+   selector -= desc->linear_min_sel;
+
+   return desc->min_uV + (desc->uV_step * selector);
+}
+EXPORT_SYMBOL_GPL(regulator_desc_list_voltage_linear);
+
 /**
  * regulator_list_voltage_linear - List voltages with simple calculation
  *
@@ -521,14 +548,7 @@ 
EXPORT_SYMBOL_GPL(regulator_map_voltage_pickable_linear_range);
 int regulator_list_voltage_linear(struct regulator_dev *rdev,
  unsigned int selector)
 {
-   if (selector >= rdev->desc->n_voltages)
-   return -EINVAL;
-   if (selector < rdev->desc->linear_min_sel)
-   return 0;
-
-   selector -= rdev->desc->linear_min_sel;
-
-   return rdev->desc->min_uV + (rdev->desc->uV_step * selector);
+   return regulator_desc_list_voltage_linear(rdev->desc, selector);
 }
 EXPORT_SYMBOL_GPL(regulator_list_voltage_linear);
 
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index d7c77ee370f3..39a540111645 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -543,4 +543,6 @@ void *regulator_get_init_drvdata(struct regulator_init_data 
*reg_init_data);
 int regulator_desc_list_voltage_linear_range(const struct regulator_desc *desc,
 unsigned int selector);
 
+int regulator_desc_list_voltage_linear(const struct regulator_desc *desc,
+      unsigned int selector);
 #endif
-- 
2.25.4


-- 
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 =] 


[PATCH v5 09/19] gpio: support ROHM BD71815 GPOs

2021-03-29 Thread Matti Vaittinen
Support GPO(s) found from ROHM BD71815 power management IC. The IC has two
GPO pins but only one is properly documented in data-sheet. The driver
exposes by default only the documented GPO. The second GPO is connected to
E5 pin and is marked as GND in data-sheet. Control for this undocumented
pin can be enabled using a special DT property.

This driver is derived from work by Peter Yang 
although not so much of original is left.

Signed-off-by: Matti Vaittinen 
Acked-by: Bartosz Golaszewski 
Acked-by: Linus Walleij 
---

Linus, Bartosz, please note that I changed this patch somewhat according
to suggestions from Andy. Please let me know if you want to revoke acks.

Changes since v4:
 - styling fixes
 - implemented init_valid_mask
 - added comment that the ngpio hack can be deleted later
   if sysfs IF does respect the valid_mask

 drivers/gpio/Kconfig|  10 ++
 drivers/gpio/Makefile   |   1 +
 drivers/gpio/gpio-bd71815.c | 193 
 3 files changed, 204 insertions(+)
 create mode 100644 drivers/gpio/gpio-bd71815.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index e3607ec4c2e8..d3b3de514f6e 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -1105,6 +1105,16 @@ config GPIO_BD70528
  This driver can also be built as a module. If so, the module
  will be called gpio-bd70528.
 
+config GPIO_BD71815
+   tristate "ROHM BD71815 PMIC GPIO support"
+   depends on MFD_ROHM_BD71828
+   help
+ Support for GPO(s) on ROHM BD71815 PMIC. There are two GPOs
+ available on the ROHM PMIC.
+
+ This driver can also be built as a module. If so, the module
+ will be called gpio-bd71815.
+
 config GPIO_BD71828
tristate "ROHM BD71828 GPIO support"
depends on MFD_ROHM_BD71828
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index c58a90a3c3b1..4c12f31db31f 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_GPIO_ATH79)  += gpio-ath79.o
 obj-$(CONFIG_GPIO_BCM_KONA)+= gpio-bcm-kona.o
 obj-$(CONFIG_GPIO_BCM_XGS_IPROC)   += gpio-xgs-iproc.o
 obj-$(CONFIG_GPIO_BD70528) += gpio-bd70528.o
+obj-$(CONFIG_GPIO_BD71815) += gpio-bd71815.o
 obj-$(CONFIG_GPIO_BD71828) += gpio-bd71828.o
 obj-$(CONFIG_GPIO_BD9571MWV)   += gpio-bd9571mwv.o
 obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
diff --git a/drivers/gpio/gpio-bd71815.c b/drivers/gpio/gpio-bd71815.c
new file mode 100644
index ..c7f37813d629
--- /dev/null
+++ b/drivers/gpio/gpio-bd71815.c
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Support to GPOs on ROHM BD71815
+ * Copyright 2021 ROHM Semiconductors.
+ * Author: Matti Vaittinen 
+ *
+ * Copyright 2014 Embest Technology Co. Ltd. Inc.
+ * Author: yang...@embest-tech.com
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+/* For the BD71815 register definitions */
+#include 
+
+struct bd71815_gpio {
+   struct gpio_chip chip;
+   struct device *dev;
+   struct regmap *regmap;
+};
+
+static int bd71815gpo_get(struct gpio_chip *chip, unsigned int offset)
+{
+   struct bd71815_gpio *bd71815 = gpiochip_get_data(chip);
+   int ret, val;
+
+   ret = regmap_read(bd71815->regmap, BD71815_REG_GPO, );
+   if (ret)
+   return ret;
+
+   return (val >> offset) & 1;
+}
+
+static void bd71815gpo_set(struct gpio_chip *chip, unsigned int offset,
+  int value)
+{
+   struct bd71815_gpio *bd71815 = gpiochip_get_data(chip);
+   int ret, bit;
+
+   bit = BIT(offset);
+
+   if (value)
+   ret = regmap_set_bits(bd71815->regmap, BD71815_REG_GPO, bit);
+   else
+   ret = regmap_clear_bits(bd71815->regmap, BD71815_REG_GPO, bit);
+
+   if (ret)
+   dev_warn(bd71815->dev, "failed to toggle GPO\n");
+}
+
+static int bd71815_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+  unsigned long config)
+{
+   struct bd71815_gpio *bdgpio = gpiochip_get_data(chip);
+
+   switch (pinconf_to_config_param(config)) {
+   case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+   return regmap_update_bits(bdgpio->regmap,
+ BD71815_REG_GPO,
+ BD71815_GPIO_DRIVE_MASK << offset,
+ BD71815_GPIO_OPEN_DRAIN << offset);
+   case PIN_CONFIG_DRIVE_PUSH_PULL:
+   return regmap_update_bits(bdgpio->regmap,
+ BD71815_REG_GPO,
+ BD71815_GPIO_DRIVE_MASK << offset,
+ BD71815_GPIO_CMOS << offset);
+   default:
+   break;
+   }
+   return -ENOTS

[PATCH v5 08/19] mfd: Support for ROHM BD71815 PMIC core

2021-03-29 Thread Matti Vaittinen
Add core support for ROHM BD71815 Power Management IC.

The IC integrates regulators, a battery charger with a coulomb counter,
a real-time clock (RTC), clock gate and general-purpose outputs (GPO).

Signed-off-by: Matti Vaittinen 
Acked-for-MFD-by: Lee Jones 
---
No changes since v4
 drivers/mfd/Kconfig  |  15 +-
 drivers/mfd/rohm-bd71828.c   | 486 +++---
 include/linux/mfd/rohm-bd71815.h | 562 +++
 include/linux/mfd/rohm-bd71828.h |   3 +
 4 files changed, 933 insertions(+), 133 deletions(-)
 create mode 100644 include/linux/mfd/rohm-bd71815.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index b74efa469e90..60d9ae559f0a 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1975,19 +1975,20 @@ config MFD_ROHM_BD70528
  charger.
 
 config MFD_ROHM_BD71828
-   tristate "ROHM BD71828 Power Management IC"
+   tristate "ROHM BD71828 and BD71815 Power Management IC"
depends on I2C=y
depends on OF
select REGMAP_I2C
select REGMAP_IRQ
select MFD_CORE
help
- Select this option to get support for the ROHM BD71828 Power
- Management IC. BD71828GW is a single-chip power management IC for
- battery-powered portable devices. The IC integrates 7 buck
- converters, 7 LDOs, and a 1500 mA single-cell linear charger.
- Also included is a Coulomb counter, a real-time clock (RTC), and
- a 32.768 kHz clock gate.
+ Select this option to get support for the ROHM BD71828 and BD71815
+ Power Management ICs. BD71828GW and BD71815AGW are single-chip power
+ management ICs mainly for battery-powered portable devices.
+ The BD71828 integrates 7 buck converters and 7 LDOs. The BD71815
+ has 5 bucks, 7 LDOs, and a boost for driving LEDs. Both ICs provide
+ also a single-cell linear charger, a Coulomb counter, a real-time
+ clock (RTC), GPIOs and a 32.768 kHz clock gate.
 
 config MFD_STM32_LPTIMER
tristate "Support for STM32 Low-Power Timer"
diff --git a/drivers/mfd/rohm-bd71828.c b/drivers/mfd/rohm-bd71828.c
index 210261d026f2..714d9fcbf07b 100644
--- a/drivers/mfd/rohm-bd71828.c
+++ b/drivers/mfd/rohm-bd71828.c
@@ -2,7 +2,7 @@
 //
 // Copyright (C) 2019 ROHM Semiconductors
 //
-// ROHM BD71828 PMIC driver
+// ROHM BD71828/BD71815 PMIC driver
 
 #include 
 #include 
@@ -11,7 +11,9 @@
 #include 
 #include 
 #include 
+#include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -29,12 +31,84 @@ static struct gpio_keys_platform_data bd71828_powerkey_data 
= {
.name = "bd71828-pwrkey",
 };
 
-static const struct resource rtc_irqs[] = {
+static const struct resource bd71815_rtc_irqs[] = {
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC0, "bd71815-rtc-alm-0"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC1, "bd71815-rtc-alm-1"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC2, "bd71815-rtc-alm-2"),
+};
+
+static const struct resource bd71828_rtc_irqs[] = {
DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC0, "bd71828-rtc-alm-0"),
DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC1, "bd71828-rtc-alm-1"),
DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC2, "bd71828-rtc-alm-2"),
 };
 
+static struct resource bd71815_power_irqs[] = {
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_RMV, "bd71815-dcin-rmv"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_CLPS_OUT, "bd71815-clps-out"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_CLPS_IN, "bd71815-clps-in"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_OVP_RES, "bd71815-dcin-ovp-res"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_OVP_DET, "bd71815-dcin-ovp-det"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_MON_RES, "bd71815-dcin-mon-res"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_MON_DET, "bd71815-dcin-mon-det"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_UV_RES, "bd71815-vsys-uv-res"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_UV_DET, "bd71815-vsys-uv-det"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_LOW_RES, "bd71815-vsys-low-res"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_LOW_DET, "bd71815-vsys-low-det"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_MON_RES, "bd71815-vsys-mon-res"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_MON_RES, "bd71815-vsys-mon-det"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_WDG_TEMP, "bd71815-chg-wdg-temp"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_WDG_TIME, "bd71815-chg-wdg"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_RECHARGE_RES, "bd71815-rechg-res"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_RECHARGE_DET, "bd71815-rechg-det"),
+   DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_RANGED_TEMP_TRANSITION, 
"bd71815-ranged-temp

[PATCH v5 07/19] mfd: Sort ROHM chip ID list for better readability

2021-03-29 Thread Matti Vaittinen
Sort the ID list so it is easier to see which ICs are present.

Signed-off-by: Matti Vaittinen 
Suggested-by: Lee Jones 
---
No changes since v4

 include/linux/mfd/rohm-generic.h | 8 
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/include/linux/mfd/rohm-generic.h b/include/linux/mfd/rohm-generic.h
index e107b4769101..9e2880e06950 100644
--- a/include/linux/mfd/rohm-generic.h
+++ b/include/linux/mfd/rohm-generic.h
@@ -8,13 +8,13 @@
 #include 
 
 enum rohm_chip_type {
-   ROHM_CHIP_TYPE_BD71837 = 0,
-   ROHM_CHIP_TYPE_BD71847,
+   ROHM_CHIP_TYPE_BD9571,
+   ROHM_CHIP_TYPE_BD9574,
ROHM_CHIP_TYPE_BD70528,
ROHM_CHIP_TYPE_BD71815,
ROHM_CHIP_TYPE_BD71828,
-   ROHM_CHIP_TYPE_BD9571,
-   ROHM_CHIP_TYPE_BD9574,
+   ROHM_CHIP_TYPE_BD71837,
+   ROHM_CHIP_TYPE_BD71847,
ROHM_CHIP_TYPE_AMOUNT
 };
 
-- 
2.25.4


-- 
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 =] 


[PATCH v5 06/19] mfd: Add ROHM BD71815 ID

2021-03-29 Thread Matti Vaittinen
Add chip ID for ROHM BD71815 and PMIC so that drivers can identify
this IC.

Signed-off-by: Matti Vaittinen 
Acked-for-MFD-by: Lee Jones 
---
No changes since v4

 include/linux/mfd/rohm-generic.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/linux/mfd/rohm-generic.h b/include/linux/mfd/rohm-generic.h
index 66f673c35303..e107b4769101 100644
--- a/include/linux/mfd/rohm-generic.h
+++ b/include/linux/mfd/rohm-generic.h
@@ -11,6 +11,7 @@ enum rohm_chip_type {
ROHM_CHIP_TYPE_BD71837 = 0,
ROHM_CHIP_TYPE_BD71847,
ROHM_CHIP_TYPE_BD70528,
+   ROHM_CHIP_TYPE_BD71815,
ROHM_CHIP_TYPE_BD71828,
ROHM_CHIP_TYPE_BD9571,
ROHM_CHIP_TYPE_BD9574,
-- 
2.25.4


-- 
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 =] 


[PATCH v5 05/19] dt_bindings: mfd: Add ROHM BD71815 PMIC

2021-03-29 Thread Matti Vaittinen
Document DT bindings for ROHM BD71815.

BD71815 is a single-chip power management IC mainly for battery-powered
portable devices. The IC integrates 5 bucks, 7 LDOs, a boost driver for
LED, a battery charger with a Coulomb counter, a real-time clock, a 32kHz
clock and two general-purpose outputs although only one is documented by
the data-sheet.

Signed-off-by: Matti Vaittinen 
Reviewed-by: Rob Herring 
---
No changes since v3
 .../bindings/mfd/rohm,bd71815-pmic.yaml   | 201 ++
 1 file changed, 201 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml

diff --git a/Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml 
b/Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml
new file mode 100644
index ..fe265bcab50d
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml
@@ -0,0 +1,201 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/rohm,bd71815-pmic.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ROHM BD71815 Power Management Integrated Circuit bindings
+
+maintainers:
+  - Matti Vaittinen 
+
+description: |
+  BD71815AGW is a single-chip power management ICs for battery-powered
+  portable devices. It integrates 5 buck converters, 8 LDOs, a boost driver
+  for LED and a 500 mA single-cell linear charger. Also included is a Coulomb
+  counter, a real-time clock (RTC), and a 32.768 kHz clock gate and two GPOs.
+
+properties:
+  compatible:
+const: rohm,bd71815
+
+  reg:
+description:
+  I2C slave address.
+maxItems: 1
+
+  interrupts:
+maxItems: 1
+
+  gpio-controller: true
+
+  "#gpio-cells":
+const: 2
+description: |
+  The first cell is the pin number and the second cell is used to specify
+  flags. See ../gpio/gpio.txt for more information.
+
+  clocks:
+maxItems: 1
+
+  "#clock-cells":
+const: 0
+
+  clock-output-names:
+const: bd71815-32k-out
+
+  rohm,clkout-open-drain:
+description: clk32kout mode. Set to 1 for "open-drain" or 0 for "cmos".
+$ref: "/schemas/types.yaml#/definitions/uint32"
+minimum: 0
+maximum: 1
+
+  rohm,charger-sense-resistor-ohms:
+minimum: 1000
+maximum: 5000
+description: |
+  BD71827 and BD71828 have SAR ADC for measuring charging currents.
+  External sense resistor (RSENSE in data sheet) should be used. If
+  something other but 30MOhm resistor is used the resistance value
+  should be given here in Ohms.
+default: 3000
+
+  regulators:
+$ref: ../regulator/rohm,bd71815-regulator.yaml
+description:
+  List of child nodes that specify the regulators.
+
+  gpio-reserved-ranges:
+description: |
+  Usage of BD71828 GPIO pins can be changed via OTP. This property can be
+  used to mark the pins which should not be configured for GPIO. Please see
+  the ../gpio/gpio.txt for more information.
+
+  rohm,enable-hidden-gpo:
+description: |
+  The BD71815 has undocumented GPO at pin E5. Pin is marked as GND at the
+  data-sheet as it's location in the middle of GND pins makes it hard to
+  use on PCB. If your board has managed to use this pin you can enable the
+  second GPO by defining this property. Dont enable this if you are unsure
+  about how the E5 pin is connected on your board.
+type: boolean
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - "#clock-cells"
+  - regulators
+  - gpio-controller
+  - "#gpio-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+#include 
+#include 
+i2c {
+#address-cells = <1>;
+#size-cells = <0>;
+pmic: pmic@4b {
+compatible = "rohm,bd71815";
+reg = <0x4b>;
+
+interrupt-parent = <>;
+interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
+
+clocks = < 0>;
+#clock-cells = <0>;
+clock-output-names = "bd71815-32k-out";
+
+gpio-controller;
+#gpio-cells = <2>;
+
+rohm,charger-sense-resistor-ohms = <1000>;
+
+regulators {
+buck1: buck1 {
+regulator-name = "buck1";
+regulator-min-microvolt = <80>;
+regulator-max-microvolt = <200>;
+regulator-always-on;
+regulator-ramp-delay = <1250>;
+rohm,dvs-run-voltage = <115>;
+rohm,dvs-suspend-voltage = <95>;
+};
+buck2: buck2 {
+regulator-name = "buck2";
+regulator-min-microvolt = <80>;
+regulator-max-microvolt

[PATCH v5 04/19] dt_bindings: regulator: Add ROHM BD71815 PMIC regulators

2021-03-29 Thread Matti Vaittinen
Add binding documentation for regulators on ROHM BD71815 PMIC.
5 bucks, 7 LDOs and a boost for LED.

Signed-off-by: Matti Vaittinen 
Reviewed-by: Rob Herring 
---
No Changes since v3
 .../regulator/rohm,bd71815-regulator.yaml | 116 ++
 1 file changed, 116 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/regulator/rohm,bd71815-regulator.yaml

diff --git 
a/Documentation/devicetree/bindings/regulator/rohm,bd71815-regulator.yaml 
b/Documentation/devicetree/bindings/regulator/rohm,bd71815-regulator.yaml
new file mode 100644
index ..7d0adb74a396
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/rohm,bd71815-regulator.yaml
@@ -0,0 +1,116 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/rohm,bd71815-regulator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ROHM BD71815 Power Management Integrated Circuit regulators
+
+maintainers:
+  - Matti Vaittinen 
+
+description: |
+  This module is part of the ROHM BD718215 MFD device. For more details
+  see Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml.
+
+  The regulator controller is represented as a sub-node of the PMIC node
+  on the device tree.
+
+  The valid names for BD71815 regulator nodes are
+  buck1, buck2, buck3, buck4, buck5,
+  ldo1, ldo2, ldo3, ldo4, ldo5,
+  ldodvref, ldolpsr, wled
+
+properties:
+  wled:
+type: object
+description:
+  properties for wled regulator
+$ref: regulator.yaml#
+
+properties:
+  regulator-name:
+const: wled
+
+patternProperties:
+  "^((ldo|buck)[1-5]|ldolpsr|ldodvref)$":
+type: object
+description:
+  Properties for single LDO/BUCK regulator.
+$ref: regulator.yaml#
+
+properties:
+  regulator-name:
+pattern: "^((ldo|buck)[1-5]|ldolpsr|ldodvref)$"
+description:
+  should be "ldo1", ..., "ldo5", "buck1", ..., "buck5" and "ldolpsr"
+  for ldolpsr regulator, "ldodvref" for ldodvref reglator.
+
+  rohm,vsel-gpios:
+description:
+  GPIO used to control ldo4 state (when ldo4 is controlled by GPIO).
+
+  rohm,dvs-run-voltage:
+description:
+  PMIC "RUN" state voltage in uV when PMIC HW states are used. See
+  comments below for bucks/LDOs which support this. 0 means
+  regulator should be disabled at RUN state.
+$ref: "/schemas/types.yaml#/definitions/uint32"
+minimum: 0
+maximum: 330
+
+  rohm,dvs-snvs-voltage:
+description:
+  Whether to keep regulator enabled at "SNVS" state or not.
+  0 means regulator should be disabled at SNVS state, non zero voltage
+  keeps regulator enabled. BD71815 does not change voltage level
+  when PMIC transitions to SNVS.SNVS voltage depends on the previous
+  state (from which the PMIC transitioned to SNVS).
+$ref: "/schemas/types.yaml#/definitions/uint32"
+minimum: 0
+maximum: 330
+
+  rohm,dvs-suspend-voltage:
+description:
+  PMIC "SUSPEND" state voltage in uV when PMIC HW states are used. See
+  comments below for bucks/LDOs which support this. 0 means
+  regulator should be disabled at SUSPEND state.
+$ref: "/schemas/types.yaml#/definitions/uint32"
+minimum: 0
+maximum: 330
+
+  rohm,dvs-lpsr-voltage:
+description:
+  PMIC "LPSR" state voltage in uV when PMIC HW states are used. See
+  comments below for bucks/LDOs which support this. 0 means
+  regulator should be disabled at LPSR state.
+$ref: "/schemas/types.yaml#/definitions/uint32"
+minimum: 0
+maximum: 330
+
+# Bucks 1 and 2 support giving separate voltages for operational states
+# (RUN /CLEAN according to data-sheet) and non operational states
+# (LPSR/SUSPEND). The voltage is automatically changed when HW
+# state changes. Omitting these properties from bucks 1 and 2 leave
+# buck voltages to not be toggled by HW state. Enable status may still
+# be toggled by state changes depending on HW default settings.
+#
+# Bucks 3-5 and ldos 1-5 support setting the RUN state voltage here.
+# Given RUN voltage is used at all states if regulator is enabled at
+# given state.
+# Values given for other states are regarded as enable/disable at
+# given state (see below).
+#
+# All regulators except WLED support specifying enable/disable status
+# for each of the HW states (RUN/SNVS/SUSPEND/LPSR). HW defaults can
+# be overridden by setting voltage to 0 (regulator disabled at given
+# state) or non-zero (regulator en

[PATCH v5 03/19] dt_bindings: bd71828: Add clock output mode

2021-03-29 Thread Matti Vaittinen
The BD71828 allows configuring the clk32kout pin mode to CMOS or
open-drain. Add device-tree property for specifying the preferred mode.

Signed-off-by: Matti Vaittinen 
Reviewed-by: Rob Herring 
---
No changes since v3
 .../devicetree/bindings/mfd/rohm,bd71828-pmic.yaml  | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml 
b/Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml
index 3a6a1a26e2b3..8380166d176c 100644
--- a/Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml
+++ b/Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml
@@ -44,6 +44,12 @@ properties:
   clock-output-names:
 const: bd71828-32k-out
 
+  rohm,clkout-open-drain:
+description: clk32kout mode. Set to 1 for "open-drain" or 0 for "cmos".
+$ref: "/schemas/types.yaml#/definitions/uint32"
+minimum: 0
+maximum: 1
+
   rohm,charger-sense-resistor-ohms:
 minimum: 1000
 maximum: 5000
-- 
2.25.4


-- 
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 =] 


[PATCH v5 02/19] mfd: bd718x7: simplify by cleaning unnecessary device data

2021-03-29 Thread Matti Vaittinen
Most ROHM PMIC sub-devices only use the regmap pointer from
parent device. They can obtain this by dev_get_regamap so in
most cases the MFD device does not need to allocate and populate
the driver data. Simplify drivers by removing this.

The BD70528 still needs the access to watchdog mutex so keep
rohm_regmap_dev in use on BD70528 RTC and WDG drivers for now.

Signed-off-by: Matti Vaittinen 
Acked-for-MFD-by: Lee Jones 
---
No changes since v3

 drivers/mfd/rohm-bd718x7.c   | 43 
 include/linux/mfd/rohm-bd718x7.h | 13 --
 2 files changed, 16 insertions(+), 40 deletions(-)

diff --git a/drivers/mfd/rohm-bd718x7.c b/drivers/mfd/rohm-bd718x7.c
index c32c1b6c98fa..bfd81f78beae 100644
--- a/drivers/mfd/rohm-bd718x7.c
+++ b/drivers/mfd/rohm-bd718x7.c
@@ -91,9 +91,9 @@ static const struct regmap_config bd718xx_regmap_config = {
.cache_type = REGCACHE_RBTREE,
 };
 
-static int bd718xx_init_press_duration(struct bd718xx *bd718xx)
+static int bd718xx_init_press_duration(struct regmap *regmap,
+  struct device *dev)
 {
-   struct device* dev = bd718xx->chip.dev;
u32 short_press_ms, long_press_ms;
u32 short_press_value, long_press_value;
int ret;
@@ -102,8 +102,7 @@ static int bd718xx_init_press_duration(struct bd718xx 
*bd718xx)
   _press_ms);
if (!ret) {
short_press_value = min(15u, (short_press_ms + 250) / 500);
-   ret = regmap_update_bits(bd718xx->chip.regmap,
-BD718XX_REG_PWRONCONFIG0,
+   ret = regmap_update_bits(regmap, BD718XX_REG_PWRONCONFIG0,
 BD718XX_PWRBTN_PRESS_DURATION_MASK,
 short_press_value);
if (ret) {
@@ -116,8 +115,7 @@ static int bd718xx_init_press_duration(struct bd718xx 
*bd718xx)
   _press_ms);
if (!ret) {
long_press_value = min(15u, (long_press_ms + 500) / 1000);
-   ret = regmap_update_bits(bd718xx->chip.regmap,
-BD718XX_REG_PWRONCONFIG1,
+   ret = regmap_update_bits(regmap, BD718XX_REG_PWRONCONFIG1,
 BD718XX_PWRBTN_PRESS_DURATION_MASK,
 long_press_value);
if (ret) {
@@ -132,7 +130,8 @@ static int bd718xx_init_press_duration(struct bd718xx 
*bd718xx)
 static int bd718xx_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
 {
-   struct bd718xx *bd718xx;
+   struct regmap *regmap;
+   struct regmap_irq_chip_data *irq_data;
int ret;
unsigned int chip_type;
struct mfd_cell *mfd;
@@ -142,13 +141,6 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c,
dev_err(>dev, "No IRQ configured\n");
return -EINVAL;
}
-
-   bd718xx = devm_kzalloc(>dev, sizeof(struct bd718xx), GFP_KERNEL);
-
-   if (!bd718xx)
-   return -ENOMEM;
-
-   bd718xx->chip_irq = i2c->irq;
chip_type = (unsigned int)(uintptr_t)
of_device_get_match_data(>dev);
switch (chip_type) {
@@ -164,29 +156,26 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c,
dev_err(>dev, "Unknown device type");
return -EINVAL;
}
-   bd718xx->chip.dev = >dev;
-   dev_set_drvdata(>dev, bd718xx);
 
-   bd718xx->chip.regmap = devm_regmap_init_i2c(i2c,
-   _regmap_config);
-   if (IS_ERR(bd718xx->chip.regmap)) {
+   regmap = devm_regmap_init_i2c(i2c, _regmap_config);
+   if (IS_ERR(regmap)) {
dev_err(>dev, "regmap initialization failed\n");
-   return PTR_ERR(bd718xx->chip.regmap);
+   return PTR_ERR(regmap);
}
 
-   ret = devm_regmap_add_irq_chip(>dev, bd718xx->chip.regmap,
-  bd718xx->chip_irq, IRQF_ONESHOT, 0,
-  _irq_chip, >irq_data);
+   ret = devm_regmap_add_irq_chip(>dev, regmap, i2c->irq,
+  IRQF_ONESHOT, 0, _irq_chip,
+  _data);
if (ret) {
dev_err(>dev, "Failed to add irq_chip\n");
return ret;
}
 
-   ret = bd718xx_init_press_duration(bd718xx);
+   ret = bd718xx_init_press_duration(regmap, >dev);
if (ret)
return ret;
 
-   ret = regmap_irq_get_virq(bd718xx->irq_data, BD718XX_INT_PWRBTN_S);
+   ret = regmap_irq_get_virq(irq_data, BD718XX_INT_PWRBTN_S);
 
if (ret < 0) {
dev_err(>dev, "Failed to get t

[PATCH v5 01/19] rtc: bd70528: Do not require parent data

2021-03-29 Thread Matti Vaittinen
The ROHM BD71828 and BD71815 RTC drivers only need the regmap
pointer from parent. Regmap can be obtained via dev_get_regmap()
so do not require parent to populate driver data for that.

BD70528 on the other hand requires parent data to access the
watchdog so leave the parent data for BD70528 here for now.

Signed-off-by: Matti Vaittinen 
Acked-by: Alexandre Belloni 
---
No changes since v3

 drivers/rtc/rtc-bd70528.c | 67 ++-
 1 file changed, 31 insertions(+), 36 deletions(-)

diff --git a/drivers/rtc/rtc-bd70528.c b/drivers/rtc/rtc-bd70528.c
index 17cb67f5bf6e..fb4476bb5ab6 100644
--- a/drivers/rtc/rtc-bd70528.c
+++ b/drivers/rtc/rtc-bd70528.c
@@ -52,6 +52,7 @@ struct bd70528_rtc_alm {
 
 struct bd70528_rtc {
struct rohm_regmap_dev *parent;
+   struct regmap *regmap;
struct device *dev;
u8 reg_time_start;
bool has_rtc_timers;
@@ -234,9 +235,8 @@ static int bd71828_set_alarm(struct device *dev, struct 
rtc_wkalrm *a)
int ret;
struct bd71828_rtc_alm alm;
struct bd70528_rtc *r = dev_get_drvdata(dev);
-   struct rohm_regmap_dev *parent = r->parent;
 
-   ret = regmap_bulk_read(parent->regmap, BD71828_REG_RTC_ALM_START,
+   ret = regmap_bulk_read(r->regmap, BD71828_REG_RTC_ALM_START,
   , sizeof(alm));
if (ret) {
dev_err(dev, "Failed to read alarm regs\n");
@@ -250,7 +250,7 @@ static int bd71828_set_alarm(struct device *dev, struct 
rtc_wkalrm *a)
else
alm.alm_mask |= BD70528_MASK_ALM_EN;
 
-   ret = regmap_bulk_write(parent->regmap, BD71828_REG_RTC_ALM_START,
+   ret = regmap_bulk_write(r->regmap, BD71828_REG_RTC_ALM_START,
, sizeof(alm));
if (ret)
dev_err(dev, "Failed to set alarm time\n");
@@ -265,17 +265,16 @@ static int bd70528_set_alarm(struct device *dev, struct 
rtc_wkalrm *a)
struct bd70528_rtc_alm alm;
int ret;
struct bd70528_rtc *r = dev_get_drvdata(dev);
-   struct rohm_regmap_dev *parent = r->parent;
 
-   ret = regmap_bulk_read(parent->regmap, BD70528_REG_RTC_WAKE_START,
-  , sizeof(wake));
+   ret = regmap_bulk_read(r->regmap, BD70528_REG_RTC_WAKE_START, ,
+  sizeof(wake));
if (ret) {
dev_err(dev, "Failed to read wake regs\n");
return ret;
}
 
-   ret = regmap_bulk_read(parent->regmap, BD70528_REG_RTC_ALM_START,
-  , sizeof(alm));
+   ret = regmap_bulk_read(r->regmap, BD70528_REG_RTC_ALM_START, ,
+  sizeof(alm));
if (ret) {
dev_err(dev, "Failed to read alarm regs\n");
return ret;
@@ -292,15 +291,14 @@ static int bd70528_set_alarm(struct device *dev, struct 
rtc_wkalrm *a)
wake.ctrl &= ~BD70528_MASK_WAKE_EN;
}
 
-   ret = regmap_bulk_write(parent->regmap,
-   BD70528_REG_RTC_WAKE_START, ,
+   ret = regmap_bulk_write(r->regmap, BD70528_REG_RTC_WAKE_START, ,
sizeof(wake));
if (ret) {
dev_err(dev, "Failed to set wake time\n");
return ret;
}
-   ret = regmap_bulk_write(parent->regmap, BD70528_REG_RTC_ALM_START,
-   , sizeof(alm));
+   ret = regmap_bulk_write(r->regmap, BD70528_REG_RTC_ALM_START, ,
+   sizeof(alm));
if (ret)
dev_err(dev, "Failed to set alarm time\n");
 
@@ -312,9 +310,8 @@ static int bd71828_read_alarm(struct device *dev, struct 
rtc_wkalrm *a)
int ret;
struct bd71828_rtc_alm alm;
struct bd70528_rtc *r = dev_get_drvdata(dev);
-   struct rohm_regmap_dev *parent = r->parent;
 
-   ret = regmap_bulk_read(parent->regmap, BD71828_REG_RTC_ALM_START,
+   ret = regmap_bulk_read(r->regmap, BD71828_REG_RTC_ALM_START,
   , sizeof(alm));
if (ret) {
dev_err(dev, "Failed to read alarm regs\n");
@@ -336,10 +333,9 @@ static int bd70528_read_alarm(struct device *dev, struct 
rtc_wkalrm *a)
struct bd70528_rtc_alm alm;
int ret;
struct bd70528_rtc *r = dev_get_drvdata(dev);
-   struct rohm_regmap_dev *parent = r->parent;
 
-   ret = regmap_bulk_read(parent->regmap, BD70528_REG_RTC_ALM_START,
-  , sizeof(alm));
+   ret = regmap_bulk_read(r->regmap, BD70528_REG_RTC_ALM_START, ,
+  sizeof(alm));
if (ret) {
dev_err(dev, "Failed to read alarm regs\n");
return ret;
@@ -360,14 +356,12 @@ static int bd70528_set_time_locked(struct device *dev, 
st

[PATCH v5 00/19] Support ROHM BD71815 PMIC

2021-03-29 Thread Matti Vaittinen
Patch series introducing support for ROHM BD71815 PMIC

ROHM BD71815 is a power management IC used in some battery powered
systems. It contains regulators, GPO(s), charger + coulomb counter, RTC
and a clock gate.

All regulators can be controlled via I2C. LDO4 can additionally be set to
be enabled/disabled by a GPIO. LDO3 voltage could be selected from two
voltages written into separate VSEL reisters using GPIO but this mode is
not supported by driver. On top of that the PMIC has the typical HW
state machine which is present also on many other ROHM PMICs.

IC contains two GPOs - but one of the GPOs is marked as GND in
data-sheet. Thus the driver by default only exposes one GPO. The second
GPO can be enabled by special DT property.

RTC is almost similar to what is on BD71828. For currently used features
only the register address offset to RTC block differs.

The charger driver is not included in this series. ROHM has a charger
driver with some fuel-gauging logig written in but this is not included
here. I am working on separating the logic from HW specific driver and
supporting both BD71815 and BD71828 chargers in separate patch series.

Changelog v5:
  Regulator:
  - Added regmap helper for regulator ramp-delay and taken it in use
(patches 13, 14, 16 - they can be just dropped if ramp-delay helper is not
a good idea. Patch 15 implements old-fashioned ramp-delay)
  GPIO:
  - styling changes to GPIO (Mostly suggested by Andy)
  - implemented init_valid_mask (but can't count on it yet)
Changelog v4:
  - Sorted ROHM chip ID enum
  - Statcized DVS structures in regulator driver
  - Minor styling for regulator driver
  - rebased on v5.12-rc4
Changelog v3:
  - GPIO clean-up as suggested by Bartosz
  - MFD clean-up as suggested by Lee
  - clk-mode dt-binding handling in MFD driver corrected to reflect new
property values.
  - Dropped already applied patches
  - Rebased on v5.12-rc2
Changelog v2:
  - Rebased on top of v5.11-rc3
  - Added another "preliminary patch" which fixes HW-dvs voltage
handling (patch 1)
  - split regulator patch to two.
  - changed dt-binding patch ordering.
  regulators:
- staticized probe
- removed some unnecessary defines
- updated comments
- split rohm-regulator patch adding SNVS and supporting simple
  linear mapping into two - one adding support for mapping, other
  adding SNVS.
  GPIO:
- removed unnecessary headers
- clarified dev/parent->dev usage
- removed forgotten #define DEBUG
  dt-bindings:
- changed patch order to meet ref-dependencies
- added missing regulator nodes
- changed string property for clk mode to tristated
  MFD:
- header cleanups.
  CLK:
- fixed commit message

--

Matti Vaittinen (19):
  rtc: bd70528: Do not require parent data
  mfd: bd718x7: simplify by cleaning unnecessary device data
  dt_bindings: bd71828: Add clock output mode
  dt_bindings: regulator: Add ROHM BD71815 PMIC regulators
  dt_bindings: mfd: Add ROHM BD71815 PMIC
  mfd: Add ROHM BD71815 ID
  mfd: Sort ROHM chip ID list for better readability
  mfd: Support for ROHM BD71815 PMIC core
  gpio: support ROHM BD71815 GPOs
  regulator: helpers: Export helper voltage listing
  regulator: rohm-regulator: linear voltage support
  regulator: rohm-regulator: Support SNVS HW state.
  regulator: Add regmap helper for ramp-delay setting
  regulator: bd718x7, bd71828: Use ramp-delay helper
  regulator: Support ROHM BD71815 regulators
  regulator: bd71815: use ramp-delay helper
  clk: bd718x7: Add support for clk gate on ROHM BD71815 PMIC
  rtc: bd70528: Support RTC on ROHM BD71815
  MAINTAINERS: Add ROHM BD71815AGW

 .../bindings/mfd/rohm,bd71815-pmic.yaml   | 201 ++
 .../bindings/mfd/rohm,bd71828-pmic.yaml   |   6 +
 .../regulator/rohm,bd71815-regulator.yaml | 116 
 MAINTAINERS   |   3 +
 drivers/clk/clk-bd718x7.c |   9 +-
 drivers/gpio/Kconfig  |  10 +
 drivers/gpio/Makefile |   1 +
 drivers/gpio/gpio-bd71815.c   | 193 ++
 drivers/mfd/Kconfig   |  15 +-
 drivers/mfd/rohm-bd71828.c| 486 +
 drivers/mfd/rohm-bd718x7.c|  43 +-
 drivers/regulator/Kconfig |  11 +
 drivers/regulator/Makefile|   1 +
 drivers/regulator/bd71815-regulator.c | 651 ++
 drivers/regulator/bd71828-regulator.c |  51 +-
 drivers/regulator/bd718x7-regulator.c |  60 +-
 drivers/regulator/helpers.c   | 101 ++-
 drivers/regulator/rohm-regulator.c|  23 +-
 drivers/rtc/Kconfig   |   6 +-
 drivers/rtc/rtc-bd70528.c | 104 +--
 include/linux/mfd/rohm-bd71815.h  | 562 +++
 include/linux/mfd/rohm-bd71828.h  |   3 +
 include/linux/mfd/rohm-bd718x7.h  |  13 -
 

Re: [PATCH 2/2] gpiolib: Allow drivers to return EOPNOTSUPP from config

2021-03-29 Thread Matti Vaittinen
On Mon, 2021-03-29 at 14:59 +0300, Andy Shevchenko wrote:
> On Mon, Mar 29, 2021 at 2:43 PM Matti Vaittinen
>  wrote:
> > The checkpacth instructs to switch from ENOSUPP to EOPNOTSUPP.
> > > WARNING: ENOTSUPP is not a SUSV4 error code, prefer EOPNOTSUPP
> > 
> > Make the gpiolib allow drivers to return both so driver developers
> > can avoid one of the checkpatch complaints.
> 
> Internally we are fine to use the ENOTSUPP.
> Checkpatch false positives there.

I agree. OTOH, the checkpatch check makes sense to user-visible stuff.
Yet, the checkpatch has hard time guessing what is user-visible - so it
probably is easiest to nag about all ENOTSUPP uses as it does now.

> I doubt we need this change. Rather checkpatch should rephrase this
> to
> point out that this is only applicable to _user-visible_ error path.
> Cc'ed Joe.

Yes, thanks for pulling Joe in.

Anyways, no matter what the warning says, all false positives are
annoying. I don't see why we should stay with ENOTSUPP in gpiolib?
(other than the burden of changing it).

But I have no strong opinion on this. All options I see have downsides.

Accepting both ENOTSUPP and EOPNOTSUPP is the easy way to avoid
allowing checkpatch warnings - but I admit it isn't stylish. 

Converting all ENOTSUPP cases inside gpiolib to EOPNOTSUPP is teodious
although end result might be nicer.

Leaving it as is gives annoying false-positives to driver developers.

My personal preference was this patch - others can have other view like
Andy does. I'll leave this to community/maintainers to evaluate :)

Best Regards
Matti Vaittinen




[PATCH 2/2] gpiolib: Allow drivers to return EOPNOTSUPP from config

2021-03-29 Thread Matti Vaittinen
The checkpacth instructs to switch from ENOSUPP to EOPNOTSUPP.
> WARNING: ENOTSUPP is not a SUSV4 error code, prefer EOPNOTSUPP

Make the gpiolib allow drivers to return both so driver developers
can avoid one of the checkpatch complaints.

Signed-off-by: Matti Vaittinen 
---
 drivers/gpio/gpiolib.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 6367646dce83..60d61a6314b0 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -2134,7 +2134,7 @@ static int gpio_set_config_with_argument_optional(struct 
gpio_desc *desc,
int ret;
 
ret = gpio_set_config_with_argument(desc, mode, argument);
-   if (ret != -ENOTSUPP)
+   if (ret != -ENOTSUPP && ret != -EOPNOTSUPP)
return ret;
 
switch (mode) {
-- 
2.25.4


-- 
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 =] 


[PATCH 0/2] gpiolib: misc fixups

2021-03-29 Thread Matti Vaittinen
Patch 1/2:
The deprecated and obsoleted - but still used (especially in older
releases) /sys/class/gpio interface allows modifying GPIOs which are
excluded by the "valid_mask". This makes the valid_mask not suitable for
cases where toggling GPIO can cause damage. Patch adds validity
check to export.

I assume many people are still using the /sys/class/gpio at least for
testing purposes - especially with older releases. Thus it might be
worth the hassle to exclude invalid GPIOs - they're probably set invalid
for a good reason. (Actually, I noticed this when trying to use the
valid_mask to invalidate undocumented GPO on BD71815 - which may be
connected to GND. The people using BD71815 are likely to be using some
stable-release, which probably supports the (deprected, obsolete) sysfs
until the end of the days => valid_mask is not safe way unless fix to
this is backported to stable).

Patch 2/2:
checkpatch nowadays reminds us that ENOTSUPP is not valid error and
should be replaced by EOPNOTSUPP. It'd be nice if GPIO drivers could
return also the EOPNOTSUPP from config and avoid being nagged by
checkpatch.

Matti Vaittinen (2):
  gpio: sysfs: Obey valid_mask
  gpiolib: Allow drivers to return EOPNOTSUPP from config

 drivers/gpio/gpiolib-sysfs.c | 8 
 drivers/gpio/gpiolib.c   | 2 +-
 2 files changed, 9 insertions(+), 1 deletion(-)

-- 
2.25.4


-- 
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 =] 


[PATCH 1/2] gpio: sysfs: Obey valid_mask

2021-03-29 Thread Matti Vaittinen
Do not allow exporting GPIOs which are set invalid
by the driver's valid mask.

Fixes: 726cb3ba49692bdae6caff457755e7cdb432efa4

Signed-off-by: Matti Vaittinen 
---
 drivers/gpio/gpiolib-sysfs.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index 26c5466b8179..ae49bb23c6ed 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -458,6 +458,8 @@ static ssize_t export_store(struct class *class,
longgpio;
struct gpio_desc*desc;
int status;
+   struct gpio_chip*gc;
+   int offset;
 
status = kstrtol(buf, 0, );
if (status < 0)
@@ -469,6 +471,12 @@ static ssize_t export_store(struct class *class,
pr_warn("%s: invalid GPIO %ld\n", __func__, gpio);
return -EINVAL;
}
+   gc = desc->gdev->chip;
+   offset = gpio_chip_hwgpio(desc);
+   if (!gpiochip_line_is_valid(gc, offset)) {
+   pr_warn("%s: GPIO %ld masked\n", __func__, gpio);
+   return -EINVAL;
+   }
 
/* No extra locking here; FLAG_SYSFS just signifies that the
 * request and export were done by on behalf of userspace, so
-- 
2.25.4


-- 
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 =] 


  1   2   3   4   5   6   7   8   9   10   >