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

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'regulator-v6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator

Pull regulator updates from Mark Brown:
"This is a very quiet release for regulator, almost all the changes are
new drivers but we do also have some improvements for the Rust
bindings.

- Additional APIs added to the Rust bindings

- Support for Maxim MAX77838, NXP PF0900 and PF5300, Richtek RT5133
and SpacemiT P1"

* tag 'regulator-v6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (28 commits)
regulator: dt-bindings: qcom,sdm845-refgen-regulator: document more platforms
regulator: Fix MAX77838 selection
regulator: spacemit: support SpacemiT P1 regulators
regulator: max77838: add max77838 regulator driver
dt-bindings: regulator: document max77838 pmic
rust: regulator: add devm_enable and devm_enable_optional
rust: regulator: remove Regulator<Dynamic>
regulator: dt-bindings: rpi-panel: Split 7" Raspberry Pi 720x1280 v2 binding
regulator: pf530x: Add a driver for the NXP PF5300 Regulator
regulator: dt-bindings: nxp,pf530x: Add NXP PF5300/PF5301/PF5302 PMICs
regulator: scmi: Use int type to store negative error codes
regulator: core: Remove redundant ternary operators
rust: regulator: use `to_result` for error handling
regulator: consumer.rst: document bulk operations
regulator: rt5133: Fix IS_ERR() vs NULL bug in rt5133_validate_vendor_info()
regulator: bd718x7: Use kcalloc() instead of kzalloc()
regulator: rt5133: Fix spelling mistake "regualtor" -> "regulator"
regulator: remove unneeded 'fast_io' parameter in regmap_config
regulator: rt5133: Add RT5133 PMIC regulator Support
regulator: dt-bindings: Add Richtek RT5133 Support
...

+3354 -278
-82
Documentation/devicetree/bindings/mfd/act8945a.txt
··· 1 - Device-Tree bindings for Active-semi ACT8945A MFD driver 2 - 3 - Required properties: 4 - - compatible: "active-semi,act8945a". 5 - - reg: the I2C slave address for the ACT8945A chip 6 - 7 - The chip exposes two subdevices: 8 - - a regulators: see ../regulator/act8945a-regulator.txt 9 - - a charger: see ../power/act8945a-charger.txt 10 - 11 - Example: 12 - pmic@5b { 13 - compatible = "active-semi,act8945a"; 14 - reg = <0x5b>; 15 - 16 - active-semi,vsel-high; 17 - 18 - regulators { 19 - vdd_1v35_reg: REG_DCDC1 { 20 - regulator-name = "VDD_1V35"; 21 - regulator-min-microvolt = <1350000>; 22 - regulator-max-microvolt = <1350000>; 23 - regulator-always-on; 24 - }; 25 - 26 - vdd_1v2_reg: REG_DCDC2 { 27 - regulator-name = "VDD_1V2"; 28 - regulator-min-microvolt = <1100000>; 29 - regulator-max-microvolt = <1300000>; 30 - regulator-always-on; 31 - }; 32 - 33 - vdd_3v3_reg: REG_DCDC3 { 34 - regulator-name = "VDD_3V3"; 35 - regulator-min-microvolt = <3300000>; 36 - regulator-max-microvolt = <3300000>; 37 - regulator-always-on; 38 - }; 39 - 40 - vdd_fuse_reg: REG_LDO1 { 41 - regulator-name = "VDD_FUSE"; 42 - regulator-min-microvolt = <2500000>; 43 - regulator-max-microvolt = <2500000>; 44 - regulator-always-on; 45 - }; 46 - 47 - vdd_3v3_lp_reg: REG_LDO2 { 48 - regulator-name = "VDD_3V3_LP"; 49 - regulator-min-microvolt = <3300000>; 50 - regulator-max-microvolt = <3300000>; 51 - regulator-always-on; 52 - }; 53 - 54 - vdd_led_reg: REG_LDO3 { 55 - regulator-name = "VDD_LED"; 56 - regulator-min-microvolt = <3300000>; 57 - regulator-max-microvolt = <3300000>; 58 - regulator-always-on; 59 - }; 60 - 61 - vdd_sdhc_1v8_reg: REG_LDO4 { 62 - regulator-name = "VDD_SDHC_1V8"; 63 - regulator-min-microvolt = <1800000>; 64 - regulator-max-microvolt = <1800000>; 65 - regulator-always-on; 66 - }; 67 - }; 68 - 69 - charger { 70 - compatible = "active-semi,act8945a-charger"; 71 - pinctrl-names = "default"; 72 - pinctrl-0 = <&pinctrl_charger_chglev &pinctrl_charger_lbo &pinctrl_charger_irq>; 73 - interrupt-parent = <&pioA>; 74 - interrupts = <45 IRQ_TYPE_LEVEL_LOW>; 75 - 76 - active-semi,chglev-gpios = <&pioA 12 GPIO_ACTIVE_HIGH>; 77 - active-semi,lbo-gpios = <&pioA 72 GPIO_ACTIVE_LOW>; 78 - active-semi,input-voltage-threshold-microvolt = <6600>; 79 - active-semi,precondition-timeout = <40>; 80 - active-semi,total-timeout = <3>; 81 - }; 82 - };
-76
Documentation/devicetree/bindings/power/supply/active-semi,act8945a-charger.yaml
··· 1 - # SPDX-License-Identifier: GPL-2.0 2 - %YAML 1.2 3 - --- 4 - $id: http://devicetree.org/schemas/power/supply/active-semi,act8945a-charger.yaml# 5 - $schema: http://devicetree.org/meta-schemas/core.yaml# 6 - 7 - title: Active-semi ACT8945A Charger Function 8 - 9 - maintainers: 10 - - Sebastian Reichel <sre@kernel.org> 11 - 12 - allOf: 13 - - $ref: power-supply.yaml# 14 - 15 - properties: 16 - compatible: 17 - const: active-semi,act8945a-charger 18 - 19 - interrupts: 20 - maxItems: 1 21 - 22 - active-semi,chglev-gpios: 23 - maxItems: 1 24 - description: charge current level GPIO 25 - 26 - active-semi,lbo-gpios: 27 - maxItems: 1 28 - description: low battery voltage detect GPIO 29 - 30 - active-semi,input-voltage-threshold-microvolt: 31 - description: | 32 - Specifies the charger's input over-voltage threshold value. 33 - Despite the name, specified values are in millivolt (mV). 34 - Defaults to 6.6 V 35 - enum: [ 6600, 7000, 7500, 8000 ] 36 - 37 - active-semi,precondition-timeout: 38 - $ref: /schemas/types.yaml#/definitions/uint32 39 - description: | 40 - Specifies the charger's PRECONDITION safety timer setting value in minutes. 41 - If 0, it means to disable this timer. 42 - Defaults to 40 minutes. 43 - enum: [ 0, 40, 60, 80 ] 44 - 45 - active-semi,total-timeout: 46 - $ref: /schemas/types.yaml#/definitions/uint32 47 - description: | 48 - Specifies the charger's total safety timer setting value in hours; 49 - If 0, it means to disable this timer; 50 - Defaults to 3 hours. 51 - enum: [ 0, 3, 4, 5 ] 52 - 53 - required: 54 - - compatible 55 - - interrupts 56 - - active-semi,chglev-gpios 57 - - active-semi,lbo-gpios 58 - 59 - additionalProperties: false 60 - 61 - examples: 62 - - | 63 - #include <dt-bindings/gpio/gpio.h> 64 - #include <dt-bindings/interrupt-controller/irq.h> 65 - pmic { 66 - charger { 67 - compatible = "active-semi,act8945a-charger"; 68 - interrupt-parent = <&pioA>; 69 - interrupts = <45 IRQ_TYPE_LEVEL_LOW>; 70 - active-semi,chglev-gpios = <&pioA 12 GPIO_ACTIVE_HIGH>; 71 - active-semi,lbo-gpios = <&pioA 72 GPIO_ACTIVE_LOW>; 72 - active-semi,input-voltage-threshold-microvolt = <6600>; 73 - active-semi,precondition-timeout = <40>; 74 - active-semi,total-timeout = <3>; 75 - }; 76 - };
+19 -6
Documentation/devicetree/bindings/regulator/active-semi,act8945a.yaml
··· 91 91 maxItems: 1 92 92 93 93 active-semi,chglev-gpios: 94 - description: CGHLEV GPIO 94 + description: charge current level GPIO 95 95 maxItems: 1 96 96 97 97 active-semi,lbo-gpios: 98 - description: LBO GPIO 98 + description: low battery voltage detect GPIO 99 99 maxItems: 1 100 100 101 101 active-semi,input-voltage-threshold-microvolt: 102 - description: Input voltage threshold 103 - maxItems: 1 102 + description: 103 + Specifies the charger's input over-voltage threshold value. Despite 104 + the name, specified values are in millivolt (mV). 105 + enum: [ 6600, 7000, 7500, 8000 ] 106 + default: 6600 104 107 105 108 active-semi,precondition-timeout: 106 - description: Precondition timeout 109 + description: 110 + Specifies the charger's PRECONDITION safety timer setting value in 111 + minutes. If 0, it means to disable this timer. 112 + enum: [ 0, 40, 60, 80 ] 113 + default: 40 107 114 $ref: /schemas/types.yaml#/definitions/uint32 108 115 109 116 active-semi,total-timeout: 110 - description: Total timeout 117 + description: 118 + Specifies the charger's total safety timer setting value in hours; If 119 + 0, it means to disable this timer; 120 + enum: [ 0, 3, 4, 5 ] 121 + default: 3 111 122 $ref: /schemas/types.yaml#/definitions/uint32 112 123 113 124 required: 114 125 - compatible 115 126 - interrupts 127 + - active-semi,chglev-gpios 128 + - active-semi,lbo-gpios 116 129 117 130 additionalProperties: false 118 131
+68
Documentation/devicetree/bindings/regulator/maxim,max77838.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/maxim,max77838.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Maxim Integrated MAX77838 PMIC 8 + 9 + maintainers: 10 + - Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com> 11 + 12 + properties: 13 + $nodename: 14 + pattern: "pmic@[0-9a-f]{1,2}" 15 + compatible: 16 + enum: 17 + - maxim,max77838 18 + 19 + reg: 20 + maxItems: 1 21 + 22 + regulators: 23 + type: object 24 + $ref: regulator.yaml# 25 + description: | 26 + list of regulators provided by this controller, must be named 27 + after their hardware counterparts ldo[1-4] and buck 28 + 29 + properties: 30 + buck: 31 + type: object 32 + $ref: regulator.yaml# 33 + unevaluatedProperties: false 34 + 35 + patternProperties: 36 + "^ldo([1-4])$": 37 + type: object 38 + $ref: regulator.yaml# 39 + unevaluatedProperties: false 40 + 41 + additionalProperties: false 42 + 43 + required: 44 + - compatible 45 + - reg 46 + - regulators 47 + 48 + additionalProperties: false 49 + 50 + examples: 51 + - | 52 + i2c { 53 + #address-cells = <1>; 54 + #size-cells = <0>; 55 + 56 + pmic@60 { 57 + compatible = "maxim,max77838"; 58 + reg = <0x60>; 59 + 60 + regulators { 61 + ldo2 { 62 + regulator-min-microvolt = <1800000>; 63 + regulator-max-microvolt = <1800000>; 64 + }; 65 + }; 66 + }; 67 + }; 68 + ...
+163
Documentation/devicetree/bindings/regulator/nxp,pf0900.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/nxp,pf0900.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: NXP PF0900 Power Management Integrated Circuit regulators 8 + 9 + maintainers: 10 + - Joy Zou <joy.zou@nxp.com> 11 + 12 + description: 13 + The PF0900 is a power management integrated circuit (PMIC) optimized 14 + for high performance i.MX9x based applications. It features five high 15 + efficiency buck converters, three linear and one vaon regulators. It 16 + provides low quiescent current in Standby and low power off Modes. 17 + 18 + properties: 19 + compatible: 20 + enum: 21 + - nxp,pf0900 22 + 23 + reg: 24 + maxItems: 1 25 + 26 + interrupts: 27 + maxItems: 1 28 + 29 + regulators: 30 + type: object 31 + additionalProperties: false 32 + 33 + properties: 34 + vaon: 35 + type: object 36 + $ref: regulator.yaml# 37 + unevaluatedProperties: false 38 + 39 + patternProperties: 40 + "^ldo[1-3]$": 41 + type: object 42 + $ref: regulator.yaml# 43 + unevaluatedProperties: false 44 + 45 + "^sw[1-5]$": 46 + type: object 47 + $ref: regulator.yaml# 48 + unevaluatedProperties: false 49 + 50 + nxp,i2c-crc-enable: 51 + type: boolean 52 + description: 53 + The CRC enabled during register read/write. Controlled by customer 54 + unviewable fuse bits OTP_I2C_CRC_EN. Check chip part number. 55 + 56 + required: 57 + - compatible 58 + - reg 59 + - interrupts 60 + - regulators 61 + 62 + additionalProperties: false 63 + 64 + examples: 65 + - | 66 + #include <dt-bindings/interrupt-controller/irq.h> 67 + 68 + i2c { 69 + #address-cells = <1>; 70 + #size-cells = <0>; 71 + 72 + pmic@8 { 73 + compatible = "nxp,pf0900"; 74 + reg = <0x08>; 75 + interrupt-parent = <&pcal6524>; 76 + interrupts = <89 IRQ_TYPE_LEVEL_LOW>; 77 + nxp,i2c-crc-enable; 78 + 79 + regulators { 80 + vaon { 81 + regulator-name = "VAON"; 82 + regulator-min-microvolt = <1800000>; 83 + regulator-max-microvolt = <3300000>; 84 + regulator-boot-on; 85 + regulator-always-on; 86 + }; 87 + 88 + sw1 { 89 + regulator-name = "SW1"; 90 + regulator-min-microvolt = <500000>; 91 + regulator-max-microvolt = <3300000>; 92 + regulator-boot-on; 93 + regulator-always-on; 94 + regulator-ramp-delay = <1950>; 95 + regulator-state-mem { 96 + regulator-on-in-suspend; 97 + regulator-suspend-max-microvolt = <650000>; 98 + regulator-suspend-min-microvolt = <650000>; 99 + }; 100 + }; 101 + 102 + sw2 { 103 + regulator-name = "SW2"; 104 + regulator-min-microvolt = <300000>; 105 + regulator-max-microvolt = <3300000>; 106 + regulator-boot-on; 107 + regulator-always-on; 108 + regulator-ramp-delay = <1950>; 109 + }; 110 + 111 + sw3 { 112 + regulator-name = "SW3"; 113 + regulator-min-microvolt = <300000>; 114 + regulator-max-microvolt = <3300000>; 115 + regulator-boot-on; 116 + regulator-always-on; 117 + regulator-ramp-delay = <1950>; 118 + }; 119 + 120 + sw4 { 121 + regulator-name = "SW4"; 122 + regulator-min-microvolt = <300000>; 123 + regulator-max-microvolt = <3300000>; 124 + regulator-boot-on; 125 + regulator-always-on; 126 + regulator-ramp-delay = <1950>; 127 + }; 128 + 129 + sw5 { 130 + regulator-name = "SW5"; 131 + regulator-min-microvolt = <300000>; 132 + regulator-max-microvolt = <3300000>; 133 + regulator-boot-on; 134 + regulator-always-on; 135 + regulator-ramp-delay = <1950>; 136 + }; 137 + 138 + ldo1 { 139 + regulator-name = "LDO1"; 140 + regulator-min-microvolt = <750000>; 141 + regulator-max-microvolt = <3300000>; 142 + regulator-boot-on; 143 + regulator-always-on; 144 + }; 145 + 146 + ldo2 { 147 + regulator-name = "LDO2"; 148 + regulator-min-microvolt = <650000>; 149 + regulator-max-microvolt = <3300000>; 150 + regulator-boot-on; 151 + regulator-always-on; 152 + }; 153 + 154 + ldo3 { 155 + regulator-name = "LDO3"; 156 + regulator-min-microvolt = <650000>; 157 + regulator-max-microvolt = <3300000>; 158 + regulator-boot-on; 159 + regulator-always-on; 160 + }; 161 + }; 162 + }; 163 + };
+54
Documentation/devicetree/bindings/regulator/nxp,pf5300.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/nxp,pf5300.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: NXP PF5300/PF5301/PF5302 PMIC regulators 8 + 9 + maintainers: 10 + - Woodrow Douglass <wdouglass@carnegierobotics.com> 11 + 12 + description: | 13 + The PF5300, PF5301, and PF5302 integrate high-performance buck converters, 14 + 12 A, 8 A, and 15 A, respectively, to power high-end automotive and industrial 15 + processors. With adaptive voltage positioning and a high-bandwidth loop, they 16 + offer transient regulation to minimize capacitor requirements. 17 + 18 + allOf: 19 + - $ref: regulator.yaml# 20 + 21 + properties: 22 + compatible: 23 + oneOf: 24 + - const: nxp,pf5300 25 + - items: 26 + - enum: 27 + - nxp,pf5301 28 + - nxp,pf5302 29 + - const: nxp,pf5300 30 + reg: 31 + maxItems: 1 32 + 33 + required: 34 + - compatible 35 + - reg 36 + 37 + unevaluatedProperties: false 38 + 39 + examples: 40 + - | 41 + i2c { 42 + #address-cells = <1>; 43 + #size-cells = <0>; 44 + 45 + regulator@28 { 46 + compatible = "nxp,pf5302", "nxp,pf5300"; 47 + reg = <0x28>; 48 + 49 + regulator-always-on; 50 + regulator-boot-on; 51 + regulator-max-microvolt = <1200000>; 52 + regulator-min-microvolt = <500000>; 53 + }; 54 + };
+3
Documentation/devicetree/bindings/regulator/qcom,sdm845-refgen-regulator.yaml
··· 23 23 - enum: 24 24 - qcom,sc7180-refgen-regulator 25 25 - qcom,sc8180x-refgen-regulator 26 + - qcom,sdm670-refgen-regulator 26 27 - qcom,sm8150-refgen-regulator 27 28 - const: qcom,sdm845-refgen-regulator 28 29 29 30 - items: 30 31 - enum: 32 + - qcom,qcs8300-refgen-regulator 33 + - qcom,sa8775p-refgen-regulator 31 34 - qcom,sc7280-refgen-regulator 32 35 - qcom,sc8280xp-refgen-regulator 33 36 - qcom,sm6350-refgen-regulator
+61
Documentation/devicetree/bindings/regulator/raspberrypi,7inch-touchscreen-panel-regulator-v2.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/raspberrypi,7inch-touchscreen-panel-regulator-v2.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: RaspberryPi 5" and 7" display V2 MCU-based regulator/backlight controller 8 + 9 + maintainers: 10 + - Marek Vasut <marek.vasut+renesas@mailbox.org> 11 + 12 + description: | 13 + The RaspberryPi 5" and 7" display 2 has an MCU-based regulator, PWM 14 + backlight and GPIO controller on the PCB, which is used to turn the 15 + display unit on/off and control the backlight. 16 + 17 + allOf: 18 + - $ref: regulator.yaml# 19 + 20 + properties: 21 + compatible: 22 + const: raspberrypi,touchscreen-panel-regulator-v2 23 + 24 + reg: 25 + maxItems: 1 26 + 27 + gpio-controller: true 28 + "#gpio-cells": 29 + const: 2 30 + description: 31 + The first cell is the pin number, and the second cell is used to 32 + specify the gpio polarity (GPIO_ACTIVE_HIGH or GPIO_ACTIVE_LOW). 33 + 34 + "#pwm-cells": 35 + const: 3 36 + description: See ../../pwm/pwm.yaml for description of the cell formats. 37 + 38 + additionalProperties: false 39 + 40 + required: 41 + - compatible 42 + - reg 43 + - gpio-controller 44 + - "#gpio-cells" 45 + - "#pwm-cells" 46 + 47 + examples: 48 + - | 49 + i2c { 50 + #address-cells = <1>; 51 + #size-cells = <0>; 52 + regulator@45 { 53 + compatible = "raspberrypi,touchscreen-panel-regulator-v2"; 54 + reg = <0x45>; 55 + gpio-controller; 56 + #gpio-cells = <2>; 57 + #pwm-cells = <3>; 58 + }; 59 + }; 60 + 61 + ...
+2 -5
Documentation/devicetree/bindings/regulator/raspberrypi,7inch-touchscreen-panel-regulator.yaml
··· 12 12 description: | 13 13 The RaspberryPi 7" display has an ATTINY88-based regulator/backlight 14 14 controller on the PCB, which is used to turn the display unit on/off 15 - and control the backlight. The V2 supports 5" and 7" panels and also 16 - offers PWM backlight control. 15 + and control the backlight. 17 16 18 17 allOf: 19 18 - $ref: regulator.yaml# 20 19 21 20 properties: 22 21 compatible: 23 - enum: 24 - - raspberrypi,7inch-touchscreen-panel-regulator 25 - - raspberrypi,touchscreen-panel-regulator-v2 22 + const: raspberrypi,7inch-touchscreen-panel-regulator 26 23 27 24 reg: 28 25 maxItems: 1
+178
Documentation/devicetree/bindings/regulator/richtek,rt5133.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/richtek,rt5133.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Richtek RT5133 PMIC Regulator 8 + 9 + maintainers: 10 + - ShihChia Chang <jeff_chang@richtek.com> 11 + 12 + description: 13 + The RT5133 is an integrated Power Management IC for portable devices, 14 + featuring 8 LDOs and 3 GPOs. It allows programmable output voltages, 15 + soft-start times, and protections via I2C. GPO operation depends on LDO1 16 + voltage. 17 + 18 + properties: 19 + compatible: 20 + enum: 21 + - richtek,rt5133 22 + 23 + reg: 24 + maxItems: 1 25 + 26 + enable-gpios: 27 + maxItems: 1 28 + 29 + wakeup-source: true 30 + 31 + interrupts: 32 + maxItems: 1 33 + 34 + gpio-controller: true 35 + 36 + "#gpio-cells": 37 + const: 2 38 + 39 + richtek,oc-shutdown-all: 40 + type: boolean 41 + description: 42 + Controls the behavior when any LDO (Low Dropout Regulator) enters an 43 + Over Current state. 44 + If set to true, all LDO channels will be shut down. 45 + If set to false, only the affected LDO channel will shut down itself. 46 + 47 + richtek,pgb-shutdown-all: 48 + type: boolean 49 + description: 50 + Controls the behavior when any LDO enters a Power Good Bad state. 51 + If set to true, all LDO channels will be shut down. 52 + If set to false, only the affected LDO channel will shut down itself. 53 + 54 + regulators: 55 + type: object 56 + additionalProperties: false 57 + 58 + properties: 59 + base: 60 + type: object 61 + $ref: regulator.yaml# 62 + unevaluatedProperties: false 63 + description: 64 + Properties for the base regulator, which is the top-level supply for 65 + LDO1 to LDO6. It functions merely as an on/off switch rather than 66 + regulating voltages. If none of LDO1 to LDO6 are in use, switching 67 + off the base will reduce the quiescent current. 68 + 69 + required: 70 + - regulator-name 71 + 72 + patternProperties: 73 + "^ldo([1-6])$": 74 + type: object 75 + $ref: regulator.yaml# 76 + unevaluatedProperties: false 77 + description: 78 + Properties for single LDO regulator 79 + 80 + required: 81 + - regulator-name 82 + 83 + "^ldo([7-8])$": 84 + type: object 85 + $ref: regulator.yaml# 86 + unevaluatedProperties: false 87 + description: 88 + Properties for single LDO regulator 89 + 90 + properties: 91 + vin-supply: true 92 + 93 + required: 94 + - regulator-name 95 + - vin-supply 96 + 97 + required: 98 + - compatible 99 + - reg 100 + - interrupts 101 + 102 + additionalProperties: false 103 + 104 + examples: 105 + - | 106 + #include <dt-bindings/interrupt-controller/irq.h> 107 + #include <dt-bindings/gpio/gpio.h> 108 + i2c { 109 + #address-cells = <1>; 110 + #size-cells = <0>; 111 + 112 + pmic@18 { 113 + compatible = "richtek,rt5133"; 114 + reg = <0x18>; 115 + wakeup-source; 116 + interrupts-extended = <&gpio 0 IRQ_TYPE_EDGE_FALLING>; 117 + enable-gpios = <&gpio 2 GPIO_ACTIVE_HIGH>; 118 + gpio-controller; 119 + #gpio-cells = <2>; 120 + richtek,oc-shutdown-all; 121 + richtek,pgb-shutdown-all; 122 + regulators { 123 + base { 124 + regulator-name = "base"; 125 + }; 126 + pvin78: ldo1 { 127 + regulator-name = "ldo1"; 128 + regulator-min-microvolt = <1800000>; 129 + regulator-max-microvolt = <3199998>; 130 + regulator-active-discharge = <1>; 131 + }; 132 + ldo2 { 133 + regulator-name = "ldo2"; 134 + regulator-min-microvolt = <1800000>; 135 + regulator-max-microvolt = <3200000>; 136 + regulator-active-discharge = <1>; 137 + }; 138 + ldo3 { 139 + regulator-name = "ldo3"; 140 + regulator-min-microvolt = <1700000>; 141 + regulator-max-microvolt = <3000000>; 142 + regulator-active-discharge = <1>; 143 + }; 144 + ldo4 { 145 + regulator-name = "ldo4"; 146 + regulator-min-microvolt = <1700000>; 147 + regulator-max-microvolt = <3000000>; 148 + regulator-active-discharge = <1>; 149 + }; 150 + ldo5 { 151 + regulator-name = "ldo5"; 152 + regulator-min-microvolt = <1700000>; 153 + regulator-max-microvolt = <3000000>; 154 + regulator-active-discharge = <1>; 155 + }; 156 + ldo6 { 157 + regulator-name = "ldo6"; 158 + regulator-min-microvolt = <1700000>; 159 + regulator-max-microvolt = <3000000>; 160 + regulator-active-discharge = <1>; 161 + }; 162 + ldo7 { 163 + regulator-name = "ldo7"; 164 + regulator-min-microvolt = <900000>; 165 + regulator-max-microvolt = <1200000>; 166 + regulator-active-discharge = <1>; 167 + vin-supply = <&pvin78>; 168 + }; 169 + ldo8 { 170 + regulator-name = "ldo8"; 171 + regulator-min-microvolt = <855000>; 172 + regulator-max-microvolt = <1200000>; 173 + regulator-active-discharge = <1>; 174 + vin-supply = <&pvin78>; 175 + }; 176 + }; 177 + }; 178 + };
+26 -4
Documentation/power/regulator/consumer.rst
··· 23 23 regulator_put(regulator); 24 24 25 25 Consumers can be supplied by more than one regulator e.g. codec consumer with 26 - analog and digital supplies :: 26 + analog and digital supplies by means of bulk operations :: 27 27 28 - digital = regulator_get(dev, "Vcc"); /* digital core */ 29 - analog = regulator_get(dev, "Avdd"); /* analog */ 28 + struct regulator_bulk_data supplies[2]; 29 + 30 + supplies[0].supply = "Vcc"; /* digital core */ 31 + supplies[1].supply = "Avdd"; /* analog */ 32 + 33 + ret = regulator_bulk_get(dev, ARRAY_SIZE(supplies), supplies); 34 + 35 + // convenience helper to call regulator_put() on multiple regulators 36 + regulator_bulk_free(ARRAY_SIZE(supplies), supplies); 37 + 30 38 31 39 The regulator access functions regulator_get() and regulator_put() will 32 40 usually be called in your device drivers probe() and remove() respectively. ··· 59 51 60 52 This will return > zero when the regulator is enabled. 61 53 54 + A set of regulators can be enabled with a single bulk operation :: 55 + 56 + int regulator_bulk_enable(int num_consumers, 57 + struct regulator_bulk_data *consumers); 58 + 62 59 63 60 A consumer can disable its supply when no longer needed by calling:: 64 61 65 62 int regulator_disable(regulator); 63 + 64 + Or a number of them :: 65 + 66 + int regulator_bulk_disable(int num_consumers, 67 + struct regulator_bulk_data *consumers); 66 68 67 69 NOTE: 68 70 This may not disable the supply if it's shared with other consumers. The ··· 82 64 83 65 int regulator_force_disable(regulator); 84 66 67 + This operation is also supported for multiple regulators :: 68 + 69 + int regulator_bulk_force_disable(int num_consumers, 70 + struct regulator_bulk_data *consumers); 71 + 85 72 NOTE: 86 73 this will immediately and forcefully shutdown the regulator output. All 87 74 consumers will be powered off. 88 - 89 75 90 76 3. Regulator Voltage Control & Status (dynamic drivers) 91 77 =======================================================
+14 -1
MAINTAINERS
··· 15117 15117 F: drivers/regulator/max77802-regulator.c 15118 15118 F: include/dt-bindings/*/*max77802.h 15119 15119 15120 + MAXIM MAX77838 PMIC REGULATOR DEVICE DRIVER 15121 + M: Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com> 15122 + L: linux-kernel@vger.kernel.org 15123 + S: Maintained 15124 + F: Documentation/devicetree/bindings/regulator/maxim,max77838.yaml 15125 + F: drivers/regulator/max77838-regulator.c 15126 + 15120 15127 MAXIM MAX77976 BATTERY CHARGER 15121 15128 M: Luca Ceresoli <luca@lucaceresoli.net> 15122 15129 S: Supported ··· 18375 18368 F: Documentation/devicetree/bindings/clock/*imx* 18376 18369 F: drivers/clk/imx/ 18377 18370 F: include/dt-bindings/clock/*imx* 18371 + 18372 + NXP PF5300/PF5301/PF5302 PMIC REGULATOR DEVICE DRIVER 18373 + M: Woodrow Douglass <wdouglass@carnegierobotics.com> 18374 + S: Maintained 18375 + F: Documentation/devicetree/bindings/regulator/nxp,pf5300.yaml 18376 + F: drivers/regulator/pf530x-regulator.c 18378 18377 18379 18378 NXP PF8100/PF8121A/PF8200 PMIC REGULATOR DEVICE DRIVER 18380 18379 M: Jagan Teki <jagan@amarulasolutions.com> ··· 22509 22496 F: Documentation/devicetree/bindings/regulator/samsung,s5m*.yaml 22510 22497 F: drivers/clk/clk-s2mps11.c 22511 22498 F: drivers/mfd/sec*.[ch] 22512 - F: drivers/regulator/s2m*.c 22499 + F: drivers/regulator/s2*.c 22513 22500 F: drivers/regulator/s5m*.c 22514 22501 F: drivers/rtc/rtc-s5m.c 22515 22502 F: include/linux/mfd/samsung/
+62
drivers/regulator/Kconfig
··· 777 777 It includes support for control of output voltage. This 778 778 regulator is found on the Samsung Galaxy S5 (klte) smartphone. 779 779 780 + config REGULATOR_MAX77838 781 + tristate "Maxim 77838 regulator" 782 + depends on I2C 783 + select REGMAP_I2C 784 + help 785 + This driver controls a Maxim 77838 regulator via I2C bus. 786 + The regulator include 4 LDOs and a BUCK regulator. It's 787 + present on the Samsung Galaxy S7 lineup of smartphones. 788 + 780 789 config REGULATOR_MC13XXX_CORE 781 790 tristate 782 791 ··· 1014 1005 help 1015 1006 This driver provides support for the voltage regulators of the 1016 1007 PCAP2 PMIC. 1008 + 1009 + config REGULATOR_PF0900 1010 + tristate "NXP PF0900/PF0901/PF09XX regulator driver" 1011 + depends on I2C 1012 + select REGMAP_I2C 1013 + help 1014 + Say y here to support the NXP PF0900/PF0901/PF09XX PMIC 1015 + regulator driver. 1016 + 1017 + config REGULATOR_PF530X 1018 + tristate "NXP PF5300/PF5301/PF5302 regulator driver" 1019 + depends on I2C && OF 1020 + select REGMAP_I2C 1021 + help 1022 + Say y here to support the regulators found on the NXP 1023 + PF5300/PF5301/PF5302 PMIC. 1024 + 1025 + Say M here if you want to support for the regulators found 1026 + on the NXP PF5300/PF5301/PF5302 PMIC. The module will be named 1027 + "pf530x-regulator". 1017 1028 1018 1029 config REGULATOR_PF8X00 1019 1030 tristate "NXP PF8100/PF8121A/PF8200 regulator driver" ··· 1269 1240 600mV to 1395mV, per step 6.250mV. The others are all fixed voltage 1270 1241 by external hardware circuit. 1271 1242 1243 + config REGULATOR_RT5133 1244 + tristate "Richtek RT5133 PMIC Regulators" 1245 + depends on I2C && GPIOLIB && OF 1246 + select REGMAP 1247 + select CRC8 1248 + select OF_GPIO 1249 + help 1250 + This driver adds support for RT5133 PMIC regulators. 1251 + RT5133 is an integrated chip. It includes 8 LDOs and 3 GPOs that 1252 + can be used to drive output high/low purpose. The dependency of the 1253 + GPO block is internally LDO1 Voltage. 1254 + 1272 1255 config REGULATOR_RT5190A 1273 1256 tristate "Richtek RT5190A PMIC" 1274 1257 depends on I2C ··· 1385 1344 and two ldos. It features wide output voltage range from 0.4V to 2.05V 1386 1345 and the capability to configure the corresponding power stages. 1387 1346 1347 + config REGULATOR_S2DOS05 1348 + tristate "Samsung S2DOS05 voltage regulator" 1349 + depends on MFD_SEC_CORE || COMPILE_TEST 1350 + help 1351 + This driver provides support for the voltage regulators of the S2DOS05. 1352 + The S2DOS05 is a companion power management IC for the smart phones. 1353 + The S2DOS05 has 4 LDOs and 1 BUCK outputs. 1354 + 1388 1355 config REGULATOR_S2MPA01 1389 1356 tristate "Samsung S2MPA01 voltage regulator" 1390 1357 depends on MFD_SEC_CORE || COMPILE_TEST ··· 1443 1394 Say y here to support for the Dialog Semiconductor SLG51000. 1444 1395 The SLG51000 is seven compact and customizable low dropout 1445 1396 regulators. 1397 + 1398 + config REGULATOR_SPACEMIT_P1 1399 + tristate "SpacemiT P1 regulators" 1400 + depends on ARCH_SPACEMIT || COMPILE_TEST 1401 + depends on I2C 1402 + select MFD_SPACEMIT_P1 1403 + default ARCH_SPACEMIT 1404 + help 1405 + Enable support for regulators implemented by the SpacemiT P1 1406 + power controller. The P1 implements 6 high-efficiency buck 1407 + converters and 12 programmable LDO regulators. To compile this 1408 + driver as a module, choose M here. The module will be called 1409 + "spacemit-pmic". 1446 1410 1447 1411 config REGULATOR_STM32_BOOSTER 1448 1412 tristate "STMicroelectronics STM32 BOOSTER"
+6
drivers/regulator/Makefile
··· 92 92 obj-$(CONFIG_REGULATOR_MAX77693) += max77693-regulator.o 93 93 obj-$(CONFIG_REGULATOR_MAX77802) += max77802-regulator.o 94 94 obj-$(CONFIG_REGULATOR_MAX77826) += max77826-regulator.o 95 + obj-$(CONFIG_REGULATOR_MAX77838) += max77838-regulator.o 95 96 obj-$(CONFIG_REGULATOR_MAX77857) += max77857-regulator.o 96 97 obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o 97 98 obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o ··· 125 124 obj-$(CONFIG_REGULATOR_QCOM_USB_VBUS) += qcom_usb_vbus-regulator.o 126 125 obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o 127 126 obj-$(CONFIG_REGULATOR_PCA9450) += pca9450-regulator.o 127 + obj-$(CONFIG_REGULATOR_PF0900) += pf0900-regulator.o 128 128 obj-$(CONFIG_REGULATOR_PF9453) += pf9453-regulator.o 129 + obj-$(CONFIG_REGULATOR_PF530X) += pf530x-regulator.o 129 130 obj-$(CONFIG_REGULATOR_PF8X00) += pf8x00-regulator.o 130 131 obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o 131 132 obj-$(CONFIG_REGULATOR_PV88060) += pv88060-regulator.o ··· 149 146 obj-$(CONFIG_REGULATOR_RT4831) += rt4831-regulator.o 150 147 obj-$(CONFIG_REGULATOR_RT5033) += rt5033-regulator.o 151 148 obj-$(CONFIG_REGULATOR_RT5120) += rt5120-regulator.o 149 + obj-$(CONFIG_REGULATOR_RT5133) += rt5133-regulator.o 152 150 obj-$(CONFIG_REGULATOR_RT5190A) += rt5190a-regulator.o 153 151 obj-$(CONFIG_REGULATOR_RT5739) += rt5739.o 154 152 obj-$(CONFIG_REGULATOR_RT5759) += rt5759-regulator.o ··· 160 156 obj-$(CONFIG_REGULATOR_RTQ2134) += rtq2134-regulator.o 161 157 obj-$(CONFIG_REGULATOR_RTQ6752) += rtq6752-regulator.o 162 158 obj-$(CONFIG_REGULATOR_RTQ2208) += rtq2208-regulator.o 159 + obj-$(CONFIG_REGULATOR_S2DOS05) += s2dos05-regulator.o 163 160 obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o 164 161 obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o 165 162 obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o 166 163 obj-$(CONFIG_REGULATOR_SC2731) += sc2731-regulator.o 167 164 obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o 168 165 obj-$(CONFIG_REGULATOR_SLG51000) += slg51000-regulator.o 166 + obj-$(CONFIG_REGULATOR_SPACEMIT_P1) += spacemit-p1.o 169 167 obj-$(CONFIG_REGULATOR_STM32_BOOSTER) += stm32-booster.o 170 168 obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o 171 169 obj-$(CONFIG_REGULATOR_STM32_PWR) += stm32-pwr.o
+1 -1
drivers/regulator/bd718x7-regulator.c
··· 1598 1598 if (desc->n_linear_ranges && desc->linear_ranges) { 1599 1599 struct linear_range *new; 1600 1600 1601 - new = devm_kzalloc(dev, desc->n_linear_ranges * 1601 + new = devm_kcalloc(dev, desc->n_linear_ranges, 1602 1602 sizeof(struct linear_range), 1603 1603 GFP_KERNEL); 1604 1604 if (!new)
+2 -2
drivers/regulator/core.c
··· 1586 1586 } 1587 1587 1588 1588 if (rdev->constraints->active_discharge && ops->set_active_discharge) { 1589 - bool ad_state = (rdev->constraints->active_discharge == 1590 - REGULATOR_ACTIVE_DISCHARGE_ENABLE) ? true : false; 1589 + bool ad_state = rdev->constraints->active_discharge == 1590 + REGULATOR_ACTIVE_DISCHARGE_ENABLE; 1591 1591 1592 1592 ret = ops->set_active_discharge(rdev, ad_state); 1593 1593 if (ret < 0) {
+221
drivers/regulator/max77838-regulator.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + // 3 + // regulator driver for Maxim MAX77838 4 + // 5 + // based on max77826-regulator.c 6 + // 7 + // Copyright (c) 2025, Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com> 8 + 9 + #include <linux/kernel.h> 10 + #include <linux/module.h> 11 + #include <linux/init.h> 12 + #include <linux/err.h> 13 + #include <linux/of.h> 14 + #include <linux/platform_device.h> 15 + #include <linux/regulator/driver.h> 16 + #include <linux/regulator/of_regulator.h> 17 + #include <linux/i2c.h> 18 + #include <linux/regmap.h> 19 + 20 + enum max77838_registers { 21 + MAX77838_REG_DEVICE_ID = 0x00, 22 + MAX77838_REG_TOPSYS_STAT, 23 + MAX77838_REG_STAT, 24 + MAX77838_REG_EN, 25 + MAX77838_REG_GPIO_PD_CTRL, 26 + MAX77838_REG_UVLO_CFG1, 27 + /* 0x06 - 0x0B: reserved */ 28 + MAX77838_REG_I2C_CFG = 0x0C, 29 + /* 0x0D - 0x0F: reserved */ 30 + MAX77838_REG_LDO1_CFG = 0x10, 31 + MAX77838_REG_LDO2_CFG, 32 + MAX77838_REG_LDO3_CFG, 33 + MAX77838_REG_LDO4_CFG, 34 + /* 0x14 - 0x1F: reserved */ 35 + MAX77838_REG_BUCK_CFG1 = 0x20, 36 + MAX77838_REG_BUCK_VOUT, 37 + }; 38 + 39 + enum max77838_regulators { 40 + MAX77838_LDO1 = 0, 41 + MAX77838_LDO2, 42 + MAX77838_LDO3, 43 + MAX77838_LDO4, 44 + MAX77838_BUCK, 45 + MAX77838_MAX_REGULATORS, 46 + }; 47 + 48 + #define MAX77838_MASK_LDO 0x7f 49 + #define MAX77838_MASK_BUCK 0xff 50 + 51 + #define MAX77838_LDO1_EN BIT(0) 52 + #define MAX77838_LDO2_EN BIT(1) 53 + #define MAX77838_LDO3_EN BIT(2) 54 + #define MAX77838_LDO4_EN BIT(3) 55 + #define MAX77838_BUCK_EN BIT(4) 56 + 57 + #define MAX77838_BUCK_AD BIT(3) 58 + #define MAX77838_LDO_AD BIT(7) 59 + 60 + #define MAX77838_LDO_VOLT_MIN 600000 61 + #define MAX77838_LDO_VOLT_MAX 3775000 62 + #define MAX77838_LDO_VOLT_STEP 25000 63 + 64 + #define MAX77838_BUCK_VOLT_MIN 500000 65 + #define MAX77838_BUCK_VOLT_MAX 2093750 66 + #define MAX77838_BUCK_VOLT_STEP 6250 67 + 68 + #define MAX77838_VOLT_RANGE(_type) \ 69 + ((MAX77838_ ## _type ## _VOLT_MAX - \ 70 + MAX77838_ ## _type ## _VOLT_MIN) / \ 71 + MAX77838_ ## _type ## _VOLT_STEP + 1) 72 + 73 + #define MAX77838_LDO(_id) \ 74 + [MAX77838_LDO ## _id] = { \ 75 + .id = MAX77838_LDO ## _id, \ 76 + .name = "ldo"#_id, \ 77 + .of_match = of_match_ptr("ldo"#_id), \ 78 + .regulators_node = "regulators", \ 79 + .ops = &max77838_regulator_ops, \ 80 + .min_uV = MAX77838_LDO_VOLT_MIN, \ 81 + .uV_step = MAX77838_LDO_VOLT_STEP, \ 82 + .n_voltages = MAX77838_VOLT_RANGE(LDO), \ 83 + .enable_reg = MAX77838_REG_EN, \ 84 + .enable_mask = MAX77838_LDO ## _id ## _EN, \ 85 + .vsel_reg = MAX77838_REG_LDO ## _id ## _CFG, \ 86 + .vsel_mask = MAX77838_MASK_LDO, \ 87 + .active_discharge_off = 0, \ 88 + .active_discharge_on = MAX77838_LDO_AD, \ 89 + .active_discharge_mask = MAX77838_LDO_AD, \ 90 + .active_discharge_reg = MAX77838_REG_LDO ## _id ## _CFG, \ 91 + .owner = THIS_MODULE, \ 92 + } 93 + 94 + #define MAX77838_BUCK_DESC \ 95 + [MAX77838_BUCK] = { \ 96 + .id = MAX77838_BUCK, \ 97 + .name = "buck", \ 98 + .of_match = of_match_ptr("buck"), \ 99 + .regulators_node = "regulators", \ 100 + .ops = &max77838_regulator_ops, \ 101 + .min_uV = MAX77838_BUCK_VOLT_MIN, \ 102 + .uV_step = MAX77838_BUCK_VOLT_STEP, \ 103 + .n_voltages = MAX77838_VOLT_RANGE(BUCK), \ 104 + .enable_reg = MAX77838_REG_EN, \ 105 + .enable_mask = MAX77838_BUCK_EN, \ 106 + .vsel_reg = MAX77838_REG_BUCK_VOUT, \ 107 + .vsel_mask = MAX77838_MASK_BUCK, \ 108 + .active_discharge_off = 0, \ 109 + .active_discharge_on = MAX77838_BUCK_AD, \ 110 + .active_discharge_mask = MAX77838_BUCK_AD, \ 111 + .active_discharge_reg = MAX77838_REG_BUCK_CFG1, \ 112 + .owner = THIS_MODULE, \ 113 + } 114 + 115 + struct max77838_regulator_info { 116 + struct regmap *regmap; 117 + }; 118 + 119 + static const struct regmap_config max77838_regmap_config = { 120 + .reg_bits = 8, 121 + .val_bits = 8, 122 + .max_register = MAX77838_REG_BUCK_VOUT, 123 + }; 124 + 125 + static const struct regulator_ops max77838_regulator_ops = { 126 + .enable = regulator_enable_regmap, 127 + .disable = regulator_disable_regmap, 128 + .is_enabled = regulator_is_enabled_regmap, 129 + .list_voltage = regulator_list_voltage_linear, 130 + .map_voltage = regulator_map_voltage_linear, 131 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 132 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 133 + .set_active_discharge = regulator_set_active_discharge_regmap, 134 + }; 135 + 136 + static const struct regulator_desc max77838_regulators_desc[] = { 137 + MAX77838_LDO(1), 138 + MAX77838_LDO(2), 139 + MAX77838_LDO(3), 140 + MAX77838_LDO(4), 141 + MAX77838_BUCK_DESC, 142 + }; 143 + 144 + static int max77838_read_device_id(struct regmap *regmap, struct device *dev) 145 + { 146 + unsigned int device_id; 147 + int ret; 148 + 149 + ret = regmap_read(regmap, MAX77838_REG_DEVICE_ID, &device_id); 150 + if (!ret) 151 + dev_dbg(dev, "DEVICE_ID: 0x%x\n", device_id); 152 + 153 + return ret; 154 + } 155 + 156 + static int max77838_i2c_probe(struct i2c_client *client) 157 + { 158 + struct device *dev = &client->dev; 159 + struct max77838_regulator_info *info; 160 + struct regulator_config config = {}; 161 + struct regulator_dev *rdev; 162 + struct regmap *regmap; 163 + int i; 164 + 165 + info = devm_kzalloc(dev, sizeof(struct max77838_regulator_info), 166 + GFP_KERNEL); 167 + if (!info) 168 + return -ENOMEM; 169 + 170 + regmap = devm_regmap_init_i2c(client, &max77838_regmap_config); 171 + if (IS_ERR(regmap)) { 172 + dev_err(dev, "Failed to allocate regmap!\n"); 173 + return PTR_ERR(regmap); 174 + } 175 + 176 + info->regmap = regmap; 177 + i2c_set_clientdata(client, info); 178 + 179 + config.dev = dev; 180 + config.regmap = regmap; 181 + config.driver_data = info; 182 + 183 + for (i = 0; i < MAX77838_MAX_REGULATORS; i++) { 184 + rdev = devm_regulator_register(dev, 185 + &max77838_regulators_desc[i], 186 + &config); 187 + if (IS_ERR(rdev)) { 188 + dev_err(dev, "Failed to register regulator!\n"); 189 + return PTR_ERR(rdev); 190 + } 191 + } 192 + 193 + return max77838_read_device_id(regmap, dev); 194 + } 195 + 196 + static const struct of_device_id __maybe_unused max77838_of_match[] = { 197 + { .compatible = "maxim,max77838" }, 198 + { /* sentinel */ } 199 + }; 200 + MODULE_DEVICE_TABLE(of, max77838_of_match); 201 + 202 + static const struct i2c_device_id max77838_id[] = { 203 + { "max77838-regulator" }, 204 + { /* sentinel */ } 205 + }; 206 + MODULE_DEVICE_TABLE(i2c, max77838_id); 207 + 208 + static struct i2c_driver max77838_regulator_driver = { 209 + .driver = { 210 + .name = "max77838", 211 + .probe_type = PROBE_PREFER_ASYNCHRONOUS, 212 + .of_match_table = of_match_ptr(max77838_of_match), 213 + }, 214 + .probe = max77838_i2c_probe, 215 + .id_table = max77838_id, 216 + }; 217 + module_i2c_driver(max77838_regulator_driver); 218 + 219 + MODULE_AUTHOR("Ivaylo Ivanov <ivo.ivanov.ivanov1@gmail.com>"); 220 + MODULE_DESCRIPTION("MAX77838 PMIC regulator driver"); 221 + MODULE_LICENSE("GPL");
+975
drivers/regulator/pf0900-regulator.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright 2025 NXP. 3 + // NXP PF0900 pmic driver 4 + 5 + #include <linux/bitfield.h> 6 + #include <linux/crc8.h> 7 + #include <linux/err.h> 8 + #include <linux/gpio/consumer.h> 9 + #include <linux/i2c.h> 10 + #include <linux/interrupt.h> 11 + #include <linux/kernel.h> 12 + #include <linux/module.h> 13 + #include <linux/of.h> 14 + #include <linux/of_device.h> 15 + #include <linux/platform_device.h> 16 + #include <linux/regmap.h> 17 + #include <linux/regulator/driver.h> 18 + #include <linux/regulator/machine.h> 19 + #include <linux/regulator/of_regulator.h> 20 + 21 + enum pf0900_regulators { 22 + PF0900_SW1 = 0, 23 + PF0900_SW2, 24 + PF0900_SW3, 25 + PF0900_SW4, 26 + PF0900_SW5, 27 + PF0900_LDO1, 28 + PF0900_LDO2, 29 + PF0900_LDO3, 30 + PF0900_VAON, 31 + PF0900_REGULATOR_CNT, 32 + }; 33 + 34 + enum { 35 + PF0900_DVS_LEVEL_RUN = 0, 36 + PF0900_DVS_LEVEL_STANDBY, 37 + PF0900_DVS_LEVEL_MAX, 38 + }; 39 + 40 + 41 + #define PF0900_VAON_VOLTAGE_NUM 0x03 42 + #define PF0900_SW_VOLTAGE_NUM 0x100 43 + #define PF0900_LDO_VOLTAGE_NUM 0x20 44 + 45 + #define REGU_SW_CNT 0x5 46 + #define REGU_LDO_VAON_CNT 0x4 47 + 48 + enum { 49 + PF0900_REG_DEV_ID = 0x00, 50 + PF0900_REG_DEV_FAM = 0x01, 51 + PF0900_REG_REV_ID = 0x02, 52 + PF0900_REG_PROG_ID1 = 0x03, 53 + PF0900_REG_PROG_ID2 = 0x04, 54 + PF0900_REG_SYSTEM_INT = 0x05, 55 + PF0900_REG_STATUS1_INT = 0x06, 56 + PF0900_REG_STATUS1_MSK = 0x07, 57 + PF0900_REG_STATUS1_SNS = 0x08, 58 + PF0900_REG_STATUS2_INT = 0x09, 59 + PF0900_REG_STATUS2_MSK = 0x0A, 60 + PF0900_REG_STATUS2_SNS = 0x0B, 61 + PF0900_REG_STATUS3_INT = 0x0C, 62 + PF0900_REG_STATUS3_MSK = 0x0D, 63 + PF0900_REG_SW_MODE_INT = 0x0E, 64 + PF0900_REG_SW_MODE_MSK = 0x0F, 65 + PF0900_REG_SW_ILIM_INT = 0x10, 66 + PF0900_REG_SW_ILIM_MSK = 0x11, 67 + PF0900_REG_SW_ILIM_SNS = 0x12, 68 + PF0900_REG_LDO_ILIM_INT = 0x13, 69 + PF0900_REG_LDO_ILIM_MSK = 0x14, 70 + PF0900_REG_LDO_ILIM_SNS = 0x15, 71 + PF0900_REG_SW_UV_INT = 0x16, 72 + PF0900_REG_SW_UV_MSK = 0x17, 73 + PF0900_REG_SW_UV_SNS = 0x18, 74 + PF0900_REG_SW_OV_INT = 0x19, 75 + PF0900_REG_SW_OV_MSK = 0x1A, 76 + PF0900_REG_SW_OV_SNS = 0x1B, 77 + PF0900_REG_LDO_UV_INT = 0x1C, 78 + PF0900_REG_LDO_UV_MSK = 0x1D, 79 + PF0900_REG_LDO_UV_SNS = 0x1E, 80 + PF0900_REG_LDO_OV_INT = 0x1F, 81 + PF0900_REG_LDO_OV_MSK = 0x20, 82 + PF0900_REG_LDO_OV_SNS = 0x21, 83 + PF0900_REG_PWRON_INT = 0x22, 84 + PF0900_REG_IO_INT = 0x24, 85 + PF0900_REG_IO_MSK = 0x25, 86 + PF0900_REG_IO_SNS = 0x26, 87 + PF0900_REG_IOSHORT_SNS = 0x27, 88 + PF0900_REG_ABIST_OV1 = 0x28, 89 + PF0900_REG_ABIST_OV2 = 0x29, 90 + PF0900_REG_ABIST_UV1 = 0x2A, 91 + PF0900_REG_ABIST_UV2 = 0x2B, 92 + PF0900_REG_ABIST_IO = 0x2C, 93 + PF0900_REG_TEST_FLAGS = 0x2D, 94 + PF0900_REG_HFAULT_FLAGS = 0x2E, 95 + PF0900_REG_FAULT_FLAGS = 0x2F, 96 + PF0900_REG_FS0B_CFG = 0x30, 97 + PF0900_REG_FCCU_CFG = 0x31, 98 + PF0900_REG_RSTB_CFG1 = 0x32, 99 + PF0900_REG_SYSTEM_CMD = 0x33, 100 + PF0900_REG_FS0B_CMD = 0x34, 101 + PF0900_REG_SECURE_WR1 = 0x35, 102 + PF0900_REG_SECURE_WR2 = 0x36, 103 + PF0900_REG_VMON_CFG1 = 0x37, 104 + PF0900_REG_SYS_CFG1 = 0x38, 105 + PF0900_REG_GPO_CFG = 0x39, 106 + PF0900_REG_GPO_CTRL = 0x3A, 107 + PF0900_REG_PWRUP_CFG = 0x3B, 108 + PF0900_REG_RSTB_PWRUP = 0x3C, 109 + PF0900_REG_GPIO1_PWRUP = 0x3D, 110 + PF0900_REG_GPIO2_PWRUP = 0x3E, 111 + PF0900_REG_GPIO3_PWRUP = 0x3F, 112 + PF0900_REG_GPIO4_PWRUP = 0x40, 113 + PF0900_REG_VMON1_PWRUP = 0x41, 114 + PF0900_REG_VMON2_PWRUP = 0x42, 115 + PF0900_REG_SW1_PWRUP = 0x43, 116 + PF0900_REG_SW2_PWRUP = 0x44, 117 + PF0900_REG_SW3_PWRUP = 0x45, 118 + PF0900_REG_SW4_PWRUP = 0x46, 119 + PF0900_REG_SW5_PWRUP = 0x47, 120 + PF0900_REG_LDO1_PWRUP = 0x48, 121 + PF0900_REG_LDO2_PWRUP = 0x49, 122 + PF0900_REG_LDO3_PWRUP = 0x4A, 123 + PF0900_REG_VAON_PWRUP = 0x4B, 124 + PF0900_REG_FREQ_CTRL = 0x4C, 125 + PF0900_REG_PWRON_CFG = 0x4D, 126 + PF0900_REG_WD_CTRL1 = 0x4E, 127 + PF0900_REG_WD_CTRL2 = 0x4F, 128 + PF0900_REG_WD_CFG1 = 0x50, 129 + PF0900_REG_WD_CFG2 = 0x51, 130 + PF0900_REG_WD_CNT1 = 0x52, 131 + PF0900_REG_WD_CNT2 = 0x53, 132 + PF0900_REG_FAULT_CFG = 0x54, 133 + PF0900_REG_FAULT_CNT = 0x55, 134 + PF0900_REG_DFS_CNT = 0x56, 135 + PF0900_REG_AMUX_CFG = 0x57, 136 + PF0900_REG_VMON1_RUN_CFG = 0x58, 137 + PF0900_REG_VMON1_STBY_CFG = 0x59, 138 + PF0900_REG_VMON1_CTRL = 0x5A, 139 + PF0900_REG_VMON2_RUN_CFG = 0x5B, 140 + PF0900_REG_VMON2_STBY_CFG = 0x5C, 141 + PF0900_REG_VMON2_CTRL = 0x5D, 142 + PF0900_REG_SW1_VRUN = 0x5E, 143 + PF0900_REG_SW1_VSTBY = 0x5F, 144 + PF0900_REG_SW1_MODE = 0x60, 145 + PF0900_REG_SW1_CFG1 = 0x61, 146 + PF0900_REG_SW1_CFG2 = 0x62, 147 + PF0900_REG_SW2_VRUN = 0x63, 148 + PF0900_REG_SW2_VSTBY = 0x64, 149 + PF0900_REG_SW2_MODE = 0x65, 150 + PF0900_REG_SW2_CFG1 = 0x66, 151 + PF0900_REG_SW2_CFG2 = 0x67, 152 + PF0900_REG_SW3_VRUN = 0x68, 153 + PF0900_REG_SW3_VSTBY = 0x69, 154 + PF0900_REG_SW3_MODE = 0x6A, 155 + PF0900_REG_SW3_CFG1 = 0x6B, 156 + PF0900_REG_SW3_CFG2 = 0x6C, 157 + PF0900_REG_SW4_VRUN = 0x6D, 158 + PF0900_REG_SW4_VSTBY = 0x6E, 159 + PF0900_REG_SW4_MODE = 0x6F, 160 + PF0900_REG_SW4_CFG1 = 0x70, 161 + PF0900_REG_SW4_CFG2 = 0x71, 162 + PF0900_REG_SW5_VRUN = 0x72, 163 + PF0900_REG_SW5_VSTBY = 0x73, 164 + PF0900_REG_SW5_MODE = 0x74, 165 + PF0900_REG_SW5_CFG1 = 0x75, 166 + PF0900_REG_SW5_CFG2 = 0x76, 167 + PF0900_REG_LDO1_RUN = 0x77, 168 + PF0900_REG_LDO1_STBY = 0x78, 169 + PF0900_REG_LDO1_CFG2 = 0x79, 170 + PF0900_REG_LDO2_RUN = 0x7A, 171 + PF0900_REG_LDO2_STBY = 0x7B, 172 + PF0900_REG_LDO2_CFG2 = 0x7C, 173 + PF0900_REG_LDO3_RUN = 0x7D, 174 + PF0900_REG_LDO3_STBY = 0x7E, 175 + PF0900_REG_LDO3_CFG2 = 0x7F, 176 + PF0900_REG_VAON_CFG1 = 0x80, 177 + PF0900_REG_VAON_CFG2 = 0x81, 178 + PF0900_REG_SYS_DIAG = 0x82, 179 + PF0900_MAX_REGISTER, 180 + }; 181 + 182 + /* PF0900 SW MODE */ 183 + #define SW_RUN_MODE_OFF 0x00 184 + #define SW_RUN_MODE_PWM 0x01 185 + #define SW_RUN_MODE_PFM 0x02 186 + #define SW_STBY_MODE_OFF 0x00 187 + #define SW_STBY_MODE_PWM 0x04 188 + #define SW_STBY_MODE_PFM 0x08 189 + 190 + /* PF0900 SW MODE MASK */ 191 + #define SW_RUN_MODE_MASK GENMASK(1, 0) 192 + #define SW_STBY_MODE_MASK GENMASK(3, 2) 193 + 194 + /* PF0900 SW VRUN/VSTBY MASK */ 195 + #define PF0900_SW_VOL_MASK GENMASK(7, 0) 196 + 197 + /* PF0900_REG_VAON_CFG1 bits */ 198 + #define PF0900_VAON_1P8V 0x01 199 + 200 + #define PF0900_VAON_MASK GENMASK(1, 0) 201 + 202 + /* PF0900_REG_SWX_CFG1 MASK */ 203 + #define PF0900_SW_DVS_MASK GENMASK(4, 3) 204 + 205 + /* PF0900_REG_LDO_RUN MASK */ 206 + #define VLDO_RUN_MASK GENMASK(4, 0) 207 + #define LDO_RUN_EN_MASK BIT(5) 208 + 209 + /* PF0900_REG_STATUS1_INT bits */ 210 + #define PF0900_IRQ_PWRUP BIT(3) 211 + 212 + /* PF0900_REG_ILIM_INT bits */ 213 + #define PF0900_IRQ_SW1_IL BIT(0) 214 + #define PF0900_IRQ_SW2_IL BIT(1) 215 + #define PF0900_IRQ_SW3_IL BIT(2) 216 + #define PF0900_IRQ_SW4_IL BIT(3) 217 + #define PF0900_IRQ_SW5_IL BIT(4) 218 + 219 + #define PF0900_IRQ_LDO1_IL BIT(0) 220 + #define PF0900_IRQ_LDO2_IL BIT(1) 221 + #define PF0900_IRQ_LDO3_IL BIT(2) 222 + 223 + /* PF0900_REG_UV_INT bits */ 224 + #define PF0900_IRQ_SW1_UV BIT(0) 225 + #define PF0900_IRQ_SW2_UV BIT(1) 226 + #define PF0900_IRQ_SW3_UV BIT(2) 227 + #define PF0900_IRQ_SW4_UV BIT(3) 228 + #define PF0900_IRQ_SW5_UV BIT(4) 229 + 230 + #define PF0900_IRQ_LDO1_UV BIT(0) 231 + #define PF0900_IRQ_LDO2_UV BIT(1) 232 + #define PF0900_IRQ_LDO3_UV BIT(2) 233 + #define PF0900_IRQ_VAON_UV BIT(3) 234 + 235 + /* PF0900_REG_OV_INT bits */ 236 + #define PF0900_IRQ_SW1_OV BIT(0) 237 + #define PF0900_IRQ_SW2_OV BIT(1) 238 + #define PF0900_IRQ_SW3_OV BIT(2) 239 + #define PF0900_IRQ_SW4_OV BIT(3) 240 + #define PF0900_IRQ_SW5_OV BIT(4) 241 + 242 + #define PF0900_IRQ_LDO1_OV BIT(0) 243 + #define PF0900_IRQ_LDO2_OV BIT(1) 244 + #define PF0900_IRQ_LDO3_OV BIT(2) 245 + #define PF0900_IRQ_VAON_OV BIT(3) 246 + 247 + struct pf0900_regulator_desc { 248 + struct regulator_desc desc; 249 + unsigned int suspend_enable_mask; 250 + unsigned int suspend_voltage_reg; 251 + unsigned int suspend_voltage_cache; 252 + }; 253 + 254 + struct pf0900_drvdata { 255 + const struct pf0900_regulator_desc *desc; 256 + unsigned int rcnt; 257 + }; 258 + 259 + struct pf0900 { 260 + struct device *dev; 261 + struct regmap *regmap; 262 + const struct pf0900_drvdata *drvdata; 263 + struct regulator_dev *rdevs[PF0900_REGULATOR_CNT]; 264 + int irq; 265 + unsigned short addr; 266 + bool crc_en; 267 + }; 268 + 269 + enum pf0900_regulator_type { 270 + PF0900_SW = 0, 271 + PF0900_LDO, 272 + }; 273 + 274 + #define PF0900_REGU_IRQ(_reg, _type, _event) \ 275 + { \ 276 + .reg = _reg, \ 277 + .type = _type, \ 278 + .event = _event, \ 279 + } 280 + 281 + struct pf0900_regulator_irq { 282 + unsigned int reg; 283 + unsigned int type; 284 + unsigned int event; 285 + }; 286 + 287 + static const struct regmap_range pf0900_range = { 288 + .range_min = PF0900_REG_DEV_ID, 289 + .range_max = PF0900_REG_SYS_DIAG, 290 + }; 291 + 292 + static const struct regmap_access_table pf0900_volatile_regs = { 293 + .yes_ranges = &pf0900_range, 294 + .n_yes_ranges = 1, 295 + }; 296 + 297 + static const struct regmap_config pf0900_regmap_config = { 298 + .reg_bits = 8, 299 + .val_bits = 8, 300 + .volatile_table = &pf0900_volatile_regs, 301 + .max_register = PF0900_MAX_REGISTER - 1, 302 + .cache_type = REGCACHE_MAPLE, 303 + }; 304 + 305 + static uint8_t crc8_j1850(unsigned short addr, unsigned int reg, 306 + unsigned int val) 307 + { 308 + uint8_t crcBuf[3]; 309 + uint8_t t_crc; 310 + uint8_t i, j; 311 + 312 + crcBuf[0] = addr; 313 + crcBuf[1] = reg; 314 + crcBuf[2] = val; 315 + t_crc = 0xFF; 316 + 317 + /* 318 + * The CRC calculation is based on the standard CRC-8-SAE as 319 + * defined in the SAE-J1850 specification with the following 320 + * characteristics. 321 + * Polynomial = 0x1D 322 + * Initial Value = 0xFF 323 + * The CRC byte is calculated by shifting 24-bit data through 324 + * the CRC polynomial.The 24-bits package is built as follows: 325 + * DEVICE_ADDR[b8] + REGISTER_ADDR [b8] +DATA[b8] 326 + * The DEVICE_ADDR is calculated as the 7-bit slave address 327 + * shifted left one space plus the corresponding read/write bit. 328 + * (7Bit Address [b7] << 1 ) + R/W = DEVICE_ADDR[b8] 329 + */ 330 + for (i = 0; i < sizeof(crcBuf); i++) { 331 + t_crc ^= crcBuf[i]; 332 + for (j = 0; j < 8; j++) { 333 + if ((t_crc & 0x80) != 0) { 334 + t_crc <<= 1; 335 + t_crc ^= 0x1D; 336 + } else { 337 + t_crc <<= 1; 338 + } 339 + } 340 + } 341 + 342 + return t_crc; 343 + } 344 + 345 + static int pf0900_regmap_read(void *context, unsigned int reg, 346 + unsigned int *val) 347 + { 348 + struct device *dev = context; 349 + struct i2c_client *i2c = to_i2c_client(dev); 350 + struct pf0900 *pf0900 = dev_get_drvdata(dev); 351 + int ret; 352 + u8 crc; 353 + 354 + if (!pf0900 || !pf0900->dev) 355 + return -EINVAL; 356 + 357 + if (reg >= PF0900_MAX_REGISTER) { 358 + dev_err(pf0900->dev, "Invalid register address: 0x%x\n", reg); 359 + return -EINVAL; 360 + } 361 + 362 + if (pf0900->crc_en) { 363 + ret = i2c_smbus_read_word_data(i2c, reg); 364 + if (ret < 0) { 365 + dev_err(pf0900->dev, "Read error at reg=0x%x: %d\n", reg, ret); 366 + return ret; 367 + } 368 + 369 + *val = (u16)ret; 370 + crc = crc8_j1850(pf0900->addr << 1 | 0x1, reg, FIELD_GET(GENMASK(7, 0), *val)); 371 + if (crc != FIELD_GET(GENMASK(15, 8), *val)) { 372 + dev_err(pf0900->dev, "Crc check error!\n"); 373 + return -EINVAL; 374 + } 375 + *val = FIELD_GET(GENMASK(7, 0), *val); 376 + } else { 377 + ret = i2c_smbus_read_byte_data(i2c, reg); 378 + if (ret < 0) { 379 + dev_err(pf0900->dev, "Read error at reg=0x%x: %d\n", reg, ret); 380 + return ret; 381 + } 382 + *val = ret; 383 + } 384 + 385 + return 0; 386 + } 387 + 388 + static int pf0900_regmap_write(void *context, unsigned int reg, 389 + unsigned int val) 390 + { 391 + struct device *dev = context; 392 + struct i2c_client *i2c = to_i2c_client(dev); 393 + struct pf0900 *pf0900 = dev_get_drvdata(dev); 394 + uint8_t data[2]; 395 + int ret; 396 + 397 + if (!pf0900 || !pf0900->dev) 398 + return -EINVAL; 399 + 400 + if (reg >= PF0900_MAX_REGISTER) { 401 + dev_err(pf0900->dev, "Invalid register address: 0x%x\n", reg); 402 + return -EINVAL; 403 + } 404 + 405 + data[0] = val; 406 + if (pf0900->crc_en) { 407 + /* Get CRC */ 408 + data[1] = crc8_j1850(pf0900->addr << 1, reg, data[0]); 409 + val = FIELD_PREP(GENMASK(15, 8), data[1]) | data[0]; 410 + ret = i2c_smbus_write_word_data(i2c, reg, val); 411 + } else { 412 + ret = i2c_smbus_write_byte_data(i2c, reg, data[0]); 413 + } 414 + 415 + if (ret) { 416 + dev_err(pf0900->dev, "Write reg=0x%x error!\n", reg); 417 + return ret; 418 + } 419 + 420 + return 0; 421 + } 422 + 423 + static int pf0900_suspend_enable(struct regulator_dev *rdev) 424 + { 425 + struct pf0900_regulator_desc *rdata = rdev_get_drvdata(rdev); 426 + struct regmap *rmap = rdev_get_regmap(rdev); 427 + 428 + return regmap_update_bits(rmap, rdata->desc.enable_reg, 429 + rdata->suspend_enable_mask, SW_STBY_MODE_PFM); 430 + } 431 + 432 + static int pf0900_suspend_disable(struct regulator_dev *rdev) 433 + { 434 + struct pf0900_regulator_desc *rdata = rdev_get_drvdata(rdev); 435 + struct regmap *rmap = rdev_get_regmap(rdev); 436 + 437 + return regmap_update_bits(rmap, rdata->desc.enable_reg, 438 + rdata->suspend_enable_mask, SW_STBY_MODE_OFF); 439 + } 440 + 441 + static int pf0900_set_suspend_voltage(struct regulator_dev *rdev, int uV) 442 + { 443 + struct pf0900_regulator_desc *rdata = rdev_get_drvdata(rdev); 444 + struct regmap *rmap = rdev_get_regmap(rdev); 445 + int ret; 446 + 447 + if (rdata->suspend_voltage_cache == uV) 448 + return 0; 449 + 450 + ret = regulator_map_voltage_iterate(rdev, uV, uV); 451 + if (ret < 0) { 452 + dev_err(rdev_get_dev(rdev), "failed to map %i uV\n", uV); 453 + return ret; 454 + } 455 + 456 + dev_dbg(rdev_get_dev(rdev), "uV: %i, reg: 0x%x, msk: 0x%x, val: 0x%x\n", 457 + uV, rdata->suspend_voltage_reg, rdata->desc.vsel_mask, ret); 458 + ret = regmap_update_bits(rmap, rdata->suspend_voltage_reg, 459 + rdata->desc.vsel_mask, ret); 460 + if (ret < 0) { 461 + dev_err(rdev_get_dev(rdev), "failed to set %i uV\n", uV); 462 + return ret; 463 + } 464 + 465 + rdata->suspend_voltage_cache = uV; 466 + 467 + return 0; 468 + } 469 + 470 + static const struct regmap_bus pf0900_regmap_bus = { 471 + .reg_read = pf0900_regmap_read, 472 + .reg_write = pf0900_regmap_write, 473 + }; 474 + 475 + static const struct regulator_ops pf0900_avon_regulator_ops = { 476 + .list_voltage = regulator_list_voltage_table, 477 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 478 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 479 + }; 480 + 481 + static const struct regulator_ops pf0900_dvs_sw_regulator_ops = { 482 + .enable = regulator_enable_regmap, 483 + .disable = regulator_disable_regmap, 484 + .is_enabled = regulator_is_enabled_regmap, 485 + .list_voltage = regulator_list_voltage_linear_range, 486 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 487 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 488 + .set_voltage_time_sel = regulator_set_voltage_time_sel, 489 + .set_ramp_delay = regulator_set_ramp_delay_regmap, 490 + .set_suspend_enable = pf0900_suspend_enable, 491 + .set_suspend_disable = pf0900_suspend_disable, 492 + .set_suspend_voltage = pf0900_set_suspend_voltage, 493 + }; 494 + 495 + static const struct regulator_ops pf0900_ldo_regulator_ops = { 496 + .enable = regulator_enable_regmap, 497 + .disable = regulator_disable_regmap, 498 + .is_enabled = regulator_is_enabled_regmap, 499 + .list_voltage = regulator_list_voltage_linear_range, 500 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 501 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 502 + }; 503 + 504 + /* 505 + * SW1/2/3/4/5 506 + * SW1_DVS[1:0] SW1 DVS ramp rate setting 507 + * 00: 15.6mV/8usec 508 + * 01: 15.6mV/4usec 509 + * 10: 15.6mV/2usec 510 + * 11: 15.6mV/1usec 511 + */ 512 + static const unsigned int pf0900_dvs_sw_ramp_table[] = { 513 + 1950, 3900, 7800, 15600 514 + }; 515 + 516 + /* VAON 1.8V, 3.0V, or 3.3V */ 517 + static const int pf0900_vaon_voltages[] = { 518 + 0, 1800000, 3000000, 3300000, 519 + }; 520 + 521 + /* 522 + * SW1 0.5V to 3.3V 523 + * 0.5V to 1.35V (6.25mV step) 524 + * 1.8V to 2.5V (125mV step) 525 + * 2.8V to 3.3V (250mV step) 526 + */ 527 + static const struct linear_range pf0900_dvs_sw1_volts[] = { 528 + REGULATOR_LINEAR_RANGE(0, 0x00, 0x08, 0), 529 + REGULATOR_LINEAR_RANGE(500000, 0x09, 0x91, 6250), 530 + REGULATOR_LINEAR_RANGE(0, 0x92, 0x9E, 0), 531 + REGULATOR_LINEAR_RANGE(1500000, 0x9F, 0x9F, 0), 532 + REGULATOR_LINEAR_RANGE(1800000, 0xA0, 0xD8, 12500), 533 + REGULATOR_LINEAR_RANGE(0, 0xD9, 0xDF, 0), 534 + REGULATOR_LINEAR_RANGE(2800000, 0xE0, 0xF4, 25000), 535 + REGULATOR_LINEAR_RANGE(0, 0xF5, 0xFF, 0), 536 + }; 537 + 538 + /* 539 + * SW2/3/4/5 0.3V to 3.3V 540 + * 0.45V to 1.35V (6.25mV step) 541 + * 1.8V to 2.5V (125mV step) 542 + * 2.8V to 3.3V (250mV step) 543 + */ 544 + static const struct linear_range pf0900_dvs_sw2345_volts[] = { 545 + REGULATOR_LINEAR_RANGE(300000, 0x00, 0x00, 0), 546 + REGULATOR_LINEAR_RANGE(450000, 0x01, 0x91, 6250), 547 + REGULATOR_LINEAR_RANGE(0, 0x92, 0x9E, 0), 548 + REGULATOR_LINEAR_RANGE(1500000, 0x9F, 0x9F, 0), 549 + REGULATOR_LINEAR_RANGE(1800000, 0xA0, 0xD8, 12500), 550 + REGULATOR_LINEAR_RANGE(0, 0xD9, 0xDF, 0), 551 + REGULATOR_LINEAR_RANGE(2800000, 0xE0, 0xF4, 25000), 552 + REGULATOR_LINEAR_RANGE(0, 0xF5, 0xFF, 0), 553 + }; 554 + 555 + /* 556 + * LDO1 557 + * 0.75V to 3.3V 558 + */ 559 + static const struct linear_range pf0900_ldo1_volts[] = { 560 + REGULATOR_LINEAR_RANGE(750000, 0x00, 0x0F, 50000), 561 + REGULATOR_LINEAR_RANGE(1800000, 0x10, 0x1F, 100000), 562 + }; 563 + 564 + /* 565 + * LDO2/3 566 + * 0.65V to 3.3V (50mV step) 567 + */ 568 + static const struct linear_range pf0900_ldo23_volts[] = { 569 + REGULATOR_LINEAR_RANGE(650000, 0x00, 0x0D, 50000), 570 + REGULATOR_LINEAR_RANGE(1400000, 0x0E, 0x0F, 100000), 571 + REGULATOR_LINEAR_RANGE(1800000, 0x10, 0x1F, 100000), 572 + }; 573 + 574 + static const struct pf0900_regulator_desc pf0900_regulators[] = { 575 + { 576 + .desc = { 577 + .name = "sw1", 578 + .of_match = of_match_ptr("sw1"), 579 + .regulators_node = of_match_ptr("regulators"), 580 + .id = PF0900_SW1, 581 + .ops = &pf0900_dvs_sw_regulator_ops, 582 + .type = REGULATOR_VOLTAGE, 583 + .n_voltages = PF0900_SW_VOLTAGE_NUM, 584 + .linear_ranges = pf0900_dvs_sw1_volts, 585 + .n_linear_ranges = ARRAY_SIZE(pf0900_dvs_sw1_volts), 586 + .vsel_reg = PF0900_REG_SW1_VRUN, 587 + .vsel_mask = PF0900_SW_VOL_MASK, 588 + .enable_reg = PF0900_REG_SW1_MODE, 589 + .enable_mask = SW_RUN_MODE_MASK, 590 + .enable_val = SW_RUN_MODE_PWM, 591 + .ramp_reg = PF0900_REG_SW1_CFG1, 592 + .ramp_mask = PF0900_SW_DVS_MASK, 593 + .ramp_delay_table = pf0900_dvs_sw_ramp_table, 594 + .n_ramp_values = ARRAY_SIZE(pf0900_dvs_sw_ramp_table), 595 + .owner = THIS_MODULE, 596 + }, 597 + .suspend_enable_mask = SW_STBY_MODE_MASK, 598 + .suspend_voltage_reg = PF0900_REG_SW1_VSTBY, 599 + }, 600 + { 601 + .desc = { 602 + .name = "sw2", 603 + .of_match = of_match_ptr("sw2"), 604 + .regulators_node = of_match_ptr("regulators"), 605 + .id = PF0900_SW2, 606 + .ops = &pf0900_dvs_sw_regulator_ops, 607 + .type = REGULATOR_VOLTAGE, 608 + .n_voltages = PF0900_SW_VOLTAGE_NUM, 609 + .linear_ranges = pf0900_dvs_sw2345_volts, 610 + .n_linear_ranges = ARRAY_SIZE(pf0900_dvs_sw2345_volts), 611 + .vsel_reg = PF0900_REG_SW2_VRUN, 612 + .vsel_mask = PF0900_SW_VOL_MASK, 613 + .enable_reg = PF0900_REG_SW2_MODE, 614 + .enable_mask = SW_RUN_MODE_MASK, 615 + .enable_val = SW_RUN_MODE_PWM, 616 + .ramp_reg = PF0900_REG_SW2_CFG1, 617 + .ramp_mask = PF0900_SW_DVS_MASK, 618 + .ramp_delay_table = pf0900_dvs_sw_ramp_table, 619 + .n_ramp_values = ARRAY_SIZE(pf0900_dvs_sw_ramp_table), 620 + .owner = THIS_MODULE, 621 + }, 622 + .suspend_enable_mask = SW_STBY_MODE_MASK, 623 + .suspend_voltage_reg = PF0900_REG_SW2_VSTBY, 624 + }, 625 + { 626 + .desc = { 627 + .name = "sw3", 628 + .of_match = of_match_ptr("sw3"), 629 + .regulators_node = of_match_ptr("regulators"), 630 + .id = PF0900_SW3, 631 + .ops = &pf0900_dvs_sw_regulator_ops, 632 + .type = REGULATOR_VOLTAGE, 633 + .n_voltages = PF0900_SW_VOLTAGE_NUM, 634 + .linear_ranges = pf0900_dvs_sw2345_volts, 635 + .n_linear_ranges = ARRAY_SIZE(pf0900_dvs_sw2345_volts), 636 + .vsel_reg = PF0900_REG_SW3_VRUN, 637 + .vsel_mask = PF0900_SW_VOL_MASK, 638 + .enable_reg = PF0900_REG_SW3_MODE, 639 + .enable_mask = SW_RUN_MODE_MASK, 640 + .enable_val = SW_RUN_MODE_PWM, 641 + .ramp_reg = PF0900_REG_SW3_CFG1, 642 + .ramp_mask = PF0900_SW_DVS_MASK, 643 + .ramp_delay_table = pf0900_dvs_sw_ramp_table, 644 + .n_ramp_values = ARRAY_SIZE(pf0900_dvs_sw_ramp_table), 645 + .owner = THIS_MODULE, 646 + }, 647 + .suspend_enable_mask = SW_STBY_MODE_MASK, 648 + .suspend_voltage_reg = PF0900_REG_SW3_VSTBY, 649 + }, 650 + { 651 + .desc = { 652 + .name = "sw4", 653 + .of_match = of_match_ptr("sw4"), 654 + .regulators_node = of_match_ptr("regulators"), 655 + .id = PF0900_SW4, 656 + .ops = &pf0900_dvs_sw_regulator_ops, 657 + .type = REGULATOR_VOLTAGE, 658 + .n_voltages = PF0900_SW_VOLTAGE_NUM, 659 + .linear_ranges = pf0900_dvs_sw2345_volts, 660 + .n_linear_ranges = ARRAY_SIZE(pf0900_dvs_sw2345_volts), 661 + .vsel_reg = PF0900_REG_SW4_VRUN, 662 + .vsel_mask = PF0900_SW_VOL_MASK, 663 + .enable_reg = PF0900_REG_SW4_MODE, 664 + .enable_mask = SW_RUN_MODE_MASK, 665 + .enable_val = SW_RUN_MODE_PWM, 666 + .ramp_reg = PF0900_REG_SW4_CFG1, 667 + .ramp_mask = PF0900_SW_DVS_MASK, 668 + .ramp_delay_table = pf0900_dvs_sw_ramp_table, 669 + .n_ramp_values = ARRAY_SIZE(pf0900_dvs_sw_ramp_table), 670 + .owner = THIS_MODULE, 671 + }, 672 + .suspend_enable_mask = SW_STBY_MODE_MASK, 673 + .suspend_voltage_reg = PF0900_REG_SW4_VSTBY, 674 + }, 675 + { 676 + .desc = { 677 + .name = "sw5", 678 + .of_match = of_match_ptr("sw5"), 679 + .regulators_node = of_match_ptr("regulators"), 680 + .id = PF0900_SW5, 681 + .ops = &pf0900_dvs_sw_regulator_ops, 682 + .type = REGULATOR_VOLTAGE, 683 + .n_voltages = PF0900_SW_VOLTAGE_NUM, 684 + .linear_ranges = pf0900_dvs_sw2345_volts, 685 + .n_linear_ranges = ARRAY_SIZE(pf0900_dvs_sw2345_volts), 686 + .vsel_reg = PF0900_REG_SW5_VRUN, 687 + .vsel_mask = PF0900_SW_VOL_MASK, 688 + .enable_reg = PF0900_REG_SW5_MODE, 689 + .enable_mask = SW_RUN_MODE_MASK, 690 + .enable_val = SW_RUN_MODE_PWM, 691 + .ramp_reg = PF0900_REG_SW5_CFG1, 692 + .ramp_mask = PF0900_SW_DVS_MASK, 693 + .ramp_delay_table = pf0900_dvs_sw_ramp_table, 694 + .n_ramp_values = ARRAY_SIZE(pf0900_dvs_sw_ramp_table), 695 + .owner = THIS_MODULE, 696 + }, 697 + .suspend_enable_mask = SW_STBY_MODE_MASK, 698 + .suspend_voltage_reg = PF0900_REG_SW5_VSTBY, 699 + }, 700 + { 701 + .desc = { 702 + .name = "ldo1", 703 + .of_match = of_match_ptr("ldo1"), 704 + .regulators_node = of_match_ptr("regulators"), 705 + .id = PF0900_LDO1, 706 + .ops = &pf0900_ldo_regulator_ops, 707 + .type = REGULATOR_VOLTAGE, 708 + .n_voltages = PF0900_LDO_VOLTAGE_NUM, 709 + .linear_ranges = pf0900_ldo1_volts, 710 + .n_linear_ranges = ARRAY_SIZE(pf0900_ldo1_volts), 711 + .vsel_reg = PF0900_REG_LDO1_RUN, 712 + .vsel_mask = VLDO_RUN_MASK, 713 + .enable_reg = PF0900_REG_LDO1_RUN, 714 + .enable_mask = LDO_RUN_EN_MASK, 715 + .owner = THIS_MODULE, 716 + }, 717 + }, 718 + { 719 + .desc = { 720 + .name = "ldo2", 721 + .of_match = of_match_ptr("ldo2"), 722 + .regulators_node = of_match_ptr("regulators"), 723 + .id = PF0900_LDO2, 724 + .ops = &pf0900_ldo_regulator_ops, 725 + .type = REGULATOR_VOLTAGE, 726 + .n_voltages = PF0900_LDO_VOLTAGE_NUM, 727 + .linear_ranges = pf0900_ldo23_volts, 728 + .n_linear_ranges = ARRAY_SIZE(pf0900_ldo23_volts), 729 + .vsel_reg = PF0900_REG_LDO2_RUN, 730 + .vsel_mask = VLDO_RUN_MASK, 731 + .enable_reg = PF0900_REG_LDO2_RUN, 732 + .enable_mask = LDO_RUN_EN_MASK, 733 + .owner = THIS_MODULE, 734 + }, 735 + }, 736 + { 737 + .desc = { 738 + .name = "ldo3", 739 + .of_match = of_match_ptr("ldo3"), 740 + .regulators_node = of_match_ptr("regulators"), 741 + .id = PF0900_LDO3, 742 + .ops = &pf0900_ldo_regulator_ops, 743 + .type = REGULATOR_VOLTAGE, 744 + .n_voltages = PF0900_LDO_VOLTAGE_NUM, 745 + .linear_ranges = pf0900_ldo23_volts, 746 + .n_linear_ranges = ARRAY_SIZE(pf0900_ldo23_volts), 747 + .vsel_reg = PF0900_REG_LDO3_RUN, 748 + .vsel_mask = VLDO_RUN_MASK, 749 + .enable_reg = PF0900_REG_LDO3_RUN, 750 + .enable_mask = LDO_RUN_EN_MASK, 751 + .owner = THIS_MODULE, 752 + }, 753 + }, 754 + { 755 + .desc = { 756 + .name = "vaon", 757 + .of_match = of_match_ptr("vaon"), 758 + .regulators_node = of_match_ptr("regulators"), 759 + .id = PF0900_VAON, 760 + .ops = &pf0900_avon_regulator_ops, 761 + .type = REGULATOR_VOLTAGE, 762 + .n_voltages = PF0900_VAON_VOLTAGE_NUM, 763 + .volt_table = pf0900_vaon_voltages, 764 + .enable_reg = PF0900_REG_VAON_CFG1, 765 + .enable_mask = PF0900_VAON_MASK, 766 + .enable_val = PF0900_VAON_1P8V, 767 + .vsel_reg = PF0900_REG_VAON_CFG1, 768 + .vsel_mask = PF0900_VAON_MASK, 769 + .owner = THIS_MODULE, 770 + }, 771 + }, 772 + }; 773 + 774 + struct pf0900_regulator_irq regu_irqs[] = { 775 + PF0900_REGU_IRQ(PF0900_REG_SW_ILIM_INT, PF0900_SW, REGULATOR_ERROR_OVER_CURRENT_WARN), 776 + PF0900_REGU_IRQ(PF0900_REG_LDO_ILIM_INT, PF0900_LDO, REGULATOR_ERROR_OVER_CURRENT_WARN), 777 + PF0900_REGU_IRQ(PF0900_REG_SW_UV_INT, PF0900_SW, REGULATOR_ERROR_UNDER_VOLTAGE_WARN), 778 + PF0900_REGU_IRQ(PF0900_REG_LDO_UV_INT, PF0900_LDO, REGULATOR_ERROR_UNDER_VOLTAGE_WARN), 779 + PF0900_REGU_IRQ(PF0900_REG_SW_OV_INT, PF0900_SW, REGULATOR_ERROR_OVER_VOLTAGE_WARN), 780 + PF0900_REGU_IRQ(PF0900_REG_LDO_OV_INT, PF0900_LDO, REGULATOR_ERROR_OVER_VOLTAGE_WARN), 781 + }; 782 + 783 + static irqreturn_t pf0900_irq_handler(int irq, void *data) 784 + { 785 + unsigned int val, regu, i, index; 786 + struct pf0900 *pf0900 = data; 787 + int ret; 788 + 789 + for (i = 0; i < ARRAY_SIZE(regu_irqs); i++) { 790 + ret = regmap_read(pf0900->regmap, regu_irqs[i].reg, &val); 791 + if (ret < 0) { 792 + dev_err(pf0900->dev, "Failed to read %d\n", ret); 793 + return IRQ_NONE; 794 + } 795 + if (val) { 796 + ret = regmap_write_bits(pf0900->regmap, regu_irqs[i].reg, val, val); 797 + if (ret < 0) { 798 + dev_err(pf0900->dev, "Failed to update %d\n", ret); 799 + return IRQ_NONE; 800 + } 801 + 802 + if (regu_irqs[i].type == PF0900_SW) { 803 + for (index = 0; index < REGU_SW_CNT; index++) { 804 + if (val & BIT(index)) { 805 + regu = (enum pf0900_regulators)index; 806 + regulator_notifier_call_chain(pf0900->rdevs[regu], 807 + regu_irqs[i].event, 808 + NULL); 809 + } 810 + } 811 + } else if (regu_irqs[i].type == PF0900_LDO) { 812 + for (index = 0; index < REGU_LDO_VAON_CNT; index++) { 813 + if (val & BIT(index)) { 814 + regu = (enum pf0900_regulators)index + PF0900_LDO1; 815 + regulator_notifier_call_chain(pf0900->rdevs[regu], 816 + regu_irqs[i].event, 817 + NULL); 818 + } 819 + } 820 + } 821 + } 822 + } 823 + 824 + return IRQ_HANDLED; 825 + } 826 + 827 + static int pf0900_i2c_probe(struct i2c_client *i2c) 828 + { 829 + const struct pf0900_regulator_desc *regulator_desc; 830 + const struct pf0900_drvdata *drvdata = NULL; 831 + struct device_node *np = i2c->dev.of_node; 832 + unsigned int device_id, device_fam, i; 833 + struct regulator_config config = { }; 834 + struct pf0900 *pf0900; 835 + int ret; 836 + 837 + if (!i2c->irq) 838 + return dev_err_probe(&i2c->dev, -EINVAL, "No IRQ configured?\n"); 839 + 840 + pf0900 = devm_kzalloc(&i2c->dev, sizeof(struct pf0900), GFP_KERNEL); 841 + if (!pf0900) 842 + return -ENOMEM; 843 + 844 + drvdata = device_get_match_data(&i2c->dev); 845 + if (!drvdata) 846 + return dev_err_probe(&i2c->dev, -EINVAL, "unable to find driver data\n"); 847 + 848 + regulator_desc = drvdata->desc; 849 + pf0900->drvdata = drvdata; 850 + pf0900->crc_en = of_property_read_bool(np, "nxp,i2c-crc-enable"); 851 + pf0900->irq = i2c->irq; 852 + pf0900->dev = &i2c->dev; 853 + pf0900->addr = i2c->addr; 854 + 855 + dev_set_drvdata(&i2c->dev, pf0900); 856 + 857 + pf0900->regmap = devm_regmap_init(&i2c->dev, &pf0900_regmap_bus, &i2c->dev, 858 + &pf0900_regmap_config); 859 + if (IS_ERR(pf0900->regmap)) 860 + return dev_err_probe(&i2c->dev, PTR_ERR(pf0900->regmap), 861 + "regmap initialization failed\n"); 862 + ret = regmap_read(pf0900->regmap, PF0900_REG_DEV_ID, &device_id); 863 + if (ret) 864 + return dev_err_probe(&i2c->dev, ret, "Read device id error\n"); 865 + 866 + ret = regmap_read(pf0900->regmap, PF0900_REG_DEV_FAM, &device_fam); 867 + if (ret) 868 + return dev_err_probe(&i2c->dev, ret, "Read device fam error\n"); 869 + 870 + /* Check your board and dts for match the right pmic */ 871 + if (device_fam == 0x09 && (device_id & 0x1F) != 0x0) 872 + return dev_err_probe(&i2c->dev, -EINVAL, "Device id(%x) mismatched\n", 873 + device_id >> 4); 874 + 875 + for (i = 0; i < drvdata->rcnt; i++) { 876 + const struct regulator_desc *desc; 877 + const struct pf0900_regulator_desc *r; 878 + 879 + r = &regulator_desc[i]; 880 + desc = &r->desc; 881 + config.regmap = pf0900->regmap; 882 + config.driver_data = (void *)r; 883 + config.dev = pf0900->dev; 884 + 885 + pf0900->rdevs[i] = devm_regulator_register(pf0900->dev, desc, &config); 886 + if (IS_ERR(pf0900->rdevs[i])) 887 + return dev_err_probe(pf0900->dev, PTR_ERR(pf0900->rdevs[i]), 888 + "Failed to register regulator(%s)\n", desc->name); 889 + } 890 + 891 + ret = devm_request_threaded_irq(pf0900->dev, pf0900->irq, NULL, 892 + pf0900_irq_handler, 893 + (IRQF_TRIGGER_FALLING | IRQF_ONESHOT), 894 + "pf0900-irq", pf0900); 895 + 896 + if (ret != 0) 897 + return dev_err_probe(pf0900->dev, ret, "Failed to request IRQ: %d\n", 898 + pf0900->irq); 899 + /* 900 + * The PWRUP_M is unmasked by default. When the device enter in RUN state, 901 + * it will assert the PWRUP_I interrupt and assert the INTB pin to inform 902 + * the MCU that it has finished the power up sequence properly. 903 + */ 904 + ret = regmap_write_bits(pf0900->regmap, PF0900_REG_STATUS1_INT, PF0900_IRQ_PWRUP, 905 + PF0900_IRQ_PWRUP); 906 + if (ret) 907 + return dev_err_probe(&i2c->dev, ret, "Clean PWRUP_I error\n"); 908 + 909 + /* mask interrupt PWRUP */ 910 + ret = regmap_update_bits(pf0900->regmap, PF0900_REG_STATUS1_MSK, PF0900_IRQ_PWRUP, 911 + PF0900_IRQ_PWRUP); 912 + if (ret) 913 + return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n"); 914 + 915 + ret = regmap_update_bits(pf0900->regmap, PF0900_REG_SW_ILIM_MSK, PF0900_IRQ_SW1_IL | 916 + PF0900_IRQ_SW2_IL | PF0900_IRQ_SW3_IL | PF0900_IRQ_SW4_IL | 917 + PF0900_IRQ_SW5_IL, 0); 918 + if (ret) 919 + return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n"); 920 + 921 + ret = regmap_update_bits(pf0900->regmap, PF0900_REG_SW_UV_MSK, PF0900_IRQ_SW1_UV | 922 + PF0900_IRQ_SW2_UV | PF0900_IRQ_SW3_UV | PF0900_IRQ_SW4_UV | 923 + PF0900_IRQ_SW5_UV, 0); 924 + if (ret) 925 + return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n"); 926 + 927 + ret = regmap_update_bits(pf0900->regmap, PF0900_REG_SW_OV_MSK, PF0900_IRQ_SW1_OV | 928 + PF0900_IRQ_SW2_OV | PF0900_IRQ_SW3_OV | PF0900_IRQ_SW4_OV | 929 + PF0900_IRQ_SW5_OV, 0); 930 + if (ret) 931 + return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n"); 932 + 933 + ret = regmap_update_bits(pf0900->regmap, PF0900_REG_LDO_ILIM_MSK, PF0900_IRQ_LDO1_IL | 934 + PF0900_IRQ_LDO2_IL | PF0900_IRQ_LDO3_IL, 0); 935 + if (ret) 936 + return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n"); 937 + 938 + ret = regmap_update_bits(pf0900->regmap, PF0900_REG_LDO_UV_MSK, PF0900_IRQ_LDO1_UV | 939 + PF0900_IRQ_LDO2_UV | PF0900_IRQ_LDO3_UV | PF0900_IRQ_VAON_UV, 0); 940 + if (ret) 941 + return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n"); 942 + 943 + ret = regmap_update_bits(pf0900->regmap, PF0900_REG_LDO_OV_MSK, PF0900_IRQ_LDO1_OV | 944 + PF0900_IRQ_LDO2_OV | PF0900_IRQ_LDO3_OV | PF0900_IRQ_VAON_OV, 0); 945 + if (ret) 946 + return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n"); 947 + 948 + return 0; 949 + } 950 + 951 + static struct pf0900_drvdata pf0900_drvdata = { 952 + .desc = pf0900_regulators, 953 + .rcnt = ARRAY_SIZE(pf0900_regulators), 954 + }; 955 + 956 + static const struct of_device_id pf0900_of_match[] = { 957 + { .compatible = "nxp,pf0900", .data = &pf0900_drvdata}, 958 + { } 959 + }; 960 + 961 + MODULE_DEVICE_TABLE(of, pf0900_of_match); 962 + 963 + static struct i2c_driver pf0900_i2c_driver = { 964 + .driver = { 965 + .name = "nxp-pf0900", 966 + .of_match_table = pf0900_of_match, 967 + }, 968 + .probe = pf0900_i2c_probe, 969 + }; 970 + 971 + module_i2c_driver(pf0900_i2c_driver); 972 + 973 + MODULE_AUTHOR("Joy Zou <joy.zou@nxp.com>"); 974 + MODULE_DESCRIPTION("NXP PF0900 Power Management IC driver"); 975 + MODULE_LICENSE("GPL");
+375
drivers/regulator/pf530x-regulator.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + 3 + // documentation of this device is available at 4 + // https://www.nxp.com/docs/en/data-sheet/PF5300.pdf 5 + 6 + #include <linux/delay.h> 7 + #include <linux/err.h> 8 + #include <linux/gpio/consumer.h> 9 + #include <linux/i2c.h> 10 + #include <linux/module.h> 11 + #include <linux/regmap.h> 12 + #include <linux/regulator/driver.h> 13 + #include <linux/regulator/consumer.h> 14 + #include <linux/regulator/machine.h> 15 + #include <linux/regulator/of_regulator.h> 16 + 17 + /* registers */ 18 + #define PF530X_DEVICEID 0x00 19 + #define PF530X_REV 0x01 20 + #define PF530X_EMREV 0x02 21 + #define PF530X_PROGID 0x03 22 + #define PF530X_CONFIG1 0x04 23 + #define PF530X_INT_STATUS1 0x05 24 + #define PF530X_INT_SENSE1 0x06 25 + #define PF530X_INT_STATUS2 0x07 26 + #define PF530X_INT_SENSE2 0x08 27 + #define PF530X_BIST_STAT1 0x09 28 + #define PF530X_BIST_CTRL 0x0a 29 + #define PF530X_STATE 0x0b 30 + #define PF530X_STATE_CTRL 0x0c 31 + #define PF530X_SW1_VOLT 0x0d 32 + #define PF530X_SW1_STBY_VOLT 0x0e 33 + #define PF530X_SW1_CTRL1 0x0f 34 + #define PF530X_SW1_CTRL2 0x10 35 + #define PF530X_CLK_CTRL 0x11 36 + #define PF530X_SEQ_CTRL1 0x12 37 + #define PF530X_SEQ_CTRL2 0x13 38 + #define PF530X_RANDOM_CHK 0x14 39 + #define PF530X_RANDOM_GEN 0x15 40 + #define PF530X_WD_CTRL1 0x16 41 + #define PF530X_WD_SEED 0x17 42 + #define PF530X_WD_ANSWER 0x18 43 + #define PF530X_FLT_CNT1 0x19 44 + #define PF530X_FLT_CNT2 0x1a 45 + #define PF530X_OTP_MODE 0x2f 46 + 47 + enum pf530x_states { 48 + PF530X_STATE_POF, 49 + PF530X_STATE_FUSE_LOAD, 50 + PF530X_STATE_LP_OFF, 51 + PF530X_STATE_SELF_TEST, 52 + PF530X_STATE_POWER_UP, 53 + PF530X_STATE_INIT, 54 + PF530X_STATE_IO_RELEASE, 55 + PF530X_STATE_RUN, 56 + PF530X_STATE_STANDBY, 57 + PF530X_STATE_FAULT, 58 + PF530X_STATE_FAILSAFE, 59 + PF530X_STATE_POWER_DOWN, 60 + PF530X_STATE_2MS_SELFTEST_RETRY, 61 + PF530X_STATE_OFF_DLY, 62 + }; 63 + 64 + #define PF530_FAM 0x50 65 + enum pf530x_devid { 66 + PF5300 = 0x3, 67 + PF5301 = 0x4, 68 + PF5302 = 0x5, 69 + }; 70 + 71 + #define PF530x_FAM 0x50 72 + #define PF530x_DEVICE_FAM_MASK GENMASK(7, 4) 73 + #define PF530x_DEVICE_ID_MASK GENMASK(3, 0) 74 + 75 + #define PF530x_STATE_MASK GENMASK(3, 0) 76 + #define PF530x_STATE_RUN 0x07 77 + #define PF530x_STATE_STANDBY 0x08 78 + #define PF530x_STATE_LP_OFF 0x02 79 + 80 + #define PF530X_OTP_STBY_MODE GENMASK(3, 2) 81 + #define PF530X_OTP_RUN_MODE GENMASK(1, 0) 82 + 83 + #define PF530X_INT_STATUS_OV BIT(1) 84 + #define PF530X_INT_STATUS_UV BIT(2) 85 + #define PF530X_INT_STATUS_ILIM BIT(3) 86 + 87 + #define SW1_ILIM_S BIT(0) 88 + #define VMON_UV_S BIT(1) 89 + #define VMON_OV_S BIT(2) 90 + #define VIN_OVLO_S BIT(3) 91 + #define BG_ERR_S BIT(6) 92 + 93 + #define THERM_155_S BIT(3) 94 + #define THERM_140_S BIT(2) 95 + #define THERM_125_S BIT(1) 96 + #define THERM_110_S BIT(0) 97 + 98 + struct pf530x_chip { 99 + struct regmap *regmap; 100 + struct device *dev; 101 + }; 102 + 103 + static const struct regmap_config pf530x_regmap_config = { 104 + .reg_bits = 8, 105 + .val_bits = 8, 106 + .max_register = PF530X_OTP_MODE, 107 + .cache_type = REGCACHE_MAPLE, 108 + }; 109 + 110 + static int pf530x_get_status(struct regulator_dev *rdev) 111 + { 112 + unsigned int state; 113 + int ret; 114 + 115 + ret = regmap_read(rdev->regmap, PF530X_INT_SENSE1, &state); 116 + if (ret != 0) 117 + return ret; 118 + 119 + if ((state & (BG_ERR_S | SW1_ILIM_S | VMON_UV_S | VMON_OV_S | VIN_OVLO_S)) 120 + != 0) 121 + return REGULATOR_STATUS_ERROR; 122 + 123 + // no errors, check if what non-error state we're in 124 + ret = regmap_read(rdev->regmap, PF530X_STATE, &state); 125 + if (ret != 0) 126 + return ret; 127 + 128 + state &= PF530x_STATE_MASK; 129 + 130 + switch (state) { 131 + case PF530x_STATE_RUN: 132 + ret = REGULATOR_STATUS_NORMAL; 133 + break; 134 + case PF530x_STATE_STANDBY: 135 + ret = REGULATOR_STATUS_STANDBY; 136 + break; 137 + case PF530x_STATE_LP_OFF: 138 + ret = REGULATOR_STATUS_OFF; 139 + break; 140 + default: 141 + ret = REGULATOR_STATUS_ERROR; 142 + break; 143 + } 144 + return ret; 145 + } 146 + 147 + static int pf530x_get_error_flags(struct regulator_dev *rdev, unsigned int *flags) 148 + { 149 + unsigned int status; 150 + int ret; 151 + 152 + ret = regmap_read(rdev->regmap, PF530X_INT_STATUS1, &status); 153 + 154 + if (ret != 0) 155 + return ret; 156 + 157 + *flags = 0; 158 + 159 + if (status & PF530X_INT_STATUS_OV) 160 + *flags |= REGULATOR_ERROR_OVER_VOLTAGE_WARN; 161 + 162 + if (status & PF530X_INT_STATUS_UV) 163 + *flags |= REGULATOR_ERROR_UNDER_VOLTAGE; 164 + 165 + if (status & PF530X_INT_STATUS_ILIM) 166 + *flags |= REGULATOR_ERROR_OVER_CURRENT; 167 + 168 + ret = regmap_read(rdev->regmap, PF530X_INT_SENSE2, &status); 169 + 170 + if (ret != 0) 171 + return ret; 172 + 173 + if ((status & (THERM_155_S | 174 + THERM_140_S | 175 + THERM_125_S | 176 + THERM_110_S)) != 0) 177 + *flags |= REGULATOR_ERROR_OVER_TEMP_WARN; 178 + 179 + return 0; 180 + } 181 + 182 + static const struct regulator_ops pf530x_regulator_ops = { 183 + .enable = regulator_enable_regmap, 184 + .disable = regulator_disable_regmap, 185 + .is_enabled = regulator_is_enabled_regmap, 186 + .map_voltage = regulator_map_voltage_linear_range, 187 + .list_voltage = regulator_list_voltage_linear_range, 188 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 189 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 190 + .get_status = pf530x_get_status, 191 + .get_error_flags = pf530x_get_error_flags, 192 + .set_bypass = regulator_set_bypass_regmap, 193 + .get_bypass = regulator_get_bypass_regmap, 194 + }; 195 + 196 + static const struct linear_range vrange = REGULATOR_LINEAR_RANGE(500000, 0, 140, 5000); 197 + 198 + static const struct regulator_desc pf530x_reg_desc = { 199 + .name = "SW1", 200 + .ops = &pf530x_regulator_ops, 201 + .linear_ranges = &vrange, 202 + .n_linear_ranges = 1, 203 + .type = REGULATOR_VOLTAGE, 204 + .id = 0, 205 + .owner = THIS_MODULE, 206 + .vsel_reg = PF530X_SW1_VOLT, 207 + .vsel_mask = 0xFF, 208 + .bypass_reg = PF530X_SW1_CTRL2, 209 + .bypass_mask = 0x07, 210 + .bypass_val_on = 0x07, 211 + .bypass_val_off = 0x00, 212 + .enable_reg = PF530X_SW1_CTRL1, 213 + .enable_mask = GENMASK(5, 2), 214 + .enable_val = GENMASK(5, 2), 215 + .disable_val = 0, 216 + }; 217 + 218 + static int pf530x_identify(struct pf530x_chip *chip) 219 + { 220 + unsigned int value; 221 + u8 dev_fam, dev_id, full_layer_rev, metal_layer_rev, prog_idh, prog_idl, emrev; 222 + const char *name = NULL; 223 + int ret; 224 + 225 + ret = regmap_read(chip->regmap, PF530X_DEVICEID, &value); 226 + if (ret) { 227 + dev_err(chip->dev, "failed to read chip family\n"); 228 + return ret; 229 + } 230 + 231 + dev_fam = value & PF530x_DEVICE_FAM_MASK; 232 + switch (dev_fam) { 233 + case PF530x_FAM: 234 + break; 235 + default: 236 + dev_err(chip->dev, 237 + "Chip 0x%x is not from PF530X family\n", dev_fam); 238 + return ret; 239 + } 240 + 241 + dev_id = value & PF530x_DEVICE_ID_MASK; 242 + switch (dev_id) { 243 + case PF5300: 244 + name = "PF5300"; 245 + break; 246 + case PF5301: 247 + name = "PF5301"; 248 + break; 249 + case PF5302: 250 + name = "PF5302"; 251 + break; 252 + default: 253 + dev_err(chip->dev, "Unknown pf530x device id 0x%x\n", dev_id); 254 + return -ENODEV; 255 + } 256 + 257 + ret = regmap_read(chip->regmap, PF530X_REV, &value); 258 + if (ret) { 259 + dev_err(chip->dev, "failed to read chip rev\n"); 260 + return ret; 261 + } 262 + 263 + full_layer_rev = ((value & 0xF0) == 0) ? '0' : ((((value & 0xF0) >> 4) - 1) + 'A'); 264 + metal_layer_rev = value & 0xF; 265 + 266 + ret = regmap_read(chip->regmap, PF530X_EMREV, &value); 267 + if (ret) { 268 + dev_err(chip->dev, "failed to read chip emrev register\n"); 269 + return ret; 270 + } 271 + 272 + prog_idh = (value >> 4) + 'A'; 273 + // prog_idh skips 'O', per page 96 of the datasheet 274 + if (prog_idh >= 'O') 275 + prog_idh += 1; 276 + 277 + emrev = value & 0x7; 278 + 279 + ret = regmap_read(chip->regmap, PF530X_PROGID, &value); 280 + if (ret) { 281 + dev_err(chip->dev, "failed to read chip progid register\n"); 282 + return ret; 283 + } 284 + 285 + if (value >= 0x22) { 286 + dev_err(chip->dev, "invalid value for progid register\n"); 287 + return -ENODEV; 288 + } else if (value < 10) { 289 + prog_idl = value + '0'; 290 + } else { 291 + prog_idl = (value - 10) + 'A'; 292 + // prog_idh skips 'O', per page 97 of the datasheet 293 + if (prog_idl >= 'O') 294 + prog_idl += 1; 295 + } 296 + 297 + dev_info(chip->dev, "%s Regulator found (Rev %c%d ProgID %c%c EMREV %x).\n", 298 + name, full_layer_rev, metal_layer_rev, prog_idh, prog_idl, emrev); 299 + 300 + return 0; 301 + } 302 + 303 + static int pf530x_i2c_probe(struct i2c_client *client) 304 + { 305 + struct regulator_config config = { NULL, }; 306 + struct pf530x_chip *chip; 307 + int ret; 308 + struct regulator_dev *rdev; 309 + struct regulator_init_data *init_data; 310 + 311 + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); 312 + if (!chip) 313 + return -ENOMEM; 314 + 315 + i2c_set_clientdata(client, chip); 316 + chip->dev = &client->dev; 317 + 318 + chip->regmap = devm_regmap_init_i2c(client, &pf530x_regmap_config); 319 + if (IS_ERR(chip->regmap)) { 320 + ret = PTR_ERR(chip->regmap); 321 + dev_err(&client->dev, 322 + "regmap allocation failed with err %d\n", ret); 323 + return ret; 324 + } 325 + 326 + ret = pf530x_identify(chip); 327 + if (ret) 328 + return ret; 329 + 330 + init_data = of_get_regulator_init_data(chip->dev, chip->dev->of_node, &pf530x_reg_desc); 331 + if (!init_data) 332 + return -ENODATA; 333 + 334 + config.dev = chip->dev; 335 + config.of_node = chip->dev->of_node; 336 + config.regmap = chip->regmap; 337 + config.init_data = init_data; 338 + 339 + // the config parameter gets copied, it's ok to pass a pointer on the stack here 340 + rdev = devm_regulator_register(&client->dev, &pf530x_reg_desc, &config); 341 + if (IS_ERR(rdev)) { 342 + dev_err(&client->dev, "failed to register %s regulator\n", pf530x_reg_desc.name); 343 + return PTR_ERR(rdev); 344 + } 345 + 346 + return 0; 347 + } 348 + 349 + static const struct of_device_id pf530x_dt_ids[] = { 350 + { .compatible = "nxp,pf5300",}, 351 + { } 352 + }; 353 + MODULE_DEVICE_TABLE(of, pf530x_dt_ids); 354 + 355 + static const struct i2c_device_id pf530x_i2c_id[] = { 356 + { "pf5300", 0 }, 357 + { "pf5301", 0 }, 358 + { "pf5302", 0 }, 359 + {}, 360 + }; 361 + MODULE_DEVICE_TABLE(i2c, pf530x_i2c_id); 362 + 363 + static struct i2c_driver pf530x_regulator_driver = { 364 + .id_table = pf530x_i2c_id, 365 + .driver = { 366 + .name = "pf530x", 367 + .of_match_table = pf530x_dt_ids, 368 + }, 369 + .probe = pf530x_i2c_probe, 370 + }; 371 + module_i2c_driver(pf530x_regulator_driver); 372 + 373 + MODULE_AUTHOR("Woodrow Douglass <wdouglass@carnegierobotics.com>"); 374 + MODULE_DESCRIPTION("Regulator Driver for NXP's PF5300/PF5301/PF5302 PMIC"); 375 + MODULE_LICENSE("GPL");
-1
drivers/regulator/qcom-refgen-regulator.c
··· 94 94 .reg_bits = 32, 95 95 .reg_stride = 4, 96 96 .val_bits = 32, 97 - .fast_io = true, 98 97 }; 99 98 100 99 static int qcom_refgen_probe(struct platform_device *pdev)
+642
drivers/regulator/rt5133-regulator.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2025 Richtek Technology Corp. 3 + // Author: ChiYuan Huang <cy_huang@richtek.com> 4 + // Author: ShihChia Chang <jeff_chang@richtek.com> 5 + 6 + #include <linux/crc8.h> 7 + #include <linux/delay.h> 8 + #include <linux/gpio/consumer.h> 9 + #include <linux/gpio/driver.h> 10 + #include <linux/i2c.h> 11 + #include <linux/interrupt.h> 12 + #include <linux/kernel.h> 13 + #include <linux/module.h> 14 + #include <linux/of.h> 15 + #include <linux/regmap.h> 16 + #include <linux/regulator/driver.h> 17 + 18 + #define RT5133_REG_CHIP_INFO 0x00 19 + #define RT5133_REG_RST_CTRL 0x06 20 + #define RT5133_REG_BASE_CTRL 0x09 21 + #define RT5133_REG_GPIO_CTRL 0x0B 22 + #define RT5133_REG_BASE_EVT 0x10 23 + #define RT5133_REG_LDO_PGB_STAT 0x15 24 + #define RT5133_REG_BASE_MASK 0x16 25 + #define RT5133_REG_LDO_SHDN 0x19 26 + #define RT5133_REG_LDO_ON 0x1A 27 + #define RT5133_REG_LDO_OFF 0x1B 28 + #define RT5133_REG_LDO1_CTRL1 0x20 29 + #define RT5133_REG_LDO1_CTRL2 0x21 30 + #define RT5133_REG_LDO1_CTRL3 0x22 31 + #define RT5133_REG_LDO2_CTRL1 0x24 32 + #define RT5133_REG_LDO2_CTRL2 0x25 33 + #define RT5133_REG_LDO2_CTRL3 0x26 34 + #define RT5133_REG_LDO3_CTRL1 0x28 35 + #define RT5133_REG_LDO3_CTRL2 0x29 36 + #define RT5133_REG_LDO3_CTRL3 0x2A 37 + #define RT5133_REG_LDO4_CTRL1 0x2C 38 + #define RT5133_REG_LDO4_CTRL2 0x2D 39 + #define RT5133_REG_LDO4_CTRL3 0x2E 40 + #define RT5133_REG_LDO5_CTRL1 0x30 41 + #define RT5133_REG_LDO5_CTRL2 0x31 42 + #define RT5133_REG_LDO5_CTRL3 0x32 43 + #define RT5133_REG_LDO6_CTRL1 0x34 44 + #define RT5133_REG_LDO6_CTRL2 0x35 45 + #define RT5133_REG_LDO6_CTRL3 0x36 46 + #define RT5133_REG_LDO7_CTRL1 0x38 47 + #define RT5133_REG_LDO7_CTRL2 0x39 48 + #define RT5133_REG_LDO7_CTRL3 0x3A 49 + #define RT5133_REG_LDO8_CTRL1 0x3C 50 + #define RT5133_REG_LDO8_CTRL2 0x3D 51 + #define RT5133_REG_LDO8_CTRL3 0x3E 52 + #define RT5133_REG_LDO8_CTRL4 0x3F 53 + 54 + #define RT5133_LDO_REG_BASE(_id) (0x20 + ((_id) - 1) * 4) 55 + 56 + #define RT5133_VENDOR_ID_MASK GENMASK(7, 4) 57 + #define RT5133_RESET_CODE 0xB1 58 + 59 + #define RT5133_FOFF_BASE_MASK BIT(1) 60 + #define RT5133_OCSHDN_ALL_MASK BIT(7) 61 + #define RT5133_OCSHDN_ALL_SHIFT (7) 62 + #define RT5133_PGBSHDN_ALL_MASK BIT(6) 63 + #define RT5133_PGBSHDN_ALL_SHIFT (6) 64 + 65 + #define RT5133_OCPTSEL_MASK BIT(5) 66 + #define RT5133_PGBPTSEL_MASK BIT(4) 67 + #define RT5133_STBTDSEL_MASK GENMASK(1, 0) 68 + 69 + #define RT5133_LDO_ENABLE_MASK BIT(7) 70 + #define RT5133_LDO_VSEL_MASK GENMASK(7, 5) 71 + #define RT5133_LDO_AD_MASK BIT(2) 72 + #define RT5133_LDO_SOFT_START_MASK GENMASK(1, 0) 73 + 74 + #define RT5133_GPIO_NR 3 75 + 76 + #define RT5133_LDO_PGB_EVT_MASK GENMASK(23, 16) 77 + #define RT5133_LDO_PGB_EVT_SHIFT 16 78 + #define RT5133_LDO_OC_EVT_MASK GENMASK(15, 8) 79 + #define RT5133_LDO_OC_EVT_SHIFT 8 80 + #define RT5133_VREF_EVT_MASK BIT(6) 81 + #define RT5133_BASE_EVT_MASK GENMASK(7, 0) 82 + #define RT5133_INTR_CLR_MASK GENMASK(23, 0) 83 + #define RT5133_INTR_BYTE_NR 3 84 + 85 + #define RT5133_MAX_I2C_BLOCK_SIZE 1 86 + 87 + #define RT5133_CRC8_POLYNOMIAL 0x7 88 + 89 + #define RT5133_I2C_ADDR_LEN 1 90 + #define RT5133_PREDATA_LEN 2 91 + #define RT5133_I2C_CRC_LEN 1 92 + #define RT5133_REG_ADDR_LEN 1 93 + #define RT5133_I2C_DUMMY_LEN 1 94 + 95 + #define I2C_ADDR_XLATE_8BIT(_addr, _rw) ((((_addr) & 0x7F) << 1) | (_rw)) 96 + 97 + enum { 98 + RT5133_REGULATOR_BASE = 0, 99 + RT5133_REGULATOR_LDO1, 100 + RT5133_REGULATOR_LDO2, 101 + RT5133_REGULATOR_LDO3, 102 + RT5133_REGULATOR_LDO4, 103 + RT5133_REGULATOR_LDO5, 104 + RT5133_REGULATOR_LDO6, 105 + RT5133_REGULATOR_LDO7, 106 + RT5133_REGULATOR_LDO8, 107 + RT5133_REGULATOR_MAX 108 + }; 109 + 110 + struct chip_data { 111 + const struct regulator_desc *regulators; 112 + const u8 vendor_id; 113 + }; 114 + 115 + struct rt5133_priv { 116 + struct device *dev; 117 + struct regmap *regmap; 118 + struct gpio_desc *enable_gpio; 119 + struct regulator_dev *rdev[RT5133_REGULATOR_MAX]; 120 + struct gpio_chip gc; 121 + const struct chip_data *cdata; 122 + unsigned int gpio_output_flag; 123 + u8 crc8_tbls[CRC8_TABLE_SIZE]; 124 + }; 125 + 126 + static const unsigned int vout_type1_tables[] = { 127 + 1800000, 2500000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000 128 + }; 129 + 130 + static const unsigned int vout_type2_tables[] = { 131 + 1700000, 1800000, 1900000, 2500000, 2700000, 2800000, 2900000, 3000000 132 + }; 133 + 134 + static const unsigned int vout_type3_tables[] = { 135 + 900000, 950000, 1000000, 1050000, 1100000, 1150000, 1200000, 1800000 136 + }; 137 + 138 + static const unsigned int vout_type4_tables[] = { 139 + 855000, 900000, 950000, 1000000, 1040000, 1090000, 1140000, 1710000 140 + }; 141 + 142 + static const struct regulator_ops rt5133_regulator_ops = { 143 + .list_voltage = regulator_list_voltage_table, 144 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 145 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 146 + .enable = regulator_enable_regmap, 147 + .disable = regulator_disable_regmap, 148 + .is_enabled = regulator_is_enabled_regmap, 149 + .set_active_discharge = regulator_set_active_discharge_regmap, 150 + }; 151 + 152 + static const struct regulator_ops rt5133_base_regulator_ops = { 153 + .enable = regulator_enable_regmap, 154 + .disable = regulator_disable_regmap, 155 + .is_enabled = regulator_is_enabled_regmap, 156 + }; 157 + 158 + #define RT5133_REGULATOR_DESC(_name, _node_name, vtables, _supply) \ 159 + {\ 160 + .name = #_name,\ 161 + .id = RT5133_REGULATOR_##_name,\ 162 + .of_match = of_match_ptr(#_node_name),\ 163 + .regulators_node = of_match_ptr("regulators"),\ 164 + .supply_name = _supply,\ 165 + .type = REGULATOR_VOLTAGE,\ 166 + .owner = THIS_MODULE,\ 167 + .ops = &rt5133_regulator_ops,\ 168 + .n_voltages = ARRAY_SIZE(vtables),\ 169 + .volt_table = vtables,\ 170 + .enable_reg = RT5133_REG_##_name##_CTRL1,\ 171 + .enable_mask = RT5133_LDO_ENABLE_MASK,\ 172 + .vsel_reg = RT5133_REG_##_name##_CTRL2,\ 173 + .vsel_mask = RT5133_LDO_VSEL_MASK,\ 174 + .active_discharge_reg = RT5133_REG_##_name##_CTRL3,\ 175 + .active_discharge_mask = RT5133_LDO_AD_MASK,\ 176 + } 177 + 178 + static const struct regulator_desc rt5133_regulators[] = { 179 + /* For digital part, base current control */ 180 + { 181 + .name = "base", 182 + .id = RT5133_REGULATOR_BASE, 183 + .of_match = of_match_ptr("base"), 184 + .regulators_node = of_match_ptr("regulators"), 185 + .type = REGULATOR_VOLTAGE, 186 + .owner = THIS_MODULE, 187 + .ops = &rt5133_base_regulator_ops, 188 + .enable_reg = RT5133_REG_BASE_CTRL, 189 + .enable_mask = RT5133_FOFF_BASE_MASK, 190 + .enable_is_inverted = true, 191 + }, 192 + RT5133_REGULATOR_DESC(LDO1, ldo1, vout_type1_tables, "base"), 193 + RT5133_REGULATOR_DESC(LDO2, ldo2, vout_type1_tables, "base"), 194 + RT5133_REGULATOR_DESC(LDO3, ldo3, vout_type2_tables, "base"), 195 + RT5133_REGULATOR_DESC(LDO4, ldo4, vout_type2_tables, "base"), 196 + RT5133_REGULATOR_DESC(LDO5, ldo5, vout_type2_tables, "base"), 197 + RT5133_REGULATOR_DESC(LDO6, ldo6, vout_type2_tables, "base"), 198 + RT5133_REGULATOR_DESC(LDO7, ldo7, vout_type3_tables, "vin"), 199 + RT5133_REGULATOR_DESC(LDO8, ldo8, vout_type3_tables, "vin"), 200 + }; 201 + 202 + static const struct regulator_desc rt5133a_regulators[] = { 203 + /* For digital part, base current control */ 204 + { 205 + .name = "base", 206 + .id = RT5133_REGULATOR_BASE, 207 + .of_match = of_match_ptr("base"), 208 + .regulators_node = of_match_ptr("regulators"), 209 + .type = REGULATOR_VOLTAGE, 210 + .owner = THIS_MODULE, 211 + .ops = &rt5133_base_regulator_ops, 212 + .enable_reg = RT5133_REG_BASE_CTRL, 213 + .enable_mask = RT5133_FOFF_BASE_MASK, 214 + .enable_is_inverted = true, 215 + }, 216 + RT5133_REGULATOR_DESC(LDO1, ldo1, vout_type1_tables, "base"), 217 + RT5133_REGULATOR_DESC(LDO2, ldo2, vout_type1_tables, "base"), 218 + RT5133_REGULATOR_DESC(LDO3, ldo3, vout_type2_tables, "base"), 219 + RT5133_REGULATOR_DESC(LDO4, ldo4, vout_type2_tables, "base"), 220 + RT5133_REGULATOR_DESC(LDO5, ldo5, vout_type2_tables, "base"), 221 + RT5133_REGULATOR_DESC(LDO6, ldo6, vout_type2_tables, "base"), 222 + RT5133_REGULATOR_DESC(LDO7, ldo7, vout_type3_tables, "vin"), 223 + RT5133_REGULATOR_DESC(LDO8, ldo8, vout_type4_tables, "vin"), 224 + }; 225 + 226 + static const struct chip_data regulator_data[] = { 227 + { rt5133_regulators, 0x70}, 228 + { rt5133a_regulators, 0x80}, 229 + }; 230 + 231 + static int rt5133_gpio_direction_output(struct gpio_chip *gpio, 232 + unsigned int offset, int value) 233 + { 234 + struct rt5133_priv *priv = gpiochip_get_data(gpio); 235 + 236 + if (offset >= RT5133_GPIO_NR) 237 + return -EINVAL; 238 + 239 + return regmap_update_bits(priv->regmap, RT5133_REG_GPIO_CTRL, 240 + BIT(7 - offset) | BIT(3 - offset), 241 + value ? BIT(7 - offset) | BIT(3 - offset) : 0); 242 + } 243 + 244 + static int rt5133_gpio_get(struct gpio_chip *chip, unsigned int offset) 245 + { 246 + struct rt5133_priv *priv = gpiochip_get_data(chip); 247 + 248 + return !!(priv->gpio_output_flag & BIT(offset)); 249 + } 250 + 251 + static int rt5133_get_gpioen_mask(unsigned int offset, unsigned int *mask) 252 + { 253 + if (offset >= RT5133_GPIO_NR) 254 + return -EINVAL; 255 + 256 + *mask = (BIT(7 - offset) | BIT(3 - offset)); 257 + 258 + return 0; 259 + } 260 + 261 + static int rt5133_gpio_set(struct gpio_chip *chip, unsigned int offset, int set_val) 262 + { 263 + struct rt5133_priv *priv = gpiochip_get_data(chip); 264 + unsigned int mask = 0, val = 0, next_flag = priv->gpio_output_flag; 265 + int ret = 0; 266 + 267 + ret = rt5133_get_gpioen_mask(offset, &mask); 268 + if (ret) { 269 + dev_err(priv->dev, "%s get gpion en mask failed, offset(%d)\n", __func__, offset); 270 + return ret; 271 + } 272 + 273 + val = set_val ? mask : 0; 274 + 275 + if (set_val) 276 + next_flag |= BIT(offset); 277 + else 278 + next_flag &= ~BIT(offset); 279 + 280 + ret = regmap_update_bits(priv->regmap, RT5133_REG_GPIO_CTRL, mask, val); 281 + if (ret) { 282 + dev_err(priv->dev, "Failed to set gpio [%d] val %d\n", offset, 283 + set_val); 284 + return ret; 285 + } 286 + 287 + priv->gpio_output_flag = next_flag; 288 + return 0; 289 + } 290 + 291 + static irqreturn_t rt5133_intr_handler(int irq_number, void *data) 292 + { 293 + struct rt5133_priv *priv = data; 294 + u32 intr_evts = 0, handle_evts; 295 + int i, ret; 296 + 297 + ret = regmap_bulk_read(priv->regmap, RT5133_REG_BASE_EVT, &intr_evts, 298 + RT5133_INTR_BYTE_NR); 299 + if (ret) { 300 + dev_err(priv->dev, "%s, read event failed\n", __func__); 301 + return IRQ_NONE; 302 + } 303 + 304 + handle_evts = intr_evts & RT5133_BASE_EVT_MASK; 305 + /* 306 + * VREF_EVT is a special case, if base off 307 + * this event will also be trigger. Skip it 308 + */ 309 + if (handle_evts & ~RT5133_VREF_EVT_MASK) 310 + dev_dbg(priv->dev, "base event occurred [0x%02x]\n", 311 + handle_evts); 312 + 313 + handle_evts = (intr_evts & RT5133_LDO_OC_EVT_MASK) >> 314 + RT5133_LDO_OC_EVT_SHIFT; 315 + 316 + for (i = RT5133_REGULATOR_LDO1; i < RT5133_REGULATOR_MAX && handle_evts; i++) { 317 + if (!(handle_evts & BIT(i - 1))) 318 + continue; 319 + regulator_notifier_call_chain(priv->rdev[i], 320 + REGULATOR_EVENT_OVER_CURRENT, 321 + &i); 322 + } 323 + 324 + handle_evts = (intr_evts & RT5133_LDO_PGB_EVT_MASK) >> 325 + RT5133_LDO_PGB_EVT_SHIFT; 326 + for (i = RT5133_REGULATOR_LDO1; i < RT5133_REGULATOR_MAX && handle_evts; i++) { 327 + if (!(handle_evts & BIT(i - 1))) 328 + continue; 329 + regulator_notifier_call_chain(priv->rdev[i], 330 + REGULATOR_EVENT_FAIL, &i); 331 + } 332 + 333 + ret = regmap_bulk_write(priv->regmap, RT5133_REG_BASE_EVT, &intr_evts, 334 + RT5133_INTR_BYTE_NR); 335 + if (ret) 336 + dev_err(priv->dev, "%s, clear event failed\n", __func__); 337 + 338 + return IRQ_HANDLED; 339 + } 340 + 341 + static int rt5133_enable_interrupts(int irq_no, struct rt5133_priv *priv) 342 + { 343 + u32 mask = RT5133_INTR_CLR_MASK; 344 + int ret; 345 + 346 + /* Force to write clear all events */ 347 + ret = regmap_bulk_write(priv->regmap, RT5133_REG_BASE_EVT, &mask, 348 + RT5133_INTR_BYTE_NR); 349 + if (ret) { 350 + dev_err(priv->dev, "Failed to clear all interrupts\n"); 351 + return ret; 352 + } 353 + 354 + /* Unmask all interrupts */ 355 + mask = 0; 356 + ret = regmap_bulk_write(priv->regmap, RT5133_REG_BASE_MASK, &mask, 357 + RT5133_INTR_BYTE_NR); 358 + if (ret) { 359 + dev_err(priv->dev, "Failed to unmask all interrupts\n"); 360 + return ret; 361 + } 362 + 363 + return devm_request_threaded_irq(priv->dev, irq_no, NULL, 364 + rt5133_intr_handler, IRQF_ONESHOT, 365 + dev_name(priv->dev), priv); 366 + } 367 + 368 + static int rt5133_regmap_hw_read(void *context, const void *reg_buf, 369 + size_t reg_size, void *val_buf, 370 + size_t val_size) 371 + { 372 + struct rt5133_priv *priv = context; 373 + struct i2c_client *client = to_i2c_client(priv->dev); 374 + u8 reg = *(u8 *)reg_buf, crc; 375 + u8 *buf; 376 + int buf_len = RT5133_PREDATA_LEN + val_size + RT5133_I2C_CRC_LEN; 377 + int read_len, ret; 378 + 379 + buf = kzalloc(buf_len, GFP_KERNEL); 380 + if (!buf) 381 + return -ENOMEM; 382 + 383 + buf[0] = I2C_ADDR_XLATE_8BIT(client->addr, I2C_SMBUS_READ); 384 + buf[1] = reg; 385 + 386 + read_len = val_size + RT5133_I2C_CRC_LEN; 387 + ret = i2c_smbus_read_i2c_block_data(client, reg, read_len, 388 + buf + RT5133_PREDATA_LEN); 389 + 390 + if (ret < 0) 391 + goto out_read_err; 392 + 393 + if (ret != read_len) { 394 + ret = -EIO; 395 + goto out_read_err; 396 + } 397 + 398 + crc = crc8(priv->crc8_tbls, buf, RT5133_PREDATA_LEN + val_size, 0); 399 + if (crc != buf[RT5133_PREDATA_LEN + val_size]) { 400 + ret = -EIO; 401 + goto out_read_err; 402 + } 403 + 404 + memcpy(val_buf, buf + RT5133_PREDATA_LEN, val_size); 405 + dev_dbg(priv->dev, "%s, reg = 0x%02x, data = 0x%02x\n", __func__, reg, *(u8 *)val_buf); 406 + 407 + out_read_err: 408 + kfree(buf); 409 + return (ret < 0) ? ret : 0; 410 + } 411 + 412 + static int rt5133_regmap_hw_write(void *context, const void *data, size_t count) 413 + { 414 + struct rt5133_priv *priv = context; 415 + struct i2c_client *client = to_i2c_client(priv->dev); 416 + u8 reg = *(u8 *)data, crc; 417 + u8 *buf; 418 + int buf_len = RT5133_I2C_ADDR_LEN + count + RT5133_I2C_CRC_LEN + 419 + RT5133_I2C_DUMMY_LEN; 420 + int write_len, ret; 421 + 422 + buf = kzalloc(buf_len, GFP_KERNEL); 423 + if (!buf) 424 + return -ENOMEM; 425 + 426 + buf[0] = I2C_ADDR_XLATE_8BIT(client->addr, I2C_SMBUS_WRITE); 427 + buf[1] = reg; 428 + memcpy(buf + RT5133_PREDATA_LEN, data + RT5133_REG_ADDR_LEN, 429 + count - RT5133_REG_ADDR_LEN); 430 + 431 + crc = crc8(priv->crc8_tbls, buf, RT5133_I2C_ADDR_LEN + count, 0); 432 + buf[RT5133_I2C_ADDR_LEN + count] = crc; 433 + 434 + write_len = count - RT5133_REG_ADDR_LEN + RT5133_I2C_CRC_LEN + 435 + RT5133_I2C_DUMMY_LEN; 436 + ret = i2c_smbus_write_i2c_block_data(client, reg, write_len, 437 + buf + RT5133_PREDATA_LEN); 438 + 439 + dev_dbg(priv->dev, "%s, reg = 0x%02x, data = 0x%02x\n", __func__, reg, 440 + *(u8 *)(buf + RT5133_PREDATA_LEN)); 441 + kfree(buf); 442 + return ret; 443 + } 444 + 445 + static const struct regmap_bus rt5133_regmap_bus = { 446 + .read = rt5133_regmap_hw_read, 447 + .write = rt5133_regmap_hw_write, 448 + /* Due to crc, the block read/write length has the limit */ 449 + .max_raw_read = RT5133_MAX_I2C_BLOCK_SIZE, 450 + .max_raw_write = RT5133_MAX_I2C_BLOCK_SIZE, 451 + }; 452 + 453 + static bool rt5133_is_volatile_reg(struct device *dev, unsigned int reg) 454 + { 455 + switch (reg) { 456 + case RT5133_REG_CHIP_INFO: 457 + case RT5133_REG_BASE_EVT...RT5133_REG_LDO_PGB_STAT: 458 + case RT5133_REG_LDO_ON...RT5133_REG_LDO_OFF: 459 + case RT5133_REG_LDO1_CTRL1: 460 + case RT5133_REG_LDO2_CTRL1: 461 + case RT5133_REG_LDO3_CTRL1: 462 + case RT5133_REG_LDO4_CTRL1: 463 + case RT5133_REG_LDO5_CTRL1: 464 + case RT5133_REG_LDO6_CTRL1: 465 + case RT5133_REG_LDO7_CTRL1: 466 + case RT5133_REG_LDO8_CTRL1: 467 + return true; 468 + default: 469 + return false; 470 + }; 471 + } 472 + 473 + static const struct regmap_config rt5133_regmap_config = { 474 + .reg_bits = 8, 475 + .val_bits = 8, 476 + .max_register = RT5133_REG_LDO8_CTRL4, 477 + .cache_type = REGCACHE_FLAT, 478 + .num_reg_defaults_raw = RT5133_REG_LDO8_CTRL4 + 1, 479 + .volatile_reg = rt5133_is_volatile_reg, 480 + }; 481 + 482 + static int rt5133_chip_reset(struct rt5133_priv *priv) 483 + { 484 + int ret; 485 + 486 + ret = regmap_write(priv->regmap, RT5133_REG_RST_CTRL, 487 + RT5133_RESET_CODE); 488 + if (ret) 489 + return ret; 490 + 491 + /* Wait for register reset to take effect */ 492 + udelay(2); 493 + 494 + return 0; 495 + } 496 + 497 + static int rt5133_validate_vendor_info(struct rt5133_priv *priv) 498 + { 499 + unsigned int val = 0; 500 + int i, ret; 501 + 502 + ret = regmap_read(priv->regmap, RT5133_REG_CHIP_INFO, &val); 503 + if (ret) 504 + return ret; 505 + 506 + for (i = 0; i < ARRAY_SIZE(regulator_data); i++) { 507 + if ((val & RT5133_VENDOR_ID_MASK) == 508 + regulator_data[i].vendor_id){ 509 + priv->cdata = &regulator_data[i]; 510 + break; 511 + } 512 + } 513 + if (!priv->cdata) { 514 + dev_err(priv->dev, "Failed to find regulator match version\n"); 515 + return -ENODEV; 516 + } 517 + 518 + return 0; 519 + } 520 + 521 + static int rt5133_parse_dt(struct rt5133_priv *priv) 522 + { 523 + unsigned int val = 0; 524 + int ret = 0; 525 + 526 + if (!device_property_read_bool(priv->dev, "richtek,oc-shutdown-all")) 527 + val = 0; 528 + else 529 + val = 1 << RT5133_OCSHDN_ALL_SHIFT; 530 + ret = regmap_update_bits(priv->regmap, RT5133_REG_LDO_SHDN, 531 + RT5133_OCSHDN_ALL_MASK, val); 532 + if (ret) 533 + return ret; 534 + 535 + if (!device_property_read_bool(priv->dev, "richtek,pgb-shutdown-all")) 536 + val = 0; 537 + else 538 + val = 1 << RT5133_PGBSHDN_ALL_SHIFT; 539 + return regmap_update_bits(priv->regmap, RT5133_REG_LDO_SHDN, 540 + RT5133_PGBSHDN_ALL_MASK, val); 541 + } 542 + 543 + static int rt5133_probe(struct i2c_client *i2c) 544 + { 545 + struct rt5133_priv *priv; 546 + struct regulator_config config = {0}; 547 + int i, ret; 548 + 549 + priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL); 550 + if (!priv) 551 + return -ENOMEM; 552 + 553 + priv->dev = &i2c->dev; 554 + crc8_populate_msb(priv->crc8_tbls, RT5133_CRC8_POLYNOMIAL); 555 + 556 + priv->enable_gpio = devm_gpiod_get_optional(&i2c->dev, "enable", 557 + GPIOD_OUT_HIGH); 558 + if (IS_ERR(priv->enable_gpio)) 559 + dev_err(&i2c->dev, "Failed to request HWEN gpio, check if default en=high\n"); 560 + 561 + priv->regmap = devm_regmap_init(&i2c->dev, &rt5133_regmap_bus, priv, 562 + &rt5133_regmap_config); 563 + if (IS_ERR(priv->regmap)) { 564 + dev_err(&i2c->dev, "Failed to register regmap\n"); 565 + return PTR_ERR(priv->regmap); 566 + } 567 + 568 + ret = rt5133_validate_vendor_info(priv); 569 + if (ret) { 570 + dev_err(&i2c->dev, "Failed to check vendor info [%d]\n", ret); 571 + return ret; 572 + } 573 + 574 + ret = rt5133_chip_reset(priv); 575 + if (ret) { 576 + dev_err(&i2c->dev, "Failed to execute sw reset\n"); 577 + return ret; 578 + } 579 + 580 + config.dev = &i2c->dev; 581 + config.driver_data = priv; 582 + config.regmap = priv->regmap; 583 + 584 + for (i = 0; i < RT5133_REGULATOR_MAX; i++) { 585 + priv->rdev[i] = devm_regulator_register(&i2c->dev, 586 + priv->cdata->regulators + i, 587 + &config); 588 + if (IS_ERR(priv->rdev[i])) { 589 + dev_err(&i2c->dev, 590 + "Failed to register [%d] regulator\n", i); 591 + return PTR_ERR(priv->rdev[i]); 592 + } 593 + } 594 + 595 + ret = rt5133_parse_dt(priv); 596 + if (ret) { 597 + dev_err(&i2c->dev, "%s, Failed to parse dt\n", __func__); 598 + return ret; 599 + } 600 + 601 + priv->gc.label = dev_name(&i2c->dev); 602 + priv->gc.parent = &i2c->dev; 603 + priv->gc.base = -1; 604 + priv->gc.ngpio = RT5133_GPIO_NR; 605 + priv->gc.set = rt5133_gpio_set; 606 + priv->gc.get = rt5133_gpio_get; 607 + priv->gc.direction_output = rt5133_gpio_direction_output; 608 + priv->gc.can_sleep = true; 609 + 610 + ret = devm_gpiochip_add_data(&i2c->dev, &priv->gc, priv); 611 + if (ret) 612 + return ret; 613 + 614 + ret = rt5133_enable_interrupts(i2c->irq, priv); 615 + if (ret) { 616 + dev_err(&i2c->dev, "enable interrupt failed\n"); 617 + return ret; 618 + } 619 + 620 + i2c_set_clientdata(i2c, priv); 621 + 622 + return ret; 623 + } 624 + 625 + static const struct of_device_id __maybe_unused rt5133_of_match_table[] = { 626 + { .compatible = "richtek,rt5133", }, 627 + { } 628 + }; 629 + MODULE_DEVICE_TABLE(of, rt5133_of_match_table); 630 + 631 + static struct i2c_driver rt5133_driver = { 632 + .driver = { 633 + .name = "rt5133", 634 + .probe_type = PROBE_PREFER_ASYNCHRONOUS, 635 + .of_match_table = rt5133_of_match_table, 636 + }, 637 + .probe = rt5133_probe, 638 + }; 639 + module_i2c_driver(rt5133_driver); 640 + 641 + MODULE_DESCRIPTION("RT5133 Regulator Driver"); 642 + MODULE_LICENSE("GPL v2");
+165
drivers/regulator/s2dos05-regulator.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + // 3 + // s2dos05.c - Regulator driver for the Samsung s2dos05 4 + // 5 + // Copyright (C) 2025 Dzmitry Sankouski <dsankouski@gmail.com> 6 + 7 + #include <linux/bug.h> 8 + #include <linux/delay.h> 9 + #include <linux/err.h> 10 + #include <linux/slab.h> 11 + #include <linux/module.h> 12 + #include <linux/regmap.h> 13 + #include <linux/interrupt.h> 14 + #include <linux/platform_device.h> 15 + #include <linux/regulator/driver.h> 16 + #include <linux/regulator/machine.h> 17 + #include <linux/regulator/of_regulator.h> 18 + #include <linux/mfd/samsung/core.h> 19 + #include <linux/regulator/s2dos05.h> 20 + #include <linux/i2c.h> 21 + 22 + struct s2dos05_data { 23 + struct regmap *regmap; 24 + struct device *dev; 25 + }; 26 + 27 + #define _BUCK(macro) S2DOS05_BUCK##macro 28 + #define _buck_ops(num) s2dos05_ops##num 29 + #define _LDO(macro) S2DOS05_LDO##macro 30 + #define _REG(ctrl) S2DOS05_REG##ctrl 31 + #define _ldo_ops(num) s2dos05_ops##num 32 + #define _MASK(macro) S2DOS05_ENABLE_MASK##macro 33 + #define _TIME(macro) S2DOS05_ENABLE_TIME##macro 34 + 35 + #define BUCK_DESC(_name, _id, _ops, m, s, v, e, em, t, a) { \ 36 + .name = _name, \ 37 + .id = _id, \ 38 + .ops = _ops, \ 39 + .of_match = of_match_ptr(_name), \ 40 + .of_match_full_name = true, \ 41 + .regulators_node = of_match_ptr("regulators"), \ 42 + .type = REGULATOR_VOLTAGE, \ 43 + .owner = THIS_MODULE, \ 44 + .min_uV = m, \ 45 + .uV_step = s, \ 46 + .n_voltages = S2DOS05_BUCK_N_VOLTAGES, \ 47 + .vsel_reg = v, \ 48 + .vsel_mask = S2DOS05_BUCK_VSEL_MASK, \ 49 + .enable_reg = e, \ 50 + .enable_mask = em, \ 51 + .enable_time = t, \ 52 + .active_discharge_off = 0, \ 53 + .active_discharge_on = S2DOS05_BUCK_FD_MASK, \ 54 + .active_discharge_reg = a, \ 55 + .active_discharge_mask = S2DOS05_BUCK_FD_MASK \ 56 + } 57 + 58 + #define LDO_DESC(_name, _id, _ops, m, s, v, e, em, t, a) { \ 59 + .name = _name, \ 60 + .id = _id, \ 61 + .ops = _ops, \ 62 + .of_match = of_match_ptr(_name), \ 63 + .of_match_full_name = true, \ 64 + .regulators_node = of_match_ptr("regulators"), \ 65 + .type = REGULATOR_VOLTAGE, \ 66 + .owner = THIS_MODULE, \ 67 + .min_uV = m, \ 68 + .uV_step = s, \ 69 + .n_voltages = S2DOS05_LDO_N_VOLTAGES, \ 70 + .vsel_reg = v, \ 71 + .vsel_mask = S2DOS05_LDO_VSEL_MASK, \ 72 + .enable_reg = e, \ 73 + .enable_mask = em, \ 74 + .enable_time = t, \ 75 + .active_discharge_off = 0, \ 76 + .active_discharge_on = S2DOS05_LDO_FD_MASK, \ 77 + .active_discharge_reg = a, \ 78 + .active_discharge_mask = S2DOS05_LDO_FD_MASK \ 79 + } 80 + 81 + static const struct regulator_ops s2dos05_ops = { 82 + .list_voltage = regulator_list_voltage_linear, 83 + .map_voltage = regulator_map_voltage_linear, 84 + .is_enabled = regulator_is_enabled_regmap, 85 + .enable = regulator_enable_regmap, 86 + .disable = regulator_disable_regmap, 87 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 88 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 89 + .set_voltage_time_sel = regulator_set_voltage_time_sel, 90 + .set_active_discharge = regulator_set_active_discharge_regmap, 91 + }; 92 + 93 + static const struct regulator_desc regulators[S2DOS05_REGULATOR_MAX] = { 94 + // name, id, ops, min_uv, uV_step, vsel_reg, enable_reg 95 + LDO_DESC("ldo1", _LDO(1), &_ldo_ops(), _LDO(_MIN1), 96 + _LDO(_STEP1), _REG(_LDO1_CFG), 97 + _REG(_EN), _MASK(_L1), _TIME(_LDO), _REG(_LDO1_CFG)), 98 + LDO_DESC("ldo2", _LDO(2), &_ldo_ops(), _LDO(_MIN1), 99 + _LDO(_STEP1), _REG(_LDO2_CFG), 100 + _REG(_EN), _MASK(_L2), _TIME(_LDO), _REG(_LDO2_CFG)), 101 + LDO_DESC("ldo3", _LDO(3), &_ldo_ops(), _LDO(_MIN2), 102 + _LDO(_STEP1), _REG(_LDO3_CFG), 103 + _REG(_EN), _MASK(_L3), _TIME(_LDO), _REG(_LDO3_CFG)), 104 + LDO_DESC("ldo4", _LDO(4), &_ldo_ops(), _LDO(_MIN2), 105 + _LDO(_STEP1), _REG(_LDO4_CFG), 106 + _REG(_EN), _MASK(_L4), _TIME(_LDO), _REG(_LDO4_CFG)), 107 + BUCK_DESC("buck", _BUCK(1), &_buck_ops(), _BUCK(_MIN1), 108 + _BUCK(_STEP1), _REG(_BUCK_VOUT), 109 + _REG(_EN), _MASK(_B1), _TIME(_BUCK), _REG(_BUCK_CFG)), 110 + }; 111 + 112 + static int s2dos05_pmic_probe(struct platform_device *pdev) 113 + { 114 + struct device *dev = &pdev->dev; 115 + struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); 116 + struct s2dos05_data *s2dos05; 117 + struct regulator_config config = { }; 118 + unsigned int rdev_num = ARRAY_SIZE(regulators); 119 + 120 + s2dos05 = devm_kzalloc(dev, sizeof(*s2dos05), GFP_KERNEL); 121 + if (!s2dos05) 122 + return -ENOMEM; 123 + 124 + platform_set_drvdata(pdev, s2dos05); 125 + 126 + s2dos05->regmap = iodev->regmap_pmic; 127 + s2dos05->dev = dev; 128 + if (!dev->of_node) 129 + dev->of_node = dev->parent->of_node; 130 + 131 + config.dev = dev; 132 + config.driver_data = s2dos05; 133 + 134 + for (int i = 0; i < rdev_num; i++) { 135 + struct regulator_dev *regulator; 136 + 137 + regulator = devm_regulator_register(&pdev->dev, 138 + &regulators[i], &config); 139 + if (IS_ERR(regulator)) { 140 + return dev_err_probe(&pdev->dev, PTR_ERR(regulator), 141 + "regulator init failed for %d\n", i); 142 + } 143 + } 144 + 145 + return 0; 146 + } 147 + 148 + static const struct platform_device_id s2dos05_pmic_id[] = { 149 + { "s2dos05-regulator" }, 150 + { }, 151 + }; 152 + MODULE_DEVICE_TABLE(platform, s2dos05_pmic_id); 153 + 154 + static struct platform_driver s2dos05_platform_driver = { 155 + .driver = { 156 + .name = "s2dos05", 157 + }, 158 + .probe = s2dos05_pmic_probe, 159 + .id_table = s2dos05_pmic_id, 160 + }; 161 + module_platform_driver(s2dos05_platform_driver); 162 + 163 + MODULE_AUTHOR("Dzmitry Sankouski <dsankouski@gmail.com>"); 164 + MODULE_DESCRIPTION("Samsung S2DOS05 Regulator Driver"); 165 + MODULE_LICENSE("GPL");
+2 -1
drivers/regulator/scmi-regulator.c
··· 257 257 struct device_node *np, 258 258 struct scmi_regulator_info *rinfo) 259 259 { 260 - u32 dom, ret; 260 + u32 dom; 261 + int ret; 261 262 262 263 ret = of_property_read_u32(np, "reg", &dom); 263 264 if (ret)
+157
drivers/regulator/spacemit-p1.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Driver for regulators found in the SpacemiT P1 PMIC 4 + * 5 + * Copyright (C) 2025 by RISCstar Solutions Corporation. All rights reserved. 6 + * Derived from code from SpacemiT. 7 + * Copyright (c) 2023, SPACEMIT Co., Ltd 8 + */ 9 + 10 + #include <linux/array_size.h> 11 + #include <linux/bits.h> 12 + #include <linux/device.h> 13 + #include <linux/linear_range.h> 14 + #include <linux/module.h> 15 + #include <linux/of.h> 16 + #include <linux/platform_device.h> 17 + #include <linux/regulator/driver.h> 18 + 19 + #define MOD_NAME "spacemit-p1-regulator" 20 + 21 + enum p1_regulator_id { 22 + P1_BUCK1, 23 + P1_BUCK2, 24 + P1_BUCK3, 25 + P1_BUCK4, 26 + P1_BUCK5, 27 + P1_BUCK6, 28 + 29 + P1_ALDO1, 30 + P1_ALDO2, 31 + P1_ALDO3, 32 + P1_ALDO4, 33 + 34 + P1_DLDO1, 35 + P1_DLDO2, 36 + P1_DLDO3, 37 + P1_DLDO4, 38 + P1_DLDO5, 39 + P1_DLDO6, 40 + P1_DLDO7, 41 + }; 42 + 43 + static const struct regulator_ops p1_regulator_ops = { 44 + .list_voltage = regulator_list_voltage_linear_range, 45 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 46 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 47 + .set_voltage_time_sel = regulator_set_voltage_time_sel, 48 + .enable = regulator_enable_regmap, 49 + .disable = regulator_disable_regmap, 50 + .is_enabled = regulator_is_enabled_regmap, 51 + }; 52 + 53 + /* Selector value 255 can be used to disable the buck converter on sleep */ 54 + static const struct linear_range p1_buck_ranges[] = { 55 + REGULATOR_LINEAR_RANGE(500000, 0, 170, 5000), 56 + REGULATOR_LINEAR_RANGE(1375000, 171, 254, 25000), 57 + }; 58 + 59 + /* Selector value 0 can be used for suspend */ 60 + static const struct linear_range p1_ldo_ranges[] = { 61 + REGULATOR_LINEAR_RANGE(500000, 11, 127, 25000), 62 + }; 63 + 64 + /* These define the voltage selector field for buck and LDO regulators */ 65 + #define BUCK_MASK GENMASK(7, 0) 66 + #define LDO_MASK GENMASK(6, 0) 67 + 68 + #define P1_ID(_TYPE, _n) P1_ ## _TYPE ## _n 69 + #define P1_ENABLE_REG(_off, _n) ((_off) + 3 * ((_n) - 1)) 70 + 71 + #define P1_REG_DESC(_TYPE, _type, _n, _s, _off, _mask, _nv, _ranges) \ 72 + { \ 73 + .name = #_type #_n, \ 74 + .supply_name = _s, \ 75 + .of_match = of_match_ptr(#_type #_n), \ 76 + .regulators_node = of_match_ptr("regulators"), \ 77 + .id = P1_ID(_TYPE, _n), \ 78 + .n_voltages = _nv, \ 79 + .ops = &p1_regulator_ops, \ 80 + .owner = THIS_MODULE, \ 81 + .linear_ranges = _ranges, \ 82 + .n_linear_ranges = ARRAY_SIZE(_ranges), \ 83 + .vsel_reg = P1_ENABLE_REG(_off, _n) + 1, \ 84 + .vsel_mask = _mask, \ 85 + .enable_reg = P1_ENABLE_REG(_off, _n), \ 86 + .enable_mask = BIT(0), \ 87 + } 88 + 89 + #define P1_BUCK_DESC(_n) \ 90 + P1_REG_DESC(BUCK, buck, _n, "vcc", 0x47, BUCK_MASK, 254, p1_buck_ranges) 91 + 92 + #define P1_ALDO_DESC(_n) \ 93 + P1_REG_DESC(ALDO, aldo, _n, "vcc", 0x5b, LDO_MASK, 117, p1_ldo_ranges) 94 + 95 + #define P1_DLDO_DESC(_n) \ 96 + P1_REG_DESC(DLDO, dldo, _n, "buck5", 0x67, LDO_MASK, 117, p1_ldo_ranges) 97 + 98 + static const struct regulator_desc p1_regulator_desc[] = { 99 + P1_BUCK_DESC(1), 100 + P1_BUCK_DESC(2), 101 + P1_BUCK_DESC(3), 102 + P1_BUCK_DESC(4), 103 + P1_BUCK_DESC(5), 104 + P1_BUCK_DESC(6), 105 + 106 + P1_ALDO_DESC(1), 107 + P1_ALDO_DESC(2), 108 + P1_ALDO_DESC(3), 109 + P1_ALDO_DESC(4), 110 + 111 + P1_DLDO_DESC(1), 112 + P1_DLDO_DESC(2), 113 + P1_DLDO_DESC(3), 114 + P1_DLDO_DESC(4), 115 + P1_DLDO_DESC(5), 116 + P1_DLDO_DESC(6), 117 + P1_DLDO_DESC(7), 118 + }; 119 + 120 + static int p1_regulator_probe(struct platform_device *pdev) 121 + { 122 + struct regulator_config config = { }; 123 + struct device *dev = &pdev->dev; 124 + u32 i; 125 + 126 + /* 127 + * The parent device (PMIC) owns the regmap. Since we don't 128 + * provide one in the config structure, that one will be used. 129 + */ 130 + config.dev = dev->parent; 131 + 132 + for (i = 0; i < ARRAY_SIZE(p1_regulator_desc); i++) { 133 + const struct regulator_desc *desc = &p1_regulator_desc[i]; 134 + struct regulator_dev *rdev; 135 + 136 + rdev = devm_regulator_register(dev, desc, &config); 137 + if (IS_ERR(rdev)) 138 + return dev_err_probe(dev, PTR_ERR(rdev), 139 + "error registering regulator %s\n", 140 + desc->name); 141 + } 142 + 143 + return 0; 144 + } 145 + 146 + static struct platform_driver p1_regulator_driver = { 147 + .probe = p1_regulator_probe, 148 + .driver = { 149 + .name = MOD_NAME, 150 + }, 151 + }; 152 + 153 + module_platform_driver(p1_regulator_driver); 154 + 155 + MODULE_DESCRIPTION("SpacemiT P1 regulator driver"); 156 + MODULE_LICENSE("GPL"); 157 + MODULE_ALIAS("platform:" MOD_NAME);
-1
drivers/regulator/tps6524x-regulator.c
··· 598 598 599 599 spi_set_drvdata(spi, hw); 600 600 601 - memset(hw, 0, sizeof(struct tps6524x)); 602 601 hw->dev = dev; 603 602 hw->spi = spi; 604 603 mutex_init(&hw->lock);
+1 -1
drivers/regulator/tps6594-regulator.c
··· 647 647 default: 648 648 dev_err(tps->dev, "unknown chip_id %lu\n", tps->chip_id); 649 649 return -EINVAL; 650 - }; 650 + } 651 651 652 652 enum { 653 653 MULTI_BUCK12,
+73
include/linux/regulator/s2dos05.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0+ */ 2 + // s2dos05.h 3 + // 4 + // Copyright (c) 2016 Samsung Electronics Co., Ltd 5 + // http://www.samsung.com 6 + // Copyright (C) 2024 Dzmitry Sankouski <dsankouski@gmail.com> 7 + 8 + #ifndef __LINUX_S2DOS05_H 9 + #define __LINUX_S2DOS05_H 10 + 11 + // S2DOS05 registers 12 + // Slave Addr : 0xC0 13 + enum S2DOS05_reg { 14 + S2DOS05_REG_DEV_ID, 15 + S2DOS05_REG_TOPSYS_STAT, 16 + S2DOS05_REG_STAT, 17 + S2DOS05_REG_EN, 18 + S2DOS05_REG_LDO1_CFG, 19 + S2DOS05_REG_LDO2_CFG, 20 + S2DOS05_REG_LDO3_CFG, 21 + S2DOS05_REG_LDO4_CFG, 22 + S2DOS05_REG_BUCK_CFG, 23 + S2DOS05_REG_BUCK_VOUT, 24 + S2DOS05_REG_IRQ_MASK = 0x0D, 25 + S2DOS05_REG_SSD_TSD = 0x0E, 26 + S2DOS05_REG_OCL = 0x10, 27 + S2DOS05_REG_IRQ = 0x11 28 + }; 29 + 30 + // S2DOS05 regulator ids 31 + enum S2DOS05_regulators { 32 + S2DOS05_LDO1, 33 + S2DOS05_LDO2, 34 + S2DOS05_LDO3, 35 + S2DOS05_LDO4, 36 + S2DOS05_BUCK1, 37 + S2DOS05_REG_MAX, 38 + }; 39 + 40 + #define S2DOS05_IRQ_PWRMT_MASK BIT(5) 41 + #define S2DOS05_IRQ_TSD_MASK BIT(4) 42 + #define S2DOS05_IRQ_SSD_MASK BIT(3) 43 + #define S2DOS05_IRQ_SCP_MASK BIT(2) 44 + #define S2DOS05_IRQ_UVLO_MASK BIT(1) 45 + #define S2DOS05_IRQ_OCD_MASK BIT(0) 46 + 47 + #define S2DOS05_BUCK_MIN1 506250 48 + #define S2DOS05_LDO_MIN1 1500000 49 + #define S2DOS05_LDO_MIN2 2700000 50 + #define S2DOS05_BUCK_STEP1 6250 51 + #define S2DOS05_LDO_STEP1 25000 52 + #define S2DOS05_LDO_VSEL_MASK 0x7F 53 + #define S2DOS05_LDO_FD_MASK 0x80 54 + #define S2DOS05_BUCK_VSEL_MASK 0xFF 55 + #define S2DOS05_BUCK_FD_MASK 0x08 56 + 57 + #define S2DOS05_ENABLE_MASK_L1 BIT(0) 58 + #define S2DOS05_ENABLE_MASK_L2 BIT(1) 59 + #define S2DOS05_ENABLE_MASK_L3 BIT(2) 60 + #define S2DOS05_ENABLE_MASK_L4 BIT(3) 61 + #define S2DOS05_ENABLE_MASK_B1 BIT(4) 62 + 63 + #define S2DOS05_RAMP_DELAY 12000 64 + 65 + #define S2DOS05_ENABLE_TIME_LDO 50 66 + #define S2DOS05_ENABLE_TIME_BUCK 350 67 + 68 + #define S2DOS05_LDO_N_VOLTAGES (S2DOS05_LDO_VSEL_MASK + 1) 69 + #define S2DOS05_BUCK_N_VOLTAGES (S2DOS05_BUCK_VSEL_MASK + 1) 70 + 71 + #define S2DOS05_REGULATOR_MAX (S2DOS05_REG_MAX) 72 + 73 + #endif // __LINUX_S2DOS05_H
+10
rust/helpers/regulator.c
··· 40 40 return regulator_is_enabled(regulator); 41 41 } 42 42 43 + int rust_helper_devm_regulator_get_enable(struct device *dev, const char *id) 44 + { 45 + return devm_regulator_get_enable(dev, id); 46 + } 47 + 48 + int rust_helper_devm_regulator_get_enable_optional(struct device *dev, const char *id) 49 + { 50 + return devm_regulator_get_enable_optional(dev, id); 51 + } 52 + 43 53 #endif
+74 -97
rust/kernel/regulator.rs
··· 18 18 19 19 use crate::{ 20 20 bindings, 21 - device::Device, 21 + device::{Bound, Device}, 22 22 error::{from_err_ptr, to_result, Result}, 23 23 prelude::*, 24 24 }; ··· 30 30 31 31 impl Sealed for super::Enabled {} 32 32 impl Sealed for super::Disabled {} 33 - impl Sealed for super::Dynamic {} 34 33 } 35 34 36 35 /// A trait representing the different states a [`Regulator`] can be in. ··· 49 50 /// own an `enable` reference count, but the regulator may still be on. 50 51 pub struct Disabled; 51 52 52 - /// A state that models the C API. The [`Regulator`] can be either enabled or 53 - /// disabled, and the user is in control of the reference count. This is also 54 - /// the default state. 55 - /// 56 - /// Use [`Regulator::is_enabled`] to check the regulator's current state. 57 - pub struct Dynamic; 58 - 59 53 impl RegulatorState for Enabled { 60 54 const DISABLE_ON_DROP: bool = true; 61 55 } ··· 57 65 const DISABLE_ON_DROP: bool = false; 58 66 } 59 67 60 - impl RegulatorState for Dynamic { 61 - const DISABLE_ON_DROP: bool = false; 62 - } 63 - 64 68 /// A trait that abstracts the ability to check if a [`Regulator`] is enabled. 65 69 pub trait IsEnabled: RegulatorState {} 66 70 impl IsEnabled for Disabled {} 67 - impl IsEnabled for Dynamic {} 68 71 69 72 /// An error that can occur when trying to convert a [`Regulator`] between states. 70 73 pub struct Error<State: RegulatorState> { ··· 68 81 69 82 /// The regulator that caused the error, so that the operation may be retried. 70 83 pub regulator: Regulator<State>, 84 + } 85 + /// Obtains and enables a [`devres`]-managed regulator for a device. 86 + /// 87 + /// This calls [`regulator_disable()`] and [`regulator_put()`] automatically on 88 + /// driver detach. 89 + /// 90 + /// This API is identical to `devm_regulator_get_enable()`, and should be 91 + /// preferred over the [`Regulator<T: RegulatorState>`] API if the caller only 92 + /// cares about the regulator being enabled. 93 + /// 94 + /// [`devres`]: https://docs.kernel.org/driver-api/driver-model/devres.html 95 + /// [`regulator_disable()`]: https://docs.kernel.org/driver-api/regulator.html#c.regulator_disable 96 + /// [`regulator_put()`]: https://docs.kernel.org/driver-api/regulator.html#c.regulator_put 97 + pub fn devm_enable(dev: &Device<Bound>, name: &CStr) -> Result { 98 + // SAFETY: `dev` is a valid and bound device, while `name` is a valid C 99 + // string. 100 + to_result(unsafe { bindings::devm_regulator_get_enable(dev.as_raw(), name.as_ptr()) }) 101 + } 102 + 103 + /// Same as [`devm_enable`], but calls `devm_regulator_get_enable_optional` 104 + /// instead. 105 + /// 106 + /// This obtains and enables a [`devres`]-managed regulator for a device, but 107 + /// does not print a message nor provides a dummy if the regulator is not found. 108 + /// 109 + /// This calls [`regulator_disable()`] and [`regulator_put()`] automatically on 110 + /// driver detach. 111 + /// 112 + /// [`devres`]: https://docs.kernel.org/driver-api/driver-model/devres.html 113 + /// [`regulator_disable()`]: https://docs.kernel.org/driver-api/regulator.html#c.regulator_disable 114 + /// [`regulator_put()`]: https://docs.kernel.org/driver-api/regulator.html#c.regulator_put 115 + pub fn devm_enable_optional(dev: &Device<Bound>, name: &CStr) -> Result { 116 + // SAFETY: `dev` is a valid and bound device, while `name` is a valid C 117 + // string. 118 + to_result(unsafe { bindings::devm_regulator_get_enable_optional(dev.as_raw(), name.as_ptr()) }) 71 119 } 72 120 73 121 /// A `struct regulator` abstraction. ··· 181 159 /// } 182 160 /// ``` 183 161 /// 162 + /// If a driver only cares about the regulator being on for as long it is bound 163 + /// to a device, then it should use [`devm_enable`] or [`devm_enable_optional`]. 164 + /// This should be the default use-case unless more fine-grained control over 165 + /// the regulator's state is required. 166 + /// 167 + /// [`devm_enable`]: crate::regulator::devm_enable 168 + /// [`devm_optional`]: crate::regulator::devm_enable_optional 169 + /// 170 + /// ``` 171 + /// # use kernel::prelude::*; 172 + /// # use kernel::c_str; 173 + /// # use kernel::device::{Bound, Device}; 174 + /// # use kernel::regulator; 175 + /// fn enable(dev: &Device<Bound>) -> Result { 176 + /// // Obtain a reference to a (fictitious) regulator and enable it. This 177 + /// // call only returns whether the operation succeeded. 178 + /// regulator::devm_enable(dev, c_str!("vcc"))?; 179 + /// 180 + /// // The regulator will be disabled and put when `dev` is unbound. 181 + /// Ok(()) 182 + /// } 183 + /// ``` 184 + /// 184 185 /// ## Disabling a regulator 185 186 /// 186 187 /// ``` ··· 228 183 /// } 229 184 /// ``` 230 185 /// 231 - /// ## Using [`Regulator<Dynamic>`] 232 - /// 233 - /// This example mimics the behavior of the C API, where the user is in 234 - /// control of the enabled reference count. This is useful for drivers that 235 - /// might call enable and disable to manage the `enable` reference count at 236 - /// runtime, perhaps as a result of `open()` and `close()` calls or whatever 237 - /// other driver-specific or subsystem-specific hooks. 238 - /// 239 - /// ``` 240 - /// # use kernel::prelude::*; 241 - /// # use kernel::c_str; 242 - /// # use kernel::device::Device; 243 - /// # use kernel::regulator::{Regulator, Dynamic}; 244 - /// struct PrivateData { 245 - /// regulator: Regulator<Dynamic>, 246 - /// } 247 - /// 248 - /// // A fictictious probe function that obtains a regulator and sets it up. 249 - /// fn probe(dev: &Device) -> Result<PrivateData> { 250 - /// // Obtain a reference to a (fictitious) regulator. 251 - /// let mut regulator = Regulator::<Dynamic>::get(dev, c_str!("vcc"))?; 252 - /// 253 - /// Ok(PrivateData { regulator }) 254 - /// } 255 - /// 256 - /// // A fictictious function that indicates that the device is going to be used. 257 - /// fn open(dev: &Device, data: &mut PrivateData) -> Result { 258 - /// // Increase the `enabled` reference count. 259 - /// data.regulator.enable()?; 260 - /// 261 - /// Ok(()) 262 - /// } 263 - /// 264 - /// fn close(dev: &Device, data: &mut PrivateData) -> Result { 265 - /// // Decrease the `enabled` reference count. 266 - /// data.regulator.disable()?; 267 - /// 268 - /// Ok(()) 269 - /// } 270 - /// 271 - /// fn remove(dev: &Device, data: PrivateData) -> Result { 272 - /// // `PrivateData` is dropped here, which will drop the 273 - /// // `Regulator<Dynamic>` in turn. 274 - /// // 275 - /// // The reference that was obtained by `regulator_get()` will be 276 - /// // released, but it is up to the user to make sure that the number of calls 277 - /// // to `enable()` and `disabled()` are balanced before this point. 278 - /// Ok(()) 279 - /// } 280 - /// ``` 281 - /// 282 186 /// # Invariants 283 187 /// 284 188 /// - `inner` is a non-null wrapper over a pointer to a `struct 285 189 /// regulator` obtained from [`regulator_get()`]. 286 190 /// 287 191 /// [`regulator_get()`]: https://docs.kernel.org/driver-api/regulator.html#c.regulator_get 288 - pub struct Regulator<State = Dynamic> 192 + pub struct Regulator<State> 289 193 where 290 194 State: RegulatorState, 291 195 { ··· 261 267 pub fn get_voltage(&self) -> Result<Voltage> { 262 268 // SAFETY: Safe as per the type invariants of `Regulator`. 263 269 let voltage = unsafe { bindings::regulator_get_voltage(self.inner.as_ptr()) }; 264 - if voltage < 0 { 265 - Err(kernel::error::Error::from_errno(voltage)) 266 - } else { 267 - Ok(Voltage::from_microvolts(voltage)) 268 - } 270 + 271 + to_result(voltage).map(|()| Voltage::from_microvolts(voltage)) 269 272 } 270 273 271 274 fn get_internal(dev: &Device, name: &CStr) -> Result<Regulator<T>> { ··· 280 289 }) 281 290 } 282 291 283 - fn enable_internal(&mut self) -> Result { 292 + fn enable_internal(&self) -> Result { 284 293 // SAFETY: Safe as per the type invariants of `Regulator`. 285 294 to_result(unsafe { bindings::regulator_enable(self.inner.as_ptr()) }) 286 295 } 287 296 288 - fn disable_internal(&mut self) -> Result { 297 + fn disable_internal(&self) -> Result { 289 298 // SAFETY: Safe as per the type invariants of `Regulator`. 290 299 to_result(unsafe { bindings::regulator_disable(self.inner.as_ptr()) }) 291 300 } ··· 301 310 pub fn try_into_enabled(self) -> Result<Regulator<Enabled>, Error<Disabled>> { 302 311 // We will be transferring the ownership of our `regulator_get()` count to 303 312 // `Regulator<Enabled>`. 304 - let mut regulator = ManuallyDrop::new(self); 313 + let regulator = ManuallyDrop::new(self); 305 314 306 315 regulator 307 316 .enable_internal() ··· 330 339 pub fn try_into_disabled(self) -> Result<Regulator<Disabled>, Error<Enabled>> { 331 340 // We will be transferring the ownership of our `regulator_get()` count 332 341 // to `Regulator<Disabled>`. 333 - let mut regulator = ManuallyDrop::new(self); 342 + let regulator = ManuallyDrop::new(self); 334 343 335 344 regulator 336 345 .disable_internal() ··· 342 351 error, 343 352 regulator: ManuallyDrop::into_inner(regulator), 344 353 }) 345 - } 346 - } 347 - 348 - impl Regulator<Dynamic> { 349 - /// Obtains a [`Regulator`] instance from the system. The current state of 350 - /// the regulator is unknown and it is up to the user to manage the enabled 351 - /// reference count. 352 - /// 353 - /// This closely mimics the behavior of the C API and can be used to 354 - /// dynamically manage the enabled reference count at runtime. 355 - pub fn get(dev: &Device, name: &CStr) -> Result<Self> { 356 - Regulator::get_internal(dev, name) 357 - } 358 - 359 - /// Increases the `enabled` reference count. 360 - pub fn enable(&mut self) -> Result { 361 - self.enable_internal() 362 - } 363 - 364 - /// Decreases the `enabled` reference count. 365 - pub fn disable(&mut self) -> Result { 366 - self.disable_internal() 367 354 } 368 355 } 369 356 ··· 366 397 unsafe { bindings::regulator_put(self.inner.as_ptr()) }; 367 398 } 368 399 } 400 + 401 + // SAFETY: It is safe to send a `Regulator<T>` across threads. In particular, a 402 + // Regulator<T> can be dropped from any thread. 403 + unsafe impl<T: RegulatorState> Send for Regulator<T> {} 404 + 405 + // SAFETY: It is safe to send a &Regulator<T> across threads because the C side 406 + // handles its own locking. 407 + unsafe impl<T: RegulatorState> Sync for Regulator<T> {} 369 408 370 409 /// A voltage. 371 410 ///