Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'ib-mfd-regulator-watchdog-6.11' into ibs-for-mfd-merged

+2094
+173
Documentation/devicetree/bindings/mfd/rohm,bd96801-pmic.yaml
··· 1 + # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/mfd/rohm,bd96801-pmic.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: ROHM BD96801 Scalable Power Management Integrated Circuit 8 + 9 + maintainers: 10 + - Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com> 11 + 12 + description: 13 + BD96801 is an automotive grade single-chip power management IC. 14 + It integrates 4 buck converters and 3 LDOs with safety features like 15 + over-/under voltage and over current detection and a watchdog. 16 + 17 + properties: 18 + compatible: 19 + const: rohm,bd96801 20 + 21 + reg: 22 + maxItems: 1 23 + 24 + interrupts: 25 + description: 26 + The PMIC provides intb and errb IRQ lines. The errb IRQ line is used 27 + for fatal IRQs which will cause the PMIC to shut down power outputs. 28 + In many systems this will shut down the SoC contolling the PMIC and 29 + connecting/handling the errb can be omitted. However, there are cases 30 + where the SoC is not powered by the PMIC or has a short time backup 31 + energy to handle shutdown of critical hardware. In that case it may be 32 + useful to connect the errb and handle errb events. 33 + minItems: 1 34 + maxItems: 2 35 + 36 + interrupt-names: 37 + minItems: 1 38 + items: 39 + - enum: [intb, errb] 40 + - const: errb 41 + 42 + rohm,hw-timeout-ms: 43 + description: 44 + Watchdog timeout value(s). First walue is timeout limit. Second value is 45 + optional value for 'too early' watchdog ping if window timeout mode is 46 + to be used. 47 + minItems: 1 48 + maxItems: 2 49 + 50 + rohm,wdg-action: 51 + description: 52 + Whether the watchdog failure must turn off the regulator power outputs or 53 + just toggle the INTB line. 54 + enum: 55 + - prstb 56 + - intb-only 57 + 58 + timeout-sec: 59 + maxItems: 2 60 + 61 + regulators: 62 + $ref: /schemas/regulator/rohm,bd96801-regulator.yaml 63 + description: 64 + List of child nodes that specify the regulators. 65 + 66 + required: 67 + - compatible 68 + - reg 69 + - interrupts 70 + - interrupt-names 71 + - regulators 72 + 73 + additionalProperties: false 74 + 75 + examples: 76 + - | 77 + #include <dt-bindings/interrupt-controller/irq.h> 78 + #include <dt-bindings/leds/common.h> 79 + i2c { 80 + #address-cells = <1>; 81 + #size-cells = <0>; 82 + pmic: pmic@60 { 83 + reg = <0x60>; 84 + compatible = "rohm,bd96801"; 85 + interrupt-parent = <&gpio1>; 86 + interrupts = <29 IRQ_TYPE_LEVEL_LOW>, <6 IRQ_TYPE_LEVEL_LOW>; 87 + interrupt-names = "intb", "errb"; 88 + 89 + regulators { 90 + buck1 { 91 + regulator-name = "buck1"; 92 + regulator-ramp-delay = <1250>; 93 + /* 0.5V min INITIAL - 150 mV tune */ 94 + regulator-min-microvolt = <350000>; 95 + /* 3.3V + 150mV tune */ 96 + regulator-max-microvolt = <3450000>; 97 + 98 + /* These can be set only when PMIC is in STBY */ 99 + rohm,initial-voltage-microvolt = <500000>; 100 + regulator-ov-error-microvolt = <230000>; 101 + regulator-uv-error-microvolt = <230000>; 102 + regulator-temp-protection-kelvin = <1>; 103 + regulator-temp-warn-kelvin = <0>; 104 + }; 105 + buck2 { 106 + regulator-name = "buck2"; 107 + regulator-min-microvolt = <350000>; 108 + regulator-max-microvolt = <3450000>; 109 + 110 + rohm,initial-voltage-microvolt = <3000000>; 111 + regulator-ov-error-microvolt = <18000>; 112 + regulator-uv-error-microvolt = <18000>; 113 + regulator-temp-protection-kelvin = <1>; 114 + regulator-temp-warn-kelvin = <1>; 115 + }; 116 + buck3 { 117 + regulator-name = "buck3"; 118 + regulator-min-microvolt = <350000>; 119 + regulator-max-microvolt = <3450000>; 120 + 121 + rohm,initial-voltage-microvolt = <600000>; 122 + regulator-ov-warn-microvolt = <18000>; 123 + regulator-uv-warn-microvolt = <18000>; 124 + regulator-temp-protection-kelvin = <1>; 125 + regulator-temp-error-kelvin = <0>; 126 + }; 127 + buck4 { 128 + regulator-name = "buck4"; 129 + regulator-min-microvolt = <350000>; 130 + regulator-max-microvolt = <3450000>; 131 + 132 + rohm,initial-voltage-microvolt = <600000>; 133 + regulator-ov-warn-microvolt = <18000>; 134 + regulator-uv-warn-microvolt = <18000>; 135 + regulator-temp-protection-kelvin = <1>; 136 + regulator-temp-error-kelvin = <0>; 137 + }; 138 + ldo5 { 139 + regulator-name = "ldo5"; 140 + regulator-min-microvolt = <300000>; 141 + regulator-max-microvolt = <3300000>; 142 + 143 + rohm,initial-voltage-microvolt = <500000>; 144 + regulator-ov-error-microvolt = <36000>; 145 + regulator-uv-error-microvolt = <34000>; 146 + regulator-temp-protection-kelvin = <1>; 147 + regulator-temp-warn-kelvin = <0>; 148 + }; 149 + ldo6 { 150 + regulator-name = "ldo6"; 151 + regulator-min-microvolt = <300000>; 152 + regulator-max-microvolt = <3300000>; 153 + 154 + rohm,initial-voltage-microvolt = <300000>; 155 + regulator-ov-error-microvolt = <36000>; 156 + regulator-uv-error-microvolt = <34000>; 157 + regulator-temp-protection-kelvin = <1>; 158 + regulator-temp-warn-kelvin = <0>; 159 + }; 160 + ldo7 { 161 + regulator-name = "ldo7"; 162 + regulator-min-microvolt = <300000>; 163 + regulator-max-microvolt = <3300000>; 164 + 165 + rohm,initial-voltage-microvolt = <500000>; 166 + regulator-ov-error-microvolt = <36000>; 167 + regulator-uv-error-microvolt = <34000>; 168 + regulator-temp-protection-kelvin = <1>; 169 + regulator-temp-warn-kelvin = <0>; 170 + }; 171 + }; 172 + }; 173 + };
+63
Documentation/devicetree/bindings/regulator/rohm,bd96801-regulator.yaml
··· 1 + # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/regulator/rohm,bd96801-regulator.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: ROHM BD96801 Power Management Integrated Circuit regulators 8 + 9 + maintainers: 10 + - Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com> 11 + 12 + description: 13 + This module is part of the ROHM BD96801 MFD device. For more details 14 + see Documentation/devicetree/bindings/mfd/rohm,bd96801-pmic.yaml. 15 + 16 + The regulator controller is represented as a sub-node of the PMIC node 17 + on the device tree. 18 + 19 + Regulator nodes should be named to buck_<number> and ldo_<number>. 20 + The valid names for BD96801 regulator nodes are 21 + buck1, buck2, buck3, buck4, ldo5, ldo6, ldo7 22 + 23 + patternProperties: 24 + "^ldo[5-7]$": 25 + type: object 26 + description: 27 + Properties for single LDO regulator. 28 + $ref: regulator.yaml# 29 + 30 + properties: 31 + rohm,initial-voltage-microvolt: 32 + description: 33 + Initial voltage for regulator. Voltage can be tuned +/-150 mV from 34 + this value. NOTE, This can be modified via I2C only when PMIC is in 35 + STBY state. 36 + minimum: 300000 37 + maximum: 3300000 38 + 39 + unevaluatedProperties: false 40 + 41 + "^buck[1-4]$": 42 + type: object 43 + description: 44 + Properties for single BUCK regulator. 45 + $ref: regulator.yaml# 46 + 47 + properties: 48 + rohm,initial-voltage-microvolt: 49 + description: 50 + Initial voltage for regulator. Voltage can be tuned +/-150 mV from 51 + this value. NOTE, This can be modified via I2C only when PMIC is in 52 + STBY state. 53 + minimum: 500000 54 + maximum: 3300000 55 + 56 + rohm,keep-on-stby: 57 + description: 58 + Keep the regulator powered when PMIC transitions to STBY state. 59 + type: boolean 60 + 61 + unevaluatedProperties: false 62 + 63 + additionalProperties: false
+4
MAINTAINERS
··· 19472 19472 F: drivers/mfd/rohm-bd71828.c 19473 19473 F: drivers/mfd/rohm-bd718x7.c 19474 19474 F: drivers/mfd/rohm-bd9576.c 19475 + F: drivers/mfd/rohm-bd96801.c 19475 19476 F: drivers/regulator/bd71815-regulator.c 19476 19477 F: drivers/regulator/bd71828-regulator.c 19477 19478 F: drivers/regulator/bd718x7-regulator.c 19478 19479 F: drivers/regulator/bd9576-regulator.c 19480 + F: drivers/regulator/bd96801-regulator.c 19479 19481 F: drivers/regulator/rohm-regulator.c 19480 19482 F: drivers/rtc/rtc-bd70528.c 19481 19483 F: drivers/watchdog/bd9576_wdt.c 19484 + F: drivers/watchdog/bd96801_wdt.c 19482 19485 F: include/linux/mfd/rohm-bd71815.h 19483 19486 F: include/linux/mfd/rohm-bd71828.h 19484 19487 F: include/linux/mfd/rohm-bd718x7.h 19485 19488 F: include/linux/mfd/rohm-bd957x.h 19489 + F: include/linux/mfd/rohm-bd96801.h 19486 19490 F: include/linux/mfd/rohm-generic.h 19487 19491 F: include/linux/mfd/rohm-shared.h 19488 19492
+13
drivers/mfd/Kconfig
··· 2101 2101 BD9573MUF Power Management ICs. BD9576 and BD9573 are primarily 2102 2102 designed to be used to power R-Car series processors. 2103 2103 2104 + config MFD_ROHM_BD96801 2105 + tristate "ROHM BD96801 Power Management IC" 2106 + depends on I2C=y 2107 + depends on OF 2108 + select REGMAP_I2C 2109 + select REGMAP_IRQ 2110 + select MFD_CORE 2111 + help 2112 + Select this option to get support for the ROHM BD96801 Power 2113 + Management IC. The ROHM BD96801 is a highly scalable Power Management 2114 + IC for industrial and automotive use. The BD96801 can be used as a 2115 + master PMIC in a chained PMIC solution with suitable companion PMICs. 2116 + 2104 2117 config MFD_STM32_LPTIMER 2105 2118 tristate "Support for STM32 Low-Power Timer" 2106 2119 depends on (ARCH_STM32 && OF) || COMPILE_TEST
+1
drivers/mfd/Makefile
··· 269 269 obj-$(CONFIG_MFD_ROHM_BD71828) += rohm-bd71828.o 270 270 obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o 271 271 obj-$(CONFIG_MFD_ROHM_BD957XMUF) += rohm-bd9576.o 272 + obj-$(CONFIG_MFD_ROHM_BD96801) += rohm-bd96801.o 272 273 obj-$(CONFIG_MFD_STMFX) += stmfx.o 273 274 obj-$(CONFIG_MFD_KHADAS_MCU) += khadas-mcu.o 274 275 obj-$(CONFIG_MFD_ACER_A500_EC) += acer-ec-a500.o
+273
drivers/mfd/rohm-bd96801.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Copyright (C) 2024 ROHM Semiconductors 4 + * 5 + * ROHM BD96801 PMIC driver 6 + * 7 + * This version of the "BD86801 scalable PMIC"'s driver supports only very 8 + * basic set of the PMIC features. Most notably, there is no support for 9 + * the ERRB interrupt and the configurations which should be done when the 10 + * PMIC is in STBY mode. 11 + * 12 + * Supporting the ERRB interrupt would require dropping the regmap-IRQ 13 + * usage or working around (or accepting a presense of) a naming conflict 14 + * in debugFS IRQs. 15 + * 16 + * Being able to reliably do the configurations like changing the 17 + * regulator safety limits (like limits for the over/under -voltages, over 18 + * current, thermal protection) would require the configuring driver to be 19 + * synchronized with entity causing the PMIC state transitions. Eg, one 20 + * should be able to ensure the PMIC is in STBY state when the 21 + * configurations are applied to the hardware. How and when the PMIC state 22 + * transitions are to be done is likely to be very system specific, as will 23 + * be the need to configure these safety limits. Hence it's not simple to 24 + * come up with a generic solution. 25 + * 26 + * Users who require the ERRB handling and STBY state configurations can 27 + * have a look at the original RFC: 28 + * https://lore.kernel.org/all/cover.1712920132.git.mazziesaccount@gmail.com/ 29 + * which implements a workaround to debugFS naming conflict and some of 30 + * the safety limit configurations - but leaves the state change handling 31 + * and synchronization to be implemented. 32 + * 33 + * It would be great to hear (and receive a patch!) if you implement the 34 + * STBY configuration support or a proper fix to the debugFS naming 35 + * conflict in your downstream driver ;) 36 + */ 37 + 38 + #include <linux/i2c.h> 39 + #include <linux/interrupt.h> 40 + #include <linux/mfd/core.h> 41 + #include <linux/module.h> 42 + #include <linux/property.h> 43 + #include <linux/regmap.h> 44 + #include <linux/types.h> 45 + 46 + #include <linux/mfd/rohm-bd96801.h> 47 + #include <linux/mfd/rohm-generic.h> 48 + 49 + static const struct resource regulator_intb_irqs[] = { 50 + DEFINE_RES_IRQ_NAMED(BD96801_TW_STAT, "bd96801-core-thermal"), 51 + 52 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPH_STAT, "bd96801-buck1-overcurr-h"), 53 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPL_STAT, "bd96801-buck1-overcurr-l"), 54 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPN_STAT, "bd96801-buck1-overcurr-n"), 55 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OVD_STAT, "bd96801-buck1-overvolt"), 56 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_UVD_STAT, "bd96801-buck1-undervolt"), 57 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_TW_CH_STAT, "bd96801-buck1-thermal"), 58 + 59 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPH_STAT, "bd96801-buck2-overcurr-h"), 60 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPL_STAT, "bd96801-buck2-overcurr-l"), 61 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPN_STAT, "bd96801-buck2-overcurr-n"), 62 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OVD_STAT, "bd96801-buck2-overvolt"), 63 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_UVD_STAT, "bd96801-buck2-undervolt"), 64 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_TW_CH_STAT, "bd96801-buck2-thermal"), 65 + 66 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPH_STAT, "bd96801-buck3-overcurr-h"), 67 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPL_STAT, "bd96801-buck3-overcurr-l"), 68 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPN_STAT, "bd96801-buck3-overcurr-n"), 69 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OVD_STAT, "bd96801-buck3-overvolt"), 70 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_UVD_STAT, "bd96801-buck3-undervolt"), 71 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_TW_CH_STAT, "bd96801-buck3-thermal"), 72 + 73 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPH_STAT, "bd96801-buck4-overcurr-h"), 74 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPL_STAT, "bd96801-buck4-overcurr-l"), 75 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPN_STAT, "bd96801-buck4-overcurr-n"), 76 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OVD_STAT, "bd96801-buck4-overvolt"), 77 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_UVD_STAT, "bd96801-buck4-undervolt"), 78 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_TW_CH_STAT, "bd96801-buck4-thermal"), 79 + 80 + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_OCPH_STAT, "bd96801-ldo5-overcurr"), 81 + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_OVD_STAT, "bd96801-ldo5-overvolt"), 82 + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_UVD_STAT, "bd96801-ldo5-undervolt"), 83 + 84 + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_OCPH_STAT, "bd96801-ldo6-overcurr"), 85 + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_OVD_STAT, "bd96801-ldo6-overvolt"), 86 + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_UVD_STAT, "bd96801-ldo6-undervolt"), 87 + 88 + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_OCPH_STAT, "bd96801-ldo7-overcurr"), 89 + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_OVD_STAT, "bd96801-ldo7-overvolt"), 90 + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_UVD_STAT, "bd96801-ldo7-undervolt"), 91 + }; 92 + 93 + static const struct resource wdg_intb_irqs[] = { 94 + DEFINE_RES_IRQ_NAMED(BD96801_WDT_ERR_STAT, "bd96801-wdg"), 95 + }; 96 + 97 + static struct mfd_cell bd96801_cells[] = { 98 + { 99 + .name = "bd96801-wdt", 100 + .resources = wdg_intb_irqs, 101 + .num_resources = ARRAY_SIZE(wdg_intb_irqs), 102 + }, { 103 + .name = "bd96801-regulator", 104 + .resources = regulator_intb_irqs, 105 + .num_resources = ARRAY_SIZE(regulator_intb_irqs), 106 + }, 107 + }; 108 + 109 + static const struct regmap_range bd96801_volatile_ranges[] = { 110 + /* Status registers */ 111 + regmap_reg_range(BD96801_REG_WD_FEED, BD96801_REG_WD_FAILCOUNT), 112 + regmap_reg_range(BD96801_REG_WD_ASK, BD96801_REG_WD_ASK), 113 + regmap_reg_range(BD96801_REG_WD_STATUS, BD96801_REG_WD_STATUS), 114 + regmap_reg_range(BD96801_REG_PMIC_STATE, BD96801_REG_INT_LDO7_INTB), 115 + /* Registers which do not update value unless PMIC is in STBY */ 116 + regmap_reg_range(BD96801_REG_SSCG_CTRL, BD96801_REG_SHD_INTB), 117 + regmap_reg_range(BD96801_REG_BUCK_OVP, BD96801_REG_BOOT_OVERTIME), 118 + /* 119 + * LDO control registers have single bit (LDO MODE) which does not 120 + * change when we write it unless PMIC is in STBY. It's safer to not 121 + * cache it. 122 + */ 123 + regmap_reg_range(BD96801_LDO5_VOL_LVL_REG, BD96801_LDO7_VOL_LVL_REG), 124 + }; 125 + 126 + static const struct regmap_access_table volatile_regs = { 127 + .yes_ranges = bd96801_volatile_ranges, 128 + .n_yes_ranges = ARRAY_SIZE(bd96801_volatile_ranges), 129 + }; 130 + 131 + static const struct regmap_irq bd96801_intb_irqs[] = { 132 + /* STATUS SYSTEM INTB */ 133 + REGMAP_IRQ_REG(BD96801_TW_STAT, 0, BD96801_TW_STAT_MASK), 134 + REGMAP_IRQ_REG(BD96801_WDT_ERR_STAT, 0, BD96801_WDT_ERR_STAT_MASK), 135 + REGMAP_IRQ_REG(BD96801_I2C_ERR_STAT, 0, BD96801_I2C_ERR_STAT_MASK), 136 + REGMAP_IRQ_REG(BD96801_CHIP_IF_ERR_STAT, 0, BD96801_CHIP_IF_ERR_STAT_MASK), 137 + /* STATUS BUCK1 INTB */ 138 + REGMAP_IRQ_REG(BD96801_BUCK1_OCPH_STAT, 1, BD96801_BUCK_OCPH_STAT_MASK), 139 + REGMAP_IRQ_REG(BD96801_BUCK1_OCPL_STAT, 1, BD96801_BUCK_OCPL_STAT_MASK), 140 + REGMAP_IRQ_REG(BD96801_BUCK1_OCPN_STAT, 1, BD96801_BUCK_OCPN_STAT_MASK), 141 + REGMAP_IRQ_REG(BD96801_BUCK1_OVD_STAT, 1, BD96801_BUCK_OVD_STAT_MASK), 142 + REGMAP_IRQ_REG(BD96801_BUCK1_UVD_STAT, 1, BD96801_BUCK_UVD_STAT_MASK), 143 + REGMAP_IRQ_REG(BD96801_BUCK1_TW_CH_STAT, 1, BD96801_BUCK_TW_CH_STAT_MASK), 144 + /* BUCK 2 INTB */ 145 + REGMAP_IRQ_REG(BD96801_BUCK2_OCPH_STAT, 2, BD96801_BUCK_OCPH_STAT_MASK), 146 + REGMAP_IRQ_REG(BD96801_BUCK2_OCPL_STAT, 2, BD96801_BUCK_OCPL_STAT_MASK), 147 + REGMAP_IRQ_REG(BD96801_BUCK2_OCPN_STAT, 2, BD96801_BUCK_OCPN_STAT_MASK), 148 + REGMAP_IRQ_REG(BD96801_BUCK2_OVD_STAT, 2, BD96801_BUCK_OVD_STAT_MASK), 149 + REGMAP_IRQ_REG(BD96801_BUCK2_UVD_STAT, 2, BD96801_BUCK_UVD_STAT_MASK), 150 + REGMAP_IRQ_REG(BD96801_BUCK2_TW_CH_STAT, 2, BD96801_BUCK_TW_CH_STAT_MASK), 151 + /* BUCK 3 INTB */ 152 + REGMAP_IRQ_REG(BD96801_BUCK3_OCPH_STAT, 3, BD96801_BUCK_OCPH_STAT_MASK), 153 + REGMAP_IRQ_REG(BD96801_BUCK3_OCPL_STAT, 3, BD96801_BUCK_OCPL_STAT_MASK), 154 + REGMAP_IRQ_REG(BD96801_BUCK3_OCPN_STAT, 3, BD96801_BUCK_OCPN_STAT_MASK), 155 + REGMAP_IRQ_REG(BD96801_BUCK3_OVD_STAT, 3, BD96801_BUCK_OVD_STAT_MASK), 156 + REGMAP_IRQ_REG(BD96801_BUCK3_UVD_STAT, 3, BD96801_BUCK_UVD_STAT_MASK), 157 + REGMAP_IRQ_REG(BD96801_BUCK3_TW_CH_STAT, 3, BD96801_BUCK_TW_CH_STAT_MASK), 158 + /* BUCK 4 INTB */ 159 + REGMAP_IRQ_REG(BD96801_BUCK4_OCPH_STAT, 4, BD96801_BUCK_OCPH_STAT_MASK), 160 + REGMAP_IRQ_REG(BD96801_BUCK4_OCPL_STAT, 4, BD96801_BUCK_OCPL_STAT_MASK), 161 + REGMAP_IRQ_REG(BD96801_BUCK4_OCPN_STAT, 4, BD96801_BUCK_OCPN_STAT_MASK), 162 + REGMAP_IRQ_REG(BD96801_BUCK4_OVD_STAT, 4, BD96801_BUCK_OVD_STAT_MASK), 163 + REGMAP_IRQ_REG(BD96801_BUCK4_UVD_STAT, 4, BD96801_BUCK_UVD_STAT_MASK), 164 + REGMAP_IRQ_REG(BD96801_BUCK4_TW_CH_STAT, 4, BD96801_BUCK_TW_CH_STAT_MASK), 165 + /* LDO5 INTB */ 166 + REGMAP_IRQ_REG(BD96801_LDO5_OCPH_STAT, 5, BD96801_LDO_OCPH_STAT_MASK), 167 + REGMAP_IRQ_REG(BD96801_LDO5_OVD_STAT, 5, BD96801_LDO_OVD_STAT_MASK), 168 + REGMAP_IRQ_REG(BD96801_LDO5_UVD_STAT, 5, BD96801_LDO_UVD_STAT_MASK), 169 + /* LDO6 INTB */ 170 + REGMAP_IRQ_REG(BD96801_LDO6_OCPH_STAT, 6, BD96801_LDO_OCPH_STAT_MASK), 171 + REGMAP_IRQ_REG(BD96801_LDO6_OVD_STAT, 6, BD96801_LDO_OVD_STAT_MASK), 172 + REGMAP_IRQ_REG(BD96801_LDO6_UVD_STAT, 6, BD96801_LDO_UVD_STAT_MASK), 173 + /* LDO7 INTB */ 174 + REGMAP_IRQ_REG(BD96801_LDO7_OCPH_STAT, 7, BD96801_LDO_OCPH_STAT_MASK), 175 + REGMAP_IRQ_REG(BD96801_LDO7_OVD_STAT, 7, BD96801_LDO_OVD_STAT_MASK), 176 + REGMAP_IRQ_REG(BD96801_LDO7_UVD_STAT, 7, BD96801_LDO_UVD_STAT_MASK), 177 + }; 178 + 179 + static struct regmap_irq_chip bd96801_irq_chip_intb = { 180 + .name = "bd96801-irq-intb", 181 + .main_status = BD96801_REG_INT_MAIN, 182 + .num_main_regs = 1, 183 + .irqs = &bd96801_intb_irqs[0], 184 + .num_irqs = ARRAY_SIZE(bd96801_intb_irqs), 185 + .status_base = BD96801_REG_INT_SYS_INTB, 186 + .mask_base = BD96801_REG_MASK_SYS_INTB, 187 + .ack_base = BD96801_REG_INT_SYS_INTB, 188 + .init_ack_masked = true, 189 + .num_regs = 8, 190 + .irq_reg_stride = 1, 191 + }; 192 + 193 + static const struct regmap_config bd96801_regmap_config = { 194 + .reg_bits = 8, 195 + .val_bits = 8, 196 + .volatile_table = &volatile_regs, 197 + .cache_type = REGCACHE_RBTREE, 198 + }; 199 + 200 + static int bd96801_i2c_probe(struct i2c_client *i2c) 201 + { 202 + struct regmap_irq_chip_data *intb_irq_data; 203 + const struct fwnode_handle *fwnode; 204 + struct irq_domain *intb_domain; 205 + struct regmap *regmap; 206 + int ret, intb_irq; 207 + 208 + fwnode = dev_fwnode(&i2c->dev); 209 + if (!fwnode) 210 + return dev_err_probe(&i2c->dev, -EINVAL, "Failed to find fwnode\n"); 211 + 212 + intb_irq = fwnode_irq_get_byname(fwnode, "intb"); 213 + if (intb_irq < 0) 214 + return dev_err_probe(&i2c->dev, intb_irq, "INTB IRQ not configured\n"); 215 + 216 + regmap = devm_regmap_init_i2c(i2c, &bd96801_regmap_config); 217 + if (IS_ERR(regmap)) 218 + return dev_err_probe(&i2c->dev, PTR_ERR(regmap), 219 + "Regmap initialization failed\n"); 220 + 221 + ret = regmap_write(regmap, BD96801_LOCK_REG, BD96801_UNLOCK); 222 + if (ret) 223 + return dev_err_probe(&i2c->dev, ret, "Failed to unlock PMIC\n"); 224 + 225 + ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, intb_irq, 226 + IRQF_ONESHOT, 0, &bd96801_irq_chip_intb, 227 + &intb_irq_data); 228 + if (ret) 229 + return dev_err_probe(&i2c->dev, ret, "Failed to add INTB IRQ chip\n"); 230 + 231 + intb_domain = regmap_irq_get_domain(intb_irq_data); 232 + 233 + ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, 234 + bd96801_cells, 235 + ARRAY_SIZE(bd96801_cells), NULL, 0, 236 + intb_domain); 237 + if (ret) 238 + dev_err(&i2c->dev, "Failed to create subdevices\n"); 239 + 240 + return ret; 241 + } 242 + 243 + static const struct of_device_id bd96801_of_match[] = { 244 + { .compatible = "rohm,bd96801", }, 245 + { } 246 + }; 247 + MODULE_DEVICE_TABLE(of, bd96801_of_match); 248 + 249 + static struct i2c_driver bd96801_i2c_driver = { 250 + .driver = { 251 + .name = "rohm-bd96801", 252 + .of_match_table = bd96801_of_match, 253 + }, 254 + .probe = bd96801_i2c_probe, 255 + }; 256 + 257 + static int __init bd96801_i2c_init(void) 258 + { 259 + return i2c_add_driver(&bd96801_i2c_driver); 260 + } 261 + 262 + /* Initialise early so consumer devices can complete system boot */ 263 + subsys_initcall(bd96801_i2c_init); 264 + 265 + static void __exit bd96801_i2c_exit(void) 266 + { 267 + i2c_del_driver(&bd96801_i2c_driver); 268 + } 269 + module_exit(bd96801_i2c_exit); 270 + 271 + MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); 272 + MODULE_DESCRIPTION("ROHM BD96801 Power Management IC driver"); 273 + MODULE_LICENSE("GPL");
+12
drivers/regulator/Kconfig
··· 274 274 This driver can also be built as a module. If so, the module 275 275 will be called bd9576-regulator. 276 276 277 + config REGULATOR_BD96801 278 + tristate "ROHM BD96801 Power Regulator" 279 + depends on MFD_ROHM_BD96801 280 + select REGULATOR_ROHM 281 + help 282 + This driver supports voltage regulators on ROHM BD96801 PMIC. 283 + This will enable support for the software controllable buck 284 + and LDO regulators. 285 + 286 + This driver can also be built as a module. If so, the module 287 + will be called bd96801-regulator. 288 + 277 289 config REGULATOR_CPCAP 278 290 tristate "Motorola CPCAP regulator" 279 291 depends on MFD_CPCAP
+1
drivers/regulator/Makefile
··· 38 38 obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o 39 39 obj-$(CONFIG_REGULATOR_BD957XMUF) += bd9576-regulator.o 40 40 obj-$(CONFIG_REGULATOR_DA903X) += da903x-regulator.o 41 + obj-$(CONFIG_REGULATOR_BD96801) += bd96801-regulator.o 41 42 obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o 42 43 obj-$(CONFIG_REGULATOR_DA9055) += da9055-regulator.o 43 44 obj-$(CONFIG_REGULATOR_DA9062) += da9062-regulator.o
+908
drivers/regulator/bd96801-regulator.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2024 ROHM Semiconductors 3 + // bd96801-regulator.c ROHM BD96801 regulator driver 4 + 5 + /* 6 + * This version of the "BD86801 scalable PMIC"'s driver supports only very 7 + * basic set of the PMIC features. Most notably, there is no support for 8 + * the ERRB interrupt and the configurations which should be done when the 9 + * PMIC is in STBY mode. 10 + * 11 + * Supporting the ERRB interrupt would require dropping the regmap-IRQ 12 + * usage or working around (or accepting a presense of) a naming conflict 13 + * in debugFS IRQs. 14 + * 15 + * Being able to reliably do the configurations like changing the 16 + * regulator safety limits (like limits for the over/under -voltages, over 17 + * current, thermal protection) would require the configuring driver to be 18 + * synchronized with entity causing the PMIC state transitions. Eg, one 19 + * should be able to ensure the PMIC is in STBY state when the 20 + * configurations are applied to the hardware. How and when the PMIC state 21 + * transitions are to be done is likely to be very system specific, as will 22 + * be the need to configure these safety limits. Hence it's not simple to 23 + * come up with a generic solution. 24 + * 25 + * Users who require the ERRB handling and STBY state configurations can 26 + * have a look at the original RFC: 27 + * https://lore.kernel.org/all/cover.1712920132.git.mazziesaccount@gmail.com/ 28 + * which implements a workaround to debugFS naming conflict and some of 29 + * the safety limit configurations - but leaves the state change handling 30 + * and synchronization to be implemented. 31 + * 32 + * It would be great to hear (and receive a patch!) if you implement the 33 + * STBY configuration support or a proper fix to the debugFS naming 34 + * conflict in your downstream driver ;) 35 + */ 36 + 37 + #include <linux/delay.h> 38 + #include <linux/err.h> 39 + #include <linux/interrupt.h> 40 + #include <linux/kernel.h> 41 + #include <linux/linear_range.h> 42 + #include <linux/mfd/rohm-generic.h> 43 + #include <linux/mfd/rohm-bd96801.h> 44 + #include <linux/module.h> 45 + #include <linux/of.h> 46 + #include <linux/platform_device.h> 47 + #include <linux/regmap.h> 48 + #include <linux/regulator/coupler.h> 49 + #include <linux/regulator/driver.h> 50 + #include <linux/regulator/machine.h> 51 + #include <linux/regulator/of_regulator.h> 52 + #include <linux/slab.h> 53 + #include <linux/timer.h> 54 + 55 + enum { 56 + BD96801_BUCK1, 57 + BD96801_BUCK2, 58 + BD96801_BUCK3, 59 + BD96801_BUCK4, 60 + BD96801_LDO5, 61 + BD96801_LDO6, 62 + BD96801_LDO7, 63 + BD96801_REGULATOR_AMOUNT, 64 + }; 65 + 66 + enum { 67 + BD96801_PROT_OVP, 68 + BD96801_PROT_UVP, 69 + BD96801_PROT_OCP, 70 + BD96801_PROT_TEMP, 71 + BD96801_NUM_PROT, 72 + }; 73 + 74 + #define BD96801_ALWAYS_ON_REG 0x3c 75 + #define BD96801_REG_ENABLE 0x0b 76 + #define BD96801_BUCK1_EN_MASK BIT(0) 77 + #define BD96801_BUCK2_EN_MASK BIT(1) 78 + #define BD96801_BUCK3_EN_MASK BIT(2) 79 + #define BD96801_BUCK4_EN_MASK BIT(3) 80 + #define BD96801_LDO5_EN_MASK BIT(4) 81 + #define BD96801_LDO6_EN_MASK BIT(5) 82 + #define BD96801_LDO7_EN_MASK BIT(6) 83 + 84 + #define BD96801_BUCK1_VSEL_REG 0x28 85 + #define BD96801_BUCK2_VSEL_REG 0x29 86 + #define BD96801_BUCK3_VSEL_REG 0x2a 87 + #define BD96801_BUCK4_VSEL_REG 0x2b 88 + #define BD96801_LDO5_VSEL_REG 0x25 89 + #define BD96801_LDO6_VSEL_REG 0x26 90 + #define BD96801_LDO7_VSEL_REG 0x27 91 + #define BD96801_BUCK_VSEL_MASK 0x1F 92 + #define BD96801_LDO_VSEL_MASK 0xff 93 + 94 + #define BD96801_MASK_RAMP_DELAY 0xc0 95 + #define BD96801_INT_VOUT_BASE_REG 0x21 96 + #define BD96801_BUCK_INT_VOUT_MASK 0xff 97 + 98 + #define BD96801_BUCK_VOLTS 256 99 + #define BD96801_LDO_VOLTS 256 100 + 101 + #define BD96801_OVP_MASK 0x03 102 + #define BD96801_MASK_BUCK1_OVP_SHIFT 0x00 103 + #define BD96801_MASK_BUCK2_OVP_SHIFT 0x02 104 + #define BD96801_MASK_BUCK3_OVP_SHIFT 0x04 105 + #define BD96801_MASK_BUCK4_OVP_SHIFT 0x06 106 + #define BD96801_MASK_LDO5_OVP_SHIFT 0x00 107 + #define BD96801_MASK_LDO6_OVP_SHIFT 0x02 108 + #define BD96801_MASK_LDO7_OVP_SHIFT 0x04 109 + 110 + #define BD96801_PROT_LIMIT_OCP_MIN 0x00 111 + #define BD96801_PROT_LIMIT_LOW 0x01 112 + #define BD96801_PROT_LIMIT_MID 0x02 113 + #define BD96801_PROT_LIMIT_HI 0x03 114 + 115 + #define BD96801_REG_BUCK1_OCP 0x32 116 + #define BD96801_REG_BUCK2_OCP 0x32 117 + #define BD96801_REG_BUCK3_OCP 0x33 118 + #define BD96801_REG_BUCK4_OCP 0x33 119 + 120 + #define BD96801_MASK_BUCK1_OCP_SHIFT 0x00 121 + #define BD96801_MASK_BUCK2_OCP_SHIFT 0x04 122 + #define BD96801_MASK_BUCK3_OCP_SHIFT 0x00 123 + #define BD96801_MASK_BUCK4_OCP_SHIFT 0x04 124 + 125 + #define BD96801_REG_LDO5_OCP 0x34 126 + #define BD96801_REG_LDO6_OCP 0x34 127 + #define BD96801_REG_LDO7_OCP 0x34 128 + 129 + #define BD96801_MASK_LDO5_OCP_SHIFT 0x00 130 + #define BD96801_MASK_LDO6_OCP_SHIFT 0x02 131 + #define BD96801_MASK_LDO7_OCP_SHIFT 0x04 132 + 133 + #define BD96801_MASK_SHD_INTB BIT(7) 134 + #define BD96801_INTB_FATAL BIT(7) 135 + 136 + #define BD96801_NUM_REGULATORS 7 137 + #define BD96801_NUM_LDOS 4 138 + 139 + /* 140 + * Ramp rates for bucks are controlled by bits [7:6] as follows: 141 + * 00 => 1 mV/uS 142 + * 01 => 5 mV/uS 143 + * 10 => 10 mV/uS 144 + * 11 => 20 mV/uS 145 + */ 146 + static const unsigned int buck_ramp_table[] = { 1000, 5000, 10000, 20000 }; 147 + 148 + /* 149 + * This is a voltage range that get's appended to selected 150 + * bd96801_buck_init_volts value. The range from 0x0 to 0xF is actually 151 + * bd96801_buck_init_volts + 0 ... bd96801_buck_init_volts + 150mV 152 + * and the range from 0x10 to 0x1f is bd96801_buck_init_volts - 150mV ... 153 + * bd96801_buck_init_volts - 0. But as the members of linear_range 154 + * are all unsigned I will apply offset of -150 mV to value in 155 + * linear_range - which should increase these ranges with 156 + * 150 mV getting all the values to >= 0. 157 + */ 158 + static const struct linear_range bd96801_tune_volts[] = { 159 + REGULATOR_LINEAR_RANGE(150000, 0x00, 0xF, 10000), 160 + REGULATOR_LINEAR_RANGE(0, 0x10, 0x1F, 10000), 161 + }; 162 + 163 + static const struct linear_range bd96801_buck_init_volts[] = { 164 + REGULATOR_LINEAR_RANGE(500000 - 150000, 0x00, 0xc8, 5000), 165 + REGULATOR_LINEAR_RANGE(1550000 - 150000, 0xc9, 0xec, 50000), 166 + REGULATOR_LINEAR_RANGE(3300000 - 150000, 0xed, 0xff, 0), 167 + }; 168 + 169 + static const struct linear_range bd96801_ldo_int_volts[] = { 170 + REGULATOR_LINEAR_RANGE(300000, 0x00, 0x78, 25000), 171 + REGULATOR_LINEAR_RANGE(3300000, 0x79, 0xff, 0), 172 + }; 173 + 174 + #define BD96801_LDO_SD_VOLT_MASK 0x1 175 + #define BD96801_LDO_MODE_MASK 0x6 176 + #define BD96801_LDO_MODE_INT 0x0 177 + #define BD96801_LDO_MODE_SD 0x2 178 + #define BD96801_LDO_MODE_DDR 0x4 179 + 180 + static int ldo_ddr_volt_table[] = {500000, 300000}; 181 + static int ldo_sd_volt_table[] = {3300000, 1800000}; 182 + 183 + /* Constant IRQ initialization data (templates) */ 184 + struct bd96801_irqinfo { 185 + int type; 186 + struct regulator_irq_desc irq_desc; 187 + int err_cfg; 188 + int wrn_cfg; 189 + const char *irq_name; 190 + }; 191 + 192 + #define BD96801_IRQINFO(_type, _name, _irqoff_ms, _irqname) \ 193 + { \ 194 + .type = (_type), \ 195 + .err_cfg = -1, \ 196 + .wrn_cfg = -1, \ 197 + .irq_name = (_irqname), \ 198 + .irq_desc = { \ 199 + .name = (_name), \ 200 + .irq_off_ms = (_irqoff_ms), \ 201 + .map_event = regulator_irq_map_event_simple, \ 202 + }, \ 203 + } 204 + 205 + static const struct bd96801_irqinfo buck1_irqinfo[] = { 206 + BD96801_IRQINFO(BD96801_PROT_OCP, "buck1-over-curr-h", 500, 207 + "bd96801-buck1-overcurr-h"), 208 + BD96801_IRQINFO(BD96801_PROT_OCP, "buck1-over-curr-l", 500, 209 + "bd96801-buck1-overcurr-l"), 210 + BD96801_IRQINFO(BD96801_PROT_OCP, "buck1-over-curr-n", 500, 211 + "bd96801-buck1-overcurr-n"), 212 + BD96801_IRQINFO(BD96801_PROT_OVP, "buck1-over-voltage", 500, 213 + "bd96801-buck1-overvolt"), 214 + BD96801_IRQINFO(BD96801_PROT_UVP, "buck1-under-voltage", 500, 215 + "bd96801-buck1-undervolt"), 216 + BD96801_IRQINFO(BD96801_PROT_TEMP, "buck1-over-temp", 500, 217 + "bd96801-buck1-thermal") 218 + }; 219 + 220 + static const struct bd96801_irqinfo buck2_irqinfo[] = { 221 + BD96801_IRQINFO(BD96801_PROT_OCP, "buck2-over-curr-h", 500, 222 + "bd96801-buck2-overcurr-h"), 223 + BD96801_IRQINFO(BD96801_PROT_OCP, "buck2-over-curr-l", 500, 224 + "bd96801-buck2-overcurr-l"), 225 + BD96801_IRQINFO(BD96801_PROT_OCP, "buck2-over-curr-n", 500, 226 + "bd96801-buck2-overcurr-n"), 227 + BD96801_IRQINFO(BD96801_PROT_OVP, "buck2-over-voltage", 500, 228 + "bd96801-buck2-overvolt"), 229 + BD96801_IRQINFO(BD96801_PROT_UVP, "buck2-under-voltage", 500, 230 + "bd96801-buck2-undervolt"), 231 + BD96801_IRQINFO(BD96801_PROT_TEMP, "buck2-over-temp", 500, 232 + "bd96801-buck2-thermal") 233 + }; 234 + 235 + static const struct bd96801_irqinfo buck3_irqinfo[] = { 236 + BD96801_IRQINFO(BD96801_PROT_OCP, "buck3-over-curr-h", 500, 237 + "bd96801-buck3-overcurr-h"), 238 + BD96801_IRQINFO(BD96801_PROT_OCP, "buck3-over-curr-l", 500, 239 + "bd96801-buck3-overcurr-l"), 240 + BD96801_IRQINFO(BD96801_PROT_OCP, "buck3-over-curr-n", 500, 241 + "bd96801-buck3-overcurr-n"), 242 + BD96801_IRQINFO(BD96801_PROT_OVP, "buck3-over-voltage", 500, 243 + "bd96801-buck3-overvolt"), 244 + BD96801_IRQINFO(BD96801_PROT_UVP, "buck3-under-voltage", 500, 245 + "bd96801-buck3-undervolt"), 246 + BD96801_IRQINFO(BD96801_PROT_TEMP, "buck3-over-temp", 500, 247 + "bd96801-buck3-thermal") 248 + }; 249 + 250 + static const struct bd96801_irqinfo buck4_irqinfo[] = { 251 + BD96801_IRQINFO(BD96801_PROT_OCP, "buck4-over-curr-h", 500, 252 + "bd96801-buck4-overcurr-h"), 253 + BD96801_IRQINFO(BD96801_PROT_OCP, "buck4-over-curr-l", 500, 254 + "bd96801-buck4-overcurr-l"), 255 + BD96801_IRQINFO(BD96801_PROT_OCP, "buck4-over-curr-n", 500, 256 + "bd96801-buck4-overcurr-n"), 257 + BD96801_IRQINFO(BD96801_PROT_OVP, "buck4-over-voltage", 500, 258 + "bd96801-buck4-overvolt"), 259 + BD96801_IRQINFO(BD96801_PROT_UVP, "buck4-under-voltage", 500, 260 + "bd96801-buck4-undervolt"), 261 + BD96801_IRQINFO(BD96801_PROT_TEMP, "buck4-over-temp", 500, 262 + "bd96801-buck4-thermal") 263 + }; 264 + 265 + static const struct bd96801_irqinfo ldo5_irqinfo[] = { 266 + BD96801_IRQINFO(BD96801_PROT_OCP, "ldo5-overcurr", 500, 267 + "bd96801-ldo5-overcurr"), 268 + BD96801_IRQINFO(BD96801_PROT_OVP, "ldo5-over-voltage", 500, 269 + "bd96801-ldo5-overvolt"), 270 + BD96801_IRQINFO(BD96801_PROT_UVP, "ldo5-under-voltage", 500, 271 + "bd96801-ldo5-undervolt"), 272 + }; 273 + 274 + static const struct bd96801_irqinfo ldo6_irqinfo[] = { 275 + BD96801_IRQINFO(BD96801_PROT_OCP, "ldo6-overcurr", 500, 276 + "bd96801-ldo6-overcurr"), 277 + BD96801_IRQINFO(BD96801_PROT_OVP, "ldo6-over-voltage", 500, 278 + "bd96801-ldo6-overvolt"), 279 + BD96801_IRQINFO(BD96801_PROT_UVP, "ldo6-under-voltage", 500, 280 + "bd96801-ldo6-undervolt"), 281 + }; 282 + 283 + static const struct bd96801_irqinfo ldo7_irqinfo[] = { 284 + BD96801_IRQINFO(BD96801_PROT_OCP, "ldo7-overcurr", 500, 285 + "bd96801-ldo7-overcurr"), 286 + BD96801_IRQINFO(BD96801_PROT_OVP, "ldo7-over-voltage", 500, 287 + "bd96801-ldo7-overvolt"), 288 + BD96801_IRQINFO(BD96801_PROT_UVP, "ldo7-under-voltage", 500, 289 + "bd96801-ldo7-undervolt"), 290 + }; 291 + 292 + struct bd96801_irq_desc { 293 + struct bd96801_irqinfo *irqinfo; 294 + int num_irqs; 295 + }; 296 + 297 + struct bd96801_regulator_data { 298 + struct regulator_desc desc; 299 + const struct linear_range *init_ranges; 300 + int num_ranges; 301 + struct bd96801_irq_desc irq_desc; 302 + int initial_voltage; 303 + int ldo_vol_lvl; 304 + int ldo_errs; 305 + }; 306 + 307 + struct bd96801_pmic_data { 308 + struct bd96801_regulator_data regulator_data[BD96801_NUM_REGULATORS]; 309 + struct regmap *regmap; 310 + int fatal_ind; 311 + }; 312 + 313 + static int ldo_map_notif(int irq, struct regulator_irq_data *rid, 314 + unsigned long *dev_mask) 315 + { 316 + int i; 317 + 318 + for (i = 0; i < rid->num_states; i++) { 319 + struct bd96801_regulator_data *rdata; 320 + struct regulator_dev *rdev; 321 + 322 + rdev = rid->states[i].rdev; 323 + rdata = container_of(rdev->desc, struct bd96801_regulator_data, 324 + desc); 325 + rid->states[i].notifs = regulator_err2notif(rdata->ldo_errs); 326 + rid->states[i].errors = rdata->ldo_errs; 327 + *dev_mask |= BIT(i); 328 + } 329 + return 0; 330 + } 331 + 332 + static int bd96801_list_voltage_lr(struct regulator_dev *rdev, 333 + unsigned int selector) 334 + { 335 + int voltage; 336 + struct bd96801_regulator_data *data; 337 + 338 + data = container_of(rdev->desc, struct bd96801_regulator_data, desc); 339 + 340 + /* 341 + * The BD096801 has voltage setting in two registers. One giving the 342 + * "initial voltage" (can be changed only when regulator is disabled. 343 + * This driver caches the value and sets it only at startup. The other 344 + * register is voltage tuning value which applies -150 mV ... +150 mV 345 + * offset to the voltage. 346 + * 347 + * Note that the cached initial voltage stored in regulator data is 348 + * 'scaled down' by the 150 mV so that all of our tuning values are 349 + * >= 0. This is done because the linear_ranges uses unsigned values. 350 + * 351 + * As a result, we increase the tuning voltage which we get based on 352 + * the selector by the stored initial_voltage. 353 + */ 354 + voltage = regulator_list_voltage_linear_range(rdev, selector); 355 + if (voltage < 0) 356 + return voltage; 357 + 358 + return voltage + data->initial_voltage; 359 + } 360 + 361 + 362 + static const struct regulator_ops bd96801_ldo_table_ops = { 363 + .is_enabled = regulator_is_enabled_regmap, 364 + .list_voltage = regulator_list_voltage_table, 365 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 366 + }; 367 + 368 + static const struct regulator_ops bd96801_buck_ops = { 369 + .is_enabled = regulator_is_enabled_regmap, 370 + .list_voltage = bd96801_list_voltage_lr, 371 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 372 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 373 + .set_voltage_time_sel = regulator_set_voltage_time_sel, 374 + .set_ramp_delay = regulator_set_ramp_delay_regmap, 375 + }; 376 + 377 + static const struct regulator_ops bd96801_ldo_ops = { 378 + .is_enabled = regulator_is_enabled_regmap, 379 + .list_voltage = regulator_list_voltage_linear_range, 380 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 381 + }; 382 + 383 + static int buck_get_initial_voltage(struct regmap *regmap, struct device *dev, 384 + struct bd96801_regulator_data *data) 385 + { 386 + int ret = 0, sel, initial_uv; 387 + int reg = BD96801_INT_VOUT_BASE_REG + data->desc.id; 388 + 389 + if (data->num_ranges) { 390 + ret = regmap_read(regmap, reg, &sel); 391 + sel &= BD96801_BUCK_INT_VOUT_MASK; 392 + 393 + ret = linear_range_get_value_array(data->init_ranges, 394 + data->num_ranges, sel, 395 + &initial_uv); 396 + if (ret) 397 + return ret; 398 + 399 + data->initial_voltage = initial_uv; 400 + dev_dbg(dev, "Tune-scaled initial voltage %u\n", 401 + data->initial_voltage); 402 + } 403 + 404 + return 0; 405 + } 406 + 407 + static int get_ldo_initial_voltage(struct regmap *regmap, 408 + struct device *dev, 409 + struct bd96801_regulator_data *data) 410 + { 411 + int ret; 412 + int cfgreg; 413 + 414 + ret = regmap_read(regmap, data->ldo_vol_lvl, &cfgreg); 415 + if (ret) 416 + return ret; 417 + 418 + switch (cfgreg & BD96801_LDO_MODE_MASK) { 419 + case BD96801_LDO_MODE_DDR: 420 + data->desc.volt_table = ldo_ddr_volt_table; 421 + data->desc.n_voltages = ARRAY_SIZE(ldo_ddr_volt_table); 422 + break; 423 + case BD96801_LDO_MODE_SD: 424 + data->desc.volt_table = ldo_sd_volt_table; 425 + data->desc.n_voltages = ARRAY_SIZE(ldo_sd_volt_table); 426 + break; 427 + default: 428 + dev_info(dev, "Leaving LDO to normal mode"); 429 + return 0; 430 + } 431 + 432 + /* SD or DDR mode => override default ops */ 433 + data->desc.ops = &bd96801_ldo_table_ops, 434 + data->desc.vsel_mask = 1; 435 + data->desc.vsel_reg = data->ldo_vol_lvl; 436 + 437 + return 0; 438 + } 439 + 440 + static int get_initial_voltage(struct device *dev, struct regmap *regmap, 441 + struct bd96801_regulator_data *data) 442 + { 443 + /* BUCK */ 444 + if (data->desc.id <= BD96801_BUCK4) 445 + return buck_get_initial_voltage(regmap, dev, data); 446 + 447 + /* LDO */ 448 + return get_ldo_initial_voltage(regmap, dev, data); 449 + } 450 + 451 + static int bd96801_walk_regulator_dt(struct device *dev, struct regmap *regmap, 452 + struct bd96801_regulator_data *data, 453 + int num) 454 + { 455 + int i, ret; 456 + struct device_node *np; 457 + struct device_node *nproot = dev->parent->of_node; 458 + 459 + nproot = of_get_child_by_name(nproot, "regulators"); 460 + if (!nproot) { 461 + dev_err(dev, "failed to find regulators node\n"); 462 + return -ENODEV; 463 + } 464 + for_each_child_of_node(nproot, np) 465 + for (i = 0; i < num; i++) { 466 + if (!of_node_name_eq(np, data[i].desc.of_match)) 467 + continue; 468 + /* 469 + * If STBY configs are supported, we must pass node 470 + * here to extract the initial voltages from the DT. 471 + * Thus we do the initial voltage getting in this 472 + * loop. 473 + */ 474 + ret = get_initial_voltage(dev, regmap, &data[i]); 475 + if (ret) { 476 + dev_err(dev, 477 + "Initializing voltages for %s failed\n", 478 + data[i].desc.name); 479 + of_node_put(np); 480 + of_node_put(nproot); 481 + 482 + return ret; 483 + } 484 + if (of_property_read_bool(np, "rohm,keep-on-stby")) { 485 + ret = regmap_set_bits(regmap, 486 + BD96801_ALWAYS_ON_REG, 487 + 1 << data[i].desc.id); 488 + if (ret) { 489 + dev_err(dev, 490 + "failed to set %s on-at-stby\n", 491 + data[i].desc.name); 492 + of_node_put(np); 493 + of_node_put(nproot); 494 + 495 + return ret; 496 + } 497 + } 498 + } 499 + of_node_put(nproot); 500 + 501 + return 0; 502 + } 503 + 504 + /* 505 + * Template for regulator data. Probe will allocate dynamic / driver instance 506 + * struct so we should be on a safe side even if there were multiple PMICs to 507 + * control. Note that there is a plan to allow multiple PMICs to be used so 508 + * systems can scale better. I am however still slightly unsure how the 509 + * multi-PMIC case will be handled. I don't know if the processor will have I2C 510 + * acces to all of the PMICs or only the first one. I'd guess there will be 511 + * access provided to all PMICs for voltage scaling - but the errors will only 512 + * be informed via the master PMIC. Eg, we should prepare to support multiple 513 + * driver instances - either with or without the IRQs... Well, let's first 514 + * just support the simple and clear single-PMIC setup and ponder the multi PMIC 515 + * case later. What we can easly do for preparing is to not use static global 516 + * data for regulators though. 517 + */ 518 + static const struct bd96801_pmic_data bd96801_data = { 519 + .regulator_data = { 520 + { 521 + .desc = { 522 + .name = "buck1", 523 + .of_match = of_match_ptr("buck1"), 524 + .regulators_node = of_match_ptr("regulators"), 525 + .id = BD96801_BUCK1, 526 + .ops = &bd96801_buck_ops, 527 + .type = REGULATOR_VOLTAGE, 528 + .linear_ranges = bd96801_tune_volts, 529 + .n_linear_ranges = ARRAY_SIZE(bd96801_tune_volts), 530 + .n_voltages = BD96801_BUCK_VOLTS, 531 + .enable_reg = BD96801_REG_ENABLE, 532 + .enable_mask = BD96801_BUCK1_EN_MASK, 533 + .enable_is_inverted = true, 534 + .vsel_reg = BD96801_BUCK1_VSEL_REG, 535 + .vsel_mask = BD96801_BUCK_VSEL_MASK, 536 + .ramp_reg = BD96801_BUCK1_VSEL_REG, 537 + .ramp_mask = BD96801_MASK_RAMP_DELAY, 538 + .ramp_delay_table = &buck_ramp_table[0], 539 + .n_ramp_values = ARRAY_SIZE(buck_ramp_table), 540 + .owner = THIS_MODULE, 541 + }, 542 + .init_ranges = bd96801_buck_init_volts, 543 + .num_ranges = ARRAY_SIZE(bd96801_buck_init_volts), 544 + .irq_desc = { 545 + .irqinfo = (struct bd96801_irqinfo *)&buck1_irqinfo[0], 546 + .num_irqs = ARRAY_SIZE(buck1_irqinfo), 547 + }, 548 + }, { 549 + .desc = { 550 + .name = "buck2", 551 + .of_match = of_match_ptr("buck2"), 552 + .regulators_node = of_match_ptr("regulators"), 553 + .id = BD96801_BUCK2, 554 + .ops = &bd96801_buck_ops, 555 + .type = REGULATOR_VOLTAGE, 556 + .linear_ranges = bd96801_tune_volts, 557 + .n_linear_ranges = ARRAY_SIZE(bd96801_tune_volts), 558 + .n_voltages = BD96801_BUCK_VOLTS, 559 + .enable_reg = BD96801_REG_ENABLE, 560 + .enable_mask = BD96801_BUCK2_EN_MASK, 561 + .enable_is_inverted = true, 562 + .vsel_reg = BD96801_BUCK2_VSEL_REG, 563 + .vsel_mask = BD96801_BUCK_VSEL_MASK, 564 + .ramp_reg = BD96801_BUCK2_VSEL_REG, 565 + .ramp_mask = BD96801_MASK_RAMP_DELAY, 566 + .ramp_delay_table = &buck_ramp_table[0], 567 + .n_ramp_values = ARRAY_SIZE(buck_ramp_table), 568 + .owner = THIS_MODULE, 569 + }, 570 + .irq_desc = { 571 + .irqinfo = (struct bd96801_irqinfo *)&buck2_irqinfo[0], 572 + .num_irqs = ARRAY_SIZE(buck2_irqinfo), 573 + }, 574 + .init_ranges = bd96801_buck_init_volts, 575 + .num_ranges = ARRAY_SIZE(bd96801_buck_init_volts), 576 + }, { 577 + .desc = { 578 + .name = "buck3", 579 + .of_match = of_match_ptr("buck3"), 580 + .regulators_node = of_match_ptr("regulators"), 581 + .id = BD96801_BUCK3, 582 + .ops = &bd96801_buck_ops, 583 + .type = REGULATOR_VOLTAGE, 584 + .linear_ranges = bd96801_tune_volts, 585 + .n_linear_ranges = ARRAY_SIZE(bd96801_tune_volts), 586 + .n_voltages = BD96801_BUCK_VOLTS, 587 + .enable_reg = BD96801_REG_ENABLE, 588 + .enable_mask = BD96801_BUCK3_EN_MASK, 589 + .enable_is_inverted = true, 590 + .vsel_reg = BD96801_BUCK3_VSEL_REG, 591 + .vsel_mask = BD96801_BUCK_VSEL_MASK, 592 + .ramp_reg = BD96801_BUCK3_VSEL_REG, 593 + .ramp_mask = BD96801_MASK_RAMP_DELAY, 594 + .ramp_delay_table = &buck_ramp_table[0], 595 + .n_ramp_values = ARRAY_SIZE(buck_ramp_table), 596 + .owner = THIS_MODULE, 597 + }, 598 + .irq_desc = { 599 + .irqinfo = (struct bd96801_irqinfo *)&buck3_irqinfo[0], 600 + .num_irqs = ARRAY_SIZE(buck3_irqinfo), 601 + }, 602 + .init_ranges = bd96801_buck_init_volts, 603 + .num_ranges = ARRAY_SIZE(bd96801_buck_init_volts), 604 + }, { 605 + .desc = { 606 + .name = "buck4", 607 + .of_match = of_match_ptr("buck4"), 608 + .regulators_node = of_match_ptr("regulators"), 609 + .id = BD96801_BUCK4, 610 + .ops = &bd96801_buck_ops, 611 + .type = REGULATOR_VOLTAGE, 612 + .linear_ranges = bd96801_tune_volts, 613 + .n_linear_ranges = ARRAY_SIZE(bd96801_tune_volts), 614 + .n_voltages = BD96801_BUCK_VOLTS, 615 + .enable_reg = BD96801_REG_ENABLE, 616 + .enable_mask = BD96801_BUCK4_EN_MASK, 617 + .enable_is_inverted = true, 618 + .vsel_reg = BD96801_BUCK4_VSEL_REG, 619 + .vsel_mask = BD96801_BUCK_VSEL_MASK, 620 + .ramp_reg = BD96801_BUCK4_VSEL_REG, 621 + .ramp_mask = BD96801_MASK_RAMP_DELAY, 622 + .ramp_delay_table = &buck_ramp_table[0], 623 + .n_ramp_values = ARRAY_SIZE(buck_ramp_table), 624 + .owner = THIS_MODULE, 625 + }, 626 + .irq_desc = { 627 + .irqinfo = (struct bd96801_irqinfo *)&buck4_irqinfo[0], 628 + .num_irqs = ARRAY_SIZE(buck4_irqinfo), 629 + }, 630 + .init_ranges = bd96801_buck_init_volts, 631 + .num_ranges = ARRAY_SIZE(bd96801_buck_init_volts), 632 + }, { 633 + .desc = { 634 + .name = "ldo5", 635 + .of_match = of_match_ptr("ldo5"), 636 + .regulators_node = of_match_ptr("regulators"), 637 + .id = BD96801_LDO5, 638 + .ops = &bd96801_ldo_ops, 639 + .type = REGULATOR_VOLTAGE, 640 + .linear_ranges = bd96801_ldo_int_volts, 641 + .n_linear_ranges = ARRAY_SIZE(bd96801_ldo_int_volts), 642 + .n_voltages = BD96801_LDO_VOLTS, 643 + .enable_reg = BD96801_REG_ENABLE, 644 + .enable_mask = BD96801_LDO5_EN_MASK, 645 + .enable_is_inverted = true, 646 + .vsel_reg = BD96801_LDO5_VSEL_REG, 647 + .vsel_mask = BD96801_LDO_VSEL_MASK, 648 + .owner = THIS_MODULE, 649 + }, 650 + .irq_desc = { 651 + .irqinfo = (struct bd96801_irqinfo *)&ldo5_irqinfo[0], 652 + .num_irqs = ARRAY_SIZE(ldo5_irqinfo), 653 + }, 654 + .ldo_vol_lvl = BD96801_LDO5_VOL_LVL_REG, 655 + }, { 656 + .desc = { 657 + .name = "ldo6", 658 + .of_match = of_match_ptr("ldo6"), 659 + .regulators_node = of_match_ptr("regulators"), 660 + .id = BD96801_LDO6, 661 + .ops = &bd96801_ldo_ops, 662 + .type = REGULATOR_VOLTAGE, 663 + .linear_ranges = bd96801_ldo_int_volts, 664 + .n_linear_ranges = ARRAY_SIZE(bd96801_ldo_int_volts), 665 + .n_voltages = BD96801_LDO_VOLTS, 666 + .enable_reg = BD96801_REG_ENABLE, 667 + .enable_mask = BD96801_LDO6_EN_MASK, 668 + .enable_is_inverted = true, 669 + .vsel_reg = BD96801_LDO6_VSEL_REG, 670 + .vsel_mask = BD96801_LDO_VSEL_MASK, 671 + .owner = THIS_MODULE, 672 + }, 673 + .irq_desc = { 674 + .irqinfo = (struct bd96801_irqinfo *)&ldo6_irqinfo[0], 675 + .num_irqs = ARRAY_SIZE(ldo6_irqinfo), 676 + }, 677 + .ldo_vol_lvl = BD96801_LDO6_VOL_LVL_REG, 678 + }, { 679 + .desc = { 680 + .name = "ldo7", 681 + .of_match = of_match_ptr("ldo7"), 682 + .regulators_node = of_match_ptr("regulators"), 683 + .id = BD96801_LDO7, 684 + .ops = &bd96801_ldo_ops, 685 + .type = REGULATOR_VOLTAGE, 686 + .linear_ranges = bd96801_ldo_int_volts, 687 + .n_linear_ranges = ARRAY_SIZE(bd96801_ldo_int_volts), 688 + .n_voltages = BD96801_LDO_VOLTS, 689 + .enable_reg = BD96801_REG_ENABLE, 690 + .enable_mask = BD96801_LDO7_EN_MASK, 691 + .enable_is_inverted = true, 692 + .vsel_reg = BD96801_LDO7_VSEL_REG, 693 + .vsel_mask = BD96801_LDO_VSEL_MASK, 694 + .owner = THIS_MODULE, 695 + }, 696 + .irq_desc = { 697 + .irqinfo = (struct bd96801_irqinfo *)&ldo7_irqinfo[0], 698 + .num_irqs = ARRAY_SIZE(ldo7_irqinfo), 699 + }, 700 + .ldo_vol_lvl = BD96801_LDO7_VOL_LVL_REG, 701 + }, 702 + }, 703 + }; 704 + 705 + static int initialize_pmic_data(struct device *dev, 706 + struct bd96801_pmic_data *pdata) 707 + { 708 + int r, i; 709 + 710 + /* 711 + * Allocate and initialize IRQ data for all of the regulators. We 712 + * wish to modify IRQ information independently for each driver 713 + * instance. 714 + */ 715 + for (r = 0; r < BD96801_NUM_REGULATORS; r++) { 716 + const struct bd96801_irqinfo *template; 717 + struct bd96801_irqinfo *new; 718 + int num_infos; 719 + 720 + template = pdata->regulator_data[r].irq_desc.irqinfo; 721 + num_infos = pdata->regulator_data[r].irq_desc.num_irqs; 722 + 723 + new = devm_kcalloc(dev, num_infos, sizeof(*new), GFP_KERNEL); 724 + if (!new) 725 + return -ENOMEM; 726 + 727 + pdata->regulator_data[r].irq_desc.irqinfo = new; 728 + 729 + for (i = 0; i < num_infos; i++) 730 + new[i] = template[i]; 731 + } 732 + 733 + return 0; 734 + } 735 + 736 + static int bd96801_rdev_intb_irqs(struct platform_device *pdev, 737 + struct bd96801_pmic_data *pdata, 738 + struct bd96801_irqinfo *iinfo, 739 + struct regulator_dev *rdev) 740 + { 741 + struct regulator_dev *rdev_arr[1]; 742 + void *retp; 743 + int err = 0; 744 + int irq; 745 + int err_flags[] = { 746 + [BD96801_PROT_OVP] = REGULATOR_ERROR_REGULATION_OUT, 747 + [BD96801_PROT_UVP] = REGULATOR_ERROR_UNDER_VOLTAGE, 748 + [BD96801_PROT_OCP] = REGULATOR_ERROR_OVER_CURRENT, 749 + [BD96801_PROT_TEMP] = REGULATOR_ERROR_OVER_TEMP, 750 + 751 + }; 752 + int wrn_flags[] = { 753 + [BD96801_PROT_OVP] = REGULATOR_ERROR_OVER_VOLTAGE_WARN, 754 + [BD96801_PROT_UVP] = REGULATOR_ERROR_UNDER_VOLTAGE_WARN, 755 + [BD96801_PROT_OCP] = REGULATOR_ERROR_OVER_CURRENT_WARN, 756 + [BD96801_PROT_TEMP] = REGULATOR_ERROR_OVER_TEMP_WARN, 757 + }; 758 + 759 + /* 760 + * Don't install IRQ handler if both error and warning 761 + * notifications are explicitly disabled 762 + */ 763 + if (!iinfo->err_cfg && !iinfo->wrn_cfg) 764 + return 0; 765 + 766 + if (WARN_ON(iinfo->type >= BD96801_NUM_PROT)) 767 + return -EINVAL; 768 + 769 + if (iinfo->err_cfg) 770 + err = err_flags[iinfo->type]; 771 + else if (iinfo->wrn_cfg) 772 + err = wrn_flags[iinfo->type]; 773 + 774 + iinfo->irq_desc.data = pdata; 775 + irq = platform_get_irq_byname(pdev, iinfo->irq_name); 776 + if (irq < 0) 777 + return irq; 778 + /* Find notifications for this IRQ (WARN/ERR) */ 779 + 780 + rdev_arr[0] = rdev; 781 + retp = devm_regulator_irq_helper(&pdev->dev, 782 + &iinfo->irq_desc, irq, 783 + 0, err, NULL, rdev_arr, 784 + 1); 785 + if (IS_ERR(retp)) 786 + return PTR_ERR(retp); 787 + 788 + return 0; 789 + } 790 + 791 + 792 + 793 + static int bd96801_probe(struct platform_device *pdev) 794 + { 795 + struct regulator_dev *ldo_errs_rdev_arr[BD96801_NUM_LDOS]; 796 + struct bd96801_regulator_data *rdesc; 797 + struct regulator_config config = {}; 798 + int ldo_errs_arr[BD96801_NUM_LDOS]; 799 + struct bd96801_pmic_data *pdata; 800 + int temp_notif_ldos = 0; 801 + struct device *parent; 802 + int i, ret; 803 + void *retp; 804 + 805 + parent = pdev->dev.parent; 806 + 807 + pdata = devm_kmemdup(&pdev->dev, &bd96801_data, sizeof(bd96801_data), 808 + GFP_KERNEL); 809 + if (!pdata) 810 + return -ENOMEM; 811 + 812 + if (initialize_pmic_data(&pdev->dev, pdata)) 813 + return -ENOMEM; 814 + 815 + pdata->regmap = dev_get_regmap(parent, NULL); 816 + if (!pdata->regmap) { 817 + dev_err(&pdev->dev, "No register map found\n"); 818 + return -ENODEV; 819 + } 820 + 821 + rdesc = &pdata->regulator_data[0]; 822 + 823 + config.driver_data = pdata; 824 + config.regmap = pdata->regmap; 825 + config.dev = parent; 826 + 827 + ret = bd96801_walk_regulator_dt(&pdev->dev, pdata->regmap, rdesc, 828 + BD96801_NUM_REGULATORS); 829 + if (ret) 830 + return ret; 831 + 832 + for (i = 0; i < ARRAY_SIZE(pdata->regulator_data); i++) { 833 + struct regulator_dev *rdev; 834 + struct bd96801_irq_desc *idesc = &rdesc[i].irq_desc; 835 + int j; 836 + 837 + rdev = devm_regulator_register(&pdev->dev, 838 + &rdesc[i].desc, &config); 839 + if (IS_ERR(rdev)) { 840 + dev_err(&pdev->dev, 841 + "failed to register %s regulator\n", 842 + rdesc[i].desc.name); 843 + return PTR_ERR(rdev); 844 + } 845 + /* 846 + * LDOs don't have own temperature monitoring. If temperature 847 + * notification was requested for this LDO from DT then we will 848 + * add the regulator to be notified if central IC temperature 849 + * exceeds threshold. 850 + */ 851 + if (rdesc[i].ldo_errs) { 852 + ldo_errs_rdev_arr[temp_notif_ldos] = rdev; 853 + ldo_errs_arr[temp_notif_ldos] = rdesc[i].ldo_errs; 854 + temp_notif_ldos++; 855 + } 856 + if (!idesc) 857 + continue; 858 + 859 + /* Register INTB handlers for configured protections */ 860 + for (j = 0; j < idesc->num_irqs; j++) { 861 + ret = bd96801_rdev_intb_irqs(pdev, pdata, 862 + &idesc->irqinfo[j], rdev); 863 + if (ret) 864 + return ret; 865 + } 866 + } 867 + if (temp_notif_ldos) { 868 + int irq; 869 + struct regulator_irq_desc tw_desc = { 870 + .name = "bd96801-core-thermal", 871 + .irq_off_ms = 500, 872 + .map_event = ldo_map_notif, 873 + }; 874 + 875 + irq = platform_get_irq_byname(pdev, "bd96801-core-thermal"); 876 + if (irq < 0) 877 + return irq; 878 + 879 + retp = devm_regulator_irq_helper(&pdev->dev, &tw_desc, irq, 0, 880 + 0, &ldo_errs_arr[0], 881 + &ldo_errs_rdev_arr[0], 882 + temp_notif_ldos); 883 + if (IS_ERR(retp)) 884 + return PTR_ERR(retp); 885 + } 886 + 887 + return 0; 888 + } 889 + 890 + static const struct platform_device_id bd96801_pmic_id[] = { 891 + { "bd96801-regulator", }, 892 + { } 893 + }; 894 + MODULE_DEVICE_TABLE(platform, bd96801_pmic_id); 895 + 896 + static struct platform_driver bd96801_regulator = { 897 + .driver = { 898 + .name = "bd96801-pmic" 899 + }, 900 + .probe = bd96801_probe, 901 + .id_table = bd96801_pmic_id, 902 + }; 903 + 904 + module_platform_driver(bd96801_regulator); 905 + 906 + MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); 907 + MODULE_DESCRIPTION("BD96801 voltage regulator driver"); 908 + MODULE_LICENSE("GPL");
+13
drivers/watchdog/Kconfig
··· 181 181 watchdog. Alternatively say M to compile the driver as a module, 182 182 which will be called bd9576_wdt. 183 183 184 + config BD96801_WATCHDOG 185 + tristate "ROHM BD96801 PMIC Watchdog" 186 + depends on MFD_ROHM_BD96801 187 + select WATCHDOG_CORE 188 + help 189 + Support for the watchdog in the ROHM BD96801 PMIC. Watchdog can be 190 + configured to only generate IRQ or to trigger system reset via reset 191 + pin. 192 + 193 + Say Y here to include support for the ROHM BD96801 watchdog. 194 + Alternatively say M to compile the driver as a module, 195 + which will be called bd96801_wdt. 196 + 184 197 config CROS_EC_WATCHDOG 185 198 tristate "ChromeOS EC-based watchdog" 186 199 select WATCHDOG_CORE
+1
drivers/watchdog/Makefile
··· 218 218 219 219 # Architecture Independent 220 220 obj-$(CONFIG_BD957XMUF_WATCHDOG) += bd9576_wdt.o 221 + obj-$(CONFIG_BD96801_WATCHDOG) += bd96801_wdt.o 221 222 obj-$(CONFIG_CROS_EC_WATCHDOG) += cros_ec_wdt.o 222 223 obj-$(CONFIG_DA9052_WATCHDOG) += da9052_wdt.o 223 224 obj-$(CONFIG_DA9055_WATCHDOG) += da9055_wdt.o
+416
drivers/watchdog/bd96801_wdt.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (C) 2024 ROHM Semiconductors 4 + * 5 + * ROHM BD96801 watchdog driver 6 + */ 7 + 8 + #include <linux/interrupt.h> 9 + #include <linux/kernel.h> 10 + #include <linux/mfd/rohm-bd96801.h> 11 + #include <linux/mfd/rohm-generic.h> 12 + #include <linux/module.h> 13 + #include <linux/of.h> 14 + #include <linux/platform_device.h> 15 + #include <linux/reboot.h> 16 + #include <linux/regmap.h> 17 + #include <linux/watchdog.h> 18 + 19 + static bool nowayout; 20 + module_param(nowayout, bool, 0); 21 + MODULE_PARM_DESC(nowayout, 22 + "Watchdog cannot be stopped once started (default=\"false\")"); 23 + 24 + #define BD96801_WD_TMO_SHORT_MASK 0x70 25 + #define BD96801_WD_RATIO_MASK 0x3 26 + #define BD96801_WD_TYPE_MASK 0x4 27 + #define BD96801_WD_TYPE_SLOW 0x4 28 + #define BD96801_WD_TYPE_WIN 0x0 29 + 30 + #define BD96801_WD_EN_MASK 0x3 31 + #define BD96801_WD_IF_EN 0x1 32 + #define BD96801_WD_QA_EN 0x2 33 + #define BD96801_WD_DISABLE 0x0 34 + 35 + #define BD96801_WD_ASSERT_MASK 0x8 36 + #define BD96801_WD_ASSERT_RST 0x8 37 + #define BD96801_WD_ASSERT_IRQ 0x0 38 + 39 + #define BD96801_WD_FEED_MASK 0x1 40 + #define BD96801_WD_FEED 0x1 41 + 42 + /* 1.1 mS */ 43 + #define FASTNG_MIN 11 44 + #define FASTNG_MAX_US (100 * FASTNG_MIN << 7) 45 + #define SLOWNG_MAX_US (16 * FASTNG_MAX_US) 46 + 47 + #define BD96801_WDT_DEFAULT_MARGIN_MS 1843 48 + /* Unit is seconds */ 49 + #define DEFAULT_TIMEOUT 30 50 + 51 + /* 52 + * BD96801 WDG supports window mode so the TMO consists of SHORT and LONG 53 + * timeout values. SHORT time is meaningful only in window mode where feeding 54 + * period shorter than SHORT would be an error. LONG time is used to detect if 55 + * feeding is not occurring within given time limit (SoC SW hangs). The LONG 56 + * timeout time is a multiple of (2, 4, 8 or 16 times) the SHORT timeout. 57 + */ 58 + 59 + struct wdtbd96801 { 60 + struct device *dev; 61 + struct regmap *regmap; 62 + struct watchdog_device wdt; 63 + }; 64 + 65 + static int bd96801_wdt_ping(struct watchdog_device *wdt) 66 + { 67 + struct wdtbd96801 *w = watchdog_get_drvdata(wdt); 68 + 69 + return regmap_update_bits(w->regmap, BD96801_REG_WD_FEED, 70 + BD96801_WD_FEED_MASK, BD96801_WD_FEED); 71 + } 72 + 73 + static int bd96801_wdt_start(struct watchdog_device *wdt) 74 + { 75 + struct wdtbd96801 *w = watchdog_get_drvdata(wdt); 76 + 77 + return regmap_update_bits(w->regmap, BD96801_REG_WD_CONF, 78 + BD96801_WD_EN_MASK, BD96801_WD_IF_EN); 79 + } 80 + 81 + static int bd96801_wdt_stop(struct watchdog_device *wdt) 82 + { 83 + struct wdtbd96801 *w = watchdog_get_drvdata(wdt); 84 + 85 + return regmap_update_bits(w->regmap, BD96801_REG_WD_CONF, 86 + BD96801_WD_EN_MASK, BD96801_WD_DISABLE); 87 + } 88 + 89 + static const struct watchdog_info bd96801_wdt_info = { 90 + .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | 91 + WDIOF_SETTIMEOUT, 92 + .identity = "BD96801 Watchdog", 93 + }; 94 + 95 + static const struct watchdog_ops bd96801_wdt_ops = { 96 + .start = bd96801_wdt_start, 97 + .stop = bd96801_wdt_stop, 98 + .ping = bd96801_wdt_ping, 99 + }; 100 + 101 + static int find_closest_fast(unsigned int target, int *sel, unsigned int *val) 102 + { 103 + unsigned int window = FASTNG_MIN; 104 + int i; 105 + 106 + for (i = 0; i < 8 && window < target; i++) 107 + window <<= 1; 108 + 109 + if (i == 8) 110 + return -EINVAL; 111 + 112 + *val = window; 113 + *sel = i; 114 + 115 + return 0; 116 + } 117 + 118 + static int find_closest_slow_by_fast(unsigned int fast_val, unsigned int *target, 119 + int *slowsel) 120 + { 121 + static const int multipliers[] = {2, 4, 8, 16}; 122 + int sel; 123 + 124 + for (sel = 0; sel < ARRAY_SIZE(multipliers) && 125 + multipliers[sel] * fast_val < *target; sel++) 126 + ; 127 + 128 + if (sel == ARRAY_SIZE(multipliers)) 129 + return -EINVAL; 130 + 131 + *slowsel = sel; 132 + *target = multipliers[sel] * fast_val; 133 + 134 + return 0; 135 + } 136 + 137 + static int find_closest_slow(unsigned int *target, int *slow_sel, int *fast_sel) 138 + { 139 + static const int multipliers[] = {2, 4, 8, 16}; 140 + unsigned int window = FASTNG_MIN; 141 + unsigned int val = 0; 142 + int i, j; 143 + 144 + for (i = 0; i < 8; i++) { 145 + for (j = 0; j < ARRAY_SIZE(multipliers); j++) { 146 + unsigned int slow; 147 + 148 + slow = window * multipliers[j]; 149 + if (slow >= *target && (!val || slow < val)) { 150 + val = slow; 151 + *fast_sel = i; 152 + *slow_sel = j; 153 + } 154 + } 155 + window <<= 1; 156 + } 157 + if (!val) 158 + return -EINVAL; 159 + 160 + *target = val; 161 + 162 + return 0; 163 + } 164 + 165 + static int bd96801_set_wdt_mode(struct wdtbd96801 *w, unsigned int hw_margin, 166 + unsigned int hw_margin_min) 167 + { 168 + int fastng, slowng, type, ret, reg, mask; 169 + struct device *dev = w->dev; 170 + 171 + 172 + if (hw_margin_min * 1000 > FASTNG_MAX_US) { 173 + dev_err(dev, "Unsupported fast timeout %u uS [max %u]\n", 174 + hw_margin_min * 1000, FASTNG_MAX_US); 175 + 176 + return -EINVAL; 177 + } 178 + 179 + if (hw_margin * 1000 > SLOWNG_MAX_US) { 180 + dev_err(dev, "Unsupported slow timeout %u uS [max %u]\n", 181 + hw_margin * 1000, SLOWNG_MAX_US); 182 + 183 + return -EINVAL; 184 + } 185 + 186 + /* 187 + * Convert to 100uS to guarantee reasonable timeouts fit in 188 + * 32bit maintaining also a decent accuracy. 189 + */ 190 + hw_margin *= 10; 191 + hw_margin_min *= 10; 192 + 193 + if (hw_margin_min) { 194 + unsigned int min; 195 + 196 + type = BD96801_WD_TYPE_WIN; 197 + dev_dbg(dev, "Setting type WINDOW 0x%x\n", type); 198 + ret = find_closest_fast(hw_margin_min, &fastng, &min); 199 + if (ret) 200 + return ret; 201 + 202 + ret = find_closest_slow_by_fast(min, &hw_margin, &slowng); 203 + if (ret) { 204 + dev_err(dev, 205 + "can't support slow timeout %u uS using fast %u uS. [max slow %u uS]\n", 206 + hw_margin * 100, min * 100, min * 100 * 16); 207 + 208 + return ret; 209 + } 210 + w->wdt.min_hw_heartbeat_ms = min / 10; 211 + } else { 212 + type = BD96801_WD_TYPE_SLOW; 213 + dev_dbg(dev, "Setting type SLOW 0x%x\n", type); 214 + ret = find_closest_slow(&hw_margin, &slowng, &fastng); 215 + if (ret) 216 + return ret; 217 + } 218 + 219 + w->wdt.max_hw_heartbeat_ms = hw_margin / 10; 220 + 221 + fastng = FIELD_PREP(BD96801_WD_TMO_SHORT_MASK, fastng); 222 + 223 + reg = slowng | fastng; 224 + mask = BD96801_WD_RATIO_MASK | BD96801_WD_TMO_SHORT_MASK; 225 + ret = regmap_update_bits(w->regmap, BD96801_REG_WD_TMO, 226 + mask, reg); 227 + if (ret) 228 + return ret; 229 + 230 + ret = regmap_update_bits(w->regmap, BD96801_REG_WD_CONF, 231 + BD96801_WD_TYPE_MASK, type); 232 + 233 + return ret; 234 + } 235 + 236 + static int bd96801_set_heartbeat_from_hw(struct wdtbd96801 *w, 237 + unsigned int conf_reg) 238 + { 239 + int ret; 240 + unsigned int val, sel, fast; 241 + 242 + /* 243 + * The BD96801 supports a somewhat peculiar QA-mode, which we do not 244 + * support in this driver. If the QA-mode is enabled then we just 245 + * warn and bail-out. 246 + */ 247 + if ((conf_reg & BD96801_WD_EN_MASK) != BD96801_WD_IF_EN) { 248 + dev_err(w->dev, "watchdog set to Q&A mode - exiting\n"); 249 + return -EINVAL; 250 + } 251 + 252 + ret = regmap_read(w->regmap, BD96801_REG_WD_TMO, &val); 253 + if (ret) 254 + return ret; 255 + 256 + sel = FIELD_GET(BD96801_WD_TMO_SHORT_MASK, val); 257 + fast = FASTNG_MIN << sel; 258 + 259 + sel = (val & BD96801_WD_RATIO_MASK) + 1; 260 + w->wdt.max_hw_heartbeat_ms = (fast << sel) / USEC_PER_MSEC; 261 + 262 + if ((conf_reg & BD96801_WD_TYPE_MASK) == BD96801_WD_TYPE_WIN) 263 + w->wdt.min_hw_heartbeat_ms = fast / USEC_PER_MSEC; 264 + 265 + return 0; 266 + } 267 + 268 + static int init_wdg_hw(struct wdtbd96801 *w) 269 + { 270 + u32 hw_margin[2]; 271 + int count, ret; 272 + u32 hw_margin_max = BD96801_WDT_DEFAULT_MARGIN_MS, hw_margin_min = 0; 273 + 274 + count = device_property_count_u32(w->dev->parent, "rohm,hw-timeout-ms"); 275 + if (count < 0 && count != -EINVAL) 276 + return count; 277 + 278 + if (count > 0) { 279 + if (count > ARRAY_SIZE(hw_margin)) 280 + return -EINVAL; 281 + 282 + ret = device_property_read_u32_array(w->dev->parent, 283 + "rohm,hw-timeout-ms", 284 + &hw_margin[0], count); 285 + if (ret < 0) 286 + return ret; 287 + 288 + if (count == 1) 289 + hw_margin_max = hw_margin[0]; 290 + 291 + if (count == 2) { 292 + if (hw_margin[1] > hw_margin[0]) { 293 + hw_margin_max = hw_margin[1]; 294 + hw_margin_min = hw_margin[0]; 295 + } else { 296 + hw_margin_max = hw_margin[0]; 297 + hw_margin_min = hw_margin[1]; 298 + } 299 + } 300 + } 301 + 302 + ret = bd96801_set_wdt_mode(w, hw_margin_max, hw_margin_min); 303 + if (ret) 304 + return ret; 305 + 306 + ret = device_property_match_string(w->dev->parent, "rohm,wdg-action", 307 + "prstb"); 308 + if (ret >= 0) { 309 + ret = regmap_update_bits(w->regmap, BD96801_REG_WD_CONF, 310 + BD96801_WD_ASSERT_MASK, 311 + BD96801_WD_ASSERT_RST); 312 + return ret; 313 + } 314 + 315 + ret = device_property_match_string(w->dev->parent, "rohm,wdg-action", 316 + "intb-only"); 317 + if (ret >= 0) { 318 + ret = regmap_update_bits(w->regmap, BD96801_REG_WD_CONF, 319 + BD96801_WD_ASSERT_MASK, 320 + BD96801_WD_ASSERT_IRQ); 321 + return ret; 322 + } 323 + 324 + return 0; 325 + } 326 + 327 + static irqreturn_t bd96801_irq_hnd(int irq, void *data) 328 + { 329 + emergency_restart(); 330 + 331 + return IRQ_NONE; 332 + } 333 + 334 + static int bd96801_wdt_probe(struct platform_device *pdev) 335 + { 336 + struct wdtbd96801 *w; 337 + int ret, irq; 338 + unsigned int val; 339 + 340 + w = devm_kzalloc(&pdev->dev, sizeof(*w), GFP_KERNEL); 341 + if (!w) 342 + return -ENOMEM; 343 + 344 + w->regmap = dev_get_regmap(pdev->dev.parent, NULL); 345 + w->dev = &pdev->dev; 346 + 347 + w->wdt.info = &bd96801_wdt_info; 348 + w->wdt.ops = &bd96801_wdt_ops; 349 + w->wdt.parent = pdev->dev.parent; 350 + w->wdt.timeout = DEFAULT_TIMEOUT; 351 + watchdog_set_drvdata(&w->wdt, w); 352 + 353 + ret = regmap_read(w->regmap, BD96801_REG_WD_CONF, &val); 354 + if (ret) 355 + return dev_err_probe(&pdev->dev, ret, 356 + "Failed to get the watchdog state\n"); 357 + 358 + /* 359 + * If the WDG is already enabled we assume it is configured by boot. 360 + * In this case we just update the hw-timeout based on values set to 361 + * the timeout / mode registers and leave the hardware configs 362 + * untouched. 363 + */ 364 + if ((val & BD96801_WD_EN_MASK) != BD96801_WD_DISABLE) { 365 + dev_dbg(&pdev->dev, "watchdog was running during probe\n"); 366 + ret = bd96801_set_heartbeat_from_hw(w, val); 367 + if (ret) 368 + return ret; 369 + 370 + set_bit(WDOG_HW_RUNNING, &w->wdt.status); 371 + } else { 372 + /* If WDG is not running so we will initializate it */ 373 + ret = init_wdg_hw(w); 374 + if (ret) 375 + return ret; 376 + } 377 + 378 + dev_dbg(w->dev, "heartbeat set to %u - %u\n", 379 + w->wdt.min_hw_heartbeat_ms, w->wdt.max_hw_heartbeat_ms); 380 + 381 + watchdog_init_timeout(&w->wdt, 0, pdev->dev.parent); 382 + watchdog_set_nowayout(&w->wdt, nowayout); 383 + watchdog_stop_on_reboot(&w->wdt); 384 + 385 + irq = platform_get_irq_byname(pdev, "bd96801-wdg"); 386 + if (irq > 0) { 387 + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, 388 + bd96801_irq_hnd, 389 + IRQF_ONESHOT, "bd96801-wdg", 390 + NULL); 391 + if (ret) 392 + return dev_err_probe(&pdev->dev, ret, 393 + "Failed to register IRQ\n"); 394 + } 395 + 396 + return devm_watchdog_register_device(&pdev->dev, &w->wdt); 397 + } 398 + 399 + static const struct platform_device_id bd96801_wdt_id[] = { 400 + { "bd96801-wdt", }, 401 + { } 402 + }; 403 + MODULE_DEVICE_TABLE(platform, bd96801_wdt_id); 404 + 405 + static struct platform_driver bd96801_wdt = { 406 + .driver = { 407 + .name = "bd96801-wdt" 408 + }, 409 + .probe = bd96801_wdt_probe, 410 + .id_table = bd96801_wdt_id, 411 + }; 412 + module_platform_driver(bd96801_wdt); 413 + 414 + MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); 415 + MODULE_DESCRIPTION("BD96801 watchdog driver"); 416 + MODULE_LICENSE("GPL");
+215
include/linux/mfd/rohm-bd96801.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + /* Copyright (C) 2024 ROHM Semiconductors */ 3 + 4 + #ifndef __MFD_BD96801_H__ 5 + #define __MFD_BD96801_H__ 6 + 7 + #define BD96801_REG_SSCG_CTRL 0x09 8 + #define BD96801_REG_SHD_INTB 0x20 9 + #define BD96801_LDO5_VOL_LVL_REG 0x2c 10 + #define BD96801_LDO6_VOL_LVL_REG 0x2d 11 + #define BD96801_LDO7_VOL_LVL_REG 0x2e 12 + #define BD96801_REG_BUCK_OVP 0x30 13 + #define BD96801_REG_BUCK_OVD 0x35 14 + #define BD96801_REG_LDO_OVP 0x31 15 + #define BD96801_REG_LDO_OVD 0x36 16 + #define BD96801_REG_BOOT_OVERTIME 0x3a 17 + #define BD96801_REG_WD_TMO 0x40 18 + #define BD96801_REG_WD_CONF 0x41 19 + #define BD96801_REG_WD_FEED 0x42 20 + #define BD96801_REG_WD_FAILCOUNT 0x43 21 + #define BD96801_REG_WD_ASK 0x46 22 + #define BD96801_REG_WD_STATUS 0x4a 23 + #define BD96801_REG_PMIC_STATE 0x4f 24 + #define BD96801_REG_EXT_STATE 0x50 25 + 26 + #define BD96801_STATE_STBY 0x09 27 + 28 + #define BD96801_LOCK_REG 0x04 29 + #define BD96801_UNLOCK 0x9d 30 + #define BD96801_LOCK 0x00 31 + 32 + /* IRQ register area */ 33 + #define BD96801_REG_INT_MAIN 0x51 34 + 35 + /* 36 + * The BD96801 has two physical IRQ lines, INTB and ERRB. 37 + * 38 + * The 'main status register' is located at 0x51. 39 + * The ERRB status registers are located at 0x52 ... 0x5B 40 + * INTB status registers are at range 0x5c ... 0x63 41 + */ 42 + #define BD96801_REG_INT_SYS_ERRB1 0x52 43 + #define BD96801_REG_INT_SYS_INTB 0x5c 44 + #define BD96801_REG_INT_LDO7_INTB 0x63 45 + 46 + /* MASK registers */ 47 + #define BD96801_REG_MASK_SYS_INTB 0x73 48 + #define BD96801_REG_MASK_SYS_ERRB 0x69 49 + 50 + #define BD96801_MAX_REGISTER 0x7a 51 + 52 + #define BD96801_OTP_ERR_MASK BIT(0) 53 + #define BD96801_DBIST_ERR_MASK BIT(1) 54 + #define BD96801_EEP_ERR_MASK BIT(2) 55 + #define BD96801_ABIST_ERR_MASK BIT(3) 56 + #define BD96801_PRSTB_ERR_MASK BIT(4) 57 + #define BD96801_DRMOS1_ERR_MASK BIT(5) 58 + #define BD96801_DRMOS2_ERR_MASK BIT(6) 59 + #define BD96801_SLAVE_ERR_MASK BIT(7) 60 + #define BD96801_VREF_ERR_MASK BIT(0) 61 + #define BD96801_TSD_ERR_MASK BIT(1) 62 + #define BD96801_UVLO_ERR_MASK BIT(2) 63 + #define BD96801_OVLO_ERR_MASK BIT(3) 64 + #define BD96801_OSC_ERR_MASK BIT(4) 65 + #define BD96801_PON_ERR_MASK BIT(5) 66 + #define BD96801_POFF_ERR_MASK BIT(6) 67 + #define BD96801_CMD_SHDN_ERR_MASK BIT(7) 68 + #define BD96801_INT_PRSTB_WDT_ERR_MASK BIT(0) 69 + #define BD96801_INT_CHIP_IF_ERR_MASK BIT(3) 70 + #define BD96801_INT_SHDN_ERR_MASK BIT(7) 71 + #define BD96801_OUT_PVIN_ERR_MASK BIT(0) 72 + #define BD96801_OUT_OVP_ERR_MASK BIT(1) 73 + #define BD96801_OUT_UVP_ERR_MASK BIT(2) 74 + #define BD96801_OUT_SHDN_ERR_MASK BIT(7) 75 + 76 + /* ERRB IRQs */ 77 + enum { 78 + /* Reg 0x52, 0x53, 0x54 - ERRB system IRQs */ 79 + BD96801_OTP_ERR_STAT, 80 + BD96801_DBIST_ERR_STAT, 81 + BD96801_EEP_ERR_STAT, 82 + BD96801_ABIST_ERR_STAT, 83 + BD96801_PRSTB_ERR_STAT, 84 + BD96801_DRMOS1_ERR_STAT, 85 + BD96801_DRMOS2_ERR_STAT, 86 + BD96801_SLAVE_ERR_STAT, 87 + BD96801_VREF_ERR_STAT, 88 + BD96801_TSD_ERR_STAT, 89 + BD96801_UVLO_ERR_STAT, 90 + BD96801_OVLO_ERR_STAT, 91 + BD96801_OSC_ERR_STAT, 92 + BD96801_PON_ERR_STAT, 93 + BD96801_POFF_ERR_STAT, 94 + BD96801_CMD_SHDN_ERR_STAT, 95 + BD96801_INT_PRSTB_WDT_ERR, 96 + BD96801_INT_CHIP_IF_ERR, 97 + BD96801_INT_SHDN_ERR_STAT, 98 + 99 + /* Reg 0x55 BUCK1 ERR IRQs */ 100 + BD96801_BUCK1_PVIN_ERR_STAT, 101 + BD96801_BUCK1_OVP_ERR_STAT, 102 + BD96801_BUCK1_UVP_ERR_STAT, 103 + BD96801_BUCK1_SHDN_ERR_STAT, 104 + 105 + /* Reg 0x56 BUCK2 ERR IRQs */ 106 + BD96801_BUCK2_PVIN_ERR_STAT, 107 + BD96801_BUCK2_OVP_ERR_STAT, 108 + BD96801_BUCK2_UVP_ERR_STAT, 109 + BD96801_BUCK2_SHDN_ERR_STAT, 110 + 111 + /* Reg 0x57 BUCK3 ERR IRQs */ 112 + BD96801_BUCK3_PVIN_ERR_STAT, 113 + BD96801_BUCK3_OVP_ERR_STAT, 114 + BD96801_BUCK3_UVP_ERR_STAT, 115 + BD96801_BUCK3_SHDN_ERR_STAT, 116 + 117 + /* Reg 0x58 BUCK4 ERR IRQs */ 118 + BD96801_BUCK4_PVIN_ERR_STAT, 119 + BD96801_BUCK4_OVP_ERR_STAT, 120 + BD96801_BUCK4_UVP_ERR_STAT, 121 + BD96801_BUCK4_SHDN_ERR_STAT, 122 + 123 + /* Reg 0x59 LDO5 ERR IRQs */ 124 + BD96801_LDO5_PVIN_ERR_STAT, 125 + BD96801_LDO5_OVP_ERR_STAT, 126 + BD96801_LDO5_UVP_ERR_STAT, 127 + BD96801_LDO5_SHDN_ERR_STAT, 128 + 129 + /* Reg 0x5a LDO6 ERR IRQs */ 130 + BD96801_LDO6_PVIN_ERR_STAT, 131 + BD96801_LDO6_OVP_ERR_STAT, 132 + BD96801_LDO6_UVP_ERR_STAT, 133 + BD96801_LDO6_SHDN_ERR_STAT, 134 + 135 + /* Reg 0x5b LDO7 ERR IRQs */ 136 + BD96801_LDO7_PVIN_ERR_STAT, 137 + BD96801_LDO7_OVP_ERR_STAT, 138 + BD96801_LDO7_UVP_ERR_STAT, 139 + BD96801_LDO7_SHDN_ERR_STAT, 140 + }; 141 + 142 + /* INTB IRQs */ 143 + enum { 144 + /* Reg 0x5c (System INTB) */ 145 + BD96801_TW_STAT, 146 + BD96801_WDT_ERR_STAT, 147 + BD96801_I2C_ERR_STAT, 148 + BD96801_CHIP_IF_ERR_STAT, 149 + 150 + /* Reg 0x5d (BUCK1 INTB) */ 151 + BD96801_BUCK1_OCPH_STAT, 152 + BD96801_BUCK1_OCPL_STAT, 153 + BD96801_BUCK1_OCPN_STAT, 154 + BD96801_BUCK1_OVD_STAT, 155 + BD96801_BUCK1_UVD_STAT, 156 + BD96801_BUCK1_TW_CH_STAT, 157 + 158 + /* Reg 0x5e (BUCK2 INTB) */ 159 + BD96801_BUCK2_OCPH_STAT, 160 + BD96801_BUCK2_OCPL_STAT, 161 + BD96801_BUCK2_OCPN_STAT, 162 + BD96801_BUCK2_OVD_STAT, 163 + BD96801_BUCK2_UVD_STAT, 164 + BD96801_BUCK2_TW_CH_STAT, 165 + 166 + /* Reg 0x5f (BUCK3 INTB)*/ 167 + BD96801_BUCK3_OCPH_STAT, 168 + BD96801_BUCK3_OCPL_STAT, 169 + BD96801_BUCK3_OCPN_STAT, 170 + BD96801_BUCK3_OVD_STAT, 171 + BD96801_BUCK3_UVD_STAT, 172 + BD96801_BUCK3_TW_CH_STAT, 173 + 174 + /* Reg 0x60 (BUCK4 INTB)*/ 175 + BD96801_BUCK4_OCPH_STAT, 176 + BD96801_BUCK4_OCPL_STAT, 177 + BD96801_BUCK4_OCPN_STAT, 178 + BD96801_BUCK4_OVD_STAT, 179 + BD96801_BUCK4_UVD_STAT, 180 + BD96801_BUCK4_TW_CH_STAT, 181 + 182 + /* Reg 0x61 (LDO5 INTB) */ 183 + BD96801_LDO5_OCPH_STAT, /* bit [0] */ 184 + BD96801_LDO5_OVD_STAT, /* bit [3] */ 185 + BD96801_LDO5_UVD_STAT, /* bit [4] */ 186 + 187 + /* Reg 0x62 (LDO6 INTB) */ 188 + BD96801_LDO6_OCPH_STAT, /* bit [0] */ 189 + BD96801_LDO6_OVD_STAT, /* bit [3] */ 190 + BD96801_LDO6_UVD_STAT, /* bit [4] */ 191 + 192 + /* Reg 0x63 (LDO7 INTB) */ 193 + BD96801_LDO7_OCPH_STAT, /* bit [0] */ 194 + BD96801_LDO7_OVD_STAT, /* bit [3] */ 195 + BD96801_LDO7_UVD_STAT, /* bit [4] */ 196 + }; 197 + 198 + /* IRQ MASKs */ 199 + #define BD96801_TW_STAT_MASK BIT(0) 200 + #define BD96801_WDT_ERR_STAT_MASK BIT(1) 201 + #define BD96801_I2C_ERR_STAT_MASK BIT(2) 202 + #define BD96801_CHIP_IF_ERR_STAT_MASK BIT(3) 203 + 204 + #define BD96801_BUCK_OCPH_STAT_MASK BIT(0) 205 + #define BD96801_BUCK_OCPL_STAT_MASK BIT(1) 206 + #define BD96801_BUCK_OCPN_STAT_MASK BIT(2) 207 + #define BD96801_BUCK_OVD_STAT_MASK BIT(3) 208 + #define BD96801_BUCK_UVD_STAT_MASK BIT(4) 209 + #define BD96801_BUCK_TW_CH_STAT_MASK BIT(5) 210 + 211 + #define BD96801_LDO_OCPH_STAT_MASK BIT(0) 212 + #define BD96801_LDO_OVD_STAT_MASK BIT(3) 213 + #define BD96801_LDO_UVD_STAT_MASK BIT(4) 214 + 215 + #endif
+1
include/linux/mfd/rohm-generic.h
··· 16 16 ROHM_CHIP_TYPE_BD71828, 17 17 ROHM_CHIP_TYPE_BD71837, 18 18 ROHM_CHIP_TYPE_BD71847, 19 + ROHM_CHIP_TYPE_BD96801, 19 20 ROHM_CHIP_TYPE_AMOUNT 20 21 }; 21 22