Merge branches 'ib-mfd-thermal-7.4', 'ib-mfd-clk-gpio-regulator-rtc-7.4' and 'ib-mfd-backlight-iio-leds-7.4' into ibs-for-mfd-merged

This commit is contained in:
Lee Jones 2026-09-24 15:11:43 +01:00
commit 5f4e029576
28 changed files with 2410 additions and 618 deletions

View File

@ -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 <clamor95@gmail.com>
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

View File

@ -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 <clamor95@gmail.com>
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

View File

@ -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 <clamor95@gmail.com>
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 <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
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;
};
};
};
...

View File

@ -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

View File

@ -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

View File

@ -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<X>-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

View File

@ -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 <mazziesaccount@gmail.com>
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 <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/leds/common.h>
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;
};
};
};
};

View File

@ -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 <mazziesaccount@gmail.com>
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<X>-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

View File

@ -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

View File

@ -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 <mazziesaccount@gmail.com>
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<number> and ldo<number>.
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

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

209
drivers/gpio/gpio-bd73800.c Normal file
View File

@ -0,0 +1,209 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Support to GPIOs on ROHM BD73800
* Copyright 2024 ROHM Semiconductors.
* Author: Matti Vaittinen <mazziesaccount@gmail.com>
*/
#include <linux/bitmap.h>
#include <linux/bitops.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/regmap.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mfd/rohm-bd73800.h>
#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: "<pin> output is controlled by
* GPIO<N>_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 <mazziesaccount@gmail.com>");
MODULE_DESCRIPTION("GPIO interface for BD73800");
MODULE_LICENSE("GPL");

View File

@ -17,14 +17,17 @@
#include <linux/mutex.h>
#include <linux/mfd/core.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/units.h>
#include <linux/mfd/lm3533.h>
#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,

View File

@ -12,6 +12,8 @@
#include <linux/mfd/core.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/mfd/lm3533.h>
@ -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,

View File

@ -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"

View File

@ -7,6 +7,7 @@
* Author: Johan Hovold <jhovold@gmail.com>
*/
#include <linux/bitfield.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
@ -14,19 +15,24 @@
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/units.h>
#include <linux/mfd/lm3533.h>
#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", &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", &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,

View File

@ -9,14 +9,10 @@
#include <linux/device.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/mfd/lm3533.h>
#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");

View File

@ -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 <linux/i2c.h>
@ -14,6 +14,7 @@
#include <linux/mfd/rohm-bd71815.h>
#include <linux/mfd/rohm-bd71828.h>
#include <linux/mfd/rohm-bd72720.h>
#include <linux/mfd/rohm-bd73800.h>
#include <linux/mfd/rohm-generic.h>
#include <linux/module.h>
#include <linux/of.h>
@ -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,
},
{ },
};

View File

@ -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

View File

@ -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 <linux/cleanup.h>
#include <linux/delay.h>
@ -10,6 +9,7 @@
#include <linux/kernel.h>
#include <linux/mfd/rohm-bd71828.h>
#include <linux/mfd/rohm-bd72720.h>
#include <linux/mfd/rohm-bd73800.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@ -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 <state>_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);

View File

@ -8,6 +8,7 @@
#include <linux/mfd/rohm-bd71815.h>
#include <linux/mfd/rohm-bd71828.h>
#include <linux/mfd/rohm-bd72720.h>
#include <linux/mfd/rohm-bd73800.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@ -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);

View File

@ -10,7 +10,9 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/backlight.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/mfd/lm3533.h>
@ -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,

View File

@ -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 */

View File

@ -0,0 +1,306 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright 2026 ROHM Semiconductors.
*
* Author: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
*/
#ifndef _MFD_BD73800_H
#define _MFD_BD73800_H
#include <linux/regmap.h>
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 */

View File

@ -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,