diff --git a/Documentation/devicetree/bindings/leds/backlight/ti,lm3533-backlight.yaml b/Documentation/devicetree/bindings/leds/backlight/ti,lm3533-backlight.yaml new file mode 100644 index 000000000000..a25846e9b375 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/backlight/ti,lm3533-backlight.yaml @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/backlight/ti,lm3533-backlight.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI LM3533 high voltage series LED strings + +description: + This is part of the TI LM3533 MFD device. It represents two high voltage series + LED strings for display backlight controlled by the TI LM3533. + +maintainers: + - Svyatoslav Ryhel + +allOf: + - $ref: /schemas/leds/backlight/common.yaml# + +properties: + compatible: + const: ti,lm3533-backlight + + reg: + description: Control bank selection (0 = bank A, 1 = bank B). + maximum: 1 + + led-max-microamp: + description: maximum current in uA with a 800 uA step. + minimum: 5000 + maximum: 29800 + default: 5000 + + led-sources: + description: | + HVLED strings associated with this control bank: + 0 - HVLED1 + 1 - HVLED2 + minItems: 1 + maxItems: 2 + items: + maximum: 1 + + ti,pwm-config-mask: + $ref: /schemas/types.yaml#/definitions/uint32 + description: | + Control Bank PWM Configuration Register mask that allows to configure + PWM input in Zones 0-4 + BIT(0) - PWM Input is enabled + BIT(1) - PWM Input is enabled in Zone 0 + BIT(2) - PWM Input is enabled in Zone 1 + BIT(3) - PWM Input is enabled in Zone 2 + BIT(4) - PWM Input is enabled in Zone 3 + BIT(5) - PWM Input is enabled in Zone 4 + default: 0 + + ti,linear-mapping-mode: + description: + Enable linear mapping mode. If disabled, then it will use exponential + mapping mode in which the ramp up/down appears to have a more uniform + transition to the human eye. + type: boolean + +required: + - compatible + - reg + +unevaluatedProperties: false + +# see ti,lm3533.yaml for an example diff --git a/Documentation/devicetree/bindings/leds/ti,lm3533-leds.yaml b/Documentation/devicetree/bindings/leds/ti,lm3533-leds.yaml new file mode 100644 index 000000000000..d8dbefef3323 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/ti,lm3533-leds.yaml @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/ti,lm3533-leds.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI LM3533 low voltage control banks for individual LEDs + +description: + This is part of the TI LM3533 MFD device. It represents four low voltage + control banks for individual LEDs provided by the TI LM3533. + +maintainers: + - Svyatoslav Ryhel + +allOf: + - $ref: /schemas/leds/common.yaml# + +properties: + compatible: + const: ti,lm3533-leds + + reg: + description: + Control bank selection (2 = bank C, 3 = bank D, 4 = bank E, 5 = bank F). + minimum: 2 + maximum: 5 + + led-max-microamp: + description: maximum current in uA with a 800 uA step. + minimum: 5000 + maximum: 29800 + default: 5000 + + led-sources: + description: | + LVLED associated with this control bank. May be more than 1 source per bank. + 0 - LVLED1 + 1 - LVLED2 + 2 - LVLED3 + 3 - LVLED4 + 4 - LVLED5 + minItems: 1 + maxItems: 5 + items: + maximum: 4 + + ti,pwm-config-mask: + $ref: /schemas/types.yaml#/definitions/uint32 + description: | + Control Bank PWM Configuration Register mask that allows to configure + PWM input in Zones 0-4 + BIT(0) - PWM Input is enabled + BIT(1) - PWM Input is enabled in Zone 0 + BIT(2) - PWM Input is enabled in Zone 1 + BIT(3) - PWM Input is enabled in Zone 2 + BIT(4) - PWM Input is enabled in Zone 3 + BIT(5) - PWM Input is enabled in Zone 4 + default: 0 + +required: + - compatible + - reg + +unevaluatedProperties: false + +# see ti,lm3533.yaml for an example diff --git a/Documentation/devicetree/bindings/leds/ti,lm3533.yaml b/Documentation/devicetree/bindings/leds/ti,lm3533.yaml new file mode 100644 index 000000000000..bdc05a9f3d66 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/ti,lm3533.yaml @@ -0,0 +1,169 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/ti,lm3533.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI LM3533 Complete Lighting Power Solution + +description: > + The LM3533 is a complete power source for backlight, keypad, and indicator LEDs + in smartphone handsets. The high-voltage inductive boost converter provides the + power for two high voltage series LED strings for display backlight and four low + voltage control banks for individual LEDs. Additionally, LM3533 features an + interface for an external light sensor. + + https://www.ti.com/product/LM3533 + +maintainers: + - Svyatoslav Ryhel + +properties: + compatible: + const: ti,lm3533 + + reg: + maxItems: 1 + + enable-gpios: + description: GPIO connected to the HWEN pin. + maxItems: 1 + + vin-supply: + description: Supply connected to the IN line (2.7 V to 5.5 V). + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + + ti,boost-ovp-microvolt: + description: boost OVP select (16V, 24V, 32V, 40V) + enum: [ 16000000, 24000000, 32000000, 40000000 ] + default: 16000000 + + ti,boost-freq-hz: + description: boost frequency select (500KHz or 1MHz) + enum: [ 500000, 1000000 ] + default: 500000 + + light-sensor: + type: object + additionalProperties: false + + properties: + compatible: + const: ti,lm3533-als + + interrupts: + maxItems: 1 + + ti,resistor-ohms: + description: + Internal configuration resistor value when light sensor is in + Analog Sensor mode and PWM mode is disabled. The expectation is + the input is a current from the external analog light sensor and + this is used to convert it to a voltage within the target range. + minimum: 1575 + maximum: 200000 + + ti,pwm-mode: + type: boolean + description: + Switch for mode in which light sensor interface is running. If + this property is set then the light sensor interface is running + in PWM mode, internal resistor value is set to high-impedance (0) + and ti,resistor-ohms property is ignored. + + required: + - compatible + + oneOf: + - required: + - ti,resistor-ohms + - required: + - ti,pwm-mode + +patternProperties: + "^backlight@[01]$": + $ref: /schemas/leds/backlight/ti,lm3533-backlight.yaml# + + "^led@[2-5]$": + $ref: /schemas/leds/ti,lm3533-leds.yaml# + +required: + - compatible + - reg + - '#address-cells' + - '#size-cells' + +additionalProperties: false + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + led-controller@36 { + compatible = "ti,lm3533"; + reg = <0x36>; + + enable-gpios = <&gpio 110 GPIO_ACTIVE_HIGH>; + vin-supply = <&vdd_3v3_bat>; + + ti,boost-ovp-microvolt = <24000000>; + ti,boost-freq-hz = <500000>; + + #address-cells = <1>; + #size-cells = <0>; + + backlight@0 { + compatible = "ti,lm3533-backlight"; + reg = <0>; + + default-brightness = <113>; + + led-max-microamp = <23400>; + led-sources = <0 1>; + }; + + led@2 { + compatible = "ti,lm3533-leds"; + reg = <2>; + + led-max-microamp = <23400>; + led-sources = <0 1>; + }; + + led@4 { + compatible = "ti,lm3533-leds"; + reg = <4>; + + led-max-microamp = <23400>; + led-sources = <2>; + }; + + led@5 { + compatible = "ti,lm3533-leds"; + reg = <5>; + + led-max-microamp = <23400>; + led-sources = <3 4>; + }; + + light-sensor { + compatible = "ti,lm3533-als"; + + interrupt-parent = <&gpio>; + interrupts = <80 IRQ_TYPE_LEVEL_LOW>; + + ti,pwm-mode; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml b/Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml index 4fc78efaa550..0a67de054674 100644 --- a/Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml +++ b/Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml @@ -15,6 +15,9 @@ description: | for LED and a 500 mA single-cell linear charger. Also included is a Coulomb counter, a real-time clock (RTC), and a 32.768 kHz clock gate and two GPOs. +allOf: + - $ref: rohm,pmic-pins.yaml# + properties: compatible: const: rohm,bd71815 @@ -44,11 +47,7 @@ properties: clock-output-names: const: bd71815-32k-out - rohm,clkout-open-drain: - description: clk32kout mode. Set to 1 for "open-drain" or 0 for "cmos". - $ref: /schemas/types.yaml#/definitions/uint32 - minimum: 0 - maximum: 1 + rohm,clkout-open-drain: true rohm,charger-sense-resistor-micro-ohms: minimum: 10000 diff --git a/Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml b/Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml index 09e7d68e92bf..e5043dec990d 100644 --- a/Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml +++ b/Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml @@ -15,6 +15,9 @@ description: | single-cell linear charger. Also included is a Coulomb counter, a real-time clock (RTC), and a 32.768 kHz clock gate. +allOf: + - $ref: rohm,pmic-pins.yaml# + properties: compatible: oneOf: @@ -49,11 +52,7 @@ properties: clock-output-names: const: bd71828-32k-out - rohm,clkout-open-drain: - description: clk32kout mode. Set to 1 for "open-drain" or 0 for "cmos". - $ref: /schemas/types.yaml#/definitions/uint32 - minimum: 0 - maximum: 1 + rohm,clkout-open-drain: true rohm,charger-sense-resistor-micro-ohms: minimum: 10000 diff --git a/Documentation/devicetree/bindings/mfd/rohm,bd72720-pmic.yaml b/Documentation/devicetree/bindings/mfd/rohm,bd72720-pmic.yaml index b094542339e8..52d0f6e4ef0f 100644 --- a/Documentation/devicetree/bindings/mfd/rohm,bd72720-pmic.yaml +++ b/Documentation/devicetree/bindings/mfd/rohm,bd72720-pmic.yaml @@ -15,6 +15,9 @@ description: and a 3000 mA switching charger. ICs also include a Coulomb counter, a real-time clock (RTC), GPIOs and a 32.768 kHz clock gate. +allOf: + - $ref: rohm,pmic-pins.yaml# + # In addition to the properties found from the charger node, PMICs # use properties from a static battery node. Please see the: # Documentation/devicetree/bindings/power/supply/battery.yaml @@ -80,10 +83,7 @@ properties: clock-output-names: const: bd71828-32k-out - rohm,clkout-open-drain: - description: clk32kout mode. Set to 1 for "open-drain" or 0 for "cmos". - $ref: /schemas/types.yaml#/definitions/uint32 - maximum: 1 + rohm,clkout-open-drain: true rohm,charger-sense-resistor-micro-ohms: minimum: 10000 @@ -103,14 +103,6 @@ properties: $ref: /schemas/leds/rohm,bd71828-leds.yaml rohm,pin-fault_b: - $ref: /schemas/types.yaml#/definitions/string - description: - PMIC has an OTP option to use fault_b-pin for different - purposes. Set this property accordingly. OTP options are - OTP0 - bi-directional FAULT_B or READY indicator depending on a - 'sub option' - OTP1 - GPO - OTP2 - Power sequencer output. enum: - faultb - readyind @@ -119,14 +111,6 @@ properties: patternProperties: "^rohm,pin-dvs[0-1]$": - $ref: /schemas/types.yaml#/definitions/string - description: - PMIC has 4 different OTP options to determine the use of dvs-pins. - OTP0 - regulator RUN state control. - OTP1 - GPI. - OTP2 - GPO. - OTP3 - Power sequencer output. - This property specifies the use of the pin. enum: - dvs-input - gpi @@ -134,11 +118,6 @@ patternProperties: - pwrseq "^rohm,pin-exten[0-1]$": - $ref: /schemas/types.yaml#/definitions/string - description: PMIC has an OTP option to use exten0-pin for different - purposes. Set this property accordingly. - OTP0 - GPO - OTP1 - Power sequencer output. enum: - gpo - pwrseq diff --git a/Documentation/devicetree/bindings/mfd/rohm,bd73800-pmic.yaml b/Documentation/devicetree/bindings/mfd/rohm,bd73800-pmic.yaml new file mode 100644 index 000000000000..8371e7f2ab84 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/rohm,bd73800-pmic.yaml @@ -0,0 +1,218 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/rohm,bd73800-pmic.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ROHM BD73800 Power Management Integrated Circuit + +maintainers: + - Matti Vaittinen + +description: + BD73800GW is a single-chip power management IC for battery-powered + portable devices. It integrates 8 buck converters, 4 LDOs and a current + sense amplifier with ADC. Also included is a Real Time Clock (RTC) and a + 32.768 kHz clock gate. Depending on the OTP configuration the BD73800 + may also have interrupt controller and GPIOs. + + There are also different variants called BD71851 and BD71885 which are + almost identical from the software point of view. + +allOf: + - $ref: rohm,pmic-pins.yaml# + +properties: + compatible: + oneOf: + - const: rohm,bd73800 + + - items: + - enum: + - rohm,bd71851 + - rohm,bd71885 + - const: rohm,bd73800 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + # The GPIO1, CLKOUT (GPIO2), FAULT_B and EXTEN_OUT pins can be + # configured to interrupt pins by OTP. + interrupt-controller: true + + "#interrupt-cells": + const: 1 + description: + The IRQ number. 0 is GPIO1, 1 CLKOUT (GPIO2), 2 FAULT_B and 3 EXTEN_OUT. + NOTE, A pin can operate as IRQ source only when the OTP + configuration for it has been set to GPI. + + gpio-controller: true + + "#gpio-cells": + const: 2 + + rohm,pin-gpio1: + $ref: /schemas/types.yaml#/definitions/string + description: + Indicate if the GPIO1 pin has been set to GPI or GPO at manufacturing. + The GPIO1, CLKOUT, FAULT_B and EXTEN_OUT pins may be configured for a + specific purpose (like ADC input, 32.768 clk output, fault indicator or + delivering power sequence to a companion PMIC when multiple PMICs are + used) - but also to be either a GPO or GPI. (When used as a GPI the pin + can also be used as an IRQ source). The pin purpose is determined by + OTP (One Time Programmable memory), typically during device + manufacturing. The OTP can't be read at runtime so device-tree should + describe the GPIO pins. + enum: [gpi, gpo] + + rohm,pin-clkout: + enum: [gpi, gpo] + + rohm,pin-fault_b: + enum: [gpi, gpo] + + rohm,pin-exten: + enum: [gpi, gpo] + + clocks: + description: + The CLKOUT pin may have its purpose overridden by OTP configuration. It + is possible the BD73800 does not output a clock signal. Hence the clk + properties are optional. + maxItems: 1 + + "#clock-cells": + const: 0 + + clock-output-names: + maxItems: 1 + + rohm,clkout-open-drain: true + + regulators: + $ref: /schemas/regulator/rohm,bd73800-regulator.yaml + description: + List of child nodes that specify the regulators. + +required: + - compatible + - reg + - interrupts + - regulators + +additionalProperties: false + +examples: + - | + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + pmic: pmic@4b { + compatible = "rohm,bd73800"; + reg = <0x4b>; + + interrupt-parent = <&gpio1>; + interrupts = <29 IRQ_TYPE_LEVEL_LOW>; + + clocks = <&osc 0>; + #clock-cells = <0>; + clock-output-names = "bd73800-32k-out"; + + gpio-controller; + #gpio-cells = <2>; + + rohm,pin-gpio1 = "gpo"; + rohm,pin-exten = "gpi"; + + regulators { + buck1: buck1 { + regulator-name = "buck1"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <2000000>; + regulator-always-on; + regulator-ramp-delay = <1250>; + rohm,dvs-run-voltage = <1150000>; + rohm,dvs-suspend-voltage = <950000>; + }; + buck2: buck2 { + regulator-name = "buck2"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <2000000>; + regulator-always-on; + regulator-ramp-delay = <1250>; + rohm,dvs-run-voltage = <1150000>; + rohm,dvs-suspend-voltage = <950000>; + }; + buck3: buck3 { + regulator-name = "buck3"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <2700000>; + rohm,dvs-run-voltage = <1150000>; + rohm,dvs-idle-voltage = <1100000>; + rohm,dvs-suspend-voltage = <950000>; + regulator-always-on; + }; + buck4: buck4 { + regulator-name = "buck4"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1850000>; + regulator-always-on; + }; + buck5: buck5 { + regulator-name = "buck5"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + buck6: buck6 { + regulator-name = "buck6"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + buck7: buck7 { + regulator-name = "buck7"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + buck8: buck8 { + regulator-name = "buck8"; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1300000>; + regulator-always-on; + }; + ldo1: ldo1 { + regulator-name = "ldo1"; + rohm,ldo-range-high; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + ldo2: ldo2 { + regulator-name = "ldo2"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + ldo3: ldo3 { + regulator-name = "ldo3"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + ldo4: ldo4 { + regulator-name = "ldo4"; + regulator-min-microvolt = <650000>; + regulator-max-microvolt = <1750000>; + regulator-always-on; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/mfd/rohm,pmic-pins.yaml b/Documentation/devicetree/bindings/mfd/rohm,pmic-pins.yaml new file mode 100644 index 000000000000..0d1082804f5a --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/rohm,pmic-pins.yaml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/rohm,pmic-pins.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ROHM PMICs' OTP configured pin descriptions + +maintainers: + - Matti Vaittinen + +description: + Collection of properties which are commonly used to describe various + ROHM PMIC's pins. + +properties: + rohm,clkout-open-drain: + description: clk32kout mode. Set to 1 for "open-drain" or 0 for "cmos" + a.k.a "push-pull". + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 1 + + rohm,pin-clkout: + $ref: /schemas/types.yaml#/definitions/string + description: + The IC has different OTP options to use clkout-pin for different + purposes. Set this property to indicate the OTP variant. + + Many of the ROHM ICs have pins, which function can be defined in + OTP. Some of them provide no means to detect the pin configuration + at run-time, leaving software unaware of which features the IC + really has. These properties can be used to inform which pins + provide which functionality. IOW, these properties aren't used to + configure pin, they are used to tell what functionality pins on + this specific IC have. + + # Supported functionalities depend on the exact IC model. Following + # values are already defined: gpi, gpo. + # Please, re-use them when adding new ICs. + + rohm,pin-fault_b: + $ref: /schemas/types.yaml#/definitions/string + description: + The IC has different OTP options to use fault_b-pin for different + purposes. Set this property to indicate the OTP variant. + + # Supported functionalities depend on the exact IC model. Following + # values are already defined: gpi, gpo, faultb, readyind, pwrseq. + # Please, re-use them when adding new ICs. + +patternProperties: + "^rohm,pin-dvs[0-1]$": + $ref: /schemas/types.yaml#/definitions/string + description: + The IC has different OTP options to use dvs-pins for different + purposes. Set this property to indicate the OTP variant. + # Supported functionalities depend on the exact IC model. Following + # values are already defined: dvs-input, gpi, gpo, pwrseq. + # Please, re-use them when adding new ICs. + + "^rohm,pin-exten([0-1])?$": + $ref: /schemas/types.yaml#/definitions/string + description: + The IC has an OTP option to use exten -pin(s) for different purposes. + Set this property to indicate the OTP variant. + # Supported functionalities depend on the exact IC model. Following + # values are already defined: gpi, gpo, pwrseq. + # Please, re-use them when adding new ICs. + +# The schema is expected to be reference by IC schemas, which may introduce +# other properties that must be allowed. +additionalProperties: true diff --git a/Documentation/devicetree/bindings/mfd/stericsson,ab8500.yaml b/Documentation/devicetree/bindings/mfd/stericsson,ab8500.yaml index 0fdfbfdfe88a..873e08266a2b 100644 --- a/Documentation/devicetree/bindings/mfd/stericsson,ab8500.yaml +++ b/Documentation/devicetree/bindings/mfd/stericsson,ab8500.yaml @@ -312,6 +312,33 @@ properties: items: - const: audioclk + '#sound-dai-cells': + description: Selects one of the two digital audio interfaces + const: 1 + + ports: + $ref: /schemas/sound/audio-graph-port.yaml#/definitions/ports + + stericsson,amic1-type-single-ended: + description: Configure analog microphone 1 as single-ended + type: boolean + + stericsson,amic2-type-single-ended: + description: Configure analog microphone 2 as single-ended + type: boolean + + stericsson,amic1a-bias-vamic2: + description: Supply analog microphone 1A from VAMIC2 instead of VAMIC1 + type: boolean + + stericsson,amic1b-bias-vamic2: + description: Supply analog microphone 1B from VAMIC2 instead of VAMIC1 + type: boolean + + stericsson,amic2-bias-vamic1: + description: Supply analog microphone 2 from VAMIC1 instead of VAMIC2 + type: boolean + stericsson,earpeice-cmv: description: Earpiece voltage $ref: /schemas/types.yaml#/definitions/uint32 @@ -319,6 +346,7 @@ properties: required: - compatible + - '#sound-dai-cells' additionalProperties: false diff --git a/Documentation/devicetree/bindings/regulator/rohm,bd73800-regulator.yaml b/Documentation/devicetree/bindings/regulator/rohm,bd73800-regulator.yaml new file mode 100644 index 000000000000..2db4585272c5 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/rohm,bd73800-regulator.yaml @@ -0,0 +1,99 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/regulator/rohm,bd73800-regulator.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ROHM BD73800 Power Management Integrated Circuit regulators + +maintainers: + - Matti Vaittinen + +description: | + This module is part of the ROHM BD73800 MFD device. For more details + see Documentation/devicetree/bindings/mfd/rohm,bd73800-pmic.yaml. + + The regulator controller is represented as a sub-node of the PMIC node + on the device tree. + + Regulator nodes should be named to buck and ldo. + The valid names for BD73800 regulator nodes are + buck1, buck2, buck3, buck4, buck5, buck6, buck7, buck8 + ldo1, ldo2, ldo3, ldo4 + +patternProperties: + "^buck[1-8]$": + type: object + description: + Properties for a single BUCK regulator. + allOf: + - $ref: regulator.yaml# + - $ref: rohm,pmic-states.yaml# + + properties: + regulator-name: + pattern: "^buck[1-8]$" + description: + should be "buck1", ..., "buck8" + + rohm,dvs-run-voltage: + minimum: 0 + maximum: 3500000 + + rohm,dvs-idle-voltage: + minimum: 0 + maximum: 3500000 + + rohm,dvs-suspend-voltage: + minimum: 0 + maximum: 3500000 + + # BUCKs 1,2,3,4 and 8 support voltages 0.5 - 1.3V + # BUCK 5 supports voltages 0.3 - 1.3V + # BUCKs 6 and 7 support voltages 1.5 - 3.5V + + required: + - regulator-name + + unevaluatedProperties: false + + "^ldo[1-4]$": + type: object + description: + Properties for single LDO regulator. + allOf: + - $ref: regulator.yaml# + - $ref: rohm,pmic-states.yaml# + + properties: + regulator-name: + pattern: "^ldo[1-4]$" + description: + should be "ldo1", ..., "ldo4" + + rohm,dvs-run-voltage: + minimum: 0 + maximum: 1 + + rohm,dvs-idle-voltage: + minimum: 0 + maximum: 1 + + rohm,dvs-suspend-voltage: + minimum: 0 + maximum: 1 + + rohm,ldo-range-high: + type: boolean + description: + LDO1 and LDO3 voltage ranges can be "high" or "low" depending on + OTP. Indicate that the "high" range is used. See comment below + for voltages. + + # LDOs 2 and 4 support voltages 0.75 - 3.3V + # LDOs 1 and 3 may support different ranges depending on OTP. + # either 0.6 - 1.8V or 0.75 - 3.3V. + + unevaluatedProperties: false + +additionalProperties: false diff --git a/MAINTAINERS b/MAINTAINERS index 3a19da74d00c..b0925fa212cc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23821,6 +23821,7 @@ F: drivers/clk/clk-bd718x7.c F: drivers/gpio/gpio-bd71815.c F: drivers/gpio/gpio-bd71828.c F: drivers/gpio/gpio-bd72720.c +F: drivers/gpio/gpio-bd73800.c F: drivers/mfd/rohm-bd71828.c F: drivers/mfd/rohm-bd718x7.c F: drivers/mfd/rohm-bd9576.c @@ -23840,6 +23841,7 @@ F: include/linux/mfd/rohm-bd71815.h F: include/linux/mfd/rohm-bd71828.h F: include/linux/mfd/rohm-bd718x7.h F: include/linux/mfd/rohm-bd72720.h +F: include/linux/mfd/rohm-bd73800.h F: include/linux/mfd/rohm-bd957x.h F: include/linux/mfd/rohm-bd96801.h F: include/linux/mfd/rohm-bd96802.h diff --git a/drivers/clk/clk-bd718x7.c b/drivers/clk/clk-bd718x7.c index 8ddb50c67757..1698b763bcb7 100644 --- a/drivers/clk/clk-bd718x7.c +++ b/drivers/clk/clk-bd718x7.c @@ -21,6 +21,9 @@ #define BD718XX_REG_OUT32K 0x2E /* BD72720 */ #define BD72720_REG_OUT32K 0x9a +/* BD73800 */ +#define BD73800_REG_OUT32K 0x50 + /* * BD71837, BD71847, and BD71828 all use bit [0] to clk output control */ @@ -123,6 +126,10 @@ static int bd71837_clk_probe(struct platform_device *pdev) c->reg = BD72720_REG_OUT32K; c->mask = CLK_OUT_EN_MASK; break; + case ROHM_CHIP_TYPE_BD73800: + c->reg = BD73800_REG_OUT32K; + c->mask = CLK_OUT_EN_MASK; + break; default: dev_err(&pdev->dev, "Unknown clk chip\n"); return -EINVAL; @@ -152,6 +159,7 @@ static const struct platform_device_id bd718x7_clk_id[] = { { .name = "bd71828-clk", .driver_data = ROHM_CHIP_TYPE_BD71828 }, { .name = "bd71815-clk", .driver_data = ROHM_CHIP_TYPE_BD71815 }, { .name = "bd72720-clk", .driver_data = ROHM_CHIP_TYPE_BD72720 }, + { .name = "bd73800-clk", .driver_data = ROHM_CHIP_TYPE_BD73800 }, { } }; MODULE_DEVICE_TABLE(platform, bd718x7_clk_id); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index a48586bb8edb..64127740a248 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1385,6 +1385,18 @@ config GPIO_BD72720 be configured to GPO on the ROHM PMIC. The pin configuration is done on OTP at manufacturing. +config GPIO_BD73800 + tristate "ROHM BD73800 GPIO support" + depends on MFD_ROHM_BD71828 + select GPIO_REGMAP + help + Support for GPIOs on ROHM BD73800 PMIC. There can be up to 4 + GPI or GPO pins available on the PMIC in total. The purpose of + the pins is decided at the device manufacturing by OTP + configuration and can't be reconfigured later. Enable this + if your PMIC has pins set as GPIs or GPOs and if you wish to + control the pins via the GPIO framework. + config GPIO_BD9571MWV tristate "ROHM BD9571 GPIO support" depends on MFD_BD9571MWV diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index dc9e6d643b5b..dc5e0583e328 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_GPIO_BCM_XGS_IPROC) += gpio-xgs-iproc.o obj-$(CONFIG_GPIO_BD71815) += gpio-bd71815.o obj-$(CONFIG_GPIO_BD71828) += gpio-bd71828.o obj-$(CONFIG_GPIO_BD72720) += gpio-bd72720.o +obj-$(CONFIG_GPIO_BD73800) += gpio-bd73800.o obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o obj-$(CONFIG_GPIO_BLZP1600) += gpio-blzp1600.o obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o diff --git a/drivers/gpio/gpio-bd73800.c b/drivers/gpio/gpio-bd73800.c new file mode 100644 index 000000000000..2be2a885820e --- /dev/null +++ b/drivers/gpio/gpio-bd73800.c @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Support to GPIOs on ROHM BD73800 + * Copyright 2024 ROHM Semiconductors. + * Author: Matti Vaittinen + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define BD73800_GPIO_MAX_PINS 4 +/* + * The BD73800 has several "one time programmable" (OTP) configurations which + * can be set at manufacturing phase. Some of these options allow using + * individual pins as GPI or GPO (not both at the same time). The OTP + * configuration can't be read at run-time, so drivers rely on device-tree to + * advertise the OTP programmed in manufacturing. + * + * The pins which can be used as GPIO are: + * GPIO1, CLKOUT (GPIO2), FAULT_B, EXTEN_OUT. + * + * The OTP options 2 and 3 state for all the pins: + * - OTP2: GPI (also IRQ source) + * - OTP3: GPO (NOTE: This is actually 2 different OTP options. Either a + * register controllable output or a power-sequence controlled output. + * The "gpo" referred here means only the register controllable output.) + * The datasheet refers to this as: " output is controlled by + * GPIO_OUT or power on/off sequencer to control external VRs. ON/OFF + * sequence timing is configurable." + * + * The data-sheet further says that the GPI/GPO is not a default OTP + * configuration for any of the pins. Hence the GPIO driver defaults to a pin + * not being a GPI or GPO, but requires the pin to be explicitly marked as a + * GPI or GPO in the device-tree. + * + * DT properties: + * "rohm,pin-gpio1", "rohm,pin-clkout", "rohm,pin-fault_b", "rohm,pin-exten" + * can be set to one of the values "gpi" or "gpo" to enable them to be used as + * GPIO. + * + * The amount of GPIO lines the chip exposes to the user-space (chip.ngpio) is + * always the same, regardless of the OTP variant in use. The lines which are + * not usable as GPIO on a given OTP variant are marked invalid via the GPIO + * valid_mask. This way the user-space always sees a constant amount of GPIO + * lines, where numbering (relative to the chip's base) stays also the same. + * Users can then use the valid_mask to find out which of the lines are usable. + */ + +struct bd73800_gpio { + /* dev points to the platform device for devm and prints */ + struct device *dev; + struct regmap *regmap; + /* Pins which have been OTP configured as GPI or GPO */ + DECLARE_BITMAP(valid_mask, BD73800_GPIO_MAX_PINS); + /* Subset of valid_mask - pins which have been OTP configured as GPO */ + DECLARE_BITMAP(output_mask, BD73800_GPIO_MAX_PINS); +}; + +static const char * const bd73800_gpio_properties[BD73800_GPIO_MAX_PINS] = { + "rohm,pin-gpio1", + "rohm,pin-clkout", + "rohm,pin-fault_b", + "rohm,pin-exten" +}; + +static int bd73800_gpio_get_pins(struct bd73800_gpio *data) +{ + struct device *parent = data->dev->parent; + const char *val; + int i, ret; + + for (i = 0; i < BD73800_GPIO_MAX_PINS; i++) { + ret = device_property_read_string(parent, + bd73800_gpio_properties[i], + &val); + if (ret) { + if (ret == -EINVAL) + continue; + + return dev_err_probe(data->dev, ret, + "pin %d (%s), bad configuration\n", i, + bd73800_gpio_properties[i]); + } + + if (!strcmp(val, "gpi")) { + __set_bit(i, data->valid_mask); + } else if (!strcmp(val, "gpo")) { + __set_bit(i, data->valid_mask); + __set_bit(i, data->output_mask); + } else { + dev_warn(data->dev, + "pin %d (%s), unknown value '%s' ignored\n", i, + bd73800_gpio_properties[i], val); + } + } + + return 0; +} + +static int bd73800_gpio_init_valid_mask(struct gpio_chip *gc, + unsigned long *valid_mask, + unsigned int ngpios) +{ + struct gpio_regmap *gpio = gpiochip_get_data(gc); + struct bd73800_gpio *data = gpio_regmap_get_drvdata(gpio); + + bitmap_copy(valid_mask, data->valid_mask, ngpios); + + return 0; +} + +/* + * The used register depends on OTP: + * - If OTP has set pin as GPO, only the GPO_OUT register is valid. + * - If OTP has set pin as GPI, only the INT_5_SRC register is valid. + */ +static int bd73800_gpio_reg_mask_xlate(struct gpio_regmap *gpio, + enum gpio_regmap_operation op, + unsigned int base, unsigned int offset, + unsigned int *reg, unsigned int *mask) +{ + struct bd73800_gpio *data = gpio_regmap_get_drvdata(gpio); + bool is_output = test_bit(offset, data->output_mask); + + if (is_output) + *reg = BD73800_REG_GPO_OUT; + else + *reg = base; + + *mask = BIT(offset); + + return 0; +} + +static int gpo_bd73800_probe(struct platform_device *pdev) +{ + struct gpio_regmap_config config = { }; + struct bd73800_gpio *data; + struct device *parent, *dev; + int ret; + + dev = &pdev->dev; + /* The device-tree and regmap come from MFD => use parent for that */ + parent = dev->parent; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->dev = dev; + data->regmap = dev_get_regmap(parent, NULL); + if (!data->regmap) + return dev_err_probe(dev, -ENODEV, "no parent regmap\n"); + + ret = bd73800_gpio_get_pins(data); + if (ret) + return ret; + + if (bitmap_empty(data->valid_mask, BD73800_GPIO_MAX_PINS)) { + /* + * The BD73800 may or may not have pins allocated for GPIO + * depending on the OTP used at manufacturing. + * If there are no pins, then we have nothing to do. + */ + dev_dbg(dev, "no GPIO pins\n"); + return -ENODEV; + } + + config.parent = parent; + config.regmap = data->regmap; + config.label = "bd73800"; + config.ngpio = BD73800_GPIO_MAX_PINS; + config.reg_dat_base = BD73800_REG_INT_5_SRC; + config.reg_set_base = BD73800_REG_GPO_OUT; + config.reg_mask_xlate = bd73800_gpio_reg_mask_xlate; + config.init_valid_mask = bd73800_gpio_init_valid_mask; + /* All pins that are valid GPIO lines also have a fixed direction */ + config.fixed_direction_mask = data->valid_mask; + config.fixed_direction_output = data->output_mask; + config.drvdata = data; + + return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &config)); +} + +static const struct platform_device_id bd73800_gpio_id[] = { + { "bd73800-gpio" }, + { }, +}; +MODULE_DEVICE_TABLE(platform, bd73800_gpio_id); + +static struct platform_driver gpo_bd73800_driver = { + .driver = { + .name = "bd73800-gpio", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, + .probe = gpo_bd73800_probe, + .id_table = bd73800_gpio_id, +}; +module_platform_driver(gpo_bd73800_driver); + +MODULE_AUTHOR("Matti Vaittinen "); +MODULE_DESCRIPTION("GPIO interface for BD73800"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/light/lm3533-als.c b/drivers/iio/light/lm3533-als.c index 99f0b903018c..4870e8050088 100644 --- a/drivers/iio/light/lm3533-als.c +++ b/drivers/iio/light/lm3533-als.c @@ -17,14 +17,17 @@ #include #include #include +#include +#include #include #include +#include #include -#define LM3533_ALS_RESISTOR_MIN 1 -#define LM3533_ALS_RESISTOR_MAX 127 +#define LM3533_ALS_RESISTOR_MIN_OHMS 1575 +#define LM3533_ALS_RESISTOR_MAX_OHMS 200000 #define LM3533_ALS_CHANNEL_CURRENT_MAX 2 #define LM3533_ALS_THRESH_MAX 3 #define LM3533_ALS_ZONE_MAX 4 @@ -48,7 +51,7 @@ struct lm3533_als { - struct lm3533 *lm3533; + struct regmap *regmap; struct platform_device *pdev; unsigned long flags; @@ -56,6 +59,9 @@ struct lm3533_als { atomic_t zone; struct mutex thresh_mutex; + + u32 r_select; + bool pwm_mode; }; @@ -64,7 +70,7 @@ static int lm3533_als_get_adc(struct iio_dev *indio_dev, bool average, { struct lm3533_als *als = iio_priv(indio_dev); u8 reg; - u8 val; + u32 val; int ret; if (average) @@ -72,7 +78,7 @@ static int lm3533_als_get_adc(struct iio_dev *indio_dev, bool average, else reg = LM3533_REG_ALS_READ_ADC_RAW; - ret = lm3533_read(als->lm3533, reg, &val); + ret = regmap_read(als->regmap, reg, &val); if (ret) { dev_err(&indio_dev->dev, "failed to read adc\n"); return ret; @@ -86,10 +92,10 @@ static int lm3533_als_get_adc(struct iio_dev *indio_dev, bool average, static int _lm3533_als_get_zone(struct iio_dev *indio_dev, u8 *zone) { struct lm3533_als *als = iio_priv(indio_dev); - u8 val; + u32 val; int ret; - ret = lm3533_read(als->lm3533, LM3533_REG_ALS_ZONE_INFO, &val); + ret = regmap_read(als->regmap, LM3533_REG_ALS_ZONE_INFO, &val); if (ret) { dev_err(&indio_dev->dev, "failed to read zone\n"); return ret; @@ -127,7 +133,7 @@ static inline u8 lm3533_als_get_target_reg(unsigned channel, unsigned zone) } static int lm3533_als_get_target(struct iio_dev *indio_dev, unsigned channel, - unsigned zone, u8 *val) + unsigned zone, u32 *val) { struct lm3533_als *als = iio_priv(indio_dev); u8 reg; @@ -140,7 +146,7 @@ static int lm3533_als_get_target(struct iio_dev *indio_dev, unsigned channel, return -EINVAL; reg = lm3533_als_get_target_reg(channel, zone); - ret = lm3533_read(als->lm3533, reg, val); + ret = regmap_read(als->regmap, reg, val); if (ret) dev_err(&indio_dev->dev, "failed to get target current\n"); @@ -161,7 +167,7 @@ static int lm3533_als_set_target(struct iio_dev *indio_dev, unsigned channel, return -EINVAL; reg = lm3533_als_get_target_reg(channel, zone); - ret = lm3533_write(als->lm3533, reg, val); + ret = regmap_write(als->regmap, reg, val); if (ret) dev_err(&indio_dev->dev, "failed to set target current\n"); @@ -171,8 +177,8 @@ static int lm3533_als_set_target(struct iio_dev *indio_dev, unsigned channel, static int lm3533_als_get_current(struct iio_dev *indio_dev, unsigned channel, int *val) { + u32 target; u8 zone; - u8 target; int ret; ret = lm3533_als_get_zone(indio_dev, &zone); @@ -271,16 +277,10 @@ static irqreturn_t lm3533_als_isr(int irq, void *dev_id) static int lm3533_als_set_int_mode(struct iio_dev *indio_dev, int enable) { struct lm3533_als *als = iio_priv(indio_dev); - u8 mask = LM3533_ALS_INT_ENABLE_MASK; - u8 val; int ret; - if (enable) - val = mask; - else - val = 0; - - ret = lm3533_update(als->lm3533, LM3533_REG_ALS_ZONE_INFO, val, mask); + ret = regmap_assign_bits(als->regmap, LM3533_REG_ALS_ZONE_INFO, + LM3533_ALS_INT_ENABLE_MASK, enable); if (ret) { dev_err(&indio_dev->dev, "failed to set int mode %d\n", enable); @@ -293,17 +293,16 @@ static int lm3533_als_set_int_mode(struct iio_dev *indio_dev, int enable) static int lm3533_als_get_int_mode(struct iio_dev *indio_dev, int *enable) { struct lm3533_als *als = iio_priv(indio_dev); - u8 mask = LM3533_ALS_INT_ENABLE_MASK; - u8 val; int ret; - ret = lm3533_read(als->lm3533, LM3533_REG_ALS_ZONE_INFO, &val); - if (ret) { + ret = regmap_test_bits(als->regmap, LM3533_REG_ALS_ZONE_INFO, + LM3533_ALS_INT_ENABLE_MASK); + if (ret < 0) { dev_err(&indio_dev->dev, "failed to get int mode\n"); return ret; } - *enable = !!(val & mask); + *enable = ret; return 0; } @@ -316,7 +315,7 @@ static inline u8 lm3533_als_get_threshold_reg(unsigned nr, bool raising) } static int lm3533_als_get_threshold(struct iio_dev *indio_dev, unsigned nr, - bool raising, u8 *val) + bool raising, u32 *val) { struct lm3533_als *als = iio_priv(indio_dev); u8 reg; @@ -326,7 +325,7 @@ static int lm3533_als_get_threshold(struct iio_dev *indio_dev, unsigned nr, return -EINVAL; reg = lm3533_als_get_threshold_reg(nr, raising); - ret = lm3533_read(als->lm3533, reg, val); + ret = regmap_read(als->regmap, reg, val); if (ret) dev_err(&indio_dev->dev, "failed to get threshold\n"); @@ -337,8 +336,8 @@ static int lm3533_als_set_threshold(struct iio_dev *indio_dev, unsigned nr, bool raising, u8 val) { struct lm3533_als *als = iio_priv(indio_dev); - u8 val2; u8 reg, reg2; + u32 val2; int ret; if (nr > LM3533_ALS_THRESH_MAX) @@ -348,7 +347,7 @@ static int lm3533_als_set_threshold(struct iio_dev *indio_dev, unsigned nr, reg2 = lm3533_als_get_threshold_reg(nr, !raising); mutex_lock(&als->thresh_mutex); - ret = lm3533_read(als->lm3533, reg2, &val2); + ret = regmap_read(als->regmap, reg2, &val2); if (ret) { dev_err(&indio_dev->dev, "failed to get threshold\n"); goto out; @@ -363,7 +362,7 @@ static int lm3533_als_set_threshold(struct iio_dev *indio_dev, unsigned nr, goto out; } - ret = lm3533_write(als->lm3533, reg, val); + ret = regmap_write(als->regmap, reg, val); if (ret) { dev_err(&indio_dev->dev, "failed to set threshold\n"); goto out; @@ -375,11 +374,11 @@ static int lm3533_als_set_threshold(struct iio_dev *indio_dev, unsigned nr, } static int lm3533_als_get_hysteresis(struct iio_dev *indio_dev, unsigned nr, - u8 *val) + u32 *val) { struct lm3533_als *als = iio_priv(indio_dev); - u8 falling; - u8 raising; + u32 falling; + u32 raising; int ret; if (nr > LM3533_ALS_THRESH_MAX) @@ -409,7 +408,7 @@ static ssize_t show_thresh_either_en(struct device *dev, int enable; int ret; - if (als->irq) { + if (als->irq > 0) { ret = lm3533_als_get_int_mode(indio_dev, &enable); if (ret) return ret; @@ -431,7 +430,7 @@ static ssize_t store_thresh_either_en(struct device *dev, u8 zone; int ret; - if (!als->irq) + if (als->irq <= 0) return -EBUSY; if (kstrtoul(buf, 0, &enable)) @@ -503,7 +502,7 @@ static ssize_t show_als_attr(struct device *dev, { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct lm3533_als_attribute *als_attr = to_lm3533_als_attr(attr); - u8 val; + u32 val; int ret; switch (als_attr->type) { @@ -714,71 +713,51 @@ static const struct attribute_group lm3533_als_attribute_group = { .attrs = lm3533_als_attributes }; -static int lm3533_als_set_input_mode(struct lm3533_als *als, bool pwm_mode) +static int lm3533_als_setup(struct lm3533_als *als) { - u8 mask = LM3533_ALS_INPUT_MODE_MASK; - u8 val; + struct device *dev = &als->pdev->dev; int ret; - if (pwm_mode) - val = mask; /* pwm input */ - else - val = 0; /* analog input */ + als->pwm_mode = device_property_read_bool(dev, "ti,pwm-mode"); - ret = lm3533_update(als->lm3533, LM3533_REG_ALS_CONF, val, mask); - if (ret) { - dev_err(&als->pdev->dev, "failed to set input mode %d\n", - pwm_mode); - return ret; - } - - return 0; -} - -static int lm3533_als_set_resistor(struct lm3533_als *als, u8 val) -{ - int ret; - - if (val < LM3533_ALS_RESISTOR_MIN || val > LM3533_ALS_RESISTOR_MAX) { - dev_err(&als->pdev->dev, "invalid resistor value\n"); - return -EINVAL; - } - - ret = lm3533_write(als->lm3533, LM3533_REG_ALS_RESISTOR_SELECT, val); - if (ret) { - dev_err(&als->pdev->dev, "failed to set resistor\n"); - return ret; - } - - return 0; -} - -static int lm3533_als_setup(struct lm3533_als *als, - const struct lm3533_als_platform_data *pdata) -{ - int ret; - - ret = lm3533_als_set_input_mode(als, pdata->pwm_mode); + ret = regmap_assign_bits(als->regmap, LM3533_REG_ALS_CONF, + LM3533_ALS_INPUT_MODE_MASK, als->pwm_mode); if (ret) - return ret; + return dev_err_probe(dev, ret, "failed to set input mode %d\n", + als->pwm_mode); /* ALS input is always high impedance in PWM-mode. */ - if (!pdata->pwm_mode) { - ret = lm3533_als_set_resistor(als, pdata->r_select); - if (ret) - return ret; - } + if (als->pwm_mode) + return 0; + + ret = device_property_read_u32(dev, "ti,resistor-ohms", + &als->r_select); + if (ret) + return dev_err_probe(dev, ret, + "failed to ger resistor value\n"); + + if (als->r_select < LM3533_ALS_RESISTOR_MIN_OHMS || + als->r_select > LM3533_ALS_RESISTOR_MAX_OHMS) + return dev_err_probe(dev, -EINVAL, + "invalid resistor value\n"); + + als->r_select = DIV_ROUND_UP(2 * MICRO, 10 * als->r_select); + + ret = regmap_write(als->regmap, LM3533_REG_ALS_RESISTOR_SELECT, + als->r_select); + if (ret) + return dev_err_probe(dev, ret, "failed to set resistor\n"); return 0; } static int lm3533_als_setup_irq(struct lm3533_als *als, void *dev) { - u8 mask = LM3533_ALS_INT_ENABLE_MASK; int ret; /* Make sure interrupts are disabled. */ - ret = lm3533_update(als->lm3533, LM3533_REG_ALS_ZONE_INFO, 0, mask); + ret = regmap_clear_bits(als->regmap, LM3533_REG_ALS_ZONE_INFO, + LM3533_ALS_INT_ENABLE_MASK); if (ret) { dev_err(&als->pdev->dev, "failed to disable interrupts\n"); return ret; @@ -798,10 +777,10 @@ static int lm3533_als_setup_irq(struct lm3533_als *als, void *dev) static int lm3533_als_enable(struct lm3533_als *als) { - u8 mask = LM3533_ALS_ENABLE_MASK; int ret; - ret = lm3533_update(als->lm3533, LM3533_REG_ALS_CONF, mask, mask); + ret = regmap_set_bits(als->regmap, LM3533_REG_ALS_CONF, + LM3533_ALS_ENABLE_MASK); if (ret) dev_err(&als->pdev->dev, "failed to enable ALS\n"); @@ -810,10 +789,10 @@ static int lm3533_als_enable(struct lm3533_als *als) static int lm3533_als_disable(struct lm3533_als *als) { - u8 mask = LM3533_ALS_ENABLE_MASK; int ret; - ret = lm3533_update(als->lm3533, LM3533_REG_ALS_CONF, 0, mask); + ret = regmap_clear_bits(als->regmap, LM3533_REG_ALS_CONF, + LM3533_ALS_ENABLE_MASK); if (ret) dev_err(&als->pdev->dev, "failed to disable ALS\n"); @@ -828,7 +807,6 @@ static const struct iio_info lm3533_als_info = { static int lm3533_als_probe(struct platform_device *pdev) { - const struct lm3533_als_platform_data *pdata; struct lm3533 *lm3533; struct lm3533_als *als; struct iio_dev *indio_dev; @@ -838,12 +816,6 @@ static int lm3533_als_probe(struct platform_device *pdev) if (!lm3533) return -EINVAL; - pdata = dev_get_platdata(&pdev->dev); - if (!pdata) { - dev_err(&pdev->dev, "no platform data\n"); - return -EINVAL; - } - indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*als)); if (!indio_dev) return -ENOMEM; @@ -852,25 +824,27 @@ static int lm3533_als_probe(struct platform_device *pdev) indio_dev->channels = lm3533_als_channels; indio_dev->num_channels = ARRAY_SIZE(lm3533_als_channels); indio_dev->name = dev_name(&pdev->dev); - iio_device_set_parent(indio_dev, pdev->dev.parent); indio_dev->modes = INDIO_DIRECT_MODE; als = iio_priv(indio_dev); - als->lm3533 = lm3533; + als->regmap = lm3533->regmap; als->pdev = pdev; - als->irq = lm3533->irq; + als->irq = platform_get_irq_optional(pdev, 0); + if (als->irq == -EPROBE_DEFER) + return -EPROBE_DEFER; + atomic_set(&als->zone, 0); mutex_init(&als->thresh_mutex); platform_set_drvdata(pdev, indio_dev); - if (als->irq) { + if (als->irq > 0) { ret = lm3533_als_setup_irq(als, indio_dev); if (ret) return ret; } - ret = lm3533_als_setup(als, pdata); + ret = lm3533_als_setup(als); if (ret) goto err_free_irq; @@ -889,7 +863,7 @@ static int lm3533_als_probe(struct platform_device *pdev) err_disable: lm3533_als_disable(als); err_free_irq: - if (als->irq) + if (als->irq > 0) free_irq(als->irq, indio_dev); return ret; @@ -903,13 +877,20 @@ static void lm3533_als_remove(struct platform_device *pdev) lm3533_als_set_int_mode(indio_dev, false); iio_device_unregister(indio_dev); lm3533_als_disable(als); - if (als->irq) + if (als->irq > 0) free_irq(als->irq, indio_dev); } +static const struct of_device_id lm3533_als_match_table[] = { + { .compatible = "ti,lm3533-als" }, + { } +}; +MODULE_DEVICE_TABLE(of, lm3533_als_match_table); + static struct platform_driver lm3533_als_driver = { .driver = { .name = "lm3533-als", + .of_match_table = lm3533_als_match_table, }, .probe = lm3533_als_probe, .remove = lm3533_als_remove, diff --git a/drivers/leds/leds-lm3533.c b/drivers/leds/leds-lm3533.c index 45795f2a1042..7259097bd6a7 100644 --- a/drivers/leds/leds-lm3533.c +++ b/drivers/leds/leds-lm3533.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include @@ -41,13 +43,18 @@ struct lm3533_led { - struct lm3533 *lm3533; + struct regmap *regmap; struct lm3533_ctrlbank cb; struct led_classdev cdev; int id; struct mutex mutex; unsigned long flags; + + u32 max_current; + u32 pwm; + + bool have_als; }; @@ -80,7 +87,6 @@ static inline u8 lm3533_led_get_pattern_reg(struct lm3533_led *led, static int lm3533_led_pattern_enable(struct lm3533_led *led, int enable) { u8 mask; - u8 val; int pattern; int state; int ret = 0; @@ -96,12 +102,8 @@ static int lm3533_led_pattern_enable(struct lm3533_led *led, int enable) pattern = lm3533_led_get_pattern(led); mask = 1 << (2 * pattern); - if (enable) - val = mask; - else - val = 0; - - ret = lm3533_update(led->lm3533, LM3533_REG_PATTERN_ENABLE, val, mask); + ret = regmap_assign_bits(led->regmap, + LM3533_REG_PATTERN_ENABLE, mask, enable); if (ret) { dev_err(led->cdev.dev, "failed to enable pattern %d (%d)\n", pattern, enable); @@ -131,7 +133,7 @@ static int lm3533_led_set(struct led_classdev *cdev, static enum led_brightness lm3533_led_get(struct led_classdev *cdev) { struct lm3533_led *led = to_lm3533_led(cdev); - u8 val; + u32 val; int ret; ret = lm3533_ctrlbank_get_brightness(&led->cb, &val); @@ -259,7 +261,7 @@ static u8 lm3533_led_delay_set(struct lm3533_led *led, u8 base, dev_dbg(led->cdev.dev, "%s - %lu: %u (0x%02x)\n", __func__, *delay, t, val); reg = lm3533_led_get_pattern_reg(led, base); - ret = lm3533_write(led->lm3533, reg, val); + ret = regmap_write(led->regmap, reg, val); if (ret) dev_err(led->cdev.dev, "failed to set delay (%02x)\n", reg); @@ -337,10 +339,10 @@ static ssize_t show_risefalltime(struct device *dev, struct lm3533_led *led = to_lm3533_led(led_cdev); ssize_t ret; u8 reg; - u8 val; + u32 val; reg = lm3533_led_get_pattern_reg(led, base); - ret = lm3533_read(led->lm3533, reg, &val); + ret = regmap_read(led->regmap, reg, &val); if (ret) return ret; @@ -375,7 +377,7 @@ static ssize_t store_risefalltime(struct device *dev, return -EINVAL; reg = lm3533_led_get_pattern_reg(led, base); - ret = lm3533_write(led->lm3533, reg, val); + ret = regmap_write(led->regmap, reg, val); if (ret) return ret; @@ -405,11 +407,11 @@ static ssize_t show_als_channel(struct device *dev, struct lm3533_led *led = to_lm3533_led(led_cdev); unsigned channel; u8 reg; - u8 val; + u32 val; int ret; reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE); - ret = lm3533_read(led->lm3533, reg, &val); + ret = regmap_read(led->regmap, reg, &val); if (ret) return ret; @@ -441,7 +443,7 @@ static ssize_t store_als_channel(struct device *dev, mask = LM3533_REG_CTRLBANK_BCONF_ALS_CHANNEL_MASK; val = channel - 1; - ret = lm3533_update(led->lm3533, reg, val, mask); + ret = regmap_update_bits(led->regmap, reg, mask, val); if (ret) return ret; @@ -455,11 +457,11 @@ static ssize_t show_als_en(struct device *dev, struct lm3533_led *led = to_lm3533_led(led_cdev); bool enable; u8 reg; - u8 val; + u32 val; int ret; reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE); - ret = lm3533_read(led->lm3533, reg, &val); + ret = regmap_read(led->regmap, reg, &val); if (ret) return ret; @@ -476,22 +478,15 @@ static ssize_t store_als_en(struct device *dev, struct lm3533_led *led = to_lm3533_led(led_cdev); unsigned enable; u8 reg; - u8 mask; - u8 val; int ret; if (kstrtouint(buf, 0, &enable)) return -EINVAL; reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE); - mask = LM3533_REG_CTRLBANK_BCONF_ALS_EN_MASK; - if (enable) - val = mask; - else - val = 0; - - ret = lm3533_update(led->lm3533, reg, val, mask); + ret = regmap_assign_bits(led->regmap, reg, + LM3533_REG_CTRLBANK_BCONF_ALS_EN_MASK, enable); if (ret) return ret; @@ -504,12 +499,12 @@ static ssize_t show_linear(struct device *dev, struct led_classdev *led_cdev = dev_get_drvdata(dev); struct lm3533_led *led = to_lm3533_led(led_cdev); u8 reg; - u8 val; + u32 val; int linear; int ret; reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE); - ret = lm3533_read(led->lm3533, reg, &val); + ret = regmap_read(led->regmap, reg, &val); if (ret) return ret; @@ -529,22 +524,15 @@ static ssize_t store_linear(struct device *dev, struct lm3533_led *led = to_lm3533_led(led_cdev); unsigned long linear; u8 reg; - u8 mask; - u8 val; int ret; if (kstrtoul(buf, 0, &linear)) return -EINVAL; reg = lm3533_led_get_lv_reg(led, LM3533_REG_CTRLBANK_BCONF_BASE); - mask = LM3533_REG_CTRLBANK_BCONF_MAPPING_MASK; - if (linear) - val = mask; - else - val = 0; - - ret = lm3533_update(led->lm3533, reg, val, mask); + ret = regmap_assign_bits(led->regmap, reg, + LM3533_REG_CTRLBANK_BCONF_MAPPING_MASK, linear); if (ret) return ret; @@ -557,7 +545,7 @@ static ssize_t show_pwm(struct device *dev, { struct led_classdev *led_cdev = dev_get_drvdata(dev); struct lm3533_led *led = to_lm3533_led(led_cdev); - u8 val; + u32 val; int ret; ret = lm3533_ctrlbank_get_pwm(&led->cb, &val); @@ -573,10 +561,10 @@ static ssize_t store_pwm(struct device *dev, { struct led_classdev *led_cdev = dev_get_drvdata(dev); struct lm3533_led *led = to_lm3533_led(led_cdev); - u8 val; + u32 val; int ret; - if (kstrtou8(buf, 0, &val)) + if (kstrtou32(buf, 0, &val)) return -EINVAL; ret = lm3533_ctrlbank_set_pwm(&led->cb, val); @@ -615,7 +603,7 @@ static umode_t lm3533_led_attr_is_visible(struct kobject *kobj, if (attr == &dev_attr_als_channel.attr || attr == &dev_attr_als_en.attr) { - if (!led->lm3533->have_als) + if (!led->have_als) mode = 0; } @@ -632,22 +620,20 @@ static const struct attribute_group *lm3533_led_attribute_groups[] = { NULL }; -static int lm3533_led_setup(struct lm3533_led *led, - struct lm3533_led_platform_data *pdata) +static int lm3533_led_setup(struct lm3533_led *led) { int ret; - ret = lm3533_ctrlbank_set_max_current(&led->cb, pdata->max_current); + ret = lm3533_ctrlbank_set_max_current(&led->cb, led->max_current); if (ret) return ret; - return lm3533_ctrlbank_set_pwm(&led->cb, pdata->pwm); + return lm3533_ctrlbank_set_pwm(&led->cb, led->pwm); } static int lm3533_led_probe(struct platform_device *pdev) { struct lm3533 *lm3533; - struct lm3533_led_platform_data *pdata; struct lm3533_led *led; int ret; @@ -657,12 +643,6 @@ static int lm3533_led_probe(struct platform_device *pdev) if (!lm3533) return -EINVAL; - pdata = dev_get_platdata(&pdev->dev); - if (!pdata) { - dev_err(&pdev->dev, "no platform data\n"); - return -EINVAL; - } - if (pdev->id < 0 || pdev->id >= LM3533_LVCTRLBANK_COUNT) { dev_err(&pdev->dev, "illegal LED id %d\n", pdev->id); return -EINVAL; @@ -672,9 +652,9 @@ static int lm3533_led_probe(struct platform_device *pdev) if (!led) return -ENOMEM; - led->lm3533 = lm3533; - led->cdev.name = pdata->name; - led->cdev.default_trigger = pdata->default_trigger; + led->regmap = lm3533->regmap; + led->have_als = lm3533->have_als; + led->cdev.brightness_set_blocking = lm3533_led_set; led->cdev.brightness_get = lm3533_led_get; led->cdev.blink_set = lm3533_led_blink_set; @@ -682,19 +662,28 @@ static int lm3533_led_probe(struct platform_device *pdev) led->cdev.groups = lm3533_led_attribute_groups; led->id = pdev->id; + led->cdev.name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s-%d", + pdev->name, led->id); + if (!led->cdev.name) + return -ENOMEM; + + led->cdev.default_trigger = "none"; + device_property_read_string(&pdev->dev, "linux,default-trigger", + &led->cdev.default_trigger); + mutex_init(&led->mutex); /* The class framework makes a callback to get brightness during * registration so use parent device (for error reporting) until * registered. */ - led->cb.lm3533 = lm3533; + led->cb.regmap = lm3533->regmap; led->cb.id = lm3533_led_get_ctrlbank_id(led); led->cb.dev = lm3533->dev; platform_set_drvdata(pdev, led); - ret = led_classdev_register(pdev->dev.parent, &led->cdev); + ret = led_classdev_register(&pdev->dev, &led->cdev); if (ret) { dev_err(&pdev->dev, "failed to register LED %d\n", pdev->id); return ret; @@ -702,7 +691,14 @@ static int lm3533_led_probe(struct platform_device *pdev) led->cb.dev = led->cdev.dev; - ret = lm3533_led_setup(led, pdata); + device_property_read_u32(&pdev->dev, "led-max-microamp", + &led->max_current); + led->max_current = clamp(led->max_current, LM3533_MAX_CURRENT_MIN, + LM3533_MAX_CURRENT_MAX); + + device_property_read_u32(&pdev->dev, "ti,pwm-config-mask", &led->pwm); + + ret = lm3533_led_setup(led); if (ret) goto err_deregister; @@ -739,9 +735,16 @@ static void lm3533_led_shutdown(struct platform_device *pdev) lm3533_led_set(&led->cdev, LED_OFF); /* disable blink */ } +static const struct of_device_id lm3533_led_match_table[] = { + { .compatible = "ti,lm3533-leds" }, + { } +}; +MODULE_DEVICE_TABLE(of, lm3533_led_match_table); + static struct platform_driver lm3533_led_driver = { .driver = { .name = "lm3533-leds", + .of_match_table = lm3533_led_match_table, }, .probe = lm3533_led_probe, .remove = lm3533_led_remove, diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index e4fd4572472f..439dbf5ee110 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -2226,7 +2226,7 @@ config MFD_ROHM_BD718XX and emergency shut down as well as 32,768KHz clock output. config MFD_ROHM_BD71828 - tristate "ROHM BD718[15/28/79], BD72720 and BD73900 PMICs" + tristate "ROHM BD718[15/28/79], BD72720 and BD73[8/9]00 PMICs" depends on I2C=y depends on OF select REGMAP_I2C @@ -2235,14 +2235,17 @@ config MFD_ROHM_BD71828 select MFD_ROHM_PWRBUTTON help Select this option to get support for the ROHM BD71815, BD71828, - BD71879, BD72720 and BD73900 Power Management ICs (PMICs). These are - single-chip Power Management ICs (PMIC), mainly for battery-powered - portable devices. + BD71879, BD72720, BD73800 and BD73900 Power Management ICs (PMICs). + These are single-chip Power Management ICs (PMIC), mainly for + battery-powered portable devices. The BD71815 has 5 bucks, 7 LDOs, and a boost for driving LEDs. The BD718[28/79] have 7 buck converters and 7 LDOs. The BD72720 and the BD73900 have 10 bucks and 11 LDOs. - All ICs provide a single-cell linear charger, a Coulomb counter, - a Real-Time Clock (RTC), GPIOs and a 32.768 kHz clock gate. + All the above ICs provide a single-cell linear charger, and a Coulomb + counter. + The BD73800 has 8 bucks, 4 LDOs and ADC for power/current + accumulation but no charging logic. All these PMICs integrate also a + Real-Time Clock (RTC), GPIOs and a 32.768 kHz clock gate. config MFD_ROHM_BD957XMUF tristate "ROHM BD9576MUF and BD9573MUF Power Management ICs" diff --git a/drivers/mfd/lm3533-core.c b/drivers/mfd/lm3533-core.c index 0a2409d00b2e..9233da7ce099 100644 --- a/drivers/mfd/lm3533-core.c +++ b/drivers/mfd/lm3533-core.c @@ -7,6 +7,7 @@ * Author: Johan Hovold */ +#include #include #include #include @@ -14,19 +15,24 @@ #include #include #include +#include #include +#include #include #include #include +#include #include #define LM3533_BOOST_OVP_MASK 0x06 -#define LM3533_BOOST_OVP_SHIFT 1 +#define LM3533_BOOST_OVP_MIN (16 * MICRO) +#define LM3533_BOOST_OVP_MAX (40 * MICRO) #define LM3533_BOOST_FREQ_MASK 0x01 -#define LM3533_BOOST_FREQ_SHIFT 0 +#define LM3533_BOOST_FREQ_MIN (500 * HZ_PER_KHZ) +#define LM3533_BOOST_FREQ_MAX (1000 * HZ_PER_KHZ) #define LM3533_BL_ID_MASK 1 #define LM3533_LED_ID_MASK 3 @@ -35,6 +41,7 @@ #define LM3533_HVLED_ID_MAX 2 #define LM3533_LVLED_ID_MAX 5 +#define LM3533_CELLS_MAX 7 #define LM3533_REG_OUTPUT_CONF1 0x10 #define LM3533_REG_OUTPUT_CONF2 0x11 @@ -42,125 +49,6 @@ #define LM3533_REG_MAX 0xb2 - -static struct mfd_cell lm3533_als_devs[] = { - { - .name = "lm3533-als", - .id = -1, - }, -}; - -static struct mfd_cell lm3533_bl_devs[] = { - { - .name = "lm3533-backlight", - .id = 0, - }, - { - .name = "lm3533-backlight", - .id = 1, - }, -}; - -static struct mfd_cell lm3533_led_devs[] = { - { - .name = "lm3533-leds", - .id = 0, - }, - { - .name = "lm3533-leds", - .id = 1, - }, - { - .name = "lm3533-leds", - .id = 2, - }, - { - .name = "lm3533-leds", - .id = 3, - }, -}; - -int lm3533_read(struct lm3533 *lm3533, u8 reg, u8 *val) -{ - int tmp; - int ret; - - ret = regmap_read(lm3533->regmap, reg, &tmp); - if (ret < 0) { - dev_err(lm3533->dev, "failed to read register %02x: %d\n", - reg, ret); - return ret; - } - - *val = tmp; - - dev_dbg(lm3533->dev, "read [%02x]: %02x\n", reg, *val); - - return ret; -} -EXPORT_SYMBOL_GPL(lm3533_read); - -int lm3533_write(struct lm3533 *lm3533, u8 reg, u8 val) -{ - int ret; - - dev_dbg(lm3533->dev, "write [%02x]: %02x\n", reg, val); - - ret = regmap_write(lm3533->regmap, reg, val); - if (ret < 0) { - dev_err(lm3533->dev, "failed to write register %02x: %d\n", - reg, ret); - } - - return ret; -} -EXPORT_SYMBOL_GPL(lm3533_write); - -int lm3533_update(struct lm3533 *lm3533, u8 reg, u8 val, u8 mask) -{ - int ret; - - dev_dbg(lm3533->dev, "update [%02x]: %02x/%02x\n", reg, val, mask); - - ret = regmap_update_bits(lm3533->regmap, reg, mask, val); - if (ret < 0) { - dev_err(lm3533->dev, "failed to update register %02x: %d\n", - reg, ret); - } - - return ret; -} -EXPORT_SYMBOL_GPL(lm3533_update); - -static int lm3533_set_boost_freq(struct lm3533 *lm3533, - enum lm3533_boost_freq freq) -{ - int ret; - - ret = lm3533_update(lm3533, LM3533_REG_BOOST_PWM, - freq << LM3533_BOOST_FREQ_SHIFT, - LM3533_BOOST_FREQ_MASK); - if (ret) - dev_err(lm3533->dev, "failed to set boost frequency\n"); - - return ret; -} - - -static int lm3533_set_boost_ovp(struct lm3533 *lm3533, - enum lm3533_boost_ovp ovp) -{ - int ret; - - ret = lm3533_update(lm3533, LM3533_REG_BOOST_PWM, - ovp << LM3533_BOOST_OVP_SHIFT, - LM3533_BOOST_OVP_MASK); - if (ret) - dev_err(lm3533->dev, "failed to set boost ovp\n"); - - return ret; -} - /* * HVLED output config -- output hvled controlled by backlight bl */ @@ -181,7 +69,8 @@ static int lm3533_set_hvled_config(struct lm3533 *lm3533, u8 hvled, u8 bl) mask = LM3533_BL_ID_MASK << shift; val = bl << shift; - ret = lm3533_update(lm3533, LM3533_REG_OUTPUT_CONF1, val, mask); + ret = regmap_update_bits(lm3533->regmap, LM3533_REG_OUTPUT_CONF1, + mask, val); if (ret) dev_err(lm3533->dev, "failed to set hvled config\n"); @@ -216,21 +105,32 @@ static int lm3533_set_lvled_config(struct lm3533 *lm3533, u8 lvled, u8 led) mask = LM3533_LED_ID_MASK << shift; val = led << shift; - ret = lm3533_update(lm3533, reg, val, mask); + ret = regmap_update_bits(lm3533->regmap, reg, mask, val); if (ret) dev_err(lm3533->dev, "failed to set lvled config\n"); return ret; } -static void lm3533_enable(struct lm3533 *lm3533) +static int lm3533_enable(struct lm3533 *lm3533) { + int ret; + + ret = regulator_enable(lm3533->vin_supply); + if (ret) { + dev_err(lm3533->dev, "failed to enable vin power supply\n"); + return ret; + } + gpiod_set_value(lm3533->hwen, 1); + + return 0; } static void lm3533_disable(struct lm3533 *lm3533) { gpiod_set_value(lm3533->hwen, 0); + regulator_disable(lm3533->vin_supply); } enum lm3533_attribute_type { @@ -258,7 +158,7 @@ static ssize_t show_output(struct device *dev, struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(attr); int id = lattr->u.output.id; u8 reg; - u8 val; + u32 val; u8 mask; int shift; int ret; @@ -278,7 +178,7 @@ static ssize_t show_output(struct device *dev, mask = LM3533_LED_ID_MASK << shift; } - ret = lm3533_read(lm3533, reg, &val); + ret = regmap_read(lm3533->regmap, reg, &val); if (ret) return ret; @@ -376,136 +276,102 @@ static struct attribute_group lm3533_attribute_group = { .attrs = lm3533_attributes }; -static int lm3533_device_als_init(struct lm3533 *lm3533) -{ - struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev); - int ret; - - if (!pdata->als) - return 0; - - lm3533_als_devs[0].platform_data = pdata->als; - lm3533_als_devs[0].pdata_size = sizeof(*pdata->als); - - ret = mfd_add_devices(lm3533->dev, 0, lm3533_als_devs, 1, NULL, - 0, NULL); - if (ret) { - dev_err(lm3533->dev, "failed to add ALS device\n"); - return ret; - } - - lm3533->have_als = 1; - - return 0; -} - -static int lm3533_device_bl_init(struct lm3533 *lm3533) -{ - struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev); - int i; - int ret; - - if (!pdata->backlights || pdata->num_backlights == 0) - return 0; - - if (pdata->num_backlights > ARRAY_SIZE(lm3533_bl_devs)) - pdata->num_backlights = ARRAY_SIZE(lm3533_bl_devs); - - for (i = 0; i < pdata->num_backlights; ++i) { - lm3533_bl_devs[i].platform_data = &pdata->backlights[i]; - lm3533_bl_devs[i].pdata_size = sizeof(pdata->backlights[i]); - } - - ret = mfd_add_devices(lm3533->dev, 0, lm3533_bl_devs, - pdata->num_backlights, NULL, 0, NULL); - if (ret) { - dev_err(lm3533->dev, "failed to add backlight devices\n"); - return ret; - } - - lm3533->have_backlights = 1; - - return 0; -} - -static int lm3533_device_led_init(struct lm3533 *lm3533) -{ - struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev); - int i; - int ret; - - if (!pdata->leds || pdata->num_leds == 0) - return 0; - - if (pdata->num_leds > ARRAY_SIZE(lm3533_led_devs)) - pdata->num_leds = ARRAY_SIZE(lm3533_led_devs); - - for (i = 0; i < pdata->num_leds; ++i) { - lm3533_led_devs[i].platform_data = &pdata->leds[i]; - lm3533_led_devs[i].pdata_size = sizeof(pdata->leds[i]); - } - - ret = mfd_add_devices(lm3533->dev, 0, lm3533_led_devs, - pdata->num_leds, NULL, 0, NULL); - if (ret) { - dev_err(lm3533->dev, "failed to add LED devices\n"); - return ret; - } - - lm3533->have_leds = 1; - - return 0; -} - -static int lm3533_device_setup(struct lm3533 *lm3533, - struct lm3533_platform_data *pdata) -{ - int ret; - - ret = lm3533_set_boost_freq(lm3533, pdata->boost_freq); - if (ret) - return ret; - - return lm3533_set_boost_ovp(lm3533, pdata->boost_ovp); -} +static const struct attribute_group *lm3533_attribute_groups[] = { + &lm3533_attribute_group, + NULL, +}; static int lm3533_device_init(struct lm3533 *lm3533) { - struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev); + struct device *dev = lm3533->dev; + struct mfd_cell *lm3533_devices; + u32 reg, nchilds; + u32 count = 0; int ret; - dev_dbg(lm3533->dev, "%s\n", __func__); + nchilds = device_get_child_node_count(dev); + if (!nchilds || nchilds > LM3533_CELLS_MAX) + return dev_err_probe(dev, -ENODEV, + "num of child nodes is not supported\n"); - if (!pdata) { - dev_err(lm3533->dev, "no platform data\n"); - return -EINVAL; + lm3533_devices = devm_kcalloc(dev, nchilds, sizeof(*lm3533_devices), + GFP_KERNEL); + if (!lm3533_devices) + return -ENOMEM; + + device_for_each_child_node_scoped(dev, child) { + if (count >= nchilds) + break; + + if (fwnode_device_is_compatible(child, "ti,lm3533-als")) { + lm3533_devices[count].name = "lm3533-als"; + lm3533_devices[count].of_compatible = "ti,lm3533-als"; + lm3533_devices[count].id = PLATFORM_DEVID_NONE; + + lm3533->have_als = true; + count++; + } else if (fwnode_device_is_compatible(child, "ti,lm3533-backlight")) { + ret = fwnode_property_read_u32(child, "reg", ®); + if (ret || reg >= LM3533_HVLED_ID_MAX) { + dev_err(dev, "invalid backlight node %pfw\n", child); + continue; + } + + lm3533_devices[count].name = "lm3533-backlight"; + lm3533_devices[count].of_compatible = "ti,lm3533-backlight"; + lm3533_devices[count].id = reg; + lm3533_devices[count].of_reg = reg; + lm3533_devices[count].use_of_reg = true; + + lm3533->have_backlights = true; + count++; + } else if (fwnode_device_is_compatible(child, "ti,lm3533-leds")) { + ret = fwnode_property_read_u32(child, "reg", ®); + if (ret || reg < LM3533_HVLED_ID_MAX || + reg > LM3533_LVLED_ID_MAX) { + dev_err(dev, "invalid LED node %pfw\n", child); + continue; + } + + lm3533_devices[count].name = "lm3533-leds"; + lm3533_devices[count].of_compatible = "ti,lm3533-leds"; + lm3533_devices[count].id = reg - LM3533_HVLED_ID_MAX; + lm3533_devices[count].of_reg = reg; + lm3533_devices[count].use_of_reg = true; + + lm3533->have_leds = true; + count++; + } } - lm3533->hwen = devm_gpiod_get(lm3533->dev, NULL, GPIOD_OUT_LOW); - if (IS_ERR(lm3533->hwen)) - return dev_err_probe(lm3533->dev, PTR_ERR(lm3533->hwen), "failed to request HWEN GPIO\n"); - gpiod_set_consumer_name(lm3533->hwen, "lm3533-hwen"); - - lm3533_enable(lm3533); - - ret = lm3533_device_setup(lm3533, pdata); + ret = lm3533_enable(lm3533); if (ret) + return ret; + + ret = regmap_update_bits(lm3533->regmap, LM3533_REG_BOOST_PWM, + LM3533_BOOST_FREQ_MASK, + FIELD_PREP(LM3533_BOOST_FREQ_MASK, lm3533->boost_freq)); + if (ret) { + dev_err(dev, "failed to set boost frequency\n"); goto err_disable; + } - lm3533_device_als_init(lm3533); - lm3533_device_bl_init(lm3533); - lm3533_device_led_init(lm3533); + ret = regmap_update_bits(lm3533->regmap, LM3533_REG_BOOST_PWM, + LM3533_BOOST_OVP_MASK, + FIELD_PREP(LM3533_BOOST_OVP_MASK, lm3533->boost_ovp)); + if (ret) { + dev_err(dev, "failed to set boost ovp\n"); + goto err_disable; + } - ret = sysfs_create_group(&lm3533->dev->kobj, &lm3533_attribute_group); - if (ret < 0) { - dev_err(lm3533->dev, "failed to create sysfs attributes\n"); - goto err_unregister; + ret = mfd_add_devices(dev, 0, lm3533_devices, count, NULL, 0, NULL); + if (ret) { + dev_err(dev, "failed to add MFD devices: %d\n", ret); + goto err_disable; } return 0; -err_unregister: - mfd_remove_devices(lm3533->dev); err_disable: lm3533_disable(lm3533); @@ -516,8 +382,6 @@ static void lm3533_device_exit(struct lm3533 *lm3533) { dev_dbg(lm3533->dev, "%s\n", __func__); - sysfs_remove_group(&lm3533->dev->kobj, &lm3533_attribute_group); - mfd_remove_devices(lm3533->dev); lm3533_disable(lm3533); } @@ -589,7 +453,35 @@ static int lm3533_i2c_probe(struct i2c_client *i2c) return PTR_ERR(lm3533->regmap); lm3533->dev = &i2c->dev; - lm3533->irq = i2c->irq; + + lm3533->hwen = devm_gpiod_get_optional(lm3533->dev, "enable", + GPIOD_OUT_LOW); + if (IS_ERR(lm3533->hwen)) + return dev_err_probe(lm3533->dev, PTR_ERR(lm3533->hwen), + "failed to get HWEN GPIO\n"); + + lm3533->vin_supply = devm_regulator_get(lm3533->dev, "vin"); + if (IS_ERR(lm3533->vin_supply)) + return dev_err_probe(lm3533->dev, PTR_ERR(lm3533->vin_supply), + "failed to get vin-supply\n"); + + device_property_read_u32(lm3533->dev, "ti,boost-ovp-microvolt", + &lm3533->boost_ovp); + + lm3533->boost_ovp = clamp(lm3533->boost_ovp, LM3533_BOOST_OVP_MIN, + LM3533_BOOST_OVP_MAX); + lm3533->boost_ovp = lm3533->boost_ovp / (8 * MICRO) - 2; + + device_property_read_u32(lm3533->dev, "ti,boost-freq-hz", + &lm3533->boost_freq); + + lm3533->boost_freq = clamp(lm3533->boost_freq, LM3533_BOOST_FREQ_MIN, + LM3533_BOOST_FREQ_MAX); + lm3533->boost_freq = lm3533->boost_freq / (500 * KILO) - 1; + + /* LM3533 and child devices do not use DMA */ + i2c->dev.coherent_dma_mask = 0; + i2c->dev.dma_mask = &i2c->dev.coherent_dma_mask; return lm3533_device_init(lm3533); } @@ -603,6 +495,12 @@ static void lm3533_i2c_remove(struct i2c_client *i2c) lm3533_device_exit(lm3533); } +static const struct of_device_id lm3533_match_table[] = { + { .compatible = "ti,lm3533" }, + { } +}; +MODULE_DEVICE_TABLE(of, lm3533_match_table); + static const struct i2c_device_id lm3533_i2c_ids[] = { { "lm3533" }, { } @@ -612,6 +510,8 @@ MODULE_DEVICE_TABLE(i2c, lm3533_i2c_ids); static struct i2c_driver lm3533_i2c_driver = { .driver = { .name = "lm3533", + .dev_groups = lm3533_attribute_groups, + .of_match_table = lm3533_match_table, }, .id_table = lm3533_i2c_ids, .probe = lm3533_i2c_probe, diff --git a/drivers/mfd/lm3533-ctrlbank.c b/drivers/mfd/lm3533-ctrlbank.c index 2537dfade51c..3aab8ece4e8c 100644 --- a/drivers/mfd/lm3533-ctrlbank.c +++ b/drivers/mfd/lm3533-ctrlbank.c @@ -9,14 +9,10 @@ #include #include +#include #include - -#define LM3533_MAX_CURRENT_MIN 5000 -#define LM3533_MAX_CURRENT_MAX 29800 -#define LM3533_MAX_CURRENT_STEP 800 - #define LM3533_PWM_MAX 0x3f #define LM3533_REG_PWM_BASE 0x14 @@ -38,8 +34,8 @@ int lm3533_ctrlbank_enable(struct lm3533_ctrlbank *cb) dev_dbg(cb->dev, "%s - %d\n", __func__, cb->id); mask = 1 << cb->id; - ret = lm3533_update(cb->lm3533, LM3533_REG_CTRLBANK_ENABLE, - mask, mask); + ret = regmap_set_bits(cb->regmap, LM3533_REG_CTRLBANK_ENABLE, + mask); if (ret) dev_err(cb->dev, "failed to enable ctrlbank %d\n", cb->id); @@ -55,7 +51,8 @@ int lm3533_ctrlbank_disable(struct lm3533_ctrlbank *cb) dev_dbg(cb->dev, "%s - %d\n", __func__, cb->id); mask = 1 << cb->id; - ret = lm3533_update(cb->lm3533, LM3533_REG_CTRLBANK_ENABLE, 0, mask); + ret = regmap_clear_bits(cb->regmap, LM3533_REG_CTRLBANK_ENABLE, + mask); if (ret) dev_err(cb->dev, "failed to disable ctrlbank %d\n", cb->id); @@ -68,7 +65,7 @@ EXPORT_SYMBOL_GPL(lm3533_ctrlbank_disable); * * imax 5000 - 29800 uA (800 uA step) */ -int lm3533_ctrlbank_set_max_current(struct lm3533_ctrlbank *cb, u16 imax) +int lm3533_ctrlbank_set_max_current(struct lm3533_ctrlbank *cb, u32 imax) { u8 reg; u8 val; @@ -80,7 +77,7 @@ int lm3533_ctrlbank_set_max_current(struct lm3533_ctrlbank *cb, u16 imax) val = (imax - LM3533_MAX_CURRENT_MIN) / LM3533_MAX_CURRENT_STEP; reg = lm3533_ctrlbank_get_reg(cb, LM3533_REG_MAX_CURRENT_BASE); - ret = lm3533_write(cb->lm3533, reg, val); + ret = regmap_write(cb->regmap, reg, val); if (ret) dev_err(cb->dev, "failed to set max current\n"); @@ -88,13 +85,13 @@ int lm3533_ctrlbank_set_max_current(struct lm3533_ctrlbank *cb, u16 imax) } EXPORT_SYMBOL_GPL(lm3533_ctrlbank_set_max_current); -int lm3533_ctrlbank_set_brightness(struct lm3533_ctrlbank *cb, u8 val) +int lm3533_ctrlbank_set_brightness(struct lm3533_ctrlbank *cb, u32 val) { u8 reg; int ret; reg = lm3533_ctrlbank_get_reg(cb, LM3533_REG_BRIGHTNESS_BASE); - ret = lm3533_write(cb->lm3533, reg, val); + ret = regmap_write(cb->regmap, reg, val); if (ret) dev_err(cb->dev, "failed to set brightness\n"); @@ -102,13 +99,13 @@ int lm3533_ctrlbank_set_brightness(struct lm3533_ctrlbank *cb, u8 val) } EXPORT_SYMBOL_GPL(lm3533_ctrlbank_set_brightness); -int lm3533_ctrlbank_get_brightness(struct lm3533_ctrlbank *cb, u8 *val) +int lm3533_ctrlbank_get_brightness(struct lm3533_ctrlbank *cb, u32 *val) { u8 reg; int ret; reg = lm3533_ctrlbank_get_reg(cb, LM3533_REG_BRIGHTNESS_BASE); - ret = lm3533_read(cb->lm3533, reg, val); + ret = regmap_read(cb->regmap, reg, val); if (ret) dev_err(cb->dev, "failed to get brightness\n"); @@ -126,7 +123,7 @@ EXPORT_SYMBOL_GPL(lm3533_ctrlbank_get_brightness); * bit 1 - PWM-input enabled in Zone 0 * bit 0 - PWM-input enabled */ -int lm3533_ctrlbank_set_pwm(struct lm3533_ctrlbank *cb, u8 val) +int lm3533_ctrlbank_set_pwm(struct lm3533_ctrlbank *cb, u32 val) { u8 reg; int ret; @@ -135,7 +132,7 @@ int lm3533_ctrlbank_set_pwm(struct lm3533_ctrlbank *cb, u8 val) return -EINVAL; reg = lm3533_ctrlbank_get_reg(cb, LM3533_REG_PWM_BASE); - ret = lm3533_write(cb->lm3533, reg, val); + ret = regmap_write(cb->regmap, reg, val); if (ret) dev_err(cb->dev, "failed to set PWM mask\n"); @@ -143,13 +140,13 @@ int lm3533_ctrlbank_set_pwm(struct lm3533_ctrlbank *cb, u8 val) } EXPORT_SYMBOL_GPL(lm3533_ctrlbank_set_pwm); -int lm3533_ctrlbank_get_pwm(struct lm3533_ctrlbank *cb, u8 *val) +int lm3533_ctrlbank_get_pwm(struct lm3533_ctrlbank *cb, u32 *val) { u8 reg; int ret; reg = lm3533_ctrlbank_get_reg(cb, LM3533_REG_PWM_BASE); - ret = lm3533_read(cb->lm3533, reg, val); + ret = regmap_read(cb->regmap, reg, val); if (ret) dev_err(cb->dev, "failed to get PWM mask\n"); diff --git a/drivers/mfd/rohm-bd71828.c b/drivers/mfd/rohm-bd71828.c index bf4df8e1b34c..46faef7058f8 100644 --- a/drivers/mfd/rohm-bd71828.c +++ b/drivers/mfd/rohm-bd71828.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (C) 2019 ROHM Semiconductors + * Copyright (C) 2019, 2026 ROHM Semiconductor * - * ROHM BD718[15/28/79] and BD72720 PMIC driver + * ROHM BD718[15/28/79], BD72720 and BD73[8/9]00 PMIC driver */ #include @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -56,6 +57,12 @@ static const struct resource bd72720_rtc_irqs[] = { DEFINE_RES_IRQ_NAMED(BD72720_INT_RTC2, "bd70528-rtc-alm-2"), }; +static const struct resource bd73800_rtc_irqs[] = { + DEFINE_RES_IRQ_NAMED(BD73800_INT_RTC0, "bd70528-rtc-alm-0"), + DEFINE_RES_IRQ_NAMED(BD73800_INT_RTC1, "bd70528-rtc-alm-1"), + DEFINE_RES_IRQ_NAMED(BD73800_INT_RTC2, "bd70528-rtc-alm-2"), +}; + static const struct resource bd71815_power_irqs[] = { DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_RMV, "bd71815-dcin-rmv"), DEFINE_RES_IRQ_NAMED(BD71815_INT_CLPS_OUT, "bd71815-dcin-clps-out"), @@ -230,6 +237,17 @@ static const struct mfd_cell bd72720_mfd_cells[] = { /* Power button is registered separately */ }; +static const struct mfd_cell bd73800_mfd_cells[] = { + { .name = "bd73800-pmic", }, + { .name = "bd73800-clk", }, + { .name = "bd73800-gpio", }, + { + .name = "bd73800-rtc", + .num_resources = ARRAY_SIZE(bd73800_rtc_irqs), + .resources = bd73800_rtc_irqs, + }, +}; + static const struct regmap_range bd71815_volatile_ranges[] = { regmap_reg_range(BD71815_REG_SEC, BD71815_REG_YEAR), regmap_reg_range(BD71815_REG_CONF, BD71815_REG_BAT_TEMP), @@ -339,6 +357,17 @@ static const struct regmap_range bd72720_volatile_ranges_4c[] = { BD72720_UNWRAP_REG_RANGE(BD72720_REG_IMPCHK_CTRL, BD72720_REG_IMPCHK_CTRL), }; +static const struct regmap_range bd73800_volatile_ranges[] = { + regmap_reg_range(BD73800_REG_POR_REASON, BD73800_REG_POW_STATE), + regmap_reg_range(BD73800_REG_PS_CTRL_1, BD73800_REG_PS_CTRL_2), + regmap_reg_range(BD73800_REG_RCVNUM, BD73800_REG_RCVNUM), + regmap_reg_range(BD73800_REG_RTC_SEC, BD73800_REG_RTC_YEAR), + regmap_reg_range(BD73800_REG_RTC_CONF, BD73800_REG_RTC_CONF), + regmap_reg_range(BD73800_REG_ADC_ACCUM_KICK, BD73800_REG_ADC_TEMP_VAL0), + regmap_reg_range(BD73800_REG_INT_MAIN_STAT, BD73800_REG_INT_5_STAT), + regmap_reg_range(BD73800_REG_INT_MAIN_SRC, BD73800_REG_INT_5_SRC), +}; + static const struct regmap_access_table bd71815_volatile_regs = { .yes_ranges = &bd71815_volatile_ranges[0], .n_yes_ranges = ARRAY_SIZE(bd71815_volatile_ranges), @@ -364,6 +393,24 @@ static const struct regmap_access_table bd72720_volatile_regs_4c = { .n_yes_ranges = ARRAY_SIZE(bd72720_volatile_ranges_4c), }; +static const struct regmap_access_table bd73800_volatile_regs = { + .yes_ranges = bd73800_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(bd73800_volatile_ranges), +}; + +static const struct regmap_range bd73800_read_only_ranges[] = { + regmap_reg_range(BD73800_REG_PRODUCT_ID, BD73800_REG_NVMVERSION), + regmap_reg_range(BD73800_REG_POW_STATE, BD73800_REG_POW_STATE), + regmap_reg_range(BD73800_REG_ADC_ACCUM_CNT2, BD73800_REG_ADC_TEMP_VAL0), + regmap_reg_range(BD73800_REG_INT_MAIN_STAT, BD73800_REG_INT_MAIN_STAT), + regmap_reg_range(BD73800_REG_INT_MAIN_SRC, BD73800_REG_INT_5_SRC), +}; + +static const struct regmap_access_table bd73800_ro_regs = { + .no_ranges = bd73800_read_only_ranges, + .n_no_ranges = ARRAY_SIZE(bd73800_read_only_ranges), +}; + static const struct regmap_config bd71815_regmap = { .reg_bits = 8, .val_bits = 8, @@ -448,6 +495,15 @@ static const struct regmap_config bd72720_regmap_4c = { .cache_type = REGCACHE_MAPLE, }; +static const struct regmap_config bd73800_regmap = { + .reg_bits = 8, + .val_bits = 8, + .wr_table = &bd73800_ro_regs, + .volatile_table = &bd73800_volatile_regs, + .max_register = BD73800_MAX_REGISTER - 1, + .cache_type = REGCACHE_MAPLE, +}; + /* * Mapping of main IRQ register bits to sub-IRQ register offsets so that we can * access corect sub-IRQ registers based on bits that are set in main IRQ @@ -779,6 +835,60 @@ static int bd72720_set_type_config(unsigned int **buf, unsigned int type, return regmap_irq_set_type_config_simple(buf, type, irq_data, idx, irq_drv_data); } +static const struct regmap_irq bd73800_irqs[] = { + /* INT_STAT_1 register IRQs, ADC and RTC */ + REGMAP_IRQ_REG(BD73800_INT_ADC_ACCUM_DONE, 0, BD73800_INT_ADC_ACCUM_DONE_MASK), + REGMAP_IRQ_REG(BD73800_INT_ADC_ACCUM_OVF, 0, BD73800_INT_ADC_ACCUM_OVF_MASK), + REGMAP_IRQ_REG(BD73800_INT_ADC_ACCUM_VAL, 0, BD73800_INT_ADC_ACCUM_VAL_MASK), + REGMAP_IRQ_REG(BD73800_INT_ADC_ACCUM_TW, 0, BD73800_INT_ADC_ACCUM_TW_MASK), + REGMAP_IRQ_REG(BD73800_INT_ADC_POW_VAL, 0, BD73800_INT_ADC_POW_VAL_MASK), + REGMAP_IRQ_REG(BD73800_INT_RTC0, 0, BD73800_INT_RTC0_MASK), + REGMAP_IRQ_REG(BD73800_INT_RTC1, 0, BD73800_INT_RTC1_MASK), + REGMAP_IRQ_REG(BD73800_INT_RTC2, 0, BD73800_INT_RTC2_MASK), + + /* BUCK reg interrupts */ + /* INT_STAT_2 IRQs */ + REGMAP_IRQ_REG(BD73800_INT_BUCK1_DVS_DONE, 1, BD73800_INT_BUCK1_DVS_DONE_MASK), + REGMAP_IRQ_REG(BD73800_INT_BUCK2_DVS_DONE, 1, BD73800_INT_BUCK2_DVS_DONE_MASK), + REGMAP_IRQ_REG(BD73800_INT_BUCK3_DVS_DONE, 1, BD73800_INT_BUCK3_DVS_DONE_MASK), + REGMAP_IRQ_REG(BD73800_INT_BUCK4_DVS_DONE, 1, BD73800_INT_BUCK4_DVS_DONE_MASK), + REGMAP_IRQ_REG(BD73800_INT_BUCK5_DVS_DONE, 1, BD73800_INT_BUCK5_DVS_DONE_MASK), + REGMAP_IRQ_REG(BD73800_INT_BUCK6_DVS_DONE, 1, BD73800_INT_BUCK6_DVS_DONE_MASK), + REGMAP_IRQ_REG(BD73800_INT_BUCK7_DVS_DONE, 1, BD73800_INT_BUCK7_DVS_DONE_MASK), + REGMAP_IRQ_REG(BD73800_INT_BUCK8_DVS_DONE, 1, BD73800_INT_BUCK8_DVS_DONE_MASK), + /* INT_STAT_3 IRQs */ + REGMAP_IRQ_REG(BD73800_INT_BUCK1_OCP, 2, BD73800_INT_BUCK1_OCP_MASK), + REGMAP_IRQ_REG(BD73800_INT_BUCK2_OCP, 2, BD73800_INT_BUCK2_OCP_MASK), + REGMAP_IRQ_REG(BD73800_INT_BUCK3_OCP, 2, BD73800_INT_BUCK3_OCP_MASK), + REGMAP_IRQ_REG(BD73800_INT_BUCK4_OCP, 2, BD73800_INT_BUCK4_OCP_MASK), + REGMAP_IRQ_REG(BD73800_INT_BUCK5_OCP, 2, BD73800_INT_BUCK5_OCP_MASK), + REGMAP_IRQ_REG(BD73800_INT_BUCK6_OCP, 2, BD73800_INT_BUCK6_OCP_MASK), + REGMAP_IRQ_REG(BD73800_INT_BUCK7_OCP, 2, BD73800_INT_BUCK7_OCP_MASK), + REGMAP_IRQ_REG(BD73800_INT_BUCK8_OCP, 2, BD73800_INT_BUCK8_OCP_MASK), + + /* INT_STAT_4 IRQs, power-button, WDG and reset */ + REGMAP_IRQ_REG(BD73800_INT_PBTN_LONG_PRESS, 3, BD73800_INT_PBTN_LONG_PRESS_MASK), + REGMAP_IRQ_REG(BD73800_INT_PBTN_MID_PRESS, 3, BD73800_INT_PBTN_MID_PRESS_MASK), + /* + * The SHORT_PUSH is generated when button is first pressed (longer + * than configured time limit), and then released before the MID_PRESS + * time limit. The SHORT_PRESS is generated immediately when button is + * pressed for longer than configured limit, whether it is released or + * not. + */ + REGMAP_IRQ_REG(BD73800_INT_PBTN_SHORT_PUSH, 3, BD73800_INT_PBTN_SHORT_PUSH_MASK), + REGMAP_IRQ_REG(BD73800_INT_PBTN_SHORT_PRESS, 3, BD73800_INT_PBTN_SHORT_PRESS_MASK), + REGMAP_IRQ_REG(BD73800_INT_WDG, 3, BD73800_INT_WDG_MASK), + REGMAP_IRQ_REG(BD73800_INT_SWRESET, 3, BD73800_INT_SWRESET_MASK), + REGMAP_IRQ_REG(BD73800_INT_SEQ_DONE, 3, BD73800_INT_SEQ_DONE_MASK), + + /* INT_STAT_5 IRQs, GPIO */ + REGMAP_IRQ_REG(BD73800_INT_GPIO1, 4, BD73800_INT_GPIO1_MASK), + REGMAP_IRQ_REG(BD73800_INT_GPIO2, 4, BD73800_INT_GPIO2_MASK), + REGMAP_IRQ_REG(BD73800_INT_GPIO3, 4, BD73800_INT_GPIO3_MASK), + REGMAP_IRQ_REG(BD73800_INT_GPIO4, 4, BD73800_INT_GPIO4_MASK), +}; + static const struct regmap_irq_chip bd71828_irq_chip = { .name = "bd71828_irq", .main_status = BD71828_REG_INT_MAIN, @@ -833,6 +943,25 @@ static const struct regmap_irq_chip bd72720_irq_chip = { .irq_reg_stride = 1, }; +static const struct regmap_irq_chip bd73800_irq_chip = { + .name = "bd73800_irq", + .main_status = BD73800_REG_INT_MAIN_STAT, + .irqs = bd73800_irqs, + .num_irqs = ARRAY_SIZE(bd73800_irqs), + .status_base = BD73800_REG_INT_1_STAT, + .unmask_base = BD73800_REG_INT_1_EN, + .ack_base = BD73800_REG_INT_1_STAT, + .init_ack_masked = true, + .num_regs = 5, + .num_main_regs = 1, + /* + * Ignore mirrored bits [7:5]. They are handled as part of normal INT_4 + * handling. + */ + .num_main_status_bits = 5, + .irq_reg_stride = 1, +}; + static int set_clk_mode(struct device *dev, struct regmap *regmap, int clkmode_reg) { @@ -971,6 +1100,17 @@ static int bd71828_i2c_probe(struct i2c_client *i2c) main_lvl_val = BD72720_MASK_LVL1_EN_ALL; break; } + case ROHM_CHIP_TYPE_BD73800: + mfd = bd73800_mfd_cells; + cells = ARRAY_SIZE(bd73800_mfd_cells); + regmap_config = &bd73800_regmap; + irqchip = &bd73800_irq_chip; + clkmode_reg = BD73800_REG_OUT32K; + button_irq = BD73800_INT_PBTN_SHORT_PUSH; + main_lvl_mask_reg = BD73800_REG_INT_MAIN_EN; + main_lvl_val = BD73800_INT_MAIN_EN_ALL; + break; + default: dev_err(&i2c->dev, "Unknown device type"); return -EINVAL; @@ -1051,6 +1191,9 @@ static const struct of_device_id bd71828_of_match[] = { }, { .compatible = "rohm,bd72720", .data = (void *)ROHM_CHIP_TYPE_BD72720, + }, { + .compatible = "rohm,bd73800", + .data = (void *)ROHM_CHIP_TYPE_BD73800, }, { }, }; diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 89789ac7a786..13928af8cad4 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -241,12 +241,12 @@ config REGULATOR_BD71815 will be called bd71815-regulator. config REGULATOR_BD71828 - tristate "ROHM BD71828, BD72720 and BD73900 Power Regulators" + tristate "ROHM BD71828, BD72720 and BD73[8/9]00 Power Regulators" depends on MFD_ROHM_BD71828 select REGULATOR_ROHM help This driver supports voltage regulators on ROHM BD71828, - BD71879, BD72720 and BD73900 PMICs. This will enable + BD71879, BD72720 and BD73[8/9]00 PMICs. This will enable support for the software controllable buck and LDO regulators. This driver can also be built as a module. If so, the module diff --git a/drivers/regulator/bd71828-regulator.c b/drivers/regulator/bd71828-regulator.c index 2ced81df0c02..dea551cf658a 100644 --- a/drivers/regulator/bd71828-regulator.c +++ b/drivers/regulator/bd71828-regulator.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // Copyright (C) 2019 ROHM Semiconductors // bd71828-regulator.c ROHM BD71828GW-DS1 regulator driver -// #include #include @@ -10,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +31,13 @@ struct bd71828_regulator_data { int reg_init_amnt; }; +/* + * LDO1 and LDO3 node names are used also in the driver to find OTP setting for + * the used voltage range. + */ +#define LDO1_NODE_NAME "ldo1" +#define LDO3_NODE_NAME "ldo3" + static const struct reg_init bd71828_buck1_inits[] = { /* * DVS Buck voltages can be changed by register values or via GPIO. @@ -172,6 +179,55 @@ static const struct linear_range bd72720_ldo6_volts[] = { REGULATOR_LINEAR_RANGE(1800000, 0x79, 0x7f, 0), }; +static const struct linear_range bd73800_buck12348_volts[] = { + REGULATOR_LINEAR_RANGE(500000, 0x00, 0x50, 10000), + REGULATOR_LINEAR_RANGE(1300000, 0x51, 0xff, 0), +}; + +static const unsigned int bd73800_buck5_volt_range_sel[] = { + 0x0, 0x0, 0x1, 0x1, +}; + +static const struct linear_range bd73800_buck5_volts[] = { + /* range selector 0 */ + REGULATOR_LINEAR_RANGE(500000, 0x00, 0x50, 10000), + REGULATOR_LINEAR_RANGE(1300000, 0x51, 0x7f, 0), + /* range selector 1 */ + REGULATOR_LINEAR_RANGE(300000, 0x00, 0x46, 10000), + REGULATOR_LINEAR_RANGE(1000000, 0x47, 0x7f, 0), +}; + +/* + * BUCK5 has two different pickable ranges, each having voltages matching + * selectors 0x0 to 0x7f. This gives 0x7f + 1 different voltages for each of + * the ranges. + */ +#define BD73800_NUM_BUCK5_VOLTS ((0x7f + 1) * 2) + +static const struct linear_range bd73800_buck67_volts[] = { + REGULATOR_LINEAR_RANGE(1500000, 0x00, 0xc8, 10000), + REGULATOR_LINEAR_RANGE(3500000, 0xc9, 0xff, 0), +}; + +/* + * On the BD73800 the LDO1 and LDO3 support two different voltage areas. + * Whether to use 'high' or 'low' ranges is configured by OTP. There seems + * to be no register to read the configured area so it must be given via + * device-tree properties. + */ +static const struct linear_range bd73800_ldo13_low_volts[] = { + REGULATOR_LINEAR_RANGE(600000, 0x00, 0x78, 10000), + REGULATOR_LINEAR_RANGE(1800000, 0x79, 0xff, 0), +}; + +static const struct linear_range bd73800_ldo13_high_volts[] = { + REGULATOR_LINEAR_RANGE(750000, 0x00, 0xff, 10000), +}; + +static const struct linear_range bd73800_ldo24_volts[] = { + REGULATOR_LINEAR_RANGE(750000, 0x00, 0xff, 10000), +}; + static const unsigned int bd71828_ramp_delay[] = { 2500, 5000, 10000, 20000 }; /* @@ -225,6 +281,36 @@ static int bd71828_ldo6_parse_dt(struct device_node *np, return 0; } +/* Operations for all other BUCKs but BUCK 5 */ +static const struct regulator_ops bd73800_buck_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_ramp_delay = regulator_set_ramp_delay_regmap, +}; + +static const struct regulator_ops bd73800_buck5_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_pickable_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_pickable_regmap, + .get_voltage_sel = regulator_get_voltage_sel_pickable_regmap, + .set_ramp_delay = regulator_set_ramp_delay_regmap, +}; + +static const struct regulator_ops bd73800_ldo_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, +}; + static const struct regulator_ops bd71828_buck_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -1565,6 +1651,412 @@ static const struct bd71828_regulator_data bd72720_rdata[] = { }, }; +static const struct bd71828_regulator_data bd73800_rdata[] = { + { + .desc = { + .name = "buck1", + .of_match = of_match_ptr("buck1"), + .regulators_node = of_match_ptr("regulators"), + .id = BD73800_BUCK1, + .ops = &bd73800_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd73800_buck12348_volts, + .n_linear_ranges = ARRAY_SIZE(bd73800_buck12348_volts), + .n_voltages = BD73800_NUM_VOLTS, + .enable_reg = BD73800_REG_BUCK1_ON, + .enable_mask = BD73800_MASK_RUN_EN, + .vsel_reg = BD73800_REG_BUCK1_VOLT_RUN, + .vsel_mask = BD73800_MASK_VOLT, + .ramp_delay_table = bd71828_ramp_delay, + .n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay), + .ramp_reg = BD73800_REG_BUCK1_MODE, + .ramp_mask = BD73800_MASK_RAMP_DELAY, + .owner = THIS_MODULE, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND, + .run_reg = BD73800_REG_BUCK1_VOLT_RUN, + .run_mask = BD73800_MASK_VOLT, + .idle_reg = BD73800_REG_BUCK1_VOLT_IDLE, + .idle_mask = BD73800_MASK_VOLT, + .idle_on_mask = BD73800_MASK_IDLE_EN, + .suspend_reg = BD73800_REG_BUCK1_VOLT_SUSP, + .suspend_mask = BD73800_MASK_VOLT, + .suspend_on_mask = BD73800_MASK_SUSP_EN, + }, + }, { + .desc = { + .name = "buck2", + .of_match = of_match_ptr("buck2"), + .regulators_node = of_match_ptr("regulators"), + .id = BD73800_BUCK2, + .ops = &bd73800_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd73800_buck12348_volts, + .n_linear_ranges = ARRAY_SIZE(bd73800_buck12348_volts), + .n_voltages = BD73800_NUM_VOLTS, + .enable_reg = BD73800_REG_BUCK2_ON, + .enable_mask = BD73800_MASK_RUN_EN, + .vsel_reg = BD73800_REG_BUCK2_VOLT_RUN, + .vsel_mask = BD73800_MASK_VOLT, + .ramp_delay_table = bd71828_ramp_delay, + .n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay), + .ramp_reg = BD73800_REG_BUCK2_MODE, + .ramp_mask = BD73800_MASK_RAMP_DELAY, + .owner = THIS_MODULE, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND, + .run_reg = BD73800_REG_BUCK2_VOLT_RUN, + .run_mask = BD73800_MASK_VOLT, + .idle_reg = BD73800_REG_BUCK2_VOLT_IDLE, + .idle_mask = BD73800_MASK_VOLT, + .idle_on_mask = BD73800_MASK_IDLE_EN, + .suspend_reg = BD73800_REG_BUCK2_VOLT_SUSP, + .suspend_mask = BD73800_MASK_VOLT, + .suspend_on_mask = BD73800_MASK_SUSP_EN, + }, + }, { + .desc = { + .name = "buck3", + .of_match = of_match_ptr("buck3"), + .regulators_node = of_match_ptr("regulators"), + .id = BD73800_BUCK3, + .ops = &bd73800_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd73800_buck12348_volts, + .n_linear_ranges = ARRAY_SIZE(bd73800_buck12348_volts), + .n_voltages = BD73800_NUM_VOLTS, + .enable_reg = BD73800_REG_BUCK3_ON, + .enable_mask = BD73800_MASK_RUN_EN, + .vsel_reg = BD73800_REG_BUCK3_VOLT_RUN, + .vsel_mask = BD73800_MASK_VOLT, + .ramp_delay_table = bd71828_ramp_delay, + .n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay), + .ramp_reg = BD73800_REG_BUCK3_MODE, + .ramp_mask = BD73800_MASK_RAMP_DELAY, + .owner = THIS_MODULE, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND, + .run_reg = BD73800_REG_BUCK3_VOLT_RUN, + .run_mask = BD73800_MASK_VOLT, + .idle_reg = BD73800_REG_BUCK3_VOLT_IDLE, + .idle_mask = BD73800_MASK_VOLT, + .idle_on_mask = BD73800_MASK_IDLE_EN, + .suspend_reg = BD73800_REG_BUCK3_VOLT_SUSP, + .suspend_mask = BD73800_MASK_VOLT, + .suspend_on_mask = BD73800_MASK_SUSP_EN, + }, + + }, { + .desc = { + .name = "buck4", + .of_match = of_match_ptr("buck4"), + .regulators_node = of_match_ptr("regulators"), + .id = BD73800_BUCK4, + .ops = &bd73800_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd73800_buck12348_volts, + .n_linear_ranges = ARRAY_SIZE(bd73800_buck12348_volts), + .n_voltages = BD73800_NUM_VOLTS, + .enable_reg = BD73800_REG_BUCK4_ON, + .enable_mask = BD73800_MASK_RUN_EN, + .vsel_reg = BD73800_REG_BUCK4_VOLT_RUN, + .vsel_mask = BD73800_MASK_VOLT, + .ramp_delay_table = bd71828_ramp_delay, + .n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay), + .ramp_reg = BD73800_REG_BUCK4_MODE, + .ramp_mask = BD73800_MASK_RAMP_DELAY, + .owner = THIS_MODULE, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND, + .run_reg = BD73800_REG_BUCK4_VOLT_RUN, + .run_mask = BD73800_MASK_VOLT, + .idle_reg = BD73800_REG_BUCK4_VOLT_IDLE, + .idle_mask = BD73800_MASK_VOLT, + .idle_on_mask = BD73800_MASK_IDLE_EN, + .suspend_reg = BD73800_REG_BUCK4_VOLT_SUSP, + .suspend_mask = BD73800_MASK_VOLT, + .suspend_on_mask = BD73800_MASK_SUSP_EN, + }, + }, { + .desc = { + .name = "buck5", + .of_match = of_match_ptr("buck5"), + .regulators_node = of_match_ptr("regulators"), + .id = BD73800_BUCK5, + .ops = &bd73800_buck5_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd73800_buck5_volts, + .n_linear_ranges = ARRAY_SIZE(bd73800_buck5_volts), + .linear_range_selectors_bitfield = + bd73800_buck5_volt_range_sel, + .n_voltages = BD73800_NUM_BUCK5_VOLTS, + .enable_reg = BD73800_REG_BUCK5_ON, + .enable_mask = BD73800_MASK_RUN_EN, + .vsel_reg = BD73800_REG_BUCK5_VOLT_RUN, + .vsel_mask = BD73800_MASK_BUCK5_VOLT, + .vsel_range_reg = BD73800_REG_BUCK5_MODE, + .vsel_range_mask = BD73800_BUCK5_RANGE_MASK, + .range_applied_by_vsel = true, + .ramp_delay_table = bd71828_ramp_delay, + .n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay), + .ramp_reg = BD73800_REG_BUCK5_MODE, + .ramp_mask = BD73800_MASK_RAMP_DELAY, + .owner = THIS_MODULE, + }, + .dvs = { + /* + * We don't support setting the IDLE / SUSPEND voltages + * for the BUCK 5 for now. Reason is that the pickable + * range selector bit is common for all states (RUN, + * SUSPEND and IDLE), and toggling it for one impacts + * also others. + * Furthermore, writing the BD73800 range selector does + * not impact the RUN voltage until a new voltage value + * is also written to the vsel register. Hence the + * voltage change can be done without any 'intermediate + * voltages', even when the range is changed when the + * BUCK is enabled. + * It, however, is not documented how the IDLE / SUSPEND + * states work in this regard. I expect the full + * combination of the range selector and vsel is taken + * into account at the state change, no matter when they + * have been written to. + */ + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND, + .run_reg = BD73800_REG_BUCK5_VOLT_RUN, + .run_mask = BD73800_MASK_VOLT, + .idle_on_mask = BD73800_MASK_IDLE_EN, + .suspend_on_mask = BD73800_MASK_SUSP_EN, + }, + + }, { + .desc = { + .name = "buck6", + .of_match = of_match_ptr("buck6"), + .regulators_node = of_match_ptr("regulators"), + .id = BD73800_BUCK6, + .ops = &bd73800_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd73800_buck67_volts, + .n_linear_ranges = ARRAY_SIZE(bd73800_buck67_volts), + .n_voltages = BD73800_NUM_VOLTS, + .enable_reg = BD73800_REG_BUCK6_ON, + .enable_mask = BD73800_MASK_RUN_EN, + .vsel_reg = BD73800_REG_BUCK6_VOLT_RUN, + .vsel_mask = BD73800_MASK_VOLT, + .ramp_delay_table = bd71828_ramp_delay, + .n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay), + .ramp_reg = BD73800_REG_BUCK6_MODE, + .ramp_mask = BD73800_MASK_RAMP_DELAY, + .owner = THIS_MODULE, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND, + .run_reg = BD73800_REG_BUCK6_VOLT_RUN, + .run_mask = BD73800_MASK_VOLT, + .idle_reg = BD73800_REG_BUCK6_VOLT_IDLE, + .idle_mask = BD73800_MASK_VOLT, + .idle_on_mask = BD73800_MASK_IDLE_EN, + .suspend_reg = BD73800_REG_BUCK6_VOLT_SUSP, + .suspend_mask = BD73800_MASK_VOLT, + .suspend_on_mask = BD73800_MASK_SUSP_EN, + }, + }, { + .desc = { + .name = "buck7", + .of_match = of_match_ptr("buck7"), + .regulators_node = of_match_ptr("regulators"), + .id = BD73800_BUCK7, + .ops = &bd73800_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd73800_buck67_volts, + .n_linear_ranges = ARRAY_SIZE(bd73800_buck67_volts), + .n_voltages = BD73800_NUM_VOLTS, + .enable_reg = BD73800_REG_BUCK7_ON, + .enable_mask = BD73800_MASK_RUN_EN, + .vsel_reg = BD73800_REG_BUCK7_VOLT_RUN, + .vsel_mask = BD73800_MASK_VOLT, + .ramp_delay_table = bd71828_ramp_delay, + .n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay), + .ramp_reg = BD73800_REG_BUCK7_MODE, + .ramp_mask = BD73800_MASK_RAMP_DELAY, + .owner = THIS_MODULE, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND, + .run_reg = BD73800_REG_BUCK7_VOLT_RUN, + .run_mask = BD73800_MASK_VOLT, + .idle_reg = BD73800_REG_BUCK7_VOLT_IDLE, + .idle_mask = BD73800_MASK_VOLT, + .idle_on_mask = BD73800_MASK_IDLE_EN, + .suspend_reg = BD73800_REG_BUCK7_VOLT_SUSP, + .suspend_mask = BD73800_MASK_VOLT, + .suspend_on_mask = BD73800_MASK_SUSP_EN, + }, + }, { + .desc = { + .name = "buck8", + .of_match = of_match_ptr("buck8"), + .regulators_node = of_match_ptr("regulators"), + .id = BD73800_BUCK8, + .ops = &bd73800_buck_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd73800_buck12348_volts, + .n_linear_ranges = ARRAY_SIZE(bd73800_buck12348_volts), + .n_voltages = BD73800_NUM_VOLTS, + .enable_reg = BD73800_REG_BUCK8_ON, + .enable_mask = BD73800_MASK_RUN_EN, + .vsel_reg = BD73800_REG_BUCK8_VOLT_RUN, + .vsel_mask = BD73800_MASK_VOLT, + .ramp_delay_table = bd71828_ramp_delay, + .n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay), + .ramp_reg = BD73800_REG_BUCK8_MODE, + .ramp_mask = BD73800_MASK_RAMP_DELAY, + .owner = THIS_MODULE, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND, + .run_reg = BD73800_REG_BUCK8_VOLT_RUN, + .run_mask = BD73800_MASK_VOLT, + .idle_reg = BD73800_REG_BUCK8_VOLT_IDLE, + .idle_mask = BD73800_MASK_VOLT, + .idle_on_mask = BD73800_MASK_IDLE_EN, + .suspend_reg = BD73800_REG_BUCK8_VOLT_SUSP, + .suspend_mask = BD73800_MASK_VOLT, + .suspend_on_mask = BD73800_MASK_SUSP_EN, + }, + }, { + .desc = { + .name = "ldo1", + .of_match = of_match_ptr(LDO1_NODE_NAME), + .regulators_node = of_match_ptr("regulators"), + .id = BD73800_LDO1, + .ops = &bd73800_ldo_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd73800_ldo13_low_volts, + .n_linear_ranges = ARRAY_SIZE(bd73800_ldo13_low_volts), + .n_voltages = BD73800_NUM_VOLTS, + .enable_reg = BD73800_REG_LDO1_ON, + .enable_mask = BD73800_MASK_RUN_EN, + .vsel_reg = BD73800_REG_LDO1_VOLT, + .vsel_mask = BD73800_MASK_VOLT, + .owner = THIS_MODULE, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + /* + * LDOs support only single voltage for all states. + * Voltage can be individually enabled for each state + * though. Allow setting enable/disable config by + * setting the _on_mask for all supported states. + */ + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND, + .run_reg = BD73800_REG_LDO1_VOLT, + .run_mask = BD73800_MASK_VOLT, + .idle_on_mask = BD73800_MASK_IDLE_EN, + .suspend_on_mask = BD73800_MASK_SUSP_EN, + }, + }, { + .desc = { + .name = "ldo2", + .of_match = of_match_ptr("ldo2"), + .regulators_node = of_match_ptr("regulators"), + .id = BD73800_LDO2, + .ops = &bd73800_ldo_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd73800_ldo24_volts, + .n_linear_ranges = ARRAY_SIZE(bd73800_ldo24_volts), + .n_voltages = BD73800_NUM_VOLTS, + .enable_reg = BD73800_REG_LDO2_ON, + .enable_mask = BD73800_MASK_RUN_EN, + .vsel_reg = BD73800_REG_LDO2_VOLT, + .vsel_mask = BD73800_MASK_VOLT, + .owner = THIS_MODULE, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND, + .run_reg = BD73800_REG_LDO2_VOLT, + .run_mask = BD73800_MASK_VOLT, + .idle_on_mask = BD73800_MASK_IDLE_EN, + .suspend_on_mask = BD73800_MASK_SUSP_EN, + }, + }, { + .desc = { + .name = "ldo3", + .of_match = of_match_ptr(LDO3_NODE_NAME), + .regulators_node = of_match_ptr("regulators"), + .id = BD73800_LDO3, + .ops = &bd73800_ldo_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd73800_ldo13_low_volts, + .n_linear_ranges = ARRAY_SIZE(bd73800_ldo13_low_volts), + .n_voltages = BD73800_NUM_VOLTS, + .enable_reg = BD73800_REG_LDO3_ON, + .enable_mask = BD73800_MASK_RUN_EN, + .vsel_reg = BD73800_REG_LDO3_VOLT, + .vsel_mask = BD73800_MASK_VOLT, + .owner = THIS_MODULE, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND, + .run_reg = BD73800_REG_LDO3_VOLT, + .run_mask = BD73800_MASK_VOLT, + .idle_on_mask = BD73800_MASK_IDLE_EN, + .suspend_on_mask = BD73800_MASK_SUSP_EN, + }, + }, { + .desc = { + .name = "ldo4", + .of_match = of_match_ptr("ldo4"), + .regulators_node = of_match_ptr("regulators"), + .id = BD73800_LDO4, + .ops = &bd73800_ldo_ops, + .type = REGULATOR_VOLTAGE, + .linear_ranges = bd73800_ldo24_volts, + .n_linear_ranges = ARRAY_SIZE(bd73800_ldo24_volts), + .n_voltages = BD73800_NUM_VOLTS, + .enable_reg = BD73800_REG_LDO4_ON, + .enable_mask = BD73800_MASK_RUN_EN, + .vsel_reg = BD73800_REG_LDO4_VOLT, + .vsel_mask = BD73800_MASK_VOLT, + .owner = THIS_MODULE, + .of_parse_cb = buck_set_hw_dvs_levels, + }, + .dvs = { + .level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE | + ROHM_DVS_LEVEL_SUSPEND, + .run_reg = BD73800_REG_LDO4_VOLT, + .run_mask = BD73800_MASK_VOLT, + .idle_on_mask = BD73800_MASK_IDLE_EN, + .suspend_on_mask = BD73800_MASK_SUSP_EN, + }, + }, +}; + static int bd72720_buck10_ldon_head_mode(struct device *dev, struct device_node *npreg, struct regmap *regmap, @@ -1619,6 +2111,52 @@ static int bd72720_dt_parse(struct device *dev, return bd72720_buck10_ldon_head_mode(dev, nproot, regmap, buck10_desc); } +static bool bd73800_use_ldo_high_range(struct device_node *nproot, + const char *ldo_node) +{ + struct device_node *np __free(device_node) = + of_get_child_by_name(nproot, ldo_node); + + if (!np) + return false; + + return of_property_read_bool(np, "rohm,ldo-range-high"); +} + +static int bd73800_check_ldo_otp_options(struct device *dev, + struct bd71828_regulator_data *d, + unsigned int num_reg_data) +{ + struct device_node *nproot __free(device_node) = + of_get_child_by_name(dev->parent->of_node, "regulators"); + + /* + * The code assumes regulator IDs to start from 0 and to match the + * indexing of regulator data arrays. WARN if someone changes this. + */ + WARN_ON(d[BD73800_LDO1].desc.id != BD73800_LDO1); + WARN_ON(d[BD73800_LDO3].desc.id != BD73800_LDO3); + + if (!nproot) { + dev_err(dev, "failed to find regulators node\n"); + return -ENODEV; + } + + if (bd73800_use_ldo_high_range(nproot, LDO1_NODE_NAME)) { + d[BD73800_LDO1].desc.linear_ranges = bd73800_ldo13_high_volts; + d[BD73800_LDO1].desc.n_linear_ranges = + ARRAY_SIZE(bd73800_ldo13_high_volts); + } + + if (bd73800_use_ldo_high_range(nproot, LDO3_NODE_NAME)) { + d[BD73800_LDO3].desc.linear_ranges = bd73800_ldo13_high_volts; + d[BD73800_LDO3].desc.n_linear_ranges = + ARRAY_SIZE(bd73800_ldo13_high_volts); + } + + return 0; +} + static int bd71828_probe(struct platform_device *pdev) { int i, j, ret, num_regulators; @@ -1656,6 +2194,23 @@ static int bd71828_probe(struct platform_device *pdev) num_regulators = ARRAY_SIZE(bd71828_rdata); break; + + case ROHM_CHIP_TYPE_BD73800: + { + rdata = devm_kmemdup(&pdev->dev, bd73800_rdata, + sizeof(bd73800_rdata), GFP_KERNEL); + if (!rdata) + return -ENOMEM; + + num_regulators = ARRAY_SIZE(bd73800_rdata); + + ret = bd73800_check_ldo_otp_options(&pdev->dev, rdata, + num_regulators); + if (ret) + return ret; + + break; + } default: return dev_err_probe(&pdev->dev, -EINVAL, "Unsupported device\n"); @@ -1692,6 +2247,7 @@ static int bd71828_probe(struct platform_device *pdev) static const struct platform_device_id bd71828_pmic_id[] = { { .name = "bd71828-pmic", .driver_data = ROHM_CHIP_TYPE_BD71828 }, { .name = "bd72720-pmic", .driver_data = ROHM_CHIP_TYPE_BD72720 }, + { .name = "bd73800-pmic", .driver_data = ROHM_CHIP_TYPE_BD73800 }, { } }; MODULE_DEVICE_TABLE(platform, bd71828_pmic_id); diff --git a/drivers/rtc/rtc-bd70528.c b/drivers/rtc/rtc-bd70528.c index 482810b61495..fd415e327ea6 100644 --- a/drivers/rtc/rtc-bd70528.c +++ b/drivers/rtc/rtc-bd70528.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -284,6 +285,12 @@ static int bd70528_probe(struct platform_device *pdev) bd_rtc->bd718xx_alm_block_start = BD72720_REG_RTC_ALM_START; hour_reg = BD72720_REG_RTC_HOUR; break; + case ROHM_CHIP_TYPE_BD73800: + bd_rtc->reg_time_start = BD73800_REG_RTC_START; + bd_rtc->bd718xx_alm_block_start = BD73800_REG_RTC_ALM_START; + hour_reg = BD73800_REG_RTC_HOUR; + break; + default: dev_err(&pdev->dev, "Unknown chip\n"); return -ENOENT; @@ -344,6 +351,7 @@ static const struct platform_device_id bd718x7_rtc_id[] = { { .name = "bd71828-rtc", .driver_data = ROHM_CHIP_TYPE_BD71828 }, { .name = "bd71815-rtc", .driver_data = ROHM_CHIP_TYPE_BD71815 }, { .name = "bd72720-rtc", .driver_data = ROHM_CHIP_TYPE_BD72720 }, + { .name = "bd73800-rtc", .driver_data = ROHM_CHIP_TYPE_BD73800 }, { } }; MODULE_DEVICE_TABLE(platform, bd718x7_rtc_id); diff --git a/drivers/video/backlight/lm3533_bl.c b/drivers/video/backlight/lm3533_bl.c index babfd3ceec86..adcd6ac7cf22 100644 --- a/drivers/video/backlight/lm3533_bl.c +++ b/drivers/video/backlight/lm3533_bl.c @@ -10,7 +10,9 @@ #include #include #include +#include #include +#include #include #include @@ -20,13 +22,21 @@ #define LM3533_BL_MAX_BRIGHTNESS 255 #define LM3533_REG_CTRLBANK_AB_BCONF 0x1a +#define CTRLBANK_AB_BCONF_ALS(n) BIT(2 * (n)) +#define CTRLBANK_AB_BCONF_MODE(n) BIT(2 * (n) + 1) struct lm3533_bl { - struct lm3533 *lm3533; + struct regmap *regmap; struct lm3533_ctrlbank cb; struct backlight_device *bd; int id; + + u32 max_current; + u32 pwm; + + bool have_als; + bool linear; }; @@ -45,7 +55,7 @@ static int lm3533_bl_update_status(struct backlight_device *bd) static int lm3533_bl_get_brightness(struct backlight_device *bd) { struct lm3533_bl *bl = bl_get_data(bd); - u8 val; + u32 val; int ret; ret = lm3533_ctrlbank_get_brightness(&bl->cb, &val); @@ -77,103 +87,75 @@ static ssize_t show_als_channel(struct device *dev, return scnprintf(buf, PAGE_SIZE, "%u\n", channel); } -static ssize_t show_als_en(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t show_als_en(struct device *dev, struct device_attribute *attr, + char *buf) { struct lm3533_bl *bl = dev_get_drvdata(dev); int ctrlbank = lm3533_bl_get_ctrlbank_id(bl); - u8 val; - u8 mask; - bool enable; int ret; - ret = lm3533_read(bl->lm3533, LM3533_REG_CTRLBANK_AB_BCONF, &val); - if (ret) + ret = regmap_test_bits(bl->regmap, LM3533_REG_CTRLBANK_AB_BCONF, + CTRLBANK_AB_BCONF_ALS(ctrlbank)); + if (ret < 0) return ret; - mask = 1 << (2 * ctrlbank); - enable = val & mask; - - return scnprintf(buf, PAGE_SIZE, "%d\n", enable); + return scnprintf(buf, PAGE_SIZE, "%d\n", ret); } -static ssize_t store_als_en(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) +static ssize_t store_als_en(struct device *dev, struct device_attribute *attr, + const char *buf, size_t len) { struct lm3533_bl *bl = dev_get_drvdata(dev); int ctrlbank = lm3533_bl_get_ctrlbank_id(bl); int enable; - u8 val; - u8 mask; int ret; if (kstrtoint(buf, 0, &enable)) return -EINVAL; - mask = 1 << (2 * ctrlbank); - - if (enable) - val = mask; - else - val = 0; - - ret = lm3533_update(bl->lm3533, LM3533_REG_CTRLBANK_AB_BCONF, val, - mask); + ret = regmap_assign_bits(bl->regmap, LM3533_REG_CTRLBANK_AB_BCONF, + CTRLBANK_AB_BCONF_ALS(ctrlbank), enable); if (ret) return ret; return len; } -static ssize_t show_linear(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t show_linear(struct device *dev, struct device_attribute *attr, + char *buf) { struct lm3533_bl *bl = dev_get_drvdata(dev); - u8 val; - u8 mask; - int linear; + int ctrlbank = lm3533_bl_get_ctrlbank_id(bl); int ret; - ret = lm3533_read(bl->lm3533, LM3533_REG_CTRLBANK_AB_BCONF, &val); - if (ret) + ret = regmap_test_bits(bl->regmap, LM3533_REG_CTRLBANK_AB_BCONF, + CTRLBANK_AB_BCONF_MODE(ctrlbank)); + if (ret < 0) return ret; - mask = 1 << (2 * lm3533_bl_get_ctrlbank_id(bl) + 1); - - if (val & mask) - linear = 1; - else - linear = 0; - - return scnprintf(buf, PAGE_SIZE, "%x\n", linear); + return scnprintf(buf, PAGE_SIZE, "%x\n", ret); } -static ssize_t store_linear(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) +static ssize_t store_linear(struct device *dev, struct device_attribute *attr, + const char *buf, size_t len) { struct lm3533_bl *bl = dev_get_drvdata(dev); + int ctrlbank = lm3533_bl_get_ctrlbank_id(bl); + struct backlight_device *bd = bl->bd; unsigned long linear; - u8 mask; - u8 val; int ret; if (kstrtoul(buf, 0, &linear)) return -EINVAL; - mask = 1 << (2 * lm3533_bl_get_ctrlbank_id(bl) + 1); - - if (linear) - val = mask; - else - val = 0; - - ret = lm3533_update(bl->lm3533, LM3533_REG_CTRLBANK_AB_BCONF, val, - mask); + ret = regmap_assign_bits(bl->regmap, LM3533_REG_CTRLBANK_AB_BCONF, + CTRLBANK_AB_BCONF_MODE(ctrlbank), linear); if (ret) return ret; + bd->props.scale = linear ? BACKLIGHT_SCALE_LINEAR : + BACKLIGHT_SCALE_NON_LINEAR; + return len; } @@ -182,7 +164,7 @@ static ssize_t show_pwm(struct device *dev, char *buf) { struct lm3533_bl *bl = dev_get_drvdata(dev); - u8 val; + u32 val; int ret; ret = lm3533_ctrlbank_get_pwm(&bl->cb, &val); @@ -197,10 +179,10 @@ static ssize_t store_pwm(struct device *dev, const char *buf, size_t len) { struct lm3533_bl *bl = dev_get_drvdata(dev); - u8 val; + u32 val; int ret; - if (kstrtou8(buf, 0, &val)) + if (kstrtou32(buf, 0, &val)) return -EINVAL; ret = lm3533_ctrlbank_set_pwm(&bl->cb, val); @@ -234,7 +216,7 @@ static umode_t lm3533_bl_attr_is_visible(struct kobject *kobj, if (attr == &dev_attr_als_channel.attr || attr == &dev_attr_als_en.attr) { - if (!bl->lm3533->have_als) + if (!bl->have_als) mode = 0; } @@ -246,25 +228,36 @@ static struct attribute_group lm3533_bl_attribute_group = { .attrs = lm3533_bl_attributes }; -static int lm3533_bl_setup(struct lm3533_bl *bl, - struct lm3533_bl_platform_data *pdata) +static const struct attribute_group *lm3533_bl_attribute_groups[] = { + &lm3533_bl_attribute_group, + NULL, +}; + +static int lm3533_bl_setup(struct lm3533_bl *bl) { + int ctrlbank = lm3533_bl_get_ctrlbank_id(bl); int ret; - ret = lm3533_ctrlbank_set_max_current(&bl->cb, pdata->max_current); + ret = regmap_assign_bits(bl->regmap, LM3533_REG_CTRLBANK_AB_BCONF, + CTRLBANK_AB_BCONF_MODE(ctrlbank), bl->linear); if (ret) return ret; - return lm3533_ctrlbank_set_pwm(&bl->cb, pdata->pwm); + ret = lm3533_ctrlbank_set_max_current(&bl->cb, bl->max_current); + if (ret) + return ret; + + return lm3533_ctrlbank_set_pwm(&bl->cb, bl->pwm); } static int lm3533_bl_probe(struct platform_device *pdev) { struct lm3533 *lm3533; - struct lm3533_bl_platform_data *pdata; struct lm3533_bl *bl; struct backlight_device *bd; struct backlight_properties props; + char *name = NULL; + u32 default_brightness = LM3533_BL_MAX_BRIGHTNESS; int ret; dev_dbg(&pdev->dev, "%s\n", __func__); @@ -273,12 +266,6 @@ static int lm3533_bl_probe(struct platform_device *pdev) if (!lm3533) return -EINVAL; - pdata = dev_get_platdata(&pdev->dev); - if (!pdata) { - dev_err(&pdev->dev, "no platform data\n"); - return -EINVAL; - } - if (pdev->id < 0 || pdev->id >= LM3533_HVCTRLBANK_COUNT) { dev_err(&pdev->dev, "illegal backlight id %d\n", pdev->id); return -EINVAL; @@ -288,20 +275,34 @@ static int lm3533_bl_probe(struct platform_device *pdev) if (!bl) return -ENOMEM; - bl->lm3533 = lm3533; + bl->regmap = lm3533->regmap; + bl->have_als = lm3533->have_als; bl->id = pdev->id; - bl->cb.lm3533 = lm3533; + bl->cb.regmap = lm3533->regmap; bl->cb.id = lm3533_bl_get_ctrlbank_id(bl); bl->cb.dev = NULL; /* until registered */ + name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s-%d", + pdev->name, pdev->id); + if (!name) + return -ENOMEM; + + device_property_read_u32(&pdev->dev, "default-brightness", + &default_brightness); + memset(&props, 0, sizeof(props)); props.type = BACKLIGHT_RAW; props.max_brightness = LM3533_BL_MAX_BRIGHTNESS; - props.brightness = pdata->default_brightness; - bd = devm_backlight_device_register(&pdev->dev, pdata->name, - pdev->dev.parent, bl, &lm3533_bl_ops, - &props); + props.brightness = default_brightness; + + bl->linear = device_property_read_bool(&pdev->dev, + "ti,linear-mapping-mode"); + props.scale = bl->linear ? BACKLIGHT_SCALE_LINEAR : + BACKLIGHT_SCALE_NON_LINEAR; + + bd = devm_backlight_device_register(&pdev->dev, name, &pdev->dev, + bl, &lm3533_bl_ops, &props); if (IS_ERR(bd)) { dev_err(&pdev->dev, "failed to register backlight device\n"); return PTR_ERR(bd); @@ -312,28 +313,24 @@ static int lm3533_bl_probe(struct platform_device *pdev) platform_set_drvdata(pdev, bl); - ret = sysfs_create_group(&bd->dev.kobj, &lm3533_bl_attribute_group); - if (ret < 0) { - dev_err(&pdev->dev, "failed to create sysfs attributes\n"); + device_property_read_u32(&pdev->dev, "led-max-microamp", + &bl->max_current); + bl->max_current = clamp(bl->max_current, LM3533_MAX_CURRENT_MIN, + LM3533_MAX_CURRENT_MAX); + + device_property_read_u32(&pdev->dev, "ti,pwm-config-mask", &bl->pwm); + + ret = lm3533_bl_setup(bl); + if (ret) return ret; - } backlight_update_status(bd); - ret = lm3533_bl_setup(bl, pdata); - if (ret) - goto err_sysfs_remove; - ret = lm3533_ctrlbank_enable(&bl->cb); if (ret) - goto err_sysfs_remove; + return ret; return 0; - -err_sysfs_remove: - sysfs_remove_group(&bd->dev.kobj, &lm3533_bl_attribute_group); - - return ret; } static void lm3533_bl_remove(struct platform_device *pdev) @@ -347,7 +344,6 @@ static void lm3533_bl_remove(struct platform_device *pdev) bd->props.brightness = 0; lm3533_ctrlbank_disable(&bl->cb); - sysfs_remove_group(&bd->dev.kobj, &lm3533_bl_attribute_group); } #ifdef CONFIG_PM_SLEEP @@ -381,10 +377,18 @@ static void lm3533_bl_shutdown(struct platform_device *pdev) lm3533_ctrlbank_disable(&bl->cb); } +static const struct of_device_id lm3533_bl_match_table[] = { + { .compatible = "ti,lm3533-backlight" }, + { } +}; +MODULE_DEVICE_TABLE(of, lm3533_bl_match_table); + static struct platform_driver lm3533_bl_driver = { .driver = { .name = "lm3533-backlight", .pm = &lm3533_bl_pm_ops, + .dev_groups = lm3533_bl_attribute_groups, + .of_match_table = lm3533_bl_match_table, }, .probe = lm3533_bl_probe, .remove = lm3533_bl_remove, diff --git a/include/linux/mfd/lm3533.h b/include/linux/mfd/lm3533.h index 69059a7a2ce5..8f72dd41e8f0 100644 --- a/include/linux/mfd/lm3533.h +++ b/include/linux/mfd/lm3533.h @@ -15,9 +15,14 @@ #define LM3533_ATTR_RW(_name) \ DEVICE_ATTR(_name, S_IRUGO | S_IWUSR , show_##_name, store_##_name) +#define LM3533_MAX_CURRENT_MIN 5000 +#define LM3533_MAX_CURRENT_MAX 29800 +#define LM3533_MAX_CURRENT_STEP 800 + struct device; struct gpio_desc; struct regmap; +struct regulator; struct lm3533 { struct device *dev; @@ -25,7 +30,10 @@ struct lm3533 { struct regmap *regmap; struct gpio_desc *hwen; - int irq; + struct regulator *vin_supply; + + u32 boost_ovp; + u32 boost_freq; unsigned have_als:1; unsigned have_backlights:1; @@ -33,67 +41,18 @@ struct lm3533 { }; struct lm3533_ctrlbank { - struct lm3533 *lm3533; + struct regmap *regmap; struct device *dev; int id; }; -struct lm3533_als_platform_data { - unsigned pwm_mode:1; /* PWM input mode (default analog) */ - u8 r_select; /* 1 - 127 (ignored in PWM-mode) */ -}; +int lm3533_ctrlbank_enable(struct lm3533_ctrlbank *cb); +int lm3533_ctrlbank_disable(struct lm3533_ctrlbank *cb); -struct lm3533_bl_platform_data { - char *name; - u16 max_current; /* 5000 - 29800 uA (800 uA step) */ - u8 default_brightness; /* 0 - 255 */ - u8 pwm; /* 0 - 0x3f */ -}; - -struct lm3533_led_platform_data { - char *name; - const char *default_trigger; - u16 max_current; /* 5000 - 29800 uA (800 uA step) */ - u8 pwm; /* 0 - 0x3f */ -}; - -enum lm3533_boost_freq { - LM3533_BOOST_FREQ_500KHZ, - LM3533_BOOST_FREQ_1000KHZ, -}; - -enum lm3533_boost_ovp { - LM3533_BOOST_OVP_16V, - LM3533_BOOST_OVP_24V, - LM3533_BOOST_OVP_32V, - LM3533_BOOST_OVP_40V, -}; - -struct lm3533_platform_data { - enum lm3533_boost_ovp boost_ovp; - enum lm3533_boost_freq boost_freq; - - struct lm3533_als_platform_data *als; - - struct lm3533_bl_platform_data *backlights; - int num_backlights; - - struct lm3533_led_platform_data *leds; - int num_leds; -}; - -extern int lm3533_ctrlbank_enable(struct lm3533_ctrlbank *cb); -extern int lm3533_ctrlbank_disable(struct lm3533_ctrlbank *cb); - -extern int lm3533_ctrlbank_set_brightness(struct lm3533_ctrlbank *cb, u8 val); -extern int lm3533_ctrlbank_get_brightness(struct lm3533_ctrlbank *cb, u8 *val); -extern int lm3533_ctrlbank_set_max_current(struct lm3533_ctrlbank *cb, - u16 imax); -extern int lm3533_ctrlbank_set_pwm(struct lm3533_ctrlbank *cb, u8 val); -extern int lm3533_ctrlbank_get_pwm(struct lm3533_ctrlbank *cb, u8 *val); - -extern int lm3533_read(struct lm3533 *lm3533, u8 reg, u8 *val); -extern int lm3533_write(struct lm3533 *lm3533, u8 reg, u8 val); -extern int lm3533_update(struct lm3533 *lm3533, u8 reg, u8 val, u8 mask); +int lm3533_ctrlbank_set_brightness(struct lm3533_ctrlbank *cb, u32 val); +int lm3533_ctrlbank_get_brightness(struct lm3533_ctrlbank *cb, u32 *val); +int lm3533_ctrlbank_set_max_current(struct lm3533_ctrlbank *cb, u32 imax); +int lm3533_ctrlbank_set_pwm(struct lm3533_ctrlbank *cb, u32 val); +int lm3533_ctrlbank_get_pwm(struct lm3533_ctrlbank *cb, u32 *val); #endif /* __LINUX_MFD_LM3533_H */ diff --git a/include/linux/mfd/rohm-bd73800.h b/include/linux/mfd/rohm-bd73800.h new file mode 100644 index 000000000000..c6c0d453a40d --- /dev/null +++ b/include/linux/mfd/rohm-bd73800.h @@ -0,0 +1,306 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright 2026 ROHM Semiconductors. + * + * Author: Matti Vaittinen + */ + +#ifndef _MFD_BD73800_H +#define _MFD_BD73800_H + +#include + +enum { + BD73800_BUCK1 = 0, + BD73800_BUCK2, + BD73800_BUCK3, + BD73800_BUCK4, + BD73800_BUCK5, + BD73800_BUCK6, + BD73800_BUCK7, + BD73800_BUCK8, + BD73800_LDO1, + BD73800_LDO2, + BD73800_LDO3, + BD73800_LDO4, +}; + +/* + * All regulators except BUCK 5 have full 8-bit register of valid voltage + * values, including 0. + */ +#define BD73800_NUM_VOLTS (0xff + 1) +/* + * BUCK 5 has two sets of voltage ranges, both having valid voltage selectors + * from 0x0 to 0x7f + */ +#define BD73800_BUCK5_VOLTS (0x80 + 0x80) + +/* BD73800 interrupts */ +enum { + /* INT_STAT_1 register IRQs, ADC and RTC */ + BD73800_INT_ADC_ACCUM_DONE, + BD73800_INT_ADC_ACCUM_OVF, + BD73800_INT_ADC_ACCUM_VAL, + BD73800_INT_ADC_ACCUM_TW, + BD73800_INT_ADC_POW_VAL, + BD73800_INT_RTC0, + BD73800_INT_RTC1, + BD73800_INT_RTC2, + + /* BUCK reg interrupts */ + /* INT_STAT_2 IRQs */ + BD73800_INT_BUCK1_DVS_DONE, + BD73800_INT_BUCK2_DVS_DONE, + BD73800_INT_BUCK3_DVS_DONE, + BD73800_INT_BUCK4_DVS_DONE, + BD73800_INT_BUCK5_DVS_DONE, + BD73800_INT_BUCK6_DVS_DONE, + BD73800_INT_BUCK7_DVS_DONE, + BD73800_INT_BUCK8_DVS_DONE, + /* INT_STAT_3 IRQs */ + BD73800_INT_BUCK1_OCP, + BD73800_INT_BUCK2_OCP, + BD73800_INT_BUCK3_OCP, + BD73800_INT_BUCK4_OCP, + BD73800_INT_BUCK5_OCP, + BD73800_INT_BUCK6_OCP, + BD73800_INT_BUCK7_OCP, + BD73800_INT_BUCK8_OCP, + + /* INT_STAT_4 IRQs, power-button, WDG and reset */ + BD73800_INT_PBTN_LONG_PRESS, + BD73800_INT_PBTN_MID_PRESS, + /* + * The SHORT_PUSH is generated when button is first pressed (longer + * than configured time limit), and then released before the MID_PRESS + * time limit. The SHORT_PRESS is generated immediately when button is + * pressed for longer than configured limit, whether it is released or + * not. + */ + BD73800_INT_PBTN_SHORT_PUSH, + BD73800_INT_PBTN_SHORT_PRESS, + BD73800_INT_WDG, + BD73800_INT_SWRESET, + BD73800_INT_SEQ_DONE, + + /* INT_STAT_5 IRQs, GPIO */ + BD73800_INT_GPIO1, + BD73800_INT_GPIO2, + BD73800_INT_GPIO3, + BD73800_INT_GPIO4, +}; + +#define BD73800_MASK_RUN_EN BIT(2) +#define BD73800_MASK_SUSP_EN BIT(1) +#define BD73800_MASK_IDLE_EN BIT(0) +#define BD73800_MASK_VOLT GENMASK(7, 0) +#define BD73800_MASK_BUCK5_VOLT GENMASK(6, 0) +#define BD73800_MASK_RAMP_DELAY GENMASK(2, 1) +#define BD73800_BUCK5_RANGE_MASK BIT(7) + +/* BD73800 registers */ +enum { + BD73800_REG_PRODUCT_ID = 0x0, + BD73800_REG_MANUFACTURER_ID, + BD73800_REG_REVISION, + BD73800_REG_NVMVERSION, + BD73800_REG_POR_REASON, + BD73800_REG_RESET_REASON1, + BD73800_REG_RESET_REASON2, + BD73800_REG_RESET_REASON3, + BD73800_REG_POW_STATE, + BD73800_REG_WRST_SEL, + BD73800_REG_PS_CTRL_1, + BD73800_REG_PS_CTRL_2, + BD73800_REG_RCVCFG, + BD73800_REG_RCVNUM, + BD73800_REG_CRDCFG, /* 0x0f, followed by undocumented reg */ + + BD73800_REG_BUCK1_ON = 0x11, + BD73800_REG_BUCK1_MODE, + BD73800_REG_BUCK1_VOLT_RUN, + BD73800_REG_BUCK1_VOLT_IDLE, + BD73800_REG_BUCK1_VOLT_SUSP, /* 0x15, followed by undocumented reg */ + + BD73800_REG_BUCK2_ON = 0x17, + BD73800_REG_BUCK2_MODE, + BD73800_REG_BUCK2_VOLT_RUN, + BD73800_REG_BUCK2_VOLT_IDLE, + BD73800_REG_BUCK2_VOLT_SUSP, /* 0x1b */ + + BD73800_REG_BUCK3_ON = 0x1d, + BD73800_REG_BUCK3_MODE, + BD73800_REG_BUCK3_VOLT_RUN, + BD73800_REG_BUCK3_VOLT_IDLE, + BD73800_REG_BUCK3_VOLT_SUSP, /* 0x21 */ + + BD73800_REG_BUCK4_ON = 0x23, + BD73800_REG_BUCK4_MODE, + BD73800_REG_BUCK4_VOLT_RUN, + BD73800_REG_BUCK4_VOLT_IDLE, + BD73800_REG_BUCK4_VOLT_SUSP, /* 0x27 */ + + BD73800_REG_BUCK5_ON = 0x29, + BD73800_REG_BUCK5_MODE, + BD73800_REG_BUCK5_VOLT_RUN, + BD73800_REG_BUCK5_VOLT_IDLE, + BD73800_REG_BUCK5_VOLT_SUSP, /* 0x2d */ + + BD73800_REG_BUCK6_ON = 0x2f, + BD73800_REG_BUCK6_MODE, + BD73800_REG_BUCK6_VOLT_RUN, + BD73800_REG_BUCK6_VOLT_IDLE, + BD73800_REG_BUCK6_VOLT_SUSP, /* 0x33 */ + + BD73800_REG_BUCK7_ON = 0x35, + BD73800_REG_BUCK7_MODE, + BD73800_REG_BUCK7_VOLT_RUN, + BD73800_REG_BUCK7_VOLT_IDLE, + BD73800_REG_BUCK7_VOLT_SUSP, /* 0x39 */ + + BD73800_REG_BUCK8_ON = 0x3b, + BD73800_REG_BUCK8_MODE, + BD73800_REG_BUCK8_VOLT_RUN, + BD73800_REG_BUCK8_VOLT_IDLE, + BD73800_REG_BUCK8_VOLT_SUSP, /* 0x3f */ + + BD73800_REG_LDO1_ON = 0x41, + BD73800_REG_LDO1_VOLT, + BD73800_REG_LDO1_MODE, + BD73800_REG_LDO2_ON, + BD73800_REG_LDO2_VOLT, + BD73800_REG_LDO2_MODE, + BD73800_REG_LDO3_ON, + BD73800_REG_LDO3_VOLT, + BD73800_REG_LDO3_MODE, + BD73800_REG_LDO4_ON, + BD73800_REG_LDO4_VOLT, + BD73800_REG_LDO4_MODE, /* 0x4c */ + + BD73800_REG_GPO_OUT = 0x4e, + BD73800_REG_OUT32K = 0x50, + BD73800_REG_RTC_SEC, + BD73800_REG_RTC_MIN, + BD73800_REG_RTC_HOUR, + BD73800_REG_RTC_WEEK, + BD73800_REG_RTC_DAY, + BD73800_REG_RTC_MONTH, + BD73800_REG_RTC_YEAR, + BD73800_REG_RTC_ALM0_SEC, + BD73800_REG_RTC_ALM0_MIN, + BD73800_REG_RTC_ALM0_HOUR, + BD73800_REG_RTC_ALM0_WEEK, + BD73800_REG_RTC_ALM0_DAY, + BD73800_REG_RTC_ALM0_MONTH, + BD73800_REG_RTC_ALM0_YEAR, + BD73800_REG_RTC_ALM1_SEC, + BD73800_REG_RTC_ALM1_MIN, + BD73800_REG_RTC_ALM1_HOUR, + BD73800_REG_RTC_ALM1_WEEK, + BD73800_REG_RTC_ALM1_DAY, + BD73800_REG_RTC_ALM1_MONTH, + BD73800_REG_RTC_ALM1_YEAR, + BD73800_REG_RTC_ALM2, + BD73800_REG_RTC_CONF, /* 0x69 */ + + BD73800_REG_ADC_CTRL_1 = 0x6b, + BD73800_REG_ADC_CTRL_2, + BD73800_REG_ADC_ACCUM_NUM2, + BD73800_REG_ADC_ACCUM_NUM1, + BD73800_REG_ADC_ACCUM_NUM0, + BD73800_REG_ADC_ACCUM_KICK, + BD73800_REG_ADC_ACCUM_CNT2, + BD73800_REG_ADC_ACCUM_CNT1, + BD73800_REG_ADC_ACCUM_CNT0, + BD73800_REG_ADC_ACCUM_VAL2, + BD73800_REG_ADC_ACCUM_VAL1, + BD73800_REG_ADC_ACCUM_VAL0, + BD73800_REG_ADC_VOL_VAL1, + BD73800_REG_ADC_VOL_VAL0, + BD73800_REG_ADC_CUR_VAL1, + BD73800_REG_ADC_CUR_VAL0, + BD73800_REG_ADC_POW_VAL1, + BD73800_REG_ADC_POW_VAL0, + BD73800_REG_ADC_TEMP_VAL1, + BD73800_REG_ADC_TEMP_VAL0, + BD73800_REG_ADC_ACCUM_VAL_INT_TH4, + BD73800_REG_ADC_ACCUM_VAL_INT_TH3, + BD73800_REG_ADC_ACCUM_VAL_INT_TH2, + BD73800_REG_ADC_ACCUM_VAL_INT_TH1, + BD73800_REG_ADC_ACCUM_VAL_INT_TH0, + BD73800_REG_ADC_WARN_TEMP_INT_TH1, + BD73800_REG_ADC_WARN_TEMP_INT_TH0, + BD73800_REG_ADC_POW_VAL_INT_TH1, + BD73800_REG_ADC_POW_VAL_INT_TH0, /* 0x89 */ + + BD73800_REG_PBTN_CONF = 0x8b, + + BD73800_REG_INT_MAIN_EN = 0x8f, + BD73800_REG_INT_1_EN, + BD73800_REG_INT_2_EN, + BD73800_REG_INT_3_EN, + BD73800_REG_INT_4_EN, + BD73800_REG_INT_5_EN, /* 0x94 */ + + BD73800_REG_INT_MAIN_STAT = 0x96, + BD73800_REG_INT_1_STAT, + BD73800_REG_INT_2_STAT, + BD73800_REG_INT_3_STAT, + BD73800_REG_INT_4_STAT, + BD73800_REG_INT_5_STAT, /* 0x9b */ + + BD73800_REG_INT_MAIN_SRC = 0x9d, + BD73800_REG_INT_1_SRC, + BD73800_REG_INT_2_SRC, + BD73800_REG_INT_3_SRC, + BD73800_REG_INT_4_SRC, + BD73800_REG_INT_5_SRC, /* 0xa2 */ + + BD73800_REG_RST_MASK = 0xaf, + BD73800_MAX_REGISTER, +}; + +#define BD73800_REG_RTC_START BD73800_REG_RTC_SEC +#define BD73800_REG_RTC_ALM_START BD73800_REG_RTC_ALM0_SEC + +/* BD73800 IRQ register masks */ + +#define BD73800_INT_MAIN_EN_ALL GENMASK(4, 0) +#define BD73800_INT_ADC_ACCUM_DONE_MASK BIT(0) +#define BD73800_INT_ADC_ACCUM_OVF_MASK BIT(1) +#define BD73800_INT_ADC_ACCUM_VAL_MASK BIT(2) +#define BD73800_INT_ADC_ACCUM_TW_MASK BIT(3) +#define BD73800_INT_ADC_POW_VAL_MASK BIT(4) +#define BD73800_INT_RTC0_MASK BIT(5) +#define BD73800_INT_RTC1_MASK BIT(6) +#define BD73800_INT_RTC2_MASK BIT(7) +#define BD73800_INT_BUCK1_DVS_DONE_MASK BIT(0) +#define BD73800_INT_BUCK2_DVS_DONE_MASK BIT(1) +#define BD73800_INT_BUCK3_DVS_DONE_MASK BIT(2) +#define BD73800_INT_BUCK4_DVS_DONE_MASK BIT(3) +#define BD73800_INT_BUCK5_DVS_DONE_MASK BIT(4) +#define BD73800_INT_BUCK6_DVS_DONE_MASK BIT(5) +#define BD73800_INT_BUCK7_DVS_DONE_MASK BIT(6) +#define BD73800_INT_BUCK8_DVS_DONE_MASK BIT(7) +#define BD73800_INT_BUCK1_OCP_MASK BIT(0) +#define BD73800_INT_BUCK2_OCP_MASK BIT(1) +#define BD73800_INT_BUCK3_OCP_MASK BIT(2) +#define BD73800_INT_BUCK4_OCP_MASK BIT(3) +#define BD73800_INT_BUCK5_OCP_MASK BIT(4) +#define BD73800_INT_BUCK6_OCP_MASK BIT(5) +#define BD73800_INT_BUCK7_OCP_MASK BIT(6) +#define BD73800_INT_BUCK8_OCP_MASK BIT(7) +#define BD73800_INT_PBTN_LONG_PRESS_MASK BIT(0) +#define BD73800_INT_PBTN_MID_PRESS_MASK BIT(1) +#define BD73800_INT_PBTN_SHORT_PUSH_MASK BIT(2) +#define BD73800_INT_PBTN_SHORT_PRESS_MASK BIT(3) +#define BD73800_INT_WDG_MASK BIT(4) +#define BD73800_INT_SWRESET_MASK BIT(5) +#define BD73800_INT_SEQ_DONE_MASK BIT(6) +#define BD73800_INT_GPIO1_MASK BIT(0) +#define BD73800_INT_GPIO2_MASK BIT(1) +#define BD73800_INT_GPIO3_MASK BIT(2) +#define BD73800_INT_GPIO4_MASK BIT(3) + +#endif /* _MFD_BD73800_H */ diff --git a/include/linux/mfd/rohm-generic.h b/include/linux/mfd/rohm-generic.h index 0a284919a6c3..3ec87428ee97 100644 --- a/include/linux/mfd/rohm-generic.h +++ b/include/linux/mfd/rohm-generic.h @@ -17,6 +17,7 @@ enum rohm_chip_type { ROHM_CHIP_TYPE_BD71837, ROHM_CHIP_TYPE_BD71847, ROHM_CHIP_TYPE_BD72720, + ROHM_CHIP_TYPE_BD73800, ROHM_CHIP_TYPE_BD96801, ROHM_CHIP_TYPE_BD96802, ROHM_CHIP_TYPE_BD96805,