forked from Minki/linux
- Core Frameworks
- Add support for Software Nodes to MFD Core - Remove support for Device Properties from MFD Core - Use standard APIs in MFD Core - New Drivers - Add support for ROHM BD9576MUF and BD9573MUF PMICs - Add support for Netronix Embedded Controller, PWM and RTC - Add support for Actions Semi ATC260x PMICs and OnKey - New Device Support - Add support for DG1 PCIe Graphics Card to Intel PMT - Add support for ROHM BD71815 PMIC to ROHM BD71828 - Add support for Tolino Shine 2 HD to Netronix Embedded Controller - Add support for AX10 BMC Secure Updates to Intel M10 BMC - Removed Device Support - Remove Arizona Extcon support from MFD - Remove ST-E AB8500 Power Supply code from MFD - Remove AB3100 altogether - New Functionality - Add support for SMBus and I2C modes to Dialog DA9063 - Switch to using Software Nodes in Intel (various) - New/converted Device Tree bindings; rohm,bd71815-pmic, rohm,bd9576-pmic, netronix,ntxec, actions,atc260x, ricoh,rn5t618, qcom-pm8xxx - Fix-ups - Fix error handling/path; intel_pmt - Simplify code; rohm-bd718x7, ab8500-core, intel-m10-bmc - Trivial clean-ups (reordering, spelling); rohm-generic, rn5t618, max8997 - Use correct data-type; db8500-prcmu - Remove superfluous code; lp87565, intel_quark_i2c_gpi, lpc_sch, twl - Use generic APIs/defines; lm3533-core, intel_quark_i2c_gpio - Regmap related fix-ups; intel-m10-bmc, sec-core - Reorder resource freeing during remove; intel_quark_i2c_gpio - Make table indexing more robust; intel_quark_i2c_gpio - Fix reference imbalances; arizona-irq - Staticify and (un)constify things; arizona-spi, stmpe, ene-kb3930, intel-lpss-acpi, intel-lpss-pci, atc260x-i2c, intel_quark_i2c_gpio - Bug Fixes - Fix incorrect (register) values; intel-m10-bmc - Kconfig related fixes; ABX500_CORE - Do not clear the Auto Reload Register; stm32-timers -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEdrbJNaO+IJqU8IdIUa+KL4f8d2EFAmCJIPEACgkQUa+KL4f8 d2FRZA//Xu9f8u2uLuIfuhxIjUUXOqIjRAFnkhKlgGZhKsY8BohjQ80Tj9yp6UKy St6ABwACO0hJap4zL4FxPW9+HXTmqZvAibnvHnvZdYSQ3ai6x9h6kTNvhSNLeRQU fuY7eN8kpAHHiHNKNJCsQLQMvcIyP7+0KAP6qir5GYsMjiXspWq7THUnfBi2JXC6 y60guDo9XrgmQTO+pB870UJrKLM/h+iiohNRGxLFlShKhFCgbTB/wyw6bFeKy1SB 0/6XuY6fOt1IQyBDuzw383Q2faMWO9U+es29bwvFxdqJDK0MHQXC47zBba2q94wL /9i/HSoz9dRHnTJNYUKWsVcPv4T84w/Iq7scyDvE00ubehJ+oo/M7Au3M6Tt3M1/ 6lBAwFYXiwhQnp9EP3nwPwgJF6JzX1IGuMOsUAqrVFOEMuIkZKbRdUlatUhqepJT spV4/TOfztAhY/7BzEOZLnF8cFNjmL5sn42/UzSRW708V5SxuTNsS48KJ4l0c7Er CZSTlR/T1rKkWqf7ejaS2TNqMCdYyB3vZW0quDxZTHTZHv9huNUvtbKPR7jmd+4p mrMIik7EE4BzC5m8tBPnXXZl+Og0keeYv4LUDBuLDX1agrxYIErl4ITvQTqqMfX1 Jt14SIjSO56iu2ngQuvGWwegVK4/urO2kBJKUAH1QN1OocNaajQ= =IJSL -----END PGP SIGNATURE----- Merge tag 'mfd-next-5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd Pull MFD updates from Lee Jones: "Core Framework: - Add support for Software Nodes to MFD Core - Remove support for Device Properties from MFD Core - Use standard APIs in MFD Core New Drivers: - Add support for ROHM BD9576MUF and BD9573MUF PMICs - Add support for Netronix Embedded Controller, PWM and RTC - Add support for Actions Semi ATC260x PMICs and OnKey New Device Support: - Add support for DG1 PCIe Graphics Card to Intel PMT - Add support for ROHM BD71815 PMIC to ROHM BD71828 - Add support for Tolino Shine 2 HD to Netronix Embedded Controller - Add support for AX10 BMC Secure Updates to Intel M10 BMC Removed Device Support: - Remove Arizona Extcon support from MFD - Remove ST-E AB8500 Power Supply code from MFD - Remove AB3100 altogether New Functionality: - Add support for SMBus and I2C modes to Dialog DA9063 - Switch to using Software Nodes in Intel (various) New/converted Device Tree bindings: - rohm bd71815-pmic, rohm bd9576-pmic, netronix ntxec, actions atc260x, ricoh rn5t618, qcom pm8xxx - Fix-ups: - Fix error handling/path; intel_pmt - Simplify code; rohm-bd718x7, ab8500-core, intel-m10-bmc - Trivial clean-ups (reordering, spelling); rohm-generic, rn5t618, max8997 - Use correct data-type; db8500-prcmu - Remove superfluous code; lp87565, intel_quark_i2c_gpi, lpc_sch, twl - Use generic APIs/defines; lm3533-core, intel_quark_i2c_gpio - Regmap related fix-ups; intel-m10-bmc, sec-core - Reorder resource freeing during remove; intel_quark_i2c_gpio - Make table indexing more robust; intel_quark_i2c_gpio - Fix reference imbalances; arizona-irq - Staticify and (un)constify things; arizona-spi, stmpe, ene-kb3930, intel-lpss-acpi, intel-lpss-pci, atc260x-i2c, intel_quark_i2c_gpio Bug Fixes: - Fix incorrect (register) values; intel-m10-bmc - Kconfig related fixes; ABX500_CORE - Do not clear the Auto Reload Register; stm32-timers" * tag 'mfd-next-5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (84 commits) mfd: intel-m10-bmc: Add support for MAX10 BMC Secure Updates Revert "mfd: max8997: Add of_compatible to Extcon and Charger mfd_cell" mfd: twl: Remove unused inline function twl4030charger_usb_en() dt-bindings: mfd: Convert pm8xxx bindings to yaml dt-bindings: mfd: Add compatible for pmk8350 rtc i2c: designware: Get rid of legacy platform data mfd: intel_quark_i2c_gpio: Convert I²C to use software nodes mfd: lpc_sch: Partially revert "Add support for Intel Quark X1000" mfd: arizona: Fix rumtime PM imbalance on error mfd: max8997: Replace 8998 with 8997 mfd: core: Use acpi_find_child_device() for child devices lookup mfd: intel_quark_i2c_gpio: Don't play dirty trick with const mfd: intel_quark_i2c_gpio: Enable MSI interrupt mfd: intel_quark_i2c_gpio: Reuse BAR definitions for MFD cell indexing mfd: ntxec: Support for EC in Tolino Shine 2 HD mfd: stm32-timers: Avoid clearing auto reload register mfd: intel_quark_i2c_gpio: Replace I²C speeds with descriptive definitions mfd: intel_quark_i2c_gpio: Remove unused struct device member mfd: intel_quark_i2c_gpio: Unregister resources in reversed order mfd: Kconfig: ABX500_CORE should depend on ARCH_U8500 ...
This commit is contained in:
commit
71a5cc28e8
3
CREDITS
3
CREDITS
@ -1933,6 +1933,9 @@ N: Kukjin Kim
|
||||
E: kgene@kernel.org
|
||||
D: Samsung S3C, S5P and Exynos ARM architectures
|
||||
|
||||
N: Milo Kim
|
||||
D: TI LP855x, LP8727 and LP8788 drivers
|
||||
|
||||
N: Sangbeom Kim
|
||||
E: sbkim73@samsung.com
|
||||
D: Samsung SoC Audio (ASoC) drivers
|
||||
|
@ -33,4 +33,11 @@ properties:
|
||||
power off automatically. Device with key pressed shutdown feature can
|
||||
specify this property.
|
||||
|
||||
reset-time-sec:
|
||||
description:
|
||||
Duration in seconds which the key should be kept pressed for device to
|
||||
reset automatically. Device with key pressed reset feature can specify
|
||||
this property.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
|
||||
additionalProperties: true
|
||||
|
183
Documentation/devicetree/bindings/mfd/actions,atc260x.yaml
Normal file
183
Documentation/devicetree/bindings/mfd/actions,atc260x.yaml
Normal file
@ -0,0 +1,183 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mfd/actions,atc260x.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Actions Semi ATC260x Power Management IC bindings
|
||||
|
||||
maintainers:
|
||||
- Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
- Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
|
||||
|
||||
description: |
|
||||
ATC260x series PMICs integrates Audio Codec, Power Management, RTC, IR
|
||||
and GPIO controller blocks. Currently only the PM related functionalities
|
||||
(i.e. regulators and system power-off/reboot) for the ATC2603C and ATC2609A
|
||||
chip variants are supported.
|
||||
ATC2603C includes 3 programmable DC-DC converters, 9 programmable LDO
|
||||
regulators and 1 fixed LDO regulator.
|
||||
ATC2609A includes 5 programmable DC-DC converters and 10 programmable LDO
|
||||
regulators.
|
||||
|
||||
allOf:
|
||||
- $ref: ../input/input.yaml
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- actions,atc2603c
|
||||
- actions,atc2609a
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
reset-time-sec:
|
||||
description: |
|
||||
Duration in seconds which the key should be kept pressed for device
|
||||
to reset automatically. The hardware default is 8. Use 0 to disable
|
||||
this functionality.
|
||||
enum: [0, 6, 8, 10, 12]
|
||||
|
||||
regulators:
|
||||
type: object
|
||||
description: |
|
||||
List of child nodes specifying the regulators, depending on chip variant:
|
||||
* ATC2603C: dcdc[1-3], ldo[1-3,5-8,11,12], switchldo1
|
||||
* ATC2609A: dcdc[0-4], ldo[0-9]
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- actions,atc2603c-regulator
|
||||
- actions,atc2609a-regulator
|
||||
|
||||
switchldo1:
|
||||
type: object
|
||||
$ref: ../regulator/regulator.yaml
|
||||
|
||||
properties:
|
||||
regulator-name: true
|
||||
regulator-boot-on: true
|
||||
regulator-always-on: true
|
||||
regulator-min-microvolt: true
|
||||
regulator-max-microvolt: true
|
||||
regulator-allow-bypass: true
|
||||
regulator-active-discharge: true
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
patternProperties:
|
||||
"^(dcdc[0-4]|ldo[0-9]|ldo1[1-2]|switchldo1)-supply$":
|
||||
description: ATC260x voltage regulators supplies
|
||||
|
||||
"^(dcdc[0-4]|ldo[0-9]|ldo1[1-2])$":
|
||||
type: object
|
||||
$ref: ../regulator/regulator.yaml
|
||||
|
||||
properties:
|
||||
regulator-name: true
|
||||
regulator-boot-on: true
|
||||
regulator-always-on: true
|
||||
regulator-min-microvolt: true
|
||||
regulator-max-microvolt: true
|
||||
regulator-allow-bypass: true
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: actions,atc2603c-regulator
|
||||
then:
|
||||
patternProperties:
|
||||
"^(dcdc[0,4]|ldo[0,4,9])(-supply)?$": false
|
||||
|
||||
"^(ldo|dcdc)":
|
||||
properties:
|
||||
regulator-allow-bypass: false
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: actions,atc2609a-regulator
|
||||
then:
|
||||
patternProperties:
|
||||
"^(ldo1[1-2]|switchldo1)(-supply)?$": false
|
||||
|
||||
"^(dcdc|ldo[3-9])":
|
||||
properties:
|
||||
regulator-allow-bypass: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
i2c0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
pmic@65 {
|
||||
compatible = "actions,atc2603c";
|
||||
reg = <0x65>;
|
||||
interrupt-parent = <&sirq>;
|
||||
interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
|
||||
|
||||
reset-time-sec = <6>;
|
||||
|
||||
regulators {
|
||||
compatible = "actions,atc2603c-regulator";
|
||||
|
||||
dcdc1-supply = <®_5v0>;
|
||||
dcdc3-supply = <®_5v0>;
|
||||
ldo5-supply = <®_5v0>;
|
||||
switchldo1-supply = <&vcc>;
|
||||
|
||||
vdd_cpu: dcdc1 {
|
||||
regulator-name = "VDD_CPU";
|
||||
regulator-min-microvolt = <700000>;
|
||||
regulator-max-microvolt = <1400000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
vcc: dcdc3 {
|
||||
regulator-name = "VCC";
|
||||
regulator-min-microvolt = <2600000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
vcc_3v1: ldo5 {
|
||||
regulator-name = "VCC_3V1";
|
||||
regulator-min-microvolt = <2600000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
};
|
||||
|
||||
sd_vcc: switchldo1 {
|
||||
regulator-name = "SD_VCC";
|
||||
regulator-min-microvolt = <3000000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
76
Documentation/devicetree/bindings/mfd/netronix,ntxec.yaml
Normal file
76
Documentation/devicetree/bindings/mfd/netronix,ntxec.yaml
Normal file
@ -0,0 +1,76 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mfd/netronix,ntxec.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Netronix Embedded Controller
|
||||
|
||||
maintainers:
|
||||
- Jonathan Neuschäfer <j.neuschaefer@gmx.net>
|
||||
|
||||
description: |
|
||||
This EC is found in e-book readers of multiple brands (e.g. Kobo, Tolino), and
|
||||
is typically implemented as a TI MSP430 microcontroller.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: netronix,ntxec
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: The I2C address of the EC
|
||||
|
||||
system-power-controller:
|
||||
type: boolean
|
||||
description: See Documentation/devicetree/bindings/power/power-controller.txt
|
||||
|
||||
interrupts:
|
||||
minItems: 1
|
||||
description:
|
||||
The EC can signal interrupts via a GPIO line
|
||||
|
||||
"#pwm-cells":
|
||||
const: 2
|
||||
description: |
|
||||
Number of cells in a PWM specifier.
|
||||
|
||||
The following PWM channels are supported:
|
||||
- 0: The PWM channel controlled by registers 0xa1-0xa7
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ec: embedded-controller@43 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_ntxec>;
|
||||
|
||||
compatible = "netronix,ntxec";
|
||||
reg = <0x43>;
|
||||
system-power-controller;
|
||||
interrupt-parent = <&gpio4>;
|
||||
interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
|
||||
#pwm-cells = <2>;
|
||||
};
|
||||
};
|
||||
|
||||
backlight {
|
||||
compatible = "pwm-backlight";
|
||||
pwms = <&ec 0 50000>;
|
||||
power-supply = <&backlight_regulator>;
|
||||
};
|
||||
|
||||
backlight_regulator: regulator-dummy {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "backlight";
|
||||
};
|
@ -1,99 +0,0 @@
|
||||
Qualcomm PM8xxx PMIC multi-function devices
|
||||
|
||||
The PM8xxx family of Power Management ICs are used to provide regulated
|
||||
voltages and other various functionality to Qualcomm SoCs.
|
||||
|
||||
= PROPERTIES
|
||||
|
||||
- compatible:
|
||||
Usage: required
|
||||
Value type: <string>
|
||||
Definition: must be one of:
|
||||
"qcom,pm8058"
|
||||
"qcom,pm8821"
|
||||
"qcom,pm8921"
|
||||
|
||||
- #address-cells:
|
||||
Usage: required
|
||||
Value type: <u32>
|
||||
Definition: must be 1
|
||||
|
||||
- #size-cells:
|
||||
Usage: required
|
||||
Value type: <u32>
|
||||
Definition: must be 0
|
||||
|
||||
- interrupts:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: specifies the interrupt that indicates a subdevice
|
||||
has generated an interrupt (summary interrupt). The
|
||||
format of the specifier is defined by the binding document
|
||||
describing the node's interrupt parent.
|
||||
|
||||
- #interrupt-cells:
|
||||
Usage: required
|
||||
Value type : <u32>
|
||||
Definition: must be 2. Specifies the number of cells needed to encode
|
||||
an interrupt source. The 1st cell contains the interrupt
|
||||
number. The 2nd cell is the trigger type and level flags
|
||||
encoded as follows:
|
||||
|
||||
1 = low-to-high edge triggered
|
||||
2 = high-to-low edge triggered
|
||||
4 = active high level-sensitive
|
||||
8 = active low level-sensitive
|
||||
|
||||
- interrupt-controller:
|
||||
Usage: required
|
||||
Value type: <empty>
|
||||
Definition: identifies this node as an interrupt controller
|
||||
|
||||
= SUBCOMPONENTS
|
||||
|
||||
The PMIC contains multiple independent functions, each described in a subnode.
|
||||
The below bindings specify the set of valid subnodes.
|
||||
|
||||
== Real-Time Clock
|
||||
|
||||
- compatible:
|
||||
Usage: required
|
||||
Value type: <string>
|
||||
Definition: must be one of:
|
||||
"qcom,pm8058-rtc"
|
||||
"qcom,pm8921-rtc"
|
||||
"qcom,pm8941-rtc"
|
||||
"qcom,pm8018-rtc"
|
||||
|
||||
- reg:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: single entry specifying the base address of the RTC registers
|
||||
|
||||
- interrupts:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: single entry specifying the RTC's alarm interrupt
|
||||
|
||||
- allow-set-time:
|
||||
Usage: optional
|
||||
Value type: <empty>
|
||||
Definition: indicates that the setting of RTC time is allowed by
|
||||
the host CPU
|
||||
|
||||
= EXAMPLE
|
||||
|
||||
pmicintc: pmic@0 {
|
||||
compatible = "qcom,pm8921";
|
||||
interrupts = <104 8>;
|
||||
#interrupt-cells = <2>;
|
||||
interrupt-controller;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
rtc@11d {
|
||||
compatible = "qcom,pm8921-rtc";
|
||||
reg = <0x11d>;
|
||||
interrupts = <0x27 0>;
|
||||
};
|
||||
};
|
54
Documentation/devicetree/bindings/mfd/qcom-pm8xxx.yaml
Normal file
54
Documentation/devicetree/bindings/mfd/qcom-pm8xxx.yaml
Normal file
@ -0,0 +1,54 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mfd/qcom-pm8xxx.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm PM8xxx PMIC multi-function devices
|
||||
|
||||
maintainers:
|
||||
- Satya Priya <skakit@codeaurora.org>
|
||||
|
||||
description: |
|
||||
The PM8xxx family of Power Management ICs are used to provide regulated
|
||||
voltages and other various functionality to Qualcomm SoCs.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,pm8058
|
||||
- qcom,pm8821
|
||||
- qcom,pm8921
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
'#address-cells':
|
||||
const: 1
|
||||
|
||||
'#size-cells':
|
||||
const: 0
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
'#interrupt-cells':
|
||||
const: 2
|
||||
|
||||
interrupt-controller: true
|
||||
|
||||
patternProperties:
|
||||
"rtc@[0-9a-f]+$":
|
||||
type: object
|
||||
$ref: "../rtc/qcom-pm8xxx-rtc.yaml"
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- '#address-cells'
|
||||
- '#size-cells'
|
||||
- interrupts
|
||||
- '#interrupt-cells'
|
||||
- interrupt-controller
|
||||
|
||||
additionalProperties: false
|
||||
...
|
111
Documentation/devicetree/bindings/mfd/ricoh,rn5t618.yaml
Normal file
111
Documentation/devicetree/bindings/mfd/ricoh,rn5t618.yaml
Normal file
@ -0,0 +1,111 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mfd/ricoh,rn5t618.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Ricoh RN5T567/RN5T618/RC5T619 PMIC
|
||||
|
||||
maintainers:
|
||||
- Andreas Kemnade <andreas@kemnade.info>
|
||||
|
||||
description: |
|
||||
Ricoh RN5T567/RN5T618/RC5T619 is a power management IC family which
|
||||
integrates 3 to 5 step-down DCDC converters, 7 to 10 low-dropout regulators,
|
||||
GPIOs, and a watchdog timer. It can be controlled through an I2C interface.
|
||||
The RN5T618/RC5T619 provides additionally a Li-ion battery charger,
|
||||
fuel gauge, and an ADC.
|
||||
The RC5T619 additionally includes USB charger detection and an RTC.
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: ricoh,rn5t567
|
||||
then:
|
||||
properties:
|
||||
regulators:
|
||||
patternProperties:
|
||||
"^(DCDC[1-4]|LDO[1-5]|LDORTC[12])$":
|
||||
$ref: ../regulator/regulator.yaml
|
||||
additionalProperties: false
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: ricoh,rn5t618
|
||||
then:
|
||||
properties:
|
||||
regulators:
|
||||
patternProperties:
|
||||
"^(DCDC[1-3]|LDO[1-5]|LDORTC[12])$":
|
||||
$ref: ../regulator/regulator.yaml
|
||||
additionalProperties: false
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: ricoh,rc5t619
|
||||
then:
|
||||
properties:
|
||||
regulators:
|
||||
patternProperties:
|
||||
"^(DCDC[1-5]|LDO[1-9]|LDO10|LDORTC[12])$":
|
||||
$ref: ../regulator/regulator.yaml
|
||||
additionalProperties: false
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ricoh,rn5t567
|
||||
- ricoh,rn5t618
|
||||
- ricoh,rc5t619
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
system-power-controller:
|
||||
type: boolean
|
||||
description: |
|
||||
See Documentation/devicetree/bindings/power/power-controller.txt
|
||||
|
||||
regulators:
|
||||
type: object
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
pmic@32 {
|
||||
compatible = "ricoh,rn5t618";
|
||||
reg = <0x32>;
|
||||
interrupt-parent = <&gpio5>;
|
||||
interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
|
||||
system-power-controller;
|
||||
|
||||
regulators {
|
||||
DCDC1 {
|
||||
regulator-min-microvolt = <1050000>;
|
||||
regulator-max-microvolt = <1050000>;
|
||||
};
|
||||
|
||||
DCDC2 {
|
||||
regulator-min-microvolt = <1175000>;
|
||||
regulator-max-microvolt = <1175000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
@ -1,52 +0,0 @@
|
||||
* Ricoh RN5T567/RN5T618 PMIC
|
||||
|
||||
Ricoh RN5T567/RN5T618/RC5T619 is a power management IC family which
|
||||
integrates 3 to 5 step-down DCDC converters, 7 to 10 low-dropout regulators,
|
||||
GPIOs, and a watchdog timer. It can be controlled through an I2C interface.
|
||||
The RN5T618/RC5T619 provides additionally a Li-ion battery charger,
|
||||
fuel gauge, and an ADC.
|
||||
The RC5T619 additionnally includes USB charger detection and an RTC.
|
||||
|
||||
Required properties:
|
||||
- compatible: must be one of
|
||||
"ricoh,rn5t567"
|
||||
"ricoh,rn5t618"
|
||||
"ricoh,rc5t619"
|
||||
- reg: the I2C slave address of the device
|
||||
|
||||
Optional properties:
|
||||
- interrupts: interrupt mapping for IRQ
|
||||
See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
|
||||
- system-power-controller:
|
||||
See Documentation/devicetree/bindings/power/power-controller.txt
|
||||
|
||||
Sub-nodes:
|
||||
- regulators: the node is required if the regulator functionality is
|
||||
needed. The valid regulator names are: DCDC1, DCDC2, DCDC3, DCDC4
|
||||
(RN5T567/RC5T619), LDO1, LDO2, LDO3, LDO4, LDO5, LDO6, LDO7, LDO8,
|
||||
LDO9, LDO10, LDORTC1 and LDORTC2.
|
||||
LDO7-10 are specific to RC5T619.
|
||||
The common bindings for each individual regulator can be found in:
|
||||
Documentation/devicetree/bindings/regulator/regulator.txt
|
||||
|
||||
Example:
|
||||
|
||||
pmic@32 {
|
||||
compatible = "ricoh,rn5t618";
|
||||
reg = <0x32>;
|
||||
interrupt-parent = <&gpio5>;
|
||||
interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
|
||||
system-power-controller;
|
||||
|
||||
regulators {
|
||||
DCDC1 {
|
||||
regulator-min-microvolt = <1050000>;
|
||||
regulator-max-microvolt = <1050000>;
|
||||
};
|
||||
|
||||
DCDC2 {
|
||||
regulator-min-microvolt = <1175000>;
|
||||
regulator-max-microvolt = <1175000>;
|
||||
};
|
||||
};
|
||||
};
|
201
Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml
Normal file
201
Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml
Normal file
@ -0,0 +1,201 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mfd/rohm,bd71815-pmic.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: ROHM BD71815 Power Management Integrated Circuit bindings
|
||||
|
||||
maintainers:
|
||||
- Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
|
||||
|
||||
description: |
|
||||
BD71815AGW is a single-chip power management ICs for battery-powered
|
||||
portable devices. It integrates 5 buck converters, 8 LDOs, a boost driver
|
||||
for LED and a 500 mA single-cell linear charger. Also included is a Coulomb
|
||||
counter, a real-time clock (RTC), and a 32.768 kHz clock gate and two GPOs.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: rohm,bd71815
|
||||
|
||||
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 ../gpio/gpio.txt for more information.
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
"#clock-cells":
|
||||
const: 0
|
||||
|
||||
clock-output-names:
|
||||
const: bd71815-32k-out
|
||||
|
||||
rohm,clkout-open-drain:
|
||||
description: clk32kout mode. Set to 1 for "open-drain" or 0 for "cmos".
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
minimum: 0
|
||||
maximum: 1
|
||||
|
||||
rohm,charger-sense-resistor-ohms:
|
||||
minimum: 10000000
|
||||
maximum: 50000000
|
||||
description: |
|
||||
BD71827 and BD71828 have SAR ADC for measuring charging currents.
|
||||
External sense resistor (RSENSE in data sheet) should be used. If
|
||||
something other but 30MOhm resistor is used the resistance value
|
||||
should be given here in Ohms.
|
||||
default: 30000000
|
||||
|
||||
regulators:
|
||||
$ref: ../regulator/rohm,bd71815-regulator.yaml
|
||||
description:
|
||||
List of child nodes that specify the regulators.
|
||||
|
||||
gpio-reserved-ranges:
|
||||
description: |
|
||||
Usage of BD71828 GPIO pins can be changed via OTP. This property can be
|
||||
used to mark the pins which should not be configured for GPIO. Please see
|
||||
the ../gpio/gpio.txt for more information.
|
||||
|
||||
rohm,enable-hidden-gpo:
|
||||
description: |
|
||||
The BD71815 has undocumented GPO at pin E5. Pin is marked as GND at the
|
||||
data-sheet as it's location in the middle of GND pins makes it hard to
|
||||
use on PCB. If your board has managed to use this pin you can enable the
|
||||
second GPO by defining this property. Dont enable this if you are unsure
|
||||
about how the E5 pin is connected on your board.
|
||||
type: boolean
|
||||
|
||||
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,bd71815";
|
||||
reg = <0x4b>;
|
||||
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
|
||||
|
||||
clocks = <&osc 0>;
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "bd71815-32k-out";
|
||||
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
||||
rohm,charger-sense-resistor-ohms = <10000000>;
|
||||
|
||||
regulators {
|
||||
buck1: buck1 {
|
||||
regulator-name = "buck1";
|
||||
regulator-min-microvolt = <800000>;
|
||||
regulator-max-microvolt = <2000000>;
|
||||
regulator-always-on;
|
||||
regulator-ramp-delay = <1250>;
|
||||
rohm,dvs-run-voltage = <1150000>;
|
||||
rohm,dvs-suspend-voltage = <950000>;
|
||||
};
|
||||
buck2: buck2 {
|
||||
regulator-name = "buck2";
|
||||
regulator-min-microvolt = <800000>;
|
||||
regulator-max-microvolt = <2000000>;
|
||||
regulator-always-on;
|
||||
regulator-ramp-delay = <1250>;
|
||||
rohm,dvs-run-voltage = <1150000>;
|
||||
rohm,dvs-suspend-voltage = <950000>;
|
||||
};
|
||||
buck3: buck3 {
|
||||
regulator-name = "buck3";
|
||||
regulator-min-microvolt = <1200000>;
|
||||
regulator-max-microvolt = <2700000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
buck4: buck4 {
|
||||
regulator-name = "buck4";
|
||||
regulator-min-microvolt = <1100000>;
|
||||
regulator-max-microvolt = <1850000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
buck5: buck5 {
|
||||
regulator-name = "buck5";
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
ldo1: ldo1 {
|
||||
regulator-name = "ldo1";
|
||||
regulator-min-microvolt = <800000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
ldo2: ldo2 {
|
||||
regulator-name = "ldo2";
|
||||
regulator-min-microvolt = <800000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
ldo3: ldo3 {
|
||||
regulator-name = "ldo3";
|
||||
regulator-min-microvolt = <800000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
ldo4: ldo4 {
|
||||
regulator-name = "ldo4";
|
||||
regulator-min-microvolt = <800000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
ldo5: ldo5 {
|
||||
regulator-name = "ldo5";
|
||||
regulator-min-microvolt = <800000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-always-on;
|
||||
};
|
||||
ldo6: ldodvref {
|
||||
regulator-name = "ldodvref";
|
||||
regulator-always-on;
|
||||
};
|
||||
ldo7: ldolpsr {
|
||||
regulator-name = "ldolpsr";
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
boost: wled {
|
||||
regulator-name = "wled";
|
||||
regulator-min-microamp = <10>;
|
||||
regulator-max-microamp = <25000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
@ -44,6 +44,12 @@ properties:
|
||||
clock-output-names:
|
||||
const: bd71828-32k-out
|
||||
|
||||
rohm,clkout-open-drain:
|
||||
description: clk32kout mode. Set to 1 for "open-drain" or 0 for "cmos".
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
minimum: 0
|
||||
maximum: 1
|
||||
|
||||
rohm,charger-sense-resistor-ohms:
|
||||
minimum: 10000000
|
||||
maximum: 50000000
|
||||
|
123
Documentation/devicetree/bindings/mfd/rohm,bd9576-pmic.yaml
Normal file
123
Documentation/devicetree/bindings/mfd/rohm,bd9576-pmic.yaml
Normal file
@ -0,0 +1,123 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mfd/rohm,bd9576-pmic.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: ROHM BD9576MUF and BD9573MUF Power Management Integrated Circuit bindings
|
||||
|
||||
maintainers:
|
||||
- Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
|
||||
|
||||
description: |
|
||||
BD9576MUF and BD9573MUF are power management ICs primarily intended for
|
||||
powering the R-Car series processors.
|
||||
The IC provides 6 power outputs with configurable sequencing and safety
|
||||
monitoring. A watchdog logic with slow ping/windowed modes is also included.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- rohm,bd9576
|
||||
- rohm,bd9573
|
||||
|
||||
reg:
|
||||
description:
|
||||
I2C slave address.
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
rohm,vout1-en-low:
|
||||
description:
|
||||
BD9576 and BD9573 VOUT1 regulator enable state can be individually
|
||||
controlled by a GPIO. This is dictated by state of vout1-en pin during
|
||||
the PMIC startup. If vout1-en is LOW during PMIC startup then the VOUT1
|
||||
enable sate is controlled via this pin. Set this property if vout1-en
|
||||
is wired to be down at PMIC start-up.
|
||||
type: boolean
|
||||
|
||||
rohm,vout1-en-gpios:
|
||||
description:
|
||||
GPIO specifier to specify the GPIO connected to vout1-en for vout1 ON/OFF
|
||||
state control.
|
||||
maxItems: 1
|
||||
|
||||
rohm,ddr-sel-low:
|
||||
description:
|
||||
The BD9576 and BD9573 output voltage for DDR can be selected by setting
|
||||
the ddr-sel pin low or high. Set this property if ddr-sel is grounded.
|
||||
type: boolean
|
||||
|
||||
rohm,watchdog-enable-gpios:
|
||||
description: The GPIO line used to enable the watchdog.
|
||||
maxItems: 1
|
||||
|
||||
rohm,watchdog-ping-gpios:
|
||||
description: The GPIO line used to ping the watchdog.
|
||||
maxItems: 1
|
||||
|
||||
rohm,hw-timeout-ms:
|
||||
maxItems: 2
|
||||
description:
|
||||
Watchog timeout in milliseconds. If single value is given it is
|
||||
the maximum timeout. Eg. if pinging watchdog is not done within this time
|
||||
limit the watchdog will be triggered. If two values are given watchdog
|
||||
is configured in "window mode". Then first value is limit for short-ping
|
||||
Eg. if watchdog is pinged sooner than that the watchdog will trigger.
|
||||
When two values is given the second value is the maximum timeout.
|
||||
# (HW) minimum for short timeout is 2ms, maximum 220 ms.
|
||||
# (HW) minimum for max timeout is 4ms, maximum 4416 ms.
|
||||
|
||||
regulators:
|
||||
$ref: ../regulator/rohm,bd9576-regulator.yaml
|
||||
description:
|
||||
List of child nodes that specify the regulators.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- regulators
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/leds/common.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
pmic: pmic@30 {
|
||||
compatible = "rohm,bd9576";
|
||||
reg = <0x30>;
|
||||
rohm,vout1-en-low;
|
||||
rohm,vout1-en-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>;
|
||||
rohm,ddr-sel-low;
|
||||
rohm,watchdog-enable-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>;
|
||||
rohm,watchdog-ping-gpios = <&gpio2 7 GPIO_ACTIVE_HIGH>;
|
||||
rohm,hw-timeout-ms = <150>, <2300>;
|
||||
|
||||
regulators {
|
||||
boost1: regulator-vd50 {
|
||||
regulator-name = "VD50";
|
||||
};
|
||||
buck1: regulator-vd18 {
|
||||
regulator-name = "VD18";
|
||||
};
|
||||
buck2: regulator-vdddr {
|
||||
regulator-name = "VDDDR";
|
||||
};
|
||||
buck3: regulator-vd10 {
|
||||
regulator-name = "VD10";
|
||||
};
|
||||
ldo: regulator-voutl1 {
|
||||
regulator-name = "VOUTL1";
|
||||
};
|
||||
sw: regulator-vouts1 {
|
||||
regulator-name = "VOUTS1";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
@ -17,6 +17,10 @@ properties:
|
||||
description: I2C slave address
|
||||
const: 0x60
|
||||
|
||||
reset-gpios:
|
||||
description: GPIO connected to NRST pin (active low reset, pin 20)
|
||||
maxItems: 1
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
'#gpio-cells':
|
||||
|
@ -17,6 +17,10 @@ properties:
|
||||
description: I2C slave address
|
||||
const: 0x60
|
||||
|
||||
reset-gpios:
|
||||
description: GPIO connected to NRST pin (active low reset, pin 20)
|
||||
maxItems: 1
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
'#gpio-cells':
|
||||
|
@ -19,6 +19,10 @@ properties:
|
||||
description: I2C slave address
|
||||
const: 0x60
|
||||
|
||||
reset-gpios:
|
||||
description: GPIO connected to NRST pin (active low reset, pin 20)
|
||||
maxItems: 1
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
'#gpio-cells':
|
||||
|
@ -0,0 +1,116 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/regulator/rohm,bd71815-regulator.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: ROHM BD71815 Power Management Integrated Circuit regulators
|
||||
|
||||
maintainers:
|
||||
- Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
|
||||
|
||||
description: |
|
||||
This module is part of the ROHM BD718215 MFD device. For more details
|
||||
see Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml.
|
||||
|
||||
The regulator controller is represented as a sub-node of the PMIC node
|
||||
on the device tree.
|
||||
|
||||
The valid names for BD71815 regulator nodes are
|
||||
buck1, buck2, buck3, buck4, buck5,
|
||||
ldo1, ldo2, ldo3, ldo4, ldo5,
|
||||
ldodvref, ldolpsr, wled
|
||||
|
||||
properties:
|
||||
wled:
|
||||
type: object
|
||||
description:
|
||||
properties for wled regulator
|
||||
$ref: regulator.yaml#
|
||||
|
||||
properties:
|
||||
regulator-name:
|
||||
const: wled
|
||||
|
||||
patternProperties:
|
||||
"^((ldo|buck)[1-5]|ldolpsr|ldodvref)$":
|
||||
type: object
|
||||
description:
|
||||
Properties for single LDO/BUCK regulator.
|
||||
$ref: regulator.yaml#
|
||||
|
||||
properties:
|
||||
regulator-name:
|
||||
pattern: "^((ldo|buck)[1-5]|ldolpsr|ldodvref)$"
|
||||
description:
|
||||
should be "ldo1", ..., "ldo5", "buck1", ..., "buck5" and "ldolpsr"
|
||||
for ldolpsr regulator, "ldodvref" for ldodvref reglator.
|
||||
|
||||
rohm,vsel-gpios:
|
||||
description:
|
||||
GPIO used to control ldo4 state (when ldo4 is controlled by GPIO).
|
||||
|
||||
rohm,dvs-run-voltage:
|
||||
description:
|
||||
PMIC "RUN" state voltage in uV when PMIC HW states are used. See
|
||||
comments below for bucks/LDOs which support this. 0 means
|
||||
regulator should be disabled at RUN state.
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
minimum: 0
|
||||
maximum: 3300000
|
||||
|
||||
rohm,dvs-snvs-voltage:
|
||||
description:
|
||||
Whether to keep regulator enabled at "SNVS" state or not.
|
||||
0 means regulator should be disabled at SNVS state, non zero voltage
|
||||
keeps regulator enabled. BD71815 does not change voltage level
|
||||
when PMIC transitions to SNVS.SNVS voltage depends on the previous
|
||||
state (from which the PMIC transitioned to SNVS).
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
minimum: 0
|
||||
maximum: 3300000
|
||||
|
||||
rohm,dvs-suspend-voltage:
|
||||
description:
|
||||
PMIC "SUSPEND" state voltage in uV when PMIC HW states are used. See
|
||||
comments below for bucks/LDOs which support this. 0 means
|
||||
regulator should be disabled at SUSPEND state.
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
minimum: 0
|
||||
maximum: 3300000
|
||||
|
||||
rohm,dvs-lpsr-voltage:
|
||||
description:
|
||||
PMIC "LPSR" state voltage in uV when PMIC HW states are used. See
|
||||
comments below for bucks/LDOs which support this. 0 means
|
||||
regulator should be disabled at LPSR state.
|
||||
$ref: "/schemas/types.yaml#/definitions/uint32"
|
||||
minimum: 0
|
||||
maximum: 3300000
|
||||
|
||||
# Bucks 1 and 2 support giving separate voltages for operational states
|
||||
# (RUN /CLEAN according to data-sheet) and non operational states
|
||||
# (LPSR/SUSPEND). The voltage is automatically changed when HW
|
||||
# state changes. Omitting these properties from bucks 1 and 2 leave
|
||||
# buck voltages to not be toggled by HW state. Enable status may still
|
||||
# be toggled by state changes depending on HW default settings.
|
||||
#
|
||||
# Bucks 3-5 and ldos 1-5 support setting the RUN state voltage here.
|
||||
# Given RUN voltage is used at all states if regulator is enabled at
|
||||
# given state.
|
||||
# Values given for other states are regarded as enable/disable at
|
||||
# given state (see below).
|
||||
#
|
||||
# All regulators except WLED support specifying enable/disable status
|
||||
# for each of the HW states (RUN/SNVS/SUSPEND/LPSR). HW defaults can
|
||||
# be overridden by setting voltage to 0 (regulator disabled at given
|
||||
# state) or non-zero (regulator enabled at given state). Please note
|
||||
# that setting non zero voltages for bucks 1/2 will also enable voltage
|
||||
# changes according to state change.
|
||||
|
||||
required:
|
||||
- regulator-name
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
additionalProperties: false
|
@ -772,6 +772,8 @@ patternProperties:
|
||||
description: Broadcom Corporation (formerly NetLogic Microsystems)
|
||||
"^netron-dy,.*":
|
||||
description: Netron DY
|
||||
"^netronix,.*":
|
||||
description: Netronix, Inc.
|
||||
"^netxeon,.*":
|
||||
description: Shenzhen Netxeon Technology CO., LTD
|
||||
"^neweast,.*":
|
||||
|
74
MAINTAINERS
74
MAINTAINERS
@ -2894,6 +2894,18 @@ W: http://www.openaoe.org/
|
||||
F: Documentation/admin-guide/aoe/
|
||||
F: drivers/block/aoe/
|
||||
|
||||
ATC260X PMIC MFD DRIVER
|
||||
M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
M: Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
|
||||
L: linux-actions@lists.infradead.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/mfd/actions,atc260x.yaml
|
||||
F: drivers/input/misc/atc260x-onkey.c
|
||||
F: drivers/mfd/atc260*
|
||||
F: drivers/power/reset/atc260x-poweroff.c
|
||||
F: drivers/regulator/atc260x-regulator.c
|
||||
F: include/linux/mfd/atc260x/*
|
||||
|
||||
ATHEROS 71XX/9XXX GPIO DRIVER
|
||||
M: Alban Bedel <albeu@free.fr>
|
||||
S: Maintained
|
||||
@ -9221,6 +9233,26 @@ F: include/linux/mei_cl_bus.h
|
||||
F: include/uapi/linux/mei.h
|
||||
F: samples/mei/*
|
||||
|
||||
INTEL MAX 10 BMC MFD DRIVER
|
||||
M: Xu Yilun <yilun.xu@intel.com>
|
||||
R: Tom Rix <trix@redhat.com>
|
||||
S: Maintained
|
||||
F: Documentation/ABI/testing/sysfs-driver-intel-m10-bmc
|
||||
F: Documentation/hwmon/intel-m10-bmc-hwmon.rst
|
||||
F: drivers/hwmon/intel-m10-bmc-hwmon.c
|
||||
F: drivers/mfd/intel-m10-bmc.c
|
||||
F: include/linux/mfd/intel-m10-bmc.h
|
||||
|
||||
INTEL MAX 10 BMC MFD DRIVER
|
||||
M: Xu Yilun <yilun.xu@intel.com>
|
||||
R: Tom Rix <trix@redhat.com>
|
||||
S: Maintained
|
||||
F: Documentation/ABI/testing/sysfs-driver-intel-m10-bmc
|
||||
F: Documentation/hwmon/intel-m10-bmc-hwmon.rst
|
||||
F: drivers/hwmon/intel-m10-bmc-hwmon.c
|
||||
F: drivers/mfd/intel-m10-bmc.c
|
||||
F: include/linux/mfd/intel-m10-bmc.h
|
||||
|
||||
INTEL MENLOW THERMAL DRIVER
|
||||
M: Sujith Thomas <sujith.thomas@intel.com>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
@ -12543,6 +12575,15 @@ F: include/net/netrom.h
|
||||
F: include/uapi/linux/netrom.h
|
||||
F: net/netrom/
|
||||
|
||||
NETRONIX EMBEDDED CONTROLLER
|
||||
M: Jonathan Neuschäfer <j.neuschaefer@gmx.net>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/mfd/netronix,ntxec.yaml
|
||||
F: drivers/mfd/ntxec.c
|
||||
F: drivers/pwm/pwm-ntxec.c
|
||||
F: drivers/rtc/rtc-ntxec.c
|
||||
F: include/linux/mfd/ntxec.h
|
||||
|
||||
NETRONOME ETHERNET DRIVERS
|
||||
M: Simon Horman <simon.horman@netronome.com>
|
||||
R: Jakub Kicinski <kuba@kernel.org>
|
||||
@ -15634,20 +15675,27 @@ F: Documentation/devicetree/bindings/mfd/rohm,bd70528-pmic.txt
|
||||
F: Documentation/devicetree/bindings/regulator/rohm,bd70528-regulator.txt
|
||||
F: drivers/clk/clk-bd718x7.c
|
||||
F: drivers/gpio/gpio-bd70528.c
|
||||
F: drivers/gpio/gpio-bd71815.c
|
||||
F: drivers/gpio/gpio-bd71828.c
|
||||
F: drivers/mfd/rohm-bd70528.c
|
||||
F: drivers/mfd/rohm-bd71828.c
|
||||
F: drivers/mfd/rohm-bd718x7.c
|
||||
F: drivers/mfd/rohm-bd9576.c
|
||||
F: drivers/power/supply/bd70528-charger.c
|
||||
F: drivers/regulator/bd70528-regulator.c
|
||||
F: drivers/regulator/bd71815-regulator.c
|
||||
F: drivers/regulator/bd71828-regulator.c
|
||||
F: drivers/regulator/bd718x7-regulator.c
|
||||
F: drivers/regulator/bd9576-regulator.c
|
||||
F: drivers/regulator/rohm-regulator.c
|
||||
F: drivers/rtc/rtc-bd70528.c
|
||||
F: drivers/watchdog/bd70528_wdt.c
|
||||
F: drivers/watchdog/bd9576_wdt.c
|
||||
F: include/linux/mfd/rohm-bd70528.h
|
||||
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-bd957x.h
|
||||
F: include/linux/mfd/rohm-generic.h
|
||||
F: include/linux/mfd/rohm-shared.h
|
||||
|
||||
@ -18147,29 +18195,6 @@ S: Maintained
|
||||
F: sound/soc/codecs/isabelle*
|
||||
F: sound/soc/codecs/lm49453*
|
||||
|
||||
TI LP855x BACKLIGHT DRIVER
|
||||
M: Milo Kim <milo.kim@ti.com>
|
||||
S: Maintained
|
||||
F: Documentation/driver-api/backlight/lp855x-driver.rst
|
||||
F: drivers/video/backlight/lp855x_bl.c
|
||||
F: include/linux/platform_data/lp855x.h
|
||||
|
||||
TI LP8727 CHARGER DRIVER
|
||||
M: Milo Kim <milo.kim@ti.com>
|
||||
S: Maintained
|
||||
F: drivers/power/supply/lp8727_charger.c
|
||||
F: include/linux/platform_data/lp8727.h
|
||||
|
||||
TI LP8788 MFD DRIVER
|
||||
M: Milo Kim <milo.kim@ti.com>
|
||||
S: Maintained
|
||||
F: drivers/iio/adc/lp8788_adc.c
|
||||
F: drivers/leds/leds-lp8788.c
|
||||
F: drivers/mfd/lp8788*.c
|
||||
F: drivers/power/supply/lp8788-charger.c
|
||||
F: drivers/regulator/lp8788-*.c
|
||||
F: include/linux/mfd/lp8788*.h
|
||||
|
||||
TI NETCP ETHERNET DRIVER
|
||||
M: Wingman Kwok <w-kwok2@ti.com>
|
||||
M: Murali Karicheri <m-karicheri2@ti.com>
|
||||
@ -19587,7 +19612,6 @@ F: Documentation/devicetree/bindings/sound/wlf,arizona.yaml
|
||||
F: Documentation/hwmon/wm83??.rst
|
||||
F: arch/arm/mach-s3c/mach-crag6410*
|
||||
F: drivers/clk/clk-wm83*.c
|
||||
F: drivers/extcon/extcon-arizona.c
|
||||
F: drivers/gpio/gpio-*wm*.c
|
||||
F: drivers/gpio/gpio-arizona.c
|
||||
F: drivers/hwmon/wm83??-hwmon.c
|
||||
@ -19611,7 +19635,7 @@ F: include/linux/mfd/wm8400*
|
||||
F: include/linux/regulator/arizona*
|
||||
F: include/linux/wm97xx.h
|
||||
F: include/sound/wm????.h
|
||||
F: sound/soc/codecs/arizona.?
|
||||
F: sound/soc/codecs/arizona*
|
||||
F: sound/soc/codecs/cs47l24*
|
||||
F: sound/soc/codecs/wm*
|
||||
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/* clk control registers */
|
||||
/* BD71815 */
|
||||
#define BD71815_REG_OUT32K 0x1d
|
||||
/* BD70528 */
|
||||
#define BD70528_REG_OUT32K 0x2c
|
||||
/* BD71828 */
|
||||
@ -118,6 +120,10 @@ static int bd71837_clk_probe(struct platform_device *pdev)
|
||||
c->reg = BD70528_REG_OUT32K;
|
||||
c->mask = CLK_OUT_EN_MASK;
|
||||
break;
|
||||
case ROHM_CHIP_TYPE_BD71815:
|
||||
c->reg = BD71815_REG_OUT32K;
|
||||
c->mask = CLK_OUT_EN_MASK;
|
||||
break;
|
||||
default:
|
||||
dev_err(&pdev->dev, "Unknown clk chip\n");
|
||||
return -EINVAL;
|
||||
@ -146,6 +152,7 @@ static const struct platform_device_id bd718x7_clk_id[] = {
|
||||
{ "bd71847-clk", ROHM_CHIP_TYPE_BD71847 },
|
||||
{ "bd70528-clk", ROHM_CHIP_TYPE_BD70528 },
|
||||
{ "bd71828-clk", ROHM_CHIP_TYPE_BD71828 },
|
||||
{ "bd71815-clk", ROHM_CHIP_TYPE_BD71815 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, bd718x7_clk_id);
|
||||
@ -161,6 +168,6 @@ static struct platform_driver bd71837_clk = {
|
||||
module_platform_driver(bd71837_clk);
|
||||
|
||||
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
|
||||
MODULE_DESCRIPTION("BD71837/BD71847/BD70528 chip clk driver");
|
||||
MODULE_DESCRIPTION("BD718(15/18/28/37/47/50) and BD70528 chip clk driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:bd718xx-clk");
|
||||
|
@ -21,14 +21,6 @@ config EXTCON_ADC_JACK
|
||||
help
|
||||
Say Y here to enable extcon device driver based on ADC values.
|
||||
|
||||
config EXTCON_ARIZONA
|
||||
tristate "Wolfson Arizona EXTCON support"
|
||||
depends on MFD_ARIZONA && INPUT && SND_SOC
|
||||
help
|
||||
Say Y here to enable support for external accessory detection
|
||||
with Wolfson Arizona devices. These are audio CODECs with
|
||||
advanced audio accessory detection support.
|
||||
|
||||
config EXTCON_AXP288
|
||||
tristate "X-Power AXP288 EXTCON support"
|
||||
depends on MFD_AXP20X && USB_SUPPORT && X86 && ACPI
|
||||
|
@ -6,7 +6,6 @@
|
||||
obj-$(CONFIG_EXTCON) += extcon-core.o
|
||||
extcon-core-objs += extcon.o devres.o
|
||||
obj-$(CONFIG_EXTCON_ADC_JACK) += extcon-adc-jack.o
|
||||
obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o
|
||||
obj-$(CONFIG_EXTCON_AXP288) += extcon-axp288.o
|
||||
obj-$(CONFIG_EXTCON_FSA9480) += extcon-fsa9480.o
|
||||
obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o
|
||||
|
@ -1105,6 +1105,16 @@ config GPIO_BD70528
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called gpio-bd70528.
|
||||
|
||||
config GPIO_BD71815
|
||||
tristate "ROHM BD71815 PMIC GPIO support"
|
||||
depends on MFD_ROHM_BD71828
|
||||
help
|
||||
Support for GPO(s) on ROHM BD71815 PMIC. There are two GPOs
|
||||
available on the ROHM PMIC.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called gpio-bd71815.
|
||||
|
||||
config GPIO_BD71828
|
||||
tristate "ROHM BD71828 GPIO support"
|
||||
depends on MFD_ROHM_BD71828
|
||||
|
@ -39,6 +39,7 @@ obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o
|
||||
obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
|
||||
obj-$(CONFIG_GPIO_BCM_XGS_IPROC) += gpio-xgs-iproc.o
|
||||
obj-$(CONFIG_GPIO_BD70528) += gpio-bd70528.o
|
||||
obj-$(CONFIG_GPIO_BD71815) += gpio-bd71815.o
|
||||
obj-$(CONFIG_GPIO_BD71828) += gpio-bd71828.o
|
||||
obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
|
||||
obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
|
||||
|
185
drivers/gpio/gpio-bd71815.c
Normal file
185
drivers/gpio/gpio-bd71815.c
Normal file
@ -0,0 +1,185 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Support to GPOs on ROHM BD71815
|
||||
* Copyright 2021 ROHM Semiconductors.
|
||||
* Author: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
|
||||
*
|
||||
* Copyright 2014 Embest Technology Co. Ltd. Inc.
|
||||
* Author: yanglsh@embest-tech.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>
|
||||
/* For the BD71815 register definitions */
|
||||
#include <linux/mfd/rohm-bd71815.h>
|
||||
|
||||
struct bd71815_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;
|
||||
};
|
||||
|
||||
static int bd71815gpo_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct bd71815_gpio *bd71815 = gpiochip_get_data(chip);
|
||||
int ret, val;
|
||||
|
||||
ret = regmap_read(bd71815->regmap, BD71815_REG_GPO, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return (val >> offset) & 1;
|
||||
}
|
||||
|
||||
static void bd71815gpo_set(struct gpio_chip *chip, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct bd71815_gpio *bd71815 = gpiochip_get_data(chip);
|
||||
int ret, bit;
|
||||
|
||||
bit = BIT(offset);
|
||||
|
||||
if (value)
|
||||
ret = regmap_set_bits(bd71815->regmap, BD71815_REG_GPO, bit);
|
||||
else
|
||||
ret = regmap_clear_bits(bd71815->regmap, BD71815_REG_GPO, bit);
|
||||
|
||||
if (ret)
|
||||
dev_warn(bd71815->dev, "failed to toggle GPO\n");
|
||||
}
|
||||
|
||||
static int bd71815_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
|
||||
unsigned long config)
|
||||
{
|
||||
struct bd71815_gpio *bdgpio = gpiochip_get_data(chip);
|
||||
|
||||
switch (pinconf_to_config_param(config)) {
|
||||
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
|
||||
return regmap_update_bits(bdgpio->regmap,
|
||||
BD71815_REG_GPO,
|
||||
BD71815_GPIO_DRIVE_MASK << offset,
|
||||
BD71815_GPIO_OPEN_DRAIN << offset);
|
||||
case PIN_CONFIG_DRIVE_PUSH_PULL:
|
||||
return regmap_update_bits(bdgpio->regmap,
|
||||
BD71815_REG_GPO,
|
||||
BD71815_GPIO_DRIVE_MASK << offset,
|
||||
BD71815_GPIO_CMOS << offset);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
/* BD71815 GPIO is actually GPO */
|
||||
static int bd71815gpo_direction_get(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
/* Template for GPIO chip */
|
||||
static const struct gpio_chip bd71815gpo_chip = {
|
||||
.label = "bd71815",
|
||||
.owner = THIS_MODULE,
|
||||
.get = bd71815gpo_get,
|
||||
.get_direction = bd71815gpo_direction_get,
|
||||
.set = bd71815gpo_set,
|
||||
.set_config = bd71815_gpio_set_config,
|
||||
.can_sleep = true,
|
||||
};
|
||||
|
||||
#define BD71815_TWO_GPIOS GENMASK(1, 0)
|
||||
#define BD71815_ONE_GPIO BIT(0)
|
||||
|
||||
/*
|
||||
* Sigh. The BD71815 and BD71817 were originally designed to support two GPO
|
||||
* pins. At some point it was noticed the second GPO pin which is the E5 pin
|
||||
* located at the center of IC is hard to use on PCB (due to the location). It
|
||||
* was decided to not promote this second GPO and the pin is marked as GND in
|
||||
* the datasheet. The functionality is still there though! I guess driving a GPO
|
||||
* connected to the ground is a bad idea. Thus we do not support it by default.
|
||||
* OTOH - the original driver written by colleagues at Embest did support
|
||||
* controlling this second GPO. It is thus possible this is used in some of the
|
||||
* products.
|
||||
*
|
||||
* This driver does not by default support configuring this second GPO
|
||||
* but allows using it by providing the DT property
|
||||
* "rohm,enable-hidden-gpo".
|
||||
*/
|
||||
static int bd71815_init_valid_mask(struct gpio_chip *gc,
|
||||
unsigned long *valid_mask,
|
||||
unsigned int ngpios)
|
||||
{
|
||||
if (ngpios != 2)
|
||||
return 0;
|
||||
|
||||
if (gc->parent && device_property_present(gc->parent,
|
||||
"rohm,enable-hidden-gpo"))
|
||||
*valid_mask = BD71815_TWO_GPIOS;
|
||||
else
|
||||
*valid_mask = BD71815_ONE_GPIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpo_bd71815_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct bd71815_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 = bd71815gpo_chip;
|
||||
|
||||
/*
|
||||
* FIXME: As writing of this the sysfs interface for GPIO control does
|
||||
* not respect the valid_mask. Do not trust it but rather set the ngpios
|
||||
* to 1 if "rohm,enable-hidden-gpo" is not given.
|
||||
*
|
||||
* This check can be removed later if the sysfs export is fixed and
|
||||
* if the fix is backported.
|
||||
*
|
||||
* For now it is safest to just set the ngpios though.
|
||||
*/
|
||||
if (device_property_present(parent, "rohm,enable-hidden-gpo"))
|
||||
g->chip.ngpio = 2;
|
||||
else
|
||||
g->chip.ngpio = 1;
|
||||
|
||||
g->chip.init_valid_mask = bd71815_init_valid_mask;
|
||||
g->chip.base = -1;
|
||||
g->chip.parent = parent;
|
||||
g->regmap = dev_get_regmap(parent, NULL);
|
||||
g->dev = dev;
|
||||
|
||||
return devm_gpiochip_add_data(dev, &g->chip, g);
|
||||
}
|
||||
|
||||
static struct platform_driver gpo_bd71815_driver = {
|
||||
.driver = {
|
||||
.name = "bd71815-gpo",
|
||||
},
|
||||
.probe = gpo_bd71815_probe,
|
||||
};
|
||||
module_platform_driver(gpo_bd71815_driver);
|
||||
|
||||
MODULE_ALIAS("platform:bd71815-gpo");
|
||||
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
|
||||
MODULE_AUTHOR("Peter Yang <yanglsh@embest-tech.com>");
|
||||
MODULE_DESCRIPTION("GPO interface for BD71815");
|
||||
MODULE_LICENSE("GPL");
|
@ -22,7 +22,6 @@
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_data/i2c-designware.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
@ -206,7 +205,6 @@ static const struct dmi_system_id dw_i2c_hwmon_class_dmi[] = {
|
||||
|
||||
static int dw_i2c_plat_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct i2c_adapter *adap;
|
||||
struct dw_i2c_dev *dev;
|
||||
struct i2c_timings *t;
|
||||
@ -236,10 +234,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
|
||||
reset_control_deassert(dev->rst);
|
||||
|
||||
t = &dev->timings;
|
||||
if (pdata)
|
||||
t->bus_freq_hz = pdata->i2c_scl_freq;
|
||||
else
|
||||
i2c_parse_fw_timings(&pdev->dev, t, false);
|
||||
i2c_parse_fw_timings(&pdev->dev, t, false);
|
||||
|
||||
i2c_dw_adjust_bus_speed(dev);
|
||||
|
||||
|
@ -94,6 +94,17 @@ config INPUT_ARIZONA_HAPTICS
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called arizona-haptics.
|
||||
|
||||
config INPUT_ATC260X_ONKEY
|
||||
tristate "Actions Semi ATC260x PMIC ONKEY"
|
||||
depends on MFD_ATC260X
|
||||
help
|
||||
Support the ONKEY of ATC260x PMICs as an input device reporting
|
||||
power button status. ONKEY can be used to wakeup from low power
|
||||
modes and force a reset on long press.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called atc260x-onkey.
|
||||
|
||||
config INPUT_ATMEL_CAPTOUCH
|
||||
tristate "Atmel Capacitive Touch Button Driver"
|
||||
depends on OF || COMPILE_TEST
|
||||
|
@ -17,6 +17,7 @@ obj-$(CONFIG_INPUT_ADXL34X_SPI) += adxl34x-spi.o
|
||||
obj-$(CONFIG_INPUT_APANEL) += apanel.o
|
||||
obj-$(CONFIG_INPUT_ARIEL_PWRBUTTON) += ariel-pwrbutton.o
|
||||
obj-$(CONFIG_INPUT_ARIZONA_HAPTICS) += arizona-haptics.o
|
||||
obj-$(CONFIG_INPUT_ATC260X_ONKEY) += atc260x-onkey.o
|
||||
obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
|
||||
obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o
|
||||
obj-$(CONFIG_INPUT_ATMEL_CAPTOUCH) += atmel_captouch.o
|
||||
@ -86,4 +87,3 @@ obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o
|
||||
obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o
|
||||
obj-$(CONFIG_INPUT_YEALINK) += yealink.o
|
||||
obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o
|
||||
|
||||
|
305
drivers/input/misc/atc260x-onkey.c
Normal file
305
drivers/input/misc/atc260x-onkey.c
Normal file
@ -0,0 +1,305 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Onkey driver for Actions Semi ATC260x PMICs.
|
||||
*
|
||||
* Copyright (c) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mfd/atc260x/core.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/* <2s for short press, >2s for long press */
|
||||
#define KEY_PRESS_TIME_SEC 2
|
||||
|
||||
/* Driver internals */
|
||||
enum atc260x_onkey_reset_status {
|
||||
KEY_RESET_HW_DEFAULT,
|
||||
KEY_RESET_DISABLED,
|
||||
KEY_RESET_USER_SEL,
|
||||
};
|
||||
|
||||
struct atc260x_onkey_params {
|
||||
u32 reg_int_ctl;
|
||||
u32 kdwn_state_bm;
|
||||
u32 long_int_pnd_bm;
|
||||
u32 short_int_pnd_bm;
|
||||
u32 kdwn_int_pnd_bm;
|
||||
u32 press_int_en_bm;
|
||||
u32 kdwn_int_en_bm;
|
||||
u32 press_time_bm;
|
||||
u32 reset_en_bm;
|
||||
u32 reset_time_bm;
|
||||
};
|
||||
|
||||
struct atc260x_onkey {
|
||||
struct atc260x *atc260x;
|
||||
const struct atc260x_onkey_params *params;
|
||||
struct input_dev *input_dev;
|
||||
struct delayed_work work;
|
||||
int irq;
|
||||
};
|
||||
|
||||
static const struct atc260x_onkey_params atc2603c_onkey_params = {
|
||||
.reg_int_ctl = ATC2603C_PMU_SYS_CTL2,
|
||||
.long_int_pnd_bm = ATC2603C_PMU_SYS_CTL2_ONOFF_LONG_PRESS,
|
||||
.short_int_pnd_bm = ATC2603C_PMU_SYS_CTL2_ONOFF_SHORT_PRESS,
|
||||
.kdwn_int_pnd_bm = ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_PD,
|
||||
.press_int_en_bm = ATC2603C_PMU_SYS_CTL2_ONOFF_INT_EN,
|
||||
.kdwn_int_en_bm = ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_INT_EN,
|
||||
.kdwn_state_bm = ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS,
|
||||
.press_time_bm = ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_TIME,
|
||||
.reset_en_bm = ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_RESET_EN,
|
||||
.reset_time_bm = ATC2603C_PMU_SYS_CTL2_ONOFF_RESET_TIME_SEL,
|
||||
};
|
||||
|
||||
static const struct atc260x_onkey_params atc2609a_onkey_params = {
|
||||
.reg_int_ctl = ATC2609A_PMU_SYS_CTL2,
|
||||
.long_int_pnd_bm = ATC2609A_PMU_SYS_CTL2_ONOFF_LONG_PRESS,
|
||||
.short_int_pnd_bm = ATC2609A_PMU_SYS_CTL2_ONOFF_SHORT_PRESS,
|
||||
.kdwn_int_pnd_bm = ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS_PD,
|
||||
.press_int_en_bm = ATC2609A_PMU_SYS_CTL2_ONOFF_LSP_INT_EN,
|
||||
.kdwn_int_en_bm = ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS_INT_EN,
|
||||
.kdwn_state_bm = ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS,
|
||||
.press_time_bm = ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS_TIME,
|
||||
.reset_en_bm = ATC2609A_PMU_SYS_CTL2_ONOFF_RESET_EN,
|
||||
.reset_time_bm = ATC2609A_PMU_SYS_CTL2_ONOFF_RESET_TIME_SEL,
|
||||
};
|
||||
|
||||
static int atc2603x_onkey_hw_init(struct atc260x_onkey *onkey,
|
||||
enum atc260x_onkey_reset_status reset_status,
|
||||
u32 reset_time, u32 press_time)
|
||||
{
|
||||
u32 reg_bm, reg_val;
|
||||
|
||||
reg_bm = onkey->params->long_int_pnd_bm |
|
||||
onkey->params->short_int_pnd_bm |
|
||||
onkey->params->kdwn_int_pnd_bm |
|
||||
onkey->params->press_int_en_bm |
|
||||
onkey->params->kdwn_int_en_bm;
|
||||
|
||||
reg_val = reg_bm | press_time;
|
||||
reg_bm |= onkey->params->press_time_bm;
|
||||
|
||||
if (reset_status == KEY_RESET_DISABLED) {
|
||||
reg_bm |= onkey->params->reset_en_bm;
|
||||
} else if (reset_status == KEY_RESET_USER_SEL) {
|
||||
reg_bm |= onkey->params->reset_en_bm |
|
||||
onkey->params->reset_time_bm;
|
||||
reg_val |= onkey->params->reset_en_bm | reset_time;
|
||||
}
|
||||
|
||||
return regmap_update_bits(onkey->atc260x->regmap,
|
||||
onkey->params->reg_int_ctl, reg_bm, reg_val);
|
||||
}
|
||||
|
||||
static void atc260x_onkey_query(struct atc260x_onkey *onkey)
|
||||
{
|
||||
u32 reg_bits;
|
||||
int ret, key_down;
|
||||
|
||||
ret = regmap_read(onkey->atc260x->regmap,
|
||||
onkey->params->reg_int_ctl, &key_down);
|
||||
if (ret) {
|
||||
key_down = 1;
|
||||
dev_err(onkey->atc260x->dev,
|
||||
"Failed to read onkey status: %d\n", ret);
|
||||
} else {
|
||||
key_down &= onkey->params->kdwn_state_bm;
|
||||
}
|
||||
|
||||
/*
|
||||
* The hardware generates interrupt only when the onkey pin is
|
||||
* asserted. Hence, the deassertion of the pin is simulated through
|
||||
* work queue.
|
||||
*/
|
||||
if (key_down) {
|
||||
schedule_delayed_work(&onkey->work, msecs_to_jiffies(200));
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The key-down status bit is cleared when the On/Off button
|
||||
* is released.
|
||||
*/
|
||||
input_report_key(onkey->input_dev, KEY_POWER, 0);
|
||||
input_sync(onkey->input_dev);
|
||||
|
||||
reg_bits = onkey->params->long_int_pnd_bm |
|
||||
onkey->params->short_int_pnd_bm |
|
||||
onkey->params->kdwn_int_pnd_bm |
|
||||
onkey->params->press_int_en_bm |
|
||||
onkey->params->kdwn_int_en_bm;
|
||||
|
||||
/* Clear key press pending events and enable key press interrupts. */
|
||||
regmap_update_bits(onkey->atc260x->regmap, onkey->params->reg_int_ctl,
|
||||
reg_bits, reg_bits);
|
||||
}
|
||||
|
||||
static void atc260x_onkey_work(struct work_struct *work)
|
||||
{
|
||||
struct atc260x_onkey *onkey = container_of(work, struct atc260x_onkey,
|
||||
work.work);
|
||||
atc260x_onkey_query(onkey);
|
||||
}
|
||||
|
||||
static irqreturn_t atc260x_onkey_irq(int irq, void *data)
|
||||
{
|
||||
struct atc260x_onkey *onkey = data;
|
||||
int ret;
|
||||
|
||||
/* Disable key press interrupts. */
|
||||
ret = regmap_update_bits(onkey->atc260x->regmap,
|
||||
onkey->params->reg_int_ctl,
|
||||
onkey->params->press_int_en_bm |
|
||||
onkey->params->kdwn_int_en_bm, 0);
|
||||
if (ret)
|
||||
dev_err(onkey->atc260x->dev,
|
||||
"Failed to disable interrupts: %d\n", ret);
|
||||
|
||||
input_report_key(onkey->input_dev, KEY_POWER, 1);
|
||||
input_sync(onkey->input_dev);
|
||||
|
||||
atc260x_onkey_query(onkey);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int atc260x_onkey_open(struct input_dev *dev)
|
||||
{
|
||||
struct atc260x_onkey *onkey = input_get_drvdata(dev);
|
||||
|
||||
enable_irq(onkey->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void atc260x_onkey_close(struct input_dev *dev)
|
||||
{
|
||||
struct atc260x_onkey *onkey = input_get_drvdata(dev);
|
||||
|
||||
disable_irq(onkey->irq);
|
||||
cancel_delayed_work_sync(&onkey->work);
|
||||
}
|
||||
|
||||
static int atc260x_onkey_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct atc260x *atc260x = dev_get_drvdata(pdev->dev.parent);
|
||||
struct atc260x_onkey *onkey;
|
||||
struct input_dev *input_dev;
|
||||
enum atc260x_onkey_reset_status reset_status;
|
||||
u32 press_time = KEY_PRESS_TIME_SEC, reset_time = 0;
|
||||
int val, error;
|
||||
|
||||
onkey = devm_kzalloc(&pdev->dev, sizeof(*onkey), GFP_KERNEL);
|
||||
if (!onkey)
|
||||
return -ENOMEM;
|
||||
|
||||
error = device_property_read_u32(pdev->dev.parent,
|
||||
"reset-time-sec", &val);
|
||||
if (error) {
|
||||
reset_status = KEY_RESET_HW_DEFAULT;
|
||||
} else if (val) {
|
||||
if (val < 6 || val > 12) {
|
||||
dev_err(&pdev->dev, "reset-time-sec out of range\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
reset_status = KEY_RESET_USER_SEL;
|
||||
reset_time = (val - 6) / 2;
|
||||
} else {
|
||||
reset_status = KEY_RESET_DISABLED;
|
||||
dev_dbg(&pdev->dev, "Disabled reset on long-press\n");
|
||||
}
|
||||
|
||||
switch (atc260x->ic_type) {
|
||||
case ATC2603C:
|
||||
onkey->params = &atc2603c_onkey_params;
|
||||
press_time = FIELD_PREP(ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_TIME,
|
||||
press_time);
|
||||
reset_time = FIELD_PREP(ATC2603C_PMU_SYS_CTL2_ONOFF_RESET_TIME_SEL,
|
||||
reset_time);
|
||||
break;
|
||||
case ATC2609A:
|
||||
onkey->params = &atc2609a_onkey_params;
|
||||
press_time = FIELD_PREP(ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS_TIME,
|
||||
press_time);
|
||||
reset_time = FIELD_PREP(ATC2609A_PMU_SYS_CTL2_ONOFF_RESET_TIME_SEL,
|
||||
reset_time);
|
||||
break;
|
||||
default:
|
||||
dev_err(&pdev->dev,
|
||||
"OnKey not supported for ATC260x PMIC type: %u\n",
|
||||
atc260x->ic_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
input_dev = devm_input_allocate_device(&pdev->dev);
|
||||
if (!input_dev) {
|
||||
dev_err(&pdev->dev, "Failed to allocate input device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
onkey->input_dev = input_dev;
|
||||
onkey->atc260x = atc260x;
|
||||
|
||||
input_dev->name = "atc260x-onkey";
|
||||
input_dev->phys = "atc260x-onkey/input0";
|
||||
input_dev->open = atc260x_onkey_open;
|
||||
input_dev->close = atc260x_onkey_close;
|
||||
|
||||
input_set_capability(input_dev, EV_KEY, KEY_POWER);
|
||||
input_set_drvdata(input_dev, onkey);
|
||||
|
||||
INIT_DELAYED_WORK(&onkey->work, atc260x_onkey_work);
|
||||
|
||||
onkey->irq = platform_get_irq(pdev, 0);
|
||||
if (onkey->irq < 0)
|
||||
return onkey->irq;
|
||||
|
||||
error = devm_request_threaded_irq(&pdev->dev, onkey->irq, NULL,
|
||||
atc260x_onkey_irq, IRQF_ONESHOT,
|
||||
dev_name(&pdev->dev), onkey);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to register IRQ %d: %d\n", onkey->irq, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Keep IRQ disabled until atc260x_onkey_open() is called. */
|
||||
disable_irq(onkey->irq);
|
||||
|
||||
error = input_register_device(input_dev);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to register input device: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = atc2603x_onkey_hw_init(onkey, reset_status,
|
||||
reset_time, press_time);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
device_init_wakeup(&pdev->dev, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver atc260x_onkey_driver = {
|
||||
.probe = atc260x_onkey_probe,
|
||||
.driver = {
|
||||
.name = "atc260x-onkey",
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(atc260x_onkey_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Onkey driver for ATC260x PMICs");
|
||||
MODULE_AUTHOR("Cristian Ciocaltea <cristian.ciocaltea@gmail.com>");
|
||||
MODULE_LICENSE("GPL");
|
@ -967,6 +967,17 @@ config MFD_VIPERBOARD
|
||||
You need to select the mfd cell drivers separately.
|
||||
The drivers do not support all features the board exposes.
|
||||
|
||||
config MFD_NTXEC
|
||||
tristate "Netronix embedded controller (EC)"
|
||||
depends on OF || COMPILE_TEST
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
select MFD_CORE
|
||||
help
|
||||
Say yes here if you want to support the embedded controller found in
|
||||
certain e-book readers designed by the original design manufacturer
|
||||
Netronix.
|
||||
|
||||
config MFD_RETU
|
||||
tristate "Nokia Retu and Tahvo multi-function device"
|
||||
select MFD_CORE
|
||||
@ -1224,7 +1235,8 @@ config MFD_SC27XX_PMIC
|
||||
|
||||
config ABX500_CORE
|
||||
bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions"
|
||||
default y if ARCH_U300 || ARCH_U8500 || COMPILE_TEST
|
||||
depends on ARCH_U8500 || COMPILE_TEST
|
||||
default y if ARCH_U8500
|
||||
help
|
||||
Say yes here if you have the ABX500 Mixed Signal IC family
|
||||
chips. This core driver expose register access functions.
|
||||
@ -1232,30 +1244,6 @@ config ABX500_CORE
|
||||
remain unchanged when IC changes. Binding of the functions to
|
||||
actual register access is done by the IC core driver.
|
||||
|
||||
config AB3100_CORE
|
||||
bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions"
|
||||
depends on I2C=y && ABX500_CORE
|
||||
select MFD_CORE
|
||||
default y if ARCH_U300
|
||||
help
|
||||
Select this to enable the AB3100 Mixed Signal IC core
|
||||
functionality. This connects to a AB3100 on the I2C bus
|
||||
and expose a number of symbols needed for dependent devices
|
||||
to read and write registers and subscribe to events from
|
||||
this multi-functional IC. This is needed to use other features
|
||||
of the AB3100 such as battery-backed RTC, charging control,
|
||||
LEDs, vibrator, system power and temperature, power management
|
||||
and ALSA sound.
|
||||
|
||||
config AB3100_OTP
|
||||
tristate "ST-Ericsson AB3100 OTP functions"
|
||||
depends on AB3100_CORE
|
||||
default y if AB3100_CORE
|
||||
help
|
||||
Select this to enable the AB3100 Mixed Signal IC OTP (one-time
|
||||
programmable memory) support. This exposes a sysfs file to read
|
||||
out OTP values.
|
||||
|
||||
config AB8500_CORE
|
||||
bool "ST-Ericsson AB8500 Mixed Signal Power Management chip"
|
||||
depends on ABX500_CORE && MFD_DB8500_PRCMU
|
||||
@ -1975,19 +1963,31 @@ config MFD_ROHM_BD70528
|
||||
charger.
|
||||
|
||||
config MFD_ROHM_BD71828
|
||||
tristate "ROHM BD71828 Power Management IC"
|
||||
tristate "ROHM BD71828 and BD71815 Power Management IC"
|
||||
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 Power
|
||||
Management IC. BD71828GW is a single-chip power management IC for
|
||||
battery-powered portable devices. The IC integrates 7 buck
|
||||
converters, 7 LDOs, and a 1500 mA single-cell linear charger.
|
||||
Also included is a Coulomb counter, a real-time clock (RTC), and
|
||||
a 32.768 kHz clock gate.
|
||||
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.
|
||||
|
||||
config MFD_ROHM_BD957XMUF
|
||||
tristate "ROHM BD9576MUF and BD9573MUF Power Management ICs"
|
||||
depends on I2C=y
|
||||
depends on OF
|
||||
select REGMAP_I2C
|
||||
select MFD_CORE
|
||||
help
|
||||
Select this option to get support for the ROHM BD9576MUF and
|
||||
BD9573MUF Power Management ICs. BD9576 and BD9573 are primarily
|
||||
designed to be used to power R-Car series processors.
|
||||
|
||||
config MFD_STM32_LPTIMER
|
||||
tristate "Support for STM32 Low-Power Timer"
|
||||
@ -2055,6 +2055,24 @@ config MFD_WCD934X
|
||||
This driver provides common support WCD934x audio codec and its
|
||||
associated Pin Controller, Soundwire Controller and Audio codec.
|
||||
|
||||
config MFD_ATC260X
|
||||
tristate
|
||||
select MFD_CORE
|
||||
select REGMAP
|
||||
select REGMAP_IRQ
|
||||
|
||||
config MFD_ATC260X_I2C
|
||||
tristate "Actions Semi ATC260x PMICs with I2C"
|
||||
select MFD_ATC260X
|
||||
select REGMAP_I2C
|
||||
depends on I2C
|
||||
help
|
||||
Support for the Actions Semi ATC260x PMICs controlled via I2C.
|
||||
|
||||
This driver provides common support for accessing the ATC2603C
|
||||
and ATC2609A chip variants, additional drivers must be enabled
|
||||
in order to use the functionality of the device.
|
||||
|
||||
config MFD_KHADAS_MCU
|
||||
tristate "Support for Khadas System control Microcontroller"
|
||||
depends on I2C
|
||||
|
@ -178,8 +178,6 @@ obj-$(CONFIG_MFD_PCF50633) += pcf50633.o
|
||||
obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o
|
||||
obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o
|
||||
obj-$(CONFIG_ABX500_CORE) += abx500-core.o
|
||||
obj-$(CONFIG_AB3100_CORE) += ab3100-core.o
|
||||
obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o
|
||||
obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o
|
||||
obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o
|
||||
# ab8500-core need to come after db8500-prcmu (which provides the channel)
|
||||
@ -218,6 +216,7 @@ obj-$(CONFIG_MFD_INTEL_PMC_BXT) += intel_pmc_bxt.o
|
||||
obj-$(CONFIG_MFD_INTEL_PMT) += intel_pmt.o
|
||||
obj-$(CONFIG_MFD_PALMAS) += palmas.o
|
||||
obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o
|
||||
obj-$(CONFIG_MFD_NTXEC) += ntxec.o
|
||||
obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
|
||||
obj-$(CONFIG_MFD_RK808) += rk808.o
|
||||
obj-$(CONFIG_MFD_RN5T618) += rn5t618.o
|
||||
@ -261,6 +260,7 @@ obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o
|
||||
obj-$(CONFIG_MFD_ROHM_BD70528) += rohm-bd70528.o
|
||||
obj-$(CONFIG_MFD_ROHM_BD71828) += rohm-bd71828.o
|
||||
obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o
|
||||
obj-$(CONFIG_MFD_ROHM_BD957XMUF) += rohm-bd9576.o
|
||||
obj-$(CONFIG_MFD_STMFX) += stmfx.o
|
||||
obj-$(CONFIG_MFD_KHADAS_MCU) += khadas-mcu.o
|
||||
obj-$(CONFIG_MFD_ACER_A500_EC) += acer-ec-a500.o
|
||||
@ -268,3 +268,6 @@ obj-$(CONFIG_MFD_ACER_A500_EC) += acer-ec-a500.o
|
||||
obj-$(CONFIG_SGI_MFD_IOC3) += ioc3.o
|
||||
obj-$(CONFIG_MFD_SIMPLE_MFD_I2C) += simple-mfd-i2c.o
|
||||
obj-$(CONFIG_MFD_INTEL_M10_BMC) += intel-m10-bmc.o
|
||||
|
||||
obj-$(CONFIG_MFD_ATC260X) += atc260x-core.o
|
||||
obj-$(CONFIG_MFD_ATC260X_I2C) += atc260x-i2c.o
|
||||
|
@ -1,929 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2007-2010 ST-Ericsson
|
||||
* Low-level core for exclusive access to the AB3100 IC on the I2C bus
|
||||
* and some basic chip-configuration.
|
||||
* Author: Linus Walleij <linus.walleij@stericsson.com>
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/ab3100.h>
|
||||
#include <linux/mfd/abx500.h>
|
||||
|
||||
/* These are the only registers inside AB3100 used in this main file */
|
||||
|
||||
/* Interrupt event registers */
|
||||
#define AB3100_EVENTA1 0x21
|
||||
#define AB3100_EVENTA2 0x22
|
||||
#define AB3100_EVENTA3 0x23
|
||||
|
||||
/* AB3100 DAC converter registers */
|
||||
#define AB3100_DIS 0x00
|
||||
#define AB3100_D0C 0x01
|
||||
#define AB3100_D1C 0x02
|
||||
#define AB3100_D2C 0x03
|
||||
#define AB3100_D3C 0x04
|
||||
|
||||
/* Chip ID register */
|
||||
#define AB3100_CID 0x20
|
||||
|
||||
/* AB3100 interrupt registers */
|
||||
#define AB3100_IMRA1 0x24
|
||||
#define AB3100_IMRA2 0x25
|
||||
#define AB3100_IMRA3 0x26
|
||||
#define AB3100_IMRB1 0x2B
|
||||
#define AB3100_IMRB2 0x2C
|
||||
#define AB3100_IMRB3 0x2D
|
||||
|
||||
/* System Power Monitoring and control registers */
|
||||
#define AB3100_MCA 0x2E
|
||||
#define AB3100_MCB 0x2F
|
||||
|
||||
/* SIM power up */
|
||||
#define AB3100_SUP 0x50
|
||||
|
||||
/*
|
||||
* I2C communication
|
||||
*
|
||||
* The AB3100 is usually assigned address 0x48 (7-bit)
|
||||
* The chip is defined in the platform i2c_board_data section.
|
||||
*/
|
||||
static int ab3100_get_chip_id(struct device *dev)
|
||||
{
|
||||
struct ab3100 *ab3100 = dev_get_drvdata(dev->parent);
|
||||
|
||||
return (int)ab3100->chip_id;
|
||||
}
|
||||
|
||||
static int ab3100_set_register_interruptible(struct ab3100 *ab3100,
|
||||
u8 reg, u8 regval)
|
||||
{
|
||||
u8 regandval[2] = {reg, regval};
|
||||
int err;
|
||||
|
||||
err = mutex_lock_interruptible(&ab3100->access_mutex);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* A two-byte write message with the first byte containing the register
|
||||
* number and the second byte containing the value to be written
|
||||
* effectively sets a register in the AB3100.
|
||||
*/
|
||||
err = i2c_master_send(ab3100->i2c_client, regandval, 2);
|
||||
if (err < 0) {
|
||||
dev_err(ab3100->dev,
|
||||
"write error (write register): %d\n",
|
||||
err);
|
||||
} else if (err != 2) {
|
||||
dev_err(ab3100->dev,
|
||||
"write error (write register)\n"
|
||||
" %d bytes transferred (expected 2)\n",
|
||||
err);
|
||||
err = -EIO;
|
||||
} else {
|
||||
/* All is well */
|
||||
err = 0;
|
||||
}
|
||||
mutex_unlock(&ab3100->access_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int set_register_interruptible(struct device *dev,
|
||||
u8 bank, u8 reg, u8 value)
|
||||
{
|
||||
struct ab3100 *ab3100 = dev_get_drvdata(dev->parent);
|
||||
|
||||
return ab3100_set_register_interruptible(ab3100, reg, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* The test registers exist at an I2C bus address up one
|
||||
* from the ordinary base. They are not supposed to be used
|
||||
* in production code, but sometimes you have to do that
|
||||
* anyway. It's currently only used from this file so declare
|
||||
* it static and do not export.
|
||||
*/
|
||||
static int ab3100_set_test_register_interruptible(struct ab3100 *ab3100,
|
||||
u8 reg, u8 regval)
|
||||
{
|
||||
u8 regandval[2] = {reg, regval};
|
||||
int err;
|
||||
|
||||
err = mutex_lock_interruptible(&ab3100->access_mutex);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = i2c_master_send(ab3100->testreg_client, regandval, 2);
|
||||
if (err < 0) {
|
||||
dev_err(ab3100->dev,
|
||||
"write error (write test register): %d\n",
|
||||
err);
|
||||
} else if (err != 2) {
|
||||
dev_err(ab3100->dev,
|
||||
"write error (write test register)\n"
|
||||
" %d bytes transferred (expected 2)\n",
|
||||
err);
|
||||
err = -EIO;
|
||||
} else {
|
||||
/* All is well */
|
||||
err = 0;
|
||||
}
|
||||
mutex_unlock(&ab3100->access_mutex);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ab3100_get_register_interruptible(struct ab3100 *ab3100,
|
||||
u8 reg, u8 *regval)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = mutex_lock_interruptible(&ab3100->access_mutex);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* AB3100 require an I2C "stop" command between each message, else
|
||||
* it will not work. The only way of achieveing this with the
|
||||
* message transport layer is to send the read and write messages
|
||||
* separately.
|
||||
*/
|
||||
err = i2c_master_send(ab3100->i2c_client, ®, 1);
|
||||
if (err < 0) {
|
||||
dev_err(ab3100->dev,
|
||||
"write error (send register address): %d\n",
|
||||
err);
|
||||
goto get_reg_out_unlock;
|
||||
} else if (err != 1) {
|
||||
dev_err(ab3100->dev,
|
||||
"write error (send register address)\n"
|
||||
" %d bytes transferred (expected 1)\n",
|
||||
err);
|
||||
err = -EIO;
|
||||
goto get_reg_out_unlock;
|
||||
} else {
|
||||
/* All is well */
|
||||
err = 0;
|
||||
}
|
||||
|
||||
err = i2c_master_recv(ab3100->i2c_client, regval, 1);
|
||||
if (err < 0) {
|
||||
dev_err(ab3100->dev,
|
||||
"write error (read register): %d\n",
|
||||
err);
|
||||
goto get_reg_out_unlock;
|
||||
} else if (err != 1) {
|
||||
dev_err(ab3100->dev,
|
||||
"write error (read register)\n"
|
||||
" %d bytes transferred (expected 1)\n",
|
||||
err);
|
||||
err = -EIO;
|
||||
goto get_reg_out_unlock;
|
||||
} else {
|
||||
/* All is well */
|
||||
err = 0;
|
||||
}
|
||||
|
||||
get_reg_out_unlock:
|
||||
mutex_unlock(&ab3100->access_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int get_register_interruptible(struct device *dev, u8 bank, u8 reg,
|
||||
u8 *value)
|
||||
{
|
||||
struct ab3100 *ab3100 = dev_get_drvdata(dev->parent);
|
||||
|
||||
return ab3100_get_register_interruptible(ab3100, reg, value);
|
||||
}
|
||||
|
||||
static int ab3100_get_register_page_interruptible(struct ab3100 *ab3100,
|
||||
u8 first_reg, u8 *regvals, u8 numregs)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (ab3100->chip_id == 0xa0 ||
|
||||
ab3100->chip_id == 0xa1)
|
||||
/* These don't support paged reads */
|
||||
return -EIO;
|
||||
|
||||
err = mutex_lock_interruptible(&ab3100->access_mutex);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* Paged read also require an I2C "stop" command.
|
||||
*/
|
||||
err = i2c_master_send(ab3100->i2c_client, &first_reg, 1);
|
||||
if (err < 0) {
|
||||
dev_err(ab3100->dev,
|
||||
"write error (send first register address): %d\n",
|
||||
err);
|
||||
goto get_reg_page_out_unlock;
|
||||
} else if (err != 1) {
|
||||
dev_err(ab3100->dev,
|
||||
"write error (send first register address)\n"
|
||||
" %d bytes transferred (expected 1)\n",
|
||||
err);
|
||||
err = -EIO;
|
||||
goto get_reg_page_out_unlock;
|
||||
}
|
||||
|
||||
err = i2c_master_recv(ab3100->i2c_client, regvals, numregs);
|
||||
if (err < 0) {
|
||||
dev_err(ab3100->dev,
|
||||
"write error (read register page): %d\n",
|
||||
err);
|
||||
goto get_reg_page_out_unlock;
|
||||
} else if (err != numregs) {
|
||||
dev_err(ab3100->dev,
|
||||
"write error (read register page)\n"
|
||||
" %d bytes transferred (expected %d)\n",
|
||||
err, numregs);
|
||||
err = -EIO;
|
||||
goto get_reg_page_out_unlock;
|
||||
}
|
||||
|
||||
/* All is well */
|
||||
err = 0;
|
||||
|
||||
get_reg_page_out_unlock:
|
||||
mutex_unlock(&ab3100->access_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int get_register_page_interruptible(struct device *dev, u8 bank,
|
||||
u8 first_reg, u8 *regvals, u8 numregs)
|
||||
{
|
||||
struct ab3100 *ab3100 = dev_get_drvdata(dev->parent);
|
||||
|
||||
return ab3100_get_register_page_interruptible(ab3100,
|
||||
first_reg, regvals, numregs);
|
||||
}
|
||||
|
||||
static int ab3100_mask_and_set_register_interruptible(struct ab3100 *ab3100,
|
||||
u8 reg, u8 andmask, u8 ormask)
|
||||
{
|
||||
u8 regandval[2] = {reg, 0};
|
||||
int err;
|
||||
|
||||
err = mutex_lock_interruptible(&ab3100->access_mutex);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* First read out the target register */
|
||||
err = i2c_master_send(ab3100->i2c_client, ®, 1);
|
||||
if (err < 0) {
|
||||
dev_err(ab3100->dev,
|
||||
"write error (maskset send address): %d\n",
|
||||
err);
|
||||
goto get_maskset_unlock;
|
||||
} else if (err != 1) {
|
||||
dev_err(ab3100->dev,
|
||||
"write error (maskset send address)\n"
|
||||
" %d bytes transferred (expected 1)\n",
|
||||
err);
|
||||
err = -EIO;
|
||||
goto get_maskset_unlock;
|
||||
}
|
||||
|
||||
err = i2c_master_recv(ab3100->i2c_client, ®andval[1], 1);
|
||||
if (err < 0) {
|
||||
dev_err(ab3100->dev,
|
||||
"write error (maskset read register): %d\n",
|
||||
err);
|
||||
goto get_maskset_unlock;
|
||||
} else if (err != 1) {
|
||||
dev_err(ab3100->dev,
|
||||
"write error (maskset read register)\n"
|
||||
" %d bytes transferred (expected 1)\n",
|
||||
err);
|
||||
err = -EIO;
|
||||
goto get_maskset_unlock;
|
||||
}
|
||||
|
||||
/* Modify the register */
|
||||
regandval[1] &= andmask;
|
||||
regandval[1] |= ormask;
|
||||
|
||||
/* Write the register */
|
||||
err = i2c_master_send(ab3100->i2c_client, regandval, 2);
|
||||
if (err < 0) {
|
||||
dev_err(ab3100->dev,
|
||||
"write error (write register): %d\n",
|
||||
err);
|
||||
goto get_maskset_unlock;
|
||||
} else if (err != 2) {
|
||||
dev_err(ab3100->dev,
|
||||
"write error (write register)\n"
|
||||
" %d bytes transferred (expected 2)\n",
|
||||
err);
|
||||
err = -EIO;
|
||||
goto get_maskset_unlock;
|
||||
}
|
||||
|
||||
/* All is well */
|
||||
err = 0;
|
||||
|
||||
get_maskset_unlock:
|
||||
mutex_unlock(&ab3100->access_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mask_and_set_register_interruptible(struct device *dev, u8 bank,
|
||||
u8 reg, u8 bitmask, u8 bitvalues)
|
||||
{
|
||||
struct ab3100 *ab3100 = dev_get_drvdata(dev->parent);
|
||||
|
||||
return ab3100_mask_and_set_register_interruptible(ab3100,
|
||||
reg, bitmask, (bitmask & bitvalues));
|
||||
}
|
||||
|
||||
/*
|
||||
* Register a simple callback for handling any AB3100 events.
|
||||
*/
|
||||
int ab3100_event_register(struct ab3100 *ab3100,
|
||||
struct notifier_block *nb)
|
||||
{
|
||||
return blocking_notifier_chain_register(&ab3100->event_subscribers,
|
||||
nb);
|
||||
}
|
||||
EXPORT_SYMBOL(ab3100_event_register);
|
||||
|
||||
/*
|
||||
* Remove a previously registered callback.
|
||||
*/
|
||||
int ab3100_event_unregister(struct ab3100 *ab3100,
|
||||
struct notifier_block *nb)
|
||||
{
|
||||
return blocking_notifier_chain_unregister(&ab3100->event_subscribers,
|
||||
nb);
|
||||
}
|
||||
EXPORT_SYMBOL(ab3100_event_unregister);
|
||||
|
||||
|
||||
static int ab3100_event_registers_startup_state_get(struct device *dev,
|
||||
u8 *event)
|
||||
{
|
||||
struct ab3100 *ab3100 = dev_get_drvdata(dev->parent);
|
||||
|
||||
if (!ab3100->startup_events_read)
|
||||
return -EAGAIN; /* Try again later */
|
||||
memcpy(event, ab3100->startup_events, 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct abx500_ops ab3100_ops = {
|
||||
.get_chip_id = ab3100_get_chip_id,
|
||||
.set_register = set_register_interruptible,
|
||||
.get_register = get_register_interruptible,
|
||||
.get_register_page = get_register_page_interruptible,
|
||||
.set_register_page = NULL,
|
||||
.mask_and_set_register = mask_and_set_register_interruptible,
|
||||
.event_registers_startup_state_get =
|
||||
ab3100_event_registers_startup_state_get,
|
||||
.startup_irq_enabled = NULL,
|
||||
};
|
||||
|
||||
/*
|
||||
* This is a threaded interrupt handler so we can make some
|
||||
* I2C calls etc.
|
||||
*/
|
||||
static irqreturn_t ab3100_irq_handler(int irq, void *data)
|
||||
{
|
||||
struct ab3100 *ab3100 = data;
|
||||
u8 event_regs[3];
|
||||
u32 fatevent;
|
||||
int err;
|
||||
|
||||
err = ab3100_get_register_page_interruptible(ab3100, AB3100_EVENTA1,
|
||||
event_regs, 3);
|
||||
if (err)
|
||||
goto err_event;
|
||||
|
||||
fatevent = (event_regs[0] << 16) |
|
||||
(event_regs[1] << 8) |
|
||||
event_regs[2];
|
||||
|
||||
if (!ab3100->startup_events_read) {
|
||||
ab3100->startup_events[0] = event_regs[0];
|
||||
ab3100->startup_events[1] = event_regs[1];
|
||||
ab3100->startup_events[2] = event_regs[2];
|
||||
ab3100->startup_events_read = true;
|
||||
}
|
||||
/*
|
||||
* The notified parties will have to mask out the events
|
||||
* they're interested in and react to them. They will be
|
||||
* notified on all events, then they use the fatevent value
|
||||
* to determine if they're interested.
|
||||
*/
|
||||
blocking_notifier_call_chain(&ab3100->event_subscribers,
|
||||
fatevent, NULL);
|
||||
|
||||
dev_dbg(ab3100->dev,
|
||||
"IRQ Event: 0x%08x\n", fatevent);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
||||
err_event:
|
||||
dev_dbg(ab3100->dev,
|
||||
"error reading event status\n");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
/*
|
||||
* Some debugfs entries only exposed if we're using debug
|
||||
*/
|
||||
static int ab3100_registers_print(struct seq_file *s, void *p)
|
||||
{
|
||||
struct ab3100 *ab3100 = s->private;
|
||||
u8 value;
|
||||
u8 reg;
|
||||
|
||||
seq_puts(s, "AB3100 registers:\n");
|
||||
|
||||
for (reg = 0; reg < 0xff; reg++) {
|
||||
ab3100_get_register_interruptible(ab3100, reg, &value);
|
||||
seq_printf(s, "[0x%x]: 0x%x\n", reg, value);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ab3100_registers_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, ab3100_registers_print, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations ab3100_registers_fops = {
|
||||
.open = ab3100_registers_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
struct ab3100_get_set_reg_priv {
|
||||
struct ab3100 *ab3100;
|
||||
bool mode;
|
||||
};
|
||||
|
||||
static ssize_t ab3100_get_set_reg(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ab3100_get_set_reg_priv *priv = file->private_data;
|
||||
struct ab3100 *ab3100 = priv->ab3100;
|
||||
char buf[32];
|
||||
ssize_t buf_size;
|
||||
int regp;
|
||||
u8 user_reg;
|
||||
int err;
|
||||
int i = 0;
|
||||
|
||||
/* Get userspace string and assure termination */
|
||||
buf_size = min((ssize_t)count, (ssize_t)(sizeof(buf)-1));
|
||||
if (copy_from_user(buf, user_buf, buf_size))
|
||||
return -EFAULT;
|
||||
buf[buf_size] = 0;
|
||||
|
||||
/*
|
||||
* The idea is here to parse a string which is either
|
||||
* "0xnn" for reading a register, or "0xaa 0xbb" for
|
||||
* writing 0xbb to the register 0xaa. First move past
|
||||
* whitespace and then begin to parse the register.
|
||||
*/
|
||||
while ((i < buf_size) && (buf[i] == ' '))
|
||||
i++;
|
||||
regp = i;
|
||||
|
||||
/*
|
||||
* Advance pointer to end of string then terminate
|
||||
* the register string. This is needed to satisfy
|
||||
* the kstrtou8() function.
|
||||
*/
|
||||
while ((i < buf_size) && (buf[i] != ' '))
|
||||
i++;
|
||||
buf[i] = '\0';
|
||||
|
||||
err = kstrtou8(&buf[regp], 16, &user_reg);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Either we read or we write a register here */
|
||||
if (!priv->mode) {
|
||||
/* Reading */
|
||||
u8 regvalue;
|
||||
|
||||
ab3100_get_register_interruptible(ab3100, user_reg, ®value);
|
||||
|
||||
dev_info(ab3100->dev,
|
||||
"debug read AB3100 reg[0x%02x]: 0x%02x\n",
|
||||
user_reg, regvalue);
|
||||
} else {
|
||||
int valp;
|
||||
u8 user_value;
|
||||
u8 regvalue;
|
||||
|
||||
/*
|
||||
* Writing, we need some value to write to
|
||||
* the register so keep parsing the string
|
||||
* from userspace.
|
||||
*/
|
||||
i++;
|
||||
while ((i < buf_size) && (buf[i] == ' '))
|
||||
i++;
|
||||
valp = i;
|
||||
while ((i < buf_size) && (buf[i] != ' '))
|
||||
i++;
|
||||
buf[i] = '\0';
|
||||
|
||||
err = kstrtou8(&buf[valp], 16, &user_value);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ab3100_set_register_interruptible(ab3100, user_reg, user_value);
|
||||
ab3100_get_register_interruptible(ab3100, user_reg, ®value);
|
||||
|
||||
dev_info(ab3100->dev,
|
||||
"debug write reg[0x%02x]\n"
|
||||
" with 0x%02x, after readback: 0x%02x\n",
|
||||
user_reg, user_value, regvalue);
|
||||
}
|
||||
return buf_size;
|
||||
}
|
||||
|
||||
static const struct file_operations ab3100_get_set_reg_fops = {
|
||||
.open = simple_open,
|
||||
.write = ab3100_get_set_reg,
|
||||
.llseek = noop_llseek,
|
||||
};
|
||||
|
||||
static struct ab3100_get_set_reg_priv ab3100_get_priv;
|
||||
static struct ab3100_get_set_reg_priv ab3100_set_priv;
|
||||
|
||||
static void ab3100_setup_debugfs(struct ab3100 *ab3100)
|
||||
{
|
||||
struct dentry *ab3100_dir;
|
||||
|
||||
ab3100_dir = debugfs_create_dir("ab3100", NULL);
|
||||
|
||||
debugfs_create_file("registers", S_IRUGO, ab3100_dir, ab3100,
|
||||
&ab3100_registers_fops);
|
||||
|
||||
ab3100_get_priv.ab3100 = ab3100;
|
||||
ab3100_get_priv.mode = false;
|
||||
debugfs_create_file("get_reg", S_IWUSR, ab3100_dir, &ab3100_get_priv,
|
||||
&ab3100_get_set_reg_fops);
|
||||
|
||||
ab3100_set_priv.ab3100 = ab3100;
|
||||
ab3100_set_priv.mode = true;
|
||||
debugfs_create_file("set_reg", S_IWUSR, ab3100_dir, &ab3100_set_priv,
|
||||
&ab3100_get_set_reg_fops);
|
||||
}
|
||||
#else
|
||||
static inline void ab3100_setup_debugfs(struct ab3100 *ab3100)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Basic set-up, datastructure creation/destruction and I2C interface.
|
||||
* This sets up a default config in the AB3100 chip so that it
|
||||
* will work as expected.
|
||||
*/
|
||||
|
||||
struct ab3100_init_setting {
|
||||
u8 abreg;
|
||||
u8 setting;
|
||||
};
|
||||
|
||||
static const struct ab3100_init_setting ab3100_init_settings[] = {
|
||||
{
|
||||
.abreg = AB3100_MCA,
|
||||
.setting = 0x01
|
||||
}, {
|
||||
.abreg = AB3100_MCB,
|
||||
.setting = 0x30
|
||||
}, {
|
||||
.abreg = AB3100_IMRA1,
|
||||
.setting = 0x00
|
||||
}, {
|
||||
.abreg = AB3100_IMRA2,
|
||||
.setting = 0xFF
|
||||
}, {
|
||||
.abreg = AB3100_IMRA3,
|
||||
.setting = 0x01
|
||||
}, {
|
||||
.abreg = AB3100_IMRB1,
|
||||
.setting = 0xBF
|
||||
}, {
|
||||
.abreg = AB3100_IMRB2,
|
||||
.setting = 0xFF
|
||||
}, {
|
||||
.abreg = AB3100_IMRB3,
|
||||
.setting = 0xFF
|
||||
}, {
|
||||
.abreg = AB3100_SUP,
|
||||
.setting = 0x00
|
||||
}, {
|
||||
.abreg = AB3100_DIS,
|
||||
.setting = 0xF0
|
||||
}, {
|
||||
.abreg = AB3100_D0C,
|
||||
.setting = 0x00
|
||||
}, {
|
||||
.abreg = AB3100_D1C,
|
||||
.setting = 0x00
|
||||
}, {
|
||||
.abreg = AB3100_D2C,
|
||||
.setting = 0x00
|
||||
}, {
|
||||
.abreg = AB3100_D3C,
|
||||
.setting = 0x00
|
||||
},
|
||||
};
|
||||
|
||||
static int ab3100_setup(struct ab3100 *ab3100)
|
||||
{
|
||||
int err = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ab3100_init_settings); i++) {
|
||||
err = ab3100_set_register_interruptible(ab3100,
|
||||
ab3100_init_settings[i].abreg,
|
||||
ab3100_init_settings[i].setting);
|
||||
if (err)
|
||||
goto exit_no_setup;
|
||||
}
|
||||
|
||||
/*
|
||||
* Special trick to make the AB3100 use the 32kHz clock (RTC)
|
||||
* bit 3 in test register 0x02 is a special, undocumented test
|
||||
* register bit that only exist in AB3100 P1E
|
||||
*/
|
||||
if (ab3100->chip_id == 0xc4) {
|
||||
dev_warn(ab3100->dev,
|
||||
"AB3100 P1E variant detected forcing chip to 32KHz\n");
|
||||
err = ab3100_set_test_register_interruptible(ab3100,
|
||||
0x02, 0x08);
|
||||
}
|
||||
|
||||
exit_no_setup:
|
||||
return err;
|
||||
}
|
||||
|
||||
/* The subdevices of the AB3100 */
|
||||
static struct mfd_cell ab3100_devs[] = {
|
||||
{
|
||||
.name = "ab3100-dac",
|
||||
.id = -1,
|
||||
},
|
||||
{
|
||||
.name = "ab3100-leds",
|
||||
.id = -1,
|
||||
},
|
||||
{
|
||||
.name = "ab3100-power",
|
||||
.id = -1,
|
||||
},
|
||||
{
|
||||
.name = "ab3100-regulators",
|
||||
.of_compatible = "stericsson,ab3100-regulators",
|
||||
.id = -1,
|
||||
},
|
||||
{
|
||||
.name = "ab3100-sim",
|
||||
.id = -1,
|
||||
},
|
||||
{
|
||||
.name = "ab3100-uart",
|
||||
.id = -1,
|
||||
},
|
||||
{
|
||||
.name = "ab3100-rtc",
|
||||
.id = -1,
|
||||
},
|
||||
{
|
||||
.name = "ab3100-charger",
|
||||
.id = -1,
|
||||
},
|
||||
{
|
||||
.name = "ab3100-boost",
|
||||
.id = -1,
|
||||
},
|
||||
{
|
||||
.name = "ab3100-adc",
|
||||
.id = -1,
|
||||
},
|
||||
{
|
||||
.name = "ab3100-fuelgauge",
|
||||
.id = -1,
|
||||
},
|
||||
{
|
||||
.name = "ab3100-vibrator",
|
||||
.id = -1,
|
||||
},
|
||||
{
|
||||
.name = "ab3100-otp",
|
||||
.id = -1,
|
||||
},
|
||||
{
|
||||
.name = "ab3100-codec",
|
||||
.id = -1,
|
||||
},
|
||||
};
|
||||
|
||||
struct ab_family_id {
|
||||
u8 id;
|
||||
char *name;
|
||||
};
|
||||
|
||||
static const struct ab_family_id ids[] = {
|
||||
/* AB3100 */
|
||||
{
|
||||
.id = 0xc0,
|
||||
.name = "P1A"
|
||||
}, {
|
||||
.id = 0xc1,
|
||||
.name = "P1B"
|
||||
}, {
|
||||
.id = 0xc2,
|
||||
.name = "P1C"
|
||||
}, {
|
||||
.id = 0xc3,
|
||||
.name = "P1D"
|
||||
}, {
|
||||
.id = 0xc4,
|
||||
.name = "P1E"
|
||||
}, {
|
||||
.id = 0xc5,
|
||||
.name = "P1F/R1A"
|
||||
}, {
|
||||
.id = 0xc6,
|
||||
.name = "P1G/R1A"
|
||||
}, {
|
||||
.id = 0xc7,
|
||||
.name = "P2A/R2A"
|
||||
}, {
|
||||
.id = 0xc8,
|
||||
.name = "P2B/R2B"
|
||||
},
|
||||
/* AB3000 variants, not supported */
|
||||
{
|
||||
.id = 0xa0
|
||||
}, {
|
||||
.id = 0xa1
|
||||
}, {
|
||||
.id = 0xa2
|
||||
}, {
|
||||
.id = 0xa3
|
||||
}, {
|
||||
.id = 0xa4
|
||||
}, {
|
||||
.id = 0xa5
|
||||
}, {
|
||||
.id = 0xa6
|
||||
}, {
|
||||
.id = 0xa7
|
||||
},
|
||||
/* Terminator */
|
||||
{
|
||||
.id = 0x00,
|
||||
},
|
||||
};
|
||||
|
||||
static int ab3100_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct ab3100 *ab3100;
|
||||
struct ab3100_platform_data *ab3100_plf_data =
|
||||
dev_get_platdata(&client->dev);
|
||||
int err;
|
||||
int i;
|
||||
|
||||
ab3100 = devm_kzalloc(&client->dev, sizeof(struct ab3100), GFP_KERNEL);
|
||||
if (!ab3100)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Initialize data structure */
|
||||
mutex_init(&ab3100->access_mutex);
|
||||
BLOCKING_INIT_NOTIFIER_HEAD(&ab3100->event_subscribers);
|
||||
|
||||
ab3100->i2c_client = client;
|
||||
ab3100->dev = &ab3100->i2c_client->dev;
|
||||
|
||||
i2c_set_clientdata(client, ab3100);
|
||||
|
||||
/* Read chip ID register */
|
||||
err = ab3100_get_register_interruptible(ab3100, AB3100_CID,
|
||||
&ab3100->chip_id);
|
||||
if (err) {
|
||||
dev_err(&client->dev,
|
||||
"failed to communicate with AB3100 chip\n");
|
||||
goto exit_no_detect;
|
||||
}
|
||||
|
||||
for (i = 0; ids[i].id != 0x0; i++) {
|
||||
if (ids[i].id == ab3100->chip_id) {
|
||||
if (ids[i].name)
|
||||
break;
|
||||
|
||||
dev_err(&client->dev, "AB3000 is not supported\n");
|
||||
goto exit_no_detect;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(&ab3100->chip_name[0],
|
||||
sizeof(ab3100->chip_name) - 1, "AB3100 %s", ids[i].name);
|
||||
|
||||
if (ids[i].id == 0x0) {
|
||||
dev_err(&client->dev, "unknown analog baseband chip id: 0x%x\n",
|
||||
ab3100->chip_id);
|
||||
dev_err(&client->dev,
|
||||
"accepting it anyway. Please update the driver.\n");
|
||||
goto exit_no_detect;
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "Detected chip: %s\n",
|
||||
&ab3100->chip_name[0]);
|
||||
|
||||
/* Attach a second dummy i2c_client to the test register address */
|
||||
ab3100->testreg_client = i2c_new_dummy_device(client->adapter,
|
||||
client->addr + 1);
|
||||
if (IS_ERR(ab3100->testreg_client)) {
|
||||
err = PTR_ERR(ab3100->testreg_client);
|
||||
goto exit_no_testreg_client;
|
||||
}
|
||||
|
||||
err = ab3100_setup(ab3100);
|
||||
if (err)
|
||||
goto exit_no_setup;
|
||||
|
||||
err = devm_request_threaded_irq(&client->dev,
|
||||
client->irq, NULL, ab3100_irq_handler,
|
||||
IRQF_ONESHOT, "ab3100-core", ab3100);
|
||||
if (err)
|
||||
goto exit_no_irq;
|
||||
|
||||
err = abx500_register_ops(&client->dev, &ab3100_ops);
|
||||
if (err)
|
||||
goto exit_no_ops;
|
||||
|
||||
/* Set up and register the platform devices. */
|
||||
for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++) {
|
||||
ab3100_devs[i].platform_data = ab3100_plf_data;
|
||||
ab3100_devs[i].pdata_size = sizeof(struct ab3100_platform_data);
|
||||
}
|
||||
|
||||
err = mfd_add_devices(&client->dev, 0, ab3100_devs,
|
||||
ARRAY_SIZE(ab3100_devs), NULL, 0, NULL);
|
||||
|
||||
ab3100_setup_debugfs(ab3100);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_no_ops:
|
||||
exit_no_irq:
|
||||
exit_no_setup:
|
||||
i2c_unregister_device(ab3100->testreg_client);
|
||||
exit_no_testreg_client:
|
||||
exit_no_detect:
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ab3100_id[] = {
|
||||
{ "ab3100", 0 },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct i2c_driver ab3100_driver = {
|
||||
.driver = {
|
||||
.name = "ab3100",
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
.id_table = ab3100_id,
|
||||
.probe = ab3100_probe,
|
||||
};
|
||||
|
||||
static int __init ab3100_i2c_init(void)
|
||||
{
|
||||
return i2c_add_driver(&ab3100_driver);
|
||||
}
|
||||
subsys_initcall(ab3100_i2c_init);
|
@ -1,240 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* drivers/mfd/ab3100_otp.c
|
||||
*
|
||||
* Copyright (C) 2007-2009 ST-Ericsson AB
|
||||
* Driver to read out OTP from the AB3100 Mixed-signal circuit
|
||||
* Author: Linus Walleij <linus.walleij@stericsson.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/abx500.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
/* The OTP registers */
|
||||
#define AB3100_OTP0 0xb0
|
||||
#define AB3100_OTP1 0xb1
|
||||
#define AB3100_OTP2 0xb2
|
||||
#define AB3100_OTP3 0xb3
|
||||
#define AB3100_OTP4 0xb4
|
||||
#define AB3100_OTP5 0xb5
|
||||
#define AB3100_OTP6 0xb6
|
||||
#define AB3100_OTP7 0xb7
|
||||
#define AB3100_OTPP 0xbf
|
||||
|
||||
/**
|
||||
* struct ab3100_otp
|
||||
* @dev: containing device
|
||||
* @locked: whether the OTP is locked, after locking, no more bits
|
||||
* can be changed but before locking it is still possible
|
||||
* to change bits from 1->0.
|
||||
* @freq: clocking frequency for the OTP, this frequency is either
|
||||
* 32768Hz or 1MHz/30
|
||||
* @paf: product activation flag, indicates whether this is a real
|
||||
* product (paf true) or a lab board etc (paf false)
|
||||
* @imeich: if this is set it is possible to override the
|
||||
* IMEI number found in the tac, fac and svn fields with
|
||||
* (secured) software
|
||||
* @cid: customer ID
|
||||
* @tac: type allocation code of the IMEI
|
||||
* @fac: final assembly code of the IMEI
|
||||
* @svn: software version number of the IMEI
|
||||
* @debugfs: a debugfs file used when dumping to file
|
||||
*/
|
||||
struct ab3100_otp {
|
||||
struct device *dev;
|
||||
bool locked;
|
||||
u32 freq;
|
||||
bool paf;
|
||||
bool imeich;
|
||||
u16 cid:14;
|
||||
u32 tac:20;
|
||||
u8 fac;
|
||||
u32 svn:20;
|
||||
struct dentry *debugfs;
|
||||
};
|
||||
|
||||
static int __init ab3100_otp_read(struct ab3100_otp *otp)
|
||||
{
|
||||
u8 otpval[8];
|
||||
u8 otpp;
|
||||
int err;
|
||||
|
||||
err = abx500_get_register_interruptible(otp->dev, 0,
|
||||
AB3100_OTPP, &otpp);
|
||||
if (err) {
|
||||
dev_err(otp->dev, "unable to read OTPP register\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = abx500_get_register_page_interruptible(otp->dev, 0,
|
||||
AB3100_OTP0, otpval, 8);
|
||||
if (err) {
|
||||
dev_err(otp->dev, "unable to read OTP register page\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Cache OTP properties, they never change by nature */
|
||||
otp->locked = (otpp & 0x80);
|
||||
otp->freq = (otpp & 0x40) ? 32768 : 34100;
|
||||
otp->paf = (otpval[1] & 0x80);
|
||||
otp->imeich = (otpval[1] & 0x40);
|
||||
otp->cid = ((otpval[1] << 8) | otpval[0]) & 0x3fff;
|
||||
otp->tac = ((otpval[4] & 0x0f) << 16) | (otpval[3] << 8) | otpval[2];
|
||||
otp->fac = ((otpval[5] & 0x0f) << 4) | (otpval[4] >> 4);
|
||||
otp->svn = (otpval[7] << 12) | (otpval[6] << 4) | (otpval[5] >> 4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a simple debugfs human-readable file that dumps out
|
||||
* the contents of the OTP.
|
||||
*/
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
static int ab3100_show_otp(struct seq_file *s, void *v)
|
||||
{
|
||||
struct ab3100_otp *otp = s->private;
|
||||
|
||||
seq_printf(s, "OTP is %s\n", otp->locked ? "LOCKED" : "UNLOCKED");
|
||||
seq_printf(s, "OTP clock switch startup is %uHz\n", otp->freq);
|
||||
seq_printf(s, "PAF is %s\n", otp->paf ? "SET" : "NOT SET");
|
||||
seq_printf(s, "IMEI is %s\n", otp->imeich ?
|
||||
"CHANGEABLE" : "NOT CHANGEABLE");
|
||||
seq_printf(s, "CID: 0x%04x (decimal: %d)\n", otp->cid, otp->cid);
|
||||
seq_printf(s, "IMEI: %u-%u-%u\n", otp->tac, otp->fac, otp->svn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ab3100_otp_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, ab3100_show_otp, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations ab3100_otp_operations = {
|
||||
.open = ab3100_otp_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static void __init ab3100_otp_init_debugfs(struct device *dev,
|
||||
struct ab3100_otp *otp)
|
||||
{
|
||||
otp->debugfs = debugfs_create_file("ab3100_otp", S_IFREG | S_IRUGO,
|
||||
NULL, otp, &ab3100_otp_operations);
|
||||
}
|
||||
|
||||
static void __exit ab3100_otp_exit_debugfs(struct ab3100_otp *otp)
|
||||
{
|
||||
debugfs_remove(otp->debugfs);
|
||||
}
|
||||
#else
|
||||
/* Compile this out if debugfs not selected */
|
||||
static inline void __init ab3100_otp_init_debugfs(struct device *dev,
|
||||
struct ab3100_otp *otp)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void __exit ab3100_otp_exit_debugfs(struct ab3100_otp *otp)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#define SHOW_AB3100_ATTR(name) \
|
||||
static ssize_t ab3100_otp_##name##_show(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{\
|
||||
struct ab3100_otp *otp = dev_get_drvdata(dev); \
|
||||
return sprintf(buf, "%u\n", otp->name); \
|
||||
}
|
||||
|
||||
SHOW_AB3100_ATTR(locked)
|
||||
SHOW_AB3100_ATTR(freq)
|
||||
SHOW_AB3100_ATTR(paf)
|
||||
SHOW_AB3100_ATTR(imeich)
|
||||
SHOW_AB3100_ATTR(cid)
|
||||
SHOW_AB3100_ATTR(fac)
|
||||
SHOW_AB3100_ATTR(tac)
|
||||
SHOW_AB3100_ATTR(svn)
|
||||
|
||||
static struct device_attribute ab3100_otp_attrs[] = {
|
||||
__ATTR(locked, S_IRUGO, ab3100_otp_locked_show, NULL),
|
||||
__ATTR(freq, S_IRUGO, ab3100_otp_freq_show, NULL),
|
||||
__ATTR(paf, S_IRUGO, ab3100_otp_paf_show, NULL),
|
||||
__ATTR(imeich, S_IRUGO, ab3100_otp_imeich_show, NULL),
|
||||
__ATTR(cid, S_IRUGO, ab3100_otp_cid_show, NULL),
|
||||
__ATTR(fac, S_IRUGO, ab3100_otp_fac_show, NULL),
|
||||
__ATTR(tac, S_IRUGO, ab3100_otp_tac_show, NULL),
|
||||
__ATTR(svn, S_IRUGO, ab3100_otp_svn_show, NULL),
|
||||
};
|
||||
|
||||
static int __init ab3100_otp_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ab3100_otp *otp;
|
||||
int err = 0;
|
||||
int i;
|
||||
|
||||
otp = devm_kzalloc(&pdev->dev, sizeof(struct ab3100_otp), GFP_KERNEL);
|
||||
if (!otp)
|
||||
return -ENOMEM;
|
||||
|
||||
otp->dev = &pdev->dev;
|
||||
|
||||
/* Replace platform data coming in with a local struct */
|
||||
platform_set_drvdata(pdev, otp);
|
||||
|
||||
err = ab3100_otp_read(otp);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
dev_info(&pdev->dev, "AB3100 OTP readout registered\n");
|
||||
|
||||
/* sysfs entries */
|
||||
for (i = 0; i < ARRAY_SIZE(ab3100_otp_attrs); i++) {
|
||||
err = device_create_file(&pdev->dev,
|
||||
&ab3100_otp_attrs[i]);
|
||||
if (err)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* debugfs entries */
|
||||
ab3100_otp_init_debugfs(&pdev->dev, otp);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
while (--i >= 0)
|
||||
device_remove_file(&pdev->dev, &ab3100_otp_attrs[i]);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __exit ab3100_otp_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ab3100_otp *otp = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ab3100_otp_attrs); i++)
|
||||
device_remove_file(&pdev->dev,
|
||||
&ab3100_otp_attrs[i]);
|
||||
ab3100_otp_exit_debugfs(otp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ab3100_otp_driver = {
|
||||
.driver = {
|
||||
.name = "ab3100-otp",
|
||||
},
|
||||
.remove = __exit_p(ab3100_otp_remove),
|
||||
};
|
||||
|
||||
module_platform_driver_probe(ab3100_otp_driver, ab3100_otp_probe);
|
||||
|
||||
MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
|
||||
MODULE_DESCRIPTION("AB3100 OTP Readout Driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -120,12 +120,6 @@
|
||||
static DEFINE_SPINLOCK(on_stat_lock);
|
||||
static u8 turn_on_stat_mask = 0xFF;
|
||||
static u8 turn_on_stat_set;
|
||||
static bool no_bm; /* No battery management */
|
||||
/*
|
||||
* not really modular, but the easiest way to keep compat with existing
|
||||
* bootargs behaviour is to continue using module_param here.
|
||||
*/
|
||||
module_param(no_bm, bool, S_IRUGO);
|
||||
|
||||
#define AB9540_MODEM_CTRL2_REG 0x23
|
||||
#define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT BIT(2)
|
||||
@ -1254,14 +1248,12 @@ static int ab8500_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!no_bm) {
|
||||
/* Add battery management devices */
|
||||
ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs,
|
||||
ARRAY_SIZE(ab8500_bm_devs), NULL,
|
||||
0, ab8500->domain);
|
||||
if (ret)
|
||||
dev_err(ab8500->dev, "error adding bm devices\n");
|
||||
}
|
||||
/* Add battery management devices */
|
||||
ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs,
|
||||
ARRAY_SIZE(ab8500_bm_devs), NULL,
|
||||
0, ab8500->domain);
|
||||
if (ret)
|
||||
dev_err(ab8500->dev, "error adding bm devices\n");
|
||||
|
||||
if (((is_ab8505(ab8500) || is_ab9540(ab8500)) &&
|
||||
ab8500->chip_id >= AB8500_CUT2P0) || is_ab8540(ab8500))
|
||||
|
@ -881,11 +881,6 @@ static const char * const wm5102_supplies[] = {
|
||||
static const struct mfd_cell wm5102_devs[] = {
|
||||
{ .name = "arizona-micsupp" },
|
||||
{ .name = "arizona-gpio" },
|
||||
{
|
||||
.name = "arizona-extcon",
|
||||
.parent_supplies = wm5102_supplies,
|
||||
.num_parent_supplies = 1, /* We only need MICVDD */
|
||||
},
|
||||
{ .name = "arizona-haptics" },
|
||||
{ .name = "arizona-pwm" },
|
||||
{
|
||||
@ -898,11 +893,6 @@ static const struct mfd_cell wm5102_devs[] = {
|
||||
static const struct mfd_cell wm5110_devs[] = {
|
||||
{ .name = "arizona-micsupp" },
|
||||
{ .name = "arizona-gpio" },
|
||||
{
|
||||
.name = "arizona-extcon",
|
||||
.parent_supplies = wm5102_supplies,
|
||||
.num_parent_supplies = 1, /* We only need MICVDD */
|
||||
},
|
||||
{ .name = "arizona-haptics" },
|
||||
{ .name = "arizona-pwm" },
|
||||
{
|
||||
@ -939,11 +929,6 @@ static const char * const wm8997_supplies[] = {
|
||||
static const struct mfd_cell wm8997_devs[] = {
|
||||
{ .name = "arizona-micsupp" },
|
||||
{ .name = "arizona-gpio" },
|
||||
{
|
||||
.name = "arizona-extcon",
|
||||
.parent_supplies = wm8997_supplies,
|
||||
.num_parent_supplies = 1, /* We only need MICVDD */
|
||||
},
|
||||
{ .name = "arizona-haptics" },
|
||||
{ .name = "arizona-pwm" },
|
||||
{
|
||||
@ -956,11 +941,6 @@ static const struct mfd_cell wm8997_devs[] = {
|
||||
static const struct mfd_cell wm8998_devs[] = {
|
||||
{ .name = "arizona-micsupp" },
|
||||
{ .name = "arizona-gpio" },
|
||||
{
|
||||
.name = "arizona-extcon",
|
||||
.parent_supplies = wm5102_supplies,
|
||||
.num_parent_supplies = 1, /* We only need MICVDD */
|
||||
},
|
||||
{ .name = "arizona-haptics" },
|
||||
{ .name = "arizona-pwm" },
|
||||
{
|
||||
|
@ -100,7 +100,7 @@ static irqreturn_t arizona_irq_thread(int irq, void *data)
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_get_sync(arizona->dev);
|
||||
ret = pm_runtime_resume_and_get(arizona->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(arizona->dev, "Failed to resume device: %d\n", ret);
|
||||
return IRQ_NONE;
|
||||
|
@ -25,8 +25,8 @@
|
||||
#include "arizona.h"
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
const struct acpi_gpio_params reset_gpios = { 1, 0, false };
|
||||
const struct acpi_gpio_params ldoena_gpios = { 2, 0, false };
|
||||
static const struct acpi_gpio_params reset_gpios = { 1, 0, false };
|
||||
static const struct acpi_gpio_params ldoena_gpios = { 2, 0, false };
|
||||
|
||||
static const struct acpi_gpio_mapping arizona_acpi_gpios[] = {
|
||||
{ "reset-gpios", &reset_gpios, 1, },
|
||||
|
310
drivers/mfd/atc260x-core.c
Normal file
310
drivers/mfd/atc260x-core.c
Normal file
@ -0,0 +1,310 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Core support for ATC260x PMICs
|
||||
*
|
||||
* Copyright (C) 2019 Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
* Copyright (C) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mfd/atc260x/core.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define ATC260X_CHIP_REV_MAX 31
|
||||
|
||||
struct atc260x_init_regs {
|
||||
unsigned int cmu_devrst;
|
||||
unsigned int cmu_devrst_ints;
|
||||
unsigned int ints_msk;
|
||||
unsigned int pad_en;
|
||||
unsigned int pad_en_extirq;
|
||||
};
|
||||
|
||||
static void regmap_lock_mutex(void *__mutex)
|
||||
{
|
||||
struct mutex *mutex = __mutex;
|
||||
|
||||
/*
|
||||
* Using regmap within an atomic context (e.g. accessing a PMIC when
|
||||
* powering system down) is normally allowed only if the regmap type
|
||||
* is MMIO and the regcache type is either REGCACHE_NONE or
|
||||
* REGCACHE_FLAT. For slow buses like I2C and SPI, the regmap is
|
||||
* internally protected by a mutex which is acquired non-atomically.
|
||||
*
|
||||
* Let's improve this by using a customized locking scheme inspired
|
||||
* from I2C atomic transfer. See i2c_in_atomic_xfer_mode() for a
|
||||
* starting point.
|
||||
*/
|
||||
if (system_state > SYSTEM_RUNNING && irqs_disabled())
|
||||
mutex_trylock(mutex);
|
||||
else
|
||||
mutex_lock(mutex);
|
||||
}
|
||||
|
||||
static void regmap_unlock_mutex(void *__mutex)
|
||||
{
|
||||
struct mutex *mutex = __mutex;
|
||||
|
||||
mutex_unlock(mutex);
|
||||
}
|
||||
|
||||
static const struct regmap_config atc2603c_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 16,
|
||||
.max_register = ATC2603C_SADDR,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
};
|
||||
|
||||
static const struct regmap_config atc2609a_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 16,
|
||||
.max_register = ATC2609A_SADDR,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
};
|
||||
|
||||
static const struct regmap_irq atc2603c_regmap_irqs[] = {
|
||||
REGMAP_IRQ_REG(ATC2603C_IRQ_AUDIO, 0, ATC2603C_INTS_MSK_AUDIO),
|
||||
REGMAP_IRQ_REG(ATC2603C_IRQ_OV, 0, ATC2603C_INTS_MSK_OV),
|
||||
REGMAP_IRQ_REG(ATC2603C_IRQ_OC, 0, ATC2603C_INTS_MSK_OC),
|
||||
REGMAP_IRQ_REG(ATC2603C_IRQ_OT, 0, ATC2603C_INTS_MSK_OT),
|
||||
REGMAP_IRQ_REG(ATC2603C_IRQ_UV, 0, ATC2603C_INTS_MSK_UV),
|
||||
REGMAP_IRQ_REG(ATC2603C_IRQ_ALARM, 0, ATC2603C_INTS_MSK_ALARM),
|
||||
REGMAP_IRQ_REG(ATC2603C_IRQ_ONOFF, 0, ATC2603C_INTS_MSK_ONOFF),
|
||||
REGMAP_IRQ_REG(ATC2603C_IRQ_SGPIO, 0, ATC2603C_INTS_MSK_SGPIO),
|
||||
REGMAP_IRQ_REG(ATC2603C_IRQ_IR, 0, ATC2603C_INTS_MSK_IR),
|
||||
REGMAP_IRQ_REG(ATC2603C_IRQ_REMCON, 0, ATC2603C_INTS_MSK_REMCON),
|
||||
REGMAP_IRQ_REG(ATC2603C_IRQ_POWER_IN, 0, ATC2603C_INTS_MSK_POWERIN),
|
||||
};
|
||||
|
||||
static const struct regmap_irq atc2609a_regmap_irqs[] = {
|
||||
REGMAP_IRQ_REG(ATC2609A_IRQ_AUDIO, 0, ATC2609A_INTS_MSK_AUDIO),
|
||||
REGMAP_IRQ_REG(ATC2609A_IRQ_OV, 0, ATC2609A_INTS_MSK_OV),
|
||||
REGMAP_IRQ_REG(ATC2609A_IRQ_OC, 0, ATC2609A_INTS_MSK_OC),
|
||||
REGMAP_IRQ_REG(ATC2609A_IRQ_OT, 0, ATC2609A_INTS_MSK_OT),
|
||||
REGMAP_IRQ_REG(ATC2609A_IRQ_UV, 0, ATC2609A_INTS_MSK_UV),
|
||||
REGMAP_IRQ_REG(ATC2609A_IRQ_ALARM, 0, ATC2609A_INTS_MSK_ALARM),
|
||||
REGMAP_IRQ_REG(ATC2609A_IRQ_ONOFF, 0, ATC2609A_INTS_MSK_ONOFF),
|
||||
REGMAP_IRQ_REG(ATC2609A_IRQ_WKUP, 0, ATC2609A_INTS_MSK_WKUP),
|
||||
REGMAP_IRQ_REG(ATC2609A_IRQ_IR, 0, ATC2609A_INTS_MSK_IR),
|
||||
REGMAP_IRQ_REG(ATC2609A_IRQ_REMCON, 0, ATC2609A_INTS_MSK_REMCON),
|
||||
REGMAP_IRQ_REG(ATC2609A_IRQ_POWER_IN, 0, ATC2609A_INTS_MSK_POWERIN),
|
||||
};
|
||||
|
||||
static const struct regmap_irq_chip atc2603c_regmap_irq_chip = {
|
||||
.name = "atc2603c",
|
||||
.irqs = atc2603c_regmap_irqs,
|
||||
.num_irqs = ARRAY_SIZE(atc2603c_regmap_irqs),
|
||||
.num_regs = 1,
|
||||
.status_base = ATC2603C_INTS_PD,
|
||||
.mask_base = ATC2603C_INTS_MSK,
|
||||
.mask_invert = true,
|
||||
};
|
||||
|
||||
static const struct regmap_irq_chip atc2609a_regmap_irq_chip = {
|
||||
.name = "atc2609a",
|
||||
.irqs = atc2609a_regmap_irqs,
|
||||
.num_irqs = ARRAY_SIZE(atc2609a_regmap_irqs),
|
||||
.num_regs = 1,
|
||||
.status_base = ATC2609A_INTS_PD,
|
||||
.mask_base = ATC2609A_INTS_MSK,
|
||||
.mask_invert = true,
|
||||
};
|
||||
|
||||
static const struct resource atc2603c_onkey_resources[] = {
|
||||
DEFINE_RES_IRQ(ATC2603C_IRQ_ONOFF),
|
||||
};
|
||||
|
||||
static const struct resource atc2609a_onkey_resources[] = {
|
||||
DEFINE_RES_IRQ(ATC2609A_IRQ_ONOFF),
|
||||
};
|
||||
|
||||
static const struct mfd_cell atc2603c_mfd_cells[] = {
|
||||
{ .name = "atc260x-regulator" },
|
||||
{ .name = "atc260x-pwrc" },
|
||||
{
|
||||
.name = "atc260x-onkey",
|
||||
.num_resources = ARRAY_SIZE(atc2603c_onkey_resources),
|
||||
.resources = atc2603c_onkey_resources,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct mfd_cell atc2609a_mfd_cells[] = {
|
||||
{ .name = "atc260x-regulator" },
|
||||
{ .name = "atc260x-pwrc" },
|
||||
{
|
||||
.name = "atc260x-onkey",
|
||||
.num_resources = ARRAY_SIZE(atc2609a_onkey_resources),
|
||||
.resources = atc2609a_onkey_resources,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct atc260x_init_regs atc2603c_init_regs = {
|
||||
.cmu_devrst = ATC2603C_CMU_DEVRST,
|
||||
.cmu_devrst_ints = ATC2603C_CMU_DEVRST_INTS,
|
||||
.ints_msk = ATC2603C_INTS_MSK,
|
||||
.pad_en = ATC2603C_PAD_EN,
|
||||
.pad_en_extirq = ATC2603C_PAD_EN_EXTIRQ,
|
||||
};
|
||||
|
||||
static const struct atc260x_init_regs atc2609a_init_regs = {
|
||||
.cmu_devrst = ATC2609A_CMU_DEVRST,
|
||||
.cmu_devrst_ints = ATC2609A_CMU_DEVRST_INTS,
|
||||
.ints_msk = ATC2609A_INTS_MSK,
|
||||
.pad_en = ATC2609A_PAD_EN,
|
||||
.pad_en_extirq = ATC2609A_PAD_EN_EXTIRQ,
|
||||
};
|
||||
|
||||
static void atc260x_cmu_reset(struct atc260x *atc260x)
|
||||
{
|
||||
const struct atc260x_init_regs *regs = atc260x->init_regs;
|
||||
|
||||
/* Assert reset */
|
||||
regmap_update_bits(atc260x->regmap, regs->cmu_devrst,
|
||||
regs->cmu_devrst_ints, ~regs->cmu_devrst_ints);
|
||||
|
||||
/* De-assert reset */
|
||||
regmap_update_bits(atc260x->regmap, regs->cmu_devrst,
|
||||
regs->cmu_devrst_ints, regs->cmu_devrst_ints);
|
||||
}
|
||||
|
||||
static void atc260x_dev_init(struct atc260x *atc260x)
|
||||
{
|
||||
const struct atc260x_init_regs *regs = atc260x->init_regs;
|
||||
|
||||
/* Initialize interrupt block */
|
||||
atc260x_cmu_reset(atc260x);
|
||||
|
||||
/* Disable all interrupt sources */
|
||||
regmap_write(atc260x->regmap, regs->ints_msk, 0);
|
||||
|
||||
/* Enable EXTIRQ pad */
|
||||
regmap_update_bits(atc260x->regmap, regs->pad_en,
|
||||
regs->pad_en_extirq, regs->pad_en_extirq);
|
||||
}
|
||||
|
||||
/**
|
||||
* atc260x_match_device(): Setup ATC260x variant related fields
|
||||
*
|
||||
* @atc260x: ATC260x device to setup (.dev field must be set)
|
||||
* @regmap_cfg: regmap config associated with this ATC260x device
|
||||
*
|
||||
* This lets the ATC260x core configure the MFD cells and register maps
|
||||
* for later use.
|
||||
*/
|
||||
int atc260x_match_device(struct atc260x *atc260x, struct regmap_config *regmap_cfg)
|
||||
{
|
||||
struct device *dev = atc260x->dev;
|
||||
const void *of_data;
|
||||
|
||||
of_data = of_device_get_match_data(dev);
|
||||
if (!of_data)
|
||||
return -ENODEV;
|
||||
|
||||
atc260x->ic_type = (unsigned long)of_data;
|
||||
|
||||
switch (atc260x->ic_type) {
|
||||
case ATC2603C:
|
||||
*regmap_cfg = atc2603c_regmap_config;
|
||||
atc260x->regmap_irq_chip = &atc2603c_regmap_irq_chip;
|
||||
atc260x->cells = atc2603c_mfd_cells;
|
||||
atc260x->nr_cells = ARRAY_SIZE(atc2603c_mfd_cells);
|
||||
atc260x->type_name = "atc2603c";
|
||||
atc260x->rev_reg = ATC2603C_CHIP_VER;
|
||||
atc260x->init_regs = &atc2603c_init_regs;
|
||||
break;
|
||||
case ATC2609A:
|
||||
*regmap_cfg = atc2609a_regmap_config;
|
||||
atc260x->regmap_irq_chip = &atc2609a_regmap_irq_chip;
|
||||
atc260x->cells = atc2609a_mfd_cells;
|
||||
atc260x->nr_cells = ARRAY_SIZE(atc2609a_mfd_cells);
|
||||
atc260x->type_name = "atc2609a";
|
||||
atc260x->rev_reg = ATC2609A_CHIP_VER;
|
||||
atc260x->init_regs = &atc2609a_init_regs;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Unsupported ATC260x device type: %u\n",
|
||||
atc260x->ic_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
atc260x->regmap_mutex = devm_kzalloc(dev, sizeof(*atc260x->regmap_mutex),
|
||||
GFP_KERNEL);
|
||||
if (!atc260x->regmap_mutex)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(atc260x->regmap_mutex);
|
||||
|
||||
regmap_cfg->lock = regmap_lock_mutex,
|
||||
regmap_cfg->unlock = regmap_unlock_mutex,
|
||||
regmap_cfg->lock_arg = atc260x->regmap_mutex;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(atc260x_match_device);
|
||||
|
||||
/**
|
||||
* atc260x_device_probe(): Probe a configured ATC260x device
|
||||
*
|
||||
* @atc260x: ATC260x device to probe (must be configured)
|
||||
*
|
||||
* This function lets the ATC260x core register the ATC260x MFD devices
|
||||
* and IRQCHIP. The ATC260x device passed in must be fully configured
|
||||
* with atc260x_match_device, its IRQ set, and regmap created.
|
||||
*/
|
||||
int atc260x_device_probe(struct atc260x *atc260x)
|
||||
{
|
||||
struct device *dev = atc260x->dev;
|
||||
unsigned int chip_rev;
|
||||
int ret;
|
||||
|
||||
if (!atc260x->irq) {
|
||||
dev_err(dev, "No interrupt support\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Initialize the hardware */
|
||||
atc260x_dev_init(atc260x);
|
||||
|
||||
ret = regmap_read(atc260x->regmap, atc260x->rev_reg, &chip_rev);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to get chip revision\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (chip_rev > ATC260X_CHIP_REV_MAX) {
|
||||
dev_err(dev, "Unknown chip revision: %u\n", chip_rev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
atc260x->ic_ver = __ffs(chip_rev + 1U);
|
||||
|
||||
dev_info(dev, "Detected chip type %s rev.%c\n",
|
||||
atc260x->type_name, 'A' + atc260x->ic_ver);
|
||||
|
||||
ret = devm_regmap_add_irq_chip(dev, atc260x->regmap, atc260x->irq, IRQF_ONESHOT,
|
||||
-1, atc260x->regmap_irq_chip, &atc260x->irq_data);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to add IRQ chip: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
|
||||
atc260x->cells, atc260x->nr_cells, NULL, 0,
|
||||
regmap_irq_get_domain(atc260x->irq_data));
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to add child devices: %d\n", ret);
|
||||
regmap_del_irq_chip(atc260x->irq, atc260x->irq_data);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(atc260x_device_probe);
|
||||
|
||||
MODULE_DESCRIPTION("ATC260x PMICs Core support");
|
||||
MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
|
||||
MODULE_AUTHOR("Cristian Ciocaltea <cristian.ciocaltea@gmail.com>");
|
||||
MODULE_LICENSE("GPL");
|
64
drivers/mfd/atc260x-i2c.c
Normal file
64
drivers/mfd/atc260x-i2c.c
Normal file
@ -0,0 +1,64 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* I2C bus interface for ATC260x PMICs
|
||||
*
|
||||
* Copyright (C) 2019 Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
* Copyright (C) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mfd/atc260x/core.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
static int atc260x_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct atc260x *atc260x;
|
||||
struct regmap_config regmap_cfg;
|
||||
int ret;
|
||||
|
||||
atc260x = devm_kzalloc(&client->dev, sizeof(*atc260x), GFP_KERNEL);
|
||||
if (!atc260x)
|
||||
return -ENOMEM;
|
||||
|
||||
atc260x->dev = &client->dev;
|
||||
atc260x->irq = client->irq;
|
||||
|
||||
ret = atc260x_match_device(atc260x, ®map_cfg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
i2c_set_clientdata(client, atc260x);
|
||||
|
||||
atc260x->regmap = devm_regmap_init_i2c(client, ®map_cfg);
|
||||
if (IS_ERR(atc260x->regmap)) {
|
||||
ret = PTR_ERR(atc260x->regmap);
|
||||
dev_err(&client->dev, "failed to init regmap: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return atc260x_device_probe(atc260x);
|
||||
}
|
||||
|
||||
static const struct of_device_id atc260x_i2c_of_match[] = {
|
||||
{ .compatible = "actions,atc2603c", .data = (void *)ATC2603C },
|
||||
{ .compatible = "actions,atc2609a", .data = (void *)ATC2609A },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, atc260x_i2c_of_match);
|
||||
|
||||
static struct i2c_driver atc260x_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "atc260x",
|
||||
.of_match_table = of_match_ptr(atc260x_i2c_of_match),
|
||||
},
|
||||
.probe = atc260x_i2c_probe,
|
||||
};
|
||||
module_i2c_driver(atc260x_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ATC260x PMICs I2C bus interface");
|
||||
MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
|
||||
MODULE_AUTHOR("Cristian Ciocaltea <cristian.ciocaltea@gmail.com>");
|
||||
MODULE_LICENSE("GPL");
|
@ -442,6 +442,16 @@ static int da9063_i2c_probe(struct i2c_client *i2c,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* If SMBus is not available and only I2C is possible, enter I2C mode */
|
||||
if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) {
|
||||
ret = regmap_clear_bits(da9063->regmap, DA9063_REG_CONFIG_J,
|
||||
DA9063_TWOWIRE_TO);
|
||||
if (ret < 0) {
|
||||
dev_err(da9063->dev, "Failed to set Two-Wire Bus Mode.\n");
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
return da9063_device_init(da9063, i2c->irq);
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ struct kb3930 {
|
||||
struct gpio_descs *off_gpios;
|
||||
};
|
||||
|
||||
struct kb3930 *kb3930_power_off;
|
||||
static struct kb3930 *kb3930_power_off;
|
||||
|
||||
#define EC_GPIO_WAVE 0
|
||||
#define EC_GPIO_OFF_MODE 1
|
||||
|
@ -22,55 +22,71 @@ static const struct intel_lpss_platform_info spt_info = {
|
||||
.clk_rate = 120000000,
|
||||
};
|
||||
|
||||
static struct property_entry spt_i2c_properties[] = {
|
||||
static const struct property_entry spt_i2c_properties[] = {
|
||||
PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 230),
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct intel_lpss_platform_info spt_i2c_info = {
|
||||
.clk_rate = 120000000,
|
||||
static const struct software_node spt_i2c_node = {
|
||||
.properties = spt_i2c_properties,
|
||||
};
|
||||
|
||||
static struct property_entry uart_properties[] = {
|
||||
static const struct intel_lpss_platform_info spt_i2c_info = {
|
||||
.clk_rate = 120000000,
|
||||
.swnode = &spt_i2c_node,
|
||||
};
|
||||
|
||||
static const struct property_entry uart_properties[] = {
|
||||
PROPERTY_ENTRY_U32("reg-io-width", 4),
|
||||
PROPERTY_ENTRY_U32("reg-shift", 2),
|
||||
PROPERTY_ENTRY_BOOL("snps,uart-16550-compatible"),
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct software_node uart_node = {
|
||||
.properties = uart_properties,
|
||||
};
|
||||
|
||||
static const struct intel_lpss_platform_info spt_uart_info = {
|
||||
.clk_rate = 120000000,
|
||||
.clk_con_id = "baudclk",
|
||||
.properties = uart_properties,
|
||||
.swnode = &uart_node,
|
||||
};
|
||||
|
||||
static const struct intel_lpss_platform_info bxt_info = {
|
||||
.clk_rate = 100000000,
|
||||
};
|
||||
|
||||
static struct property_entry bxt_i2c_properties[] = {
|
||||
static const struct property_entry bxt_i2c_properties[] = {
|
||||
PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 42),
|
||||
PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171),
|
||||
PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 208),
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct intel_lpss_platform_info bxt_i2c_info = {
|
||||
.clk_rate = 133000000,
|
||||
static const struct software_node bxt_i2c_node = {
|
||||
.properties = bxt_i2c_properties,
|
||||
};
|
||||
|
||||
static struct property_entry apl_i2c_properties[] = {
|
||||
static const struct intel_lpss_platform_info bxt_i2c_info = {
|
||||
.clk_rate = 133000000,
|
||||
.swnode = &bxt_i2c_node,
|
||||
};
|
||||
|
||||
static const struct property_entry apl_i2c_properties[] = {
|
||||
PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 207),
|
||||
PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171),
|
||||
PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 208),
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct software_node apl_i2c_node = {
|
||||
.properties = apl_i2c_properties,
|
||||
};
|
||||
|
||||
static const struct intel_lpss_platform_info apl_i2c_info = {
|
||||
.clk_rate = 133000000,
|
||||
.properties = apl_i2c_properties,
|
||||
.swnode = &apl_i2c_node,
|
||||
};
|
||||
|
||||
static const struct acpi_device_id intel_lpss_acpi_ids[] = {
|
||||
|
@ -65,27 +65,35 @@ static const struct intel_lpss_platform_info spt_info = {
|
||||
.clk_rate = 120000000,
|
||||
};
|
||||
|
||||
static struct property_entry spt_i2c_properties[] = {
|
||||
static const struct property_entry spt_i2c_properties[] = {
|
||||
PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 230),
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct intel_lpss_platform_info spt_i2c_info = {
|
||||
.clk_rate = 120000000,
|
||||
static const struct software_node spt_i2c_node = {
|
||||
.properties = spt_i2c_properties,
|
||||
};
|
||||
|
||||
static struct property_entry uart_properties[] = {
|
||||
static const struct intel_lpss_platform_info spt_i2c_info = {
|
||||
.clk_rate = 120000000,
|
||||
.swnode = &spt_i2c_node,
|
||||
};
|
||||
|
||||
static const struct property_entry uart_properties[] = {
|
||||
PROPERTY_ENTRY_U32("reg-io-width", 4),
|
||||
PROPERTY_ENTRY_U32("reg-shift", 2),
|
||||
PROPERTY_ENTRY_BOOL("snps,uart-16550-compatible"),
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct software_node uart_node = {
|
||||
.properties = uart_properties,
|
||||
};
|
||||
|
||||
static const struct intel_lpss_platform_info spt_uart_info = {
|
||||
.clk_rate = 120000000,
|
||||
.clk_con_id = "baudclk",
|
||||
.properties = uart_properties,
|
||||
.swnode = &uart_node,
|
||||
};
|
||||
|
||||
static const struct intel_lpss_platform_info bxt_info = {
|
||||
@ -95,53 +103,65 @@ static const struct intel_lpss_platform_info bxt_info = {
|
||||
static const struct intel_lpss_platform_info bxt_uart_info = {
|
||||
.clk_rate = 100000000,
|
||||
.clk_con_id = "baudclk",
|
||||
.properties = uart_properties,
|
||||
.swnode = &uart_node,
|
||||
};
|
||||
|
||||
static struct property_entry bxt_i2c_properties[] = {
|
||||
static const struct property_entry bxt_i2c_properties[] = {
|
||||
PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 42),
|
||||
PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171),
|
||||
PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 208),
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct intel_lpss_platform_info bxt_i2c_info = {
|
||||
.clk_rate = 133000000,
|
||||
static const struct software_node bxt_i2c_node = {
|
||||
.properties = bxt_i2c_properties,
|
||||
};
|
||||
|
||||
static struct property_entry apl_i2c_properties[] = {
|
||||
static const struct intel_lpss_platform_info bxt_i2c_info = {
|
||||
.clk_rate = 133000000,
|
||||
.swnode = &bxt_i2c_node,
|
||||
};
|
||||
|
||||
static const struct property_entry apl_i2c_properties[] = {
|
||||
PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 207),
|
||||
PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171),
|
||||
PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 208),
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct intel_lpss_platform_info apl_i2c_info = {
|
||||
.clk_rate = 133000000,
|
||||
static const struct software_node apl_i2c_node = {
|
||||
.properties = apl_i2c_properties,
|
||||
};
|
||||
|
||||
static struct property_entry glk_i2c_properties[] = {
|
||||
static const struct intel_lpss_platform_info apl_i2c_info = {
|
||||
.clk_rate = 133000000,
|
||||
.swnode = &apl_i2c_node,
|
||||
};
|
||||
|
||||
static const struct property_entry glk_i2c_properties[] = {
|
||||
PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 313),
|
||||
PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171),
|
||||
PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 290),
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct software_node glk_i2c_node = {
|
||||
.properties = glk_i2c_properties,
|
||||
};
|
||||
|
||||
static const struct intel_lpss_platform_info glk_i2c_info = {
|
||||
.clk_rate = 133000000,
|
||||
.properties = glk_i2c_properties,
|
||||
.swnode = &glk_i2c_node,
|
||||
};
|
||||
|
||||
static const struct intel_lpss_platform_info cnl_i2c_info = {
|
||||
.clk_rate = 216000000,
|
||||
.properties = spt_i2c_properties,
|
||||
.swnode = &spt_i2c_node,
|
||||
};
|
||||
|
||||
static const struct intel_lpss_platform_info ehl_i2c_info = {
|
||||
.clk_rate = 100000000,
|
||||
.properties = bxt_i2c_properties,
|
||||
.swnode = &bxt_i2c_node,
|
||||
};
|
||||
|
||||
static const struct pci_device_id intel_lpss_pci_ids[] = {
|
||||
|
@ -399,7 +399,7 @@ int intel_lpss_probe(struct device *dev,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
lpss->cell->properties = info->properties;
|
||||
lpss->cell->swnode = info->swnode;
|
||||
|
||||
intel_lpss_init_dev(lpss);
|
||||
|
||||
|
@ -15,14 +15,14 @@
|
||||
|
||||
struct device;
|
||||
struct resource;
|
||||
struct property_entry;
|
||||
struct software_node;
|
||||
|
||||
struct intel_lpss_platform_info {
|
||||
struct resource *mem;
|
||||
int irq;
|
||||
unsigned long clk_rate;
|
||||
const char *clk_con_id;
|
||||
struct property_entry *properties;
|
||||
const struct software_node *swnode;
|
||||
};
|
||||
|
||||
int intel_lpss_probe(struct device *dev,
|
||||
|
@ -28,10 +28,23 @@ static struct mfd_cell m10bmc_pacn3000_subdevs[] = {
|
||||
{ .name = "n3000bmc-secure" },
|
||||
};
|
||||
|
||||
static const struct regmap_range m10bmc_regmap_range[] = {
|
||||
regmap_reg_range(M10BMC_LEGACY_BUILD_VER, M10BMC_LEGACY_BUILD_VER),
|
||||
regmap_reg_range(M10BMC_SYS_BASE, M10BMC_SYS_END),
|
||||
regmap_reg_range(M10BMC_FLASH_BASE, M10BMC_FLASH_END),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table m10bmc_access_table = {
|
||||
.yes_ranges = m10bmc_regmap_range,
|
||||
.n_yes_ranges = ARRAY_SIZE(m10bmc_regmap_range),
|
||||
};
|
||||
|
||||
static struct regmap_config intel_m10bmc_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.wr_table = &m10bmc_access_table,
|
||||
.rd_table = &m10bmc_access_table,
|
||||
.max_register = M10BMC_MEM_END,
|
||||
};
|
||||
|
||||
@ -121,17 +134,14 @@ static int check_m10bmc_version(struct intel_m10bmc *ddata)
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* This check is to filter out the very old legacy BMC versions,
|
||||
* M10BMC_LEGACY_SYS_BASE is the offset to this old block of mmio
|
||||
* registers. In the old BMC chips, the BMC version info is stored
|
||||
* in this old version register (M10BMC_LEGACY_SYS_BASE +
|
||||
* M10BMC_BUILD_VER), so its read out value would have not been
|
||||
* LEGACY_INVALID (0xffffffff). But in new BMC chips that the
|
||||
* driver supports, the value of this register should be
|
||||
* LEGACY_INVALID.
|
||||
* This check is to filter out the very old legacy BMC versions. In the
|
||||
* old BMC chips, the BMC version info is stored in the old version
|
||||
* register (M10BMC_LEGACY_BUILD_VER), so its read out value would have
|
||||
* not been M10BMC_VER_LEGACY_INVALID (0xffffffff). But in new BMC
|
||||
* chips that the driver supports, the value of this register should be
|
||||
* M10BMC_VER_LEGACY_INVALID.
|
||||
*/
|
||||
ret = m10bmc_raw_read(ddata,
|
||||
M10BMC_LEGACY_SYS_BASE + M10BMC_BUILD_VER, &v);
|
||||
ret = m10bmc_raw_read(ddata, M10BMC_LEGACY_BUILD_VER, &v);
|
||||
if (ret)
|
||||
return -ENODEV;
|
||||
|
||||
|
@ -16,8 +16,9 @@
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/platform_data/gpio-dwapb.h>
|
||||
#include <linux/platform_data/i2c-designware.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
/* PCI BAR for register base address */
|
||||
#define MFD_I2C_BAR 0
|
||||
@ -45,29 +46,48 @@
|
||||
#define INTEL_QUARK_I2C_CLK_HZ 33000000
|
||||
|
||||
struct intel_quark_mfd {
|
||||
struct device *dev;
|
||||
struct clk *i2c_clk;
|
||||
struct clk_lookup *i2c_clk_lookup;
|
||||
};
|
||||
|
||||
static const struct property_entry intel_quark_i2c_controller_standard_properties[] = {
|
||||
PROPERTY_ENTRY_U32("clock-frequency", I2C_MAX_STANDARD_MODE_FREQ),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct software_node intel_quark_i2c_controller_standard_node = {
|
||||
.name = "intel-quark-i2c-controller",
|
||||
.properties = intel_quark_i2c_controller_standard_properties,
|
||||
};
|
||||
|
||||
static const struct property_entry intel_quark_i2c_controller_fast_properties[] = {
|
||||
PROPERTY_ENTRY_U32("clock-frequency", I2C_MAX_FAST_MODE_FREQ),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct software_node intel_quark_i2c_controller_fast_node = {
|
||||
.name = "intel-quark-i2c-controller",
|
||||
.properties = intel_quark_i2c_controller_fast_properties,
|
||||
};
|
||||
|
||||
static const struct dmi_system_id dmi_platform_info[] = {
|
||||
{
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "Galileo"),
|
||||
},
|
||||
.driver_data = (void *)100000,
|
||||
.driver_data = (void *)&intel_quark_i2c_controller_standard_node,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "GalileoGen2"),
|
||||
},
|
||||
.driver_data = (void *)400000,
|
||||
.driver_data = (void *)&intel_quark_i2c_controller_fast_node,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"),
|
||||
},
|
||||
.driver_data = (void *)400000,
|
||||
.driver_data = (void *)&intel_quark_i2c_controller_fast_node,
|
||||
},
|
||||
{}
|
||||
};
|
||||
@ -98,15 +118,7 @@ static struct mfd_cell_acpi_match intel_quark_acpi_match_gpio = {
|
||||
};
|
||||
|
||||
static struct mfd_cell intel_quark_mfd_cells[] = {
|
||||
{
|
||||
.id = MFD_GPIO_BAR,
|
||||
.name = "gpio-dwapb",
|
||||
.acpi_match = &intel_quark_acpi_match_gpio,
|
||||
.num_resources = ARRAY_SIZE(intel_quark_gpio_res),
|
||||
.resources = intel_quark_gpio_res,
|
||||
.ignore_resource_conflicts = true,
|
||||
},
|
||||
{
|
||||
[MFD_I2C_BAR] = {
|
||||
.id = MFD_I2C_BAR,
|
||||
.name = "i2c_designware",
|
||||
.acpi_match = &intel_quark_acpi_match_i2c,
|
||||
@ -114,6 +126,14 @@ static struct mfd_cell intel_quark_mfd_cells[] = {
|
||||
.resources = intel_quark_i2c_res,
|
||||
.ignore_resource_conflicts = true,
|
||||
},
|
||||
[MFD_GPIO_BAR] = {
|
||||
.id = MFD_GPIO_BAR,
|
||||
.name = "gpio-dwapb",
|
||||
.acpi_match = &intel_quark_acpi_match_gpio,
|
||||
.num_resources = ARRAY_SIZE(intel_quark_gpio_res),
|
||||
.resources = intel_quark_gpio_res,
|
||||
.ignore_resource_conflicts = true,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct pci_device_id intel_quark_mfd_ids[] = {
|
||||
@ -157,48 +177,37 @@ static void intel_quark_unregister_i2c_clk(struct device *dev)
|
||||
clk_unregister(quark_mfd->i2c_clk);
|
||||
}
|
||||
|
||||
static int intel_quark_i2c_setup(struct pci_dev *pdev, struct mfd_cell *cell)
|
||||
static int intel_quark_i2c_setup(struct pci_dev *pdev)
|
||||
{
|
||||
struct mfd_cell *cell = &intel_quark_mfd_cells[MFD_I2C_BAR];
|
||||
struct resource *res = intel_quark_i2c_res;
|
||||
const struct dmi_system_id *dmi_id;
|
||||
struct dw_i2c_platform_data *pdata;
|
||||
struct resource *res = (struct resource *)cell->resources;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
res[INTEL_QUARK_IORES_MEM].start =
|
||||
pci_resource_start(pdev, MFD_I2C_BAR);
|
||||
res[INTEL_QUARK_IORES_MEM].end =
|
||||
pci_resource_end(pdev, MFD_I2C_BAR);
|
||||
res[INTEL_QUARK_IORES_MEM].start = pci_resource_start(pdev, MFD_I2C_BAR);
|
||||
res[INTEL_QUARK_IORES_MEM].end = pci_resource_end(pdev, MFD_I2C_BAR);
|
||||
|
||||
res[INTEL_QUARK_IORES_IRQ].start = pdev->irq;
|
||||
res[INTEL_QUARK_IORES_IRQ].end = pdev->irq;
|
||||
|
||||
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
res[INTEL_QUARK_IORES_IRQ].start = pci_irq_vector(pdev, 0);
|
||||
res[INTEL_QUARK_IORES_IRQ].end = pci_irq_vector(pdev, 0);
|
||||
|
||||
/* Normal mode by default */
|
||||
pdata->i2c_scl_freq = 100000;
|
||||
cell->swnode = &intel_quark_i2c_controller_standard_node;
|
||||
|
||||
dmi_id = dmi_first_match(dmi_platform_info);
|
||||
if (dmi_id)
|
||||
pdata->i2c_scl_freq = (uintptr_t)dmi_id->driver_data;
|
||||
|
||||
cell->platform_data = pdata;
|
||||
cell->pdata_size = sizeof(*pdata);
|
||||
cell->swnode = (struct software_node *)dmi_id->driver_data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intel_quark_gpio_setup(struct pci_dev *pdev, struct mfd_cell *cell)
|
||||
static int intel_quark_gpio_setup(struct pci_dev *pdev)
|
||||
{
|
||||
struct mfd_cell *cell = &intel_quark_mfd_cells[MFD_GPIO_BAR];
|
||||
struct resource *res = intel_quark_gpio_res;
|
||||
struct dwapb_platform_data *pdata;
|
||||
struct resource *res = (struct resource *)cell->resources;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
res[INTEL_QUARK_IORES_MEM].start =
|
||||
pci_resource_start(pdev, MFD_GPIO_BAR);
|
||||
res[INTEL_QUARK_IORES_MEM].end =
|
||||
pci_resource_end(pdev, MFD_GPIO_BAR);
|
||||
res[INTEL_QUARK_IORES_MEM].start = pci_resource_start(pdev, MFD_GPIO_BAR);
|
||||
res[INTEL_QUARK_IORES_MEM].end = pci_resource_end(pdev, MFD_GPIO_BAR);
|
||||
|
||||
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
@ -217,7 +226,7 @@ static int intel_quark_gpio_setup(struct pci_dev *pdev, struct mfd_cell *cell)
|
||||
pdata->properties->idx = 0;
|
||||
pdata->properties->ngpio = INTEL_QUARK_MFD_NGPIO;
|
||||
pdata->properties->gpio_base = INTEL_QUARK_MFD_GPIO_BASE;
|
||||
pdata->properties->irq[0] = pdev->irq;
|
||||
pdata->properties->irq[0] = pci_irq_vector(pdev, 0);
|
||||
pdata->properties->irq_shared = true;
|
||||
|
||||
cell->platform_data = pdata;
|
||||
@ -240,29 +249,37 @@ static int intel_quark_mfd_probe(struct pci_dev *pdev,
|
||||
if (!quark_mfd)
|
||||
return -ENOMEM;
|
||||
|
||||
quark_mfd->dev = &pdev->dev;
|
||||
dev_set_drvdata(&pdev->dev, quark_mfd);
|
||||
|
||||
ret = intel_quark_register_i2c_clk(&pdev->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = intel_quark_i2c_setup(pdev, &intel_quark_mfd_cells[1]);
|
||||
if (ret)
|
||||
pci_set_master(pdev);
|
||||
|
||||
/* This driver only requires 1 IRQ vector */
|
||||
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
|
||||
if (ret < 0)
|
||||
goto err_unregister_i2c_clk;
|
||||
|
||||
ret = intel_quark_gpio_setup(pdev, &intel_quark_mfd_cells[0]);
|
||||
ret = intel_quark_i2c_setup(pdev);
|
||||
if (ret)
|
||||
goto err_unregister_i2c_clk;
|
||||
goto err_free_irq_vectors;
|
||||
|
||||
ret = intel_quark_gpio_setup(pdev);
|
||||
if (ret)
|
||||
goto err_free_irq_vectors;
|
||||
|
||||
ret = mfd_add_devices(&pdev->dev, 0, intel_quark_mfd_cells,
|
||||
ARRAY_SIZE(intel_quark_mfd_cells), NULL, 0,
|
||||
NULL);
|
||||
if (ret)
|
||||
goto err_unregister_i2c_clk;
|
||||
goto err_free_irq_vectors;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_irq_vectors:
|
||||
pci_free_irq_vectors(pdev);
|
||||
err_unregister_i2c_clk:
|
||||
intel_quark_unregister_i2c_clk(&pdev->dev);
|
||||
return ret;
|
||||
@ -270,8 +287,9 @@ err_unregister_i2c_clk:
|
||||
|
||||
static void intel_quark_mfd_remove(struct pci_dev *pdev)
|
||||
{
|
||||
intel_quark_unregister_i2c_clk(&pdev->dev);
|
||||
mfd_remove_devices(&pdev->dev);
|
||||
pci_free_irq_vectors(pdev);
|
||||
intel_quark_unregister_i2c_clk(&pdev->dev);
|
||||
}
|
||||
|
||||
static struct pci_driver intel_quark_mfd_driver = {
|
||||
|
@ -358,7 +358,7 @@ static struct attribute *lm3533_attributes[] = {
|
||||
static umode_t lm3533_attr_is_visible(struct kobject *kobj,
|
||||
struct attribute *attr, int n)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct lm3533 *lm3533 = dev_get_drvdata(dev);
|
||||
struct device_attribute *dattr = to_dev_attr(attr);
|
||||
struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(dattr);
|
||||
|
@ -26,9 +26,6 @@
|
||||
#define GPIO_IO_SIZE 64
|
||||
#define GPIO_IO_SIZE_CENTERTON 128
|
||||
|
||||
/* Intel Quark X1000 GPIO IRQ Number */
|
||||
#define GPIO_IRQ_QUARK_X1000 9
|
||||
|
||||
#define WDTBASE 0x84
|
||||
#define WDT_IO_SIZE 64
|
||||
|
||||
@ -43,30 +40,25 @@ struct lpc_sch_info {
|
||||
unsigned int io_size_smbus;
|
||||
unsigned int io_size_gpio;
|
||||
unsigned int io_size_wdt;
|
||||
int irq_gpio;
|
||||
};
|
||||
|
||||
static struct lpc_sch_info sch_chipset_info[] = {
|
||||
[LPC_SCH] = {
|
||||
.io_size_smbus = SMBUS_IO_SIZE,
|
||||
.io_size_gpio = GPIO_IO_SIZE,
|
||||
.irq_gpio = -1,
|
||||
},
|
||||
[LPC_ITC] = {
|
||||
.io_size_smbus = SMBUS_IO_SIZE,
|
||||
.io_size_gpio = GPIO_IO_SIZE,
|
||||
.io_size_wdt = WDT_IO_SIZE,
|
||||
.irq_gpio = -1,
|
||||
},
|
||||
[LPC_CENTERTON] = {
|
||||
.io_size_smbus = SMBUS_IO_SIZE,
|
||||
.io_size_gpio = GPIO_IO_SIZE_CENTERTON,
|
||||
.io_size_wdt = WDT_IO_SIZE,
|
||||
.irq_gpio = -1,
|
||||
},
|
||||
[LPC_QUARK_X1000] = {
|
||||
.io_size_gpio = GPIO_IO_SIZE,
|
||||
.irq_gpio = GPIO_IRQ_QUARK_X1000,
|
||||
.io_size_wdt = WDT_IO_SIZE,
|
||||
},
|
||||
};
|
||||
@ -113,13 +105,13 @@ static int lpc_sch_get_io(struct pci_dev *pdev, int where, const char *name,
|
||||
}
|
||||
|
||||
static int lpc_sch_populate_cell(struct pci_dev *pdev, int where,
|
||||
const char *name, int size, int irq,
|
||||
int id, struct mfd_cell *cell)
|
||||
const char *name, int size, int id,
|
||||
struct mfd_cell *cell)
|
||||
{
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
res = devm_kcalloc(&pdev->dev, 2, sizeof(*res), GFP_KERNEL);
|
||||
res = devm_kzalloc(&pdev->dev, sizeof(*res), GFP_KERNEL);
|
||||
if (!res)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -135,18 +127,6 @@ static int lpc_sch_populate_cell(struct pci_dev *pdev, int where,
|
||||
cell->ignore_resource_conflicts = true;
|
||||
cell->id = id;
|
||||
|
||||
/* Check if we need to add an IRQ resource */
|
||||
if (irq < 0)
|
||||
return 0;
|
||||
|
||||
res++;
|
||||
|
||||
res->start = irq;
|
||||
res->end = irq;
|
||||
res->flags = IORESOURCE_IRQ;
|
||||
|
||||
cell->num_resources++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -158,7 +138,7 @@ static int lpc_sch_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
int ret;
|
||||
|
||||
ret = lpc_sch_populate_cell(dev, SMBASE, "isch_smbus",
|
||||
info->io_size_smbus, -1,
|
||||
info->io_size_smbus,
|
||||
id->device, &lpc_sch_cells[cells]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -166,7 +146,7 @@ static int lpc_sch_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
cells++;
|
||||
|
||||
ret = lpc_sch_populate_cell(dev, GPIOBASE, "sch_gpio",
|
||||
info->io_size_gpio, info->irq_gpio,
|
||||
info->io_size_gpio,
|
||||
id->device, &lpc_sch_cells[cells]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -174,7 +154,7 @@ static int lpc_sch_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
cells++;
|
||||
|
||||
ret = lpc_sch_populate_cell(dev, WDTBASE, "ie6xx_wdt",
|
||||
info->io_size_wdt, -1,
|
||||
info->io_size_wdt,
|
||||
id->device, &lpc_sch_cells[cells]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -29,9 +29,9 @@
|
||||
static const struct mfd_cell max8997_devs[] = {
|
||||
{ .name = "max8997-pmic", },
|
||||
{ .name = "max8997-rtc", },
|
||||
{ .name = "max8997-battery", .of_compatible = "maxim,max8997-battery", },
|
||||
{ .name = "max8997-battery", },
|
||||
{ .name = "max8997-haptic", },
|
||||
{ .name = "max8997-muic", .of_compatible = "maxim,max8997-muic", },
|
||||
{ .name = "max8997-muic", },
|
||||
{ .name = "max8997-led", .id = 1 },
|
||||
{ .name = "max8997-led", .id = 2 },
|
||||
};
|
||||
|
@ -65,7 +65,7 @@ static void mfd_acpi_add_device(const struct mfd_cell *cell,
|
||||
{
|
||||
const struct mfd_cell_acpi_match *match = cell->acpi_match;
|
||||
struct acpi_device *parent, *child;
|
||||
struct acpi_device *adev;
|
||||
struct acpi_device *adev = NULL;
|
||||
|
||||
parent = ACPI_COMPANION(pdev->dev.parent);
|
||||
if (!parent)
|
||||
@ -77,10 +77,9 @@ static void mfd_acpi_add_device(const struct mfd_cell *cell,
|
||||
* _ADR or it will use the parent handle if is no ID is given.
|
||||
*
|
||||
* Note that use of _ADR is a grey area in the ACPI specification,
|
||||
* though Intel Galileo Gen2 is using it to distinguish the children
|
||||
* devices.
|
||||
* though at least Intel Galileo Gen 2 is using it to distinguish
|
||||
* the children devices.
|
||||
*/
|
||||
adev = parent;
|
||||
if (match) {
|
||||
if (match->pnpid) {
|
||||
struct acpi_device_id ids[2] = {};
|
||||
@ -93,22 +92,11 @@ static void mfd_acpi_add_device(const struct mfd_cell *cell,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unsigned long long adr;
|
||||
acpi_status status;
|
||||
|
||||
list_for_each_entry(child, &parent->children, node) {
|
||||
status = acpi_evaluate_integer(child->handle,
|
||||
"_ADR", NULL,
|
||||
&adr);
|
||||
if (ACPI_SUCCESS(status) && match->adr == adr) {
|
||||
adev = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
adev = acpi_find_child_device(parent, match->adr, false);
|
||||
}
|
||||
}
|
||||
|
||||
ACPI_COMPANION_SET(&pdev->dev, adev);
|
||||
ACPI_COMPANION_SET(&pdev->dev, adev ?: parent);
|
||||
}
|
||||
#else
|
||||
static inline void mfd_acpi_add_device(const struct mfd_cell *cell,
|
||||
@ -238,8 +226,8 @@ static int mfd_add_device(struct device *parent, int id,
|
||||
goto fail_of_entry;
|
||||
}
|
||||
|
||||
if (cell->properties) {
|
||||
ret = platform_device_add_properties(pdev, cell->properties);
|
||||
if (cell->swnode) {
|
||||
ret = device_add_software_node(&pdev->dev, cell->swnode);
|
||||
if (ret)
|
||||
goto fail_of_entry;
|
||||
}
|
||||
@ -304,6 +292,7 @@ fail_of_entry:
|
||||
list_del(&of_entry->list);
|
||||
kfree(of_entry);
|
||||
}
|
||||
device_remove_software_node(&pdev->dev);
|
||||
fail_alias:
|
||||
regulator_bulk_unregister_supply_alias(&pdev->dev,
|
||||
cell->parent_supplies,
|
||||
@ -372,6 +361,8 @@ static int mfd_remove_devices_fn(struct device *dev, void *data)
|
||||
regulator_bulk_unregister_supply_alias(dev, cell->parent_supplies,
|
||||
cell->num_parent_supplies);
|
||||
|
||||
device_remove_software_node(&pdev->dev);
|
||||
|
||||
platform_device_unregister(pdev);
|
||||
return 0;
|
||||
}
|
||||
|
271
drivers/mfd/ntxec.c
Normal file
271
drivers/mfd/ntxec.c
Normal file
@ -0,0 +1,271 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* The Netronix embedded controller is a microcontroller found in some
|
||||
* e-book readers designed by the original design manufacturer Netronix, Inc.
|
||||
* It contains RTC, battery monitoring, system power management, and PWM
|
||||
* functionality.
|
||||
*
|
||||
* This driver implements register access, version detection, and system
|
||||
* power-off/reset.
|
||||
*
|
||||
* Copyright 2020 Jonathan Neuschäfer <j.neuschaefer@gmx.net>
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/ntxec.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/types.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#define NTXEC_REG_VERSION 0x00
|
||||
#define NTXEC_REG_POWEROFF 0x50
|
||||
#define NTXEC_REG_POWERKEEP 0x70
|
||||
#define NTXEC_REG_RESET 0x90
|
||||
|
||||
#define NTXEC_POWEROFF_VALUE 0x0100
|
||||
#define NTXEC_POWERKEEP_VALUE 0x0800
|
||||
#define NTXEC_RESET_VALUE 0xff00
|
||||
|
||||
static struct i2c_client *poweroff_restart_client;
|
||||
|
||||
static void ntxec_poweroff(void)
|
||||
{
|
||||
int res;
|
||||
u8 buf[3] = { NTXEC_REG_POWEROFF };
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = poweroff_restart_client->addr,
|
||||
.flags = 0,
|
||||
.len = sizeof(buf),
|
||||
.buf = buf,
|
||||
},
|
||||
};
|
||||
|
||||
put_unaligned_be16(NTXEC_POWEROFF_VALUE, buf + 1);
|
||||
|
||||
res = i2c_transfer(poweroff_restart_client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||
if (res < 0)
|
||||
dev_warn(&poweroff_restart_client->dev,
|
||||
"Failed to power off (err = %d)\n", res);
|
||||
|
||||
/*
|
||||
* The time from the register write until the host CPU is powered off
|
||||
* has been observed to be about 2.5 to 3 seconds. Sleep long enough to
|
||||
* safely avoid returning from the poweroff handler.
|
||||
*/
|
||||
msleep(5000);
|
||||
}
|
||||
|
||||
static int ntxec_restart(struct notifier_block *nb,
|
||||
unsigned long action, void *data)
|
||||
{
|
||||
int res;
|
||||
u8 buf[3] = { NTXEC_REG_RESET };
|
||||
/*
|
||||
* NOTE: The lower half of the reset value is not sent, because sending
|
||||
* it causes an I2C error. (The reset handler in the downstream driver
|
||||
* does send the full two-byte value, but doesn't check the result).
|
||||
*/
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = poweroff_restart_client->addr,
|
||||
.flags = 0,
|
||||
.len = sizeof(buf) - 1,
|
||||
.buf = buf,
|
||||
},
|
||||
};
|
||||
|
||||
put_unaligned_be16(NTXEC_RESET_VALUE, buf + 1);
|
||||
|
||||
res = i2c_transfer(poweroff_restart_client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||
if (res < 0)
|
||||
dev_warn(&poweroff_restart_client->dev,
|
||||
"Failed to restart (err = %d)\n", res);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static struct notifier_block ntxec_restart_handler = {
|
||||
.notifier_call = ntxec_restart,
|
||||
.priority = 128,
|
||||
};
|
||||
|
||||
static int regmap_ignore_write(void *context,
|
||||
unsigned int reg, unsigned int val)
|
||||
|
||||
{
|
||||
struct regmap *regmap = context;
|
||||
|
||||
regmap_write(regmap, reg, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int regmap_wrap_read(void *context, unsigned int reg,
|
||||
unsigned int *val)
|
||||
{
|
||||
struct regmap *regmap = context;
|
||||
|
||||
return regmap_read(regmap, reg, val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Some firmware versions do not ack written data, add a wrapper. It
|
||||
* is used to stack another regmap on top.
|
||||
*/
|
||||
static const struct regmap_config regmap_config_noack = {
|
||||
.name = "ntxec_noack",
|
||||
.reg_bits = 8,
|
||||
.val_bits = 16,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
.reg_write = regmap_ignore_write,
|
||||
.reg_read = regmap_wrap_read
|
||||
};
|
||||
|
||||
static const struct regmap_config regmap_config = {
|
||||
.name = "ntxec",
|
||||
.reg_bits = 8,
|
||||
.val_bits = 16,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
.val_format_endian = REGMAP_ENDIAN_BIG,
|
||||
};
|
||||
|
||||
static const struct mfd_cell ntxec_subdev[] = {
|
||||
{ .name = "ntxec-rtc" },
|
||||
{ .name = "ntxec-pwm" },
|
||||
};
|
||||
|
||||
static const struct mfd_cell ntxec_subdev_pwm[] = {
|
||||
{ .name = "ntxec-pwm" },
|
||||
};
|
||||
|
||||
static int ntxec_probe(struct i2c_client *client)
|
||||
{
|
||||
struct ntxec *ec;
|
||||
unsigned int version;
|
||||
int res;
|
||||
const struct mfd_cell *subdevs;
|
||||
size_t n_subdevs;
|
||||
|
||||
ec = devm_kmalloc(&client->dev, sizeof(*ec), GFP_KERNEL);
|
||||
if (!ec)
|
||||
return -ENOMEM;
|
||||
|
||||
ec->dev = &client->dev;
|
||||
|
||||
ec->regmap = devm_regmap_init_i2c(client, ®map_config);
|
||||
if (IS_ERR(ec->regmap)) {
|
||||
dev_err(ec->dev, "Failed to set up regmap for device\n");
|
||||
return PTR_ERR(ec->regmap);
|
||||
}
|
||||
|
||||
/* Determine the firmware version */
|
||||
res = regmap_read(ec->regmap, NTXEC_REG_VERSION, &version);
|
||||
if (res < 0) {
|
||||
dev_err(ec->dev, "Failed to read firmware version number\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Bail out if we encounter an unknown firmware version */
|
||||
switch (version) {
|
||||
case NTXEC_VERSION_KOBO_AURA:
|
||||
subdevs = ntxec_subdev;
|
||||
n_subdevs = ARRAY_SIZE(ntxec_subdev);
|
||||
break;
|
||||
case NTXEC_VERSION_TOLINO_SHINE2:
|
||||
subdevs = ntxec_subdev_pwm;
|
||||
n_subdevs = ARRAY_SIZE(ntxec_subdev_pwm);
|
||||
/* Another regmap stacked on top of the other */
|
||||
ec->regmap = devm_regmap_init(ec->dev, NULL,
|
||||
ec->regmap,
|
||||
®map_config_noack);
|
||||
if (IS_ERR(ec->regmap))
|
||||
return PTR_ERR(ec->regmap);
|
||||
break;
|
||||
default:
|
||||
dev_err(ec->dev,
|
||||
"Netronix embedded controller version %04x is not supported.\n",
|
||||
version);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev_info(ec->dev,
|
||||
"Netronix embedded controller version %04x detected.\n", version);
|
||||
|
||||
if (of_device_is_system_power_controller(ec->dev->of_node)) {
|
||||
/*
|
||||
* Set the 'powerkeep' bit. This is necessary on some boards
|
||||
* in order to keep the system running.
|
||||
*/
|
||||
res = regmap_write(ec->regmap, NTXEC_REG_POWERKEEP,
|
||||
NTXEC_POWERKEEP_VALUE);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
if (poweroff_restart_client)
|
||||
/*
|
||||
* Another instance of the driver already took
|
||||
* poweroff/restart duties.
|
||||
*/
|
||||
dev_err(ec->dev, "poweroff_restart_client already assigned\n");
|
||||
else
|
||||
poweroff_restart_client = client;
|
||||
|
||||
if (pm_power_off)
|
||||
/* Another driver already registered a poweroff handler. */
|
||||
dev_err(ec->dev, "pm_power_off already assigned\n");
|
||||
else
|
||||
pm_power_off = ntxec_poweroff;
|
||||
|
||||
res = register_restart_handler(&ntxec_restart_handler);
|
||||
if (res)
|
||||
dev_err(ec->dev,
|
||||
"Failed to register restart handler: %d\n", res);
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, ec);
|
||||
|
||||
res = devm_mfd_add_devices(ec->dev, PLATFORM_DEVID_NONE,
|
||||
subdevs, n_subdevs, NULL, 0, NULL);
|
||||
if (res)
|
||||
dev_err(ec->dev, "Failed to add subdevices: %d\n", res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int ntxec_remove(struct i2c_client *client)
|
||||
{
|
||||
if (client == poweroff_restart_client) {
|
||||
poweroff_restart_client = NULL;
|
||||
pm_power_off = NULL;
|
||||
unregister_restart_handler(&ntxec_restart_handler);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id of_ntxec_match_table[] = {
|
||||
{ .compatible = "netronix,ntxec", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_ntxec_match_table);
|
||||
|
||||
static struct i2c_driver ntxec_driver = {
|
||||
.driver = {
|
||||
.name = "ntxec",
|
||||
.of_match_table = of_ntxec_match_table,
|
||||
},
|
||||
.probe_new = ntxec_probe,
|
||||
.remove = ntxec_remove,
|
||||
};
|
||||
module_i2c_driver(ntxec_driver);
|
||||
|
||||
MODULE_AUTHOR("Jonathan Neuschäfer <j.neuschaefer@gmx.net>");
|
||||
MODULE_DESCRIPTION("Core driver for Netronix EC");
|
||||
MODULE_LICENSE("GPL");
|
@ -45,8 +45,11 @@ static bool rn5t618_volatile_reg(struct device *dev, unsigned int reg)
|
||||
case RN5T618_INTMON:
|
||||
case RN5T618_RTC_CTRL1 ... RN5T618_RTC_CTRL2:
|
||||
case RN5T618_RTC_SECONDS ... RN5T618_RTC_YEAR:
|
||||
case RN5T618_CHGCTL1:
|
||||
case RN5T618_REGISET1 ... RN5T618_REGISET2:
|
||||
case RN5T618_CHGSTATE:
|
||||
case RN5T618_CHGCTRL_IRR ... RN5T618_CHGERR_MONI:
|
||||
case RN5T618_GCHGDET:
|
||||
case RN5T618_CONTROL ... RN5T618_CC_AVEREG0:
|
||||
return true;
|
||||
default:
|
||||
|
@ -2,7 +2,7 @@
|
||||
//
|
||||
// Copyright (C) 2019 ROHM Semiconductors
|
||||
//
|
||||
// ROHM BD71828 PMIC driver
|
||||
// ROHM BD71828/BD71815 PMIC driver
|
||||
|
||||
#include <linux/gpio_keys.h>
|
||||
#include <linux/i2c.h>
|
||||
@ -11,7 +11,9 @@
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/rohm-bd71815.h>
|
||||
#include <linux/mfd/rohm-bd71828.h>
|
||||
#include <linux/mfd/rohm-generic.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/regmap.h>
|
||||
@ -29,12 +31,84 @@ static struct gpio_keys_platform_data bd71828_powerkey_data = {
|
||||
.name = "bd71828-pwrkey",
|
||||
};
|
||||
|
||||
static const struct resource rtc_irqs[] = {
|
||||
static const struct resource bd71815_rtc_irqs[] = {
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC0, "bd71815-rtc-alm-0"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC1, "bd71815-rtc-alm-1"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC2, "bd71815-rtc-alm-2"),
|
||||
};
|
||||
|
||||
static const struct resource bd71828_rtc_irqs[] = {
|
||||
DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC0, "bd71828-rtc-alm-0"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC1, "bd71828-rtc-alm-1"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC2, "bd71828-rtc-alm-2"),
|
||||
};
|
||||
|
||||
static 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-clps-out"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_CLPS_IN, "bd71815-clps-in"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_OVP_RES, "bd71815-dcin-ovp-res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_OVP_DET, "bd71815-dcin-ovp-det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_MON_RES, "bd71815-dcin-mon-res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_MON_DET, "bd71815-dcin-mon-det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_UV_RES, "bd71815-vsys-uv-res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_UV_DET, "bd71815-vsys-uv-det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_LOW_RES, "bd71815-vsys-low-res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_LOW_DET, "bd71815-vsys-low-det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_MON_RES, "bd71815-vsys-mon-res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_MON_RES, "bd71815-vsys-mon-det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_WDG_TEMP, "bd71815-chg-wdg-temp"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_WDG_TIME, "bd71815-chg-wdg"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_RECHARGE_RES, "bd71815-rechg-res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_RECHARGE_DET, "bd71815-rechg-det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_RANGED_TEMP_TRANSITION, "bd71815-ranged-temp-transit"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_STATE_TRANSITION, "bd71815-chg-state-change"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_TEMP_NORMAL, "bd71815-bat-temp-normal"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_TEMP_ERANGE, "bd71815-bat-temp-erange"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_REMOVED, "bd71815-bat-rmv"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_DETECTED, "bd71815-bat-det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_THERM_REMOVED, "bd71815-therm-rmv"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_THERM_DETECTED, "bd71815-therm-det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_DEAD, "bd71815-bat-dead"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_SHORTC_RES, "bd71815-bat-short-res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_SHORTC_DET, "bd71815-bat-short-det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_LOW_VOLT_RES, "bd71815-bat-low-res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_LOW_VOLT_DET, "bd71815-bat-low-det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_VOLT_RES, "bd71815-bat-over-res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_VOLT_DET, "bd71815-bat-over-det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_MON_RES, "bd71815-bat-mon-res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_MON_DET, "bd71815-bat-mon-det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_CC_MON1, "bd71815-bat-cc-mon1"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_CC_MON2, "bd71815-bat-cc-mon2"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_CC_MON3, "bd71815-bat-cc-mon3"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_1_RES, "bd71815-bat-oc1-res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_1_DET, "bd71815-bat-oc1-det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_2_RES, "bd71815-bat-oc2-res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_2_DET, "bd71815-bat-oc2-det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_3_RES, "bd71815-bat-oc3-res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_3_DET, "bd71815-bat-oc3-det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_LOW_RES, "bd71815-bat-low-res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_LOW_DET, "bd71815-bat-low-det"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_HI_RES, "bd71815-bat-hi-res"),
|
||||
DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_HI_DET, "bd71815-bat-hi-det"),
|
||||
};
|
||||
|
||||
static struct mfd_cell bd71815_mfd_cells[] = {
|
||||
{ .name = "bd71815-pmic", },
|
||||
{ .name = "bd71815-clk", },
|
||||
{ .name = "bd71815-gpo", },
|
||||
{
|
||||
.name = "bd71815-power",
|
||||
.num_resources = ARRAY_SIZE(bd71815_power_irqs),
|
||||
.resources = &bd71815_power_irqs[0],
|
||||
},
|
||||
{
|
||||
.name = "bd71815-rtc",
|
||||
.num_resources = ARRAY_SIZE(bd71815_rtc_irqs),
|
||||
.resources = &bd71815_rtc_irqs[0],
|
||||
},
|
||||
};
|
||||
|
||||
static struct mfd_cell bd71828_mfd_cells[] = {
|
||||
{ .name = "bd71828-pmic", },
|
||||
{ .name = "bd71828-gpio", },
|
||||
@ -47,8 +121,8 @@ static struct mfd_cell bd71828_mfd_cells[] = {
|
||||
{ .name = "bd71827-power", },
|
||||
{
|
||||
.name = "bd71828-rtc",
|
||||
.resources = rtc_irqs,
|
||||
.num_resources = ARRAY_SIZE(rtc_irqs),
|
||||
.resources = bd71828_rtc_irqs,
|
||||
.num_resources = ARRAY_SIZE(bd71828_rtc_irqs),
|
||||
}, {
|
||||
.name = "gpio-keys",
|
||||
.platform_data = &bd71828_powerkey_data,
|
||||
@ -56,7 +130,35 @@ static struct mfd_cell bd71828_mfd_cells[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regmap_range volatile_ranges[] = {
|
||||
static const struct regmap_range bd71815_volatile_ranges[] = {
|
||||
{
|
||||
.range_min = BD71815_REG_SEC,
|
||||
.range_max = BD71815_REG_YEAR,
|
||||
}, {
|
||||
.range_min = BD71815_REG_CONF,
|
||||
.range_max = BD71815_REG_BAT_TEMP,
|
||||
}, {
|
||||
.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,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regmap_range bd71828_volatile_ranges[] = {
|
||||
{
|
||||
.range_min = BD71828_REG_PS_CTRL_1,
|
||||
.range_max = BD71828_REG_PS_CTRL_1,
|
||||
@ -80,15 +182,28 @@ static const struct regmap_range volatile_ranges[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regmap_access_table volatile_regs = {
|
||||
.yes_ranges = &volatile_ranges[0],
|
||||
.n_yes_ranges = ARRAY_SIZE(volatile_ranges),
|
||||
static const struct regmap_access_table bd71815_volatile_regs = {
|
||||
.yes_ranges = &bd71815_volatile_ranges[0],
|
||||
.n_yes_ranges = ARRAY_SIZE(bd71815_volatile_ranges),
|
||||
};
|
||||
|
||||
static struct regmap_config bd71828_regmap = {
|
||||
static const struct regmap_access_table bd71828_volatile_regs = {
|
||||
.yes_ranges = &bd71828_volatile_ranges[0],
|
||||
.n_yes_ranges = ARRAY_SIZE(bd71828_volatile_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_config bd71815_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.volatile_table = &volatile_regs,
|
||||
.volatile_table = &bd71815_volatile_regs,
|
||||
.max_register = BD71815_MAX_REGISTER - 1,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static const struct regmap_config bd71828_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.volatile_table = &bd71828_volatile_regs,
|
||||
.max_register = BD71828_MAX_REGISTER,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
@ -96,7 +211,7 @@ static struct regmap_config bd71828_regmap = {
|
||||
/*
|
||||
* 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.
|
||||
* register. BD71815 and BD71828 have same sub-register-block offests.
|
||||
*/
|
||||
|
||||
static unsigned int bit0_offsets[] = {11}; /* RTC IRQ */
|
||||
@ -108,7 +223,7 @@ 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 struct regmap_irq_sub_irq_map bd71828_sub_irq_offsets[] = {
|
||||
static struct regmap_irq_sub_irq_map bd718xx_sub_irq_offsets[] = {
|
||||
REGMAP_IRQ_MAIN_REG_OFFSET(bit0_offsets),
|
||||
REGMAP_IRQ_MAIN_REG_OFFSET(bit1_offsets),
|
||||
REGMAP_IRQ_MAIN_REG_OFFSET(bit2_offsets),
|
||||
@ -119,6 +234,88 @@ static struct regmap_irq_sub_irq_map bd71828_sub_irq_offsets[] = {
|
||||
REGMAP_IRQ_MAIN_REG_OFFSET(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),
|
||||
REGMAP_IRQ_REG(BD71815_INT_BUCK3_OCP, 0, BD71815_INT_BUCK3_OCP_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_BUCK4_OCP, 0, BD71815_INT_BUCK4_OCP_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_BUCK5_OCP, 0, BD71815_INT_BUCK5_OCP_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_LED_OVP, 0, BD71815_INT_LED_OVP_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_LED_OCP, 0, BD71815_INT_LED_OCP_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_LED_SCP, 0, BD71815_INT_LED_SCP_MASK),
|
||||
/* DCIN1 interrupts */
|
||||
REGMAP_IRQ_REG(BD71815_INT_DCIN_RMV, 1, BD71815_INT_DCIN_RMV_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_CLPS_OUT, 1, BD71815_INT_CLPS_OUT_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_CLPS_IN, 1, BD71815_INT_CLPS_IN_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_DCIN_OVP_RES, 1, BD71815_INT_DCIN_OVP_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_DCIN_OVP_DET, 1, BD71815_INT_DCIN_OVP_DET_MASK),
|
||||
/* DCIN2 interrupts */
|
||||
REGMAP_IRQ_REG(BD71815_INT_DCIN_MON_RES, 2, BD71815_INT_DCIN_MON_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_DCIN_MON_DET, 2, BD71815_INT_DCIN_MON_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_WDOG, 2, BD71815_INT_WDOG_MASK),
|
||||
/* Vsys */
|
||||
REGMAP_IRQ_REG(BD71815_INT_VSYS_UV_RES, 3, BD71815_INT_VSYS_UV_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_VSYS_UV_DET, 3, BD71815_INT_VSYS_UV_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_VSYS_LOW_RES, 3, BD71815_INT_VSYS_LOW_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_VSYS_LOW_DET, 3, BD71815_INT_VSYS_LOW_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_VSYS_MON_RES, 3, BD71815_INT_VSYS_MON_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_VSYS_MON_DET, 3, BD71815_INT_VSYS_MON_DET_MASK),
|
||||
/* Charger */
|
||||
REGMAP_IRQ_REG(BD71815_INT_CHG_WDG_TEMP, 4, BD71815_INT_CHG_WDG_TEMP_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_CHG_WDG_TIME, 4, BD71815_INT_CHG_WDG_TIME_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_CHG_RECHARGE_RES, 4, BD71815_INT_CHG_RECHARGE_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_CHG_RECHARGE_DET, 4, BD71815_INT_CHG_RECHARGE_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_CHG_RANGED_TEMP_TRANSITION, 4,
|
||||
BD71815_INT_CHG_RANGED_TEMP_TRANSITION_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_CHG_STATE_TRANSITION, 4, BD71815_INT_CHG_STATE_TRANSITION_MASK),
|
||||
/* Battery */
|
||||
REGMAP_IRQ_REG(BD71815_INT_BAT_TEMP_NORMAL, 5, BD71815_INT_BAT_TEMP_NORMAL_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_BAT_TEMP_ERANGE, 5, BD71815_INT_BAT_TEMP_ERANGE_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_BAT_REMOVED, 5, BD71815_INT_BAT_REMOVED_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_BAT_DETECTED, 5, BD71815_INT_BAT_DETECTED_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_THERM_REMOVED, 5, BD71815_INT_THERM_REMOVED_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_THERM_DETECTED, 5, BD71815_INT_THERM_DETECTED_MASK),
|
||||
/* Battery Mon 1 */
|
||||
REGMAP_IRQ_REG(BD71815_INT_BAT_DEAD, 6, BD71815_INT_BAT_DEAD_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_BAT_SHORTC_RES, 6, BD71815_INT_BAT_SHORTC_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_BAT_SHORTC_DET, 6, BD71815_INT_BAT_SHORTC_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_BAT_LOW_VOLT_RES, 6, BD71815_INT_BAT_LOW_VOLT_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_BAT_LOW_VOLT_DET, 6, BD71815_INT_BAT_LOW_VOLT_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_VOLT_RES, 6, BD71815_INT_BAT_OVER_VOLT_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_VOLT_DET, 6, BD71815_INT_BAT_OVER_VOLT_DET_MASK),
|
||||
/* Battery Mon 2 */
|
||||
REGMAP_IRQ_REG(BD71815_INT_BAT_MON_RES, 7, BD71815_INT_BAT_MON_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_BAT_MON_DET, 7, BD71815_INT_BAT_MON_DET_MASK),
|
||||
/* Battery Mon 3 (Coulomb counter) */
|
||||
REGMAP_IRQ_REG(BD71815_INT_BAT_CC_MON1, 8, BD71815_INT_BAT_CC_MON1_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_BAT_CC_MON2, 8, BD71815_INT_BAT_CC_MON2_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_BAT_CC_MON3, 8, BD71815_INT_BAT_CC_MON3_MASK),
|
||||
/* Battery Mon 4 */
|
||||
REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_1_RES, 9, BD71815_INT_BAT_OVER_CURR_1_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_1_DET, 9, BD71815_INT_BAT_OVER_CURR_1_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_2_RES, 9, BD71815_INT_BAT_OVER_CURR_2_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_2_DET, 9, BD71815_INT_BAT_OVER_CURR_2_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_3_RES, 9, BD71815_INT_BAT_OVER_CURR_3_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_3_DET, 9, BD71815_INT_BAT_OVER_CURR_3_DET_MASK),
|
||||
/* Temperature */
|
||||
REGMAP_IRQ_REG(BD71815_INT_TEMP_BAT_LOW_RES, 10, BD71815_INT_TEMP_BAT_LOW_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_TEMP_BAT_LOW_DET, 10, BD71815_INT_TEMP_BAT_LOW_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_TEMP_BAT_HI_RES, 10, BD71815_INT_TEMP_BAT_HI_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_TEMP_BAT_HI_DET, 10, BD71815_INT_TEMP_BAT_HI_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_TEMP_CHIP_OVER_125_RES, 10,
|
||||
BD71815_INT_TEMP_CHIP_OVER_125_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_TEMP_CHIP_OVER_125_DET, 10,
|
||||
BD71815_INT_TEMP_CHIP_OVER_125_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_TEMP_CHIP_OVER_VF_RES, 10,
|
||||
BD71815_INT_TEMP_CHIP_OVER_VF_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_TEMP_CHIP_OVER_VF_DET, 10,
|
||||
BD71815_INT_TEMP_CHIP_OVER_VF_DET_MASK),
|
||||
/* RTC Alarm */
|
||||
REGMAP_IRQ_REG(BD71815_INT_RTC0, 11, BD71815_INT_RTC0_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_RTC1, 11, BD71815_INT_RTC1_MASK),
|
||||
REGMAP_IRQ_REG(BD71815_INT_RTC2, 11, BD71815_INT_RTC2_MASK),
|
||||
};
|
||||
|
||||
static struct regmap_irq bd71828_irqs[] = {
|
||||
REGMAP_IRQ_REG(BD71828_INT_BUCK1_OCP, 0, BD71828_INT_BUCK1_OCP_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BUCK2_OCP, 0, BD71828_INT_BUCK2_OCP_MASK),
|
||||
@ -134,10 +331,8 @@ static struct regmap_irq bd71828_irqs[] = {
|
||||
REGMAP_IRQ_REG(BD71828_INT_CLPS_OUT, 1, BD71828_INT_CLPS_OUT_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_CLPS_IN, 1, BD71828_INT_CLPS_IN_MASK),
|
||||
/* DCIN2 interrupts */
|
||||
REGMAP_IRQ_REG(BD71828_INT_DCIN_MON_RES, 2,
|
||||
BD71828_INT_DCIN_MON_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_DCIN_MON_DET, 2,
|
||||
BD71828_INT_DCIN_MON_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_DCIN_MON_RES, 2, BD71828_INT_DCIN_MON_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_DCIN_MON_DET, 2, BD71828_INT_DCIN_MON_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_LONGPUSH, 2, BD71828_INT_LONGPUSH_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_MIDPUSH, 2, BD71828_INT_MIDPUSH_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_SHORTPUSH, 2, BD71828_INT_SHORTPUSH_MASK),
|
||||
@ -145,102 +340,59 @@ static struct regmap_irq bd71828_irqs[] = {
|
||||
REGMAP_IRQ_REG(BD71828_INT_WDOG, 2, BD71828_INT_WDOG_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_SWRESET, 2, BD71828_INT_SWRESET_MASK),
|
||||
/* Vsys */
|
||||
REGMAP_IRQ_REG(BD71828_INT_VSYS_UV_RES, 3,
|
||||
BD71828_INT_VSYS_UV_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_VSYS_UV_DET, 3,
|
||||
BD71828_INT_VSYS_UV_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_VSYS_LOW_RES, 3,
|
||||
BD71828_INT_VSYS_LOW_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_VSYS_LOW_DET, 3,
|
||||
BD71828_INT_VSYS_LOW_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_VSYS_HALL_IN, 3,
|
||||
BD71828_INT_VSYS_HALL_IN_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_VSYS_HALL_TOGGLE, 3,
|
||||
BD71828_INT_VSYS_HALL_TOGGLE_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_VSYS_MON_RES, 3,
|
||||
BD71828_INT_VSYS_MON_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_VSYS_MON_DET, 3,
|
||||
BD71828_INT_VSYS_MON_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_VSYS_UV_RES, 3, BD71828_INT_VSYS_UV_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_VSYS_UV_DET, 3, BD71828_INT_VSYS_UV_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_VSYS_LOW_RES, 3, BD71828_INT_VSYS_LOW_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_VSYS_LOW_DET, 3, BD71828_INT_VSYS_LOW_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_VSYS_HALL_IN, 3, BD71828_INT_VSYS_HALL_IN_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_VSYS_HALL_TOGGLE, 3, BD71828_INT_VSYS_HALL_TOGGLE_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_VSYS_MON_RES, 3, BD71828_INT_VSYS_MON_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_VSYS_MON_DET, 3, BD71828_INT_VSYS_MON_DET_MASK),
|
||||
/* Charger */
|
||||
REGMAP_IRQ_REG(BD71828_INT_CHG_DCIN_ILIM, 4,
|
||||
BD71828_INT_CHG_DCIN_ILIM_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_CHG_TOPOFF_TO_DONE, 4,
|
||||
BD71828_INT_CHG_TOPOFF_TO_DONE_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_CHG_WDG_TEMP, 4,
|
||||
BD71828_INT_CHG_WDG_TEMP_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_CHG_WDG_TIME, 4,
|
||||
BD71828_INT_CHG_WDG_TIME_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_CHG_RECHARGE_RES, 4,
|
||||
BD71828_INT_CHG_RECHARGE_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_CHG_RECHARGE_DET, 4,
|
||||
BD71828_INT_CHG_RECHARGE_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_CHG_DCIN_ILIM, 4, BD71828_INT_CHG_DCIN_ILIM_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_CHG_TOPOFF_TO_DONE, 4, BD71828_INT_CHG_TOPOFF_TO_DONE_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_CHG_WDG_TEMP, 4, BD71828_INT_CHG_WDG_TEMP_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_CHG_WDG_TIME, 4, BD71828_INT_CHG_WDG_TIME_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_CHG_RECHARGE_RES, 4, BD71828_INT_CHG_RECHARGE_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_CHG_RECHARGE_DET, 4, BD71828_INT_CHG_RECHARGE_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_CHG_RANGED_TEMP_TRANSITION, 4,
|
||||
BD71828_INT_CHG_RANGED_TEMP_TRANSITION_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_CHG_STATE_TRANSITION, 4,
|
||||
BD71828_INT_CHG_STATE_TRANSITION_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_CHG_STATE_TRANSITION, 4, BD71828_INT_CHG_STATE_TRANSITION_MASK),
|
||||
/* Battery */
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_NORMAL, 5,
|
||||
BD71828_INT_BAT_TEMP_NORMAL_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_ERANGE, 5,
|
||||
BD71828_INT_BAT_TEMP_ERANGE_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_WARN, 5,
|
||||
BD71828_INT_BAT_TEMP_WARN_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_REMOVED, 5,
|
||||
BD71828_INT_BAT_REMOVED_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_DETECTED, 5,
|
||||
BD71828_INT_BAT_DETECTED_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_THERM_REMOVED, 5,
|
||||
BD71828_INT_THERM_REMOVED_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_THERM_DETECTED, 5,
|
||||
BD71828_INT_THERM_DETECTED_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_NORMAL, 5, BD71828_INT_BAT_TEMP_NORMAL_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_ERANGE, 5, BD71828_INT_BAT_TEMP_ERANGE_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_WARN, 5, BD71828_INT_BAT_TEMP_WARN_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_REMOVED, 5, BD71828_INT_BAT_REMOVED_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_DETECTED, 5, BD71828_INT_BAT_DETECTED_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_THERM_REMOVED, 5, BD71828_INT_THERM_REMOVED_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_THERM_DETECTED, 5, BD71828_INT_THERM_DETECTED_MASK),
|
||||
/* Battery Mon 1 */
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_DEAD, 6, BD71828_INT_BAT_DEAD_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_SHORTC_RES, 6,
|
||||
BD71828_INT_BAT_SHORTC_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_SHORTC_DET, 6,
|
||||
BD71828_INT_BAT_SHORTC_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_LOW_VOLT_RES, 6,
|
||||
BD71828_INT_BAT_LOW_VOLT_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_LOW_VOLT_DET, 6,
|
||||
BD71828_INT_BAT_LOW_VOLT_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_VOLT_RES, 6,
|
||||
BD71828_INT_BAT_OVER_VOLT_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_VOLT_DET, 6,
|
||||
BD71828_INT_BAT_OVER_VOLT_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_SHORTC_RES, 6, BD71828_INT_BAT_SHORTC_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_SHORTC_DET, 6, BD71828_INT_BAT_SHORTC_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_LOW_VOLT_RES, 6, BD71828_INT_BAT_LOW_VOLT_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_LOW_VOLT_DET, 6, BD71828_INT_BAT_LOW_VOLT_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_VOLT_RES, 6, BD71828_INT_BAT_OVER_VOLT_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_VOLT_DET, 6, BD71828_INT_BAT_OVER_VOLT_DET_MASK),
|
||||
/* Battery Mon 2 */
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_MON_RES, 7,
|
||||
BD71828_INT_BAT_MON_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_MON_DET, 7,
|
||||
BD71828_INT_BAT_MON_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_MON_RES, 7, BD71828_INT_BAT_MON_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_MON_DET, 7, BD71828_INT_BAT_MON_DET_MASK),
|
||||
/* Battery Mon 3 (Coulomb counter) */
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON1, 8,
|
||||
BD71828_INT_BAT_CC_MON1_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON2, 8,
|
||||
BD71828_INT_BAT_CC_MON2_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON3, 8,
|
||||
BD71828_INT_BAT_CC_MON3_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON1, 8, BD71828_INT_BAT_CC_MON1_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON2, 8, BD71828_INT_BAT_CC_MON2_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON3, 8, BD71828_INT_BAT_CC_MON3_MASK),
|
||||
/* Battery Mon 4 */
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_1_RES, 9,
|
||||
BD71828_INT_BAT_OVER_CURR_1_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_1_DET, 9,
|
||||
BD71828_INT_BAT_OVER_CURR_1_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_2_RES, 9,
|
||||
BD71828_INT_BAT_OVER_CURR_2_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_2_DET, 9,
|
||||
BD71828_INT_BAT_OVER_CURR_2_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_3_RES, 9,
|
||||
BD71828_INT_BAT_OVER_CURR_3_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_3_DET, 9,
|
||||
BD71828_INT_BAT_OVER_CURR_3_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_1_RES, 9, BD71828_INT_BAT_OVER_CURR_1_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_1_DET, 9, BD71828_INT_BAT_OVER_CURR_1_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_2_RES, 9, BD71828_INT_BAT_OVER_CURR_2_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_2_DET, 9, BD71828_INT_BAT_OVER_CURR_2_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_3_RES, 9, BD71828_INT_BAT_OVER_CURR_3_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_3_DET, 9, BD71828_INT_BAT_OVER_CURR_3_DET_MASK),
|
||||
/* Temperature */
|
||||
REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_LOW_RES, 10,
|
||||
BD71828_INT_TEMP_BAT_LOW_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_LOW_DET, 10,
|
||||
BD71828_INT_TEMP_BAT_LOW_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_HI_RES, 10,
|
||||
BD71828_INT_TEMP_BAT_HI_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_HI_DET, 10,
|
||||
BD71828_INT_TEMP_BAT_HI_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_LOW_RES, 10, BD71828_INT_TEMP_BAT_LOW_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_LOW_DET, 10, BD71828_INT_TEMP_BAT_LOW_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_HI_RES, 10, BD71828_INT_TEMP_BAT_HI_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_HI_DET, 10, BD71828_INT_TEMP_BAT_HI_DET_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_TEMP_CHIP_OVER_125_RES, 10,
|
||||
BD71828_INT_TEMP_CHIP_OVER_125_RES_MASK),
|
||||
REGMAP_IRQ_REG(BD71828_INT_TEMP_CHIP_OVER_125_DET, 10,
|
||||
@ -267,57 +419,133 @@ static struct regmap_irq_chip bd71828_irq_chip = {
|
||||
.init_ack_masked = true,
|
||||
.num_regs = 12,
|
||||
.num_main_regs = 1,
|
||||
.sub_reg_offsets = &bd71828_sub_irq_offsets[0],
|
||||
.sub_reg_offsets = &bd718xx_sub_irq_offsets[0],
|
||||
.num_main_status_bits = 8,
|
||||
.irq_reg_stride = 1,
|
||||
};
|
||||
|
||||
static struct regmap_irq_chip bd71815_irq_chip = {
|
||||
.name = "bd71815_irq",
|
||||
.main_status = BD71815_REG_INT_STAT,
|
||||
.irqs = &bd71815_irqs[0],
|
||||
.num_irqs = ARRAY_SIZE(bd71815_irqs),
|
||||
.status_base = BD71815_REG_INT_STAT_01,
|
||||
.mask_base = BD71815_REG_INT_EN_01,
|
||||
.ack_base = BD71815_REG_INT_STAT_01,
|
||||
.mask_invert = true,
|
||||
.init_ack_masked = true,
|
||||
.num_regs = 12,
|
||||
.num_main_regs = 1,
|
||||
.sub_reg_offsets = &bd718xx_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)
|
||||
{
|
||||
int ret;
|
||||
unsigned int open_drain;
|
||||
|
||||
ret = of_property_read_u32(dev->of_node, "rohm,clkout-open-drain", &open_drain);
|
||||
if (ret) {
|
||||
if (ret == -EINVAL)
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
if (open_drain > 1) {
|
||||
dev_err(dev, "bad clk32kout mode configuration");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (open_drain)
|
||||
return regmap_update_bits(regmap, clkmode_reg, OUT32K_MODE,
|
||||
OUT32K_MODE_OPEN_DRAIN);
|
||||
|
||||
return regmap_update_bits(regmap, clkmode_reg, OUT32K_MODE,
|
||||
OUT32K_MODE_CMOS);
|
||||
}
|
||||
|
||||
static int bd71828_i2c_probe(struct i2c_client *i2c)
|
||||
{
|
||||
struct rohm_regmap_dev *chip;
|
||||
struct regmap_irq_chip_data *irq_data;
|
||||
int ret;
|
||||
struct regmap *regmap;
|
||||
const struct regmap_config *regmap_config;
|
||||
struct regmap_irq_chip *irqchip;
|
||||
unsigned int chip_type;
|
||||
struct mfd_cell *mfd;
|
||||
int cells;
|
||||
int button_irq;
|
||||
int clkmode_reg;
|
||||
|
||||
if (!i2c->irq) {
|
||||
dev_err(&i2c->dev, "No IRQ configured\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chip = devm_kzalloc(&i2c->dev, sizeof(*chip), GFP_KERNEL);
|
||||
if (!chip)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(&i2c->dev, chip);
|
||||
|
||||
chip->regmap = devm_regmap_init_i2c(i2c, &bd71828_regmap);
|
||||
if (IS_ERR(chip->regmap)) {
|
||||
dev_err(&i2c->dev, "Failed to initialize Regmap\n");
|
||||
return PTR_ERR(chip->regmap);
|
||||
chip_type = (unsigned int)(uintptr_t)
|
||||
of_device_get_match_data(&i2c->dev);
|
||||
switch (chip_type) {
|
||||
case ROHM_CHIP_TYPE_BD71828:
|
||||
mfd = bd71828_mfd_cells;
|
||||
cells = ARRAY_SIZE(bd71828_mfd_cells);
|
||||
regmap_config = &bd71828_regmap;
|
||||
irqchip = &bd71828_irq_chip;
|
||||
clkmode_reg = BD71828_REG_OUT32K;
|
||||
button_irq = BD71828_INT_SHORTPUSH;
|
||||
break;
|
||||
case ROHM_CHIP_TYPE_BD71815:
|
||||
mfd = bd71815_mfd_cells;
|
||||
cells = ARRAY_SIZE(bd71815_mfd_cells);
|
||||
regmap_config = &bd71815_regmap;
|
||||
irqchip = &bd71815_irq_chip;
|
||||
clkmode_reg = BD71815_REG_OUT32K;
|
||||
/*
|
||||
* If BD71817 support is needed we should be able to handle it
|
||||
* with proper DT configs + BD71815 drivers + power-button.
|
||||
* BD71815 data-sheet does not list the power-button IRQ so we
|
||||
* don't use it.
|
||||
*/
|
||||
button_irq = 0;
|
||||
break;
|
||||
default:
|
||||
dev_err(&i2c->dev, "Unknown device type");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = devm_regmap_add_irq_chip(&i2c->dev, chip->regmap,
|
||||
i2c->irq, IRQF_ONESHOT, 0,
|
||||
&bd71828_irq_chip, &irq_data);
|
||||
regmap = devm_regmap_init_i2c(i2c, regmap_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(&i2c->dev, "Failed to initialize Regmap\n");
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, i2c->irq,
|
||||
IRQF_ONESHOT, 0, irqchip, &irq_data);
|
||||
if (ret) {
|
||||
dev_err(&i2c->dev, "Failed to add IRQ chip\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_dbg(&i2c->dev, "Registered %d IRQs for chip\n",
|
||||
bd71828_irq_chip.num_irqs);
|
||||
irqchip->num_irqs);
|
||||
|
||||
ret = regmap_irq_get_virq(irq_data, BD71828_INT_SHORTPUSH);
|
||||
if (ret < 0) {
|
||||
dev_err(&i2c->dev, "Failed to get the power-key IRQ\n");
|
||||
return ret;
|
||||
if (button_irq) {
|
||||
ret = regmap_irq_get_virq(irq_data, button_irq);
|
||||
if (ret < 0) {
|
||||
dev_err(&i2c->dev, "Failed to get the power-key IRQ\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
button.irq = ret;
|
||||
}
|
||||
|
||||
button.irq = ret;
|
||||
ret = set_clk_mode(&i2c->dev, regmap, clkmode_reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO,
|
||||
bd71828_mfd_cells,
|
||||
ARRAY_SIZE(bd71828_mfd_cells), NULL, 0,
|
||||
regmap_irq_get_domain(irq_data));
|
||||
ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, mfd, cells,
|
||||
NULL, 0, regmap_irq_get_domain(irq_data));
|
||||
if (ret)
|
||||
dev_err(&i2c->dev, "Failed to create subdevices\n");
|
||||
|
||||
@ -325,7 +553,13 @@ static int bd71828_i2c_probe(struct i2c_client *i2c)
|
||||
}
|
||||
|
||||
static const struct of_device_id bd71828_of_match[] = {
|
||||
{ .compatible = "rohm,bd71828", },
|
||||
{
|
||||
.compatible = "rohm,bd71828",
|
||||
.data = (void *)ROHM_CHIP_TYPE_BD71828,
|
||||
}, {
|
||||
.compatible = "rohm,bd71815",
|
||||
.data = (void *)ROHM_CHIP_TYPE_BD71815,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bd71828_of_match);
|
||||
|
@ -91,9 +91,9 @@ static const struct regmap_config bd718xx_regmap_config = {
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static int bd718xx_init_press_duration(struct bd718xx *bd718xx)
|
||||
static int bd718xx_init_press_duration(struct regmap *regmap,
|
||||
struct device *dev)
|
||||
{
|
||||
struct device* dev = bd718xx->chip.dev;
|
||||
u32 short_press_ms, long_press_ms;
|
||||
u32 short_press_value, long_press_value;
|
||||
int ret;
|
||||
@ -102,8 +102,7 @@ static int bd718xx_init_press_duration(struct bd718xx *bd718xx)
|
||||
&short_press_ms);
|
||||
if (!ret) {
|
||||
short_press_value = min(15u, (short_press_ms + 250) / 500);
|
||||
ret = regmap_update_bits(bd718xx->chip.regmap,
|
||||
BD718XX_REG_PWRONCONFIG0,
|
||||
ret = regmap_update_bits(regmap, BD718XX_REG_PWRONCONFIG0,
|
||||
BD718XX_PWRBTN_PRESS_DURATION_MASK,
|
||||
short_press_value);
|
||||
if (ret) {
|
||||
@ -116,8 +115,7 @@ static int bd718xx_init_press_duration(struct bd718xx *bd718xx)
|
||||
&long_press_ms);
|
||||
if (!ret) {
|
||||
long_press_value = min(15u, (long_press_ms + 500) / 1000);
|
||||
ret = regmap_update_bits(bd718xx->chip.regmap,
|
||||
BD718XX_REG_PWRONCONFIG1,
|
||||
ret = regmap_update_bits(regmap, BD718XX_REG_PWRONCONFIG1,
|
||||
BD718XX_PWRBTN_PRESS_DURATION_MASK,
|
||||
long_press_value);
|
||||
if (ret) {
|
||||
@ -132,7 +130,8 @@ static int bd718xx_init_press_duration(struct bd718xx *bd718xx)
|
||||
static int bd718xx_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct bd718xx *bd718xx;
|
||||
struct regmap *regmap;
|
||||
struct regmap_irq_chip_data *irq_data;
|
||||
int ret;
|
||||
unsigned int chip_type;
|
||||
struct mfd_cell *mfd;
|
||||
@ -142,13 +141,6 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c,
|
||||
dev_err(&i2c->dev, "No IRQ configured\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bd718xx = devm_kzalloc(&i2c->dev, sizeof(struct bd718xx), GFP_KERNEL);
|
||||
|
||||
if (!bd718xx)
|
||||
return -ENOMEM;
|
||||
|
||||
bd718xx->chip_irq = i2c->irq;
|
||||
chip_type = (unsigned int)(uintptr_t)
|
||||
of_device_get_match_data(&i2c->dev);
|
||||
switch (chip_type) {
|
||||
@ -164,29 +156,26 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c,
|
||||
dev_err(&i2c->dev, "Unknown device type");
|
||||
return -EINVAL;
|
||||
}
|
||||
bd718xx->chip.dev = &i2c->dev;
|
||||
dev_set_drvdata(&i2c->dev, bd718xx);
|
||||
|
||||
bd718xx->chip.regmap = devm_regmap_init_i2c(i2c,
|
||||
&bd718xx_regmap_config);
|
||||
if (IS_ERR(bd718xx->chip.regmap)) {
|
||||
regmap = devm_regmap_init_i2c(i2c, &bd718xx_regmap_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(&i2c->dev, "regmap initialization failed\n");
|
||||
return PTR_ERR(bd718xx->chip.regmap);
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
ret = devm_regmap_add_irq_chip(&i2c->dev, bd718xx->chip.regmap,
|
||||
bd718xx->chip_irq, IRQF_ONESHOT, 0,
|
||||
&bd718xx_irq_chip, &bd718xx->irq_data);
|
||||
ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, i2c->irq,
|
||||
IRQF_ONESHOT, 0, &bd718xx_irq_chip,
|
||||
&irq_data);
|
||||
if (ret) {
|
||||
dev_err(&i2c->dev, "Failed to add irq_chip\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = bd718xx_init_press_duration(bd718xx);
|
||||
ret = bd718xx_init_press_duration(regmap, &i2c->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_irq_get_virq(bd718xx->irq_data, BD718XX_INT_PWRBTN_S);
|
||||
ret = regmap_irq_get_virq(irq_data, BD718XX_INT_PWRBTN_S);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&i2c->dev, "Failed to get the IRQ\n");
|
||||
@ -195,9 +184,9 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c,
|
||||
|
||||
button.irq = ret;
|
||||
|
||||
ret = devm_mfd_add_devices(bd718xx->chip.dev, PLATFORM_DEVID_AUTO,
|
||||
ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO,
|
||||
mfd, cells, NULL, 0,
|
||||
regmap_irq_get_domain(bd718xx->irq_data));
|
||||
regmap_irq_get_domain(irq_data));
|
||||
if (ret)
|
||||
dev_err(&i2c->dev, "Failed to create subdevices\n");
|
||||
|
||||
|
189
drivers/mfd/rohm-bd9576.c
Normal file
189
drivers/mfd/rohm-bd9576.c
Normal file
@ -0,0 +1,189 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2021 ROHM Semiconductors
|
||||
*
|
||||
* ROHM BD9576MUF and BD9573MUF PMIC driver
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/rohm-bd957x.h>
|
||||
#include <linux/mfd/rohm-generic.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
enum {
|
||||
BD957X_REGULATOR_CELL,
|
||||
BD957X_WDT_CELL,
|
||||
};
|
||||
|
||||
/*
|
||||
* Due to the BD9576MUF nasty IRQ behaiour we don't always populate IRQs.
|
||||
* These will be added to regulator resources only if IRQ information for the
|
||||
* PMIC is populated in device-tree.
|
||||
*/
|
||||
static const struct resource bd9576_regulator_irqs[] = {
|
||||
DEFINE_RES_IRQ_NAMED(BD9576_INT_THERM, "bd9576-temp"),
|
||||
DEFINE_RES_IRQ_NAMED(BD9576_INT_OVD, "bd9576-ovd"),
|
||||
DEFINE_RES_IRQ_NAMED(BD9576_INT_UVD, "bd9576-uvd"),
|
||||
};
|
||||
|
||||
static struct mfd_cell bd9573_mfd_cells[] = {
|
||||
[BD957X_REGULATOR_CELL] = { .name = "bd9573-regulator", },
|
||||
[BD957X_WDT_CELL] = { .name = "bd9576-wdt", },
|
||||
};
|
||||
|
||||
static struct mfd_cell bd9576_mfd_cells[] = {
|
||||
[BD957X_REGULATOR_CELL] = { .name = "bd9576-regulator", },
|
||||
[BD957X_WDT_CELL] = { .name = "bd9576-wdt", },
|
||||
};
|
||||
|
||||
static const struct regmap_range volatile_ranges[] = {
|
||||
regmap_reg_range(BD957X_REG_SMRB_ASSERT, BD957X_REG_SMRB_ASSERT),
|
||||
regmap_reg_range(BD957X_REG_PMIC_INTERNAL_STAT,
|
||||
BD957X_REG_PMIC_INTERNAL_STAT),
|
||||
regmap_reg_range(BD957X_REG_INT_THERM_STAT, BD957X_REG_INT_THERM_STAT),
|
||||
regmap_reg_range(BD957X_REG_INT_OVP_STAT, BD957X_REG_INT_SYS_STAT),
|
||||
regmap_reg_range(BD957X_REG_INT_MAIN_STAT, BD957X_REG_INT_MAIN_STAT),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table volatile_regs = {
|
||||
.yes_ranges = &volatile_ranges[0],
|
||||
.n_yes_ranges = ARRAY_SIZE(volatile_ranges),
|
||||
};
|
||||
|
||||
static struct regmap_config bd957x_regmap = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.volatile_table = &volatile_regs,
|
||||
.max_register = BD957X_MAX_REGISTER,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static struct regmap_irq bd9576_irqs[] = {
|
||||
REGMAP_IRQ_REG(BD9576_INT_THERM, 0, BD957X_MASK_INT_MAIN_THERM),
|
||||
REGMAP_IRQ_REG(BD9576_INT_OVP, 0, BD957X_MASK_INT_MAIN_OVP),
|
||||
REGMAP_IRQ_REG(BD9576_INT_SCP, 0, BD957X_MASK_INT_MAIN_SCP),
|
||||
REGMAP_IRQ_REG(BD9576_INT_OCP, 0, BD957X_MASK_INT_MAIN_OCP),
|
||||
REGMAP_IRQ_REG(BD9576_INT_OVD, 0, BD957X_MASK_INT_MAIN_OVD),
|
||||
REGMAP_IRQ_REG(BD9576_INT_UVD, 0, BD957X_MASK_INT_MAIN_UVD),
|
||||
REGMAP_IRQ_REG(BD9576_INT_UVP, 0, BD957X_MASK_INT_MAIN_UVP),
|
||||
REGMAP_IRQ_REG(BD9576_INT_SYS, 0, BD957X_MASK_INT_MAIN_SYS),
|
||||
};
|
||||
|
||||
static struct regmap_irq_chip bd9576_irq_chip = {
|
||||
.name = "bd9576_irq",
|
||||
.irqs = &bd9576_irqs[0],
|
||||
.num_irqs = ARRAY_SIZE(bd9576_irqs),
|
||||
.status_base = BD957X_REG_INT_MAIN_STAT,
|
||||
.mask_base = BD957X_REG_INT_MAIN_MASK,
|
||||
.ack_base = BD957X_REG_INT_MAIN_STAT,
|
||||
.init_ack_masked = true,
|
||||
.num_regs = 1,
|
||||
.irq_reg_stride = 1,
|
||||
};
|
||||
|
||||
static int bd957x_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int ret;
|
||||
struct regmap *regmap;
|
||||
struct mfd_cell *cells;
|
||||
int num_cells;
|
||||
unsigned long chip_type;
|
||||
struct irq_domain *domain;
|
||||
bool usable_irqs;
|
||||
|
||||
chip_type = (unsigned long)of_device_get_match_data(&i2c->dev);
|
||||
|
||||
switch (chip_type) {
|
||||
case ROHM_CHIP_TYPE_BD9576:
|
||||
cells = bd9576_mfd_cells;
|
||||
num_cells = ARRAY_SIZE(bd9576_mfd_cells);
|
||||
usable_irqs = !!i2c->irq;
|
||||
break;
|
||||
case ROHM_CHIP_TYPE_BD9573:
|
||||
cells = bd9573_mfd_cells;
|
||||
num_cells = ARRAY_SIZE(bd9573_mfd_cells);
|
||||
/*
|
||||
* BD9573 only supports fatal IRQs which we can not handle
|
||||
* because SoC is going to lose the power.
|
||||
*/
|
||||
usable_irqs = false;
|
||||
break;
|
||||
default:
|
||||
dev_err(&i2c->dev, "Unknown device type");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap = devm_regmap_init_i2c(i2c, &bd957x_regmap);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(&i2c->dev, "Failed to initialize Regmap\n");
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
/*
|
||||
* BD9576 behaves badly. It kepts IRQ line asserted for the whole
|
||||
* duration of detected HW condition (like over temperature). So we
|
||||
* don't require IRQ to be populated.
|
||||
* If IRQ information is not given, then we mask all IRQs and do not
|
||||
* provide IRQ resources to regulator driver - which then just omits
|
||||
* the notifiers.
|
||||
*/
|
||||
if (usable_irqs) {
|
||||
struct regmap_irq_chip_data *irq_data;
|
||||
struct mfd_cell *regulators;
|
||||
|
||||
regulators = &bd9576_mfd_cells[BD957X_REGULATOR_CELL];
|
||||
regulators->resources = bd9576_regulator_irqs;
|
||||
regulators->num_resources = ARRAY_SIZE(bd9576_regulator_irqs);
|
||||
|
||||
ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, i2c->irq,
|
||||
IRQF_ONESHOT, 0,
|
||||
&bd9576_irq_chip, &irq_data);
|
||||
if (ret) {
|
||||
dev_err(&i2c->dev, "Failed to add IRQ chip\n");
|
||||
return ret;
|
||||
}
|
||||
domain = regmap_irq_get_domain(irq_data);
|
||||
} else {
|
||||
ret = regmap_update_bits(regmap, BD957X_REG_INT_MAIN_MASK,
|
||||
BD957X_MASK_INT_ALL,
|
||||
BD957X_MASK_INT_ALL);
|
||||
if (ret)
|
||||
return ret;
|
||||
domain = NULL;
|
||||
}
|
||||
|
||||
ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, cells,
|
||||
num_cells, NULL, 0, domain);
|
||||
if (ret)
|
||||
dev_err(&i2c->dev, "Failed to create subdevices\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id bd957x_of_match[] = {
|
||||
{ .compatible = "rohm,bd9576", .data = (void *)ROHM_CHIP_TYPE_BD9576, },
|
||||
{ .compatible = "rohm,bd9573", .data = (void *)ROHM_CHIP_TYPE_BD9573, },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bd957x_of_match);
|
||||
|
||||
static struct i2c_driver bd957x_drv = {
|
||||
.driver = {
|
||||
.name = "rohm-bd957x",
|
||||
.of_match_table = bd957x_of_match,
|
||||
},
|
||||
.probe = &bd957x_i2c_probe,
|
||||
};
|
||||
module_i2c_driver(bd957x_drv);
|
||||
|
||||
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
|
||||
MODULE_DESCRIPTION("ROHM BD9576MUF and BD9573MUF Power Management IC driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -549,19 +549,7 @@ static struct i2c_driver sec_pmic_driver = {
|
||||
.shutdown = sec_pmic_shutdown,
|
||||
.id_table = sec_pmic_id,
|
||||
};
|
||||
|
||||
static int __init sec_pmic_init(void)
|
||||
{
|
||||
return i2c_add_driver(&sec_pmic_driver);
|
||||
}
|
||||
|
||||
subsys_initcall(sec_pmic_init);
|
||||
|
||||
static void __exit sec_pmic_exit(void)
|
||||
{
|
||||
i2c_del_driver(&sec_pmic_driver);
|
||||
}
|
||||
module_exit(sec_pmic_exit);
|
||||
module_i2c_driver(sec_pmic_driver);
|
||||
|
||||
MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
|
||||
MODULE_DESCRIPTION("Core support for the S5M MFD");
|
||||
|
@ -158,13 +158,18 @@ static const struct regmap_config stm32_timers_regmap_cfg = {
|
||||
|
||||
static void stm32_timers_get_arr_size(struct stm32_timers *ddata)
|
||||
{
|
||||
u32 arr;
|
||||
|
||||
/* Backup ARR to restore it after getting the maximum value */
|
||||
regmap_read(ddata->regmap, TIM_ARR, &arr);
|
||||
|
||||
/*
|
||||
* Only the available bits will be written so when readback
|
||||
* we get the maximum value of auto reload register
|
||||
*/
|
||||
regmap_write(ddata->regmap, TIM_ARR, ~0L);
|
||||
regmap_read(ddata->regmap, TIM_ARR, &ddata->max_arr);
|
||||
regmap_write(ddata->regmap, TIM_ARR, 0x0);
|
||||
regmap_write(ddata->regmap, TIM_ARR, arr);
|
||||
}
|
||||
|
||||
static int stm32_timers_dma_probe(struct device *dev,
|
||||
|
@ -312,7 +312,7 @@ EXPORT_SYMBOL_GPL(stmpe_set_altfunc);
|
||||
* GPIO (all variants)
|
||||
*/
|
||||
|
||||
static const struct resource stmpe_gpio_resources[] = {
|
||||
static struct resource stmpe_gpio_resources[] = {
|
||||
/* Start and end filled dynamically */
|
||||
{
|
||||
.flags = IORESOURCE_IRQ,
|
||||
@ -336,7 +336,8 @@ static const struct mfd_cell stmpe_gpio_cell_noirq = {
|
||||
* Keypad (1601, 2401, 2403)
|
||||
*/
|
||||
|
||||
static const struct resource stmpe_keypad_resources[] = {
|
||||
static struct resource stmpe_keypad_resources[] = {
|
||||
/* Start and end filled dynamically */
|
||||
{
|
||||
.name = "KEYPAD",
|
||||
.flags = IORESOURCE_IRQ,
|
||||
@ -357,7 +358,8 @@ static const struct mfd_cell stmpe_keypad_cell = {
|
||||
/*
|
||||
* PWM (1601, 2401, 2403)
|
||||
*/
|
||||
static const struct resource stmpe_pwm_resources[] = {
|
||||
static struct resource stmpe_pwm_resources[] = {
|
||||
/* Start and end filled dynamically */
|
||||
{
|
||||
.name = "PWM0",
|
||||
.flags = IORESOURCE_IRQ,
|
||||
@ -445,7 +447,8 @@ static struct stmpe_variant_info stmpe801_noirq = {
|
||||
* Touchscreen (STMPE811 or STMPE610)
|
||||
*/
|
||||
|
||||
static const struct resource stmpe_ts_resources[] = {
|
||||
static struct resource stmpe_ts_resources[] = {
|
||||
/* Start and end filled dynamically */
|
||||
{
|
||||
.name = "TOUCH_DET",
|
||||
.flags = IORESOURCE_IRQ,
|
||||
@ -467,7 +470,8 @@ static const struct mfd_cell stmpe_ts_cell = {
|
||||
* ADC (STMPE811)
|
||||
*/
|
||||
|
||||
static const struct resource stmpe_adc_resources[] = {
|
||||
static struct resource stmpe_adc_resources[] = {
|
||||
/* Start and end filled dynamically */
|
||||
{
|
||||
.name = "STMPE_TEMP_SENS",
|
||||
.flags = IORESOURCE_IRQ,
|
||||
|
@ -393,6 +393,14 @@ config PWM_MXS
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called pwm-mxs.
|
||||
|
||||
config PWM_NTXEC
|
||||
tristate "Netronix embedded controller PWM support"
|
||||
depends on MFD_NTXEC
|
||||
help
|
||||
Say yes here if you want to support the PWM output of the embedded
|
||||
controller found in certain e-book readers designed by the original
|
||||
design manufacturer Netronix.
|
||||
|
||||
config PWM_OMAP_DMTIMER
|
||||
tristate "OMAP Dual-Mode Timer PWM support"
|
||||
depends on OF
|
||||
|
@ -35,6 +35,7 @@ obj-$(CONFIG_PWM_MESON) += pwm-meson.o
|
||||
obj-$(CONFIG_PWM_MEDIATEK) += pwm-mediatek.o
|
||||
obj-$(CONFIG_PWM_MTK_DISP) += pwm-mtk-disp.o
|
||||
obj-$(CONFIG_PWM_MXS) += pwm-mxs.o
|
||||
obj-$(CONFIG_PWM_NTXEC) += pwm-ntxec.o
|
||||
obj-$(CONFIG_PWM_OMAP_DMTIMER) += pwm-omap-dmtimer.o
|
||||
obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o
|
||||
obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
|
||||
|
184
drivers/pwm/pwm-ntxec.c
Normal file
184
drivers/pwm/pwm-ntxec.c
Normal file
@ -0,0 +1,184 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* The Netronix embedded controller is a microcontroller found in some
|
||||
* e-book readers designed by the original design manufacturer Netronix, Inc.
|
||||
* It contains RTC, battery monitoring, system power management, and PWM
|
||||
* functionality.
|
||||
*
|
||||
* This driver implements PWM output.
|
||||
*
|
||||
* Copyright 2020 Jonathan Neuschäfer <j.neuschaefer@gmx.net>
|
||||
*
|
||||
* Limitations:
|
||||
* - The get_state callback is not implemented, because the current state of
|
||||
* the PWM output can't be read back from the hardware.
|
||||
* - The hardware can only generate normal polarity output.
|
||||
* - The period and duty cycle can't be changed together in one atomic action.
|
||||
*/
|
||||
|
||||
#include <linux/mfd/ntxec.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct ntxec_pwm {
|
||||
struct device *dev;
|
||||
struct ntxec *ec;
|
||||
struct pwm_chip chip;
|
||||
};
|
||||
|
||||
static struct ntxec_pwm *ntxec_pwm_from_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct ntxec_pwm, chip);
|
||||
}
|
||||
|
||||
#define NTXEC_REG_AUTO_OFF_HI 0xa1
|
||||
#define NTXEC_REG_AUTO_OFF_LO 0xa2
|
||||
#define NTXEC_REG_ENABLE 0xa3
|
||||
#define NTXEC_REG_PERIOD_LOW 0xa4
|
||||
#define NTXEC_REG_PERIOD_HIGH 0xa5
|
||||
#define NTXEC_REG_DUTY_LOW 0xa6
|
||||
#define NTXEC_REG_DUTY_HIGH 0xa7
|
||||
|
||||
/*
|
||||
* The time base used in the EC is 8MHz, or 125ns. Period and duty cycle are
|
||||
* measured in this unit.
|
||||
*/
|
||||
#define TIME_BASE_NS 125
|
||||
|
||||
/*
|
||||
* The maximum input value (in nanoseconds) is determined by the time base and
|
||||
* the range of the hardware registers that hold the converted value.
|
||||
* It fits into 32 bits, so we can do our calculations in 32 bits as well.
|
||||
*/
|
||||
#define MAX_PERIOD_NS (TIME_BASE_NS * 0xffff)
|
||||
|
||||
static int ntxec_pwm_set_raw_period_and_duty_cycle(struct pwm_chip *chip,
|
||||
int period, int duty)
|
||||
{
|
||||
struct ntxec_pwm *priv = ntxec_pwm_from_chip(chip);
|
||||
|
||||
/*
|
||||
* Changes to the period and duty cycle take effect as soon as the
|
||||
* corresponding low byte is written, so the hardware may be configured
|
||||
* to an inconsistent state after the period is written and before the
|
||||
* duty cycle is fully written. If, in such a case, the old duty cycle
|
||||
* is longer than the new period, the EC may output 100% for a moment.
|
||||
*
|
||||
* To minimize the time between the changes to period and duty cycle
|
||||
* taking effect, the writes are interleaved.
|
||||
*/
|
||||
|
||||
struct reg_sequence regs[] = {
|
||||
{ NTXEC_REG_PERIOD_HIGH, ntxec_reg8(period >> 8) },
|
||||
{ NTXEC_REG_DUTY_HIGH, ntxec_reg8(duty >> 8) },
|
||||
{ NTXEC_REG_PERIOD_LOW, ntxec_reg8(period) },
|
||||
{ NTXEC_REG_DUTY_LOW, ntxec_reg8(duty) },
|
||||
};
|
||||
|
||||
return regmap_multi_reg_write(priv->ec->regmap, regs, ARRAY_SIZE(regs));
|
||||
}
|
||||
|
||||
static int ntxec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm_dev,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
struct ntxec_pwm *priv = ntxec_pwm_from_chip(chip);
|
||||
unsigned int period, duty;
|
||||
int res;
|
||||
|
||||
if (state->polarity != PWM_POLARITY_NORMAL)
|
||||
return -EINVAL;
|
||||
|
||||
period = min_t(u64, state->period, MAX_PERIOD_NS);
|
||||
duty = min_t(u64, state->duty_cycle, period);
|
||||
|
||||
period /= TIME_BASE_NS;
|
||||
duty /= TIME_BASE_NS;
|
||||
|
||||
/*
|
||||
* Writing a duty cycle of zero puts the device into a state where
|
||||
* writing a higher duty cycle doesn't result in the brightness that it
|
||||
* usually results in. This can be fixed by cycling the ENABLE register.
|
||||
*
|
||||
* As a workaround, write ENABLE=0 when the duty cycle is zero.
|
||||
* The case that something has previously set the duty cycle to zero
|
||||
* but ENABLE=1, is not handled.
|
||||
*/
|
||||
if (state->enabled && duty != 0) {
|
||||
res = ntxec_pwm_set_raw_period_and_duty_cycle(chip, period, duty);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
res = regmap_write(priv->ec->regmap, NTXEC_REG_ENABLE, ntxec_reg8(1));
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
/* Disable the auto-off timer */
|
||||
res = regmap_write(priv->ec->regmap, NTXEC_REG_AUTO_OFF_HI, ntxec_reg8(0xff));
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
return regmap_write(priv->ec->regmap, NTXEC_REG_AUTO_OFF_LO, ntxec_reg8(0xff));
|
||||
} else {
|
||||
return regmap_write(priv->ec->regmap, NTXEC_REG_ENABLE, ntxec_reg8(0));
|
||||
}
|
||||
}
|
||||
|
||||
static const struct pwm_ops ntxec_pwm_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.apply = ntxec_pwm_apply,
|
||||
/*
|
||||
* No .get_state callback, because the current state cannot be read
|
||||
* back from the hardware.
|
||||
*/
|
||||
};
|
||||
|
||||
static int ntxec_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ntxec *ec = dev_get_drvdata(pdev->dev.parent);
|
||||
struct ntxec_pwm *priv;
|
||||
struct pwm_chip *chip;
|
||||
|
||||
pdev->dev.of_node = pdev->dev.parent->of_node;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->ec = ec;
|
||||
priv->dev = &pdev->dev;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
chip = &priv->chip;
|
||||
chip->dev = &pdev->dev;
|
||||
chip->ops = &ntxec_pwm_ops;
|
||||
chip->base = -1;
|
||||
chip->npwm = 1;
|
||||
|
||||
return pwmchip_add(chip);
|
||||
}
|
||||
|
||||
static int ntxec_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ntxec_pwm *priv = platform_get_drvdata(pdev);
|
||||
struct pwm_chip *chip = &priv->chip;
|
||||
|
||||
return pwmchip_remove(chip);
|
||||
}
|
||||
|
||||
static struct platform_driver ntxec_pwm_driver = {
|
||||
.driver = {
|
||||
.name = "ntxec-pwm",
|
||||
},
|
||||
.probe = ntxec_pwm_probe,
|
||||
.remove = ntxec_pwm_remove,
|
||||
};
|
||||
module_platform_driver(ntxec_pwm_driver);
|
||||
|
||||
MODULE_AUTHOR("Jonathan Neuschäfer <j.neuschaefer@gmx.net>");
|
||||
MODULE_DESCRIPTION("PWM driver for Netronix EC");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:ntxec-pwm");
|
@ -204,6 +204,17 @@ config REGULATOR_BD70528
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called bd70528-regulator.
|
||||
|
||||
config REGULATOR_BD71815
|
||||
tristate "ROHM BD71815 Power Regulator"
|
||||
depends on MFD_ROHM_BD71828
|
||||
help
|
||||
This driver supports voltage regulators on ROHM BD71815 PMIC.
|
||||
This will enable support for the software controllable buck
|
||||
and LDO regulators and a current regulator for LEDs.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called bd71815-regulator.
|
||||
|
||||
config REGULATOR_BD71828
|
||||
tristate "ROHM BD71828 Power Regulator"
|
||||
depends on MFD_ROHM_BD71828
|
||||
|
@ -30,6 +30,7 @@ obj-$(CONFIG_REGULATOR_ATC260X) += atc260x-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_BD70528) += bd70528-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_BD71815) += bd71815-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_BD71828) += bd71828-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_BD718XX) += bd718x7-regulator.o
|
||||
obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o
|
||||
|
652
drivers/regulator/bd71815-regulator.c
Normal file
652
drivers/regulator/bd71815-regulator.c
Normal file
@ -0,0 +1,652 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
//
|
||||
// Copyright 2014 Embest Technology Co. Ltd. Inc.
|
||||
// bd71815-regulator.c ROHM BD71815 regulator driver
|
||||
//
|
||||
// Author: Tony Luo <luofc@embedinfo.com>
|
||||
//
|
||||
// Partially rewritten at 2021 by
|
||||
// Matti Vaittinen <matti.vaitinen@fi.rohmeurope.com>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/mfd/rohm-generic.h>
|
||||
#include <linux/mfd/rohm-bd71815.h>
|
||||
#include <linux/regulator/of_regulator.h>
|
||||
|
||||
struct bd71815_regulator {
|
||||
struct regulator_desc desc;
|
||||
const struct rohm_dvs_config *dvs;
|
||||
};
|
||||
|
||||
struct bd71815_pmic {
|
||||
struct bd71815_regulator descs[BD71815_REGULATOR_CNT];
|
||||
struct regmap *regmap;
|
||||
struct device *dev;
|
||||
struct gpio_descs *gps;
|
||||
struct regulator_dev *rdev[BD71815_REGULATOR_CNT];
|
||||
};
|
||||
|
||||
static const int bd7181x_wled_currents[] = {
|
||||
10, 20, 30, 50, 70, 100, 200, 300, 500, 700, 1000, 2000, 3000, 4000,
|
||||
5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000, 13000, 14000, 15000,
|
||||
16000, 17000, 18000, 19000, 20000, 21000, 22000, 23000, 24000, 25000,
|
||||
};
|
||||
|
||||
static const struct rohm_dvs_config buck1_dvs = {
|
||||
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
|
||||
ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
|
||||
.run_reg = BD71815_REG_BUCK1_VOLT_H,
|
||||
.run_mask = BD71815_VOLT_MASK,
|
||||
.run_on_mask = BD71815_BUCK_RUN_ON,
|
||||
.snvs_on_mask = BD71815_BUCK_SNVS_ON,
|
||||
.suspend_reg = BD71815_REG_BUCK1_VOLT_L,
|
||||
.suspend_mask = BD71815_VOLT_MASK,
|
||||
.suspend_on_mask = BD71815_BUCK_SUSP_ON,
|
||||
.lpsr_reg = BD71815_REG_BUCK1_VOLT_L,
|
||||
.lpsr_mask = BD71815_VOLT_MASK,
|
||||
.lpsr_on_mask = BD71815_BUCK_LPSR_ON,
|
||||
};
|
||||
|
||||
static const struct rohm_dvs_config buck2_dvs = {
|
||||
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
|
||||
ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
|
||||
.run_reg = BD71815_REG_BUCK2_VOLT_H,
|
||||
.run_mask = BD71815_VOLT_MASK,
|
||||
.run_on_mask = BD71815_BUCK_RUN_ON,
|
||||
.snvs_on_mask = BD71815_BUCK_SNVS_ON,
|
||||
.suspend_reg = BD71815_REG_BUCK2_VOLT_L,
|
||||
.suspend_mask = BD71815_VOLT_MASK,
|
||||
.suspend_on_mask = BD71815_BUCK_SUSP_ON,
|
||||
.lpsr_reg = BD71815_REG_BUCK2_VOLT_L,
|
||||
.lpsr_mask = BD71815_VOLT_MASK,
|
||||
.lpsr_on_mask = BD71815_BUCK_LPSR_ON,
|
||||
};
|
||||
|
||||
static const struct rohm_dvs_config buck3_dvs = {
|
||||
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
|
||||
ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
|
||||
.run_reg = BD71815_REG_BUCK3_VOLT,
|
||||
.run_mask = BD71815_VOLT_MASK,
|
||||
.run_on_mask = BD71815_BUCK_RUN_ON,
|
||||
.snvs_on_mask = BD71815_BUCK_SNVS_ON,
|
||||
.suspend_on_mask = BD71815_BUCK_SUSP_ON,
|
||||
.lpsr_on_mask = BD71815_BUCK_LPSR_ON,
|
||||
};
|
||||
|
||||
static const struct rohm_dvs_config buck4_dvs = {
|
||||
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
|
||||
ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
|
||||
.run_reg = BD71815_REG_BUCK4_VOLT,
|
||||
.run_mask = BD71815_VOLT_MASK,
|
||||
.run_on_mask = BD71815_BUCK_RUN_ON,
|
||||
.snvs_on_mask = BD71815_BUCK_SNVS_ON,
|
||||
.suspend_on_mask = BD71815_BUCK_SUSP_ON,
|
||||
.lpsr_on_mask = BD71815_BUCK_LPSR_ON,
|
||||
};
|
||||
|
||||
static const struct rohm_dvs_config ldo1_dvs = {
|
||||
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
|
||||
ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
|
||||
.run_reg = BD71815_REG_LDO_MODE1,
|
||||
.run_mask = BD71815_VOLT_MASK,
|
||||
.run_on_mask = LDO1_RUN_ON,
|
||||
.snvs_on_mask = LDO1_SNVS_ON,
|
||||
.suspend_on_mask = LDO1_SUSP_ON,
|
||||
.lpsr_on_mask = LDO1_LPSR_ON,
|
||||
};
|
||||
|
||||
static const struct rohm_dvs_config ldo2_dvs = {
|
||||
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
|
||||
ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
|
||||
.run_reg = BD71815_REG_LDO_MODE2,
|
||||
.run_mask = BD71815_VOLT_MASK,
|
||||
.run_on_mask = LDO2_RUN_ON,
|
||||
.snvs_on_mask = LDO2_SNVS_ON,
|
||||
.suspend_on_mask = LDO2_SUSP_ON,
|
||||
.lpsr_on_mask = LDO2_LPSR_ON,
|
||||
};
|
||||
|
||||
static const struct rohm_dvs_config ldo3_dvs = {
|
||||
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
|
||||
ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
|
||||
.run_reg = BD71815_REG_LDO_MODE2,
|
||||
.run_mask = BD71815_VOLT_MASK,
|
||||
.run_on_mask = LDO3_RUN_ON,
|
||||
.snvs_on_mask = LDO3_SNVS_ON,
|
||||
.suspend_on_mask = LDO3_SUSP_ON,
|
||||
.lpsr_on_mask = LDO3_LPSR_ON,
|
||||
};
|
||||
|
||||
static const struct rohm_dvs_config ldo4_dvs = {
|
||||
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
|
||||
ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
|
||||
.run_reg = BD71815_REG_LDO_MODE3,
|
||||
.run_mask = BD71815_VOLT_MASK,
|
||||
.run_on_mask = LDO4_RUN_ON,
|
||||
.snvs_on_mask = LDO4_SNVS_ON,
|
||||
.suspend_on_mask = LDO4_SUSP_ON,
|
||||
.lpsr_on_mask = LDO4_LPSR_ON,
|
||||
};
|
||||
|
||||
static const struct rohm_dvs_config ldo5_dvs = {
|
||||
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
|
||||
ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
|
||||
.run_reg = BD71815_REG_LDO_MODE3,
|
||||
.run_mask = BD71815_VOLT_MASK,
|
||||
.run_on_mask = LDO5_RUN_ON,
|
||||
.snvs_on_mask = LDO5_SNVS_ON,
|
||||
.suspend_on_mask = LDO5_SUSP_ON,
|
||||
.lpsr_on_mask = LDO5_LPSR_ON,
|
||||
};
|
||||
|
||||
static const struct rohm_dvs_config dvref_dvs = {
|
||||
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
|
||||
ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
|
||||
.run_on_mask = DVREF_RUN_ON,
|
||||
.snvs_on_mask = DVREF_SNVS_ON,
|
||||
.suspend_on_mask = DVREF_SUSP_ON,
|
||||
.lpsr_on_mask = DVREF_LPSR_ON,
|
||||
};
|
||||
|
||||
static const struct rohm_dvs_config ldolpsr_dvs = {
|
||||
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
|
||||
ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
|
||||
.run_on_mask = DVREF_RUN_ON,
|
||||
.snvs_on_mask = DVREF_SNVS_ON,
|
||||
.suspend_on_mask = DVREF_SUSP_ON,
|
||||
.lpsr_on_mask = DVREF_LPSR_ON,
|
||||
};
|
||||
|
||||
static const struct rohm_dvs_config buck5_dvs = {
|
||||
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS |
|
||||
ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR,
|
||||
.run_reg = BD71815_REG_BUCK5_VOLT,
|
||||
.run_mask = BD71815_VOLT_MASK,
|
||||
.run_on_mask = BD71815_BUCK_RUN_ON,
|
||||
.snvs_on_mask = BD71815_BUCK_SNVS_ON,
|
||||
.suspend_on_mask = BD71815_BUCK_SUSP_ON,
|
||||
.lpsr_on_mask = BD71815_BUCK_LPSR_ON,
|
||||
};
|
||||
|
||||
static int set_hw_dvs_levels(struct device_node *np,
|
||||
const struct regulator_desc *desc,
|
||||
struct regulator_config *cfg)
|
||||
{
|
||||
struct bd71815_regulator *data;
|
||||
|
||||
data = container_of(desc, struct bd71815_regulator, desc);
|
||||
return rohm_regulator_set_dvs_levels(data->dvs, np, desc, cfg->regmap);
|
||||
}
|
||||
|
||||
/*
|
||||
* Bucks 1 and 2 have two voltage selection registers where selected
|
||||
* voltage can be set. Which of the registers is used can be either controlled
|
||||
* by a control bit in register - or by HW state. If HW state specific voltages
|
||||
* are given - then we assume HW state based control should be used.
|
||||
*
|
||||
* If volatge value is updated to currently selected register - then output
|
||||
* voltage is immediately changed no matter what is set as ramp rate. Thus we
|
||||
* default changing voltage by writing new value to inactive register and
|
||||
* then updating the 'register selection' bit. This naturally only works when
|
||||
* HW state machine is not used to select the voltage.
|
||||
*/
|
||||
static int buck12_set_hw_dvs_levels(struct device_node *np,
|
||||
const struct regulator_desc *desc,
|
||||
struct regulator_config *cfg)
|
||||
{
|
||||
struct bd71815_regulator *data;
|
||||
int ret = 0, val;
|
||||
|
||||
data = container_of(desc, struct bd71815_regulator, desc);
|
||||
|
||||
if (of_find_property(np, "rohm,dvs-run-voltage", NULL) ||
|
||||
of_find_property(np, "rohm,dvs-suspend-voltage", NULL) ||
|
||||
of_find_property(np, "rohm,dvs-lpsr-voltage", NULL) ||
|
||||
of_find_property(np, "rohm,dvs-snvs-voltage", NULL)) {
|
||||
ret = regmap_read(cfg->regmap, desc->vsel_reg, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!(BD71815_BUCK_STBY_DVS & val) &&
|
||||
!(BD71815_BUCK_DVSSEL & val)) {
|
||||
int val2;
|
||||
|
||||
/*
|
||||
* We are currently using voltage from _L.
|
||||
* We'd better copy it to _H and switch to it to
|
||||
* avoid shutting us down if LPSR or SUSPEND is set to
|
||||
* disabled. _L value is at reg _H + 1
|
||||
*/
|
||||
ret = regmap_read(cfg->regmap, desc->vsel_reg + 1,
|
||||
&val2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_update_bits(cfg->regmap, desc->vsel_reg,
|
||||
BD71815_VOLT_MASK |
|
||||
BD71815_BUCK_DVSSEL,
|
||||
val2 | BD71815_BUCK_DVSSEL);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
ret = rohm_regulator_set_dvs_levels(data->dvs, np, desc,
|
||||
cfg->regmap);
|
||||
if (ret)
|
||||
return ret;
|
||||
/*
|
||||
* DVS levels were given => use HW-state machine for voltage
|
||||
* controls. NOTE: AFAIK, This means that if voltage is changed
|
||||
* by SW the ramp-rate is not respected. Should we disable
|
||||
* SW voltage control when the HW state machine is used?
|
||||
*/
|
||||
ret = regmap_update_bits(cfg->regmap, desc->vsel_reg,
|
||||
BD71815_BUCK_STBY_DVS,
|
||||
BD71815_BUCK_STBY_DVS);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* BUCK1/2
|
||||
* BUCK1RAMPRATE[1:0] BUCK1 DVS ramp rate setting
|
||||
* 00: 10.00mV/usec 10mV 1uS
|
||||
* 01: 5.00mV/usec 10mV 2uS
|
||||
* 10: 2.50mV/usec 10mV 4uS
|
||||
* 11: 1.25mV/usec 10mV 8uS
|
||||
*/
|
||||
static const unsigned int bd7181x_ramp_table[] = { 1250, 2500, 5000, 10000 };
|
||||
|
||||
static int bd7181x_led_set_current_limit(struct regulator_dev *rdev,
|
||||
int min_uA, int max_uA)
|
||||
{
|
||||
int ret;
|
||||
int onstatus;
|
||||
|
||||
onstatus = regulator_is_enabled_regmap(rdev);
|
||||
|
||||
ret = regulator_set_current_limit_regmap(rdev, min_uA, max_uA);
|
||||
if (!ret) {
|
||||
int newstatus;
|
||||
|
||||
newstatus = regulator_is_enabled_regmap(rdev);
|
||||
if (onstatus != newstatus) {
|
||||
/*
|
||||
* HW FIX: spurious led status change detected. Toggle
|
||||
* state as a workaround
|
||||
*/
|
||||
if (onstatus)
|
||||
ret = regulator_enable_regmap(rdev);
|
||||
else
|
||||
ret = regulator_disable_regmap(rdev);
|
||||
|
||||
if (ret)
|
||||
dev_err(rdev_get_dev(rdev),
|
||||
"failed to revert the LED state (%d)\n",
|
||||
ret);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bd7181x_buck12_get_voltage_sel(struct regulator_dev *rdev)
|
||||
{
|
||||
struct bd71815_pmic *pmic = rdev_get_drvdata(rdev);
|
||||
int rid = rdev_get_id(rdev);
|
||||
int ret, regh, regl, val;
|
||||
|
||||
regh = BD71815_REG_BUCK1_VOLT_H + rid * 0x2;
|
||||
regl = BD71815_REG_BUCK1_VOLT_L + rid * 0x2;
|
||||
|
||||
ret = regmap_read(pmic->regmap, regh, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* If we use HW state machine based voltage reg selection - then we
|
||||
* return BD71815_REG_BUCK1_VOLT_H which is used at RUN.
|
||||
* Else we do return the BD71815_REG_BUCK1_VOLT_H or
|
||||
* BD71815_REG_BUCK1_VOLT_L depending on which is selected to be used
|
||||
* by BD71815_BUCK_DVSSEL bit
|
||||
*/
|
||||
if ((!(val & BD71815_BUCK_STBY_DVS)) && (!(val & BD71815_BUCK_DVSSEL)))
|
||||
ret = regmap_read(pmic->regmap, regl, &val);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return val & BD71815_VOLT_MASK;
|
||||
}
|
||||
|
||||
/*
|
||||
* For Buck 1/2.
|
||||
*/
|
||||
static int bd7181x_buck12_set_voltage_sel(struct regulator_dev *rdev,
|
||||
unsigned int sel)
|
||||
{
|
||||
struct bd71815_pmic *pmic = rdev_get_drvdata(rdev);
|
||||
int rid = rdev_get_id(rdev);
|
||||
int ret, val, reg, regh, regl;
|
||||
|
||||
regh = BD71815_REG_BUCK1_VOLT_H + rid*0x2;
|
||||
regl = BD71815_REG_BUCK1_VOLT_L + rid*0x2;
|
||||
|
||||
ret = regmap_read(pmic->regmap, regh, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* If bucks 1 & 2 are controlled by state machine - then the RUN state
|
||||
* voltage is set to BD71815_REG_BUCK1_VOLT_H. Changing SUSPEND/LPSR
|
||||
* voltages at runtime is not supported by this driver.
|
||||
*/
|
||||
if (((val & BD71815_BUCK_STBY_DVS))) {
|
||||
return regmap_update_bits(pmic->regmap, regh, BD71815_VOLT_MASK,
|
||||
sel);
|
||||
}
|
||||
/* Update new voltage to the register which is not selected now */
|
||||
if (val & BD71815_BUCK_DVSSEL)
|
||||
reg = regl;
|
||||
else
|
||||
reg = regh;
|
||||
|
||||
ret = regmap_update_bits(pmic->regmap, reg, BD71815_VOLT_MASK, sel);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Select the other DVS register to be used */
|
||||
return regmap_update_bits(pmic->regmap, regh, BD71815_BUCK_DVSSEL, ~val);
|
||||
}
|
||||
|
||||
static const struct regulator_ops bd7181x_ldo_regulator_ops = {
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.list_voltage = regulator_list_voltage_linear,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
};
|
||||
|
||||
static const struct regulator_ops bd7181x_fixed_regulator_ops = {
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.list_voltage = regulator_list_voltage_linear,
|
||||
};
|
||||
|
||||
static const struct regulator_ops bd7181x_buck_regulator_ops = {
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.list_voltage = regulator_list_voltage_linear,
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.set_voltage_time_sel = regulator_set_voltage_time_sel,
|
||||
};
|
||||
|
||||
static const struct regulator_ops bd7181x_buck12_regulator_ops = {
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.list_voltage = regulator_list_voltage_linear,
|
||||
.set_voltage_sel = bd7181x_buck12_set_voltage_sel,
|
||||
.get_voltage_sel = bd7181x_buck12_get_voltage_sel,
|
||||
.set_voltage_time_sel = regulator_set_voltage_time_sel,
|
||||
.set_ramp_delay = regulator_set_ramp_delay_regmap,
|
||||
};
|
||||
|
||||
static const struct regulator_ops bd7181x_led_regulator_ops = {
|
||||
.enable = regulator_enable_regmap,
|
||||
.disable = regulator_disable_regmap,
|
||||
.is_enabled = regulator_is_enabled_regmap,
|
||||
.set_current_limit = bd7181x_led_set_current_limit,
|
||||
.get_current_limit = regulator_get_current_limit_regmap,
|
||||
};
|
||||
|
||||
#define BD71815_FIXED_REG(_name, _id, ereg, emsk, voltage, _dvs) \
|
||||
[(_id)] = { \
|
||||
.desc = { \
|
||||
.name = #_name, \
|
||||
.of_match = of_match_ptr(#_name), \
|
||||
.regulators_node = of_match_ptr("regulators"), \
|
||||
.n_voltages = 1, \
|
||||
.ops = &bd7181x_fixed_regulator_ops, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.id = (_id), \
|
||||
.owner = THIS_MODULE, \
|
||||
.min_uV = (voltage), \
|
||||
.enable_reg = (ereg), \
|
||||
.enable_mask = (emsk), \
|
||||
.of_parse_cb = set_hw_dvs_levels, \
|
||||
}, \
|
||||
.dvs = (_dvs), \
|
||||
}
|
||||
|
||||
#define BD71815_BUCK_REG(_name, _id, vsel, ereg, min, max, step, _dvs) \
|
||||
[(_id)] = { \
|
||||
.desc = { \
|
||||
.name = #_name, \
|
||||
.of_match = of_match_ptr(#_name), \
|
||||
.regulators_node = of_match_ptr("regulators"), \
|
||||
.n_voltages = ((max) - (min)) / (step) + 1, \
|
||||
.ops = &bd7181x_buck_regulator_ops, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.id = (_id), \
|
||||
.owner = THIS_MODULE, \
|
||||
.min_uV = (min), \
|
||||
.uV_step = (step), \
|
||||
.vsel_reg = (vsel), \
|
||||
.vsel_mask = BD71815_VOLT_MASK, \
|
||||
.enable_reg = (ereg), \
|
||||
.enable_mask = BD71815_BUCK_RUN_ON, \
|
||||
.of_parse_cb = set_hw_dvs_levels, \
|
||||
}, \
|
||||
.dvs = (_dvs), \
|
||||
}
|
||||
|
||||
#define BD71815_BUCK12_REG(_name, _id, vsel, ereg, min, max, step, \
|
||||
_dvs) \
|
||||
[(_id)] = { \
|
||||
.desc = { \
|
||||
.name = #_name, \
|
||||
.of_match = of_match_ptr(#_name), \
|
||||
.regulators_node = of_match_ptr("regulators"), \
|
||||
.n_voltages = ((max) - (min)) / (step) + 1, \
|
||||
.ops = &bd7181x_buck12_regulator_ops, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.id = (_id), \
|
||||
.owner = THIS_MODULE, \
|
||||
.min_uV = (min), \
|
||||
.uV_step = (step), \
|
||||
.vsel_reg = (vsel), \
|
||||
.vsel_mask = 0x3f, \
|
||||
.enable_reg = (ereg), \
|
||||
.enable_mask = 0x04, \
|
||||
.ramp_reg = (ereg), \
|
||||
.ramp_mask = BD71815_BUCK_RAMPRATE_MASK, \
|
||||
.ramp_delay_table = bd7181x_ramp_table, \
|
||||
.n_ramp_values = ARRAY_SIZE(bd7181x_ramp_table),\
|
||||
.of_parse_cb = buck12_set_hw_dvs_levels, \
|
||||
}, \
|
||||
.dvs = (_dvs), \
|
||||
}
|
||||
|
||||
#define BD71815_LED_REG(_name, _id, csel, mask, ereg, emsk, currents) \
|
||||
[(_id)] = { \
|
||||
.desc = { \
|
||||
.name = #_name, \
|
||||
.of_match = of_match_ptr(#_name), \
|
||||
.regulators_node = of_match_ptr("regulators"), \
|
||||
.n_current_limits = ARRAY_SIZE(currents), \
|
||||
.ops = &bd7181x_led_regulator_ops, \
|
||||
.type = REGULATOR_CURRENT, \
|
||||
.id = (_id), \
|
||||
.owner = THIS_MODULE, \
|
||||
.curr_table = currents, \
|
||||
.csel_reg = (csel), \
|
||||
.csel_mask = (mask), \
|
||||
.enable_reg = (ereg), \
|
||||
.enable_mask = (emsk), \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define BD71815_LDO_REG(_name, _id, vsel, ereg, emsk, min, max, step, \
|
||||
_dvs) \
|
||||
[(_id)] = { \
|
||||
.desc = { \
|
||||
.name = #_name, \
|
||||
.of_match = of_match_ptr(#_name), \
|
||||
.regulators_node = of_match_ptr("regulators"), \
|
||||
.n_voltages = ((max) - (min)) / (step) + 1, \
|
||||
.ops = &bd7181x_ldo_regulator_ops, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.id = (_id), \
|
||||
.owner = THIS_MODULE, \
|
||||
.min_uV = (min), \
|
||||
.uV_step = (step), \
|
||||
.vsel_reg = (vsel), \
|
||||
.vsel_mask = BD71815_VOLT_MASK, \
|
||||
.enable_reg = (ereg), \
|
||||
.enable_mask = (emsk), \
|
||||
.of_parse_cb = set_hw_dvs_levels, \
|
||||
}, \
|
||||
.dvs = (_dvs), \
|
||||
}
|
||||
|
||||
static struct bd71815_regulator bd71815_regulators[] = {
|
||||
BD71815_BUCK12_REG(buck1, BD71815_BUCK1, BD71815_REG_BUCK1_VOLT_H,
|
||||
BD71815_REG_BUCK1_MODE, 800000, 2000000, 25000,
|
||||
&buck1_dvs),
|
||||
BD71815_BUCK12_REG(buck2, BD71815_BUCK2, BD71815_REG_BUCK2_VOLT_H,
|
||||
BD71815_REG_BUCK2_MODE, 800000, 2000000, 25000,
|
||||
&buck2_dvs),
|
||||
BD71815_BUCK_REG(buck3, BD71815_BUCK3, BD71815_REG_BUCK3_VOLT,
|
||||
BD71815_REG_BUCK3_MODE, 1200000, 2700000, 50000,
|
||||
&buck3_dvs),
|
||||
BD71815_BUCK_REG(buck4, BD71815_BUCK4, BD71815_REG_BUCK4_VOLT,
|
||||
BD71815_REG_BUCK4_MODE, 1100000, 1850000, 25000,
|
||||
&buck4_dvs),
|
||||
BD71815_BUCK_REG(buck5, BD71815_BUCK5, BD71815_REG_BUCK5_VOLT,
|
||||
BD71815_REG_BUCK5_MODE, 1800000, 3300000, 50000,
|
||||
&buck5_dvs),
|
||||
BD71815_LDO_REG(ldo1, BD71815_LDO1, BD71815_REG_LDO1_VOLT,
|
||||
BD71815_REG_LDO_MODE1, LDO1_RUN_ON, 800000, 3300000,
|
||||
50000, &ldo1_dvs),
|
||||
BD71815_LDO_REG(ldo2, BD71815_LDO2, BD71815_REG_LDO2_VOLT,
|
||||
BD71815_REG_LDO_MODE2, LDO2_RUN_ON, 800000, 3300000,
|
||||
50000, &ldo2_dvs),
|
||||
/*
|
||||
* Let's default LDO3 to be enabled by SW. We can override ops if DT
|
||||
* says LDO3 should be enabled by HW when DCIN is connected.
|
||||
*/
|
||||
BD71815_LDO_REG(ldo3, BD71815_LDO3, BD71815_REG_LDO3_VOLT,
|
||||
BD71815_REG_LDO_MODE2, LDO3_RUN_ON, 800000, 3300000,
|
||||
50000, &ldo3_dvs),
|
||||
BD71815_LDO_REG(ldo4, BD71815_LDO4, BD71815_REG_LDO4_VOLT,
|
||||
BD71815_REG_LDO_MODE3, LDO4_RUN_ON, 800000, 3300000,
|
||||
50000, &ldo4_dvs),
|
||||
BD71815_LDO_REG(ldo5, BD71815_LDO5, BD71815_REG_LDO5_VOLT_H,
|
||||
BD71815_REG_LDO_MODE3, LDO5_RUN_ON, 800000, 3300000,
|
||||
50000, &ldo5_dvs),
|
||||
BD71815_FIXED_REG(ldodvref, BD71815_LDODVREF, BD71815_REG_LDO_MODE4,
|
||||
DVREF_RUN_ON, 3000000, &dvref_dvs),
|
||||
BD71815_FIXED_REG(ldolpsr, BD71815_LDOLPSR, BD71815_REG_LDO_MODE4,
|
||||
LDO_LPSR_RUN_ON, 1800000, &ldolpsr_dvs),
|
||||
BD71815_LED_REG(wled, BD71815_WLED, BD71815_REG_LED_DIMM, LED_DIMM_MASK,
|
||||
BD71815_REG_LED_CTRL, LED_RUN_ON,
|
||||
bd7181x_wled_currents),
|
||||
};
|
||||
|
||||
static int bd7181x_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct bd71815_pmic *pmic;
|
||||
struct regulator_config config = {};
|
||||
int i, ret;
|
||||
struct gpio_desc *ldo4_en;
|
||||
|
||||
pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
|
||||
if (!pmic)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(pmic->descs, bd71815_regulators, sizeof(pmic->descs));
|
||||
|
||||
pmic->dev = &pdev->dev;
|
||||
pmic->regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
||||
if (!pmic->regmap) {
|
||||
dev_err(pmic->dev, "No parent regmap\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
platform_set_drvdata(pdev, pmic);
|
||||
ldo4_en = devm_gpiod_get_from_of_node(&pdev->dev,
|
||||
pdev->dev.parent->of_node,
|
||||
"rohm,vsel-gpios", 0,
|
||||
GPIOD_ASIS, "ldo4-en");
|
||||
|
||||
if (IS_ERR(ldo4_en)) {
|
||||
ret = PTR_ERR(ldo4_en);
|
||||
if (ret != -ENOENT)
|
||||
return ret;
|
||||
ldo4_en = NULL;
|
||||
}
|
||||
|
||||
/* Disable to go to ship-mode */
|
||||
ret = regmap_update_bits(pmic->regmap, BD71815_REG_PWRCTRL,
|
||||
RESTARTEN, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
config.dev = pdev->dev.parent;
|
||||
config.regmap = pmic->regmap;
|
||||
|
||||
for (i = 0; i < BD71815_REGULATOR_CNT; i++) {
|
||||
struct regulator_desc *desc;
|
||||
struct regulator_dev *rdev;
|
||||
|
||||
desc = &pmic->descs[i].desc;
|
||||
if (i == BD71815_LDO4)
|
||||
config.ena_gpiod = ldo4_en;
|
||||
|
||||
config.driver_data = pmic;
|
||||
|
||||
rdev = devm_regulator_register(&pdev->dev, desc, &config);
|
||||
if (IS_ERR(rdev)) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to register %s regulator\n",
|
||||
desc->name);
|
||||
return PTR_ERR(rdev);
|
||||
}
|
||||
config.ena_gpiod = NULL;
|
||||
pmic->rdev[i] = rdev;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id bd7181x_pmic_id[] = {
|
||||
{ "bd71815-pmic", ROHM_CHIP_TYPE_BD71815 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, bd7181x_pmic_id);
|
||||
|
||||
static struct platform_driver bd7181x_regulator = {
|
||||
.driver = {
|
||||
.name = "bd7181x-pmic",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = bd7181x_probe,
|
||||
.id_table = bd7181x_pmic_id,
|
||||
};
|
||||
module_platform_driver(bd7181x_regulator);
|
||||
|
||||
MODULE_AUTHOR("Tony Luo <luofc@embedinfo.com>");
|
||||
MODULE_DESCRIPTION("BD71815 voltage regulator driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:bd7181x-pmic");
|
@ -90,38 +90,7 @@ static const struct linear_range bd71828_ldo_volts[] = {
|
||||
REGULATOR_LINEAR_RANGE(3300000, 0x32, 0x3f, 0),
|
||||
};
|
||||
|
||||
static int bd71828_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
switch (ramp_delay) {
|
||||
case 1 ... 2500:
|
||||
val = 0;
|
||||
break;
|
||||
case 2501 ... 5000:
|
||||
val = 1;
|
||||
break;
|
||||
case 5001 ... 10000:
|
||||
val = 2;
|
||||
break;
|
||||
case 10001 ... 20000:
|
||||
val = 3;
|
||||
break;
|
||||
default:
|
||||
val = 3;
|
||||
dev_err(&rdev->dev,
|
||||
"ramp_delay: %d not supported, setting 20mV/uS",
|
||||
ramp_delay);
|
||||
}
|
||||
|
||||
/*
|
||||
* On BD71828 the ramp delay level control reg is at offset +2 to
|
||||
* enable reg
|
||||
*/
|
||||
return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg + 2,
|
||||
BD71828_MASK_RAMP_DELAY,
|
||||
val << (ffs(BD71828_MASK_RAMP_DELAY) - 1));
|
||||
}
|
||||
static const unsigned int bd71828_ramp_delay[] = { 2500, 5000, 10000, 20000 };
|
||||
|
||||
static int buck_set_hw_dvs_levels(struct device_node *np,
|
||||
const struct regulator_desc *desc,
|
||||
@ -185,7 +154,7 @@ static const struct regulator_ops bd71828_dvs_buck_ops = {
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.set_voltage_time_sel = regulator_set_voltage_time_sel,
|
||||
.set_ramp_delay = bd71828_set_ramp_delay,
|
||||
.set_ramp_delay = regulator_set_ramp_delay_regmap,
|
||||
};
|
||||
|
||||
static const struct regulator_ops bd71828_ldo_ops = {
|
||||
@ -219,6 +188,10 @@ static const struct bd71828_regulator_data bd71828_rdata[] = {
|
||||
.enable_mask = BD71828_MASK_RUN_EN,
|
||||
.vsel_reg = BD71828_REG_BUCK1_VOLT,
|
||||
.vsel_mask = BD71828_MASK_BUCK1267_VOLT,
|
||||
.ramp_delay_table = bd71828_ramp_delay,
|
||||
.n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
|
||||
.ramp_reg = BD71828_REG_BUCK1_MODE,
|
||||
.ramp_mask = BD71828_MASK_RAMP_DELAY,
|
||||
.owner = THIS_MODULE,
|
||||
.of_parse_cb = buck_set_hw_dvs_levels,
|
||||
},
|
||||
@ -261,6 +234,10 @@ static const struct bd71828_regulator_data bd71828_rdata[] = {
|
||||
.enable_mask = BD71828_MASK_RUN_EN,
|
||||
.vsel_reg = BD71828_REG_BUCK2_VOLT,
|
||||
.vsel_mask = BD71828_MASK_BUCK1267_VOLT,
|
||||
.ramp_delay_table = bd71828_ramp_delay,
|
||||
.n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
|
||||
.ramp_reg = BD71828_REG_BUCK2_MODE,
|
||||
.ramp_mask = BD71828_MASK_RAMP_DELAY,
|
||||
.owner = THIS_MODULE,
|
||||
.of_parse_cb = buck_set_hw_dvs_levels,
|
||||
},
|
||||
@ -421,6 +398,10 @@ static const struct bd71828_regulator_data bd71828_rdata[] = {
|
||||
.enable_mask = BD71828_MASK_RUN_EN,
|
||||
.vsel_reg = BD71828_REG_BUCK6_VOLT,
|
||||
.vsel_mask = BD71828_MASK_BUCK1267_VOLT,
|
||||
.ramp_delay_table = bd71828_ramp_delay,
|
||||
.n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
|
||||
.ramp_reg = BD71828_REG_BUCK6_MODE,
|
||||
.ramp_mask = BD71828_MASK_RAMP_DELAY,
|
||||
.owner = THIS_MODULE,
|
||||
.of_parse_cb = buck_set_hw_dvs_levels,
|
||||
},
|
||||
@ -458,6 +439,10 @@ static const struct bd71828_regulator_data bd71828_rdata[] = {
|
||||
.enable_mask = BD71828_MASK_RUN_EN,
|
||||
.vsel_reg = BD71828_REG_BUCK7_VOLT,
|
||||
.vsel_mask = BD71828_MASK_BUCK1267_VOLT,
|
||||
.ramp_delay_table = bd71828_ramp_delay,
|
||||
.n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay),
|
||||
.ramp_reg = BD71828_REG_BUCK7_MODE,
|
||||
.ramp_mask = BD71828_MASK_RAMP_DELAY,
|
||||
.owner = THIS_MODULE,
|
||||
.of_parse_cb = buck_set_hw_dvs_levels,
|
||||
},
|
||||
|
@ -86,37 +86,7 @@ static const struct regulator_ops BD718XX_HWOPNAME(name) = { \
|
||||
* 10: 2.50mV/usec 10mV 4uS
|
||||
* 11: 1.25mV/usec 10mV 8uS
|
||||
*/
|
||||
static int bd718xx_buck1234_set_ramp_delay(struct regulator_dev *rdev,
|
||||
int ramp_delay)
|
||||
{
|
||||
int id = rdev_get_id(rdev);
|
||||
unsigned int ramp_value;
|
||||
|
||||
dev_dbg(&rdev->dev, "Buck[%d] Set Ramp = %d\n", id + 1,
|
||||
ramp_delay);
|
||||
switch (ramp_delay) {
|
||||
case 1 ... 1250:
|
||||
ramp_value = BUCK_RAMPRATE_1P25MV;
|
||||
break;
|
||||
case 1251 ... 2500:
|
||||
ramp_value = BUCK_RAMPRATE_2P50MV;
|
||||
break;
|
||||
case 2501 ... 5000:
|
||||
ramp_value = BUCK_RAMPRATE_5P00MV;
|
||||
break;
|
||||
case 5001 ... 10000:
|
||||
ramp_value = BUCK_RAMPRATE_10P00MV;
|
||||
break;
|
||||
default:
|
||||
ramp_value = BUCK_RAMPRATE_10P00MV;
|
||||
dev_err(&rdev->dev,
|
||||
"%s: ramp_delay: %d not supported, setting 10000mV//us\n",
|
||||
rdev->desc->name, ramp_delay);
|
||||
}
|
||||
|
||||
return regmap_update_bits(rdev->regmap, BD718XX_REG_BUCK1_CTRL + id,
|
||||
BUCK_RAMPRATE_MASK, ramp_value << 6);
|
||||
}
|
||||
static const unsigned int bd718xx_ramp_delay[] = { 10000, 5000, 2500, 1250 };
|
||||
|
||||
/* These functions are used when regulators are under HW state machine control.
|
||||
* We assume PMIC is in RUN state because SW running and able to query the
|
||||
@ -378,7 +348,7 @@ static const struct regulator_ops bd71837_buck34_ops_hwctrl = {
|
||||
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
||||
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
||||
.set_voltage_time_sel = regulator_set_voltage_time_sel,
|
||||
.set_ramp_delay = bd718xx_buck1234_set_ramp_delay,
|
||||
.set_ramp_delay = regulator_set_ramp_delay_regmap,
|
||||
};
|
||||
|
||||
/*
|
||||
@ -387,7 +357,7 @@ static const struct regulator_ops bd71837_buck34_ops_hwctrl = {
|
||||
BD718XX_OPS(bd718xx_dvs_buck_regulator_ops, regulator_list_voltage_linear_range,
|
||||
NULL, regulator_set_voltage_sel_regmap,
|
||||
regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel,
|
||||
bd718xx_buck1234_set_ramp_delay);
|
||||
/* bd718xx_buck1234_set_ramp_delay */ regulator_set_ramp_delay_regmap);
|
||||
|
||||
/*
|
||||
* BD71837 BUCK1/2/3/4
|
||||
@ -645,6 +615,10 @@ static struct bd718xx_regulator_data bd71847_regulators[] = {
|
||||
.enable_mask = BD718XX_BUCK_EN,
|
||||
.enable_time = BD71847_BUCK1_STARTUP_TIME,
|
||||
.owner = THIS_MODULE,
|
||||
.ramp_delay_table = bd718xx_ramp_delay,
|
||||
.n_ramp_values = ARRAY_SIZE(bd718xx_ramp_delay),
|
||||
.ramp_reg = BD718XX_REG_BUCK1_CTRL,
|
||||
.ramp_mask = BUCK_RAMPRATE_MASK,
|
||||
.of_parse_cb = buck_set_hw_dvs_levels,
|
||||
},
|
||||
.dvs = {
|
||||
@ -678,6 +652,10 @@ static struct bd718xx_regulator_data bd71847_regulators[] = {
|
||||
.enable_reg = BD718XX_REG_BUCK2_CTRL,
|
||||
.enable_mask = BD718XX_BUCK_EN,
|
||||
.enable_time = BD71847_BUCK2_STARTUP_TIME,
|
||||
.ramp_delay_table = bd718xx_ramp_delay,
|
||||
.n_ramp_values = ARRAY_SIZE(bd718xx_ramp_delay),
|
||||
.ramp_reg = BD718XX_REG_BUCK2_CTRL,
|
||||
.ramp_mask = BUCK_RAMPRATE_MASK,
|
||||
.owner = THIS_MODULE,
|
||||
.of_parse_cb = buck_set_hw_dvs_levels,
|
||||
},
|
||||
@ -985,6 +963,10 @@ static struct bd718xx_regulator_data bd71837_regulators[] = {
|
||||
.enable_reg = BD718XX_REG_BUCK1_CTRL,
|
||||
.enable_mask = BD718XX_BUCK_EN,
|
||||
.enable_time = BD71837_BUCK1_STARTUP_TIME,
|
||||
.ramp_delay_table = bd718xx_ramp_delay,
|
||||
.n_ramp_values = ARRAY_SIZE(bd718xx_ramp_delay),
|
||||
.ramp_reg = BD718XX_REG_BUCK1_CTRL,
|
||||
.ramp_mask = BUCK_RAMPRATE_MASK,
|
||||
.owner = THIS_MODULE,
|
||||
.of_parse_cb = buck_set_hw_dvs_levels,
|
||||
},
|
||||
@ -1019,6 +1001,10 @@ static struct bd718xx_regulator_data bd71837_regulators[] = {
|
||||
.enable_reg = BD718XX_REG_BUCK2_CTRL,
|
||||
.enable_mask = BD718XX_BUCK_EN,
|
||||
.enable_time = BD71837_BUCK2_STARTUP_TIME,
|
||||
.ramp_delay_table = bd718xx_ramp_delay,
|
||||
.n_ramp_values = ARRAY_SIZE(bd718xx_ramp_delay),
|
||||
.ramp_reg = BD718XX_REG_BUCK2_CTRL,
|
||||
.ramp_mask = BUCK_RAMPRATE_MASK,
|
||||
.owner = THIS_MODULE,
|
||||
.of_parse_cb = buck_set_hw_dvs_levels,
|
||||
},
|
||||
@ -1050,6 +1036,10 @@ static struct bd718xx_regulator_data bd71837_regulators[] = {
|
||||
.enable_reg = BD71837_REG_BUCK3_CTRL,
|
||||
.enable_mask = BD718XX_BUCK_EN,
|
||||
.enable_time = BD71837_BUCK3_STARTUP_TIME,
|
||||
.ramp_delay_table = bd718xx_ramp_delay,
|
||||
.n_ramp_values = ARRAY_SIZE(bd718xx_ramp_delay),
|
||||
.ramp_reg = BD71837_REG_BUCK3_CTRL,
|
||||
.ramp_mask = BUCK_RAMPRATE_MASK,
|
||||
.owner = THIS_MODULE,
|
||||
.of_parse_cb = buck_set_hw_dvs_levels,
|
||||
},
|
||||
@ -1079,6 +1069,10 @@ static struct bd718xx_regulator_data bd71837_regulators[] = {
|
||||
.enable_reg = BD71837_REG_BUCK4_CTRL,
|
||||
.enable_mask = BD718XX_BUCK_EN,
|
||||
.enable_time = BD71837_BUCK4_STARTUP_TIME,
|
||||
.ramp_delay_table = bd718xx_ramp_delay,
|
||||
.n_ramp_values = ARRAY_SIZE(bd718xx_ramp_delay),
|
||||
.ramp_reg = BD71837_REG_BUCK4_CTRL,
|
||||
.ramp_mask = BUCK_RAMPRATE_MASK,
|
||||
.owner = THIS_MODULE,
|
||||
.of_parse_cb = buck_set_hw_dvs_levels,
|
||||
},
|
||||
|
@ -22,13 +22,26 @@ static int set_dvs_level(const struct regulator_desc *desc,
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If voltage is set to 0 => disable */
|
||||
if (uv == 0) {
|
||||
if (omask)
|
||||
return regmap_update_bits(regmap, oreg, omask, 0);
|
||||
}
|
||||
/* Some setups don't allow setting own voltage but do allow enabling */
|
||||
if (!mask) {
|
||||
if (omask)
|
||||
return regmap_update_bits(regmap, oreg, omask, omask);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
for (i = 0; i < desc->n_voltages; i++) {
|
||||
ret = regulator_desc_list_voltage_linear_range(desc, i);
|
||||
/* NOTE to next hacker - Does not support pickable ranges */
|
||||
if (desc->linear_range_selectors)
|
||||
return -EINVAL;
|
||||
if (desc->n_linear_ranges)
|
||||
ret = regulator_desc_list_voltage_linear_range(desc, i);
|
||||
else
|
||||
ret = regulator_desc_list_voltage_linear(desc, i);
|
||||
if (ret < 0)
|
||||
continue;
|
||||
if (ret == uv) {
|
||||
@ -82,6 +95,12 @@ int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs,
|
||||
mask = dvs->lpsr_mask;
|
||||
omask = dvs->lpsr_on_mask;
|
||||
break;
|
||||
case ROHM_DVS_LEVEL_SNVS:
|
||||
prop = "rohm,dvs-snvs-voltage";
|
||||
reg = dvs->snvs_reg;
|
||||
mask = dvs->snvs_mask;
|
||||
omask = dvs->snvs_on_mask;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -501,11 +501,11 @@ config RTC_DRV_M41T80_WDT
|
||||
watchdog timer in the ST M41T60 and M41T80 RTC chips series.
|
||||
|
||||
config RTC_DRV_BD70528
|
||||
tristate "ROHM BD70528 PMIC RTC"
|
||||
depends on MFD_ROHM_BD70528 && (BD70528_WATCHDOG || !BD70528_WATCHDOG)
|
||||
tristate "ROHM BD70528, BD71815 and BD71828 PMIC RTC"
|
||||
depends on MFD_ROHM_BD71828 || MFD_ROHM_BD70528 && (BD70528_WATCHDOG || !BD70528_WATCHDOG)
|
||||
help
|
||||
If you say Y here you will get support for the RTC
|
||||
block on ROHM BD70528 and BD71828 Power Management IC.
|
||||
block on ROHM BD70528, BD71815 and BD71828 Power Management IC.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-bd70528.
|
||||
@ -1296,6 +1296,14 @@ config RTC_DRV_CROS_EC
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-cros-ec.
|
||||
|
||||
config RTC_DRV_NTXEC
|
||||
tristate "Netronix embedded controller RTC"
|
||||
depends on MFD_NTXEC
|
||||
help
|
||||
Say yes here if you want to support the RTC functionality of the
|
||||
embedded controller found in certain e-book readers designed by the
|
||||
original design manufacturer Netronix.
|
||||
|
||||
comment "on-CPU RTC drivers"
|
||||
|
||||
config RTC_DRV_ASM9260
|
||||
|
@ -108,6 +108,7 @@ obj-$(CONFIG_RTC_DRV_MT7622) += rtc-mt7622.o
|
||||
obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o
|
||||
obj-$(CONFIG_RTC_DRV_MXC) += rtc-mxc.o
|
||||
obj-$(CONFIG_RTC_DRV_MXC_V2) += rtc-mxc_v2.o
|
||||
obj-$(CONFIG_RTC_DRV_NTXEC) += rtc-ntxec.o
|
||||
obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
|
||||
obj-$(CONFIG_RTC_DRV_OPAL) += rtc-opal.o
|
||||
obj-$(CONFIG_RTC_DRV_PALMAS) += rtc-palmas.o
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/mfd/rohm-bd70528.h>
|
||||
#include <linux/mfd/rohm-bd71815.h>
|
||||
#include <linux/mfd/rohm-bd71828.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
@ -13,6 +14,12 @@
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/rtc.h>
|
||||
|
||||
/*
|
||||
* On BD71828 and BD71815 the ALM0 MASK is 14 bytes after the ALM0
|
||||
* block start
|
||||
*/
|
||||
#define BD718XX_ALM_EN_OFFSET 14
|
||||
|
||||
/*
|
||||
* We read regs RTC_SEC => RTC_YEAR
|
||||
* this struct is ordered according to chip registers.
|
||||
@ -52,8 +59,10 @@ struct bd70528_rtc_alm {
|
||||
|
||||
struct bd70528_rtc {
|
||||
struct rohm_regmap_dev *parent;
|
||||
struct regmap *regmap;
|
||||
struct device *dev;
|
||||
u8 reg_time_start;
|
||||
u8 bd718xx_alm_block_start;
|
||||
bool has_rtc_timers;
|
||||
};
|
||||
|
||||
@ -234,10 +243,9 @@ static int bd71828_set_alarm(struct device *dev, struct rtc_wkalrm *a)
|
||||
int ret;
|
||||
struct bd71828_rtc_alm alm;
|
||||
struct bd70528_rtc *r = dev_get_drvdata(dev);
|
||||
struct rohm_regmap_dev *parent = r->parent;
|
||||
|
||||
ret = regmap_bulk_read(parent->regmap, BD71828_REG_RTC_ALM_START,
|
||||
&alm, sizeof(alm));
|
||||
ret = regmap_bulk_read(r->regmap, r->bd718xx_alm_block_start, &alm,
|
||||
sizeof(alm));
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to read alarm regs\n");
|
||||
return ret;
|
||||
@ -250,8 +258,8 @@ static int bd71828_set_alarm(struct device *dev, struct rtc_wkalrm *a)
|
||||
else
|
||||
alm.alm_mask |= BD70528_MASK_ALM_EN;
|
||||
|
||||
ret = regmap_bulk_write(parent->regmap, BD71828_REG_RTC_ALM_START,
|
||||
&alm, sizeof(alm));
|
||||
ret = regmap_bulk_write(r->regmap, r->bd718xx_alm_block_start, &alm,
|
||||
sizeof(alm));
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to set alarm time\n");
|
||||
|
||||
@ -265,17 +273,16 @@ static int bd70528_set_alarm(struct device *dev, struct rtc_wkalrm *a)
|
||||
struct bd70528_rtc_alm alm;
|
||||
int ret;
|
||||
struct bd70528_rtc *r = dev_get_drvdata(dev);
|
||||
struct rohm_regmap_dev *parent = r->parent;
|
||||
|
||||
ret = regmap_bulk_read(parent->regmap, BD70528_REG_RTC_WAKE_START,
|
||||
&wake, sizeof(wake));
|
||||
ret = regmap_bulk_read(r->regmap, BD70528_REG_RTC_WAKE_START, &wake,
|
||||
sizeof(wake));
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to read wake regs\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_bulk_read(parent->regmap, BD70528_REG_RTC_ALM_START,
|
||||
&alm, sizeof(alm));
|
||||
ret = regmap_bulk_read(r->regmap, BD70528_REG_RTC_ALM_START, &alm,
|
||||
sizeof(alm));
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to read alarm regs\n");
|
||||
return ret;
|
||||
@ -292,15 +299,14 @@ static int bd70528_set_alarm(struct device *dev, struct rtc_wkalrm *a)
|
||||
wake.ctrl &= ~BD70528_MASK_WAKE_EN;
|
||||
}
|
||||
|
||||
ret = regmap_bulk_write(parent->regmap,
|
||||
BD70528_REG_RTC_WAKE_START, &wake,
|
||||
ret = regmap_bulk_write(r->regmap, BD70528_REG_RTC_WAKE_START, &wake,
|
||||
sizeof(wake));
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to set wake time\n");
|
||||
return ret;
|
||||
}
|
||||
ret = regmap_bulk_write(parent->regmap, BD70528_REG_RTC_ALM_START,
|
||||
&alm, sizeof(alm));
|
||||
ret = regmap_bulk_write(r->regmap, BD70528_REG_RTC_ALM_START, &alm,
|
||||
sizeof(alm));
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to set alarm time\n");
|
||||
|
||||
@ -312,10 +318,9 @@ static int bd71828_read_alarm(struct device *dev, struct rtc_wkalrm *a)
|
||||
int ret;
|
||||
struct bd71828_rtc_alm alm;
|
||||
struct bd70528_rtc *r = dev_get_drvdata(dev);
|
||||
struct rohm_regmap_dev *parent = r->parent;
|
||||
|
||||
ret = regmap_bulk_read(parent->regmap, BD71828_REG_RTC_ALM_START,
|
||||
&alm, sizeof(alm));
|
||||
ret = regmap_bulk_read(r->regmap, r->bd718xx_alm_block_start, &alm,
|
||||
sizeof(alm));
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to read alarm regs\n");
|
||||
return ret;
|
||||
@ -336,10 +341,9 @@ static int bd70528_read_alarm(struct device *dev, struct rtc_wkalrm *a)
|
||||
struct bd70528_rtc_alm alm;
|
||||
int ret;
|
||||
struct bd70528_rtc *r = dev_get_drvdata(dev);
|
||||
struct rohm_regmap_dev *parent = r->parent;
|
||||
|
||||
ret = regmap_bulk_read(parent->regmap, BD70528_REG_RTC_ALM_START,
|
||||
&alm, sizeof(alm));
|
||||
ret = regmap_bulk_read(r->regmap, BD70528_REG_RTC_ALM_START, &alm,
|
||||
sizeof(alm));
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to read alarm regs\n");
|
||||
return ret;
|
||||
@ -360,14 +364,12 @@ static int bd70528_set_time_locked(struct device *dev, struct rtc_time *t)
|
||||
int ret, tmpret, old_states;
|
||||
struct bd70528_rtc_data rtc_data;
|
||||
struct bd70528_rtc *r = dev_get_drvdata(dev);
|
||||
struct rohm_regmap_dev *parent = r->parent;
|
||||
|
||||
ret = bd70528_disable_rtc_based_timers(r, &old_states);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tmpret = regmap_bulk_read(parent->regmap,
|
||||
r->reg_time_start, &rtc_data,
|
||||
tmpret = regmap_bulk_read(r->regmap, r->reg_time_start, &rtc_data,
|
||||
sizeof(rtc_data));
|
||||
if (tmpret) {
|
||||
dev_err(dev, "Failed to read RTC time registers\n");
|
||||
@ -375,8 +377,7 @@ static int bd70528_set_time_locked(struct device *dev, struct rtc_time *t)
|
||||
}
|
||||
tm2rtc(t, &rtc_data);
|
||||
|
||||
tmpret = regmap_bulk_write(parent->regmap,
|
||||
r->reg_time_start, &rtc_data,
|
||||
tmpret = regmap_bulk_write(r->regmap, r->reg_time_start, &rtc_data,
|
||||
sizeof(rtc_data));
|
||||
if (tmpret) {
|
||||
dev_err(dev, "Failed to set RTC time\n");
|
||||
@ -410,13 +411,11 @@ static int bd70528_set_time(struct device *dev, struct rtc_time *t)
|
||||
static int bd70528_get_time(struct device *dev, struct rtc_time *t)
|
||||
{
|
||||
struct bd70528_rtc *r = dev_get_drvdata(dev);
|
||||
struct rohm_regmap_dev *parent = r->parent;
|
||||
struct bd70528_rtc_data rtc_data;
|
||||
int ret;
|
||||
|
||||
/* read the RTC date and time registers all at once */
|
||||
ret = regmap_bulk_read(parent->regmap,
|
||||
r->reg_time_start, &rtc_data,
|
||||
ret = regmap_bulk_read(r->regmap, r->reg_time_start, &rtc_data,
|
||||
sizeof(rtc_data));
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to read RTC time (err %d)\n", ret);
|
||||
@ -443,7 +442,7 @@ static int bd70528_alm_enable(struct device *dev, unsigned int enabled)
|
||||
dev_err(dev, "Failed to change wake state\n");
|
||||
goto out_unlock;
|
||||
}
|
||||
ret = regmap_update_bits(r->parent->regmap, BD70528_REG_RTC_ALM_MASK,
|
||||
ret = regmap_update_bits(r->regmap, BD70528_REG_RTC_ALM_MASK,
|
||||
BD70528_MASK_ALM_EN, enableval);
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to change alarm state\n");
|
||||
@ -462,8 +461,9 @@ static int bd71828_alm_enable(struct device *dev, unsigned int enabled)
|
||||
if (!enabled)
|
||||
enableval = 0;
|
||||
|
||||
ret = regmap_update_bits(r->parent->regmap, BD71828_REG_RTC_ALM0_MASK,
|
||||
BD70528_MASK_ALM_EN, enableval);
|
||||
ret = regmap_update_bits(r->regmap, r->bd718xx_alm_block_start +
|
||||
BD718XX_ALM_EN_OFFSET, BD70528_MASK_ALM_EN,
|
||||
enableval);
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to change alarm state\n");
|
||||
|
||||
@ -498,7 +498,6 @@ static int bd70528_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct bd70528_rtc *bd_rtc;
|
||||
const struct rtc_class_ops *rtc_ops;
|
||||
struct rohm_regmap_dev *parent;
|
||||
const char *irq_name;
|
||||
int ret;
|
||||
struct rtc_device *rtc;
|
||||
@ -508,20 +507,25 @@ static int bd70528_probe(struct platform_device *pdev)
|
||||
u8 hour_reg;
|
||||
enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data;
|
||||
|
||||
parent = dev_get_drvdata(pdev->dev.parent);
|
||||
if (!parent) {
|
||||
dev_err(&pdev->dev, "No MFD driver data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
bd_rtc = devm_kzalloc(&pdev->dev, sizeof(*bd_rtc), GFP_KERNEL);
|
||||
if (!bd_rtc)
|
||||
return -ENOMEM;
|
||||
|
||||
bd_rtc->parent = parent;
|
||||
bd_rtc->regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
||||
if (!bd_rtc->regmap) {
|
||||
dev_err(&pdev->dev, "No regmap\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bd_rtc->dev = &pdev->dev;
|
||||
|
||||
switch (chip) {
|
||||
case ROHM_CHIP_TYPE_BD70528:
|
||||
bd_rtc->parent = dev_get_drvdata(pdev->dev.parent);
|
||||
if (!bd_rtc->parent) {
|
||||
dev_err(&pdev->dev, "No MFD data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
irq_name = "bd70528-rtc-alm";
|
||||
bd_rtc->has_rtc_timers = true;
|
||||
bd_rtc->reg_time_start = BD70528_REG_RTC_START;
|
||||
@ -529,9 +533,28 @@ static int bd70528_probe(struct platform_device *pdev)
|
||||
enable_main_irq = true;
|
||||
rtc_ops = &bd70528_rtc_ops;
|
||||
break;
|
||||
case ROHM_CHIP_TYPE_BD71815:
|
||||
irq_name = "bd71815-rtc-alm-0";
|
||||
bd_rtc->reg_time_start = BD71815_REG_RTC_START;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
bd_rtc->bd718xx_alm_block_start = BD71815_REG_RTC_ALM_START;
|
||||
hour_reg = BD71815_REG_HOUR;
|
||||
rtc_ops = &bd71828_rtc_ops;
|
||||
break;
|
||||
case ROHM_CHIP_TYPE_BD71828:
|
||||
irq_name = "bd71828-rtc-alm-0";
|
||||
bd_rtc->reg_time_start = BD71828_REG_RTC_START;
|
||||
bd_rtc->bd718xx_alm_block_start = BD71828_REG_RTC_ALM_START;
|
||||
hour_reg = BD71828_REG_RTC_HOUR;
|
||||
rtc_ops = &bd71828_rtc_ops;
|
||||
break;
|
||||
@ -547,7 +570,7 @@ static int bd70528_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, bd_rtc);
|
||||
|
||||
ret = regmap_read(parent->regmap, hour_reg, &hr);
|
||||
ret = regmap_read(bd_rtc->regmap, hour_reg, &hr);
|
||||
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to reag RTC clock\n");
|
||||
@ -595,7 +618,7 @@ static int bd70528_probe(struct platform_device *pdev)
|
||||
* from sub-registers when IRQ is disabled or freed.
|
||||
*/
|
||||
if (enable_main_irq) {
|
||||
ret = regmap_update_bits(parent->regmap,
|
||||
ret = regmap_update_bits(bd_rtc->regmap,
|
||||
BD70528_REG_INT_MAIN_MASK,
|
||||
BD70528_INT_RTC_MASK, 0);
|
||||
if (ret) {
|
||||
@ -610,6 +633,7 @@ static int bd70528_probe(struct platform_device *pdev)
|
||||
static const struct platform_device_id bd718x7_rtc_id[] = {
|
||||
{ "bd70528-rtc", ROHM_CHIP_TYPE_BD70528 },
|
||||
{ "bd71828-rtc", ROHM_CHIP_TYPE_BD71828 },
|
||||
{ "bd71815-rtc", ROHM_CHIP_TYPE_BD71815 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, bd718x7_rtc_id);
|
||||
|
145
drivers/rtc/rtc-ntxec.c
Normal file
145
drivers/rtc/rtc-ntxec.c
Normal file
@ -0,0 +1,145 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* The Netronix embedded controller is a microcontroller found in some
|
||||
* e-book readers designed by the original design manufacturer Netronix, Inc.
|
||||
* It contains RTC, battery monitoring, system power management, and PWM
|
||||
* functionality.
|
||||
*
|
||||
* This driver implements access to the RTC time and date.
|
||||
*
|
||||
* Copyright 2020 Jonathan Neuschäfer <j.neuschaefer@gmx.net>
|
||||
*/
|
||||
|
||||
#include <linux/mfd/ntxec.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct ntxec_rtc {
|
||||
struct device *dev;
|
||||
struct ntxec *ec;
|
||||
};
|
||||
|
||||
#define NTXEC_REG_WRITE_YEAR 0x10
|
||||
#define NTXEC_REG_WRITE_MONTH 0x11
|
||||
#define NTXEC_REG_WRITE_DAY 0x12
|
||||
#define NTXEC_REG_WRITE_HOUR 0x13
|
||||
#define NTXEC_REG_WRITE_MINUTE 0x14
|
||||
#define NTXEC_REG_WRITE_SECOND 0x15
|
||||
|
||||
#define NTXEC_REG_READ_YEAR_MONTH 0x20
|
||||
#define NTXEC_REG_READ_MDAY_HOUR 0x21
|
||||
#define NTXEC_REG_READ_MINUTE_SECOND 0x23
|
||||
|
||||
static int ntxec_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct ntxec_rtc *rtc = dev_get_drvdata(dev);
|
||||
unsigned int value;
|
||||
int res;
|
||||
|
||||
retry:
|
||||
res = regmap_read(rtc->ec->regmap, NTXEC_REG_READ_MINUTE_SECOND, &value);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
tm->tm_min = value >> 8;
|
||||
tm->tm_sec = value & 0xff;
|
||||
|
||||
res = regmap_read(rtc->ec->regmap, NTXEC_REG_READ_MDAY_HOUR, &value);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
tm->tm_mday = value >> 8;
|
||||
tm->tm_hour = value & 0xff;
|
||||
|
||||
res = regmap_read(rtc->ec->regmap, NTXEC_REG_READ_YEAR_MONTH, &value);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
tm->tm_year = (value >> 8) + 100;
|
||||
tm->tm_mon = (value & 0xff) - 1;
|
||||
|
||||
/*
|
||||
* Read the minutes/seconds field again. If it changed since the first
|
||||
* read, we can't assume that the values read so far are consistent,
|
||||
* and should start from the beginning.
|
||||
*/
|
||||
res = regmap_read(rtc->ec->regmap, NTXEC_REG_READ_MINUTE_SECOND, &value);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
if (tm->tm_min != value >> 8 || tm->tm_sec != (value & 0xff))
|
||||
goto retry;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ntxec_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct ntxec_rtc *rtc = dev_get_drvdata(dev);
|
||||
|
||||
/*
|
||||
* To avoid time overflows while we're writing the full date/time,
|
||||
* set the seconds field to zero before doing anything else. For the
|
||||
* next 59 seconds (plus however long it takes until the RTC's next
|
||||
* update of the second field), the seconds field will not overflow
|
||||
* into the other fields.
|
||||
*/
|
||||
struct reg_sequence regs[] = {
|
||||
{ NTXEC_REG_WRITE_SECOND, ntxec_reg8(0) },
|
||||
{ NTXEC_REG_WRITE_YEAR, ntxec_reg8(tm->tm_year - 100) },
|
||||
{ NTXEC_REG_WRITE_MONTH, ntxec_reg8(tm->tm_mon + 1) },
|
||||
{ NTXEC_REG_WRITE_DAY, ntxec_reg8(tm->tm_mday) },
|
||||
{ NTXEC_REG_WRITE_HOUR, ntxec_reg8(tm->tm_hour) },
|
||||
{ NTXEC_REG_WRITE_MINUTE, ntxec_reg8(tm->tm_min) },
|
||||
{ NTXEC_REG_WRITE_SECOND, ntxec_reg8(tm->tm_sec) },
|
||||
};
|
||||
|
||||
return regmap_multi_reg_write(rtc->ec->regmap, regs, ARRAY_SIZE(regs));
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops ntxec_rtc_ops = {
|
||||
.read_time = ntxec_read_time,
|
||||
.set_time = ntxec_set_time,
|
||||
};
|
||||
|
||||
static int ntxec_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rtc_device *dev;
|
||||
struct ntxec_rtc *rtc;
|
||||
|
||||
pdev->dev.of_node = pdev->dev.parent->of_node;
|
||||
|
||||
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
|
||||
if (!rtc)
|
||||
return -ENOMEM;
|
||||
|
||||
rtc->dev = &pdev->dev;
|
||||
rtc->ec = dev_get_drvdata(pdev->dev.parent);
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
dev = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(dev))
|
||||
return PTR_ERR(dev);
|
||||
|
||||
dev->ops = &ntxec_rtc_ops;
|
||||
dev->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
dev->range_max = 9025257599LL; /* 2255-12-31 23:59:59 */
|
||||
|
||||
return devm_rtc_register_device(dev);
|
||||
}
|
||||
|
||||
static struct platform_driver ntxec_rtc_driver = {
|
||||
.driver = {
|
||||
.name = "ntxec-rtc",
|
||||
},
|
||||
.probe = ntxec_rtc_probe,
|
||||
};
|
||||
module_platform_driver(ntxec_rtc_driver);
|
||||
|
||||
MODULE_AUTHOR("Jonathan Neuschäfer <j.neuschaefer@gmx.net>");
|
||||
MODULE_DESCRIPTION("RTC driver for Netronix EC");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:ntxec-rtc");
|
@ -172,6 +172,19 @@ config BD70528_WATCHDOG
|
||||
Alternatively say M to compile the driver as a module,
|
||||
which will be called bd70528_wdt.
|
||||
|
||||
config BD957XMUF_WATCHDOG
|
||||
tristate "ROHM BD9576MUF and BD9573MUF PMIC Watchdog"
|
||||
depends on MFD_ROHM_BD957XMUF
|
||||
select WATCHDOG_CORE
|
||||
help
|
||||
Support for the watchdog in the ROHM BD9576 and BD9573 PMICs.
|
||||
These PMIC ICs contain watchdog block which can be configured
|
||||
to toggle reset line if SoC fails to ping watchdog via GPIO.
|
||||
|
||||
Say Y here to include support for the ROHM BD9576 or BD9573
|
||||
watchdog. Alternatively say M to compile the driver as a module,
|
||||
which will be called bd9576_wdt.
|
||||
|
||||
config DA9052_WATCHDOG
|
||||
tristate "Dialog DA9052 Watchdog"
|
||||
depends on PMIC_DA9052 || COMPILE_TEST
|
||||
|
@ -204,6 +204,7 @@ obj-$(CONFIG_XEN_WDT) += xen_wdt.o
|
||||
|
||||
# Architecture Independent
|
||||
obj-$(CONFIG_BD70528_WATCHDOG) += bd70528_wdt.o
|
||||
obj-$(CONFIG_BD957XMUF_WATCHDOG) += bd9576_wdt.o
|
||||
obj-$(CONFIG_DA9052_WATCHDOG) += da9052_wdt.o
|
||||
obj-$(CONFIG_DA9055_WATCHDOG) += da9055_wdt.o
|
||||
obj-$(CONFIG_DA9062_WATCHDOG) += da9062_wdt.o
|
||||
|
291
drivers/watchdog/bd9576_wdt.c
Normal file
291
drivers/watchdog/bd9576_wdt.c
Normal file
@ -0,0 +1,291 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2020 ROHM Semiconductors
|
||||
*
|
||||
* ROHM BD9576MUF and BD9573MUF Watchdog driver
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/mfd/rohm-bd957x.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/watchdog.h>
|
||||
|
||||
static bool nowayout;
|
||||
module_param(nowayout, bool, 0);
|
||||
MODULE_PARM_DESC(nowayout,
|
||||
"Watchdog cannot be stopped once started (default=\"false\")");
|
||||
|
||||
#define HW_MARGIN_MIN 2
|
||||
#define HW_MARGIN_MAX 4416
|
||||
#define BD957X_WDT_DEFAULT_MARGIN 4416
|
||||
#define WATCHDOG_TIMEOUT 30
|
||||
|
||||
struct bd9576_wdt_priv {
|
||||
struct gpio_desc *gpiod_ping;
|
||||
struct gpio_desc *gpiod_en;
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
bool always_running;
|
||||
struct watchdog_device wdd;
|
||||
};
|
||||
|
||||
static void bd9576_wdt_disable(struct bd9576_wdt_priv *priv)
|
||||
{
|
||||
gpiod_set_value_cansleep(priv->gpiod_en, 0);
|
||||
}
|
||||
|
||||
static int bd9576_wdt_ping(struct watchdog_device *wdd)
|
||||
{
|
||||
struct bd9576_wdt_priv *priv = watchdog_get_drvdata(wdd);
|
||||
|
||||
/* Pulse */
|
||||
gpiod_set_value_cansleep(priv->gpiod_ping, 1);
|
||||
gpiod_set_value_cansleep(priv->gpiod_ping, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bd9576_wdt_start(struct watchdog_device *wdd)
|
||||
{
|
||||
struct bd9576_wdt_priv *priv = watchdog_get_drvdata(wdd);
|
||||
|
||||
gpiod_set_value_cansleep(priv->gpiod_en, 1);
|
||||
|
||||
return bd9576_wdt_ping(wdd);
|
||||
}
|
||||
|
||||
static int bd9576_wdt_stop(struct watchdog_device *wdd)
|
||||
{
|
||||
struct bd9576_wdt_priv *priv = watchdog_get_drvdata(wdd);
|
||||
|
||||
if (!priv->always_running)
|
||||
bd9576_wdt_disable(priv);
|
||||
else
|
||||
set_bit(WDOG_HW_RUNNING, &wdd->status);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct watchdog_info bd957x_wdt_ident = {
|
||||
.options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING |
|
||||
WDIOF_SETTIMEOUT,
|
||||
.identity = "BD957x Watchdog",
|
||||
};
|
||||
|
||||
static const struct watchdog_ops bd957x_wdt_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.start = bd9576_wdt_start,
|
||||
.stop = bd9576_wdt_stop,
|
||||
.ping = bd9576_wdt_ping,
|
||||
};
|
||||
|
||||
/* Unit is hundreds of uS */
|
||||
#define FASTNG_MIN 23
|
||||
|
||||
static int find_closest_fast(int target, int *sel, int *val)
|
||||
{
|
||||
int i;
|
||||
int window = FASTNG_MIN;
|
||||
|
||||
for (i = 0; i < 8 && window < target; i++)
|
||||
window <<= 1;
|
||||
|
||||
*val = window;
|
||||
*sel = i;
|
||||
|
||||
if (i == 8)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int find_closest_slow_by_fast(int fast_val, int target, int *slowsel)
|
||||
{
|
||||
int sel;
|
||||
static const int multipliers[] = {2, 3, 7, 15};
|
||||
|
||||
for (sel = 0; sel < ARRAY_SIZE(multipliers) &&
|
||||
multipliers[sel] * fast_val < target; sel++)
|
||||
;
|
||||
|
||||
if (sel == ARRAY_SIZE(multipliers))
|
||||
return -EINVAL;
|
||||
|
||||
*slowsel = sel;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int find_closest_slow(int target, int *slow_sel, int *fast_sel)
|
||||
{
|
||||
static const int multipliers[] = {2, 3, 7, 15};
|
||||
int i, j;
|
||||
int val = 0;
|
||||
int window = FASTNG_MIN;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
for (j = 0; j < ARRAY_SIZE(multipliers); j++) {
|
||||
int slow;
|
||||
|
||||
slow = window * multipliers[j];
|
||||
if (slow >= target && (!val || slow < val)) {
|
||||
val = slow;
|
||||
*fast_sel = i;
|
||||
*slow_sel = j;
|
||||
}
|
||||
}
|
||||
window <<= 1;
|
||||
}
|
||||
if (!val)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define BD957X_WDG_TYPE_WINDOW BIT(5)
|
||||
#define BD957X_WDG_TYPE_SLOW 0
|
||||
#define BD957X_WDG_TYPE_MASK BIT(5)
|
||||
#define BD957X_WDG_NG_RATIO_MASK 0x18
|
||||
#define BD957X_WDG_FASTNG_MASK 0x7
|
||||
|
||||
static int bd957x_set_wdt_mode(struct bd9576_wdt_priv *priv, int hw_margin,
|
||||
int hw_margin_min)
|
||||
{
|
||||
int ret, fastng, slowng, type, reg, mask;
|
||||
struct device *dev = priv->dev;
|
||||
|
||||
/* convert to 100uS */
|
||||
hw_margin *= 10;
|
||||
hw_margin_min *= 10;
|
||||
if (hw_margin_min) {
|
||||
int min;
|
||||
|
||||
type = BD957X_WDG_TYPE_WINDOW;
|
||||
dev_dbg(dev, "Setting type WINDOW 0x%x\n", type);
|
||||
ret = find_closest_fast(hw_margin_min, &fastng, &min);
|
||||
if (ret) {
|
||||
dev_err(dev, "bad WDT window for fast timeout\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = find_closest_slow_by_fast(min, hw_margin, &slowng);
|
||||
if (ret) {
|
||||
dev_err(dev, "bad WDT window\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
} else {
|
||||
type = BD957X_WDG_TYPE_SLOW;
|
||||
dev_dbg(dev, "Setting type SLOW 0x%x\n", type);
|
||||
ret = find_closest_slow(hw_margin, &slowng, &fastng);
|
||||
if (ret) {
|
||||
dev_err(dev, "bad WDT window\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
slowng <<= ffs(BD957X_WDG_NG_RATIO_MASK) - 1;
|
||||
reg = type | slowng | fastng;
|
||||
mask = BD957X_WDG_TYPE_MASK | BD957X_WDG_NG_RATIO_MASK |
|
||||
BD957X_WDG_FASTNG_MASK;
|
||||
ret = regmap_update_bits(priv->regmap, BD957X_REG_WDT_CONF,
|
||||
mask, reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bd9576_wdt_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->parent->of_node;
|
||||
struct bd9576_wdt_priv *priv;
|
||||
u32 hw_margin[2];
|
||||
u32 hw_margin_max = BD957X_WDT_DEFAULT_MARGIN, hw_margin_min = 0;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
priv->dev = dev;
|
||||
priv->regmap = dev_get_regmap(dev->parent, NULL);
|
||||
if (!priv->regmap) {
|
||||
dev_err(dev, "No regmap found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
priv->gpiod_en = devm_gpiod_get_from_of_node(dev, dev->parent->of_node,
|
||||
"rohm,watchdog-enable-gpios",
|
||||
0, GPIOD_OUT_LOW,
|
||||
"watchdog-enable");
|
||||
if (IS_ERR(priv->gpiod_en))
|
||||
return dev_err_probe(dev, PTR_ERR(priv->gpiod_en),
|
||||
"getting watchdog-enable GPIO failed\n");
|
||||
|
||||
priv->gpiod_ping = devm_gpiod_get_from_of_node(dev, dev->parent->of_node,
|
||||
"rohm,watchdog-ping-gpios",
|
||||
0, GPIOD_OUT_LOW,
|
||||
"watchdog-ping");
|
||||
if (IS_ERR(priv->gpiod_ping))
|
||||
return dev_err_probe(dev, PTR_ERR(priv->gpiod_ping),
|
||||
"getting watchdog-ping GPIO failed\n");
|
||||
|
||||
ret = of_property_read_variable_u32_array(np, "rohm,hw-timeout-ms",
|
||||
&hw_margin[0], 1, 2);
|
||||
if (ret < 0 && ret != -EINVAL)
|
||||
return ret;
|
||||
|
||||
if (ret == 1)
|
||||
hw_margin_max = hw_margin[0];
|
||||
|
||||
if (ret == 2) {
|
||||
hw_margin_max = hw_margin[1];
|
||||
hw_margin_min = hw_margin[0];
|
||||
}
|
||||
|
||||
ret = bd957x_set_wdt_mode(priv, hw_margin_max, hw_margin_min);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->always_running = of_property_read_bool(np, "always-running");
|
||||
|
||||
watchdog_set_drvdata(&priv->wdd, priv);
|
||||
|
||||
priv->wdd.info = &bd957x_wdt_ident;
|
||||
priv->wdd.ops = &bd957x_wdt_ops;
|
||||
priv->wdd.min_hw_heartbeat_ms = hw_margin_min;
|
||||
priv->wdd.max_hw_heartbeat_ms = hw_margin_max;
|
||||
priv->wdd.parent = dev;
|
||||
priv->wdd.timeout = WATCHDOG_TIMEOUT;
|
||||
|
||||
watchdog_init_timeout(&priv->wdd, 0, dev);
|
||||
watchdog_set_nowayout(&priv->wdd, nowayout);
|
||||
|
||||
watchdog_stop_on_reboot(&priv->wdd);
|
||||
|
||||
if (priv->always_running)
|
||||
bd9576_wdt_start(&priv->wdd);
|
||||
|
||||
return devm_watchdog_register_device(dev, &priv->wdd);
|
||||
}
|
||||
|
||||
static struct platform_driver bd9576_wdt_driver = {
|
||||
.driver = {
|
||||
.name = "bd9576-wdt",
|
||||
},
|
||||
.probe = bd9576_wdt_probe,
|
||||
};
|
||||
|
||||
module_platform_driver(bd9576_wdt_driver);
|
||||
|
||||
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
|
||||
MODULE_DESCRIPTION("ROHM BD9576/BD9573 Watchdog driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:bd9576-wdt");
|
@ -1,128 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2007-2009 ST-Ericsson AB
|
||||
* AB3100 core access functions
|
||||
* Author: Linus Walleij <linus.walleij@stericsson.com>
|
||||
*/
|
||||
|
||||
#include <linux/regulator/machine.h>
|
||||
|
||||
struct device;
|
||||
|
||||
#ifndef MFD_AB3100_H
|
||||
#define MFD_AB3100_H
|
||||
|
||||
|
||||
#define AB3100_P1A 0xc0
|
||||
#define AB3100_P1B 0xc1
|
||||
#define AB3100_P1C 0xc2
|
||||
#define AB3100_P1D 0xc3
|
||||
#define AB3100_P1E 0xc4
|
||||
#define AB3100_P1F 0xc5
|
||||
#define AB3100_P1G 0xc6
|
||||
#define AB3100_R2A 0xc7
|
||||
#define AB3100_R2B 0xc8
|
||||
|
||||
/*
|
||||
* AB3100, EVENTA1, A2 and A3 event register flags
|
||||
* these are catenated into a single 32-bit flag in the code
|
||||
* for event notification broadcasts.
|
||||
*/
|
||||
#define AB3100_EVENTA1_ONSWA (0x01<<16)
|
||||
#define AB3100_EVENTA1_ONSWB (0x02<<16)
|
||||
#define AB3100_EVENTA1_ONSWC (0x04<<16)
|
||||
#define AB3100_EVENTA1_DCIO (0x08<<16)
|
||||
#define AB3100_EVENTA1_OVER_TEMP (0x10<<16)
|
||||
#define AB3100_EVENTA1_SIM_OFF (0x20<<16)
|
||||
#define AB3100_EVENTA1_VBUS (0x40<<16)
|
||||
#define AB3100_EVENTA1_VSET_USB (0x80<<16)
|
||||
|
||||
#define AB3100_EVENTA2_READY_TX (0x01<<8)
|
||||
#define AB3100_EVENTA2_READY_RX (0x02<<8)
|
||||
#define AB3100_EVENTA2_OVERRUN_ERROR (0x04<<8)
|
||||
#define AB3100_EVENTA2_FRAMING_ERROR (0x08<<8)
|
||||
#define AB3100_EVENTA2_CHARG_OVERCURRENT (0x10<<8)
|
||||
#define AB3100_EVENTA2_MIDR (0x20<<8)
|
||||
#define AB3100_EVENTA2_BATTERY_REM (0x40<<8)
|
||||
#define AB3100_EVENTA2_ALARM (0x80<<8)
|
||||
|
||||
#define AB3100_EVENTA3_ADC_TRIG5 (0x01)
|
||||
#define AB3100_EVENTA3_ADC_TRIG4 (0x02)
|
||||
#define AB3100_EVENTA3_ADC_TRIG3 (0x04)
|
||||
#define AB3100_EVENTA3_ADC_TRIG2 (0x08)
|
||||
#define AB3100_EVENTA3_ADC_TRIGVBAT (0x10)
|
||||
#define AB3100_EVENTA3_ADC_TRIGVTX (0x20)
|
||||
#define AB3100_EVENTA3_ADC_TRIG1 (0x40)
|
||||
#define AB3100_EVENTA3_ADC_TRIG0 (0x80)
|
||||
|
||||
/* AB3100, STR register flags */
|
||||
#define AB3100_STR_ONSWA (0x01)
|
||||
#define AB3100_STR_ONSWB (0x02)
|
||||
#define AB3100_STR_ONSWC (0x04)
|
||||
#define AB3100_STR_DCIO (0x08)
|
||||
#define AB3100_STR_BOOT_MODE (0x10)
|
||||
#define AB3100_STR_SIM_OFF (0x20)
|
||||
#define AB3100_STR_BATT_REMOVAL (0x40)
|
||||
#define AB3100_STR_VBUS (0x80)
|
||||
|
||||
/*
|
||||
* AB3100 contains 8 regulators, one external regulator controller
|
||||
* and a buck converter, further the LDO E and buck converter can
|
||||
* have separate settings if they are in sleep mode, this is
|
||||
* modeled as a separate regulator.
|
||||
*/
|
||||
#define AB3100_NUM_REGULATORS 10
|
||||
|
||||
/**
|
||||
* struct ab3100
|
||||
* @access_mutex: lock out concurrent accesses to the AB3100 registers
|
||||
* @dev: pointer to the containing device
|
||||
* @i2c_client: I2C client for this chip
|
||||
* @testreg_client: secondary client for test registers
|
||||
* @chip_name: name of this chip variant
|
||||
* @chip_id: 8 bit chip ID for this chip variant
|
||||
* @event_subscribers: event subscribers are listed here
|
||||
* @startup_events: a copy of the first reading of the event registers
|
||||
* @startup_events_read: whether the first events have been read
|
||||
*
|
||||
* This struct is PRIVATE and devices using it should NOT
|
||||
* access ANY fields. It is used as a token for calling the
|
||||
* AB3100 functions.
|
||||
*/
|
||||
struct ab3100 {
|
||||
struct mutex access_mutex;
|
||||
struct device *dev;
|
||||
struct i2c_client *i2c_client;
|
||||
struct i2c_client *testreg_client;
|
||||
char chip_name[32];
|
||||
u8 chip_id;
|
||||
struct blocking_notifier_head event_subscribers;
|
||||
u8 startup_events[3];
|
||||
bool startup_events_read;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ab3100_platform_data
|
||||
* Data supplied to initialize board connections to the AB3100
|
||||
* @reg_constraints: regulator constraints for target board
|
||||
* the order of these constraints are: LDO A, C, D, E,
|
||||
* F, G, H, K, EXT and BUCK.
|
||||
* @reg_initvals: initial values for the regulator registers
|
||||
* plus two sleep settings for LDO E and the BUCK converter.
|
||||
* exactly AB3100_NUM_REGULATORS+2 values must be sent in.
|
||||
* Order: LDO A, C, E, E sleep, F, G, H, K, EXT, BUCK,
|
||||
* BUCK sleep, LDO D. (LDO D need to be initialized last.)
|
||||
* @external_voltage: voltage level of the external regulator.
|
||||
*/
|
||||
struct ab3100_platform_data {
|
||||
struct regulator_init_data reg_constraints[AB3100_NUM_REGULATORS];
|
||||
u8 reg_initvals[AB3100_NUM_REGULATORS+2];
|
||||
int external_voltage;
|
||||
};
|
||||
|
||||
int ab3100_event_register(struct ab3100 *ab3100,
|
||||
struct notifier_block *nb);
|
||||
int ab3100_event_unregister(struct ab3100 *ab3100,
|
||||
struct notifier_block *nb);
|
||||
|
||||
#endif /* MFD_AB3100_H */
|
281
include/linux/mfd/atc260x/atc2603c.h
Normal file
281
include/linux/mfd/atc260x/atc2603c.h
Normal file
@ -0,0 +1,281 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* ATC2603C PMIC register definitions
|
||||
*
|
||||
* Copyright (C) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MFD_ATC260X_ATC2603C_H
|
||||
#define __LINUX_MFD_ATC260X_ATC2603C_H
|
||||
|
||||
enum atc2603c_irq_def {
|
||||
ATC2603C_IRQ_AUDIO = 0,
|
||||
ATC2603C_IRQ_OV,
|
||||
ATC2603C_IRQ_OC,
|
||||
ATC2603C_IRQ_OT,
|
||||
ATC2603C_IRQ_UV,
|
||||
ATC2603C_IRQ_ALARM,
|
||||
ATC2603C_IRQ_ONOFF,
|
||||
ATC2603C_IRQ_SGPIO,
|
||||
ATC2603C_IRQ_IR,
|
||||
ATC2603C_IRQ_REMCON,
|
||||
ATC2603C_IRQ_POWER_IN,
|
||||
};
|
||||
|
||||
/* PMU Registers */
|
||||
#define ATC2603C_PMU_SYS_CTL0 0x00
|
||||
#define ATC2603C_PMU_SYS_CTL1 0x01
|
||||
#define ATC2603C_PMU_SYS_CTL2 0x02
|
||||
#define ATC2603C_PMU_SYS_CTL3 0x03
|
||||
#define ATC2603C_PMU_SYS_CTL4 0x04
|
||||
#define ATC2603C_PMU_SYS_CTL5 0x05
|
||||
#define ATC2603C_PMU_SYS_CTL6 0x06
|
||||
#define ATC2603C_PMU_SYS_CTL7 0x07
|
||||
#define ATC2603C_PMU_SYS_CTL8 0x08
|
||||
#define ATC2603C_PMU_SYS_CTL9 0x09
|
||||
#define ATC2603C_PMU_BAT_CTL0 0x0A
|
||||
#define ATC2603C_PMU_BAT_CTL1 0x0B
|
||||
#define ATC2603C_PMU_VBUS_CTL0 0x0C
|
||||
#define ATC2603C_PMU_VBUS_CTL1 0x0D
|
||||
#define ATC2603C_PMU_WALL_CTL0 0x0E
|
||||
#define ATC2603C_PMU_WALL_CTL1 0x0F
|
||||
#define ATC2603C_PMU_SYS_PENDING 0x10
|
||||
#define ATC2603C_PMU_DC1_CTL0 0x11
|
||||
#define ATC2603C_PMU_DC1_CTL1 0x12 // Undocumented
|
||||
#define ATC2603C_PMU_DC1_CTL2 0x13 // Undocumented
|
||||
#define ATC2603C_PMU_DC2_CTL0 0x14
|
||||
#define ATC2603C_PMU_DC2_CTL1 0x15 // Undocumented
|
||||
#define ATC2603C_PMU_DC2_CTL2 0x16 // Undocumented
|
||||
#define ATC2603C_PMU_DC3_CTL0 0x17
|
||||
#define ATC2603C_PMU_DC3_CTL1 0x18 // Undocumented
|
||||
#define ATC2603C_PMU_DC3_CTL2 0x19 // Undocumented
|
||||
#define ATC2603C_PMU_DC4_CTL0 0x1A // Undocumented
|
||||
#define ATC2603C_PMU_DC4_CTL1 0x1B // Undocumented
|
||||
#define ATC2603C_PMU_DC5_CTL0 0x1C // Undocumented
|
||||
#define ATC2603C_PMU_DC5_CTL1 0x1D // Undocumented
|
||||
#define ATC2603C_PMU_LDO1_CTL 0x1E
|
||||
#define ATC2603C_PMU_LDO2_CTL 0x1F
|
||||
#define ATC2603C_PMU_LDO3_CTL 0x20
|
||||
#define ATC2603C_PMU_LDO4_CTL 0x21 // Undocumented
|
||||
#define ATC2603C_PMU_LDO5_CTL 0x22
|
||||
#define ATC2603C_PMU_LDO6_CTL 0x23
|
||||
#define ATC2603C_PMU_LDO7_CTL 0x24
|
||||
#define ATC2603C_PMU_LDO8_CTL 0x25 // Undocumented
|
||||
#define ATC2603C_PMU_LDO9_CTL 0x26 // Undocumented
|
||||
#define ATC2603C_PMU_LDO10_CTL 0x27 // Undocumented
|
||||
#define ATC2603C_PMU_LDO11_CTL 0x28
|
||||
#define ATC2603C_PMU_SWITCH_CTL 0x29
|
||||
#define ATC2603C_PMU_OV_CTL0 0x2A
|
||||
#define ATC2603C_PMU_OV_CTL1 0x2B
|
||||
#define ATC2603C_PMU_OV_STATUS 0x2C
|
||||
#define ATC2603C_PMU_OV_EN 0x2D
|
||||
#define ATC2603C_PMU_OV_INT_EN 0x2E
|
||||
#define ATC2603C_PMU_OC_CTL 0x2F
|
||||
#define ATC2603C_PMU_OC_STATUS 0x30
|
||||
#define ATC2603C_PMU_OC_EN 0x31
|
||||
#define ATC2603C_PMU_OC_INT_EN 0x32
|
||||
#define ATC2603C_PMU_UV_CTL0 0x33
|
||||
#define ATC2603C_PMU_UV_CTL1 0x34
|
||||
#define ATC2603C_PMU_UV_STATUS 0x35
|
||||
#define ATC2603C_PMU_UV_EN 0x36
|
||||
#define ATC2603C_PMU_UV_INT_EN 0x37
|
||||
#define ATC2603C_PMU_OT_CTL 0x38
|
||||
#define ATC2603C_PMU_CHARGER_CTL0 0x39
|
||||
#define ATC2603C_PMU_CHARGER_CTL1 0x3A
|
||||
#define ATC2603C_PMU_CHARGER_CTL2 0x3B
|
||||
#define ATC2603C_PMU_BAKCHARGER_CTL 0x3C // Undocumented
|
||||
#define ATC2603C_PMU_APDS_CTL 0x3D
|
||||
#define ATC2603C_PMU_AUXADC_CTL0 0x3E
|
||||
#define ATC2603C_PMU_AUXADC_CTL1 0x3F
|
||||
#define ATC2603C_PMU_BATVADC 0x40
|
||||
#define ATC2603C_PMU_BATIADC 0x41
|
||||
#define ATC2603C_PMU_WALLVADC 0x42
|
||||
#define ATC2603C_PMU_WALLIADC 0x43
|
||||
#define ATC2603C_PMU_VBUSVADC 0x44
|
||||
#define ATC2603C_PMU_VBUSIADC 0x45
|
||||
#define ATC2603C_PMU_SYSPWRADC 0x46
|
||||
#define ATC2603C_PMU_REMCONADC 0x47
|
||||
#define ATC2603C_PMU_SVCCADC 0x48
|
||||
#define ATC2603C_PMU_CHGIADC 0x49
|
||||
#define ATC2603C_PMU_IREFADC 0x4A
|
||||
#define ATC2603C_PMU_BAKBATADC 0x4B
|
||||
#define ATC2603C_PMU_ICTEMPADC 0x4C
|
||||
#define ATC2603C_PMU_AUXADC0 0x4D
|
||||
#define ATC2603C_PMU_AUXADC1 0x4E
|
||||
#define ATC2603C_PMU_AUXADC2 0x4F
|
||||
#define ATC2603C_PMU_ICMADC 0x50
|
||||
#define ATC2603C_PMU_BDG_CTL 0x51 // Undocumented
|
||||
#define ATC2603C_RTC_CTL 0x52
|
||||
#define ATC2603C_RTC_MSALM 0x53
|
||||
#define ATC2603C_RTC_HALM 0x54
|
||||
#define ATC2603C_RTC_YMDALM 0x55
|
||||
#define ATC2603C_RTC_MS 0x56
|
||||
#define ATC2603C_RTC_H 0x57
|
||||
#define ATC2603C_RTC_DC 0x58
|
||||
#define ATC2603C_RTC_YMD 0x59
|
||||
#define ATC2603C_EFUSE_DAT 0x5A // Undocumented
|
||||
#define ATC2603C_EFUSECRTL1 0x5B // Undocumented
|
||||
#define ATC2603C_EFUSECRTL2 0x5C // Undocumented
|
||||
#define ATC2603C_PMU_FW_USE0 0x5D // Undocumented
|
||||
#define ATC2603C_PMU_FW_USE1 0x5E // Undocumented
|
||||
#define ATC2603C_PMU_FW_USE2 0x5F // Undocumented
|
||||
#define ATC2603C_PMU_FW_USE3 0x60 // Undocumented
|
||||
#define ATC2603C_PMU_FW_USE4 0x61 // Undocumented
|
||||
#define ATC2603C_PMU_ABNORMAL_STATUS 0x62
|
||||
#define ATC2603C_PMU_WALL_APDS_CTL 0x63
|
||||
#define ATC2603C_PMU_REMCON_CTL0 0x64
|
||||
#define ATC2603C_PMU_REMCON_CTL1 0x65
|
||||
#define ATC2603C_PMU_MUX_CTL0 0x66
|
||||
#define ATC2603C_PMU_SGPIO_CTL0 0x67
|
||||
#define ATC2603C_PMU_SGPIO_CTL1 0x68
|
||||
#define ATC2603C_PMU_SGPIO_CTL2 0x69
|
||||
#define ATC2603C_PMU_SGPIO_CTL3 0x6A
|
||||
#define ATC2603C_PMU_SGPIO_CTL4 0x6B
|
||||
#define ATC2603C_PWMCLK_CTL 0x6C
|
||||
#define ATC2603C_PWM0_CTL 0x6D
|
||||
#define ATC2603C_PWM1_CTL 0x6E
|
||||
#define ATC2603C_PMU_ADC_DBG0 0x70
|
||||
#define ATC2603C_PMU_ADC_DBG1 0x71
|
||||
#define ATC2603C_PMU_ADC_DBG2 0x72
|
||||
#define ATC2603C_PMU_ADC_DBG3 0x73
|
||||
#define ATC2603C_PMU_ADC_DBG4 0x74
|
||||
#define ATC2603C_IRC_CTL 0x80
|
||||
#define ATC2603C_IRC_STAT 0x81
|
||||
#define ATC2603C_IRC_CC 0x82
|
||||
#define ATC2603C_IRC_KDC 0x83
|
||||
#define ATC2603C_IRC_WK 0x84
|
||||
#define ATC2603C_IRC_RCC 0x85
|
||||
#define ATC2603C_IRC_FILTER 0x86
|
||||
|
||||
/* AUDIO_OUT Registers */
|
||||
#define ATC2603C_AUDIOINOUT_CTL 0xA0
|
||||
#define ATC2603C_AUDIO_DEBUGOUTCTL 0xA1
|
||||
#define ATC2603C_DAC_DIGITALCTL 0xA2
|
||||
#define ATC2603C_DAC_VOLUMECTL0 0xA3
|
||||
#define ATC2603C_DAC_ANALOG0 0xA4
|
||||
#define ATC2603C_DAC_ANALOG1 0xA5
|
||||
#define ATC2603C_DAC_ANALOG2 0xA6
|
||||
#define ATC2603C_DAC_ANALOG3 0xA7
|
||||
|
||||
/* AUDIO_IN Registers */
|
||||
#define ATC2603C_ADC_DIGITALCTL 0xA8
|
||||
#define ATC2603C_ADC_HPFCTL 0xA9
|
||||
#define ATC2603C_ADC_CTL 0xAA
|
||||
#define ATC2603C_AGC_CTL0 0xAB
|
||||
#define ATC2603C_AGC_CTL1 0xAC // Undocumented
|
||||
#define ATC2603C_AGC_CTL2 0xAD
|
||||
#define ATC2603C_ADC_ANALOG0 0xAE
|
||||
#define ATC2603C_ADC_ANALOG1 0xAF
|
||||
|
||||
/* PCM_IF Registers */
|
||||
#define ATC2603C_PCM0_CTL 0xB0 // Undocumented
|
||||
#define ATC2603C_PCM1_CTL 0xB1 // Undocumented
|
||||
#define ATC2603C_PCM2_CTL 0xB2 // Undocumented
|
||||
#define ATC2603C_PCMIF_CTL 0xB3 // Undocumented
|
||||
|
||||
/* CMU_CONTROL Registers */
|
||||
#define ATC2603C_CMU_DEVRST 0xC1 // Undocumented
|
||||
|
||||
/* INTS Registers */
|
||||
#define ATC2603C_INTS_PD 0xC8
|
||||
#define ATC2603C_INTS_MSK 0xC9
|
||||
|
||||
/* MFP Registers */
|
||||
#define ATC2603C_MFP_CTL 0xD0
|
||||
#define ATC2603C_PAD_VSEL 0xD1 // Undocumented
|
||||
#define ATC2603C_GPIO_OUTEN 0xD2
|
||||
#define ATC2603C_GPIO_INEN 0xD3
|
||||
#define ATC2603C_GPIO_DAT 0xD4
|
||||
#define ATC2603C_PAD_DRV 0xD5
|
||||
#define ATC2603C_PAD_EN 0xD6
|
||||
#define ATC2603C_DEBUG_SEL 0xD7 // Undocumented
|
||||
#define ATC2603C_DEBUG_IE 0xD8 // Undocumented
|
||||
#define ATC2603C_DEBUG_OE 0xD9 // Undocumented
|
||||
#define ATC2603C_BIST_START 0x0A // Undocumented
|
||||
#define ATC2603C_BIST_RESULT 0x0B // Undocumented
|
||||
#define ATC2603C_CHIP_VER 0xDC
|
||||
|
||||
/* TWSI Registers */
|
||||
#define ATC2603C_SADDR 0xFF
|
||||
|
||||
/* PMU_SYS_CTL0 Register Mask Bits */
|
||||
#define ATC2603C_PMU_SYS_CTL0_IR_WK_EN BIT(5)
|
||||
#define ATC2603C_PMU_SYS_CTL0_RESET_WK_EN BIT(6)
|
||||
#define ATC2603C_PMU_SYS_CTL0_HDSW_WK_EN BIT(7)
|
||||
#define ATC2603C_PMU_SYS_CTL0_ALARM_WK_EN BIT(8)
|
||||
#define ATC2603C_PMU_SYS_CTL0_REM_CON_WK_EN BIT(9)
|
||||
#define ATC2603C_PMU_SYS_CTL0_RESTART_EN BIT(10)
|
||||
#define ATC2603C_PMU_SYS_CTL0_SGPIOIRQ_WK_EN BIT(11)
|
||||
#define ATC2603C_PMU_SYS_CTL0_ONOFF_SHORT_WK_EN BIT(12)
|
||||
#define ATC2603C_PMU_SYS_CTL0_ONOFF_LONG_WK_EN BIT(13)
|
||||
#define ATC2603C_PMU_SYS_CTL0_WALL_WK_EN BIT(14)
|
||||
#define ATC2603C_PMU_SYS_CTL0_USB_WK_EN BIT(15)
|
||||
#define ATC2603C_PMU_SYS_CTL0_WK_ALL (GENMASK(15, 5) & (~BIT(10)))
|
||||
|
||||
/* PMU_SYS_CTL1 Register Mask Bits */
|
||||
#define ATC2603C_PMU_SYS_CTL1_EN_S1 BIT(0)
|
||||
#define ATC2603C_PMU_SYS_CTL1_LB_S4_EN BIT(2)
|
||||
#define ATC2603C_PMU_SYS_CTL1_LB_S4 GENMASK(4, 3)
|
||||
#define ATC2603C_PMU_SYS_CTL1_LB_S4_3_1V BIT(4)
|
||||
#define ATC2603C_PMU_SYS_CTL1_IR_WK_FLAG BIT(5)
|
||||
#define ATC2603C_PMU_SYS_CTL1_RESET_WK_FLAG BIT(6)
|
||||
#define ATC2603C_PMU_SYS_CTL1_HDSW_WK_FLAG BIT(7)
|
||||
#define ATC2603C_PMU_SYS_CTL1_ALARM_WK_FLAG BIT(8)
|
||||
#define ATC2603C_PMU_SYS_CTL1_REM_CON_WK_FLAG BIT(9)
|
||||
#define ATC2603C_PMU_SYS_CTL1_ONOFF_PRESS_RESET_IRQ_PD BIT(10)
|
||||
#define ATC2603C_PMU_SYS_CTL1_SGPIOIRQ_WK_FLAG BIT(11)
|
||||
#define ATC2603C_PMU_SYS_CTL1_ONOFF_SHORT_WK_FLAG BIT(12)
|
||||
#define ATC2603C_PMU_SYS_CTL1_ONOFF_LONG_WK_FLAG BIT(13)
|
||||
#define ATC2603C_PMU_SYS_CTL1_WALL_WK_FLAG BIT(14)
|
||||
#define ATC2603C_PMU_SYS_CTL1_USB_WK_FLAG BIT(15)
|
||||
|
||||
/* PMU_SYS_CTL2 Register Mask Bits */
|
||||
#define ATC2603C_PMU_SYS_CTL2_PMU_A_EN BIT(0)
|
||||
#define ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_INT_EN BIT(1)
|
||||
#define ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_PD BIT(2)
|
||||
#define ATC2603C_PMU_SYS_CTL2_S2TIMER GENMASK(5, 3)
|
||||
#define ATC2603C_PMU_SYS_CTL2_S2_TIMER_EN BIT(6)
|
||||
#define ATC2603C_PMU_SYS_CTL2_ONOFF_RESET_TIME_SEL GENMASK(8, 7)
|
||||
#define ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_RESET_EN BIT(9)
|
||||
#define ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_TIME GENMASK(11, 10)
|
||||
#define ATC2603C_PMU_SYS_CTL2_ONOFF_INT_EN BIT(12)
|
||||
#define ATC2603C_PMU_SYS_CTL2_ONOFF_LONG_PRESS BIT(13)
|
||||
#define ATC2603C_PMU_SYS_CTL2_ONOFF_SHORT_PRESS BIT(14)
|
||||
#define ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS BIT(15)
|
||||
|
||||
/* PMU_SYS_CTL3 Register Mask Bits */
|
||||
#define ATC2603C_PMU_SYS_CTL3_S2S3TOS1_TIMER GENMASK(8, 7)
|
||||
#define ATC2603C_PMU_SYS_CTL3_S2S3TOS1_TIMER_EN BIT(9)
|
||||
#define ATC2603C_PMU_SYS_CTL3_S3_TIMER GENMASK(12, 10)
|
||||
#define ATC2603C_PMU_SYS_CTL3_S3_TIMER_EN BIT(13)
|
||||
#define ATC2603C_PMU_SYS_CTL3_EN_S3 BIT(14)
|
||||
#define ATC2603C_PMU_SYS_CTL3_EN_S2 BIT(15)
|
||||
|
||||
/* PMU_SYS_CTL5 Register Mask Bits */
|
||||
#define ATC2603C_PMU_SYS_CTL5_WALLWKDTEN BIT(7)
|
||||
#define ATC2603C_PMU_SYS_CTL5_VBUSWKDTEN BIT(8)
|
||||
#define ATC2603C_PMU_SYS_CTL5_REMCON_DECT_EN BIT(9)
|
||||
#define ATC2603C_PMU_SYS_CTL5_ONOFF_8S_SEL BIT(10)
|
||||
|
||||
/* INTS_MSK Register Mask Bits */
|
||||
#define ATC2603C_INTS_MSK_AUDIO BIT(0)
|
||||
#define ATC2603C_INTS_MSK_OV BIT(1)
|
||||
#define ATC2603C_INTS_MSK_OC BIT(2)
|
||||
#define ATC2603C_INTS_MSK_OT BIT(3)
|
||||
#define ATC2603C_INTS_MSK_UV BIT(4)
|
||||
#define ATC2603C_INTS_MSK_ALARM BIT(5)
|
||||
#define ATC2603C_INTS_MSK_ONOFF BIT(6)
|
||||
#define ATC2603C_INTS_MSK_SGPIO BIT(7)
|
||||
#define ATC2603C_INTS_MSK_IR BIT(8)
|
||||
#define ATC2603C_INTS_MSK_REMCON BIT(9)
|
||||
#define ATC2603C_INTS_MSK_POWERIN BIT(10)
|
||||
|
||||
/* CMU_DEVRST Register Mask Bits */
|
||||
#define ATC2603C_CMU_DEVRST_MFP BIT(1)
|
||||
#define ATC2603C_CMU_DEVRST_INTS BIT(2)
|
||||
#define ATC2603C_CMU_DEVRST_AUDIO BIT(4)
|
||||
|
||||
/* PAD_EN Register Mask Bits */
|
||||
#define ATC2603C_PAD_EN_EXTIRQ BIT(0)
|
||||
|
||||
#endif /* __LINUX_MFD_ATC260X_ATC2603C_H */
|
308
include/linux/mfd/atc260x/atc2609a.h
Normal file
308
include/linux/mfd/atc260x/atc2609a.h
Normal file
@ -0,0 +1,308 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* ATC2609A PMIC register definitions
|
||||
*
|
||||
* Copyright (C) 2019 Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MFD_ATC260X_ATC2609A_H
|
||||
#define __LINUX_MFD_ATC260X_ATC2609A_H
|
||||
|
||||
enum atc2609a_irq_def {
|
||||
ATC2609A_IRQ_AUDIO = 0,
|
||||
ATC2609A_IRQ_OV,
|
||||
ATC2609A_IRQ_OC,
|
||||
ATC2609A_IRQ_OT,
|
||||
ATC2609A_IRQ_UV,
|
||||
ATC2609A_IRQ_ALARM,
|
||||
ATC2609A_IRQ_ONOFF,
|
||||
ATC2609A_IRQ_WKUP,
|
||||
ATC2609A_IRQ_IR,
|
||||
ATC2609A_IRQ_REMCON,
|
||||
ATC2609A_IRQ_POWER_IN,
|
||||
};
|
||||
|
||||
/* PMU Registers */
|
||||
#define ATC2609A_PMU_SYS_CTL0 0x00
|
||||
#define ATC2609A_PMU_SYS_CTL1 0x01
|
||||
#define ATC2609A_PMU_SYS_CTL2 0x02
|
||||
#define ATC2609A_PMU_SYS_CTL3 0x03
|
||||
#define ATC2609A_PMU_SYS_CTL4 0x04
|
||||
#define ATC2609A_PMU_SYS_CTL5 0x05
|
||||
#define ATC2609A_PMU_SYS_CTL6 0x06
|
||||
#define ATC2609A_PMU_SYS_CTL7 0x07
|
||||
#define ATC2609A_PMU_SYS_CTL8 0x08
|
||||
#define ATC2609A_PMU_SYS_CTL9 0x09
|
||||
#define ATC2609A_PMU_BAT_CTL0 0x0A
|
||||
#define ATC2609A_PMU_BAT_CTL1 0x0B
|
||||
#define ATC2609A_PMU_VBUS_CTL0 0x0C
|
||||
#define ATC2609A_PMU_VBUS_CTL1 0x0D
|
||||
#define ATC2609A_PMU_WALL_CTL0 0x0E
|
||||
#define ATC2609A_PMU_WALL_CTL1 0x0F
|
||||
#define ATC2609A_PMU_SYS_PENDING 0x10
|
||||
#define ATC2609A_PMU_APDS_CTL0 0x11
|
||||
#define ATC2609A_PMU_APDS_CTL1 0x12
|
||||
#define ATC2609A_PMU_APDS_CTL2 0x13
|
||||
#define ATC2609A_PMU_CHARGER_CTL 0x14
|
||||
#define ATC2609A_PMU_BAKCHARGER_CTL 0x15
|
||||
#define ATC2609A_PMU_SWCHG_CTL0 0x16
|
||||
#define ATC2609A_PMU_SWCHG_CTL1 0x17
|
||||
#define ATC2609A_PMU_SWCHG_CTL2 0x18
|
||||
#define ATC2609A_PMU_SWCHG_CTL3 0x19
|
||||
#define ATC2609A_PMU_SWCHG_CTL4 0x1A
|
||||
#define ATC2609A_PMU_DC_OSC 0x1B
|
||||
#define ATC2609A_PMU_DC0_CTL0 0x1C
|
||||
#define ATC2609A_PMU_DC0_CTL1 0x1D
|
||||
#define ATC2609A_PMU_DC0_CTL2 0x1E
|
||||
#define ATC2609A_PMU_DC0_CTL3 0x1F
|
||||
#define ATC2609A_PMU_DC0_CTL4 0x20
|
||||
#define ATC2609A_PMU_DC0_CTL5 0x21
|
||||
#define ATC2609A_PMU_DC0_CTL6 0x22
|
||||
#define ATC2609A_PMU_DC1_CTL0 0x23
|
||||
#define ATC2609A_PMU_DC1_CTL1 0x24
|
||||
#define ATC2609A_PMU_DC1_CTL2 0x25
|
||||
#define ATC2609A_PMU_DC1_CTL3 0x26
|
||||
#define ATC2609A_PMU_DC1_CTL4 0x27
|
||||
#define ATC2609A_PMU_DC1_CTL5 0x28
|
||||
#define ATC2609A_PMU_DC1_CTL6 0x29
|
||||
#define ATC2609A_PMU_DC2_CTL0 0x2A
|
||||
#define ATC2609A_PMU_DC2_CTL1 0x2B
|
||||
#define ATC2609A_PMU_DC2_CTL2 0x2C
|
||||
#define ATC2609A_PMU_DC2_CTL3 0x2D
|
||||
#define ATC2609A_PMU_DC2_CTL4 0x2E
|
||||
#define ATC2609A_PMU_DC2_CTL5 0x2F
|
||||
#define ATC2609A_PMU_DC2_CTL6 0x30
|
||||
#define ATC2609A_PMU_DC3_CTL0 0x31
|
||||
#define ATC2609A_PMU_DC3_CTL1 0x32
|
||||
#define ATC2609A_PMU_DC3_CTL2 0x33
|
||||
#define ATC2609A_PMU_DC3_CTL3 0x34
|
||||
#define ATC2609A_PMU_DC3_CTL4 0x35
|
||||
#define ATC2609A_PMU_DC3_CTL5 0x36
|
||||
#define ATC2609A_PMU_DC3_CTL6 0x37
|
||||
#define ATC2609A_PMU_DC_ZR 0x38
|
||||
#define ATC2609A_PMU_LDO0_CTL0 0x39
|
||||
#define ATC2609A_PMU_LDO0_CTL1 0x3A
|
||||
#define ATC2609A_PMU_LDO1_CTL0 0x3B
|
||||
#define ATC2609A_PMU_LDO1_CTL1 0x3C
|
||||
#define ATC2609A_PMU_LDO2_CTL0 0x3D
|
||||
#define ATC2609A_PMU_LDO2_CTL1 0x3E
|
||||
#define ATC2609A_PMU_LDO3_CTL0 0x3F
|
||||
#define ATC2609A_PMU_LDO3_CTL1 0x40
|
||||
#define ATC2609A_PMU_LDO4_CTL0 0x41
|
||||
#define ATC2609A_PMU_LDO4_CTL1 0x42
|
||||
#define ATC2609A_PMU_LDO5_CTL0 0x43
|
||||
#define ATC2609A_PMU_LDO5_CTL1 0x44
|
||||
#define ATC2609A_PMU_LDO6_CTL0 0x45
|
||||
#define ATC2609A_PMU_LDO6_CTL1 0x46
|
||||
#define ATC2609A_PMU_LDO7_CTL0 0x47
|
||||
#define ATC2609A_PMU_LDO7_CTL1 0x48
|
||||
#define ATC2609A_PMU_LDO8_CTL0 0x49
|
||||
#define ATC2609A_PMU_LDO8_CTL1 0x4A
|
||||
#define ATC2609A_PMU_LDO9_CTL 0x4B
|
||||
#define ATC2609A_PMU_OV_INT_EN 0x4C
|
||||
#define ATC2609A_PMU_OV_STATUS 0x4D
|
||||
#define ATC2609A_PMU_UV_INT_EN 0x4E
|
||||
#define ATC2609A_PMU_UV_STATUS 0x4F
|
||||
#define ATC2609A_PMU_OC_INT_EN 0x50
|
||||
#define ATC2609A_PMU_OC_STATUS 0x51
|
||||
#define ATC2609A_PMU_OT_CTL 0x52
|
||||
#define ATC2609A_PMU_CM_CTL0 0x53
|
||||
#define ATC2609A_PMU_FW_USE0 0x54
|
||||
#define ATC2609A_PMU_FW_USE1 0x55
|
||||
#define ATC2609A_PMU_ADC12B_I 0x56
|
||||
#define ATC2609A_PMU_ADC12B_V 0x57
|
||||
#define ATC2609A_PMU_ADC12B_DUMMY 0x58
|
||||
#define ATC2609A_PMU_AUXADC_CTL0 0x59
|
||||
#define ATC2609A_PMU_AUXADC_CTL1 0x5A
|
||||
#define ATC2609A_PMU_BATVADC 0x5B
|
||||
#define ATC2609A_PMU_BATIADC 0x5C
|
||||
#define ATC2609A_PMU_WALLVADC 0x5D
|
||||
#define ATC2609A_PMU_WALLIADC 0x5E
|
||||
#define ATC2609A_PMU_VBUSVADC 0x5F
|
||||
#define ATC2609A_PMU_VBUSIADC 0x60
|
||||
#define ATC2609A_PMU_SYSPWRADC 0x61
|
||||
#define ATC2609A_PMU_REMCONADC 0x62
|
||||
#define ATC2609A_PMU_SVCCADC 0x63
|
||||
#define ATC2609A_PMU_CHGIADC 0x64
|
||||
#define ATC2609A_PMU_IREFADC 0x65
|
||||
#define ATC2609A_PMU_BAKBATADC 0x66
|
||||
#define ATC2609A_PMU_ICTEMPADC 0x67
|
||||
#define ATC2609A_PMU_AUXADC0 0x68
|
||||
#define ATC2609A_PMU_AUXADC1 0x69
|
||||
#define ATC2609A_PMU_AUXADC2 0x6A
|
||||
#define ATC2609A_PMU_AUXADC3 0x6B
|
||||
#define ATC2609A_PMU_ICTEMPADC_ADJ 0x6C
|
||||
#define ATC2609A_PMU_BDG_CTL 0x6D
|
||||
#define ATC2609A_RTC_CTL 0x6E
|
||||
#define ATC2609A_RTC_MSALM 0x6F
|
||||
#define ATC2609A_RTC_HALM 0x70
|
||||
#define ATC2609A_RTC_YMDALM 0x71
|
||||
#define ATC2609A_RTC_MS 0x72
|
||||
#define ATC2609A_RTC_H 0x73
|
||||
#define ATC2609A_RTC_DC 0x74
|
||||
#define ATC2609A_RTC_YMD 0x75
|
||||
#define ATC2609A_EFUSE_DAT 0x76
|
||||
#define ATC2609A_EFUSECRTL1 0x77
|
||||
#define ATC2609A_EFUSECRTL2 0x78
|
||||
#define ATC2609A_PMU_DC4_CTL0 0x79
|
||||
#define ATC2609A_PMU_DC4_CTL1 0x7A
|
||||
#define ATC2609A_PMU_DC4_CTL2 0x7B
|
||||
#define ATC2609A_PMU_DC4_CTL3 0x7C
|
||||
#define ATC2609A_PMU_DC4_CTL4 0x7D
|
||||
#define ATC2609A_PMU_DC4_CTL5 0x7E
|
||||
#define ATC2609A_PMU_DC4_CTL6 0x7F
|
||||
#define ATC2609A_PMU_PWR_STATUS 0x80
|
||||
#define ATC2609A_PMU_S2_PWR 0x81
|
||||
#define ATC2609A_CLMT_CTL0 0x82
|
||||
#define ATC2609A_CLMT_DATA0 0x83
|
||||
#define ATC2609A_CLMT_DATA1 0x84
|
||||
#define ATC2609A_CLMT_DATA2 0x85
|
||||
#define ATC2609A_CLMT_DATA3 0x86
|
||||
#define ATC2609A_CLMT_ADD0 0x87
|
||||
#define ATC2609A_CLMT_ADD1 0x88
|
||||
#define ATC2609A_CLMT_OCV_TABLE 0x89
|
||||
#define ATC2609A_CLMT_R_TABLE 0x8A
|
||||
#define ATC2609A_PMU_PWRON_CTL0 0x8D
|
||||
#define ATC2609A_PMU_PWRON_CTL1 0x8E
|
||||
#define ATC2609A_PMU_PWRON_CTL2 0x8F
|
||||
#define ATC2609A_IRC_CTL 0x90
|
||||
#define ATC2609A_IRC_STAT 0x91
|
||||
#define ATC2609A_IRC_CC 0x92
|
||||
#define ATC2609A_IRC_KDC 0x93
|
||||
#define ATC2609A_IRC_WK 0x94
|
||||
#define ATC2609A_IRC_RCC 0x95
|
||||
|
||||
/* AUDIO_OUT Registers */
|
||||
#define ATC2609A_AUDIOINOUT_CTL 0xA0
|
||||
#define ATC2609A_AUDIO_DEBUGOUTCTL 0xA1
|
||||
#define ATC2609A_DAC_DIGITALCTL 0xA2
|
||||
#define ATC2609A_DAC_VOLUMECTL0 0xA3
|
||||
#define ATC2609A_DAC_ANALOG0 0xA4
|
||||
#define ATC2609A_DAC_ANALOG1 0xA5
|
||||
#define ATC2609A_DAC_ANALOG2 0xA6
|
||||
#define ATC2609A_DAC_ANALOG3 0xA7
|
||||
|
||||
/* AUDIO_IN Registers */
|
||||
#define ATC2609A_ADC_DIGITALCTL 0xA8
|
||||
#define ATC2609A_ADC_HPFCTL 0xA9
|
||||
#define ATC2609A_ADC_CTL 0xAA
|
||||
#define ATC2609A_AGC_CTL0 0xAB
|
||||
#define ATC2609A_AGC_CTL1 0xAC
|
||||
#define ATC2609A_AGC_CTL2 0xAD
|
||||
#define ATC2609A_ADC_ANALOG0 0xAE
|
||||
#define ATC2609A_ADC_ANALOG1 0xAF
|
||||
|
||||
/* PCM_IF Registers */
|
||||
#define ATC2609A_PCM0_CTL 0xB0
|
||||
#define ATC2609A_PCM1_CTL 0xB1
|
||||
#define ATC2609A_PCM2_CTL 0xB2
|
||||
#define ATC2609A_PCMIF_CTL 0xB3
|
||||
|
||||
/* CMU_CONTROL Registers */
|
||||
#define ATC2609A_CMU_DEVRST 0xC1
|
||||
|
||||
/* INTS Registers */
|
||||
#define ATC2609A_INTS_PD 0xC8
|
||||
#define ATC2609A_INTS_MSK 0xC9
|
||||
|
||||
/* MFP Registers */
|
||||
#define ATC2609A_MFP_CTL 0xD0
|
||||
#define ATC2609A_PAD_VSEL 0xD1
|
||||
#define ATC2609A_GPIO_OUTEN 0xD2
|
||||
#define ATC2609A_GPIO_INEN 0xD3
|
||||
#define ATC2609A_GPIO_DAT 0xD4
|
||||
#define ATC2609A_PAD_DRV 0xD5
|
||||
#define ATC2609A_PAD_EN 0xD6
|
||||
#define ATC2609A_DEBUG_SEL 0xD7
|
||||
#define ATC2609A_DEBUG_IE 0xD8
|
||||
#define ATC2609A_DEBUG_OE 0xD9
|
||||
#define ATC2609A_CHIP_VER 0xDC
|
||||
|
||||
/* PWSI Registers */
|
||||
#define ATC2609A_PWSI_CTL 0xF0
|
||||
#define ATC2609A_PWSI_STATUS 0xF1
|
||||
|
||||
/* TWSI Registers */
|
||||
#define ATC2609A_SADDR 0xFF
|
||||
|
||||
/* PMU_SYS_CTL0 Register Mask Bits */
|
||||
#define ATC2609A_PMU_SYS_CTL0_IR_WK_EN BIT(5)
|
||||
#define ATC2609A_PMU_SYS_CTL0_RESET_WK_EN BIT(6)
|
||||
#define ATC2609A_PMU_SYS_CTL0_HDSW_WK_EN BIT(7)
|
||||
#define ATC2609A_PMU_SYS_CTL0_ALARM_WK_EN BIT(8)
|
||||
#define ATC2609A_PMU_SYS_CTL0_REM_CON_WK_EN BIT(9)
|
||||
#define ATC2609A_PMU_SYS_CTL0_RESTART_EN BIT(10)
|
||||
#define ATC2609A_PMU_SYS_CTL0_WKIRQ_WK_EN BIT(11)
|
||||
#define ATC2609A_PMU_SYS_CTL0_ONOFF_SHORT_WK_EN BIT(12)
|
||||
#define ATC2609A_PMU_SYS_CTL0_ONOFF_LONG_WK_EN BIT(13)
|
||||
#define ATC2609A_PMU_SYS_CTL0_WALL_WK_EN BIT(14)
|
||||
#define ATC2609A_PMU_SYS_CTL0_USB_WK_EN BIT(15)
|
||||
#define ATC2609A_PMU_SYS_CTL0_WK_ALL (GENMASK(15, 5) & (~BIT(10)))
|
||||
|
||||
/* PMU_SYS_CTL1 Register Mask Bits */
|
||||
#define ATC2609A_PMU_SYS_CTL1_EN_S1 BIT(0)
|
||||
#define ATC2609A_PMU_SYS_CTL1_LB_S4_EN BIT(2)
|
||||
#define ATC2609A_PMU_SYS_CTL1_LB_S4 GENMASK(4, 3)
|
||||
#define ATC2609A_PMU_SYS_CTL1_LB_S4_3_1V BIT(4)
|
||||
#define ATC2609A_PMU_SYS_CTL1_IR_WK_FLAG BIT(5)
|
||||
#define ATC2609A_PMU_SYS_CTL1_RESET_WK_FLAG BIT(6)
|
||||
#define ATC2609A_PMU_SYS_CTL1_HDSW_WK_FLAG BIT(7)
|
||||
#define ATC2609A_PMU_SYS_CTL1_ALARM_WK_FLAG BIT(8)
|
||||
#define ATC2609A_PMU_SYS_CTL1_REM_CON_WK_FLAG BIT(9)
|
||||
#define ATC2609A_PMU_SYS_CTL1_RESTART_WK_FLAG BIT(10)
|
||||
#define ATC2609A_PMU_SYS_CTL1_WKIRQ_WK_FLAG BIT(11)
|
||||
#define ATC2609A_PMU_SYS_CTL1_ONOFF_SHORT_WK_FLAG BIT(12)
|
||||
#define ATC2609A_PMU_SYS_CTL1_ONOFF_LONG_WK_FLAG BIT(13)
|
||||
#define ATC2609A_PMU_SYS_CTL1_WALL_WK_FLAG BIT(14)
|
||||
#define ATC2609A_PMU_SYS_CTL1_USB_WK_FLAG BIT(15)
|
||||
|
||||
/* PMU_SYS_CTL2 Register Mask Bits */
|
||||
#define ATC2609A_PMU_SYS_CTL2_PMU_A_EN BIT(0)
|
||||
#define ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS_INT_EN BIT(1)
|
||||
#define ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS_PD BIT(2)
|
||||
#define ATC2609A_PMU_SYS_CTL2_S2TIMER GENMASK(5, 3)
|
||||
#define ATC2609A_PMU_SYS_CTL2_S2_TIMER_EN BIT(6)
|
||||
#define ATC2609A_PMU_SYS_CTL2_ONOFF_RESET_TIME_SEL GENMASK(8, 7)
|
||||
#define ATC2609A_PMU_SYS_CTL2_ONOFF_RESET_EN BIT(9)
|
||||
#define ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS_TIME GENMASK(11, 10)
|
||||
#define ATC2609A_PMU_SYS_CTL2_ONOFF_LSP_INT_EN BIT(12)
|
||||
#define ATC2609A_PMU_SYS_CTL2_ONOFF_LONG_PRESS BIT(13)
|
||||
#define ATC2609A_PMU_SYS_CTL2_ONOFF_SHORT_PRESS BIT(14)
|
||||
#define ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS BIT(15)
|
||||
|
||||
/* PMU_SYS_CTL3 Register Mask Bits */
|
||||
#define ATC2609A_PMU_SYS_CTL3_S2S3TOS1_TIMER GENMASK(8, 7)
|
||||
#define ATC2609A_PMU_SYS_CTL3_S2S3TOS1_TIMER_EN BIT(9)
|
||||
#define ATC2609A_PMU_SYS_CTL3_S3_TIMER GENMASK(12, 10)
|
||||
#define ATC2609A_PMU_SYS_CTL3_S3_TIMER_EN BIT(13)
|
||||
#define ATC2609A_PMU_SYS_CTL3_EN_S3 BIT(14)
|
||||
#define ATC2609A_PMU_SYS_CTL3_EN_S2 BIT(15)
|
||||
|
||||
/* PMU_SYS_CTL5 Register Mask Bits */
|
||||
#define ATC2609A_PMU_SYS_CTL5_WALLWKDTEN BIT(7)
|
||||
#define ATC2609A_PMU_SYS_CTL5_VBUSWKDTEN BIT(8)
|
||||
#define ATC2609A_PMU_SYS_CTL5_REMCON_DECT_EN BIT(9)
|
||||
#define ATC2609A_PMU_SYS_CTL5_ONOFF_8S_SEL BIT(10)
|
||||
|
||||
/* INTS_MSK Register Mask Bits */
|
||||
#define ATC2609A_INTS_MSK_AUDIO BIT(0)
|
||||
#define ATC2609A_INTS_MSK_OV BIT(1)
|
||||
#define ATC2609A_INTS_MSK_OC BIT(2)
|
||||
#define ATC2609A_INTS_MSK_OT BIT(3)
|
||||
#define ATC2609A_INTS_MSK_UV BIT(4)
|
||||
#define ATC2609A_INTS_MSK_ALARM BIT(5)
|
||||
#define ATC2609A_INTS_MSK_ONOFF BIT(6)
|
||||
#define ATC2609A_INTS_MSK_WKUP BIT(7)
|
||||
#define ATC2609A_INTS_MSK_IR BIT(8)
|
||||
#define ATC2609A_INTS_MSK_REMCON BIT(9)
|
||||
#define ATC2609A_INTS_MSK_POWERIN BIT(10)
|
||||
|
||||
/* CMU_DEVRST Register Mask Bits */
|
||||
#define ATC2609A_CMU_DEVRST_AUDIO BIT(0)
|
||||
#define ATC2609A_CMU_DEVRST_MFP BIT(1)
|
||||
#define ATC2609A_CMU_DEVRST_INTS BIT(2)
|
||||
|
||||
/* PAD_EN Register Mask Bits */
|
||||
#define ATC2609A_PAD_EN_EXTIRQ BIT(0)
|
||||
|
||||
#endif /* __LINUX_MFD_ATC260X_ATC2609A_H */
|
58
include/linux/mfd/atc260x/core.h
Normal file
58
include/linux/mfd/atc260x/core.h
Normal file
@ -0,0 +1,58 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Core MFD defines for ATC260x PMICs
|
||||
*
|
||||
* Copyright (C) 2019 Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
* Copyright (C) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MFD_ATC260X_CORE_H
|
||||
#define __LINUX_MFD_ATC260X_CORE_H
|
||||
|
||||
#include <linux/mfd/atc260x/atc2603c.h>
|
||||
#include <linux/mfd/atc260x/atc2609a.h>
|
||||
|
||||
enum atc260x_type {
|
||||
ATC2603A = 0,
|
||||
ATC2603C,
|
||||
ATC2609A,
|
||||
};
|
||||
|
||||
enum atc260x_ver {
|
||||
ATC260X_A = 0,
|
||||
ATC260X_B,
|
||||
ATC260X_C,
|
||||
ATC260X_D,
|
||||
ATC260X_E,
|
||||
ATC260X_F,
|
||||
ATC260X_G,
|
||||
ATC260X_H,
|
||||
};
|
||||
|
||||
struct atc260x {
|
||||
struct device *dev;
|
||||
|
||||
struct regmap *regmap;
|
||||
const struct regmap_irq_chip *regmap_irq_chip;
|
||||
struct regmap_irq_chip_data *irq_data;
|
||||
|
||||
struct mutex *regmap_mutex; /* mutex for custom regmap locking */
|
||||
|
||||
const struct mfd_cell *cells;
|
||||
int nr_cells;
|
||||
int irq;
|
||||
|
||||
enum atc260x_type ic_type;
|
||||
enum atc260x_ver ic_ver;
|
||||
const char *type_name;
|
||||
unsigned int rev_reg;
|
||||
|
||||
const struct atc260x_init_regs *init_regs; /* regs for device init */
|
||||
};
|
||||
|
||||
struct regmap_config;
|
||||
|
||||
int atc260x_match_device(struct atc260x *atc260x, struct regmap_config *regmap_cfg);
|
||||
int atc260x_device_probe(struct atc260x *atc260x);
|
||||
|
||||
#endif /* __LINUX_MFD_ATC260X_CORE_H */
|
@ -50,7 +50,7 @@
|
||||
#define MFD_DEP_LEVEL_HIGH 1
|
||||
|
||||
struct irq_domain;
|
||||
struct property_entry;
|
||||
struct software_node;
|
||||
|
||||
/* Matches ACPI PNP id, either _HID or _CID, or ACPI _ADR */
|
||||
struct mfd_cell_acpi_match {
|
||||
@ -78,8 +78,8 @@ struct mfd_cell {
|
||||
void *platform_data;
|
||||
size_t pdata_size;
|
||||
|
||||
/* device properties passed to the sub devices drivers */
|
||||
const struct property_entry *properties;
|
||||
/* Software node for the device. */
|
||||
const struct software_node *swnode;
|
||||
|
||||
/*
|
||||
* Device Tree compatible string
|
||||
|
@ -1037,6 +1037,9 @@
|
||||
#define DA9063_NONKEY_PIN_AUTODOWN 0x02
|
||||
#define DA9063_NONKEY_PIN_AUTOFLPRT 0x03
|
||||
|
||||
/* DA9063_REG_CONFIG_J (addr=0x10F) */
|
||||
#define DA9063_TWOWIRE_TO 0x40
|
||||
|
||||
/* DA9063_REG_MON_REG_5 (addr=0x116) */
|
||||
#define DA9063_MON_A8_IDX_MASK 0x07
|
||||
#define DA9063_MON_A8_IDX_NONE 0x00
|
||||
|
@ -720,7 +720,7 @@ static inline int db8500_prcmu_load_a9wdog(u8 id, u32 val)
|
||||
|
||||
static inline bool db8500_prcmu_is_ac_wake_requested(void)
|
||||
{
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int db8500_prcmu_set_arm_opp(u8 opp)
|
||||
|
@ -9,9 +9,15 @@
|
||||
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define M10BMC_LEGACY_SYS_BASE 0x300400
|
||||
#define M10BMC_LEGACY_BUILD_VER 0x300468
|
||||
#define M10BMC_SYS_BASE 0x300800
|
||||
#define M10BMC_MEM_END 0x200000fc
|
||||
#define M10BMC_SYS_END 0x300fff
|
||||
#define M10BMC_FLASH_BASE 0x10000000
|
||||
#define M10BMC_FLASH_END 0x1fffffff
|
||||
#define M10BMC_MEM_END M10BMC_FLASH_END
|
||||
|
||||
#define M10BMC_STAGING_BASE 0x18000000
|
||||
#define M10BMC_STAGING_SIZE 0x3800000
|
||||
|
||||
/* Register offset of system registers */
|
||||
#define NIOS2_FW_VERSION 0x0
|
||||
@ -30,6 +36,88 @@
|
||||
#define M10BMC_VER_PCB_INFO_MSK GENMASK(31, 24)
|
||||
#define M10BMC_VER_LEGACY_INVALID 0xffffffff
|
||||
|
||||
/* Secure update doorbell register, in system register region */
|
||||
#define M10BMC_DOORBELL 0x400
|
||||
|
||||
/* Authorization Result register, in system register region */
|
||||
#define M10BMC_AUTH_RESULT 0x404
|
||||
|
||||
/* Doorbell register fields */
|
||||
#define DRBL_RSU_REQUEST BIT(0)
|
||||
#define DRBL_RSU_PROGRESS GENMASK(7, 4)
|
||||
#define DRBL_HOST_STATUS GENMASK(11, 8)
|
||||
#define DRBL_RSU_STATUS GENMASK(23, 16)
|
||||
#define DRBL_PKVL_EEPROM_LOAD_SEC BIT(24)
|
||||
#define DRBL_PKVL1_POLL_EN BIT(25)
|
||||
#define DRBL_PKVL2_POLL_EN BIT(26)
|
||||
#define DRBL_CONFIG_SEL BIT(28)
|
||||
#define DRBL_REBOOT_REQ BIT(29)
|
||||
#define DRBL_REBOOT_DISABLED BIT(30)
|
||||
|
||||
/* Progress states */
|
||||
#define RSU_PROG_IDLE 0x0
|
||||
#define RSU_PROG_PREPARE 0x1
|
||||
#define RSU_PROG_READY 0x3
|
||||
#define RSU_PROG_AUTHENTICATING 0x4
|
||||
#define RSU_PROG_COPYING 0x5
|
||||
#define RSU_PROG_UPDATE_CANCEL 0x6
|
||||
#define RSU_PROG_PROGRAM_KEY_HASH 0x7
|
||||
#define RSU_PROG_RSU_DONE 0x8
|
||||
#define RSU_PROG_PKVL_PROM_DONE 0x9
|
||||
|
||||
/* Device and error states */
|
||||
#define RSU_STAT_NORMAL 0x0
|
||||
#define RSU_STAT_TIMEOUT 0x1
|
||||
#define RSU_STAT_AUTH_FAIL 0x2
|
||||
#define RSU_STAT_COPY_FAIL 0x3
|
||||
#define RSU_STAT_FATAL 0x4
|
||||
#define RSU_STAT_PKVL_REJECT 0x5
|
||||
#define RSU_STAT_NON_INC 0x6
|
||||
#define RSU_STAT_ERASE_FAIL 0x7
|
||||
#define RSU_STAT_WEAROUT 0x8
|
||||
#define RSU_STAT_NIOS_OK 0x80
|
||||
#define RSU_STAT_USER_OK 0x81
|
||||
#define RSU_STAT_FACTORY_OK 0x82
|
||||
#define RSU_STAT_USER_FAIL 0x83
|
||||
#define RSU_STAT_FACTORY_FAIL 0x84
|
||||
#define RSU_STAT_NIOS_FLASH_ERR 0x85
|
||||
#define RSU_STAT_FPGA_FLASH_ERR 0x86
|
||||
|
||||
#define HOST_STATUS_IDLE 0x0
|
||||
#define HOST_STATUS_WRITE_DONE 0x1
|
||||
#define HOST_STATUS_ABORT_RSU 0x2
|
||||
|
||||
#define rsu_prog(doorbell) FIELD_GET(DRBL_RSU_PROGRESS, doorbell)
|
||||
#define rsu_stat(doorbell) FIELD_GET(DRBL_RSU_STATUS, doorbell)
|
||||
|
||||
/* interval 100ms and timeout 5s */
|
||||
#define NIOS_HANDSHAKE_INTERVAL_US (100 * 1000)
|
||||
#define NIOS_HANDSHAKE_TIMEOUT_US (5 * 1000 * 1000)
|
||||
|
||||
/* RSU PREP Timeout (2 minutes) to erase flash staging area */
|
||||
#define RSU_PREP_INTERVAL_MS 100
|
||||
#define RSU_PREP_TIMEOUT_MS (2 * 60 * 1000)
|
||||
|
||||
/* RSU Complete Timeout (40 minutes) for full flash update */
|
||||
#define RSU_COMPLETE_INTERVAL_MS 1000
|
||||
#define RSU_COMPLETE_TIMEOUT_MS (40 * 60 * 1000)
|
||||
|
||||
/* Addresses for security related data in FLASH */
|
||||
#define BMC_REH_ADDR 0x17ffc004
|
||||
#define BMC_PROG_ADDR 0x17ffc000
|
||||
#define BMC_PROG_MAGIC 0x5746
|
||||
|
||||
#define SR_REH_ADDR 0x17ffd004
|
||||
#define SR_PROG_ADDR 0x17ffd000
|
||||
#define SR_PROG_MAGIC 0x5253
|
||||
|
||||
#define PR_REH_ADDR 0x17ffe004
|
||||
#define PR_PROG_ADDR 0x17ffe000
|
||||
#define PR_PROG_MAGIC 0x5250
|
||||
|
||||
/* Address of 4KB inverted bit vector containing staging area FLASH count */
|
||||
#define STAGING_FLASH_COUNT 0x17ffb000
|
||||
|
||||
/**
|
||||
* struct intel_m10bmc - Intel MAX 10 BMC parent driver data structure
|
||||
* @dev: this device
|
||||
|
@ -237,9 +237,6 @@ enum lp87565_device_type {
|
||||
#define LP87565_GOIO2_OUT BIT(1)
|
||||
#define LP87565_GOIO1_OUT BIT(0)
|
||||
|
||||
/* Number of step-down converters available */
|
||||
#define LP87565_NUM_BUCK 6
|
||||
|
||||
enum LP87565_regulator_id {
|
||||
/* BUCK's */
|
||||
LP87565_BUCK_0,
|
||||
|
@ -14,13 +14,13 @@
|
||||
* others and b) it can be enabled simply by using MAX17042 driver.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MFD_MAX8998_H
|
||||
#define __LINUX_MFD_MAX8998_H
|
||||
#ifndef __LINUX_MFD_MAX8997_H
|
||||
#define __LINUX_MFD_MAX8997_H
|
||||
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
/* MAX8997/8966 regulator IDs */
|
||||
enum max8998_regulators {
|
||||
enum max8997_regulators {
|
||||
MAX8997_LDO1 = 0,
|
||||
MAX8997_LDO2,
|
||||
MAX8997_LDO3,
|
||||
@ -207,4 +207,4 @@ struct max8997_platform_data {
|
||||
struct max8997_led_platform_data *led_pdata;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_MFD_MAX8998_H */
|
||||
#endif /* __LINUX_MFD_MAX8997_H */
|
||||
|
38
include/linux/mfd/ntxec.h
Normal file
38
include/linux/mfd/ntxec.h
Normal file
@ -0,0 +1,38 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright 2020 Jonathan Neuschäfer
|
||||
*
|
||||
* Register access and version information for the Netronix embedded
|
||||
* controller.
|
||||
*/
|
||||
|
||||
#ifndef NTXEC_H
|
||||
#define NTXEC_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct device;
|
||||
struct regmap;
|
||||
|
||||
struct ntxec {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
/*
|
||||
* Some registers, such as the battery status register (0x41), are in
|
||||
* big-endian, but others only have eight significant bits, which are in the
|
||||
* first byte transmitted over I2C (the MSB of the big-endian value).
|
||||
* This convenience function converts an 8-bit value to 16-bit for use in the
|
||||
* second kind of register.
|
||||
*/
|
||||
static inline __be16 ntxec_reg8(u8 value)
|
||||
{
|
||||
return value << 8;
|
||||
}
|
||||
|
||||
/* Known firmware versions */
|
||||
#define NTXEC_VERSION_KOBO_AURA 0xd726 /* found in Kobo Aura */
|
||||
#define NTXEC_VERSION_TOLINO_SHINE2 0xf110 /* found in Tolino Shine 2 HD */
|
||||
|
||||
#endif
|
@ -188,6 +188,7 @@
|
||||
#define RN5T618_CHGOSCSCORESET3 0xd7
|
||||
#define RN5T618_CHGOSCFREQSET1 0xd8
|
||||
#define RN5T618_CHGOSCFREQSET2 0xd9
|
||||
#define RN5T618_GCHGDET 0xda
|
||||
#define RN5T618_CONTROL 0xe0
|
||||
#define RN5T618_SOC 0xe1
|
||||
#define RN5T618_RE_CAP_H 0xe2
|
||||
|
562
include/linux/mfd/rohm-bd71815.h
Normal file
562
include/linux/mfd/rohm-bd71815.h
Normal file
@ -0,0 +1,562 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright 2021 ROHM Semiconductors.
|
||||
*
|
||||
* Author: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
|
||||
*
|
||||
* Copyright 2014 Embest Technology Co. Ltd. Inc.
|
||||
*
|
||||
* Author: yanglsh@embest-tech.com
|
||||
*/
|
||||
|
||||
#ifndef _MFD_BD71815_H
|
||||
#define _MFD_BD71815_H
|
||||
|
||||
#include <linux/regmap.h>
|
||||
|
||||
enum {
|
||||
BD71815_BUCK1 = 0,
|
||||
BD71815_BUCK2,
|
||||
BD71815_BUCK3,
|
||||
BD71815_BUCK4,
|
||||
BD71815_BUCK5,
|
||||
/* General Purpose */
|
||||
BD71815_LDO1,
|
||||
BD71815_LDO2,
|
||||
BD71815_LDO3,
|
||||
/* LDOs for SD Card and SD Card Interface */
|
||||
BD71815_LDO4,
|
||||
BD71815_LDO5,
|
||||
/* LDO for DDR Reference Voltage */
|
||||
BD71815_LDODVREF,
|
||||
/* LDO for Low-Power State Retention */
|
||||
BD71815_LDOLPSR,
|
||||
BD71815_WLED,
|
||||
BD71815_REGULATOR_CNT,
|
||||
};
|
||||
|
||||
#define BD71815_SUPPLY_STATE_ENABLED 0x1
|
||||
|
||||
enum {
|
||||
BD71815_REG_DEVICE = 0,
|
||||
BD71815_REG_PWRCTRL,
|
||||
BD71815_REG_BUCK1_MODE,
|
||||
BD71815_REG_BUCK2_MODE,
|
||||
BD71815_REG_BUCK3_MODE,
|
||||
BD71815_REG_BUCK4_MODE,
|
||||
BD71815_REG_BUCK5_MODE,
|
||||
BD71815_REG_BUCK1_VOLT_H,
|
||||
BD71815_REG_BUCK1_VOLT_L,
|
||||
BD71815_REG_BUCK2_VOLT_H,
|
||||
BD71815_REG_BUCK2_VOLT_L,
|
||||
BD71815_REG_BUCK3_VOLT,
|
||||
BD71815_REG_BUCK4_VOLT,
|
||||
BD71815_REG_BUCK5_VOLT,
|
||||
BD71815_REG_LED_CTRL,
|
||||
BD71815_REG_LED_DIMM,
|
||||
BD71815_REG_LDO_MODE1,
|
||||
BD71815_REG_LDO_MODE2,
|
||||
BD71815_REG_LDO_MODE3,
|
||||
BD71815_REG_LDO_MODE4,
|
||||
BD71815_REG_LDO1_VOLT,
|
||||
BD71815_REG_LDO2_VOLT,
|
||||
BD71815_REG_LDO3_VOLT,
|
||||
BD71815_REG_LDO4_VOLT,
|
||||
BD71815_REG_LDO5_VOLT_H,
|
||||
BD71815_REG_LDO5_VOLT_L,
|
||||
BD71815_REG_BUCK_PD_DIS,
|
||||
BD71815_REG_LDO_PD_DIS,
|
||||
BD71815_REG_GPO,
|
||||
BD71815_REG_OUT32K,
|
||||
BD71815_REG_SEC,
|
||||
BD71815_REG_MIN,
|
||||
BD71815_REG_HOUR,
|
||||
BD71815_REG_WEEK,
|
||||
BD71815_REG_DAY,
|
||||
BD71815_REG_MONTH,
|
||||
BD71815_REG_YEAR,
|
||||
BD71815_REG_ALM0_SEC,
|
||||
|
||||
BD71815_REG_ALM1_SEC = 0x2C,
|
||||
|
||||
BD71815_REG_ALM0_MASK = 0x33,
|
||||
BD71815_REG_ALM1_MASK,
|
||||
BD71815_REG_ALM2,
|
||||
BD71815_REG_TRIM,
|
||||
BD71815_REG_CONF,
|
||||
BD71815_REG_SYS_INIT,
|
||||
BD71815_REG_CHG_STATE,
|
||||
BD71815_REG_CHG_LAST_STATE,
|
||||
BD71815_REG_BAT_STAT,
|
||||
BD71815_REG_DCIN_STAT,
|
||||
BD71815_REG_VSYS_STAT,
|
||||
BD71815_REG_CHG_STAT,
|
||||
BD71815_REG_CHG_WDT_STAT,
|
||||
BD71815_REG_BAT_TEMP,
|
||||
BD71815_REG_IGNORE_0,
|
||||
BD71815_REG_INHIBIT_0,
|
||||
BD71815_REG_DCIN_CLPS,
|
||||
BD71815_REG_VSYS_REG,
|
||||
BD71815_REG_VSYS_MAX,
|
||||
BD71815_REG_VSYS_MIN,
|
||||
BD71815_REG_CHG_SET1,
|
||||
BD71815_REG_CHG_SET2,
|
||||
BD71815_REG_CHG_WDT_PRE,
|
||||
BD71815_REG_CHG_WDT_FST,
|
||||
BD71815_REG_CHG_IPRE,
|
||||
BD71815_REG_CHG_IFST,
|
||||
BD71815_REG_CHG_IFST_TERM,
|
||||
BD71815_REG_CHG_VPRE,
|
||||
BD71815_REG_CHG_VBAT_1,
|
||||
BD71815_REG_CHG_VBAT_2,
|
||||
BD71815_REG_CHG_VBAT_3,
|
||||
BD71815_REG_CHG_LED_1,
|
||||
BD71815_REG_VF_TH,
|
||||
BD71815_REG_BAT_SET_1,
|
||||
BD71815_REG_BAT_SET_2,
|
||||
BD71815_REG_BAT_SET_3,
|
||||
BD71815_REG_ALM_VBAT_TH_U,
|
||||
BD71815_REG_ALM_VBAT_TH_L,
|
||||
BD71815_REG_ALM_DCIN_TH,
|
||||
BD71815_REG_ALM_VSYS_TH,
|
||||
BD71815_REG_VM_IBAT_U,
|
||||
BD71815_REG_VM_IBAT_L,
|
||||
BD71815_REG_VM_VBAT_U,
|
||||
BD71815_REG_VM_VBAT_L,
|
||||
BD71815_REG_VM_BTMP,
|
||||
BD71815_REG_VM_VTH,
|
||||
BD71815_REG_VM_DCIN_U,
|
||||
BD71815_REG_VM_DCIN_L,
|
||||
BD71815_REG_VM_VSYS,
|
||||
BD71815_REG_VM_VF,
|
||||
BD71815_REG_VM_OCI_PRE_U,
|
||||
BD71815_REG_VM_OCI_PRE_L,
|
||||
BD71815_REG_VM_OCV_PRE_U,
|
||||
BD71815_REG_VM_OCV_PRE_L,
|
||||
BD71815_REG_VM_OCI_PST_U,
|
||||
BD71815_REG_VM_OCI_PST_L,
|
||||
BD71815_REG_VM_OCV_PST_U,
|
||||
BD71815_REG_VM_OCV_PST_L,
|
||||
BD71815_REG_VM_SA_VBAT_U,
|
||||
BD71815_REG_VM_SA_VBAT_L,
|
||||
BD71815_REG_VM_SA_IBAT_U,
|
||||
BD71815_REG_VM_SA_IBAT_L,
|
||||
BD71815_REG_CC_CTRL,
|
||||
BD71815_REG_CC_BATCAP1_TH_U,
|
||||
BD71815_REG_CC_BATCAP1_TH_L,
|
||||
BD71815_REG_CC_BATCAP2_TH_U,
|
||||
BD71815_REG_CC_BATCAP2_TH_L,
|
||||
BD71815_REG_CC_BATCAP3_TH_U,
|
||||
BD71815_REG_CC_BATCAP3_TH_L,
|
||||
BD71815_REG_CC_STAT,
|
||||
BD71815_REG_CC_CCNTD_3,
|
||||
BD71815_REG_CC_CCNTD_2,
|
||||
BD71815_REG_CC_CCNTD_1,
|
||||
BD71815_REG_CC_CCNTD_0,
|
||||
BD71815_REG_CC_CURCD_U,
|
||||
BD71815_REG_CC_CURCD_L,
|
||||
BD71815_REG_VM_OCUR_THR_1,
|
||||
BD71815_REG_VM_OCUR_DUR_1,
|
||||
BD71815_REG_VM_OCUR_THR_2,
|
||||
BD71815_REG_VM_OCUR_DUR_2,
|
||||
BD71815_REG_VM_OCUR_THR_3,
|
||||
BD71815_REG_VM_OCUR_DUR_3,
|
||||
BD71815_REG_VM_OCUR_MON,
|
||||
BD71815_REG_VM_BTMP_OV_THR,
|
||||
BD71815_REG_VM_BTMP_OV_DUR,
|
||||
BD71815_REG_VM_BTMP_LO_THR,
|
||||
BD71815_REG_VM_BTMP_LO_DUR,
|
||||
BD71815_REG_VM_BTMP_MON,
|
||||
BD71815_REG_INT_EN_01,
|
||||
|
||||
BD71815_REG_INT_EN_11 = 0x95,
|
||||
BD71815_REG_INT_EN_12,
|
||||
BD71815_REG_INT_STAT,
|
||||
BD71815_REG_INT_STAT_01,
|
||||
BD71815_REG_INT_STAT_02,
|
||||
BD71815_REG_INT_STAT_03,
|
||||
BD71815_REG_INT_STAT_04,
|
||||
BD71815_REG_INT_STAT_05,
|
||||
BD71815_REG_INT_STAT_06,
|
||||
BD71815_REG_INT_STAT_07,
|
||||
BD71815_REG_INT_STAT_08,
|
||||
BD71815_REG_INT_STAT_09,
|
||||
BD71815_REG_INT_STAT_10,
|
||||
BD71815_REG_INT_STAT_11,
|
||||
BD71815_REG_INT_STAT_12,
|
||||
BD71815_REG_INT_UPDATE,
|
||||
|
||||
BD71815_REG_VM_VSYS_U = 0xC0,
|
||||
BD71815_REG_VM_VSYS_L,
|
||||
BD71815_REG_VM_SA_VSYS_U,
|
||||
BD71815_REG_VM_SA_VSYS_L,
|
||||
|
||||
BD71815_REG_VM_SA_IBAT_MIN_U = 0xD0,
|
||||
BD71815_REG_VM_SA_IBAT_MIN_L,
|
||||
BD71815_REG_VM_SA_IBAT_MAX_U,
|
||||
BD71815_REG_VM_SA_IBAT_MAX_L,
|
||||
BD71815_REG_VM_SA_VBAT_MIN_U,
|
||||
BD71815_REG_VM_SA_VBAT_MIN_L,
|
||||
BD71815_REG_VM_SA_VBAT_MAX_U,
|
||||
BD71815_REG_VM_SA_VBAT_MAX_L,
|
||||
BD71815_REG_VM_SA_VSYS_MIN_U,
|
||||
BD71815_REG_VM_SA_VSYS_MIN_L,
|
||||
BD71815_REG_VM_SA_VSYS_MAX_U,
|
||||
BD71815_REG_VM_SA_VSYS_MAX_L,
|
||||
BD71815_REG_VM_SA_MINMAX_CLR,
|
||||
|
||||
BD71815_REG_REX_CCNTD_3 = 0xE0,
|
||||
BD71815_REG_REX_CCNTD_2,
|
||||
BD71815_REG_REX_CCNTD_1,
|
||||
BD71815_REG_REX_CCNTD_0,
|
||||
BD71815_REG_REX_SA_VBAT_U,
|
||||
BD71815_REG_REX_SA_VBAT_L,
|
||||
BD71815_REG_REX_CTRL_1,
|
||||
BD71815_REG_REX_CTRL_2,
|
||||
BD71815_REG_FULL_CCNTD_3,
|
||||
BD71815_REG_FULL_CCNTD_2,
|
||||
BD71815_REG_FULL_CCNTD_1,
|
||||
BD71815_REG_FULL_CCNTD_0,
|
||||
BD71815_REG_FULL_CTRL,
|
||||
|
||||
BD71815_REG_CCNTD_CHG_3 = 0xF0,
|
||||
BD71815_REG_CCNTD_CHG_2,
|
||||
|
||||
BD71815_REG_TEST_MODE = 0xFE,
|
||||
BD71815_MAX_REGISTER,
|
||||
};
|
||||
|
||||
/* BD71815_REG_BUCK1_MODE bits */
|
||||
#define BD71815_BUCK_RAMPRATE_MASK 0xC0
|
||||
#define BD71815_BUCK_RAMPRATE_10P00MV 0x0
|
||||
#define BD71815_BUCK_RAMPRATE_5P00MV 0x01
|
||||
#define BD71815_BUCK_RAMPRATE_2P50MV 0x02
|
||||
#define BD71815_BUCK_RAMPRATE_1P25MV 0x03
|
||||
|
||||
#define BD71815_BUCK_PWM_FIXED BIT(4)
|
||||
#define BD71815_BUCK_SNVS_ON BIT(3)
|
||||
#define BD71815_BUCK_RUN_ON BIT(2)
|
||||
#define BD71815_BUCK_LPSR_ON BIT(1)
|
||||
#define BD71815_BUCK_SUSP_ON BIT(0)
|
||||
|
||||
/* BD71815_REG_BUCK1_VOLT_H bits */
|
||||
#define BD71815_BUCK_DVSSEL BIT(7)
|
||||
#define BD71815_BUCK_STBY_DVS BIT(6)
|
||||
#define BD71815_VOLT_MASK 0x3F
|
||||
#define BD71815_BUCK1_H_DEFAULT 0x14
|
||||
#define BD71815_BUCK1_L_DEFAULT 0x14
|
||||
|
||||
/* BD71815_REG_BUCK2_VOLT_H bits */
|
||||
#define BD71815_BUCK2_H_DEFAULT 0x14
|
||||
#define BD71815_BUCK2_L_DEFAULT 0x14
|
||||
|
||||
/* WLED output */
|
||||
/* current register mask */
|
||||
#define LED_DIMM_MASK 0x3f
|
||||
/* LED enable bits at LED_CTRL reg */
|
||||
#define LED_CHGDONE_EN BIT(4)
|
||||
#define LED_RUN_ON BIT(2)
|
||||
#define LED_LPSR_ON BIT(1)
|
||||
#define LED_SUSP_ON BIT(0)
|
||||
|
||||
/* BD71815_REG_LDO1_CTRL bits */
|
||||
#define LDO1_EN BIT(0)
|
||||
#define LDO2_EN BIT(1)
|
||||
#define LDO3_EN BIT(2)
|
||||
#define DVREF_EN BIT(3)
|
||||
#define VOSNVS_SW_EN BIT(4)
|
||||
|
||||
/* LDO_MODE1_register */
|
||||
#define LDO1_SNVS_ON BIT(7)
|
||||
#define LDO1_RUN_ON BIT(6)
|
||||
#define LDO1_LPSR_ON BIT(5)
|
||||
#define LDO1_SUSP_ON BIT(4)
|
||||
/* set => register control, unset => GPIO control */
|
||||
#define LDO4_MODE_MASK BIT(3)
|
||||
#define LDO4_MODE_I2C BIT(3)
|
||||
#define LDO4_MODE_GPIO 0
|
||||
/* set => register control, unset => start when DCIN connected */
|
||||
#define LDO3_MODE_MASK BIT(2)
|
||||
#define LDO3_MODE_I2C BIT(2)
|
||||
#define LDO3_MODE_DCIN 0
|
||||
|
||||
/* LDO_MODE2 register */
|
||||
#define LDO3_SNVS_ON BIT(7)
|
||||
#define LDO3_RUN_ON BIT(6)
|
||||
#define LDO3_LPSR_ON BIT(5)
|
||||
#define LDO3_SUSP_ON BIT(4)
|
||||
#define LDO2_SNVS_ON BIT(3)
|
||||
#define LDO2_RUN_ON BIT(2)
|
||||
#define LDO2_LPSR_ON BIT(1)
|
||||
#define LDO2_SUSP_ON BIT(0)
|
||||
|
||||
|
||||
/* LDO_MODE3 register */
|
||||
#define LDO5_SNVS_ON BIT(7)
|
||||
#define LDO5_RUN_ON BIT(6)
|
||||
#define LDO5_LPSR_ON BIT(5)
|
||||
#define LDO5_SUSP_ON BIT(4)
|
||||
#define LDO4_SNVS_ON BIT(3)
|
||||
#define LDO4_RUN_ON BIT(2)
|
||||
#define LDO4_LPSR_ON BIT(1)
|
||||
#define LDO4_SUSP_ON BIT(0)
|
||||
|
||||
/* LDO_MODE4 register */
|
||||
#define DVREF_SNVS_ON BIT(7)
|
||||
#define DVREF_RUN_ON BIT(6)
|
||||
#define DVREF_LPSR_ON BIT(5)
|
||||
#define DVREF_SUSP_ON BIT(4)
|
||||
#define LDO_LPSR_SNVS_ON BIT(3)
|
||||
#define LDO_LPSR_RUN_ON BIT(2)
|
||||
#define LDO_LPSR_LPSR_ON BIT(1)
|
||||
#define LDO_LPSR_SUSP_ON BIT(0)
|
||||
|
||||
/* BD71815_REG_OUT32K bits */
|
||||
#define OUT32K_EN BIT(0)
|
||||
#define OUT32K_MODE BIT(1)
|
||||
#define OUT32K_MODE_CMOS BIT(1)
|
||||
#define OUT32K_MODE_OPEN_DRAIN 0
|
||||
|
||||
/* BD71815_REG_BAT_STAT bits */
|
||||
#define BAT_DET BIT(5)
|
||||
#define BAT_DET_OFFSET 5
|
||||
#define BAT_DET_DONE BIT(4)
|
||||
#define VBAT_OV BIT(3)
|
||||
#define DBAT_DET BIT(0)
|
||||
|
||||
/* BD71815_REG_VBUS_STAT bits */
|
||||
#define VBUS_DET BIT(0)
|
||||
|
||||
#define BD71815_REG_RTC_START BD71815_REG_SEC
|
||||
#define BD71815_REG_RTC_ALM_START BD71815_REG_ALM0_SEC
|
||||
|
||||
/* BD71815_REG_ALM0_MASK bits */
|
||||
#define A0_ONESEC BIT(7)
|
||||
|
||||
/* BD71815_REG_INT_EN_00 bits */
|
||||
#define ALMALE BIT(0)
|
||||
|
||||
/* BD71815_REG_INT_STAT_03 bits */
|
||||
#define DCIN_MON_DET BIT(1)
|
||||
#define DCIN_MON_RES BIT(0)
|
||||
#define POWERON_LONG BIT(2)
|
||||
#define POWERON_MID BIT(3)
|
||||
#define POWERON_SHORT BIT(4)
|
||||
#define POWERON_PRESS BIT(5)
|
||||
|
||||
/* BD71805_REG_INT_STAT_08 bits */
|
||||
#define VBAT_MON_DET BIT(1)
|
||||
#define VBAT_MON_RES BIT(0)
|
||||
|
||||
/* BD71805_REG_INT_STAT_11 bits */
|
||||
#define INT_STAT_11_VF_DET BIT(7)
|
||||
#define INT_STAT_11_VF_RES BIT(6)
|
||||
#define INT_STAT_11_VF125_DET BIT(5)
|
||||
#define INT_STAT_11_VF125_RES BIT(4)
|
||||
#define INT_STAT_11_OVTMP_DET BIT(3)
|
||||
#define INT_STAT_11_OVTMP_RES BIT(2)
|
||||
#define INT_STAT_11_LOTMP_DET BIT(1)
|
||||
#define INT_STAT_11_LOTMP_RES BIT(0)
|
||||
|
||||
#define VBAT_MON_DET BIT(1)
|
||||
#define VBAT_MON_RES BIT(0)
|
||||
|
||||
/* BD71815_REG_PWRCTRL bits */
|
||||
#define RESTARTEN BIT(0)
|
||||
|
||||
/* BD71815_REG_GPO bits */
|
||||
#define READY_FORCE_LOW BIT(2)
|
||||
#define BD71815_GPIO_DRIVE_MASK BIT(4)
|
||||
#define BD71815_GPIO_OPEN_DRAIN 0
|
||||
#define BD71815_GPIO_CMOS BIT(4)
|
||||
|
||||
/* BD71815 interrupt masks */
|
||||
enum {
|
||||
BD71815_INT_EN_01_BUCKAST_MASK = 0x0F,
|
||||
BD71815_INT_EN_02_DCINAST_MASK = 0x3E,
|
||||
BD71815_INT_EN_03_DCINAST_MASK = 0x3F,
|
||||
BD71815_INT_EN_04_VSYSAST_MASK = 0xCF,
|
||||
BD71815_INT_EN_05_CHGAST_MASK = 0xFC,
|
||||
BD71815_INT_EN_06_BATAST_MASK = 0xF3,
|
||||
BD71815_INT_EN_07_BMONAST_MASK = 0xFE,
|
||||
BD71815_INT_EN_08_BMONAST_MASK = 0x03,
|
||||
BD71815_INT_EN_09_BMONAST_MASK = 0x07,
|
||||
BD71815_INT_EN_10_BMONAST_MASK = 0x3F,
|
||||
BD71815_INT_EN_11_TMPAST_MASK = 0xFF,
|
||||
BD71815_INT_EN_12_ALMAST_MASK = 0x07,
|
||||
};
|
||||
/* BD71815 interrupt irqs */
|
||||
enum {
|
||||
/* BUCK reg interrupts */
|
||||
BD71815_INT_BUCK1_OCP,
|
||||
BD71815_INT_BUCK2_OCP,
|
||||
BD71815_INT_BUCK3_OCP,
|
||||
BD71815_INT_BUCK4_OCP,
|
||||
BD71815_INT_BUCK5_OCP,
|
||||
BD71815_INT_LED_OVP,
|
||||
BD71815_INT_LED_OCP,
|
||||
BD71815_INT_LED_SCP,
|
||||
/* DCIN1 interrupts */
|
||||
BD71815_INT_DCIN_RMV,
|
||||
BD71815_INT_CLPS_OUT,
|
||||
BD71815_INT_CLPS_IN,
|
||||
BD71815_INT_DCIN_OVP_RES,
|
||||
BD71815_INT_DCIN_OVP_DET,
|
||||
/* DCIN2 interrupts */
|
||||
BD71815_INT_DCIN_MON_RES,
|
||||
BD71815_INT_DCIN_MON_DET,
|
||||
BD71815_INT_WDOG,
|
||||
/* Vsys INT_STAT_04 */
|
||||
BD71815_INT_VSYS_UV_RES,
|
||||
BD71815_INT_VSYS_UV_DET,
|
||||
BD71815_INT_VSYS_LOW_RES,
|
||||
BD71815_INT_VSYS_LOW_DET,
|
||||
BD71815_INT_VSYS_MON_RES,
|
||||
BD71815_INT_VSYS_MON_DET,
|
||||
/* Charger INT_STAT_05 */
|
||||
BD71815_INT_CHG_WDG_TEMP,
|
||||
BD71815_INT_CHG_WDG_TIME,
|
||||
BD71815_INT_CHG_RECHARGE_RES,
|
||||
BD71815_INT_CHG_RECHARGE_DET,
|
||||
BD71815_INT_CHG_RANGED_TEMP_TRANSITION,
|
||||
BD71815_INT_CHG_STATE_TRANSITION,
|
||||
/* Battery INT_STAT_06 */
|
||||
BD71815_INT_BAT_TEMP_NORMAL,
|
||||
BD71815_INT_BAT_TEMP_ERANGE,
|
||||
BD71815_INT_BAT_REMOVED,
|
||||
BD71815_INT_BAT_DETECTED,
|
||||
BD71815_INT_THERM_REMOVED,
|
||||
BD71815_INT_THERM_DETECTED,
|
||||
/* Battery Mon 1 INT_STAT_07 */
|
||||
BD71815_INT_BAT_DEAD,
|
||||
BD71815_INT_BAT_SHORTC_RES,
|
||||
BD71815_INT_BAT_SHORTC_DET,
|
||||
BD71815_INT_BAT_LOW_VOLT_RES,
|
||||
BD71815_INT_BAT_LOW_VOLT_DET,
|
||||
BD71815_INT_BAT_OVER_VOLT_RES,
|
||||
BD71815_INT_BAT_OVER_VOLT_DET,
|
||||
/* Battery Mon 2 INT_STAT_08 */
|
||||
BD71815_INT_BAT_MON_RES,
|
||||
BD71815_INT_BAT_MON_DET,
|
||||
/* Battery Mon 3 (Coulomb counter) INT_STAT_09 */
|
||||
BD71815_INT_BAT_CC_MON1,
|
||||
BD71815_INT_BAT_CC_MON2,
|
||||
BD71815_INT_BAT_CC_MON3,
|
||||
/* Battery Mon 4 INT_STAT_10 */
|
||||
BD71815_INT_BAT_OVER_CURR_1_RES,
|
||||
BD71815_INT_BAT_OVER_CURR_1_DET,
|
||||
BD71815_INT_BAT_OVER_CURR_2_RES,
|
||||
BD71815_INT_BAT_OVER_CURR_2_DET,
|
||||
BD71815_INT_BAT_OVER_CURR_3_RES,
|
||||
BD71815_INT_BAT_OVER_CURR_3_DET,
|
||||
/* Temperature INT_STAT_11 */
|
||||
BD71815_INT_TEMP_BAT_LOW_RES,
|
||||
BD71815_INT_TEMP_BAT_LOW_DET,
|
||||
BD71815_INT_TEMP_BAT_HI_RES,
|
||||
BD71815_INT_TEMP_BAT_HI_DET,
|
||||
BD71815_INT_TEMP_CHIP_OVER_125_RES,
|
||||
BD71815_INT_TEMP_CHIP_OVER_125_DET,
|
||||
BD71815_INT_TEMP_CHIP_OVER_VF_RES,
|
||||
BD71815_INT_TEMP_CHIP_OVER_VF_DET,
|
||||
/* RTC Alarm INT_STAT_12 */
|
||||
BD71815_INT_RTC0,
|
||||
BD71815_INT_RTC1,
|
||||
BD71815_INT_RTC2,
|
||||
};
|
||||
|
||||
#define BD71815_INT_BUCK1_OCP_MASK BIT(0)
|
||||
#define BD71815_INT_BUCK2_OCP_MASK BIT(1)
|
||||
#define BD71815_INT_BUCK3_OCP_MASK BIT(2)
|
||||
#define BD71815_INT_BUCK4_OCP_MASK BIT(3)
|
||||
#define BD71815_INT_BUCK5_OCP_MASK BIT(4)
|
||||
#define BD71815_INT_LED_OVP_MASK BIT(5)
|
||||
#define BD71815_INT_LED_OCP_MASK BIT(6)
|
||||
#define BD71815_INT_LED_SCP_MASK BIT(7)
|
||||
|
||||
#define BD71815_INT_DCIN_RMV_MASK BIT(1)
|
||||
#define BD71815_INT_CLPS_OUT_MASK BIT(2)
|
||||
#define BD71815_INT_CLPS_IN_MASK BIT(3)
|
||||
#define BD71815_INT_DCIN_OVP_RES_MASK BIT(4)
|
||||
#define BD71815_INT_DCIN_OVP_DET_MASK BIT(5)
|
||||
|
||||
#define BD71815_INT_DCIN_MON_RES_MASK BIT(0)
|
||||
#define BD71815_INT_DCIN_MON_DET_MASK BIT(1)
|
||||
#define BD71815_INT_WDOG_MASK BIT(6)
|
||||
|
||||
#define BD71815_INT_VSYS_UV_RES_MASK BIT(0)
|
||||
#define BD71815_INT_VSYS_UV_DET_MASK BIT(1)
|
||||
#define BD71815_INT_VSYS_LOW_RES_MASK BIT(2)
|
||||
#define BD71815_INT_VSYS_LOW_DET_MASK BIT(3)
|
||||
#define BD71815_INT_VSYS_MON_RES_MASK BIT(6)
|
||||
#define BD71815_INT_VSYS_MON_DET_MASK BIT(7)
|
||||
|
||||
#define BD71815_INT_CHG_WDG_TEMP_MASK BIT(2)
|
||||
#define BD71815_INT_CHG_WDG_TIME_MASK BIT(3)
|
||||
#define BD71815_INT_CHG_RECHARGE_RES_MASK BIT(4)
|
||||
#define BD71815_INT_CHG_RECHARGE_DET_MASK BIT(5)
|
||||
#define BD71815_INT_CHG_RANGED_TEMP_TRANSITION_MASK BIT(6)
|
||||
#define BD71815_INT_CHG_STATE_TRANSITION_MASK BIT(7)
|
||||
|
||||
#define BD71815_INT_BAT_TEMP_NORMAL_MASK BIT(0)
|
||||
#define BD71815_INT_BAT_TEMP_ERANGE_MASK BIT(1)
|
||||
#define BD71815_INT_BAT_REMOVED_MASK BIT(4)
|
||||
#define BD71815_INT_BAT_DETECTED_MASK BIT(5)
|
||||
#define BD71815_INT_THERM_REMOVED_MASK BIT(6)
|
||||
#define BD71815_INT_THERM_DETECTED_MASK BIT(7)
|
||||
|
||||
#define BD71815_INT_BAT_DEAD_MASK BIT(1)
|
||||
#define BD71815_INT_BAT_SHORTC_RES_MASK BIT(2)
|
||||
#define BD71815_INT_BAT_SHORTC_DET_MASK BIT(3)
|
||||
#define BD71815_INT_BAT_LOW_VOLT_RES_MASK BIT(4)
|
||||
#define BD71815_INT_BAT_LOW_VOLT_DET_MASK BIT(5)
|
||||
#define BD71815_INT_BAT_OVER_VOLT_RES_MASK BIT(6)
|
||||
#define BD71815_INT_BAT_OVER_VOLT_DET_MASK BIT(7)
|
||||
|
||||
#define BD71815_INT_BAT_MON_RES_MASK BIT(0)
|
||||
#define BD71815_INT_BAT_MON_DET_MASK BIT(1)
|
||||
|
||||
#define BD71815_INT_BAT_CC_MON1_MASK BIT(0)
|
||||
#define BD71815_INT_BAT_CC_MON2_MASK BIT(1)
|
||||
#define BD71815_INT_BAT_CC_MON3_MASK BIT(2)
|
||||
|
||||
#define BD71815_INT_BAT_OVER_CURR_1_RES_MASK BIT(0)
|
||||
#define BD71815_INT_BAT_OVER_CURR_1_DET_MASK BIT(1)
|
||||
#define BD71815_INT_BAT_OVER_CURR_2_RES_MASK BIT(2)
|
||||
#define BD71815_INT_BAT_OVER_CURR_2_DET_MASK BIT(3)
|
||||
#define BD71815_INT_BAT_OVER_CURR_3_RES_MASK BIT(4)
|
||||
#define BD71815_INT_BAT_OVER_CURR_3_DET_MASK BIT(5)
|
||||
|
||||
#define BD71815_INT_TEMP_BAT_LOW_RES_MASK BIT(0)
|
||||
#define BD71815_INT_TEMP_BAT_LOW_DET_MASK BIT(1)
|
||||
#define BD71815_INT_TEMP_BAT_HI_RES_MASK BIT(2)
|
||||
#define BD71815_INT_TEMP_BAT_HI_DET_MASK BIT(3)
|
||||
#define BD71815_INT_TEMP_CHIP_OVER_125_RES_MASK BIT(4)
|
||||
#define BD71815_INT_TEMP_CHIP_OVER_125_DET_MASK BIT(5)
|
||||
#define BD71815_INT_TEMP_CHIP_OVER_VF_RES_MASK BIT(6)
|
||||
#define BD71815_INT_TEMP_CHIP_OVER_VF_DET_MASK BIT(7)
|
||||
|
||||
#define BD71815_INT_RTC0_MASK BIT(0)
|
||||
#define BD71815_INT_RTC1_MASK BIT(1)
|
||||
#define BD71815_INT_RTC2_MASK BIT(2)
|
||||
|
||||
/* BD71815_REG_CC_CTRL bits */
|
||||
#define CCNTRST 0x80
|
||||
#define CCNTENB 0x40
|
||||
#define CCCALIB 0x20
|
||||
|
||||
/* BD71815_REG_CC_CURCD */
|
||||
#define CURDIR_Discharging 0x8000
|
||||
|
||||
/* BD71815_REG_VM_SA_IBAT */
|
||||
#define IBAT_SA_DIR_Discharging 0x8000
|
||||
|
||||
/* BD71815_REG_REX_CTRL_1 bits */
|
||||
#define REX_CLR BIT(4)
|
||||
|
||||
/* BD71815_REG_REX_CTRL_1 bits */
|
||||
#define REX_PMU_STATE_MASK BIT(2)
|
||||
|
||||
/* BD71815_REG_LED_CTRL bits */
|
||||
#define CHGDONE_LED_EN BIT(4)
|
||||
|
||||
#endif /* __LINUX_MFD_BD71815_H */
|
@ -151,6 +151,9 @@ enum {
|
||||
#define BD71828_REG_GPIO_CTRL3 0x49
|
||||
#define BD71828_REG_IO_STAT 0xed
|
||||
|
||||
/* clk */
|
||||
#define BD71828_REG_OUT32K 0x4b
|
||||
|
||||
/* RTC */
|
||||
#define BD71828_REG_RTC_SEC 0x4c
|
||||
#define BD71828_REG_RTC_MINUTE 0x4d
|
||||
|
@ -310,17 +310,4 @@ enum {
|
||||
BD718XX_PWRBTN_LONG_PRESS_15S
|
||||
};
|
||||
|
||||
struct bd718xx {
|
||||
/*
|
||||
* Please keep this as the first member here as some
|
||||
* drivers (clk) supporting more than one chip may only know this
|
||||
* generic struct 'struct rohm_regmap_dev' and assume it is
|
||||
* the first chunk of parent device's private data.
|
||||
*/
|
||||
struct rohm_regmap_dev chip;
|
||||
|
||||
int chip_irq;
|
||||
struct regmap_irq_chip_data *irq_data;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_MFD_BD718XX_H__ */
|
||||
|
140
include/linux/mfd/rohm-bd957x.h
Normal file
140
include/linux/mfd/rohm-bd957x.h
Normal file
@ -0,0 +1,140 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/* Copyright (C) 2021 ROHM Semiconductors */
|
||||
|
||||
#ifndef __LINUX_MFD_BD957X_H__
|
||||
#define __LINUX_MFD_BD957X_H__
|
||||
|
||||
enum {
|
||||
BD957X_VD50,
|
||||
BD957X_VD18,
|
||||
BD957X_VDDDR,
|
||||
BD957X_VD10,
|
||||
BD957X_VOUTL1,
|
||||
BD957X_VOUTS1,
|
||||
};
|
||||
|
||||
/*
|
||||
* The BD9576 has own IRQ 'blocks' for:
|
||||
* - I2C/thermal,
|
||||
* - Over voltage protection
|
||||
* - Short-circuit protection
|
||||
* - Over current protection
|
||||
* - Over voltage detection
|
||||
* - Under voltage detection
|
||||
* - Under voltage protection
|
||||
* - 'system interrupt'.
|
||||
*
|
||||
* Each of the blocks have a status register giving more accurate IRQ source
|
||||
* information - for example which of the regulators have over-voltage.
|
||||
*
|
||||
* On top of this, there is "main IRQ" status register where each bit indicates
|
||||
* which of sub-blocks have active IRQs. Fine. That would fit regmap-irq main
|
||||
* status handling. Except that:
|
||||
* - Only some sub-IRQs can be masked.
|
||||
* - The IRQ informs us about fault-condition, not when fault state changes.
|
||||
* The IRQ line it is kept asserted until the detected condition is acked
|
||||
* AND cleared in HW. This is annoying for IRQs like the one informing high
|
||||
* temperature because if IRQ is not disabled it keeps the CPU in IRQ
|
||||
* handling loop.
|
||||
*
|
||||
* For now we do just use the main-IRQ register as source for our IRQ
|
||||
* information and bind the regmap-irq to this. We leave fine-grained sub-IRQ
|
||||
* register handling to handlers in sub-devices. The regulator driver shall
|
||||
* read which regulators are source for problem - or if the detected error is
|
||||
* regulator temperature error. The sub-drivers do also handle masking of "sub-
|
||||
* IRQs" if this is supported/needed.
|
||||
*
|
||||
* To overcome the problem with HW keeping IRQ asserted we do call
|
||||
* disable_irq_nosync() from sub-device handler and add a delayed work to
|
||||
* re-enable IRQ roughly 1 second later. This should keep our CPU out of
|
||||
* busy-loop.
|
||||
*/
|
||||
#define IRQS_SILENT_MS 1000
|
||||
|
||||
enum {
|
||||
BD9576_INT_THERM,
|
||||
BD9576_INT_OVP,
|
||||
BD9576_INT_SCP,
|
||||
BD9576_INT_OCP,
|
||||
BD9576_INT_OVD,
|
||||
BD9576_INT_UVD,
|
||||
BD9576_INT_UVP,
|
||||
BD9576_INT_SYS,
|
||||
};
|
||||
|
||||
#define BD957X_REG_SMRB_ASSERT 0x15
|
||||
#define BD957X_REG_PMIC_INTERNAL_STAT 0x20
|
||||
#define BD957X_REG_INT_THERM_STAT 0x23
|
||||
#define BD957X_REG_INT_THERM_MASK 0x24
|
||||
#define BD957X_REG_INT_OVP_STAT 0x25
|
||||
#define BD957X_REG_INT_SCP_STAT 0x26
|
||||
#define BD957X_REG_INT_OCP_STAT 0x27
|
||||
#define BD957X_REG_INT_OVD_STAT 0x28
|
||||
#define BD957X_REG_INT_UVD_STAT 0x29
|
||||
#define BD957X_REG_INT_UVP_STAT 0x2a
|
||||
#define BD957X_REG_INT_SYS_STAT 0x2b
|
||||
#define BD957X_REG_INT_SYS_MASK 0x2c
|
||||
#define BD957X_REG_INT_MAIN_STAT 0x30
|
||||
#define BD957X_REG_INT_MAIN_MASK 0x31
|
||||
|
||||
#define UVD_IRQ_VALID_MASK 0x6F
|
||||
#define OVD_IRQ_VALID_MASK 0x2F
|
||||
|
||||
#define BD957X_MASK_INT_MAIN_THERM BIT(0)
|
||||
#define BD957X_MASK_INT_MAIN_OVP BIT(1)
|
||||
#define BD957X_MASK_INT_MAIN_SCP BIT(2)
|
||||
#define BD957X_MASK_INT_MAIN_OCP BIT(3)
|
||||
#define BD957X_MASK_INT_MAIN_OVD BIT(4)
|
||||
#define BD957X_MASK_INT_MAIN_UVD BIT(5)
|
||||
#define BD957X_MASK_INT_MAIN_UVP BIT(6)
|
||||
#define BD957X_MASK_INT_MAIN_SYS BIT(7)
|
||||
#define BD957X_MASK_INT_ALL 0xff
|
||||
|
||||
#define BD957X_REG_WDT_CONF 0x16
|
||||
|
||||
#define BD957X_REG_POW_TRIGGER1 0x41
|
||||
#define BD957X_REG_POW_TRIGGER2 0x42
|
||||
#define BD957X_REG_POW_TRIGGER3 0x43
|
||||
#define BD957X_REG_POW_TRIGGER4 0x44
|
||||
#define BD957X_REG_POW_TRIGGERL1 0x45
|
||||
#define BD957X_REG_POW_TRIGGERS1 0x46
|
||||
|
||||
#define BD957X_REGULATOR_EN_MASK 0xff
|
||||
#define BD957X_REGULATOR_DIS_VAL 0xff
|
||||
|
||||
#define BD957X_VSEL_REG_MASK 0xff
|
||||
|
||||
#define BD957X_MASK_VOUT1_TUNE 0x87
|
||||
#define BD957X_MASK_VOUT2_TUNE 0x87
|
||||
#define BD957X_MASK_VOUT3_TUNE 0x1f
|
||||
#define BD957X_MASK_VOUT4_TUNE 0x1f
|
||||
#define BD957X_MASK_VOUTL1_TUNE 0x87
|
||||
|
||||
#define BD957X_REG_VOUT1_TUNE 0x50
|
||||
#define BD957X_REG_VOUT2_TUNE 0x53
|
||||
#define BD957X_REG_VOUT3_TUNE 0x56
|
||||
#define BD957X_REG_VOUT4_TUNE 0x59
|
||||
#define BD957X_REG_VOUTL1_TUNE 0x5c
|
||||
|
||||
#define BD9576_REG_VOUT1_OVD 0x51
|
||||
#define BD9576_REG_VOUT1_UVD 0x52
|
||||
#define BD9576_REG_VOUT2_OVD 0x54
|
||||
#define BD9576_REG_VOUT2_UVD 0x55
|
||||
#define BD9576_REG_VOUT3_OVD 0x57
|
||||
#define BD9576_REG_VOUT3_UVD 0x58
|
||||
#define BD9576_REG_VOUT4_OVD 0x5a
|
||||
#define BD9576_REG_VOUT4_UVD 0x5b
|
||||
#define BD9576_REG_VOUTL1_OVD 0x5d
|
||||
#define BD9576_REG_VOUTL1_UVD 0x5e
|
||||
|
||||
#define BD9576_MASK_XVD 0x7f
|
||||
|
||||
#define BD9576_REG_VOUT1S_OCW 0x5f
|
||||
#define BD9576_REG_VOUT1S_OCP 0x60
|
||||
|
||||
#define BD9576_MASK_VOUT1S_OCW 0x3f
|
||||
#define BD9576_MASK_VOUT1S_OCP 0x3f
|
||||
|
||||
#define BD957X_MAX_REGISTER 0x61
|
||||
|
||||
#endif
|
@ -8,12 +8,15 @@
|
||||
#include <linux/regulator/driver.h>
|
||||
|
||||
enum rohm_chip_type {
|
||||
ROHM_CHIP_TYPE_BD71837 = 0,
|
||||
ROHM_CHIP_TYPE_BD71847,
|
||||
ROHM_CHIP_TYPE_BD70528,
|
||||
ROHM_CHIP_TYPE_BD71828,
|
||||
ROHM_CHIP_TYPE_BD9571,
|
||||
ROHM_CHIP_TYPE_BD9573,
|
||||
ROHM_CHIP_TYPE_BD9574,
|
||||
ROHM_CHIP_TYPE_BD9576,
|
||||
ROHM_CHIP_TYPE_BD70528,
|
||||
ROHM_CHIP_TYPE_BD71815,
|
||||
ROHM_CHIP_TYPE_BD71828,
|
||||
ROHM_CHIP_TYPE_BD71837,
|
||||
ROHM_CHIP_TYPE_BD71847,
|
||||
ROHM_CHIP_TYPE_AMOUNT
|
||||
};
|
||||
|
||||
@ -26,7 +29,8 @@ struct rohm_regmap_dev {
|
||||
#define ROHM_DVS_LEVEL_IDLE BIT(1)
|
||||
#define ROHM_DVS_LEVEL_SUSPEND BIT(2)
|
||||
#define ROHM_DVS_LEVEL_LPSR BIT(3)
|
||||
#define ROHM_DVS_LEVEL_VALID_AMOUNT 4
|
||||
#define ROHM_DVS_LEVEL_SNVS BIT(4)
|
||||
#define ROHM_DVS_LEVEL_VALID_AMOUNT 5
|
||||
#define ROHM_DVS_LEVEL_UNKNOWN 0
|
||||
|
||||
/**
|
||||
@ -65,6 +69,9 @@ struct rohm_dvs_config {
|
||||
unsigned int lpsr_reg;
|
||||
unsigned int lpsr_mask;
|
||||
unsigned int lpsr_on_mask;
|
||||
unsigned int snvs_reg;
|
||||
unsigned int snvs_mask;
|
||||
unsigned int snvs_on_mask;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_REGULATOR_ROHM)
|
||||
|
@ -781,8 +781,6 @@ int twl4030_sih_setup(struct device *dev, int module, int irq_base);
|
||||
#define TWL4030_VAUX3_DEV_GRP 0x1F
|
||||
#define TWL4030_VAUX3_DEDICATED 0x22
|
||||
|
||||
static inline int twl4030charger_usb_en(int enable) { return 0; }
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
/* Linux-specific regulator identifiers ... for now, we only support
|
||||
|
@ -1,13 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright(c) 2014 Intel Corporation.
|
||||
*/
|
||||
|
||||
#ifndef I2C_DESIGNWARE_H
|
||||
#define I2C_DESIGNWARE_H
|
||||
|
||||
struct dw_i2c_platform_data {
|
||||
unsigned int i2c_scl_freq;
|
||||
};
|
||||
|
||||
#endif
|
@ -290,7 +290,7 @@ static void arizona_start_mic(struct arizona_extcon_info *info)
|
||||
unsigned int mode;
|
||||
|
||||
/* Microphone detection can't use idle mode */
|
||||
pm_runtime_get(info->dev);
|
||||
pm_runtime_get_sync(info->dev);
|
||||
|
||||
if (info->detecting) {
|
||||
ret = regulator_allow_bypass(info->micvdd, false);
|
||||
@ -601,7 +601,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
|
||||
struct arizona *arizona = info->arizona;
|
||||
int id_gpio = arizona->pdata.hpdet_id_gpio;
|
||||
unsigned int report = EXTCON_JACK_HEADPHONE;
|
||||
int ret, reading;
|
||||
int ret, reading, state;
|
||||
bool mic = false;
|
||||
|
||||
mutex_lock(&info->lock);
|
||||
@ -614,12 +614,11 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
|
||||
}
|
||||
|
||||
/* If the cable was removed while measuring ignore the result */
|
||||
ret = extcon_get_state(info->edev, EXTCON_MECHANICAL);
|
||||
if (ret < 0) {
|
||||
dev_err(arizona->dev, "Failed to check cable state: %d\n",
|
||||
ret);
|
||||
state = extcon_get_state(info->edev, EXTCON_MECHANICAL);
|
||||
if (state < 0) {
|
||||
dev_err(arizona->dev, "Failed to check cable state: %d\n", state);
|
||||
goto out;
|
||||
} else if (!ret) {
|
||||
} else if (!state) {
|
||||
dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n");
|
||||
goto done;
|
||||
}
|
||||
@ -667,7 +666,7 @@ done:
|
||||
gpio_set_value_cansleep(id_gpio, 0);
|
||||
|
||||
/* If we have a mic then reenable MICDET */
|
||||
if (mic || info->mic)
|
||||
if (state && (mic || info->mic))
|
||||
arizona_start_mic(info);
|
||||
|
||||
if (info->hpdet_active) {
|
||||
@ -675,7 +674,9 @@ done:
|
||||
info->hpdet_active = false;
|
||||
}
|
||||
|
||||
info->hpdet_done = true;
|
||||
/* Do not set hp_det done when the cable has been unplugged */
|
||||
if (state)
|
||||
info->hpdet_done = true;
|
||||
|
||||
out:
|
||||
mutex_unlock(&info->lock);
|
||||
@ -694,7 +695,7 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info)
|
||||
dev_dbg(arizona->dev, "Starting HPDET\n");
|
||||
|
||||
/* Make sure we keep the device enabled during the measurement */
|
||||
pm_runtime_get(info->dev);
|
||||
pm_runtime_get_sync(info->dev);
|
||||
|
||||
info->hpdet_active = true;
|
||||
|
||||
@ -1509,7 +1510,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
|
||||
*/
|
||||
info->micd_pol_gpio = gpiod_get_optional(arizona->dev,
|
||||
"wlf,micd-pol",
|
||||
GPIOD_OUT_LOW);
|
||||
mode);
|
||||
if (IS_ERR(info->micd_pol_gpio)) {
|
||||
ret = PTR_ERR(info->micd_pol_gpio);
|
||||
dev_err(arizona->dev,
|
||||
@ -1759,25 +1760,6 @@ static int arizona_extcon_remove(struct platform_device *pdev)
|
||||
bool change;
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
|
||||
ARIZONA_MICD_ENA, 0,
|
||||
&change);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to disable micd on remove: %d\n",
|
||||
ret);
|
||||
} else if (change) {
|
||||
regulator_disable(info->micvdd);
|
||||
pm_runtime_put(info->dev);
|
||||
}
|
||||
|
||||
gpiod_put(info->micd_pol_gpio);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
regmap_update_bits(arizona->regmap,
|
||||
ARIZONA_MICD_CLAMP_CONTROL,
|
||||
ARIZONA_MICD_CLAMP_MODE_MASK, 0);
|
||||
|
||||
if (info->micd_clamp) {
|
||||
jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE;
|
||||
jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL;
|
||||
@ -1793,10 +1775,31 @@ static int arizona_extcon_remove(struct platform_device *pdev)
|
||||
arizona_free_irq(arizona, jack_irq_rise, info);
|
||||
arizona_free_irq(arizona, jack_irq_fall, info);
|
||||
cancel_delayed_work_sync(&info->hpdet_work);
|
||||
cancel_delayed_work_sync(&info->micd_detect_work);
|
||||
cancel_delayed_work_sync(&info->micd_timeout_work);
|
||||
|
||||
ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
|
||||
ARIZONA_MICD_ENA, 0,
|
||||
&change);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to disable micd on remove: %d\n",
|
||||
ret);
|
||||
} else if (change) {
|
||||
regulator_disable(info->micvdd);
|
||||
pm_runtime_put(info->dev);
|
||||
}
|
||||
|
||||
regmap_update_bits(arizona->regmap,
|
||||
ARIZONA_MICD_CLAMP_CONTROL,
|
||||
ARIZONA_MICD_CLAMP_MODE_MASK, 0);
|
||||
regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
|
||||
ARIZONA_JD1_ENA, 0);
|
||||
arizona_clk32k_disable(arizona);
|
||||
|
||||
gpiod_put(info->micd_pol_gpio);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user