From ec4acd3166d8a7a03b059d01b9c6f11a658e833f Mon Sep 17 00:00:00 2001 From: Len Brown Date: Sun, 6 Apr 2025 14:29:57 -0400 Subject: [PATCH 01/16] tools/power turbostat: disable "cpuidle" invocation counters, by default Create "pct_idle" counter group, the sofware notion of residency so it can now be singled out, independent of other counter groups. Create "cpuidle" group, the cpuidle invocation counts. Disable "cpuidle", by default. Create "swidle" = "cpuidle" + "pct_idle". Undocument "sysfs", the old name for "swidle", but keep it working for backwards compatibilty. Create "hwidle", all the HW idle counters Modify "idle", enabled by default "idle" = "hwidle" + "pct_idle" (and now excludes "cpuidle") Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.8 | 12 +++++----- tools/power/x86/turbostat/turbostat.c | 34 +++++++++++++++++++++------ 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8 index e86493880c16..b74ed916057e 100644 --- a/tools/power/x86/turbostat/turbostat.8 +++ b/tools/power/x86/turbostat/turbostat.8 @@ -100,7 +100,7 @@ The column name "all" can be used to enable all disabled-by-default built-in cou .PP \fB--show column\fP show only the specified built-in columns. May be invoked multiple times, or with a comma-separated list of column names. .PP -\fB--show CATEGORY --hide CATEGORY\fP Show and hide also accept a single CATEGORY of columns: "all", "topology", "idle", "frequency", "power", "sysfs", "other". +\fB--show CATEGORY --hide CATEGORY\fP Show and hide also accept a single CATEGORY of columns: "all", "topology", "idle", "frequency", "power", "cpuidle", "hwidle", "swidle", "other". "idle" (enabled by default), includes "hwidle" and "idle_pct". "cpuidle" (default disabled) includes cpuidle software invocation counters. "swidle" includes "cpuidle" plus "idle_pct". "hwidle" includes only hardware based idle residency counters. Older versions of turbostat used the term "sysfs" for what is now "swidle". .PP \fB--Dump\fP displays the raw counter values. .PP @@ -158,15 +158,15 @@ The system configuration dump (if --quiet is not used) is followed by statistics .PP \fBSMI\fP The number of System Management Interrupts serviced CPU during the measurement interval. While this counter is actually per-CPU, SMI are triggered on all processors, so the number should be the same for all CPUs. .PP -\fBC1, C2, C3...\fP The number times Linux requested the C1, C2, C3 idle state during the measurement interval. The system summary line shows the sum for all CPUs. These are C-state names as exported in /sys/devices/system/cpu/cpu*/cpuidle/state*/name. While their names are generic, their attributes are processor specific. They the system description section of output shows what MWAIT sub-states they are mapped to on each system. +\fBC1, C2, C3...\fP The number times Linux requested the C1, C2, C3 idle state during the measurement interval. The system summary line shows the sum for all CPUs. These are C-state names as exported in /sys/devices/system/cpu/cpu*/cpuidle/state*/name. While their names are generic, their attributes are processor specific. They the system description section of output shows what MWAIT sub-states they are mapped to on each system. These counters are in the "cpuidle" group, which is disabled, by default. .PP -\fBC1+, C2+, C3+...\fP The idle governor idle state misprediction statistics. Inidcates the number times Linux requested the C1, C2, C3 idle state during the measurement interval, but should have requested a deeper idle state (if it exists and enabled). These statistics come from the /sys/devices/system/cpu/cpu*/cpuidle/state*/below file. +\fBC1+, C2+, C3+...\fP The idle governor idle state misprediction statistics. Inidcates the number times Linux requested the C1, C2, C3 idle state during the measurement interval, but should have requested a deeper idle state (if it exists and enabled). These statistics come from the /sys/devices/system/cpu/cpu*/cpuidle/state*/below file. These counters are in the "cpuidle" group, which is disabled, by default. .PP -\fBC1-, C2-, C3-...\fP The idle governor idle state misprediction statistics. Inidcates the number times Linux requested the C1, C2, C3 idle state during the measurement interval, but should have requested a shallower idle state (if it exists and enabled). These statistics come from the /sys/devices/system/cpu/cpu*/cpuidle/state*/above file. +\fBC1-, C2-, C3-...\fP The idle governor idle state misprediction statistics. Inidcates the number times Linux requested the C1, C2, C3 idle state during the measurement interval, but should have requested a shallower idle state (if it exists and enabled). These statistics come from the /sys/devices/system/cpu/cpu*/cpuidle/state*/above file. These counters are in the "cpuidle" group, which is disabled, by default. .PP -\fBC1%, C2%, C3%\fP The residency percentage that Linux requested C1, C2, C3.... The system summary is the average of all CPUs in the system. Note that these are software, reflecting what was requested. The hardware counters reflect what was actually achieved. +\fBC1%, C2%, C3%\fP The residency percentage that Linux requested C1, C2, C3.... The system summary is the average of all CPUs in the system. Note that these are software, reflecting what was requested. The hardware counters reflect what was actually achieved. These counters are in the "pct_idle" group, which is enabled by default. .PP -\fBCPU%c1, CPU%c3, CPU%c6, CPU%c7\fP show the percentage residency in hardware core idle states. These numbers are from hardware residency counters. +\fBCPU%c1, CPU%c3, CPU%c6, CPU%c7\fP show the percentage residency in hardware core idle states. These numbers are from hardware residency counters and are in the "hwidle" group, which is enabled, by default. .PP \fBCoreTmp\fP Degrees Celsius reported by the per-core Digital Thermal Sensor. .PP diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index df0391bedcde..ab184f95cdaf 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -153,7 +153,7 @@ struct msr_counter bic[] = { { 0x0, "TSC_MHz", NULL, 0, 0, 0, NULL, 0 }, { 0x0, "IRQ", NULL, 0, 0, 0, NULL, 0 }, { 0x0, "SMI", NULL, 32, 0, FORMAT_DELTA, NULL, 0 }, - { 0x0, "sysfs", NULL, 0, 0, 0, NULL, 0 }, + { 0x0, "cpuidle", NULL, 0, 0, 0, NULL, 0 }, { 0x0, "CPU%c1", NULL, 0, 0, 0, NULL, 0 }, { 0x0, "CPU%c3", NULL, 0, 0, 0, NULL, 0 }, { 0x0, "CPU%c6", NULL, 0, 0, 0, NULL, 0 }, @@ -206,6 +206,7 @@ struct msr_counter bic[] = { { 0x0, "Sys_J", NULL, 0, 0, 0, NULL, 0 }, { 0x0, "NMI", NULL, 0, 0, 0, NULL, 0 }, { 0x0, "CPU%c1e", NULL, 0, 0, 0, NULL, 0 }, + { 0x0, "pct_idle", NULL, 0, 0, 0, NULL, 0 }, }; #define MAX_BIC (sizeof(bic) / sizeof(struct msr_counter)) @@ -219,7 +220,7 @@ struct msr_counter bic[] = { #define BIC_TSC_MHz (1ULL << 7) #define BIC_IRQ (1ULL << 8) #define BIC_SMI (1ULL << 9) -#define BIC_sysfs (1ULL << 10) +#define BIC_cpuidle (1ULL << 10) #define BIC_CPU_c1 (1ULL << 11) #define BIC_CPU_c3 (1ULL << 12) #define BIC_CPU_c6 (1ULL << 13) @@ -272,17 +273,20 @@ struct msr_counter bic[] = { #define BIC_Sys_J (1ULL << 60) #define BIC_NMI (1ULL << 61) #define BIC_CPU_c1e (1ULL << 62) +#define BIC_pct_idle (1ULL << 63) #define BIC_GROUP_TOPOLOGY (BIC_Package | BIC_Node | BIC_CoreCnt | BIC_PkgCnt | BIC_Core | BIC_CPU | BIC_Die) #define BIC_GROUP_THERMAL_PWR (BIC_CoreTmp | BIC_PkgTmp | BIC_PkgWatt | BIC_CorWatt | BIC_GFXWatt | BIC_RAMWatt | BIC_PKG__ | BIC_RAM__ | BIC_SysWatt) #define BIC_GROUP_FREQUENCY (BIC_Avg_MHz | BIC_Busy | BIC_Bzy_MHz | BIC_TSC_MHz | BIC_GFXMHz | BIC_GFXACTMHz | BIC_SAMMHz | BIC_SAMACTMHz | BIC_UNCORE_MHZ) -#define BIC_GROUP_IDLE (BIC_Busy | BIC_sysfs | BIC_CPU_c1 | BIC_CPU_c3 | BIC_CPU_c6 | BIC_CPU_c7 | BIC_GFX_rc6 | BIC_Pkgpc2 | BIC_Pkgpc3 | BIC_Pkgpc6 | BIC_Pkgpc7 | BIC_Pkgpc8 | BIC_Pkgpc9 | BIC_Pkgpc10 | BIC_CPU_LPI | BIC_SYS_LPI | BIC_Mod_c6 | BIC_Totl_c0 | BIC_Any_c0 | BIC_GFX_c0 | BIC_CPUGFX | BIC_SAM_mc6 | BIC_Diec6) +#define BIC_GROUP_HW_IDLE (BIC_Busy | BIC_CPU_c1 | BIC_CPU_c3 | BIC_CPU_c6 | BIC_CPU_c7 | BIC_GFX_rc6 | BIC_Pkgpc2 | BIC_Pkgpc3 | BIC_Pkgpc6 | BIC_Pkgpc7 | BIC_Pkgpc8 | BIC_Pkgpc9 | BIC_Pkgpc10 | BIC_CPU_LPI | BIC_SYS_LPI | BIC_Mod_c6 | BIC_Totl_c0 | BIC_Any_c0 | BIC_GFX_c0 | BIC_CPUGFX | BIC_SAM_mc6 | BIC_Diec6) +#define BIC_GROUP_SW_IDLE (BIC_Busy | BIC_cpuidle | BIC_pct_idle ) +#define BIC_GROUP_IDLE (BIC_GROUP_HW_IDLE | BIC_pct_idle) #define BIC_OTHER (BIC_IRQ | BIC_NMI | BIC_SMI | BIC_ThreadC | BIC_CoreTmp | BIC_IPC) -#define BIC_DISABLED_BY_DEFAULT (BIC_USEC | BIC_TOD | BIC_APIC | BIC_X2APIC) +#define BIC_DISABLED_BY_DEFAULT (BIC_USEC | BIC_TOD | BIC_APIC | BIC_X2APIC | BIC_cpuidle) unsigned long long bic_enabled = (0xFFFFFFFFFFFFFFFFULL & ~BIC_DISABLED_BY_DEFAULT); -unsigned long long bic_present = BIC_USEC | BIC_TOD | BIC_sysfs | BIC_APIC | BIC_X2APIC; +unsigned long long bic_present = BIC_USEC | BIC_TOD | BIC_cpuidle | BIC_pct_idle | BIC_APIC | BIC_X2APIC; #define DO_BIC(COUNTER_NAME) (bic_enabled & bic_present & COUNTER_NAME) #define DO_BIC_READ(COUNTER_NAME) (bic_present & COUNTER_NAME) @@ -2362,6 +2366,15 @@ unsigned long long bic_lookup(char *name_list, enum show_hide_mode mode) } else if (!strcmp(name_list, "idle")) { retval |= BIC_GROUP_IDLE; break; + } else if (!strcmp(name_list, "swidle")) { + retval |= BIC_GROUP_SW_IDLE; + break; + } else if (!strcmp(name_list, "sysfs")) { /* legacy compatibility */ + retval |= BIC_GROUP_SW_IDLE; + break; + } else if (!strcmp(name_list, "hwidle")) { + retval |= BIC_GROUP_HW_IDLE; + break; } else if (!strcmp(name_list, "frequency")) { retval |= BIC_GROUP_FREQUENCY; break; @@ -2372,6 +2385,7 @@ unsigned long long bic_lookup(char *name_list, enum show_hide_mode mode) } if (i == MAX_BIC) { + fprintf(stderr, "deferred %s\n", name_list); if (mode == SHOW_LIST) { deferred_add_names[deferred_add_index++] = name_list; if (deferred_add_index >= MAX_DEFERRED) { @@ -10269,6 +10283,9 @@ void probe_cpuidle_residency(void) int min_state = 1024, max_state = 0; char *sp; + if (!DO_BIC(BIC_pct_idle)) + return; + for (state = 10; state >= 0; --state) { sprintf(path, "/sys/devices/system/cpu/cpu%d/cpuidle/state%d/name", base_cpu, state); @@ -10291,7 +10308,7 @@ void probe_cpuidle_residency(void) sprintf(path, "cpuidle/state%d/time", state); - if (!DO_BIC(BIC_sysfs) && !is_deferred_add(name_buf)) + if (!DO_BIC(BIC_pct_idle) && !is_deferred_add(name_buf)) continue; if (is_deferred_skip(name_buf)) @@ -10315,6 +10332,9 @@ void probe_cpuidle_counts(void) int min_state = 1024, max_state = 0; char *sp; + if (!DO_BIC(BIC_cpuidle)) + return; + for (state = 10; state >= 0; --state) { sprintf(path, "/sys/devices/system/cpu/cpu%d/cpuidle/state%d/name", base_cpu, state); @@ -10327,7 +10347,7 @@ void probe_cpuidle_counts(void) remove_underbar(name_buf); - if (!DO_BIC(BIC_sysfs) && !is_deferred_add(name_buf)) + if (!DO_BIC(BIC_cpuidle) && !is_deferred_add(name_buf)) continue; if (is_deferred_skip(name_buf)) -- 2.51.0 From 03e00e373cab981ad808271b2650700cfa0fbda6 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Sun, 6 Apr 2025 14:49:20 -0400 Subject: [PATCH 02/16] tools/power turbostat: v2025.05.06 Support up to 8192 processors Add cpuidle governor debug telemetry, disabled by default Update default output to exclude cpuidle invocation counts Bug fixes Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index ab184f95cdaf..1b9fdc1a7ee8 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -9594,7 +9594,7 @@ int get_and_dump_counters(void) void print_version() { - fprintf(outf, "turbostat version 2025.02.02 - Len Brown \n"); + fprintf(outf, "turbostat version 2025.04.06 - Len Brown \n"); } #define COMMAND_LINE_SIZE 2048 -- 2.51.0 From 0efdedb3358aa78102967f242379686f94315830 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 2 Apr 2025 21:21:57 +0100 Subject: [PATCH 03/16] tools/include: make uapi/linux/types.h usable from assembly MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The "real" linux/types.h UAPI header gracefully degrades to a NOOP when included from assembly code. Mirror this behaviour in the tools/ variant. Test for __ASSEMBLER__ over __ASSEMBLY__ as the former is provided by the toolchain automatically. Reported-by: Mark Brown Closes: https://lore.kernel.org/lkml/af553c62-ca2f-4956-932c-dd6e3a126f58@sirena.org.uk/ Fixes: c9fbaa879508 ("selftests: vDSO: parse_vdso: Use UAPI headers instead of libc headers") Signed-off-by: Thomas Weißschuh Link: https://patch.msgid.link/20250321-uapi-consistency-v1-1-439070118dc0@linutronix.de Signed-off-by: Mark Brown Reviewed-by: Mark Brown Signed-off-by: Linus Torvalds --- tools/include/uapi/linux/types.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/include/uapi/linux/types.h b/tools/include/uapi/linux/types.h index 91fa51a9c31d..85aa327245c6 100644 --- a/tools/include/uapi/linux/types.h +++ b/tools/include/uapi/linux/types.h @@ -4,6 +4,8 @@ #include +#ifndef __ASSEMBLER__ + /* copied from linux:include/uapi/linux/types.h */ #define __bitwise typedef __u16 __bitwise __le16; @@ -20,4 +22,5 @@ typedef __u32 __bitwise __wsum; #define __aligned_be64 __be64 __attribute__((aligned(8))) #define __aligned_le64 __le64 __attribute__((aligned(8))) +#endif /* __ASSEMBLER__ */ #endif /* _UAPI_LINUX_TYPES_H */ -- 2.51.0 From 0af2f6be1b4281385b618cb86ad946eded089ac8 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 6 Apr 2025 13:11:33 -0700 Subject: [PATCH 04/16] Linux 6.15-rc1 --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index e55726a71d95..38689a0c3605 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 6 -PATCHLEVEL = 14 +PATCHLEVEL = 15 SUBLEVEL = 0 -EXTRAVERSION = +EXTRAVERSION = -rc1 NAME = Baby Opossum Posse # *DOCUMENTATION* -- 2.51.0 From 9effbfda6bfd677042434722a9c2f2e17d261dce Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Tue, 8 Apr 2025 11:40:41 +0300 Subject: [PATCH 05/16] dt-bindings: regulator: Add ROHM BD96802 PMIC BD96802Qxx-C is an automotive grade configurable Power Management Integrated Circuit supporting Functional Safety features for application processors, SoCs and FPGAs. BD96802 is controlled via I2C, provides two interrupt lines and has two controllable buck regulators. The BD96802 belongs to the family of ROHM Scalable PMICs and is intended to be used as a companion PMIC for the BD96801. Signed-off-by: Matti Vaittinen Acked-by: Conor Dooley Link: https://lore.kernel.org/r/df7983e7c623041f14a4fbe409a2cff846e68a05.1744090658.git.mazziesaccount@gmail.com Signed-off-by: Lee Jones --- .../regulator/rohm,bd96802-regulator.yaml | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/rohm,bd96802-regulator.yaml diff --git a/Documentation/devicetree/bindings/regulator/rohm,bd96802-regulator.yaml b/Documentation/devicetree/bindings/regulator/rohm,bd96802-regulator.yaml new file mode 100644 index 000000000000..671eaf1096d3 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/rohm,bd96802-regulator.yaml @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/rohm,bd96802-regulator.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ROHM BD96802 Power Management Integrated Circuit regulators + +maintainers: + - Matti Vaittinen + +description: + This module is part of the ROHM BD96802 MFD device. For more details + see Documentation/devicetree/bindings/mfd/rohm,bd96802-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 buck1 and buck2. + +patternProperties: + "^buck[1-2]$": + 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 -- 2.51.0 From 9d851b2e016a13b0a673503f5600315b6601e025 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Tue, 8 Apr 2025 11:40:56 +0300 Subject: [PATCH 06/16] dt-bindings: mfd: Add ROHM BD96802 PMIC BD96802Qxx-C is an automotive grade configurable Power Management Integrated Circuit supporting Functional Safety features for application processors, SoCs and FPGAs. BD96802 is controlled via I2C, provides two interrupt lines and has two controllable buck regulators. Signed-off-by: Matti Vaittinen Acked-by: Conor Dooley Link: https://lore.kernel.org/r/ed55edffca3b0a2d7e8bcd9ebd8d8abd9a9b7dfe.1744090658.git.mazziesaccount@gmail.com Signed-off-by: Lee Jones --- .../bindings/mfd/rohm,bd96802-pmic.yaml | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/rohm,bd96802-pmic.yaml diff --git a/Documentation/devicetree/bindings/mfd/rohm,bd96802-pmic.yaml b/Documentation/devicetree/bindings/mfd/rohm,bd96802-pmic.yaml new file mode 100644 index 000000000000..ccabbebf9a29 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/rohm,bd96802-pmic.yaml @@ -0,0 +1,98 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/rohm,bd96802-pmic.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ROHM BD96802 Scalable Power Management Integrated Circuit + +maintainers: + - Matti Vaittinen + +description: | + BD96802Qxx-C is an automotive grade configurable Power Management + Integrated Circuit supporting Functional Safety features for application + processors, SoCs and FPGAs + +properties: + compatible: + const: rohm,bd96802 + + 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. 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 + + regulators: + $ref: ../regulator/rohm,bd96802-regulator.yaml + description: + List of child nodes that specify the regulators. + +required: + - compatible + - reg + - interrupts + - interrupt-names + - regulators + +additionalProperties: false + +examples: + - | + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + pmic: pmic@62 { + reg = <0x62>; + compatible = "rohm,bd96802"; + 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>; + }; + }; + }; + }; -- 2.51.0 From d5a30228b6fa86cf841d8c12af0025c0bacb90fb Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Tue, 8 Apr 2025 11:41:16 +0300 Subject: [PATCH 07/16] dt-bindings: mfd: bd96801: Add ROHM BD96805 The ROHM BD96805 is very similar to the BD96801. The differences visible to the drivers is different tune voltage ranges. Add compatible for the ROHM BD96805 PMIC. Signed-off-by: Matti Vaittinen Acked-by: Conor Dooley Link: https://lore.kernel.org/r/f49addee698b683a071c12808f06a56509152f5c.1744090658.git.mazziesaccount@gmail.com Signed-off-by: Lee Jones --- .../devicetree/bindings/mfd/rohm,bd96801-pmic.yaml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/mfd/rohm,bd96801-pmic.yaml b/Documentation/devicetree/bindings/mfd/rohm,bd96801-pmic.yaml index efee3de0d9ad..0e06570483ae 100644 --- a/Documentation/devicetree/bindings/mfd/rohm,bd96801-pmic.yaml +++ b/Documentation/devicetree/bindings/mfd/rohm,bd96801-pmic.yaml @@ -4,19 +4,21 @@ $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 +title: ROHM BD96801/BD96805 Scalable Power Management Integrated Circuit maintainers: - Matti Vaittinen description: - BD96801 is an automotive grade single-chip power management IC. - It integrates 4 buck converters and 3 LDOs with safety features like + BD96801 and BD96805 are automotive grade, single-chip power management ICs. + They both integrate 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 + enum: + - rohm,bd96801 + - rohm,bd96805 reg: maxItems: 1 -- 2.51.0 From 82c218969eb0ec989d8e049878fd3d6a97ccd8ba Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Tue, 8 Apr 2025 11:44:24 +0300 Subject: [PATCH 08/16] dt-bindings: mfd: bd96802: Add ROHM BD96806 The ROHM BD96806 is very similar to the BD96802. The differences visible to the drivers is different tune voltage ranges. Add compatible for the ROHM BD96805 PMIC. Signed-off-by: Matti Vaittinen Acked-by: Conor Dooley Link: https://lore.kernel.org/r/3c245cc3829dc64d977c97eae7ae8e2be6233481.1744090658.git.mazziesaccount@gmail.com Signed-off-by: Lee Jones --- .../devicetree/bindings/mfd/rohm,bd96802-pmic.yaml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/mfd/rohm,bd96802-pmic.yaml b/Documentation/devicetree/bindings/mfd/rohm,bd96802-pmic.yaml index ccabbebf9a29..6cbea796d12f 100644 --- a/Documentation/devicetree/bindings/mfd/rohm,bd96802-pmic.yaml +++ b/Documentation/devicetree/bindings/mfd/rohm,bd96802-pmic.yaml @@ -4,19 +4,21 @@ $id: http://devicetree.org/schemas/mfd/rohm,bd96802-pmic.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: ROHM BD96802 Scalable Power Management Integrated Circuit +title: ROHM BD96802 / BD96806 Scalable Power Management Integrated Circuit maintainers: - Matti Vaittinen description: | - BD96802Qxx-C is an automotive grade configurable Power Management - Integrated Circuit supporting Functional Safety features for application + BD96802Qxx-C and BD96806 are automotive grade configurable Power Management + Integrated Circuits supporting Functional Safety features for application processors, SoCs and FPGAs properties: compatible: - const: rohm,bd96802 + enum: + - rohm,bd96802 + - rohm,bd96806 reg: maxItems: 1 @@ -27,7 +29,8 @@ properties: 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. In that case it may be + 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 -- 2.51.0 From 7289d96ba557fb5e0a90813b7e24f3815127d14d Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Tue, 8 Apr 2025 11:44:48 +0300 Subject: [PATCH 09/16] mfd: rohm-bd96801: Add chip info Prepare for adding support for BD96802 which is very similar to BD96801. Separate chip specific data into own structure which can be picked based on the type of the IC. Signed-off-by: Matti Vaittinen Acked-by: Conor Dooley Link: https://lore.kernel.org/r/826f9aa28795a2aa70ea41a3688ff9a83ec25a98.1744090658.git.mazziesaccount@gmail.com Signed-off-by: Lee Jones --- drivers/mfd/rohm-bd96801.c | 90 +++++++++++++++++++++++++++----------- 1 file changed, 64 insertions(+), 26 deletions(-) diff --git a/drivers/mfd/rohm-bd96801.c b/drivers/mfd/rohm-bd96801.c index 60ec8db790a7..52e25d7ca888 100644 --- a/drivers/mfd/rohm-bd96801.c +++ b/drivers/mfd/rohm-bd96801.c @@ -40,7 +40,21 @@ #include #include -static const struct resource regulator_errb_irqs[] = { +struct bd968xx { + const struct resource *errb_irqs; + const struct resource *intb_irqs; + int num_errb_irqs; + int num_intb_irqs; + const struct regmap_irq_chip *errb_irq_chip; + const struct regmap_irq_chip *intb_irq_chip; + const struct regmap_config *regmap_config; + struct mfd_cell *cells; + int num_cells; + int unlock_reg; + int unlock_val; +}; + +static const struct resource bd96801_reg_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"), @@ -98,7 +112,7 @@ static const struct resource regulator_errb_irqs[] = { DEFINE_RES_IRQ_NAMED(BD96801_LDO7_SHDN_ERR_STAT, "bd96801-ldo7-shdn-err"), }; -static const struct resource regulator_intb_irqs[] = { +static const struct resource bd96801_reg_intb_irqs[] = { DEFINE_RES_IRQ_NAMED(BD96801_TW_STAT, "bd96801-core-thermal"), DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPH_STAT, "bd96801-buck1-overcurr-h"), @@ -345,18 +359,44 @@ static const struct regmap_config bd96801_regmap_config = { .cache_type = REGCACHE_MAPLE, }; +static const struct bd968xx bd96801_data = { + .errb_irqs = bd96801_reg_errb_irqs, + .intb_irqs = bd96801_reg_intb_irqs, + .num_errb_irqs = ARRAY_SIZE(bd96801_reg_errb_irqs), + .num_intb_irqs = ARRAY_SIZE(bd96801_reg_intb_irqs), + .errb_irq_chip = &bd96801_irq_chip_errb, + .intb_irq_chip = &bd96801_irq_chip_intb, + .regmap_config = &bd96801_regmap_config, + .cells = bd96801_cells, + .num_cells = ARRAY_SIZE(bd96801_cells), + .unlock_reg = BD96801_LOCK_REG, + .unlock_val = BD96801_UNLOCK, +}; + static int bd96801_i2c_probe(struct i2c_client *i2c) { struct regmap_irq_chip_data *intb_irq_data, *errb_irq_data; struct irq_domain *intb_domain, *errb_domain; + const struct bd968xx *ddata; const struct fwnode_handle *fwnode; struct resource *regulator_res; struct resource wdg_irq; struct regmap *regmap; - int intb_irq, errb_irq, num_intb, num_errb = 0; + int intb_irq, errb_irq, num_errb = 0; int num_regu_irqs, wdg_irq_no; + unsigned int chip_type; int i, ret; + chip_type = (unsigned int)(uintptr_t)device_get_match_data(&i2c->dev); + switch (chip_type) { + case ROHM_CHIP_TYPE_BD96801: + ddata = &bd96801_data; + break; + default: + dev_err(&i2c->dev, "Unknown IC\n"); + return -EINVAL; + } + fwnode = dev_fwnode(&i2c->dev); if (!fwnode) return dev_err_probe(&i2c->dev, -EINVAL, "Failed to find fwnode\n"); @@ -365,34 +405,32 @@ 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 == -EPROBE_DEFER) + return errb_irq; - if (errb_irq) - num_errb = ARRAY_SIZE(regulator_errb_irqs); + if (errb_irq > 0) + num_errb = ddata->num_errb_irqs; - num_regu_irqs = num_intb + num_errb; + num_regu_irqs = ddata->num_intb_irqs + num_errb; regulator_res = devm_kcalloc(&i2c->dev, num_regu_irqs, sizeof(*regulator_res), GFP_KERNEL); if (!regulator_res) return -ENOMEM; - regmap = devm_regmap_init_i2c(i2c, &bd96801_regmap_config); + regmap = devm_regmap_init_i2c(i2c, ddata->regmap_config); if (IS_ERR(regmap)) return dev_err_probe(&i2c->dev, PTR_ERR(regmap), "Regmap initialization failed\n"); - ret = regmap_write(regmap, BD96801_LOCK_REG, BD96801_UNLOCK); + ret = regmap_write(regmap, ddata->unlock_reg, ddata->unlock_val); if (ret) return dev_err_probe(&i2c->dev, ret, "Failed to unlock PMIC\n"); ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, intb_irq, - IRQF_ONESHOT, 0, &bd96801_irq_chip_intb, + IRQF_ONESHOT, 0, ddata->intb_irq_chip, &intb_irq_data); if (ret) return dev_err_probe(&i2c->dev, ret, "Failed to add INTB IRQ chip\n"); @@ -404,24 +442,25 @@ static int bd96801_i2c_probe(struct i2c_client *i2c) * 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++) { + for (i = 0; i < ddata->num_intb_irqs; i++) { struct resource *res = ®ulator_res[i]; - *res = regulator_intb_irqs[i]; + *res = ddata->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_cells[WDG_CELL].resources = &wdg_irq; - bd96801_cells[WDG_CELL].num_resources = 1; + + ddata->cells[WDG_CELL].resources = &wdg_irq; + ddata->cells[WDG_CELL].num_resources = 1; if (!num_errb) goto skip_errb; ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, errb_irq, IRQF_ONESHOT, - 0, &bd96801_irq_chip_errb, &errb_irq_data); + 0, ddata->errb_irq_chip, &errb_irq_data); if (ret) return dev_err_probe(&i2c->dev, ret, "Failed to add ERRB IRQ chip\n"); @@ -429,18 +468,17 @@ static int bd96801_i2c_probe(struct i2c_client *i2c) errb_domain = regmap_irq_get_domain(errb_irq_data); for (i = 0; i < num_errb; i++) { - struct resource *res = ®ulator_res[num_intb + i]; + struct resource *res = ®ulator_res[ddata->num_intb_irqs + i]; - *res = regulator_errb_irqs[i]; + *res = ddata->errb_irqs[i]; res->start = res->end = irq_create_mapping(errb_domain, res->start); } skip_errb: - bd96801_cells[REGULATOR_CELL].resources = regulator_res; - bd96801_cells[REGULATOR_CELL].num_resources = num_regu_irqs; - - ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, bd96801_cells, - ARRAY_SIZE(bd96801_cells), NULL, 0, NULL); + ddata->cells[REGULATOR_CELL].resources = regulator_res; + ddata->cells[REGULATOR_CELL].num_resources = num_regu_irqs; + ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, ddata->cells, + ddata->num_cells, NULL, 0, NULL); if (ret) dev_err_probe(&i2c->dev, ret, "Failed to create subdevices\n"); @@ -448,7 +486,7 @@ skip_errb: } static const struct of_device_id bd96801_of_match[] = { - { .compatible = "rohm,bd96801", }, + { .compatible = "rohm,bd96801", .data = (void *)ROHM_CHIP_TYPE_BD96801 }, { } }; MODULE_DEVICE_TABLE(of, bd96801_of_match); -- 2.51.0 From d082571fca4d1db5642ad4436cef22d65bfe4153 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Tue, 8 Apr 2025 11:45:16 +0300 Subject: [PATCH 10/16] mfd: bd96801: Drop IC name from the regulator IRQ resources The resources generated in the BD96801 MFD driver are only visible to the sub-drivers whose resource fields they are added. This makes abbreviating the resource name with the IC name pointless. It just adds confusion in those sub-drivers which do not really care the exact model that generates the IRQ but just want to know the purpose IRQ was generated for. This is a preparatory fix to simplify adding support for ROHM BD96802 PMIC. Signed-off-by: Matti Vaittinen Acked-by: Conor Dooley Link: https://lore.kernel.org/r/0b39a793d925651b1ec2d78e92d47a24849d216b.1744090658.git.mazziesaccount@gmail.com Signed-off-by: Lee Jones --- drivers/mfd/rohm-bd96801.c | 187 +++++++++++++++++++------------------ 1 file changed, 94 insertions(+), 93 deletions(-) diff --git a/drivers/mfd/rohm-bd96801.c b/drivers/mfd/rohm-bd96801.c index 52e25d7ca888..d1d2a4cea605 100644 --- a/drivers/mfd/rohm-bd96801.c +++ b/drivers/mfd/rohm-bd96801.c @@ -55,105 +55,106 @@ struct bd968xx { }; static const struct resource bd96801_reg_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_OTP_ERR_STAT, "otp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_DBIST_ERR_STAT, "dbist-err"), + DEFINE_RES_IRQ_NAMED(BD96801_EEP_ERR_STAT, "eep-err"), + DEFINE_RES_IRQ_NAMED(BD96801_ABIST_ERR_STAT, "abist-err"), + DEFINE_RES_IRQ_NAMED(BD96801_PRSTB_ERR_STAT, "prstb-err"), + DEFINE_RES_IRQ_NAMED(BD96801_DRMOS1_ERR_STAT, "drmoserr1"), + DEFINE_RES_IRQ_NAMED(BD96801_DRMOS2_ERR_STAT, "drmoserr2"), + DEFINE_RES_IRQ_NAMED(BD96801_SLAVE_ERR_STAT, "slave-err"), + DEFINE_RES_IRQ_NAMED(BD96801_VREF_ERR_STAT, "vref-err"), + DEFINE_RES_IRQ_NAMED(BD96801_TSD_ERR_STAT, "tsd"), + DEFINE_RES_IRQ_NAMED(BD96801_UVLO_ERR_STAT, "uvlo-err"), + DEFINE_RES_IRQ_NAMED(BD96801_OVLO_ERR_STAT, "ovlo-err"), + DEFINE_RES_IRQ_NAMED(BD96801_OSC_ERR_STAT, "osc-err"), + DEFINE_RES_IRQ_NAMED(BD96801_PON_ERR_STAT, "pon-err"), + DEFINE_RES_IRQ_NAMED(BD96801_POFF_ERR_STAT, "poff-err"), + DEFINE_RES_IRQ_NAMED(BD96801_CMD_SHDN_ERR_STAT, "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"), + + DEFINE_RES_IRQ_NAMED(BD96801_INT_SHDN_ERR_STAT, "int-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_PVIN_ERR_STAT, "buck1-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OVP_ERR_STAT, "buck1-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_UVP_ERR_STAT, "buck1-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_SHDN_ERR_STAT, "buck1-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_PVIN_ERR_STAT, "buck2-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OVP_ERR_STAT, "buck2-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_UVP_ERR_STAT, "buck2-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_SHDN_ERR_STAT, "buck2-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_PVIN_ERR_STAT, "buck3-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OVP_ERR_STAT, "buck3-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_UVP_ERR_STAT, "buck3-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_SHDN_ERR_STAT, "buck3-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_PVIN_ERR_STAT, "buck4-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OVP_ERR_STAT, "buck4-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_UVP_ERR_STAT, "buck4-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_SHDN_ERR_STAT, "buck4-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_PVIN_ERR_STAT, "ldo5-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_OVP_ERR_STAT, "ldo5-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_UVP_ERR_STAT, "ldo5-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_SHDN_ERR_STAT, "ldo5-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_PVIN_ERR_STAT, "ldo6-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_OVP_ERR_STAT, "ldo6-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_UVP_ERR_STAT, "ldo6-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_SHDN_ERR_STAT, "ldo6-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_PVIN_ERR_STAT, "ldo7-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_OVP_ERR_STAT, "ldo7-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_UVP_ERR_STAT, "ldo7-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_SHDN_ERR_STAT, "ldo7-shdn-err"), }; static const struct resource bd96801_reg_intb_irqs[] = { - DEFINE_RES_IRQ_NAMED(BD96801_TW_STAT, "bd96801-core-thermal"), - - DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPH_STAT, "bd96801-buck1-overcurr-h"), - DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPL_STAT, "bd96801-buck1-overcurr-l"), - DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPN_STAT, "bd96801-buck1-overcurr-n"), - DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OVD_STAT, "bd96801-buck1-overvolt"), - DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_UVD_STAT, "bd96801-buck1-undervolt"), - DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_TW_CH_STAT, "bd96801-buck1-thermal"), - - DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPH_STAT, "bd96801-buck2-overcurr-h"), - DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPL_STAT, "bd96801-buck2-overcurr-l"), - DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPN_STAT, "bd96801-buck2-overcurr-n"), - DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OVD_STAT, "bd96801-buck2-overvolt"), - DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_UVD_STAT, "bd96801-buck2-undervolt"), - DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_TW_CH_STAT, "bd96801-buck2-thermal"), - - DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPH_STAT, "bd96801-buck3-overcurr-h"), - DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPL_STAT, "bd96801-buck3-overcurr-l"), - DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPN_STAT, "bd96801-buck3-overcurr-n"), - DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OVD_STAT, "bd96801-buck3-overvolt"), - DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_UVD_STAT, "bd96801-buck3-undervolt"), - DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_TW_CH_STAT, "bd96801-buck3-thermal"), - - DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPH_STAT, "bd96801-buck4-overcurr-h"), - DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPL_STAT, "bd96801-buck4-overcurr-l"), - DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPN_STAT, "bd96801-buck4-overcurr-n"), - DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OVD_STAT, "bd96801-buck4-overvolt"), - DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_UVD_STAT, "bd96801-buck4-undervolt"), - DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_TW_CH_STAT, "bd96801-buck4-thermal"), - - DEFINE_RES_IRQ_NAMED(BD96801_LDO5_OCPH_STAT, "bd96801-ldo5-overcurr"), - DEFINE_RES_IRQ_NAMED(BD96801_LDO5_OVD_STAT, "bd96801-ldo5-overvolt"), - DEFINE_RES_IRQ_NAMED(BD96801_LDO5_UVD_STAT, "bd96801-ldo5-undervolt"), - - DEFINE_RES_IRQ_NAMED(BD96801_LDO6_OCPH_STAT, "bd96801-ldo6-overcurr"), - DEFINE_RES_IRQ_NAMED(BD96801_LDO6_OVD_STAT, "bd96801-ldo6-overvolt"), - DEFINE_RES_IRQ_NAMED(BD96801_LDO6_UVD_STAT, "bd96801-ldo6-undervolt"), - - DEFINE_RES_IRQ_NAMED(BD96801_LDO7_OCPH_STAT, "bd96801-ldo7-overcurr"), - DEFINE_RES_IRQ_NAMED(BD96801_LDO7_OVD_STAT, "bd96801-ldo7-overvolt"), - DEFINE_RES_IRQ_NAMED(BD96801_LDO7_UVD_STAT, "bd96801-ldo7-undervolt"), + DEFINE_RES_IRQ_NAMED(BD96801_TW_STAT, "core-thermal"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPH_STAT, "buck1-overcurr-h"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPL_STAT, "buck1-overcurr-l"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPN_STAT, "buck1-overcurr-n"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OVD_STAT, "buck1-overvolt"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_UVD_STAT, "buck1-undervolt"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_TW_CH_STAT, "buck1-thermal"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPH_STAT, "buck2-overcurr-h"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPL_STAT, "buck2-overcurr-l"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPN_STAT, "buck2-overcurr-n"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OVD_STAT, "buck2-overvolt"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_UVD_STAT, "buck2-undervolt"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_TW_CH_STAT, "buck2-thermal"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPH_STAT, "buck3-overcurr-h"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPL_STAT, "buck3-overcurr-l"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPN_STAT, "buck3-overcurr-n"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OVD_STAT, "buck3-overvolt"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_UVD_STAT, "buck3-undervolt"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_TW_CH_STAT, "buck3-thermal"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPH_STAT, "buck4-overcurr-h"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPL_STAT, "buck4-overcurr-l"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPN_STAT, "buck4-overcurr-n"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OVD_STAT, "buck4-overvolt"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_UVD_STAT, "buck4-undervolt"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_TW_CH_STAT, "buck4-thermal"), + + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_OCPH_STAT, "ldo5-overcurr"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_OVD_STAT, "ldo5-overvolt"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_UVD_STAT, "ldo5-undervolt"), + + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_OCPH_STAT, "ldo6-overcurr"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_OVD_STAT, "ldo6-overvolt"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_UVD_STAT, "ldo6-undervolt"), + + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_OCPH_STAT, "ldo7-overcurr"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_OVD_STAT, "ldo7-overvolt"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_UVD_STAT, "ldo7-undervolt"), }; enum { -- 2.51.0 From 9cc957546e3865bc3adfd39ceeedc8074521024d Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Tue, 8 Apr 2025 11:45:34 +0300 Subject: [PATCH 11/16] regulator: bd96801: Drop IC name from the IRQ resources The resources generated in the BD96801 MFD driver are only visible to the sub-drivers whose resource fields they are added. This makes abbreviating the resource name with the IC name pointless. It just adds confusion in those sub-drivers which do not really care the exact model that generates the IRQ but just want to know the purpose IRQ was generated for. Thus, as a preparatory fix to simplify adding support for ROHM BD96802 PMIC the IC name "bd96801-" prefix was dropped from the IRQ resource names. Adapt the regulator driver to this change. Signed-off-by: Matti Vaittinen Reviewed-by: Mark Brown Acked-by: Conor Dooley Link: https://lore.kernel.org/r/73ec2425655ab19c9f0cf990419641ad36561590.1744090658.git.mazziesaccount@gmail.com Signed-off-by: Lee Jones --- drivers/regulator/bd96801-regulator.c | 83 +++++++++++++-------------- 1 file changed, 40 insertions(+), 43 deletions(-) diff --git a/drivers/regulator/bd96801-regulator.c b/drivers/regulator/bd96801-regulator.c index 3a9d772491a8..48cdd583e92d 100644 --- a/drivers/regulator/bd96801-regulator.c +++ b/drivers/regulator/bd96801-regulator.c @@ -198,89 +198,89 @@ struct bd96801_irqinfo { static const struct bd96801_irqinfo buck1_irqinfo[] = { BD96801_IRQINFO(BD96801_PROT_OCP, "buck1-over-curr-h", 500, - "bd96801-buck1-overcurr-h"), + "buck1-overcurr-h"), BD96801_IRQINFO(BD96801_PROT_OCP, "buck1-over-curr-l", 500, - "bd96801-buck1-overcurr-l"), + "buck1-overcurr-l"), BD96801_IRQINFO(BD96801_PROT_OCP, "buck1-over-curr-n", 500, - "bd96801-buck1-overcurr-n"), + "buck1-overcurr-n"), BD96801_IRQINFO(BD96801_PROT_OVP, "buck1-over-voltage", 500, - "bd96801-buck1-overvolt"), + "buck1-overvolt"), BD96801_IRQINFO(BD96801_PROT_UVP, "buck1-under-voltage", 500, - "bd96801-buck1-undervolt"), + "buck1-undervolt"), BD96801_IRQINFO(BD96801_PROT_TEMP, "buck1-over-temp", 500, - "bd96801-buck1-thermal") + "buck1-thermal") }; static const struct bd96801_irqinfo buck2_irqinfo[] = { BD96801_IRQINFO(BD96801_PROT_OCP, "buck2-over-curr-h", 500, - "bd96801-buck2-overcurr-h"), + "buck2-overcurr-h"), BD96801_IRQINFO(BD96801_PROT_OCP, "buck2-over-curr-l", 500, - "bd96801-buck2-overcurr-l"), + "buck2-overcurr-l"), BD96801_IRQINFO(BD96801_PROT_OCP, "buck2-over-curr-n", 500, - "bd96801-buck2-overcurr-n"), + "buck2-overcurr-n"), BD96801_IRQINFO(BD96801_PROT_OVP, "buck2-over-voltage", 500, - "bd96801-buck2-overvolt"), + "buck2-overvolt"), BD96801_IRQINFO(BD96801_PROT_UVP, "buck2-under-voltage", 500, - "bd96801-buck2-undervolt"), + "buck2-undervolt"), BD96801_IRQINFO(BD96801_PROT_TEMP, "buck2-over-temp", 500, - "bd96801-buck2-thermal") + "buck2-thermal") }; static const struct bd96801_irqinfo buck3_irqinfo[] = { BD96801_IRQINFO(BD96801_PROT_OCP, "buck3-over-curr-h", 500, - "bd96801-buck3-overcurr-h"), + "buck3-overcurr-h"), BD96801_IRQINFO(BD96801_PROT_OCP, "buck3-over-curr-l", 500, - "bd96801-buck3-overcurr-l"), + "buck3-overcurr-l"), BD96801_IRQINFO(BD96801_PROT_OCP, "buck3-over-curr-n", 500, - "bd96801-buck3-overcurr-n"), + "buck3-overcurr-n"), BD96801_IRQINFO(BD96801_PROT_OVP, "buck3-over-voltage", 500, - "bd96801-buck3-overvolt"), + "buck3-overvolt"), BD96801_IRQINFO(BD96801_PROT_UVP, "buck3-under-voltage", 500, - "bd96801-buck3-undervolt"), + "buck3-undervolt"), BD96801_IRQINFO(BD96801_PROT_TEMP, "buck3-over-temp", 500, - "bd96801-buck3-thermal") + "buck3-thermal") }; static const struct bd96801_irqinfo buck4_irqinfo[] = { BD96801_IRQINFO(BD96801_PROT_OCP, "buck4-over-curr-h", 500, - "bd96801-buck4-overcurr-h"), + "buck4-overcurr-h"), BD96801_IRQINFO(BD96801_PROT_OCP, "buck4-over-curr-l", 500, - "bd96801-buck4-overcurr-l"), + "buck4-overcurr-l"), BD96801_IRQINFO(BD96801_PROT_OCP, "buck4-over-curr-n", 500, - "bd96801-buck4-overcurr-n"), + "buck4-overcurr-n"), BD96801_IRQINFO(BD96801_PROT_OVP, "buck4-over-voltage", 500, - "bd96801-buck4-overvolt"), + "buck4-overvolt"), BD96801_IRQINFO(BD96801_PROT_UVP, "buck4-under-voltage", 500, - "bd96801-buck4-undervolt"), + "buck4-undervolt"), BD96801_IRQINFO(BD96801_PROT_TEMP, "buck4-over-temp", 500, - "bd96801-buck4-thermal") + "buck4-thermal") }; static const struct bd96801_irqinfo ldo5_irqinfo[] = { BD96801_IRQINFO(BD96801_PROT_OCP, "ldo5-overcurr", 500, - "bd96801-ldo5-overcurr"), + "ldo5-overcurr"), BD96801_IRQINFO(BD96801_PROT_OVP, "ldo5-over-voltage", 500, - "bd96801-ldo5-overvolt"), + "ldo5-overvolt"), BD96801_IRQINFO(BD96801_PROT_UVP, "ldo5-under-voltage", 500, - "bd96801-ldo5-undervolt"), + "ldo5-undervolt"), }; static const struct bd96801_irqinfo ldo6_irqinfo[] = { BD96801_IRQINFO(BD96801_PROT_OCP, "ldo6-overcurr", 500, - "bd96801-ldo6-overcurr"), + "ldo6-overcurr"), BD96801_IRQINFO(BD96801_PROT_OVP, "ldo6-over-voltage", 500, - "bd96801-ldo6-overvolt"), + "ldo6-overvolt"), BD96801_IRQINFO(BD96801_PROT_UVP, "ldo6-under-voltage", 500, - "bd96801-ldo6-undervolt"), + "ldo6-undervolt"), }; static const struct bd96801_irqinfo ldo7_irqinfo[] = { BD96801_IRQINFO(BD96801_PROT_OCP, "ldo7-overcurr", 500, - "bd96801-ldo7-overcurr"), + "ldo7-overcurr"), BD96801_IRQINFO(BD96801_PROT_OVP, "ldo7-over-voltage", 500, - "bd96801-ldo7-overvolt"), + "ldo7-overvolt"), BD96801_IRQINFO(BD96801_PROT_UVP, "ldo7-under-voltage", 500, - "bd96801-ldo7-undervolt"), + "ldo7-undervolt"), }; struct bd96801_irq_desc { @@ -741,8 +741,7 @@ static int bd96801_rdev_errb_irqs(struct platform_device *pdev, 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", + "%s-pvin-err", "%s-ovp-err", "%s-uvp-err", "%s-shdn-err", }; for (i = 0; i < ARRAY_SIZE(single_out_errb_irqs); i++) { @@ -779,12 +778,10 @@ static int bd96801_global_errb_irqs(struct platform_device *pdev, 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" + "otp-err", "dbist-err", "eep-err", "abist-err", "prstb-err", + "drmoserr1", "drmoserr2", "slave-err", "vref-err", "tsd", + "uvlo-err", "ovlo-err", "osc-err", "pon-err", "poff-err", + "cmd-shdn-err", "int-shdn-err" }; num_irqs = ARRAY_SIZE(global_errb_irqs); @@ -956,12 +953,12 @@ static int bd96801_probe(struct platform_device *pdev) if (temp_notif_ldos) { int irq; struct regulator_irq_desc tw_desc = { - .name = "bd96801-core-thermal", + .name = "core-thermal", .irq_off_ms = 500, .map_event = ldo_map_notif, }; - irq = platform_get_irq_byname(pdev, "bd96801-core-thermal"); + irq = platform_get_irq_byname(pdev, "core-thermal"); if (irq < 0) return irq; -- 2.51.0 From 4094040b1a133206ed893da2cf5e17cc22f7ca7c Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Tue, 8 Apr 2025 11:45:59 +0300 Subject: [PATCH 12/16] mfd: rohm-bd96801: Support ROHM BD96802 The ROHM BD96802 PMIC looks from software point of view a lot like ROHM BD96801 PMIC. Just with reduced number of voltage rails. Both PMICs provide two physical IRQ lines referred as INTB and ERRB and contain blocks implementing regulator controls and a weatchdog. Hence it makes sense to use same MFD core for both PMICs. Add support for ROHM BD96802 scalable companion PMIC to the BD96801 core driver. Signed-off-by: Matti Vaittinen Acked-by: Conor Dooley Link: https://lore.kernel.org/r/05957d194425a79a4f35f287695c3d9ca2ed1ae2.1744090658.git.mazziesaccount@gmail.com Signed-off-by: Lee Jones --- drivers/mfd/rohm-bd96801.c | 239 ++++++++++++++++++++++++++++++- include/linux/mfd/rohm-bd96801.h | 2 + include/linux/mfd/rohm-bd96802.h | 74 ++++++++++ include/linux/mfd/rohm-generic.h | 1 + 4 files changed, 311 insertions(+), 5 deletions(-) create mode 100644 include/linux/mfd/rohm-bd96802.h diff --git a/drivers/mfd/rohm-bd96801.c b/drivers/mfd/rohm-bd96801.c index d1d2a4cea605..e5ee5f556a55 100644 --- a/drivers/mfd/rohm-bd96801.c +++ b/drivers/mfd/rohm-bd96801.c @@ -38,6 +38,7 @@ #include #include +#include #include struct bd968xx { @@ -113,6 +114,36 @@ static const struct resource bd96801_reg_errb_irqs[] = { DEFINE_RES_IRQ_NAMED(BD96801_LDO7_SHDN_ERR_STAT, "ldo7-shdn-err"), }; +static const struct resource bd96802_reg_errb_irqs[] = { + DEFINE_RES_IRQ_NAMED(BD96802_OTP_ERR_STAT, "otp-err"), + DEFINE_RES_IRQ_NAMED(BD96802_DBIST_ERR_STAT, "dbist-err"), + DEFINE_RES_IRQ_NAMED(BD96802_EEP_ERR_STAT, "eep-err"), + DEFINE_RES_IRQ_NAMED(BD96802_ABIST_ERR_STAT, "abist-err"), + DEFINE_RES_IRQ_NAMED(BD96802_PRSTB_ERR_STAT, "prstb-err"), + DEFINE_RES_IRQ_NAMED(BD96802_DRMOS1_ERR_STAT, "drmoserr1"), + DEFINE_RES_IRQ_NAMED(BD96802_DRMOS1_ERR_STAT, "drmoserr2"), + DEFINE_RES_IRQ_NAMED(BD96802_SLAVE_ERR_STAT, "slave-err"), + DEFINE_RES_IRQ_NAMED(BD96802_VREF_ERR_STAT, "vref-err"), + DEFINE_RES_IRQ_NAMED(BD96802_TSD_ERR_STAT, "tsd"), + DEFINE_RES_IRQ_NAMED(BD96802_UVLO_ERR_STAT, "uvlo-err"), + DEFINE_RES_IRQ_NAMED(BD96802_OVLO_ERR_STAT, "ovlo-err"), + DEFINE_RES_IRQ_NAMED(BD96802_OSC_ERR_STAT, "osc-err"), + DEFINE_RES_IRQ_NAMED(BD96802_PON_ERR_STAT, "pon-err"), + DEFINE_RES_IRQ_NAMED(BD96802_POFF_ERR_STAT, "poff-err"), + DEFINE_RES_IRQ_NAMED(BD96802_CMD_SHDN_ERR_STAT, "cmd-shdn-err"), + DEFINE_RES_IRQ_NAMED(BD96802_INT_SHDN_ERR_STAT, "int-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_PVIN_ERR_STAT, "buck1-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_OVP_ERR_STAT, "buck1-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_UVP_ERR_STAT, "buck1-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_SHDN_ERR_STAT, "buck1-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_PVIN_ERR_STAT, "buck2-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_OVP_ERR_STAT, "buck2-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_UVP_ERR_STAT, "buck2-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_SHDN_ERR_STAT, "buck2-shdn-err"), +}; + static const struct resource bd96801_reg_intb_irqs[] = { DEFINE_RES_IRQ_NAMED(BD96801_TW_STAT, "core-thermal"), @@ -157,6 +188,24 @@ static const struct resource bd96801_reg_intb_irqs[] = { DEFINE_RES_IRQ_NAMED(BD96801_LDO7_UVD_STAT, "ldo7-undervolt"), }; +static const struct resource bd96802_reg_intb_irqs[] = { + DEFINE_RES_IRQ_NAMED(BD96802_TW_STAT, "core-thermal"), + + DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_OCPH_STAT, "buck1-overcurr-h"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_OCPL_STAT, "buck1-overcurr-l"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_OCPN_STAT, "buck1-overcurr-n"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_OVD_STAT, "buck1-overvolt"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_UVD_STAT, "buck1-undervolt"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_TW_CH_STAT, "buck1-thermal"), + + DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_OCPH_STAT, "buck2-overcurr-h"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_OCPL_STAT, "buck2-overcurr-l"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_OCPN_STAT, "buck2-overcurr-n"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_OVD_STAT, "buck2-overvolt"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_UVD_STAT, "buck2-undervolt"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_TW_CH_STAT, "buck2-thermal"), +}; + enum { WDG_CELL = 0, REGULATOR_CELL, @@ -167,6 +216,11 @@ static struct mfd_cell bd96801_cells[] = { [REGULATOR_CELL] = { .name = "bd96801-regulator", }, }; +static struct mfd_cell bd96802_cells[] = { + [WDG_CELL] = { .name = "bd96801-wdt", }, + [REGULATOR_CELL] = { .name = "bd96802-regulator", }, +}; + static const struct regmap_range bd96801_volatile_ranges[] = { /* Status registers */ regmap_reg_range(BD96801_REG_WD_FEED, BD96801_REG_WD_FAILCOUNT), @@ -184,11 +238,28 @@ static const struct regmap_range bd96801_volatile_ranges[] = { regmap_reg_range(BD96801_LDO5_VOL_LVL_REG, BD96801_LDO7_VOL_LVL_REG), }; -static const struct regmap_access_table volatile_regs = { +static const struct regmap_range bd96802_volatile_ranges[] = { + /* Status regs */ + regmap_reg_range(BD96801_REG_WD_FEED, BD96801_REG_WD_FAILCOUNT), + regmap_reg_range(BD96801_REG_WD_ASK, BD96801_REG_WD_ASK), + regmap_reg_range(BD96801_REG_WD_STATUS, BD96801_REG_WD_STATUS), + regmap_reg_range(BD96801_REG_PMIC_STATE, BD96801_REG_INT_BUCK2_ERRB), + regmap_reg_range(BD96801_REG_INT_SYS_INTB, BD96801_REG_INT_BUCK2_INTB), + /* Registers which do not update value unless PMIC is in STBY */ + regmap_reg_range(BD96801_REG_SSCG_CTRL, BD96801_REG_SHD_INTB), + regmap_reg_range(BD96801_REG_BUCK_OVP, BD96801_REG_BOOT_OVERTIME), +}; + +static const struct regmap_access_table bd96801_volatile_regs = { .yes_ranges = bd96801_volatile_ranges, .n_yes_ranges = ARRAY_SIZE(bd96801_volatile_ranges), }; +static const struct regmap_access_table bd96802_volatile_regs = { + .yes_ranges = bd96802_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(bd96802_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 @@ -203,7 +274,7 @@ 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 const struct regmap_irq_sub_irq_map errb_sub_irq_offsets[] = { +static const struct regmap_irq_sub_irq_map bd96801_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), @@ -214,6 +285,12 @@ static const struct regmap_irq_sub_irq_map errb_sub_irq_offsets[] = { REGMAP_IRQ_MAIN_REG_OFFSET(bit7_offsets), }; +static const struct regmap_irq_sub_irq_map bd96802_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), +}; + static const struct regmap_irq bd96801_errb_irqs[] = { /* Reg 0x52 Fatal ERRB1 */ REGMAP_IRQ_REG(BD96801_OTP_ERR_STAT, 0, BD96801_OTP_ERR_MASK), @@ -274,6 +351,39 @@ static const struct regmap_irq bd96801_errb_irqs[] = { REGMAP_IRQ_REG(BD96801_LDO7_SHDN_ERR_STAT, 9, BD96801_OUT_SHDN_ERR_MASK), }; +static const struct regmap_irq bd96802_errb_irqs[] = { + /* Reg 0x52 Fatal ERRB1 */ + REGMAP_IRQ_REG(BD96802_OTP_ERR_STAT, 0, BD96801_OTP_ERR_MASK), + REGMAP_IRQ_REG(BD96802_DBIST_ERR_STAT, 0, BD96801_DBIST_ERR_MASK), + REGMAP_IRQ_REG(BD96802_EEP_ERR_STAT, 0, BD96801_EEP_ERR_MASK), + REGMAP_IRQ_REG(BD96802_ABIST_ERR_STAT, 0, BD96801_ABIST_ERR_MASK), + REGMAP_IRQ_REG(BD96802_PRSTB_ERR_STAT, 0, BD96801_PRSTB_ERR_MASK), + REGMAP_IRQ_REG(BD96802_DRMOS1_ERR_STAT, 0, BD96801_DRMOS1_ERR_MASK), + REGMAP_IRQ_REG(BD96802_DRMOS2_ERR_STAT, 0, BD96801_DRMOS2_ERR_MASK), + REGMAP_IRQ_REG(BD96802_SLAVE_ERR_STAT, 0, BD96801_SLAVE_ERR_MASK), + /* 0x53 Fatal ERRB2 */ + REGMAP_IRQ_REG(BD96802_VREF_ERR_STAT, 1, BD96801_VREF_ERR_MASK), + REGMAP_IRQ_REG(BD96802_TSD_ERR_STAT, 1, BD96801_TSD_ERR_MASK), + REGMAP_IRQ_REG(BD96802_UVLO_ERR_STAT, 1, BD96801_UVLO_ERR_MASK), + REGMAP_IRQ_REG(BD96802_OVLO_ERR_STAT, 1, BD96801_OVLO_ERR_MASK), + REGMAP_IRQ_REG(BD96802_OSC_ERR_STAT, 1, BD96801_OSC_ERR_MASK), + REGMAP_IRQ_REG(BD96802_PON_ERR_STAT, 1, BD96801_PON_ERR_MASK), + REGMAP_IRQ_REG(BD96802_POFF_ERR_STAT, 1, BD96801_POFF_ERR_MASK), + REGMAP_IRQ_REG(BD96802_CMD_SHDN_ERR_STAT, 1, BD96801_CMD_SHDN_ERR_MASK), + /* 0x54 Fatal INTB shadowed to ERRB */ + REGMAP_IRQ_REG(BD96802_INT_SHDN_ERR_STAT, 2, BD96801_INT_SHDN_ERR_MASK), + /* Reg 0x55 BUCK1 ERR IRQs */ + REGMAP_IRQ_REG(BD96802_BUCK1_PVIN_ERR_STAT, 3, BD96801_OUT_PVIN_ERR_MASK), + REGMAP_IRQ_REG(BD96802_BUCK1_OVP_ERR_STAT, 3, BD96801_OUT_OVP_ERR_MASK), + REGMAP_IRQ_REG(BD96802_BUCK1_UVP_ERR_STAT, 3, BD96801_OUT_UVP_ERR_MASK), + REGMAP_IRQ_REG(BD96802_BUCK1_SHDN_ERR_STAT, 3, BD96801_OUT_SHDN_ERR_MASK), + /* Reg 0x56 BUCK2 ERR IRQs */ + REGMAP_IRQ_REG(BD96802_BUCK2_PVIN_ERR_STAT, 4, BD96801_OUT_PVIN_ERR_MASK), + REGMAP_IRQ_REG(BD96802_BUCK2_OVP_ERR_STAT, 4, BD96801_OUT_OVP_ERR_MASK), + REGMAP_IRQ_REG(BD96802_BUCK2_UVP_ERR_STAT, 4, BD96801_OUT_UVP_ERR_MASK), + REGMAP_IRQ_REG(BD96802_BUCK2_SHDN_ERR_STAT, 4, 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), @@ -322,6 +432,69 @@ static const struct regmap_irq bd96801_intb_irqs[] = { REGMAP_IRQ_REG(BD96801_LDO7_UVD_STAT, 7, BD96801_LDO_UVD_STAT_MASK), }; +static const struct regmap_irq bd96802_intb_irqs[] = { + /* STATUS SYSTEM INTB */ + REGMAP_IRQ_REG(BD96802_TW_STAT, 0, BD96801_TW_STAT_MASK), + REGMAP_IRQ_REG(BD96802_WDT_ERR_STAT, 0, BD96801_WDT_ERR_STAT_MASK), + REGMAP_IRQ_REG(BD96802_I2C_ERR_STAT, 0, BD96801_I2C_ERR_STAT_MASK), + REGMAP_IRQ_REG(BD96802_CHIP_IF_ERR_STAT, 0, BD96801_CHIP_IF_ERR_STAT_MASK), + /* STATUS BUCK1 INTB */ + REGMAP_IRQ_REG(BD96802_BUCK1_OCPH_STAT, 1, BD96801_BUCK_OCPH_STAT_MASK), + REGMAP_IRQ_REG(BD96802_BUCK1_OCPL_STAT, 1, BD96801_BUCK_OCPL_STAT_MASK), + REGMAP_IRQ_REG(BD96802_BUCK1_OCPN_STAT, 1, BD96801_BUCK_OCPN_STAT_MASK), + REGMAP_IRQ_REG(BD96802_BUCK1_OVD_STAT, 1, BD96801_BUCK_OVD_STAT_MASK), + REGMAP_IRQ_REG(BD96802_BUCK1_UVD_STAT, 1, BD96801_BUCK_UVD_STAT_MASK), + REGMAP_IRQ_REG(BD96802_BUCK1_TW_CH_STAT, 1, BD96801_BUCK_TW_CH_STAT_MASK), + /* BUCK 2 INTB */ + REGMAP_IRQ_REG(BD96802_BUCK2_OCPH_STAT, 2, BD96801_BUCK_OCPH_STAT_MASK), + REGMAP_IRQ_REG(BD96802_BUCK2_OCPL_STAT, 2, BD96801_BUCK_OCPL_STAT_MASK), + REGMAP_IRQ_REG(BD96802_BUCK2_OCPN_STAT, 2, BD96801_BUCK_OCPN_STAT_MASK), + REGMAP_IRQ_REG(BD96802_BUCK2_OVD_STAT, 2, BD96801_BUCK_OVD_STAT_MASK), + REGMAP_IRQ_REG(BD96802_BUCK2_UVD_STAT, 2, BD96801_BUCK_UVD_STAT_MASK), + REGMAP_IRQ_REG(BD96802_BUCK2_TW_CH_STAT, 2, BD96801_BUCK_TW_CH_STAT_MASK), +}; + +/* + * The IRQ stuff is a bit hairy. The BD96801 / BD96802 provide two physical + * IRQ lines called INTB and ERRB. They share the same main status register. + * + * For ERRB, mapping from main status to sub-status is such that the + * 'global' faults are mapped to first 3 sub-status registers - and indicated + * by the first bit[0] in main status reg. + * + * Rest of the status registers are for indicating stuff for individual + * regulators, 1 sub register / regulator and 1 main status register bit / + * regulator, starting from bit[1]. + * + * Eg, regulator specific stuff has 1 to 1 mapping from main-status to sub + * registers but 'global' ERRB IRQs require mapping from main status bit[0] to + * 3 status registers. + * + * Furthermore, the BD96801 has 7 regulators where the BD96802 has only 2. + * + * INTB has only 1 sub status register for 'global' events and then own sub + * status register for each of the regulators. So, for INTB we have direct + * 1 to 1 mapping - BD96801 just having 5 register and 5 main status bits + * more than the BD96802. + * + * Sharing the main status bits could be a problem if we had both INTB and + * ERRB IRQs asserted but for different sub-status offsets. This might lead + * IRQ controller code to go read a sub status register which indicates no + * active IRQs. I assume this occurring repeteadly might lead the IRQ to be + * disabled by core as a result of repeteadly returned IRQ_NONEs. + * + * I don't consider this as a fatal problem for now because: + * a) Having ERRB asserted leads to PMIC fault state which will kill + * the SoC powered by the PMIC. (So, relevant only for potential + * case of not powering the processor with this PMIC). + * b) Having ERRB set without having respective INTB is unlikely + * (haven't actually verified this). + * + * So, let's proceed with main status enabled for both INTB and ERRB. We can + * later disable main-status usage on systems where this ever proves to be + * a problem. + */ + static const struct regmap_irq_chip bd96801_irq_chip_errb = { .name = "bd96801-irq-errb", .domain_suffix = "errb", @@ -335,7 +508,23 @@ static const struct regmap_irq_chip bd96801_irq_chip_errb = { .init_ack_masked = true, .num_regs = 10, .irq_reg_stride = 1, - .sub_reg_offsets = &errb_sub_irq_offsets[0], + .sub_reg_offsets = &bd96801_errb_sub_irq_offsets[0], +}; + +static const struct regmap_irq_chip bd96802_irq_chip_errb = { + .name = "bd96802-irq-errb", + .domain_suffix = "errb", + .main_status = BD96801_REG_INT_MAIN, + .num_main_regs = 1, + .irqs = &bd96802_errb_irqs[0], + .num_irqs = ARRAY_SIZE(bd96802_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 = 5, + .irq_reg_stride = 1, + .sub_reg_offsets = &bd96802_errb_sub_irq_offsets[0], }; static const struct regmap_irq_chip bd96801_irq_chip_intb = { @@ -353,10 +542,32 @@ static const struct regmap_irq_chip bd96801_irq_chip_intb = { .irq_reg_stride = 1, }; +static const struct regmap_irq_chip bd96802_irq_chip_intb = { + .name = "bd96802-irq-intb", + .domain_suffix = "intb", + .main_status = BD96801_REG_INT_MAIN, + .num_main_regs = 1, + .irqs = &bd96802_intb_irqs[0], + .num_irqs = ARRAY_SIZE(bd96802_intb_irqs), + .status_base = BD96801_REG_INT_SYS_INTB, + .mask_base = BD96801_REG_MASK_SYS_INTB, + .ack_base = BD96801_REG_INT_SYS_INTB, + .init_ack_masked = true, + .num_regs = 3, + .irq_reg_stride = 1, +}; + static const struct regmap_config bd96801_regmap_config = { .reg_bits = 8, .val_bits = 8, - .volatile_table = &volatile_regs, + .volatile_table = &bd96801_volatile_regs, + .cache_type = REGCACHE_MAPLE, +}; + +static const struct regmap_config bd96802_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_table = &bd96802_volatile_regs, .cache_type = REGCACHE_MAPLE, }; @@ -374,6 +585,20 @@ static const struct bd968xx bd96801_data = { .unlock_val = BD96801_UNLOCK, }; +static const struct bd968xx bd96802_data = { + .errb_irqs = bd96802_reg_errb_irqs, + .intb_irqs = bd96802_reg_intb_irqs, + .num_errb_irqs = ARRAY_SIZE(bd96802_reg_errb_irqs), + .num_intb_irqs = ARRAY_SIZE(bd96802_reg_intb_irqs), + .errb_irq_chip = &bd96802_irq_chip_errb, + .intb_irq_chip = &bd96802_irq_chip_intb, + .regmap_config = &bd96802_regmap_config, + .cells = bd96802_cells, + .num_cells = ARRAY_SIZE(bd96802_cells), + .unlock_reg = BD96801_LOCK_REG, + .unlock_val = BD96801_UNLOCK, +}; + static int bd96801_i2c_probe(struct i2c_client *i2c) { struct regmap_irq_chip_data *intb_irq_data, *errb_irq_data; @@ -393,6 +618,9 @@ static int bd96801_i2c_probe(struct i2c_client *i2c) case ROHM_CHIP_TYPE_BD96801: ddata = &bd96801_data; break; + case ROHM_CHIP_TYPE_BD96802: + ddata = &bd96802_data; + break; default: dev_err(&i2c->dev, "Unknown IC\n"); return -EINVAL; @@ -488,6 +716,7 @@ skip_errb: static const struct of_device_id bd96801_of_match[] = { { .compatible = "rohm,bd96801", .data = (void *)ROHM_CHIP_TYPE_BD96801 }, + { .compatible = "rohm,bd96802", .data = (void *)ROHM_CHIP_TYPE_BD96802 }, { } }; MODULE_DEVICE_TABLE(of, bd96801_of_match); @@ -515,5 +744,5 @@ static void __exit bd96801_i2c_exit(void) module_exit(bd96801_i2c_exit); MODULE_AUTHOR("Matti Vaittinen "); -MODULE_DESCRIPTION("ROHM BD96801 Power Management IC driver"); +MODULE_DESCRIPTION("ROHM BD9680X Power Management IC driver"); MODULE_LICENSE("GPL"); diff --git a/include/linux/mfd/rohm-bd96801.h b/include/linux/mfd/rohm-bd96801.h index e2d9e10b6364..68c8ac8ad409 100644 --- a/include/linux/mfd/rohm-bd96801.h +++ b/include/linux/mfd/rohm-bd96801.h @@ -40,7 +40,9 @@ * INTB status registers are at range 0x5c ... 0x63 */ #define BD96801_REG_INT_SYS_ERRB1 0x52 +#define BD96801_REG_INT_BUCK2_ERRB 0x56 #define BD96801_REG_INT_SYS_INTB 0x5c +#define BD96801_REG_INT_BUCK2_INTB 0x5e #define BD96801_REG_INT_LDO7_INTB 0x63 /* MASK registers */ diff --git a/include/linux/mfd/rohm-bd96802.h b/include/linux/mfd/rohm-bd96802.h new file mode 100644 index 000000000000..bf4b77944edf --- /dev/null +++ b/include/linux/mfd/rohm-bd96802.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2025 ROHM Semiconductors + * + * The digital interface of trhe BD96802 PMIC is a reduced version of the + * BD96801. Hence the BD96801 definitions are used for registers and masks + * while this header only holds the IRQ definitions - mainly to avoid gaps in + * IRQ numbers caused by the lack of some BUCKs / LDOs and their respective + * IRQs. + */ + +#ifndef __LINUX_MFD_BD96802_H__ +#define __LINUX_MFD_BD96802_H__ + +/* ERRB IRQs */ +enum { + /* Reg 0x52, 0x53, 0x54 - ERRB system IRQs */ + BD96802_OTP_ERR_STAT, + BD96802_DBIST_ERR_STAT, + BD96802_EEP_ERR_STAT, + BD96802_ABIST_ERR_STAT, + BD96802_PRSTB_ERR_STAT, + BD96802_DRMOS1_ERR_STAT, + BD96802_DRMOS2_ERR_STAT, + BD96802_SLAVE_ERR_STAT, + BD96802_VREF_ERR_STAT, + BD96802_TSD_ERR_STAT, + BD96802_UVLO_ERR_STAT, + BD96802_OVLO_ERR_STAT, + BD96802_OSC_ERR_STAT, + BD96802_PON_ERR_STAT, + BD96802_POFF_ERR_STAT, + BD96802_CMD_SHDN_ERR_STAT, + BD96802_INT_SHDN_ERR_STAT, + + /* Reg 0x55 BUCK1 ERR IRQs */ + BD96802_BUCK1_PVIN_ERR_STAT, + BD96802_BUCK1_OVP_ERR_STAT, + BD96802_BUCK1_UVP_ERR_STAT, + BD96802_BUCK1_SHDN_ERR_STAT, + + /* Reg 0x56 BUCK2 ERR IRQs */ + BD96802_BUCK2_PVIN_ERR_STAT, + BD96802_BUCK2_OVP_ERR_STAT, + BD96802_BUCK2_UVP_ERR_STAT, + BD96802_BUCK2_SHDN_ERR_STAT, +}; + +/* INTB IRQs */ +enum { + /* Reg 0x5c (System INTB) */ + BD96802_TW_STAT, + BD96802_WDT_ERR_STAT, + BD96802_I2C_ERR_STAT, + BD96802_CHIP_IF_ERR_STAT, + + /* Reg 0x5d (BUCK1 INTB) */ + BD96802_BUCK1_OCPH_STAT, + BD96802_BUCK1_OCPL_STAT, + BD96802_BUCK1_OCPN_STAT, + BD96802_BUCK1_OVD_STAT, + BD96802_BUCK1_UVD_STAT, + BD96802_BUCK1_TW_CH_STAT, + + /* Reg 0x5e (BUCK2 INTB) */ + BD96802_BUCK2_OCPH_STAT, + BD96802_BUCK2_OCPL_STAT, + BD96802_BUCK2_OCPN_STAT, + BD96802_BUCK2_OVD_STAT, + BD96802_BUCK2_UVD_STAT, + BD96802_BUCK2_TW_CH_STAT, +}; + +#endif diff --git a/include/linux/mfd/rohm-generic.h b/include/linux/mfd/rohm-generic.h index e7d4e6afe388..11b86f9129e3 100644 --- a/include/linux/mfd/rohm-generic.h +++ b/include/linux/mfd/rohm-generic.h @@ -17,6 +17,7 @@ enum rohm_chip_type { ROHM_CHIP_TYPE_BD71837, ROHM_CHIP_TYPE_BD71847, ROHM_CHIP_TYPE_BD96801, + ROHM_CHIP_TYPE_BD96802, ROHM_CHIP_TYPE_AMOUNT }; -- 2.51.0 From 55606b9b20639b634560f44a070ff6153b59b557 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Tue, 8 Apr 2025 11:46:16 +0300 Subject: [PATCH 13/16] regulator: bd96801: Support ROHM BD96802 The ROHM BD96802 PMIC is primarily intended to be used as a companion PMIC extending the capabilities of the BD96802 but it can be used on it's own as well. When used as a companion PMIC, the start-up and shut-down sequences are usually intitiated by the master PMIC using IF pins. The BD96802 looks from the digital interface point of view pretty much like a reduced version of BD96801. It includes only 2 BUCKs and provides the same error protection/detection mechanisms as the BD96801. Also, the voltage control logic is same up to the register addresses. Add support for controlling BD96802 using the BD96801 driver. Signed-off-by: Matti Vaittinen Reviewed-by: Mark Brown Link: https://lore.kernel.org/r/2fb2d0d4997c32d18bfa32cea4564352c00eebc8.1744090658.git.mazziesaccount@gmail.com Signed-off-by: Lee Jones --- drivers/regulator/bd96801-regulator.c | 95 ++++++++++++++++++++++++--- 1 file changed, 86 insertions(+), 9 deletions(-) diff --git a/drivers/regulator/bd96801-regulator.c b/drivers/regulator/bd96801-regulator.c index 48cdd583e92d..8e96c460c8ae 100644 --- a/drivers/regulator/bd96801-regulator.c +++ b/drivers/regulator/bd96801-regulator.c @@ -160,6 +160,9 @@ static const struct linear_range bd96801_buck_init_volts[] = { REGULATOR_LINEAR_RANGE(3300000 - 150000, 0xed, 0xff, 0), }; +/* BD96802 uses same voltage ranges for bucks as BD96801 */ +#define bd96802_tune_volts bd96801_tune_volts +#define bd96802_buck_init_volts bd96801_buck_init_volts static const struct linear_range bd96801_ldo_int_volts[] = { REGULATOR_LINEAR_RANGE(300000, 0x00, 0x78, 25000), REGULATOR_LINEAR_RANGE(3300000, 0x79, 0xff, 0), @@ -302,6 +305,7 @@ struct bd96801_pmic_data { struct bd96801_regulator_data regulator_data[BD96801_NUM_REGULATORS]; struct regmap *regmap; int fatal_ind; + int num_regulators; }; static int ldo_map_notif(int irq, struct regulator_irq_data *rid, @@ -503,6 +507,70 @@ static int bd96801_walk_regulator_dt(struct device *dev, struct regmap *regmap, * case later. What we can easly do for preparing is to not use static global * data for regulators though. */ +static const struct bd96801_pmic_data bd96802_data = { + .regulator_data = { + { + .desc = { + .name = "buck1", + .of_match = of_match_ptr("buck1"), + .regulators_node = of_match_ptr("regulators"), + .id = BD96801_BUCK1, + .ops = &bd96801_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd96802_tune_volts, + .n_linear_ranges = ARRAY_SIZE(bd96802_tune_volts), + .n_voltages = BD96801_BUCK_VOLTS, + .enable_reg = BD96801_REG_ENABLE, + .enable_mask = BD96801_BUCK1_EN_MASK, + .enable_is_inverted = true, + .vsel_reg = BD96801_BUCK1_VSEL_REG, + .vsel_mask = BD96801_BUCK_VSEL_MASK, + .ramp_reg = BD96801_BUCK1_VSEL_REG, + .ramp_mask = BD96801_MASK_RAMP_DELAY, + .ramp_delay_table = &buck_ramp_table[0], + .n_ramp_values = ARRAY_SIZE(buck_ramp_table), + .owner = THIS_MODULE, + }, + .init_ranges = bd96802_buck_init_volts, + .num_ranges = ARRAY_SIZE(bd96802_buck_init_volts), + .irq_desc = { + .irqinfo = (struct bd96801_irqinfo *)&buck1_irqinfo[0], + .num_irqs = ARRAY_SIZE(buck1_irqinfo), + }, + }, + { + .desc = { + .name = "buck2", + .of_match = of_match_ptr("buck2"), + .regulators_node = of_match_ptr("regulators"), + .id = BD96801_BUCK2, + .ops = &bd96801_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd96802_tune_volts, + .n_linear_ranges = ARRAY_SIZE(bd96802_tune_volts), + .n_voltages = BD96801_BUCK_VOLTS, + .enable_reg = BD96801_REG_ENABLE, + .enable_mask = BD96801_BUCK2_EN_MASK, + .enable_is_inverted = true, + .vsel_reg = BD96801_BUCK2_VSEL_REG, + .vsel_mask = BD96801_BUCK_VSEL_MASK, + .ramp_reg = BD96801_BUCK2_VSEL_REG, + .ramp_mask = BD96801_MASK_RAMP_DELAY, + .ramp_delay_table = &buck_ramp_table[0], + .n_ramp_values = ARRAY_SIZE(buck_ramp_table), + .owner = THIS_MODULE, + }, + .irq_desc = { + .irqinfo = (struct bd96801_irqinfo *)&buck2_irqinfo[0], + .num_irqs = ARRAY_SIZE(buck2_irqinfo), + }, + .init_ranges = bd96802_buck_init_volts, + .num_ranges = ARRAY_SIZE(bd96802_buck_init_volts), + }, + }, + .num_regulators = 2, +}; + static const struct bd96801_pmic_data bd96801_data = { .regulator_data = { { @@ -688,11 +756,13 @@ static const struct bd96801_pmic_data bd96801_data = { .ldo_vol_lvl = BD96801_LDO7_VOL_LVL_REG, }, }, + .num_regulators = 7, }; -static int initialize_pmic_data(struct device *dev, +static int initialize_pmic_data(struct platform_device *pdev, struct bd96801_pmic_data *pdata) { + struct device *dev = &pdev->dev; int r, i; /* @@ -700,7 +770,7 @@ static int initialize_pmic_data(struct device *dev, * wish to modify IRQ information independently for each driver * instance. */ - for (r = 0; r < BD96801_NUM_REGULATORS; r++) { + for (r = 0; r < pdata->num_regulators; r++) { const struct bd96801_irqinfo *template; struct bd96801_irqinfo *new; int num_infos; @@ -866,6 +936,7 @@ 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_pmic_data *pdata_template; struct bd96801_regulator_data *rdesc; struct regulator_config config = {}; int ldo_errs_arr[BD96801_NUM_LDOS]; @@ -878,12 +949,16 @@ static int bd96801_probe(struct platform_device *pdev) parent = pdev->dev.parent; - pdata = devm_kmemdup(&pdev->dev, &bd96801_data, sizeof(bd96801_data), + pdata_template = (struct bd96801_pmic_data *)platform_get_device_id(pdev)->driver_data; + if (!pdata_template) + return -ENODEV; + + pdata = devm_kmemdup(&pdev->dev, pdata_template, sizeof(bd96801_data), GFP_KERNEL); if (!pdata) return -ENOMEM; - if (initialize_pmic_data(&pdev->dev, pdata)) + if (initialize_pmic_data(pdev, pdata)) return -ENOMEM; pdata->regmap = dev_get_regmap(parent, NULL); @@ -906,11 +981,11 @@ static int bd96801_probe(struct platform_device *pdev) use_errb = true; ret = bd96801_walk_regulator_dt(&pdev->dev, pdata->regmap, rdesc, - BD96801_NUM_REGULATORS); + pdata->num_regulators); if (ret) return ret; - for (i = 0; i < ARRAY_SIZE(pdata->regulator_data); i++) { + for (i = 0; i < pdata->num_regulators; i++) { struct regulator_dev *rdev; struct bd96801_irq_desc *idesc = &rdesc[i].irq_desc; int j; @@ -923,6 +998,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 @@ -972,14 +1048,15 @@ static int bd96801_probe(struct platform_device *pdev) if (use_errb) return bd96801_global_errb_irqs(pdev, all_rdevs, - ARRAY_SIZE(all_rdevs)); + pdata->num_regulators); return 0; } static const struct platform_device_id bd96801_pmic_id[] = { - { "bd96801-regulator", }, - { } + { "bd96801-regulator", (kernel_ulong_t)&bd96801_data }, + { "bd96802-regulator", (kernel_ulong_t)&bd96802_data }, + { }, }; MODULE_DEVICE_TABLE(platform, bd96801_pmic_id); -- 2.51.0 From 6a309b489215f705c20cb4ed7f85d9c16f768e55 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Tue, 8 Apr 2025 11:46:36 +0300 Subject: [PATCH 14/16] mfd: bd96801: Support ROHM BD96805 The ROHM BD96805 is from the software perspective almost identical to the ROHM BD96801. The main difference is different voltage tuning ranges. Add support differentiating these PMICs based on the compatible, and invoking the regulator driver with correct IC type. Signed-off-by: Matti Vaittinen Acked-by: Conor Dooley Link: https://lore.kernel.org/r/8680097dc083f191bea56d3ac7c6fe5c005644ec.1744090658.git.mazziesaccount@gmail.com Signed-off-by: Lee Jones --- drivers/mfd/rohm-bd96801.c | 22 ++++++++++++++++++++++ include/linux/mfd/rohm-generic.h | 1 + 2 files changed, 23 insertions(+) diff --git a/drivers/mfd/rohm-bd96801.c b/drivers/mfd/rohm-bd96801.c index e5ee5f556a55..dd0be7d675b8 100644 --- a/drivers/mfd/rohm-bd96801.c +++ b/drivers/mfd/rohm-bd96801.c @@ -220,6 +220,10 @@ static struct mfd_cell bd96802_cells[] = { [WDG_CELL] = { .name = "bd96801-wdt", }, [REGULATOR_CELL] = { .name = "bd96802-regulator", }, }; +static struct mfd_cell bd96805_cells[] = { + [WDG_CELL] = { .name = "bd96801-wdt", }, + [REGULATOR_CELL] = { .name = "bd96805-regulator", }, +}; static const struct regmap_range bd96801_volatile_ranges[] = { /* Status registers */ @@ -599,6 +603,20 @@ static const struct bd968xx bd96802_data = { .unlock_val = BD96801_UNLOCK, }; +static const struct bd968xx bd96805_data = { + .errb_irqs = bd96801_reg_errb_irqs, + .intb_irqs = bd96801_reg_intb_irqs, + .num_errb_irqs = ARRAY_SIZE(bd96801_reg_errb_irqs), + .num_intb_irqs = ARRAY_SIZE(bd96801_reg_intb_irqs), + .errb_irq_chip = &bd96801_irq_chip_errb, + .intb_irq_chip = &bd96801_irq_chip_intb, + .regmap_config = &bd96801_regmap_config, + .cells = bd96805_cells, + .num_cells = ARRAY_SIZE(bd96805_cells), + .unlock_reg = BD96801_LOCK_REG, + .unlock_val = BD96801_UNLOCK, +}; + static int bd96801_i2c_probe(struct i2c_client *i2c) { struct regmap_irq_chip_data *intb_irq_data, *errb_irq_data; @@ -621,6 +639,9 @@ static int bd96801_i2c_probe(struct i2c_client *i2c) case ROHM_CHIP_TYPE_BD96802: ddata = &bd96802_data; break; + case ROHM_CHIP_TYPE_BD96805: + ddata = &bd96805_data; + break; default: dev_err(&i2c->dev, "Unknown IC\n"); return -EINVAL; @@ -717,6 +738,7 @@ skip_errb: static const struct of_device_id bd96801_of_match[] = { { .compatible = "rohm,bd96801", .data = (void *)ROHM_CHIP_TYPE_BD96801 }, { .compatible = "rohm,bd96802", .data = (void *)ROHM_CHIP_TYPE_BD96802 }, + { .compatible = "rohm,bd96805", .data = (void *)ROHM_CHIP_TYPE_BD96805 }, { } }; MODULE_DEVICE_TABLE(of, bd96801_of_match); diff --git a/include/linux/mfd/rohm-generic.h b/include/linux/mfd/rohm-generic.h index 11b86f9129e3..867acf5baefc 100644 --- a/include/linux/mfd/rohm-generic.h +++ b/include/linux/mfd/rohm-generic.h @@ -18,6 +18,7 @@ enum rohm_chip_type { ROHM_CHIP_TYPE_BD71847, ROHM_CHIP_TYPE_BD96801, ROHM_CHIP_TYPE_BD96802, + ROHM_CHIP_TYPE_BD96805, ROHM_CHIP_TYPE_AMOUNT }; -- 2.51.0 From 7baf818d0d90e00c0688d8156bc7d9d1d1ee1dbb Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Tue, 8 Apr 2025 11:46:53 +0300 Subject: [PATCH 15/16] regulator: bd96801: Support ROHM BD96805 PMIC The ROHM BD96805 is from the software perspective almost identical to the ROHM BD96801. The main difference is different voltage tuning ranges. Add support differentiating these PMICs and provide correct voltages for both models. Signed-off-by: Matti Vaittinen Reviewed-by: Mark Brown Link: https://lore.kernel.org/r/eab1369557b14a9762c41a5429d1ac87a4644d9e.1744090658.git.mazziesaccount@gmail.com Signed-off-by: Lee Jones --- drivers/regulator/bd96801-regulator.c | 208 ++++++++++++++++++++++++++ 1 file changed, 208 insertions(+) diff --git a/drivers/regulator/bd96801-regulator.c b/drivers/regulator/bd96801-regulator.c index 8e96c460c8ae..9c7109a2ab96 100644 --- a/drivers/regulator/bd96801-regulator.c +++ b/drivers/regulator/bd96801-regulator.c @@ -83,6 +83,7 @@ enum { #define BD96801_LDO6_VSEL_REG 0x26 #define BD96801_LDO7_VSEL_REG 0x27 #define BD96801_BUCK_VSEL_MASK 0x1F +#define BD96805_BUCK_VSEL_MASK 0x3f #define BD96801_LDO_VSEL_MASK 0xff #define BD96801_MASK_RAMP_DELAY 0xc0 @@ -90,6 +91,7 @@ enum { #define BD96801_BUCK_INT_VOUT_MASK 0xff #define BD96801_BUCK_VOLTS 256 +#define BD96805_BUCK_VOLTS 64 #define BD96801_LDO_VOLTS 256 #define BD96801_OVP_MASK 0x03 @@ -163,6 +165,23 @@ static const struct linear_range bd96801_buck_init_volts[] = { /* BD96802 uses same voltage ranges for bucks as BD96801 */ #define bd96802_tune_volts bd96801_tune_volts #define bd96802_buck_init_volts bd96801_buck_init_volts + +/* + * On BD96805 we have similar "negative tuning range" as on BD96801, except + * that the max tuning is -310 ... +310 mV (instead of the 150mV). We use same + * approach as with the BD96801 ranges. + */ +static const struct linear_range bd96805_tune_volts[] = { + REGULATOR_LINEAR_RANGE(310000, 0x00, 0x1F, 10000), + REGULATOR_LINEAR_RANGE(0, 0x20, 0x3F, 10000), +}; + +static const struct linear_range bd96805_buck_init_volts[] = { + REGULATOR_LINEAR_RANGE(500000 - 310000, 0x00, 0xc8, 5000), + REGULATOR_LINEAR_RANGE(1550000 - 310000, 0xc9, 0xec, 50000), + REGULATOR_LINEAR_RANGE(3300000 - 310000, 0xed, 0xff, 0), +}; + static const struct linear_range bd96801_ldo_int_volts[] = { REGULATOR_LINEAR_RANGE(300000, 0x00, 0x78, 25000), REGULATOR_LINEAR_RANGE(3300000, 0x79, 0xff, 0), @@ -759,6 +778,194 @@ static const struct bd96801_pmic_data bd96801_data = { .num_regulators = 7, }; +static const struct bd96801_pmic_data bd96805_data = { + .regulator_data = { + { + .desc = { + .name = "buck1", + .of_match = of_match_ptr("buck1"), + .regulators_node = of_match_ptr("regulators"), + .id = BD96801_BUCK1, + .ops = &bd96801_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd96805_tune_volts, + .n_linear_ranges = ARRAY_SIZE(bd96805_tune_volts), + .n_voltages = BD96805_BUCK_VOLTS, + .enable_reg = BD96801_REG_ENABLE, + .enable_mask = BD96801_BUCK1_EN_MASK, + .enable_is_inverted = true, + .vsel_reg = BD96801_BUCK1_VSEL_REG, + .vsel_mask = BD96805_BUCK_VSEL_MASK, + .ramp_reg = BD96801_BUCK1_VSEL_REG, + .ramp_mask = BD96801_MASK_RAMP_DELAY, + .ramp_delay_table = &buck_ramp_table[0], + .n_ramp_values = ARRAY_SIZE(buck_ramp_table), + .owner = THIS_MODULE, + }, + .init_ranges = bd96805_buck_init_volts, + .num_ranges = ARRAY_SIZE(bd96805_buck_init_volts), + .irq_desc = { + .irqinfo = (struct bd96801_irqinfo *)&buck1_irqinfo[0], + .num_irqs = ARRAY_SIZE(buck1_irqinfo), + }, + }, { + .desc = { + .name = "buck2", + .of_match = of_match_ptr("buck2"), + .regulators_node = of_match_ptr("regulators"), + .id = BD96801_BUCK2, + .ops = &bd96801_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd96805_tune_volts, + .n_linear_ranges = ARRAY_SIZE(bd96805_tune_volts), + .n_voltages = BD96805_BUCK_VOLTS, + .enable_reg = BD96801_REG_ENABLE, + .enable_mask = BD96801_BUCK2_EN_MASK, + .enable_is_inverted = true, + .vsel_reg = BD96801_BUCK2_VSEL_REG, + .vsel_mask = BD96805_BUCK_VSEL_MASK, + .ramp_reg = BD96801_BUCK2_VSEL_REG, + .ramp_mask = BD96801_MASK_RAMP_DELAY, + .ramp_delay_table = &buck_ramp_table[0], + .n_ramp_values = ARRAY_SIZE(buck_ramp_table), + .owner = THIS_MODULE, + }, + .irq_desc = { + .irqinfo = (struct bd96801_irqinfo *)&buck2_irqinfo[0], + .num_irqs = ARRAY_SIZE(buck2_irqinfo), + }, + .init_ranges = bd96805_buck_init_volts, + .num_ranges = ARRAY_SIZE(bd96805_buck_init_volts), + }, { + .desc = { + .name = "buck3", + .of_match = of_match_ptr("buck3"), + .regulators_node = of_match_ptr("regulators"), + .id = BD96801_BUCK3, + .ops = &bd96801_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd96805_tune_volts, + .n_linear_ranges = ARRAY_SIZE(bd96805_tune_volts), + .n_voltages = BD96805_BUCK_VOLTS, + .enable_reg = BD96801_REG_ENABLE, + .enable_mask = BD96801_BUCK3_EN_MASK, + .enable_is_inverted = true, + .vsel_reg = BD96801_BUCK3_VSEL_REG, + .vsel_mask = BD96805_BUCK_VSEL_MASK, + .ramp_reg = BD96801_BUCK3_VSEL_REG, + .ramp_mask = BD96801_MASK_RAMP_DELAY, + .ramp_delay_table = &buck_ramp_table[0], + .n_ramp_values = ARRAY_SIZE(buck_ramp_table), + .owner = THIS_MODULE, + }, + .irq_desc = { + .irqinfo = (struct bd96801_irqinfo *)&buck3_irqinfo[0], + .num_irqs = ARRAY_SIZE(buck3_irqinfo), + }, + .init_ranges = bd96805_buck_init_volts, + .num_ranges = ARRAY_SIZE(bd96805_buck_init_volts), + }, { + .desc = { + .name = "buck4", + .of_match = of_match_ptr("buck4"), + .regulators_node = of_match_ptr("regulators"), + .id = BD96801_BUCK4, + .ops = &bd96801_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd96805_tune_volts, + .n_linear_ranges = ARRAY_SIZE(bd96805_tune_volts), + .n_voltages = BD96805_BUCK_VOLTS, + .enable_reg = BD96801_REG_ENABLE, + .enable_mask = BD96801_BUCK4_EN_MASK, + .enable_is_inverted = true, + .vsel_reg = BD96801_BUCK4_VSEL_REG, + .vsel_mask = BD96805_BUCK_VSEL_MASK, + .ramp_reg = BD96801_BUCK4_VSEL_REG, + .ramp_mask = BD96801_MASK_RAMP_DELAY, + .ramp_delay_table = &buck_ramp_table[0], + .n_ramp_values = ARRAY_SIZE(buck_ramp_table), + .owner = THIS_MODULE, + }, + .irq_desc = { + .irqinfo = (struct bd96801_irqinfo *)&buck4_irqinfo[0], + .num_irqs = ARRAY_SIZE(buck4_irqinfo), + }, + .init_ranges = bd96805_buck_init_volts, + .num_ranges = ARRAY_SIZE(bd96805_buck_init_volts), + }, { + .desc = { + .name = "ldo5", + .of_match = of_match_ptr("ldo5"), + .regulators_node = of_match_ptr("regulators"), + .id = BD96801_LDO5, + .ops = &bd96801_ldo_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd96801_ldo_int_volts, + .n_linear_ranges = ARRAY_SIZE(bd96801_ldo_int_volts), + .n_voltages = BD96801_LDO_VOLTS, + .enable_reg = BD96801_REG_ENABLE, + .enable_mask = BD96801_LDO5_EN_MASK, + .enable_is_inverted = true, + .vsel_reg = BD96801_LDO5_VSEL_REG, + .vsel_mask = BD96801_LDO_VSEL_MASK, + .owner = THIS_MODULE, + }, + .irq_desc = { + .irqinfo = (struct bd96801_irqinfo *)&ldo5_irqinfo[0], + .num_irqs = ARRAY_SIZE(ldo5_irqinfo), + }, + .ldo_vol_lvl = BD96801_LDO5_VOL_LVL_REG, + }, { + .desc = { + .name = "ldo6", + .of_match = of_match_ptr("ldo6"), + .regulators_node = of_match_ptr("regulators"), + .id = BD96801_LDO6, + .ops = &bd96801_ldo_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd96801_ldo_int_volts, + .n_linear_ranges = ARRAY_SIZE(bd96801_ldo_int_volts), + .n_voltages = BD96801_LDO_VOLTS, + .enable_reg = BD96801_REG_ENABLE, + .enable_mask = BD96801_LDO6_EN_MASK, + .enable_is_inverted = true, + .vsel_reg = BD96801_LDO6_VSEL_REG, + .vsel_mask = BD96801_LDO_VSEL_MASK, + .owner = THIS_MODULE, + }, + .irq_desc = { + .irqinfo = (struct bd96801_irqinfo *)&ldo6_irqinfo[0], + .num_irqs = ARRAY_SIZE(ldo6_irqinfo), + }, + .ldo_vol_lvl = BD96801_LDO6_VOL_LVL_REG, + }, { + .desc = { + .name = "ldo7", + .of_match = of_match_ptr("ldo7"), + .regulators_node = of_match_ptr("regulators"), + .id = BD96801_LDO7, + .ops = &bd96801_ldo_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd96801_ldo_int_volts, + .n_linear_ranges = ARRAY_SIZE(bd96801_ldo_int_volts), + .n_voltages = BD96801_LDO_VOLTS, + .enable_reg = BD96801_REG_ENABLE, + .enable_mask = BD96801_LDO7_EN_MASK, + .enable_is_inverted = true, + .vsel_reg = BD96801_LDO7_VSEL_REG, + .vsel_mask = BD96801_LDO_VSEL_MASK, + .owner = THIS_MODULE, + }, + .irq_desc = { + .irqinfo = (struct bd96801_irqinfo *)&ldo7_irqinfo[0], + .num_irqs = ARRAY_SIZE(ldo7_irqinfo), + }, + .ldo_vol_lvl = BD96801_LDO7_VOL_LVL_REG, + }, + }, + .num_regulators = 7, +}; + static int initialize_pmic_data(struct platform_device *pdev, struct bd96801_pmic_data *pdata) { @@ -1056,6 +1263,7 @@ static int bd96801_probe(struct platform_device *pdev) static const struct platform_device_id bd96801_pmic_id[] = { { "bd96801-regulator", (kernel_ulong_t)&bd96801_data }, { "bd96802-regulator", (kernel_ulong_t)&bd96802_data }, + { "bd96805-regulator", (kernel_ulong_t)&bd96805_data }, { }, }; MODULE_DEVICE_TABLE(platform, bd96801_pmic_id); -- 2.51.0 From fecc18a9f59ce9c36eb3622ae77bff5fa5c6d976 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Tue, 8 Apr 2025 11:47:10 +0300 Subject: [PATCH 16/16] mfd: bd96801: Support ROHM BD96806 The ROHM BD96806 is from the software perspective almost identical to the ROHM BD96802. The main difference is different voltage tuning ranges. Add support differentiating these PMICs based on the compatible, and invoking the regulator driver with correct IC type. Signed-off-by: Matti Vaittinen Acked-by: Conor Dooley Link: https://lore.kernel.org/r/ccc95ae33613648fdcba08915777d945412ac5c4.1744090658.git.mazziesaccount@gmail.com Signed-off-by: Lee Jones --- drivers/mfd/rohm-bd96801.c | 23 +++++++++++++++++++++++ include/linux/mfd/rohm-generic.h | 1 + 2 files changed, 24 insertions(+) diff --git a/drivers/mfd/rohm-bd96801.c b/drivers/mfd/rohm-bd96801.c index dd0be7d675b8..66fa017ad568 100644 --- a/drivers/mfd/rohm-bd96801.c +++ b/drivers/mfd/rohm-bd96801.c @@ -225,6 +225,11 @@ static struct mfd_cell bd96805_cells[] = { [REGULATOR_CELL] = { .name = "bd96805-regulator", }, }; +static struct mfd_cell bd96806_cells[] = { + [WDG_CELL] = { .name = "bd96806-wdt", }, + [REGULATOR_CELL] = { .name = "bd96806-regulator", }, +}; + static const struct regmap_range bd96801_volatile_ranges[] = { /* Status registers */ regmap_reg_range(BD96801_REG_WD_FEED, BD96801_REG_WD_FAILCOUNT), @@ -617,6 +622,20 @@ static const struct bd968xx bd96805_data = { .unlock_val = BD96801_UNLOCK, }; +static struct bd968xx bd96806_data = { + .errb_irqs = bd96802_reg_errb_irqs, + .intb_irqs = bd96802_reg_intb_irqs, + .num_errb_irqs = ARRAY_SIZE(bd96802_reg_errb_irqs), + .num_intb_irqs = ARRAY_SIZE(bd96802_reg_intb_irqs), + .errb_irq_chip = &bd96802_irq_chip_errb, + .intb_irq_chip = &bd96802_irq_chip_intb, + .regmap_config = &bd96802_regmap_config, + .cells = bd96806_cells, + .num_cells = ARRAY_SIZE(bd96806_cells), + .unlock_reg = BD96801_LOCK_REG, + .unlock_val = BD96801_UNLOCK, +}; + static int bd96801_i2c_probe(struct i2c_client *i2c) { struct regmap_irq_chip_data *intb_irq_data, *errb_irq_data; @@ -642,6 +661,9 @@ static int bd96801_i2c_probe(struct i2c_client *i2c) case ROHM_CHIP_TYPE_BD96805: ddata = &bd96805_data; break; + case ROHM_CHIP_TYPE_BD96806: + ddata = &bd96806_data; + break; default: dev_err(&i2c->dev, "Unknown IC\n"); return -EINVAL; @@ -739,6 +761,7 @@ static const struct of_device_id bd96801_of_match[] = { { .compatible = "rohm,bd96801", .data = (void *)ROHM_CHIP_TYPE_BD96801 }, { .compatible = "rohm,bd96802", .data = (void *)ROHM_CHIP_TYPE_BD96802 }, { .compatible = "rohm,bd96805", .data = (void *)ROHM_CHIP_TYPE_BD96805 }, + { .compatible = "rohm,bd96806", .data = (void *)ROHM_CHIP_TYPE_BD96806 }, { } }; MODULE_DEVICE_TABLE(of, bd96801_of_match); diff --git a/include/linux/mfd/rohm-generic.h b/include/linux/mfd/rohm-generic.h index 867acf5baefc..579e8dcfcca4 100644 --- a/include/linux/mfd/rohm-generic.h +++ b/include/linux/mfd/rohm-generic.h @@ -19,6 +19,7 @@ enum rohm_chip_type { ROHM_CHIP_TYPE_BD96801, ROHM_CHIP_TYPE_BD96802, ROHM_CHIP_TYPE_BD96805, + ROHM_CHIP_TYPE_BD96806, ROHM_CHIP_TYPE_AMOUNT }; -- 2.51.0