Commit 8350e833 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull MFD updates from Lee Jones:
 "New Drivers:
   - Add support for Maxim MAX77714 PMIC

  Removed Drivers:
   - Remove support for ST-Ericsson AB8500 DebugFS

  New Device Support:
   - Add support for Silergy SY7636A to Simple MFD I2C
   - Add support for MediaTek MT6366 PMIC to MT6358 IRQ
   - Add support for Charger to Intel PMIC CRC
   - Add support for Raptor Lake to Intel LPSS PCI

  New Functionality:
   - Add support for Reboot to Rockchip RK808

  Fix-ups:
   - Device Tree changes (includcing YAML conversion) for
     silergy,sy7636a, maxim,max77843, google,cros-ec, maxim,max14577,
     maxim,max77802, maxim,max77714, qcom,tcsr, qcom,spmi-pmic,
     stericsson,ab8500, stericsson,db8500-prcmu,
     samsung,exynos5433-lpass, mt6397, syscon, brcm,cru
   - Visible to menuconfig; simple-mfd-i2c
   - Clean-up or clarify code; max77686, intel_soc_pmic_crc
   - Improve error handling; mc13xxx-core, stmfx, asic3
   - Pass device information to child devices; iqs62x, intel-lpss-acpi
   - Individually identify IRQ domains; intel_soc_pmic_core
   - Remove superfluous code; dbx500-prcmu, exynos-lpass
   - Staticify and constify; arizona-i2c
   - Mark sometimes used data as __maybe_unused; atmel-flexcom
   - Account for different ACPI tables on AOSP/Windows platforms; arizona-spi
   - Use provided (platform) APIs; ab8500-core
   - Trivial (whitespace, spelling); rohm-bd9576"

* tag 'mfd-next-5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (50 commits)
  dt-bindings: mfd: syscon: Add microchip,lan966x-cpu-syscon compatible
  mfd: bd9576: fix typos in comments
  mfd: Use platform_get_irq() to get the interrupt
  mfd: db8500-prcmu: Remove unused inline function
  mfd: arizona-spi: Add Android board ACPI table handling
  mfd: arizona-spi: Split Windows ACPI init code into its own function
  mfd: asic3: Add missing iounmap() on error asic3_mfd_probe
  MAINTAINERS: Rectify entry for ROHM MULTIFUNCTION BD9571MWV-M PMIC DEVICE DRIVERS
  mfd: intel-lpss: Provide an SSP type to the driver
  dt-bindings: mfd: brcm,cru: Rename pinctrl node
  dt-bindings: Add compatibles for undocumented trivial syscons
  mfd: atmel-flexcom: Fix compilation warning
  dt-bindings: mfd: Add compatible for the MediaTek MT6366 PMIC
  dt-bindings: mfd: samsung,exynos5433-lpass: Convert to dtschema
  mfd: exynos-lpass: Drop unneeded syscon.h include
  mfd: intel-lpss: Add Intel Raptor Lake PCH-S PCI IDs
  mfd: ab8500: Drop debugfs module
  mfd: sta2x11: Use GFP_KERNEL instead of GFP_ATOMIC
  mfd: ab8500: Rewrite bindings in YAML
  mfd: qcom-spmi-pmic: Add pm8953 compatible
  ...
parents e35a4a4e d99460ed
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/leds/maxim,max77693.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Maxim MAX77693 MicroUSB and Companion Power Management IC LEDs
maintainers:
- Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
description: |
This is a part of device tree bindings for Maxim MAX77693 MicroUSB Integrated
Circuit (MUIC).
There are two LED outputs available - FLED1 and FLED2. Each of them can
control a separate LED or they can be connected together to double the
maximum current for a single connected LED. One LED is represented by one
child node.
See also Documentation/devicetree/bindings/mfd/maxim,max77693.yaml for
additional information and example.
properties:
compatible:
const: maxim,max77693-led
maxim,boost-mode:
description:
In boost mode the device can produce up to 1.2A of total current on both
outputs. The maximum current on each output is reduced to 625mA then. If
not enabled explicitly, boost setting defaults to LEDS_BOOST_FIXED in
case both current sources are used.
See LEDS_BOOST_* in include/dt-bindings/leds/common.h.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1, 2]
maxim,boost-mvout:
description: |
Output voltage of the boost module in millivolts.
Valid values: 3300 - 5500, step by 25 (rounded down)
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 3300
maximum: 5500
default: 3300
maxim,mvsys-min:
description: |
Low input voltage level in millivolts. Flash is not fired if chip
estimates that system voltage could drop below this level due to flash
power consumption.
Valid values: 2400 - 3400, step by 33 (rounded down)
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 2400
maximum: 3400
default: 2400
patternProperties:
"^([a-z]+-)?led[01]?$":
type: object
$ref: common.yaml#
unevaluatedProperties: false
properties:
led-sources:
allOf:
- minItems: 1
maxItems: 2
items:
minimum: 0
maximum: 1
led-max-microamp:
description: |
Valid values for a LED connected to one FLED output:
15625 - 250000, step by 15625 (rounded down)
Valid values for a LED connected to both FLED outputs:
15625 - 500000, step by 15625 (rounded down)
flash-max-microamp:
description: |
Valid values for a single LED connected to one FLED output
(boost mode must be turned off):
15625 - 1000000, step by 15625 (rounded down)
Valid values for a single LED connected to both FLED outputs:
15625 - 1250000, step by 15625 (rounded down)
Valid values for two LEDs case:
15625 - 625000, step by 15625 (rounded down)
flash-max-timeout-us:
description: |
Valid values: 62500 - 1000000, step by 62500 (rounded down)
minimum: 62500
maximum: 1000000
required:
- flash-max-microamp
- flash-max-timeout-us
- led-max-microamp
- led-sources
required:
- compatible
additionalProperties: false
* AB8500 Multi-Functional Device (MFD)
Required parent device properties:
- compatible : contains "stericsson,ab8500" or "stericsson,ab8505";
- interrupts : contains the IRQ line for the AB8500
- interrupt-controller : describes the AB8500 as an Interrupt Controller (has its own domain)
- #interrupt-cells : should be 2, for 2-cell format
- The first cell is the AB8500 local IRQ number
- The second cell is used to specify optional parameters
- bits[3:0] trigger type and level flags:
1 = low-to-high edge triggered
2 = high-to-low edge triggered
4 = active high level-sensitive
8 = active low level-sensitive
The AB8500 consists of a large and varied group of sub-devices:
Device IRQ Names Supply Names Description
------ --------- ------------ -----------
ab8500-bm : : : Battery Manager
ab8500-btemp : : : Battery Temperature
ab8500-charger : : : Battery Charger
ab8500-codec : : : Audio Codec
ab8500-fg : : vddadc : Fuel Gauge
: NCONV_ACCU : : Accumulate N Sample Conversion
: BATT_OVV : : Battery Over Voltage
: LOW_BAT_F : : LOW threshold battery voltage
: CC_INT_CALIB : : Coulomb Counter Internal Calibration
: CCEOC : : Coulomb Counter End of Conversion
ab8500-btemp : : vtvout : Battery Temperature
: BAT_CTRL_INDB : : Battery Removal Indicator
: BTEMP_LOW : : Btemp < BtempLow, if battery temperature is lower than -10°C
: BTEMP_LOW_MEDIUM : : BtempLow < Btemp < BtempMedium,if battery temperature is between -10 and 0°C
: BTEMP_MEDIUM_HIGH : : BtempMedium < Btemp < BtempHigh,if battery temperature is between 0°C and MaxTemp
: BTEMP_HIGH : : Btemp > BtempHigh, if battery temperature is higher than MaxTemp
ab8500-charger : : vddadc : Charger interface
: MAIN_CH_UNPLUG_DET : : main charger unplug detection management (not in 8505)
: MAIN_CHARGE_PLUG_DET : : main charger plug detection management (not in 8505)
: MAIN_EXT_CH_NOT_OK : : main charger not OK
: MAIN_CH_TH_PROT_R : : Die temp is above main charger
: MAIN_CH_TH_PROT_F : : Die temp is below main charger
: VBUS_DET_F : : VBUS falling detected
: VBUS_DET_R : : VBUS rising detected
: USB_LINK_STATUS : : USB link status has changed
: USB_CH_TH_PROT_R : : Die temp is above usb charger
: USB_CH_TH_PROT_F : : Die temp is below usb charger
: USB_CHARGER_NOT_OKR : : allowed USB charger not ok detection
: VBUS_OVV : : Overvoltage on Vbus ball detected (USB charge is stopped)
: CH_WD_EXP : : Charger watchdog detected
ab8500-gpadc : HW_CONV_END : vddadc : Analogue to Digital Converter
SW_CONV_END : :
ab8500-gpio : : : GPIO Controller (AB8500)
ab8505-gpio : : : GPIO Controller (AB8505)
ab8500-ponkey : ONKEY_DBF : : Power-on Key
ONKEY_DBR : :
ab8500-pwm : : : Pulse Width Modulator
ab8500-regulator : : : Regulators (AB8500)
ab8505-regulator : : : Regulators (AB8505)
ab8500-rtc : 60S : : Real Time Clock
: ALARM : :
ab8500-sysctrl : : : System Control
ab8500-usb : ID_WAKEUP_R : vddulpivio18 : Universal Serial Bus
: ID_WAKEUP_F : v-ape :
: VBUS_DET_F : musb_1v8 :
: VBUS_DET_R : :
: USB_LINK_STATUS : :
: USB_ADP_PROBE_PLUG : :
: USB_ADP_PROBE_UNPLUG : :
Required child device properties:
- compatible : "stericsson,ab8500-[bm|btemp|charger|fg|gpadc|gpio|ponkey|
pwm|regulator|rtc|sysctrl|usb]";
A few child devices require ADC channels from the GPADC node. Those follow the
standard bindings from
https://github.com/devicetree-org/dt-schema/blob/master/schemas/iio/iio-consumer.yaml
and Documentation/devicetree/bindings/iio/adc/adc.yaml
abx500-temp : io-channels "aux1" and "aux2" for measuring external
temperatures.
ab8500-fg : io-channel "main_bat_v" for measuring main battery voltage,
ab8500-btemp : io-channels "btemp_ball" and "bat_ctrl" for measuring the
battery voltage.
ab8500-charger : io-channels "main_charger_v", "main_charger_c", "vbus_v",
"usb_charger_c" for measuring voltage and current of the
different charging supplies.
Optional child device properties:
- interrupts : contains the device IRQ(s) using the 2-cell format (see above)
- interrupt-names : contains names of IRQ resource in the order in which they were
supplied in the interrupts property
- <supply_name>-supply : contains a phandle to the regulator supply node in Device Tree
Non-standard child device properties:
- Audio CODEC:
- stericsson,amic[1|2]-type-single-ended : Single-ended Analoge Mic (default: differential)
- stericsson,amic1a-bias-vamic2 : Analoge Mic wishes to use a non-standard Vamic
- stericsson,amic1b-bias-vamic2 : Analoge Mic wishes to use a non-standard Vamic
- stericsson,amic2-bias-vamic1 : Analoge Mic wishes to use a non-standard Vamic
- stericsson,earpeice-cmv : Earpeice voltage (only: 950 | 1100 | 1270 | 1580)
ab8500 {
compatible = "stericsson,ab8500";
interrupts = <0 40 0x4>;
interrupt-controller;
#interrupt-cells = <2>;
ab8500-rtc {
compatible = "stericsson,ab8500-rtc";
interrupts = <17 0x4
18 0x4>;
interrupt-names = "60S", "ALARM";
};
ab8500-gpadc {
compatible = "stericsson,ab8500-gpadc";
interrupts = <32 0x4
39 0x4>;
interrupt-names = "HW_CONV_END", "SW_CONV_END";
vddadc-supply = <&ab8500_ldo_tvout_reg>;
#address-cells = <1>;
#size-cells = <0>;
#io-channel-cells = <1>;
/* GPADC channels */
bat_ctrl: channel@1 {
reg = <0x01>;
};
btemp_ball: channel@2 {
reg = <0x02>;
};
main_charger_v: channel@3 {
reg = <0x03>;
};
acc_detect1: channel@4 {
reg = <0x04>;
};
acc_detect2: channel@5 {
reg = <0x05>;
};
adc_aux1: channel@6 {
reg = <0x06>;
};
adc_aux2: channel@7 {
reg = <0x07>;
};
main_batt_v: channel@8 {
reg = <0x08>;
};
vbus_v: channel@9 {
reg = <0x09>;
};
main_charger_c: channel@a {
reg = <0x0a>;
};
usb_charger_c: channel@b {
reg = <0x0b>;
};
bk_bat_v: channel@c {
reg = <0x0c>;
};
die_temp: channel@d {
reg = <0x0d>;
};
usb_id: channel@e {
reg = <0x0e>;
};
xtal_temp: channel@12 {
reg = <0x12>;
};
vbat_true_meas: channel@13 {
reg = <0x13>;
};
bat_ctrl_and_ibat: channel@1c {
reg = <0x1c>;
};
vbat_meas_and_ibat: channel@1d {
reg = <0x1d>;
};
vbat_true_meas_and_ibat: channel@1e {
reg = <0x1e>;
};
bat_temp_and_ibat: channel@1f {
reg = <0x1f>;
};
};
ab8500_temp {
compatible = "stericsson,abx500-temp";
io-channels = <&gpadc 0x06>,
<&gpadc 0x07>;
io-channel-name = "aux1", "aux2";
};
ab8500_battery: ab8500_battery {
stericsson,battery-type = "LIPO";
thermistor-on-batctrl;
};
ab8500_fg {
compatible = "stericsson,ab8500-fg";
battery = <&ab8500_battery>;
io-channels = <&gpadc 0x08>;
io-channel-name = "main_bat_v";
};
ab8500_btemp {
compatible = "stericsson,ab8500-btemp";
battery = <&ab8500_battery>;
io-channels = <&gpadc 0x02>,
<&gpadc 0x01>;
io-channel-name = "btemp_ball",
"bat_ctrl";
};
ab8500_charger {
compatible = "stericsson,ab8500-charger";
battery = <&ab8500_battery>;
vddadc-supply = <&ab8500_ldo_tvout_reg>;
io-channels = <&gpadc 0x03>,
<&gpadc 0x0a>,
<&gpadc 0x09>,
<&gpadc 0x0b>;
io-channel-name = "main_charger_v",
"main_charger_c",
"vbus_v",
"usb_charger_c";
};
ab8500-usb {
compatible = "stericsson,ab8500-usb";
interrupts = < 90 0x4
96 0x4
14 0x4
15 0x4
79 0x4
74 0x4
75 0x4>;
interrupt-names = "ID_WAKEUP_R",
"ID_WAKEUP_F",
"VBUS_DET_F",
"VBUS_DET_R",
"USB_LINK_STATUS",
"USB_ADP_PROBE_PLUG",
"USB_ADP_PROBE_UNPLUG";
vddulpivio18-supply = <&ab8500_ldo_intcore_reg>;
v-ape-supply = <&db8500_vape_reg>;
musb_1v8-supply = <&db8500_vsmps2_reg>;
};
ab8500-ponkey {
compatible = "stericsson,ab8500-ponkey";
interrupts = <6 0x4
7 0x4>;
interrupt-names = "ONKEY_DBF", "ONKEY_DBR";
};
ab8500-sysctrl {
compatible = "stericsson,ab8500-sysctrl";
};
ab8500-pwm {
compatible = "stericsson,ab8500-pwm";
};
codec: ab8500-codec {
compatible = "stericsson,ab8500-codec";
stericsson,earpeice-cmv = <950>; /* Units in mV. */
};
ab8500-regulators {
compatible = "stericsson,ab8500-regulator";
ab8500_ldo_aux1_reg: ab8500_ldo_aux1 {
/*
* See: Documentation/devicetree/bindings/regulator/regulator.txt
* for more information on regulators
*/
};
};
};
Maxim MAX77693 multi-function device
MAX77693 is a Multifunction device with the following submodules:
- PMIC,
- CHARGER,
- LED,
- MUIC,
- HAPTIC
It is interfaced to host controller using i2c.
This document describes the bindings for the mfd device.
Required properties:
- compatible : Must be "maxim,max77693".
- reg : Specifies the i2c slave address of PMIC block.
- interrupts : This i2c device has an IRQ line connected to the main SoC.
Optional properties:
- regulators : The regulators of max77693 have to be instantiated under subnode
named "regulators" using the following format.
regulators {
regulator-compatible = ESAFEOUT1/ESAFEOUT2/CHARGER
standard regulator constraints[*].
};
[*] refer Documentation/devicetree/bindings/regulator/regulator.txt
- haptic : The MAX77693 haptic device utilises a PWM controlled motor to provide
users with tactile feedback. PWM period and duty-cycle are varied in
order to provide the appropriate level of feedback.
Required properties:
- compatible : Must be "maxim,max77693-haptic"
- haptic-supply : power supply for the haptic motor
[*] refer Documentation/devicetree/bindings/regulator/regulator.txt
- pwms : phandle to the physical PWM(Pulse Width Modulation) device.
PWM properties should be named "pwms". And number of cell is different
for each pwm device.
To get more information, please refer to documentation.
[*] refer Documentation/devicetree/bindings/pwm/pwm.txt
- charger : Node configuring the charger driver.
If present, required properties:
- compatible : Must be "maxim,max77693-charger".
Optional properties (if not set, defaults will be used):
- maxim,constant-microvolt : Battery constant voltage in uV. The charger
will operate in fast charge constant current mode till battery voltage
reaches this level. Then the charger will switch to fast charge constant
voltage mode. Also vsys (system voltage) will be set to this value when
DC power is supplied but charger is not enabled.
Valid values: 3650000 - 4400000, step by 25000 (rounded down)
Default: 4200000
- maxim,min-system-microvolt : Minimal system voltage in uV.
Valid values: 3000000 - 3700000, step by 100000 (rounded down)
Default: 3600000
- maxim,thermal-regulation-celsius : Temperature in Celsius for entering
high temperature charging mode. If die temperature exceeds this value
the charging current will be reduced by 105 mA/Celsius.
Valid values: 70, 85, 100, 115
Default: 100
- maxim,battery-overcurrent-microamp : Overcurrent protection threshold
in uA (current from battery to system).
Valid values: 2000000 - 3500000, step by 250000 (rounded down)
Default: 3500000
- maxim,charge-input-threshold-microvolt : Threshold voltage in uV for
triggering input voltage regulation loop. If input voltage decreases
below this value, the input current will be reduced to reach the
threshold voltage.
Valid values: 4300000, 4700000, 4800000, 4900000
Default: 4300000
- led : the LED submodule device node
There are two LED outputs available - FLED1 and FLED2. Each of them can
control a separate LED or they can be connected together to double
the maximum current for a single connected LED. One LED is represented
by one child node.
Required properties:
- compatible : Must be "maxim,max77693-led".
Optional properties:
- maxim,boost-mode :
In boost mode the device can produce up to 1.2A of total current
on both outputs. The maximum current on each output is reduced
to 625mA then. If not enabled explicitly, boost setting defaults to
LEDS_BOOST_FIXED in case both current sources are used.
Possible values:
LEDS_BOOST_OFF (0) - no boost,
LEDS_BOOST_ADAPTIVE (1) - adaptive mode,
LEDS_BOOST_FIXED (2) - fixed mode.
- maxim,boost-mvout : Output voltage of the boost module in millivolts.
Valid values: 3300 - 5500, step by 25 (rounded down)
Default: 3300
- maxim,mvsys-min : Low input voltage level in millivolts. Flash is not fired
if chip estimates that system voltage could drop below this level due
to flash power consumption.
Valid values: 2400 - 3400, step by 33 (rounded down)
Default: 2400
Required properties for the LED child node:
- led-sources : see Documentation/devicetree/bindings/leds/common.txt;
device current output identifiers: 0 - FLED1, 1 - FLED2
- led-max-microamp : see Documentation/devicetree/bindings/leds/common.txt
Valid values for a LED connected to one FLED output:
15625 - 250000, step by 15625 (rounded down)
Valid values for a LED connected to both FLED outputs:
15625 - 500000, step by 15625 (rounded down)
- flash-max-microamp : see Documentation/devicetree/bindings/leds/common.txt
Valid values for a single LED connected to one FLED output
(boost mode must be turned off):
15625 - 1000000, step by 15625 (rounded down)
Valid values for a single LED connected to both FLED outputs:
15625 - 1250000, step by 15625 (rounded down)
Valid values for two LEDs case:
15625 - 625000, step by 15625 (rounded down)
- flash-max-timeout-us : see Documentation/devicetree/bindings/leds/common.txt
Valid values: 62500 - 1000000, step by 62500 (rounded down)
Optional properties for the LED child node:
- label : see Documentation/devicetree/bindings/leds/common.txt
Optional nodes:
- max77693-muic :
Node used only by extcon consumers.
Required properties:
- compatible : "maxim,max77693-muic"
Example:
#include <dt-bindings/leds/common.h>
max77693@66 {
compatible = "maxim,max77693";
reg = <0x66>;
interrupt-parent = <&gpx1>;
interrupts = <5 IRQ_TYPE_LEVEL_LOW>;
regulators {
esafeout@1 {
regulator-compatible = "ESAFEOUT1";
regulator-name = "ESAFEOUT1";
regulator-boot-on;
};
esafeout@2 {
regulator-compatible = "ESAFEOUT2";
regulator-name = "ESAFEOUT2";
};
charger@0 {
regulator-compatible = "CHARGER";
regulator-name = "CHARGER";
regulator-min-microamp = <60000>;
regulator-max-microamp = <2580000>;
regulator-boot-on;
};
};
haptic {
compatible = "maxim,max77693-haptic";
haptic-supply = <&haptic_supply>;
pwms = <&pwm 0 40000 0>;
pwm-names = "haptic";
};
charger {
compatible = "maxim,max77693-charger";
maxim,constant-microvolt = <4200000>;
maxim,min-system-microvolt = <3600000>;
maxim,thermal-regulation-celsius = <75>;
maxim,battery-overcurrent-microamp = <3000000>;
maxim,charge-input-threshold-microvolt = <4300000>;
};
led {
compatible = "maxim,max77693-led";
maxim,boost-mode = <LEDS_BOOST_FIXED>;
maxim,boost-mvout = <5000>;
maxim,mvsys-min = <2400>;
camera_flash: flash-led {
label = "max77693-flash";
led-sources = <0>, <1>;
led-max-microamp = <500000>;
flash-max-microamp = <1250000>;
flash-max-timeout-us = <1000000>;
};
};
};
# SPDX-License-Identifier: GPL-2.0-only
%YAML 1.2
---
$id: http://devicetree.org/schemas/mfd/maxim,max77693.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Maxim MAX77693 MicroUSB and Companion Power Management IC
maintainers:
- Chanwoo Choi <cw00.choi@samsung.com>
- Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
description: |
This is a part of device tree bindings for Maxim MAX77693 MicroUSB
Integrated Circuit (MUIC).
The Maxim MAX77693 is a MicroUSB and Companion Power Management IC which
includes voltage current regulators, charger, LED/flash, haptic motor driver
and MicroUSB management IC.
properties:
compatible:
const: maxim,max77693
interrupts:
maxItems: 1
reg:
maxItems: 1
charger:
$ref: /schemas/power/supply/maxim,max77693.yaml
led:
$ref: /schemas/leds/maxim,max77693.yaml
max77693-muic:
type: object
additionalProperties: false
properties:
compatible:
const: maxim,max77693-muic
required:
- compatible
motor-driver:
type: object
additionalProperties: false
properties:
compatible:
const: maxim,max77693-haptic
haptic-supply:
description: Power supply to the haptic motor
pwms:
maxItems: 1
required:
- compatible
- haptic-supply
- pwms
regulators:
$ref: ../regulator/maxim,max77693.yaml
description:
List of child nodes that specify the regulators.
required:
- compatible
- interrupts
- reg
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/leds/common.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
pmic@66 {
compatible = "maxim,max77693";
reg = <0x66>;
interrupt-parent = <&gpx1>;
interrupts = <5 IRQ_TYPE_LEVEL_LOW>;
regulators {
ESAFEOUT1 {
regulator-name = "ESAFEOUT1";
};
ESAFEOUT2 {
regulator-name = "ESAFEOUT2";
};
CHARGER {
regulator-name = "CHARGER";
regulator-min-microamp = <60000>;
regulator-max-microamp = <2580000>;
};
};
motor-driver {
compatible = "maxim,max77693-haptic";
haptic-supply = <&ldo26_reg>;
pwms = <&pwm 0 38022 0>;
};
charger {
compatible = "maxim,max77693-charger";
maxim,constant-microvolt = <4350000>;
maxim,min-system-microvolt = <3600000>;
maxim,thermal-regulation-celsius = <100>;
maxim,battery-overcurrent-microamp = <3500000>;
maxim,charge-input-threshold-microvolt = <4300000>;
};
led {
compatible = "maxim,max77693-led";
maxim,boost-mode = <LEDS_BOOST_FIXED>;
maxim,boost-mvout = <5000>;
maxim,mvsys-min = <2400>;
flash-led {
label = "max77693-flash";
function = LED_FUNCTION_FLASH;
color = <LED_COLOR_ID_WHITE>;
led-sources = <0>, <1>;
led-max-microamp = <500000>;
flash-max-microamp = <1250000>;
flash-max-timeout-us = <1000000>;
};
};
};
};
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/mfd/maxim,max77714.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MAX77714 PMIC with GPIO, RTC and watchdog from Maxim Integrated.
maintainers:
- Luca Ceresoli <luca@lucaceresoli.net>
description: |
MAX77714 is a Power Management IC with 4 buck regulators, 9
low-dropout regulators, 8 GPIOs, RTC and watchdog.
properties:
compatible:
const: maxim,max77714
reg:
maxItems: 1
interrupts:
maxItems: 1
interrupt-controller: true
"#interrupt-cells":
const: 2
description:
The first cell is the IRQ number, the second cell is the trigger type.
regulators:
type: object
additionalProperties: false
patternProperties:
'^(buck[0-3]|ldo[0-8])$':
type: object
unevaluatedProperties: false
$ref: /schemas/regulator/regulator.yaml#
required:
- compatible
- reg
- interrupts
- interrupt-controller
- "#interrupt-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
pmic@1c {
compatible = "maxim,max77714";
reg = <0x1c>;
interrupt-parent = <&gpio2>;
interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
interrupt-controller;
#interrupt-cells = <2>;
};
};
......@@ -20,7 +20,7 @@ This document describes the binding for MFD device and its sub module.
Required properties:
compatible:
"mediatek,mt6323" for PMIC MT6323
"mediatek,mt6358" for PMIC MT6358
"mediatek,mt6358" for PMIC MT6358 and MT6366
"mediatek,mt6359" for PMIC MT6359
"mediatek,mt6397" for PMIC MT6397
......
......@@ -35,6 +35,7 @@ Required properties:
"qcom,pm8916",
"qcom,pm8941",
"qcom,pm8950",
"qcom,pm8953",
"qcom,pm8994",
"qcom,pm8998",
"qcom,pma8084",
......
......@@ -10,6 +10,7 @@ Required properties:
"qcom,tcsr-ipq8064", "syscon" for IPQ8064
"qcom,tcsr-apq8064", "syscon" for APQ8064
"qcom,tcsr-msm8660", "syscon" for MSM8660
"qcom,tcsr-msm8953", "syscon" for MSM8953
"qcom,tcsr-msm8960", "syscon" for MSM8960
"qcom,tcsr-msm8974", "syscon" for MSM8974
"qcom,tcsr-apq8084", "syscon" for APQ8084
......
Samsung Exynos SoC Low Power Audio Subsystem (LPASS)
Required properties:
- compatible : "samsung,exynos5433-lpass"
- reg : should contain the LPASS top SFR region location
and size
- clock-names : should contain following required clocks: "sfr0_ctrl"
- clocks : should contain clock specifiers of all clocks, which
input names have been specified in clock-names
property, in same order.
- #address-cells : should be 1
- #size-cells : should be 1
- ranges : must be present
Each IP block of the Low Power Audio Subsystem should be specified as
an optional sub-node. For "samsung,exynos5433-lpass" compatible this includes:
UART, SLIMBUS, PCM, I2S, DMAC, Timers 0...4, VIC, WDT 0...1 devices.
Bindings of the sub-nodes are described in:
../serial/samsung_uart.yaml
../sound/samsung-i2s.txt
../dma/arm-pl330.txt
Example:
audio-subsystem {
compatible = "samsung,exynos5433-lpass";
reg = <0x11400000 0x100>, <0x11500000 0x08>;
clocks = <&cmu_aud CLK_PCLK_SFR0_CTRL>;
clock-names = "sfr0_ctrl";
#address-cells = <1>;
#size-cells = <1>;
ranges;
adma: adma@11420000 {
compatible = "arm,pl330", "arm,primecell";
reg = <0x11420000 0x1000>;
interrupts = <0 73 0>;
clocks = <&cmu_aud CLK_ACLK_DMAC>;
clock-names = "apb_pclk";
#dma-cells = <1>;
#dma-channels = <8>;
#dma-requests = <32>;
};
i2s0: i2s0@11440000 {
compatible = "samsung,exynos7-i2s";
reg = <0x11440000 0x100>;
dmas = <&adma 0 &adma 2>;
dma-names = "tx", "rx";
interrupts = <0 70 0>;
clocks = <&cmu_aud CLK_PCLK_AUD_I2S>,
<&cmu_aud CLK_SCLK_AUD_I2S>,
<&cmu_aud CLK_SCLK_I2S_BCLK>;
clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
pinctrl-names = "default";
pinctrl-0 = <&i2s0_bus>;
};
serial_3: serial@11460000 {
compatible = "samsung,exynos5433-uart";
reg = <0x11460000 0x100>;
interrupts = <0 67 0>;
clocks = <&cmu_aud CLK_PCLK_AUD_UART>,
<&cmu_aud CLK_SCLK_AUD_UART>;
clock-names = "uart", "clk_uart_baud0";
pinctrl-names = "default";
pinctrl-0 = <&uart_aud_bus>;
};
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/mfd/samsung,exynos5433-lpass.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Samsung Exynos SoC Low Power Audio Subsystem (LPASS)
maintainers:
- Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
- Sylwester Nawrocki <s.nawrocki@samsung.com>
properties:
compatible:
const: samsung,exynos5433-lpass
'#address-cells':
const: 1
clocks:
maxItems: 1
clock-names:
items:
- const: sfr0_ctrl
power-domains:
maxItems: 1
ranges: true
reg:
minItems: 2
maxItems: 2
'#size-cells':
const: 1
patternProperties:
"^dma-controller@[0-9a-f]+$":
$ref: /schemas/dma/arm,pl330.yaml
"^i2s@[0-9a-f]+$":
$ref: /schemas/sound/samsung-i2s.yaml
"^serial@[0-9a-f]+$":
$ref: /schemas/serial/samsung_uart.yaml
required:
- compatible
- '#address-cells'
- clocks
- clock-names
- ranges
- reg
- '#size-cells'
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/exynos5433.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
audio-subsystem@11400000 {
compatible = "samsung,exynos5433-lpass";
reg = <0x11400000 0x100>, <0x11500000 0x08>;
clocks = <&cmu_aud CLK_PCLK_SFR0_CTRL>;
clock-names = "sfr0_ctrl";
power-domains = <&pd_aud>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
dma-controller@11420000 {
compatible = "arm,pl330", "arm,primecell";
reg = <0x11420000 0x1000>;
interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cmu_aud CLK_ACLK_DMAC>;
clock-names = "apb_pclk";
#dma-cells = <1>;
#dma-channels = <8>;
#dma-requests = <32>;
power-domains = <&pd_aud>;
};
i2s@11440000 {
compatible = "samsung,exynos7-i2s";
reg = <0x11440000 0x100>;
dmas = <&adma 0>, <&adma 2>;
dma-names = "tx", "rx";
interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&cmu_aud CLK_PCLK_AUD_I2S>,
<&cmu_aud CLK_SCLK_AUD_I2S>,
<&cmu_aud CLK_SCLK_I2S_BCLK>;
clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
#clock-cells = <1>;
pinctrl-names = "default";
pinctrl-0 = <&i2s0_bus>;
power-domains = <&pd_aud>;
#sound-dai-cells = <1>;
};
serial@11460000 {
compatible = "samsung,exynos5433-uart";
reg = <0x11460000 0x100>;
interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cmu_aud CLK_PCLK_AUD_UART>,
<&cmu_aud CLK_SCLK_AUD_UART>;
clock-names = "uart", "clk_uart_baud0";
pinctrl-names = "default";
pinctrl-0 = <&uart_aud_bus>;
power-domains = <&pd_aud>;
};
};
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/mfd/silergy,sy7636a.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: silergy sy7636a PMIC
maintainers:
- Alistair Francis <alistair@alistair23.me>
properties:
compatible:
const: silergy,sy7636a
reg:
description:
I2C device address.
maxItems: 1
"#address-cells":
const: 1
"#size-cells":
const: 0
'#thermal-sensor-cells':
const: 0
epd-pwr-good-gpios:
description:
Specifying the power good GPIOs.
maxItems: 1
regulators:
type: object
properties:
compatible:
const: silergy,sy7636a-regulator
vcom:
type: object
$ref: /schemas/regulator/regulator.yaml#
description:
The regulator for the compenstation voltage. Enabling/disabling this
enables/disables the entire device.
properties:
regulator-name:
const: vcom
additionalProperties: false
required:
- compatible
- reg
- '#thermal-sensor-cells'
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
pmic@62 {
compatible = "silergy,sy7636a";
reg = <0x62>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_epdpmic>;
#thermal-sensor-cells = <0>;
regulators {
reg_epdpmic: vcom {
regulator-name = "vcom";
regulator-boot-on;
};
};
};
};
...
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/mfd/stericsson,ab8500.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ST-Ericsson Analog Baseband AB8500 and AB8505
maintainers:
- Linus Walleij <linus.walleij@linaro.org>
description:
the AB8500 "Analog Baseband" is the mixed-signals integrated circuit
handling power management (regulators), analog-to-digital conversion
(ADC), battery charging, fuel gauging of the battery, battery-backed
RTC, PWM, USB PHY and some GPIO lines in the ST-Ericsson U8500 platforms
in connection with the DB8500 digital baseband. The DB8500 PRCMU
communicates directly and autonomously with the AB8500 and thus it
appears as a subnode of the DB8500 PRCMU. An altered version called
AB8505 also exist, the difference in AB8505 is that some of the USB and
USB charging handling has changed, and it has an embedded USB-to-serial
converter. Most subblocks takes their interrupts directly from the
AB8500 embedded interrupt controller.
properties:
$nodename:
pattern: '^ab850[05]$'
compatible:
enum:
- stericsson,ab8500
- stericsson,ab8505
interrupts:
maxItems: 1
interrupt-controller: true
'#interrupt-cells':
const: 2
# Some subnodes use a reg, some don't. Those that do use a single cell.
'#address-cells':
const: 1
'#size-cells':
const: 0
clock-controller:
description: Node describing the AB8500 clock controller. This
provides the reference clock for the entire U8500 system and
the DB8500 counterpart.
type: object
properties:
compatible:
const: stericsson,ab8500-clk
'#clock-cells':
const: 1
gpio:
description: Node describing the AB8500 GPIO controller. A few
GPIO pins available for misc usage.
type: object
properties:
compatible:
enum:
- stericsson,ab8500-gpio
- stericsson,ab8505-gpio
gpio-controller: true
'#gpio-cells':
const: 2
rtc:
description: Node describing the AB8500 battery-backed RTC.
type: object
properties:
compatible:
const: stericsson,ab8500-rtc
interrupts:
items:
- description: 60 second interval alarm interrupt
- description: RTC alarm
interrupt-names:
items:
- const: 60S
- const: ALARM
adc:
description: Node describing the AB8500 general purpose analog to digital
converter, GPADC.
type: object
properties:
compatible:
const: stericsson,ab8500-gpadc
# AB8505 only supports one (software) EOC interrupt
interrupts:
minItems: 1
maxItems: 2
interrupt-names: true
vddadc-supply: true
'#address-cells':
const: 1
'#size-cells':
const: 0
'#io-channel-cells':
const: 1
patternProperties:
"^channel@[0-9a-f]+$":
type: object
$ref: ../iio/adc/adc.yaml#
description: Represents each of the external channels which are
connected to the ADC.
properties:
reg:
items:
minimum: 1
maximum: 31
required:
- reg
additionalProperties: false
required:
- compatible
- interrupts
- interrupt-names
- vddadc-supply
- '#address-cells'
- '#size-cells'
- '#io-channel-cells'
additionalProperties: false
thermal:
description: Node describing the AB8500 thermal control block. All this block
really does is to fire an interrupt when the die becomes 130 degrees Celsius
in temperature.
type: object
properties:
compatible:
const: stericsson,abx500-temp
interrupts:
items:
- description: Thermal warm warning interrupt
interrupt-names:
items:
- const: ABX500_TEMP_WARM
required:
- compatible
- interrupts
- interrupt-names
additionalProperties: false
ab8500_fg:
description: Node describing the AB8500 fuel gauge control block.
type: object
$ref: ../power/supply/stericsson,ab8500-fg.yaml
ab8500_btemp:
description: Node describing the AB8500 battery temperature control block.
type: object
$ref: ../power/supply/stericsson,ab8500-btemp.yaml
ab8500_charger:
description: Node describing the AB8500 battery charger control block.
type: object
$ref: ../power/supply/stericsson,ab8500-charger.yaml
ab8500_chargalg:
description: Node describing the AB8500 battery charger algorithm.
type: object
$ref: ../power/supply/stericsson,ab8500-chargalg.yaml
phy:
description: Node describing the AB8500 USB PHY control block.
type: object
properties:
compatible:
const: stericsson,ab8500-usb
interrupts:
items:
- description: ID wakeup rising IRQ
- description: ID wakeup falling IRQ
- description: VBUS detection falling IRQ
- description: VBUS detection rising IRQ
- description: USB link status change IRQ
- description: ADP probe plug IRQ
- description: ADP probe unplug IRQ
interrupt-names:
items:
- const: ID_WAKEUP_R
- const: ID_WAKEUP_F
- const: VBUS_DET_F
- const: VBUS_DET_R
- const: USB_LINK_STATUS
- const: USB_ADP_PROBE_PLUG
- const: USB_ADP_PROBE_UNPLUG
vddulpivio18-supply: true
v-ape-supply: true
musb_1v8-supply: true
clocks:
items:
- description: PRCMY system clock
clock-names:
items:
- const: sysclk
'#phy-cells':
const: 0
required:
- compatible
- interrupts
- interrupt-names
- vddulpivio18-supply
- v-ape-supply
- musb_1v8-supply
- clocks
- clock-names
- '#phy-cells'
additionalProperties: false
key:
description: Node describing the AB8500 power-on key control block.
type: object
properties:
compatible:
const: stericsson,ab8500-poweron-key
interrupts:
items:
- description: ON key falling IRQ
- description: ON key rising IRQ
interrupt-names:
items:
- const: ONKEY_DBF
- const: ONKEY_DBR
required:
- compatible
- interrupts
- interrupt-names
additionalProperties: false
ab8500-sysctrl:
description: Node describing the AB8500 system control block.
type: object
properties:
compatible:
const: stericsson,ab8500-sysctrl
required:
- compatible
additionalProperties: false
codec:
description: Node describing the AB8500 audio codec block.
type: object
properties:
compatible:
const: stericsson,ab8500-codec
V-AUD-supply: true
V-AMIC1-supply: true
V-AMIC2-supply: true
V-DMIC-supply: true
clocks:
items:
- description: Audio system clock
clock-names:
items:
- const: audioclk
stericsson,earpeice-cmv:
description: Earpeice voltage
$ref: /schemas/types.yaml#/definitions/uint32
enum: [ 950, 1100, 1270, 1580 ]
required:
- compatible
additionalProperties: false
regulator:
description: Node describing the AB8500 internal regulators.
type: object
properties:
compatible:
enum:
- stericsson,ab8500-regulator
- stericsson,ab8505-regulator
vin-supply:
description: The regulator supplying all of the internal regulators
with power.
ab8500_ldo_aux1:
description: The voltage for the auxilary LDO regulator 1
type: object
$ref: ../regulator/regulator.yaml#
ab8500_ldo_aux2:
description: The voltage for the auxilary LDO regulator 2
type: object
$ref: ../regulator/regulator.yaml#
ab8500_ldo_aux3:
description: The voltage for the auxilary LDO regulator 3
type: object
$ref: ../regulator/regulator.yaml#
ab8500_ldo_aux4:
description: The voltage for the auxilary LDO regulator 4
only present on AB8505
type: object
$ref: ../regulator/regulator.yaml#
ab8500_ldo_aux5:
description: The voltage for the auxilary LDO regulator 5
only present on AB8505
type: object
$ref: ../regulator/regulator.yaml#
ab8500_ldo_aux6:
description: The voltage for the auxilary LDO regulator 6
only present on AB8505
type: object
$ref: ../regulator/regulator.yaml#
# There is never any AUX7 regulator which is confusing
ab8500_ldo_aux8:
description: The voltage for the auxilary LDO regulator 8
only present on AB8505
type: object
$ref: ../regulator/regulator.yaml#
ab8500_ldo_intcore:
description: The LDO regulator for the internal core voltage
of the AB8500
type: object
$ref: ../regulator/regulator.yaml#
ab8500_ldo_adc:
description: Analog power regulator for the analog to digital converter
ADC, only present on AB8505
type: object
$ref: ../regulator/regulator.yaml#
ab8500_ldo_tvout:
description: The voltage for the TV output regulator, incidentally
this voltage is also used for other purposes such as measuring
the temperature of the NTC thermistor on the battery.
Only present on AB8500.
type: object
$ref: ../regulator/regulator.yaml#
ab8500_ldo_audio:
description: The LDO regulator for the audio codec output
type: object
$ref: ../regulator/regulator.yaml#
ab8500_ldo_anamic1:
description: The LDO regulator for the analog microphone 1
type: object
$ref: ../regulator/regulator.yaml#
ab8500_ldo_anamic2:
description: The LDO regulator for the analog microphone 2
type: object
$ref: ../regulator/regulator.yaml#
ab8500_ldo_dmic:
description: The LDO regulator for the digital microphone
only present on AB8500
type: object
$ref: ../regulator/regulator.yaml#
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#
required:
- compatible
additionalProperties: false
regulator-external:
description: Node describing the AB8500 external regulators. This
concerns the autonomous regulators VSMPS1, VSMPS2 and VSMPS3
that are normally controlled by external electronics but also
sometimes need to be explicitly controlled by software.
type: object
properties:
compatible:
const: stericsson,ab8500-ext-regulator
ab8500_ext1:
description: The voltage for the VSMPS1 external regulator
type: object
$ref: ../regulator/regulator.yaml#
ab8500_ext2:
description: The voltage for the VSMPS2 external regulator
type: object
$ref: ../regulator/regulator.yaml#
ab8500_ext3:
description: The voltage for the VSMPS3 external regulator
type: object
$ref: ../regulator/regulator.yaml#
required:
- compatible
additionalProperties: false
patternProperties:
"^pwm@[1-9]+?$":
type: object
$ref: ../pwm/pwm.yaml#
description: Represents each of the PWM blocks in the AB8500
properties:
compatible:
const: stericsson,ab8500-pwm
reg: true
clocks:
items:
- description: internal clock
clock-names:
items:
- const: intclk
required:
- compatible
- reg
required:
- compatible
- clock-controller
- gpio
- rtc
- adc
- thermal
- ab8500_fg
- ab8500_btemp
- ab8500_charger
- ab8500_chargalg
- phy
- key
- regulator
additionalProperties: false
......@@ -263,6 +263,7 @@ patternProperties:
set of devicetree bindings. The AB8505 is a newer version of the
same ASIC.
type: object
$ref: stericsson,ab8500.yaml#
required:
- compatible
......
......@@ -44,6 +44,11 @@ properties:
- hisilicon,hi6220-sramctrl
- hisilicon,pcie-sas-subctrl
- hisilicon,peri-subctrl
- intel,lgm-syscon
- marvell,armada-3700-usb2-host-misc
- mediatek,mt8135-pctl-a-syscfg
- mediatek,mt8135-pctl-b-syscfg
- microchip,lan966x-cpu-syscon
- microchip,sparx5-cpu-syscon
- mstar,msc313-pmsleep
- rockchip,px30-qos
......
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/power/supply/maxim,max77693.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Maxim MAX77693 MicroUSB and Companion Power Management IC Charger
maintainers:
- Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
description: |
This is a part of device tree bindings for Maxim MAX77693 MicroUSB Integrated
Circuit (MUIC).
See also Documentation/devicetree/bindings/mfd/maxim,max77693.yaml for
additional information and example.
properties:
compatible:
const: maxim,max77693-charger
maxim,constant-microvolt:
description: |
Battery constant voltage in uV. The charger will operate in fast
charge constant current mode till battery voltage reaches this level.
Then the charger will switch to fast charge constant voltage mode.
Also vsys (system voltage) will be set to this value when DC power is
supplied but charger is not enabled.
Valid values: 3650000 - 4400000, step by 25000 (rounded down)
minimum: 3650000
maximum: 4400000
default: 4200000
maxim,min-system-microvolt:
description: |
Minimal system voltage in uV.
enum: [3000000, 3100000, 3200000, 3300000, 3400000, 3500000,
3600000, 3700000]
default: 3600000
maxim,thermal-regulation-celsius:
description: |
Temperature in Celsius for entering high temperature charging mode.
If die temperature exceeds this value the charging current will be
reduced by 105 mA/Celsius.
enum: [70, 85, 100, 115]
default: 100
maxim,battery-overcurrent-microamp:
description: |
Overcurrent protection threshold in uA (current from battery to
system).
Valid values: 2000000 - 3500000, step by 250000 (rounded down)
minimum: 2000000
maximum: 3500000
default: 3500000
maxim,charge-input-threshold-microvolt:
description: |
Threshold voltage in uV for triggering input voltage regulation loop.
If input voltage decreases below this value, the input current will
be reduced to reach the threshold voltage.
enum: [4300000, 4700000, 4800000, 4900000]
default: 4300000
required:
- compatible
additionalProperties: false
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/regulator/maxim,max77693.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Maxim MAX77693 MicroUSB and Companion Power Management IC regulators
maintainers:
- Chanwoo Choi <cw00.choi@samsung.com>
- Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
description: |
This is a part of device tree bindings for Maxim MAX77693 MicroUSB Integrated
Circuit (MUIC).
See also Documentation/devicetree/bindings/mfd/maxim,max77693.yaml for
additional information and example.
properties:
CHARGER:
type: object
$ref: regulator.yaml#
additionalProperties: false
description: |
Current regulator.
properties:
regulator-name: true
regulator-always-on: true
regulator-boot-on: true
regulator-min-microamp:
minimum: 60000
regulator-max-microamp:
maximum: 2580000
required:
- regulator-name
patternProperties:
"^ESAFEOUT[12]$":
type: object
$ref: regulator.yaml#
additionalProperties: false
description: |
Safeout LDO regulator.
properties:
regulator-name: true
regulator-always-on: true
regulator-boot-on: true
regulator-min-microvolt:
minimum: 3300000
regulator-max-microvolt:
maximum: 4950000
required:
- regulator-name
additionalProperties: false
......@@ -187,6 +187,7 @@ Hardware Monitoring Kernel Drivers
smsc47m1
sparx5-temp
stpddc60
sy7636a-hwmon
tc654
tc74
thmc50
......
.. SPDX-License-Identifier: GPL-2.0-or-later
Kernel driver sy7636a-hwmon
===========================
Supported chips:
* Silergy SY7636A PMIC
Description
-----------
This driver adds hardware temperature reading support for
the Silergy SY7636A PMIC.
The following sensors are supported
* Temperature
- SoC on-die temperature in milli-degree C
sysfs-Interface
---------------
temp0_input
- SoC on-die temperature (milli-degree C)
......@@ -11824,6 +11824,13 @@ F: drivers/power/supply/max77650-charger.c
F: drivers/regulator/max77650-regulator.c
F: include/linux/mfd/max77650.h
MAXIM MAX77714 PMIC MFD DRIVER
M: Luca Ceresoli <luca@lucaceresoli.net>
S: Maintained
F: Documentation/devicetree/bindings/mfd/maxim,max77714.yaml
F: drivers/mfd/max77714.c
F: include/linux/mfd/max77714.h
MAXIM MAX77802 PMIC REGULATOR DEVICE DRIVER
M: Javier Martinez Canillas <javier@dowhile0.org>
L: linux-kernel@vger.kernel.org
......@@ -11844,6 +11851,7 @@ M: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
L: linux-pm@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/power/supply/maxim,max14577.yaml
F: Documentation/devicetree/bindings/power/supply/maxim,max77693.yaml
F: drivers/power/supply/max14577_charger.c
F: drivers/power/supply/max77693_charger.c
......@@ -11855,6 +11863,7 @@ L: linux-kernel@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/*/maxim,max14577.yaml
F: Documentation/devicetree/bindings/*/maxim,max77686.yaml
F: Documentation/devicetree/bindings/*/maxim,max77693.yaml
F: Documentation/devicetree/bindings/*/maxim,max77843.yaml
F: Documentation/devicetree/bindings/clock/maxim,max77686.txt
F: Documentation/devicetree/bindings/mfd/max77693.txt
......@@ -16842,7 +16851,7 @@ M: Marek Vasut <marek.vasut+renesas@gmail.com>
L: linux-kernel@vger.kernel.org
L: linux-renesas-soc@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/mfd/bd9571mwv.txt
F: Documentation/devicetree/bindings/mfd/rohm,bd9571mwv.yaml
F: drivers/gpio/gpio-bd9571mwv.c
F: drivers/mfd/bd9571mwv.c
F: drivers/regulator/bd9571mwv-regulator.c
......
......@@ -1689,6 +1689,15 @@ config SENSORS_SIS5595
This driver can also be built as a module. If so, the module
will be called sis5595.
config SENSORS_SY7636A
tristate "Silergy SY7636A"
help
If you say yes here you get support for the thermistor readout of
the Silergy SY7636A PMIC.
This driver can also be built as a module. If so, the module
will be called sy7636a-hwmon.
config SENSORS_DME1737
tristate "SMSC DME1737, SCH311x and compatibles"
depends on I2C && !PPC
......
......@@ -187,6 +187,7 @@ obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
obj-$(CONFIG_SENSORS_SPARX5) += sparx5-temp.o
obj-$(CONFIG_SENSORS_STTS751) += stts751.o
obj-$(CONFIG_SENSORS_SY7636A) += sy7636a-hwmon.o
obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o
obj-$(CONFIG_SENSORS_TC74) += tc74.o
obj-$(CONFIG_SENSORS_THMC50) += thmc50.o
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Functions to access SY3686A power management chip temperature
*
* Copyright (C) 2021 reMarkable AS - http://www.remarkable.com/
*
* Authors: Lars Ivar Miljeteig <lars.ivar.miljeteig@remarkable.com>
* Alistair Francis <alistair@alistair23.me>
*/
#include <linux/err.h>
#include <linux/hwmon.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/machine.h>
#include <linux/mfd/sy7636a.h>
static int sy7636a_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *temp)
{
struct regmap *regmap = dev_get_drvdata(dev);
int ret, reg_val;
ret = regmap_read(regmap,
SY7636A_REG_TERMISTOR_READOUT, &reg_val);
if (ret)
return ret;
*temp = reg_val * 1000;
return 0;
}
static umode_t sy7636a_is_visible(const void *data,
enum hwmon_sensor_types type,
u32 attr, int channel)
{
if (type != hwmon_temp)
return 0;
if (attr != hwmon_temp_input)
return 0;
return 0444;
}
static const struct hwmon_ops sy7636a_hwmon_ops = {
.is_visible = sy7636a_is_visible,
.read = sy7636a_read,
};
static const struct hwmon_channel_info *sy7636a_info[] = {
HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
NULL
};
static const struct hwmon_chip_info sy7636a_chip_info = {
.ops = &sy7636a_hwmon_ops,
.info = sy7636a_info,
};
static int sy7636a_sensor_probe(struct platform_device *pdev)
{
struct regmap *regmap = dev_get_regmap(pdev->dev.parent, NULL);
struct regulator *regulator;
struct device *hwmon_dev;
int err;
if (!regmap)
return -EPROBE_DEFER;
regulator = devm_regulator_get(&pdev->dev, "vcom");
if (IS_ERR(regulator))
return PTR_ERR(regulator);
err = regulator_enable(regulator);
if (err)
return err;
hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
"sy7636a_temperature", regmap,
&sy7636a_chip_info, NULL);
if (IS_ERR(hwmon_dev)) {
err = PTR_ERR(hwmon_dev);
dev_err(&pdev->dev, "Unable to register hwmon device, returned %d\n", err);
return err;
}
return 0;
}
static struct platform_driver sy7636a_sensor_driver = {
.probe = sy7636a_sensor_probe,
.driver = {
.name = "sy7636a-temperature",
},
};
module_platform_driver(sy7636a_sensor_driver);
MODULE_DESCRIPTION("SY7636A sensor driver");
MODULE_LICENSE("GPL");
......@@ -17,6 +17,7 @@
#define IQS620_TEMP_SCALE 1000
#define IQS620_TEMP_OFFSET (-100)
#define IQS620_TEMP_OFFSET_V3 (-40)
static int iqs620_temp_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
......@@ -41,7 +42,8 @@ static int iqs620_temp_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
case IIO_CHAN_INFO_OFFSET:
*val = IQS620_TEMP_OFFSET;
*val = iqs62x->hw_num < IQS620_HW_NUM_V3 ? IQS620_TEMP_OFFSET
: IQS620_TEMP_OFFSET_V3;
return IIO_VAL_INT;
default:
......
......@@ -849,6 +849,20 @@ config MFD_MAX77693
additional drivers must be enabled in order to use the functionality
of the device.
config MFD_MAX77714
tristate "Maxim Semiconductor MAX77714 PMIC Support"
depends on I2C
depends on OF || COMPILE_TEST
select MFD_CORE
select REGMAP_I2C
help
Say yes here to add support for Maxim Semiconductor MAX77714.
This is a Power Management IC with 4 buck regulators, 9
low-dropout regulators, 8 GPIOs, RTC, watchdog etc. This driver
provides common support for accessing the device; additional
drivers must be enabled in order to use each functionality of the
device.
config MFD_MAX77843
bool "Maxim Semiconductor MAX77843 PMIC Support"
depends on I2C=y
......@@ -1188,7 +1202,7 @@ config MFD_SI476X_CORE
module will be called si476x-core.
config MFD_SIMPLE_MFD_I2C
tristate
tristate "Simple Multi-Functional Device support (I2C)"
depends on I2C
select MFD_CORE
select REGMAP_I2C
......@@ -1283,14 +1297,6 @@ config AB8500_CORE
the irq_chip parts for handling the Mixed Signal chip events.
This chip embeds various other multimedia functionalities as well.
config AB8500_DEBUG
bool "Enable debug info via debugfs"
depends on AB8500_GPADC && DEBUG_FS
default y if DEBUG_FS
help
Select this option if you want debug information using the debug
filesystem, debugfs.
config MFD_DB8500_PRCMU
bool "ST-Ericsson DB8500 Power Reset Control Management Unit"
depends on UX500_SOC_DB8500
......
......@@ -162,6 +162,7 @@ obj-$(CONFIG_MFD_MAX77620) += max77620.o
obj-$(CONFIG_MFD_MAX77650) += max77650.o
obj-$(CONFIG_MFD_MAX77686) += max77686.o
obj-$(CONFIG_MFD_MAX77693) += max77693.o
obj-$(CONFIG_MFD_MAX77714) += max77714.o
obj-$(CONFIG_MFD_MAX77843) += max77843.o
obj-$(CONFIG_MFD_MAX8907) += max8907.o
max8925-objs := max8925-core.o max8925-i2c.o
......@@ -176,7 +177,6 @@ obj-$(CONFIG_MFD_PCF50633) += pcf50633.o
obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o
obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o
obj-$(CONFIG_ABX500_CORE) += abx500-core.o
obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o
obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o
# ab8500-core need to come after db8500-prcmu (which provides the channel)
obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o
......
......@@ -613,10 +613,6 @@ static const struct mfd_cell ab8500_bm_devs[] = {
};
static const struct mfd_cell ab8500_devs[] = {
#ifdef CONFIG_DEBUG_FS
MFD_CELL_OF("ab8500-debug",
NULL, NULL, 0, 0, "stericsson,ab8500-debug"),
#endif
MFD_CELL_OF("ab8500-sysctrl",
NULL, NULL, 0, 0, "stericsson,ab8500-sysctrl"),
MFD_CELL_OF("ab8500-ext-regulator",
......@@ -652,11 +648,6 @@ static const struct mfd_cell ab8500_devs[] = {
};
static const struct mfd_cell ab9540_devs[] = {
#ifdef CONFIG_DEBUG_FS
{
.name = "ab8500-debug",
},
#endif
{
.name = "ab8500-sysctrl",
},
......@@ -707,12 +698,6 @@ static const struct mfd_cell ab9540_devs[] = {
/* Device list for ab8505 */
static const struct mfd_cell ab8505_devs[] = {
#ifdef CONFIG_DEBUG_FS
{
.name = "ab8500-debug",
.of_compatible = "stericsson,ab8500-debug",
},
#endif
{
.name = "ab8500-sysctrl",
.of_compatible = "stericsson,ab8500-sysctrl",
......@@ -764,11 +749,6 @@ static const struct mfd_cell ab8505_devs[] = {
};
static const struct mfd_cell ab8540_devs[] = {
#ifdef CONFIG_DEBUG_FS
{
.name = "ab8500-debug",
},
#endif
{
.name = "ab8500-sysctrl",
},
......@@ -1042,9 +1022,9 @@ static int ab8500_probe(struct platform_device *pdev)
enum ab8500_version version = AB8500_VERSION_UNDEFINED;
struct device_node *np = pdev->dev.of_node;
struct ab8500 *ab8500;
struct resource *resource;
int ret;
int i;
int irq;
u8 value;
ab8500 = devm_kzalloc(&pdev->dev, sizeof(*ab8500), GFP_KERNEL);
......@@ -1053,13 +1033,11 @@ static int ab8500_probe(struct platform_device *pdev)
ab8500->dev = &pdev->dev;
resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!resource) {
dev_err(&pdev->dev, "no IRQ resource\n");
return -ENODEV;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
ab8500->irq = resource->start;
ab8500->irq = irq;
ab8500->read = ab8500_prcmu_read;
ab8500->write = ab8500_prcmu_write;
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) ST-Ericsson SA 2010
*
* Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson.
*/
/*
* AB8500 register access
* ======================
*
* read:
* # echo BANK > <debugfs>/ab8500/register-bank
* # echo ADDR > <debugfs>/ab8500/register-address
* # cat <debugfs>/ab8500/register-value
*
* write:
* # echo BANK > <debugfs>/ab8500/register-bank
* # echo ADDR > <debugfs>/ab8500/register-address
* # echo VALUE > <debugfs>/ab8500/register-value
*
* read all registers from a bank:
* # echo BANK > <debugfs>/ab8500/register-bank
* # cat <debugfs>/ab8500/all-bank-register
*
* BANK target AB8500 register bank
* ADDR target AB8500 register address
* VALUE decimal or 0x-prefixed hexadecimal
*
*
* User Space notification on AB8500 IRQ
* =====================================
*
* Allows user space entity to be notified when target AB8500 IRQ occurs.
* When subscribed, a sysfs entry is created in ab8500.i2c platform device.
* One can pool this file to get target IRQ occurence information.
*
* subscribe to an AB8500 IRQ:
* # echo IRQ > <debugfs>/ab8500/irq-subscribe
*
* unsubscribe from an AB8500 IRQ:
* # echo IRQ > <debugfs>/ab8500/irq-unsubscribe
*
*
* AB8500 register formated read/write access
* ==========================================
*
* Read: read data, data>>SHIFT, data&=MASK, output data
* [0xABCDEF98] shift=12 mask=0xFFF => 0x00000CDE
* Write: read data, data &= ~(MASK<<SHIFT), data |= (VALUE<<SHIFT), write data
* [0xABCDEF98] shift=12 mask=0xFFF value=0x123 => [0xAB123F98]
*
* Usage:
* # echo "CMD [OPTIONS] BANK ADRESS [VALUE]" > $debugfs/ab8500/hwreg
*
* CMD read read access
* write write access
*
* BANK target reg bank
* ADDRESS target reg address
* VALUE (write) value to be updated
*
* OPTIONS
* -d|-dec (read) output in decimal
* -h|-hexa (read) output in 0x-hexa (default)
* -l|-w|-b 32bit (default), 16bit or 8bit reg access
* -m|-mask MASK 0x-hexa mask (default 0xFFFFFFFF)
* -s|-shift SHIFT bit shift value (read:left, write:right)
* -o|-offset OFFSET address offset to add to ADDRESS value
*
* Warning: bit shift operation is applied to bit-mask.
* Warning: bit shift direction depends on read or right command.
*/
#include <linux/seq_file.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/debugfs.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/kobject.h>
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
#ifdef CONFIG_DEBUG_FS
#include <linux/string.h>
#include <linux/ctype.h>
#endif
static u32 debug_bank;
static u32 debug_address;
static int irq_ab8500;
static int irq_first;
static int irq_last;
static u32 *irq_count;
static int num_irqs;
static struct device_attribute **dev_attr;
static char **event_name;
/**
* struct ab8500_reg_range
* @first: the first address of the range
* @last: the last address of the range
* @perm: access permissions for the range
*/
struct ab8500_reg_range {
u8 first;
u8 last;
u8 perm;
};
/**
* struct ab8500_prcmu_ranges
* @num_ranges: the number of ranges in the list
* @bankid: bank identifier
* @range: the list of register ranges
*/
struct ab8500_prcmu_ranges {
u8 num_ranges;
u8 bankid;
const struct ab8500_reg_range *range;
};
/* hwreg- "mask" and "shift" entries ressources */
struct hwreg_cfg {
u32 bank; /* target bank */
unsigned long addr; /* target address */
uint fmt; /* format */
unsigned long mask; /* read/write mask, applied before any bit shift */
long shift; /* bit shift (read:right shift, write:left shift */
};
/* fmt bit #0: 0=hexa, 1=dec */
#define REG_FMT_DEC(c) ((c)->fmt & 0x1)
#define REG_FMT_HEX(c) (!REG_FMT_DEC(c))
static struct hwreg_cfg hwreg_cfg = {
.addr = 0, /* default: invalid phys addr */
.fmt = 0, /* default: 32bit access, hex output */
.mask = 0xFFFFFFFF, /* default: no mask */
.shift = 0, /* default: no bit shift */
};
#define AB8500_NAME_STRING "ab8500"
#define AB8500_NUM_BANKS AB8500_DEBUG_FIELD_LAST
#define AB8500_REV_REG 0x80
static struct ab8500_prcmu_ranges *debug_ranges;
static struct ab8500_prcmu_ranges ab8500_debug_ranges[AB8500_NUM_BANKS] = {
[AB8500_M_FSM_RANK] = {
.num_ranges = 0,
.range = NULL,
},
[AB8500_SYS_CTRL1_BLOCK] = {
.num_ranges = 3,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x02,
},
{
.first = 0x42,
.last = 0x42,
},
{
.first = 0x80,
.last = 0x81,
},
},
},
[AB8500_SYS_CTRL2_BLOCK] = {
.num_ranges = 4,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x0D,
},
{
.first = 0x0F,
.last = 0x17,
},
{
.first = 0x30,
.last = 0x30,
},
{
.first = 0x32,
.last = 0x33,
},
},
},
[AB8500_REGU_CTRL1] = {
.num_ranges = 3,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x00,
},
{
.first = 0x03,
.last = 0x10,
},
{
.first = 0x80,
.last = 0x84,
},
},
},
[AB8500_REGU_CTRL2] = {
.num_ranges = 5,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x15,
},
{
.first = 0x17,
.last = 0x19,
},
{
.first = 0x1B,
.last = 0x1D,
},
{
.first = 0x1F,
.last = 0x22,
},
{
.first = 0x40,
.last = 0x44,
},
/*
* 0x80-0x8B are SIM registers and should
* not be accessed from here
*/
},
},
[AB8500_USB] = {
.num_ranges = 2,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x80,
.last = 0x83,
},
{
.first = 0x87,
.last = 0x8A,
},
},
},
[AB8500_TVOUT] = {
.num_ranges = 9,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x12,
},
{
.first = 0x15,
.last = 0x17,
},
{
.first = 0x19,
.last = 0x21,
},
{
.first = 0x27,
.last = 0x2C,
},
{
.first = 0x41,
.last = 0x41,
},
{
.first = 0x45,
.last = 0x5B,
},
{
.first = 0x5D,
.last = 0x5D,
},
{
.first = 0x69,
.last = 0x69,
},
{
.first = 0x80,
.last = 0x81,
},
},
},
[AB8500_DBI] = {
.num_ranges = 0,
.range = NULL,
},
[AB8500_ECI_AV_ACC] = {
.num_ranges = 1,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x80,
.last = 0x82,
},
},
},
[AB8500_RESERVED] = {
.num_ranges = 0,
.range = NULL,
},
[AB8500_GPADC] = {
.num_ranges = 1,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x08,
},
},
},
[AB8500_CHARGER] = {
.num_ranges = 9,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x03,
},
{
.first = 0x05,
.last = 0x05,
},
{
.first = 0x40,
.last = 0x40,
},
{
.first = 0x42,
.last = 0x42,
},
{
.first = 0x44,
.last = 0x44,
},
{
.first = 0x50,
.last = 0x55,
},
{
.first = 0x80,
.last = 0x82,
},
{
.first = 0xC0,
.last = 0xC2,
},
{
.first = 0xf5,
.last = 0xf6,
},
},
},
[AB8500_GAS_GAUGE] = {
.num_ranges = 3,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x00,
},
{
.first = 0x07,
.last = 0x0A,
},
{
.first = 0x10,
.last = 0x14,
},
},
},
[AB8500_AUDIO] = {
.num_ranges = 1,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x6F,
},
},
},
[AB8500_INTERRUPT] = {
.num_ranges = 0,
.range = NULL,
},
[AB8500_RTC] = {
.num_ranges = 1,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x0F,
},
},
},
[AB8500_MISC] = {
.num_ranges = 8,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x05,
},
{
.first = 0x10,
.last = 0x15,
},
{
.first = 0x20,
.last = 0x25,
},
{
.first = 0x30,
.last = 0x35,
},
{
.first = 0x40,
.last = 0x45,
},
{
.first = 0x50,
.last = 0x50,
},
{
.first = 0x60,
.last = 0x67,
},
{
.first = 0x80,
.last = 0x80,
},
},
},
[AB8500_DEVELOPMENT] = {
.num_ranges = 1,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x00,
},
},
},
[AB8500_DEBUG] = {
.num_ranges = 1,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x05,
.last = 0x07,
},
},
},
[AB8500_PROD_TEST] = {
.num_ranges = 0,
.range = NULL,
},
[AB8500_STE_TEST] = {
.num_ranges = 0,
.range = NULL,
},
[AB8500_OTP_EMUL] = {
.num_ranges = 1,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x01,
.last = 0x0F,
},
},
},
};
static struct ab8500_prcmu_ranges ab8505_debug_ranges[AB8500_NUM_BANKS] = {
[0x0] = {
.num_ranges = 0,
.range = NULL,
},
[AB8500_SYS_CTRL1_BLOCK] = {
.num_ranges = 5,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x04,
},
{
.first = 0x42,
.last = 0x42,
},
{
.first = 0x52,
.last = 0x52,
},
{
.first = 0x54,
.last = 0x57,
},
{
.first = 0x80,
.last = 0x83,
},
},
},
[AB8500_SYS_CTRL2_BLOCK] = {
.num_ranges = 5,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x0D,
},
{
.first = 0x0F,
.last = 0x17,
},
{
.first = 0x20,
.last = 0x20,
},
{
.first = 0x30,
.last = 0x30,
},
{
.first = 0x32,
.last = 0x3A,
},
},
},
[AB8500_REGU_CTRL1] = {
.num_ranges = 3,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x00,
},
{
.first = 0x03,
.last = 0x11,
},
{
.first = 0x80,
.last = 0x86,
},
},
},
[AB8500_REGU_CTRL2] = {
.num_ranges = 6,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x06,
},
{
.first = 0x08,
.last = 0x15,
},
{
.first = 0x17,
.last = 0x19,
},
{
.first = 0x1B,
.last = 0x1D,
},
{
.first = 0x1F,
.last = 0x30,
},
{
.first = 0x40,
.last = 0x48,
},
/*
* 0x80-0x8B are SIM registers and should
* not be accessed from here
*/
},
},
[AB8500_USB] = {
.num_ranges = 3,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x80,
.last = 0x83,
},
{
.first = 0x87,
.last = 0x8A,
},
{
.first = 0x91,
.last = 0x94,
},
},
},
[AB8500_TVOUT] = {
.num_ranges = 0,
.range = NULL,
},
[AB8500_DBI] = {
.num_ranges = 0,
.range = NULL,
},
[AB8500_ECI_AV_ACC] = {
.num_ranges = 1,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x80,
.last = 0x82,
},
},
},
[AB8500_RESERVED] = {
.num_ranges = 0,
.range = NULL,
},
[AB8500_GPADC] = {
.num_ranges = 1,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x08,
},
},
},
[AB8500_CHARGER] = {
.num_ranges = 9,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x02,
.last = 0x03,
},
{
.first = 0x05,
.last = 0x05,
},
{
.first = 0x40,
.last = 0x44,
},
{
.first = 0x50,
.last = 0x57,
},
{
.first = 0x60,
.last = 0x60,
},
{
.first = 0xA0,
.last = 0xA7,
},
{
.first = 0xAF,
.last = 0xB2,
},
{
.first = 0xC0,
.last = 0xC2,
},
{
.first = 0xF5,
.last = 0xF5,
},
},
},
[AB8500_GAS_GAUGE] = {
.num_ranges = 3,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x00,
},
{
.first = 0x07,
.last = 0x0A,
},
{
.first = 0x10,
.last = 0x14,
},
},
},
[AB8500_AUDIO] = {
.num_ranges = 1,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x83,
},
},
},
[AB8500_INTERRUPT] = {
.num_ranges = 11,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x04,
},
{
.first = 0x06,
.last = 0x07,
},
{
.first = 0x09,
.last = 0x09,
},
{
.first = 0x0B,
.last = 0x0C,
},
{
.first = 0x12,
.last = 0x15,
},
{
.first = 0x18,
.last = 0x18,
},
/* Latch registers should not be read here */
{
.first = 0x40,
.last = 0x44,
},
{
.first = 0x46,
.last = 0x49,
},
{
.first = 0x4B,
.last = 0x4D,
},
{
.first = 0x52,
.last = 0x55,
},
{
.first = 0x58,
.last = 0x58,
},
/* LatchHier registers should not be read here */
},
},
[AB8500_RTC] = {
.num_ranges = 2,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x14,
},
{
.first = 0x16,
.last = 0x17,
},
},
},
[AB8500_MISC] = {
.num_ranges = 8,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x06,
},
{
.first = 0x10,
.last = 0x16,
},
{
.first = 0x20,
.last = 0x26,
},
{
.first = 0x30,
.last = 0x36,
},
{
.first = 0x40,
.last = 0x46,
},
{
.first = 0x50,
.last = 0x50,
},
{
.first = 0x60,
.last = 0x6B,
},
{
.first = 0x80,
.last = 0x82,
},
},
},
[AB8500_DEVELOPMENT] = {
.num_ranges = 2,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x00,
},
{
.first = 0x05,
.last = 0x05,
},
},
},
[AB8500_DEBUG] = {
.num_ranges = 1,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x05,
.last = 0x07,
},
},
},
[AB8500_PROD_TEST] = {
.num_ranges = 0,
.range = NULL,
},
[AB8500_STE_TEST] = {
.num_ranges = 0,
.range = NULL,
},
[AB8500_OTP_EMUL] = {
.num_ranges = 1,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x01,
.last = 0x15,
},
},
},
};
static struct ab8500_prcmu_ranges ab8540_debug_ranges[AB8500_NUM_BANKS] = {
[AB8500_M_FSM_RANK] = {
.num_ranges = 1,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x0B,
},
},
},
[AB8500_SYS_CTRL1_BLOCK] = {
.num_ranges = 6,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x04,
},
{
.first = 0x42,
.last = 0x42,
},
{
.first = 0x50,
.last = 0x54,
},
{
.first = 0x57,
.last = 0x57,
},
{
.first = 0x80,
.last = 0x83,
},
{
.first = 0x90,
.last = 0x90,
},
},
},
[AB8500_SYS_CTRL2_BLOCK] = {
.num_ranges = 5,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x0D,
},
{
.first = 0x0F,
.last = 0x10,
},
{
.first = 0x20,
.last = 0x21,
},
{
.first = 0x32,
.last = 0x3C,
},
{
.first = 0x40,
.last = 0x42,
},
},
},
[AB8500_REGU_CTRL1] = {
.num_ranges = 4,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x03,
.last = 0x15,
},
{
.first = 0x20,
.last = 0x20,
},
{
.first = 0x80,
.last = 0x85,
},
{
.first = 0x87,
.last = 0x88,
},
},
},
[AB8500_REGU_CTRL2] = {
.num_ranges = 8,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x06,
},
{
.first = 0x08,
.last = 0x15,
},
{
.first = 0x17,
.last = 0x19,
},
{
.first = 0x1B,
.last = 0x1D,
},
{
.first = 0x1F,
.last = 0x2F,
},
{
.first = 0x31,
.last = 0x3A,
},
{
.first = 0x43,
.last = 0x44,
},
{
.first = 0x48,
.last = 0x49,
},
},
},
[AB8500_USB] = {
.num_ranges = 3,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x80,
.last = 0x83,
},
{
.first = 0x87,
.last = 0x8A,
},
{
.first = 0x91,
.last = 0x94,
},
},
},
[AB8500_TVOUT] = {
.num_ranges = 0,
.range = NULL
},
[AB8500_DBI] = {
.num_ranges = 4,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x07,
},
{
.first = 0x10,
.last = 0x11,
},
{
.first = 0x20,
.last = 0x21,
},
{
.first = 0x30,
.last = 0x43,
},
},
},
[AB8500_ECI_AV_ACC] = {
.num_ranges = 2,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x03,
},
{
.first = 0x80,
.last = 0x82,
},
},
},
[AB8500_RESERVED] = {
.num_ranges = 0,
.range = NULL,
},
[AB8500_GPADC] = {
.num_ranges = 4,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x01,
},
{
.first = 0x04,
.last = 0x06,
},
{
.first = 0x09,
.last = 0x0A,
},
{
.first = 0x10,
.last = 0x14,
},
},
},
[AB8500_CHARGER] = {
.num_ranges = 10,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x00,
},
{
.first = 0x02,
.last = 0x05,
},
{
.first = 0x40,
.last = 0x44,
},
{
.first = 0x50,
.last = 0x57,
},
{
.first = 0x60,
.last = 0x60,
},
{
.first = 0x70,
.last = 0x70,
},
{
.first = 0xA0,
.last = 0xA9,
},
{
.first = 0xAF,
.last = 0xB2,
},
{
.first = 0xC0,
.last = 0xC6,
},
{
.first = 0xF5,
.last = 0xF5,
},
},
},
[AB8500_GAS_GAUGE] = {
.num_ranges = 3,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x00,
},
{
.first = 0x07,
.last = 0x0A,
},
{
.first = 0x10,
.last = 0x14,
},
},
},
[AB8500_AUDIO] = {
.num_ranges = 1,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x9f,
},
},
},
[AB8500_INTERRUPT] = {
.num_ranges = 6,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x05,
},
{
.first = 0x0B,
.last = 0x0D,
},
{
.first = 0x12,
.last = 0x20,
},
/* Latch registers should not be read here */
{
.first = 0x40,
.last = 0x45,
},
{
.first = 0x4B,
.last = 0x4D,
},
{
.first = 0x52,
.last = 0x60,
},
/* LatchHier registers should not be read here */
},
},
[AB8500_RTC] = {
.num_ranges = 3,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x07,
},
{
.first = 0x0B,
.last = 0x18,
},
{
.first = 0x20,
.last = 0x25,
},
},
},
[AB8500_MISC] = {
.num_ranges = 9,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x06,
},
{
.first = 0x10,
.last = 0x16,
},
{
.first = 0x20,
.last = 0x26,
},
{
.first = 0x30,
.last = 0x36,
},
{
.first = 0x40,
.last = 0x49,
},
{
.first = 0x50,
.last = 0x50,
},
{
.first = 0x60,
.last = 0x6B,
},
{
.first = 0x70,
.last = 0x74,
},
{
.first = 0x80,
.last = 0x82,
},
},
},
[AB8500_DEVELOPMENT] = {
.num_ranges = 3,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x01,
},
{
.first = 0x06,
.last = 0x06,
},
{
.first = 0x10,
.last = 0x21,
},
},
},
[AB8500_DEBUG] = {
.num_ranges = 3,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x01,
.last = 0x0C,
},
{
.first = 0x0E,
.last = 0x11,
},
{
.first = 0x80,
.last = 0x81,
},
},
},
[AB8500_PROD_TEST] = {
.num_ranges = 0,
.range = NULL,
},
[AB8500_STE_TEST] = {
.num_ranges = 0,
.range = NULL,
},
[AB8500_OTP_EMUL] = {
.num_ranges = 1,
.range = (struct ab8500_reg_range[]) {
{
.first = 0x00,
.last = 0x3F,
},
},
},
};
static irqreturn_t ab8500_debug_handler(int irq, void *data)
{
char buf[16];
struct kobject *kobj = (struct kobject *)data;
unsigned int irq_abb = irq - irq_first;
if (irq_abb < num_irqs)
irq_count[irq_abb]++;
/*
* This makes it possible to use poll for events (EPOLLPRI | EPOLLERR)
* from userspace on sysfs file named <irq-nr>
*/
sprintf(buf, "%d", irq);
sysfs_notify(kobj, NULL, buf);
return IRQ_HANDLED;
}
/* Prints to seq_file or log_buf */
static int ab8500_registers_print(struct device *dev, u32 bank,
struct seq_file *s)
{
unsigned int i;
for (i = 0; i < debug_ranges[bank].num_ranges; i++) {
u32 reg;
for (reg = debug_ranges[bank].range[i].first;
reg <= debug_ranges[bank].range[i].last;
reg++) {
u8 value;
int err;
err = abx500_get_register_interruptible(dev,
(u8)bank, (u8)reg, &value);
if (err < 0) {
dev_err(dev, "ab->read fail %d\n", err);
return err;
}
if (s) {
seq_printf(s, " [0x%02X/0x%02X]: 0x%02X\n",
bank, reg, value);
/*
* Error is not returned here since
* the output is wanted in any case
*/
if (seq_has_overflowed(s))
return 0;
} else {
dev_info(dev, " [0x%02X/0x%02X]: 0x%02X\n",
bank, reg, value);
}
}
}
return 0;
}
static int ab8500_bank_registers_show(struct seq_file *s, void *p)
{
struct device *dev = s->private;
u32 bank = debug_bank;
seq_puts(s, AB8500_NAME_STRING " register values:\n");
seq_printf(s, " bank 0x%02X:\n", bank);
return ab8500_registers_print(dev, bank, s);
}
DEFINE_SHOW_ATTRIBUTE(ab8500_bank_registers);
static int ab8500_print_all_banks(struct seq_file *s, void *p)
{
struct device *dev = s->private;
unsigned int i;
seq_puts(s, AB8500_NAME_STRING " register values:\n");
for (i = 0; i < AB8500_NUM_BANKS; i++) {
int err;
seq_printf(s, " bank 0x%02X:\n", i);
err = ab8500_registers_print(dev, i, s);
if (err)
return err;
}
return 0;
}
/* Dump registers to kernel log */
void ab8500_dump_all_banks(struct device *dev)
{
unsigned int i;
dev_info(dev, "ab8500 register values:\n");
for (i = 1; i < AB8500_NUM_BANKS; i++) {
dev_info(dev, " bank 0x%02X:\n", i);
ab8500_registers_print(dev, i, NULL);
}
}
static int ab8500_all_banks_open(struct inode *inode, struct file *file)
{
struct seq_file *s;
int err;
err = single_open(file, ab8500_print_all_banks, inode->i_private);
if (!err) {
/* Default buf size in seq_read is not enough */
s = (struct seq_file *)file->private_data;
s->size = (PAGE_SIZE * 2);
s->buf = kmalloc(s->size, GFP_KERNEL);
if (!s->buf) {
single_release(inode, file);
err = -ENOMEM;
}
}
return err;
}
static const struct file_operations ab8500_all_banks_fops = {
.open = ab8500_all_banks_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static int ab8500_bank_print(struct seq_file *s, void *p)
{
seq_printf(s, "0x%02X\n", debug_bank);
return 0;
}
static int ab8500_bank_open(struct inode *inode, struct file *file)
{
return single_open(file, ab8500_bank_print, inode->i_private);
}
static ssize_t ab8500_bank_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct device *dev = ((struct seq_file *)(file->private_data))->private;
unsigned long user_bank;
int err;
err = kstrtoul_from_user(user_buf, count, 0, &user_bank);
if (err)
return err;
if (user_bank >= AB8500_NUM_BANKS) {
dev_err(dev, "debugfs error input > number of banks\n");
return -EINVAL;
}
debug_bank = user_bank;
return count;
}
static int ab8500_address_print(struct seq_file *s, void *p)
{
seq_printf(s, "0x%02X\n", debug_address);
return 0;
}
static int ab8500_address_open(struct inode *inode, struct file *file)
{
return single_open(file, ab8500_address_print, inode->i_private);
}
static ssize_t ab8500_address_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct device *dev = ((struct seq_file *)(file->private_data))->private;
unsigned long user_address;
int err;
err = kstrtoul_from_user(user_buf, count, 0, &user_address);
if (err)
return err;
if (user_address > 0xff) {
dev_err(dev, "debugfs error input > 0xff\n");
return -EINVAL;
}
debug_address = user_address;
return count;
}
static int ab8500_val_print(struct seq_file *s, void *p)
{
struct device *dev = s->private;
int ret;
u8 regvalue;
ret = abx500_get_register_interruptible(dev,
(u8)debug_bank, (u8)debug_address, &regvalue);
if (ret < 0) {
dev_err(dev, "abx500_get_reg fail %d, %d\n",
ret, __LINE__);
return -EINVAL;
}
seq_printf(s, "0x%02X\n", regvalue);
return 0;
}
static int ab8500_val_open(struct inode *inode, struct file *file)
{
return single_open(file, ab8500_val_print, inode->i_private);
}
static ssize_t ab8500_val_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct device *dev = ((struct seq_file *)(file->private_data))->private;
unsigned long user_val;
int err;
err = kstrtoul_from_user(user_buf, count, 0, &user_val);
if (err)
return err;
if (user_val > 0xff) {
dev_err(dev, "debugfs error input > 0xff\n");
return -EINVAL;
}
err = abx500_set_register_interruptible(dev,
(u8)debug_bank, debug_address, (u8)user_val);
if (err < 0) {
pr_err("abx500_set_reg failed %d, %d", err, __LINE__);
return -EINVAL;
}
return count;
}
/*
* Interrupt status
*/
static u32 num_interrupts[AB8500_MAX_NR_IRQS];
static u32 num_wake_interrupts[AB8500_MAX_NR_IRQS];
static int num_interrupt_lines;
void ab8500_debug_register_interrupt(int line)
{
if (line < num_interrupt_lines)
num_interrupts[line]++;
}
static int ab8500_interrupts_show(struct seq_file *s, void *p)
{
int line;
seq_puts(s, "name: number: irq: number of: wake:\n");
for (line = 0; line < num_interrupt_lines; line++) {
seq_printf(s, "%3i: %4i %6i %4i\n",
line,
line + irq_first,
num_interrupts[line],
num_wake_interrupts[line]);
}
return 0;
}
DEFINE_SHOW_ATTRIBUTE(ab8500_interrupts);
/*
* - HWREG DB8500 formated routines
*/
static int ab8500_hwreg_print(struct seq_file *s, void *d)
{
struct device *dev = s->private;
int ret;
u8 regvalue;
ret = abx500_get_register_interruptible(dev,
(u8)hwreg_cfg.bank, (u8)hwreg_cfg.addr, &regvalue);
if (ret < 0) {
dev_err(dev, "abx500_get_reg fail %d, %d\n",
ret, __LINE__);
return -EINVAL;
}
if (hwreg_cfg.shift >= 0)
regvalue >>= hwreg_cfg.shift;
else
regvalue <<= -hwreg_cfg.shift;
regvalue &= hwreg_cfg.mask;
if (REG_FMT_DEC(&hwreg_cfg))
seq_printf(s, "%d\n", regvalue);
else
seq_printf(s, "0x%02X\n", regvalue);
return 0;
}
static int ab8500_hwreg_open(struct inode *inode, struct file *file)
{
return single_open(file, ab8500_hwreg_print, inode->i_private);
}
#define AB8500_SUPPLY_CONTROL_CONFIG_1 0x01
#define AB8500_SUPPLY_CONTROL_REG 0x00
#define AB8500_FIRST_SIM_REG 0x80
#define AB8500_LAST_SIM_REG 0x8B
#define AB8505_LAST_SIM_REG 0x8C
static int ab8500_modem_show(struct seq_file *s, void *p)
{
struct device *dev = s->private;
struct ab8500 *ab8500;
int err;
u8 value;
u8 orig_value;
u32 bank = AB8500_REGU_CTRL2;
u32 last_sim_reg = AB8500_LAST_SIM_REG;
u32 reg;
ab8500 = dev_get_drvdata(dev->parent);
dev_warn(dev, "WARNING! This operation can interfer with modem side\n"
"and should only be done with care\n");
err = abx500_get_register_interruptible(dev,
AB8500_REGU_CTRL1, AB8500_SUPPLY_CONTROL_REG, &orig_value);
if (err < 0)
goto report_read_failure;
/* Config 1 will allow APE side to read SIM registers */
err = abx500_set_register_interruptible(dev,
AB8500_REGU_CTRL1, AB8500_SUPPLY_CONTROL_REG,
AB8500_SUPPLY_CONTROL_CONFIG_1);
if (err < 0)
goto report_write_failure;
seq_printf(s, " bank 0x%02X:\n", bank);
if (is_ab9540(ab8500) || is_ab8505(ab8500))
last_sim_reg = AB8505_LAST_SIM_REG;
for (reg = AB8500_FIRST_SIM_REG; reg <= last_sim_reg; reg++) {
err = abx500_get_register_interruptible(dev,
bank, reg, &value);
if (err < 0)
goto report_read_failure;
seq_printf(s, " [0x%02X/0x%02X]: 0x%02X\n", bank, reg, value);
}
err = abx500_set_register_interruptible(dev,
AB8500_REGU_CTRL1, AB8500_SUPPLY_CONTROL_REG, orig_value);
if (err < 0)
goto report_write_failure;
return 0;
report_read_failure:
dev_err(dev, "ab->read fail %d\n", err);
return err;
report_write_failure:
dev_err(dev, "ab->write fail %d\n", err);
return err;
}
DEFINE_SHOW_ATTRIBUTE(ab8500_modem);
/*
* return length of an ASCII numerical value, 0 is string is not a
* numerical value.
* string shall start at value 1st char.
* string can be tailed with \0 or space or newline chars only.
* value can be decimal or hexadecimal (prefixed 0x or 0X).
*/
static int strval_len(char *b)
{
char *s = b;
if ((*s == '0') && ((*(s+1) == 'x') || (*(s+1) == 'X'))) {
s += 2;
for (; *s && (*s != ' ') && (*s != '\n'); s++) {
if (!isxdigit(*s))
return 0;
}
} else {
if (*s == '-')
s++;
for (; *s && (*s != ' ') && (*s != '\n'); s++) {
if (!isdigit(*s))
return 0;
}
}
return (int) (s-b);
}
/*
* parse hwreg input data.
* update global hwreg_cfg only if input data syntax is ok.
*/
static ssize_t hwreg_common_write(char *b, struct hwreg_cfg *cfg,
struct device *dev)
{
uint write, val = 0;
u8 regvalue;
int ret;
struct hwreg_cfg loc = {
.bank = 0, /* default: invalid phys addr */
.addr = 0, /* default: invalid phys addr */
.fmt = 0, /* default: 32bit access, hex output */
.mask = 0xFFFFFFFF, /* default: no mask */
.shift = 0, /* default: no bit shift */
};
/* read or write ? */
if (!strncmp(b, "read ", 5)) {
write = 0;
b += 5;
} else if (!strncmp(b, "write ", 6)) {
write = 1;
b += 6;
} else
return -EINVAL;
/* OPTIONS -l|-w|-b -s -m -o */
while ((*b == ' ') || (*b == '-')) {
if (*(b-1) != ' ') {
b++;
continue;
}
if ((!strncmp(b, "-d ", 3)) ||
(!strncmp(b, "-dec ", 5))) {
b += (*(b+2) == ' ') ? 3 : 5;
loc.fmt |= (1<<0);
} else if ((!strncmp(b, "-h ", 3)) ||
(!strncmp(b, "-hex ", 5))) {
b += (*(b+2) == ' ') ? 3 : 5;
loc.fmt &= ~(1<<0);
} else if ((!strncmp(b, "-m ", 3)) ||
(!strncmp(b, "-mask ", 6))) {
b += (*(b+2) == ' ') ? 3 : 6;
if (strval_len(b) == 0)
return -EINVAL;
ret = kstrtoul(b, 0, &loc.mask);
if (ret)
return ret;
} else if ((!strncmp(b, "-s ", 3)) ||
(!strncmp(b, "-shift ", 7))) {
b += (*(b+2) == ' ') ? 3 : 7;
if (strval_len(b) == 0)
return -EINVAL;
ret = kstrtol(b, 0, &loc.shift);
if (ret)
return ret;
} else {
return -EINVAL;
}
}
/* get arg BANK and ADDRESS */
if (strval_len(b) == 0)
return -EINVAL;
ret = kstrtouint(b, 0, &loc.bank);
if (ret)
return ret;
while (*b == ' ')
b++;
if (strval_len(b) == 0)
return -EINVAL;
ret = kstrtoul(b, 0, &loc.addr);
if (ret)
return ret;
if (write) {
while (*b == ' ')
b++;
if (strval_len(b) == 0)
return -EINVAL;
ret = kstrtouint(b, 0, &val);
if (ret)
return ret;
}
/* args are ok, update target cfg (mainly for read) */
*cfg = loc;
#ifdef ABB_HWREG_DEBUG
pr_warn("HWREG request: %s, %s,\n", (write) ? "write" : "read",
REG_FMT_DEC(cfg) ? "decimal" : "hexa");
pr_warn(" addr=0x%08X, mask=0x%X, shift=%d" "value=0x%X\n",
cfg->addr, cfg->mask, cfg->shift, val);
#endif
if (!write)
return 0;
ret = abx500_get_register_interruptible(dev,
(u8)cfg->bank, (u8)cfg->addr, &regvalue);
if (ret < 0) {
dev_err(dev, "abx500_get_reg fail %d, %d\n",
ret, __LINE__);
return -EINVAL;
}
if (cfg->shift >= 0) {
regvalue &= ~(cfg->mask << (cfg->shift));
val = (val & cfg->mask) << (cfg->shift);
} else {
regvalue &= ~(cfg->mask >> (-cfg->shift));
val = (val & cfg->mask) >> (-cfg->shift);
}
val = val | regvalue;
ret = abx500_set_register_interruptible(dev,
(u8)cfg->bank, (u8)cfg->addr, (u8)val);
if (ret < 0) {
pr_err("abx500_set_reg failed %d, %d", ret, __LINE__);
return -EINVAL;
}
return 0;
}
static ssize_t ab8500_hwreg_write(struct file *file,
const char __user *user_buf, size_t count, loff_t *ppos)
{
struct device *dev = ((struct seq_file *)(file->private_data))->private;
char buf[128];
int buf_size, ret;
/* Get userspace string and assure termination */
buf_size = min((int)count, (int)(sizeof(buf)-1));
if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT;
buf[buf_size] = 0;
/* get args and process */
ret = hwreg_common_write(buf, &hwreg_cfg, dev);
return (ret) ? ret : buf_size;
}
/*
* - irq subscribe/unsubscribe stuff
*/
static int ab8500_subscribe_unsubscribe_print(struct seq_file *s, void *p)
{
seq_printf(s, "%d\n", irq_first);
return 0;
}
static int ab8500_subscribe_unsubscribe_open(struct inode *inode,
struct file *file)
{
return single_open(file, ab8500_subscribe_unsubscribe_print,
inode->i_private);
}
/*
* Userspace should use poll() on this file. When an event occur
* the blocking poll will be released.
*/
static ssize_t show_irq(struct device *dev,
struct device_attribute *attr, char *buf)
{
unsigned long name;
unsigned int irq_index;
int err;
err = kstrtoul(attr->attr.name, 0, &name);
if (err)
return err;
irq_index = name - irq_first;
if (irq_index >= num_irqs)
return -EINVAL;
return sprintf(buf, "%u\n", irq_count[irq_index]);
}
static ssize_t ab8500_subscribe_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct device *dev = ((struct seq_file *)(file->private_data))->private;
unsigned long user_val;
int err;
unsigned int irq_index;
err = kstrtoul_from_user(user_buf, count, 0, &user_val);
if (err)
return err;
if (user_val < irq_first) {
dev_err(dev, "debugfs error input < %d\n", irq_first);
return -EINVAL;
}
if (user_val > irq_last) {
dev_err(dev, "debugfs error input > %d\n", irq_last);
return -EINVAL;
}
irq_index = user_val - irq_first;
if (irq_index >= num_irqs)
return -EINVAL;
/*
* This will create a sysfs file named <irq-nr> which userspace can
* use to select or poll and get the AB8500 events
*/
dev_attr[irq_index] = kmalloc(sizeof(struct device_attribute),
GFP_KERNEL);
if (!dev_attr[irq_index])
return -ENOMEM;
event_name[irq_index] = kasprintf(GFP_KERNEL, "%lu", user_val);
if (!event_name[irq_index])
return -ENOMEM;
dev_attr[irq_index]->show = show_irq;
dev_attr[irq_index]->store = NULL;
dev_attr[irq_index]->attr.name = event_name[irq_index];
dev_attr[irq_index]->attr.mode = S_IRUGO;
err = sysfs_create_file(&dev->kobj, &dev_attr[irq_index]->attr);
if (err < 0) {
pr_info("sysfs_create_file failed %d\n", err);
return err;
}
err = request_threaded_irq(user_val, NULL, ab8500_debug_handler,
IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT,
"ab8500-debug", &dev->kobj);
if (err < 0) {
pr_info("request_threaded_irq failed %d, %lu\n",
err, user_val);
sysfs_remove_file(&dev->kobj, &dev_attr[irq_index]->attr);
return err;
}
return count;
}
static ssize_t ab8500_unsubscribe_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct device *dev = ((struct seq_file *)(file->private_data))->private;
unsigned long user_val;
int err;
unsigned int irq_index;
err = kstrtoul_from_user(user_buf, count, 0, &user_val);
if (err)
return err;
if (user_val < irq_first) {
dev_err(dev, "debugfs error input < %d\n", irq_first);
return -EINVAL;
}
if (user_val > irq_last) {
dev_err(dev, "debugfs error input > %d\n", irq_last);
return -EINVAL;
}
irq_index = user_val - irq_first;
if (irq_index >= num_irqs)
return -EINVAL;
/* Set irq count to 0 when unsubscribe */
irq_count[irq_index] = 0;
if (dev_attr[irq_index])
sysfs_remove_file(&dev->kobj, &dev_attr[irq_index]->attr);
free_irq(user_val, &dev->kobj);
kfree(event_name[irq_index]);
kfree(dev_attr[irq_index]);
return count;
}
/*
* - several debugfs nodes fops
*/
static const struct file_operations ab8500_bank_fops = {
.open = ab8500_bank_open,
.write = ab8500_bank_write,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static const struct file_operations ab8500_address_fops = {
.open = ab8500_address_open,
.write = ab8500_address_write,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static const struct file_operations ab8500_val_fops = {
.open = ab8500_val_open,
.write = ab8500_val_write,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static const struct file_operations ab8500_subscribe_fops = {
.open = ab8500_subscribe_unsubscribe_open,
.write = ab8500_subscribe_write,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static const struct file_operations ab8500_unsubscribe_fops = {
.open = ab8500_subscribe_unsubscribe_open,
.write = ab8500_unsubscribe_write,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static const struct file_operations ab8500_hwreg_fops = {
.open = ab8500_hwreg_open,
.write = ab8500_hwreg_write,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
};
static int ab8500_debug_probe(struct platform_device *plf)
{
struct dentry *ab8500_dir;
struct ab8500 *ab8500;
struct resource *res;
debug_bank = AB8500_MISC;
debug_address = AB8500_REV_REG & 0x00FF;
ab8500 = dev_get_drvdata(plf->dev.parent);
num_irqs = ab8500->mask_size;
irq_count = devm_kcalloc(&plf->dev,
num_irqs, sizeof(*irq_count), GFP_KERNEL);
if (!irq_count)
return -ENOMEM;
dev_attr = devm_kcalloc(&plf->dev,
num_irqs, sizeof(*dev_attr), GFP_KERNEL);
if (!dev_attr)
return -ENOMEM;
event_name = devm_kcalloc(&plf->dev,
num_irqs, sizeof(*event_name), GFP_KERNEL);
if (!event_name)
return -ENOMEM;
res = platform_get_resource_byname(plf, 0, "IRQ_AB8500");
if (!res) {
dev_err(&plf->dev, "AB8500 irq not found, err %d\n", irq_first);
return -ENXIO;
}
irq_ab8500 = res->start;
irq_first = platform_get_irq_byname(plf, "IRQ_FIRST");
if (irq_first < 0)
return irq_first;
irq_last = platform_get_irq_byname(plf, "IRQ_LAST");
if (irq_last < 0)
return irq_last;
ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL);
debugfs_create_file("all-bank-registers", S_IRUGO, ab8500_dir,
&plf->dev, &ab8500_bank_registers_fops);
debugfs_create_file("all-banks", S_IRUGO, ab8500_dir,
&plf->dev, &ab8500_all_banks_fops);
debugfs_create_file("register-bank", (S_IRUGO | S_IWUSR | S_IWGRP),
ab8500_dir, &plf->dev, &ab8500_bank_fops);
debugfs_create_file("register-address", (S_IRUGO | S_IWUSR | S_IWGRP),
ab8500_dir, &plf->dev, &ab8500_address_fops);
debugfs_create_file("register-value", (S_IRUGO | S_IWUSR | S_IWGRP),
ab8500_dir, &plf->dev, &ab8500_val_fops);
debugfs_create_file("irq-subscribe", (S_IRUGO | S_IWUSR | S_IWGRP),
ab8500_dir, &plf->dev, &ab8500_subscribe_fops);
if (is_ab8500(ab8500)) {
debug_ranges = ab8500_debug_ranges;
num_interrupt_lines = AB8500_NR_IRQS;
} else if (is_ab8505(ab8500)) {
debug_ranges = ab8505_debug_ranges;
num_interrupt_lines = AB8505_NR_IRQS;
} else if (is_ab9540(ab8500)) {
debug_ranges = ab8505_debug_ranges;
num_interrupt_lines = AB9540_NR_IRQS;
} else if (is_ab8540(ab8500)) {
debug_ranges = ab8540_debug_ranges;
num_interrupt_lines = AB8540_NR_IRQS;
}
debugfs_create_file("interrupts", (S_IRUGO), ab8500_dir, &plf->dev,
&ab8500_interrupts_fops);
debugfs_create_file("irq-unsubscribe", (S_IRUGO | S_IWUSR | S_IWGRP),
ab8500_dir, &plf->dev, &ab8500_unsubscribe_fops);
debugfs_create_file("hwreg", (S_IRUGO | S_IWUSR | S_IWGRP), ab8500_dir,
&plf->dev, &ab8500_hwreg_fops);
debugfs_create_file("all-modem-registers", (S_IRUGO | S_IWUSR | S_IWGRP),
ab8500_dir, &plf->dev, &ab8500_modem_fops);
return 0;
}
static struct platform_driver ab8500_debug_driver = {
.driver = {
.name = "ab8500-debug",
.suppress_bind_attrs = true,
},
.probe = ab8500_debug_probe,
};
static int __init ab8500_debug_init(void)
{
return platform_driver_register(&ab8500_debug_driver);
}
subsys_initcall(ab8500_debug_init);
......@@ -105,7 +105,7 @@ static const struct i2c_device_id arizona_i2c_id[] = {
MODULE_DEVICE_TABLE(i2c, arizona_i2c_id);
#ifdef CONFIG_OF
const struct of_device_id arizona_i2c_of_match[] = {
static const struct of_device_id arizona_i2c_of_match[] = {
{ .compatible = "wlf,wm5102", .data = (void *)WM5102 },
{ .compatible = "wlf,wm5110", .data = (void *)WM5110 },
{ .compatible = "wlf,wm8280", .data = (void *)WM8280 },
......
......@@ -43,31 +43,13 @@ static const struct gpiod_lookup arizona_soc_gpios[] = {
{ "arizona", 4, "wlf,micd-pol", 0, GPIO_ACTIVE_LOW },
};
/*
* The AOSP 3.5 mm Headset: Accessory Specification gives the following values:
* Function A Play/Pause: 0 ohm
* Function D Voice assistant: 135 ohm
* Function B Volume Up 240 ohm
* Function C Volume Down 470 ohm
* Minimum Mic DC resistance 1000 ohm
* Minimum Ear speaker impedance 16 ohm
* Note the first max value below must be less then the min. speaker impedance,
* to allow CTIA/OMTP detection to work. The other max values are the closest
* value from extcon-arizona.c:arizona_micd_levels halfway 2 button resistances.
*/
static const struct arizona_micd_range arizona_micd_aosp_ranges[] = {
{ .max = 11, .key = KEY_PLAYPAUSE },
{ .max = 186, .key = KEY_VOICECOMMAND },
{ .max = 348, .key = KEY_VOLUMEUP },
{ .max = 752, .key = KEY_VOLUMEDOWN },
};
static void arizona_spi_acpi_remove_lookup(void *lookup)
{
gpiod_remove_lookup_table(lookup);
}
static int arizona_spi_acpi_probe(struct arizona *arizona)
/* For ACPI tables from boards which ship with Windows as factory OS */
static int arizona_spi_acpi_windows_probe(struct arizona *arizona)
{
struct gpiod_lookup_table *lookup;
acpi_status status;
......@@ -96,6 +78,65 @@ static int arizona_spi_acpi_probe(struct arizona *arizona)
if (ACPI_FAILURE(status))
dev_warn(arizona->dev, "Failed to enable 32KHz clk ACPI error %d\n", status);
return 0;
}
/* For ACPI tables from boards which ship with Android as factory OS */
static int arizona_spi_acpi_android_probe(struct arizona *arizona)
{
int ret;
/*
* Get the reset GPIO, treating -ENOENT as -EPROBE_DEFER to wait for
* the x86-android-tablets module to register the board specific GPIO
* lookup table.
*/
arizona->pdata.reset = devm_gpiod_get(arizona->dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(arizona->pdata.reset)) {
ret = PTR_ERR(arizona->pdata.reset);
if (ret == -ENOENT) {
dev_info_once(arizona->dev,
"Deferring probe till GPIO lookup is registered\n");
ret = -EPROBE_DEFER;
}
return dev_err_probe(arizona->dev, ret, "getting reset GPIO\n");
}
return 0;
}
/*
* The AOSP 3.5 mm Headset: Accessory Specification gives the following values:
* Function A Play/Pause: 0 ohm
* Function D Voice assistant: 135 ohm
* Function B Volume Up 240 ohm
* Function C Volume Down 470 ohm
* Minimum Mic DC resistance 1000 ohm
* Minimum Ear speaker impedance 16 ohm
* Note the first max value below must be less then the min. speaker impedance,
* to allow CTIA/OMTP detection to work. The other max values are the closest
* value from extcon-arizona.c:arizona_micd_levels halfway 2 button resistances.
*/
static const struct arizona_micd_range arizona_micd_aosp_ranges[] = {
{ .max = 11, .key = KEY_PLAYPAUSE },
{ .max = 186, .key = KEY_VOICECOMMAND },
{ .max = 348, .key = KEY_VOLUMEUP },
{ .max = 752, .key = KEY_VOLUMEDOWN },
};
static int arizona_spi_acpi_probe(struct arizona *arizona)
{
struct acpi_device *adev = ACPI_COMPANION(arizona->dev);
int ret;
if (acpi_dev_hid_uid_match(adev, "10WM5102", NULL))
ret = arizona_spi_acpi_android_probe(arizona);
else
ret = arizona_spi_acpi_windows_probe(arizona);
if (ret)
return ret;
/*
* Some DSDTs wrongly declare the IRQ trigger-type as IRQF_TRIGGER_FALLING
* The IRQ line will stay low when a new IRQ event happens between reading
......@@ -130,6 +171,10 @@ static const struct acpi_device_id arizona_acpi_match[] = {
.id = "WM510205",
.driver_data = WM5102,
},
{
.id = "10WM5102",
.driver_data = WM5102,
},
{ }
};
MODULE_DEVICE_TABLE(acpi, arizona_acpi_match);
......@@ -224,7 +269,7 @@ static const struct spi_device_id arizona_spi_ids[] = {
MODULE_DEVICE_TABLE(spi, arizona_spi_ids);
#ifdef CONFIG_OF
const struct of_device_id arizona_spi_of_match[] = {
static const struct of_device_id arizona_spi_of_match[] = {
{ .compatible = "wlf,wm5102", .data = (void *)WM5102 },
{ .compatible = "wlf,wm5110", .data = (void *)WM5110 },
{ .compatible = "wlf,wm8280", .data = (void *)WM8280 },
......
......@@ -906,14 +906,14 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
ret = mfd_add_devices(&pdev->dev, pdev->id,
&asic3_cell_ds1wm, 1, mem, asic->irq_base, NULL);
if (ret < 0)
goto out;
goto out_unmap;
}
if (mem_sdio && (irq >= 0)) {
ret = mfd_add_devices(&pdev->dev, pdev->id,
&asic3_cell_mmc, 1, mem_sdio, irq, NULL);
if (ret < 0)
goto out;
goto out_unmap;
}
ret = 0;
......@@ -927,8 +927,12 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
ret = mfd_add_devices(&pdev->dev, 0,
asic3_cell_leds, ASIC3_NUM_LEDS, NULL, 0, NULL);
}
return ret;
out:
out_unmap:
if (asic->tmio_cnf)
iounmap(asic->tmio_cnf);
out:
return ret;
}
......
......@@ -105,7 +105,7 @@ static int __maybe_unused atmel_flexcom_resume_noirq(struct device *dev)
return 0;
}
static const struct dev_pm_ops atmel_flexcom_pm_ops = {
static const struct dev_pm_ops __maybe_unused atmel_flexcom_pm_ops = {
.resume_noirq = atmel_flexcom_resume_noirq,
};
......
......@@ -15,7 +15,6 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/mfd/syscon.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
......
......@@ -15,11 +15,22 @@
#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/pxa2xx_ssp.h>
#include "intel-lpss.h"
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[] = {
......@@ -53,8 +64,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 property_entry bxt_i2c_properties[] = {
......@@ -89,6 +110,20 @@ static const struct intel_lpss_platform_info apl_i2c_info = {
.swnode = &apl_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,
......@@ -108,8 +143,8 @@ static const struct acpi_device_id intel_lpss_acpi_ids[] = {
{ "INT3449", (kernel_ulong_t)&spt_uart_info },
{ "INT344A", (kernel_ulong_t)&spt_uart_info },
/* CNL */
{ "INT34B0", (kernel_ulong_t)&spt_info },
{ "INT34B1", (kernel_ulong_t)&spt_info },
{ "INT34B0", (kernel_ulong_t)&cnl_info },
{ "INT34B1", (kernel_ulong_t)&cnl_info },
{ "INT34B2", (kernel_ulong_t)&cnl_i2c_info },
{ "INT34B3", (kernel_ulong_t)&cnl_i2c_info },
{ "INT34B4", (kernel_ulong_t)&cnl_i2c_info },
......@@ -119,7 +154,7 @@ static const struct acpi_device_id intel_lpss_acpi_ids[] = {
{ "INT34B8", (kernel_ulong_t)&spt_uart_info },
{ "INT34B9", (kernel_ulong_t)&spt_uart_info },
{ "INT34BA", (kernel_ulong_t)&spt_uart_info },
{ "INT34BC", (kernel_ulong_t)&spt_info },
{ "INT34BC", (kernel_ulong_t)&cnl_info },
/* BXT */
{ "80860AAC", (kernel_ulong_t)&bxt_i2c_info },
{ "80860ABC", (kernel_ulong_t)&bxt_info },
......
......@@ -353,6 +353,21 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x5ac4), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x5ac6), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x5aee), (kernel_ulong_t)&bxt_uart_info },
/* 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, 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, 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 },
......
......@@ -64,6 +64,10 @@ static int intel_soc_pmic_i2c_probe(struct i2c_client *i2c,
/* 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));
......
......@@ -28,18 +28,10 @@
#define CRYSTAL_COVE_IRQ_GPIO 5
#define CRYSTAL_COVE_IRQ_VHDMIOCP 6
static const struct resource gpio_resources[] = {
DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_GPIO, "GPIO"),
};
static const struct resource pwrsrc_resources[] = {
DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_PWRSRC, "PWRSRC"),
};
static const struct resource adc_resources[] = {
DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_ADC, "ADC"),
};
static const struct resource thermal_resources[] = {
DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_THRM, "THERMAL"),
};
......@@ -48,17 +40,24 @@ static const struct resource bcu_resources[] = {
DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_BCU, "BCU"),
};
static const struct resource adc_resources[] = {
DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_ADC, "ADC"),
};
static const struct resource charger_resources[] = {
DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_CHGR, "CHGR"),
};
static const struct resource gpio_resources[] = {
DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_GPIO, "GPIO"),
};
static struct mfd_cell crystal_cove_byt_dev[] = {
{
.name = "crystal_cove_pwrsrc",
.num_resources = ARRAY_SIZE(pwrsrc_resources),
.resources = pwrsrc_resources,
},
{
.name = "crystal_cove_adc",
.num_resources = ARRAY_SIZE(adc_resources),
.resources = adc_resources,
},
{
.name = "crystal_cove_thermal",
.num_resources = ARRAY_SIZE(thermal_resources),
......@@ -69,6 +68,16 @@ static struct mfd_cell crystal_cove_byt_dev[] = {
.num_resources = ARRAY_SIZE(bcu_resources),
.resources = bcu_resources,
},
{
.name = "crystal_cove_adc",
.num_resources = ARRAY_SIZE(adc_resources),
.resources = adc_resources,
},
{
.name = "crystal_cove_charger",
.num_resources = ARRAY_SIZE(charger_resources),
.resources = charger_resources,
},
{
.name = "crystal_cove_gpio",
.num_resources = ARRAY_SIZE(gpio_resources),
......
......@@ -898,7 +898,6 @@ static int iqs62x_probe(struct i2c_client *client)
struct iqs62x_info info;
unsigned int val;
int ret, i, j;
u8 sw_num = 0;
const char *fw_name = NULL;
iqs62x = devm_kzalloc(&client->dev, sizeof(*iqs62x), GFP_KERNEL);
......@@ -949,7 +948,8 @@ static int iqs62x_probe(struct i2c_client *client)
if (info.sw_num < iqs62x->dev_desc->sw_num)
continue;
sw_num = info.sw_num;
iqs62x->sw_num = info.sw_num;
iqs62x->hw_num = info.hw_num;
/*
* Read each of the device's designated calibration registers,
......@@ -985,7 +985,7 @@ static int iqs62x_probe(struct i2c_client *client)
return -EINVAL;
}
if (!sw_num) {
if (!iqs62x->sw_num) {
dev_err(&client->dev, "Unrecognized software number: 0x%02X\n",
info.sw_num);
return -EINVAL;
......
......@@ -87,7 +87,7 @@ static bool max77802_rtc_is_volatile_reg(struct device *dev, unsigned int reg)
reg == MAX77802_RTC_WEEKDAY ||
reg == MAX77802_RTC_MONTH ||
reg == MAX77802_RTC_YEAR ||
reg == MAX77802_RTC_DATE);
reg == MAX77802_RTC_MONTHDAY);
}
static bool max77802_is_volatile_reg(struct device *dev, unsigned int reg)
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* Maxim MAX77714 Core Driver
*
* Copyright (C) 2022 Luca Ceresoli
* Author: Luca Ceresoli <luca@lucaceresoli.net>
*/
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/mfd/core.h>
#include <linux/mfd/max77714.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regmap.h>
static const struct mfd_cell max77714_cells[] = {
{ .name = "max77714-watchdog" },
{ .name = "max77714-rtc" },
};
static const struct regmap_range max77714_readable_ranges[] = {
regmap_reg_range(MAX77714_INT_TOP, MAX77714_INT_TOP),
regmap_reg_range(MAX77714_INT_TOPM, MAX77714_INT_TOPM),
regmap_reg_range(MAX77714_32K_STATUS, MAX77714_32K_CONFIG),
regmap_reg_range(MAX77714_CNFG_GLBL2, MAX77714_CNFG2_ONOFF),
};
static const struct regmap_range max77714_writable_ranges[] = {
regmap_reg_range(MAX77714_INT_TOPM, MAX77714_INT_TOPM),
regmap_reg_range(MAX77714_32K_CONFIG, MAX77714_32K_CONFIG),
regmap_reg_range(MAX77714_CNFG_GLBL2, MAX77714_CNFG2_ONOFF),
};
static const struct regmap_access_table max77714_readable_table = {
.yes_ranges = max77714_readable_ranges,
.n_yes_ranges = ARRAY_SIZE(max77714_readable_ranges),
};
static const struct regmap_access_table max77714_writable_table = {
.yes_ranges = max77714_writable_ranges,
.n_yes_ranges = ARRAY_SIZE(max77714_writable_ranges),
};
static const struct regmap_config max77714_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = MAX77714_CNFG2_ONOFF,
.rd_table = &max77714_readable_table,
.wr_table = &max77714_writable_table,
};
static const struct regmap_irq max77714_top_irqs[] = {
REGMAP_IRQ_REG(MAX77714_IRQ_TOP_ONOFF, 0, MAX77714_INT_TOP_ONOFF),
REGMAP_IRQ_REG(MAX77714_IRQ_TOP_RTC, 0, MAX77714_INT_TOP_RTC),
REGMAP_IRQ_REG(MAX77714_IRQ_TOP_GPIO, 0, MAX77714_INT_TOP_GPIO),
REGMAP_IRQ_REG(MAX77714_IRQ_TOP_LDO, 0, MAX77714_INT_TOP_LDO),
REGMAP_IRQ_REG(MAX77714_IRQ_TOP_SD, 0, MAX77714_INT_TOP_SD),
REGMAP_IRQ_REG(MAX77714_IRQ_TOP_GLBL, 0, MAX77714_INT_TOP_GLBL),
};
static const struct regmap_irq_chip max77714_irq_chip = {
.name = "max77714-pmic",
.status_base = MAX77714_INT_TOP,
.mask_base = MAX77714_INT_TOPM,
.num_regs = 1,
.irqs = max77714_top_irqs,
.num_irqs = ARRAY_SIZE(max77714_top_irqs),
};
/*
* MAX77714 initially uses the internal, low precision oscillator. Enable
* the external oscillator by setting the XOSC_RETRY bit. If the external
* oscillator is not OK (probably not installed) this has no effect.
*/
static int max77714_setup_xosc(struct device *dev, struct regmap *regmap)
{
/* Internal Crystal Load Capacitance, indexed by value of 32KLOAD bits */
static const unsigned int load_cap[4] = {0, 10, 12, 22}; /* pF */
unsigned int load_cap_idx;
unsigned int status;
int err;
err = regmap_update_bits(regmap, MAX77714_32K_CONFIG,
MAX77714_32K_CONFIG_XOSC_RETRY,
MAX77714_32K_CONFIG_XOSC_RETRY);
if (err)
return dev_err_probe(dev, err, "Failed to configure the external oscillator\n");
err = regmap_read(regmap, MAX77714_32K_STATUS, &status);
if (err)
return dev_err_probe(dev, err, "Failed to read external oscillator status\n");
load_cap_idx = (status >> MAX77714_32K_STATUS_32KLOAD_SHF)
& MAX77714_32K_STATUS_32KLOAD_MSK;
dev_info(dev, "Using %s oscillator, %d pF load cap\n",
status & MAX77714_32K_STATUS_32KSOURCE ? "internal" : "external",
load_cap[load_cap_idx]);
return 0;
}
static int max77714_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct regmap *regmap;
struct regmap_irq_chip_data *irq_data;
int err;
regmap = devm_regmap_init_i2c(client, &max77714_regmap_config);
if (IS_ERR(regmap))
return dev_err_probe(dev, PTR_ERR(regmap),
"Failed to initialise regmap\n");
err = max77714_setup_xosc(dev, regmap);
if (err)
return err;
err = devm_regmap_add_irq_chip(dev, regmap, client->irq,
IRQF_ONESHOT | IRQF_SHARED, 0,
&max77714_irq_chip, &irq_data);
if (err)
return dev_err_probe(dev, err, "Failed to add PMIC IRQ chip\n");
err = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
max77714_cells, ARRAY_SIZE(max77714_cells),
NULL, 0, NULL);
if (err)
return dev_err_probe(dev, err, "Failed to register child devices\n");
return 0;
}
static const struct of_device_id max77714_dt_match[] = {
{ .compatible = "maxim,max77714" },
{},
};
MODULE_DEVICE_TABLE(of, max77714_dt_match);
static struct i2c_driver max77714_driver = {
.driver = {
.name = "max77714",
.of_match_table = max77714_dt_match,
},
.probe_new = max77714_probe,
};
module_i2c_driver(max77714_driver);
MODULE_DESCRIPTION("Maxim MAX77714 MFD core driver");
MODULE_AUTHOR("Luca Ceresoli <luca@lucaceresoli.net>");
MODULE_LICENSE("GPL");
......@@ -323,8 +323,10 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
adc1 |= MC13783_ADC1_ATOX;
dev_dbg(mc13xxx->dev, "%s: request irq\n", __func__);
mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_ADCDONE,
ret = mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_ADCDONE,
mc13xxx_handler_adcdone, __func__, &adcdone_data);
if (ret)
goto out;
mc13xxx_reg_write(mc13xxx, MC13XXX_ADC0, adc0);
mc13xxx_reg_write(mc13xxx, MC13XXX_ADC1, adc1);
......
......@@ -212,6 +212,7 @@ int mt6358_irq_init(struct mt6397_chip *chip)
switch (chip->chip_id) {
case MT6358_CHIP_ID:
case MT6366_CHIP_ID:
chip->irq_data = &mt6358_irqd;
break;
......
......@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/reboot.h>
struct rk808_reg_data {
int addr;
......@@ -543,6 +544,7 @@ static void rk808_pm_power_off(void)
reg = RK808_DEVCTRL_REG,
bit = DEV_OFF_RST;
break;
case RK809_ID:
case RK817_ID:
reg = RK817_SYS_CFG(3);
bit = DEV_OFF;
......@@ -559,6 +561,34 @@ static void rk808_pm_power_off(void)
dev_err(&rk808_i2c_client->dev, "Failed to shutdown device!\n");
}
static int rk808_restart_notify(struct notifier_block *this, unsigned long mode, void *cmd)
{
struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
unsigned int reg, bit;
int ret;
switch (rk808->variant) {
case RK809_ID:
case RK817_ID:
reg = RK817_SYS_CFG(3);
bit = DEV_RST;
break;
default:
return NOTIFY_DONE;
}
ret = regmap_update_bits(rk808->regmap, reg, bit, bit);
if (ret)
dev_err(&rk808_i2c_client->dev, "Failed to restart device!\n");
return NOTIFY_DONE;
}
static struct notifier_block rk808_restart_handler = {
.notifier_call = rk808_restart_notify,
.priority = 192,
};
static void rk8xx_shutdown(struct i2c_client *client)
{
struct rk808 *rk808 = i2c_get_clientdata(client);
......@@ -727,6 +757,18 @@ static int rk808_probe(struct i2c_client *client,
if (of_property_read_bool(np, "rockchip,system-power-controller")) {
rk808_i2c_client = client;
pm_power_off = rk808_pm_power_off;
switch (rk808->variant) {
case RK809_ID:
case RK817_ID:
ret = register_restart_handler(&rk808_restart_handler);
if (ret)
dev_warn(&client->dev, "failed to register rst handler, %d\n", ret);
break;
default:
dev_dbg(&client->dev, "pmic controlled board reset not supported\n");
break;
}
}
return 0;
......@@ -749,6 +791,8 @@ static int rk808_remove(struct i2c_client *client)
if (pm_power_off == rk808_pm_power_off)
pm_power_off = NULL;
unregister_restart_handler(&rk808_restart_handler);
return 0;
}
......
......@@ -23,7 +23,7 @@ enum {
};
/*
* Due to the BD9576MUF nasty IRQ behaiour we don't always populate IRQs.
* Due to the BD9576MUF nasty IRQ behaviour we don't always populate IRQs.
* These will be added to regulator resources only if IRQ information for the
* PMIC is populated in device-tree.
*/
......
......@@ -62,8 +62,19 @@ static int simple_mfd_i2c_probe(struct i2c_client *i2c)
return ret;
}
static const struct mfd_cell sy7636a_cells[] = {
{ .name = "sy7636a-regulator", },
{ .name = "sy7636a-temperature", },
};
static const struct simple_mfd_data silergy_sy7636a = {
.mfd_cell = sy7636a_cells,
.mfd_cell_size = ARRAY_SIZE(sy7636a_cells),
};
static const struct of_device_id simple_mfd_i2c_of_match[] = {
{ .compatible = "kontron,sl28cpld" },
{ .compatible = "silergy,sy7636a", .data = &silergy_sy7636a},
{}
};
MODULE_DEVICE_TABLE(of, simple_mfd_i2c_of_match);
......
......@@ -590,7 +590,7 @@ static int sta2x11_mfd_probe(struct pci_dev *pdev,
/* Record this pdev before mfd_add_devices: their probe looks for it */
if (!sta2x11_mfd_find(pdev))
sta2x11_mfd_add(pdev, GFP_ATOMIC);
sta2x11_mfd_add(pdev, GFP_KERNEL);
/* Just 2 bars for all mfd's at present */
for (i = 0; i < 2; i++) {
......
......@@ -392,17 +392,22 @@ static int stmfx_chip_init(struct i2c_client *client)
return ret;
}
static int stmfx_chip_exit(struct i2c_client *client)
static void stmfx_chip_exit(struct i2c_client *client)
{
struct stmfx *stmfx = i2c_get_clientdata(client);
regmap_write(stmfx->map, STMFX_REG_IRQ_SRC_EN, 0);
regmap_write(stmfx->map, STMFX_REG_SYS_CTRL, 0);
if (stmfx->vdd)
return regulator_disable(stmfx->vdd);
if (stmfx->vdd) {
int ret;
return 0;
ret = regulator_disable(stmfx->vdd);
if (ret)
dev_err(&client->dev,
"Failed to disable vdd regulator: %pe\n",
ERR_PTR(ret));
}
}
static int stmfx_probe(struct i2c_client *client,
......@@ -466,7 +471,9 @@ static int stmfx_remove(struct i2c_client *client)
{
stmfx_irq_exit(client);
return stmfx_chip_exit(client);
stmfx_chip_exit(client);
return 0;
}
#ifdef CONFIG_PM_SLEEP
......
......@@ -1219,7 +1219,6 @@ config REGULATOR_STW481X_VMMC
config REGULATOR_SY7636A
tristate "Silergy SY7636A voltage regulator"
depends on MFD_SY7636A
help
This driver supports Silergy SY3686A voltage regulator.
......
......@@ -7,11 +7,14 @@
// Authors: Lars Ivar Miljeteig <lars.ivar.miljeteig@remarkable.com>
// Alistair Francis <alistair@alistair23.me>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/mfd/sy7636a.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regmap.h>
#include <linux/gpio/consumer.h>
#include <linux/mfd/sy7636a.h>
struct sy7636a_data {
struct regmap *regmap;
......
......@@ -375,7 +375,7 @@ config RTC_DRV_MAX8997
config RTC_DRV_MAX77686
tristate "Maxim MAX77686"
depends on MFD_MAX77686 || MFD_MAX77620 || COMPILE_TEST
depends on MFD_MAX77686 || MFD_MAX77620 || MFD_MAX77714 || COMPILE_TEST
help
If you say yes here you will get support for the
RTC of Maxim MAX77686/MAX77620/MAX77802 PMIC.
......
......@@ -19,6 +19,7 @@
#define MAX77686_I2C_ADDR_RTC (0x0C >> 1)
#define MAX77620_I2C_ADDR_RTC 0x68
#define MAX77714_I2C_ADDR_RTC 0x48
#define MAX77686_INVALID_I2C_ADDR (-1)
/* Define non existing register */
......@@ -34,9 +35,6 @@
#define RTC_UDR_MASK BIT(RTC_UDR_SHIFT)
#define RTC_RBUDR_SHIFT 4
#define RTC_RBUDR_MASK BIT(RTC_RBUDR_SHIFT)
/* RTC Hour register */
#define HOUR_PM_SHIFT 6
#define HOUR_PM_MASK BIT(HOUR_PM_SHIFT)
/* RTC Alarm Enable */
#define ALARM_ENABLE_SHIFT 7
#define ALARM_ENABLE_MASK BIT(ALARM_ENABLE_SHIFT)
......@@ -57,28 +55,31 @@ enum {
RTC_WEEKDAY,
RTC_MONTH,
RTC_YEAR,
RTC_DATE,
RTC_MONTHDAY,
RTC_NR_TIME
};
/**
* struct max77686_rtc_driver_data - model-specific configuration
* @delay: Minimum usecs needed for a RTC update
* @mask: Mask used to read RTC registers value
* @map: Registers offset to I2C addresses map
* @alarm_enable_reg: Has a separate alarm enable register?
* @rtc_i2c_addr: I2C address for RTC block
* @rtc_irq_from_platform: RTC interrupt via platform resource
* @alarm_pending_status_reg: Pending alarm status register
* @rtc_irq_chip: RTC IRQ CHIP for regmap
* @regmap_config: regmap configuration for the chip
*/
struct max77686_rtc_driver_data {
/* Minimum usecs needed for a RTC update */
unsigned long delay;
/* Mask used to read RTC registers value */
u8 mask;
/* Registers offset to I2C addresses map */
const unsigned int *map;
/* Has a separate alarm enable register? */
bool alarm_enable_reg;
/* I2C address for RTC block */
int rtc_i2c_addr;
/* RTC interrupt via platform resource */
bool rtc_irq_from_platform;
/* Pending alarm status register */
int alarm_pending_status_reg;
/* RTC IRQ CHIP for regmap */
const struct regmap_irq_chip *rtc_irq_chip;
/* regmap configuration for the chip */
const struct regmap_config *regmap_config;
};
......@@ -96,7 +97,6 @@ struct max77686_rtc_info {
int rtc_irq;
int virq;
int rtc_24hr_mode;
};
enum MAX77686_RTC_OP {
......@@ -116,7 +116,7 @@ enum max77686_rtc_reg_offset {
REG_RTC_WEEKDAY,
REG_RTC_MONTH,
REG_RTC_YEAR,
REG_RTC_DATE,
REG_RTC_MONTHDAY,
REG_ALARM1_SEC,
REG_ALARM1_MIN,
REG_ALARM1_HOUR,
......@@ -147,7 +147,7 @@ static const unsigned int max77686_map[REG_RTC_END] = {
[REG_RTC_WEEKDAY] = MAX77686_RTC_WEEKDAY,
[REG_RTC_MONTH] = MAX77686_RTC_MONTH,
[REG_RTC_YEAR] = MAX77686_RTC_YEAR,
[REG_RTC_DATE] = MAX77686_RTC_DATE,
[REG_RTC_MONTHDAY] = MAX77686_RTC_MONTHDAY,
[REG_ALARM1_SEC] = MAX77686_ALARM1_SEC,
[REG_ALARM1_MIN] = MAX77686_ALARM1_MIN,
[REG_ALARM1_HOUR] = MAX77686_ALARM1_HOUR,
......@@ -201,6 +201,28 @@ static const struct max77686_rtc_driver_data max77686_drv_data = {
.regmap_config = &max77686_rtc_regmap_config,
};
static const struct regmap_irq_chip max77714_rtc_irq_chip = {
.name = "max77714-rtc",
.status_base = MAX77686_RTC_INT,
.mask_base = MAX77686_RTC_INTM,
.num_regs = 1,
.irqs = max77686_rtc_irqs,
.num_irqs = ARRAY_SIZE(max77686_rtc_irqs) - 1, /* no WTSR on 77714 */
};
static const struct max77686_rtc_driver_data max77714_drv_data = {
.delay = 16000,
.mask = 0x7f,
.map = max77686_map,
.alarm_enable_reg = false,
.rtc_irq_from_platform = false,
/* On MAX77714 RTCA1 is BIT 1 of RTCINT (0x00). Not supported by this driver. */
.alarm_pending_status_reg = MAX77686_INVALID_REG,
.rtc_i2c_addr = MAX77714_I2C_ADDR_RTC,
.rtc_irq_chip = &max77714_rtc_irq_chip,
.regmap_config = &max77686_rtc_regmap_config,
};
static const struct regmap_config max77620_rtc_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
......@@ -230,7 +252,7 @@ static const unsigned int max77802_map[REG_RTC_END] = {
[REG_RTC_WEEKDAY] = MAX77802_RTC_WEEKDAY,
[REG_RTC_MONTH] = MAX77802_RTC_MONTH,
[REG_RTC_YEAR] = MAX77802_RTC_YEAR,
[REG_RTC_DATE] = MAX77802_RTC_DATE,
[REG_RTC_MONTHDAY] = MAX77802_RTC_MONTHDAY,
[REG_ALARM1_SEC] = MAX77802_ALARM1_SEC,
[REG_ALARM1_MIN] = MAX77802_ALARM1_MIN,
[REG_ALARM1_HOUR] = MAX77802_ALARM1_HOUR,
......@@ -275,17 +297,11 @@ static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm,
tm->tm_sec = data[RTC_SEC] & mask;
tm->tm_min = data[RTC_MIN] & mask;
if (info->rtc_24hr_mode) {
tm->tm_hour = data[RTC_HOUR] & 0x1f;
} else {
tm->tm_hour = data[RTC_HOUR] & 0x0f;
if (data[RTC_HOUR] & HOUR_PM_MASK)
tm->tm_hour += 12;
}
tm->tm_hour = data[RTC_HOUR] & 0x1f;
/* Only a single bit is set in data[], so fls() would be equivalent */
tm->tm_wday = ffs(data[RTC_WEEKDAY] & mask) - 1;
tm->tm_mday = data[RTC_DATE] & 0x1f;
tm->tm_mday = data[RTC_MONTHDAY] & 0x1f;
tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1;
tm->tm_year = data[RTC_YEAR] & mask;
tm->tm_yday = 0;
......@@ -306,7 +322,7 @@ static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data,
data[RTC_MIN] = tm->tm_min;
data[RTC_HOUR] = tm->tm_hour;
data[RTC_WEEKDAY] = 1 << tm->tm_wday;
data[RTC_DATE] = tm->tm_mday;
data[RTC_MONTHDAY] = tm->tm_mday;
data[RTC_MONTH] = tm->tm_mon + 1;
if (info->drv_data->alarm_enable_reg) {
......@@ -562,8 +578,8 @@ static int max77686_rtc_start_alarm(struct max77686_rtc_info *info)
data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT);
if (data[RTC_YEAR] & info->drv_data->mask)
data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT);
if (data[RTC_DATE] & 0x1f)
data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT);
if (data[RTC_MONTHDAY] & 0x1f)
data[RTC_MONTHDAY] |= (1 << ALARM_ENABLE_SHIFT);
ret = regmap_bulk_write(info->rtc_regmap, map[REG_ALARM1_SEC],
data, ARRAY_SIZE(data));
......@@ -659,8 +675,6 @@ static int max77686_rtc_init_reg(struct max77686_rtc_info *info)
data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
info->rtc_24hr_mode = 1;
ret = regmap_bulk_write(info->rtc_regmap,
info->drv_data->map[REG_RTC_CONTROLM],
data, ARRAY_SIZE(data));
......@@ -852,6 +866,7 @@ static const struct platform_device_id rtc_id[] = {
{ "max77686-rtc", .driver_data = (kernel_ulong_t)&max77686_drv_data, },
{ "max77802-rtc", .driver_data = (kernel_ulong_t)&max77802_drv_data, },
{ "max77620-rtc", .driver_data = (kernel_ulong_t)&max77620_drv_data, },
{ "max77714-rtc", .driver_data = (kernel_ulong_t)&max77714_drv_data, },
{},
};
MODULE_DEVICE_TABLE(platform, rtc_id);
......
......@@ -678,7 +678,7 @@ config MAX63XX_WATCHDOG
config MAX77620_WATCHDOG
tristate "Maxim Max77620 Watchdog Timer"
depends on MFD_MAX77620 || COMPILE_TEST
depends on MFD_MAX77620 || MFD_MAX77714 || COMPILE_TEST
select WATCHDOG_CORE
help
This is the driver for the Max77620 watchdog timer.
......
......@@ -3,8 +3,10 @@
* Maxim MAX77620 Watchdog Driver
*
* Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved.
* Copyright (C) 2022 Luca Ceresoli
*
* Author: Laxman Dewangan <ldewangan@nvidia.com>
* Author: Luca Ceresoli <luca@lucaceresoli.net>
*/
#include <linux/err.h>
......@@ -13,6 +15,7 @@
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/mfd/max77620.h>
#include <linux/mfd/max77714.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
......@@ -20,17 +23,57 @@
static bool nowayout = WATCHDOG_NOWAYOUT;
/**
* struct max77620_variant - Data specific to a chip variant
* @wdt_info: watchdog descriptor
* @reg_onoff_cnfg2: ONOFF_CNFG2 register offset
* @reg_cnfg_glbl2: CNFG_GLBL2 register offset
* @reg_cnfg_glbl3: CNFG_GLBL3 register offset
* @wdtc_mask: WDTC bit mask in CNFG_GLBL3 (=bits to update to ping the watchdog)
* @bit_wd_rst_wk: WD_RST_WK bit offset within ONOFF_CNFG2
* @cnfg_glbl2_cfg_bits: configuration bits to enable in CNFG_GLBL2 register
*/
struct max77620_variant {
u8 reg_onoff_cnfg2;
u8 reg_cnfg_glbl2;
u8 reg_cnfg_glbl3;
u8 wdtc_mask;
u8 bit_wd_rst_wk;
u8 cnfg_glbl2_cfg_bits;
};
struct max77620_wdt {
struct device *dev;
struct regmap *rmap;
const struct max77620_variant *drv_data;
struct watchdog_device wdt_dev;
};
static const struct max77620_variant max77620_wdt_data = {
.reg_onoff_cnfg2 = MAX77620_REG_ONOFFCNFG2,
.reg_cnfg_glbl2 = MAX77620_REG_CNFGGLBL2,
.reg_cnfg_glbl3 = MAX77620_REG_CNFGGLBL3,
.wdtc_mask = MAX77620_WDTC_MASK,
.bit_wd_rst_wk = MAX77620_ONOFFCNFG2_WD_RST_WK,
/* Set WDT clear in OFF and sleep mode */
.cnfg_glbl2_cfg_bits = MAX77620_WDTSLPC | MAX77620_WDTOFFC,
};
static const struct max77620_variant max77714_wdt_data = {
.reg_onoff_cnfg2 = MAX77714_CNFG2_ONOFF,
.reg_cnfg_glbl2 = MAX77714_CNFG_GLBL2,
.reg_cnfg_glbl3 = MAX77714_CNFG_GLBL3,
.wdtc_mask = MAX77714_WDTC,
.bit_wd_rst_wk = MAX77714_WD_RST_WK,
/* Set WDT clear in sleep mode (there is no WDTOFFC on MAX77714) */
.cnfg_glbl2_cfg_bits = MAX77714_WDTSLPC,
};
static int max77620_wdt_start(struct watchdog_device *wdt_dev)
{
struct max77620_wdt *wdt = watchdog_get_drvdata(wdt_dev);
return regmap_update_bits(wdt->rmap, MAX77620_REG_CNFGGLBL2,
return regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl2,
MAX77620_WDTEN, MAX77620_WDTEN);
}
......@@ -38,7 +81,7 @@ static int max77620_wdt_stop(struct watchdog_device *wdt_dev)
{
struct max77620_wdt *wdt = watchdog_get_drvdata(wdt_dev);
return regmap_update_bits(wdt->rmap, MAX77620_REG_CNFGGLBL2,
return regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl2,
MAX77620_WDTEN, 0);
}
......@@ -46,8 +89,8 @@ static int max77620_wdt_ping(struct watchdog_device *wdt_dev)
{
struct max77620_wdt *wdt = watchdog_get_drvdata(wdt_dev);
return regmap_update_bits(wdt->rmap, MAX77620_REG_CNFGGLBL3,
MAX77620_WDTC_MASK, 0x1);
return regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl3,
wdt->drv_data->wdtc_mask, 0x1);
}
static int max77620_wdt_set_timeout(struct watchdog_device *wdt_dev,
......@@ -80,12 +123,17 @@ static int max77620_wdt_set_timeout(struct watchdog_device *wdt_dev,
break;
}
ret = regmap_update_bits(wdt->rmap, MAX77620_REG_CNFGGLBL3,
MAX77620_WDTC_MASK, 0x1);
/*
* "If the value of TWD needs to be changed, clear the system
* watchdog timer first [...], then change the value of TWD."
* (MAX77714 datasheet but applies to MAX77620 too)
*/
ret = regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl3,
wdt->drv_data->wdtc_mask, 0x1);
if (ret < 0)
return ret;
ret = regmap_update_bits(wdt->rmap, MAX77620_REG_CNFGGLBL2,
ret = regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl2,
MAX77620_TWD_MASK, regval);
if (ret < 0)
return ret;
......@@ -109,6 +157,7 @@ static const struct watchdog_ops max77620_wdt_ops = {
static int max77620_wdt_probe(struct platform_device *pdev)
{
const struct platform_device_id *id = platform_get_device_id(pdev);
struct device *dev = &pdev->dev;
struct max77620_wdt *wdt;
struct watchdog_device *wdt_dev;
......@@ -120,6 +169,8 @@ static int max77620_wdt_probe(struct platform_device *pdev)
return -ENOMEM;
wdt->dev = dev;
wdt->drv_data = (const struct max77620_variant *) id->driver_data;
wdt->rmap = dev_get_regmap(dev->parent, NULL);
if (!wdt->rmap) {
dev_err(wdt->dev, "Failed to get parent regmap\n");
......@@ -136,25 +187,25 @@ static int max77620_wdt_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, wdt);
/* Enable WD_RST_WK - WDT expire results in a restart */
ret = regmap_update_bits(wdt->rmap, MAX77620_REG_ONOFFCNFG2,
MAX77620_ONOFFCNFG2_WD_RST_WK,
MAX77620_ONOFFCNFG2_WD_RST_WK);
ret = regmap_update_bits(wdt->rmap, wdt->drv_data->reg_onoff_cnfg2,
wdt->drv_data->bit_wd_rst_wk,
wdt->drv_data->bit_wd_rst_wk);
if (ret < 0) {
dev_err(wdt->dev, "Failed to set WD_RST_WK: %d\n", ret);
return ret;
}
/* Set WDT clear in OFF and sleep mode */
ret = regmap_update_bits(wdt->rmap, MAX77620_REG_CNFGGLBL2,
MAX77620_WDTOFFC | MAX77620_WDTSLPC,
MAX77620_WDTOFFC | MAX77620_WDTSLPC);
/* Set the "auto WDT clear" bits available on the chip */
ret = regmap_update_bits(wdt->rmap, wdt->drv_data->reg_cnfg_glbl2,
wdt->drv_data->cnfg_glbl2_cfg_bits,
wdt->drv_data->cnfg_glbl2_cfg_bits);
if (ret < 0) {
dev_err(wdt->dev, "Failed to set WDT OFF mode: %d\n", ret);
return ret;
}
/* Check if WDT running and if yes then set flags properly */
ret = regmap_read(wdt->rmap, MAX77620_REG_CNFGGLBL2, &regval);
ret = regmap_read(wdt->rmap, wdt->drv_data->reg_cnfg_glbl2, &regval);
if (ret < 0) {
dev_err(wdt->dev, "Failed to read WDT CFG register: %d\n", ret);
return ret;
......@@ -186,7 +237,8 @@ static int max77620_wdt_probe(struct platform_device *pdev)
}
static const struct platform_device_id max77620_wdt_devtype[] = {
{ .name = "max77620-watchdog", },
{ "max77620-watchdog", (kernel_ulong_t)&max77620_wdt_data },
{ "max77714-watchdog", (kernel_ulong_t)&max77714_wdt_data },
{ },
};
MODULE_DEVICE_TABLE(platform, max77620_wdt_devtype);
......@@ -208,4 +260,5 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
MODULE_AUTHOR("Luca Ceresoli <luca@lucaceresoli.net>");
MODULE_LICENSE("GPL v2");
......@@ -556,31 +556,11 @@ static inline void prcmu_clear(unsigned int reg, u32 bits)
#define PRCMU_QOS_ARM_OPP 3
#define PRCMU_QOS_DEFAULT_VALUE -1
#ifdef CONFIG_DBX500_PRCMU_QOS_POWER
unsigned long prcmu_qos_get_cpufreq_opp_delay(void);
void prcmu_qos_set_cpufreq_opp_delay(unsigned long);
void prcmu_qos_force_opp(int, s32);
int prcmu_qos_requirement(int pm_qos_class);
int prcmu_qos_add_requirement(int pm_qos_class, char *name, s32 value);
int prcmu_qos_update_requirement(int pm_qos_class, char *name, s32 new_value);
void prcmu_qos_remove_requirement(int pm_qos_class, char *name);
int prcmu_qos_add_notifier(int prcmu_qos_class,
struct notifier_block *notifier);
int prcmu_qos_remove_notifier(int prcmu_qos_class,
struct notifier_block *notifier);
#else
static inline unsigned long prcmu_qos_get_cpufreq_opp_delay(void)
{
return 0;
}
static inline void prcmu_qos_set_cpufreq_opp_delay(unsigned long n) {}
static inline void prcmu_qos_force_opp(int prcmu_qos_class, s32 i) {}
static inline int prcmu_qos_requirement(int prcmu_qos_class)
{
return 0;
......@@ -613,6 +593,4 @@ static inline int prcmu_qos_remove_notifier(int prcmu_qos_class,
return 0;
}
#endif
#endif /* __MACH_PRCMU_H */
......@@ -14,6 +14,11 @@
#define IQS624_PROD_NUM 0x43
#define IQS625_PROD_NUM 0x4E
#define IQS620_HW_NUM_V0 0x82
#define IQS620_HW_NUM_V1 IQS620_HW_NUM_V0
#define IQS620_HW_NUM_V2 IQS620_HW_NUM_V0
#define IQS620_HW_NUM_V3 0x92
#define IQS621_ALS_FLAGS 0x16
#define IQS622_ALS_FLAGS 0x14
......@@ -129,6 +134,8 @@ struct iqs62x_core {
struct completion fw_done;
enum iqs62x_ui_sel ui_sel;
unsigned long event_cache;
u8 sw_num;
u8 hw_num;
};
extern const struct iqs62x_event_desc iqs62x_events[IQS62X_NUM_EVENTS];
......
......@@ -152,7 +152,7 @@ enum max77686_rtc_reg {
MAX77686_RTC_WEEKDAY = 0x0A,
MAX77686_RTC_MONTH = 0x0B,
MAX77686_RTC_YEAR = 0x0C,
MAX77686_RTC_DATE = 0x0D,
MAX77686_RTC_MONTHDAY = 0x0D,
MAX77686_ALARM1_SEC = 0x0E,
MAX77686_ALARM1_MIN = 0x0F,
MAX77686_ALARM1_HOUR = 0x10,
......@@ -352,7 +352,7 @@ enum max77802_rtc_reg {
MAX77802_RTC_WEEKDAY = 0xCA,
MAX77802_RTC_MONTH = 0xCB,
MAX77802_RTC_YEAR = 0xCC,
MAX77802_RTC_DATE = 0xCD,
MAX77802_RTC_MONTHDAY = 0xCD,
MAX77802_RTC_AE1 = 0xCE,
MAX77802_ALARM1_SEC = 0xCF,
MAX77802_ALARM1_MIN = 0xD0,
......
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Maxim MAX77714 Register and data structures definition.
*
* Copyright (C) 2022 Luca Ceresoli
* Author: Luca Ceresoli <luca@lucaceresoli.net>
*/
#ifndef __LINUX_MFD_MAX77714_H_
#define __LINUX_MFD_MAX77714_H_
#include <linux/bits.h>
#define MAX77714_INT_TOP 0x00
#define MAX77714_INT_TOPM 0x07 /* Datasheet says "read only", but it is RW */
#define MAX77714_INT_TOP_ONOFF BIT(1)
#define MAX77714_INT_TOP_RTC BIT(3)
#define MAX77714_INT_TOP_GPIO BIT(4)
#define MAX77714_INT_TOP_LDO BIT(5)
#define MAX77714_INT_TOP_SD BIT(6)
#define MAX77714_INT_TOP_GLBL BIT(7)
#define MAX77714_32K_STATUS 0x30
#define MAX77714_32K_STATUS_SIOSCOK BIT(5)
#define MAX77714_32K_STATUS_XOSCOK BIT(4)
#define MAX77714_32K_STATUS_32KSOURCE BIT(3)
#define MAX77714_32K_STATUS_32KLOAD_MSK 0x3
#define MAX77714_32K_STATUS_32KLOAD_SHF 1
#define MAX77714_32K_STATUS_CRYSTAL_CFG BIT(0)
#define MAX77714_32K_CONFIG 0x31
#define MAX77714_32K_CONFIG_XOSC_RETRY BIT(4)
#define MAX77714_CNFG_GLBL2 0x91
#define MAX77714_WDTEN BIT(2)
#define MAX77714_WDTSLPC BIT(3)
#define MAX77714_TWD_MASK 0x3
#define MAX77714_TWD_2s 0x0
#define MAX77714_TWD_16s 0x1
#define MAX77714_TWD_64s 0x2
#define MAX77714_TWD_128s 0x3
#define MAX77714_CNFG_GLBL3 0x92
#define MAX77714_WDTC BIT(0)
#define MAX77714_CNFG2_ONOFF 0x94
#define MAX77714_WD_RST_WK BIT(5)
/* Interrupts */
enum {
MAX77714_IRQ_TOP_ONOFF,
MAX77714_IRQ_TOP_RTC, /* Real-time clock */
MAX77714_IRQ_TOP_GPIO, /* GPIOs */
MAX77714_IRQ_TOP_LDO, /* Low-dropout regulators */
MAX77714_IRQ_TOP_SD, /* Step-down regulators */
MAX77714_IRQ_TOP_GLBL, /* "Global resources": Low-Battery, overtemp... */
};
#endif /* __LINUX_MFD_MAX77714_H_ */
......@@ -94,6 +94,10 @@
#define MT6358_BUCK_VCORE_CON0 0x1488
#define MT6358_BUCK_VCORE_DBG0 0x149e
#define MT6358_BUCK_VCORE_DBG1 0x14a0
#define MT6358_BUCK_VCORE_SSHUB_CON0 0x14a4
#define MT6358_BUCK_VCORE_SSHUB_CON1 0x14a6
#define MT6358_BUCK_VCORE_SSHUB_ELR0 MT6358_BUCK_VCORE_SSHUB_CON1
#define MT6358_BUCK_VCORE_SSHUB_DBG1 MT6358_BUCK_VCORE_DBG1
#define MT6358_BUCK_VCORE_ELR0 0x14aa
#define MT6358_BUCK_VGPU_CON0 0x1508
#define MT6358_BUCK_VGPU_DBG0 0x151e
......@@ -169,6 +173,9 @@
#define MT6358_LDO_VSRAM_OTHERS_CON0 0x1ba6
#define MT6358_LDO_VSRAM_OTHERS_DBG0 0x1bc0
#define MT6358_LDO_VSRAM_OTHERS_DBG1 0x1bc2
#define MT6358_LDO_VSRAM_OTHERS_SSHUB_CON0 0x1bc4
#define MT6358_LDO_VSRAM_OTHERS_SSHUB_CON1 0x1bc6
#define MT6358_LDO_VSRAM_OTHERS_SSHUB_DBG1 MT6358_LDO_VSRAM_OTHERS_DBG1
#define MT6358_LDO_VSRAM_GPU_CON0 0x1bc8
#define MT6358_LDO_VSRAM_GPU_DBG0 0x1be2
#define MT6358_LDO_VSRAM_GPU_DBG1 0x1be4
......
......@@ -14,6 +14,7 @@ enum chip_id {
MT6323_CHIP_ID = 0x23,
MT6358_CHIP_ID = 0x58,
MT6359_CHIP_ID = 0x59,
MT6366_CHIP_ID = 0x66,
MT6391_CHIP_ID = 0x91,
MT6397_CHIP_ID = 0x97,
};
......
......@@ -373,6 +373,7 @@ enum rk805_reg {
#define SWITCH2_EN BIT(6)
#define SWITCH1_EN BIT(5)
#define DEV_OFF_RST BIT(3)
#define DEV_RST BIT(2)
#define DEV_OFF BIT(0)
#define RTC_STOP BIT(0)
......
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Functions to access SY3686A power management chip.
*
* Copyright (C) 2021 reMarkable AS - http://www.remarkable.com/
*/
#ifndef __MFD_SY7636A_H
#define __MFD_SY7636A_H
#define SY7636A_REG_OPERATION_MODE_CRL 0x00
/* It is set if a gpio is used to control the regulator */
#define SY7636A_OPERATION_MODE_CRL_VCOMCTL BIT(6)
#define SY7636A_OPERATION_MODE_CRL_ONOFF BIT(7)
#define SY7636A_REG_VCOM_ADJUST_CTRL_L 0x01
#define SY7636A_REG_VCOM_ADJUST_CTRL_H 0x02
#define SY7636A_REG_VCOM_ADJUST_CTRL_MASK 0x01ff
#define SY7636A_REG_VLDO_VOLTAGE_ADJULST_CTRL 0x03
#define SY7636A_REG_POWER_ON_DELAY_TIME 0x06
#define SY7636A_REG_FAULT_FLAG 0x07
#define SY7636A_FAULT_FLAG_PG BIT(0)
#define SY7636A_REG_TERMISTOR_READOUT 0x08
#define SY7636A_REG_MAX 0x08
#define VCOM_ADJUST_CTRL_MASK 0x1ff
// Used to shift the high byte
#define VCOM_ADJUST_CTRL_SHIFT 8
// Used to scale from VCOM_ADJUST_CTRL to mv
#define VCOM_ADJUST_CTRL_SCAL 10000
#define FAULT_FLAG_SHIFT 1
#endif /* __LINUX_MFD_SY7636A_H */
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