Skip to contentSkip to conversation

Support ROHM BD96801 Scalable PMIC

PATCH Superseded Matti Vaittinen 5 participants 21 messages May 24, 2024 – Jun 3, 2024

Subsystems (9)

v2 of 5 Superseded Latest is v5 →

lore
Share & tools
lore

Matti Vaittinen

author maintainer
#0 lore raw

v2 cover Support ROHM BD96801 Scalable PMIC

Support ROHM BD96801 Scalable PMIC

The ROHM BD96801 is automotive grade PMIC, intended to be usable in multiple solutions. The BD96801 can be used as a stand-alone, or together with separate 'companion PMICs'. This modular approach aims to make this PMIC suitable for various use-cases.

This series brings only limited support. The more complete set of features was sent in the RFC:
https://lore.kernel.org/lkml/[email protected]/

The BD96801 provides two physical IRQ lines called "intb" and "errb" in the data-sheet. These are handled using own regmap-IRQ controller for both of the IRQ lines. This causes a debugFS naming conflict for IRQ domains created by the regmap-IRQ. This series adds support for setting a name suffix to IRQ domains. Some prior discussion can be seen here:
https://lore.kernel.org/all/[email protected]/

As writing of this there is no known system doing configurations which require the PMIC to be in STBY state using Linux driver. Furthermore, ensuring the PMIC is and stays in the STBY state when configurations are done may not be trivial. Especially, not in a generic way in a regulator driver. This is likely to be system specific.

Hence it felt natural to upstream only partial support for now, while leaving a note about the RFC series with more complete support for those who may need it later.

The patches from 1 to 6 are just typical "add support for device X" stuff. They should provide very much usable driver for BD96801 and I hope they don't cause too many questions and can be merged when quality seems high enough :)

Supporting the ERRB IRQ (patches 9 and 10) requires the regmap IRQ change (patch 8) which further requires the IRQ domain change (patch 7).

Patches 7 and 8 may need more careful thinking. Thus, the ERRB IRQ support is added as a separate step, which can be merged later or even dropped if the irqdomain changes prove to be unacceptable.

Revision history still tries to summarize changes from the RFC for the reviewers.

Revision history:
v1 => v2:
- Add support for setting a name suffix for fwnode backed IRQ domains.
- Add support for setting a domain name suffix for regmap-IRQ.
- Add handling of ERRB IRQs.
- Small fixes based on feedback.

RFCv2 => v1:
- Drop ERRB IRQ from drivers (but not DT bindings).
- Drop configuration which requires STBY - state.
- Fix the register lock race by moving it from the regulator driver to the MFD driver.

RFCv1 => RFCv2:
- Tidying code based on feedback form Krzysztof Kozlowski and Lee Jones.
- Documented undocumented watchdog related DT properties.
- Added usage of the watchdog IRQ.
- Use irq_domain_update_bus_token() to work-around debugFS name collision for IRQ domains.

---

Matti Vaittinen (10):
dt-bindings: ROHM BD96801 PMIC regulators
dt-bindings: mfd: bd96801 PMIC core
mfd: support ROHM BD96801 PMIC core
regulator: bd96801: ROHM BD96801 PMIC regulators
watchdog: ROHM BD96801 PMIC WDG driver
MAINTAINERS: Add ROHM BD96801 'scalable PMIC' entries
irqdomain: Allow giving name suffix for domain
regmap: Allow setting IRQ domain name suffix
mfd: bd96801: Add ERRB IRQ
regulator: bd96801: Add ERRB IRQ

 .../bindings/mfd/rohm,bd96801-pmic.yaml       |  173 +++
 .../regulator/rohm,bd96801-regulator.yaml     |   63 ++
 MAINTAINERS                                   |    4 +
 drivers/base/regmap/regmap-irq.c              |   13 +-
 drivers/mfd/Kconfig                           |   13 +
 drivers/mfd/Makefile                          |    1 +
 drivers/mfd/rohm-bd96801.c                    |  488 ++++++++
 drivers/regulator/Kconfig                     |   12 +
 drivers/regulator/Makefile                    |    2 +
 drivers/regulator/bd96801-regulator.c         | 1008 +++++++++++++++++
 drivers/watchdog/Kconfig                      |   13 +
 drivers/watchdog/Makefile                     |    1 +
 drivers/watchdog/bd96801_wdt.c                |  416 +++++++
 include/linux/irqdomain.h                     |   28 +-
 include/linux/mfd/rohm-bd96801.h              |  215 ++++
 include/linux/mfd/rohm-generic.h              |    1 +
 include/linux/regmap.h                        |    4 +
 kernel/irq/irqdomain.c                        |   53 +-
 18 files changed, 2487 insertions(+), 21 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mfd/rohm,bd96801-pmic.yaml
 create mode 100644 Documentation/devicetree/bindings/regulator/rohm,bd96801-regulator.yaml
 create mode 100644 drivers/mfd/rohm-bd96801.c
 create mode 100644 drivers/regulator/bd96801-regulator.c
 create mode 100644 drivers/watchdog/bd96801_wdt.c
 create mode 100644 include/linux/mfd/rohm-bd96801.h

base-commit: 4cece764965020c22cff7665b18a012006359095

Signature · 14 lines
2.45.1


-- 
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 =] 
author maintainer
#1 lore raw

PATCH v2 1/10 dt-bindings: ROHM BD96801 PMIC regulators

ROHM BD96801 is a highly configurable automotive grade PMIC. Introduce DT bindings for the BD96801 regulators.

---
v1 => v2:
- use lowercase node names in example
- drop unnecessary '|' from description

RFCv2 => v1
- Drop regulator-name pattern requirement
- do not require regulator-name

---
 .../regulator/rohm,bd96801-regulator.yaml     | 63 +++++++++++++++++++
 1 file changed, 63 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/regulator/rohm,bd96801-regulator.yaml
Documentation/devicetree/bindings/regulator/rohm,bd96801-regulator.yaml new file +63 -0
new file mode 100644
index 000000000000..b3d2d7d583ce
@@ -0,0 +1,63 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/rohm,bd96801-regulator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ROHM BD96801 Power Management Integrated Circuit regulators
+
+maintainers:
+  - Matti Vaittinen <[email protected]>
+
+description:
+  This module is part of the ROHM BD96801 MFD device. For more details
+  see Documentation/devicetree/bindings/mfd/rohm,bd96801-pmic.yaml.
+
+  The regulator controller is represented as a sub-node of the PMIC node
+  on the device tree.
+
+  Regulator nodes should be named to buck_<number> and ldo_<number>.
+  The valid names for BD96801 regulator nodes are
+  buck1, buck2, buck3, buck4, ldo5, ldo6, ldo7
+
+patternProperties:
+  "^ldo[5-7]$":
+    type: object
+    description:
+      Properties for single LDO regulator.
+    $ref: regulator.yaml#
+
+    properties:
+      rohm,initial-voltage-microvolt:
+        description:
+          Initial voltage for regulator. Voltage can be tuned +/-150 mV from
+          this value. NOTE, This can be modified via I2C only when PMIC is in
+          STBY state.
+        minimum: 300000
+        maximum: 3300000
+
+    unevaluatedProperties: false
+
+  "^buck[1-4]$":
+    type: object
+    description:
+      Properties for single BUCK regulator.
+    $ref: regulator.yaml#
+
+    properties:
+      rohm,initial-voltage-microvolt:
+        description:
+          Initial voltage for regulator. Voltage can be tuned +/-150 mV from
+          this value. NOTE, This can be modified via I2C only when PMIC is in
+          STBY state.
+        minimum: 500000
+        maximum: 3300000
+
+      rohm,keep-on-stby:
+        description:
+          Keep the regulator powered when PMIC transitions to STBY state.
+        type: boolean
+
+    unevaluatedProperties: false
+
+additionalProperties: false
Signature · 14 lines
2.45.1


-- 
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 =] 
author maintainer
#3 lore raw

PATCH v2 2/10 dt-bindings: mfd: bd96801 PMIC core

In reply to Matti Vaittinen

ROHM BD96801 is a highly configurable automotive grade PMIC. Introduce DT bindings for the BD96801 core.

---
Revision history:
v1 => v2:
- use lowercase node names in example
- minor addition to ERRB use-cases

RFCv2 => v1
- minor cleaning
- add timeout-sec

RFCv1 => RFCv2:
- Document rohm,hw-timeout-ms
- Document rohm,wdg-action

---
 .../bindings/mfd/rohm,bd96801-pmic.yaml       | 173 ++++++++++++++++++
 1 file changed, 173 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/rohm,bd96801-pmic.yaml
Documentation/devicetree/bindings/mfd/rohm,bd96801-pmic.yaml new file +173 -0
new file mode 100644
index 000000000000..d381125a0a15
@@ -0,0 +1,173 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/rohm,bd96801-pmic.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ROHM BD96801 Scalable Power Management Integrated Circuit
+
+maintainers:
+  - Matti Vaittinen <[email protected]>
+
+description:
+  BD96801 is an automotive grade single-chip power management IC.
+  It integrates 4 buck converters and 3 LDOs with safety features like
+  over-/under voltage and over current detection and a watchdog.
+
+properties:
+  compatible:
+    const: rohm,bd96801
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    description:
+      The PMIC provides intb and errb IRQ lines. The errb IRQ line is used
+      for fatal IRQs which will cause the PMIC to shut down power outputs.
+      In many systems this will shut down the SoC contolling the PMIC and
+      connecting/handling the errb can be omitted. However, there are cases
+      where the SoC is not powered by the PMIC or has a short time backup
+      energy to handle shutdown of critical hardware. In that case it may be
+      useful to connect the errb and handle errb events.
+    minItems: 1
+    maxItems: 2
+
+  interrupt-names:
+    minItems: 1
+    items:
+      - enum: [intb, errb]
+      - const: errb
+
+  rohm,hw-timeout-ms:
+    description:
+      Watchdog timeout value(s). First walue is timeout limit. Second value is
+      optional value for 'too early' watchdog ping if window timeout mode is
+      to be used.
+    minItems: 1
+    maxItems: 2
+
+  rohm,wdg-action:
+    description:
+      Whether the watchdog failure must turn off the regulator power outputs or
+      just toggle the INTB line.
+    enum:
+      - prstb
+      - intb-only
+
+  timeout-sec:
+    maxItems: 2
+
+  regulators:
+    $ref: /schemas/regulator/rohm,bd96801-regulator.yaml
+    description:
+      List of child nodes that specify the regulators.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-names
+  - regulators
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/leds/common.h>
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+        pmic: pmic@60 {
+            reg = <0x60>;
+            compatible = "rohm,bd96801";
+            interrupt-parent = <&gpio1>;
+            interrupts = <29 IRQ_TYPE_LEVEL_LOW>, <6 IRQ_TYPE_LEVEL_LOW>;
+            interrupt-names = "intb", "errb";
+
+            regulators {
+                buck1 {
+                    regulator-name = "buck1";
+                    regulator-ramp-delay = <1250>;
+                    /* 0.5V min INITIAL - 150 mV tune */
+                    regulator-min-microvolt = <350000>;
+                    /* 3.3V + 150mV tune */
+                    regulator-max-microvolt = <3450000>;
+
+                    /* These can be set only when PMIC is in STBY */
+                    rohm,initial-voltage-microvolt = <500000>;
+                    regulator-ov-error-microvolt = <230000>;
+                    regulator-uv-error-microvolt = <230000>;
+                    regulator-temp-protection-kelvin = <1>;
+                    regulator-temp-warn-kelvin = <0>;
+                };
+                buck2 {
+                    regulator-name = "buck2";
+                    regulator-min-microvolt = <350000>;
+                    regulator-max-microvolt = <3450000>;
+
+                    rohm,initial-voltage-microvolt = <3000000>;
+                    regulator-ov-error-microvolt = <18000>;
+                    regulator-uv-error-microvolt = <18000>;
+                    regulator-temp-protection-kelvin = <1>;
+                    regulator-temp-warn-kelvin = <1>;
+                };
+                buck3 {
+                    regulator-name = "buck3";
+                    regulator-min-microvolt = <350000>;
+                    regulator-max-microvolt = <3450000>;
+
+                    rohm,initial-voltage-microvolt = <600000>;
+                    regulator-ov-warn-microvolt = <18000>;
+                    regulator-uv-warn-microvolt = <18000>;
+                    regulator-temp-protection-kelvin = <1>;
+                    regulator-temp-error-kelvin = <0>;
+                };
+                buck4 {
+                    regulator-name = "buck4";
+                    regulator-min-microvolt = <350000>;
+                    regulator-max-microvolt = <3450000>;
+
+                    rohm,initial-voltage-microvolt = <600000>;
+                    regulator-ov-warn-microvolt = <18000>;
+                    regulator-uv-warn-microvolt = <18000>;
+                    regulator-temp-protection-kelvin = <1>;
+                    regulator-temp-error-kelvin = <0>;
+                };
+                ldo5 {
+                    regulator-name = "ldo5";
+                    regulator-min-microvolt = <300000>;
+                    regulator-max-microvolt = <3300000>;
+
+                    rohm,initial-voltage-microvolt = <500000>;
+                    regulator-ov-error-microvolt = <36000>;
+                    regulator-uv-error-microvolt = <34000>;
+                    regulator-temp-protection-kelvin = <1>;
+                    regulator-temp-warn-kelvin = <0>;
+                };
+                ldo6 {
+                    regulator-name = "ldo6";
+                    regulator-min-microvolt = <300000>;
+                    regulator-max-microvolt = <3300000>;
+
+                    rohm,initial-voltage-microvolt = <300000>;
+                    regulator-ov-error-microvolt = <36000>;
+                    regulator-uv-error-microvolt = <34000>;
+                    regulator-temp-protection-kelvin = <1>;
+                    regulator-temp-warn-kelvin = <0>;
+                };
+                ldo7 {
+                    regulator-name = "ldo7";
+                    regulator-min-microvolt = <300000>;
+                    regulator-max-microvolt = <3300000>;
+
+                    rohm,initial-voltage-microvolt = <500000>;
+                    regulator-ov-error-microvolt = <36000>;
+                    regulator-uv-error-microvolt = <34000>;
+                    regulator-temp-protection-kelvin = <1>;
+                    regulator-temp-warn-kelvin = <0>;
+                };
+            };
+        };
+    };
Signature · 14 lines
2.45.1


-- 
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 =] 
author maintainer
#5 lore raw

PATCH v2 3/10 mfd: support ROHM BD96801 PMIC core

In reply to Matti Vaittinen

The ROHM BD96801 PMIC is highly customizable automotive grade PMIC which integrates regulator and watchdog funtionalities.

Provide INTB IRQ and register accesses for regulator/watchdog drivers.

---
Changelog:
v1 => v2:
- Drop unused enum
- Improve error prints
- improve comments

RFCv2 => v1:
- drop ERRB interrupts (for now)
- bd96801: Unlock registers in core driver

Changelog: RFCv1 => RFCv2
- Work-around the IRQ domain name conflict
- Add watchdog IRQ
- Various styling fixes based on review by Lee

---
 drivers/mfd/Kconfig              |  13 ++
 drivers/mfd/Makefile             |   1 +
 drivers/mfd/rohm-bd96801.c       | 273 +++++++++++++++++++++++++++++++
 include/linux/mfd/rohm-bd96801.h | 215 ++++++++++++++++++++++++
 include/linux/mfd/rohm-generic.h |   1 +
 5 files changed, 503 insertions(+)
 create mode 100644 drivers/mfd/rohm-bd96801.c
 create mode 100644 include/linux/mfd/rohm-bd96801.h
drivers/mfd/Kconfig +13 -0
index 4b023ee229cf..9e874453d94d 100644
@@ -2089,6 +2089,19 @@ config MFD_ROHM_BD957XMUF
 	  BD9573MUF Power Management ICs. BD9576 and BD9573 are primarily
 	  designed to be used to power R-Car series processors.
 
+config MFD_ROHM_BD96801
+	tristate "ROHM BD96801 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 BD96801 Power
+	  Management IC. The ROHM BD96801 is a highly scalable Power Management
+	  IC for industrial and automotive use. The BD96801 can be used as a
+	  master PMIC in a chained PMIC solution with suitable companion PMICs.
+
 config MFD_STM32_LPTIMER
 	tristate "Support for STM32 Low-Power Timer"
 	depends on (ARCH_STM32 && OF) || COMPILE_TEST
drivers/mfd/Makefile +1 -0
index c66f07edcd0e..e792892d4a8b 100644
@@ -264,6 +264,7 @@ obj-$(CONFIG_RAVE_SP_CORE)	+= rave-sp.o
 obj-$(CONFIG_MFD_ROHM_BD71828)	+= rohm-bd71828.o
 obj-$(CONFIG_MFD_ROHM_BD718XX)	+= rohm-bd718x7.o
 obj-$(CONFIG_MFD_ROHM_BD957XMUF)	+= rohm-bd9576.o
+obj-$(CONFIG_MFD_ROHM_BD96801)	+= rohm-bd96801.o
 obj-$(CONFIG_MFD_STMFX) 	+= stmfx.o
 obj-$(CONFIG_MFD_KHADAS_MCU) 	+= khadas-mcu.o
 obj-$(CONFIG_MFD_ACER_A500_EC)	+= acer-ec-a500.o
drivers/mfd/rohm-bd96801.c new file +273 -0

273 lines not on this page · raw message

include/linux/mfd/rohm-bd96801.h new file +215 -0

215 lines not on this page · raw message

include/linux/mfd/rohm-generic.h +1 -0
index 4eeb22876bad..e7d4e6afe388 100644
@@ -16,6 +16,7 @@ enum rohm_chip_type {
 	ROHM_CHIP_TYPE_BD71828,
 	ROHM_CHIP_TYPE_BD71837,
 	ROHM_CHIP_TYPE_BD71847,
+	ROHM_CHIP_TYPE_BD96801,
 	ROHM_CHIP_TYPE_AMOUNT
 };
 
Signature · 14 lines
2.45.1


-- 
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 =] 
author maintainer
#6 lore raw

PATCH v2 4/10 regulator: bd96801: ROHM BD96801 PMIC regulators

In reply to Matti Vaittinen

The ROHM BD96801 "Scalable PMIC" is an automotive grade PMIC which can scale to different applications by allowing chaining of PMICs. The PMIC also supports various protection features which can be configured either to fire IRQs - or to shut down power outputs when failure is detected.

The driver implements basic voltage control and sending error notifications.

NOTE:
The driver does not support doing configuration which require the PMIC to be in STBY state. The omitted feature set includes setting safety limit values, changing LDO voltages and controlling enable state for some regulators.
Also, the ERRB IRQ is not handled.

---
Revision history:
v1 => v2:
- regulator: bd96801: lowercase DT node names
- split intb registration to own function

RFCv2 => v1:
- Drop STBY mode configurations
- Drop ERRB IRQs
- drop PMIC register unlock (moved to MFD to prevent races)

RFCv1 => RFCv2:
- Use devm_kcalloc() instead of devm_kzalloc() where appropriate
- Use devm_kmemdup()
- Add MODULE_DEVICE_TABLE
- drop MODULE_ALIAS

---
 drivers/regulator/Kconfig             |  12 +
 drivers/regulator/Makefile            |   2 +
 drivers/regulator/bd96801-regulator.c | 908 ++++++++++++++++++++++++++
 3 files changed, 922 insertions(+)
 create mode 100644 drivers/regulator/bd96801-regulator.c
drivers/regulator/Kconfig +12 -0
index 7db0a29b5b8d..2e8187a92952 100644
@@ -268,6 +268,18 @@ config REGULATOR_BD957XMUF
 	  This driver can also be built as a module. If so, the module
 	  will be called bd9576-regulator.
 
+config REGULATOR_BD96801
+	tristate "ROHM BD96801 Power Regulator"
+	depends on MFD_ROHM_BD96801
+	select REGULATOR_ROHM
+	help
+	  This driver supports voltage regulators on ROHM BD96801 PMIC.
+	  This will enable support for the software controllable buck
+	  and LDO regulators.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called bd96801-regulator.
+
 config REGULATOR_CPCAP
 	tristate "Motorola CPCAP regulator"
 	depends on MFD_CPCAP
drivers/regulator/Makefile +2 -0
index 46fb569e6be8..ae8896e879d5 100644
@@ -37,6 +37,8 @@ obj-$(CONFIG_REGULATOR_BD718XX) += bd718x7-regulator.o
 obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o
 obj-$(CONFIG_REGULATOR_BD957XMUF) += bd9576-regulator.o
 obj-$(CONFIG_REGULATOR_DA903X)	+= da903x-regulator.o
+obj-$(CONFIG_REGULATOR_BD96801) += bd96801-regulator.o
+obj-$(CONFIG_REGULATOR_DA903X)	+= da903x.o
 obj-$(CONFIG_REGULATOR_DA9052)	+= da9052-regulator.o
 obj-$(CONFIG_REGULATOR_DA9055)	+= da9055-regulator.o
 obj-$(CONFIG_REGULATOR_DA9062)	+= da9062-regulator.o
drivers/regulator/bd96801-regulator.c new file +908 -0

908 lines not on this page · raw message

Signature · 14 lines
2.45.1


-- 
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 =] 
author maintainer
#8 lore raw

PATCH v2 5/10 watchdog: ROHM BD96801 PMIC WDG driver

In reply to Matti Vaittinen

Introduce driver for WDG block on ROHM BD96801 scalable PMIC.

This driver only supports watchdog with I2C feeding and delayed response detection. Whether the watchdog toggles PRSTB pin or just causes an interrupt can be configured via device-tree.

The BD96801 PMIC HW supports also window watchdog (too early feeding detection) and Q&A mode. These are not supported by this driver.

---
Revision history:
v1 => v2:
- Drop the forward declaration for emergency_reboot()
- Typofixes
- Do error checks before assignments in find_closest_fast()
- Improve prints for unsupported (HW) timeout values
- Use FIELD_GET() and FIELD_PREP()
- Use error severity when unsupported Q&A WDG mode is tried to be used.
- Minor styling fixes

RFCv2 => v1:
- Fix watchdog time-outs to match DS4
- Fix target timeout overflow
- Improve dbg prints

RFCv1 => RFCv2:
- remove always running
- add IRQ handling
- call emergency_restart()
- drop MODULE_ALIAS and add MODULE_DEVICE_TABLE

watchdog: bd96801: styling fix

---
 drivers/watchdog/Kconfig       |  13 ++
 drivers/watchdog/Makefile      |   1 +
 drivers/watchdog/bd96801_wdt.c | 416 +++++++++++++++++++++++++++++++++
 3 files changed, 430 insertions(+)
 create mode 100644 drivers/watchdog/bd96801_wdt.c
drivers/watchdog/Kconfig +13 -0
index 6bee137cfbe0..d97e735e1faa 100644
@@ -181,6 +181,19 @@ config BD957XMUF_WATCHDOG
 	  watchdog. Alternatively say M to compile the driver as a module,
 	  which will be called bd9576_wdt.
 
+config BD96801_WATCHDOG
+	tristate "ROHM BD96801 PMIC Watchdog"
+	depends on MFD_ROHM_BD96801
+	select WATCHDOG_CORE
+	help
+	  Support for the watchdog in the ROHM BD96801 PMIC. Watchdog can be
+	  configured to only generate IRQ or to trigger system reset via reset
+	  pin.
+
+	  Say Y here to include support for the ROHM BD96801 watchdog.
+	  Alternatively say M to compile the driver as a module,
+	  which will be called bd96801_wdt.
+
 config CROS_EC_WATCHDOG
 	tristate "ChromeOS EC-based watchdog"
 	select WATCHDOG_CORE
drivers/watchdog/Makefile +1 -0
index 3710c218f05e..31bc94436c81 100644
@@ -217,6 +217,7 @@ obj-$(CONFIG_XEN_WDT) += xen_wdt.o
 
 # Architecture Independent
 obj-$(CONFIG_BD957XMUF_WATCHDOG) += bd9576_wdt.o
+obj-$(CONFIG_BD96801_WATCHDOG) += bd96801_wdt.o
 obj-$(CONFIG_CROS_EC_WATCHDOG) += cros_ec_wdt.o
 obj-$(CONFIG_DA9052_WATCHDOG) += da9052_wdt.o
 obj-$(CONFIG_DA9055_WATCHDOG) += da9055_wdt.o
drivers/watchdog/bd96801_wdt.c new file +416 -0

416 lines not on this page · raw message

Signature · 14 lines
2.45.1


-- 
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 =] 
author maintainer
#9 lore raw

PATCH v2 6/10 MAINTAINERS: Add ROHM BD96801 'scalable PMIC' entries

In reply to Matti Vaittinen

Add maintainer entries for ROHM BD96801 a.k.a 'scalable PMIC' drivers to be reviewed by ROHM people.

---
 MAINTAINERS | 4 ++++
 1 file changed, 4 insertions(+)
MAINTAINERS +4 -0
index aa3b947fb080..da68144d51ae 100644
@@ -19111,17 +19111,21 @@ F:	drivers/gpio/gpio-bd71828.c
 F:	drivers/mfd/rohm-bd71828.c
 F:	drivers/mfd/rohm-bd718x7.c
 F:	drivers/mfd/rohm-bd9576.c
+F:	drivers/mfd/rohm-bd96801.c
 F:	drivers/regulator/bd71815-regulator.c
 F:	drivers/regulator/bd71828-regulator.c
 F:	drivers/regulator/bd718x7-regulator.c
 F:	drivers/regulator/bd9576-regulator.c
+F:	drivers/regulator/bd96801-regulator.c
 F:	drivers/regulator/rohm-regulator.c
 F:	drivers/rtc/rtc-bd70528.c
 F:	drivers/watchdog/bd9576_wdt.c
+F:	drivers/watchdog/bd96801_wdt.c
 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-bd957x.h
+F:	include/linux/mfd/rohm-bd96801.h
 F:	include/linux/mfd/rohm-generic.h
 F:	include/linux/mfd/rohm-shared.h
 
Signature · 14 lines
2.45.1


-- 
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 =] 
author maintainer
#10 lore raw

PATCH v2 7/10 irqdomain: Allow giving name suffix for domain

In reply to Matti Vaittinen

When multiple IRQ domains are created from same device-tree node they will get same name based on the device-tree path. This will cause a naming collision in debugFS when IRQ domain specific entries are created.

One use-case for being able to create multiple IRQ domains / single device node is using regmap-IRQ controller code for devices which provide more than one physical IRQ. It seems much cleaner to instantiate own regmap-IRQ controller for each parent IRQ because most of the regmap IRQ properties are really specific to parent IRQ.

Allow giving a suffix to IRQ domain name to avoid naming collisions.

---
Some devices which could use this are ROHM's BD96801, BD96802 and BD96811 PMICs. BD96801 is being upstreamed, others are on my TODO list - but I believe this may be beneficial to any other devices as well. Especially for those which provide IRQs that are clearly different form each other.

Some discussion about this can be found from:
https://lore.kernel.org/all/[email protected]/

---
 include/linux/irqdomain.h | 28 ++++++++++++++++-----
 kernel/irq/irqdomain.c    | 53 +++++++++++++++++++++++++++++++--------
 2 files changed, 65 insertions(+), 16 deletions(-)
include/linux/irqdomain.h +22 -6
index 21ecf582a0fe..7b1123fbd453 100644
@@ -260,7 +260,7 @@ void irq_domain_free_fwnode(struct fwnode_handle *fwnode);
 struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, unsigned int size,
 				    irq_hw_number_t hwirq_max, int direct_max,
 				    const struct irq_domain_ops *ops,
-				    void *host_data);
+				    void *host_data, const char *name_suffix);
 struct irq_domain *irq_domain_create_simple(struct fwnode_handle *fwnode,
 					    unsigned int size,
 					    unsigned int first_irq,
@@ -272,6 +272,12 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
 					 irq_hw_number_t first_hwirq,
 					 const struct irq_domain_ops *ops,
 					 void *host_data);
+struct irq_domain *irq_domain_create_legacy_named(struct fwnode_handle *fwnode,
+					    unsigned int size,
+					    unsigned int first_irq,
+					    irq_hw_number_t first_hwirq,
+					    const struct irq_domain_ops *ops,
+					    void *host_data, const char *name_suffix);
 struct irq_domain *irq_domain_create_legacy(struct fwnode_handle *fwnode,
 					    unsigned int size,
 					    unsigned int first_irq,
@@ -350,7 +356,8 @@ static inline struct irq_domain *irq_domain_add_linear(struct device_node *of_no
 					 const struct irq_domain_ops *ops,
 					 void *host_data)
 {
-	return __irq_domain_add(of_node_to_fwnode(of_node), size, size, 0, ops, host_data);
+	return __irq_domain_add(of_node_to_fwnode(of_node), size, size, 0, ops,
+				host_data, NULL);
 }
 
 #ifdef CONFIG_IRQ_DOMAIN_NOMAP
@@ -359,7 +366,8 @@ static inline struct irq_domain *irq_domain_add_nomap(struct device_node *of_nod
 					 const struct irq_domain_ops *ops,
 					 void *host_data)
 {
-	return __irq_domain_add(of_node_to_fwnode(of_node), 0, max_irq, max_irq, ops, host_data);
+	return __irq_domain_add(of_node_to_fwnode(of_node), 0, max_irq, max_irq,
+						  ops, host_data, NULL);
 }
 
 extern unsigned int irq_create_direct_mapping(struct irq_domain *host);
@@ -369,7 +377,7 @@ static inline struct irq_domain *irq_domain_add_tree(struct device_node *of_node
 					 const struct irq_domain_ops *ops,
 					 void *host_data)
 {
-	return __irq_domain_add(of_node_to_fwnode(of_node), 0, ~0, 0, ops, host_data);
+	return __irq_domain_add(of_node_to_fwnode(of_node), 0, ~0, 0, ops, host_data, NULL);
 }
 
 static inline struct irq_domain *irq_domain_create_linear(struct fwnode_handle *fwnode,
@@ -377,14 +385,22 @@ static inline struct irq_domain *irq_domain_create_linear(struct fwnode_handle *
 					 const struct irq_domain_ops *ops,
 					 void *host_data)
 {
-	return __irq_domain_add(fwnode, size, size, 0, ops, host_data);
+	return __irq_domain_add(fwnode, size, size, 0, ops, host_data, NULL);
+}
+
+static inline struct irq_domain *irq_domain_create_linear_named(struct fwnode_handle *fwnode,
+					 unsigned int size,
+					 const struct irq_domain_ops *ops,
+					 void *host_data, const char *name_suffix)
+{
+	return __irq_domain_add(fwnode, size, size, 0, ops, host_data, name_suffix);
 }
 
 static inline struct irq_domain *irq_domain_create_tree(struct fwnode_handle *fwnode,
 					 const struct irq_domain_ops *ops,
 					 void *host_data)
 {
-	return __irq_domain_add(fwnode, 0, ~0, 0, ops, host_data);
+	return __irq_domain_add(fwnode, 0, ~0, 0, ops, host_data, NULL);
 }
 
 extern void irq_domain_remove(struct irq_domain *host);
kernel/irq/irqdomain.c +43 -10

118 lines not on this page · raw message

Signature · 14 lines
2.45.1


-- 
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 =] 
author maintainer
#17 lore raw

PATCH v2 8/10 regmap: Allow setting IRQ domain name suffix

In reply to Matti Vaittinen

When multiple IRQ domains are created from same device-tree node they will get same name based on the device-tree path. This will cause a naming collision in debugFS when IRQ domain specific entries are created.

The regmap-IRQ creates per instance IRQ domains. This will lead to the domain name conflict when a device which provides more than one physical IRQ uses the regmap-IRQ.

Add support for specifying an IRQ domain name suffix when creating a regmap-IRQ controller.

---
 drivers/base/regmap/regmap-irq.c | 13 ++++++++-----
 include/linux/regmap.h           |  4 ++++
 2 files changed, 12 insertions(+), 5 deletions(-)
drivers/base/regmap/regmap-irq.c +8 -5
index 45fd13ef13fc..e86964a9843b 100644
@@ -857,12 +857,15 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
 	}
 
 	if (irq_base)
-		d->domain = irq_domain_create_legacy(fwnode, chip->num_irqs,
-						     irq_base, 0,
-						     &regmap_domain_ops, d);
+		d->domain = irq_domain_create_legacy_named(fwnode,
+						chip->num_irqs,	irq_base, 0,
+						&regmap_domain_ops, d,
+						chip->domain_suffix);
 	else
-		d->domain = irq_domain_create_linear(fwnode, chip->num_irqs,
-						     &regmap_domain_ops, d);
+		d->domain = irq_domain_create_linear_named(fwnode,
+						chip->num_irqs, &regmap_domain_ops,
+						d, chip->domain_suffix);
+
 	if (!d->domain) {
 		dev_err(map->dev, "Failed to create IRQ domain\n");
 		ret = -ENOMEM;
include/linux/regmap.h +4 -0
index b743241cfb7c..9df971986abb 100644
@@ -1518,6 +1518,9 @@ struct regmap_irq_chip_data;
  * struct regmap_irq_chip - Description of a generic regmap irq_chip.
  *
  * @name:        Descriptive name for IRQ controller.
+ * @domain_suffix: Name suffix to be appended to end of IRQ domain name. Needed
+ *		   when multiple regmap-IRQ controllers are created from same
+ *		   device.
  *
  * @main_status: Base main status register address. For chips which have
  *		 interrupts arranged in separate sub-irq blocks with own IRQ
@@ -1603,6 +1606,7 @@ struct regmap_irq_chip_data;
  */
 struct regmap_irq_chip {
 	const char *name;
+	const char *domain_suffix;
 
 	unsigned int main_status;
 	unsigned int num_main_status_bits;
Signature · 14 lines
2.45.1


-- 
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 =] 
author maintainer
#18 lore raw

PATCH v2 9/10 mfd: bd96801: Add ERRB IRQ

In reply to Matti Vaittinen

The ROHM BD96801 "scalable PMIC" provides two physical IRQs. The ERRB handling can in many cases be omitted because it is used to inform fatal IRQs, which usually kill the power from the SOC.

There may however be use-cases where the SOC has a 'back-up' emergency power source which allows some very short time of operation to try to gracefully shut down sensitive hardware. Furthermore, it is possible the processor controlling the PMIC is not powered by the PMIC. In such cases handling the ERRB IRQs may be beneficial.

Add support for ERRB IRQs.

---
Revision history:
v1 => v2:
- New patch

---
 drivers/mfd/rohm-bd96801.c | 291 ++++++++++++++++++++++++++++++++-----
 1 file changed, 253 insertions(+), 38 deletions(-)
drivers/mfd/rohm-bd96801.c +253 -38
index 1c2a9591be7b..b7f073318873 100644
@@ -5,13 +5,9 @@
  * ROHM BD96801 PMIC driver
  *
  * This version of the "BD86801 scalable PMIC"'s driver supports only very
- * basic set of the PMIC features. Most notably, there is no support for
- * the ERRB interrupt and the configurations which should be done when the
- * PMIC is in STBY mode.
- *
- * Supporting the ERRB interrupt would require dropping the regmap-IRQ
- * usage or working around (or accepting a presense of) a naming conflict
- * in debugFS IRQs.
+ * basic set of the PMIC features.
+ * Most notably, there is no support for the configurations which should
+ * be done when the PMIC is in STBY mode.
  *
  * Being able to reliably do the configurations like changing the
  * regulator safety limits (like limits for the over/under -voltages, over
@@ -23,16 +19,14 @@
  * be the need to configure these safety limits. Hence it's not simple to
  * come up with a generic solution.
  *
- * Users who require the ERRB handling and STBY state configurations can
- * have a look at the original RFC:
+ * Users who require the STBY state configurations can  have a look at the
+ * original RFC:
  * https://lore.kernel.org/all/[email protected]/
- * which implements a workaround to debugFS naming conflict and some of
- * the safety limit configurations - but leaves the state change handling
- * and synchronization to be implemented.
+ * which implements some of the safety limit configurations - but leaves the
+ * state change handling and synchronization to be implemented.
  *
  * It would be great to hear (and receive a patch!) if you implement the
- * STBY configuration support or a proper fix to the debugFS naming
- * conflict in your downstream driver ;)
+ * STBY configuration support or a proper fix in your downstream driver ;)
  */
 
 #include <linux/i2c.h>
@@ -45,6 +39,65 @@
 
 #include <linux/mfd/rohm-bd96801.h>
 #include <linux/mfd/rohm-generic.h>
+
+static const struct resource regulator_errb_irqs[] = {
+	DEFINE_RES_IRQ_NAMED(BD96801_OTP_ERR_STAT, "bd96801-otp-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_DBIST_ERR_STAT, "bd96801-dbist-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_EEP_ERR_STAT, "bd96801-eep-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_ABIST_ERR_STAT, "bd96801-abist-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_PRSTB_ERR_STAT, "bd96801-prstb-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_DRMOS1_ERR_STAT, "bd96801-drmoserr1"),
+	DEFINE_RES_IRQ_NAMED(BD96801_DRMOS2_ERR_STAT, "bd96801-drmoserr2"),
+	DEFINE_RES_IRQ_NAMED(BD96801_SLAVE_ERR_STAT, "bd96801-slave-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_VREF_ERR_STAT, "bd96801-vref-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_TSD_ERR_STAT, "bd96801-tsd"),
+	DEFINE_RES_IRQ_NAMED(BD96801_UVLO_ERR_STAT, "bd96801-uvlo-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_OVLO_ERR_STAT, "bd96801-ovlo-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_OSC_ERR_STAT, "bd96801-osc-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_PON_ERR_STAT, "bd96801-pon-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_POFF_ERR_STAT, "bd96801-poff-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_CMD_SHDN_ERR_STAT, "bd96801-cmd-shdn-err"),
+
+	DEFINE_RES_IRQ_NAMED(BD96801_INT_PRSTB_WDT_ERR, "bd96801-prstb-wdt-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_INT_CHIP_IF_ERR, "bd96801-chip-if-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_INT_SHDN_ERR_STAT, "bd96801-int-shdn-err"),
+
+	DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_PVIN_ERR_STAT, "bd96801-buck1-pvin-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OVP_ERR_STAT, "bd96801-buck1-ovp-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_UVP_ERR_STAT, "bd96801-buck1-uvp-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_SHDN_ERR_STAT, "bd96801-buck1-shdn-err"),
+
+	DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_PVIN_ERR_STAT, "bd96801-buck2-pvin-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OVP_ERR_STAT, "bd96801-buck2-ovp-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_UVP_ERR_STAT, "bd96801-buck2-uvp-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_SHDN_ERR_STAT, "bd96801-buck2-shdn-err"),
+
+	DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_PVIN_ERR_STAT, "bd96801-buck3-pvin-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OVP_ERR_STAT, "bd96801-buck3-ovp-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_UVP_ERR_STAT, "bd96801-buck3-uvp-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_SHDN_ERR_STAT, "bd96801-buck3-shdn-err"),
+
+	DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_PVIN_ERR_STAT, "bd96801-buck4-pvin-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OVP_ERR_STAT, "bd96801-buck4-ovp-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_UVP_ERR_STAT, "bd96801-buck4-uvp-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_SHDN_ERR_STAT, "bd96801-buck4-shdn-err"),
+
+	DEFINE_RES_IRQ_NAMED(BD96801_LDO5_PVIN_ERR_STAT, "bd96801-ldo5-pvin-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_LDO5_OVP_ERR_STAT, "bd96801-ldo5-ovp-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_LDO5_UVP_ERR_STAT, "bd96801-ldo5-uvp-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_LDO5_SHDN_ERR_STAT, "bd96801-ldo5-shdn-err"),
+
+	DEFINE_RES_IRQ_NAMED(BD96801_LDO6_PVIN_ERR_STAT, "bd96801-ldo6-pvin-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_LDO6_OVP_ERR_STAT, "bd96801-ldo6-ovp-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_LDO6_UVP_ERR_STAT, "bd96801-ldo6-uvp-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_LDO6_SHDN_ERR_STAT, "bd96801-ldo6-shdn-err"),
+
+	DEFINE_RES_IRQ_NAMED(BD96801_LDO7_PVIN_ERR_STAT, "bd96801-ldo7-pvin-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_LDO7_OVP_ERR_STAT, "bd96801-ldo7-ovp-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_LDO7_UVP_ERR_STAT, "bd96801-ldo7-uvp-err"),
+	DEFINE_RES_IRQ_NAMED(BD96801_LDO7_SHDN_ERR_STAT, "bd96801-ldo7-shdn-err"),
+};
+
 static const struct resource regulator_intb_irqs[] = {
 	DEFINE_RES_IRQ_NAMED(BD96801_TW_STAT, "bd96801-core-thermal"),
 
@@ -89,20 +142,14 @@ static const struct resource regulator_intb_irqs[] = {
 	DEFINE_RES_IRQ_NAMED(BD96801_LDO7_UVD_STAT, "bd96801-ldo7-undervolt"),
 };
 
-static const struct resource wdg_intb_irqs[] = {
-	DEFINE_RES_IRQ_NAMED(BD96801_WDT_ERR_STAT, "bd96801-wdg"),
+enum {
+	WDG_CELL = 0,
+	REGULATOR_CELL,
 };
 
 static struct mfd_cell bd96801_mfd_cells[] = {
-	{
-		.name = "bd96801-wdt",
-		.resources = wdg_intb_irqs,
-		.num_resources = ARRAY_SIZE(wdg_intb_irqs),
-	}, {
-		.name = "bd96801-pmic",
-		.resources = regulator_intb_irqs,
-		.num_resources = ARRAY_SIZE(regulator_intb_irqs),
-	},
+	[WDG_CELL] = { .name = "bd96801-wdt", },
+	[REGULATOR_CELL] = { .name = "bd96801-pmic", },
 };
 
 static const struct regmap_range bd96801_volatile_ranges[] = {
@@ -127,6 +174,91 @@ static const struct regmap_access_table volatile_regs = {
 	.n_yes_ranges = ARRAY_SIZE(bd96801_volatile_ranges),
 };
 
+/*
+ * For ERRB we need main register bit mapping as bit(0) indicates active IRQ
+ * in one of the first 3 sub IRQ registers, For INTB we can use default 1 to 1
+ * mapping.
+ */
+static unsigned int bit0_offsets[] = {0, 1, 2};	/* System stat, 3 registers */
+static unsigned int bit1_offsets[] = {3};	/* Buck 1 stat */
+static unsigned int bit2_offsets[] = {4};	/* Buck 2 stat */
+static unsigned int bit3_offsets[] = {5};	/* Buck 3 stat */
+static unsigned int bit4_offsets[] = {6};	/* Buck 4 stat */
+static unsigned int bit5_offsets[] = {7};	/* LDO 5 stat */
+static unsigned int bit6_offsets[] = {8};	/* LDO 6 stat */
+static unsigned int bit7_offsets[] = {9};	/* LDO 7 stat */
+
+static struct regmap_irq_sub_irq_map errb_sub_irq_offsets[] = {
+	REGMAP_IRQ_MAIN_REG_OFFSET(bit0_offsets),
+	REGMAP_IRQ_MAIN_REG_OFFSET(bit1_offsets),
+	REGMAP_IRQ_MAIN_REG_OFFSET(bit2_offsets),
+	REGMAP_IRQ_MAIN_REG_OFFSET(bit3_offsets),
+	REGMAP_IRQ_MAIN_REG_OFFSET(bit4_offsets),
+	REGMAP_IRQ_MAIN_REG_OFFSET(bit5_offsets),
+	REGMAP_IRQ_MAIN_REG_OFFSET(bit6_offsets),
+	REGMAP_IRQ_MAIN_REG_OFFSET(bit7_offsets),
+};
+
+static const struct regmap_irq bd96801_errb_irqs[] = {
+	/* Reg 0x52 Fatal ERRB1 */
+	REGMAP_IRQ_REG(BD96801_OTP_ERR_STAT, 0, BD96801_OTP_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_DBIST_ERR_STAT, 0, BD96801_DBIST_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_EEP_ERR_STAT, 0, BD96801_EEP_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_ABIST_ERR_STAT, 0, BD96801_ABIST_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_PRSTB_ERR_STAT, 0, BD96801_PRSTB_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_DRMOS1_ERR_STAT, 0, BD96801_DRMOS1_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_DRMOS2_ERR_STAT, 0, BD96801_DRMOS2_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_SLAVE_ERR_STAT, 0, BD96801_SLAVE_ERR_MASK),
+	/* 0x53 Fatal ERRB2 */
+	REGMAP_IRQ_REG(BD96801_VREF_ERR_STAT, 1, BD96801_VREF_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_TSD_ERR_STAT, 1, BD96801_TSD_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_UVLO_ERR_STAT, 1, BD96801_UVLO_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_OVLO_ERR_STAT, 1, BD96801_OVLO_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_OSC_ERR_STAT, 1, BD96801_OSC_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_PON_ERR_STAT, 1, BD96801_PON_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_POFF_ERR_STAT, 1, BD96801_POFF_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_CMD_SHDN_ERR_STAT, 1, BD96801_CMD_SHDN_ERR_MASK),
+	/* 0x54 Fatal INTB shadowed to ERRB */
+	REGMAP_IRQ_REG(BD96801_INT_PRSTB_WDT_ERR, 2, BD96801_INT_PRSTB_WDT_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_INT_CHIP_IF_ERR, 2, BD96801_INT_CHIP_IF_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_INT_SHDN_ERR_STAT, 2, BD96801_INT_SHDN_ERR_MASK),
+	/* Reg 0x55 BUCK1 ERR IRQs */
+	REGMAP_IRQ_REG(BD96801_BUCK1_PVIN_ERR_STAT, 3, BD96801_OUT_PVIN_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_BUCK1_OVP_ERR_STAT, 3, BD96801_OUT_OVP_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_BUCK1_UVP_ERR_STAT, 3, BD96801_OUT_UVP_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_BUCK1_SHDN_ERR_STAT, 3, BD96801_OUT_SHDN_ERR_MASK),
+	/* Reg 0x56 BUCK2 ERR IRQs */
+	REGMAP_IRQ_REG(BD96801_BUCK2_PVIN_ERR_STAT, 4, BD96801_OUT_PVIN_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_BUCK2_OVP_ERR_STAT, 4, BD96801_OUT_OVP_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_BUCK2_UVP_ERR_STAT, 4, BD96801_OUT_UVP_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_BUCK2_SHDN_ERR_STAT, 4, BD96801_OUT_SHDN_ERR_MASK),
+	/* Reg 0x57 BUCK3 ERR IRQs */
+	REGMAP_IRQ_REG(BD96801_BUCK3_PVIN_ERR_STAT, 5, BD96801_OUT_PVIN_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_BUCK3_OVP_ERR_STAT, 5, BD96801_OUT_OVP_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_BUCK3_UVP_ERR_STAT, 5, BD96801_OUT_UVP_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_BUCK3_SHDN_ERR_STAT, 5, BD96801_OUT_SHDN_ERR_MASK),
+	/* Reg 0x58 BUCK4 ERR IRQs */
+	REGMAP_IRQ_REG(BD96801_BUCK4_PVIN_ERR_STAT, 6, BD96801_OUT_PVIN_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_BUCK4_OVP_ERR_STAT, 6, BD96801_OUT_OVP_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_BUCK4_UVP_ERR_STAT, 6, BD96801_OUT_UVP_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_BUCK4_SHDN_ERR_STAT, 6, BD96801_OUT_SHDN_ERR_MASK),
+	/* Reg 0x59 LDO5 ERR IRQs */
+	REGMAP_IRQ_REG(BD96801_LDO5_PVIN_ERR_STAT, 7, BD96801_OUT_PVIN_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_LDO5_OVP_ERR_STAT, 7, BD96801_OUT_OVP_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_LDO5_UVP_ERR_STAT, 7, BD96801_OUT_UVP_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_LDO5_SHDN_ERR_STAT, 7, BD96801_OUT_SHDN_ERR_MASK),
+	/* Reg 0x5a LDO6 ERR IRQs */
+	REGMAP_IRQ_REG(BD96801_LDO6_PVIN_ERR_STAT, 8, BD96801_OUT_PVIN_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_LDO6_OVP_ERR_STAT, 8, BD96801_OUT_OVP_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_LDO6_UVP_ERR_STAT, 8, BD96801_OUT_UVP_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_LDO6_SHDN_ERR_STAT, 8, BD96801_OUT_SHDN_ERR_MASK),
+	/* Reg 0x5b LDO7 ERR IRQs */
+	REGMAP_IRQ_REG(BD96801_LDO7_PVIN_ERR_STAT, 9, BD96801_OUT_PVIN_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_LDO7_OVP_ERR_STAT, 9, BD96801_OUT_OVP_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_LDO7_UVP_ERR_STAT, 9, BD96801_OUT_UVP_ERR_MASK),
+	REGMAP_IRQ_REG(BD96801_LDO7_SHDN_ERR_STAT, 9, BD96801_OUT_SHDN_ERR_MASK),
+};
+
 static const struct regmap_irq bd96801_intb_irqs[] = {
 	/* STATUS SYSTEM INTB */
 	REGMAP_IRQ_REG(BD96801_TW_STAT, 0, BD96801_TW_STAT_MASK),
@@ -175,8 +307,25 @@ static const struct regmap_irq bd96801_intb_irqs[] = {
 	REGMAP_IRQ_REG(BD96801_LDO7_UVD_STAT, 7, BD96801_LDO_UVD_STAT_MASK),
 };
 
+static struct regmap_irq_chip bd96801_irq_chip_errb = {
+	.name = "bd96801-irq-errb",
+	.domain_suffix = "errb",
+	.main_status = BD96801_REG_INT_MAIN,
+	.num_main_regs = 1,
+	.irqs = &bd96801_errb_irqs[0],
+	.num_irqs = ARRAY_SIZE(bd96801_errb_irqs),
+	.status_base = BD96801_REG_INT_SYS_ERRB1,
+	.mask_base = BD96801_REG_MASK_SYS_ERRB,
+	.ack_base = BD96801_REG_INT_SYS_ERRB1,
+	.init_ack_masked = true,
+	.num_regs = 10,
+	.irq_reg_stride = 1,
+	.sub_reg_offsets = &errb_sub_irq_offsets[0],
+};
+
 static struct regmap_irq_chip bd96801_irq_chip_intb = {
 	.name = "bd96801-irq-intb",
+	.domain_suffix = "intb",
 	.main_status = BD96801_REG_INT_MAIN,
 	.num_main_regs = 1,
 	.irqs = &bd96801_intb_irqs[0],
@@ -198,11 +347,14 @@ static const struct regmap_config bd96801_regmap_config = {
 
 static int bd96801_i2c_probe(struct i2c_client *i2c)
 {
-	struct regmap_irq_chip_data *intb_irq_data;
+	int i, ret, intb_irq, errb_irq, num_regu_irqs, num_intb, num_errb = 0;
+	int wdg_irq_no;
+	struct regmap_irq_chip_data *intb_irq_data, *errb_irq_data;
+	struct irq_domain *intb_domain, *errb_domain;
+	struct resource wdg_irq;
 	const struct fwnode_handle *fwnode;
-	struct irq_domain *intb_domain;
+	struct resource *regulator_res;
 	struct regmap *regmap;
-	int ret, intb_irq;
 
 	fwnode = dev_fwnode(&i2c->dev);
 	if (!fwnode)
@@ -212,10 +364,28 @@ static int bd96801_i2c_probe(struct i2c_client *i2c)
 	if (intb_irq < 0)
 		return dev_err_probe(&i2c->dev, intb_irq, "INTB IRQ not configured\n");
 
+	num_intb =  ARRAY_SIZE(regulator_intb_irqs);
+
+	/* ERRB may be omitted if processor is powered by the PMIC */
+	errb_irq = fwnode_irq_get_byname(fwnode, "errb");
+	if (errb_irq < 0)
+		errb_irq = 0;
+
+	if (errb_irq)
+		num_errb = ARRAY_SIZE(regulator_errb_irqs);
+
+	num_regu_irqs = num_intb + num_errb;
+
+	regulator_res = kcalloc(num_regu_irqs, sizeof(*regulator_res), GFP_KERNEL);
+	if (!regulator_res)
+		return -ENOMEM;
+
 	regmap = devm_regmap_init_i2c(i2c, &bd96801_regmap_config);
-	if (IS_ERR(regmap))
-		return dev_err_probe(&i2c->dev, PTR_ERR(regmap),
+	if (IS_ERR(regmap)) {
+		ret = dev_err_probe(&i2c->dev, PTR_ERR(regmap),
 				    "Regmap initialization failed\n");
+		goto free_out;
+	}
 
 	ret = regmap_write(regmap, BD96801_LOCK_REG, BD96801_UNLOCK);
 	if (ret)
@@ -224,18 +394,63 @@ static int bd96801_i2c_probe(struct i2c_client *i2c)
 	ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, intb_irq,
 				       IRQF_ONESHOT, 0, &bd96801_irq_chip_intb,
 				       &intb_irq_data);
-	if (ret)
-		return dev_err_probe(&i2c->dev, ret, "Failed to add INTB IRQ chip\n");
+	if (ret) {
+		dev_err_probe(&i2c->dev, ret, "Failed to add INTB irq_chip\n");
+		goto free_out;
+	}
 
 	intb_domain = regmap_irq_get_domain(intb_irq_data);
 
-	ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO,
-				   bd96801_mfd_cells,
-				   ARRAY_SIZE(bd96801_mfd_cells), NULL, 0,
-				   intb_domain);
-
+	/*
+	 * MFD core code is built to handle only one IRQ domain. BD96801
+	 * has two domains so we do IRQ mapping here and provide the
+	 * already mapped IRQ numbers to sub-devices.
+	 */
+	for (i = 0; i < num_intb; i++) {
+		struct resource *res = &regulator_res[i];
+
+		*res = regulator_intb_irqs[i];
+		res->start = res->end = irq_create_mapping(intb_domain,
+							    res->start);
+	}
+
+	wdg_irq_no = irq_create_mapping(intb_domain, BD96801_WDT_ERR_STAT);
+	wdg_irq = DEFINE_RES_IRQ_NAMED(wdg_irq_no, "bd96801-wdg");
+	bd96801_mfd_cells[WDG_CELL].resources = &wdg_irq;
+	bd96801_mfd_cells[WDG_CELL].num_resources = 1;
+
+	if (num_errb) {
+		ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, errb_irq,
+					       IRQF_ONESHOT, 0,
+					       &bd96801_irq_chip_errb,
+					       &errb_irq_data);
+		if (ret) {
+			dev_err_probe(&i2c->dev, ret,
+				      "Failed to add ERRB (%d) irq_chip\n",
+				      errb_irq);
+			goto free_out;
+		}
+		errb_domain = regmap_irq_get_domain(errb_irq_data);
+
+		for (i = 0; i < num_errb; i++) {
+			struct resource *res = &regulator_res[num_intb + i];
+
+			*res = regulator_errb_irqs[i];
+			res->start = res->end = irq_create_mapping(errb_domain,
+								   res->start);
+		}
+	}
+
+	bd96801_mfd_cells[REGULATOR_CELL].resources = regulator_res;
+	bd96801_mfd_cells[REGULATOR_CELL].num_resources = num_regu_irqs;
+
+	ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, bd96801_mfd_cells,
+				   ARRAY_SIZE(bd96801_mfd_cells), NULL, 0, NULL);
 	if (ret)
-		dev_err(&i2c->dev, "Failed to create subdevices\n");
+		dev_err_probe(&i2c->dev, ret, "Failed to create subdevices\n");
+
+free_out:
+	kfree(regulator_res);
 
 	return ret;
 }
Signature · 14 lines
2.45.1


-- 
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 =] 
author maintainer
#19 lore raw

PATCH v2 10/10 regulator: bd96801: Add ERRB IRQ

In reply to Matti Vaittinen

The ROHM BD96801 "scalable PMIC" provides two physical IRQs. The ERRB handling can in many cases be omitted because it is used to inform fatal IRQs, which usually kill the power from the SOC.

There may however be use-cases where the SOC has a 'back-up' emergency power source which allows some very short time of operation to try to gracefully shut down sensitive hardware. Furthermore, it is possible the processor controlling the PMIC is not powered by the PMIC. In such cases handling the ERRB IRQs may be beneficial.

Add support for ERRB IRQs.

---
Revision history:
v1 => v2:
- New patch

---
 drivers/regulator/bd96801-regulator.c | 130 +++++++++++++++++++++++---
 1 file changed, 115 insertions(+), 15 deletions(-)
drivers/regulator/bd96801-regulator.c +115 -15
index a1ac068c69f8..e49a9948223e 100644
@@ -5,12 +5,7 @@
 /*
  * This version of the "BD86801 scalable PMIC"'s driver supports only very
  * basic set of the PMIC features. Most notably, there is no support for
- * the ERRB interrupt and the configurations which should be done when the
- * PMIC is in STBY mode.
- *
- * Supporting the ERRB interrupt would require dropping the regmap-IRQ
- * usage or working around (or accepting a presense of) a naming conflict
- * in debugFS IRQs.
+ * the configurations which should be done when the PMIC is in STBY mode.
  *
  * Being able to reliably do the configurations like changing the
  * regulator safety limits (like limits for the over/under -voltages, over
@@ -22,16 +17,14 @@
  * be the need to configure these safety limits. Hence it's not simple to
  * come up with a generic solution.
  *
- * Users who require the ERRB handling and STBY state configurations can
- * have a look at the original RFC:
+ * Users who require the STBY state configurations can have a look at the
+ * original RFC:
  * https://lore.kernel.org/all/[email protected]/
- * which implements a workaround to debugFS naming conflict and some of
- * the safety limit configurations - but leaves the state change handling
- * and synchronization to be implemented.
+ * which implements some of the safety limit configurations - but leaves the
+ * state change handling and synchronization to be implemented.
  *
  * It would be great to hear (and receive a patch!) if you implement the
- * STBY configuration support or a proper fix to the debugFS naming
- * conflict in your downstream driver ;)
+ * STBY configuration support in your downstream driver ;)
  */
 
 #include <linux/delay.h>
@@ -733,6 +726,95 @@ static int initialize_pmic_data(struct device *dev,
 	return 0;
 }
 
+static int bd96801_map_event_all(int irq, struct regulator_irq_data *rid,
+			  unsigned long *dev_mask)
+{
+	int i;
+
+	for (i = 0; i < rid->num_states; i++) {
+		rid->states[i].notifs = REGULATOR_EVENT_FAIL;
+		rid->states[i].errors = REGULATOR_ERROR_FAIL;
+		*dev_mask |= BIT(i);
+	}
+
+	return 0;
+}
+
+static int bd96801_rdev_errb_irqs(struct platform_device *pdev,
+				  struct regulator_dev *rdev)
+{
+	int i;
+	void *retp;
+	static const char * const single_out_errb_irqs[] = {
+		"bd96801-%s-pvin-err", "bd96801-%s-ovp-err",
+		"bd96801-%s-uvp-err", "bd96801-%s-shdn-err",
+	};
+
+	for (i = 0; i < ARRAY_SIZE(single_out_errb_irqs); i++) {
+		struct regulator_irq_desc id = {
+			.map_event = bd96801_map_event_all,
+			.irq_off_ms = 1000,
+		};
+		struct regulator_dev *rdev_arr[1];
+		char tmp[255];
+		int irq;
+
+		snprintf(tmp, 255, single_out_errb_irqs[i], rdev->desc->name);
+		tmp[254] = 0;
+		id.name = tmp;
+
+		irq = platform_get_irq_byname(pdev, tmp);
+		if (irq < 0)
+			continue;
+
+		rdev_arr[0] = rdev;
+		retp = devm_regulator_irq_helper(&pdev->dev, &id, irq, 0,
+						 REGULATOR_ERROR_FAIL, NULL,
+						 rdev_arr, 1);
+		if (IS_ERR(retp))
+			return PTR_ERR(retp);
+
+	}
+	return 0;
+}
+
+static int bd96801_global_errb_irqs(struct platform_device *pdev,
+				    struct regulator_dev **rdev, int num_rdev)
+{
+	int i, num_irqs;
+	void *retp;
+	static const char * const global_errb_irqs[] = {
+		"bd96801-otp-err", "bd96801-dbist-err", "bd96801-eep-err",
+		"bd96801-abist-err", "bd96801-prstb-err", "bd96801-drmoserr1",
+		"bd96801-drmoserr2", "bd96801-slave-err", "bd96801-vref-err",
+		"bd96801-tsd", "bd96801-uvlo-err", "bd96801-ovlo-err",
+		"bd96801-osc-err", "bd96801-pon-err", "bd96801-poff-err",
+		"bd96801-cmd-shdn-err", "bd96801-int-shdn-err"
+	};
+
+	num_irqs = ARRAY_SIZE(global_errb_irqs);
+	for (i = 0; i < num_irqs; i++) {
+		int irq;
+		struct regulator_irq_desc id = {
+			.name = global_errb_irqs[i],
+			.map_event = bd96801_map_event_all,
+			.irq_off_ms = 1000,
+		};
+
+		irq = platform_get_irq_byname(pdev, global_errb_irqs[i]);
+		if (irq < 0)
+			continue;
+
+		retp = devm_regulator_irq_helper(&pdev->dev, &id, irq, 0,
+						 REGULATOR_ERROR_FAIL, NULL,
+						  rdev, num_rdev);
+		if (IS_ERR(retp))
+			return PTR_ERR(retp);
+	}
+
+	return 0;
+}
+
 static int bd96801_rdev_intb_irqs(struct platform_device *pdev,
 				  struct bd96801_pmic_data *pdata,
 				  struct bd96801_irqinfo *iinfo,
@@ -788,11 +870,10 @@ static int bd96801_rdev_intb_irqs(struct platform_device *pdev,
 	return 0;
 }
 
-
-
 static int bd96801_probe(struct platform_device *pdev)
 {
 	struct regulator_dev *ldo_errs_rdev_arr[BD96801_NUM_LDOS];
+	struct regulator_dev *all_rdevs[BD96801_NUM_REGULATORS];
 	struct bd96801_regulator_data *rdesc;
 	struct regulator_config config = {};
 	int ldo_errs_arr[BD96801_NUM_LDOS];
@@ -800,6 +881,7 @@ static int bd96801_probe(struct platform_device *pdev)
 	int temp_notif_ldos = 0;
 	struct device *parent;
 	int i, ret;
+	bool use_errb;
 	void *retp;
 
 	parent = pdev->dev.parent;
@@ -824,6 +906,13 @@ static int bd96801_probe(struct platform_device *pdev)
 	config.regmap = pdata->regmap;
 	config.dev = parent;
 
+	ret = of_property_match_string(pdev->dev.parent->of_node,
+				       "interrupt-names", "errb");
+	if (ret < 0)
+		use_errb = false;
+	else
+		use_errb = true;
+
 	ret = bd96801_walk_regulator_dt(&pdev->dev, pdata->regmap, rdesc,
 					BD96801_NUM_REGULATORS);
 	if (ret)
@@ -842,6 +931,7 @@ static int bd96801_probe(struct platform_device *pdev)
 				rdesc[i].desc.name);
 			return PTR_ERR(rdev);
 		}
+		all_rdevs[i] = rdev;
 		/*
 		 * LDOs don't have own temperature monitoring. If temperature
 		 * notification was requested for this LDO from DT then we will
@@ -863,6 +953,12 @@ static int bd96801_probe(struct platform_device *pdev)
 			if (ret)
 				return ret;
 		}
+		/* Register per regulator ERRB notifiers */
+		if (use_errb) {
+			ret = bd96801_rdev_errb_irqs(pdev, rdev);
+			if (ret)
+				return ret;
+		}
 	}
 	if (temp_notif_ldos) {
 		int irq;
@@ -884,6 +980,10 @@ static int bd96801_probe(struct platform_device *pdev)
 			return PTR_ERR(retp);
 	}
 
+	if (use_errb)
+		return bd96801_global_errb_irqs(pdev, all_rdevs,
+						ARRAY_SIZE(all_rdevs));
+
 	return 0;
 }
 
Signature · 14 lines
2.45.1


-- 
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 =] 
maintainer Reviewed-by on v2 4/10
#7 lore raw

Re: [PATCH v2 04/10] regulator: bd96801: ROHM BD96801 PMIC regulators

In reply to Matti Vaittinen
Quoted 4 lines · Matti Vaittinen

The ROHM BD96801 "Scalable PMIC" is an automotive grade PMIC which can scale to different applications by allowing chaining of PMICs. The PMIC also supports various protection features which can be configured either to fire IRQs - or to shut down power outputs when failure is detected.

maintainer Reviewed-by on v2 10/10
#20 lore raw

Re: [PATCH v2 10/10] regulator: bd96801: Add ERRB IRQ

In reply to Matti Vaittinen
Quoted 3 lines · Matti Vaittinen

The ROHM BD96801 "scalable PMIC" provides two physical IRQs. The ERRB handling can in many cases be omitted because it is used to inform fatal IRQs, which usually kill the power from the SOC.

#11 lore raw

Re: [PATCH v2 07/10] irqdomain: Allow giving name suffix for domain

In reply to Matti Vaittinen
Quoted 1 line · Matti Vaittinen

When multiple IRQ domains are created from same device-tree node they

s/IRQ/interrupt/

Also most of your sentences lack a substantial amount of articles.

Quoted 7 lines

will get same name based on the device-tree path. This will cause a naming collision in debugFS when IRQ domain specific entries are created.

One use-case for being able to create multiple IRQ domains / single device node is using regmap-IRQ controller code for devices which provide more than one physical IRQ.

This does not make sense. Why do you need multiple interrupt domains if there is more than one physical interrupt?

Quoted 1 line

It seems much cleaner to instantiate

'It seems' is not a technical argument.

Quoted 2 lines

own regmap-IRQ controller for each parent IRQ because most of the regmap IRQ properties are really specific to parent IRQ.

Now you start talking about parent interrupts. Can you please make your mind up and concisely explain what this is about?

Quoted 10 lines
kernel/irq/irqdomain.c +2 -2
-struct irq_domain *irq_domain_create_legacy(struct fwnode_handle *fwnode,
+struct irq_domain *irq_domain_create_legacy_named(struct fwnode_handle *fwnode,
 					 unsigned int size,
 					 unsigned int first_irq,
 					 irq_hw_number_t first_hwirq,
 					 const struct irq_domain_ops *ops,
-					 void *host_data)
+					 void *host_data, const char *name_suffix)
 {
 	struct irq_domain *domain;

kernel/irq/irqdomain.c struct irq_domain *irq_domain_add_legacy(struct device_node *of_node, · line 446

Quoted 10 lines
kernel/irq/irqdomain.c +3 -1
 
-	domain = __irq_domain_add(fwnode, first_hwirq + size, first_hwirq + size, 0, ops, host_data);
+	domain = __irq_domain_add(fwnode, first_hwirq + size, first_hwirq + size,
+				  0, ops, host_data, name_suffix);
 	if (domain)
 		irq_domain_associate_many(domain, first_irq, first_hwirq, size);
 
 	return domain;
 }
+EXPORT_SYMBOL_GPL(irq_domain_create_legacy_named);

What for? This new stuff is not going to be used for legacy setups with hard coded Linux interrupt numbers. So there is no point to add a function plus an export which is never used.

Thanks,

tglx

author maintainer
#12 lore raw

Re: [PATCH v2 07/10] irqdomain: Allow giving name suffix for domain

Hi Thomas,

Thanks for taking a look at this.

Quoted 6 lines · Thomas Gleixner
Quoted 1 line · Matti Vaittinen

When multiple IRQ domains are created from same device-tree node they

s/IRQ/interrupt/

Also most of your sentences lack a substantial amount of articles.

Usual ack for any language related comments. I'll try to proofread and improve.

Quoted 10 lines
Quoted 7 lines

will get same name based on the device-tree path. This will cause a naming collision in debugFS when IRQ domain specific entries are created.

One use-case for being able to create multiple IRQ domains / single device node is using regmap-IRQ controller code for devices which provide more than one physical IRQ.

This does not make sense. Why do you need multiple interrupt domains if there is more than one physical interrupt?

I'll try to explain myself better below.

Quoted 3 lines
Quoted 1 line

It seems much cleaner to instantiate

'It seems' is not a technical argument.

I am always having problems claiming something is _absolutely_ cleaner, as "clean" or "messy" are subjective and depend on reader. To me this is cleaner. Also, Mark Brown thought it is cleaner. Still, it does not mean this is absolutely cleaner for everyone. I am open to suggestions how to rephrase.

Quoted 5 lines
Quoted 2 lines

own regmap-IRQ controller for each parent IRQ because most of the regmap IRQ properties are really specific to parent IRQ.

Now you start talking about parent interrupts. Can you please make your mind up and concisely explain what this is about?

I hope I can explain what I am after here. I am also very happy when incorrect terminology is pointed out! So, it'd be great to know if I should use 'parent' or 'physical IRQ' here after I explain this further.

What I am dealing with is an I2C device (PMIC) which provides two GPIO IRQ lines for SOC. This is what I meant by "physical IRQs".

---------------- INTB IRQ -----------------

|		|-----------------------|		|
|	PMIC	|			|    SOC	|
|		|-----------------------|		|

----------------- ERRB IRQ -----------------

Both the INTB and ERRB can report various events, and correct event can be further read from the PMIC registers when IRQ line is asserted. I think this is business as usual.

I'd like to use the regmap_irq for representing these events as separate 'IRQs' (which can be handled using handlers registered with request_threaded_irq() as usual).

Here, when talking about 'parent IRQ', I was referring to ERRB or INTB as 'parent IRQ'. My thinking was that, the regmap IRQ instance uses INTB or ERRB as it's parent IRQ, which it splits (demuxes) to separate "child IRQs" for the rest of the PMIC drivers to use. I'd be grateful if better terms were suggested so that readers can stay on same page with me.

After talking with Mark:

we both thought it'd be cleaner to have separate regmap IRQ instances for the ERRB and INTB lines. This makes sense (to me) because a lot of (almost all of?) the regmap IRQ internal data describe the IRQ line related things like registers related to the IRQ line, IRQ line polarity etc. Hence, making single regmap-IRQ instance to support more than one <please, add what is the correct term for INTB / ERRB like line> would require duplicating a plenty of the regmap data. This would make registering an regmap-IRQ entity much more complex and additionally it'd also complicate the internals of the regmap-IRQ. It'd be a bit like trying to fill and drink a six-pack of lemonade at once, instead of going a bottle by bottle :)

Quoted 17 lines
Quoted 17 lines
kernel/irq/irqdomain.c +4 -3
-struct irq_domain *irq_domain_create_legacy(struct fwnode_handle *fwnode,
+struct irq_domain *irq_domain_create_legacy_named(struct fwnode_handle *fwnode,
  					 unsigned int size,
  					 unsigned int first_irq,
  					 irq_hw_number_t first_hwirq,
  					 const struct irq_domain_ops *ops,
-					 void *host_data)
+					 void *host_data, const char *name_suffix)
  {
  	struct irq_domain *domain;
 
-	domain = __irq_domain_add(fwnode, first_hwirq + size, first_hwirq + size, 0, ops, host_data);
+	domain = __irq_domain_add(fwnode, first_hwirq + size, first_hwirq + size,
+				  0, ops, host_data, name_suffix);
  	if (domain)
  		irq_domain_associate_many(domain, first_irq, first_hwirq, size);
Quoted 7 lines
Quoted 3 lines

return domain;
}
+EXPORT_SYMBOL_GPL(irq_domain_create_legacy_named);

What for? This new stuff is not going to be used for legacy setups with hard coded Linux interrupt numbers. So there is no point to add a function plus an export which is never used.

Thanks for pointing this out. I am more than glad to drop this. It'll just mean that the regmap-IRQ (which supports using the legacy domains) should warn if user tries to use legacy domain with name suffix. Mark, does this sound reasonable to you?

Thanks for all the input!
-- Matti

Signature · 5 lines
Matti Vaittinen
Linux kernel developer at ROHM Semiconductors
Oulu Finland

~~ When things go utterly wrong vim users can always type :help! ~~
author maintainer
#13 lore raw

Re: [PATCH v2 07/10] irqdomain: Allow giving name suffix for domain

Quoted 3 lines · Matti Vaittinen

Here, when talking about 'parent IRQ', I was referring to ERRB or INTB as 'parent IRQ'. My thinking was that, the regmap IRQ instance uses INTB or ERRB as it's parent IRQ, which it splits (demuxes) to separate "child IRQs" for the rest of the PMIC drivers to use. I'd be grateful if better terms were suggested so that readers can stay on same page with me.

After talking with Mark:

Sorry, I forgot the link:
https://lore.kernel.org/all/[email protected]/

Quoted 2 lines

we both thought it'd be cleaner to have separate regmap IRQ instances for the ERRB and INTB lines. This makes sense (to me) because a lot of (almost all of?) the regmap IRQ internal data describe the IRQ line related things like registers related to the IRQ line, IRQ line polarity etc. Hence, making single regmap-IRQ instance to support more than one <please, add what is the correct term for INTB / ERRB like line> would require duplicating a plenty of the regmap data. This would make registering an regmap-IRQ entity much more complex and additionally it'd also complicate the internals of the regmap-IRQ. It'd be a bit like trying to fill and drink a six-pack of lemonade at once, instead of going a bottle by bottle :)

Yours,
-- Matti

Signature · 5 lines
Matti Vaittinen
Linux kernel developer at ROHM Semiconductors
Oulu Finland

~~ When things go utterly wrong vim users can always type :help! ~~
#14 lore raw

Re: [PATCH v2 07/10] irqdomain: Allow giving name suffix for domain

In reply to Matti Vaittinen

Matti!

Quoted 35 lines · Matti Vaittinen
Quoted 3 lines · Thomas Gleixner

On Fri, May 24 2024 at 11:18, Matti Vaittinen wrote:
Now you start talking about parent interrupts. Can you please make your mind up and concisely explain what this is about?

I hope I can explain what I am after here. I am also very happy when incorrect terminology is pointed out! So, it'd be great to know if I should use 'parent' or 'physical IRQ' here after I explain this further.

What I am dealing with is an I2C device (PMIC) which provides two GPIO IRQ lines for SOC. This is what I meant by "physical IRQs".

---------------- INTB IRQ -----------------

|		|-----------------------|		|
|	PMIC	|			|    SOC	|
|		|-----------------------|		|

----------------- ERRB IRQ -----------------

Both the INTB and ERRB can report various events, and correct event can be further read from the PMIC registers when IRQ line is asserted. I think this is business as usual.

I'd like to use the regmap_irq for representing these events as separate 'IRQs' (which can be handled using handlers registered with request_threaded_irq() as usual).

Here, when talking about 'parent IRQ', I was referring to ERRB or INTB as 'parent IRQ'. My thinking was that, the regmap IRQ instance uses INTB or ERRB as it's parent IRQ, which it splits (demuxes) to separate "child IRQs" for the rest of the PMIC drivers to use. I'd be grateful if better terms were suggested so that readers can stay on same page with me.

After talking with Mark:

Quoted 11 lines

we both thought it'd be cleaner to have separate regmap IRQ instances for the ERRB and INTB lines. This makes sense (to me) because a lot of (almost all of?) the regmap IRQ internal data describe the IRQ line related things like registers related to the IRQ line, IRQ line polarity etc. Hence, making single regmap-IRQ instance to support more than one <please, add what is the correct term for INTB / ERRB like line> would require duplicating a plenty of the regmap data. This would make registering an regmap-IRQ entity much more complex and additionally it'd also complicate the internals of the regmap-IRQ. It'd be a bit like trying to fill and drink a six-pack of lemonade at once, instead of going a bottle by bottle :)

This makes a lot more sense now. So what I read out of this in change log style is:

Devices can have subfunctions where each has its own interrupt line. Each interrupt line acts as demultiplex interrupt for subfunction specific interrupts and has its distinct set of registers.

regmap can support such a setup, but the interrupt domain code ends up to assign the same device name when creating the underlying per subfunction interrupt domains. This causes name space collision in the debugfs code and also leads to confusion in other places, e.g. /proc/interrupts would show two distinct interrupts with the same domain name and hardware interrupt number.

Instead of working around this in the driver or the regmap code, allow to provide a name suffix for the domain name when creating the interrupt domains.

Add the infrastructure to __irq_domain_add() and expose it via irq_domain_create_linear_named() which is the only function required by the regmap code to support such setups.

Did I get it halfways right?

Thanks,

tglx

author maintainer
#15 lore raw

Re: [PATCH v2 07/10] irqdomain: Allow giving name suffix for domain

Quoted 68 lines · Thomas Gleixner

Matti!

Quoted 35 lines · Matti Vaittinen
Quoted 3 lines · Thomas Gleixner

On Fri, May 24 2024 at 11:18, Matti Vaittinen wrote:
Now you start talking about parent interrupts. Can you please make your mind up and concisely explain what this is about?

I hope I can explain what I am after here. I am also very happy when incorrect terminology is pointed out! So, it'd be great to know if I should use 'parent' or 'physical IRQ' here after I explain this further.

What I am dealing with is an I2C device (PMIC) which provides two GPIO IRQ lines for SOC. This is what I meant by "physical IRQs".

---------------- INTB IRQ -----------------

|		|-----------------------|		|
|	PMIC	|			|    SOC	|
|		|-----------------------|		|

----------------- ERRB IRQ -----------------

Both the INTB and ERRB can report various events, and correct event can be further read from the PMIC registers when IRQ line is asserted. I think this is business as usual.

I'd like to use the regmap_irq for representing these events as separate 'IRQs' (which can be handled using handlers registered with request_threaded_irq() as usual).

Here, when talking about 'parent IRQ', I was referring to ERRB or INTB as 'parent IRQ'. My thinking was that, the regmap IRQ instance uses INTB or ERRB as it's parent IRQ, which it splits (demuxes) to separate "child IRQs" for the rest of the PMIC drivers to use. I'd be grateful if better terms were suggested so that readers can stay on same page with me.

After talking with Mark:

Quoted 11 lines

we both thought it'd be cleaner to have separate regmap IRQ instances for the ERRB and INTB lines. This makes sense (to me) because a lot of (almost all of?) the regmap IRQ internal data describe the IRQ line related things like registers related to the IRQ line, IRQ line polarity etc. Hence, making single regmap-IRQ instance to support more than one <please, add what is the correct term for INTB / ERRB like line> would require duplicating a plenty of the regmap data. This would make registering an regmap-IRQ entity much more complex and additionally it'd also complicate the internals of the regmap-IRQ. It'd be a bit like trying to fill and drink a six-pack of lemonade at once, instead of going a bottle by bottle :)

This makes a lot more sense now. So what I read out of this in change log style is:

Devices can have subfunctions where each has its own interrupt line. Each interrupt line acts as demultiplex interrupt for subfunction specific interrupts and has its distinct set of registers.

regmap can support such a setup, but the interrupt domain code ends up to assign the same device name when creating the underlying per subfunction interrupt domains. This causes name space collision in the debugfs code and also leads to confusion in other places, e.g. /proc/interrupts would show two distinct interrupts with the same domain name and hardware interrupt number.

Instead of working around this in the driver or the regmap code, allow to provide a name suffix for the domain name when creating the interrupt domains.

Quoted 5 lines

Add the infrastructure to __irq_domain_add() and expose it via irq_domain_create_linear_named() which is the only function required by the regmap code to support such setups.

Did I get it halfways right?

I think you got it perfectly right. :) And, I really appreciate the extra mile you went when spelling it out in this way. I will send a new version where the legacy domain function is dropped, and the commit message will use what you wrote here :)

Thanks a ton!

Yours,
-- Matti

Signature · 5 lines
Matti Vaittinen
Linux kernel developer at ROHM Semiconductors
Oulu Finland

~~ When things go utterly wrong vim users can always type :help! ~~
#16 lore raw

Re: [PATCH v2 07/10] irqdomain: Allow giving name suffix for domain

Matti!

Quoted 7 lines · Matti Vaittinen
Quoted 1 line · Thomas Gleixner

Did I get it halfways right?

I think you got it perfectly right. :) And, I really appreciate the extra mile you went when spelling it out in this way. I will send a new version where the legacy domain function is dropped, and the commit message will use what you wrote here :)

Please don't use it verbatim. Use it as a guideline and express it in your own words. Copy & pasta is conveniant but rephrasing it makes you learn. :)

Thanks,

tglx