Commit ae955959 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mfd-next-6.1' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd

Pull MFD updates from Lee Jones:
 "Core Frameworks:
   - Fix 'mfd_of_node_list' OF node entry resource leak

  New Drivers:
   - Add support for Ocelot VSC7512 Networking Chip
   - Add support for MediaTek MT6370 subPMIC
   - Add support for Richtek RT5120 (I2C) PMIC

  New Device Support:
   - Add support for Rockchip RV1126 and RK3588 to Syscon
   - Add support for Rockchip RK817 Battery Charger to RK808
   - Add support for Silergy SY7636a Voltage Regulator to Simple MFD
   - Add support for Qualcomm PMP8074 PMIC to QCOM SPMI
   - Add support for Secure Update to Intel M10 BMC

  New Functionality:
   - Provide SSP type to Intel's LPSS (PCI) SPI driver

  Fix-ups:
   - Remove legacy / unused code; stmpe, intel_soc_pmic_crc, syscon
   - Unify / simplify; intel_soc_pmic_crc
   - Trivial reordering / spelling, etc; Makefile, twl-core
   - Convert to managed resources; intel_soc_pmic_crc
   - Use appropriate APIs; intel_soc_pmic_crc
   - strscpy() conversion; htc-i2cpld, lpc_ich, mfd-core
   - GPIOD conversion; htc-i2cpld, stmpe
   - Add missing header file includes; twl4030-irq
   - DT goodies; stmpe, mediatek,mt6370, x-powers,axp152,
     aspeed,ast2x00-scu, mediatek,mt8195-scpsys, qcom,spmi-pmic, syscon,
     qcom,tcsr, rockchip,rk817, sprd,ums512-glbreg, dlg,da9063

  Bug Fixes:
   - Properly check return values; sm501, htc-i2cpld
   - Repair Two-Wire Bus Mode; da9062-core
   - Fix error handling; intel_soc_pmic_core, fsl-imx25-tsadc, lp8788,
     lp8788-irq"

* tag 'mfd-next-6.1' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (60 commits)
  mfd: syscon: Remove repetition of the regmap_get_val_endian()
  mfd: ocelot-spi: Add missing MODULE_DEVICE_TABLE
  power: supply: Add charger driver for Rockchip RK817
  dt-bindings: mfd: mt6370: Fix the indentation in the example
  mfd: da9061: Fix Failed to set Two-Wire Bus Mode.
  mfd: htc-i2cpld: Fix an IS_ERR() vs NULL bug in htcpld_core_probe()
  dt-bindings: mfd: qcom,tcsr: Drop simple-mfd from IPQ6018
  mfd: sm501: Add check for platform_driver_register()
  dt-bindings: mfd: mediatek: Add scpsys compatible for mt8186
  mfd: twl4030: Add missed linux/device.h header
  dt-bindings: mfd: dlg,da9063: Add missing regulator patterns
  dt-bindings: mfd: sprd: Add bindings for ums512 global registers
  mfd: intel_soc_pmic_chtdc_ti: Switch from __maybe_unused to pm_sleep_ptr() etc
  dt-bindings: mfd: syscon: Add rk3588 QoS register compatible
  mfd: stmpe: Switch to using gpiod API
  mfd: qcom-spmi-pmic: Add pm7250b compatible
  dt-bindings: mfd: Add missing (unevaluated|additional)Properties on child nodes
  mfd/omap1: htc-i2cpld: Convert to a pure GPIO driver
  mfd: intel-m10-bmc: Add d5005 bmc secure update driver
  dt-bindings: mfd: syscon: Drop ref from reg-io-width
  ...
parents 79d11de9 72a95859
......@@ -22,6 +22,7 @@ properties:
patternProperties:
"^.*_(clk|rst)$":
type: object
unevaluatedProperties: false
properties:
compatible:
......@@ -34,6 +35,45 @@ patternProperties:
- fixed-factor-clock
allOf:
- if:
properties:
compatible:
contains:
const: fixed-factor-clock
then:
$ref: /schemas/clock/fixed-factor-clock.yaml#
- if:
properties:
compatible:
contains:
const: allwinner,sun4i-a10-mod0-clk
then:
properties:
"#clock-cells":
const: 0
# Already checked in the main schema
compatible: true
clocks:
maxItems: 2
clock-output-names:
maxItems: 1
phandle: true
required:
- "#clock-cells"
- compatible
- clocks
- clock-output-names
additionalProperties: false
- if:
properties:
compatible:
......
......@@ -22,6 +22,7 @@ properties:
patternProperties:
"^.*(clk|rst|codec).*$":
type: object
unevaluatedProperties: false
properties:
compatible:
......@@ -36,6 +37,15 @@ patternProperties:
- compatible
allOf:
- if:
properties:
compatible:
contains:
const: fixed-factor-clock
then:
$ref: /schemas/clock/fixed-factor-clock.yaml#
- if:
properties:
compatible:
......
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/mfd/aspeed,ast2x00-scu.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Aspeed System Control Unit
description:
The Aspeed System Control Unit manages the global behaviour of the SoC,
configuring elements such as clocks, pinmux, and reset.
maintainers:
- Joel Stanley <joel@jms.id.au>
- Andrew Jeffery <andrew@aj.id.au>
properties:
compatible:
items:
- enum:
- aspeed,ast2400-scu
- aspeed,ast2500-scu
- aspeed,ast2600-scu
- const: syscon
- const: simple-mfd
reg:
maxItems: 1
ranges: true
'#address-cells':
const: 1
'#size-cells':
const: 1
'#clock-cells':
const: 1
'#reset-cells':
const: 1
patternProperties:
'^p2a-control@[0-9a-f]+$':
description: See Documentation/devicetree/bindings/misc/aspeed-p2a-ctrl.txt
type: object
'^pinctrl(@[0-9a-f]+)?$':
oneOf:
- $ref: /schemas/pinctrl/aspeed,ast2400-pinctrl.yaml
- $ref: /schemas/pinctrl/aspeed,ast2500-pinctrl.yaml
- $ref: /schemas/pinctrl/aspeed,ast2600-pinctrl.yaml
'^interrupt-controller@[0-9a-f]+$':
description: See Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2xxx-scu-ic.txt
type: object
'^silicon-id@[0-9a-f]+$':
description: Unique hardware silicon identifiers within the SoC
type: object
additionalProperties: false
properties:
compatible:
items:
- enum:
- aspeed,ast2400-silicon-id
- aspeed,ast2500-silicon-id
- aspeed,ast2600-silicon-id
- const: aspeed,silicon-id
reg:
description:
The reg should be the unique silicon id register, and not backwards
compatible one in eg. the 2600.
minItems: 1
items:
- description: silicon id information registers
- description: unique chip id registers
required:
- compatible
- reg
- ranges
- '#address-cells'
- '#size-cells'
- '#clock-cells'
- '#reset-cells'
additionalProperties: false
examples:
- |
syscon@1e6e2000 {
compatible = "aspeed,ast2400-scu", "syscon", "simple-mfd";
reg = <0x1e6e2000 0x1a8>;
#clock-cells = <1>;
#reset-cells = <1>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x0 0x1e6e2000 0x1000>;
silicon-id@7c {
compatible = "aspeed,ast2500-silicon-id", "aspeed,silicon-id";
reg = <0x7c 0x4>, <0x150 0x8>;
};
};
...
The Aspeed System Control Unit manages the global behaviour of the SoC,
configuring elements such as clocks, pinmux, and reset.
Required properties:
- compatible: One of:
"aspeed,ast2400-scu", "syscon", "simple-mfd"
"aspeed,ast2500-scu", "syscon", "simple-mfd"
- reg: contains the offset and length of the SCU memory region
- #clock-cells: should be set to <1> - the system controller is also a
clock provider
- #reset-cells: should be set to <1> - the system controller is also a
reset line provider
Example:
syscon: syscon@1e6e2000 {
compatible = "aspeed,ast2400-scu", "syscon", "simple-mfd";
reg = <0x1e6e2000 0x1a8>;
#clock-cells = <1>;
#reset-cells = <1>;
};
Silicon ID
-----------------
Families have unique hardware silicon identifiers within the SoC.
Required properties:
- compatible: "aspeed,silicon-id" or:
"aspeed,ast2400-silicon-id" or
"aspeed,ast2500-silicon-id" or
"aspeed,ast2600-silicon-id"
- reg: offset and length of the silicon id information
optionally, a second offset and length describes the unique chip id
The reg should be the unique silicon id register, and
not backwards compatible one in eg. the 2600.
Example:
silicon-id@7c {
compatible = "aspeed,ast2500-silicon-id", "aspeed,silicon-id";
reg = <0x7c 0x4 0x150 0x8>;
};
......@@ -144,6 +144,7 @@ properties:
CODECs digital core if not being provided by an internal regulator.
type: object
$ref: /schemas/regulator/regulator.yaml#
unevaluatedProperties: false
properties:
compatible:
enum:
......@@ -161,6 +162,7 @@ properties:
CODECs MICVDD.
type: object
$ref: /schemas/regulator/regulator.yaml#
unevaluatedProperties: false
properties:
compatible:
enum:
......@@ -177,6 +179,7 @@ properties:
Initialisation data for the MIC1VDD supplies.
type: object
$ref: /schemas/regulator/regulator.yaml#
unevaluatedProperties: false
properties:
compatible:
enum:
......@@ -202,6 +205,7 @@ properties:
Initialisation data for the MIC2VDD supplies.
type: object
$ref: /schemas/regulator/regulator.yaml#
unevaluatedProperties: false
properties:
compatible:
enum:
......@@ -228,6 +232,7 @@ properties:
the CODECs analog and 1.8V digital supplies.
type: object
$ref: /schemas/regulator/regulator.yaml#
unevaluatedProperties: false
properties:
compatible:
enum:
......
......@@ -71,8 +71,9 @@ properties:
regulators:
type: object
additionalProperties: false
patternProperties:
"^(ldo[1-11]|bcore[1-2]|bpro|bmem|bio|bperi)$":
"^(ldo([1-9]|1[01])|bcore([1-2]|s-merged)|b(pro|mem|io|peri)|bmem-bio-merged)$":
$ref: /schemas/regulator/regulator.yaml
unevaluatedProperties: false
......@@ -112,7 +113,7 @@ examples:
};
regulators {
regulator-bcore1 {
bcore1 {
regulator-name = "BCORE1";
regulator-min-microvolt = <300000>;
regulator-max-microvolt = <1570000>;
......@@ -120,7 +121,7 @@ examples:
regulator-max-microamp = <2000000>;
regulator-boot-on;
};
regulator-ldo11 {
ldo11 {
regulator-name = "LDO_11";
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <3600000>;
......
......@@ -46,6 +46,7 @@ properties:
adc:
type: object
additionalProperties: false
description: Optional hardware monitoring module
properties:
......@@ -59,8 +60,9 @@ properties:
const: 0
patternProperties:
"^channel@[0-9]+$":
"^channel@[0-9a-f]+$":
type: object
additionalProperties: false
description: |
Properties for a single ADC which can report cooked values
(i.e. temperature sensor based on thermister), raw values
......@@ -113,6 +115,7 @@ properties:
patternProperties:
"^fan-controller@[0-9a-f]+$":
type: object
additionalProperties: false
description: Optional fan controller
properties:
......
......@@ -39,6 +39,7 @@ properties:
extcon:
type: object
additionalProperties: false
properties:
compatible:
enum:
......
......@@ -32,6 +32,7 @@ properties:
motor-driver:
type: object
additionalProperties: false
properties:
compatible:
const: maxim,max77843-haptic
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/mfd/mediatek,mt6370.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek MT6370 SubPMIC
maintainers:
- ChiYuan Huang <cy_huang@richtek.com>
description: |
MT6370 is a highly-integrated smart power management IC, which includes a
single cell Li-Ion/Li-Polymer switching battery charger, a USB Type-C &
Power Delivery (PD) controller, dual flash LED current sources, a RGB LED
driver, a backlight WLED driver, a display bias driver and a general LDO for
portable devices.
properties:
compatible:
const: mediatek,mt6370
reg:
maxItems: 1
wakeup-source: true
interrupts:
maxItems: 1
interrupt-controller: true
"#interrupt-cells":
const: 1
adc:
type: object
description: |
Provides 9 channels for system monitoring, including VBUSDIV5 (lower
accuracy, higher measure range), VBUSDIV2 (higher accuracy, lower
measure range), VBAT, VSYS, CHG_VDDP, TS_BAT, IBUS, IBAT, and TEMP_JC.
properties:
compatible:
const: mediatek,mt6370-adc
"#io-channel-cells":
const: 1
required:
- compatible
- "#io-channel-cells"
backlight:
type: object
$ref: /schemas/leds/backlight/mediatek,mt6370-backlight.yaml#
charger:
type: object
$ref: /schemas/power/supply/mediatek,mt6370-charger.yaml#
tcpc:
type: object
$ref: /schemas/usb/mediatek,mt6370-tcpc.yaml#
indicator:
type: object
$ref: /schemas/leds/mediatek,mt6370-indicator.yaml#
flashlight:
type: object
$ref: /schemas/leds/mediatek,mt6370-flashlight.yaml#
regulators:
type: object
description: |
List all supported regulators, which support the control for DisplayBias
voltages and one general purpose LDO which commonly used to drive the
vibrator.
patternProperties:
"^(dsvbst|vibldo)$":
$ref: /schemas/regulator/regulator.yaml#
type: object
unevaluatedProperties: false
"^(dsvpos|dsvneg)$":
$ref: /schemas/regulator/regulator.yaml#
type: object
unevaluatedProperties: false
properties:
enable-gpios:
maxItems: 1
required:
- compatible
- reg
- interrupts
- interrupt-controller
- "#interrupt-cells"
- regulators
- adc
- backlight
- indicator
- tcpc
- charger
- flashlight
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/leds/common.h>
#include <dt-bindings/iio/adc/mediatek,mt6370_adc.h>
#include <dt-bindings/usb/pd.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
pmic@34 {
compatible = "mediatek,mt6370";
reg = <0x34>;
wakeup-source;
interrupts-extended = <&gpio26 3 IRQ_TYPE_LEVEL_LOW>;
interrupt-controller;
#interrupt-cells = <1>;
mt6370_adc: adc {
compatible = "mediatek,mt6370-adc";
#io-channel-cells = <1>;
};
backlight {
compatible = "mediatek,mt6370-backlight";
mediatek,bled-channel-use = /bits/ 8 <15>;
};
charger {
compatible = "mediatek,mt6370-charger";
interrupts = <48>, <68>, <6>;
interrupt-names = "attach_i", "uvp_d_evt", "mivr";
io-channels = <&mt6370_adc MT6370_CHAN_IBUS>;
mt6370_otg_vbus: usb-otg-vbus-regulator {
regulator-name = "mt6370-usb-otg-vbus";
regulator-min-microvolt = <4350000>;
regulator-max-microvolt = <5800000>;
regulator-min-microamp = <500000>;
regulator-max-microamp = <3000000>;
};
};
indicator {
compatible = "mediatek,mt6370-indicator";
#address-cells = <1>;
#size-cells = <0>;
multi-led@0 {
reg = <0>;
function = LED_FUNCTION_INDICATOR;
color = <LED_COLOR_ID_RGB>;
led-max-microamp = <24000>;
#address-cells = <1>;
#size-cells = <0>;
led@0 {
reg = <0>;
color = <LED_COLOR_ID_RED>;
};
led@1 {
reg = <1>;
color = <LED_COLOR_ID_GREEN>;
};
led@2 {
reg = <2>;
color = <LED_COLOR_ID_BLUE>;
};
};
led@3 {
reg = <3>;
function = LED_FUNCTION_INDICATOR;
color = <LED_COLOR_ID_WHITE>;
led-max-microamp = <6000>;
};
};
flashlight {
compatible = "mediatek,mt6370-flashlight";
#address-cells = <1>;
#size-cells = <0>;
led@0 {
reg = <0>;
led-sources = <0>;
function = LED_FUNCTION_FLASH;
color = <LED_COLOR_ID_WHITE>;
function-enumerator = <1>;
led-max-microamp = <200000>;
flash-max-microamp = <500000>;
flash-max-timeout-us = <1248000>;
};
led@1 {
reg = <1>;
led-sources = <1>;
function = LED_FUNCTION_FLASH;
color = <LED_COLOR_ID_WHITE>;
function-enumerator = <2>;
led-max-microamp = <200000>;
flash-max-microamp = <500000>;
flash-max-timeout-us = <1248000>;
};
};
tcpc {
compatible = "mediatek,mt6370-tcpc";
interrupts-extended = <&gpio26 4 IRQ_TYPE_LEVEL_LOW>;
connector {
compatible = "usb-c-connector";
label = "USB-C";
vbus-supply = <&mt6370_otg_vbus>;
data-role = "dual";
power-role = "dual";
try-power-role = "sink";
source-pdos = <PDO_FIXED(5000, 1000, PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP)>;
sink-pdos = <PDO_FIXED(5000, 2000, PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP)>;
op-sink-microwatt = <10000000>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
endpoint {
remote-endpoint = <&usb_hs>;
};
};
port@1 {
reg = <1>;
endpoint {
remote-endpoint = <&usb_ss>;
};
};
port@2 {
reg = <2>;
endpoint {
remote-endpoint = <&dp_aux>;
};
};
};
};
};
regulators {
dsvbst {
regulator-name = "mt6370-dsv-vbst";
regulator-min-microvolt = <4000000>;
regulator-max-microvolt = <6200000>;
};
dsvpos {
regulator-name = "mt6370-dsv-vpos";
regulator-min-microvolt = <4000000>;
regulator-max-microvolt = <6000000>;
regulator-boot-on;
};
dsvneg {
regulator-name = "mt6370-dsv-vneg";
regulator-min-microvolt = <4000000>;
regulator-max-microvolt = <6000000>;
regulator-boot-on;
};
vibldo {
regulator-name = "mt6370-vib-ldo";
regulator-min-microvolt = <1600000>;
regulator-max-microvolt = <4000000>;
};
};
};
};
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/mfd/mediatek,mt8195-scpsys.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek System Control Processor System
maintainers:
- MandyJH Liu <mandyjh.liu@mediatek.com>
description:
MediaTek System Control Processor System (SCPSYS) has several
power management tasks. The tasks include MTCMOS power
domain control, thermal measurement, DVFS, etc.
properties:
compatible:
items:
- enum:
- mediatek,mt8167-scpsys
- mediatek,mt8173-scpsys
- mediatek,mt8183-scpsys
- mediatek,mt8186-scpsys
- mediatek,mt8192-scpsys
- mediatek,mt8195-scpsys
- const: syscon
- const: simple-mfd
reg:
maxItems: 1
power-controller:
$ref: /schemas/power/mediatek,power-controller.yaml#
required:
- compatible
- reg
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/mt8195-clk.h>
#include <dt-bindings/power/mt8195-power.h>
syscon@10006000 {
compatible = "mediatek,mt8195-scpsys", "syscon", "simple-mfd";
reg = <0x10006000 0x100>;
spm: power-controller {
compatible = "mediatek,mt8195-power-controller";
#address-cells = <1>;
#size-cells = <0>;
#power-domain-cells = <1>;
/* sample of power domain nodes */
power-domain@MT8195_POWER_DOMAIN_PCIE_PHY {
reg = <MT8195_POWER_DOMAIN_PCIE_PHY>;
#power-domain-cells = <0>;
};
power-domain@MT8195_POWER_DOMAIN_SSUSB_PCIE_PHY {
reg = <MT8195_POWER_DOMAIN_SSUSB_PCIE_PHY>;
#power-domain-cells = <0>;
};
};
};
......@@ -33,19 +33,22 @@ properties:
compatible:
items:
- enum:
- qcom,pm660
- qcom,pm660l
- qcom,pm6150
- qcom,pm6150l
- qcom,pm6350
- qcom,pm660
- qcom,pm660l
- qcom,pm7250b
- qcom,pm7325
- qcom,pm8004
- qcom,pm8005
- qcom,pm8009
- qcom,pm8019
- qcom,pm8028
- qcom,pm8110
- qcom,pm8150
- qcom,pm8150b
- qcom,pm8150c
- qcom,pm8150l
- qcom,pm8226
- qcom,pm8350
......@@ -56,6 +59,7 @@ properties:
- qcom,pm8916
- qcom,pm8941
- qcom,pm8950
- qcom,pm8953
- qcom,pm8994
- qcom,pm8998
- qcom,pma8084
......@@ -64,8 +68,10 @@ properties:
- qcom,pmi8962
- qcom,pmi8994
- qcom,pmi8998
- qcom,pmk8002
- qcom,pmk8350
- qcom,pmm8155au
- qcom,pmp8074
- qcom,pmr735a
- qcom,pmr735b
- qcom,pms405
......@@ -90,7 +96,7 @@ properties:
regulators:
type: object
$ref: /schemas/regulator/regulator.yaml#
$ref: /schemas/regulator/qcom,spmi-regulator.yaml#
patternProperties:
"^adc@[0-9a-f]+$":
......@@ -99,7 +105,7 @@ patternProperties:
"^adc-tm@[0-9a-f]+$":
type: object
$ref: /schemas/thermal/qcom-spmi-adc-tm5.yaml#
# ref depends on compatible, see allOf below
"^audio-codec@[0-9a-f]+$":
type: object
......@@ -146,6 +152,22 @@ required:
- compatible
- reg
allOf:
- if:
properties:
compatible:
contains:
enum:
- qcom,pm8998
then:
patternProperties:
"^adc-tm@[0-9a-f]+$":
$ref: /schemas/thermal/qcom-spmi-adc-tm-hc.yaml#
else:
patternProperties:
"^adc-tm@[0-9a-f]+$":
$ref: /schemas/thermal/qcom-spmi-adc-tm5.yaml#
additionalProperties: false
examples:
......@@ -188,3 +210,87 @@ examples:
};
};
};
- |
#include <dt-bindings/input/input.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/iio/qcom,spmi-vadc.h>
#include <dt-bindings/spmi/spmi.h>
pmic@0 {
compatible = "qcom,pm6150", "qcom,spmi-pmic";
reg = <0x0 SPMI_USID>;
#address-cells = <1>;
#size-cells = <0>;
pon@800 {
compatible = "qcom,pm8998-pon";
reg = <0x800>;
mode-bootloader = <0x2>;
mode-recovery = <0x1>;
pwrkey {
compatible = "qcom,pm8941-pwrkey";
interrupts = <0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>;
debounce = <15625>;
bias-pull-up;
linux,code = <KEY_POWER>;
};
};
temp-alarm@2400 {
compatible = "qcom,spmi-temp-alarm";
reg = <0x2400>;
interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>;
io-channels = <&pm6150_adc ADC5_DIE_TEMP>;
io-channel-names = "thermal";
#thermal-sensor-cells = <0>;
};
pm6150_adc: adc@3100 {
compatible = "qcom,spmi-adc5";
reg = <0x3100>;
interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
#address-cells = <1>;
#size-cells = <0>;
#io-channel-cells = <1>;
adc-chan@6 {
reg = <ADC5_DIE_TEMP>;
label = "die_temp";
};
adc-chan@4f {
reg = <ADC5_AMUX_THM3_100K_PU>;
qcom,ratiometric;
qcom,hw-settle-time = <200>;
};
};
adc-tm@3500 {
compatible = "qcom,spmi-adc-tm5";
reg = <0x3500>;
interrupts = <0x0 0x35 0x0 IRQ_TYPE_EDGE_RISING>;
#thermal-sensor-cells = <1>;
#address-cells = <1>;
#size-cells = <0>;
charger-thermistor@0 {
reg = <0>;
io-channels = <&pm6150_adc ADC5_AMUX_THM3_100K_PU>;
qcom,ratiometric;
qcom,hw-settle-time-us = <200>;
};
};
pm6150_gpio: gpios@c000 {
compatible = "qcom,pm6150-gpio", "qcom,spmi-gpio";
reg = <0xc000>;
gpio-controller;
gpio-ranges = <&pm6150_gpio 0 0 10>;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
};
};
......@@ -15,8 +15,7 @@ description:
properties:
compatible:
oneOf:
- items:
items:
- enum:
- qcom,msm8998-tcsr
- qcom,qcs404-tcsr
......@@ -27,6 +26,7 @@ properties:
- qcom,sm8150-tcsr
- qcom,tcsr-apq8064
- qcom,tcsr-apq8084
- qcom,tcsr-ipq6018
- qcom,tcsr-ipq8064
- qcom,tcsr-mdm9615
- qcom,tcsr-msm8660
......@@ -36,10 +36,6 @@ properties:
- qcom,tcsr-msm8974
- qcom,tcsr-msm8996
- const: syscon
- items:
- const: qcom,tcsr-ipq6018
- const: syscon
- const: simple-mfd
reg:
maxItems: 1
......
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/mfd/richtek,rt5120.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Richtek RT5120 PMIC
maintainers:
- ChiYuan Huang <cy_huang@richtek.com>
description: |
The RT5120 provides four high-efficiency buck converters and one LDO voltage
regulator. The device is targeted at providingthe processor voltage, memory,
I/O, and peripheral rails in home entertainment devices. The I2C interface is
used for dynamic voltage scaling of the processor voltage, power rails on/off
sequence control, operation mode selection.
properties:
compatible:
enum:
- richtek,rt5120
reg:
maxItems: 1
interrupts:
maxItems: 1
interrupt-controller: true
"#interrupt-cells":
const: 1
wakeup-source: true
richtek,enable-undervolt-hiccup:
type: boolean
description: |
If used, under voltage protection trigger hiccup behavior, else latchup as
default
richtek,enable-overvolt-hiccup:
type: boolean
description:
Like as 'enable-uv-hiccup', it configures over voltage protection to
hiccup, else latchup as default
vin1-supply:
description: phandle for buck1 input power source
vin2-supply:
description: phandle for buck2 input power source
vin3-supply:
description: phandle for buck3 input power source
vin4-supply:
description: phandle for buck4 input power source
vinldo-supply:
description: phandle for ldo input power source
regulators:
type: object
patternProperties:
"^buck[1-4]$":
type: object
$ref: /schemas/regulator/regulator.yaml#
unevaluatedProperties: false
properties:
regulator-allowed-modes:
description: |
Used to specify the allowed buck converter operating mode
mode mapping:
0: auto mode
1: force pwm mode
items:
enum: [0, 1]
"^(ldo|exten)$":
type: object
$ref: /schemas/regulator/regulator.yaml#
unevaluatedProperties: false
additionalProperties: false
powerkey:
type: object
description:
PON key that connected to RT5120 PMIC.
properties:
compatible:
enum:
- richtek,rt5120-pwrkey
required:
- compatible
additionalProperties: false
required:
- compatible
- reg
- interrupts
- '#interrupt-cells'
- interrupt-controller
- regulators
- powerkey
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
pmic@62 {
compatible = "richtek,rt5120";
reg = <0x62>;
interrupts-extended = <&gpio_intc 32 IRQ_TYPE_LEVEL_LOW>;
interrupt-controller;
#interrupt-cells = <1>;
wakeup-source;
regulators {
buck1 {
regulator-name = "rt5120-buck1";
regulator-min-microvolt = <600000>;
regulator-max-microvolt = <1393750>;
regulator-allowed-modes = <0 1>;
regulator-boot-on;
};
buck2 {
regulator-name = "rt5120-buck2";
regulator-min-microvolt = <1100000>;
regulator-max-microvolt = <1100000>;
regulator-allowed-modes = <0 1>;
regulator-always-on;
};
buck3 {
regulator-name = "rt5120-buck3";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-allowed-modes = <0 1>;
regulator-always-on;
};
buck4 {
regulator-name = "rt5120-buck4";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-allowed-modes = <0 1>;
regulator-always-on;
};
ldo {
regulator-name = "rt5120-ldo";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
};
exten {
regulator-name = "rt5120-exten";
regulator-min-microvolt = <3000000>;
regulator-max-microvolt = <3000000>;
regulator-always-on;
};
};
powerkey {
compatible = "richtek,rt5120-pwrkey";
};
};
};
......@@ -87,6 +87,7 @@ properties:
patternProperties:
"^(LDO_REG[1-9]|DCDC_REG[1-4]|BOOST|OTG_SWITCH)$":
type: object
unevaluatedProperties: false
$ref: ../regulator/regulator.yaml#
unevaluatedProperties: false
......@@ -111,12 +112,56 @@ properties:
additional properties are required for the codec, this node can be
omitted.
type: object
additionalProperties: false
properties:
rockchip,mic-in-differential:
type: boolean
description:
Describes if the microphone uses differential mode.
charger:
description: |
The child node for the charger to hold additional properties. If a
battery is not in use, this node can be omitted.
type: object
properties:
monitored-battery:
description: |
A phandle to a monitored battery node that contains a valid
value for:
charge-full-design-microamp-hours,
charge-term-current-microamp,
constant-charge-current-max-microamp,
constant-charge-voltage-max-microvolt,
voltage-max-design-microvolt,
voltage-min-design-microvolt,
and a valid ocv-capacity table.
rockchip,resistor-sense-micro-ohms:
description: |
Value in microohms of the battery sense resistor. This value is
used by the driver to set the correct divisor value to translate
ADC readings into the proper units of measure.
enum: [10000, 20000]
rockchip,sleep-enter-current-microamp:
description: |
Value in microamps of the sleep enter current for the charger.
Value is used by the driver to calibrate the relax threshold.
rockchip,sleep-filter-current-microamp:
description:
Value in microamps of the sleep filter current for the charger.
Value is used by the driver to derive the sleep sample current.
required:
- monitored-battery
- rockchip,resistor-sense-micro-ohms
- rockchip,sleep-enter-current-microamp
- rockchip,sleep-filter-current-microamp
additionalProperties: false
allOf:
- if:
properties:
......@@ -323,6 +368,13 @@ examples:
};
};
rk817_charger: charger {
monitored-battery = <&battery>;
rockchip,resistor-sense-micro-ohms = <10000>;
rockchip,sleep-enter-current-microamp = <300000>;
rockchip,sleep-filter-current-microamp = <100000>;
};
rk817_codec: codec {
rockchip,mic-in-differential;
};
......
......@@ -42,6 +42,7 @@ properties:
vcom:
type: object
$ref: /schemas/regulator/regulator.yaml#
unevaluatedProperties: false
description:
The regulator for the compenstation voltage. Enabling/disabling this
enables/disables the entire device.
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright 2022 Unisoc Inc.
%YAML 1.2
---
$id: http://devicetree.org/schemas/mfd/sprd,ums512-glbreg.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Unisoc System Global Register
maintainers:
- Orson Zhai <orsonzhai@gmail.com>
- Baolin Wang <baolin.wang7@gmail.com>
- Chunyan Zhang <zhang.lyra@gmail.com>
description:
Unisoc system global registers provide register map
for clocks and some multimedia modules of the SoC.
properties:
compatible:
items:
- const: sprd,ums512-glbregs
- const: syscon
- const: simple-mfd
"#address-cells":
const: 1
"#size-cells":
const: 1
ranges:
maxItems: 1
reg:
maxItems: 1
patternProperties:
"^clock-controller@[0-9a-f]+$":
type: object
$ref: /schemas/clock/sprd,ums512-clk.yaml#
description:
Clock controller for the SoC clocks.
required:
- compatible
- reg
additionalProperties: false
examples:
- |
ap_apb_regs: syscon@71000000 {
compatible = "sprd,ums512-glbregs", "syscon", "simple-mfd";
reg = <0x71000000 0x3000>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <0 0x71000000 0x3000>;
clock-controller@0 {
compatible = "sprd,ums512-apahb-gate";
reg = <0x0 0x2000>;
#clock-cells = <1>;
};
};
- |
ap_intc5_regs: syscon@32360000 {
compatible = "sprd,ums512-glbregs", "syscon", "simple-mfd";
reg = <0x32360000 0x1000>;
};
......@@ -46,6 +46,7 @@ properties:
pwm:
type: object
additionalProperties: false
properties:
compatible:
......@@ -60,6 +61,7 @@ properties:
counter:
type: object
additionalProperties: false
properties:
compatible:
......@@ -70,6 +72,7 @@ properties:
timer:
type: object
additionalProperties: false
properties:
compatible:
......@@ -81,6 +84,7 @@ properties:
patternProperties:
"^trigger@[0-9]+$":
type: object
additionalProperties: false
properties:
compatible:
......
......@@ -69,6 +69,7 @@ properties:
pwm:
type: object
additionalProperties: false
properties:
compatible:
......@@ -104,6 +105,7 @@ properties:
counter:
type: object
additionalProperties: false
properties:
compatible:
......@@ -115,6 +117,7 @@ properties:
patternProperties:
"^timer@[0-9]+$":
type: object
additionalProperties: false
properties:
compatible:
......
......@@ -57,6 +57,7 @@ properties:
patternProperties:
"^[a-zA-Z]*-pins$":
type: object
additionalProperties: false
allOf:
- $ref: ../pinctrl/pinmux-node.yaml
......
......@@ -51,6 +51,7 @@ properties:
provides the reference clock for the entire U8500 system and
the DB8500 counterpart.
type: object
additionalProperties: false
properties:
compatible:
......@@ -63,6 +64,7 @@ properties:
description: Node describing the AB8500 GPIO controller. A few
GPIO pins available for misc usage.
type: object
additionalProperties: false
properties:
compatible:
......@@ -78,6 +80,7 @@ properties:
rtc:
description: Node describing the AB8500 battery-backed RTC.
type: object
additionalProperties: false
properties:
compatible:
......@@ -337,34 +340,40 @@ properties:
description: The voltage for the auxilary LDO regulator 1
type: object
$ref: ../regulator/regulator.yaml#
unevaluatedProperties: false
ab8500_ldo_aux2:
description: The voltage for the auxilary LDO regulator 2
type: object
$ref: ../regulator/regulator.yaml#
unevaluatedProperties: false
ab8500_ldo_aux3:
description: The voltage for the auxilary LDO regulator 3
type: object
$ref: ../regulator/regulator.yaml#
unevaluatedProperties: false
ab8500_ldo_aux4:
description: The voltage for the auxilary LDO regulator 4
only present on AB8505
type: object
$ref: ../regulator/regulator.yaml#
unevaluatedProperties: false
ab8500_ldo_aux5:
description: The voltage for the auxilary LDO regulator 5
only present on AB8505
type: object
$ref: ../regulator/regulator.yaml#
unevaluatedProperties: false
ab8500_ldo_aux6:
description: The voltage for the auxilary LDO regulator 6
only present on AB8505
type: object
$ref: ../regulator/regulator.yaml#
unevaluatedProperties: false
# There is never any AUX7 regulator which is confusing
......@@ -373,18 +382,21 @@ properties:
only present on AB8505
type: object
$ref: ../regulator/regulator.yaml#
unevaluatedProperties: false
ab8500_ldo_intcore:
description: The LDO regulator for the internal core voltage
of the AB8500
type: object
$ref: ../regulator/regulator.yaml#
unevaluatedProperties: false
ab8500_ldo_adc:
description: Analog power regulator for the analog to digital converter
ADC, only present on AB8505
type: object
$ref: ../regulator/regulator.yaml#
unevaluatedProperties: false
ab8500_ldo_tvout:
description: The voltage for the TV output regulator, incidentally
......@@ -393,33 +405,39 @@ properties:
Only present on AB8500.
type: object
$ref: ../regulator/regulator.yaml#
unevaluatedProperties: false
ab8500_ldo_audio:
description: The LDO regulator for the audio codec output
type: object
$ref: ../regulator/regulator.yaml#
unevaluatedProperties: false
ab8500_ldo_anamic1:
description: The LDO regulator for the analog microphone 1
type: object
$ref: ../regulator/regulator.yaml#
unevaluatedProperties: false
ab8500_ldo_anamic2:
description: The LDO regulator for the analog microphone 2
type: object
$ref: ../regulator/regulator.yaml#
unevaluatedProperties: false
ab8500_ldo_dmic:
description: The LDO regulator for the digital microphone
only present on AB8500
type: object
$ref: ../regulator/regulator.yaml#
unevaluatedProperties: false
ab8500_ldo_ana:
description: Analog power regulator for CSI and DSI interfaces,
Camera Serial Interface CSI and Display Serial Interface DSI.
type: object
$ref: ../regulator/regulator.yaml#
unevaluatedProperties: false
required:
- compatible
......@@ -442,16 +460,19 @@ properties:
description: The voltage for the VSMPS1 external regulator
type: object
$ref: ../regulator/regulator.yaml#
unevaluatedProperties: false
ab8500_ext2:
description: The voltage for the VSMPS2 external regulator
type: object
$ref: ../regulator/regulator.yaml#
unevaluatedProperties: false
ab8500_ext3:
description: The voltage for the VSMPS3 external regulator
type: object
$ref: ../regulator/regulator.yaml#
unevaluatedProperties: false
required:
- compatible
......@@ -462,6 +483,7 @@ patternProperties:
"^pwm@[1-9]+?$":
type: object
$ref: ../pwm/pwm.yaml#
unevaluatedProperties: false
description: Represents each of the PWM blocks in the AB8500
properties:
......
......@@ -61,6 +61,8 @@ properties:
- rockchip,rk3368-qos
- rockchip,rk3399-qos
- rockchip,rk3568-qos
- rockchip,rk3588-qos
- rockchip,rv1126-qos
- samsung,exynos3-sysreg
- samsung,exynos4-sysreg
- samsung,exynos5-sysreg
......@@ -73,7 +75,7 @@ properties:
- contains:
const: syscon
minItems: 2
maxItems: 4 # Should be enough
maxItems: 5 # Should be enough
reg:
maxItems: 1
......@@ -82,7 +84,6 @@ properties:
description: |
The size (in bytes) of the IO accesses that should be performed
on the device.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [1, 2, 4, 8]
hwlocks:
......@@ -94,6 +95,18 @@ required:
- compatible
- reg
allOf:
- if:
properties:
compatible:
contains:
const: simple-mfd
then:
properties:
compatible:
minItems: 3
maxItems: 5
additionalProperties: true
examples:
......
......@@ -38,6 +38,7 @@ properties:
regulators:
type: object
additionalProperties: false
description: |
List of child nodes that specify the regulator initialization data.
Child nodes must be named after their hardware counterparts:
......
......@@ -92,6 +92,9 @@ properties:
- x-powers,axp806
- x-powers,axp809
- x-powers,axp813
- items:
- const: x-powers,axp228
- const: x-powers,axp221
- items:
- const: x-powers,axp805
- const: x-powers,axp806
......@@ -260,6 +263,7 @@ properties:
"^(([a-f])?ldo[0-9]|dcdc[0-7a-e]|ldo(_|-)io(0|1)|(dc1)?sw|rtc(_|-)ldo|drivevbus|dc5ldo)$":
$ref: /schemas/regulator/regulator.yaml#
type: object
unevaluatedProperties: false
properties:
regulator-ramp-delay:
......
......@@ -135,7 +135,7 @@ examples:
#size-cells = <2>;
scpsys: syscon@10006000 {
compatible = "syscon", "simple-mfd";
compatible = "mediatek,mt8173-scpsys", "syscon", "simple-mfd";
reg = <0 0x10006000 0 0x1000>;
spm: power-controller {
......
......@@ -8475,7 +8475,6 @@ F: tools/testing/selftests/futex/
GATEWORKS SYSTEM CONTROLLER (GSC) DRIVER
M: Tim Harvey <tharvey@gateworks.com>
M: Robert Jones <rjones@gateworks.com>
S: Maintained
F: Documentation/devicetree/bindings/mfd/gateworks-gsc.yaml
F: drivers/mfd/gateworks-gsc.c
......
......@@ -993,7 +993,7 @@ ldo8_reg: ldo8 {
touchscreen@41 {
compatible = "st,stmpe811";
reg = <0x41>;
irq-gpio = <&gpio TEGRA_GPIO(V, 0) IRQ_TYPE_LEVEL_LOW>;
irq-gpio = <&gpio TEGRA_GPIO(V, 0) GPIO_ACTIVE_LOW>;
interrupt-controller;
id = <0>;
blocks = <0x5>;
......
......@@ -976,7 +976,7 @@ ldo8_reg: ldo8 {
touchscreen@41 {
compatible = "st,stmpe811";
reg = <0x41>;
irq-gpio = <&gpio TEGRA_GPIO(V, 0) IRQ_TYPE_LEVEL_LOW>;
irq-gpio = <&gpio TEGRA_GPIO(V, 0) GPIO_ACTIVE_LOW>;
interrupt-controller;
id = <0>;
blocks = <0x5>;
......
......@@ -849,7 +849,7 @@ ldo8_reg: ldo8 {
touchscreen@41 {
compatible = "st,stmpe811";
reg = <0x41>;
irq-gpio = <&gpio TEGRA_GPIO(V, 0) IRQ_TYPE_LEVEL_LOW>;
irq-gpio = <&gpio TEGRA_GPIO(V, 0) GPIO_ACTIVE_LOW>;
interrupt-controller;
id = <0>;
blocks = <0x5>;
......
......@@ -141,13 +141,6 @@
#define HTCPLD_GPIO_DOWN_DPAD HTCPLD_BASE(7, 4)
#define HTCPLD_GPIO_ENTER_DPAD HTCPLD_BASE(7, 3)
/*
* The htcpld chip requires a gpio write to a specific line
* to re-enable interrupts after one has occurred.
*/
#define HTCPLD_GPIO_INT_RESET_HI HTCPLD_BASE(2, 7)
#define HTCPLD_GPIO_INT_RESET_LO HTCPLD_BASE(2, 0)
/* Chip 5 */
#define HTCPLD_IRQ_RIGHT_KBD HTCPLD_IRQ(0, 7)
#define HTCPLD_IRQ_UP_KBD HTCPLD_IRQ(0, 6)
......@@ -348,8 +341,6 @@ static struct htcpld_chip_platform_data htcpld_chips[] = {
};
static struct htcpld_core_platform_data htcpld_pfdata = {
.int_reset_gpio_hi = HTCPLD_GPIO_INT_RESET_HI,
.int_reset_gpio_lo = HTCPLD_GPIO_INT_RESET_LO,
.i2c_adapter_id = 1,
.chip = htcpld_chips,
......
......@@ -1758,6 +1758,7 @@ config SENSORS_SIS5595
config SENSORS_SY7636A
tristate "Silergy SY7636A"
depends on MFD_SY7636A
help
If you say yes here you get support for the thermistor readout of
the Silergy SY7636A PMIC.
......
......@@ -589,8 +589,8 @@ config LPC_SCH
config INTEL_SOC_PMIC
bool "Support for Crystal Cove PMIC"
depends on ACPI && HAS_IOMEM && I2C=y && GPIOLIB && COMMON_CLK
depends on X86 || COMPILE_TEST
depends on HAS_IOMEM && I2C=y && GPIOLIB && COMMON_CLK
depends on (X86 && ACPI) || COMPILE_TEST
depends on I2C_DESIGNWARE_PLATFORM=y
select MFD_CORE
select REGMAP_I2C
......@@ -938,6 +938,22 @@ config MFD_MT6360
PMIC part includes 2-channel BUCKs and 2-channel LDOs
LDO part includes 4-channel LDOs
config MFD_MT6370
tristate "MediaTek MT6370 SubPMIC"
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
depends on I2C
help
Say Y here to enable MT6370 SubPMIC functional support.
It consists of a single cell battery charger with ADC monitoring, RGB
LEDs, dual channel flashlight, WLED backlight driver, display bias
voltage supply, one general purpose LDO, and the USB Type-C & PD
controller complies with the latest USB Type-C and PD standards.
This driver can also be built as a module. If so, the module
will be called "mt6370".
config MFD_MT6397
tristate "MediaTek MT6397 PMIC Support"
select MFD_CORE
......@@ -1117,6 +1133,16 @@ config MFD_SPMI_PMIC
Say M here if you want to include support for the SPMI PMIC
series as a module. The module will be called "qcom-spmi-pmic".
config MFD_SY7636A
tristate "Silergy SY7636A voltage regulator"
depends on I2C
select MFD_SIMPLE_MFD_I2C
help
Enable support for Silergy SY7636A voltage regulator.
To enable support for building sub-devices as modules,
choose M here.
config MFD_RDC321X
tristate "RDC R-321x southbridge"
select MFD_CORE
......@@ -1149,6 +1175,18 @@ config MFD_RT5033
sub-devices like charger, fuel gauge, flash LED, current source,
LDO and Buck.
config MFD_RT5120
tristate "Richtek RT5120 Power Management IC"
depends on I2C
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
help
The enables support for Richtek RT5120 PMIC. It includes four high
efficiency buck converters and one LDO voltage regulator. The device
is targeted at providing the CPU voltage, memory, I/O and peripheral
power rails in home entertainment devices.
config MFD_RC5T583
bool "Ricoh RC5T583 Power Management system device"
depends on I2C=y
......@@ -1224,7 +1262,7 @@ config MFD_SI476X_CORE
module will be called si476x-core.
config MFD_SIMPLE_MFD_I2C
tristate "Simple Multi-Functional Device support (I2C)"
tristate
depends on I2C
select MFD_CORE
select REGMAP_I2C
......
......@@ -175,6 +175,11 @@ obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-irq.o
obj-$(CONFIG_MFD_MP2629) += mp2629.o
obj-$(CONFIG_MFD_MT6360) += mt6360-core.o
obj-$(CONFIG_MFD_MT6370) += mt6370.o
mt6397-objs := mt6397-core.o mt6397-irq.o mt6358-irq.o
obj-$(CONFIG_MFD_MT6397) += mt6397.o
pcf50633-objs := pcf50633-core.o pcf50633-irq.o
obj-$(CONFIG_MFD_PCF50633) += pcf50633.o
obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o
......@@ -237,16 +242,13 @@ obj-$(CONFIG_MFD_HI655X_PMIC) += hi655x-pmic.o
obj-$(CONFIG_MFD_DLN2) += dln2.o
obj-$(CONFIG_MFD_RT4831) += rt4831.o
obj-$(CONFIG_MFD_RT5033) += rt5033.o
obj-$(CONFIG_MFD_RT5120) += rt5120.o
obj-$(CONFIG_MFD_SKY81452) += sky81452.o
intel-soc-pmic-objs := intel_soc_pmic_core.o intel_soc_pmic_crc.o
obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o
obj-$(CONFIG_INTEL_SOC_PMIC) += intel_soc_pmic_crc.o
obj-$(CONFIG_INTEL_SOC_PMIC_BXTWC) += intel_soc_pmic_bxtwc.o
obj-$(CONFIG_INTEL_SOC_PMIC_CHTWC) += intel_soc_pmic_chtwc.o
obj-$(CONFIG_INTEL_SOC_PMIC_CHTDC_TI) += intel_soc_pmic_chtdc_ti.o
obj-$(CONFIG_MFD_MT6360) += mt6360-core.o
mt6397-objs := mt6397-core.o mt6397-irq.o mt6358-irq.o
obj-$(CONFIG_MFD_MT6397) += mt6397.o
obj-$(CONFIG_INTEL_SOC_PMIC_MRFLD) += intel_soc_pmic_mrfld.o
obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o
......
......@@ -453,6 +453,7 @@ static const struct regmap_range da9061_aa_writeable_ranges[] = {
regmap_reg_range(DA9062AA_VBUCK1_B, DA9062AA_VBUCK4_B),
regmap_reg_range(DA9062AA_VBUCK3_B, DA9062AA_VBUCK3_B),
regmap_reg_range(DA9062AA_VLDO1_B, DA9062AA_VLDO4_B),
regmap_reg_range(DA9062AA_CONFIG_J, DA9062AA_CONFIG_J),
regmap_reg_range(DA9062AA_GP_ID_0, DA9062AA_GP_ID_19),
};
......
......@@ -69,7 +69,7 @@ static int mx25_tsadc_setup_irq(struct platform_device *pdev,
int irq;
irq = platform_get_irq(pdev, 0);
if (irq <= 0)
if (irq < 0)
return irq;
tsadc->domain = irq_domain_add_simple(np, 2, 0, &mx25_tsadc_domain_ops,
......@@ -84,6 +84,19 @@ static int mx25_tsadc_setup_irq(struct platform_device *pdev,
return 0;
}
static int mx25_tsadc_unset_irq(struct platform_device *pdev)
{
struct mx25_tsadc *tsadc = platform_get_drvdata(pdev);
int irq = platform_get_irq(pdev, 0);
if (irq >= 0) {
irq_set_chained_handler_and_data(irq, NULL, NULL);
irq_domain_remove(tsadc->domain);
}
return 0;
}
static void mx25_tsadc_setup_clk(struct platform_device *pdev,
struct mx25_tsadc *tsadc)
{
......@@ -171,18 +184,21 @@ static int mx25_tsadc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, tsadc);
return devm_of_platform_populate(dev);
ret = devm_of_platform_populate(dev);
if (ret)
goto err_irq;
return 0;
err_irq:
mx25_tsadc_unset_irq(pdev);
return ret;
}
static int mx25_tsadc_remove(struct platform_device *pdev)
{
struct mx25_tsadc *tsadc = platform_get_drvdata(pdev);
int irq = platform_get_irq(pdev, 0);
if (irq) {
irq_set_chained_handler_and_data(irq, NULL, NULL);
irq_domain_remove(tsadc->domain);
}
mx25_tsadc_unset_irq(pdev);
return 0;
}
......
......@@ -20,7 +20,9 @@
#include <linux/irq.h>
#include <linux/spinlock.h>
#include <linux/htcpld.h>
#include <linux/gpio.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/machine.h>
#include <linux/gpio/consumer.h>
#include <linux/slab.h>
struct htcpld_chip {
......@@ -58,8 +60,8 @@ struct htcpld_data {
uint irq_start;
int nirqs;
uint chained_irq;
unsigned int int_reset_gpio_hi;
unsigned int int_reset_gpio_lo;
struct gpio_desc *int_reset_gpio_hi;
struct gpio_desc *int_reset_gpio_lo;
/* htcpld info */
struct htcpld_chip *chip;
......@@ -196,9 +198,9 @@ static irqreturn_t htcpld_handler(int irq, void *dev)
* be asserted.
*/
if (htcpld->int_reset_gpio_hi)
gpio_set_value(htcpld->int_reset_gpio_hi, 1);
gpiod_set_value(htcpld->int_reset_gpio_hi, 1);
if (htcpld->int_reset_gpio_lo)
gpio_set_value(htcpld->int_reset_gpio_lo, 0);
gpiod_set_value(htcpld->int_reset_gpio_lo, 0);
return IRQ_HANDLED;
}
......@@ -352,7 +354,7 @@ static int htcpld_register_chip_i2c(
memset(&info, 0, sizeof(struct i2c_board_info));
info.addr = plat_chip_data->addr;
strlcpy(info.type, "htcpld-chip", I2C_NAME_SIZE);
strscpy(info.type, "htcpld-chip", I2C_NAME_SIZE);
info.platform_data = chip;
/* Add the I2C device. This calls the probe() function. */
......@@ -562,34 +564,28 @@ static int htcpld_core_probe(struct platform_device *pdev)
return ret;
/* Request the GPIO(s) for the int reset and set them up */
if (pdata->int_reset_gpio_hi) {
ret = gpio_request(pdata->int_reset_gpio_hi, "htcpld-core");
if (ret) {
htcpld->int_reset_gpio_hi = gpiochip_request_own_desc(&htcpld->chip[2].chip_out,
7, "htcpld-core", GPIO_ACTIVE_HIGH,
GPIOD_OUT_HIGH);
if (IS_ERR(htcpld->int_reset_gpio_hi)) {
/*
* If it failed, that sucks, but we can probably
* continue on without it.
*/
htcpld->int_reset_gpio_hi = NULL;
dev_warn(dev, "Unable to request int_reset_gpio_hi -- interrupts may not work\n");
htcpld->int_reset_gpio_hi = 0;
} else {
htcpld->int_reset_gpio_hi = pdata->int_reset_gpio_hi;
gpio_set_value(htcpld->int_reset_gpio_hi, 1);
}
}
if (pdata->int_reset_gpio_lo) {
ret = gpio_request(pdata->int_reset_gpio_lo, "htcpld-core");
if (ret) {
htcpld->int_reset_gpio_lo = gpiochip_request_own_desc(&htcpld->chip[2].chip_out,
0, "htcpld-core", GPIO_ACTIVE_HIGH,
GPIOD_OUT_LOW);
if (IS_ERR(htcpld->int_reset_gpio_lo)) {
/*
* If it failed, that sucks, but we can probably
* continue on without it.
*/
htcpld->int_reset_gpio_lo = NULL;
dev_warn(dev, "Unable to request int_reset_gpio_lo -- interrupts may not work\n");
htcpld->int_reset_gpio_lo = 0;
} else {
htcpld->int_reset_gpio_lo = pdata->int_reset_gpio_lo;
gpio_set_value(htcpld->int_reset_gpio_lo, 0);
}
}
dev_info(dev, "Initialized successfully\n");
......
......@@ -14,6 +14,7 @@
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/pxa2xx_ssp.h>
#include "intel-lpss.h"
......@@ -73,8 +74,18 @@ static void intel_lpss_pci_remove(struct pci_dev *pdev)
static INTEL_LPSS_PM_OPS(intel_lpss_pci_pm_ops);
static const struct property_entry spt_spi_properties[] = {
PROPERTY_ENTRY_U32("intel,spi-pxa2xx-type", LPSS_SPT_SSP),
{ }
};
static const struct software_node spt_spi_node = {
.properties = spt_spi_properties,
};
static const struct intel_lpss_platform_info spt_info = {
.clk_rate = 120000000,
.swnode = &spt_spi_node,
};
static const struct property_entry spt_i2c_properties[] = {
......@@ -108,8 +119,18 @@ static const struct intel_lpss_platform_info spt_uart_info = {
.swnode = &uart_node,
};
static const struct property_entry bxt_spi_properties[] = {
PROPERTY_ENTRY_U32("intel,spi-pxa2xx-type", LPSS_BXT_SSP),
{ }
};
static const struct software_node bxt_spi_node = {
.properties = bxt_spi_properties,
};
static const struct intel_lpss_platform_info bxt_info = {
.clk_rate = 100000000,
.swnode = &bxt_spi_node,
};
static const struct intel_lpss_platform_info bxt_uart_info = {
......@@ -166,6 +187,20 @@ static const struct intel_lpss_platform_info glk_i2c_info = {
.swnode = &glk_i2c_node,
};
static const struct property_entry cnl_spi_properties[] = {
PROPERTY_ENTRY_U32("intel,spi-pxa2xx-type", LPSS_CNL_SSP),
{ }
};
static const struct software_node cnl_spi_node = {
.properties = cnl_spi_properties,
};
static const struct intel_lpss_platform_info cnl_info = {
.clk_rate = 120000000,
.swnode = &cnl_spi_node,
};
static const struct intel_lpss_platform_info cnl_i2c_info = {
.clk_rate = 216000000,
.swnode = &spt_i2c_node,
......@@ -176,12 +211,26 @@ static const struct intel_lpss_platform_info ehl_i2c_info = {
.swnode = &bxt_i2c_node,
};
static const struct property_entry tgl_spi_properties[] = {
PROPERTY_ENTRY_U32("intel,spi-pxa2xx-type", LPSS_CNL_SSP),
{ }
};
static const struct software_node tgl_spi_node = {
.properties = tgl_spi_properties,
};
static const struct intel_lpss_platform_info tgl_info = {
.clk_rate = 100000000,
.swnode = &tgl_spi_node,
};
static const struct pci_device_id intel_lpss_pci_ids[] = {
/* CML-LP */
{ PCI_VDEVICE(INTEL, 0x02a8), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0x02a9), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0x02aa), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x02ab), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x02aa), (kernel_ulong_t)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x02ab), (kernel_ulong_t)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x02c5), (kernel_ulong_t)&cnl_i2c_info },
{ PCI_VDEVICE(INTEL, 0x02c6), (kernel_ulong_t)&cnl_i2c_info },
{ PCI_VDEVICE(INTEL, 0x02c7), (kernel_ulong_t)&spt_uart_info },
......@@ -189,18 +238,18 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x02e9), (kernel_ulong_t)&cnl_i2c_info },
{ PCI_VDEVICE(INTEL, 0x02ea), (kernel_ulong_t)&cnl_i2c_info },
{ PCI_VDEVICE(INTEL, 0x02eb), (kernel_ulong_t)&cnl_i2c_info },
{ PCI_VDEVICE(INTEL, 0x02fb), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x02fb), (kernel_ulong_t)&cnl_info },
/* CML-H */
{ PCI_VDEVICE(INTEL, 0x06a8), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0x06a9), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0x06aa), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x06ab), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x06aa), (kernel_ulong_t)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x06ab), (kernel_ulong_t)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x06c7), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0x06e8), (kernel_ulong_t)&cnl_i2c_info },
{ PCI_VDEVICE(INTEL, 0x06e9), (kernel_ulong_t)&cnl_i2c_info },
{ PCI_VDEVICE(INTEL, 0x06ea), (kernel_ulong_t)&cnl_i2c_info },
{ PCI_VDEVICE(INTEL, 0x06eb), (kernel_ulong_t)&cnl_i2c_info },
{ PCI_VDEVICE(INTEL, 0x06fb), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x06fb), (kernel_ulong_t)&cnl_info },
/* BXT A-Step */
{ PCI_VDEVICE(INTEL, 0x0aac), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x0aae), (kernel_ulong_t)&bxt_i2c_info },
......@@ -255,8 +304,8 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
/* ICL-LP */
{ PCI_VDEVICE(INTEL, 0x34a8), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0x34a9), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0x34aa), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x34ab), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x34aa), (kernel_ulong_t)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x34ab), (kernel_ulong_t)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x34c5), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x34c6), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x34c7), (kernel_ulong_t)&spt_uart_info },
......@@ -264,15 +313,15 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x34e9), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x34ea), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x34eb), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x34fb), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x34fb), (kernel_ulong_t)&cnl_info },
/* ICL-N */
{ PCI_VDEVICE(INTEL, 0x38a8), (kernel_ulong_t)&spt_uart_info },
/* TGL-H */
{ PCI_VDEVICE(INTEL, 0x43a7), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x43a8), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x43a9), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x43aa), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x43ab), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x43aa), (kernel_ulong_t)&tgl_info },
{ PCI_VDEVICE(INTEL, 0x43ab), (kernel_ulong_t)&tgl_info },
{ PCI_VDEVICE(INTEL, 0x43ad), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x43ae), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x43d8), (kernel_ulong_t)&bxt_i2c_info },
......@@ -281,8 +330,8 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x43e9), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x43ea), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x43eb), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x43fb), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x43fd), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x43fb), (kernel_ulong_t)&tgl_info },
{ PCI_VDEVICE(INTEL, 0x43fd), (kernel_ulong_t)&tgl_info },
/* EHL */
{ PCI_VDEVICE(INTEL, 0x4b28), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x4b29), (kernel_ulong_t)&bxt_uart_info },
......@@ -301,8 +350,8 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
/* JSL */
{ PCI_VDEVICE(INTEL, 0x4da8), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0x4da9), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0x4daa), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x4dab), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x4daa), (kernel_ulong_t)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x4dab), (kernel_ulong_t)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x4dc5), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x4dc6), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x4dc7), (kernel_ulong_t)&spt_uart_info },
......@@ -310,12 +359,12 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x4de9), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x4dea), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x4deb), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x4dfb), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x4dfb), (kernel_ulong_t)&cnl_info },
/* ADL-P */
{ PCI_VDEVICE(INTEL, 0x51a8), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x51a9), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x51aa), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x51ab), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x51aa), (kernel_ulong_t)&tgl_info },
{ PCI_VDEVICE(INTEL, 0x51ab), (kernel_ulong_t)&tgl_info },
{ PCI_VDEVICE(INTEL, 0x51c5), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x51c6), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x51c7), (kernel_ulong_t)&bxt_uart_info },
......@@ -325,12 +374,12 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x51e9), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x51ea), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x51eb), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x51fb), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x51fb), (kernel_ulong_t)&tgl_info },
/* ADL-M */
{ PCI_VDEVICE(INTEL, 0x54a8), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x54a9), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x54aa), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x54ab), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x54aa), (kernel_ulong_t)&tgl_info },
{ PCI_VDEVICE(INTEL, 0x54ab), (kernel_ulong_t)&tgl_info },
{ PCI_VDEVICE(INTEL, 0x54c5), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x54c6), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x54c7), (kernel_ulong_t)&bxt_uart_info },
......@@ -338,7 +387,7 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x54e9), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x54ea), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x54eb), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x54fb), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x54fb), (kernel_ulong_t)&tgl_info },
/* APL */
{ PCI_VDEVICE(INTEL, 0x5aac), (kernel_ulong_t)&apl_i2c_info },
{ PCI_VDEVICE(INTEL, 0x5aae), (kernel_ulong_t)&apl_i2c_info },
......@@ -358,39 +407,39 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
/* RPL-S */
{ PCI_VDEVICE(INTEL, 0x7a28), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x7a29), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x7a2a), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x7a2b), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x7a2a), (kernel_ulong_t)&tgl_info },
{ PCI_VDEVICE(INTEL, 0x7a2b), (kernel_ulong_t)&tgl_info },
{ PCI_VDEVICE(INTEL, 0x7a4c), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x7a4d), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x7a4e), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x7a4f), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x7a5c), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x7a79), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x7a7b), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x7a79), (kernel_ulong_t)&tgl_info },
{ PCI_VDEVICE(INTEL, 0x7a7b), (kernel_ulong_t)&tgl_info },
{ PCI_VDEVICE(INTEL, 0x7a7c), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x7a7d), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x7a7e), (kernel_ulong_t)&bxt_uart_info },
/* ADL-S */
{ PCI_VDEVICE(INTEL, 0x7aa8), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x7aa9), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x7aaa), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x7aab), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x7aaa), (kernel_ulong_t)&tgl_info },
{ PCI_VDEVICE(INTEL, 0x7aab), (kernel_ulong_t)&tgl_info },
{ PCI_VDEVICE(INTEL, 0x7acc), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x7acd), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x7ace), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x7acf), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x7adc), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x7af9), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x7afb), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x7af9), (kernel_ulong_t)&tgl_info },
{ PCI_VDEVICE(INTEL, 0x7afb), (kernel_ulong_t)&tgl_info },
{ PCI_VDEVICE(INTEL, 0x7afc), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x7afd), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x7afe), (kernel_ulong_t)&bxt_uart_info },
/* MTL-P */
{ PCI_VDEVICE(INTEL, 0x7e25), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x7e26), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x7e27), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x7e30), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x7e46), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x7e27), (kernel_ulong_t)&tgl_info },
{ PCI_VDEVICE(INTEL, 0x7e30), (kernel_ulong_t)&tgl_info },
{ PCI_VDEVICE(INTEL, 0x7e46), (kernel_ulong_t)&tgl_info },
{ PCI_VDEVICE(INTEL, 0x7e50), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x7e51), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x7e52), (kernel_ulong_t)&bxt_uart_info },
......@@ -424,8 +473,8 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
/* CNL-LP */
{ PCI_VDEVICE(INTEL, 0x9da8), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0x9da9), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0x9daa), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x9dab), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x9daa), (kernel_ulong_t)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x9dab), (kernel_ulong_t)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x9dc5), (kernel_ulong_t)&cnl_i2c_info },
{ PCI_VDEVICE(INTEL, 0x9dc6), (kernel_ulong_t)&cnl_i2c_info },
{ PCI_VDEVICE(INTEL, 0x9dc7), (kernel_ulong_t)&spt_uart_info },
......@@ -433,12 +482,12 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x9de9), (kernel_ulong_t)&cnl_i2c_info },
{ PCI_VDEVICE(INTEL, 0x9dea), (kernel_ulong_t)&cnl_i2c_info },
{ PCI_VDEVICE(INTEL, 0x9deb), (kernel_ulong_t)&cnl_i2c_info },
{ PCI_VDEVICE(INTEL, 0x9dfb), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x9dfb), (kernel_ulong_t)&cnl_info },
/* TGL-LP */
{ PCI_VDEVICE(INTEL, 0xa0a8), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0xa0a9), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0xa0aa), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0xa0ab), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0xa0aa), (kernel_ulong_t)&cnl_info },
{ PCI_VDEVICE(INTEL, 0xa0ab), (kernel_ulong_t)&cnl_info },
{ PCI_VDEVICE(INTEL, 0xa0c5), (kernel_ulong_t)&spt_i2c_info },
{ PCI_VDEVICE(INTEL, 0xa0c6), (kernel_ulong_t)&spt_i2c_info },
{ PCI_VDEVICE(INTEL, 0xa0c7), (kernel_ulong_t)&bxt_uart_info },
......@@ -448,15 +497,15 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0xa0db), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0xa0dc), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0xa0dd), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0xa0de), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0xa0df), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0xa0de), (kernel_ulong_t)&cnl_info },
{ PCI_VDEVICE(INTEL, 0xa0df), (kernel_ulong_t)&cnl_info },
{ PCI_VDEVICE(INTEL, 0xa0e8), (kernel_ulong_t)&spt_i2c_info },
{ PCI_VDEVICE(INTEL, 0xa0e9), (kernel_ulong_t)&spt_i2c_info },
{ PCI_VDEVICE(INTEL, 0xa0ea), (kernel_ulong_t)&spt_i2c_info },
{ PCI_VDEVICE(INTEL, 0xa0eb), (kernel_ulong_t)&spt_i2c_info },
{ PCI_VDEVICE(INTEL, 0xa0fb), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0xa0fd), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0xa0fe), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0xa0fb), (kernel_ulong_t)&cnl_info },
{ PCI_VDEVICE(INTEL, 0xa0fd), (kernel_ulong_t)&cnl_info },
{ PCI_VDEVICE(INTEL, 0xa0fe), (kernel_ulong_t)&cnl_info },
/* SPT-H */
{ PCI_VDEVICE(INTEL, 0xa127), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0xa128), (kernel_ulong_t)&spt_uart_info },
......@@ -479,14 +528,14 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
/* CNL-H */
{ PCI_VDEVICE(INTEL, 0xa328), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0xa329), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0xa32a), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0xa32b), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0xa32a), (kernel_ulong_t)&cnl_info },
{ PCI_VDEVICE(INTEL, 0xa32b), (kernel_ulong_t)&cnl_info },
{ PCI_VDEVICE(INTEL, 0xa347), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0xa368), (kernel_ulong_t)&cnl_i2c_info },
{ PCI_VDEVICE(INTEL, 0xa369), (kernel_ulong_t)&cnl_i2c_info },
{ PCI_VDEVICE(INTEL, 0xa36a), (kernel_ulong_t)&cnl_i2c_info },
{ PCI_VDEVICE(INTEL, 0xa36b), (kernel_ulong_t)&cnl_i2c_info },
{ PCI_VDEVICE(INTEL, 0xa37b), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0xa37b), (kernel_ulong_t)&cnl_info },
/* CML-V */
{ PCI_VDEVICE(INTEL, 0xa3a7), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0xa3a8), (kernel_ulong_t)&spt_uart_info },
......
......@@ -21,6 +21,7 @@ enum m10bmc_type {
static struct mfd_cell m10bmc_d5005_subdevs[] = {
{ .name = "d5005bmc-hwmon" },
{ .name = "d5005bmc-sec-update" }
};
static struct mfd_cell m10bmc_pacn3000_subdevs[] = {
......
......@@ -140,7 +140,7 @@ static void chtdc_ti_shutdown(struct i2c_client *i2c)
disable_irq(pmic->irq);
}
static int __maybe_unused chtdc_ti_suspend(struct device *dev)
static int chtdc_ti_suspend(struct device *dev)
{
struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
......@@ -149,7 +149,7 @@ static int __maybe_unused chtdc_ti_suspend(struct device *dev)
return 0;
}
static int __maybe_unused chtdc_ti_resume(struct device *dev)
static int chtdc_ti_resume(struct device *dev)
{
struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
......@@ -158,7 +158,7 @@ static int __maybe_unused chtdc_ti_resume(struct device *dev)
return 0;
}
static SIMPLE_DEV_PM_OPS(chtdc_ti_pm_ops, chtdc_ti_suspend, chtdc_ti_resume);
static DEFINE_SIMPLE_DEV_PM_OPS(chtdc_ti_pm_ops, chtdc_ti_suspend, chtdc_ti_resume);
static const struct acpi_device_id chtdc_ti_acpi_ids[] = {
{ "INT33F5" },
......@@ -169,7 +169,7 @@ MODULE_DEVICE_TABLE(acpi, chtdc_ti_acpi_ids);
static struct i2c_driver chtdc_ti_i2c_driver = {
.driver = {
.name = "intel_soc_pmic_chtdc_ti",
.pm = &chtdc_ti_pm_ops,
.pm = pm_sleep_ptr(&chtdc_ti_pm_ops),
.acpi_match_table = chtdc_ti_acpi_ids,
},
.probe_new = chtdc_ti_probe,
......
// SPDX-License-Identifier: GPL-2.0
/*
* Intel SoC PMIC MFD Driver
*
* Copyright (C) 2013, 2014 Intel Corporation. All rights reserved.
*
* Author: Yang, Bin <bin.yang@intel.com>
* Author: Zhu, Lejun <lejun.zhu@linux.intel.com>
*/
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/mfd/core.h>
#include <linux/mfd/intel_soc_pmic.h>
#include <linux/platform_data/x86/soc.h>
#include <linux/pwm.h>
#include <linux/regmap.h>
#include "intel_soc_pmic_core.h"
/* PWM consumed by the Intel GFX */
static struct pwm_lookup crc_pwm_lookup[] = {
PWM_LOOKUP("crystal_cove_pwm", 0, "0000:00:02.0", "pwm_pmic_backlight", 0, PWM_POLARITY_NORMAL),
};
static int intel_soc_pmic_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *i2c_id)
{
struct device *dev = &i2c->dev;
struct intel_soc_pmic_config *config;
struct intel_soc_pmic *pmic;
int ret;
if (soc_intel_is_byt())
config = &intel_soc_pmic_config_byt_crc;
else
config = &intel_soc_pmic_config_cht_crc;
pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
if (!pmic)
return -ENOMEM;
dev_set_drvdata(dev, pmic);
pmic->regmap = devm_regmap_init_i2c(i2c, config->regmap_config);
if (IS_ERR(pmic->regmap))
return PTR_ERR(pmic->regmap);
pmic->irq = i2c->irq;
ret = regmap_add_irq_chip(pmic->regmap, pmic->irq,
config->irq_flags | IRQF_ONESHOT,
0, config->irq_chip,
&pmic->irq_chip_data);
if (ret)
return ret;
ret = enable_irq_wake(pmic->irq);
if (ret)
dev_warn(dev, "Can't enable IRQ as wake source: %d\n", ret);
/* Add lookup table for crc-pwm */
pwm_add_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup));
/* To distuingish this domain from the GPIO/charger's irqchip domains */
irq_domain_update_bus_token(regmap_irq_get_domain(pmic->irq_chip_data),
DOMAIN_BUS_NEXUS);
ret = mfd_add_devices(dev, -1, config->cell_dev,
config->n_cell_devs, NULL, 0,
regmap_irq_get_domain(pmic->irq_chip_data));
if (ret)
goto err_del_irq_chip;
return 0;
err_del_irq_chip:
regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data);
return ret;
}
static void intel_soc_pmic_i2c_remove(struct i2c_client *i2c)
{
struct intel_soc_pmic *pmic = dev_get_drvdata(&i2c->dev);
regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data);
/* remove crc-pwm lookup table */
pwm_remove_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup));
mfd_remove_devices(&i2c->dev);
}
static void intel_soc_pmic_shutdown(struct i2c_client *i2c)
{
struct intel_soc_pmic *pmic = dev_get_drvdata(&i2c->dev);
disable_irq(pmic->irq);
return;
}
#if defined(CONFIG_PM_SLEEP)
static int intel_soc_pmic_suspend(struct device *dev)
{
struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
disable_irq(pmic->irq);
return 0;
}
static int intel_soc_pmic_resume(struct device *dev)
{
struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
enable_irq(pmic->irq);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(intel_soc_pmic_pm_ops, intel_soc_pmic_suspend,
intel_soc_pmic_resume);
static const struct i2c_device_id intel_soc_pmic_i2c_id[] = {
{ }
};
MODULE_DEVICE_TABLE(i2c, intel_soc_pmic_i2c_id);
#if defined(CONFIG_ACPI)
static const struct acpi_device_id intel_soc_pmic_acpi_match[] = {
{ "INT33FD" },
{ },
};
MODULE_DEVICE_TABLE(acpi, intel_soc_pmic_acpi_match);
#endif
static struct i2c_driver intel_soc_pmic_i2c_driver = {
.driver = {
.name = "intel_soc_pmic_i2c",
.pm = &intel_soc_pmic_pm_ops,
.acpi_match_table = ACPI_PTR(intel_soc_pmic_acpi_match),
},
.probe = intel_soc_pmic_i2c_probe,
.remove = intel_soc_pmic_i2c_remove,
.id_table = intel_soc_pmic_i2c_id,
.shutdown = intel_soc_pmic_shutdown,
};
module_i2c_driver(intel_soc_pmic_i2c_driver);
MODULE_DESCRIPTION("I2C driver for Intel SoC PMIC");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Yang, Bin <bin.yang@intel.com>");
MODULE_AUTHOR("Zhu, Lejun <lejun.zhu@linux.intel.com>");
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Intel SoC PMIC MFD Driver
*
* Copyright (C) 2012-2014 Intel Corporation. All rights reserved.
*
* Author: Yang, Bin <bin.yang@intel.com>
* Author: Zhu, Lejun <lejun.zhu@linux.intel.com>
*/
#ifndef __INTEL_SOC_PMIC_CORE_H__
#define __INTEL_SOC_PMIC_CORE_H__
struct intel_soc_pmic_config {
unsigned long irq_flags;
struct mfd_cell *cell_dev;
int n_cell_devs;
const struct regmap_config *regmap_config;
const struct regmap_irq_chip *irq_chip;
};
extern struct intel_soc_pmic_config intel_soc_pmic_config_byt_crc;
extern struct intel_soc_pmic_config intel_soc_pmic_config_cht_crc;
#endif /* __INTEL_SOC_PMIC_CORE_H__ */
......@@ -2,18 +2,21 @@
/*
* Device access for Crystal Cove PMIC
*
* Copyright (C) 2013, 2014 Intel Corporation. All rights reserved.
* Copyright (C) 2012-2014, 2022 Intel Corporation. All rights reserved.
*
* Author: Yang, Bin <bin.yang@intel.com>
* Author: Zhu, Lejun <lejun.zhu@linux.intel.com>
*/
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/regmap.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mfd/core.h>
#include <linux/mfd/intel_soc_pmic.h>
#include "intel_soc_pmic_core.h"
#include <linux/platform_data/x86/soc.h>
#include <linux/pwm.h>
#include <linux/regmap.h>
#define CRYSTAL_COVE_MAX_REGISTER 0xC6
......@@ -132,7 +135,20 @@ static const struct regmap_irq_chip crystal_cove_irq_chip = {
.mask_base = CRYSTAL_COVE_REG_MIRQLVL1,
};
struct intel_soc_pmic_config intel_soc_pmic_config_byt_crc = {
/* PWM consumed by the Intel GFX */
static struct pwm_lookup crc_pwm_lookup[] = {
PWM_LOOKUP("crystal_cove_pwm", 0, "0000:00:02.0", "pwm_pmic_backlight", 0, PWM_POLARITY_NORMAL),
};
struct crystal_cove_config {
unsigned long irq_flags;
struct mfd_cell *cell_dev;
int n_cell_devs;
const struct regmap_config *regmap_config;
const struct regmap_irq_chip *irq_chip;
};
static const struct crystal_cove_config crystal_cove_config_byt_crc = {
.irq_flags = IRQF_TRIGGER_RISING,
.cell_dev = crystal_cove_byt_dev,
.n_cell_devs = ARRAY_SIZE(crystal_cove_byt_dev),
......@@ -140,10 +156,121 @@ struct intel_soc_pmic_config intel_soc_pmic_config_byt_crc = {
.irq_chip = &crystal_cove_irq_chip,
};
struct intel_soc_pmic_config intel_soc_pmic_config_cht_crc = {
static const struct crystal_cove_config crystal_cove_config_cht_crc = {
.irq_flags = IRQF_TRIGGER_RISING,
.cell_dev = crystal_cove_cht_dev,
.n_cell_devs = ARRAY_SIZE(crystal_cove_cht_dev),
.regmap_config = &crystal_cove_regmap_config,
.irq_chip = &crystal_cove_irq_chip,
};
static int crystal_cove_i2c_probe(struct i2c_client *i2c)
{
const struct crystal_cove_config *config;
struct device *dev = &i2c->dev;
struct intel_soc_pmic *pmic;
int ret;
if (soc_intel_is_byt())
config = &crystal_cove_config_byt_crc;
else
config = &crystal_cove_config_cht_crc;
pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
if (!pmic)
return -ENOMEM;
i2c_set_clientdata(i2c, pmic);
pmic->regmap = devm_regmap_init_i2c(i2c, config->regmap_config);
if (IS_ERR(pmic->regmap))
return PTR_ERR(pmic->regmap);
pmic->irq = i2c->irq;
ret = devm_regmap_add_irq_chip(dev, pmic->regmap, pmic->irq,
config->irq_flags | IRQF_ONESHOT,
0, config->irq_chip, &pmic->irq_chip_data);
if (ret)
return ret;
ret = enable_irq_wake(pmic->irq);
if (ret)
dev_warn(dev, "Can't enable IRQ as wake source: %d\n", ret);
/* Add lookup table for crc-pwm */
pwm_add_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup));
/* To distuingish this domain from the GPIO/charger's irqchip domains */
irq_domain_update_bus_token(regmap_irq_get_domain(pmic->irq_chip_data),
DOMAIN_BUS_NEXUS);
ret = mfd_add_devices(dev, PLATFORM_DEVID_NONE, config->cell_dev,
config->n_cell_devs, NULL, 0,
regmap_irq_get_domain(pmic->irq_chip_data));
if (ret)
pwm_remove_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup));
return ret;
}
static void crystal_cove_i2c_remove(struct i2c_client *i2c)
{
/* remove crc-pwm lookup table */
pwm_remove_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup));
mfd_remove_devices(&i2c->dev);
}
static void crystal_cove_shutdown(struct i2c_client *i2c)
{
struct intel_soc_pmic *pmic = i2c_get_clientdata(i2c);
disable_irq(pmic->irq);
return;
}
static int crystal_cove_suspend(struct device *dev)
{
struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
disable_irq(pmic->irq);
return 0;
}
static int crystal_cove_resume(struct device *dev)
{
struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
enable_irq(pmic->irq);
return 0;
}
static DEFINE_SIMPLE_DEV_PM_OPS(crystal_cove_pm_ops, crystal_cove_suspend, crystal_cove_resume);
static const struct acpi_device_id crystal_cove_acpi_match[] = {
{ "INT33FD" },
{ },
};
MODULE_DEVICE_TABLE(acpi, crystal_cove_acpi_match);
static struct i2c_driver crystal_cove_i2c_driver = {
.driver = {
.name = "crystal_cove_i2c",
.pm = pm_sleep_ptr(&crystal_cove_pm_ops),
.acpi_match_table = crystal_cove_acpi_match,
},
.probe_new = crystal_cove_i2c_probe,
.remove = crystal_cove_i2c_remove,
.shutdown = crystal_cove_shutdown,
};
module_i2c_driver(crystal_cove_i2c_driver);
MODULE_DESCRIPTION("I2C driver for Intel SoC PMIC");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Yang, Bin <bin.yang@intel.com>");
MODULE_AUTHOR("Zhu, Lejun <lejun.zhu@linux.intel.com>");
......@@ -175,6 +175,7 @@ int lp8788_irq_init(struct lp8788 *lp, int irq)
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"lp8788-irq", irqd);
if (ret) {
irq_domain_remove(lp->irqdm);
dev_err(lp->dev, "failed to create a thread for IRQ_N\n");
return ret;
}
......@@ -188,4 +189,6 @@ void lp8788_irq_exit(struct lp8788 *lp)
{
if (lp->irq)
free_irq(lp->irq, lp->irqdm);
if (lp->irqdm)
irq_domain_remove(lp->irqdm);
}
......@@ -195,8 +195,16 @@ static int lp8788_probe(struct i2c_client *cl, const struct i2c_device_id *id)
if (ret)
return ret;
return mfd_add_devices(lp->dev, -1, lp8788_devs,
ret = mfd_add_devices(lp->dev, -1, lp8788_devs,
ARRAY_SIZE(lp8788_devs), NULL, 0, NULL);
if (ret)
goto err_exit_irq;
return 0;
err_exit_irq:
lp8788_irq_exit(lp);
return ret;
}
static void lp8788_remove(struct i2c_client *cl)
......
......@@ -959,7 +959,7 @@ static int lpc_ich_finalize_wdt_cell(struct pci_dev *dev)
info = &lpc_chipset_info[priv->chipset];
pdata->version = info->iTCO_version;
strlcpy(pdata->name, info->name, sizeof(pdata->name));
strscpy(pdata->name, info->name, sizeof(pdata->name));
cell->platform_data = pdata;
cell->pdata_size = sizeof(*pdata);
......
......@@ -105,7 +105,7 @@ static void mfd_acpi_add_device(const struct mfd_cell *cell,
.ids = ids,
};
strlcpy(ids[0].id, match->pnpid, sizeof(ids[0].id));
strscpy(ids[0].id, match->pnpid, sizeof(ids[0].id));
acpi_dev_for_each_child(parent, match_device_ids, &wd);
adev = wd.adev;
} else {
......@@ -368,6 +368,7 @@ static int mfd_remove_devices_fn(struct device *dev, void *data)
{
struct platform_device *pdev;
const struct mfd_cell *cell;
struct mfd_of_node_entry *of_entry, *tmp;
int *level = data;
if (dev->type != &mfd_dev_type)
......@@ -382,6 +383,12 @@ static int mfd_remove_devices_fn(struct device *dev, void *data)
if (cell->swnode)
device_remove_software_node(&pdev->dev);
list_for_each_entry_safe(of_entry, tmp, &mfd_of_node_list, list)
if (of_entry->dev == &pdev->dev) {
list_del(&of_entry->list);
kfree(of_entry);
}
regulator_bulk_unregister_supply_alias(dev, cell->parent_supplies,
cell->num_parent_supplies);
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2022 Richtek Technology Corp.
*
* Author: ChiYuan Huang <cy_huang@richtek.com>
*/
#include <linux/bits.h>
#include <linux/bitfield.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mfd/core.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include "mt6370.h"
#define MT6370_REG_DEV_INFO 0x100
#define MT6370_REG_CHG_IRQ1 0x1C0
#define MT6370_REG_CHG_MASK1 0x1E0
#define MT6370_REG_MAXADDR 0x1FF
#define MT6370_VENID_MASK GENMASK(7, 4)
#define MT6370_NUM_IRQREGS 16
#define MT6370_USBC_I2CADDR 0x4E
#define MT6370_MAX_ADDRLEN 2
#define MT6370_VENID_RT5081 0x8
#define MT6370_VENID_RT5081A 0xA
#define MT6370_VENID_MT6370 0xE
#define MT6370_VENID_MT6371 0xF
#define MT6370_VENID_MT6372P 0x9
#define MT6370_VENID_MT6372CP 0xB
static const struct regmap_irq mt6370_irqs[] = {
REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHGON, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_TREG, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_AICR, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_MIVR, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_PWR_RDY, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_FL_CHG_VINOVP, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VSYSUV, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VSYSOV, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VBATOV, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VINOVPCHG, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_COLD, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_COOL, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_WARM, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_HOT, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_STATC, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_FAULT, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_STATC, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_TMR, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_BATABS, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_ADPBAD, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_RVP, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_TSHUTDOWN, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_IINMEAS, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_ICCMEAS, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHGDET_DONE, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_WDTMR, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_SSFINISH, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_RECHG, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_TERM, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_IEOC, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_ADC_DONE, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_PUMPX_DONE, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_BST_BATUV, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_BST_MIDOV, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_BST_OLP, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_ATTACH, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_DETACH, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_HVDCP_STPDONE, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_HVDCP_VBUSDET_DONE, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_HVDCP_DET, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHGDET, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_DCDT, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_VGOK, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_WDTMR, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_UC, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_OC, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_OV, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_SWON, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_UVP_D, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_UVP, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_OVP_D, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_OVP, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_STRBPIN, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_TORPIN, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_TX, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_LVF, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED2_SHORT, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_SHORT, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED2_STRB, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_STRB, 8),
REGMAP_IRQ_REG_LINE(mT6370_IRQ_FLED2_STRB_TO, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_STRB_TO, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED2_TOR, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_TOR, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_OTP, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_VDDA_OVP, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_VDDA_UV, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_LDO_OC, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_BLED_OCP, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_BLED_OVP, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VNEG_OCP, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VPOS_OCP, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_BST_OCP, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VNEG_SCP, 8),
REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VPOS_SCP, 8),
};
static const struct regmap_irq_chip mt6370_irq_chip = {
.name = "mt6370-irqs",
.status_base = MT6370_REG_CHG_IRQ1,
.mask_base = MT6370_REG_CHG_MASK1,
.num_regs = MT6370_NUM_IRQREGS,
.irqs = mt6370_irqs,
.num_irqs = ARRAY_SIZE(mt6370_irqs),
};
static const struct resource mt6370_regulator_irqs[] = {
DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VPOS_SCP, "db_vpos_scp"),
DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VNEG_SCP, "db_vneg_scp"),
DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_BST_OCP, "db_vbst_ocp"),
DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VPOS_OCP, "db_vpos_ocp"),
DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VNEG_OCP, "db_vneg_ocp"),
DEFINE_RES_IRQ_NAMED(MT6370_IRQ_LDO_OC, "ldo_oc"),
};
static const struct mfd_cell mt6370_devices[] = {
MFD_CELL_OF("mt6370-adc",
NULL, NULL, 0, 0, "mediatek,mt6370-adc"),
MFD_CELL_OF("mt6370-charger",
NULL, NULL, 0, 0, "mediatek,mt6370-charger"),
MFD_CELL_OF("mt6370-flashlight",
NULL, NULL, 0, 0, "mediatek,mt6370-flashlight"),
MFD_CELL_OF("mt6370-indicator",
NULL, NULL, 0, 0, "mediatek,mt6370-indicator"),
MFD_CELL_OF("mt6370-tcpc",
NULL, NULL, 0, 0, "mediatek,mt6370-tcpc"),
MFD_CELL_RES("mt6370-regulator", mt6370_regulator_irqs),
};
static const struct mfd_cell mt6370_exclusive_devices[] = {
MFD_CELL_OF("mt6370-backlight",
NULL, NULL, 0, 0, "mediatek,mt6370-backlight"),
};
static const struct mfd_cell mt6372_exclusive_devices[] = {
MFD_CELL_OF("mt6370-backlight",
NULL, NULL, 0, 0, "mediatek,mt6372-backlight"),
};
static int mt6370_check_vendor_info(struct device *dev, struct regmap *rmap,
int *vid)
{
unsigned int devinfo;
int ret;
ret = regmap_read(rmap, MT6370_REG_DEV_INFO, &devinfo);
if (ret)
return ret;
*vid = FIELD_GET(MT6370_VENID_MASK, devinfo);
switch (*vid) {
case MT6370_VENID_RT5081:
case MT6370_VENID_RT5081A:
case MT6370_VENID_MT6370:
case MT6370_VENID_MT6371:
case MT6370_VENID_MT6372P:
case MT6370_VENID_MT6372CP:
return 0;
default:
dev_err(dev, "Unknown Vendor ID 0x%02x\n", devinfo);
return -ENODEV;
}
}
static int mt6370_regmap_read(void *context, const void *reg_buf,
size_t reg_size, void *val_buf, size_t val_size)
{
struct mt6370_info *info = context;
const u8 *u8_buf = reg_buf;
u8 bank_idx, bank_addr;
int ret;
bank_idx = u8_buf[0];
bank_addr = u8_buf[1];
ret = i2c_smbus_read_i2c_block_data(info->i2c[bank_idx], bank_addr,
val_size, val_buf);
if (ret < 0)
return ret;
if (ret != val_size)
return -EIO;
return 0;
}
static int mt6370_regmap_write(void *context, const void *data, size_t count)
{
struct mt6370_info *info = context;
const u8 *u8_buf = data;
u8 bank_idx, bank_addr;
int len = count - MT6370_MAX_ADDRLEN;
bank_idx = u8_buf[0];
bank_addr = u8_buf[1];
return i2c_smbus_write_i2c_block_data(info->i2c[bank_idx], bank_addr,
len, data + MT6370_MAX_ADDRLEN);
}
static const struct regmap_bus mt6370_regmap_bus = {
.read = mt6370_regmap_read,
.write = mt6370_regmap_write,
};
static const struct regmap_config mt6370_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
.reg_format_endian = REGMAP_ENDIAN_BIG,
.max_register = MT6370_REG_MAXADDR,
};
static int mt6370_probe(struct i2c_client *i2c)
{
struct mt6370_info *info;
struct i2c_client *usbc_i2c;
struct regmap *regmap;
struct device *dev = &i2c->dev;
int ret, vid;
info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
usbc_i2c = devm_i2c_new_dummy_device(dev, i2c->adapter,
MT6370_USBC_I2CADDR);
if (IS_ERR(usbc_i2c))
return dev_err_probe(dev, PTR_ERR(usbc_i2c),
"Failed to register USBC I2C client\n");
/* Assign I2C client for PMU and TypeC */
info->i2c[MT6370_PMU_I2C] = i2c;
info->i2c[MT6370_USBC_I2C] = usbc_i2c;
regmap = devm_regmap_init(dev, &mt6370_regmap_bus,
info, &mt6370_regmap_config);
if (IS_ERR(regmap))
return dev_err_probe(dev, PTR_ERR(regmap),
"Failed to init regmap\n");
ret = mt6370_check_vendor_info(dev, regmap, &vid);
if (ret)
return dev_err_probe(dev, ret, "Failed to check vendor info\n");
ret = devm_regmap_add_irq_chip(dev, regmap, i2c->irq,
IRQF_ONESHOT, -1, &mt6370_irq_chip,
&info->irq_data);
if (ret)
return dev_err_probe(dev, ret, "Failed to add irq chip\n");
switch (vid) {
case MT6370_VENID_MT6372P:
case MT6370_VENID_MT6372CP:
ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO,
mt6372_exclusive_devices,
ARRAY_SIZE(mt6372_exclusive_devices),
NULL, 0,
regmap_irq_get_domain(info->irq_data));
break;
default:
ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO,
mt6370_exclusive_devices,
ARRAY_SIZE(mt6370_exclusive_devices),
NULL, 0,
regmap_irq_get_domain(info->irq_data));
break;
}
if (ret)
return dev_err_probe(dev, ret, "Failed to add the exclusive devices\n");
return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO,
mt6370_devices, ARRAY_SIZE(mt6370_devices),
NULL, 0,
regmap_irq_get_domain(info->irq_data));
}
static const struct of_device_id mt6370_match_table[] = {
{ .compatible = "mediatek,mt6370" },
{}
};
MODULE_DEVICE_TABLE(of, mt6370_match_table);
static struct i2c_driver mt6370_driver = {
.driver = {
.name = "mt6370",
.of_match_table = mt6370_match_table,
},
.probe_new = mt6370_probe,
};
module_i2c_driver(mt6370_driver);
MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
MODULE_DESCRIPTION("MediaTek MT6370 SubPMIC Driver");
MODULE_LICENSE("GPL v2");
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2022 Richtek Technology Corp.
*
* Author: ChiYuan Huang <cy_huang@richtek.com>
*/
#ifndef __MFD_MT6370_H__
#define __MFD_MT6370_H__
/* IRQ definitions */
#define MT6370_IRQ_DIRCHGON 0
#define MT6370_IRQ_CHG_TREG 4
#define MT6370_IRQ_CHG_AICR 5
#define MT6370_IRQ_CHG_MIVR 6
#define MT6370_IRQ_PWR_RDY 7
#define MT6370_IRQ_FL_CHG_VINOVP 11
#define MT6370_IRQ_CHG_VSYSUV 12
#define MT6370_IRQ_CHG_VSYSOV 13
#define MT6370_IRQ_CHG_VBATOV 14
#define MT6370_IRQ_CHG_VINOVPCHG 15
#define MT6370_IRQ_TS_BAT_COLD 20
#define MT6370_IRQ_TS_BAT_COOL 21
#define MT6370_IRQ_TS_BAT_WARM 22
#define MT6370_IRQ_TS_BAT_HOT 23
#define MT6370_IRQ_TS_STATC 24
#define MT6370_IRQ_CHG_FAULT 25
#define MT6370_IRQ_CHG_STATC 26
#define MT6370_IRQ_CHG_TMR 27
#define MT6370_IRQ_CHG_BATABS 28
#define MT6370_IRQ_CHG_ADPBAD 29
#define MT6370_IRQ_CHG_RVP 30
#define MT6370_IRQ_TSHUTDOWN 31
#define MT6370_IRQ_CHG_IINMEAS 32
#define MT6370_IRQ_CHG_ICCMEAS 33
#define MT6370_IRQ_CHGDET_DONE 34
#define MT6370_IRQ_WDTMR 35
#define MT6370_IRQ_SSFINISH 36
#define MT6370_IRQ_CHG_RECHG 37
#define MT6370_IRQ_CHG_TERM 38
#define MT6370_IRQ_CHG_IEOC 39
#define MT6370_IRQ_ADC_DONE 40
#define MT6370_IRQ_PUMPX_DONE 41
#define MT6370_IRQ_BST_BATUV 45
#define MT6370_IRQ_BST_MIDOV 46
#define MT6370_IRQ_BST_OLP 47
#define MT6370_IRQ_ATTACH 48
#define MT6370_IRQ_DETACH 49
#define MT6370_IRQ_HVDCP_STPDONE 51
#define MT6370_IRQ_HVDCP_VBUSDET_DONE 52
#define MT6370_IRQ_HVDCP_DET 53
#define MT6370_IRQ_CHGDET 54
#define MT6370_IRQ_DCDT 55
#define MT6370_IRQ_DIRCHG_VGOK 59
#define MT6370_IRQ_DIRCHG_WDTMR 60
#define MT6370_IRQ_DIRCHG_UC 61
#define MT6370_IRQ_DIRCHG_OC 62
#define MT6370_IRQ_DIRCHG_OV 63
#define MT6370_IRQ_OVPCTRL_SWON 67
#define MT6370_IRQ_OVPCTRL_UVP_D 68
#define MT6370_IRQ_OVPCTRL_UVP 69
#define MT6370_IRQ_OVPCTRL_OVP_D 70
#define MT6370_IRQ_OVPCTRL_OVP 71
#define MT6370_IRQ_FLED_STRBPIN 72
#define MT6370_IRQ_FLED_TORPIN 73
#define MT6370_IRQ_FLED_TX 74
#define MT6370_IRQ_FLED_LVF 75
#define MT6370_IRQ_FLED2_SHORT 78
#define MT6370_IRQ_FLED1_SHORT 79
#define MT6370_IRQ_FLED2_STRB 80
#define MT6370_IRQ_FLED1_STRB 81
#define mT6370_IRQ_FLED2_STRB_TO 82
#define MT6370_IRQ_FLED1_STRB_TO 83
#define MT6370_IRQ_FLED2_TOR 84
#define MT6370_IRQ_FLED1_TOR 85
#define MT6370_IRQ_OTP 93
#define MT6370_IRQ_VDDA_OVP 94
#define MT6370_IRQ_VDDA_UV 95
#define MT6370_IRQ_LDO_OC 103
#define MT6370_IRQ_BLED_OCP 118
#define MT6370_IRQ_BLED_OVP 119
#define MT6370_IRQ_DSV_VNEG_OCP 123
#define MT6370_IRQ_DSV_VPOS_OCP 124
#define MT6370_IRQ_DSV_BST_OCP 125
#define MT6370_IRQ_DSV_VNEG_SCP 126
#define MT6370_IRQ_DSV_VPOS_SCP 127
enum {
MT6370_USBC_I2C = 0,
MT6370_PMU_I2C,
MT6370_MAX_I2C
};
struct mt6370_info {
struct i2c_client *i2c[MT6370_MAX_I2C];
struct regmap_irq_chip_data *irq_data;
};
#endif /* __MFD_MT6375_H__ */
......@@ -276,6 +276,7 @@ static const struct spi_device_id ocelot_spi_ids[] = {
{ "vsc7512", 0 },
{ }
};
MODULE_DEVICE_TABLE(spi, ocelot_spi_ids);
static const struct of_device_id ocelot_spi_of_match[] = {
{ .compatible = "mscc,vsc7512" },
......
......@@ -60,6 +60,7 @@ static const struct of_device_id pmic_spmi_id_table[] = {
{ .compatible = "qcom,pmi8994", .data = N_USIDS(2) },
{ .compatible = "qcom,pmi8998", .data = N_USIDS(2) },
{ .compatible = "qcom,pmk8002", .data = N_USIDS(2) },
{ .compatible = "qcom,pmp8074", .data = N_USIDS(2) },
{ .compatible = "qcom,smb2351", .data = N_USIDS(2) },
{ .compatible = "qcom,spmi-pmic", .data = N_USIDS(1) },
{ }
......
......@@ -67,6 +67,10 @@ static bool rk817_is_volatile_reg(struct device *dev, unsigned int reg)
case RK817_SECONDS_REG ... RK817_WEEKS_REG:
case RK817_RTC_STATUS_REG:
case RK817_CODEC_DTOP_LPT_SRST:
case RK817_GAS_GAUGE_ADC_CONFIG0 ... RK817_GAS_GAUGE_CUR_ADC_K0:
case RK817_PMIC_CHRG_STS:
case RK817_PMIC_CHRG_OUT:
case RK817_PMIC_CHRG_IN:
case RK817_INT_STS_REG0:
case RK817_INT_STS_REG1:
case RK817_INT_STS_REG2:
......@@ -74,7 +78,7 @@ static bool rk817_is_volatile_reg(struct device *dev, unsigned int reg)
return true;
}
return true;
return false;
}
static const struct regmap_config rk818_regmap_config = {
......@@ -127,6 +131,11 @@ static const struct resource rk817_pwrkey_resources[] = {
DEFINE_RES_IRQ(RK817_IRQ_PWRON_FALL),
};
static const struct resource rk817_charger_resources[] = {
DEFINE_RES_IRQ(RK817_IRQ_PLUG_IN),
DEFINE_RES_IRQ(RK817_IRQ_PLUG_OUT),
};
static const struct mfd_cell rk805s[] = {
{ .name = "rk808-clkout", },
{ .name = "rk808-regulator", },
......@@ -166,6 +175,11 @@ static const struct mfd_cell rk817s[] = {
.resources = &rk817_rtc_resources[0],
},
{ .name = "rk817-codec",},
{
.name = "rk817-charger",
.num_resources = ARRAY_SIZE(rk817_charger_resources),
.resources = &rk817_charger_resources[0],
},
};
static const struct mfd_cell rk818s[] = {
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2022 Richtek Technology Corp.
* Author: ChiYuan Huang <cy_huang@richtek.com>
*/
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/mfd/core.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/regmap.h>
#define RT5120_REG_INTENABLE 0x1D
#define RT5120_REG_INTSTAT 0x1E
#define RT5120_REG_FZCMODE 0x44
#define RT5120_INT_HOTDIE 0
#define RT5120_INT_PWRKEY_REL 5
#define RT5120_INT_PWRKEY_PRESS 6
static const struct regmap_range rt5120_rd_yes_ranges[] = {
regmap_reg_range(0x03, 0x13),
regmap_reg_range(0x1c, 0x20),
regmap_reg_range(0x44, 0x44),
};
static const struct regmap_range rt5120_wr_yes_ranges[] = {
regmap_reg_range(0x06, 0x13),
regmap_reg_range(0x1c, 0x20),
regmap_reg_range(0x44, 0x44),
};
static const struct regmap_access_table rt5120_rd_table = {
.yes_ranges = rt5120_rd_yes_ranges,
.n_yes_ranges = ARRAY_SIZE(rt5120_rd_yes_ranges),
};
static const struct regmap_access_table rt5120_wr_table = {
.yes_ranges = rt5120_wr_yes_ranges,
.n_yes_ranges = ARRAY_SIZE(rt5120_wr_yes_ranges),
};
static const struct regmap_config rt5120_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = RT5120_REG_FZCMODE,
.wr_table = &rt5120_wr_table,
.rd_table = &rt5120_rd_table,
};
static const struct regmap_irq rt5120_irqs[] = {
REGMAP_IRQ_REG_LINE(RT5120_INT_HOTDIE, 8),
REGMAP_IRQ_REG_LINE(RT5120_INT_PWRKEY_REL, 8),
REGMAP_IRQ_REG_LINE(RT5120_INT_PWRKEY_PRESS, 8),
};
static const struct regmap_irq_chip rt5120_irq_chip = {
.name = "rt5120-pmic",
.status_base = RT5120_REG_INTSTAT,
.mask_base = RT5120_REG_INTENABLE,
.ack_base = RT5120_REG_INTSTAT,
.mask_invert = true,
.use_ack = true,
.num_regs = 1,
.irqs = rt5120_irqs,
.num_irqs = ARRAY_SIZE(rt5120_irqs),
};
static const struct resource rt5120_regulator_resources[] = {
DEFINE_RES_IRQ(RT5120_INT_HOTDIE),
};
static const struct resource rt5120_pwrkey_resources[] = {
DEFINE_RES_IRQ_NAMED(RT5120_INT_PWRKEY_PRESS, "pwrkey-press"),
DEFINE_RES_IRQ_NAMED(RT5120_INT_PWRKEY_REL, "pwrkey-release"),
};
static const struct mfd_cell rt5120_devs[] = {
MFD_CELL_RES("rt5120-regulator", rt5120_regulator_resources),
MFD_CELL_OF("rt5120-pwrkey", rt5120_pwrkey_resources, NULL, 0, 0, "richtek,rt5120-pwrkey"),
};
static int rt5120_probe(struct i2c_client *i2c)
{
struct device *dev = &i2c->dev;
struct regmap *regmap;
struct regmap_irq_chip_data *irq_data;
int ret;
regmap = devm_regmap_init_i2c(i2c, &rt5120_regmap_config);
if (IS_ERR(regmap))
return dev_err_probe(dev, PTR_ERR(regmap),
"Failed to init regmap\n");
ret = devm_regmap_add_irq_chip(dev, regmap, i2c->irq, IRQF_ONESHOT, 0,
&rt5120_irq_chip, &irq_data);
if (ret)
return dev_err_probe(dev, ret, "Failed to add IRQ chip\n");
return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, rt5120_devs,
ARRAY_SIZE(rt5120_devs), NULL, 0,
regmap_irq_get_domain(irq_data));
}
static const struct of_device_id rt5120_device_match_table[] = {
{ .compatible = "richtek,rt5120" },
{}
};
MODULE_DEVICE_TABLE(of, rt5120_device_match_table);
static struct i2c_driver rt5120_driver = {
.driver = {
.name = "rt5120",
.of_match_table = rt5120_device_match_table,
},
.probe_new = rt5120_probe,
};
module_i2c_driver(rt5120_driver);
MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
MODULE_DESCRIPTION("Richtek RT5120 I2C driver");
MODULE_LICENSE("GPL v2");
......@@ -1720,7 +1720,12 @@ static struct platform_driver sm501_plat_driver = {
static int __init sm501_base_init(void)
{
platform_driver_register(&sm501_plat_driver);
int ret;
ret = platform_driver_register(&sm501_plat_driver);
if (ret < 0)
return ret;
return pci_register_driver(&sm501_pci_driver);
}
......
......@@ -8,14 +8,13 @@
*/
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/mfd/core.h>
......@@ -30,17 +29,12 @@
* @irq_trigger: IRQ trigger to use for the interrupt to the host
* @autosleep: bool to enable/disable stmpe autosleep
* @autosleep_timeout: inactivity timeout in milliseconds for autosleep
* @irq_over_gpio: true if gpio is used to get irq
* @irq_gpio: gpio number over which irq will be requested (significant only if
* irq_over_gpio is true)
*/
struct stmpe_platform_data {
int id;
unsigned int blocks;
unsigned int irq_trigger;
bool autosleep;
bool irq_over_gpio;
int irq_gpio;
int autosleep_timeout;
};
......@@ -1349,32 +1343,22 @@ static void stmpe_of_probe(struct stmpe_platform_data *pdata,
if (pdata->id < 0)
pdata->id = -1;
pdata->irq_gpio = of_get_named_gpio_flags(np, "irq-gpio", 0,
&pdata->irq_trigger);
if (gpio_is_valid(pdata->irq_gpio))
pdata->irq_over_gpio = 1;
else
pdata->irq_trigger = IRQF_TRIGGER_NONE;
of_property_read_u32(np, "st,autosleep-timeout",
&pdata->autosleep_timeout);
pdata->autosleep = (pdata->autosleep_timeout) ? true : false;
for_each_available_child_of_node(np, child) {
if (of_node_name_eq(child, "stmpe_gpio")) {
if (of_device_is_compatible(child, stmpe_gpio_cell.of_compatible))
pdata->blocks |= STMPE_BLOCK_GPIO;
} else if (of_node_name_eq(child, "stmpe_keypad")) {
else if (of_device_is_compatible(child, stmpe_keypad_cell.of_compatible))
pdata->blocks |= STMPE_BLOCK_KEYPAD;
} else if (of_node_name_eq(child, "stmpe_touchscreen")) {
else if (of_device_is_compatible(child, stmpe_ts_cell.of_compatible))
pdata->blocks |= STMPE_BLOCK_TOUCHSCREEN;
} else if (of_node_name_eq(child, "stmpe_adc")) {
else if (of_device_is_compatible(child, stmpe_adc_cell.of_compatible))
pdata->blocks |= STMPE_BLOCK_ADC;
} else if (of_node_name_eq(child, "stmpe_pwm")) {
else if (of_device_is_compatible(child, stmpe_pwm_cell.of_compatible))
pdata->blocks |= STMPE_BLOCK_PWM;
} else if (of_node_name_eq(child, "stmpe_rotator")) {
pdata->blocks |= STMPE_BLOCK_ROTATOR;
}
}
}
......@@ -1384,6 +1368,7 @@ int stmpe_probe(struct stmpe_client_info *ci, enum stmpe_partnum partnum)
struct stmpe_platform_data *pdata;
struct device_node *np = ci->dev->of_node;
struct stmpe *stmpe;
struct gpio_desc *irq_gpio;
int ret;
u32 val;
......@@ -1437,18 +1422,20 @@ int stmpe_probe(struct stmpe_client_info *ci, enum stmpe_partnum partnum)
if (ci->init)
ci->init(stmpe);
if (pdata->irq_over_gpio) {
ret = devm_gpio_request_one(ci->dev, pdata->irq_gpio,
GPIOF_DIR_IN, "stmpe");
irq_gpio = devm_gpiod_get_optional(ci->dev, "irq", GPIOD_ASIS);
ret = PTR_ERR_OR_ZERO(irq_gpio);
if (ret) {
dev_err(stmpe->dev, "failed to request IRQ GPIO: %d\n",
ret);
dev_err(stmpe->dev, "failed to request IRQ GPIO: %d\n", ret);
return ret;
}
stmpe->irq = gpio_to_irq(pdata->irq_gpio);
if (irq_gpio) {
stmpe->irq = gpiod_to_irq(irq_gpio);
pdata->irq_trigger = gpiod_is_active_low(irq_gpio) ?
IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH;
} else {
stmpe->irq = ci->irq;
pdata->irq_trigger = IRQF_TRIGGER_NONE;
}
if (stmpe->irq < 0) {
......
......@@ -66,14 +66,6 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk)
goto err_map;
}
/* Parse the device's DT node for an endianness specification */
if (of_property_read_bool(np, "big-endian"))
syscon_config.val_format_endian = REGMAP_ENDIAN_BIG;
else if (of_property_read_bool(np, "little-endian"))
syscon_config.val_format_endian = REGMAP_ENDIAN_LITTLE;
else if (of_property_read_bool(np, "native-endian"))
syscon_config.val_format_endian = REGMAP_ENDIAN_NATIVE;
/*
* search for reg-io-width property in DT. If it is not provided,
* default to 4 bytes. regmap_init_mmio will return an error if values
......
......@@ -882,7 +882,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
* SR_I2C_SCL_CTRL_PU(bit 4)=0 and SR_I2C_SDA_CTRL_PU(bit 6)=0.
*
* Also, always enable SmartReflex bit as that's needed for omaps to
* to do anything over I2C4 for voltage scaling even if SmartReflex
* do anything over I2C4 for voltage scaling even if SmartReflex
* is disabled. Without the SmartReflex bit omap sys_clkreq idle
* signal will never trigger for retention idle.
*/
......
......@@ -14,6 +14,7 @@
* by syed khasim <x0khasim@ti.com>
*/
#include <linux/device.h>
#include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
......
......@@ -708,6 +708,12 @@ config CHARGER_BQ256XX
charge management and system power path management devices for single
cell Li-ion and Li-polymer batteries.
config CHARGER_RK817
tristate "Rockchip RK817 PMIC Battery Charger"
depends on MFD_RK808
help
Say Y to include support for Rockchip RK817 Battery Charger.
config CHARGER_SMB347
tristate "Summit Microelectronics SMB3XX Battery Charger"
depends on I2C
......
......@@ -91,6 +91,7 @@ obj-$(CONFIG_CHARGER_BQ2515X) += bq2515x_charger.o
obj-$(CONFIG_CHARGER_BQ25890) += bq25890_charger.o
obj-$(CONFIG_CHARGER_BQ25980) += bq25980_charger.o
obj-$(CONFIG_CHARGER_BQ256XX) += bq256xx_charger.o
obj-$(CONFIG_CHARGER_RK817) += rk817_charger.o
obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o
obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o
obj-$(CONFIG_CHARGER_TPS65217) += tps65217_charger.o
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Charger Driver for Rockchip rk817
*
* Copyright (c) 2021 Maya Matuszczyk <maccraft123mc@gmail.com>
*
* Authors: Maya Matuszczyk <maccraft123mc@gmail.com>
* Chris Morgan <macromorgan@hotmail.com>
*/
#include <asm/unaligned.h>
#include <linux/devm-helpers.h>
#include <linux/mfd/rk808.h>
#include <linux/irq.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/regmap.h>
/* Charging statuses reported by hardware register */
enum rk817_charge_status {
CHRG_OFF,
DEAD_CHRG,
TRICKLE_CHRG,
CC_OR_CV_CHRG,
CHARGE_FINISH,
USB_OVER_VOL,
BAT_TMP_ERR,
BAT_TIM_ERR,
};
/*
* Max charging current read to/written from hardware register.
* Note how highest value corresponding to 0x7 is the lowest
* current, this is per the datasheet.
*/
enum rk817_chg_cur {
CHG_1A,
CHG_1_5A,
CHG_2A,
CHG_2_5A,
CHG_2_75A,
CHG_3A,
CHG_3_5A,
CHG_0_5A,
};
struct rk817_charger {
struct device *dev;
struct rk808 *rk808;
struct power_supply *bat_ps;
struct power_supply *chg_ps;
bool plugged_in;
bool battery_present;
/*
* voltage_k and voltage_b values are used to calibrate the ADC
* voltage readings. While they are documented in the BSP kernel and
* datasheet as voltage_k and voltage_b, there is no further
* information explaining them in more detail.
*/
uint32_t voltage_k;
uint32_t voltage_b;
/*
* soc - state of charge - like the BSP this is stored as a percentage,
* to the thousandth. BSP has a display state of charge (dsoc) and a
* remaining state of charge (rsoc). This value will be used for both
* purposes here so we don't do any fancy math to try and "smooth" the
* charge and just report it as it is. Note for example an soc of 100
* is stored as 100000, an soc of 50 is stored as 50000, etc.
*/
int soc;
/*
* Capacity of battery when fully charged, equal or less than design
* capacity depending upon wear. BSP kernel saves to nvram in mAh,
* so this value is in mAh not the standard uAh.
*/
int fcc_mah;
/*
* Calibrate the SOC on a fully charged battery, this way we can use
* the calibrated SOC value to correct for columb counter drift.
*/
bool soc_cal;
/* Implementation specific immutable properties from device tree */
int res_div;
int sleep_enter_current_ua;
int sleep_filter_current_ua;
int bat_charge_full_design_uah;
int bat_voltage_min_design_uv;
int bat_voltage_max_design_uv;
/* Values updated periodically by driver for display. */
int charge_now_uah;
int volt_avg_uv;
int cur_avg_ua;
int max_chg_cur_ua;
int max_chg_volt_uv;
int charge_status;
int charger_input_volt_avg_uv;
/* Work queue to periodically update values. */
struct delayed_work work;
};
/* ADC coefficients extracted from BSP kernel */
#define ADC_TO_CURRENT(adc_value, res_div) \
(adc_value * 172 / res_div)
#define CURRENT_TO_ADC(current, samp_res) \
(current * samp_res / 172)
#define CHARGE_TO_ADC(capacity, res_div) \
(capacity * res_div * 3600 / 172 * 1000)
#define ADC_TO_CHARGE_UAH(adc_value, res_div) \
(adc_value / 3600 * 172 / res_div)
static u8 rk817_chg_cur_to_reg(u32 chg_cur_ma)
{
if (chg_cur_ma >= 3500)
return CHG_3_5A;
else if (chg_cur_ma >= 3000)
return CHG_3A;
else if (chg_cur_ma >= 2750)
return CHG_2_75A;
else if (chg_cur_ma >= 2500)
return CHG_2_5A;
else if (chg_cur_ma >= 2000)
return CHG_2A;
else if (chg_cur_ma >= 1500)
return CHG_1_5A;
else if (chg_cur_ma >= 1000)
return CHG_1A;
else if (chg_cur_ma >= 500)
return CHG_0_5A;
else
return -EINVAL;
}
static int rk817_chg_cur_from_reg(u8 reg)
{
switch (reg) {
case CHG_0_5A:
return 500000;
case CHG_1A:
return 1000000;
case CHG_1_5A:
return 1500000;
case CHG_2A:
return 2000000;
case CHG_2_5A:
return 2500000;
case CHG_2_75A:
return 2750000;
case CHG_3A:
return 3000000;
case CHG_3_5A:
return 3500000;
default:
return -EINVAL;
}
}
static void rk817_bat_calib_vol(struct rk817_charger *charger)
{
uint32_t vcalib0 = 0;
uint32_t vcalib1 = 0;
u8 bulk_reg[2];
/* calibrate voltage */
regmap_bulk_read(charger->rk808->regmap, RK817_GAS_GAUGE_VCALIB0_H,
bulk_reg, 2);
vcalib0 = get_unaligned_be16(bulk_reg);
regmap_bulk_read(charger->rk808->regmap, RK817_GAS_GAUGE_VCALIB1_H,
bulk_reg, 2);
vcalib1 = get_unaligned_be16(bulk_reg);
/* values were taken from BSP kernel */
charger->voltage_k = (4025 - 2300) * 1000 /
((vcalib1 - vcalib0) ? (vcalib1 - vcalib0) : 1);
charger->voltage_b = 4025 - (charger->voltage_k * vcalib1) / 1000;
}
static void rk817_bat_calib_cur(struct rk817_charger *charger)
{
u8 bulk_reg[2];
/* calibrate current */
regmap_bulk_read(charger->rk808->regmap, RK817_GAS_GAUGE_IOFFSET_H,
bulk_reg, 2);
regmap_bulk_write(charger->rk808->regmap, RK817_GAS_GAUGE_CAL_OFFSET_H,
bulk_reg, 2);
}
/*
* note that only the fcc_mah is really used by this driver, the other values
* are to ensure we can remain backwards compatible with the BSP kernel.
*/
static int rk817_record_battery_nvram_values(struct rk817_charger *charger)
{
u8 bulk_reg[3];
int ret, rsoc;
/*
* write the soc value to the nvram location used by the BSP kernel
* for the dsoc value.
*/
put_unaligned_le24(charger->soc, bulk_reg);
ret = regmap_bulk_write(charger->rk808->regmap, RK817_GAS_GAUGE_BAT_R1,
bulk_reg, 3);
if (ret < 0)
return ret;
/*
* write the remaining capacity in mah to the nvram location used by
* the BSP kernel for the rsoc value.
*/
rsoc = (charger->soc * charger->fcc_mah) / 100000;
put_unaligned_le24(rsoc, bulk_reg);
ret = regmap_bulk_write(charger->rk808->regmap, RK817_GAS_GAUGE_DATA0,
bulk_reg, 3);
if (ret < 0)
return ret;
/* write the fcc_mah in mAh, just as the BSP kernel does. */
put_unaligned_le24(charger->fcc_mah, bulk_reg);
ret = regmap_bulk_write(charger->rk808->regmap, RK817_GAS_GAUGE_DATA3,
bulk_reg, 3);
if (ret < 0)
return ret;
return 0;
}
static int rk817_bat_calib_cap(struct rk817_charger *charger)
{
struct rk808 *rk808 = charger->rk808;
int tmp, charge_now, charge_now_adc, volt_avg;
u8 bulk_reg[4];
/* Calibrate the soc and fcc on a fully charged battery */
if (charger->charge_status == CHARGE_FINISH && (!charger->soc_cal)) {
/*
* soc should be 100000 and columb counter should show the full
* charge capacity. Note that if the device is unplugged for a
* period of several days the columb counter will have a large
* margin of error, so setting it back to the full charge on
* a completed charge cycle should correct this (my device was
* showing 33% battery after 3 days unplugged when it should
* have been closer to 95% based on voltage and charge
* current).
*/
charger->soc = 100000;
charge_now_adc = CHARGE_TO_ADC(charger->fcc_mah,
charger->res_div);
put_unaligned_be32(charge_now_adc, bulk_reg);
regmap_bulk_write(rk808->regmap, RK817_GAS_GAUGE_Q_INIT_H3,
bulk_reg, 4);
charger->soc_cal = 1;
dev_dbg(charger->dev,
"Fully charged. SOC is %d, full capacity is %d\n",
charger->soc, charger->fcc_mah * 1000);
}
/*
* The columb counter can drift up slightly, so we should correct for
* it. But don't correct it until we're at 100% soc.
*/
if (charger->charge_status == CHARGE_FINISH && charger->soc_cal) {
regmap_bulk_read(rk808->regmap, RK817_GAS_GAUGE_Q_PRES_H3,
bulk_reg, 4);
charge_now_adc = get_unaligned_be32(bulk_reg);
if (charge_now_adc < 0)
return charge_now_adc;
charge_now = ADC_TO_CHARGE_UAH(charge_now_adc,
charger->res_div);
/*
* Re-init columb counter with updated values to correct drift.
*/
if (charge_now / 1000 > charger->fcc_mah) {
dev_dbg(charger->dev,
"Recalibrating columb counter to %d uah\n",
charge_now);
/*
* Order of operations matters here to ensure we keep
* enough precision until the last step to keep from
* making needless updates to columb counter.
*/
charge_now_adc = CHARGE_TO_ADC(charger->fcc_mah,
charger->res_div);
put_unaligned_be32(charge_now_adc, bulk_reg);
regmap_bulk_write(rk808->regmap,
RK817_GAS_GAUGE_Q_INIT_H3,
bulk_reg, 4);
}
}
/*
* Calibrate the fully charged capacity when we previously had a full
* battery (soc_cal = 1) and are now empty (at or below minimum design
* voltage). If our columb counter is still positive, subtract that
* from our fcc value to get a calibrated fcc, and if our columb
* counter is negative add that to our fcc (but not to exceed our
* design capacity).
*/
regmap_bulk_read(charger->rk808->regmap, RK817_GAS_GAUGE_BAT_VOL_H,
bulk_reg, 2);
tmp = get_unaligned_be16(bulk_reg);
volt_avg = (charger->voltage_k * tmp) + 1000 * charger->voltage_b;
if (volt_avg <= charger->bat_voltage_min_design_uv &&
charger->soc_cal) {
regmap_bulk_read(rk808->regmap, RK817_GAS_GAUGE_Q_PRES_H3,
bulk_reg, 4);
charge_now_adc = get_unaligned_be32(bulk_reg);
charge_now = ADC_TO_CHARGE_UAH(charge_now_adc,
charger->res_div);
/*
* Note, if charge_now is negative this will add it (what we
* want) and if it's positive this will subtract (also what
* we want).
*/
charger->fcc_mah = charger->fcc_mah - (charge_now / 1000);
dev_dbg(charger->dev,
"Recalibrating full charge capacity to %d uah\n",
charger->fcc_mah * 1000);
}
rk817_record_battery_nvram_values(charger);
return 0;
}
static void rk817_read_props(struct rk817_charger *charger)
{
int tmp, reg;
u8 bulk_reg[4];
/*
* Recalibrate voltage and current readings if we need to BSP does both
* on CUR_CALIB_UPD, ignoring VOL_CALIB_UPD. Curiously enough, both
* documentation and the BSP show that you perform an update if bit 7
* is 1, but you clear the status by writing a 1 to bit 7.
*/
regmap_read(charger->rk808->regmap, RK817_GAS_GAUGE_ADC_CONFIG1, &reg);
if (reg & RK817_VOL_CUR_CALIB_UPD) {
rk817_bat_calib_cur(charger);
rk817_bat_calib_vol(charger);
regmap_write_bits(charger->rk808->regmap,
RK817_GAS_GAUGE_ADC_CONFIG1,
RK817_VOL_CUR_CALIB_UPD,
RK817_VOL_CUR_CALIB_UPD);
}
/* Update reported charge. */
regmap_bulk_read(charger->rk808->regmap, RK817_GAS_GAUGE_Q_PRES_H3,
bulk_reg, 4);
tmp = get_unaligned_be32(bulk_reg);
charger->charge_now_uah = ADC_TO_CHARGE_UAH(tmp, charger->res_div);
if (charger->charge_now_uah < 0)
charger->charge_now_uah = 0;
if (charger->charge_now_uah > charger->fcc_mah * 1000)
charger->charge_now_uah = charger->fcc_mah * 1000;
/* Update soc based on reported charge. */
charger->soc = charger->charge_now_uah * 100 / charger->fcc_mah;
/* Update reported voltage. */
regmap_bulk_read(charger->rk808->regmap, RK817_GAS_GAUGE_BAT_VOL_H,
bulk_reg, 2);
tmp = get_unaligned_be16(bulk_reg);
charger->volt_avg_uv = (charger->voltage_k * tmp) + 1000 *
charger->voltage_b;
/*
* Update reported current. Note value from registers is a signed 16
* bit int.
*/
regmap_bulk_read(charger->rk808->regmap, RK817_GAS_GAUGE_BAT_CUR_H,
bulk_reg, 2);
tmp = (short int)get_unaligned_be16(bulk_reg);
charger->cur_avg_ua = ADC_TO_CURRENT(tmp, charger->res_div);
/*
* Update the max charge current. This value shouldn't change, but we
* can read it to report what the PMIC says it is instead of simply
* returning the default value.
*/
regmap_read(charger->rk808->regmap, RK817_PMIC_CHRG_OUT, &reg);
charger->max_chg_cur_ua =
rk817_chg_cur_from_reg(reg & RK817_CHRG_CUR_SEL);
/*
* Update max charge voltage. Like the max charge current this value
* shouldn't change, but we can report what the PMIC says.
*/
regmap_read(charger->rk808->regmap, RK817_PMIC_CHRG_OUT, &reg);
charger->max_chg_volt_uv = ((((reg & RK817_CHRG_VOL_SEL) >> 4) *
50000) + 4100000);
/* Check if battery still present. */
regmap_read(charger->rk808->regmap, RK817_PMIC_CHRG_STS, &reg);
charger->battery_present = (reg & RK817_BAT_EXS);
/* Get which type of charge we are using (if any). */
regmap_read(charger->rk808->regmap, RK817_PMIC_CHRG_STS, &reg);
charger->charge_status = (reg >> 4) & 0x07;
/*
* Get charger input voltage. Note that on my example hardware (an
* Odroid Go Advance) the voltage of the power connector is measured
* on the register labelled USB in the datasheet; I don't know if this
* is how it is designed or just a quirk of the implementation. I
* believe this will also measure the voltage of the USB output when in
* OTG mode, if that is the case we may need to change this in the
* future to return 0 if the power supply status is offline (I can't
* test this with my current implementation. Also, when the voltage
* should be zero sometimes the ADC still shows a single bit (which
* would register as 20000uv). When this happens set it to 0.
*/
regmap_bulk_read(charger->rk808->regmap, RK817_GAS_GAUGE_USB_VOL_H,
bulk_reg, 2);
reg = get_unaligned_be16(bulk_reg);
if (reg > 1) {
tmp = ((charger->voltage_k * reg / 1000 + charger->voltage_b) *
60 / 46);
charger->charger_input_volt_avg_uv = tmp * 1000;
} else {
charger->charger_input_volt_avg_uv = 0;
}
/* Calibrate battery capacity and soc. */
rk817_bat_calib_cap(charger);
}
static int rk817_bat_get_prop(struct power_supply *ps,
enum power_supply_property prop,
union power_supply_propval *val)
{
struct rk817_charger *charger = power_supply_get_drvdata(ps);
switch (prop) {
case POWER_SUPPLY_PROP_PRESENT:
val->intval = charger->battery_present;
break;
case POWER_SUPPLY_PROP_STATUS:
if (charger->cur_avg_ua < 0) {
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
break;
}
switch (charger->charge_status) {
case CHRG_OFF:
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
break;
/*
* Dead charge is documented, but not explained. I never
* observed it but assume it's a pre-charge for a dead
* battery.
*/
case DEAD_CHRG:
case TRICKLE_CHRG:
case CC_OR_CV_CHRG:
val->intval = POWER_SUPPLY_STATUS_CHARGING;
break;
case CHARGE_FINISH:
val->intval = POWER_SUPPLY_STATUS_FULL;
break;
default:
val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
return -EINVAL;
}
break;
case POWER_SUPPLY_PROP_CHARGE_TYPE:
switch (charger->charge_status) {
case CHRG_OFF:
case CHARGE_FINISH:
val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
break;
case TRICKLE_CHRG:
val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
break;
case DEAD_CHRG:
case CC_OR_CV_CHRG:
val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
break;
default:
val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
break;
}
break;
case POWER_SUPPLY_PROP_CHARGE_FULL:
val->intval = charger->fcc_mah * 1000;
break;
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
val->intval = charger->bat_charge_full_design_uah;
break;
case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN:
val->intval = 0;
break;
case POWER_SUPPLY_PROP_CHARGE_NOW:
val->intval = charger->charge_now_uah;
break;
case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
val->intval = charger->bat_voltage_min_design_uv;
break;
case POWER_SUPPLY_PROP_CAPACITY:
/* Add 500 so that values like 99999 are 100% not 99%. */
val->intval = (charger->soc + 500) / 1000;
if (val->intval > 100)
val->intval = 100;
if (val->intval < 0)
val->intval = 0;
break;
case POWER_SUPPLY_PROP_VOLTAGE_AVG:
val->intval = charger->volt_avg_uv;
break;
case POWER_SUPPLY_PROP_CURRENT_AVG:
val->intval = charger->cur_avg_ua;
break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
val->intval = charger->max_chg_cur_ua;
break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
val->intval = charger->max_chg_volt_uv;
break;
case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
val->intval = charger->bat_voltage_max_design_uv;
break;
default:
return -EINVAL;
}
return 0;
}
static int rk817_chg_get_prop(struct power_supply *ps,
enum power_supply_property prop,
union power_supply_propval *val)
{
struct rk817_charger *charger = power_supply_get_drvdata(ps);
switch (prop) {
case POWER_SUPPLY_PROP_ONLINE:
val->intval = charger->plugged_in;
break;
case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
/* max voltage from datasheet at 5.5v (default 5.0v) */
val->intval = 5500000;
break;
case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
/* min voltage from datasheet at 3.8v (default 5.0v) */
val->intval = 3800000;
break;
case POWER_SUPPLY_PROP_VOLTAGE_AVG:
val->intval = charger->charger_input_volt_avg_uv;
break;
/*
* While it's possible that other implementations could use different
* USB types, the current implementation for this PMIC (the Odroid Go
* Advance) only uses a dedicated charging port with no rx/tx lines.
*/
case POWER_SUPPLY_PROP_USB_TYPE:
val->intval = POWER_SUPPLY_USB_TYPE_DCP;
break;
default:
return -EINVAL;
}
return 0;
}
static irqreturn_t rk817_plug_in_isr(int irq, void *cg)
{
struct rk817_charger *charger;
charger = (struct rk817_charger *)cg;
charger->plugged_in = 1;
power_supply_changed(charger->chg_ps);
power_supply_changed(charger->bat_ps);
/* try to recalibrate capacity if we hit full charge. */
charger->soc_cal = 0;
rk817_read_props(charger);
dev_dbg(charger->dev, "Power Cord Inserted\n");
return IRQ_HANDLED;
}
static irqreturn_t rk817_plug_out_isr(int irq, void *cg)
{
struct rk817_charger *charger;
struct rk808 *rk808;
charger = (struct rk817_charger *)cg;
rk808 = charger->rk808;
charger->plugged_in = 0;
power_supply_changed(charger->bat_ps);
power_supply_changed(charger->chg_ps);
/*
* For some reason the bits of RK817_PMIC_CHRG_IN reset whenever the
* power cord is unplugged. This was not documented in the BSP kernel
* or the datasheet and only discovered by trial and error. Set minimum
* USB input voltage to 4.5v and enable USB voltage input limit.
*/
regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_IN,
RK817_USB_VLIM_SEL, (0x05 << 4));
regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_IN, RK817_USB_VLIM_EN,
(0x01 << 7));
/*
* Set average USB input current limit to 1.5A and enable USB current
* input limit.
*/
regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_IN,
RK817_USB_ILIM_SEL, 0x03);
regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_IN, RK817_USB_ILIM_EN,
(0x01 << 3));
rk817_read_props(charger);
dev_dbg(charger->dev, "Power Cord Removed\n");
return IRQ_HANDLED;
}
static enum power_supply_property rk817_bat_props[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_CHARGE_TYPE,
POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN,
POWER_SUPPLY_PROP_CHARGE_NOW,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
POWER_SUPPLY_PROP_VOLTAGE_AVG,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
POWER_SUPPLY_PROP_CURRENT_AVG,
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
};
static enum power_supply_property rk817_chg_props[] = {
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_USB_TYPE,
POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
POWER_SUPPLY_PROP_VOLTAGE_AVG,
};
static enum power_supply_usb_type rk817_usb_type[] = {
POWER_SUPPLY_USB_TYPE_DCP,
POWER_SUPPLY_USB_TYPE_UNKNOWN,
};
static const struct power_supply_desc rk817_bat_desc = {
.name = "rk817-battery",
.type = POWER_SUPPLY_TYPE_BATTERY,
.properties = rk817_bat_props,
.num_properties = ARRAY_SIZE(rk817_bat_props),
.get_property = rk817_bat_get_prop,
};
static const struct power_supply_desc rk817_chg_desc = {
.name = "rk817-charger",
.type = POWER_SUPPLY_TYPE_USB,
.usb_types = rk817_usb_type,
.num_usb_types = ARRAY_SIZE(rk817_usb_type),
.properties = rk817_chg_props,
.num_properties = ARRAY_SIZE(rk817_chg_props),
.get_property = rk817_chg_get_prop,
};
static int rk817_read_battery_nvram_values(struct rk817_charger *charger)
{
u8 bulk_reg[3];
int ret;
/* Read the nvram data for full charge capacity. */
ret = regmap_bulk_read(charger->rk808->regmap,
RK817_GAS_GAUGE_DATA3, bulk_reg, 3);
if (ret < 0)
return ret;
charger->fcc_mah = get_unaligned_le24(bulk_reg);
/*
* Sanity checking for values equal to zero or less than would be
* practical for this device (BSP Kernel assumes 500mAH or less) for
* practicality purposes. Also check if the value is too large and
* correct it.
*/
if ((charger->fcc_mah < 500) ||
((charger->fcc_mah * 1000) > charger->bat_charge_full_design_uah)) {
dev_info(charger->dev,
"Invalid NVRAM max charge, setting to %u uAH\n",
charger->bat_charge_full_design_uah);
charger->fcc_mah = charger->bat_charge_full_design_uah / 1000;
}
/*
* Read the nvram for state of charge. Sanity check for values greater
* than 100 (10000). If the value is off it should get corrected
* automatically when the voltage drops to the min (soc is 0) or when
* the battery is full (soc is 100).
*/
ret = regmap_bulk_read(charger->rk808->regmap,
RK817_GAS_GAUGE_BAT_R1, bulk_reg, 3);
if (ret < 0)
return ret;
charger->soc = get_unaligned_le24(bulk_reg);
if (charger->soc > 10000)
charger->soc = 10000;
return 0;
}
static int
rk817_read_or_set_full_charge_on_boot(struct rk817_charger *charger,
struct power_supply_battery_info *bat_info)
{
struct rk808 *rk808 = charger->rk808;
u8 bulk_reg[4];
u32 boot_voltage, boot_charge_mah, tmp;
int ret, reg, off_time;
bool first_boot;
/*
* Check if the battery is uninitalized. If it is, the columb counter
* needs to be set up.
*/
ret = regmap_read(rk808->regmap, RK817_GAS_GAUGE_GG_STS, &reg);
if (ret < 0)
return ret;
first_boot = reg & RK817_BAT_CON;
/*
* If the battery is uninitialized, use the poweron voltage and an ocv
* lookup to guess our charge. The number won't be very accurate until
* we hit either our minimum voltage (0%) or full charge (100%).
*/
if (first_boot) {
regmap_bulk_read(rk808->regmap, RK817_GAS_GAUGE_PWRON_VOL_H,
bulk_reg, 2);
tmp = get_unaligned_be16(bulk_reg);
boot_voltage = (charger->voltage_k * tmp) +
1000 * charger->voltage_b;
/*
* Since only implementation has no working thermistor, assume
* 20C for OCV lookup. If lookup fails, report error with OCV
* table.
*/
charger->soc = power_supply_batinfo_ocv2cap(bat_info,
boot_voltage,
20) * 1000;
if (charger->soc < 0)
charger->soc = 0;
/* Guess that full charge capacity is the design capacity */
charger->fcc_mah = charger->bat_charge_full_design_uah / 1000;
/*
* Set battery as "set up". BSP driver uses this value even
* though datasheet claims it's a read-only value.
*/
regmap_write_bits(rk808->regmap, RK817_GAS_GAUGE_GG_STS,
RK817_BAT_CON, 0);
/* Save nvram values */
ret = rk817_record_battery_nvram_values(charger);
if (ret < 0)
return ret;
} else {
ret = rk817_read_battery_nvram_values(charger);
if (ret < 0)
return ret;
regmap_bulk_read(rk808->regmap, RK817_GAS_GAUGE_Q_PRES_H3,
bulk_reg, 4);
tmp = get_unaligned_be32(bulk_reg);
if (tmp < 0)
tmp = 0;
boot_charge_mah = ADC_TO_CHARGE_UAH(tmp,
charger->res_div) / 1000;
/*
* Check if the columb counter has been off for more than 300
* minutes as it tends to drift downward. If so, re-init soc
* with the boot voltage instead. Note the unit values for the
* OFF_CNT register appear to be in decaminutes and stops
* counting at 2550 (0xFF) minutes. BSP kernel used OCV, but
* for me occasionally that would show invalid values. Boot
* voltage is only accurate for me on first poweron (not
* reboots), but we shouldn't ever encounter an OFF_CNT more
* than 0 on a reboot anyway.
*/
regmap_read(rk808->regmap, RK817_GAS_GAUGE_OFF_CNT, &off_time);
if (off_time >= 30) {
regmap_bulk_read(rk808->regmap,
RK817_GAS_GAUGE_PWRON_VOL_H,
bulk_reg, 2);
tmp = get_unaligned_be16(bulk_reg);
boot_voltage = (charger->voltage_k * tmp) +
1000 * charger->voltage_b;
charger->soc =
power_supply_batinfo_ocv2cap(bat_info,
boot_voltage,
20) * 1000;
} else {
charger->soc = (boot_charge_mah * 1000 * 100 /
charger->fcc_mah);
}
}
regmap_bulk_read(rk808->regmap, RK817_GAS_GAUGE_PWRON_VOL_H,
bulk_reg, 2);
tmp = get_unaligned_be16(bulk_reg);
boot_voltage = (charger->voltage_k * tmp) + 1000 * charger->voltage_b;
regmap_bulk_read(rk808->regmap, RK817_GAS_GAUGE_Q_PRES_H3,
bulk_reg, 4);
tmp = get_unaligned_be32(bulk_reg);
if (tmp < 0)
tmp = 0;
boot_charge_mah = ADC_TO_CHARGE_UAH(tmp, charger->res_div) / 1000;
regmap_bulk_read(rk808->regmap, RK817_GAS_GAUGE_OCV_VOL_H,
bulk_reg, 2);
tmp = get_unaligned_be16(bulk_reg);
boot_voltage = (charger->voltage_k * tmp) + 1000 * charger->voltage_b;
/*
* Now we have our full charge capacity and soc, init the columb
* counter.
*/
boot_charge_mah = charger->soc * charger->fcc_mah / 100 / 1000;
if (boot_charge_mah > charger->fcc_mah)
boot_charge_mah = charger->fcc_mah;
tmp = CHARGE_TO_ADC(boot_charge_mah, charger->res_div);
put_unaligned_be32(tmp, bulk_reg);
ret = regmap_bulk_write(rk808->regmap, RK817_GAS_GAUGE_Q_INIT_H3,
bulk_reg, 4);
if (ret < 0)
return ret;
/* Set QMAX value to max design capacity. */
tmp = CHARGE_TO_ADC((charger->bat_charge_full_design_uah / 1000),
charger->res_div);
put_unaligned_be32(tmp, bulk_reg);
ret = regmap_bulk_write(rk808->regmap, RK817_GAS_GAUGE_Q_MAX_H3,
bulk_reg, 4);
if (ret < 0)
return ret;
return 0;
}
static int rk817_battery_init(struct rk817_charger *charger,
struct power_supply_battery_info *bat_info)
{
struct rk808 *rk808 = charger->rk808;
u32 tmp, max_chg_vol_mv, max_chg_cur_ma;
u8 max_chg_vol_reg, chg_term_i_reg, max_chg_cur_reg;
int ret, chg_term_ma;
u8 bulk_reg[2];
/* Get initial plug state */
regmap_read(rk808->regmap, RK817_SYS_STS, &tmp);
charger->plugged_in = (tmp & RK817_PLUG_IN_STS);
/*
* Turn on all ADC functions to measure battery, USB, and sys voltage,
* as well as batt temp. Note only tested implementation so far does
* not use a battery with a thermistor.
*/
regmap_write(rk808->regmap, RK817_GAS_GAUGE_ADC_CONFIG0, 0xfc);
/*
* Set relax mode voltage sampling interval and ADC offset calibration
* interval to 8 minutes to mirror BSP kernel. Set voltage and current
* modes to average to mirror BSP kernel.
*/
regmap_write(rk808->regmap, RK817_GAS_GAUGE_GG_CON, 0x04);
/* Calibrate voltage like the BSP does here. */
rk817_bat_calib_vol(charger);
/* Write relax threshold, derived from sleep enter current. */
tmp = CURRENT_TO_ADC(charger->sleep_enter_current_ua,
charger->res_div);
put_unaligned_be16(tmp, bulk_reg);
regmap_bulk_write(rk808->regmap, RK817_GAS_GAUGE_RELAX_THRE_H,
bulk_reg, 2);
/* Write sleep sample current, derived from sleep filter current. */
tmp = CURRENT_TO_ADC(charger->sleep_filter_current_ua,
charger->res_div);
put_unaligned_be16(tmp, bulk_reg);
regmap_bulk_write(rk808->regmap, RK817_GAS_GAUGE_SLEEP_CON_SAMP_CUR_H,
bulk_reg, 2);
/* Restart battery relax voltage */
regmap_write_bits(rk808->regmap, RK817_GAS_GAUGE_GG_STS,
RK817_RELAX_VOL_UPD, (0x0 << 2));
/*
* Set OCV Threshold Voltage to 127.5mV. This was hard coded like this
* in the BSP.
*/
regmap_write(rk808->regmap, RK817_GAS_GAUGE_OCV_THRE_VOL, 0xff);
/*
* Set maximum charging voltage to battery max voltage. Trying to be
* incredibly safe with these value, as setting them wrong could
* overcharge the battery, which would be very bad.
*/
max_chg_vol_mv = bat_info->constant_charge_voltage_max_uv / 1000;
max_chg_cur_ma = bat_info->constant_charge_current_max_ua / 1000;
if (max_chg_vol_mv < 4100) {
return dev_err_probe(charger->dev, -EINVAL,
"invalid max charger voltage, value %u unsupported\n",
max_chg_vol_mv * 1000);
}
if (max_chg_vol_mv > 4450) {
dev_info(charger->dev,
"Setting max charge voltage to 4450000uv\n");
max_chg_vol_mv = 4450;
}
if (max_chg_cur_ma < 500) {
return dev_err_probe(charger->dev, -EINVAL,
"invalid max charger current, value %u unsupported\n",
max_chg_cur_ma * 1000);
}
if (max_chg_cur_ma > 3500)
dev_info(charger->dev,
"Setting max charge current to 3500000ua\n");
/*
* Now that the values are sanity checked, if we subtract 4100 from the
* max voltage and divide by 50, we conviently get the exact value for
* the registers, which are 4.1v, 4.15v, 4.2v, 4.25v, 4.3v, 4.35v,
* 4.4v, and 4.45v; these correspond to values 0x00 through 0x07.
*/
max_chg_vol_reg = (max_chg_vol_mv - 4100) / 50;
max_chg_cur_reg = rk817_chg_cur_to_reg(max_chg_cur_ma);
if (max_chg_vol_reg < 0 || max_chg_vol_reg > 7) {
return dev_err_probe(charger->dev, -EINVAL,
"invalid max charger voltage, value %u unsupported\n",
max_chg_vol_mv * 1000);
}
if (max_chg_cur_reg < 0 || max_chg_cur_reg > 7) {
return dev_err_probe(charger->dev, -EINVAL,
"invalid max charger current, value %u unsupported\n",
max_chg_cur_ma * 1000);
}
/*
* Write the values to the registers, and deliver an emergency warning
* in the event they are not written correctly.
*/
ret = regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_OUT,
RK817_CHRG_VOL_SEL, (max_chg_vol_reg << 4));
if (ret) {
dev_emerg(charger->dev,
"Danger, unable to set max charger voltage: %u\n",
ret);
}
ret = regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_OUT,
RK817_CHRG_CUR_SEL, max_chg_cur_reg);
if (ret) {
dev_emerg(charger->dev,
"Danger, unable to set max charger current: %u\n",
ret);
}
/* Set charge finishing mode to analog */
regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_TERM,
RK817_CHRG_TERM_ANA_DIG, (0x0 << 2));
/*
* Set charge finish current, warn if value not in range and keep
* default.
*/
chg_term_ma = bat_info->charge_term_current_ua / 1000;
if (chg_term_ma < 150 || chg_term_ma > 400) {
dev_warn(charger->dev,
"Invalid charge termination %u, keeping default\n",
chg_term_ma * 1000);
chg_term_ma = 200;
}
/*
* Values of 150ma, 200ma, 300ma, and 400ma correspond to 00, 01, 10,
* and 11.
*/
chg_term_i_reg = (chg_term_ma - 100) / 100;
regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_TERM,
RK817_CHRG_TERM_ANA_SEL, chg_term_i_reg);
ret = rk817_read_or_set_full_charge_on_boot(charger, bat_info);
if (ret < 0)
return ret;
/*
* Set minimum USB input voltage to 4.5v and enable USB voltage input
* limit.
*/
regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_IN,
RK817_USB_VLIM_SEL, (0x05 << 4));
regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_IN, RK817_USB_VLIM_EN,
(0x01 << 7));
/*
* Set average USB input current limit to 1.5A and enable USB current
* input limit.
*/
regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_IN,
RK817_USB_ILIM_SEL, 0x03);
regmap_write_bits(rk808->regmap, RK817_PMIC_CHRG_IN, RK817_USB_ILIM_EN,
(0x01 << 3));
return 0;
}
static void rk817_charging_monitor(struct work_struct *work)
{
struct rk817_charger *charger;
charger = container_of(work, struct rk817_charger, work.work);
rk817_read_props(charger);
/* Run every 8 seconds like the BSP driver did. */
queue_delayed_work(system_wq, &charger->work, msecs_to_jiffies(8000));
}
static int rk817_charger_probe(struct platform_device *pdev)
{
struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent);
struct rk817_charger *charger;
struct device_node *node;
struct power_supply_battery_info *bat_info;
struct device *dev = &pdev->dev;
struct power_supply_config pscfg = {};
int plugin_irq, plugout_irq;
int of_value;
int ret;
node = of_get_child_by_name(dev->parent->of_node, "charger");
if (!node)
return -ENODEV;
charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
if (!charger)
return -ENOMEM;
charger->rk808 = rk808;
charger->dev = &pdev->dev;
platform_set_drvdata(pdev, charger);
rk817_bat_calib_vol(charger);
pscfg.drv_data = charger;
pscfg.of_node = node;
/*
* Get sample resistor value. Note only values of 10000 or 20000
* microohms are allowed. Schematic for my test implementation (an
* Odroid Go Advance) shows a 10 milliohm resistor for reference.
*/
ret = of_property_read_u32(node, "rockchip,resistor-sense-micro-ohms",
&of_value);
if (ret < 0) {
return dev_err_probe(dev, ret,
"Error reading sample resistor value\n");
}
/*
* Store as a 1 or a 2, since all we really use the value for is as a
* divisor in some calculations.
*/
charger->res_div = (of_value == 20000) ? 2 : 1;
/*
* Get sleep enter current value. Not sure what this value is for
* other than to help calibrate the relax threshold.
*/
ret = of_property_read_u32(node,
"rockchip,sleep-enter-current-microamp",
&of_value);
if (ret < 0) {
return dev_err_probe(dev, ret,
"Error reading sleep enter cur value\n");
}
charger->sleep_enter_current_ua = of_value;
/* Get sleep filter current value */
ret = of_property_read_u32(node,
"rockchip,sleep-filter-current-microamp",
&of_value);
if (ret < 0) {
return dev_err_probe(dev, ret,
"Error reading sleep filter cur value\n");
}
charger->sleep_filter_current_ua = of_value;
charger->bat_ps = devm_power_supply_register(&pdev->dev,
&rk817_bat_desc, &pscfg);
charger->chg_ps = devm_power_supply_register(&pdev->dev,
&rk817_chg_desc, &pscfg);
if (IS_ERR(charger->chg_ps))
return dev_err_probe(dev, -EINVAL,
"Battery failed to probe\n");
if (IS_ERR(charger->chg_ps))
return dev_err_probe(dev, -EINVAL,
"Charger failed to probe\n");
ret = power_supply_get_battery_info(charger->bat_ps,
&bat_info);
if (ret) {
return dev_err_probe(dev, ret,
"Unable to get battery info: %d\n", ret);
}
if ((bat_info->charge_full_design_uah <= 0) ||
(bat_info->voltage_min_design_uv <= 0) ||
(bat_info->voltage_max_design_uv <= 0) ||
(bat_info->constant_charge_voltage_max_uv <= 0) ||
(bat_info->constant_charge_current_max_ua <= 0) ||
(bat_info->charge_term_current_ua <= 0)) {
return dev_err_probe(dev, -EINVAL,
"Required bat info missing or invalid\n");
}
charger->bat_charge_full_design_uah = bat_info->charge_full_design_uah;
charger->bat_voltage_min_design_uv = bat_info->voltage_min_design_uv;
charger->bat_voltage_max_design_uv = bat_info->voltage_max_design_uv;
/*
* Has to run after power_supply_get_battery_info as it depends on some
* values discovered from that routine.
*/
ret = rk817_battery_init(charger, bat_info);
if (ret)
return ret;
power_supply_put_battery_info(charger->bat_ps, bat_info);
plugin_irq = platform_get_irq(pdev, 0);
if (plugin_irq < 0)
return plugin_irq;
plugout_irq = platform_get_irq(pdev, 1);
if (plugout_irq < 0)
return plugout_irq;
ret = devm_request_threaded_irq(charger->dev, plugin_irq, NULL,
rk817_plug_in_isr,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"rk817_plug_in", charger);
if (ret) {
return dev_err_probe(&pdev->dev, ret,
"plug_in_irq request failed!\n");
}
ret = devm_request_threaded_irq(charger->dev, plugout_irq, NULL,
rk817_plug_out_isr,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"rk817_plug_out", charger);
if (ret) {
return dev_err_probe(&pdev->dev, ret,
"plug_out_irq request failed!\n");
}
ret = devm_delayed_work_autocancel(&pdev->dev, &charger->work,
rk817_charging_monitor);
if (ret)
return ret;
/* Force the first update immediately. */
mod_delayed_work(system_wq, &charger->work, 0);
return 0;
}
static struct platform_driver rk817_charger_driver = {
.probe = rk817_charger_probe,
.driver = {
.name = "rk817-charger",
},
};
module_platform_driver(rk817_charger_driver);
MODULE_DESCRIPTION("Battery power supply driver for RK817 PMIC");
MODULE_AUTHOR("Maya Matuszczyk <maccraft123mc@gmail.com>");
MODULE_AUTHOR("Chris Morgan <macromorgan@hotmail.com>");
MODULE_LICENSE("GPL");
......@@ -1282,6 +1282,7 @@ config REGULATOR_STW481X_VMMC
config REGULATOR_SY7636A
tristate "Silergy SY7636A voltage regulator"
depends on MFD_SY7636A
help
This driver supports Silergy SY3686A voltage regulator.
......
/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
#ifndef __DT_BINDINGS_MEDIATEK_MT6370_ADC_H__
#define __DT_BINDINGS_MEDIATEK_MT6370_ADC_H__
/* ADC Channel Index */
#define MT6370_CHAN_VBUSDIV5 0
#define MT6370_CHAN_VBUSDIV2 1
#define MT6370_CHAN_VSYS 2
#define MT6370_CHAN_VBAT 3
#define MT6370_CHAN_TS_BAT 4
#define MT6370_CHAN_IBUS 5
#define MT6370_CHAN_IBAT 6
#define MT6370_CHAN_CHG_VDDP 7
#define MT6370_CHAN_TEMP_JC 8
#define MT6370_CHAN_MAX 9
#endif
......@@ -13,8 +13,6 @@ struct htcpld_chip_platform_data {
};
struct htcpld_core_platform_data {
unsigned int int_reset_gpio_hi;
unsigned int int_reset_gpio_lo;
unsigned int i2c_adapter_id;
struct htcpld_chip_platform_data *chip;
......
......@@ -519,6 +519,77 @@ enum rk809_reg_id {
#define MIC_DIFF_DIS (0x0 << 7)
#define MIC_DIFF_EN (0x1 << 7)
/* RK817 Battery Registers */
#define RK817_GAS_GAUGE_ADC_CONFIG0 0x50
#define RK817_GG_EN (0x1 << 7)
#define RK817_SYS_VOL_ADC_EN (0x1 << 6)
#define RK817_TS_ADC_EN (0x1 << 5)
#define RK817_USB_VOL_ADC_EN (0x1 << 4)
#define RK817_BAT_VOL_ADC_EN (0x1 << 3)
#define RK817_BAT_CUR_ADC_EN (0x1 << 2)
#define RK817_GAS_GAUGE_ADC_CONFIG1 0x55
#define RK817_VOL_CUR_CALIB_UPD BIT(7)
#define RK817_GAS_GAUGE_GG_CON 0x56
#define RK817_GAS_GAUGE_GG_STS 0x57
#define RK817_BAT_CON (0x1 << 4)
#define RK817_RELAX_VOL_UPD (0x3 << 2)
#define RK817_RELAX_STS (0x1 << 1)
#define RK817_GAS_GAUGE_RELAX_THRE_H 0x58
#define RK817_GAS_GAUGE_RELAX_THRE_L 0x59
#define RK817_GAS_GAUGE_OCV_THRE_VOL 0x62
#define RK817_GAS_GAUGE_OCV_VOL_H 0x63
#define RK817_GAS_GAUGE_OCV_VOL_L 0x64
#define RK817_GAS_GAUGE_PWRON_VOL_H 0x6b
#define RK817_GAS_GAUGE_PWRON_VOL_L 0x6c
#define RK817_GAS_GAUGE_PWRON_CUR_H 0x6d
#define RK817_GAS_GAUGE_PWRON_CUR_L 0x6e
#define RK817_GAS_GAUGE_OFF_CNT 0x6f
#define RK817_GAS_GAUGE_Q_INIT_H3 0x70
#define RK817_GAS_GAUGE_Q_INIT_H2 0x71
#define RK817_GAS_GAUGE_Q_INIT_L1 0x72
#define RK817_GAS_GAUGE_Q_INIT_L0 0x73
#define RK817_GAS_GAUGE_Q_PRES_H3 0x74
#define RK817_GAS_GAUGE_Q_PRES_H2 0x75
#define RK817_GAS_GAUGE_Q_PRES_L1 0x76
#define RK817_GAS_GAUGE_Q_PRES_L0 0x77
#define RK817_GAS_GAUGE_BAT_VOL_H 0x78
#define RK817_GAS_GAUGE_BAT_VOL_L 0x79
#define RK817_GAS_GAUGE_BAT_CUR_H 0x7a
#define RK817_GAS_GAUGE_BAT_CUR_L 0x7b
#define RK817_GAS_GAUGE_USB_VOL_H 0x7e
#define RK817_GAS_GAUGE_USB_VOL_L 0x7f
#define RK817_GAS_GAUGE_SYS_VOL_H 0x80
#define RK817_GAS_GAUGE_SYS_VOL_L 0x81
#define RK817_GAS_GAUGE_Q_MAX_H3 0x82
#define RK817_GAS_GAUGE_Q_MAX_H2 0x83
#define RK817_GAS_GAUGE_Q_MAX_L1 0x84
#define RK817_GAS_GAUGE_Q_MAX_L0 0x85
#define RK817_GAS_GAUGE_SLEEP_CON_SAMP_CUR_H 0x8f
#define RK817_GAS_GAUGE_SLEEP_CON_SAMP_CUR_L 0x90
#define RK817_GAS_GAUGE_CAL_OFFSET_H 0x91
#define RK817_GAS_GAUGE_CAL_OFFSET_L 0x92
#define RK817_GAS_GAUGE_VCALIB0_H 0x93
#define RK817_GAS_GAUGE_VCALIB0_L 0x94
#define RK817_GAS_GAUGE_VCALIB1_H 0x95
#define RK817_GAS_GAUGE_VCALIB1_L 0x96
#define RK817_GAS_GAUGE_IOFFSET_H 0x97
#define RK817_GAS_GAUGE_IOFFSET_L 0x98
#define RK817_GAS_GAUGE_BAT_R1 0x9a
#define RK817_GAS_GAUGE_BAT_R2 0x9b
#define RK817_GAS_GAUGE_BAT_R3 0x9c
#define RK817_GAS_GAUGE_DATA0 0x9d
#define RK817_GAS_GAUGE_DATA1 0x9e
#define RK817_GAS_GAUGE_DATA2 0x9f
#define RK817_GAS_GAUGE_DATA3 0xa0
#define RK817_GAS_GAUGE_DATA4 0xa1
#define RK817_GAS_GAUGE_DATA5 0xa2
#define RK817_GAS_GAUGE_CUR_ADC_K0 0xb0
#define RK817_POWER_EN_REG(i) (0xb1 + (i))
#define RK817_POWER_SLP_EN_REG(i) (0xb5 + (i))
......@@ -544,10 +615,30 @@ enum rk809_reg_id {
#define RK817_LDO_ON_VSEL_REG(idx) (0xcc + (idx) * 2)
#define RK817_BOOST_OTG_CFG (0xde)
#define RK817_PMIC_CHRG_OUT 0xe4
#define RK817_CHRG_VOL_SEL (0x07 << 4)
#define RK817_CHRG_CUR_SEL (0x07 << 0)
#define RK817_PMIC_CHRG_IN 0xe5
#define RK817_USB_VLIM_EN (0x01 << 7)
#define RK817_USB_VLIM_SEL (0x07 << 4)
#define RK817_USB_ILIM_EN (0x01 << 3)
#define RK817_USB_ILIM_SEL (0x07 << 0)
#define RK817_PMIC_CHRG_TERM 0xe6
#define RK817_CHRG_TERM_ANA_DIG (0x01 << 2)
#define RK817_CHRG_TERM_ANA_SEL (0x03 << 0)
#define RK817_CHRG_EN (0x01 << 6)
#define RK817_PMIC_CHRG_STS 0xeb
#define RK817_BAT_EXS BIT(7)
#define RK817_CHG_STS (0x07 << 4)
#define RK817_ID_MSB 0xed
#define RK817_ID_LSB 0xee
#define RK817_SYS_STS 0xf0
#define RK817_PLUG_IN_STS (0x1 << 6)
#define RK817_SYS_CFG(i) (0xf1 + (i))
#define RK817_ON_SOURCE_REG 0xf5
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment