mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 06:04:44 +01:00
gpio updates for v7.0-rc1
GPIOLIB core:
- shrink the GPIO bus driver stub code
- rework software node support for "undefined" software nodes
- provide and use devm_fwnode_gpiod_get_optional()
- only compile the OF quirk for MT2701 when needed
New drivers:
- add the GPIO driver for ROHM bd72720
- add the gpio-line-mux driver providing 1-to-many mapping for a single
real GPIO
Driver changes:
- refactor gpio-pca9570: use lock guard, add missing headers, use devres
consistently
- add support for a new model (G7 Aspeed sgpiom) to the aspeed-sgpio driver
along with some prerequisite refactoring
- use device_get_match_data() where applicable and save some lines
- add support for more models to gpio-cadence
- add the compatible property to reset-gpio and use it in shared GPIO
management
- drop unnecessary use of irqd_get_trigger_type() in gpio-max77759
- add support for a new variant to gpio-pca953x
- extend build coverage with COMPILE_TEST for more drivers
- constify configfs structures in gpio-sim and gpio-virtuser
- add support for the K3 SoC to gpio-spacemit
- implement the missing .get_direction() callback in gpio-max77620
- add support for Tegra264 to gpio-tegra186
- drop unneeded MODULE_ALIAS() from gpio-menz127
DT bindings:
- document support for the opencores GPIO controller in gpio-mmio
- document new variants for gpio-pca953x
Documentation:
- extensively describe interrupt source detection for gpio-pca953x and
add more models to the list of supported variants
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEkeUTLeW1Rh17omX8BZ0uy/82hMMFAmmK9bwACgkQBZ0uy/82
hMM3rQ/7BTRmMgGiJXlDpqkUoA9fQusiEcokwgmpvlJFM3cb2ANzrjxqZDGnUVLS
OFaVCPjgUTDrmWNgSSy5SBfyfVkvbXmT7X5+e38qotlNun6BKCPhF1H5HxBgJv9P
ObHXZ6ACrg4Ia+jl0QkpIXUDC/vAzaBUml5LUATGHpwf/pa4ZcBDXXbLIEtEfSpb
kNDDQVeWJlWxDYNuJudR8BL2saZFEoD9RaX8F4jLya8ogecoKXElK8Nj0G0Gua8D
UkH9aKMlNTIrk/iE6MiohaLWWqBgRV6+wO6vd2IRek5iItTbPffk4iT2/dOiX8H4
HcOxXBxACH/+wicXGwY360r5M5BCYaMcUvLQaCxLuac2T4302aFLcrWH7be+Ju6f
F+rPBRK1LTYwn0LNlu1I7hYBbwNWHCXfWejXXTH4pMO4uyiwCPpkBHXWCyjWSTuV
YhIbWVYuQjVgxvPCoJ0+67ju++I2ShlXtiT6NorQrxGt9CCBzMN4KU/uMPkN5j+Z
RgurHuEEB1hZ8h5Tzs058L6Pxfyp4eY6Qy8BKLPcrGZaKvvX/EZeI/JkeQOOItKe
VoVq4NIeeqYmqzFa5xrsRYnGUw6lKVj2M5SrjRfbGRz4xVX+rSgrBZMrz1gJyisP
1M5LiGj+c91oo41tysJdPjkc8dkN47hFbNLzB27kXDfm77qlbUE=
=Zhuy
-----END PGP SIGNATURE-----
Merge tag 'gpio-updates-for-v7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux
Pull gpio updates from Bartosz Golaszewski:
"There are two new drivers and some changes to GPIO core but mostly
just GPIO driver updates across a wide array of files, adding support
for new models as well as various refactoring changes. Nothing
controversial and everything has spent a good measure of time in
linux-next.
GPIOLIB core:
- shrink the GPIO bus driver stub code
- rework software node support for "undefined" software nodes
- provide and use devm_fwnode_gpiod_get_optional()
- only compile the OF quirk for MT2701 when needed
New drivers:
- add the GPIO driver for ROHM bd72720
- add the gpio-line-mux driver providing 1-to-many mapping for a
single real GPIO
Driver changes:
- refactor gpio-pca9570: use lock guard, add missing headers, use
devres consistently
- add support for a new model (G7 Aspeed sgpiom) to the aspeed-sgpio
driver along with some prerequisite refactoring
- use device_get_match_data() where applicable and save some lines
- add support for more models to gpio-cadence
- add the compatible property to reset-gpio and use it in shared GPIO
management
- drop unnecessary use of irqd_get_trigger_type() in gpio-max77759
- add support for a new variant to gpio-pca953x
- extend build coverage with COMPILE_TEST for more drivers
- constify configfs structures in gpio-sim and gpio-virtuser
- add support for the K3 SoC to gpio-spacemit
- implement the missing .get_direction() callback in gpio-max77620
- add support for Tegra264 to gpio-tegra186
- drop unneeded MODULE_ALIAS() from gpio-menz127
DT bindings:
- document support for the opencores GPIO controller in gpio-mmio
- document new variants for gpio-pca953x
Documentation:
- extensively describe interrupt source detection for gpio-pca953x
and add more models to the list of supported variants"
* tag 'gpio-updates-for-v7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (59 commits)
gpio: tegra186: Add support for Tegra264
dt-bindings: gpio: Add Tegra264 support
gpio: spacemit-k1: Use PDR for pin direction, not SDR/CDR
gpio: max77620: Implement .get_direction() callback
gpio: aspeed-sgpio: Support G7 Aspeed sgpiom controller
dt-bindings: gpio: aspeed,sgpio: Support ast2700
gpio: aspeed-sgpio: Convert IRQ functions to use llops callbacks
gpio: aspeed-sgpio: Create llops to handle hardware access
gpio: aspeed-sgpio: Remove unused bank name field
gpio: aspeed-sgpio: Change the macro to support deferred probe
regulator: bd71815: switch to devm_fwnode_gpiod_get_optional
gpiolib: introduce devm_fwnode_gpiod_get_optional() wrapper
gpio: mmio: Add compatible for opencores GPIO
dt-bindings: gpio-mmio: Correct opencores GPIO
gpio: pca9570: use lock guards
gpio: pca9570: Don't use "proxy" headers
gpio: pca9570: Use devm_mutex_init() for mutex initialization
MAINTAINERS: Add ROHM BD72720 PMIC
power: supply: bd71828-power: Support ROHM BD72720
power: supply: bd71828: Support wider register addresses
...
This commit is contained in:
commit
d701782152
51 changed files with 4172 additions and 432 deletions
|
|
@ -10,7 +10,8 @@ maintainers:
|
|||
- Andrew Jeffery <andrew@aj.id.au>
|
||||
|
||||
description:
|
||||
This SGPIO controller is for ASPEED AST2400, AST2500 and AST2600 SoC,
|
||||
This SGPIO controller is for ASPEED AST2400, AST2500, AST2600 and AST2700 SoC,
|
||||
AST2700 have two sgpio master both with 256 pins,
|
||||
AST2600 have two sgpio master one with 128 pins another one with 80 pins,
|
||||
AST2500/AST2400 have one sgpio master with 80 pins. Each of the Serial
|
||||
GPIO pins can be programmed to support the following options
|
||||
|
|
@ -27,6 +28,7 @@ properties:
|
|||
- aspeed,ast2400-sgpio
|
||||
- aspeed,ast2500-sgpio
|
||||
- aspeed,ast2600-sgpiom
|
||||
- aspeed,ast2700-sgpiom
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
|||
107
Documentation/devicetree/bindings/gpio/gpio-line-mux.yaml
Normal file
107
Documentation/devicetree/bindings/gpio/gpio-line-mux.yaml
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/gpio/gpio-line-mux.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: GPIO line mux
|
||||
|
||||
maintainers:
|
||||
- Jonas Jelonek <jelonek.jonas@gmail.com>
|
||||
|
||||
description: |
|
||||
A GPIO controller to provide virtual GPIOs for a 1-to-many input-only mapping
|
||||
backed by a single shared GPIO and a multiplexer. A simple illustrated
|
||||
example is:
|
||||
|
||||
+----- A
|
||||
IN /
|
||||
<-----o------- B
|
||||
/ |\
|
||||
| | +----- C
|
||||
| | \
|
||||
| | +--- D
|
||||
| |
|
||||
M1 M0
|
||||
|
||||
MUX CONTROL
|
||||
|
||||
M1 M0 IN
|
||||
0 0 A
|
||||
0 1 B
|
||||
1 0 C
|
||||
1 1 D
|
||||
|
||||
This can be used in case a real GPIO is connected to multiple inputs and
|
||||
controlled by a multiplexer, and another subsystem/driver does not work
|
||||
directly with the multiplexer subsystem.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: gpio-line-mux
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
"#gpio-cells":
|
||||
const: 2
|
||||
|
||||
gpio-line-mux-states:
|
||||
description: Mux states corresponding to the virtual GPIOs.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
|
||||
gpio-line-names: true
|
||||
|
||||
mux-controls:
|
||||
maxItems: 1
|
||||
description:
|
||||
Phandle to the multiplexer to control access to the GPIOs.
|
||||
|
||||
ngpios: false
|
||||
|
||||
muxed-gpios:
|
||||
maxItems: 1
|
||||
description:
|
||||
GPIO which is the '1' in 1-to-many and is shared by the virtual GPIOs
|
||||
and controlled via the mux.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- gpio-controller
|
||||
- gpio-line-mux-states
|
||||
- mux-controls
|
||||
- muxed-gpios
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/mux/mux.h>
|
||||
|
||||
sfp_gpio_mux: mux-controller-1 {
|
||||
compatible = "gpio-mux";
|
||||
mux-gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>,
|
||||
<&gpio0 1 GPIO_ACTIVE_HIGH>;
|
||||
#mux-control-cells = <0>;
|
||||
idle-state = <MUX_IDLE_AS_IS>;
|
||||
};
|
||||
|
||||
sfp1_gpio: sfp-gpio-1 {
|
||||
compatible = "gpio-line-mux";
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
||||
mux-controls = <&sfp_gpio_mux>;
|
||||
muxed-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>;
|
||||
|
||||
gpio-line-mux-states = <0>, <1>, <3>;
|
||||
};
|
||||
|
||||
sfp1: sfp-p1 {
|
||||
compatible = "sff,sfp";
|
||||
|
||||
i2c-bus = <&sfp1_i2c>;
|
||||
los-gpios = <&sfp1_gpio 0 GPIO_ACTIVE_HIGH>;
|
||||
mod-def0-gpios = <&sfp1_gpio 1 GPIO_ACTIVE_LOW>;
|
||||
tx-fault-gpios = <&sfp1_gpio 2 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
|
|
@ -20,9 +20,10 @@ properties:
|
|||
compatible:
|
||||
enum:
|
||||
- brcm,bcm6345-gpio
|
||||
- ni,169445-nand-gpio
|
||||
- wd,mbl-gpio # Western Digital MyBook Live memory-mapped GPIO controller
|
||||
- intel,ixp4xx-expansion-bus-mmio-gpio
|
||||
- ni,169445-nand-gpio
|
||||
- opencores,gpio
|
||||
- wd,mbl-gpio # Western Digital MyBook Live memory-mapped GPIO controller
|
||||
|
||||
big-endian: true
|
||||
|
||||
|
|
|
|||
|
|
@ -74,6 +74,8 @@ properties:
|
|||
- ti,tca9538
|
||||
- ti,tca9539
|
||||
- ti,tca9554
|
||||
- ti,tcal6408
|
||||
- ti,tcal6416
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
|||
|
|
@ -86,6 +86,9 @@ properties:
|
|||
- nvidia,tegra234-gpio
|
||||
- nvidia,tegra234-gpio-aon
|
||||
- nvidia,tegra256-gpio
|
||||
- nvidia,tegra264-gpio
|
||||
- nvidia,tegra264-gpio-uphy
|
||||
- nvidia,tegra264-gpio-aon
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
|
|
@ -110,6 +113,10 @@ properties:
|
|||
ports, in the order the HW manual describes them. The number of entries
|
||||
required varies depending on compatible value.
|
||||
|
||||
wakeup-parent:
|
||||
description: Phandle to the parent interrupt controller used for wake-up. On
|
||||
Tegra, this typically references the PMC interrupt controller.
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
gpio-ranges:
|
||||
|
|
@ -157,6 +164,8 @@ allOf:
|
|||
- nvidia,tegra194-gpio
|
||||
- nvidia,tegra234-gpio
|
||||
- nvidia,tegra256-gpio
|
||||
- nvidia,tegra264-gpio
|
||||
- nvidia,tegra264-gpio-uphy
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
|
|
@ -171,12 +180,25 @@ allOf:
|
|||
- nvidia,tegra186-gpio-aon
|
||||
- nvidia,tegra194-gpio-aon
|
||||
- nvidia,tegra234-gpio-aon
|
||||
- nvidia,tegra264-gpio-aon
|
||||
then:
|
||||
properties:
|
||||
interrupts:
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- nvidia,tegra264-gpio
|
||||
- nvidia,tegra264-gpio-uphy
|
||||
- nvidia,tegra264-gpio-aon
|
||||
then:
|
||||
required:
|
||||
- wakeup-parent
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@ properties:
|
|||
pattern: "^gpio@[0-9a-f]+$"
|
||||
|
||||
compatible:
|
||||
const: spacemit,k1-gpio
|
||||
enum:
|
||||
- spacemit,k1-gpio
|
||||
- spacemit,k3-gpio
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
|||
|
|
@ -10,11 +10,12 @@ maintainers:
|
|||
- Matti Vaittinen <mazziesaccount@gmail.com>
|
||||
|
||||
description: |
|
||||
This module is part of the ROHM BD71828 MFD device. For more details
|
||||
see Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml.
|
||||
This module is part of the ROHM BD71828 and BD72720 MFD device. For more
|
||||
details see Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml
|
||||
and Documentation/devicetree/bindings/mfd/rohm,bd72720-pmic.yaml
|
||||
|
||||
The LED controller is represented as a sub-node of the PMIC node on the device
|
||||
tree.
|
||||
tree. This should be located under "leds" - node in PMIC node.
|
||||
|
||||
The device has two LED outputs referred as GRNLED and AMBLED in data-sheet.
|
||||
|
||||
|
|
|
|||
339
Documentation/devicetree/bindings/mfd/rohm,bd72720-pmic.yaml
Normal file
339
Documentation/devicetree/bindings/mfd/rohm,bd72720-pmic.yaml
Normal file
|
|
@ -0,0 +1,339 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mfd/rohm,bd72720-pmic.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: ROHM BD72720 Power Management Integrated Circuit
|
||||
|
||||
maintainers:
|
||||
- Matti Vaittinen <mazziesaccount@gmail.com>
|
||||
|
||||
description:
|
||||
BD72720 is a single-chip power management IC for battery-powered portable
|
||||
devices. The BD72720 integrates 10 bucks and 11 LDOs, and a 3000 mA
|
||||
switching charger. The IC also includes a Coulomb counter, a real-time
|
||||
clock (RTC), GPIOs and a 32.768 kHz clock gate.
|
||||
|
||||
# In addition to the properties found from the charger node, the ROHM BD72720
|
||||
# uses properties from a static battery node. Please see the:
|
||||
# Documentation/devicetree/bindings/power/supply/battery.yaml
|
||||
#
|
||||
# Following properties are used
|
||||
# when present:
|
||||
#
|
||||
# charge-full-design-microamp-hours: Battry capacity in mAh
|
||||
# voltage-max-design-microvolt: Maximum voltage
|
||||
# voltage-min-design-microvolt: Minimum voltage system is still operating.
|
||||
# degrade-cycle-microamp-hours: Capacity lost due to aging at each full
|
||||
# charge cycle.
|
||||
# ocv-capacity-celsius: Array of OCV table temperatures. 1/table.
|
||||
# ocv-capacity-table-<N>: Table of OCV voltage/SOC pairs. Corresponds
|
||||
# N.th temperature in ocv-capacity-celsius
|
||||
#
|
||||
# volt-drop-thresh-microvolt: Threshold for starting the VDR correction
|
||||
# volt-drop-soc: Table of capacity values matching the
|
||||
# values in VDR tables.
|
||||
#
|
||||
# volt-drop-temperatures-millicelsius: Temperatures corresponding to the volage
|
||||
# drop values given in volt-drop-[0-9]-microvolt
|
||||
#
|
||||
# volt-drop-[0-9]-microvolt: VDR table for a temperature specified in
|
||||
# volt-drop-temperatures-millicelsius
|
||||
#
|
||||
# VDR tables are (usually) determined for a specific battery by ROHM.
|
||||
# The battery node would then be referred from the charger node:
|
||||
#
|
||||
# monitored-battery = <&battery>;
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: rohm,bd72720
|
||||
|
||||
reg:
|
||||
description:
|
||||
I2C slave address.
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
"#gpio-cells":
|
||||
const: 2
|
||||
description:
|
||||
The first cell is the pin number and the second cell is used to specify
|
||||
flags. See the gpio binding document for more information.
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
"#clock-cells":
|
||||
const: 0
|
||||
|
||||
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,charger-sense-resistor-micro-ohms:
|
||||
minimum: 10000
|
||||
maximum: 50000
|
||||
description:
|
||||
BD72720 has a SAR ADC for measuring charging currents. External sense
|
||||
resistor (RSENSE in data sheet) should be used. If some other but
|
||||
30 mOhm resistor is used the resistance value should be given here in
|
||||
micro Ohms.
|
||||
|
||||
regulators:
|
||||
$ref: /schemas/regulator/rohm,bd72720-regulator.yaml
|
||||
description:
|
||||
List of child nodes that specify the regulators.
|
||||
|
||||
leds:
|
||||
$ref: /schemas/leds/rohm,bd71828-leds.yaml
|
||||
|
||||
rohm,pin-fault_b:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
description:
|
||||
BD72720 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
|
||||
- gpo
|
||||
- pwrseq
|
||||
|
||||
patternProperties:
|
||||
"^rohm,pin-dvs[0-1]$":
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
description:
|
||||
BD72720 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
|
||||
- gpo
|
||||
- pwrseq
|
||||
|
||||
"^rohm,pin-exten[0-1]$":
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
description: BD72720 has an OTP option to use exten0-pin for different
|
||||
purposes. Set this property accordingly.
|
||||
OTP0 - GPO
|
||||
OTP1 - Power sequencer output.
|
||||
enum:
|
||||
- gpo
|
||||
- pwrseq
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- "#clock-cells"
|
||||
- regulators
|
||||
- gpio-controller
|
||||
- "#gpio-cells"
|
||||
|
||||
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,bd72720";
|
||||
reg = <0x4b>;
|
||||
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
|
||||
|
||||
clocks = <&osc 0>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "bd71828-32k-out";
|
||||
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
||||
rohm,pin-dvs0 = "gpi";
|
||||
rohm,pin-dvs1 = "gpi";
|
||||
rohm,pin-exten0 = "gpo";
|
||||
rohm,pin-exten1 = "gpo";
|
||||
rohm,pin-fault_b = "faultb";
|
||||
|
||||
rohm,charger-sense-resistor-micro-ohms = <10000>;
|
||||
|
||||
regulators {
|
||||
buck1 {
|
||||
regulator-name = "buck1";
|
||||
regulator-min-microvolt = <500000>;
|
||||
regulator-max-microvolt = <2000000>;
|
||||
regulator-ramp-delay = <2500>;
|
||||
};
|
||||
buck2 {
|
||||
regulator-name = "buck2";
|
||||
regulator-min-microvolt = <500000>;
|
||||
regulator-max-microvolt = <2000000>;
|
||||
regulator-ramp-delay = <2500>;
|
||||
};
|
||||
buck3 {
|
||||
regulator-name = "buck3";
|
||||
regulator-min-microvolt = <1200000>;
|
||||
regulator-max-microvolt = <2000000>;
|
||||
};
|
||||
buck4 {
|
||||
regulator-name = "buck4";
|
||||
regulator-min-microvolt = <1000000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
};
|
||||
buck5 {
|
||||
regulator-name = "buck5";
|
||||
regulator-min-microvolt = <2500000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
};
|
||||
buck6 {
|
||||
regulator-name = "buck6";
|
||||
regulator-min-microvolt = <500000>;
|
||||
regulator-max-microvolt = <2000000>;
|
||||
regulator-ramp-delay = <2500>;
|
||||
};
|
||||
buck7 {
|
||||
regulator-name = "buck7";
|
||||
regulator-min-microvolt = <500000>;
|
||||
regulator-max-microvolt = <2000000>;
|
||||
regulator-ramp-delay = <2500>;
|
||||
};
|
||||
buck8 {
|
||||
regulator-name = "buck8";
|
||||
regulator-min-microvolt = <500000>;
|
||||
regulator-max-microvolt = <1700000>;
|
||||
regulator-ramp-delay = <2500>;
|
||||
rohm,dvs-run-voltage = <1700000>;
|
||||
rohm,dvs-idle-voltage = <1>;
|
||||
rohm,dvs-suspend-voltage = <1>;
|
||||
rohm,dvs-lpsr-voltage = <0>;
|
||||
regulator-boot-on;
|
||||
};
|
||||
buck9 {
|
||||
regulator-name = "buck9";
|
||||
regulator-min-microvolt = <500000>;
|
||||
regulator-max-microvolt = <1700000>;
|
||||
regulator-ramp-delay = <2500>;
|
||||
rohm,dvs-run-voltage = <1700000>;
|
||||
rohm,dvs-idle-voltage = <1>;
|
||||
rohm,dvs-suspend-voltage = <1>;
|
||||
rohm,dvs-lpsr-voltage = <0>;
|
||||
regulator-boot-on;
|
||||
};
|
||||
buck10 {
|
||||
regulator-name = "buck10";
|
||||
regulator-min-microvolt = <500000>;
|
||||
regulator-max-microvolt = <1700000>;
|
||||
regulator-ramp-delay = <2500>;
|
||||
rohm,dvs-run-voltage = <1700000>;
|
||||
rohm,dvs-idle-voltage = <1>;
|
||||
rohm,dvs-suspend-voltage = <1>;
|
||||
rohm,dvs-lpsr-voltage = <0>;
|
||||
regulator-boot-on;
|
||||
};
|
||||
ldo1 {
|
||||
regulator-name = "ldo1";
|
||||
regulator-min-microvolt = <800000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
};
|
||||
ldo2 {
|
||||
regulator-name = "ldo2";
|
||||
regulator-min-microvolt = <800000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
};
|
||||
ldo3 {
|
||||
regulator-name = "ldo3";
|
||||
regulator-min-microvolt = <800000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
};
|
||||
ldo4 {
|
||||
regulator-name = "ldo4";
|
||||
regulator-min-microvolt = <800000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
};
|
||||
ldo5 {
|
||||
regulator-name = "ldo5";
|
||||
regulator-min-microvolt = <800000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
};
|
||||
ldo6 {
|
||||
regulator-name = "ldo6";
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
};
|
||||
ldo7 {
|
||||
regulator-name = "ldo7";
|
||||
regulator-min-microvolt = <800000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
};
|
||||
ldo8 {
|
||||
regulator-name = "ldo8";
|
||||
regulator-min-microvolt = <750000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
rohm,dvs-suspend-voltage = <0>;
|
||||
rohm,dvs-lpsr-voltage = <1>;
|
||||
rohm,dvs-run-voltage = <750000>;
|
||||
};
|
||||
ldo9 {
|
||||
regulator-name = "ldo9";
|
||||
regulator-min-microvolt = <750000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
rohm,dvs-suspend-voltage = <0>;
|
||||
rohm,dvs-lpsr-voltage = <1>;
|
||||
rohm,dvs-run-voltage = <750000>;
|
||||
};
|
||||
ldo10 {
|
||||
regulator-name = "ldo10";
|
||||
regulator-min-microvolt = <750000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
rohm,dvs-suspend-voltage = <0>;
|
||||
rohm,dvs-lpsr-voltage = <1>;
|
||||
rohm,dvs-run-voltage = <750000>;
|
||||
};
|
||||
ldo11 {
|
||||
regulator-name = "ldo11";
|
||||
regulator-min-microvolt = <750000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
rohm,dvs-suspend-voltage = <0>;
|
||||
rohm,dvs-lpsr-voltage = <1>;
|
||||
rohm,dvs-run-voltage = <750000>;
|
||||
};
|
||||
};
|
||||
|
||||
leds {
|
||||
compatible = "rohm,bd71828-leds";
|
||||
|
||||
led-1 {
|
||||
rohm,led-compatible = "bd71828-grnled";
|
||||
function = LED_FUNCTION_INDICATOR;
|
||||
color = <LED_COLOR_ID_GREEN>;
|
||||
};
|
||||
led-2 {
|
||||
rohm,led-compatible = "bd71828-ambled";
|
||||
function = LED_FUNCTION_CHARGING;
|
||||
color = <LED_COLOR_ID_AMBER>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -64,7 +64,16 @@ properties:
|
|||
description: battery design capacity
|
||||
|
||||
trickle-charge-current-microamp:
|
||||
description: current for trickle-charge phase
|
||||
description: current for trickle-charge phase.
|
||||
Please note that the trickle-charging here, refers "wake-up" or
|
||||
"pre-pre" -charging, for very empty batteries. Similar term is also
|
||||
used for "maintenance" or "top-off" -charging of batteries (like
|
||||
NiMh bq24400) - that is different and not controlled by this
|
||||
property.
|
||||
|
||||
tricklecharge-upper-limit-microvolt:
|
||||
description: limit when to change to precharge from trickle charge
|
||||
Trickle-charging here refers "wake-up" or "pre-pre" -charging.
|
||||
|
||||
precharge-current-microamp:
|
||||
description: current for pre-charge phase
|
||||
|
|
@ -119,6 +128,21 @@ properties:
|
|||
- description: alert when battery temperature is lower than this value
|
||||
- description: alert when battery temperature is higher than this value
|
||||
|
||||
# The volt-drop* -properties describe voltage-drop for a battery, described
|
||||
# as VDROP in:
|
||||
# https://patentimages.storage.googleapis.com/6c/f5/17/c1d901c220f6a9/US20150032394A1.pdf
|
||||
volt-drop-thresh-microvolt:
|
||||
description: Threshold for starting the VDR correction
|
||||
maximum: 48000000
|
||||
|
||||
volt-drop-soc-bp:
|
||||
description: Table of capacity values matching the values in VDR tables.
|
||||
The value should be given as basis points, 1/100 of a percent.
|
||||
|
||||
volt-drop-temperatures-millicelsius:
|
||||
description: An array containing the temperature in milli celsius, for each
|
||||
of the VDR lookup table.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
|
|
@ -137,6 +161,13 @@ patternProperties:
|
|||
- description: battery capacity percent
|
||||
maximum: 100
|
||||
|
||||
'^volt-drop-[0-9]-microvolt':
|
||||
description: Table of the voltage drop rate (VDR) values. Each entry in the
|
||||
table should match a capacity value in the volt-drop-soc table.
|
||||
Furthermore, the values should be obtained for the temperature given in
|
||||
volt-drop-temperatures-millicelsius table at index matching the
|
||||
number in this table's name.
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,148 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/regulator/rohm,bd72720-regulator.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: ROHM BD72720 Power Management Integrated Circuit regulators
|
||||
|
||||
maintainers:
|
||||
- Matti Vaittinen <mazziesaccount@gmail.com>
|
||||
|
||||
description: |
|
||||
This module is part of the ROHM BD72720 MFD device. For more details
|
||||
see Documentation/devicetree/bindings/mfd/rohm,bd72720-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 BD72720 regulator nodes are
|
||||
buck1, buck2, buck3, buck4, buck5, buck6, buck7, buck8, buck9, buck10
|
||||
ldo1, ldo2, ldo3, ldo4, ldo5, ldo6, ldo7, ldo8, ldo9, ldo10, ldo11
|
||||
|
||||
patternProperties:
|
||||
"^ldo([1-9]|1[0-1])$":
|
||||
type: object
|
||||
description:
|
||||
Properties for single LDO regulator.
|
||||
$ref: regulator.yaml#
|
||||
|
||||
properties:
|
||||
regulator-name:
|
||||
pattern: "^ldo([1-9]|1[0-1])$"
|
||||
|
||||
rohm,dvs-run-voltage:
|
||||
description:
|
||||
PMIC default "RUN" state voltage in uV. See below table for
|
||||
LDOs which support this. 0 means disabled.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 3300000
|
||||
|
||||
rohm,dvs-idle-voltage:
|
||||
description:
|
||||
PMIC default "IDLE" state voltage in uV. See below table for
|
||||
LDOs which support this. 0 means disabled.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 3300000
|
||||
|
||||
rohm,dvs-suspend-voltage:
|
||||
description:
|
||||
PMIC default "SUSPEND" state voltage in uV. See below table for
|
||||
LDOs which support this. 0 means disabled.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 3300000
|
||||
|
||||
rohm,dvs-lpsr-voltage:
|
||||
description:
|
||||
PMIC default "deep-idle" state voltage in uV. See below table for
|
||||
LDOs which support this. 0 means disabled.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 3300000
|
||||
|
||||
# Supported default DVS states:
|
||||
# ldo | run | idle | suspend | lpsr
|
||||
# --------------------------------------------------------------
|
||||
# 1, 2, 3, and 4 | supported | supported | supported | supported
|
||||
# --------------------------------------------------------------
|
||||
# 5 - 11 | supported (*)
|
||||
# --------------------------------------------------------------
|
||||
#
|
||||
# (*) All states use same voltage but have own enable / disable
|
||||
# settings. Voltage 0 can be specified for a state to make
|
||||
# regulator disabled on that state.
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
"^buck([1-9]|10)$":
|
||||
type: object
|
||||
description:
|
||||
Properties for single BUCK regulator.
|
||||
$ref: regulator.yaml#
|
||||
|
||||
properties:
|
||||
regulator-name:
|
||||
pattern: "^buck([1-9]|10)$"
|
||||
|
||||
rohm,ldon-head-microvolt:
|
||||
description:
|
||||
Set this on boards where BUCK10 is used to supply LDOs 1-4. The bucki
|
||||
voltage will be changed by the PMIC to follow the LDO output voltages
|
||||
with the offset voltage given here. This will improve the LDO efficiency.
|
||||
minimum: 50000
|
||||
maximum: 300000
|
||||
|
||||
rohm,dvs-run-voltage:
|
||||
description:
|
||||
PMIC default "RUN" state voltage in uV. See below table for
|
||||
bucks which support this. 0 means disabled.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 3300000
|
||||
|
||||
rohm,dvs-idle-voltage:
|
||||
description:
|
||||
PMIC default "IDLE" state voltage in uV. See below table for
|
||||
bucks which support this. 0 means disabled.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 3300000
|
||||
|
||||
rohm,dvs-suspend-voltage:
|
||||
description:
|
||||
PMIC default "SUSPEND" state voltage in uV. See below table for
|
||||
bucks which support this. 0 means disabled.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 3300000
|
||||
|
||||
rohm,dvs-lpsr-voltage:
|
||||
description:
|
||||
PMIC default "deep-idle" state voltage in uV. See below table for
|
||||
bucks which support this. 0 means disabled.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 0
|
||||
maximum: 3300000
|
||||
|
||||
# Supported default DVS states:
|
||||
# buck | run | idle | suspend | lpsr
|
||||
# --------------------------------------------------------------
|
||||
# 1, 2, 3, and 4 | supported | supported | supported | supported
|
||||
# --------------------------------------------------------------
|
||||
# 5 - 10 | supported (*)
|
||||
# --------------------------------------------------------------
|
||||
#
|
||||
# (*) All states use same voltage but have own enable / disable
|
||||
# settings. Voltage 0 can be specified for a state to make
|
||||
# regulator disabled on that state.
|
||||
|
||||
required:
|
||||
- regulator-name
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
additionalProperties: false
|
||||
|
|
@ -178,6 +178,8 @@ pcal9554b 8 yes 00 01 02 03
|
|||
pcal6416 16 yes 00 02 04 06
|
||||
pcal9535 16 yes 00 02 04 06
|
||||
pcal9555a 16 yes 00 02 04 06
|
||||
tcal6408 8 yes 00 01 02 03
|
||||
tcal6416 16 yes 00 02 04 06
|
||||
========== ===== ========= ===== ====== ====== =========
|
||||
|
||||
These chips have several additional features:
|
||||
|
|
@ -196,6 +198,8 @@ pcal9554b 40 42 43 44 45 46 4F
|
|||
pcal6416 40 44 46 48 4A 4C 4F
|
||||
pcal9535 40 44 46 48 4A 4C 4F
|
||||
pcal9555a 40 44 46 48 4A 4C 4F
|
||||
tcal6408 40 42 43 44 45 46 4F
|
||||
tcal6416 40 44 46 48 4A 4C 4F
|
||||
========== ============ ======== ======= ======== ======== ========== ========
|
||||
|
||||
Currently the driver has support for the input latch, pull-up/pull-down
|
||||
|
|
@ -332,6 +336,8 @@ Layouts:
|
|||
- pcal9554b
|
||||
- pcal9555a
|
||||
- pcal6524
|
||||
- tcal6408
|
||||
- tcal6416
|
||||
|
||||
2. base offset 0x30, bank 5 and 6, closely packed banks
|
||||
- pcal6534
|
||||
|
|
@ -383,6 +389,13 @@ disabled.
|
|||
Currently the driver enables the latch for each line with interrupt
|
||||
enabled.
|
||||
|
||||
An interrupt status register records which pins triggered an interrupt.
|
||||
However, the status register and the input port register must be read
|
||||
separately; there is no atomic mechanism to read both simultaneously, so races
|
||||
are possible. Refer to the chapter `Interrupt source detection`_ to understand
|
||||
the implications of this and how the driver still makes use of the latching
|
||||
feature.
|
||||
|
||||
1. base offset 0x40, bank 2, bank offsets of 2^n
|
||||
- pcal6408
|
||||
- pcal6416
|
||||
|
|
@ -390,6 +403,8 @@ enabled.
|
|||
- pcal9554b
|
||||
- pcal9555a
|
||||
- pcal6524
|
||||
- tcal6408
|
||||
- tcal6416
|
||||
|
||||
2. base offset 0x30, bank 2, closely packed banks
|
||||
- pcal6534
|
||||
|
|
@ -462,6 +477,8 @@ Layout:
|
|||
- pcal9535
|
||||
- pcal9554b
|
||||
- pcal9555a
|
||||
- tcal6408
|
||||
- tcal6416
|
||||
|
||||
`PCAL chips with extended interrupt and output configuration functions`_
|
||||
can set this for each line individually. They have the same per-port out_conf
|
||||
|
|
@ -505,12 +522,82 @@ bits drive strength
|
|||
- pcal9554b
|
||||
- pcal9555a
|
||||
- pcal6524
|
||||
- tcal6408
|
||||
- tcal6416
|
||||
|
||||
2. base offset 0x30, bank 0 and 1, closely packed banks
|
||||
- pcal6534
|
||||
|
||||
Currently not supported by the driver.
|
||||
|
||||
Interrupt source detection
|
||||
==========================
|
||||
|
||||
When triggered by the GPIO expander's interrupt, the driver determines which
|
||||
IRQs are pending by reading the input port register.
|
||||
|
||||
To be able to filter on specific interrupt events for all compatible devices,
|
||||
the driver keeps track of the previous input state of the lines, and emits an
|
||||
IRQ only for the correct edge or level. This system works irrespective of the
|
||||
number of enabled interrupts. Events will not be missed even if they occur
|
||||
between the GPIO expander's interrupt and the actual I2C read. Edges could of
|
||||
course be missed if the related signal level changes back to the value
|
||||
previously saved by the driver before the I2C read. PCAL variants offer input
|
||||
latching for that reason.
|
||||
|
||||
PCAL input latching
|
||||
-------------------
|
||||
|
||||
The PCAL variants have an input latch and the driver enables this for all
|
||||
interrupt-enabled lines. The interrupt is then only cleared when the input port
|
||||
is read out. These variants provide an interrupt status register that records
|
||||
which pins triggered an interrupt, but the status and input registers cannot be
|
||||
read atomically. If another interrupt occurs on a different line after the
|
||||
status register has been read but before the input port register is sampled,
|
||||
that event will not be reflected in the earlier status snapshot, so relying
|
||||
solely on the interrupt status register is insufficient.
|
||||
|
||||
Thus, the PCAL variants also have to use the existing level-change logic.
|
||||
|
||||
For short pulses, the first edge is captured when the input register is read,
|
||||
but if the signal returns to its previous level before this read, the second
|
||||
edge is not observed. As a result, successive pulses can produce identical
|
||||
input values at read time and no level change is detected, causing interrupts
|
||||
to be missed. Below timing diagram shows this situation where the top signal is
|
||||
the input pin level and the bottom signal indicates the latched value::
|
||||
|
||||
─────┐ ┌──*───────────────┐ ┌──*─────────────────┐ ┌──*───
|
||||
│ │ . │ │ . │ │ .
|
||||
│ │ │ │ │ │ │ │ │
|
||||
└──*──┘ │ └──*──┘ │ └──*──┘ │
|
||||
Input │ │ │ │ │ │
|
||||
▼ │ ▼ │ ▼ │
|
||||
IRQ │ IRQ │ IRQ │
|
||||
. . .
|
||||
─────┐ .┌──────────────┐ .┌────────────────┐ .┌──
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ │ │
|
||||
└────────*┘ └────────*┘ └────────*┘
|
||||
Latched │ │ │
|
||||
▼ ▼ ▼
|
||||
READ 0 READ 0 READ 0
|
||||
NO CHANGE NO CHANGE
|
||||
|
||||
To deal with this, events indicated by the interrupt status register are merged
|
||||
with events detected through the existing level-change logic. As a result:
|
||||
|
||||
- short pulses, whose second edges are invisible, are detected via the
|
||||
interrupt status register, and
|
||||
- interrupts that occur between the status and input reads are still
|
||||
caught by the generic level-change logic.
|
||||
|
||||
Note that this is still best-effort: the status and input registers are read
|
||||
separately, and short pulses on other lines may occur in between those reads.
|
||||
Such pulses can still be latched as an interrupt without leaving an observable
|
||||
level change at read time, and may not be attributable to a specific edge. This
|
||||
does not reduce detection compared to the generic path, but reflects inherent
|
||||
atomicity limitations.
|
||||
|
||||
Datasheets
|
||||
==========
|
||||
|
||||
|
|
|
|||
|
|
@ -10816,6 +10816,12 @@ S: Maintained
|
|||
F: Documentation/devicetree/bindings/leds/irled/gpio-ir-tx.yaml
|
||||
F: drivers/media/rc/gpio-ir-tx.c
|
||||
|
||||
GPIO LINE MUX
|
||||
M: Jonas Jelonek <jelonek.jonas@gmail.com>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/gpio/gpio-line-mux.yaml
|
||||
F: drivers/gpio/gpio-line-mux.c
|
||||
|
||||
GPIO MOCKUP DRIVER
|
||||
M: Bamvor Jian Zhang <bamv2005@gmail.com>
|
||||
L: linux-gpio@vger.kernel.org
|
||||
|
|
@ -22836,6 +22842,7 @@ S: Supported
|
|||
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/mfd/rohm-bd71828.c
|
||||
F: drivers/mfd/rohm-bd718x7.c
|
||||
F: drivers/mfd/rohm-bd9576.c
|
||||
|
|
@ -22852,6 +22859,7 @@ F: drivers/watchdog/bd96801_wdt.c
|
|||
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-bd957x.h
|
||||
F: include/linux/mfd/rohm-bd96801.h
|
||||
F: include/linux/mfd/rohm-bd96802.h
|
||||
|
|
|
|||
|
|
@ -475,8 +475,8 @@ config COMMON_CLK_BD718XX
|
|||
tristate "Clock driver for 32K clk gates on ROHM PMICs"
|
||||
depends on MFD_ROHM_BD718XX || MFD_ROHM_BD71828
|
||||
help
|
||||
This driver supports ROHM BD71837, BD71847, BD71850, BD71815
|
||||
and BD71828 PMICs clock gates.
|
||||
This driver supports ROHM BD71837, BD71847, BD71850, BD71815,
|
||||
BD71828, and BD72720 PMICs clock gates.
|
||||
|
||||
config COMMON_CLK_FIXED_MMIO
|
||||
bool "Clock driver for Memory Mapped Fixed values"
|
||||
|
|
|
|||
|
|
@ -19,7 +19,8 @@
|
|||
#define BD71828_REG_OUT32K 0x4B
|
||||
/* BD71837 and BD71847 */
|
||||
#define BD718XX_REG_OUT32K 0x2E
|
||||
|
||||
/* BD72720 */
|
||||
#define BD72720_REG_OUT32K 0x9a
|
||||
/*
|
||||
* BD71837, BD71847, and BD71828 all use bit [0] to clk output control
|
||||
*/
|
||||
|
|
@ -118,6 +119,10 @@ static int bd71837_clk_probe(struct platform_device *pdev)
|
|||
c->reg = BD71815_REG_OUT32K;
|
||||
c->mask = CLK_OUT_EN_MASK;
|
||||
break;
|
||||
case ROHM_CHIP_TYPE_BD72720:
|
||||
c->reg = BD72720_REG_OUT32K;
|
||||
c->mask = CLK_OUT_EN_MASK;
|
||||
break;
|
||||
default:
|
||||
dev_err(&pdev->dev, "Unknown clk chip\n");
|
||||
return -EINVAL;
|
||||
|
|
@ -146,6 +151,7 @@ static const struct platform_device_id bd718x7_clk_id[] = {
|
|||
{ "bd71847-clk", ROHM_CHIP_TYPE_BD71847 },
|
||||
{ "bd71828-clk", ROHM_CHIP_TYPE_BD71828 },
|
||||
{ "bd71815-clk", ROHM_CHIP_TYPE_BD71815 },
|
||||
{ "bd72720-clk", ROHM_CHIP_TYPE_BD72720 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, bd718x7_clk_id);
|
||||
|
|
@ -161,6 +167,6 @@ static struct platform_driver bd71837_clk = {
|
|||
module_platform_driver(bd71837_clk);
|
||||
|
||||
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
|
||||
MODULE_DESCRIPTION("BD718(15/18/28/37/47/50) and chip clk driver");
|
||||
MODULE_DESCRIPTION("BD718(15/18/28/37/47/50) and BD72720 chip clk driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:bd718xx-clk");
|
||||
|
|
|
|||
|
|
@ -600,7 +600,7 @@ config GPIO_RDA
|
|||
|
||||
config GPIO_REALTEK_OTTO
|
||||
tristate "Realtek Otto GPIO support"
|
||||
depends on MACH_REALTEK_RTL
|
||||
depends on MACH_REALTEK_RTL || COMPILE_TEST
|
||||
default MACH_REALTEK_RTL
|
||||
select GPIO_GENERIC
|
||||
select GPIOLIB_IRQCHIP
|
||||
|
|
@ -1193,11 +1193,11 @@ config GPIO_PCA953X
|
|||
|
||||
8 bits: max7310, max7315, pca6107, pca9534, pca9538, pca9554,
|
||||
pca9556, pca9557, pca9574, tca6408, tca9554, xra1202,
|
||||
pcal6408, pcal9554b, tca9538
|
||||
pcal6408, pcal9554b, tca9538, tcal6408
|
||||
|
||||
16 bits: max7312, max7313, pca9535, pca9539, pca9555, pca9575,
|
||||
tca6416, pca6416, pcal6416, pcal9535, pcal9555a, max7318,
|
||||
tca9539
|
||||
tca9539, tcal6416
|
||||
|
||||
18 bits: tca6418
|
||||
|
||||
|
|
@ -1317,6 +1317,15 @@ config GPIO_BD71828
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called gpio-bd71828.
|
||||
|
||||
config GPIO_BD72720
|
||||
tristate "ROHM BD72720 and BD73900 PMIC GPIO support"
|
||||
depends on MFD_ROHM_BD71828
|
||||
help
|
||||
Support for GPIO on ROHM BD72720 and BD73900 PMICs. There are two
|
||||
pins which can be configured to GPI or GPO, and three pins which can
|
||||
be configured to GPO on the ROHM PMIC. The pin configuration is done
|
||||
on OTP at manufacturing.
|
||||
|
||||
config GPIO_BD9571MWV
|
||||
tristate "ROHM BD9571 GPIO support"
|
||||
depends on MFD_BD9571MWV
|
||||
|
|
@ -1994,6 +2003,15 @@ config GPIO_LATCH
|
|||
Say yes here to enable a driver for GPIO multiplexers based on latches
|
||||
connected to other GPIOs.
|
||||
|
||||
config GPIO_LINE_MUX
|
||||
tristate "GPIO line mux driver"
|
||||
depends on OF_GPIO
|
||||
select MULTIPLEXER
|
||||
help
|
||||
Say Y here to support the GPIO line mux, which can provide virtual
|
||||
GPIOs backed by a shared real GPIO and a multiplexer in a 1-to-many
|
||||
fashion.
|
||||
|
||||
config GPIO_MOCKUP
|
||||
tristate "GPIO Testing Driver (DEPRECATED)"
|
||||
select IRQ_SIM
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
|
|||
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_BD9571MWV) += gpio-bd9571mwv.o
|
||||
obj-$(CONFIG_GPIO_BLZP1600) += gpio-blzp1600.o
|
||||
obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
|
||||
|
|
@ -90,6 +91,7 @@ obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4xx.o
|
|||
obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o
|
||||
obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o
|
||||
obj-$(CONFIG_GPIO_LATCH) += gpio-latch.o
|
||||
obj-$(CONFIG_GPIO_LINE_MUX) += gpio-line-mux.o
|
||||
obj-$(CONFIG_GPIO_LJCA) += gpio-ljca.o
|
||||
obj-$(CONFIG_GPIO_LOGICVC) += gpio-logicvc.o
|
||||
obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o
|
||||
|
|
|
|||
|
|
@ -1226,7 +1226,7 @@ gpio_aggregator_line_release(struct config_item *item)
|
|||
kfree(line);
|
||||
}
|
||||
|
||||
static struct configfs_item_operations gpio_aggregator_line_item_ops = {
|
||||
static const struct configfs_item_operations gpio_aggregator_line_item_ops = {
|
||||
.release = gpio_aggregator_line_release,
|
||||
};
|
||||
|
||||
|
|
@ -1247,7 +1247,7 @@ static void gpio_aggregator_device_release(struct config_item *item)
|
|||
gpio_aggregator_free(aggr);
|
||||
}
|
||||
|
||||
static struct configfs_item_operations gpio_aggregator_device_item_ops = {
|
||||
static const struct configfs_item_operations gpio_aggregator_device_item_ops = {
|
||||
.release = gpio_aggregator_device_release,
|
||||
};
|
||||
|
||||
|
|
@ -1292,7 +1292,7 @@ gpio_aggregator_device_make_group(struct config_group *group, const char *name)
|
|||
return &line->group;
|
||||
}
|
||||
|
||||
static struct configfs_group_operations gpio_aggregator_device_group_ops = {
|
||||
static const struct configfs_group_operations gpio_aggregator_device_group_ops = {
|
||||
.make_group = gpio_aggregator_device_make_group,
|
||||
};
|
||||
|
||||
|
|
@ -1328,7 +1328,7 @@ gpio_aggregator_make_group(struct config_group *group, const char *name)
|
|||
return &aggr->group;
|
||||
}
|
||||
|
||||
static struct configfs_group_operations gpio_aggregator_group_ops = {
|
||||
static const struct configfs_group_operations gpio_aggregator_group_ops = {
|
||||
.make_group = gpio_aggregator_make_group,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,31 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#define ASPEED_SGPIO_CTRL 0x54
|
||||
#define SGPIO_G7_IRQ_STS_BASE 0x40
|
||||
#define SGPIO_G7_IRQ_STS_OFFSET(x) (SGPIO_G7_IRQ_STS_BASE + (x) * 0x4)
|
||||
#define SGPIO_G7_CTRL_REG_BASE 0x80
|
||||
#define SGPIO_G7_CTRL_REG_OFFSET(x) (SGPIO_G7_CTRL_REG_BASE + (x) * 0x4)
|
||||
#define SGPIO_G7_OUT_DATA BIT(0)
|
||||
#define SGPIO_G7_PARALLEL_OUT_DATA BIT(1)
|
||||
#define SGPIO_G7_IRQ_EN BIT(2)
|
||||
#define SGPIO_G7_IRQ_TYPE0 BIT(3)
|
||||
#define SGPIO_G7_IRQ_TYPE1 BIT(4)
|
||||
#define SGPIO_G7_IRQ_TYPE2 BIT(5)
|
||||
#define SGPIO_G7_RST_TOLERANCE BIT(6)
|
||||
#define SGPIO_G7_INPUT_MASK BIT(9)
|
||||
#define SGPIO_G7_HW_BYPASS_EN BIT(10)
|
||||
#define SGPIO_G7_HW_IN_SEL BIT(11)
|
||||
#define SGPIO_G7_IRQ_STS BIT(12)
|
||||
#define SGPIO_G7_IN_DATA BIT(13)
|
||||
#define SGPIO_G7_PARALLEL_IN_DATA BIT(14)
|
||||
#define SGPIO_G7_SERIAL_OUT_SEL GENMASK(17, 16)
|
||||
#define SGPIO_G7_PARALLEL_OUT_SEL GENMASK(19, 18)
|
||||
#define SELECT_FROM_CSR 0
|
||||
#define SELECT_FROM_PARALLEL_IN 1
|
||||
#define SELECT_FROM_SERIAL_IN 2
|
||||
|
||||
#define ASPEED_SGPIO_G4_CFG_OFFSET 0x54
|
||||
#define ASPEED_SGPIO_G7_CFG_OFFSET 0x0
|
||||
|
||||
#define ASPEED_SGPIO_CLK_DIV_MASK GENMASK(31, 16)
|
||||
#define ASPEED_SGPIO_ENABLE BIT(0)
|
||||
|
|
@ -27,6 +51,8 @@
|
|||
|
||||
struct aspeed_sgpio_pdata {
|
||||
const u32 pin_mask;
|
||||
const struct aspeed_sgpio_llops *llops;
|
||||
const u32 cfg_offset;
|
||||
};
|
||||
|
||||
struct aspeed_sgpio {
|
||||
|
|
@ -36,6 +62,7 @@ struct aspeed_sgpio {
|
|||
raw_spinlock_t lock;
|
||||
void __iomem *base;
|
||||
int irq;
|
||||
const struct aspeed_sgpio_pdata *pdata;
|
||||
};
|
||||
|
||||
struct aspeed_sgpio_bank {
|
||||
|
|
@ -43,7 +70,6 @@ struct aspeed_sgpio_bank {
|
|||
u16 rdata_reg;
|
||||
u16 irq_regs;
|
||||
u16 tolerance_regs;
|
||||
const char names[4][3];
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -59,28 +85,24 @@ static const struct aspeed_sgpio_bank aspeed_sgpio_banks[] = {
|
|||
.rdata_reg = 0x0070,
|
||||
.irq_regs = 0x0004,
|
||||
.tolerance_regs = 0x0018,
|
||||
.names = { "A", "B", "C", "D" },
|
||||
},
|
||||
{
|
||||
.val_regs = 0x001C,
|
||||
.rdata_reg = 0x0074,
|
||||
.irq_regs = 0x0020,
|
||||
.tolerance_regs = 0x0034,
|
||||
.names = { "E", "F", "G", "H" },
|
||||
},
|
||||
{
|
||||
.val_regs = 0x0038,
|
||||
.rdata_reg = 0x0078,
|
||||
.irq_regs = 0x003C,
|
||||
.tolerance_regs = 0x0050,
|
||||
.names = { "I", "J", "K", "L" },
|
||||
},
|
||||
{
|
||||
.val_regs = 0x0090,
|
||||
.rdata_reg = 0x007C,
|
||||
.irq_regs = 0x0094,
|
||||
.tolerance_regs = 0x00A8,
|
||||
.names = { "M", "N", "O", "P" },
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -95,6 +117,15 @@ enum aspeed_sgpio_reg {
|
|||
reg_tolerance,
|
||||
};
|
||||
|
||||
struct aspeed_sgpio_llops {
|
||||
void (*reg_bit_set)(struct aspeed_sgpio *gpio, unsigned int offset,
|
||||
const enum aspeed_sgpio_reg reg, bool val);
|
||||
bool (*reg_bit_get)(struct aspeed_sgpio *gpio, unsigned int offset,
|
||||
const enum aspeed_sgpio_reg reg);
|
||||
int (*reg_bank_get)(struct aspeed_sgpio *gpio, unsigned int offset,
|
||||
const enum aspeed_sgpio_reg reg);
|
||||
};
|
||||
|
||||
#define GPIO_VAL_VALUE 0x00
|
||||
#define GPIO_IRQ_ENABLE 0x00
|
||||
#define GPIO_IRQ_TYPE0 0x04
|
||||
|
|
@ -102,9 +133,9 @@ enum aspeed_sgpio_reg {
|
|||
#define GPIO_IRQ_TYPE2 0x0C
|
||||
#define GPIO_IRQ_STATUS 0x10
|
||||
|
||||
static void __iomem *bank_reg(struct aspeed_sgpio *gpio,
|
||||
const struct aspeed_sgpio_bank *bank,
|
||||
const enum aspeed_sgpio_reg reg)
|
||||
static void __iomem *aspeed_sgpio_g4_bank_reg(struct aspeed_sgpio *gpio,
|
||||
const struct aspeed_sgpio_bank *bank,
|
||||
const enum aspeed_sgpio_reg reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case reg_val:
|
||||
|
|
@ -129,6 +160,30 @@ static void __iomem *bank_reg(struct aspeed_sgpio *gpio,
|
|||
}
|
||||
}
|
||||
|
||||
static u32 aspeed_sgpio_g7_reg_mask(const enum aspeed_sgpio_reg reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case reg_val:
|
||||
case reg_rdata:
|
||||
return SGPIO_G7_OUT_DATA;
|
||||
case reg_irq_enable:
|
||||
return SGPIO_G7_IRQ_EN;
|
||||
case reg_irq_type0:
|
||||
return SGPIO_G7_IRQ_TYPE0;
|
||||
case reg_irq_type1:
|
||||
return SGPIO_G7_IRQ_TYPE1;
|
||||
case reg_irq_type2:
|
||||
return SGPIO_G7_IRQ_TYPE2;
|
||||
case reg_irq_status:
|
||||
return SGPIO_G7_IRQ_STS;
|
||||
case reg_tolerance:
|
||||
return SGPIO_G7_RST_TOLERANCE;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#define GPIO_BANK(x) ((x) >> 6)
|
||||
#define GPIO_OFFSET(x) ((x) & GENMASK(5, 0))
|
||||
#define GPIO_BIT(x) BIT(GPIO_OFFSET(x) >> 1)
|
||||
|
|
@ -170,14 +225,13 @@ static bool aspeed_sgpio_is_input(unsigned int offset)
|
|||
static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
|
||||
const struct aspeed_sgpio_bank *bank = to_bank(offset);
|
||||
enum aspeed_sgpio_reg reg;
|
||||
int rc = 0;
|
||||
|
||||
guard(raw_spinlock_irqsave)(&gpio->lock);
|
||||
|
||||
reg = aspeed_sgpio_is_input(offset) ? reg_val : reg_rdata;
|
||||
rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset));
|
||||
rc = gpio->pdata->llops->reg_bit_get(gpio, offset, reg);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -185,26 +239,11 @@ static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset)
|
|||
static int sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val)
|
||||
{
|
||||
struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
|
||||
const struct aspeed_sgpio_bank *bank = to_bank(offset);
|
||||
void __iomem *addr_r, *addr_w;
|
||||
u32 reg = 0;
|
||||
|
||||
if (aspeed_sgpio_is_input(offset))
|
||||
return -EINVAL;
|
||||
|
||||
/* Since this is an output, read the cached value from rdata, then
|
||||
* update val. */
|
||||
addr_r = bank_reg(gpio, bank, reg_rdata);
|
||||
addr_w = bank_reg(gpio, bank, reg_val);
|
||||
|
||||
reg = ioread32(addr_r);
|
||||
|
||||
if (val)
|
||||
reg |= GPIO_BIT(offset);
|
||||
else
|
||||
reg &= ~GPIO_BIT(offset);
|
||||
|
||||
iowrite32(reg, addr_w);
|
||||
gpio->pdata->llops->reg_bit_set(gpio, offset, reg_val, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -243,69 +282,34 @@ static int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset)
|
|||
return !!aspeed_sgpio_is_input(offset);
|
||||
}
|
||||
|
||||
static void irqd_to_aspeed_sgpio_data(struct irq_data *d,
|
||||
struct aspeed_sgpio **gpio,
|
||||
const struct aspeed_sgpio_bank **bank,
|
||||
u32 *bit, int *offset)
|
||||
{
|
||||
struct aspeed_sgpio *internal;
|
||||
|
||||
*offset = irqd_to_hwirq(d);
|
||||
internal = irq_data_get_irq_chip_data(d);
|
||||
WARN_ON(!internal);
|
||||
|
||||
*gpio = internal;
|
||||
*bank = to_bank(*offset);
|
||||
*bit = GPIO_BIT(*offset);
|
||||
}
|
||||
|
||||
static void aspeed_sgpio_irq_ack(struct irq_data *d)
|
||||
{
|
||||
const struct aspeed_sgpio_bank *bank;
|
||||
struct aspeed_sgpio *gpio;
|
||||
void __iomem *status_addr;
|
||||
int offset;
|
||||
u32 bit;
|
||||
|
||||
irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
|
||||
|
||||
status_addr = bank_reg(gpio, bank, reg_irq_status);
|
||||
struct aspeed_sgpio *gpio = irq_data_get_irq_chip_data(d);
|
||||
int offset = irqd_to_hwirq(d);
|
||||
|
||||
guard(raw_spinlock_irqsave)(&gpio->lock);
|
||||
|
||||
iowrite32(bit, status_addr);
|
||||
gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_status, 1);
|
||||
}
|
||||
|
||||
static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set)
|
||||
{
|
||||
const struct aspeed_sgpio_bank *bank;
|
||||
struct aspeed_sgpio *gpio;
|
||||
u32 reg, bit;
|
||||
void __iomem *addr;
|
||||
int offset;
|
||||
|
||||
irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
|
||||
addr = bank_reg(gpio, bank, reg_irq_enable);
|
||||
struct aspeed_sgpio *gpio = irq_data_get_irq_chip_data(d);
|
||||
int offset = irqd_to_hwirq(d);
|
||||
|
||||
/* Unmasking the IRQ */
|
||||
if (set)
|
||||
gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(d));
|
||||
|
||||
scoped_guard(raw_spinlock_irqsave, &gpio->lock) {
|
||||
reg = ioread32(addr);
|
||||
if (set)
|
||||
reg |= bit;
|
||||
else
|
||||
reg &= ~bit;
|
||||
|
||||
iowrite32(reg, addr);
|
||||
gpiochip_enable_irq(&gpio->chip, offset);
|
||||
scoped_guard(raw_spinlock_irqsave, &gpio->lock)
|
||||
{
|
||||
gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_enable,
|
||||
set);
|
||||
}
|
||||
|
||||
/* Masking the IRQ */
|
||||
if (!set)
|
||||
gpiochip_disable_irq(&gpio->chip, irqd_to_hwirq(d));
|
||||
|
||||
|
||||
gpiochip_disable_irq(&gpio->chip, offset);
|
||||
}
|
||||
|
||||
static void aspeed_sgpio_irq_mask(struct irq_data *d)
|
||||
|
|
@ -323,30 +327,25 @@ static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type)
|
|||
u32 type0 = 0;
|
||||
u32 type1 = 0;
|
||||
u32 type2 = 0;
|
||||
u32 bit, reg;
|
||||
const struct aspeed_sgpio_bank *bank;
|
||||
irq_flow_handler_t handler;
|
||||
struct aspeed_sgpio *gpio;
|
||||
void __iomem *addr;
|
||||
int offset;
|
||||
|
||||
irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
|
||||
struct aspeed_sgpio *gpio = irq_data_get_irq_chip_data(d);
|
||||
int offset = irqd_to_hwirq(d);
|
||||
|
||||
switch (type & IRQ_TYPE_SENSE_MASK) {
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
type2 |= bit;
|
||||
type2 = 1;
|
||||
fallthrough;
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
type0 |= bit;
|
||||
type0 = 1;
|
||||
fallthrough;
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
handler = handle_edge_irq;
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
type0 |= bit;
|
||||
type0 = 1;
|
||||
fallthrough;
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
type1 |= bit;
|
||||
type1 = 1;
|
||||
handler = handle_level_irq;
|
||||
break;
|
||||
default:
|
||||
|
|
@ -354,20 +353,9 @@ static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type)
|
|||
}
|
||||
|
||||
scoped_guard(raw_spinlock_irqsave, &gpio->lock) {
|
||||
addr = bank_reg(gpio, bank, reg_irq_type0);
|
||||
reg = ioread32(addr);
|
||||
reg = (reg & ~bit) | type0;
|
||||
iowrite32(reg, addr);
|
||||
|
||||
addr = bank_reg(gpio, bank, reg_irq_type1);
|
||||
reg = ioread32(addr);
|
||||
reg = (reg & ~bit) | type1;
|
||||
iowrite32(reg, addr);
|
||||
|
||||
addr = bank_reg(gpio, bank, reg_irq_type2);
|
||||
reg = ioread32(addr);
|
||||
reg = (reg & ~bit) | type2;
|
||||
iowrite32(reg, addr);
|
||||
gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_type0, type0);
|
||||
gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_type1, type1);
|
||||
gpio->pdata->llops->reg_bit_set(gpio, offset, reg_irq_type2, type2);
|
||||
}
|
||||
|
||||
irq_set_handler_locked(d, handler);
|
||||
|
|
@ -380,15 +368,14 @@ static void aspeed_sgpio_irq_handler(struct irq_desc *desc)
|
|||
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
|
||||
struct irq_chip *ic = irq_desc_get_chip(desc);
|
||||
struct aspeed_sgpio *data = gpiochip_get_data(gc);
|
||||
unsigned int i, p;
|
||||
unsigned int i, p, banks;
|
||||
unsigned long reg;
|
||||
|
||||
chained_irq_enter(ic, desc);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
|
||||
const struct aspeed_sgpio_bank *bank = &aspeed_sgpio_banks[i];
|
||||
|
||||
reg = ioread32(bank_reg(data, bank, reg_irq_status));
|
||||
banks = DIV_ROUND_UP(gc->ngpio, 64);
|
||||
for (i = 0; i < banks; i++) {
|
||||
reg = data->pdata->llops->reg_bank_get(data, i << 6, reg_irq_status);
|
||||
|
||||
for_each_set_bit(p, ®, 32)
|
||||
generic_handle_domain_irq(gc->irq.domain, (i * 32 + p) * 2);
|
||||
|
|
@ -399,12 +386,8 @@ static void aspeed_sgpio_irq_handler(struct irq_desc *desc)
|
|||
|
||||
static void aspeed_sgpio_irq_print_chip(struct irq_data *d, struct seq_file *p)
|
||||
{
|
||||
const struct aspeed_sgpio_bank *bank;
|
||||
struct aspeed_sgpio *gpio;
|
||||
u32 bit;
|
||||
int offset;
|
||||
struct aspeed_sgpio *gpio = irq_data_get_irq_chip_data(d);
|
||||
|
||||
irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
|
||||
seq_puts(p, dev_name(gpio->dev));
|
||||
}
|
||||
|
||||
|
|
@ -422,7 +405,6 @@ static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
|
|||
struct platform_device *pdev)
|
||||
{
|
||||
int rc, i;
|
||||
const struct aspeed_sgpio_bank *bank;
|
||||
struct gpio_irq_chip *irq;
|
||||
|
||||
rc = platform_get_irq(pdev, 0);
|
||||
|
|
@ -432,12 +414,11 @@ static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
|
|||
gpio->irq = rc;
|
||||
|
||||
/* Disable IRQ and clear Interrupt status registers for all SGPIO Pins. */
|
||||
for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
|
||||
bank = &aspeed_sgpio_banks[i];
|
||||
for (i = 0; i < gpio->chip.ngpio; i += 2) {
|
||||
/* disable irq enable bits */
|
||||
iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_enable));
|
||||
gpio->pdata->llops->reg_bit_set(gpio, i, reg_irq_enable, 0);
|
||||
/* clear status bits */
|
||||
iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status));
|
||||
gpio->pdata->llops->reg_bit_set(gpio, i, reg_irq_status, 1);
|
||||
}
|
||||
|
||||
irq = &gpio->chip.irq;
|
||||
|
|
@ -451,42 +432,91 @@ static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
|
|||
irq->num_parents = 1;
|
||||
|
||||
/* Apply default IRQ settings */
|
||||
for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
|
||||
bank = &aspeed_sgpio_banks[i];
|
||||
for (i = 0; i < gpio->chip.ngpio; i += 2) {
|
||||
/* set falling or level-low irq */
|
||||
iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0));
|
||||
gpio->pdata->llops->reg_bit_set(gpio, i, reg_irq_type0, 0);
|
||||
/* trigger type is edge */
|
||||
iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type1));
|
||||
gpio->pdata->llops->reg_bit_set(gpio, i, reg_irq_type1, 0);
|
||||
/* single edge trigger */
|
||||
iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type2));
|
||||
gpio->pdata->llops->reg_bit_set(gpio, i, reg_irq_type2, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void aspeed_sgpio_g4_reg_bit_set(struct aspeed_sgpio *gpio, unsigned int offset,
|
||||
const enum aspeed_sgpio_reg reg, bool val)
|
||||
{
|
||||
const struct aspeed_sgpio_bank *bank = to_bank(offset);
|
||||
void __iomem *addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg);
|
||||
u32 temp;
|
||||
|
||||
if (reg == reg_val) {
|
||||
/* Since this is an output, read the cached value from rdata, then update val. */
|
||||
addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg_rdata);
|
||||
temp = ioread32(addr);
|
||||
if (val)
|
||||
temp |= GPIO_BIT(offset);
|
||||
else
|
||||
temp &= ~GPIO_BIT(offset);
|
||||
|
||||
addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg_val);
|
||||
iowrite32(temp, addr);
|
||||
} else if (reg == reg_irq_status) {
|
||||
if (val)
|
||||
iowrite32(GPIO_BIT(offset), addr);
|
||||
} else {
|
||||
/* When setting other registers, we read from the register itself */
|
||||
temp = ioread32(addr);
|
||||
if (val)
|
||||
temp |= GPIO_BIT(offset);
|
||||
else
|
||||
temp &= ~GPIO_BIT(offset);
|
||||
iowrite32(temp, addr);
|
||||
}
|
||||
}
|
||||
|
||||
static bool aspeed_sgpio_g4_reg_bit_get(struct aspeed_sgpio *gpio, unsigned int offset,
|
||||
const enum aspeed_sgpio_reg reg)
|
||||
{
|
||||
const struct aspeed_sgpio_bank *bank = to_bank(offset);
|
||||
void __iomem *addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg);
|
||||
|
||||
return !!(ioread32(addr) & GPIO_BIT(offset));
|
||||
}
|
||||
|
||||
static int aspeed_sgpio_g4_reg_bank_get(struct aspeed_sgpio *gpio, unsigned int offset,
|
||||
const enum aspeed_sgpio_reg reg)
|
||||
{
|
||||
const struct aspeed_sgpio_bank *bank = to_bank(offset);
|
||||
void __iomem *addr = aspeed_sgpio_g4_bank_reg(gpio, bank, reg);
|
||||
|
||||
if (reg == reg_irq_status)
|
||||
return ioread32(addr);
|
||||
else
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static const struct aspeed_sgpio_llops aspeed_sgpio_g4_llops = {
|
||||
.reg_bit_set = aspeed_sgpio_g4_reg_bit_set,
|
||||
.reg_bit_get = aspeed_sgpio_g4_reg_bit_get,
|
||||
.reg_bank_get = aspeed_sgpio_g4_reg_bank_get,
|
||||
};
|
||||
|
||||
static const struct aspeed_sgpio_pdata ast2400_sgpio_pdata = {
|
||||
.pin_mask = GENMASK(9, 6),
|
||||
.llops = &aspeed_sgpio_g4_llops,
|
||||
.cfg_offset = ASPEED_SGPIO_G4_CFG_OFFSET,
|
||||
};
|
||||
|
||||
static int aspeed_sgpio_reset_tolerance(struct gpio_chip *chip,
|
||||
unsigned int offset, bool enable)
|
||||
{
|
||||
struct aspeed_sgpio *gpio = gpiochip_get_data(chip);
|
||||
void __iomem *reg;
|
||||
u32 val;
|
||||
|
||||
reg = bank_reg(gpio, to_bank(offset), reg_tolerance);
|
||||
|
||||
guard(raw_spinlock_irqsave)(&gpio->lock);
|
||||
|
||||
val = readl(reg);
|
||||
|
||||
if (enable)
|
||||
val |= GPIO_BIT(offset);
|
||||
else
|
||||
val &= ~GPIO_BIT(offset);
|
||||
|
||||
writel(val, reg);
|
||||
gpio->pdata->llops->reg_bit_set(gpio, offset, reg_tolerance, enable);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -505,21 +535,77 @@ static int aspeed_sgpio_set_config(struct gpio_chip *chip, unsigned int offset,
|
|||
|
||||
static const struct aspeed_sgpio_pdata ast2600_sgpiom_pdata = {
|
||||
.pin_mask = GENMASK(10, 6),
|
||||
.llops = &aspeed_sgpio_g4_llops,
|
||||
.cfg_offset = ASPEED_SGPIO_G4_CFG_OFFSET,
|
||||
};
|
||||
|
||||
static void aspeed_sgpio_g7_reg_bit_set(struct aspeed_sgpio *gpio, unsigned int offset,
|
||||
const enum aspeed_sgpio_reg reg, bool val)
|
||||
{
|
||||
u32 mask = aspeed_sgpio_g7_reg_mask(reg);
|
||||
void __iomem *addr = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(offset >> 1);
|
||||
u32 write_val;
|
||||
|
||||
if (mask) {
|
||||
write_val = (ioread32(addr) & ~(mask)) | field_prep(mask, val);
|
||||
iowrite32(write_val, addr);
|
||||
}
|
||||
}
|
||||
|
||||
static bool aspeed_sgpio_g7_reg_bit_get(struct aspeed_sgpio *gpio, unsigned int offset,
|
||||
const enum aspeed_sgpio_reg reg)
|
||||
{
|
||||
u32 mask = aspeed_sgpio_g7_reg_mask(reg);
|
||||
void __iomem *addr;
|
||||
|
||||
addr = gpio->base + SGPIO_G7_CTRL_REG_OFFSET(offset >> 1);
|
||||
if (reg == reg_val)
|
||||
mask = SGPIO_G7_IN_DATA;
|
||||
|
||||
if (mask)
|
||||
return field_get(mask, ioread32(addr));
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aspeed_sgpio_g7_reg_bank_get(struct aspeed_sgpio *gpio, unsigned int offset,
|
||||
const enum aspeed_sgpio_reg reg)
|
||||
{
|
||||
void __iomem *addr;
|
||||
|
||||
if (reg == reg_irq_status) {
|
||||
addr = gpio->base + SGPIO_G7_IRQ_STS_OFFSET(offset >> 6);
|
||||
return ioread32(addr);
|
||||
} else {
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct aspeed_sgpio_llops aspeed_sgpio_g7_llops = {
|
||||
.reg_bit_set = aspeed_sgpio_g7_reg_bit_set,
|
||||
.reg_bit_get = aspeed_sgpio_g7_reg_bit_get,
|
||||
.reg_bank_get = aspeed_sgpio_g7_reg_bank_get,
|
||||
};
|
||||
|
||||
static const struct aspeed_sgpio_pdata ast2700_sgpiom_pdata = {
|
||||
.pin_mask = GENMASK(11, 6),
|
||||
.llops = &aspeed_sgpio_g7_llops,
|
||||
.cfg_offset = ASPEED_SGPIO_G7_CFG_OFFSET,
|
||||
};
|
||||
|
||||
static const struct of_device_id aspeed_sgpio_of_table[] = {
|
||||
{ .compatible = "aspeed,ast2400-sgpio", .data = &ast2400_sgpio_pdata, },
|
||||
{ .compatible = "aspeed,ast2500-sgpio", .data = &ast2400_sgpio_pdata, },
|
||||
{ .compatible = "aspeed,ast2600-sgpiom", .data = &ast2600_sgpiom_pdata, },
|
||||
{ .compatible = "aspeed,ast2700-sgpiom", .data = &ast2700_sgpiom_pdata, },
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, aspeed_sgpio_of_table);
|
||||
|
||||
static int __init aspeed_sgpio_probe(struct platform_device *pdev)
|
||||
static int aspeed_sgpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
u32 nr_gpios, sgpio_freq, sgpio_clk_div, gpio_cnt_regval, pin_mask;
|
||||
const struct aspeed_sgpio_pdata *pdata;
|
||||
struct aspeed_sgpio *gpio;
|
||||
unsigned long apb_freq;
|
||||
int rc;
|
||||
|
|
@ -534,12 +620,11 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev)
|
|||
|
||||
gpio->dev = &pdev->dev;
|
||||
|
||||
pdata = device_get_match_data(&pdev->dev);
|
||||
if (!pdata)
|
||||
gpio->pdata = device_get_match_data(&pdev->dev);
|
||||
if (!gpio->pdata)
|
||||
return -EINVAL;
|
||||
|
||||
pin_mask = pdata->pin_mask;
|
||||
|
||||
pin_mask = gpio->pdata->pin_mask;
|
||||
rc = device_property_read_u32(&pdev->dev, "ngpios", &nr_gpios);
|
||||
if (rc < 0) {
|
||||
dev_err(&pdev->dev, "Could not read ngpios property\n");
|
||||
|
|
@ -583,7 +668,7 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev)
|
|||
|
||||
gpio_cnt_regval = ((nr_gpios / 8) << ASPEED_SGPIO_PINS_SHIFT) & pin_mask;
|
||||
iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) | gpio_cnt_regval |
|
||||
ASPEED_SGPIO_ENABLE, gpio->base + ASPEED_SGPIO_CTRL);
|
||||
ASPEED_SGPIO_ENABLE, gpio->base + gpio->pdata->cfg_offset);
|
||||
|
||||
raw_spin_lock_init(&gpio->lock);
|
||||
|
||||
|
|
@ -611,11 +696,12 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
static struct platform_driver aspeed_sgpio_driver = {
|
||||
.probe = aspeed_sgpio_probe,
|
||||
.driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.of_match_table = aspeed_sgpio_of_table,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver_probe(aspeed_sgpio_driver, aspeed_sgpio_probe);
|
||||
module_platform_driver(aspeed_sgpio_driver);
|
||||
MODULE_DESCRIPTION("Aspeed Serial GPIO Driver");
|
||||
|
|
|
|||
|
|
@ -1302,7 +1302,6 @@ MODULE_DEVICE_TABLE(of, aspeed_gpio_of_table);
|
|||
|
||||
static int aspeed_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *gpio_id;
|
||||
struct gpio_irq_chip *girq;
|
||||
struct aspeed_gpio *gpio;
|
||||
int rc, irq, i, banks, err;
|
||||
|
|
@ -1320,8 +1319,8 @@ static int aspeed_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
raw_spin_lock_init(&gpio->lock);
|
||||
|
||||
gpio_id = of_match_node(aspeed_gpio_of_table, pdev->dev.of_node);
|
||||
if (!gpio_id)
|
||||
gpio->config = device_get_match_data(&pdev->dev);
|
||||
if (!gpio->config)
|
||||
return -EINVAL;
|
||||
|
||||
gpio->clk = devm_clk_get_enabled(&pdev->dev, NULL);
|
||||
|
|
@ -1331,8 +1330,6 @@ static int aspeed_gpio_probe(struct platform_device *pdev)
|
|||
gpio->clk = NULL;
|
||||
}
|
||||
|
||||
gpio->config = gpio_id->data;
|
||||
|
||||
if (!gpio->config->llops->reg_bit_set || !gpio->config->llops->reg_bit_get ||
|
||||
!gpio->config->llops->reg_bank_get)
|
||||
return -EINVAL;
|
||||
|
|
|
|||
281
drivers/gpio/gpio-bd72720.c
Normal file
281
drivers/gpio/gpio-bd72720.c
Normal file
|
|
@ -0,0 +1,281 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Support to GPIOs on ROHM BD72720 and BD79300
|
||||
* Copyright 2025 ROHM Semiconductors.
|
||||
* Author: Matti Vaittinen <mazziesaccount@gmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/rohm-bd72720.h>
|
||||
|
||||
#define BD72720_GPIO_OPEN_DRAIN 0
|
||||
#define BD72720_GPIO_CMOS BIT(1)
|
||||
#define BD72720_INT_GPIO1_IN_SRC 4
|
||||
/*
|
||||
* The BD72720 has several "one time programmable" (OTP) configurations which
|
||||
* can be set at manufacturing phase. A set of these options allow using pins
|
||||
* as GPIO. The OTP configuration can't be read at run-time, so drivers rely on
|
||||
* device-tree to advertise the correct options.
|
||||
*
|
||||
* Both DVS[0,1] pins can be configured to be used for:
|
||||
* - OTP0: regulator RUN state control
|
||||
* - OTP1: GPI
|
||||
* - OTP2: GPO
|
||||
* - OTP3: Power sequencer output
|
||||
* Data-sheet also states that these PINs can always be used for IRQ but the
|
||||
* driver limits this by allowing them to be used for IRQs with OTP1 only.
|
||||
*
|
||||
* Pins GPIO_EXTEN0 (GPIO3), GPIO_EXTEN1 (GPIO4), GPIO_FAULT_B (GPIO5) have OTP
|
||||
* options for a specific (non GPIO) purposes, but also an option to configure
|
||||
* them to be used as a GPO.
|
||||
*
|
||||
* OTP settings can be separately configured for each pin.
|
||||
*
|
||||
* DT properties:
|
||||
* "rohm,pin-dvs0" and "rohm,pin-dvs1" can be set to one of the values:
|
||||
* "dvs-input", "gpi", "gpo".
|
||||
*
|
||||
* "rohm,pin-exten0", "rohm,pin-exten1" and "rohm,pin-fault_b" can be set to:
|
||||
* "gpo"
|
||||
*/
|
||||
|
||||
enum bd72720_gpio_state {
|
||||
BD72720_PIN_UNKNOWN,
|
||||
BD72720_PIN_GPI,
|
||||
BD72720_PIN_GPO,
|
||||
};
|
||||
|
||||
enum {
|
||||
BD72720_GPIO1,
|
||||
BD72720_GPIO2,
|
||||
BD72720_GPIO3,
|
||||
BD72720_GPIO4,
|
||||
BD72720_GPIO5,
|
||||
BD72720_GPIO_EPDEN,
|
||||
BD72720_NUM_GPIOS
|
||||
};
|
||||
|
||||
struct bd72720_gpio {
|
||||
/* chip.parent points the MFD which provides DT node and regmap */
|
||||
struct gpio_chip chip;
|
||||
/* dev points to the platform device for devm and prints */
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
int gpio_is_input;
|
||||
};
|
||||
|
||||
static int bd72720gpi_get(struct bd72720_gpio *bdgpio, unsigned int reg_offset)
|
||||
{
|
||||
int ret, val, shift;
|
||||
|
||||
ret = regmap_read(bdgpio->regmap, BD72720_REG_INT_ETC1_SRC, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
shift = BD72720_INT_GPIO1_IN_SRC + reg_offset;
|
||||
|
||||
return (val >> shift) & 1;
|
||||
}
|
||||
|
||||
static int bd72720gpo_get(struct bd72720_gpio *bdgpio,
|
||||
unsigned int offset)
|
||||
{
|
||||
const int regs[] = { BD72720_REG_GPIO1_CTRL, BD72720_REG_GPIO2_CTRL,
|
||||
BD72720_REG_GPIO3_CTRL, BD72720_REG_GPIO4_CTRL,
|
||||
BD72720_REG_GPIO5_CTRL, BD72720_REG_EPDEN_CTRL };
|
||||
int ret, val;
|
||||
|
||||
ret = regmap_read(bdgpio->regmap, regs[offset], &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return val & BD72720_GPIO_HIGH;
|
||||
}
|
||||
|
||||
static int bd72720gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct bd72720_gpio *bdgpio = gpiochip_get_data(chip);
|
||||
|
||||
if (BIT(offset) & bdgpio->gpio_is_input)
|
||||
return bd72720gpi_get(bdgpio, offset);
|
||||
|
||||
return bd72720gpo_get(bdgpio, offset);
|
||||
}
|
||||
|
||||
static int bd72720gpo_set(struct gpio_chip *chip, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct bd72720_gpio *bdgpio = gpiochip_get_data(chip);
|
||||
const int regs[] = { BD72720_REG_GPIO1_CTRL, BD72720_REG_GPIO2_CTRL,
|
||||
BD72720_REG_GPIO3_CTRL, BD72720_REG_GPIO4_CTRL,
|
||||
BD72720_REG_GPIO5_CTRL, BD72720_REG_EPDEN_CTRL };
|
||||
|
||||
if (BIT(offset) & bdgpio->gpio_is_input) {
|
||||
dev_dbg(bdgpio->dev, "pin %d not output.\n", offset);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (value)
|
||||
return regmap_set_bits(bdgpio->regmap, regs[offset],
|
||||
BD72720_GPIO_HIGH);
|
||||
|
||||
return regmap_clear_bits(bdgpio->regmap, regs[offset],
|
||||
BD72720_GPIO_HIGH);
|
||||
}
|
||||
|
||||
static int bd72720_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
|
||||
unsigned long config)
|
||||
{
|
||||
struct bd72720_gpio *bdgpio = gpiochip_get_data(chip);
|
||||
const int regs[] = { BD72720_REG_GPIO1_CTRL, BD72720_REG_GPIO2_CTRL,
|
||||
BD72720_REG_GPIO3_CTRL, BD72720_REG_GPIO4_CTRL,
|
||||
BD72720_REG_GPIO5_CTRL, BD72720_REG_EPDEN_CTRL };
|
||||
|
||||
/*
|
||||
* We can only set the output mode, which makes sense only when output
|
||||
* OTP configuration is used.
|
||||
*/
|
||||
if (BIT(offset) & bdgpio->gpio_is_input)
|
||||
return -ENOTSUPP;
|
||||
|
||||
switch (pinconf_to_config_param(config)) {
|
||||
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
|
||||
return regmap_update_bits(bdgpio->regmap,
|
||||
regs[offset],
|
||||
BD72720_GPIO_DRIVE_MASK,
|
||||
BD72720_GPIO_OPEN_DRAIN);
|
||||
case PIN_CONFIG_DRIVE_PUSH_PULL:
|
||||
return regmap_update_bits(bdgpio->regmap,
|
||||
regs[offset],
|
||||
BD72720_GPIO_DRIVE_MASK,
|
||||
BD72720_GPIO_CMOS);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static int bd72720gpo_direction_get(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct bd72720_gpio *bdgpio = gpiochip_get_data(chip);
|
||||
|
||||
if (BIT(offset) & bdgpio->gpio_is_input)
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int bd72720_valid_mask(struct gpio_chip *gc,
|
||||
unsigned long *valid_mask,
|
||||
unsigned int ngpios)
|
||||
{
|
||||
static const char * const properties[] = {
|
||||
"rohm,pin-dvs0", "rohm,pin-dvs1", "rohm,pin-exten0",
|
||||
"rohm,pin-exten1", "rohm,pin-fault_b"
|
||||
};
|
||||
struct bd72720_gpio *g = gpiochip_get_data(gc);
|
||||
const char *val;
|
||||
int i, ret;
|
||||
|
||||
*valid_mask = BIT(BD72720_GPIO_EPDEN);
|
||||
|
||||
if (!gc->parent)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(properties); i++) {
|
||||
ret = fwnode_property_read_string(dev_fwnode(gc->parent),
|
||||
properties[i], &val);
|
||||
|
||||
if (ret) {
|
||||
if (ret == -EINVAL)
|
||||
continue;
|
||||
|
||||
dev_err(g->dev, "pin %d (%s), bad configuration\n", i,
|
||||
properties[i]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (strcmp(val, "gpi") == 0) {
|
||||
if (i != BD72720_GPIO1 && i != BD72720_GPIO2) {
|
||||
dev_warn(g->dev,
|
||||
"pin %d (%s) does not support INPUT mode",
|
||||
i, properties[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
*valid_mask |= BIT(i);
|
||||
g->gpio_is_input |= BIT(i);
|
||||
} else if (strcmp(val, "gpo") == 0) {
|
||||
*valid_mask |= BIT(i);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Template for GPIO chip */
|
||||
static const struct gpio_chip bd72720gpo_chip = {
|
||||
.label = "bd72720",
|
||||
.owner = THIS_MODULE,
|
||||
.get = bd72720gpio_get,
|
||||
.get_direction = bd72720gpo_direction_get,
|
||||
.set = bd72720gpo_set,
|
||||
.set_config = bd72720_gpio_set_config,
|
||||
.init_valid_mask = bd72720_valid_mask,
|
||||
.can_sleep = true,
|
||||
.ngpio = BD72720_NUM_GPIOS,
|
||||
.base = -1,
|
||||
};
|
||||
|
||||
static int gpo_bd72720_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct bd72720_gpio *g;
|
||||
struct device *parent, *dev;
|
||||
|
||||
/*
|
||||
* Bind devm lifetime to this platform device => use dev for devm.
|
||||
* also the prints should originate from this device.
|
||||
*/
|
||||
dev = &pdev->dev;
|
||||
/* The device-tree and regmap come from MFD => use parent for that */
|
||||
parent = dev->parent;
|
||||
|
||||
g = devm_kzalloc(dev, sizeof(*g), GFP_KERNEL);
|
||||
if (!g)
|
||||
return -ENOMEM;
|
||||
|
||||
g->chip = bd72720gpo_chip;
|
||||
g->dev = dev;
|
||||
g->chip.parent = parent;
|
||||
g->regmap = dev_get_regmap(parent, NULL);
|
||||
|
||||
return devm_gpiochip_add_data(dev, &g->chip, g);
|
||||
}
|
||||
|
||||
static const struct platform_device_id bd72720_gpio_id[] = {
|
||||
{ "bd72720-gpio" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, bd72720_gpio_id);
|
||||
|
||||
static struct platform_driver gpo_bd72720_driver = {
|
||||
.driver = {
|
||||
.name = "bd72720-gpio",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
},
|
||||
.probe = gpo_bd72720_probe,
|
||||
.id_table = bd72720_gpio_id,
|
||||
};
|
||||
module_platform_driver(gpo_bd72720_driver);
|
||||
|
||||
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
|
||||
MODULE_DESCRIPTION("GPIO interface for BD72720 and BD73900");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
/*
|
||||
* Copyright 2017-2018 Cadence
|
||||
* Copyright (C) 2025 Axiado Corporation.
|
||||
*
|
||||
* Authors:
|
||||
* Jan Kotas <jank@cadence.com>
|
||||
|
|
@ -31,10 +32,23 @@
|
|||
#define CDNS_GPIO_IRQ_VALUE 0x28
|
||||
#define CDNS_GPIO_IRQ_ANY_EDGE 0x2c
|
||||
|
||||
struct cdns_gpio_quirks {
|
||||
bool skip_init;
|
||||
};
|
||||
|
||||
struct cdns_gpio_chip {
|
||||
struct gpio_generic_chip gen_gc;
|
||||
void __iomem *regs;
|
||||
u32 bypass_orig;
|
||||
const struct cdns_gpio_quirks *quirks;
|
||||
};
|
||||
|
||||
static const struct cdns_gpio_quirks cdns_default_quirks = {
|
||||
.skip_init = false,
|
||||
};
|
||||
|
||||
static const struct cdns_gpio_quirks ax3000_gpio_quirks = {
|
||||
.skip_init = true,
|
||||
};
|
||||
|
||||
static int cdns_gpio_request(struct gpio_chip *chip, unsigned int offset)
|
||||
|
|
@ -84,6 +98,7 @@ static int cdns_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
|||
struct cdns_gpio_chip *cgpio = gpiochip_get_data(chip);
|
||||
u32 int_value;
|
||||
u32 int_type;
|
||||
u32 int_any;
|
||||
u32 mask = BIT(d->hwirq);
|
||||
int ret = 0;
|
||||
|
||||
|
|
@ -91,24 +106,35 @@ static int cdns_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
|||
|
||||
int_value = ioread32(cgpio->regs + CDNS_GPIO_IRQ_VALUE) & ~mask;
|
||||
int_type = ioread32(cgpio->regs + CDNS_GPIO_IRQ_TYPE) & ~mask;
|
||||
|
||||
/*
|
||||
* The GPIO controller doesn't have an ACK register.
|
||||
* All interrupt statuses are cleared on a status register read.
|
||||
* Don't support edge interrupts for now.
|
||||
* Interrupt polarity and trigger behaviour is configured like this:
|
||||
*
|
||||
* (type, value)
|
||||
* (0, 0) = Falling edge triggered
|
||||
* (0, 1) = Rising edge triggered
|
||||
* (1, 0) = Low level triggered
|
||||
* (1, 1) = High level triggered
|
||||
*/
|
||||
int_any = ioread32(cgpio->regs + CDNS_GPIO_IRQ_ANY_EDGE) & ~mask;
|
||||
|
||||
if (type == IRQ_TYPE_LEVEL_HIGH) {
|
||||
int_type |= mask;
|
||||
int_value |= mask;
|
||||
} else if (type == IRQ_TYPE_LEVEL_LOW) {
|
||||
int_type |= mask;
|
||||
} else if (type == IRQ_TYPE_EDGE_RISING) {
|
||||
int_value |= mask;
|
||||
} else if (type == IRQ_TYPE_EDGE_FALLING) {
|
||||
/* edge trigger, int_value remains cleared for falling */
|
||||
} else if (type == IRQ_TYPE_EDGE_BOTH) {
|
||||
int_any |= mask;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
iowrite32(int_value, cgpio->regs + CDNS_GPIO_IRQ_VALUE);
|
||||
iowrite32(int_type, cgpio->regs + CDNS_GPIO_IRQ_TYPE);
|
||||
iowrite32(int_any, cgpio->regs + CDNS_GPIO_IRQ_ANY_EDGE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -141,6 +167,19 @@ static const struct irq_chip cdns_gpio_irqchip = {
|
|||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static const struct of_device_id cdns_of_ids[] = {
|
||||
{
|
||||
.compatible = "axiado,ax3000-gpio",
|
||||
.data = &ax3000_gpio_quirks
|
||||
},
|
||||
{
|
||||
.compatible = "cdns,gpio-r1p02",
|
||||
.data = &cdns_default_quirks
|
||||
},
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cdns_of_ids);
|
||||
|
||||
static int cdns_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_generic_chip_config config = { };
|
||||
|
|
@ -165,6 +204,10 @@ static int cdns_gpio_probe(struct platform_device *pdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
cgpio->quirks = device_get_match_data(&pdev->dev);
|
||||
if (!cgpio->quirks)
|
||||
cgpio->quirks = &cdns_default_quirks;
|
||||
|
||||
/*
|
||||
* Set all pins as inputs by default, otherwise:
|
||||
* gpiochip_lock_as_irq:
|
||||
|
|
@ -173,8 +216,15 @@ static int cdns_gpio_probe(struct platform_device *pdev)
|
|||
* so it needs to be changed before gpio_generic_chip_init() is called.
|
||||
*/
|
||||
dir_prev = ioread32(cgpio->regs + CDNS_GPIO_DIRECTION_MODE);
|
||||
iowrite32(GENMASK(num_gpios - 1, 0),
|
||||
cgpio->regs + CDNS_GPIO_DIRECTION_MODE);
|
||||
|
||||
/*
|
||||
* The AX3000 platform performs the required configuration at boot time
|
||||
* before Linux boots, so this quirk disables pinmux initialization.
|
||||
*/
|
||||
if (!cgpio->quirks->skip_init) {
|
||||
iowrite32(GENMASK(num_gpios - 1, 0),
|
||||
cgpio->regs + CDNS_GPIO_DIRECTION_MODE);
|
||||
}
|
||||
|
||||
config.dev = &pdev->dev;
|
||||
config.sz = 4;
|
||||
|
|
@ -240,9 +290,11 @@ static int cdns_gpio_probe(struct platform_device *pdev)
|
|||
/*
|
||||
* Enable gpio outputs, ignored for input direction
|
||||
*/
|
||||
iowrite32(GENMASK(num_gpios - 1, 0),
|
||||
cgpio->regs + CDNS_GPIO_OUTPUT_EN);
|
||||
iowrite32(0, cgpio->regs + CDNS_GPIO_BYPASS_MODE);
|
||||
if (!cgpio->quirks->skip_init) {
|
||||
iowrite32(GENMASK(num_gpios - 1, 0),
|
||||
cgpio->regs + CDNS_GPIO_OUTPUT_EN);
|
||||
iowrite32(0, cgpio->regs + CDNS_GPIO_BYPASS_MODE);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, cgpio);
|
||||
return 0;
|
||||
|
|
@ -260,12 +312,6 @@ static void cdns_gpio_remove(struct platform_device *pdev)
|
|||
iowrite32(cgpio->bypass_orig, cgpio->regs + CDNS_GPIO_BYPASS_MODE);
|
||||
}
|
||||
|
||||
static const struct of_device_id cdns_of_ids[] = {
|
||||
{ .compatible = "cdns,gpio-r1p02" },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cdns_of_ids);
|
||||
|
||||
static struct platform_driver cdns_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "cdns-gpio",
|
||||
|
|
|
|||
|
|
@ -134,7 +134,6 @@ static const struct of_device_id creg_gpio_ids[] = {
|
|||
|
||||
static int creg_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *match;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct creg_gpio *hcg;
|
||||
u32 ngpios;
|
||||
|
|
@ -148,8 +147,7 @@ static int creg_gpio_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(hcg->regs))
|
||||
return PTR_ERR(hcg->regs);
|
||||
|
||||
match = of_match_node(creg_gpio_ids, pdev->dev.of_node);
|
||||
hcg->layout = match->data;
|
||||
hcg->layout = device_get_match_data(dev);
|
||||
if (!hcg->layout)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
|||
116
drivers/gpio/gpio-line-mux.c
Normal file
116
drivers/gpio/gpio-line-mux.c
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* GPIO line mux which acts as virtual gpiochip and provides a 1-to-many
|
||||
* mapping between virtual GPIOs and a real GPIO + multiplexer.
|
||||
*
|
||||
* Copyright (c) 2025 Jonas Jelonek <jelonek.jonas@gmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/mux/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define MUX_SELECT_DELAY_US 100
|
||||
|
||||
struct gpio_lmux {
|
||||
struct gpio_chip gc;
|
||||
struct mux_control *mux;
|
||||
struct gpio_desc *muxed_gpio;
|
||||
|
||||
u32 num_gpio_mux_states;
|
||||
unsigned int gpio_mux_states[] __counted_by(num_gpio_mux_states);
|
||||
};
|
||||
|
||||
static int gpio_lmux_gpio_get(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct gpio_lmux *glm = gpiochip_get_data(gc);
|
||||
int ret;
|
||||
|
||||
ret = mux_control_select_delay(glm->mux, glm->gpio_mux_states[offset],
|
||||
MUX_SELECT_DELAY_US);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = gpiod_get_raw_value_cansleep(glm->muxed_gpio);
|
||||
mux_control_deselect(glm->mux);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gpio_lmux_gpio_get_direction(struct gpio_chip *gc,
|
||||
unsigned int offset)
|
||||
{
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
}
|
||||
|
||||
static int gpio_lmux_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct gpio_lmux *glm;
|
||||
unsigned int ngpio;
|
||||
size_t size;
|
||||
int ret;
|
||||
|
||||
ngpio = device_property_count_u32(dev, "gpio-line-mux-states");
|
||||
if (!ngpio)
|
||||
return -EINVAL;
|
||||
|
||||
size = struct_size(glm, gpio_mux_states, ngpio);
|
||||
glm = devm_kzalloc(dev, size, GFP_KERNEL);
|
||||
if (!glm)
|
||||
return -ENOMEM;
|
||||
|
||||
glm->gc.base = -1;
|
||||
glm->gc.can_sleep = true;
|
||||
glm->gc.fwnode = dev_fwnode(dev);
|
||||
glm->gc.label = dev_name(dev);
|
||||
glm->gc.ngpio = ngpio;
|
||||
glm->gc.owner = THIS_MODULE;
|
||||
glm->gc.parent = dev;
|
||||
|
||||
glm->gc.get = gpio_lmux_gpio_get;
|
||||
glm->gc.get_direction = gpio_lmux_gpio_get_direction;
|
||||
|
||||
glm->mux = devm_mux_control_get(dev, NULL);
|
||||
if (IS_ERR(glm->mux))
|
||||
return dev_err_probe(dev, PTR_ERR(glm->mux),
|
||||
"could not get mux controller\n");
|
||||
|
||||
glm->muxed_gpio = devm_gpiod_get(dev, "muxed", GPIOD_IN);
|
||||
if (IS_ERR(glm->muxed_gpio))
|
||||
return dev_err_probe(dev, PTR_ERR(glm->muxed_gpio),
|
||||
"could not get muxed-gpio\n");
|
||||
|
||||
glm->num_gpio_mux_states = ngpio;
|
||||
ret = device_property_read_u32_array(dev, "gpio-line-mux-states",
|
||||
&glm->gpio_mux_states[0], ngpio);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "could not get mux states\n");
|
||||
|
||||
ret = devm_gpiochip_add_data(dev, &glm->gc, glm);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to add gpiochip\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id gpio_lmux_of_match[] = {
|
||||
{ .compatible = "gpio-line-mux" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, gpio_lmux_of_match);
|
||||
|
||||
static struct platform_driver gpio_lmux_driver = {
|
||||
.driver = {
|
||||
.name = "gpio-line-mux",
|
||||
.of_match_table = gpio_lmux_of_match,
|
||||
},
|
||||
.probe = gpio_lmux_probe,
|
||||
};
|
||||
module_platform_driver(gpio_lmux_driver);
|
||||
|
||||
MODULE_AUTHOR("Jonas Jelonek <jelonek.jonas@gmail.com>");
|
||||
MODULE_DESCRIPTION("GPIO line mux driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -132,6 +132,24 @@ static const struct irq_chip max77620_gpio_irqchip = {
|
|||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static int max77620_gpio_get_dir(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct max77620_gpio *mgpio = gpiochip_get_data(gc);
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(mgpio->rmap, GPIO_REG_ADDR(offset), &val);
|
||||
if (ret < 0) {
|
||||
dev_err(mgpio->dev, "CNFG_GPIOx read failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (val & MAX77620_CNFG_GPIO_DIR_MASK)
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
else
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int max77620_gpio_dir_input(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct max77620_gpio *mgpio = gpiochip_get_data(gc);
|
||||
|
|
@ -308,6 +326,7 @@ static int max77620_gpio_probe(struct platform_device *pdev)
|
|||
|
||||
mgpio->gpio_chip.label = pdev->name;
|
||||
mgpio->gpio_chip.parent = pdev->dev.parent;
|
||||
mgpio->gpio_chip.get_direction = max77620_gpio_get_dir;
|
||||
mgpio->gpio_chip.direction_input = max77620_gpio_dir_input;
|
||||
mgpio->gpio_chip.get = max77620_gpio_get;
|
||||
mgpio->gpio_chip.direction_output = max77620_gpio_dir_output;
|
||||
|
|
|
|||
|
|
@ -435,8 +435,6 @@ static int max77759_gpio_probe(struct platform_device *pdev)
|
|||
int irq;
|
||||
struct gpio_irq_chip *girq;
|
||||
int ret;
|
||||
unsigned long irq_flags;
|
||||
struct irq_data *irqd;
|
||||
|
||||
chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
|
||||
if (!chip)
|
||||
|
|
@ -486,13 +484,9 @@ static int max77759_gpio_probe(struct platform_device *pdev)
|
|||
return dev_err_probe(&pdev->dev, ret,
|
||||
"Failed to add GPIO chip\n");
|
||||
|
||||
irq_flags = IRQF_ONESHOT | IRQF_SHARED;
|
||||
irqd = irq_get_irq_data(irq);
|
||||
if (irqd)
|
||||
irq_flags |= irqd_get_trigger_type(irqd);
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
|
||||
max77759_gpio_irqhandler, irq_flags,
|
||||
max77759_gpio_irqhandler,
|
||||
IRQF_ONESHOT | IRQF_SHARED,
|
||||
dev_name(&pdev->dev), chip);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
|
|
|
|||
|
|
@ -223,5 +223,4 @@ module_mcb_driver(men_z127_driver);
|
|||
MODULE_AUTHOR("Andreas Werner <andreas.werner@men.de>");
|
||||
MODULE_DESCRIPTION("MEN GPIO Controller");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("mcb:16z127");
|
||||
MODULE_IMPORT_NS("MCB");
|
||||
|
|
|
|||
|
|
@ -724,6 +724,7 @@ static const struct of_device_id gpio_mmio_of_match[] = {
|
|||
{ .compatible = "wd,mbl-gpio" },
|
||||
{ .compatible = "ni,169445-nand-gpio" },
|
||||
{ .compatible = "intel,ixp4xx-expansion-bus-mmio-gpio" },
|
||||
{ .compatible = "opencores,gpio" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, gpio_mmio_of_match);
|
||||
|
|
|
|||
|
|
@ -126,6 +126,9 @@ static const struct i2c_device_id pca953x_id[] = {
|
|||
{ "tca9539", 16 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "tca9554", 8 | PCA953X_TYPE | PCA_INT, },
|
||||
{ "xra1202", 8 | PCA953X_TYPE },
|
||||
|
||||
{ "tcal6408", 8 | PCA953X_TYPE | PCA_LATCH_INT, },
|
||||
{ "tcal6416", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, pca953x_id);
|
||||
|
|
@ -1469,6 +1472,9 @@ static const struct of_device_id pca953x_dt_ids[] = {
|
|||
{ .compatible = "ti,tca9538", .data = OF_953X( 8, PCA_INT), },
|
||||
{ .compatible = "ti,tca9539", .data = OF_953X(16, PCA_INT), },
|
||||
|
||||
{ .compatible = "ti,tcal6408", .data = OF_953X( 8, PCA_LATCH_INT), },
|
||||
{ .compatible = "ti,tcal6416", .data = OF_953X(16, PCA_LATCH_INT), },
|
||||
|
||||
{ .compatible = "onnn,cat9554", .data = OF_953X( 8, PCA_INT), },
|
||||
{ .compatible = "onnn,pca9654", .data = OF_953X( 8, PCA_INT), },
|
||||
{ .compatible = "onnn,pca9655", .data = OF_953X(16, PCA_INT), },
|
||||
|
|
|
|||
|
|
@ -9,11 +9,16 @@
|
|||
* Andrew F. Davis <afd@ti.com>
|
||||
*/
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/device/devres.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define SLG7XL45106_GPO_REG 0xDB
|
||||
|
||||
|
|
@ -94,7 +99,7 @@ static int pca9570_set(struct gpio_chip *chip, unsigned int offset, int value)
|
|||
u8 buffer;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&gpio->lock);
|
||||
guard(mutex)(&gpio->lock);
|
||||
|
||||
buffer = gpio->out;
|
||||
if (value)
|
||||
|
|
@ -104,18 +109,18 @@ static int pca9570_set(struct gpio_chip *chip, unsigned int offset, int value)
|
|||
|
||||
ret = pca9570_write(gpio, buffer);
|
||||
if (ret)
|
||||
goto out;
|
||||
return ret;
|
||||
|
||||
gpio->out = buffer;
|
||||
|
||||
out:
|
||||
mutex_unlock(&gpio->lock);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pca9570_probe(struct i2c_client *client)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct pca9570 *gpio;
|
||||
int ret;
|
||||
|
||||
gpio = devm_kzalloc(&client->dev, sizeof(*gpio), GFP_KERNEL);
|
||||
if (!gpio)
|
||||
|
|
@ -132,7 +137,9 @@ static int pca9570_probe(struct i2c_client *client)
|
|||
gpio->chip.ngpio = gpio->chip_data->ngpio;
|
||||
gpio->chip.can_sleep = true;
|
||||
|
||||
mutex_init(&gpio->lock);
|
||||
ret = devm_mutex_init(dev, &gpio->lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Read the current output level */
|
||||
pca9570_read(gpio, &gpio->out);
|
||||
|
|
|
|||
|
|
@ -359,8 +359,7 @@ static int realtek_gpio_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct gpio_generic_chip_config config;
|
||||
struct device *dev = &pdev->dev;
|
||||
unsigned long gen_gc_flags;
|
||||
unsigned int dev_flags;
|
||||
unsigned long gen_gc_flags, dev_flags;
|
||||
struct gpio_irq_chip *girq;
|
||||
struct realtek_gpio_ctrl *ctrl;
|
||||
struct resource *res;
|
||||
|
|
@ -372,7 +371,7 @@ static int realtek_gpio_probe(struct platform_device *pdev)
|
|||
if (!ctrl)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_flags = (unsigned int) device_get_match_data(dev);
|
||||
dev_flags = (uintptr_t)device_get_match_data(dev);
|
||||
|
||||
ngpios = REALTEK_GPIO_MAX;
|
||||
device_property_read_u32(dev, "ngpios", &ngpios);
|
||||
|
|
|
|||
|
|
@ -1384,7 +1384,7 @@ static void gpio_sim_hog_config_item_release(struct config_item *item)
|
|||
kfree(hog);
|
||||
}
|
||||
|
||||
static struct configfs_item_operations gpio_sim_hog_config_item_ops = {
|
||||
static const struct configfs_item_operations gpio_sim_hog_config_item_ops = {
|
||||
.release = gpio_sim_hog_config_item_release,
|
||||
};
|
||||
|
||||
|
|
@ -1433,11 +1433,11 @@ static void gpio_sim_line_config_group_release(struct config_item *item)
|
|||
kfree(line);
|
||||
}
|
||||
|
||||
static struct configfs_item_operations gpio_sim_line_config_item_ops = {
|
||||
static const struct configfs_item_operations gpio_sim_line_config_item_ops = {
|
||||
.release = gpio_sim_line_config_group_release,
|
||||
};
|
||||
|
||||
static struct configfs_group_operations gpio_sim_line_config_group_ops = {
|
||||
static const struct configfs_group_operations gpio_sim_line_config_group_ops = {
|
||||
.make_item = gpio_sim_line_config_make_hog_item,
|
||||
};
|
||||
|
||||
|
|
@ -1494,11 +1494,11 @@ static void gpio_sim_bank_config_group_release(struct config_item *item)
|
|||
kfree(bank);
|
||||
}
|
||||
|
||||
static struct configfs_item_operations gpio_sim_bank_config_item_ops = {
|
||||
static const struct configfs_item_operations gpio_sim_bank_config_item_ops = {
|
||||
.release = gpio_sim_bank_config_group_release,
|
||||
};
|
||||
|
||||
static struct configfs_group_operations gpio_sim_bank_config_group_ops = {
|
||||
static const struct configfs_group_operations gpio_sim_bank_config_group_ops = {
|
||||
.make_group = gpio_sim_bank_config_make_line_group,
|
||||
};
|
||||
|
||||
|
|
@ -1549,11 +1549,11 @@ static void gpio_sim_device_config_group_release(struct config_item *item)
|
|||
kfree(dev);
|
||||
}
|
||||
|
||||
static struct configfs_item_operations gpio_sim_device_config_item_ops = {
|
||||
static const struct configfs_item_operations gpio_sim_device_config_item_ops = {
|
||||
.release = gpio_sim_device_config_group_release,
|
||||
};
|
||||
|
||||
static struct configfs_group_operations gpio_sim_device_config_group_ops = {
|
||||
static const struct configfs_group_operations gpio_sim_device_config_group_ops = {
|
||||
.make_group = gpio_sim_device_config_make_bank_group,
|
||||
};
|
||||
|
||||
|
|
@ -1589,7 +1589,7 @@ gpio_sim_config_make_device_group(struct config_group *group, const char *name)
|
|||
return &no_free_ptr(dev)->group;
|
||||
}
|
||||
|
||||
static struct configfs_group_operations gpio_sim_config_group_ops = {
|
||||
static const struct configfs_group_operations gpio_sim_config_group_ops = {
|
||||
.make_group = gpio_sim_config_make_device_group,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -15,29 +15,37 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
/* register offset */
|
||||
#define SPACEMIT_GPLR 0x00 /* port level - R */
|
||||
#define SPACEMIT_GPDR 0x0c /* port direction - R/W */
|
||||
#define SPACEMIT_GPSR 0x18 /* port set - W */
|
||||
#define SPACEMIT_GPCR 0x24 /* port clear - W */
|
||||
#define SPACEMIT_GRER 0x30 /* port rising edge R/W */
|
||||
#define SPACEMIT_GFER 0x3c /* port falling edge R/W */
|
||||
#define SPACEMIT_GEDR 0x48 /* edge detect status - R/W1C */
|
||||
#define SPACEMIT_GSDR 0x54 /* (set) direction - W */
|
||||
#define SPACEMIT_GCDR 0x60 /* (clear) direction - W */
|
||||
#define SPACEMIT_GSRER 0x6c /* (set) rising edge detect enable - W */
|
||||
#define SPACEMIT_GCRER 0x78 /* (clear) rising edge detect enable - W */
|
||||
#define SPACEMIT_GSFER 0x84 /* (set) falling edge detect enable - W */
|
||||
#define SPACEMIT_GCFER 0x90 /* (clear) falling edge detect enable - W */
|
||||
#define SPACEMIT_GAPMASK 0x9c /* interrupt mask , 0 disable, 1 enable - R/W */
|
||||
|
||||
#define SPACEMIT_NR_BANKS 4
|
||||
#define SPACEMIT_NR_GPIOS_PER_BANK 32
|
||||
|
||||
#define to_spacemit_gpio_bank(x) container_of((x), struct spacemit_gpio_bank, gc)
|
||||
#define to_spacemit_gpio_regs(gb) ((gb)->sg->data->offsets)
|
||||
|
||||
enum spacemit_gpio_registers {
|
||||
SPACEMIT_GPLR, /* port level - R */
|
||||
SPACEMIT_GPDR, /* port direction - R/W */
|
||||
SPACEMIT_GPSR, /* port set - W */
|
||||
SPACEMIT_GPCR, /* port clear - W */
|
||||
SPACEMIT_GRER, /* port rising edge R/W */
|
||||
SPACEMIT_GFER, /* port falling edge R/W */
|
||||
SPACEMIT_GEDR, /* edge detect status - R/W1C */
|
||||
SPACEMIT_GSDR, /* (set) direction - W */
|
||||
SPACEMIT_GCDR, /* (clear) direction - W */
|
||||
SPACEMIT_GSRER, /* (set) rising edge detect enable - W */
|
||||
SPACEMIT_GCRER, /* (clear) rising edge detect enable - W */
|
||||
SPACEMIT_GSFER, /* (set) falling edge detect enable - W */
|
||||
SPACEMIT_GCFER, /* (clear) falling edge detect enable - W */
|
||||
SPACEMIT_GAPMASK, /* interrupt mask , 0 disable, 1 enable - R/W */
|
||||
SPACEMIT_GCPMASK, /* interrupt mask for K3 */
|
||||
};
|
||||
|
||||
struct spacemit_gpio;
|
||||
|
||||
struct spacemit_gpio_data {
|
||||
const unsigned int *offsets;
|
||||
u32 bank_offsets[SPACEMIT_NR_BANKS];
|
||||
};
|
||||
|
||||
struct spacemit_gpio_bank {
|
||||
struct gpio_generic_chip chip;
|
||||
struct spacemit_gpio *sg;
|
||||
|
|
@ -49,9 +57,22 @@ struct spacemit_gpio_bank {
|
|||
|
||||
struct spacemit_gpio {
|
||||
struct device *dev;
|
||||
const struct spacemit_gpio_data *data;
|
||||
struct spacemit_gpio_bank sgb[SPACEMIT_NR_BANKS];
|
||||
};
|
||||
|
||||
static u32 spacemit_gpio_read(struct spacemit_gpio_bank *gb,
|
||||
enum spacemit_gpio_registers reg)
|
||||
{
|
||||
return readl(gb->base + to_spacemit_gpio_regs(gb)[reg]);
|
||||
}
|
||||
|
||||
static void spacemit_gpio_write(struct spacemit_gpio_bank *gb,
|
||||
enum spacemit_gpio_registers reg, u32 val)
|
||||
{
|
||||
writel(val, gb->base + to_spacemit_gpio_regs(gb)[reg]);
|
||||
}
|
||||
|
||||
static u32 spacemit_gpio_bank_index(struct spacemit_gpio_bank *gb)
|
||||
{
|
||||
return (u32)(gb - gb->sg->sgb);
|
||||
|
|
@ -63,10 +84,10 @@ static irqreturn_t spacemit_gpio_irq_handler(int irq, void *dev_id)
|
|||
unsigned long pending;
|
||||
u32 n, gedr;
|
||||
|
||||
gedr = readl(gb->base + SPACEMIT_GEDR);
|
||||
gedr = spacemit_gpio_read(gb, SPACEMIT_GEDR);
|
||||
if (!gedr)
|
||||
return IRQ_NONE;
|
||||
writel(gedr, gb->base + SPACEMIT_GEDR);
|
||||
spacemit_gpio_write(gb, SPACEMIT_GEDR, gedr);
|
||||
|
||||
pending = gedr & gb->irq_mask;
|
||||
if (!pending)
|
||||
|
|
@ -82,7 +103,7 @@ static void spacemit_gpio_irq_ack(struct irq_data *d)
|
|||
{
|
||||
struct spacemit_gpio_bank *gb = irq_data_get_irq_chip_data(d);
|
||||
|
||||
writel(BIT(irqd_to_hwirq(d)), gb->base + SPACEMIT_GEDR);
|
||||
spacemit_gpio_write(gb, SPACEMIT_GEDR, BIT(irqd_to_hwirq(d)));
|
||||
}
|
||||
|
||||
static void spacemit_gpio_irq_mask(struct irq_data *d)
|
||||
|
|
@ -91,13 +112,13 @@ static void spacemit_gpio_irq_mask(struct irq_data *d)
|
|||
u32 bit = BIT(irqd_to_hwirq(d));
|
||||
|
||||
gb->irq_mask &= ~bit;
|
||||
writel(gb->irq_mask, gb->base + SPACEMIT_GAPMASK);
|
||||
spacemit_gpio_write(gb, SPACEMIT_GAPMASK, gb->irq_mask);
|
||||
|
||||
if (bit & gb->irq_rising_edge)
|
||||
writel(bit, gb->base + SPACEMIT_GCRER);
|
||||
spacemit_gpio_write(gb, SPACEMIT_GCRER, bit);
|
||||
|
||||
if (bit & gb->irq_falling_edge)
|
||||
writel(bit, gb->base + SPACEMIT_GCFER);
|
||||
spacemit_gpio_write(gb, SPACEMIT_GCFER, bit);
|
||||
}
|
||||
|
||||
static void spacemit_gpio_irq_unmask(struct irq_data *d)
|
||||
|
|
@ -108,12 +129,12 @@ static void spacemit_gpio_irq_unmask(struct irq_data *d)
|
|||
gb->irq_mask |= bit;
|
||||
|
||||
if (bit & gb->irq_rising_edge)
|
||||
writel(bit, gb->base + SPACEMIT_GSRER);
|
||||
spacemit_gpio_write(gb, SPACEMIT_GSRER, bit);
|
||||
|
||||
if (bit & gb->irq_falling_edge)
|
||||
writel(bit, gb->base + SPACEMIT_GSFER);
|
||||
spacemit_gpio_write(gb, SPACEMIT_GSFER, bit);
|
||||
|
||||
writel(gb->irq_mask, gb->base + SPACEMIT_GAPMASK);
|
||||
spacemit_gpio_write(gb, SPACEMIT_GAPMASK, gb->irq_mask);
|
||||
}
|
||||
|
||||
static int spacemit_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
|
|
@ -123,18 +144,18 @@ static int spacemit_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
|||
|
||||
if (type & IRQ_TYPE_EDGE_RISING) {
|
||||
gb->irq_rising_edge |= bit;
|
||||
writel(bit, gb->base + SPACEMIT_GSRER);
|
||||
spacemit_gpio_write(gb, SPACEMIT_GSRER, bit);
|
||||
} else {
|
||||
gb->irq_rising_edge &= ~bit;
|
||||
writel(bit, gb->base + SPACEMIT_GCRER);
|
||||
spacemit_gpio_write(gb, SPACEMIT_GCRER, bit);
|
||||
}
|
||||
|
||||
if (type & IRQ_TYPE_EDGE_FALLING) {
|
||||
gb->irq_falling_edge |= bit;
|
||||
writel(bit, gb->base + SPACEMIT_GSFER);
|
||||
spacemit_gpio_write(gb, SPACEMIT_GSFER, bit);
|
||||
} else {
|
||||
gb->irq_falling_edge &= ~bit;
|
||||
writel(bit, gb->base + SPACEMIT_GCFER);
|
||||
spacemit_gpio_write(gb, SPACEMIT_GCFER, bit);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -178,16 +199,16 @@ static int spacemit_gpio_add_bank(struct spacemit_gpio *sg,
|
|||
struct gpio_chip *gc = &gb->chip.gc;
|
||||
struct device *dev = sg->dev;
|
||||
struct gpio_irq_chip *girq;
|
||||
void __iomem *dat, *set, *clr, *dirin, *dirout;
|
||||
int ret, bank_base[] = { 0x0, 0x4, 0x8, 0x100 };
|
||||
void __iomem *dat, *set, *clr, *dirout;
|
||||
int ret;
|
||||
|
||||
gb->base = regs + bank_base[index];
|
||||
gb->base = regs + sg->data->bank_offsets[index];
|
||||
gb->sg = sg;
|
||||
|
||||
dat = gb->base + SPACEMIT_GPLR;
|
||||
set = gb->base + SPACEMIT_GPSR;
|
||||
clr = gb->base + SPACEMIT_GPCR;
|
||||
dirin = gb->base + SPACEMIT_GCDR;
|
||||
dirout = gb->base + SPACEMIT_GSDR;
|
||||
dat = gb->base + to_spacemit_gpio_regs(gb)[SPACEMIT_GPLR];
|
||||
set = gb->base + to_spacemit_gpio_regs(gb)[SPACEMIT_GPSR];
|
||||
clr = gb->base + to_spacemit_gpio_regs(gb)[SPACEMIT_GPCR];
|
||||
dirout = gb->base + to_spacemit_gpio_regs(gb)[SPACEMIT_GPDR];
|
||||
|
||||
config = (struct gpio_generic_chip_config) {
|
||||
.dev = dev,
|
||||
|
|
@ -196,9 +217,7 @@ static int spacemit_gpio_add_bank(struct spacemit_gpio *sg,
|
|||
.set = set,
|
||||
.clr = clr,
|
||||
.dirout = dirout,
|
||||
.dirin = dirin,
|
||||
.flags = GPIO_GENERIC_UNREADABLE_REG_SET |
|
||||
GPIO_GENERIC_UNREADABLE_REG_DIR,
|
||||
.flags = GPIO_GENERIC_UNREADABLE_REG_SET,
|
||||
};
|
||||
|
||||
/* This registers 32 GPIO lines per bank */
|
||||
|
|
@ -206,8 +225,6 @@ static int spacemit_gpio_add_bank(struct spacemit_gpio *sg,
|
|||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to init gpio chip\n");
|
||||
|
||||
gb->sg = sg;
|
||||
|
||||
gc->label = dev_name(dev);
|
||||
gc->request = gpiochip_generic_request;
|
||||
gc->free = gpiochip_generic_free;
|
||||
|
|
@ -223,13 +240,13 @@ static int spacemit_gpio_add_bank(struct spacemit_gpio *sg,
|
|||
gpio_irq_chip_set_chip(girq, &spacemit_gpio_chip);
|
||||
|
||||
/* Disable Interrupt */
|
||||
writel(0, gb->base + SPACEMIT_GAPMASK);
|
||||
spacemit_gpio_write(gb, SPACEMIT_GAPMASK, 0);
|
||||
/* Disable Edge Detection Settings */
|
||||
writel(0x0, gb->base + SPACEMIT_GRER);
|
||||
writel(0x0, gb->base + SPACEMIT_GFER);
|
||||
spacemit_gpio_write(gb, SPACEMIT_GRER, 0x0);
|
||||
spacemit_gpio_write(gb, SPACEMIT_GFER, 0x0);
|
||||
/* Clear Interrupt */
|
||||
writel(0xffffffff, gb->base + SPACEMIT_GCRER);
|
||||
writel(0xffffffff, gb->base + SPACEMIT_GCFER);
|
||||
spacemit_gpio_write(gb, SPACEMIT_GCRER, 0xffffffff);
|
||||
spacemit_gpio_write(gb, SPACEMIT_GCFER, 0xffffffff);
|
||||
|
||||
ret = devm_request_threaded_irq(dev, irq, NULL,
|
||||
spacemit_gpio_irq_handler,
|
||||
|
|
@ -260,6 +277,10 @@ static int spacemit_gpio_probe(struct platform_device *pdev)
|
|||
if (!sg)
|
||||
return -ENOMEM;
|
||||
|
||||
sg->data = of_device_get_match_data(dev);
|
||||
if (!sg->data)
|
||||
return dev_err_probe(dev, -EINVAL, "No available compatible data.");
|
||||
|
||||
regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(regs))
|
||||
return PTR_ERR(regs);
|
||||
|
|
@ -287,8 +308,55 @@ static int spacemit_gpio_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const unsigned int spacemit_gpio_k1_offsets[] = {
|
||||
[SPACEMIT_GPLR] = 0x00,
|
||||
[SPACEMIT_GPDR] = 0x0c,
|
||||
[SPACEMIT_GPSR] = 0x18,
|
||||
[SPACEMIT_GPCR] = 0x24,
|
||||
[SPACEMIT_GRER] = 0x30,
|
||||
[SPACEMIT_GFER] = 0x3c,
|
||||
[SPACEMIT_GEDR] = 0x48,
|
||||
[SPACEMIT_GSDR] = 0x54,
|
||||
[SPACEMIT_GCDR] = 0x60,
|
||||
[SPACEMIT_GSRER] = 0x6c,
|
||||
[SPACEMIT_GCRER] = 0x78,
|
||||
[SPACEMIT_GSFER] = 0x84,
|
||||
[SPACEMIT_GCFER] = 0x90,
|
||||
[SPACEMIT_GAPMASK] = 0x9c,
|
||||
[SPACEMIT_GCPMASK] = 0xA8,
|
||||
};
|
||||
|
||||
static const unsigned int spacemit_gpio_k3_offsets[] = {
|
||||
[SPACEMIT_GPLR] = 0x0,
|
||||
[SPACEMIT_GPDR] = 0x4,
|
||||
[SPACEMIT_GPSR] = 0x8,
|
||||
[SPACEMIT_GPCR] = 0xc,
|
||||
[SPACEMIT_GRER] = 0x10,
|
||||
[SPACEMIT_GFER] = 0x14,
|
||||
[SPACEMIT_GEDR] = 0x18,
|
||||
[SPACEMIT_GSDR] = 0x1c,
|
||||
[SPACEMIT_GCDR] = 0x20,
|
||||
[SPACEMIT_GSRER] = 0x24,
|
||||
[SPACEMIT_GCRER] = 0x28,
|
||||
[SPACEMIT_GSFER] = 0x2c,
|
||||
[SPACEMIT_GCFER] = 0x30,
|
||||
[SPACEMIT_GAPMASK] = 0x34,
|
||||
[SPACEMIT_GCPMASK] = 0x38,
|
||||
};
|
||||
|
||||
static const struct spacemit_gpio_data k1_gpio_data = {
|
||||
.offsets = spacemit_gpio_k1_offsets,
|
||||
.bank_offsets = { 0x0, 0x4, 0x8, 0x100 },
|
||||
};
|
||||
|
||||
static const struct spacemit_gpio_data k3_gpio_data = {
|
||||
.offsets = spacemit_gpio_k3_offsets,
|
||||
.bank_offsets = { 0x0, 0x40, 0x80, 0x100 },
|
||||
};
|
||||
|
||||
static const struct of_device_id spacemit_gpio_dt_ids[] = {
|
||||
{ .compatible = "spacemit,k1-gpio" },
|
||||
{ .compatible = "spacemit,k1-gpio", .data = &k1_gpio_data },
|
||||
{ .compatible = "spacemit,k3-gpio", .data = &k3_gpio_data },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, spacemit_gpio_dt_ids);
|
||||
|
|
@ -296,12 +364,12 @@ MODULE_DEVICE_TABLE(of, spacemit_gpio_dt_ids);
|
|||
static struct platform_driver spacemit_gpio_driver = {
|
||||
.probe = spacemit_gpio_probe,
|
||||
.driver = {
|
||||
.name = "k1-gpio",
|
||||
.name = "spacemit-gpio",
|
||||
.of_match_table = spacemit_gpio_dt_ids,
|
||||
},
|
||||
};
|
||||
module_platform_driver(spacemit_gpio_driver);
|
||||
|
||||
MODULE_AUTHOR("Yixun Lan <dlan@gentoo.org>");
|
||||
MODULE_DESCRIPTION("GPIO driver for SpacemiT K1 SoC");
|
||||
MODULE_DESCRIPTION("GPIO driver for SpacemiT K1/K3 SoC");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2016-2025 NVIDIA Corporation
|
||||
* Copyright (c) 2016-2026 NVIDIA Corporation
|
||||
*
|
||||
* Author: Thierry Reding <treding@nvidia.com>
|
||||
* Dipen Patel <dpatel@nvidia.com>
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
#include <dt-bindings/gpio/tegra234-gpio.h>
|
||||
#include <dt-bindings/gpio/tegra241-gpio.h>
|
||||
#include <dt-bindings/gpio/tegra256-gpio.h>
|
||||
#include <dt-bindings/gpio/nvidia,tegra264-gpio.h>
|
||||
|
||||
/* security registers */
|
||||
#define TEGRA186_GPIO_CTL_SCR 0x0c
|
||||
|
|
@ -1001,7 +1002,9 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
|
|||
if (gpio->soc->num_irqs_per_bank > 1)
|
||||
tegra186_gpio_init_route_mapping(gpio);
|
||||
|
||||
np = of_find_matching_node(NULL, tegra186_pmc_of_match);
|
||||
np = of_parse_phandle(pdev->dev.of_node, "wakeup-parent", 0);
|
||||
if (!np)
|
||||
np = of_find_matching_node(NULL, tegra186_pmc_of_match);
|
||||
if (np) {
|
||||
if (of_device_is_available(np)) {
|
||||
irq->parent_domain = irq_find_host(np);
|
||||
|
|
@ -1277,6 +1280,80 @@ static const struct tegra_gpio_soc tegra241_aon_soc = {
|
|||
.has_vm_support = false,
|
||||
};
|
||||
|
||||
#define TEGRA264_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
TEGRA_GPIO_PORT(TEGRA264_MAIN, _name, _bank, _port, _pins)
|
||||
|
||||
static const struct tegra_gpio_port tegra264_main_ports[] = {
|
||||
TEGRA264_MAIN_GPIO_PORT(F, 3, 0, 8),
|
||||
TEGRA264_MAIN_GPIO_PORT(G, 3, 1, 5),
|
||||
TEGRA264_MAIN_GPIO_PORT(H, 1, 0, 8),
|
||||
TEGRA264_MAIN_GPIO_PORT(J, 1, 1, 8),
|
||||
TEGRA264_MAIN_GPIO_PORT(K, 1, 2, 8),
|
||||
TEGRA264_MAIN_GPIO_PORT(L, 1, 3, 8),
|
||||
TEGRA264_MAIN_GPIO_PORT(M, 1, 4, 6),
|
||||
TEGRA264_MAIN_GPIO_PORT(P, 2, 0, 8),
|
||||
TEGRA264_MAIN_GPIO_PORT(Q, 2, 1, 8),
|
||||
TEGRA264_MAIN_GPIO_PORT(R, 2, 2, 8),
|
||||
TEGRA264_MAIN_GPIO_PORT(S, 2, 3, 2),
|
||||
TEGRA264_MAIN_GPIO_PORT(T, 0, 0, 7),
|
||||
TEGRA264_MAIN_GPIO_PORT(U, 0, 1, 8),
|
||||
TEGRA264_MAIN_GPIO_PORT(V, 0, 2, 8),
|
||||
TEGRA264_MAIN_GPIO_PORT(W, 0, 3, 8),
|
||||
TEGRA264_MAIN_GPIO_PORT(X, 0, 7, 6),
|
||||
TEGRA264_MAIN_GPIO_PORT(Y, 0, 5, 8),
|
||||
TEGRA264_MAIN_GPIO_PORT(Z, 0, 6, 8),
|
||||
TEGRA264_MAIN_GPIO_PORT(AL, 0, 4, 3),
|
||||
};
|
||||
|
||||
static const struct tegra_gpio_soc tegra264_main_soc = {
|
||||
.num_ports = ARRAY_SIZE(tegra264_main_ports),
|
||||
.ports = tegra264_main_ports,
|
||||
.name = "tegra264-gpio",
|
||||
.instance = 0,
|
||||
.num_irqs_per_bank = 8,
|
||||
.has_vm_support = true,
|
||||
};
|
||||
|
||||
#define TEGRA264_AON_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
TEGRA_GPIO_PORT(TEGRA264_AON, _name, _bank, _port, _pins)
|
||||
|
||||
static const struct tegra_gpio_port tegra264_aon_ports[] = {
|
||||
TEGRA264_AON_GPIO_PORT(AA, 0, 0, 8),
|
||||
TEGRA264_AON_GPIO_PORT(BB, 0, 1, 2),
|
||||
TEGRA264_AON_GPIO_PORT(CC, 0, 2, 8),
|
||||
TEGRA264_AON_GPIO_PORT(DD, 0, 3, 8),
|
||||
TEGRA264_AON_GPIO_PORT(EE, 0, 4, 4)
|
||||
};
|
||||
|
||||
static const struct tegra_gpio_soc tegra264_aon_soc = {
|
||||
.num_ports = ARRAY_SIZE(tegra264_aon_ports),
|
||||
.ports = tegra264_aon_ports,
|
||||
.name = "tegra264-gpio-aon",
|
||||
.instance = 1,
|
||||
.num_irqs_per_bank = 8,
|
||||
.has_vm_support = true,
|
||||
};
|
||||
|
||||
#define TEGRA264_UPHY_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
TEGRA_GPIO_PORT(TEGRA264_UPHY, _name, _bank, _port, _pins)
|
||||
|
||||
static const struct tegra_gpio_port tegra264_uphy_ports[] = {
|
||||
TEGRA264_UPHY_GPIO_PORT(A, 0, 0, 6),
|
||||
TEGRA264_UPHY_GPIO_PORT(B, 0, 1, 8),
|
||||
TEGRA264_UPHY_GPIO_PORT(C, 0, 2, 3),
|
||||
TEGRA264_UPHY_GPIO_PORT(D, 1, 0, 8),
|
||||
TEGRA264_UPHY_GPIO_PORT(E, 1, 1, 4),
|
||||
};
|
||||
|
||||
static const struct tegra_gpio_soc tegra264_uphy_soc = {
|
||||
.num_ports = ARRAY_SIZE(tegra264_uphy_ports),
|
||||
.ports = tegra264_uphy_ports,
|
||||
.name = "tegra264-gpio-uphy",
|
||||
.instance = 2,
|
||||
.num_irqs_per_bank = 8,
|
||||
.has_vm_support = true,
|
||||
};
|
||||
|
||||
#define TEGRA256_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
|
||||
TEGRA_GPIO_PORT(TEGRA256_MAIN, _name, _bank, _port, _pins)
|
||||
|
||||
|
|
@ -1368,6 +1445,15 @@ static const struct of_device_id tegra186_gpio_of_match[] = {
|
|||
}, {
|
||||
.compatible = "nvidia,tegra256-gpio",
|
||||
.data = &tegra256_main_soc
|
||||
}, {
|
||||
.compatible = "nvidia,tegra264-gpio",
|
||||
.data = &tegra264_main_soc
|
||||
}, {
|
||||
.compatible = "nvidia,tegra264-gpio-aon",
|
||||
.data = &tegra264_aon_soc
|
||||
}, {
|
||||
.compatible = "nvidia,tegra264-gpio-uphy",
|
||||
.data = &tegra264_uphy_soc
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1631,7 +1631,7 @@ static void gpio_virtuser_lookup_config_group_release(struct config_item *item)
|
|||
kfree(lookup);
|
||||
}
|
||||
|
||||
static struct configfs_item_operations gpio_virtuser_lookup_config_item_ops = {
|
||||
static const struct configfs_item_operations gpio_virtuser_lookup_config_item_ops = {
|
||||
.release = gpio_virtuser_lookup_config_group_release,
|
||||
};
|
||||
|
||||
|
|
@ -1692,11 +1692,11 @@ static void gpio_virtuser_device_config_group_release(struct config_item *item)
|
|||
kfree(dev);
|
||||
}
|
||||
|
||||
static struct configfs_item_operations gpio_virtuser_device_config_item_ops = {
|
||||
static const struct configfs_item_operations gpio_virtuser_device_config_item_ops = {
|
||||
.release = gpio_virtuser_device_config_group_release,
|
||||
};
|
||||
|
||||
static struct configfs_group_operations gpio_virtuser_device_config_group_ops = {
|
||||
static const struct configfs_group_operations gpio_virtuser_device_config_group_ops = {
|
||||
.make_group = gpio_virtuser_make_lookup_group,
|
||||
};
|
||||
|
||||
|
|
@ -1729,7 +1729,7 @@ gpio_virtuser_config_make_device_group(struct config_group *group,
|
|||
return &no_free_ptr(dev)->group;
|
||||
}
|
||||
|
||||
static struct configfs_group_operations gpio_virtuser_config_group_ops = {
|
||||
static const struct configfs_group_operations gpio_virtuser_config_group_ops = {
|
||||
.make_group = gpio_virtuser_config_make_device_group,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -903,18 +903,16 @@ static int zynq_gpio_probe(struct platform_device *pdev)
|
|||
struct zynq_gpio *gpio;
|
||||
struct gpio_chip *chip;
|
||||
struct gpio_irq_chip *girq;
|
||||
const struct of_device_id *match;
|
||||
|
||||
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
|
||||
if (!gpio)
|
||||
return -ENOMEM;
|
||||
|
||||
match = of_match_node(zynq_gpio_of_match, pdev->dev.of_node);
|
||||
if (!match) {
|
||||
dev_err(&pdev->dev, "of_match_node() failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
gpio->p_data = match->data;
|
||||
gpio->p_data = device_get_match_data(&pdev->dev);
|
||||
if (!gpio->p_data)
|
||||
return dev_err_probe(&pdev->dev, -EINVAL,
|
||||
"device_get_match_data() failed\n");
|
||||
|
||||
platform_set_drvdata(pdev, gpio);
|
||||
|
||||
gpio->base_addr = devm_platform_ioremap_resource(pdev, 0);
|
||||
|
|
|
|||
|
|
@ -634,6 +634,7 @@ static struct gpio_desc *of_find_gpio_rename(struct device_node *np,
|
|||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_MT2701_CS42448)
|
||||
static struct gpio_desc *of_find_mt2701_gpio(struct device_node *np,
|
||||
const char *con_id,
|
||||
unsigned int idx,
|
||||
|
|
@ -665,6 +666,7 @@ static struct gpio_desc *of_find_mt2701_gpio(struct device_node *np,
|
|||
|
||||
return desc;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Trigger sources are special, they allow us to use any GPIO as a LED trigger
|
||||
|
|
@ -699,7 +701,9 @@ typedef struct gpio_desc *(*of_find_gpio_quirk)(struct device_node *np,
|
|||
enum of_gpio_flags *of_flags);
|
||||
static const of_find_gpio_quirk of_find_gpio_quirks[] = {
|
||||
of_find_gpio_rename,
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_MT2701_CS42448)
|
||||
of_find_mt2701_gpio,
|
||||
#endif
|
||||
of_find_trigger_gpio,
|
||||
NULL
|
||||
};
|
||||
|
|
|
|||
|
|
@ -455,12 +455,7 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, const char *con_id,
|
|||
list_for_each_entry(ref, &entry->refs, list) {
|
||||
guard(mutex)(&ref->lock);
|
||||
|
||||
/*
|
||||
* FIXME: use device_is_compatible() once the reset-gpio
|
||||
* drivers gains a compatible string which it currently
|
||||
* does not have.
|
||||
*/
|
||||
if (!ref->fwnode && strstarts(dev_name(consumer), "reset.gpio.")) {
|
||||
if (!ref->fwnode && device_is_compatible(consumer, "reset-gpio")) {
|
||||
if (!gpio_shared_dev_is_reset_gpio(consumer, entry, ref))
|
||||
continue;
|
||||
} else if (!device_match_fwnode(consumer, ref->fwnode)) {
|
||||
|
|
|
|||
|
|
@ -18,19 +18,18 @@
|
|||
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/gpio/property.h>
|
||||
|
||||
#include "gpiolib.h"
|
||||
#include "gpiolib-swnode.h"
|
||||
|
||||
#define GPIOLIB_SWNODE_UNDEFINED_NAME "swnode-gpio-undefined"
|
||||
|
||||
static struct gpio_device *swnode_get_gpio_device(struct fwnode_handle *fwnode)
|
||||
{
|
||||
const struct software_node *gdev_node;
|
||||
struct gpio_device *gdev;
|
||||
|
||||
gdev_node = to_software_node(fwnode);
|
||||
if (!gdev_node || !gdev_node->name)
|
||||
if (!gdev_node)
|
||||
goto fwnode_lookup;
|
||||
|
||||
/*
|
||||
|
|
@ -38,7 +37,7 @@ static struct gpio_device *swnode_get_gpio_device(struct fwnode_handle *fwnode)
|
|||
* primarily used as a key for internal chip selects in SPI bindings.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_GPIO_SWNODE_UNDEFINED) &&
|
||||
!strcmp(gdev_node->name, GPIOLIB_SWNODE_UNDEFINED_NAME))
|
||||
gdev_node == &swnode_gpio_undefined)
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
fwnode_lookup:
|
||||
|
|
@ -140,7 +139,7 @@ int swnode_gpio_count(const struct fwnode_handle *fwnode, const char *con_id)
|
|||
* a key for internal chip selects in SPI bindings.
|
||||
*/
|
||||
const struct software_node swnode_gpio_undefined = {
|
||||
.name = GPIOLIB_SWNODE_UNDEFINED_NAME,
|
||||
.name = "swnode-gpio-undefined",
|
||||
};
|
||||
EXPORT_SYMBOL_NS_GPL(swnode_gpio_undefined, "GPIO_SWNODE");
|
||||
|
||||
|
|
|
|||
|
|
@ -5261,27 +5261,21 @@ void gpiod_put_array(struct gpio_descs *descs)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(gpiod_put_array);
|
||||
|
||||
static int gpio_stub_drv_probe(struct device *dev)
|
||||
{
|
||||
/*
|
||||
* The DT node of some GPIO chips have a "compatible" property, but
|
||||
* never have a struct device added and probed by a driver to register
|
||||
* the GPIO chip with gpiolib. In such cases, fw_devlink=on will cause
|
||||
* the consumers of the GPIO chip to get probe deferred forever because
|
||||
* they will be waiting for a device associated with the GPIO chip
|
||||
* firmware node to get added and bound to a driver.
|
||||
*
|
||||
* To allow these consumers to probe, we associate the struct
|
||||
* gpio_device of the GPIO chip with the firmware node and then simply
|
||||
* bind it to this stub driver.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The DT node of some GPIO chips have a "compatible" property, but
|
||||
* never have a struct device added and probed by a driver to register
|
||||
* the GPIO chip with gpiolib. In such cases, fw_devlink=on will cause
|
||||
* the consumers of the GPIO chip to get probe deferred forever because
|
||||
* they will be waiting for a device associated with the GPIO chip
|
||||
* firmware node to get added and bound to a driver.
|
||||
*
|
||||
* To allow these consumers to probe, we associate the struct
|
||||
* gpio_device of the GPIO chip with the firmware node and then simply
|
||||
* bind it to this stub driver.
|
||||
*/
|
||||
static struct device_driver gpio_stub_drv = {
|
||||
.name = "gpio_stub_drv",
|
||||
.bus = &gpio_bus_type,
|
||||
.probe = gpio_stub_drv_probe,
|
||||
};
|
||||
|
||||
static int __init gpiolib_dev_init(void)
|
||||
|
|
|
|||
|
|
@ -2217,20 +2217,22 @@ config MFD_ROHM_BD718XX
|
|||
and emergency shut down as well as 32,768KHz clock output.
|
||||
|
||||
config MFD_ROHM_BD71828
|
||||
tristate "ROHM BD71828 and BD71815 Power Management IC"
|
||||
tristate "ROHM BD718[15/28/79], BD72720 and BD73900 PMICs"
|
||||
depends on I2C=y
|
||||
depends on OF
|
||||
select REGMAP_I2C
|
||||
select REGMAP_IRQ
|
||||
select MFD_CORE
|
||||
help
|
||||
Select this option to get support for the ROHM BD71828 and BD71815
|
||||
Power Management ICs. BD71828GW and BD71815AGW are single-chip power
|
||||
management ICs mainly for battery-powered portable devices.
|
||||
The BD71828 integrates 7 buck converters and 7 LDOs. The BD71815
|
||||
has 5 bucks, 7 LDOs, and a boost for driving LEDs. Both ICs provide
|
||||
also a single-cell linear charger, a Coulomb counter, a real-time
|
||||
clock (RTC), GPIOs and a 32.768 kHz clock gate.
|
||||
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.
|
||||
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.
|
||||
|
||||
config MFD_ROHM_BD957XMUF
|
||||
tristate "ROHM BD9576MUF and BD9573MUF Power Management ICs"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
//
|
||||
// Copyright (C) 2019 ROHM Semiconductors
|
||||
//
|
||||
// ROHM BD71828/BD71815 PMIC driver
|
||||
/*
|
||||
* Copyright (C) 2019 ROHM Semiconductors
|
||||
*
|
||||
* ROHM BD718[15/28/79] and BD72720 PMIC driver
|
||||
*/
|
||||
|
||||
#include <linux/gpio_keys.h>
|
||||
#include <linux/i2c.h>
|
||||
|
|
@ -13,12 +14,29 @@
|
|||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/rohm-bd71815.h>
|
||||
#include <linux/mfd/rohm-bd71828.h>
|
||||
#include <linux/mfd/rohm-bd72720.h>
|
||||
#include <linux/mfd/rohm-generic.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define BD72720_TYPED_IRQ_REG(_irq, _stat_offset, _mask, _type_offset) \
|
||||
[_irq] = { \
|
||||
.reg_offset = (_stat_offset), \
|
||||
.mask = (_mask), \
|
||||
{ \
|
||||
.type_reg_offset = (_type_offset), \
|
||||
.type_reg_mask = BD72720_GPIO_IRQ_TYPE_MASK, \
|
||||
.type_rising_val = BD72720_GPIO_IRQ_TYPE_RISING, \
|
||||
.type_falling_val = BD72720_GPIO_IRQ_TYPE_FALLING, \
|
||||
.type_level_low_val = BD72720_GPIO_IRQ_TYPE_LOW, \
|
||||
.type_level_high_val = BD72720_GPIO_IRQ_TYPE_HIGH, \
|
||||
.types_supported = IRQ_TYPE_EDGE_BOTH | \
|
||||
IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW, \
|
||||
}, \
|
||||
}
|
||||
|
||||
static struct gpio_keys_button button = {
|
||||
.code = KEY_POWER,
|
||||
.gpio = -1,
|
||||
|
|
@ -43,6 +61,12 @@ static const struct resource bd71828_rtc_irqs[] = {
|
|||
DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC2, "bd70528-rtc-alm-2"),
|
||||
};
|
||||
|
||||
static const struct resource bd72720_rtc_irqs[] = {
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_RTC0, "bd70528-rtc-alm-0"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_RTC1, "bd70528-rtc-alm-1"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_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"),
|
||||
|
|
@ -156,56 +180,181 @@ static struct mfd_cell bd71828_mfd_cells[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static const struct regmap_range bd71815_volatile_ranges[] = {
|
||||
static const struct resource bd72720_power_irqs[] = {
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_VBUS_RMV, "bd72720_int_vbus_rmv"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_VBUS_DET, "bd72720_int_vbus_det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_VBUS_MON_RES, "bd72720_int_vbus_mon_res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_VBUS_MON_DET, "bd72720_int_vbus_mon_det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_VSYS_MON_RES, "bd72720_int_vsys_mon_res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_VSYS_MON_DET, "bd72720_int_vsys_mon_det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_VSYS_UV_RES, "bd72720_int_vsys_uv_res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_VSYS_UV_DET, "bd72720_int_vsys_uv_det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_VSYS_LO_RES, "bd72720_int_vsys_lo_res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_VSYS_LO_DET, "bd72720_int_vsys_lo_det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_VSYS_OV_RES, "bd72720_int_vsys_ov_res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_VSYS_OV_DET, "bd72720_int_vsys_ov_det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_BAT_ILIM, "bd72720_int_bat_ilim"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_CHG_DONE, "bd72720_int_chg_done"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_EXTEMP_TOUT, "bd72720_int_extemp_tout"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_CHG_WDT_EXP, "bd72720_int_chg_wdt_exp"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_BAT_MNT_OUT, "bd72720_int_bat_mnt_out"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_BAT_MNT_IN, "bd72720_int_bat_mnt_in"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_CHG_TRNS, "bd72720_int_chg_trns"),
|
||||
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_VBAT_MON_RES, "bd72720_int_vbat_mon_res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_VBAT_MON_DET, "bd72720_int_vbat_mon_det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_VBAT_SHT_RES, "bd72720_int_vbat_sht_res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_VBAT_SHT_DET, "bd72720_int_vbat_sht_det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_VBAT_LO_RES, "bd72720_int_vbat_lo_res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_VBAT_LO_DET, "bd72720_int_vbat_lo_det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_VBAT_OV_RES, "bd72720_int_vbat_ov_res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_VBAT_OV_DET, "bd72720_int_vbat_ov_det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_BAT_RMV, "bd72720_int_bat_rmv"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_BAT_DET, "bd72720_int_bat_det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_DBAT_DET, "bd72720_int_dbat_det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_BAT_TEMP_TRNS, "bd72720_int_bat_temp_trns"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_LOBTMP_RES, "bd72720_int_lobtmp_res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_LOBTMP_DET, "bd72720_int_lobtmp_det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_OVBTMP_RES, "bd72720_int_ovbtmp_res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_OVBTMP_DET, "bd72720_int_ovbtmp_det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_OCUR1_RES, "bd72720_int_ocur1_res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_OCUR1_DET, "bd72720_int_ocur1_det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_OCUR2_RES, "bd72720_int_ocur2_res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_OCUR2_DET, "bd72720_int_ocur2_det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_OCUR3_RES, "bd72720_int_ocur3_res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_OCUR3_DET, "bd72720_int_ocur3_det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_CC_MON1_DET, "bd72720_int_cc_mon1_det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_CC_MON2_DET, "bd72720_int_cc_mon2_det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD72720_INT_CC_MON3_DET, "bd72720_int_cc_mon3_det"),
|
||||
};
|
||||
|
||||
static const struct mfd_cell bd72720_mfd_cells[] = {
|
||||
{ .name = "bd72720-pmic", },
|
||||
{ .name = "bd72720-gpio", },
|
||||
{ .name = "bd72720-led", },
|
||||
{ .name = "bd72720-clk", },
|
||||
{
|
||||
.range_min = BD71815_REG_SEC,
|
||||
.range_max = BD71815_REG_YEAR,
|
||||
.name = "bd72720-power",
|
||||
.resources = bd72720_power_irqs,
|
||||
.num_resources = ARRAY_SIZE(bd72720_power_irqs),
|
||||
}, {
|
||||
.range_min = BD71815_REG_CONF,
|
||||
.range_max = BD71815_REG_BAT_TEMP,
|
||||
.name = "bd72720-rtc",
|
||||
.resources = bd72720_rtc_irqs,
|
||||
.num_resources = ARRAY_SIZE(bd72720_rtc_irqs),
|
||||
}, {
|
||||
.range_min = BD71815_REG_VM_IBAT_U,
|
||||
.range_max = BD71815_REG_CC_CTRL,
|
||||
}, {
|
||||
.range_min = BD71815_REG_CC_STAT,
|
||||
.range_max = BD71815_REG_CC_CURCD_L,
|
||||
}, {
|
||||
.range_min = BD71815_REG_VM_BTMP_MON,
|
||||
.range_max = BD71815_REG_VM_BTMP_MON,
|
||||
}, {
|
||||
.range_min = BD71815_REG_INT_STAT,
|
||||
.range_max = BD71815_REG_INT_UPDATE,
|
||||
}, {
|
||||
.range_min = BD71815_REG_VM_VSYS_U,
|
||||
.range_max = BD71815_REG_REX_CTRL_1,
|
||||
}, {
|
||||
.range_min = BD71815_REG_FULL_CCNTD_3,
|
||||
.range_max = BD71815_REG_CCNTD_CHG_2,
|
||||
.name = "gpio-keys",
|
||||
.platform_data = &bd71828_powerkey_data,
|
||||
.pdata_size = sizeof(bd71828_powerkey_data),
|
||||
},
|
||||
};
|
||||
|
||||
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),
|
||||
regmap_reg_range(BD71815_REG_VM_IBAT_U, BD71815_REG_CC_CTRL),
|
||||
regmap_reg_range(BD71815_REG_CC_STAT, BD71815_REG_CC_CURCD_L),
|
||||
regmap_reg_range(BD71815_REG_VM_BTMP_MON, BD71815_REG_VM_BTMP_MON),
|
||||
regmap_reg_range(BD71815_REG_INT_STAT, BD71815_REG_INT_UPDATE),
|
||||
regmap_reg_range(BD71815_REG_VM_VSYS_U, BD71815_REG_REX_CTRL_1),
|
||||
regmap_reg_range(BD71815_REG_FULL_CCNTD_3, BD71815_REG_CCNTD_CHG_2),
|
||||
};
|
||||
|
||||
static const struct regmap_range bd71828_volatile_ranges[] = {
|
||||
{
|
||||
.range_min = BD71828_REG_PS_CTRL_1,
|
||||
.range_max = BD71828_REG_PS_CTRL_1,
|
||||
}, {
|
||||
.range_min = BD71828_REG_PS_CTRL_3,
|
||||
.range_max = BD71828_REG_PS_CTRL_3,
|
||||
}, {
|
||||
.range_min = BD71828_REG_RTC_SEC,
|
||||
.range_max = BD71828_REG_RTC_YEAR,
|
||||
}, {
|
||||
/*
|
||||
* For now make all charger registers volatile because many
|
||||
* needs to be and because the charger block is not that
|
||||
* performance critical.
|
||||
*/
|
||||
.range_min = BD71828_REG_CHG_STATE,
|
||||
.range_max = BD71828_REG_CHG_FULL,
|
||||
}, {
|
||||
.range_min = BD71828_REG_INT_MAIN,
|
||||
.range_max = BD71828_REG_IO_STAT,
|
||||
},
|
||||
regmap_reg_range(BD71828_REG_PS_CTRL_1, BD71828_REG_PS_CTRL_1),
|
||||
regmap_reg_range(BD71828_REG_PS_CTRL_3, BD71828_REG_PS_CTRL_3),
|
||||
regmap_reg_range(BD71828_REG_RTC_SEC, BD71828_REG_RTC_YEAR),
|
||||
/*
|
||||
* For now make all charger registers volatile because many
|
||||
* needs to be and because the charger block is not that
|
||||
* performance critical.
|
||||
*/
|
||||
regmap_reg_range(BD71828_REG_CHG_STATE, BD71828_REG_CHG_FULL),
|
||||
regmap_reg_range(BD71828_REG_INT_MAIN, BD71828_REG_IO_STAT),
|
||||
};
|
||||
|
||||
static const struct regmap_range bd72720_volatile_ranges_4b[] = {
|
||||
regmap_reg_range(BD72720_REG_RESETSRC_1, BD72720_REG_RESETSRC_2),
|
||||
regmap_reg_range(BD72720_REG_POWER_STATE, BD72720_REG_POWER_STATE),
|
||||
/* The state indicator bit changes when new state is reached */
|
||||
regmap_reg_range(BD72720_REG_PS_CTRL_1, BD72720_REG_PS_CTRL_1),
|
||||
regmap_reg_range(BD72720_REG_RCVNUM, BD72720_REG_RCVNUM),
|
||||
regmap_reg_range(BD72720_REG_CONF, BD72720_REG_HALL_STAT),
|
||||
regmap_reg_range(BD72720_REG_RTC_SEC, BD72720_REG_RTC_YEAR),
|
||||
regmap_reg_range(BD72720_REG_INT_LVL1_STAT, BD72720_REG_INT_ETC2_SRC),
|
||||
};
|
||||
|
||||
static const struct regmap_range bd72720_precious_ranges_4b[] = {
|
||||
regmap_reg_range(BD72720_REG_INT_LVL1_STAT, BD72720_REG_INT_ETC2_STAT),
|
||||
};
|
||||
|
||||
/*
|
||||
* The BD72720 is an odd beast in that it contains two separate sets of
|
||||
* registers, both starting from address 0x0. The twist is that these "pages"
|
||||
* are behind different I2C slave addresses. Most of the registers are behind
|
||||
* a slave address 0x4b, which will be used as the "main" address for this
|
||||
* device.
|
||||
*
|
||||
* Most of the charger related registers are located behind slave address 0x4c.
|
||||
* It is tempting to push the dealing with the charger registers and the extra
|
||||
* 0x4c device in power-supply driver - but perhaps it's better for the sake of
|
||||
* the cleaner re-use to deal with setting up all of the regmaps here.
|
||||
* Furthermore, the LED stuff may need access to both of these devices.
|
||||
*
|
||||
* Instead of providing one of the regmaps to sub-devices in MFD platform data,
|
||||
* we create one more 'wrapper regmap' with custom read/write operations. These
|
||||
* custom accessors will select which of the 'real' regmaps to use, based on
|
||||
* the register address.
|
||||
*
|
||||
* The register addresses are 8-bit, so we add offset 0x100 to the addresses
|
||||
* behind the secondary slave 0x4c. The 'wrapper' regmap can then detect the
|
||||
* correct slave address based on the register address and call regmap_write()
|
||||
* and regmap_read() using correct 'real' regmap. This way the registers of
|
||||
* both of the slaves can be accessed using one 'wrapper' regmap.
|
||||
*
|
||||
* NOTE: The added offsets mean that the defined addresses for slave 0x4c must
|
||||
* be used through the 'wrapper' regmap because the offset must be stripped
|
||||
* from the register addresses. The 0x4b can be accessed both indirectly using
|
||||
* the 'wrapper' regmap, and directly using the 'real' regmap.
|
||||
*/
|
||||
#define BD72720_SECONDARY_I2C_SLAVE 0x4c
|
||||
#define BD72720_SECONDARY_I2C_REG_OFFSET 0x100
|
||||
|
||||
struct bd72720_regmaps {
|
||||
struct regmap *map1_4b;
|
||||
struct regmap *map2_4c;
|
||||
};
|
||||
|
||||
/* Translate the slave 0x4c wrapper register address to a real one */
|
||||
#define BD72720_REG_UNWRAP(reg) ((reg) - BD72720_SECONDARY_I2C_REG_OFFSET)
|
||||
|
||||
/* Ranges given to 'real' 0x4c regmap must use unwrapped addresses. */
|
||||
#define BD72720_UNWRAP_REG_RANGE(startreg, endreg) \
|
||||
regmap_reg_range(BD72720_REG_UNWRAP(startreg), BD72720_REG_UNWRAP(endreg))
|
||||
|
||||
static const struct regmap_range bd72720_volatile_ranges_4c[] = {
|
||||
/* Status information */
|
||||
BD72720_UNWRAP_REG_RANGE(BD72720_REG_CHG_STATE, BD72720_REG_CHG_EN),
|
||||
/*
|
||||
* Under certain circumstances, write to some bits may be
|
||||
* ignored
|
||||
*/
|
||||
BD72720_UNWRAP_REG_RANGE(BD72720_REG_CHG_CTRL, BD72720_REG_CHG_CTRL),
|
||||
/*
|
||||
* TODO: Ensure this is used to advertise state, not (only?) to
|
||||
* control it.
|
||||
*/
|
||||
BD72720_UNWRAP_REG_RANGE(BD72720_REG_VSYS_STATE_STAT, BD72720_REG_VSYS_STATE_STAT),
|
||||
/* Measured data */
|
||||
BD72720_UNWRAP_REG_RANGE(BD72720_REG_VM_VBAT_U, BD72720_REG_VM_VF_L),
|
||||
/* Self clearing bits */
|
||||
BD72720_UNWRAP_REG_RANGE(BD72720_REG_VM_VSYS_SA_MINMAX_CTRL,
|
||||
BD72720_REG_VM_VSYS_SA_MINMAX_CTRL),
|
||||
/* Counters, self clearing bits */
|
||||
BD72720_UNWRAP_REG_RANGE(BD72720_REG_CC_CURCD_U, BD72720_REG_CC_CTRL),
|
||||
/* Self clearing bits */
|
||||
BD72720_UNWRAP_REG_RANGE(BD72720_REG_CC_CCNTD_CTRL, BD72720_REG_CC_CCNTD_CTRL),
|
||||
/* Self clearing bits */
|
||||
BD72720_UNWRAP_REG_RANGE(BD72720_REG_IMPCHK_CTRL, BD72720_REG_IMPCHK_CTRL),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table bd71815_volatile_regs = {
|
||||
|
|
@ -218,6 +367,21 @@ static const struct regmap_access_table bd71828_volatile_regs = {
|
|||
.n_yes_ranges = ARRAY_SIZE(bd71828_volatile_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table bd72720_volatile_regs_4b = {
|
||||
.yes_ranges = &bd72720_volatile_ranges_4b[0],
|
||||
.n_yes_ranges = ARRAY_SIZE(bd72720_volatile_ranges_4b),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table bd72720_precious_regs_4b = {
|
||||
.yes_ranges = &bd72720_precious_ranges_4b[0],
|
||||
.n_yes_ranges = ARRAY_SIZE(bd72720_precious_ranges_4b),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table bd72720_volatile_regs_4c = {
|
||||
.yes_ranges = &bd72720_volatile_ranges_4c[0],
|
||||
.n_yes_ranges = ARRAY_SIZE(bd72720_volatile_ranges_4c),
|
||||
};
|
||||
|
||||
static const struct regmap_config bd71815_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
|
@ -234,10 +398,79 @@ static const struct regmap_config bd71828_regmap = {
|
|||
.cache_type = REGCACHE_MAPLE,
|
||||
};
|
||||
|
||||
static int regmap_write_wrapper(void *context, unsigned int reg, unsigned int val)
|
||||
{
|
||||
struct bd72720_regmaps *maps = context;
|
||||
|
||||
if (reg < BD72720_SECONDARY_I2C_REG_OFFSET)
|
||||
return regmap_write(maps->map1_4b, reg, val);
|
||||
|
||||
reg = BD72720_REG_UNWRAP(reg);
|
||||
|
||||
return regmap_write(maps->map2_4c, reg, val);
|
||||
}
|
||||
|
||||
static int regmap_read_wrapper(void *context, unsigned int reg, unsigned int *val)
|
||||
{
|
||||
struct bd72720_regmaps *maps = context;
|
||||
|
||||
if (reg < BD72720_SECONDARY_I2C_REG_OFFSET)
|
||||
return regmap_read(maps->map1_4b, reg, val);
|
||||
|
||||
reg = BD72720_REG_UNWRAP(reg);
|
||||
|
||||
return regmap_read(maps->map2_4c, reg, val);
|
||||
}
|
||||
|
||||
static const struct regmap_config bd72720_wrapper_map_config = {
|
||||
.name = "wrap-map",
|
||||
.reg_bits = 9,
|
||||
.val_bits = 8,
|
||||
.max_register = BD72720_REG_IMPCHK_CTRL,
|
||||
/*
|
||||
* We don't want to duplicate caches. It would be a bit faster to
|
||||
* have the cache in this 'wrapper regmap', and not in the 'real
|
||||
* regmaps' bd72720_regmap_4b and bd72720_regmap_4c below. This would
|
||||
* require all the subdevices to use the wrapper-map in order to be
|
||||
* able to benefit from the cache.
|
||||
* Currently most of the sub-devices use only the same slave-address
|
||||
* as this MFD driver. Now, because we don't add the offset to the
|
||||
* registers belonging to this slave, those devices can use either the
|
||||
* wrapper map, or the bd72720_regmap_4b directly. This means majority
|
||||
* of our sub devices don't need to care which regmap they get using
|
||||
* the dev_get_regmap(). This unifies the code between the BD72720 and
|
||||
* those variants which don't have this 'multiple slave addresses'
|
||||
* -hassle.
|
||||
* So, for a small performance penalty, we simplify the code for the
|
||||
* sub-devices by having the caches in the wrapped regmaps and not here.
|
||||
*/
|
||||
.cache_type = REGCACHE_NONE,
|
||||
.reg_write = regmap_write_wrapper,
|
||||
.reg_read = regmap_read_wrapper,
|
||||
};
|
||||
|
||||
static const struct regmap_config bd72720_regmap_4b = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.volatile_table = &bd72720_volatile_regs_4b,
|
||||
.precious_table = &bd72720_precious_regs_4b,
|
||||
.max_register = BD72720_REG_INT_ETC2_SRC,
|
||||
.cache_type = REGCACHE_MAPLE,
|
||||
};
|
||||
|
||||
static const struct regmap_config bd72720_regmap_4c = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.volatile_table = &bd72720_volatile_regs_4c,
|
||||
.max_register = BD72720_REG_UNWRAP(BD72720_REG_IMPCHK_CTRL),
|
||||
.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
|
||||
* register. BD71815 and BD71828 have same sub-register-block offests.
|
||||
* register. BD71815 and BD71828 have same sub-register-block offests, the
|
||||
* BD72720 has a different one.
|
||||
*/
|
||||
|
||||
static unsigned int bit0_offsets[] = {11}; /* RTC IRQ */
|
||||
|
|
@ -249,6 +482,15 @@ static unsigned int bit5_offsets[] = {3}; /* VSYS IRQ */
|
|||
static unsigned int bit6_offsets[] = {1, 2}; /* DCIN IRQ */
|
||||
static unsigned int bit7_offsets[] = {0}; /* BUCK IRQ */
|
||||
|
||||
static unsigned int bd72720_bit0_offsets[] = {0, 1}; /* PS1 and PS2 */
|
||||
static unsigned int bd72720_bit1_offsets[] = {2, 3}; /* DVS1 and DVS2 */
|
||||
static unsigned int bd72720_bit2_offsets[] = {4}; /* VBUS */
|
||||
static unsigned int bd72720_bit3_offsets[] = {5}; /* VSYS */
|
||||
static unsigned int bd72720_bit4_offsets[] = {6}; /* CHG */
|
||||
static unsigned int bd72720_bit5_offsets[] = {7, 8}; /* BAT1 and BAT2 */
|
||||
static unsigned int bd72720_bit6_offsets[] = {9}; /* IBAT */
|
||||
static unsigned int bd72720_bit7_offsets[] = {10, 11}; /* ETC1 and ETC2 */
|
||||
|
||||
static const struct regmap_irq_sub_irq_map bd718xx_sub_irq_offsets[] = {
|
||||
REGMAP_IRQ_MAIN_REG_OFFSET(bit0_offsets),
|
||||
REGMAP_IRQ_MAIN_REG_OFFSET(bit1_offsets),
|
||||
|
|
@ -260,6 +502,17 @@ static const struct regmap_irq_sub_irq_map bd718xx_sub_irq_offsets[] = {
|
|||
REGMAP_IRQ_MAIN_REG_OFFSET(bit7_offsets),
|
||||
};
|
||||
|
||||
static const struct regmap_irq_sub_irq_map bd72720_sub_irq_offsets[] = {
|
||||
REGMAP_IRQ_MAIN_REG_OFFSET(bd72720_bit0_offsets),
|
||||
REGMAP_IRQ_MAIN_REG_OFFSET(bd72720_bit1_offsets),
|
||||
REGMAP_IRQ_MAIN_REG_OFFSET(bd72720_bit2_offsets),
|
||||
REGMAP_IRQ_MAIN_REG_OFFSET(bd72720_bit3_offsets),
|
||||
REGMAP_IRQ_MAIN_REG_OFFSET(bd72720_bit4_offsets),
|
||||
REGMAP_IRQ_MAIN_REG_OFFSET(bd72720_bit5_offsets),
|
||||
REGMAP_IRQ_MAIN_REG_OFFSET(bd72720_bit6_offsets),
|
||||
REGMAP_IRQ_MAIN_REG_OFFSET(bd72720_bit7_offsets),
|
||||
};
|
||||
|
||||
static const struct regmap_irq bd71815_irqs[] = {
|
||||
REGMAP_IRQ_REG(BD71815_INT_BUCK1_OCP, 0, BD71815_INT_BUCK1_OCP_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_BUCK2_OCP, 0, BD71815_INT_BUCK2_OCP_MASK),
|
||||
|
|
@ -433,6 +686,117 @@ static const struct regmap_irq bd71828_irqs[] = {
|
|||
REGMAP_IRQ_REG(BD71828_INT_RTC2, 11, BD71828_INT_RTC2_MASK),
|
||||
};
|
||||
|
||||
static const struct regmap_irq bd72720_irqs[] = {
|
||||
REGMAP_IRQ_REG(BD72720_INT_LONGPUSH, 0, BD72720_INT_LONGPUSH_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_MIDPUSH, 0, BD72720_INT_MIDPUSH_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_SHORTPUSH, 0, BD72720_INT_SHORTPUSH_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_PUSH, 0, BD72720_INT_PUSH_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_HALL_DET, 0, BD72720_INT_HALL_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_HALL_TGL, 0, BD72720_INT_HALL_TGL_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_WDOG, 0, BD72720_INT_WDOG_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_SWRESET, 0, BD72720_INT_SWRESET_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_SEQ_DONE, 1, BD72720_INT_SEQ_DONE_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_PGFAULT, 1, BD72720_INT_PGFAULT_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_BUCK1_DVS, 2, BD72720_INT_BUCK1_DVS_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_BUCK2_DVS, 2, BD72720_INT_BUCK2_DVS_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_BUCK3_DVS, 2, BD72720_INT_BUCK3_DVS_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_BUCK4_DVS, 2, BD72720_INT_BUCK4_DVS_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_BUCK5_DVS, 2, BD72720_INT_BUCK5_DVS_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_BUCK6_DVS, 2, BD72720_INT_BUCK6_DVS_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_BUCK7_DVS, 2, BD72720_INT_BUCK7_DVS_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_BUCK8_DVS, 2, BD72720_INT_BUCK8_DVS_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_BUCK9_DVS, 3, BD72720_INT_BUCK9_DVS_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_BUCK10_DVS, 3, BD72720_INT_BUCK10_DVS_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_LDO1_DVS, 3, BD72720_INT_LDO1_DVS_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_LDO2_DVS, 3, BD72720_INT_LDO2_DVS_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_LDO3_DVS, 3, BD72720_INT_LDO3_DVS_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_LDO4_DVS, 3, BD72720_INT_LDO4_DVS_MASK),
|
||||
|
||||
REGMAP_IRQ_REG(BD72720_INT_VBUS_RMV, 4, BD72720_INT_VBUS_RMV_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_VBUS_DET, 4, BD72720_INT_VBUS_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_VBUS_MON_RES, 4, BD72720_INT_VBUS_MON_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_VBUS_MON_DET, 4, BD72720_INT_VBUS_MON_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_VSYS_MON_RES, 5, BD72720_INT_VSYS_MON_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_VSYS_MON_DET, 5, BD72720_INT_VSYS_MON_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_VSYS_UV_RES, 5, BD72720_INT_VSYS_UV_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_VSYS_UV_DET, 5, BD72720_INT_VSYS_UV_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_VSYS_LO_RES, 5, BD72720_INT_VSYS_LO_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_VSYS_LO_DET, 5, BD72720_INT_VSYS_LO_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_VSYS_OV_RES, 5, BD72720_INT_VSYS_OV_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_VSYS_OV_DET, 5, BD72720_INT_VSYS_OV_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_BAT_ILIM, 6, BD72720_INT_BAT_ILIM_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_CHG_DONE, 6, BD72720_INT_CHG_DONE_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_EXTEMP_TOUT, 6, BD72720_INT_EXTEMP_TOUT_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_CHG_WDT_EXP, 6, BD72720_INT_CHG_WDT_EXP_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_BAT_MNT_OUT, 6, BD72720_INT_BAT_MNT_OUT_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_BAT_MNT_IN, 6, BD72720_INT_BAT_MNT_IN_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_CHG_TRNS, 6, BD72720_INT_CHG_TRNS_MASK),
|
||||
|
||||
REGMAP_IRQ_REG(BD72720_INT_VBAT_MON_RES, 7, BD72720_INT_VBAT_MON_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_VBAT_MON_DET, 7, BD72720_INT_VBAT_MON_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_VBAT_SHT_RES, 7, BD72720_INT_VBAT_SHT_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_VBAT_SHT_DET, 7, BD72720_INT_VBAT_SHT_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_VBAT_LO_RES, 7, BD72720_INT_VBAT_LO_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_VBAT_LO_DET, 7, BD72720_INT_VBAT_LO_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_VBAT_OV_RES, 7, BD72720_INT_VBAT_OV_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_VBAT_OV_DET, 7, BD72720_INT_VBAT_OV_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_BAT_RMV, 8, BD72720_INT_BAT_RMV_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_BAT_DET, 8, BD72720_INT_BAT_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_DBAT_DET, 8, BD72720_INT_DBAT_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_BAT_TEMP_TRNS, 8, BD72720_INT_BAT_TEMP_TRNS_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_LOBTMP_RES, 8, BD72720_INT_LOBTMP_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_LOBTMP_DET, 8, BD72720_INT_LOBTMP_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_OVBTMP_RES, 8, BD72720_INT_OVBTMP_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_OVBTMP_DET, 8, BD72720_INT_OVBTMP_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_OCUR1_RES, 9, BD72720_INT_OCUR1_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_OCUR1_DET, 9, BD72720_INT_OCUR1_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_OCUR2_RES, 9, BD72720_INT_OCUR2_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_OCUR2_DET, 9, BD72720_INT_OCUR2_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_OCUR3_RES, 9, BD72720_INT_OCUR3_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_OCUR3_DET, 9, BD72720_INT_OCUR3_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_CC_MON1_DET, 10, BD72720_INT_CC_MON1_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_CC_MON2_DET, 10, BD72720_INT_CC_MON2_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_CC_MON3_DET, 10, BD72720_INT_CC_MON3_DET_MASK),
|
||||
/*
|
||||
* The GPIO1_IN and GPIO2_IN IRQs are generated from the PMIC's GPIO1 and GPIO2
|
||||
* pins. Eg, they may be wired to other devices which can then use the PMIC as
|
||||
* an interrupt controller. The GPIO1 and GPIO2 can have the IRQ type
|
||||
* specified. All of the types (falling, rising, and both edges as well as low
|
||||
* and high levels) are supported.
|
||||
*/
|
||||
BD72720_TYPED_IRQ_REG(BD72720_INT_GPIO1_IN, 10, BD72720_INT_GPIO1_IN_MASK, 0),
|
||||
BD72720_TYPED_IRQ_REG(BD72720_INT_GPIO2_IN, 10, BD72720_INT_GPIO2_IN_MASK, 1),
|
||||
REGMAP_IRQ_REG(BD72720_INT_VF125_RES, 11, BD72720_INT_VF125_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_VF125_DET, 11, BD72720_INT_VF125_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_VF_RES, 11, BD72720_INT_VF_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_VF_DET, 11, BD72720_INT_VF_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_RTC0, 11, BD72720_INT_RTC0_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_RTC1, 11, BD72720_INT_RTC1_MASK),
|
||||
REGMAP_IRQ_REG(BD72720_INT_RTC2, 11, BD72720_INT_RTC2_MASK),
|
||||
};
|
||||
|
||||
static int bd72720_set_type_config(unsigned int **buf, unsigned int type,
|
||||
const struct regmap_irq *irq_data,
|
||||
int idx, void *irq_drv_data)
|
||||
{
|
||||
const struct regmap_irq_type *t = &irq_data->type;
|
||||
|
||||
/*
|
||||
* The regmap IRQ ecpects IRQ_TYPE_EDGE_BOTH to be written to register
|
||||
* as logical OR of the type_falling_val and type_rising_val. This is
|
||||
* not how the BD72720 implements this configuration, hence we need
|
||||
* to handle this specific case separately.
|
||||
*/
|
||||
if (type == IRQ_TYPE_EDGE_BOTH) {
|
||||
buf[0][idx] &= ~t->type_reg_mask;
|
||||
buf[0][idx] |= BD72720_GPIO_IRQ_TYPE_BOTH;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return regmap_irq_set_type_config_simple(buf, type, irq_data, idx, irq_drv_data);
|
||||
}
|
||||
|
||||
static const struct regmap_irq_chip bd71828_irq_chip = {
|
||||
.name = "bd71828_irq",
|
||||
.main_status = BD71828_REG_INT_MAIN,
|
||||
|
|
@ -465,6 +829,28 @@ static const struct regmap_irq_chip bd71815_irq_chip = {
|
|||
.irq_reg_stride = 1,
|
||||
};
|
||||
|
||||
static const unsigned int bd72720_irq_type_base[] = { BD72720_REG_GPIO1_CTRL };
|
||||
|
||||
static const struct regmap_irq_chip bd72720_irq_chip = {
|
||||
.name = "bd72720_irq",
|
||||
.main_status = BD72720_REG_INT_LVL1_STAT,
|
||||
.irqs = &bd72720_irqs[0],
|
||||
.num_irqs = ARRAY_SIZE(bd72720_irqs),
|
||||
.status_base = BD72720_REG_INT_PS1_STAT,
|
||||
.unmask_base = BD72720_REG_INT_PS1_EN,
|
||||
.config_base = &bd72720_irq_type_base[0],
|
||||
.num_config_bases = 1,
|
||||
.num_config_regs = 2,
|
||||
.set_type_config = bd72720_set_type_config,
|
||||
.ack_base = BD72720_REG_INT_PS1_STAT,
|
||||
.init_ack_masked = true,
|
||||
.num_regs = 12,
|
||||
.num_main_regs = 1,
|
||||
.sub_reg_offsets = &bd72720_sub_irq_offsets[0],
|
||||
.num_main_status_bits = 8,
|
||||
.irq_reg_stride = 1,
|
||||
};
|
||||
|
||||
static int set_clk_mode(struct device *dev, struct regmap *regmap,
|
||||
int clkmode_reg)
|
||||
{
|
||||
|
|
@ -511,11 +897,39 @@ static void bd71828_remove_poweroff(void *data)
|
|||
pm_power_off = NULL;
|
||||
}
|
||||
|
||||
static struct regmap *bd72720_do_regmaps(struct i2c_client *i2c)
|
||||
{
|
||||
struct bd72720_regmaps *maps;
|
||||
struct i2c_client *secondary_i2c;
|
||||
|
||||
secondary_i2c = devm_i2c_new_dummy_device(&i2c->dev, i2c->adapter,
|
||||
BD72720_SECONDARY_I2C_SLAVE);
|
||||
if (IS_ERR(secondary_i2c)) {
|
||||
dev_err_probe(&i2c->dev, PTR_ERR(secondary_i2c), "Failed to get secondary I2C\n");
|
||||
|
||||
return ERR_CAST(secondary_i2c);
|
||||
}
|
||||
|
||||
maps = devm_kzalloc(&i2c->dev, sizeof(*maps), GFP_KERNEL);
|
||||
if (!maps)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
maps->map1_4b = devm_regmap_init_i2c(i2c, &bd72720_regmap_4b);
|
||||
if (IS_ERR(maps->map1_4b))
|
||||
return maps->map1_4b;
|
||||
|
||||
maps->map2_4c = devm_regmap_init_i2c(secondary_i2c, &bd72720_regmap_4c);
|
||||
if (IS_ERR(maps->map2_4c))
|
||||
return maps->map2_4c;
|
||||
|
||||
return devm_regmap_init(&i2c->dev, NULL, maps, &bd72720_wrapper_map_config);
|
||||
}
|
||||
|
||||
static int bd71828_i2c_probe(struct i2c_client *i2c)
|
||||
{
|
||||
struct regmap_irq_chip_data *irq_data;
|
||||
int ret;
|
||||
struct regmap *regmap;
|
||||
struct regmap *regmap = NULL;
|
||||
const struct regmap_config *regmap_config;
|
||||
const struct regmap_irq_chip *irqchip;
|
||||
unsigned int chip_type;
|
||||
|
|
@ -523,6 +937,7 @@ static int bd71828_i2c_probe(struct i2c_client *i2c)
|
|||
int cells;
|
||||
int button_irq;
|
||||
int clkmode_reg;
|
||||
int main_lvl_mask_reg = 0, main_lvl_val = 0;
|
||||
|
||||
if (!i2c->irq) {
|
||||
dev_err(&i2c->dev, "No IRQ configured\n");
|
||||
|
|
@ -554,15 +969,34 @@ static int bd71828_i2c_probe(struct i2c_client *i2c)
|
|||
*/
|
||||
button_irq = 0;
|
||||
break;
|
||||
case ROHM_CHIP_TYPE_BD72720:
|
||||
{
|
||||
mfd = bd72720_mfd_cells;
|
||||
cells = ARRAY_SIZE(bd72720_mfd_cells);
|
||||
|
||||
regmap = bd72720_do_regmaps(i2c);
|
||||
if (IS_ERR(regmap))
|
||||
return dev_err_probe(&i2c->dev, PTR_ERR(regmap),
|
||||
"Failed to initialize Regmap\n");
|
||||
|
||||
irqchip = &bd72720_irq_chip;
|
||||
clkmode_reg = BD72720_REG_OUT32K;
|
||||
button_irq = BD72720_INT_SHORTPUSH;
|
||||
main_lvl_mask_reg = BD72720_REG_INT_LVL1_EN;
|
||||
main_lvl_val = BD72720_MASK_LVL1_EN_ALL;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
dev_err(&i2c->dev, "Unknown device type");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap = devm_regmap_init_i2c(i2c, regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
return dev_err_probe(&i2c->dev, PTR_ERR(regmap),
|
||||
if (!regmap) {
|
||||
regmap = devm_regmap_init_i2c(i2c, regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
return dev_err_probe(&i2c->dev, PTR_ERR(regmap),
|
||||
"Failed to initialize Regmap\n");
|
||||
}
|
||||
|
||||
ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, i2c->irq,
|
||||
IRQF_ONESHOT, 0, irqchip, &irq_data);
|
||||
|
|
@ -573,6 +1007,20 @@ static int bd71828_i2c_probe(struct i2c_client *i2c)
|
|||
dev_dbg(&i2c->dev, "Registered %d IRQs for chip\n",
|
||||
irqchip->num_irqs);
|
||||
|
||||
/*
|
||||
* On some ICs the main IRQ register has corresponding mask register.
|
||||
* This is not handled by the regmap IRQ. Let's enable all the main
|
||||
* level IRQs here. Further writes to the main level MASK is not
|
||||
* needed because masking is handled by the per IRQ 2.nd level MASK
|
||||
* registers. 2.nd level masks are handled by the regmap IRQ.
|
||||
*/
|
||||
if (main_lvl_mask_reg) {
|
||||
ret = regmap_write(regmap, main_lvl_mask_reg, main_lvl_val);
|
||||
if (ret) {
|
||||
return dev_err_probe(&i2c->dev, ret,
|
||||
"Failed to enable main level IRQs\n");
|
||||
}
|
||||
}
|
||||
if (button_irq) {
|
||||
ret = regmap_irq_get_virq(irq_data, button_irq);
|
||||
if (ret < 0)
|
||||
|
|
@ -614,6 +1062,9 @@ static const struct of_device_id bd71828_of_match[] = {
|
|||
}, {
|
||||
.compatible = "rohm,bd71815",
|
||||
.data = (void *)ROHM_CHIP_TYPE_BD71815,
|
||||
}, {
|
||||
.compatible = "rohm,bd72720",
|
||||
.data = (void *)ROHM_CHIP_TYPE_BD72720,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/rohm-bd71815.h>
|
||||
#include <linux/mfd/rohm-bd71828.h>
|
||||
#include <linux/mfd/rohm-bd72720.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
|
@ -44,19 +45,21 @@
|
|||
#define VBAT_LOW_TH 0x00D4
|
||||
|
||||
struct pwr_regs {
|
||||
u8 vbat_avg;
|
||||
u8 ibat;
|
||||
u8 ibat_avg;
|
||||
u8 btemp_vth;
|
||||
u8 chg_state;
|
||||
u8 bat_temp;
|
||||
u8 dcin_stat;
|
||||
u8 dcin_collapse_limit;
|
||||
u8 chg_set1;
|
||||
u8 chg_en;
|
||||
u8 vbat_alm_limit_u;
|
||||
u8 conf;
|
||||
u8 vdcin;
|
||||
unsigned int vbat_avg;
|
||||
unsigned int ibat;
|
||||
unsigned int ibat_avg;
|
||||
unsigned int btemp_vth;
|
||||
unsigned int chg_state;
|
||||
unsigned int bat_temp;
|
||||
unsigned int dcin_stat;
|
||||
unsigned int dcin_online_mask;
|
||||
unsigned int dcin_collapse_limit;
|
||||
unsigned int chg_set1;
|
||||
unsigned int chg_en;
|
||||
unsigned int vbat_alm_limit_u;
|
||||
unsigned int conf;
|
||||
unsigned int vdcin;
|
||||
unsigned int vdcin_himask;
|
||||
};
|
||||
|
||||
static const struct pwr_regs pwr_regs_bd71828 = {
|
||||
|
|
@ -67,12 +70,14 @@ static const struct pwr_regs pwr_regs_bd71828 = {
|
|||
.chg_state = BD71828_REG_CHG_STATE,
|
||||
.bat_temp = BD71828_REG_BAT_TEMP,
|
||||
.dcin_stat = BD71828_REG_DCIN_STAT,
|
||||
.dcin_online_mask = BD7182x_MASK_DCIN_DET,
|
||||
.dcin_collapse_limit = BD71828_REG_DCIN_CLPS,
|
||||
.chg_set1 = BD71828_REG_CHG_SET1,
|
||||
.chg_en = BD71828_REG_CHG_EN,
|
||||
.vbat_alm_limit_u = BD71828_REG_ALM_VBAT_LIMIT_U,
|
||||
.conf = BD71828_REG_CONF,
|
||||
.vdcin = BD71828_REG_VDCIN_U,
|
||||
.vdcin_himask = BD7182x_MASK_VDCIN_U,
|
||||
};
|
||||
|
||||
static const struct pwr_regs pwr_regs_bd71815 = {
|
||||
|
|
@ -85,6 +90,7 @@ static const struct pwr_regs pwr_regs_bd71815 = {
|
|||
.chg_state = BD71815_REG_CHG_STATE,
|
||||
.bat_temp = BD71815_REG_BAT_TEMP,
|
||||
.dcin_stat = BD71815_REG_DCIN_STAT,
|
||||
.dcin_online_mask = BD7182x_MASK_DCIN_DET,
|
||||
.dcin_collapse_limit = BD71815_REG_DCIN_CLPS,
|
||||
.chg_set1 = BD71815_REG_CHG_SET1,
|
||||
.chg_en = BD71815_REG_CHG_SET1,
|
||||
|
|
@ -92,6 +98,31 @@ static const struct pwr_regs pwr_regs_bd71815 = {
|
|||
.conf = BD71815_REG_CONF,
|
||||
|
||||
.vdcin = BD71815_REG_VM_DCIN_U,
|
||||
.vdcin_himask = BD7182x_MASK_VDCIN_U,
|
||||
};
|
||||
|
||||
static struct pwr_regs pwr_regs_bd72720 = {
|
||||
.vbat_avg = BD72720_REG_VM_SA_VBAT_U,
|
||||
.ibat = BD72720_REG_CC_CURCD_U,
|
||||
.ibat_avg = BD72720_REG_CC_SA_CURCD_U,
|
||||
.btemp_vth = BD72720_REG_VM_BTMP_U,
|
||||
/*
|
||||
* Note, state 0x40 IMP_CHK. not documented
|
||||
* on other variants but was still handled in
|
||||
* existing code. No memory traces as to why.
|
||||
*/
|
||||
.chg_state = BD72720_REG_CHG_STATE,
|
||||
.bat_temp = BD72720_REG_CHG_BAT_TEMP_STAT,
|
||||
.dcin_stat = BD72720_REG_INT_VBUS_SRC,
|
||||
.dcin_online_mask = BD72720_MASK_DCIN_DET,
|
||||
.dcin_collapse_limit = -1, /* Automatic. Setting not supported */
|
||||
.chg_set1 = BD72720_REG_CHG_SET_1,
|
||||
.chg_en = BD72720_REG_CHG_EN,
|
||||
/* 15mV note in data-sheet */
|
||||
.vbat_alm_limit_u = BD72720_REG_ALM_VBAT_TH_U,
|
||||
.conf = BD72720_REG_CONF, /* o XSTB, only PON. Seprate slave addr */
|
||||
.vdcin = BD72720_REG_VM_VBUS_U, /* 10 bits not 11 as with other ICs */
|
||||
.vdcin_himask = BD72720_MASK_VDCIN_U,
|
||||
};
|
||||
|
||||
struct bd71828_power {
|
||||
|
|
@ -298,7 +329,7 @@ static int get_chg_online(struct bd71828_power *pwr, int *chg_online)
|
|||
dev_err(pwr->dev, "Failed to read DCIN status\n");
|
||||
return ret;
|
||||
}
|
||||
*chg_online = ((r & BD7182x_MASK_DCIN_DET) != 0);
|
||||
*chg_online = ((r & pwr->regs->dcin_online_mask) != 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -329,8 +360,8 @@ static int bd71828_bat_inserted(struct bd71828_power *pwr)
|
|||
ret = val & BD7182x_MASK_CONF_PON;
|
||||
|
||||
if (ret)
|
||||
regmap_update_bits(pwr->regmap, pwr->regs->conf,
|
||||
BD7182x_MASK_CONF_PON, 0);
|
||||
if (regmap_update_bits(pwr->regmap, pwr->regs->conf, BD7182x_MASK_CONF_PON, 0))
|
||||
dev_err(pwr->dev, "Failed to write CONF register\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -358,11 +389,13 @@ static int bd71828_init_hardware(struct bd71828_power *pwr)
|
|||
int ret;
|
||||
|
||||
/* TODO: Collapse limit should come from device-tree ? */
|
||||
ret = regmap_write(pwr->regmap, pwr->regs->dcin_collapse_limit,
|
||||
BD7182x_DCIN_COLLAPSE_DEFAULT);
|
||||
if (ret) {
|
||||
dev_err(pwr->dev, "Failed to write DCIN collapse limit\n");
|
||||
return ret;
|
||||
if (pwr->regs->dcin_collapse_limit != (unsigned int)-1) {
|
||||
ret = regmap_write(pwr->regmap, pwr->regs->dcin_collapse_limit,
|
||||
BD7182x_DCIN_COLLAPSE_DEFAULT);
|
||||
if (ret) {
|
||||
dev_err(pwr->dev, "Failed to write DCIN collapse limit\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = pwr->bat_inserted(pwr);
|
||||
|
|
@ -419,7 +452,7 @@ static int bd71828_charger_get_property(struct power_supply *psy,
|
|||
break;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
||||
ret = bd7182x_read16_himask(pwr, pwr->regs->vdcin,
|
||||
BD7182x_MASK_VDCIN_U, &tmp);
|
||||
pwr->regs->vdcin_himask, &tmp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -630,6 +663,9 @@ BD_ISR_AC(dcin_ovp_det, "DCIN OVER VOLTAGE", true)
|
|||
BD_ISR_DUMMY(dcin_mon_det, "DCIN voltage below threshold")
|
||||
BD_ISR_DUMMY(dcin_mon_res, "DCIN voltage above threshold")
|
||||
|
||||
BD_ISR_DUMMY(vbus_curr_limit, "VBUS current limited")
|
||||
BD_ISR_DUMMY(vsys_ov_res, "VSYS over-voltage cleared")
|
||||
BD_ISR_DUMMY(vsys_ov_det, "VSYS over-voltage")
|
||||
BD_ISR_DUMMY(vsys_uv_res, "VSYS under-voltage cleared")
|
||||
BD_ISR_DUMMY(vsys_uv_det, "VSYS under-voltage")
|
||||
BD_ISR_DUMMY(vsys_low_res, "'VSYS low' cleared")
|
||||
|
|
@ -878,6 +914,51 @@ static int bd7182x_get_irqs(struct platform_device *pdev,
|
|||
BDIRQ("bd71828-temp-125-over", bd71828_temp_vf125_det),
|
||||
BDIRQ("bd71828-temp-125-under", bd71828_temp_vf125_res),
|
||||
};
|
||||
static const struct bd7182x_irq_res bd72720_irqs[] = {
|
||||
BDIRQ("bd72720_int_vbus_rmv", BD_ISR_NAME(dcin_removed)),
|
||||
BDIRQ("bd72720_int_vbus_det", bd7182x_dcin_detected),
|
||||
BDIRQ("bd72720_int_vbus_mon_res", BD_ISR_NAME(dcin_mon_res)),
|
||||
BDIRQ("bd72720_int_vbus_mon_det", BD_ISR_NAME(dcin_mon_det)),
|
||||
BDIRQ("bd72720_int_vsys_mon_res", BD_ISR_NAME(vsys_mon_res)),
|
||||
BDIRQ("bd72720_int_vsys_mon_det", BD_ISR_NAME(vsys_mon_det)),
|
||||
BDIRQ("bd72720_int_vsys_uv_res", BD_ISR_NAME(vsys_uv_res)),
|
||||
BDIRQ("bd72720_int_vsys_uv_det", BD_ISR_NAME(vsys_uv_det)),
|
||||
BDIRQ("bd72720_int_vsys_lo_res", BD_ISR_NAME(vsys_low_res)),
|
||||
BDIRQ("bd72720_int_vsys_lo_det", BD_ISR_NAME(vsys_low_det)),
|
||||
BDIRQ("bd72720_int_vsys_ov_res", BD_ISR_NAME(vsys_ov_res)),
|
||||
BDIRQ("bd72720_int_vsys_ov_det", BD_ISR_NAME(vsys_ov_det)),
|
||||
BDIRQ("bd72720_int_bat_ilim", BD_ISR_NAME(vbus_curr_limit)),
|
||||
BDIRQ("bd72720_int_chg_done", bd718x7_chg_done),
|
||||
BDIRQ("bd72720_int_extemp_tout", BD_ISR_NAME(chg_wdg_temp)),
|
||||
BDIRQ("bd72720_int_chg_wdt_exp", BD_ISR_NAME(chg_wdg)),
|
||||
BDIRQ("bd72720_int_bat_mnt_out", BD_ISR_NAME(rechg_res)),
|
||||
BDIRQ("bd72720_int_bat_mnt_in", BD_ISR_NAME(rechg_det)),
|
||||
BDIRQ("bd72720_int_chg_trns", BD_ISR_NAME(chg_state_changed)),
|
||||
|
||||
BDIRQ("bd72720_int_vbat_mon_res", BD_ISR_NAME(bat_mon_res)),
|
||||
BDIRQ("bd72720_int_vbat_mon_det", BD_ISR_NAME(bat_mon)),
|
||||
BDIRQ("bd72720_int_vbat_sht_res", BD_ISR_NAME(bat_short_res)),
|
||||
BDIRQ("bd72720_int_vbat_sht_det", BD_ISR_NAME(bat_short)),
|
||||
BDIRQ("bd72720_int_vbat_lo_res", BD_ISR_NAME(bat_low_res)),
|
||||
BDIRQ("bd72720_int_vbat_lo_det", BD_ISR_NAME(bat_low)),
|
||||
BDIRQ("bd72720_int_vbat_ov_res", BD_ISR_NAME(bat_ov_res)),
|
||||
BDIRQ("bd72720_int_vbat_ov_det", BD_ISR_NAME(bat_ov)),
|
||||
BDIRQ("bd72720_int_bat_rmv", BD_ISR_NAME(bat_removed)),
|
||||
BDIRQ("bd72720_int_bat_det", BD_ISR_NAME(bat_det)),
|
||||
BDIRQ("bd72720_int_dbat_det", BD_ISR_NAME(bat_dead)),
|
||||
BDIRQ("bd72720_int_bat_temp_trns", BD_ISR_NAME(temp_transit)),
|
||||
BDIRQ("bd72720_int_lobtmp_res", BD_ISR_NAME(temp_bat_low_res)),
|
||||
BDIRQ("bd72720_int_lobtmp_det", BD_ISR_NAME(temp_bat_low)),
|
||||
BDIRQ("bd72720_int_ovbtmp_res", BD_ISR_NAME(temp_bat_hi_res)),
|
||||
BDIRQ("bd72720_int_ovbtmp_det", BD_ISR_NAME(temp_bat_hi)),
|
||||
BDIRQ("bd72720_int_ocur1_res", BD_ISR_NAME(bat_oc1_res)),
|
||||
BDIRQ("bd72720_int_ocur1_det", BD_ISR_NAME(bat_oc1)),
|
||||
BDIRQ("bd72720_int_ocur2_res", BD_ISR_NAME(bat_oc2_res)),
|
||||
BDIRQ("bd72720_int_ocur2_det", BD_ISR_NAME(bat_oc2)),
|
||||
BDIRQ("bd72720_int_ocur3_res", BD_ISR_NAME(bat_oc3_res)),
|
||||
BDIRQ("bd72720_int_ocur3_det", BD_ISR_NAME(bat_oc3)),
|
||||
BDIRQ("bd72720_int_cc_mon2_det", BD_ISR_NAME(bat_cc_mon)),
|
||||
};
|
||||
int num_irqs;
|
||||
const struct bd7182x_irq_res *irqs;
|
||||
|
||||
|
|
@ -890,6 +971,10 @@ static int bd7182x_get_irqs(struct platform_device *pdev,
|
|||
irqs = &bd71815_irqs[0];
|
||||
num_irqs = ARRAY_SIZE(bd71815_irqs);
|
||||
break;
|
||||
case ROHM_CHIP_TYPE_BD72720:
|
||||
irqs = &bd72720_irqs[0];
|
||||
num_irqs = ARRAY_SIZE(bd72720_irqs);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -958,21 +1043,27 @@ static int bd71828_power_probe(struct platform_device *pdev)
|
|||
struct power_supply_config ac_cfg = {};
|
||||
struct power_supply_config bat_cfg = {};
|
||||
int ret;
|
||||
struct regmap *regmap;
|
||||
|
||||
regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
||||
if (!regmap) {
|
||||
dev_err(&pdev->dev, "No parent regmap\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pwr = devm_kzalloc(&pdev->dev, sizeof(*pwr), GFP_KERNEL);
|
||||
if (!pwr)
|
||||
return -ENOMEM;
|
||||
|
||||
pwr->regmap = regmap;
|
||||
pwr->dev = &pdev->dev;
|
||||
/*
|
||||
* The BD72720 MFD device registers two regmaps. Power-supply driver
|
||||
* uses the "wrap-map", which provides access to both of the I2C slave
|
||||
* addresses used by the BD72720
|
||||
*/
|
||||
pwr->chip_type = platform_get_device_id(pdev)->driver_data;
|
||||
if (pwr->chip_type != ROHM_CHIP_TYPE_BD72720)
|
||||
pwr->regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
||||
else
|
||||
pwr->regmap = dev_get_regmap(pdev->dev.parent, "wrap-map");
|
||||
if (!pwr->regmap) {
|
||||
dev_err(&pdev->dev, "No parent regmap\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pwr->dev = &pdev->dev;
|
||||
|
||||
switch (pwr->chip_type) {
|
||||
case ROHM_CHIP_TYPE_BD71828:
|
||||
|
|
@ -985,6 +1076,12 @@ static int bd71828_power_probe(struct platform_device *pdev)
|
|||
pwr->get_temp = bd71815_get_temp;
|
||||
pwr->regs = &pwr_regs_bd71815;
|
||||
break;
|
||||
case ROHM_CHIP_TYPE_BD72720:
|
||||
pwr->bat_inserted = bd71828_bat_inserted;
|
||||
pwr->regs = &pwr_regs_bd72720;
|
||||
pwr->get_temp = bd71828_get_temp;
|
||||
dev_dbg(pwr->dev, "Found ROHM BD72720\n");
|
||||
break;
|
||||
default:
|
||||
dev_err(pwr->dev, "Unknown PMIC\n");
|
||||
return -EINVAL;
|
||||
|
|
@ -1030,6 +1127,7 @@ static int bd71828_power_probe(struct platform_device *pdev)
|
|||
static const struct platform_device_id bd71828_charger_id[] = {
|
||||
{ "bd71815-power", ROHM_CHIP_TYPE_BD71815 },
|
||||
{ "bd71828-power", ROHM_CHIP_TYPE_BD71828 },
|
||||
{ "bd72720-power", ROHM_CHIP_TYPE_BD72720 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, bd71828_charger_id);
|
||||
|
|
|
|||
|
|
@ -241,13 +241,13 @@ config REGULATOR_BD71815
|
|||
will be called bd71815-regulator.
|
||||
|
||||
config REGULATOR_BD71828
|
||||
tristate "ROHM BD71828 Power Regulator"
|
||||
tristate "ROHM BD71828, BD72720 and BD73900 Power Regulators"
|
||||
depends on MFD_ROHM_BD71828
|
||||
select REGULATOR_ROHM
|
||||
help
|
||||
This driver supports voltage regulators on ROHM BD71828 PMIC.
|
||||
This will enable support for the software controllable buck
|
||||
and LDO regulators.
|
||||
This driver supports voltage regulators on ROHM BD71828,
|
||||
BD71879, BD72720 and BD73900 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
|
||||
will be called bd71828-regulator.
|
||||
|
|
|
|||
|
|
@ -571,15 +571,12 @@ static int bd7181x_probe(struct platform_device *pdev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
ldo4_en = devm_fwnode_gpiod_get(&pdev->dev,
|
||||
dev_fwnode(pdev->dev.parent),
|
||||
"rohm,vsel", GPIOD_ASIS, "ldo4-en");
|
||||
if (IS_ERR(ldo4_en)) {
|
||||
ret = PTR_ERR(ldo4_en);
|
||||
if (ret != -ENOENT)
|
||||
return ret;
|
||||
ldo4_en = NULL;
|
||||
}
|
||||
ldo4_en = devm_fwnode_gpiod_get_optional(&pdev->dev,
|
||||
dev_fwnode(pdev->dev.parent),
|
||||
"rohm,vsel", GPIOD_ASIS,
|
||||
"ldo4-en");
|
||||
if (IS_ERR(ldo4_en))
|
||||
return PTR_ERR(ldo4_en);
|
||||
|
||||
/* Disable to go to ship-mode */
|
||||
ret = regmap_update_bits(regmap, BD71815_REG_PWRCTRL, RESTARTEN, 0);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -570,7 +570,8 @@ config RTC_DRV_BD70528
|
|||
depends on MFD_ROHM_BD71828
|
||||
help
|
||||
If you say Y here you will get support for the RTC
|
||||
block on ROHM BD71815 and BD71828 Power Management IC.
|
||||
block on ROHM BD71815, BD71828 and BD72720 Power
|
||||
Management ICs.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-bd70528.
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <linux/bcd.h>
|
||||
#include <linux/mfd/rohm-bd71815.h>
|
||||
#include <linux/mfd/rohm-bd71828.h>
|
||||
#include <linux/mfd/rohm-bd72720.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
|
@ -262,13 +263,13 @@ static int bd70528_probe(struct platform_device *pdev)
|
|||
|
||||
/*
|
||||
* See also BD718XX_ALM_EN_OFFSET:
|
||||
* This works for BD71828 and BD71815 as they have same offset
|
||||
* between ALM0 start and ALM0_MASK. If new ICs are to be
|
||||
* added this requires proper check as ALM0_MASK is not located
|
||||
* at the end of ALM0 block - but after all ALM blocks so if
|
||||
* amount of ALMs differ the offset to enable/disable is likely
|
||||
* to be incorrect and enable/disable must be given as own
|
||||
* reg address here.
|
||||
* This works for BD71828, BD71815, and BD72720 as they all
|
||||
* have same offset between the ALM0 start and the ALM0_MASK.
|
||||
* If new ICs are to be added this requires proper check as
|
||||
* the ALM0_MASK is not located at the end of ALM0 block -
|
||||
* but after all ALM blocks. If amount of ALMs differ, the
|
||||
* offset to enable/disable is likely to be incorrect and
|
||||
* enable/disable must be given as own reg address here.
|
||||
*/
|
||||
bd_rtc->bd718xx_alm_block_start = BD71815_REG_RTC_ALM_START;
|
||||
hour_reg = BD71815_REG_HOUR;
|
||||
|
|
@ -278,6 +279,11 @@ static int bd70528_probe(struct platform_device *pdev)
|
|||
bd_rtc->bd718xx_alm_block_start = BD71828_REG_RTC_ALM_START;
|
||||
hour_reg = BD71828_REG_RTC_HOUR;
|
||||
break;
|
||||
case ROHM_CHIP_TYPE_BD72720:
|
||||
bd_rtc->reg_time_start = BD72720_REG_RTC_START;
|
||||
bd_rtc->bd718xx_alm_block_start = BD72720_REG_RTC_ALM_START;
|
||||
hour_reg = BD72720_REG_RTC_HOUR;
|
||||
break;
|
||||
default:
|
||||
dev_err(&pdev->dev, "Unknown chip\n");
|
||||
return -ENOENT;
|
||||
|
|
@ -337,6 +343,7 @@ static int bd70528_probe(struct platform_device *pdev)
|
|||
static const struct platform_device_id bd718x7_rtc_id[] = {
|
||||
{ "bd71828-rtc", ROHM_CHIP_TYPE_BD71828 },
|
||||
{ "bd71815-rtc", ROHM_CHIP_TYPE_BD71815 },
|
||||
{ "bd72720-rtc", ROHM_CHIP_TYPE_BD72720 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, bd718x7_rtc_id);
|
||||
|
|
|
|||
61
include/dt-bindings/gpio/nvidia,tegra264-gpio.h
Normal file
61
include/dt-bindings/gpio/nvidia,tegra264-gpio.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
|
||||
/* Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. */
|
||||
|
||||
/*
|
||||
* This header provides constants for binding nvidia,tegra264-gpio*.
|
||||
*
|
||||
* The first cell in Tegra's GPIO specifier is the GPIO ID. The macros below
|
||||
* provide names for this.
|
||||
*
|
||||
* The second cell contains standard flag values specified in gpio.h.
|
||||
*/
|
||||
|
||||
#ifndef _DT_BINDINGS_GPIO_TEGRA264_GPIO_H
|
||||
#define _DT_BINDINGS_GPIO_TEGRA264_GPIO_H
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
/* GPIOs implemented by main GPIO controller */
|
||||
#define TEGRA264_MAIN_GPIO_PORT_T 0
|
||||
#define TEGRA264_MAIN_GPIO_PORT_U 1
|
||||
#define TEGRA264_MAIN_GPIO_PORT_V 2
|
||||
#define TEGRA264_MAIN_GPIO_PORT_W 3
|
||||
#define TEGRA264_MAIN_GPIO_PORT_AL 4
|
||||
#define TEGRA264_MAIN_GPIO_PORT_Y 5
|
||||
#define TEGRA264_MAIN_GPIO_PORT_Z 6
|
||||
#define TEGRA264_MAIN_GPIO_PORT_X 7
|
||||
#define TEGRA264_MAIN_GPIO_PORT_H 8
|
||||
#define TEGRA264_MAIN_GPIO_PORT_J 9
|
||||
#define TEGRA264_MAIN_GPIO_PORT_K 10
|
||||
#define TEGRA264_MAIN_GPIO_PORT_L 11
|
||||
#define TEGRA264_MAIN_GPIO_PORT_M 12
|
||||
#define TEGRA264_MAIN_GPIO_PORT_P 13
|
||||
#define TEGRA264_MAIN_GPIO_PORT_Q 14
|
||||
#define TEGRA264_MAIN_GPIO_PORT_R 15
|
||||
#define TEGRA264_MAIN_GPIO_PORT_S 16
|
||||
#define TEGRA264_MAIN_GPIO_PORT_F 17
|
||||
#define TEGRA264_MAIN_GPIO_PORT_G 18
|
||||
|
||||
#define TEGRA264_MAIN_GPIO(port, offset) \
|
||||
((TEGRA264_MAIN_GPIO_PORT_##port * 8) + (offset))
|
||||
|
||||
/* GPIOs implemented by AON GPIO controller */
|
||||
#define TEGRA264_AON_GPIO_PORT_AA 0
|
||||
#define TEGRA264_AON_GPIO_PORT_BB 1
|
||||
#define TEGRA264_AON_GPIO_PORT_CC 2
|
||||
#define TEGRA264_AON_GPIO_PORT_DD 3
|
||||
#define TEGRA264_AON_GPIO_PORT_EE 4
|
||||
|
||||
#define TEGRA264_AON_GPIO(port, offset) \
|
||||
((TEGRA264_AON_GPIO_PORT_##port * 8) + (offset))
|
||||
|
||||
#define TEGRA264_UPHY_GPIO_PORT_A 0
|
||||
#define TEGRA264_UPHY_GPIO_PORT_B 1
|
||||
#define TEGRA264_UPHY_GPIO_PORT_C 2
|
||||
#define TEGRA264_UPHY_GPIO_PORT_D 3
|
||||
#define TEGRA264_UPHY_GPIO_PORT_E 4
|
||||
|
||||
#define TEGRA264_UPHY_GPIO(port, offset) \
|
||||
((TEGRA264_UPHY_GPIO_PORT_##port * 8) + (offset))
|
||||
|
||||
#endif
|
||||
|
|
@ -607,6 +607,42 @@ struct gpio_desc *devm_fwnode_gpiod_get(struct device *dev,
|
|||
flags, label);
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_fwnode_gpiod_get_optional - obtain an optional GPIO from firmware node
|
||||
* @dev: GPIO consumer
|
||||
* @fwnode: handle of the firmware node
|
||||
* @con_id: function within the GPIO consumer
|
||||
* @flags: GPIO initialization flags
|
||||
* @label: label to attach to the requested GPIO
|
||||
*
|
||||
* This function can be used for drivers that get their configuration
|
||||
* from opaque firmware.
|
||||
*
|
||||
* GPIO descriptors returned from this function are automatically disposed on
|
||||
* driver detach.
|
||||
*
|
||||
* Returns:
|
||||
* The GPIO descriptor corresponding to the optional function @con_id of device
|
||||
* dev, NULL if no GPIO has been assigned to the requested function, or
|
||||
* another IS_ERR() code if an error occurred while trying to acquire the GPIO.
|
||||
*/
|
||||
static inline
|
||||
struct gpio_desc *devm_fwnode_gpiod_get_optional(struct device *dev,
|
||||
struct fwnode_handle *fwnode,
|
||||
const char *con_id,
|
||||
enum gpiod_flags flags,
|
||||
const char *label)
|
||||
{
|
||||
struct gpio_desc *desc;
|
||||
|
||||
desc = devm_fwnode_gpiod_get_index(dev, fwnode, con_id, 0,
|
||||
flags, label);
|
||||
if (IS_ERR(desc) && PTR_ERR(desc) == -ENOENT)
|
||||
return NULL;
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
struct acpi_gpio_params {
|
||||
unsigned int crs_entry_index;
|
||||
unsigned short line_index;
|
||||
|
|
|
|||
634
include/linux/mfd/rohm-bd72720.h
Normal file
634
include/linux/mfd/rohm-bd72720.h
Normal file
|
|
@ -0,0 +1,634 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright 2025 ROHM Semiconductors.
|
||||
*
|
||||
* Author: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
|
||||
*/
|
||||
|
||||
#ifndef _MFD_BD72720_H
|
||||
#define _MFD_BD72720_H
|
||||
|
||||
#include <linux/regmap.h>
|
||||
|
||||
enum {
|
||||
BD72720_BUCK1,
|
||||
BD72720_BUCK2,
|
||||
BD72720_BUCK3,
|
||||
BD72720_BUCK4,
|
||||
BD72720_BUCK5,
|
||||
BD72720_BUCK6,
|
||||
BD72720_BUCK7,
|
||||
BD72720_BUCK8,
|
||||
BD72720_BUCK9,
|
||||
BD72720_BUCK10,
|
||||
BD72720_BUCK11,
|
||||
BD72720_LDO1,
|
||||
BD72720_LDO2,
|
||||
BD72720_LDO3,
|
||||
BD72720_LDO4,
|
||||
BD72720_LDO5,
|
||||
BD72720_LDO6,
|
||||
BD72720_LDO7,
|
||||
BD72720_LDO8,
|
||||
BD72720_LDO9,
|
||||
BD72720_LDO10,
|
||||
BD72720_LDO11,
|
||||
BD72720_REGULATOR_AMOUNT,
|
||||
};
|
||||
|
||||
/* BD72720 interrupts */
|
||||
#define BD72720_INT_LONGPUSH_MASK BIT(0)
|
||||
#define BD72720_INT_MIDPUSH_MASK BIT(1)
|
||||
#define BD72720_INT_SHORTPUSH_MASK BIT(2)
|
||||
#define BD72720_INT_PUSH_MASK BIT(3)
|
||||
#define BD72720_INT_HALL_DET_MASK BIT(4)
|
||||
#define BD72720_INT_HALL_TGL_MASK BIT(5)
|
||||
#define BD72720_INT_WDOG_MASK BIT(6)
|
||||
#define BD72720_INT_SWRESET_MASK BIT(7)
|
||||
#define BD72720_INT_SEQ_DONE_MASK BIT(0)
|
||||
#define BD72720_INT_PGFAULT_MASK BIT(4)
|
||||
#define BD72720_INT_BUCK1_DVS_MASK BIT(0)
|
||||
#define BD72720_INT_BUCK2_DVS_MASK BIT(1)
|
||||
#define BD72720_INT_BUCK3_DVS_MASK BIT(2)
|
||||
#define BD72720_INT_BUCK4_DVS_MASK BIT(3)
|
||||
#define BD72720_INT_BUCK5_DVS_MASK BIT(4)
|
||||
#define BD72720_INT_BUCK6_DVS_MASK BIT(5)
|
||||
#define BD72720_INT_BUCK7_DVS_MASK BIT(6)
|
||||
#define BD72720_INT_BUCK8_DVS_MASK BIT(7)
|
||||
#define BD72720_INT_BUCK9_DVS_MASK BIT(0)
|
||||
#define BD72720_INT_BUCK10_DVS_MASK BIT(1)
|
||||
#define BD72720_INT_LDO1_DVS_MASK BIT(4)
|
||||
#define BD72720_INT_LDO2_DVS_MASK BIT(5)
|
||||
#define BD72720_INT_LDO3_DVS_MASK BIT(6)
|
||||
#define BD72720_INT_LDO4_DVS_MASK BIT(7)
|
||||
#define BD72720_INT_VBUS_RMV_MASK BIT(0)
|
||||
#define BD72720_INT_VBUS_DET_MASK BIT(1)
|
||||
#define BD72720_INT_VBUS_MON_RES_MASK BIT(2)
|
||||
#define BD72720_INT_VBUS_MON_DET_MASK BIT(3)
|
||||
#define BD72720_INT_VSYS_MON_RES_MASK BIT(0)
|
||||
#define BD72720_INT_VSYS_MON_DET_MASK BIT(1)
|
||||
#define BD72720_INT_VSYS_UV_RES_MASK BIT(2)
|
||||
#define BD72720_INT_VSYS_UV_DET_MASK BIT(3)
|
||||
#define BD72720_INT_VSYS_LO_RES_MASK BIT(4)
|
||||
#define BD72720_INT_VSYS_LO_DET_MASK BIT(5)
|
||||
#define BD72720_INT_VSYS_OV_RES_MASK BIT(6)
|
||||
#define BD72720_INT_VSYS_OV_DET_MASK BIT(7)
|
||||
#define BD72720_INT_BAT_ILIM_MASK BIT(0)
|
||||
#define BD72720_INT_CHG_DONE_MASK BIT(1)
|
||||
#define BD72720_INT_EXTEMP_TOUT_MASK BIT(2)
|
||||
#define BD72720_INT_CHG_WDT_EXP_MASK BIT(3)
|
||||
#define BD72720_INT_BAT_MNT_OUT_MASK BIT(4)
|
||||
#define BD72720_INT_BAT_MNT_IN_MASK BIT(5)
|
||||
#define BD72720_INT_CHG_TRNS_MASK BIT(7)
|
||||
#define BD72720_INT_VBAT_MON_RES_MASK BIT(0)
|
||||
#define BD72720_INT_VBAT_MON_DET_MASK BIT(1)
|
||||
#define BD72720_INT_VBAT_SHT_RES_MASK BIT(2)
|
||||
#define BD72720_INT_VBAT_SHT_DET_MASK BIT(3)
|
||||
#define BD72720_INT_VBAT_LO_RES_MASK BIT(4)
|
||||
#define BD72720_INT_VBAT_LO_DET_MASK BIT(5)
|
||||
#define BD72720_INT_VBAT_OV_RES_MASK BIT(6)
|
||||
#define BD72720_INT_VBAT_OV_DET_MASK BIT(7)
|
||||
#define BD72720_INT_BAT_RMV_MASK BIT(0)
|
||||
#define BD72720_INT_BAT_DET_MASK BIT(1)
|
||||
#define BD72720_INT_DBAT_DET_MASK BIT(2)
|
||||
#define BD72720_INT_BAT_TEMP_TRNS_MASK BIT(3)
|
||||
#define BD72720_INT_LOBTMP_RES_MASK BIT(4)
|
||||
#define BD72720_INT_LOBTMP_DET_MASK BIT(5)
|
||||
#define BD72720_INT_OVBTMP_RES_MASK BIT(6)
|
||||
#define BD72720_INT_OVBTMP_DET_MASK BIT(7)
|
||||
#define BD72720_INT_OCUR1_RES_MASK BIT(0)
|
||||
#define BD72720_INT_OCUR1_DET_MASK BIT(1)
|
||||
#define BD72720_INT_OCUR2_RES_MASK BIT(2)
|
||||
#define BD72720_INT_OCUR2_DET_MASK BIT(3)
|
||||
#define BD72720_INT_OCUR3_RES_MASK BIT(4)
|
||||
#define BD72720_INT_OCUR3_DET_MASK BIT(5)
|
||||
#define BD72720_INT_CC_MON1_DET_MASK BIT(0)
|
||||
#define BD72720_INT_CC_MON2_DET_MASK BIT(1)
|
||||
#define BD72720_INT_CC_MON3_DET_MASK BIT(2)
|
||||
#define BD72720_INT_GPIO1_IN_MASK BIT(4)
|
||||
#define BD72720_INT_GPIO2_IN_MASK BIT(5)
|
||||
#define BD72720_INT_VF125_RES_MASK BIT(0)
|
||||
#define BD72720_INT_VF125_DET_MASK BIT(1)
|
||||
#define BD72720_INT_VF_RES_MASK BIT(2)
|
||||
#define BD72720_INT_VF_DET_MASK BIT(3)
|
||||
#define BD72720_INT_RTC0_MASK BIT(4)
|
||||
#define BD72720_INT_RTC1_MASK BIT(5)
|
||||
#define BD72720_INT_RTC2_MASK BIT(6)
|
||||
|
||||
enum {
|
||||
/*
|
||||
* The IRQs excluding GPIO1 and GPIO2 are ordered in a same way as the
|
||||
* respective IRQ bits in status and mask registers are ordered.
|
||||
*
|
||||
* The BD72720_INT_GPIO1_IN and BD72720_INT_GPIO2_IN are IRQs which can
|
||||
* be used by other devices. Let's have GPIO1 and GPIO2 as first IRQs
|
||||
* here so we can use the regmap-IRQ with standard device tree xlate
|
||||
* while devices connected to the BD72720 IRQ input pins can refer to
|
||||
* the first two interrupt numbers in their device tree. If we placed
|
||||
* BD72720_INT_GPIO1_IN and BD72720_INT_GPIO2_IN after the CC_MON_DET
|
||||
* interrupts (like they are in the registers), the devices using
|
||||
* BD72720 as an IRQ parent should refer the interrupts starting with
|
||||
* an offset which might not be trivial to understand.
|
||||
*/
|
||||
BD72720_INT_GPIO1_IN,
|
||||
BD72720_INT_GPIO2_IN,
|
||||
BD72720_INT_LONGPUSH,
|
||||
BD72720_INT_MIDPUSH,
|
||||
BD72720_INT_SHORTPUSH,
|
||||
BD72720_INT_PUSH,
|
||||
BD72720_INT_HALL_DET,
|
||||
BD72720_INT_HALL_TGL,
|
||||
BD72720_INT_WDOG,
|
||||
BD72720_INT_SWRESET,
|
||||
BD72720_INT_SEQ_DONE,
|
||||
BD72720_INT_PGFAULT,
|
||||
BD72720_INT_BUCK1_DVS,
|
||||
BD72720_INT_BUCK2_DVS,
|
||||
BD72720_INT_BUCK3_DVS,
|
||||
BD72720_INT_BUCK4_DVS,
|
||||
BD72720_INT_BUCK5_DVS,
|
||||
BD72720_INT_BUCK6_DVS,
|
||||
BD72720_INT_BUCK7_DVS,
|
||||
BD72720_INT_BUCK8_DVS,
|
||||
BD72720_INT_BUCK9_DVS,
|
||||
BD72720_INT_BUCK10_DVS,
|
||||
BD72720_INT_LDO1_DVS,
|
||||
BD72720_INT_LDO2_DVS,
|
||||
BD72720_INT_LDO3_DVS,
|
||||
BD72720_INT_LDO4_DVS,
|
||||
BD72720_INT_VBUS_RMV,
|
||||
BD72720_INT_VBUS_DET,
|
||||
BD72720_INT_VBUS_MON_RES,
|
||||
BD72720_INT_VBUS_MON_DET,
|
||||
BD72720_INT_VSYS_MON_RES,
|
||||
BD72720_INT_VSYS_MON_DET,
|
||||
BD72720_INT_VSYS_UV_RES,
|
||||
BD72720_INT_VSYS_UV_DET,
|
||||
BD72720_INT_VSYS_LO_RES,
|
||||
BD72720_INT_VSYS_LO_DET,
|
||||
BD72720_INT_VSYS_OV_RES,
|
||||
BD72720_INT_VSYS_OV_DET,
|
||||
BD72720_INT_BAT_ILIM,
|
||||
BD72720_INT_CHG_DONE,
|
||||
BD72720_INT_EXTEMP_TOUT,
|
||||
BD72720_INT_CHG_WDT_EXP,
|
||||
BD72720_INT_BAT_MNT_OUT,
|
||||
BD72720_INT_BAT_MNT_IN,
|
||||
BD72720_INT_CHG_TRNS,
|
||||
BD72720_INT_VBAT_MON_RES,
|
||||
BD72720_INT_VBAT_MON_DET,
|
||||
BD72720_INT_VBAT_SHT_RES,
|
||||
BD72720_INT_VBAT_SHT_DET,
|
||||
BD72720_INT_VBAT_LO_RES,
|
||||
BD72720_INT_VBAT_LO_DET,
|
||||
BD72720_INT_VBAT_OV_RES,
|
||||
BD72720_INT_VBAT_OV_DET,
|
||||
BD72720_INT_BAT_RMV,
|
||||
BD72720_INT_BAT_DET,
|
||||
BD72720_INT_DBAT_DET,
|
||||
BD72720_INT_BAT_TEMP_TRNS,
|
||||
BD72720_INT_LOBTMP_RES,
|
||||
BD72720_INT_LOBTMP_DET,
|
||||
BD72720_INT_OVBTMP_RES,
|
||||
BD72720_INT_OVBTMP_DET,
|
||||
BD72720_INT_OCUR1_RES,
|
||||
BD72720_INT_OCUR1_DET,
|
||||
BD72720_INT_OCUR2_RES,
|
||||
BD72720_INT_OCUR2_DET,
|
||||
BD72720_INT_OCUR3_RES,
|
||||
BD72720_INT_OCUR3_DET,
|
||||
BD72720_INT_CC_MON1_DET,
|
||||
BD72720_INT_CC_MON2_DET,
|
||||
BD72720_INT_CC_MON3_DET,
|
||||
BD72720_INT_VF125_RES,
|
||||
BD72720_INT_VF125_DET,
|
||||
BD72720_INT_VF_RES,
|
||||
BD72720_INT_VF_DET,
|
||||
BD72720_INT_RTC0,
|
||||
BD72720_INT_RTC1,
|
||||
BD72720_INT_RTC2,
|
||||
};
|
||||
|
||||
/*
|
||||
* BD72720 Registers:
|
||||
* The BD72720 has two sets of registers behind two different I2C slave
|
||||
* addresses. "Common" registers being behind 0x4b, the charger registers
|
||||
* being behind 0x4c.
|
||||
*/
|
||||
/* Registers behind I2C slave 0x4b */
|
||||
enum {
|
||||
BD72720_REG_PRODUCT_ID,
|
||||
BD72720_REG_MANUFACTURER_ID,
|
||||
BD72720_REG_PMIC_REV_NUM,
|
||||
BD72720_REG_NVM_REV_NUM,
|
||||
BD72720_REG_BOOTSRC = 0x10,
|
||||
BD72720_REG_RESETSRC_1,
|
||||
BD72720_REG_RESETSRC_2,
|
||||
BD72720_REG_RESETSRC_3,
|
||||
BD72720_REG_RESETSRC_4,
|
||||
BD72720_REG_RESETSRC_5,
|
||||
BD72720_REG_RESETSRC_6,
|
||||
BD72720_REG_RESETSRC_7,
|
||||
BD72720_REG_POWER_STATE,
|
||||
BD72720_REG_PS_CFG,
|
||||
BD72720_REG_PS_CTRL_1,
|
||||
BD72720_REG_PS_CTRL_2,
|
||||
BD72720_REG_RCVCFG,
|
||||
BD72720_REG_RCVNUM,
|
||||
BD72720_REG_CRDCFG,
|
||||
BD72720_REG_REX_CTRL,
|
||||
|
||||
BD72720_REG_BUCK1_ON,
|
||||
BD72720_REG_BUCK1_MODE,
|
||||
/* Deep idle vsel */
|
||||
BD72720_REG_BUCK1_VSEL_DI,
|
||||
/* Idle vsel */
|
||||
BD72720_REG_BUCK1_VSEL_I,
|
||||
/* Suspend vsel */
|
||||
BD72720_REG_BUCK1_VSEL_S,
|
||||
/* Run boot vsel */
|
||||
BD72720_REG_BUCK1_VSEL_RB,
|
||||
/* Run0 ... run3 vsel */
|
||||
BD72720_REG_BUCK1_VSEL_RB0,
|
||||
BD72720_REG_BUCK1_VSEL_RB1,
|
||||
BD72720_REG_BUCK1_VSEL_RB2,
|
||||
BD72720_REG_BUCK1_VSEL_RB3,
|
||||
|
||||
BD72720_REG_BUCK2_ON,
|
||||
BD72720_REG_BUCK2_MODE,
|
||||
BD72720_REG_BUCK2_VSEL_DI,
|
||||
BD72720_REG_BUCK2_VSEL_I,
|
||||
BD72720_REG_BUCK2_VSEL_S,
|
||||
/* Run vsel */
|
||||
BD72720_REG_BUCK2_VSEL_R,
|
||||
|
||||
BD72720_REG_BUCK3_ON,
|
||||
BD72720_REG_BUCK3_MODE,
|
||||
BD72720_REG_BUCK3_VSEL_DI,
|
||||
BD72720_REG_BUCK3_VSEL_I,
|
||||
BD72720_REG_BUCK3_VSEL_S,
|
||||
BD72720_REG_BUCK3_VSEL_R,
|
||||
|
||||
BD72720_REG_BUCK4_ON,
|
||||
BD72720_REG_BUCK4_MODE,
|
||||
BD72720_REG_BUCK4_VSEL_DI,
|
||||
BD72720_REG_BUCK4_VSEL_I,
|
||||
BD72720_REG_BUCK4_VSEL_S,
|
||||
BD72720_REG_BUCK4_VSEL_R,
|
||||
|
||||
BD72720_REG_BUCK5_ON,
|
||||
BD72720_REG_BUCK5_MODE,
|
||||
BD72720_REG_BUCK5_VSEL,
|
||||
|
||||
BD72720_REG_BUCK6_ON,
|
||||
BD72720_REG_BUCK6_MODE,
|
||||
BD72720_REG_BUCK6_VSEL,
|
||||
|
||||
BD72720_REG_BUCK7_ON,
|
||||
BD72720_REG_BUCK7_MODE,
|
||||
BD72720_REG_BUCK7_VSEL,
|
||||
|
||||
BD72720_REG_BUCK8_ON,
|
||||
BD72720_REG_BUCK8_MODE,
|
||||
BD72720_REG_BUCK8_VSEL,
|
||||
|
||||
BD72720_REG_BUCK9_ON,
|
||||
BD72720_REG_BUCK9_MODE,
|
||||
BD72720_REG_BUCK9_VSEL,
|
||||
|
||||
BD72720_REG_BUCK10_ON,
|
||||
BD72720_REG_BUCK10_MODE,
|
||||
BD72720_REG_BUCK10_VSEL,
|
||||
|
||||
BD72720_REG_LDO1_ON,
|
||||
BD72720_REG_LDO1_MODE1,
|
||||
BD72720_REG_LDO1_MODE2,
|
||||
BD72720_REG_LDO1_VSEL_DI,
|
||||
BD72720_REG_LDO1_VSEL_I,
|
||||
BD72720_REG_LDO1_VSEL_S,
|
||||
BD72720_REG_LDO1_VSEL_RB,
|
||||
BD72720_REG_LDO1_VSEL_R0,
|
||||
BD72720_REG_LDO1_VSEL_R1,
|
||||
BD72720_REG_LDO1_VSEL_R2,
|
||||
BD72720_REG_LDO1_VSEL_R3,
|
||||
|
||||
BD72720_REG_LDO2_ON,
|
||||
BD72720_REG_LDO2_MODE,
|
||||
BD72720_REG_LDO2_VSEL_DI,
|
||||
BD72720_REG_LDO2_VSEL_I,
|
||||
BD72720_REG_LDO2_VSEL_S,
|
||||
BD72720_REG_LDO2_VSEL_R,
|
||||
|
||||
BD72720_REG_LDO3_ON,
|
||||
BD72720_REG_LDO3_MODE,
|
||||
BD72720_REG_LDO3_VSEL_DI,
|
||||
BD72720_REG_LDO3_VSEL_I,
|
||||
BD72720_REG_LDO3_VSEL_S,
|
||||
BD72720_REG_LDO3_VSEL_R,
|
||||
|
||||
BD72720_REG_LDO4_ON,
|
||||
BD72720_REG_LDO4_MODE,
|
||||
BD72720_REG_LDO4_VSEL_DI,
|
||||
BD72720_REG_LDO4_VSEL_I,
|
||||
BD72720_REG_LDO4_VSEL_S,
|
||||
BD72720_REG_LDO4_VSEL_R,
|
||||
|
||||
BD72720_REG_LDO5_ON,
|
||||
BD72720_REG_LDO5_MODE,
|
||||
BD72720_REG_LDO5_VSEL,
|
||||
|
||||
BD72720_REG_LDO6_ON,
|
||||
BD72720_REG_LDO6_MODE,
|
||||
BD72720_REG_LDO6_VSEL,
|
||||
|
||||
BD72720_REG_LDO7_ON,
|
||||
BD72720_REG_LDO7_MODE,
|
||||
BD72720_REG_LDO7_VSEL,
|
||||
|
||||
BD72720_REG_LDO8_ON,
|
||||
BD72720_REG_LDO8_MODE,
|
||||
BD72720_REG_LDO8_VSEL,
|
||||
|
||||
BD72720_REG_LDO9_ON,
|
||||
BD72720_REG_LDO9_MODE,
|
||||
BD72720_REG_LDO9_VSEL,
|
||||
|
||||
BD72720_REG_LDO10_ON,
|
||||
BD72720_REG_LDO10_MODE,
|
||||
BD72720_REG_LDO10_VSEL,
|
||||
|
||||
BD72720_REG_LDO11_ON,
|
||||
BD72720_REG_LDO11_MODE,
|
||||
BD72720_REG_LDO11_VSEL,
|
||||
|
||||
BD72720_REG_GPIO1_ON = 0x8b,
|
||||
BD72720_REG_GPIO2_ON,
|
||||
BD72720_REG_GPIO3_ON,
|
||||
BD72720_REG_GPIO4_ON,
|
||||
BD72720_REG_GPIO5_ON,
|
||||
|
||||
BD72720_REG_GPIO1_CTRL,
|
||||
BD72720_REG_GPIO2_CTRL,
|
||||
#define BD72720_GPIO_IRQ_TYPE_MASK GENMASK(6, 4)
|
||||
#define BD72720_GPIO_IRQ_TYPE_FALLING 0x0
|
||||
#define BD72720_GPIO_IRQ_TYPE_RISING 0x1
|
||||
#define BD72720_GPIO_IRQ_TYPE_BOTH 0x2
|
||||
#define BD72720_GPIO_IRQ_TYPE_HIGH 0x3
|
||||
#define BD72720_GPIO_IRQ_TYPE_LOW 0x4
|
||||
BD72720_REG_GPIO3_CTRL,
|
||||
BD72720_REG_GPIO4_CTRL,
|
||||
BD72720_REG_GPIO5_CTRL,
|
||||
#define BD72720_GPIO_DRIVE_MASK BIT(1)
|
||||
#define BD72720_GPIO_HIGH BIT(0)
|
||||
|
||||
BD72720_REG_EPDEN_CTRL,
|
||||
BD72720_REG_GATECNT_CTRL,
|
||||
BD72720_REG_LED_CTRL,
|
||||
|
||||
BD72720_REG_PWRON_CFG1,
|
||||
BD72720_REG_PWRON_CFG2,
|
||||
|
||||
BD72720_REG_OUT32K,
|
||||
BD72720_REG_CONF,
|
||||
BD72720_REG_HALL_STAT,
|
||||
|
||||
BD72720_REG_RTC_SEC = 0xa0,
|
||||
#define BD72720_REG_RTC_START BD72720_REG_RTC_SEC
|
||||
BD72720_REG_RTC_MIN,
|
||||
BD72720_REG_RTC_HOUR,
|
||||
BD72720_REG_RTC_WEEK,
|
||||
BD72720_REG_RTC_DAY,
|
||||
BD72720_REG_RTC_MON,
|
||||
BD72720_REG_RTC_YEAR,
|
||||
|
||||
BD72720_REG_RTC_ALM0_SEC,
|
||||
#define BD72720_REG_RTC_ALM_START BD72720_REG_RTC_ALM0_SEC
|
||||
BD72720_REG_RTC_ALM0_MIN,
|
||||
BD72720_REG_RTC_ALM0_HOUR,
|
||||
BD72720_REG_RTC_ALM0_WEEK,
|
||||
BD72720_REG_RTC_ALM0_MON,
|
||||
BD72720_REG_RTC_ALM0_YEAR,
|
||||
|
||||
BD72720_REG_RTC_ALM1_SEC,
|
||||
BD72720_REG_RTC_ALM1_MIN,
|
||||
BD72720_REG_RTC_ALM1_HOUR,
|
||||
BD72720_REG_RTC_ALM1_WEEK,
|
||||
BD72720_REG_RTC_ALM1_MON,
|
||||
BD72720_REG_RTC_ALM1_YEAR,
|
||||
|
||||
BD72720_REG_RTC_ALM0_EN,
|
||||
BD72720_REG_RTC_ALM1_EN,
|
||||
BD72720_REG_RTC_ALM2,
|
||||
|
||||
BD72720_REG_INT_LVL1_EN = 0xc0,
|
||||
#define BD72720_MASK_LVL1_EN_ALL GENMASK(7, 0)
|
||||
BD72720_REG_INT_PS1_EN,
|
||||
BD72720_REG_INT_PS2_EN,
|
||||
BD72720_REG_INT_DVS1_EN,
|
||||
BD72720_REG_INT_DVS2_EN,
|
||||
BD72720_REG_INT_VBUS_EN,
|
||||
BD72720_REG_INT_VSYS_EN,
|
||||
BD72720_REG_INT_CHG_EN,
|
||||
BD72720_REG_INT_BAT1_EN,
|
||||
BD72720_REG_INT_BAT2_EN,
|
||||
BD72720_REG_INT_IBAT_EN,
|
||||
BD72720_REG_INT_ETC1_EN,
|
||||
BD72720_REG_INT_ETC2_EN,
|
||||
|
||||
/*
|
||||
* The _STAT registers inform IRQ line state, and are used to ack IRQ.
|
||||
* The _SRC registers below indicate current state of the function
|
||||
* connected to the line.
|
||||
*/
|
||||
BD72720_REG_INT_LVL1_STAT,
|
||||
BD72720_REG_INT_PS1_STAT,
|
||||
BD72720_REG_INT_PS2_STAT,
|
||||
BD72720_REG_INT_DVS1_STAT,
|
||||
BD72720_REG_INT_DVS2_STAT,
|
||||
BD72720_REG_INT_VBUS_STAT,
|
||||
BD72720_REG_INT_VSYS_STAT,
|
||||
BD72720_REG_INT_CHG_STAT,
|
||||
BD72720_REG_INT_BAT1_STAT,
|
||||
BD72720_REG_INT_BAT2_STAT,
|
||||
BD72720_REG_INT_IBAT_STAT,
|
||||
BD72720_REG_INT_ETC1_STAT,
|
||||
BD72720_REG_INT_ETC2_STAT,
|
||||
|
||||
BD72720_REG_INT_LVL1_SRC,
|
||||
BD72720_REG_INT_PS1_SRC,
|
||||
BD72720_REG_INT_PS2_SRC,
|
||||
BD72720_REG_INT_DVS1_SRC,
|
||||
BD72720_REG_INT_DVS2_SRC,
|
||||
BD72720_REG_INT_VBUS_SRC,
|
||||
#define BD72720_MASK_DCIN_DET BIT(1)
|
||||
BD72720_REG_INT_VSYS_SRC,
|
||||
BD72720_REG_INT_CHG_SRC,
|
||||
BD72720_REG_INT_BAT1_SRC,
|
||||
BD72720_REG_INT_BAT2_SRC,
|
||||
BD72720_REG_INT_IBAT_SRC,
|
||||
BD72720_REG_INT_ETC1_SRC,
|
||||
BD72720_REG_INT_ETC2_SRC,
|
||||
};
|
||||
|
||||
/* Register masks */
|
||||
#define BD72720_MASK_DEEP_IDLE_EN BIT(0)
|
||||
#define BD72720_MASK_IDLE_EN BIT(1)
|
||||
#define BD72720_MASK_SUSPEND_EN BIT(2)
|
||||
#define BD72720_MASK_RUN_B_EN BIT(3)
|
||||
#define BD72720_MASK_RUN_0_EN BIT(4)
|
||||
#define BD72720_MASK_RUN_1_EN BIT(5)
|
||||
#define BD72720_MASK_RUN_2_EN BIT(6)
|
||||
#define BD72720_MASK_RUN_3_EN BIT(7)
|
||||
|
||||
#define BD72720_MASK_RAMP_UP_DELAY GENMASK(7, 6)
|
||||
#define BD72720_MASK_BUCK_VSEL GENMASK(7, 0)
|
||||
#define BD72720_MASK_LDO12346_VSEL GENMASK(6, 0)
|
||||
#define BD72720_MASK_LDO_VSEL GENMASK(7, 0)
|
||||
|
||||
#define BD72720_I2C4C_ADDR_OFFSET 0x100
|
||||
|
||||
/* Registers behind I2C slave 0x4c */
|
||||
enum {
|
||||
BD72720_REG_CHG_STATE = BD72720_I2C4C_ADDR_OFFSET,
|
||||
BD72720_REG_CHG_LAST_STATE,
|
||||
BD72720_REG_CHG_VBUS_STAT,
|
||||
BD72720_REG_CHG_VSYS_STAT,
|
||||
BD72720_REG_CHG_BAT_TEMP_STAT,
|
||||
BD72720_REG_CHG_WDT_STAT,
|
||||
BD72720_REG_CHG_ILIM_STAT,
|
||||
BD72720_REG_CHG_CHG_STAT,
|
||||
BD72720_REG_CHG_EN,
|
||||
BD72720_REG_CHG_INIT,
|
||||
BD72720_REG_CHG_CTRL,
|
||||
BD72720_REG_CHG_SET_1,
|
||||
BD72720_REG_CHG_SET_2,
|
||||
BD72720_REG_CHG_SET_3,
|
||||
BD72720_REG_CHG_VPRE,
|
||||
BD72720_REG_CHG_VBAT_1,
|
||||
BD72720_REG_CHG_VBAT_2,
|
||||
BD72720_REG_CHG_VBAT_3,
|
||||
BD72720_REG_CHG_VBAT_4,
|
||||
BD72720_REG_CHG_BAT_SET_1,
|
||||
BD72720_REG_CHG_BAT_SET_2,
|
||||
BD72720_REG_CHG_BAT_SET_3,
|
||||
BD72720_REG_CHG_IPRE,
|
||||
BD72720_REG_CHG_IFST_TERM,
|
||||
BD72720_REG_CHG_VSYS_REG,
|
||||
BD72720_REG_CHG_VBUS_SET,
|
||||
BD72720_REG_CHG_WDT_PRE,
|
||||
BD72720_REG_CHG_WDT_FST,
|
||||
BD72720_REG_CHG_LED_CTRL,
|
||||
BD72720_REG_CHG_CFG_1,
|
||||
BD72720_REG_CHG_IFST_1,
|
||||
BD72720_REG_CHG_IFST_2,
|
||||
BD72720_REG_CHG_IFST_3,
|
||||
BD72720_REG_CHG_IFST_4,
|
||||
BD72720_REG_CHG_S_CFG_1,
|
||||
BD72720_REG_CHG_S_CFG_2,
|
||||
BD72720_REG_RS_VBUS,
|
||||
BD72720_REG_RS_IBUS,
|
||||
BD72720_REG_RS_VSYS,
|
||||
BD72720_REG_VSYS_STATE_STAT, /* 0x27 + offset*/
|
||||
|
||||
BD72720_REG_VM_VBAT_U = BD72720_I2C4C_ADDR_OFFSET + 0x30,
|
||||
BD72720_REG_VM_VBAT_L,
|
||||
BD72720_REG_VM_OCV_PRE_U,
|
||||
BD72720_REG_VM_OCV_PRE_L,
|
||||
BD72720_REG_VM_OCV_PST_U,
|
||||
BD72720_REG_VM_OCV_PST_L,
|
||||
BD72720_REG_VM_OCV_PWRON_U,
|
||||
BD72720_REG_VM_OCV_PWRON_L,
|
||||
BD72720_REG_VM_DVBAT_IMP_U,
|
||||
BD72720_REG_VM_DVBAT_IMP_L,
|
||||
BD72720_REG_VM_SA_VBAT_U,
|
||||
BD72720_REG_VM_SA_VBAT_L,
|
||||
BD72720_REG_VM_SA_VBAT_MIN_U,
|
||||
BD72720_REG_VM_SA_VBAT_MIN_L,
|
||||
BD72720_REG_VM_SA_VBAT_MAX_U,
|
||||
BD72720_REG_VM_SA_VBAT_MAX_L,
|
||||
BD72720_REG_REX_SA_VBAT_U,
|
||||
BD72720_REG_REX_SA_VBAT_L,
|
||||
BD72720_REG_VM_VSYS_U,
|
||||
BD72720_REG_VM_VSYS_L,
|
||||
BD72720_REG_VM_SA_VSYS_U,
|
||||
BD72720_REG_VM_SA_VSYS_L,
|
||||
BD72720_REG_VM_SA_VSYS_MIN_U,
|
||||
BD72720_REG_VM_SA_VSYS_MIN_L,
|
||||
BD72720_REG_VM_SA_VSYS_MAX_U,
|
||||
BD72720_REG_VM_SA_VSYS_MAX_L,
|
||||
BD72720_REG_VM_SA2_VSYS_U,
|
||||
BD72720_REG_VM_SA2_VSYS_L,
|
||||
BD72720_REG_VM_VBUS_U,
|
||||
#define BD72720_MASK_VDCIN_U GENMASK(3, 0)
|
||||
BD72720_REG_VM_VBUS_L,
|
||||
BD72720_REG_VM_BATID_U,
|
||||
BD72720_REG_VM_BATID_L,
|
||||
BD72720_REG_VM_BATID_NOLOAD_U,
|
||||
BD72720_REG_VM_BATID_NOLOAD_L,
|
||||
BD72720_REG_VM_BATID_OFS_U,
|
||||
BD72720_REG_VM_BATID_OFS_L,
|
||||
BD72720_REG_VM_VTH_U,
|
||||
BD72720_REG_VM_VTH_L,
|
||||
BD72720_REG_VM_VTH_CORR_U,
|
||||
BD72720_REG_VM_VTH_CORR_L,
|
||||
BD72720_REG_VM_BTMP_U,
|
||||
BD72720_REG_VM_BTMP_L,
|
||||
BD72720_REG_VM_BTMP_IMP_U,
|
||||
BD72720_REG_VM_BTMP_IMP_L,
|
||||
BD72720_REG_VM_VF_U,
|
||||
BD72720_REG_VM_VF_L,
|
||||
BD72720_REG_VM_BATID_TH_U,
|
||||
BD72720_REG_VM_BATID_TH_L,
|
||||
BD72720_REG_VM_BTMP_OV_THR,
|
||||
BD72720_REG_VM_BTMP_OV_DUR,
|
||||
BD72720_REG_VM_BTMP_LO_THR,
|
||||
BD72720_REG_VM_BTMP_LO_DUR,
|
||||
BD72720_REG_ALM_VBAT_TH_U,
|
||||
BD72720_REG_ALM_VBAT_TH_L,
|
||||
BD72720_REG_ALM_VSYS_TH,
|
||||
BD72720_REG_ALM_VBUS_TH,
|
||||
BD72720_REG_ALM_VF_TH,
|
||||
BD72720_REG_VSYS_MAX,
|
||||
BD72720_REG_VSYS_MIN,
|
||||
BD72720_REG_VM_VSYS_SA_MINMAX_CTRL,
|
||||
BD72720_REG_VM_SA_CFG, /* 0x6c + offset*/
|
||||
|
||||
BD72720_REG_CC_CURCD_U = BD72720_I2C4C_ADDR_OFFSET + 0x70,
|
||||
BD72720_REG_CC_CURCD_L,
|
||||
BD72720_REG_CC_CURCD_IMP_U,
|
||||
BD72720_REG_CC_CURCD_IMP_L,
|
||||
BD72720_REG_CC_SA_CURCD_U,
|
||||
BD72720_REG_CC_SA_CURCD_L,
|
||||
BD72720_REG_CC_OCUR_MON,
|
||||
BD72720_REG_CC_CCNTD_3,
|
||||
BD72720_REG_CC_CCNTD_2,
|
||||
BD72720_REG_CC_CCNTD_1,
|
||||
BD72720_REG_CC_CCNTD_0,
|
||||
BD72720_REG_REX_CCNTD_3,
|
||||
BD72720_REG_REX_CCNTD_2,
|
||||
BD72720_REG_REX_CCNTD_1,
|
||||
BD72720_REG_REX_CCNTD_0,
|
||||
BD72720_REG_FULL_CCNTD_3,
|
||||
BD72720_REG_FULL_CCNTD_2,
|
||||
BD72720_REG_FULL_CCNTD_1,
|
||||
BD72720_REG_FULL_CCNTD_0,
|
||||
BD72720_REG_CCNTD_CHG_3,
|
||||
BD72720_REG_CCNTD_CHG_2,
|
||||
BD72720_REG_CC_STAT,
|
||||
BD72720_REG_CC_CTRL,
|
||||
BD72720_REG_CC_OCUR_THR_1,
|
||||
BD72720_REG_CC_OCUR_THR_2,
|
||||
BD72720_REG_CC_OCUR_THR_3,
|
||||
BD72720_REG_REX_CURCD_TH,
|
||||
BD72720_REG_CC_BATCAP1_TH_U,
|
||||
BD72720_REG_CC_BATCAP1_TH_L,
|
||||
BD72720_REG_CC_BATCAP2_TH_U,
|
||||
BD72720_REG_CC_BATCAP2_TH_L,
|
||||
BD72720_REG_CC_BATCAP3_TH_U,
|
||||
BD72720_REG_CC_BATCAP3_TH_L,
|
||||
BD72720_REG_CC_CCNTD_CTRL,
|
||||
BD72720_REG_CC_SA_CFG, /* 0x92 + offset*/
|
||||
BD72720_REG_IMPCHK_CTRL = BD72720_I2C4C_ADDR_OFFSET + 0xa0,
|
||||
};
|
||||
|
||||
#endif /* __LINUX_MFD_BD72720_H */
|
||||
|
|
@ -16,6 +16,7 @@ enum rohm_chip_type {
|
|||
ROHM_CHIP_TYPE_BD71828,
|
||||
ROHM_CHIP_TYPE_BD71837,
|
||||
ROHM_CHIP_TYPE_BD71847,
|
||||
ROHM_CHIP_TYPE_BD72720,
|
||||
ROHM_CHIP_TYPE_BD96801,
|
||||
ROHM_CHIP_TYPE_BD96802,
|
||||
ROHM_CHIP_TYPE_BD96805,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue