diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-03-25 13:56:18 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-03-25 13:56:18 -0700 |
commit | 8350e8331b3971533d6e6112ab596eda2c2ffffd (patch) | |
tree | 1add05c103644650616f17f1ae90ae2fc91482ee | |
parent | e35a4a4e13c35f500a8d38e836b5e335c7515494 (diff) | |
parent | d99460ed5cdcc28feba6b992630b04650e410902 (diff) |
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
...
60 files changed, 1947 insertions, 2814 deletions
diff --git a/Documentation/devicetree/bindings/leds/maxim,max77693.yaml b/Documentation/devicetree/bindings/leds/maxim,max77693.yaml new file mode 100644 index 000000000000..86a0005cf156 --- /dev/null +++ b/Documentation/devicetree/bindings/leds/maxim,max77693.yaml @@ -0,0 +1,105 @@ +# 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 diff --git a/Documentation/devicetree/bindings/mfd/ab8500.txt b/Documentation/devicetree/bindings/mfd/ab8500.txt deleted file mode 100644 index 937b3e5505e0..000000000000 --- a/Documentation/devicetree/bindings/mfd/ab8500.txt +++ /dev/null @@ -1,282 +0,0 @@ -* 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 - */ - }; - }; -}; diff --git a/Documentation/devicetree/bindings/mfd/max77693.txt b/Documentation/devicetree/bindings/mfd/max77693.txt deleted file mode 100644 index 1032df14498b..000000000000 --- a/Documentation/devicetree/bindings/mfd/max77693.txt +++ /dev/null @@ -1,194 +0,0 @@ -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>; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/mfd/maxim,max77693.yaml b/Documentation/devicetree/bindings/mfd/maxim,max77693.yaml new file mode 100644 index 000000000000..906101197e11 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/maxim,max77693.yaml @@ -0,0 +1,143 @@ +# 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>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/mfd/maxim,max77714.yaml b/Documentation/devicetree/bindings/mfd/maxim,max77714.yaml new file mode 100644 index 000000000000..74a6867d3c82 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/maxim,max77714.yaml @@ -0,0 +1,68 @@ +# 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>; + }; + }; diff --git a/Documentation/devicetree/bindings/mfd/mt6397.txt b/Documentation/devicetree/bindings/mfd/mt6397.txt index 99a84b69a29f..293db2a71ef2 100644 --- a/Documentation/devicetree/bindings/mfd/mt6397.txt +++ b/Documentation/devicetree/bindings/mfd/mt6397.txt @@ -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 diff --git a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt index 7a27c500ff63..a461ec2f758f 100644 --- a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt +++ b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.txt @@ -35,6 +35,7 @@ Required properties: "qcom,pm8916", "qcom,pm8941", "qcom,pm8950", + "qcom,pm8953", "qcom,pm8994", "qcom,pm8998", "qcom,pma8084", diff --git a/Documentation/devicetree/bindings/mfd/qcom,tcsr.txt b/Documentation/devicetree/bindings/mfd/qcom,tcsr.txt index c5f4f0ddfcc3..add61bcc3c74 100644 --- a/Documentation/devicetree/bindings/mfd/qcom,tcsr.txt +++ b/Documentation/devicetree/bindings/mfd/qcom,tcsr.txt @@ -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 diff --git a/Documentation/devicetree/bindings/mfd/samsung,exynos5433-lpass.txt b/Documentation/devicetree/bindings/mfd/samsung,exynos5433-lpass.txt deleted file mode 100644 index 30ea27c3936d..000000000000 --- a/Documentation/devicetree/bindings/mfd/samsung,exynos5433-lpass.txt +++ /dev/null @@ -1,72 +0,0 @@ -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>; - }; - }; diff --git a/Documentation/devicetree/bindings/mfd/samsung,exynos5433-lpass.yaml b/Documentation/devicetree/bindings/mfd/samsung,exynos5433-lpass.yaml new file mode 100644 index 000000000000..bae55c98961c --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/samsung,exynos5433-lpass.yaml @@ -0,0 +1,117 @@ +# 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>; + }; + }; diff --git a/Documentation/devicetree/bindings/mfd/silergy,sy7636a.yaml b/Documentation/devicetree/bindings/mfd/silergy,sy7636a.yaml new file mode 100644 index 000000000000..6de74c701635 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/silergy,sy7636a.yaml @@ -0,0 +1,82 @@ +# 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; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/mfd/stericsson,ab8500.yaml b/Documentation/devicetree/bindings/mfd/stericsson,ab8500.yaml new file mode 100644 index 000000000000..623a4b5cd27a --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/stericsson,ab8500.yaml @@ -0,0 +1,500 @@ +# 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 diff --git a/Documentation/devicetree/bindings/mfd/stericsson,db8500-prcmu.yaml b/Documentation/devicetree/bindings/mfd/stericsson,db8500-prcmu.yaml index a0d4bad5dc81..1d4d88f7e82d 100644 --- a/Documentation/devicetree/bindings/mfd/stericsson,db8500-prcmu.yaml +++ b/Documentation/devicetree/bindings/mfd/stericsson,db8500-prcmu.yaml @@ -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 diff --git a/Documentation/devicetree/bindings/mfd/syscon.yaml b/Documentation/devicetree/bindings/mfd/syscon.yaml index eeac1cbc5a17..13baa452cc9d 100644 --- a/Documentation/devicetree/bindings/mfd/syscon.yaml +++ b/Documentation/devicetree/bindings/mfd/syscon.yaml @@ -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 diff --git a/Documentation/devicetree/bindings/power/supply/maxim,max77693.yaml b/Documentation/devicetree/bindings/power/supply/maxim,max77693.yaml new file mode 100644 index 000000000000..a21dc1a8890f --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/maxim,max77693.yaml @@ -0,0 +1,70 @@ +# 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 diff --git a/Documentation/devicetree/bindings/regulator/maxim,max77693.yaml b/Documentation/devicetree/bindings/regulator/maxim,max77693.yaml new file mode 100644 index 000000000000..20d8559bdc2b --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/maxim,max77693.yaml @@ -0,0 +1,60 @@ +# 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 diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index 9d2787a12a69..a8838cb0d17e 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -187,6 +187,7 @@ Hardware Monitoring Kernel Drivers smsc47m1 sparx5-temp stpddc60 + sy7636a-hwmon tc654 tc74 thmc50 diff --git a/Documentation/hwmon/sy7636a-hwmon.rst b/Documentation/hwmon/sy7636a-hwmon.rst new file mode 100644 index 000000000000..c85db7b32941 --- /dev/null +++ b/Documentation/hwmon/sy7636a-hwmon.rst @@ -0,0 +1,26 @@ +.. 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) diff --git a/MAINTAINERS b/MAINTAINERS index 8b57f24c659f..2f3056772c3a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -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 diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 9ab4e9b3d27b..db8bc55e5f50 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -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 diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 4ed138d0621f..7fd5e94d88f6 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -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 diff --git a/drivers/hwmon/sy7636a-hwmon.c b/drivers/hwmon/sy7636a-hwmon.c new file mode 100644 index 000000000000..6dd9c2a0f0e0 --- /dev/null +++ b/drivers/hwmon/sy7636a-hwmon.c @@ -0,0 +1,106 @@ +// 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, ®_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"); diff --git a/drivers/iio/temperature/iqs620at-temp.c b/drivers/iio/temperature/iqs620at-temp.c index fe126e1fb783..e2f878d57af7 100644 --- a/drivers/iio/temperature/iqs620at-temp.c +++ b/drivers/iio/temperature/iqs620at-temp.c @@ -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: diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index ba0b3eb131f1..3b59456f5545 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -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 diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index df1ecc4a4c95..858cacf659d6 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -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 diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index cca0aac26148..9d9e9787d5e8 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -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; diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c deleted file mode 100644 index e43dea89b094..000000000000 --- a/drivers/mfd/ab8500-debugfs.c +++ /dev/null @@ -1,2096 +0,0 @@ -// 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, ®value); - 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, ®value); - 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, ®value); - 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); diff --git a/drivers/mfd/arizona-i2c.c b/drivers/mfd/arizona-i2c.c index 3ed810e81f63..6d83e6b9a692 100644 --- a/drivers/mfd/arizona-i2c.c +++ b/drivers/mfd/arizona-i2c.c @@ -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 }, diff --git a/drivers/mfd/arizona-spi.c b/drivers/mfd/arizona-spi.c index 03620c8efe34..941b0267d09d 100644 --- a/drivers/mfd/arizona-spi.c +++ b/drivers/mfd/arizona-spi.c @@ -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 }, diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 8d58c8df46cf..56338f9dbd0b 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -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; } diff --git a/drivers/mfd/atmel-flexcom.c b/drivers/mfd/atmel-flexcom.c index 559eb4d352b6..33caa4fba6af 100644 --- a/drivers/mfd/atmel-flexcom.c +++ b/drivers/mfd/atmel-flexcom.c @@ -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, }; diff --git a/drivers/mfd/exynos-lpass.c b/drivers/mfd/exynos-lpass.c index 99bd0e73c19c..166cd21088cd 100644 --- a/drivers/mfd/exynos-lpass.c +++ b/drivers/mfd/exynos-lpass.c @@ -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> diff --git a/drivers/mfd/intel-lpss-acpi.c b/drivers/mfd/intel-lpss-acpi.c index f2ea6540a01e..a143c8dca2d9 100644 --- a/drivers/mfd/intel-lpss-acpi.c +++ b/drivers/mfd/intel-lpss-acpi.c @@ -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 }, diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index 5513fae6be92..962ee14c62dd 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -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 }, diff --git a/drivers/mfd/intel_soc_pmic_core.c b/drivers/mfd/intel_soc_pmic_core.c index 47cb7f00dfcf..5e8c94e008ed 100644 --- a/drivers/mfd/intel_soc_pmic_core.c +++ b/drivers/mfd/intel_soc_pmic_core.c @@ -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)); diff --git a/drivers/mfd/intel_soc_pmic_crc.c b/drivers/mfd/intel_soc_pmic_crc.c index 38acb20e2d60..5bb0367bd974 100644 --- a/drivers/mfd/intel_soc_pmic_crc.c +++ b/drivers/mfd/intel_soc_pmic_crc.c @@ -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,6 +40,18 @@ 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", @@ -55,11 +59,6 @@ static struct mfd_cell crystal_cove_byt_dev[] = { .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), .resources = thermal_resources, @@ -70,6 +69,16 @@ static struct mfd_cell crystal_cove_byt_dev[] = { .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), .resources = gpio_resources, diff --git a/drivers/mfd/iqs62x.c b/drivers/mfd/iqs62x.c index 9805cf191245..575ab67e243d 100644 --- a/drivers/mfd/iqs62x.c +++ b/drivers/mfd/iqs62x.c @@ -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; diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index f9e12ab2bc75..2ac64277fb84 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c @@ -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) diff --git a/drivers/mfd/max77714.c b/drivers/mfd/max77714.c new file mode 100644 index 000000000000..d1e4247800d2 --- /dev/null +++ b/drivers/mfd/max77714.c @@ -0,0 +1,152 @@ +// 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"); diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index 8a4f1d90dcfd..1000572761a8 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -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); diff --git a/drivers/mfd/mt6358-irq.c b/drivers/mfd/mt6358-irq.c index 83f3ffbdbb4c..ea5e452510eb 100644 --- a/drivers/mfd/mt6358-irq.c +++ b/drivers/mfd/mt6358-irq.c @@ -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; diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c index b181fe401330..4142b638e5fa 100644 --- a/drivers/mfd/rk808.c +++ b/drivers/mfd/rk808.c @@ -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; } diff --git a/drivers/mfd/rohm-bd9576.c b/drivers/mfd/rohm-bd9576.c index 6661a27d69a8..f37cd4f27aeb 100644 --- a/drivers/mfd/rohm-bd9576.c +++ b/drivers/mfd/rohm-bd9576.c @@ -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. */ diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c index 51536691ad9d..f4c8fc3ee463 100644 --- a/drivers/mfd/simple-mfd-i2c.c +++ b/drivers/mfd/simple-mfd-i2c.c @@ -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); diff --git a/drivers/mfd/sta2x11-mfd.c b/drivers/mfd/sta2x11-mfd.c index 1819c8fe4d8f..02cc49daf2e3 100644 --- a/drivers/mfd/sta2x11-mfd.c +++ b/drivers/mfd/sta2x11-mfd.c @@ -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++) { diff --git a/drivers/mfd/stmfx.c b/drivers/mfd/stmfx.c index e095a3930142..122f96094410 100644 --- a/drivers/mfd/stmfx.c +++ b/drivers/mfd/stmfx.c @@ -392,17 +392,22 @@ err: 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 diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index c8ce6e5eea24..5ef2306fce04 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -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. diff --git a/drivers/regulator/sy7636a-regulator.c b/drivers/regulator/sy7636a-regulator.c index 22fddf868e4c..29fc27c2cda0 100644 --- a/drivers/regulator/sy7636a-regulator.c +++ b/drivers/regulator/sy7636a-regulator.c @@ -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; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index d85a3c31347c..f6d6d4c26361 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -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. diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index eae7cb9faf1e..b0250d91fb00 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -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); diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index aa42f0686591..085f5a4ad06c 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -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. diff --git a/drivers/watchdog/max77620_wdt.c b/drivers/watchdog/max77620_wdt.c index be6a53c30002..b76ad6ba0915 100644 --- a/drivers/watchdog/max77620_wdt.c +++ b/drivers/watchdog/max77620_wdt.c @@ -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, ®val); + ret = regmap_read(wdt->rmap, wdt->drv_data->reg_cnfg_glbl2, ®val); 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"); diff --git a/include/linux/mfd/dbx500-prcmu.h b/include/linux/mfd/dbx500-prcmu.h index cbf9d7619493..e7a7e70fdb38 100644 --- a/include/linux/mfd/dbx500-prcmu.h +++ b/include/linux/mfd/dbx500-prcmu.h @@ -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 */ diff --git a/include/linux/mfd/iqs62x.h b/include/linux/mfd/iqs62x.h index 5ced55eae11b..ffc86010af74 100644 --- a/include/linux/mfd/iqs62x.h +++ b/include/linux/mfd/iqs62x.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]; diff --git a/include/linux/mfd/max77686-private.h b/include/linux/mfd/max77686-private.h index b1482b3cf353..3acceeedbaba 100644 --- a/include/linux/mfd/max77686-private.h +++ b/include/linux/mfd/max77686-private.h @@ -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, diff --git a/include/linux/mfd/max77714.h b/include/linux/mfd/max77714.h new file mode 100644 index 000000000000..a970dc455426 --- /dev/null +++ b/include/linux/mfd/max77714.h @@ -0,0 +1,60 @@ +/* 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_ */ diff --git a/include/linux/mfd/mt6358/registers.h b/include/linux/mfd/mt6358/registers.h index 201139b12140..3d33517f178c 100644 --- a/include/linux/mfd/mt6358/registers.h +++ b/include/linux/mfd/mt6358/registers.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 diff --git a/include/linux/mfd/mt6397/core.h b/include/linux/mfd/mt6397/core.h index 56f210eebc54..1cf78726503b 100644 --- a/include/linux/mfd/mt6397/core.h +++ b/include/linux/mfd/mt6397/core.h @@ -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, }; diff --git a/include/linux/mfd/rk808.h b/include/linux/mfd/rk808.h index a96e6d43ca06..58602032e642 100644 --- a/include/linux/mfd/rk808.h +++ b/include/linux/mfd/rk808.h @@ -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) diff --git a/include/linux/mfd/sy7636a.h b/include/linux/mfd/sy7636a.h new file mode 100644 index 000000000000..22f03b2f851e --- /dev/null +++ b/include/linux/mfd/sy7636a.h @@ -0,0 +1,34 @@ +/* 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 */ |