Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

Pull MFD updates from Lee Jones:
"New Drivers:
- ROHM BD96801 Power Management IC
- Cirrus Logic CS40L50 Haptic Driver with Waveform Memory
- Marvell 88PM886 Power Management IC

New Device Support:
- Keyboard Backlight to ChromeOS Embedded Controller
- LEDs to ChromeOS Embedded Controller
- Charge Control to ChromeOS Embedded Controller
- HW Monitoring Service to ChromeOS Embedded Controller
- AUXADCs to MediaTek MT635{7,8,9} Power Management ICs

New Functionality:
- Allow Syscon consumers to supply their own Regmaps on registration

Fix-ups:
- Constify/staticise applicable data structures
- Remove superfluous/duplicated/unused sections
- Device Tree binding adaptions/conversions/creation
- Trivial; spelling, whitespace, coding-style adaptions
- Utilise centrally provided helpers and macros to aid
simplicity/duplication
- Drop i2c_device_id::driver_data where the value is unused
- Replace ACPI/DT firmware helpers with agnostic variants
- Move over to GPIOD (descriptor-based) APIs
- Annotate a bunch of __counted_by() cases
- Straighten out some includes

Bug Fixes:
- Ensure potentially asserted recent lines are deasserted during
initialisation
- Avoid "<module>.ko is added to multiple modules" warnings
- Supply a bunch of MODULE_DESCRIPTIONs to silence modpost warnings
- Fix Wvoid-pointer-to-enum-cast warnings"

* tag 'mfd-next-6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (87 commits)
mfd: timberdale: Attach device properties to TSC2007 board info
mfd: tmio: Move header to platform_data
mfd: tmio: Sanitize comments
mfd: tmio: Update include files
mmc: tmio/sdhi: Fix includes
mfd: tmio: Remove obsolete io accessors
mfd: tmio: Remove obsolete platform_data
watchdog: bd96801_wdt: Add missing include for FIELD_*()
dt-bindings: mfd: syscon: Add APM poweroff mailbox
dt-bindings: mfd: syscon: Split and enforce documenting MFD children
dt-bindings: mfd: rk817: Merge support for RK809
dt-bindings: mfd: rk817: Fixup clocks and reference dai-common
dt-bindings: mfd: syscon: Add TI's opp table compatible
mfd: omap-usb-tll: Use struct_size to allocate tll
dt-bindings: mfd: Explain lack of child dependency in simple-mfd
dt-bindings: mfd: Dual licensing for st,stpmic1 bindings
mfd: omap-usb-tll: Annotate struct usbtll_omap with __counted_by
mfd: tps6594-core: Remove unneeded semicolon in tps6594_check_crc_mode()
mfd: lm3533: Move to new GPIO descriptor-based APIs
mfd: tps65912: Use devm helper functions to simplify probe
...

+6730 -1194
-20
Documentation/devicetree/bindings/arm/amlogic/analog-top.txt
··· 1 - Amlogic Meson8 and Meson8b "analog top" registers: 2 - -------------------------------------------------- 3 - 4 - The analog top registers contain information about the so-called 5 - "metal revision" (which encodes the "minor version") of the SoC. 6 - 7 - Required properties: 8 - - reg: the register range of the analog top registers 9 - - compatible: depending on the SoC this should be one of: 10 - - "amlogic,meson8-analog-top" 11 - - "amlogic,meson8b-analog-top" 12 - along with "syscon" 13 - 14 - 15 - Example: 16 - 17 - analog_top: analog-top@81a8 { 18 - compatible = "amlogic,meson8-analog-top", "syscon"; 19 - reg = <0x81a8 0x14>; 20 - };
-17
Documentation/devicetree/bindings/arm/amlogic/assist.txt
··· 1 - Amlogic Meson6/Meson8/Meson8b assist registers: 2 - ----------------------------------------------- 3 - 4 - The assist registers contain basic information about the SoC, 5 - for example the encoded SoC part number. 6 - 7 - Required properties: 8 - - reg: the register range of the assist registers 9 - - compatible: should be "amlogic,meson-mx-assist" along with "syscon" 10 - 11 - 12 - Example: 13 - 14 - assist: assist@7c00 { 15 - compatible = "amlogic,meson-mx-assist", "syscon"; 16 - reg = <0x7c00 0x200>; 17 - };
-17
Documentation/devicetree/bindings/arm/amlogic/bootrom.txt
··· 1 - Amlogic Meson6/Meson8/Meson8b bootrom: 2 - -------------------------------------- 3 - 4 - The bootrom register area can be used to access SoC specific 5 - information, such as the "misc version". 6 - 7 - Required properties: 8 - - reg: the register range of the bootrom registers 9 - - compatible: should be "amlogic,meson-mx-bootrom" along with "syscon" 10 - 11 - 12 - Example: 13 - 14 - bootrom: bootrom@d9040000 { 15 - compatible = "amlogic,meson-mx-bootrom", "syscon"; 16 - reg = <0xd9040000 0x10000>; 17 - };
-18
Documentation/devicetree/bindings/arm/amlogic/pmu.txt
··· 1 - Amlogic Meson8 and Meson8b power-management-unit: 2 - ------------------------------------------------- 3 - 4 - The pmu is used to turn off and on different power domains of the SoCs 5 - This includes the power to the CPU cores. 6 - 7 - Required node properties: 8 - - compatible value : depending on the SoC this should be one of: 9 - "amlogic,meson8-pmu" 10 - "amlogic,meson8b-pmu" 11 - - reg : physical base address and the size of the registers window 12 - 13 - Example: 14 - 15 - pmu@c81000e4 { 16 - compatible = "amlogic,meson8b-pmu", "syscon"; 17 - reg = <0xc81000e0 0x18>; 18 - };
-29
Documentation/devicetree/bindings/arm/atmel-sysregs.txt
··· 41 41 reg = <0xffffe800 0x200>; 42 42 }; 43 43 44 - RAMC PHY Controller required properties: 45 - - compatible: Should be "microchip,sama7g5-ddr3phy", "syscon" 46 - - reg: Should contain registers location and length 47 - 48 - Example: 49 - 50 - ddr3phy: ddr3phy@e3804000 { 51 - compatible = "microchip,sama7g5-ddr3phy", "syscon"; 52 - reg = <0xe3804000 0x1000>; 53 - }; 54 - 55 - Special Function Registers (SFR) 56 - 57 - Special Function Registers (SFR) manage specific aspects of the integrated 58 - memory, bridge implementations, processor and other functionality not controlled 59 - elsewhere. 60 - 61 - required properties: 62 - - compatible: Should be "atmel,<chip>-sfr", "syscon" or 63 - "atmel,<chip>-sfrbu", "syscon" 64 - <chip> can be "sama5d3", "sama5d4" or "sama5d2". 65 - It also can be "microchip,sam9x60-sfr", "syscon". 66 - - reg: Should contain registers location and length 67 - 68 - sfr@f0038000 { 69 - compatible = "atmel,sama5d3-sfr", "syscon"; 70 - reg = <0xf0038000 0x60>; 71 - }; 72 - 73 44 Security Module (SECUMOD) 74 45 75 46 The Security Module macrocell provides all necessary secure functions to avoid
-16
Documentation/devicetree/bindings/arm/axis.txt
··· 7 7 Required root node properties: 8 8 - compatible = "axis,artpec6"; 9 9 10 - ARTPEC-6 System Controller 11 - -------------------------- 12 - 13 - The ARTPEC-6 has a system controller with mixed functions controlling DMA, PCIe 14 - and resets. 15 - 16 - Required properties: 17 - - compatible: "axis,artpec6-syscon", "syscon" 18 - - reg: Address and length of the register bank. 19 - 20 - Example: 21 - syscon { 22 - compatible = "axis,artpec6-syscon", "syscon"; 23 - reg = <0xf8000000 0x48>; 24 - }; 25 - 26 10 ARTPEC-6 Development board: 27 11 --------------------------- 28 12 Required root node properties:
-10
Documentation/devicetree/bindings/arm/cpu-enable-method/al,alpine-smp
··· 27 27 - reg : Offset and length of the register set for the device 28 28 29 29 30 - * Alpine System-Fabric Service Registers 31 - 32 - The System-Fabric Service Registers allow various operation on CPU and 33 - system fabric, like powering CPUs off. 34 - 35 - Properties: 36 - - compatible : Should contain "al,alpine-sysfabric-service" and "syscon". 37 - - reg : Offset and length of the register set for the device 38 - 39 - 40 30 Example: 41 31 42 32 cpus {
-14
Documentation/devicetree/bindings/arm/freescale/fsl,vf610-mscm-cpucfg.txt
··· 1 - Freescale Vybrid Miscellaneous System Control - CPU Configuration 2 - 3 - The MSCM IP contains multiple sub modules, this binding describes the first 4 - block of registers which contains CPU configuration information. 5 - 6 - Required properties: 7 - - compatible: "fsl,vf610-mscm-cpucfg", "syscon" 8 - - reg: the register range of the MSCM CPU configuration registers 9 - 10 - Example: 11 - mscm_cpucfg: cpucfg@40001000 { 12 - compatible = "fsl,vf610-mscm-cpucfg", "syscon"; 13 - reg = <0x40001000 0x800>; 14 - }
-15
Documentation/devicetree/bindings/arm/marvell/marvell,dove.txt
··· 5 5 6 6 Required root node property: 7 7 - compatible: must contain "marvell,dove"; 8 - 9 - * Global Configuration registers 10 - 11 - Global Configuration registers of Dove SoC are shared by a syscon node. 12 - 13 - Required properties: 14 - - compatible: must contain "marvell,dove-global-config" and "syscon". 15 - - reg: base address and size of the Global Configuration registers. 16 - 17 - Example: 18 - 19 - gconf: global-config@e802c { 20 - compatible = "marvell,dove-global-config", "syscon"; 21 - reg = <0xe802c 0x14>; 22 - };
-9
Documentation/devicetree/bindings/arm/spear-misc.txt
··· 1 - SPEAr Misc configuration 2 - =========================== 3 - SPEAr SOCs have some miscellaneous registers which are used to configure 4 - few properties of different peripheral controllers. 5 - 6 - misc node required properties: 7 - 8 - - compatible Should be "st,spear1340-misc", "syscon". 9 - - reg: Address range of misc space up to 8K
-20
Documentation/devicetree/bindings/clock/ti-keystone-pllctrl.txt
··· 1 - * Device tree bindings for Texas Instruments keystone pll controller 2 - 3 - The main pll controller used to drive theC66x CorePacs, the switch fabric, 4 - and a majority of the peripheral clocks (all but the ARM CorePacs, DDR3 and 5 - the NETCP modules) requires a PLL Controller to manage the various clock 6 - divisions, gating, and synchronization. 7 - 8 - Required properties: 9 - 10 - - compatible: "ti,keystone-pllctrl", "syscon" 11 - 12 - - reg: contains offset/length value for pll controller 13 - registers space. 14 - 15 - Example: 16 - 17 - pllctrl: pll-controller@02310000 { 18 - compatible = "ti,keystone-pllctrl", "syscon"; 19 - reg = <0x02310000 0x200>; 20 - };
+68
Documentation/devicetree/bindings/input/cirrus,cs40l50.yaml
··· 1 + # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/input/cirrus,cs40l50.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Cirrus Logic CS40L50 Advanced Haptic Driver 8 + 9 + maintainers: 10 + - James Ogletree <jogletre@opensource.cirrus.com> 11 + 12 + description: 13 + CS40L50 is a haptic driver with waveform memory, 14 + integrated DSP, and closed-loop algorithms. 15 + 16 + properties: 17 + compatible: 18 + enum: 19 + - cirrus,cs40l50 20 + 21 + reg: 22 + maxItems: 1 23 + 24 + interrupts: 25 + maxItems: 1 26 + 27 + reset-gpios: 28 + maxItems: 1 29 + 30 + vdd-a-supply: 31 + description: Power supply for internal analog circuits. 32 + 33 + vdd-p-supply: 34 + description: Power supply for always-on circuits. 35 + 36 + vdd-io-supply: 37 + description: Power supply for digital input/output. 38 + 39 + vdd-b-supply: 40 + description: Power supply for the boost converter. 41 + 42 + required: 43 + - compatible 44 + - reg 45 + - interrupts 46 + - reset-gpios 47 + - vdd-io-supply 48 + 49 + additionalProperties: false 50 + 51 + examples: 52 + - | 53 + #include <dt-bindings/gpio/gpio.h> 54 + #include <dt-bindings/interrupt-controller/irq.h> 55 + 56 + i2c { 57 + #address-cells = <1>; 58 + #size-cells = <0>; 59 + 60 + haptic-driver@34 { 61 + compatible = "cirrus,cs40l50"; 62 + reg = <0x34>; 63 + interrupt-parent = <&gpio>; 64 + interrupts = <113 IRQ_TYPE_LEVEL_LOW>; 65 + reset-gpios = <&gpio 112 GPIO_ACTIVE_LOW>; 66 + vdd-io-supply = <&vreg>; 67 + }; 68 + };
+76
Documentation/devicetree/bindings/mfd/marvell,88pm886-a1.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/mfd/marvell,88pm886-a1.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Marvell 88PM886 PMIC core 8 + 9 + maintainers: 10 + - Karel Balej <balejk@matfyz.cz> 11 + 12 + description: 13 + Marvell 88PM886 is a PMIC providing several functions such as onkey, 14 + regulators or battery and charger. 15 + 16 + properties: 17 + compatible: 18 + const: marvell,88pm886-a1 19 + 20 + reg: 21 + maxItems: 1 22 + 23 + interrupts: 24 + maxItems: 1 25 + 26 + wakeup-source: true 27 + 28 + regulators: 29 + type: object 30 + additionalProperties: false 31 + patternProperties: 32 + "^(ldo(1[0-6]|[1-9])|buck[1-5])$": 33 + type: object 34 + $ref: /schemas/regulator/regulator.yaml# 35 + description: LDO or buck regulator. 36 + unevaluatedProperties: false 37 + 38 + required: 39 + - compatible 40 + - reg 41 + - interrupts 42 + 43 + additionalProperties: false 44 + 45 + examples: 46 + - | 47 + #include <dt-bindings/interrupt-controller/irq.h> 48 + i2c { 49 + #address-cells = <1>; 50 + #size-cells = <0>; 51 + pmic@30 { 52 + compatible = "marvell,88pm886-a1"; 53 + reg = <0x30>; 54 + interrupts = <0 4 IRQ_TYPE_LEVEL_HIGH>; 55 + interrupt-parent = <&gic>; 56 + wakeup-source; 57 + 58 + regulators { 59 + ldo2: ldo2 { 60 + regulator-min-microvolt = <3100000>; 61 + regulator-max-microvolt = <3300000>; 62 + }; 63 + 64 + ldo15: ldo15 { 65 + regulator-min-microvolt = <3300000>; 66 + regulator-max-microvolt = <3300000>; 67 + }; 68 + 69 + buck2: buck2 { 70 + regulator-min-microvolt = <1800000>; 71 + regulator-max-microvolt = <1800000>; 72 + }; 73 + }; 74 + }; 75 + }; 76 + ...
+2
Documentation/devicetree/bindings/mfd/mediatek,mt8195-scpsys.yaml
··· 22 22 - mediatek,mt8173-scpsys 23 23 - mediatek,mt8183-scpsys 24 24 - mediatek,mt8186-scpsys 25 + - mediatek,mt8188-scpsys 25 26 - mediatek,mt8192-scpsys 26 27 - mediatek,mt8195-scpsys 28 + - mediatek,mt8365-scpsys 27 29 - const: syscon 28 30 - const: simple-mfd 29 31
+8 -7
Documentation/devicetree/bindings/mfd/mfd.txt
··· 17 17 18 18 Optional properties: 19 19 20 - - compatible : "simple-mfd" - this signifies that the operating system should 21 - consider all subnodes of the MFD device as separate devices akin to how 22 - "simple-bus" indicates when to see subnodes as children for a simple 23 - memory-mapped bus. For more complex devices, when the nexus driver has to 24 - probe registers to figure out what child devices exist etc, this should not 25 - be used. In the latter case the child devices will be determined by the 26 - operating system. 20 + - compatible : "simple-mfd" - this signifies that the operating system 21 + should consider all subnodes of the MFD device as separate and independent 22 + devices, so not needing any resources to be provided by the parent device. 23 + Similarly to how "simple-bus" indicates when to see subnodes as children for 24 + a simple memory-mapped bus. 25 + For more complex devices, when the nexus driver has to probe registers to 26 + figure out what child devices exist etc, this should not be used. In the 27 + latter case the child devices will be determined by the operating system. 27 28 28 29 - ranges: Describes the address mapping relationship to the parent. Should set 29 30 the child's base address to 0, the physical address within parent's address
+94 -68
Documentation/devicetree/bindings/mfd/qcom,pm8008.yaml
··· 19 19 const: qcom,pm8008 20 20 21 21 reg: 22 - description: 23 - I2C slave address. 24 - 25 22 maxItems: 1 26 23 27 24 interrupts: 28 25 maxItems: 1 29 26 30 - description: Parent interrupt. 27 + reset-gpios: 28 + maxItems: 1 29 + 30 + vdd-l1-l2-supply: true 31 + vdd-l3-l4-supply: true 32 + vdd-l5-supply: true 33 + vdd-l6-supply: true 34 + vdd-l7-supply: true 35 + 36 + gpio-controller: true 37 + 38 + "#gpio-cells": 39 + const: 2 40 + 41 + gpio-ranges: 42 + maxItems: 1 43 + 44 + interrupt-controller: true 31 45 32 46 "#interrupt-cells": 33 47 const: 2 34 48 35 - description: | 36 - The first cell is the IRQ number, the second cell is the IRQ trigger 37 - flag. All interrupts are listed in include/dt-bindings/mfd/qcom-pm8008.h. 38 - 39 - interrupt-controller: true 40 - 41 - "#address-cells": 42 - const: 1 43 - 44 - "#size-cells": 49 + "#thermal-sensor-cells": 45 50 const: 0 46 51 47 - patternProperties: 48 - "^gpio@[0-9a-f]+$": 52 + pinctrl: 49 53 type: object 50 - 51 - description: | 52 - The GPIO peripheral. This node may be specified twice, one for each GPIO. 53 - 54 - properties: 55 - compatible: 56 - items: 57 - - const: qcom,pm8008-gpio 58 - - const: qcom,spmi-gpio 59 - 60 - reg: 61 - description: Peripheral address of one of the two GPIO peripherals. 62 - maxItems: 1 63 - 64 - gpio-controller: true 65 - 66 - gpio-ranges: 67 - maxItems: 1 68 - 69 - interrupt-controller: true 70 - 71 - "#interrupt-cells": 72 - const: 2 73 - 74 - "#gpio-cells": 75 - const: 2 76 - 77 - required: 78 - - compatible 79 - - reg 80 - - gpio-controller 81 - - interrupt-controller 82 - - "#gpio-cells" 83 - - gpio-ranges 84 - - "#interrupt-cells" 85 - 86 54 additionalProperties: false 55 + patternProperties: 56 + "-state$": 57 + type: object 58 + 59 + allOf: 60 + - $ref: /schemas/pinctrl/pinmux-node.yaml 61 + - $ref: /schemas/pinctrl/pincfg-node.yaml 62 + 63 + properties: 64 + pins: 65 + items: 66 + pattern: "^gpio[12]$" 67 + 68 + function: 69 + items: 70 + - enum: 71 + - normal 72 + 73 + required: 74 + - pins 75 + - function 76 + 77 + additionalProperties: false 78 + 79 + regulators: 80 + type: object 81 + additionalProperties: false 82 + patternProperties: 83 + "^ldo[1-7]$": 84 + type: object 85 + $ref: /schemas/regulator/regulator.yaml# 86 + unevaluatedProperties: false 87 87 88 88 required: 89 89 - compatible 90 90 - reg 91 91 - interrupts 92 - - "#address-cells" 93 - - "#size-cells" 92 + - vdd-l1-l2-supply 93 + - vdd-l3-l4-supply 94 + - vdd-l5-supply 95 + - vdd-l6-supply 96 + - vdd-l7-supply 97 + - gpio-controller 98 + - "#gpio-cells" 99 + - gpio-ranges 100 + - interrupt-controller 94 101 - "#interrupt-cells" 102 + - "#thermal-sensor-cells" 95 103 96 104 additionalProperties: false 97 105 98 106 examples: 99 107 - | 100 - #include <dt-bindings/mfd/qcom-pm8008.h> 108 + #include <dt-bindings/gpio/gpio.h> 101 109 #include <dt-bindings/interrupt-controller/irq.h> 102 110 103 111 i2c { 104 112 #address-cells = <1>; 105 113 #size-cells = <0>; 106 114 107 - pmic@8 { 115 + pm8008: pmic@8 { 108 116 compatible = "qcom,pm8008"; 109 117 reg = <0x8>; 110 - #address-cells = <1>; 111 - #size-cells = <0>; 112 - interrupt-controller; 113 - #interrupt-cells = <2>; 114 118 115 119 interrupt-parent = <&tlmm>; 116 120 interrupts = <32 IRQ_TYPE_EDGE_RISING>; 117 121 118 - pm8008_gpios: gpio@c000 { 119 - compatible = "qcom,pm8008-gpio", "qcom,spmi-gpio"; 120 - reg = <0xc000>; 121 - gpio-controller; 122 - gpio-ranges = <&pm8008_gpios 0 0 2>; 123 - #gpio-cells = <2>; 124 - interrupt-controller; 125 - #interrupt-cells = <2>; 122 + reset-gpios = <&tlmm 42 GPIO_ACTIVE_LOW>; 123 + 124 + vdd-l1-l2-supply = <&vreg_s8b_1p2>; 125 + vdd-l3-l4-supply = <&vreg_s1b_1p8>; 126 + vdd-l5-supply = <&vreg_bob>; 127 + vdd-l6-supply = <&vreg_bob>; 128 + vdd-l7-supply = <&vreg_bob>; 129 + 130 + gpio-controller; 131 + #gpio-cells = <2>; 132 + gpio-ranges = <&pm8008 0 0 2>; 133 + 134 + interrupt-controller; 135 + #interrupt-cells = <2>; 136 + 137 + #thermal-sensor-cells = <0>; 138 + 139 + pinctrl { 140 + gpio-keys-state { 141 + pins = "gpio1"; 142 + function = "normal"; 143 + }; 144 + }; 145 + 146 + regulators { 147 + ldo1 { 148 + regulator-name = "vreg_l1"; 149 + regulator-min-microvolt = <950000>; 150 + regulator-max-microvolt = <1300000>; 151 + }; 126 152 }; 127 153 }; 128 154 };
+2
Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml
··· 75 75 - qcom,pma8084 76 76 - qcom,pmc8180 77 77 - qcom,pmc8180c 78 + - qcom,pmc8380 78 79 - qcom,pmd9635 79 80 - qcom,pmi632 80 81 - qcom,pmi8950 ··· 96 95 - qcom,pmx65 97 96 - qcom,pmx75 98 97 - qcom,smb2351 98 + - qcom,smb2360 99 99 - const: qcom,spmi-pmic 100 100 101 101 reg:
-288
Documentation/devicetree/bindings/mfd/rockchip,rk809.yaml
··· 1 - # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause 2 - %YAML 1.2 3 - --- 4 - $id: http://devicetree.org/schemas/mfd/rockchip,rk809.yaml# 5 - $schema: http://devicetree.org/meta-schemas/core.yaml# 6 - 7 - title: RK809 Power Management Integrated Circuit 8 - 9 - maintainers: 10 - - Chris Zhong <zyw@rock-chips.com> 11 - - Zhang Qing <zhangqing@rock-chips.com> 12 - 13 - description: | 14 - Rockchip RK809 series PMIC. This device consists of an i2c controlled MFD 15 - that includes regulators, an RTC, and power button. 16 - 17 - properties: 18 - compatible: 19 - enum: 20 - - rockchip,rk809 21 - 22 - reg: 23 - maxItems: 1 24 - 25 - interrupts: 26 - maxItems: 1 27 - 28 - '#clock-cells': 29 - description: | 30 - See <dt-bindings/clock/rockchip,rk808.h> for clock IDs. 31 - minimum: 0 32 - maximum: 1 33 - 34 - clock-output-names: 35 - description: 36 - From common clock binding to override the default output clock name. 37 - 38 - rockchip,system-power-controller: 39 - type: boolean 40 - deprecated: true 41 - description: 42 - Telling whether or not this PMIC is controlling the system power. 43 - 44 - system-power-controller: true 45 - 46 - wakeup-source: 47 - type: boolean 48 - description: 49 - Device can be used as a wakeup source. 50 - 51 - vcc1-supply: 52 - description: 53 - The input supply for DCDC_REG1. 54 - 55 - vcc2-supply: 56 - description: 57 - The input supply for DCDC_REG2. 58 - 59 - vcc3-supply: 60 - description: 61 - The input supply for DCDC_REG3. 62 - 63 - vcc4-supply: 64 - description: 65 - The input supply for DCDC_REG4. 66 - 67 - vcc5-supply: 68 - description: 69 - The input supply for LDO_REG1, LDO_REG2, and LDO_REG3. 70 - 71 - vcc6-supply: 72 - description: 73 - The input supply for LDO_REG4, LDO_REG5, and LDO_REG6. 74 - 75 - vcc7-supply: 76 - description: 77 - The input supply for LDO_REG7, LDO_REG8, and LDO_REG9. 78 - 79 - vcc8-supply: 80 - description: 81 - The input supply for SWITCH_REG1. 82 - 83 - vcc9-supply: 84 - description: 85 - The input supply for DCDC_REG5 and SWITCH_REG2. 86 - 87 - regulators: 88 - type: object 89 - patternProperties: 90 - "^(LDO_REG[1-9]|DCDC_REG[1-5]|SWITCH_REG[1-2])$": 91 - type: object 92 - $ref: /schemas/regulator/regulator.yaml# 93 - unevaluatedProperties: false 94 - unevaluatedProperties: false 95 - 96 - allOf: 97 - - if: 98 - properties: 99 - '#clock-cells': 100 - const: 0 101 - 102 - then: 103 - properties: 104 - clock-output-names: 105 - maxItems: 1 106 - 107 - else: 108 - properties: 109 - clock-output-names: 110 - maxItems: 2 111 - 112 - required: 113 - - compatible 114 - - reg 115 - - interrupts 116 - - "#clock-cells" 117 - 118 - additionalProperties: false 119 - 120 - examples: 121 - - | 122 - #include <dt-bindings/pinctrl/rockchip.h> 123 - #include <dt-bindings/interrupt-controller/irq.h> 124 - #include <dt-bindings/gpio/gpio.h> 125 - i2c { 126 - #address-cells = <1>; 127 - #size-cells = <0>; 128 - 129 - rk808: pmic@1b { 130 - compatible = "rockchip,rk808"; 131 - reg = <0x1b>; 132 - #clock-cells = <1>; 133 - clock-output-names = "xin32k", "rk808-clkout2"; 134 - interrupt-parent = <&gpio3>; 135 - interrupts = <10 IRQ_TYPE_LEVEL_LOW>; 136 - pinctrl-names = "default"; 137 - pinctrl-0 = <&pmic_int_l_pin>; 138 - rockchip,system-power-controller; 139 - wakeup-source; 140 - 141 - vcc1-supply = <&vcc_sysin>; 142 - vcc2-supply = <&vcc_sysin>; 143 - vcc3-supply = <&vcc_sysin>; 144 - vcc4-supply = <&vcc_sysin>; 145 - vcc6-supply = <&vcc_sysin>; 146 - vcc7-supply = <&vcc_sysin>; 147 - vcc8-supply = <&vcc3v3_sys>; 148 - vcc9-supply = <&vcc_sysin>; 149 - vcc10-supply = <&vcc_sysin>; 150 - vcc11-supply = <&vcc_sysin>; 151 - vcc12-supply = <&vcc3v3_sys>; 152 - 153 - regulators { 154 - vdd_center: DCDC_REG1 { 155 - regulator-name = "vdd_center"; 156 - regulator-always-on; 157 - regulator-boot-on; 158 - regulator-min-microvolt = <750000>; 159 - regulator-max-microvolt = <1350000>; 160 - regulator-ramp-delay = <6001>; 161 - regulator-state-mem { 162 - regulator-off-in-suspend; 163 - }; 164 - }; 165 - 166 - vdd_cpu_l: DCDC_REG2 { 167 - regulator-name = "vdd_cpu_l"; 168 - regulator-always-on; 169 - regulator-boot-on; 170 - regulator-min-microvolt = <750000>; 171 - regulator-max-microvolt = <1350000>; 172 - regulator-ramp-delay = <6001>; 173 - regulator-state-mem { 174 - regulator-off-in-suspend; 175 - }; 176 - }; 177 - 178 - vcc_ddr: DCDC_REG3 { 179 - regulator-name = "vcc_ddr"; 180 - regulator-always-on; 181 - regulator-boot-on; 182 - regulator-state-mem { 183 - regulator-on-in-suspend; 184 - }; 185 - }; 186 - 187 - vcc_1v8: vcc_wl: DCDC_REG4 { 188 - regulator-name = "vcc_1v8"; 189 - regulator-always-on; 190 - regulator-boot-on; 191 - regulator-min-microvolt = <1800000>; 192 - regulator-max-microvolt = <1800000>; 193 - regulator-state-mem { 194 - regulator-on-in-suspend; 195 - regulator-suspend-microvolt = <1800000>; 196 - }; 197 - }; 198 - 199 - vcc1v8_pmupll: LDO_REG3 { 200 - regulator-name = "vcc1v8_pmupll"; 201 - regulator-always-on; 202 - regulator-boot-on; 203 - regulator-min-microvolt = <1800000>; 204 - regulator-max-microvolt = <1800000>; 205 - regulator-state-mem { 206 - regulator-on-in-suspend; 207 - regulator-suspend-microvolt = <1800000>; 208 - }; 209 - }; 210 - 211 - vcc_sdio: LDO_REG4 { 212 - regulator-name = "vcc_sdio"; 213 - regulator-always-on; 214 - regulator-boot-on; 215 - regulator-min-microvolt = <1800000>; 216 - regulator-max-microvolt = <3000000>; 217 - regulator-state-mem { 218 - regulator-on-in-suspend; 219 - regulator-suspend-microvolt = <3000000>; 220 - }; 221 - }; 222 - 223 - vcca3v0_codec: LDO_REG5 { 224 - regulator-name = "vcca3v0_codec"; 225 - regulator-always-on; 226 - regulator-boot-on; 227 - regulator-min-microvolt = <3000000>; 228 - regulator-max-microvolt = <3000000>; 229 - regulator-state-mem { 230 - regulator-off-in-suspend; 231 - }; 232 - }; 233 - 234 - vcc_1v5: LDO_REG6 { 235 - regulator-name = "vcc_1v5"; 236 - regulator-always-on; 237 - regulator-boot-on; 238 - regulator-min-microvolt = <1500000>; 239 - regulator-max-microvolt = <1500000>; 240 - regulator-state-mem { 241 - regulator-on-in-suspend; 242 - regulator-suspend-microvolt = <1500000>; 243 - }; 244 - }; 245 - 246 - vcca1v8_codec: LDO_REG7 { 247 - regulator-name = "vcca1v8_codec"; 248 - regulator-always-on; 249 - regulator-boot-on; 250 - regulator-min-microvolt = <1800000>; 251 - regulator-max-microvolt = <1800000>; 252 - regulator-state-mem { 253 - regulator-off-in-suspend; 254 - }; 255 - }; 256 - 257 - vcc_3v0: LDO_REG8 { 258 - regulator-name = "vcc_3v0"; 259 - regulator-always-on; 260 - regulator-boot-on; 261 - regulator-min-microvolt = <3000000>; 262 - regulator-max-microvolt = <3000000>; 263 - regulator-state-mem { 264 - regulator-on-in-suspend; 265 - regulator-suspend-microvolt = <3000000>; 266 - }; 267 - }; 268 - 269 - vcc3v3_s3: SWITCH_REG1 { 270 - regulator-name = "vcc3v3_s3"; 271 - regulator-always-on; 272 - regulator-boot-on; 273 - regulator-state-mem { 274 - regulator-off-in-suspend; 275 - }; 276 - }; 277 - 278 - vcc3v3_s0: SWITCH_REG2 { 279 - regulator-name = "vcc3v3_s0"; 280 - regulator-always-on; 281 - regulator-boot-on; 282 - regulator-state-mem { 283 - regulator-off-in-suspend; 284 - }; 285 - }; 286 - }; 287 - }; 288 - };
+38 -32
Documentation/devicetree/bindings/mfd/rockchip,rk817.yaml
··· 4 4 $id: http://devicetree.org/schemas/mfd/rockchip,rk817.yaml# 5 5 $schema: http://devicetree.org/meta-schemas/core.yaml# 6 6 7 - title: RK817 Power Management Integrated Circuit 7 + title: RK809/RK817 Power Management Integrated Circuit 8 8 9 9 maintainers: 10 10 - Chris Zhong <zyw@rock-chips.com> 11 11 - Zhang Qing <zhangqing@rock-chips.com> 12 12 13 13 description: | 14 - Rockchip RK817 series PMIC. This device consists of an i2c controlled MFD 15 - that includes regulators, an RTC, a power button, an audio codec, and a 16 - battery charger manager. 14 + Rockchip RK809/RK817 series PMIC. This device consists of an i2c controlled 15 + MFD that includes regulators, an RTC, a power button and an audio codec. 16 + The RK817 variant also provides a battery charger manager. 17 17 18 18 properties: 19 19 compatible: 20 20 enum: 21 + - rockchip,rk809 21 22 - rockchip,rk817 22 23 23 24 reg: ··· 33 32 minimum: 0 34 33 maximum: 1 35 34 35 + clocks: 36 + maxItems: 1 37 + 38 + clock-names: 39 + items: 40 + - const: mclk 41 + 36 42 clock-output-names: 37 43 description: 38 44 From common clock binding to override the default output clock name. ··· 49 41 deprecated: true 50 42 description: 51 43 Telling whether or not this PMIC is controlling the system power. 44 + 45 + '#sound-dai-cells': 46 + const: 0 52 47 53 48 system-power-controller: true 54 49 ··· 90 79 91 80 vcc8-supply: 92 81 description: 93 - The input supply for BOOST. 82 + The input supply for BOOST on RK817, or for SWITCH_REG2 on RK809. 94 83 95 84 vcc9-supply: 96 85 description: 97 - The input supply for OTG_SWITCH. 86 + The input supply for OTG_SWITCH on RK817, 87 + or for DCDC_REG5 and SWITCH_REG1 on RK809. 98 88 99 89 regulators: 100 90 type: object 101 91 patternProperties: 102 - "^(LDO_REG[1-9]|DCDC_REG[1-4]|BOOST|OTG_SWITCH)$": 103 - type: object 92 + "^(LDO_REG[1-9]|DCDC_REG[1-5]|BOOST|OTG_SWITCH|SWITCH_REG[1-2])$": 93 + $ref: /schemas/regulator/regulator.yaml 104 94 unevaluatedProperties: false 105 - $ref: /schemas/regulator/regulator.yaml# 106 - unevaluatedProperties: false 107 - 108 - clocks: 109 - description: 110 - The input clock for the audio codec. 111 - 112 - clock-names: 113 - description: 114 - The clock name for the codec clock. 115 - items: 116 - - const: mclk 117 - 118 - '#sound-dai-cells': 119 - description: 120 - Needed for the interpretation of sound dais. 121 - const: 0 95 + additionalProperties: false 122 96 123 97 codec: 124 - description: | 125 - The child node for the codec to hold additional properties. If no 126 - additional properties are required for the codec, this node can be 127 - omitted. 128 98 type: object 129 99 additionalProperties: false 130 100 properties: ··· 115 123 Describes if the microphone uses differential mode. 116 124 117 125 charger: 118 - description: | 119 - The child node for the charger to hold additional properties. If a 120 - battery is not in use, this node can be omitted. 121 126 type: object 122 127 $ref: /schemas/power/supply/power-supply.yaml 123 128 ··· 157 168 additionalProperties: false 158 169 159 170 allOf: 171 + - $ref: /schemas/sound/dai-common.yaml# 160 172 - if: 161 173 properties: 162 174 '#clock-cells': ··· 172 182 properties: 173 183 clock-output-names: 174 184 maxItems: 2 185 + 186 + - if: 187 + properties: 188 + compatible: 189 + contains: 190 + const: rockchip,rk817 191 + then: 192 + properties: 193 + regulators: 194 + patternProperties: 195 + "^(DCDC_REG5|SWITCH_REG[1-2])$": false 196 + else: 197 + properties: 198 + regulators: 199 + patternProperties: 200 + "^(BOOST|OTG_SWITCH)$": false 175 201 176 202 required: 177 203 - compatible
+173
Documentation/devicetree/bindings/mfd/rohm,bd96801-pmic.yaml
··· 1 + # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/mfd/rohm,bd96801-pmic.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: ROHM BD96801 Scalable Power Management Integrated Circuit 8 + 9 + maintainers: 10 + - Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com> 11 + 12 + description: 13 + BD96801 is an automotive grade single-chip power management IC. 14 + It integrates 4 buck converters and 3 LDOs with safety features like 15 + over-/under voltage and over current detection and a watchdog. 16 + 17 + properties: 18 + compatible: 19 + const: rohm,bd96801 20 + 21 + reg: 22 + maxItems: 1 23 + 24 + interrupts: 25 + description: 26 + The PMIC provides intb and errb IRQ lines. The errb IRQ line is used 27 + for fatal IRQs which will cause the PMIC to shut down power outputs. 28 + In many systems this will shut down the SoC contolling the PMIC and 29 + connecting/handling the errb can be omitted. However, there are cases 30 + where the SoC is not powered by the PMIC or has a short time backup 31 + energy to handle shutdown of critical hardware. In that case it may be 32 + useful to connect the errb and handle errb events. 33 + minItems: 1 34 + maxItems: 2 35 + 36 + interrupt-names: 37 + minItems: 1 38 + items: 39 + - enum: [intb, errb] 40 + - const: errb 41 + 42 + rohm,hw-timeout-ms: 43 + description: 44 + Watchdog timeout value(s). First walue is timeout limit. Second value is 45 + optional value for 'too early' watchdog ping if window timeout mode is 46 + to be used. 47 + minItems: 1 48 + maxItems: 2 49 + 50 + rohm,wdg-action: 51 + description: 52 + Whether the watchdog failure must turn off the regulator power outputs or 53 + just toggle the INTB line. 54 + enum: 55 + - prstb 56 + - intb-only 57 + 58 + timeout-sec: 59 + maxItems: 2 60 + 61 + regulators: 62 + $ref: /schemas/regulator/rohm,bd96801-regulator.yaml 63 + description: 64 + List of child nodes that specify the regulators. 65 + 66 + required: 67 + - compatible 68 + - reg 69 + - interrupts 70 + - interrupt-names 71 + - regulators 72 + 73 + additionalProperties: false 74 + 75 + examples: 76 + - | 77 + #include <dt-bindings/interrupt-controller/irq.h> 78 + #include <dt-bindings/leds/common.h> 79 + i2c { 80 + #address-cells = <1>; 81 + #size-cells = <0>; 82 + pmic: pmic@60 { 83 + reg = <0x60>; 84 + compatible = "rohm,bd96801"; 85 + interrupt-parent = <&gpio1>; 86 + interrupts = <29 IRQ_TYPE_LEVEL_LOW>, <6 IRQ_TYPE_LEVEL_LOW>; 87 + interrupt-names = "intb", "errb"; 88 + 89 + regulators { 90 + buck1 { 91 + regulator-name = "buck1"; 92 + regulator-ramp-delay = <1250>; 93 + /* 0.5V min INITIAL - 150 mV tune */ 94 + regulator-min-microvolt = <350000>; 95 + /* 3.3V + 150mV tune */ 96 + regulator-max-microvolt = <3450000>; 97 + 98 + /* These can be set only when PMIC is in STBY */ 99 + rohm,initial-voltage-microvolt = <500000>; 100 + regulator-ov-error-microvolt = <230000>; 101 + regulator-uv-error-microvolt = <230000>; 102 + regulator-temp-protection-kelvin = <1>; 103 + regulator-temp-warn-kelvin = <0>; 104 + }; 105 + buck2 { 106 + regulator-name = "buck2"; 107 + regulator-min-microvolt = <350000>; 108 + regulator-max-microvolt = <3450000>; 109 + 110 + rohm,initial-voltage-microvolt = <3000000>; 111 + regulator-ov-error-microvolt = <18000>; 112 + regulator-uv-error-microvolt = <18000>; 113 + regulator-temp-protection-kelvin = <1>; 114 + regulator-temp-warn-kelvin = <1>; 115 + }; 116 + buck3 { 117 + regulator-name = "buck3"; 118 + regulator-min-microvolt = <350000>; 119 + regulator-max-microvolt = <3450000>; 120 + 121 + rohm,initial-voltage-microvolt = <600000>; 122 + regulator-ov-warn-microvolt = <18000>; 123 + regulator-uv-warn-microvolt = <18000>; 124 + regulator-temp-protection-kelvin = <1>; 125 + regulator-temp-error-kelvin = <0>; 126 + }; 127 + buck4 { 128 + regulator-name = "buck4"; 129 + regulator-min-microvolt = <350000>; 130 + regulator-max-microvolt = <3450000>; 131 + 132 + rohm,initial-voltage-microvolt = <600000>; 133 + regulator-ov-warn-microvolt = <18000>; 134 + regulator-uv-warn-microvolt = <18000>; 135 + regulator-temp-protection-kelvin = <1>; 136 + regulator-temp-error-kelvin = <0>; 137 + }; 138 + ldo5 { 139 + regulator-name = "ldo5"; 140 + regulator-min-microvolt = <300000>; 141 + regulator-max-microvolt = <3300000>; 142 + 143 + rohm,initial-voltage-microvolt = <500000>; 144 + regulator-ov-error-microvolt = <36000>; 145 + regulator-uv-error-microvolt = <34000>; 146 + regulator-temp-protection-kelvin = <1>; 147 + regulator-temp-warn-kelvin = <0>; 148 + }; 149 + ldo6 { 150 + regulator-name = "ldo6"; 151 + regulator-min-microvolt = <300000>; 152 + regulator-max-microvolt = <3300000>; 153 + 154 + rohm,initial-voltage-microvolt = <300000>; 155 + regulator-ov-error-microvolt = <36000>; 156 + regulator-uv-error-microvolt = <34000>; 157 + regulator-temp-protection-kelvin = <1>; 158 + regulator-temp-warn-kelvin = <0>; 159 + }; 160 + ldo7 { 161 + regulator-name = "ldo7"; 162 + regulator-min-microvolt = <300000>; 163 + regulator-max-microvolt = <3300000>; 164 + 165 + rohm,initial-voltage-microvolt = <500000>; 166 + regulator-ov-error-microvolt = <36000>; 167 + regulator-uv-error-microvolt = <34000>; 168 + regulator-temp-protection-kelvin = <1>; 169 + regulator-temp-warn-kelvin = <0>; 170 + }; 171 + }; 172 + }; 173 + };
+71
Documentation/devicetree/bindings/mfd/syscon-common.yaml
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/mfd/syscon-common.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: System Controller Registers R/W Common Properties 8 + 9 + description: 10 + System controller node represents a register region containing a set 11 + of miscellaneous registers. The registers are not cohesive enough to 12 + represent as any specific type of device. The typical use-case is 13 + for some other node's driver, or platform-specific code, to acquire 14 + a reference to the syscon node (e.g. by phandle, node path, or 15 + search using a specific compatible value), interrogate the node (or 16 + associated OS driver) to determine the location of the registers, 17 + and access the registers directly. 18 + 19 + maintainers: 20 + - Lee Jones <lee@kernel.org> 21 + 22 + select: 23 + properties: 24 + compatible: 25 + contains: 26 + const: syscon 27 + 28 + required: 29 + - compatible 30 + 31 + properties: 32 + compatible: 33 + contains: 34 + const: syscon 35 + minItems: 2 36 + maxItems: 5 # Should be enough 37 + 38 + reg: 39 + maxItems: 1 40 + 41 + reg-io-width: 42 + description: 43 + The size (in bytes) of the IO accesses that should be performed 44 + on the device. 45 + enum: [1, 2, 4, 8] 46 + 47 + required: 48 + - compatible 49 + - reg 50 + 51 + allOf: 52 + - if: 53 + properties: 54 + compatible: 55 + contains: 56 + const: simple-mfd 57 + then: 58 + properties: 59 + compatible: 60 + minItems: 3 61 + maxItems: 5 62 + 63 + additionalProperties: true 64 + 65 + examples: 66 + - | 67 + syscon: syscon@1c00000 { 68 + compatible = "allwinner,sun8i-h3-system-controller", "syscon"; 69 + reg = <0x01c00000 0x1000>; 70 + }; 71 + ...
+185 -93
Documentation/devicetree/bindings/mfd/syscon.yaml
··· 4 4 $id: http://devicetree.org/schemas/mfd/syscon.yaml# 5 5 $schema: http://devicetree.org/meta-schemas/core.yaml# 6 6 7 - title: System Controller Registers R/W 7 + title: System Controller Devices 8 8 9 9 description: | 10 10 System controller node represents a register region containing a set ··· 19 19 maintainers: 20 20 - Lee Jones <lee@kernel.org> 21 21 22 + # Need a select with all compatibles listed for compatibility with older 23 + # dtschema (<2024.02), so this will not be selected for other schemas having 24 + # syscon fallback. 22 25 select: 23 26 properties: 24 27 compatible: 25 28 contains: 26 29 enum: 27 - - syscon 28 - 30 + - al,alpine-sysfabric-servic 31 + - allwinner,sun8i-a83t-system-controller 32 + - allwinner,sun8i-h3-system-controller 33 + - allwinner,sun8i-v3s-system-controller 34 + - allwinner,sun50i-a64-system-controller 35 + - altr,l3regs 36 + - altr,sdr-ctl 37 + - amd,pensando-elba-syscon 38 + - amlogic,meson-mx-assist 39 + - amlogic,meson-mx-bootrom 40 + - amlogic,meson8-analog-top 41 + - amlogic,meson8b-analog-top 42 + - amlogic,meson8-pmu 43 + - amlogic,meson8b-pmu 44 + - apm,merlin-poweroff-mailbox 45 + - apm,mustang-poweroff-mailbox 46 + - apm,xgene-csw 47 + - apm,xgene-efuse 48 + - apm,xgene-mcb 49 + - apm,xgene-rb 50 + - apm,xgene-scu 51 + - atmel,sama5d2-sfrbu 52 + - atmel,sama5d3-nfc-io 53 + - atmel,sama5d3-sfrbu 54 + - atmel,sama5d4-sfrbu 55 + - axis,artpec6-syscon 56 + - brcm,cru-clkset 57 + - brcm,sr-cdru 58 + - brcm,sr-mhb 59 + - cirrus,ep7209-syscon1 60 + - cirrus,ep7209-syscon2 61 + - cirrus,ep7209-syscon3 62 + - cnxt,cx92755-uc 63 + - freecom,fsg-cs2-system-controller 64 + - fsl,imx93-aonmix-ns-syscfg 65 + - fsl,imx93-wakeupmix-syscfg 66 + - fsl,ls1088a-reset 67 + - fsl,vf610-anatop 68 + - fsl,vf610-mscm-cpucfg 69 + - hisilicon,dsa-subctrl 70 + - hisilicon,hi6220-sramctrl 71 + - hisilicon,hip04-ppe 72 + - hisilicon,pcie-sas-subctrl 73 + - hisilicon,peri-subctrl 74 + - hpe,gxp-sysreg 75 + - loongson,ls1b-syscon 76 + - loongson,ls1c-syscon 77 + - lsi,axxia-syscon 78 + - marvell,armada-3700-cpu-misc 79 + - marvell,armada-3700-nb-pm 80 + - marvell,armada-3700-avs 81 + - marvell,armada-3700-usb2-host-misc 82 + - marvell,dove-global-config 83 + - mediatek,mt2701-pctl-a-syscfg 84 + - mediatek,mt2712-pctl-a-syscfg 85 + - mediatek,mt6397-pctl-pmic-syscfg 86 + - mediatek,mt8135-pctl-a-syscfg 87 + - mediatek,mt8135-pctl-b-syscfg 88 + - mediatek,mt8173-pctl-a-syscfg 89 + - mediatek,mt8365-syscfg 90 + - microchip,lan966x-cpu-syscon 91 + - microchip,sam9x60-sfr 92 + - microchip,sama7g5-ddr3phy 93 + - mscc,ocelot-cpu-syscon 94 + - mstar,msc313-pmsleep 95 + - nuvoton,ma35d1-sys 96 + - nuvoton,wpcm450-shm 97 + - rockchip,px30-qos 98 + - rockchip,rk3036-qos 99 + - rockchip,rk3066-qos 100 + - rockchip,rk3128-qos 101 + - rockchip,rk3228-qos 102 + - rockchip,rk3288-qos 103 + - rockchip,rk3368-qos 104 + - rockchip,rk3399-qos 105 + - rockchip,rk3568-qos 106 + - rockchip,rk3588-qos 107 + - rockchip,rv1126-qos 108 + - st,spear1340-misc 109 + - stericsson,nomadik-pmu 110 + - starfive,jh7100-sysmain 111 + - ti,am62-opp-efuse-table 112 + - ti,am62-usb-phy-ctrl 113 + - ti,am625-dss-oldi-io-ctrl 114 + - ti,am62p-cpsw-mac-efuse 115 + - ti,am654-dss-oldi-io-ctrl 116 + - ti,j784s4-pcie-ctrl 117 + - ti,keystone-pllctrl 29 118 required: 30 119 - compatible 31 120 32 121 properties: 33 122 compatible: 34 - anyOf: 35 - - items: 36 - - enum: 37 - - allwinner,sun8i-a83t-system-controller 38 - - allwinner,sun8i-h3-system-controller 39 - - allwinner,sun8i-v3s-system-controller 40 - - allwinner,sun50i-a64-system-controller 41 - - altr,sdr-ctl 42 - - amd,pensando-elba-syscon 43 - - apm,xgene-csw 44 - - apm,xgene-efuse 45 - - apm,xgene-mcb 46 - - apm,xgene-rb 47 - - apm,xgene-scu 48 - - brcm,cru-clkset 49 - - brcm,sr-cdru 50 - - brcm,sr-mhb 51 - - freecom,fsg-cs2-system-controller 52 - - fsl,imx93-aonmix-ns-syscfg 53 - - fsl,imx93-wakeupmix-syscfg 54 - - fsl,ls1088a-reset 55 - - hisilicon,dsa-subctrl 56 - - hisilicon,hi6220-sramctrl 57 - - hisilicon,pcie-sas-subctrl 58 - - hisilicon,peri-subctrl 59 - - hpe,gxp-sysreg 60 - - intel,lgm-syscon 61 - - loongson,ls1b-syscon 62 - - loongson,ls1c-syscon 63 - - marvell,armada-3700-cpu-misc 64 - - marvell,armada-3700-nb-pm 65 - - marvell,armada-3700-avs 66 - - marvell,armada-3700-usb2-host-misc 67 - - mediatek,mt2712-pctl-a-syscfg 68 - - mediatek,mt6397-pctl-pmic-syscfg 69 - - mediatek,mt8135-pctl-a-syscfg 70 - - mediatek,mt8135-pctl-b-syscfg 71 - - mediatek,mt8173-pctl-a-syscfg 72 - - mediatek,mt8365-syscfg 73 - - microchip,lan966x-cpu-syscon 74 - - microchip,sparx5-cpu-syscon 75 - - mstar,msc313-pmsleep 76 - - nuvoton,ma35d1-sys 77 - - nuvoton,wpcm450-shm 78 - - rockchip,px30-qos 79 - - rockchip,rk3036-qos 80 - - rockchip,rk3066-qos 81 - - rockchip,rk3128-qos 82 - - rockchip,rk3228-qos 83 - - rockchip,rk3288-qos 84 - - rockchip,rk3368-qos 85 - - rockchip,rk3399-qos 86 - - rockchip,rk3568-qos 87 - - rockchip,rk3588-qos 88 - - rockchip,rv1126-qos 89 - - starfive,jh7100-sysmain 90 - - ti,am62-usb-phy-ctrl 91 - - ti,am62p-cpsw-mac-efuse 92 - - ti,am654-dss-oldi-io-ctrl 93 - - ti,am654-serdes-ctrl 94 - - ti,j784s4-pcie-ctrl 95 - 96 - - const: syscon 97 - 98 - - contains: 99 - const: syscon 100 - minItems: 2 101 - maxItems: 5 # Should be enough 123 + items: 124 + - enum: 125 + - al,alpine-sysfabric-service 126 + - allwinner,sun8i-a83t-system-controller 127 + - allwinner,sun8i-h3-system-controller 128 + - allwinner,sun8i-v3s-system-controller 129 + - allwinner,sun50i-a64-system-controller 130 + - altr,l3regs 131 + - altr,sdr-ctl 132 + - amd,pensando-elba-syscon 133 + - amlogic,meson-mx-assist 134 + - amlogic,meson-mx-bootrom 135 + - amlogic,meson8-analog-top 136 + - amlogic,meson8b-analog-top 137 + - amlogic,meson8-pmu 138 + - amlogic,meson8b-pmu 139 + - apm,merlin-poweroff-mailbox 140 + - apm,mustang-poweroff-mailbox 141 + - apm,xgene-csw 142 + - apm,xgene-efuse 143 + - apm,xgene-mcb 144 + - apm,xgene-rb 145 + - apm,xgene-scu 146 + - atmel,sama5d2-sfrbu 147 + - atmel,sama5d3-nfc-io 148 + - atmel,sama5d3-sfrbu 149 + - atmel,sama5d4-sfrbu 150 + - axis,artpec6-syscon 151 + - brcm,cru-clkset 152 + - brcm,sr-cdru 153 + - brcm,sr-mhb 154 + - cirrus,ep7209-syscon1 155 + - cirrus,ep7209-syscon2 156 + - cirrus,ep7209-syscon3 157 + - cnxt,cx92755-uc 158 + - freecom,fsg-cs2-system-controller 159 + - fsl,imx93-aonmix-ns-syscfg 160 + - fsl,imx93-wakeupmix-syscfg 161 + - fsl,ls1088a-reset 162 + - fsl,vf610-anatop 163 + - fsl,vf610-mscm-cpucfg 164 + - hisilicon,dsa-subctrl 165 + - hisilicon,hi6220-sramctrl 166 + - hisilicon,hip04-ppe 167 + - hisilicon,pcie-sas-subctrl 168 + - hisilicon,peri-subctrl 169 + - hpe,gxp-sysreg 170 + - loongson,ls1b-syscon 171 + - loongson,ls1c-syscon 172 + - lsi,axxia-syscon 173 + - marvell,armada-3700-cpu-misc 174 + - marvell,armada-3700-nb-pm 175 + - marvell,armada-3700-avs 176 + - marvell,armada-3700-usb2-host-misc 177 + - marvell,dove-global-config 178 + - mediatek,mt2701-pctl-a-syscfg 179 + - mediatek,mt2712-pctl-a-syscfg 180 + - mediatek,mt6397-pctl-pmic-syscfg 181 + - mediatek,mt8135-pctl-a-syscfg 182 + - mediatek,mt8135-pctl-b-syscfg 183 + - mediatek,mt8173-pctl-a-syscfg 184 + - mediatek,mt8365-syscfg 185 + - microchip,lan966x-cpu-syscon 186 + - microchip,sam9x60-sfr 187 + - microchip,sama7g5-ddr3phy 188 + - mscc,ocelot-cpu-syscon 189 + - mstar,msc313-pmsleep 190 + - nuvoton,ma35d1-sys 191 + - nuvoton,wpcm450-shm 192 + - rockchip,px30-qos 193 + - rockchip,rk3036-qos 194 + - rockchip,rk3066-qos 195 + - rockchip,rk3128-qos 196 + - rockchip,rk3228-qos 197 + - rockchip,rk3288-qos 198 + - rockchip,rk3368-qos 199 + - rockchip,rk3399-qos 200 + - rockchip,rk3568-qos 201 + - rockchip,rk3588-qos 202 + - rockchip,rv1126-qos 203 + - st,spear1340-misc 204 + - stericsson,nomadik-pmu 205 + - starfive,jh7100-sysmain 206 + - ti,am62-opp-efuse-table 207 + - ti,am62-usb-phy-ctrl 208 + - ti,am625-dss-oldi-io-ctrl 209 + - ti,am62p-cpsw-mac-efuse 210 + - ti,am654-dss-oldi-io-ctrl 211 + - ti,j784s4-pcie-ctrl 212 + - ti,keystone-pllctrl 213 + - const: syscon 102 214 103 215 reg: 104 216 maxItems: 1 105 217 106 - reg-io-width: 107 - description: | 108 - The size (in bytes) of the IO accesses that should be performed 109 - on the device. 110 - enum: [1, 2, 4, 8] 111 - 112 218 resets: 113 219 maxItems: 1 114 - 115 - hwlocks: 116 - maxItems: 1 117 - description: 118 - Reference to a phandle of a hardware spinlock provider node. 119 220 120 221 required: 121 222 - compatible 122 223 - reg 123 224 124 225 allOf: 125 - - if: 126 - properties: 127 - compatible: 128 - contains: 129 - const: simple-mfd 130 - then: 131 - properties: 132 - compatible: 133 - minItems: 3 134 - maxItems: 5 226 + - $ref: syscon-common.yaml# 135 227 136 - additionalProperties: true 228 + unevaluatedProperties: false 137 229 138 230 examples: 139 231 - |
-17
Documentation/devicetree/bindings/mips/mscc.txt
··· 25 25 reg = <0x71070000 0x1c>; 26 26 }; 27 27 28 - 29 - o CPU system control: 30 - 31 - The SoC has a few registers (ICPU_CFG:CPU_SYSTEM_CTRL) handling configuration of 32 - the CPU: 8 general purpose registers, reset control, CPU en/disabling, CPU 33 - endianness, CPU bus control, CPU status. 34 - 35 - Required properties: 36 - - compatible: Should be "mscc,ocelot-cpu-syscon", "syscon" 37 - - reg : Should contain registers location and length 38 - 39 - Example: 40 - syscon@70000000 { 41 - compatible = "mscc,ocelot-cpu-syscon", "syscon"; 42 - reg = <0x70000000 0x2c>; 43 - }; 44 - 45 28 o HSIO regs: 46 29 47 30 The SoC has a few registers (HSIO) handling miscellaneous functionalities:
-9
Documentation/devicetree/bindings/mtd/atmel-nand.txt
··· 60 60 - reg: should contain 2 register ranges. The first one is pointing to the PMECC 61 61 block, and the second one to the PMECC_ERRLOC block. 62 62 63 - * SAMA5 NFC I/O bindings: 64 - 65 - SAMA5 SoCs embed an advanced NAND controller logic to automate READ/WRITE page 66 - operations. This interface to this logic is placed in a separate I/O range and 67 - should thus have its own DT node. 68 - 69 - - compatible: should be "atmel,sama5d3-nfc-io", "syscon". 70 - - reg: should contain the I/O range used to interact with the NFC logic. 71 - 72 63 Example: 73 64 74 65 nfc_io: nfc-io@70000000 {
-10
Documentation/devicetree/bindings/net/hisilicon-hip04-net.txt
··· 19 19 [1] Documentation/devicetree/bindings/net/ethernet.txt 20 20 21 21 22 - * Ethernet ppe node: 23 - Control rx & tx fifos of all ethernet controllers. 24 - Have 2048 recv channels shared by all ethernet controllers, only if no overlap. 25 - Each controller's recv channel start from channel * number (RX_DESC_NUM). 26 - 27 - Required properties: 28 - - compatible: "hisilicon,hip04-ppe", "syscon". 29 - - reg: address and length of the register set for the device. 30 - 31 - 32 22 * MDIO bus node: 33 23 34 24 Required properties:
+63
Documentation/devicetree/bindings/regulator/rohm,bd96801-regulator.yaml
··· 1 + # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/regulator/rohm,bd96801-regulator.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: ROHM BD96801 Power Management Integrated Circuit regulators 8 + 9 + maintainers: 10 + - Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com> 11 + 12 + description: 13 + This module is part of the ROHM BD96801 MFD device. For more details 14 + see Documentation/devicetree/bindings/mfd/rohm,bd96801-pmic.yaml. 15 + 16 + The regulator controller is represented as a sub-node of the PMIC node 17 + on the device tree. 18 + 19 + Regulator nodes should be named to buck_<number> and ldo_<number>. 20 + The valid names for BD96801 regulator nodes are 21 + buck1, buck2, buck3, buck4, ldo5, ldo6, ldo7 22 + 23 + patternProperties: 24 + "^ldo[5-7]$": 25 + type: object 26 + description: 27 + Properties for single LDO regulator. 28 + $ref: regulator.yaml# 29 + 30 + properties: 31 + rohm,initial-voltage-microvolt: 32 + description: 33 + Initial voltage for regulator. Voltage can be tuned +/-150 mV from 34 + this value. NOTE, This can be modified via I2C only when PMIC is in 35 + STBY state. 36 + minimum: 300000 37 + maximum: 3300000 38 + 39 + unevaluatedProperties: false 40 + 41 + "^buck[1-4]$": 42 + type: object 43 + description: 44 + Properties for single BUCK regulator. 45 + $ref: regulator.yaml# 46 + 47 + properties: 48 + rohm,initial-voltage-microvolt: 49 + description: 50 + Initial voltage for regulator. Voltage can be tuned +/-150 mV from 51 + this value. NOTE, This can be modified via I2C only when PMIC is in 52 + STBY state. 53 + minimum: 500000 54 + maximum: 3300000 55 + 56 + rohm,keep-on-stby: 57 + description: 58 + Keep the regulator powered when PMIC transitions to STBY state. 59 + type: boolean 60 + 61 + unevaluatedProperties: false 62 + 63 + additionalProperties: false
+57
Documentation/devicetree/bindings/soc/intel/intel,lgm-syscon.yaml
··· 1 + # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/soc/intel/intel,lgm-syscon.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Intel Lightning Mountain(LGM) Syscon 8 + 9 + maintainers: 10 + - Chuanhua Lei <lchuanhua@maxlinear.com> 11 + - Rahul Tanwar <rtanwar@maxlinear.com> 12 + 13 + properties: 14 + compatible: 15 + items: 16 + - const: intel,lgm-syscon 17 + - const: syscon 18 + 19 + reg: 20 + maxItems: 1 21 + 22 + ranges: true 23 + 24 + "#address-cells": 25 + const: 1 26 + 27 + "#size-cells": 28 + const: 1 29 + 30 + patternProperties: 31 + "^emmc-phy@[0-9a-f]+$": 32 + $ref: /schemas/phy/intel,lgm-emmc-phy.yaml# 33 + 34 + required: 35 + - compatible 36 + - reg 37 + - "#address-cells" 38 + - "#size-cells" 39 + 40 + additionalProperties: false 41 + 42 + examples: 43 + - | 44 + chiptop@e0200000 { 45 + compatible = "intel,lgm-syscon", "syscon"; 46 + reg = <0xe0200000 0x100>; 47 + ranges = <0x0 0xe0200000 0x100>; 48 + #address-cells = <1>; 49 + #size-cells = <1>; 50 + 51 + emmc-phy@a8 { 52 + compatible = "intel,lgm-emmc-phy"; 53 + reg = <0x00a8 0x10>; 54 + clocks = <&emmc>; 55 + #phy-cells = <0>; 56 + }; 57 + };
+49
Documentation/devicetree/bindings/soc/microchip/microchip,sparx5-cpu-syscon.yaml
··· 1 + # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/soc/microchip/microchip,sparx5-cpu-syscon.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Microchip Sparx5 CPU Syscon 8 + 9 + maintainers: 10 + - Lars Povlsen <lars.povlsen@microchip.com> 11 + 12 + properties: 13 + compatible: 14 + items: 15 + - const: microchip,sparx5-cpu-syscon 16 + - const: syscon 17 + - const: simple-mfd 18 + 19 + reg: 20 + maxItems: 1 21 + 22 + mux-controller: 23 + $ref: /schemas/mux/reg-mux.yaml# 24 + 25 + required: 26 + - compatible 27 + - reg 28 + - mux-controller 29 + 30 + additionalProperties: false 31 + 32 + examples: 33 + - | 34 + soc { 35 + #address-cells = <2>; 36 + #size-cells = <1>; 37 + 38 + syscon@600000000 { 39 + compatible = "microchip,sparx5-cpu-syscon", "syscon", 40 + "simple-mfd"; 41 + reg = <0x6 0x00000000 0xd0>; 42 + 43 + mux: mux-controller { 44 + compatible = "mmio-mux"; 45 + #mux-control-cells = <1>; 46 + mux-reg-masks = <0x88 0xf0>; 47 + }; 48 + }; 49 + };
+55
Documentation/devicetree/bindings/soc/sprd/sprd,sc9863a-glbregs.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/soc/sprd/sprd,sc9863a-glbregs.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: SC9863A Syscon 8 + 9 + maintainers: 10 + - Orson Zhai <orsonzhai@gmail.com> 11 + - Baolin Wang <baolin.wang7@gmail.com> 12 + - Chunyan Zhang <zhang.lyra@gmail.com> 13 + 14 + properties: 15 + compatible: 16 + items: 17 + - const: sprd,sc9863a-glbregs 18 + - const: syscon 19 + - const: simple-mfd 20 + 21 + reg: 22 + maxItems: 1 23 + 24 + ranges: true 25 + 26 + "#address-cells": 27 + const: 1 28 + 29 + "#size-cells": 30 + const: 1 31 + 32 + patternProperties: 33 + "@[0-9a-f]+$": 34 + $ref: /schemas/clock/sprd,sc9863a-clk.yaml 35 + description: Clock controllers 36 + 37 + additionalProperties: false 38 + 39 + examples: 40 + - | 41 + syscon@20e00000 { 42 + compatible = "sprd,sc9863a-glbregs", "syscon", "simple-mfd"; 43 + reg = <0x20e00000 0x4000>; 44 + ranges = <0 0x20e00000 0x4000>; 45 + #address-cells = <1>; 46 + #size-cells = <1>; 47 + 48 + apahb_gate: apahb-gate@0 { 49 + compatible = "sprd,sc9863a-apahb-gate"; 50 + reg = <0x0 0x1020>; 51 + #clock-cells = <1>; 52 + }; 53 + }; 54 + 55 + ...
+42
Documentation/devicetree/bindings/soc/ti/ti,am654-serdes-ctrl.yaml
··· 1 + # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/soc/ti/ti,am654-serdes-ctrl.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Texas Instruments AM654 Serdes Control Syscon 8 + 9 + maintainers: 10 + - Nishanth Menon <nm@ti.com> 11 + 12 + properties: 13 + compatible: 14 + items: 15 + - const: ti,am654-serdes-ctrl 16 + - const: syscon 17 + 18 + reg: 19 + maxItems: 1 20 + 21 + mux-controller: 22 + $ref: /schemas/mux/reg-mux.yaml# 23 + 24 + required: 25 + - compatible 26 + - reg 27 + - mux-controller 28 + 29 + additionalProperties: false 30 + 31 + examples: 32 + - | 33 + clock@4080 { 34 + compatible = "ti,am654-serdes-ctrl", "syscon"; 35 + reg = <0x4080 0x4>; 36 + 37 + mux-controller { 38 + compatible = "mmio-mux"; 39 + #mux-control-cells = <1>; 40 + mux-reg-masks = <0x0 0x3>; /* lane select */ 41 + }; 42 + };
+31 -1
MAINTAINERS
··· 5213 5213 F: Documentation/hwmon/cros_ec_hwmon.rst 5214 5214 F: drivers/hwmon/cros_ec_hwmon.c 5215 5215 5216 + CHROMEOS EC LED DRIVER 5217 + M: Thomas Weißschuh <thomas@weissschuh.net> 5218 + S: Maintained 5219 + F: drivers/leds/leds-cros_ec.c 5220 + 5216 5221 CHROMEOS EC SUBDRIVERS 5217 5222 M: Benson Leung <bleung@chromium.org> 5218 5223 R: Guenter Roeck <groeck@chromium.org> ··· 5288 5283 F: sound/pci/hda/hda_component* 5289 5284 F: sound/pci/hda/hda_cs_dsp_ctl.* 5290 5285 F: sound/soc/codecs/cs* 5286 + 5287 + CIRRUS LOGIC HAPTIC DRIVERS 5288 + M: James Ogletree <jogletre@opensource.cirrus.com> 5289 + M: Fred Treven <fred.treven@cirrus.com> 5290 + M: Ben Bright <ben.bright@cirrus.com> 5291 + L: patches@opensource.cirrus.com 5292 + S: Supported 5293 + F: Documentation/devicetree/bindings/input/cirrus,cs40l50.yaml 5294 + F: drivers/input/misc/cs40l* 5295 + F: drivers/mfd/cs40l* 5296 + F: include/linux/mfd/cs40l* 5297 + F: sound/soc/codecs/cs40l* 5291 5298 5292 5299 CIRRUS LOGIC DSP FIRMWARE DRIVER 5293 5300 M: Simon Trimmer <simont@opensource.cirrus.com> ··· 13404 13387 F: include/linux/dsa/mv88e6xxx.h 13405 13388 F: include/linux/platform_data/mv88e6xxx.h 13406 13389 13390 + MARVELL 88PM886 PMIC DRIVER 13391 + M: Karel Balej <balejk@matfyz.cz> 13392 + S: Maintained 13393 + F: Documentation/devicetree/bindings/mfd/marvell,88pm886-a1.yaml 13394 + F: drivers/input/misc/88pm886-onkey.c 13395 + F: drivers/mfd/88pm886.c 13396 + F: drivers/regulators/88pm886-regulator.c 13397 + F: include/linux/mfd/88pm886.h 13398 + 13407 13399 MARVELL ARMADA 3700 PHY DRIVERS 13408 13400 M: Miquel Raynal <miquel.raynal@bootlin.com> 13409 13401 S: Maintained ··· 19633 19607 F: drivers/mfd/rohm-bd71828.c 19634 19608 F: drivers/mfd/rohm-bd718x7.c 19635 19609 F: drivers/mfd/rohm-bd9576.c 19610 + F: drivers/mfd/rohm-bd96801.c 19636 19611 F: drivers/regulator/bd71815-regulator.c 19637 19612 F: drivers/regulator/bd71828-regulator.c 19638 19613 F: drivers/regulator/bd718x7-regulator.c 19639 19614 F: drivers/regulator/bd9576-regulator.c 19615 + F: drivers/regulator/bd96801-regulator.c 19640 19616 F: drivers/regulator/rohm-regulator.c 19641 19617 F: drivers/rtc/rtc-bd70528.c 19642 19618 F: drivers/watchdog/bd9576_wdt.c 19619 + F: drivers/watchdog/bd96801_wdt.c 19643 19620 F: include/linux/mfd/rohm-bd71815.h 19644 19621 F: include/linux/mfd/rohm-bd71828.h 19645 19622 F: include/linux/mfd/rohm-bd718x7.h 19646 19623 F: include/linux/mfd/rohm-bd957x.h 19624 + F: include/linux/mfd/rohm-bd96801.h 19647 19625 F: include/linux/mfd/rohm-generic.h 19648 19626 F: include/linux/mfd/rohm-shared.h 19649 19627 ··· 22852 22822 S: Supported 22853 22823 F: drivers/mmc/host/renesas_sdhi* 22854 22824 F: drivers/mmc/host/tmio_mmc* 22855 - F: include/linux/mfd/tmio.h 22825 + F: include/linux/platform_data/tmio.h 22856 22826 22857 22827 TMP513 HARDWARE MONITOR DRIVER 22858 22828 M: Eric Tremblay <etremblay@distech-controls.com>
+1 -1
arch/sh/boards/board-sh7757lcr.c
··· 14 14 #include <linux/spi/spi.h> 15 15 #include <linux/spi/flash.h> 16 16 #include <linux/io.h> 17 - #include <linux/mfd/tmio.h> 18 17 #include <linux/mmc/host.h> 19 18 #include <linux/platform_data/sh_mmcif.h> 19 + #include <linux/platform_data/tmio.h> 20 20 #include <linux/sh_eth.h> 21 21 #include <linux/sh_intc.h> 22 22 #include <linux/usb/renesas_usbhs.h>
+1 -1
arch/sh/boards/mach-ap325rxa/setup.c
··· 24 24 #include <linux/init.h> 25 25 #include <linux/interrupt.h> 26 26 #include <linux/memblock.h> 27 - #include <linux/mfd/tmio.h> 28 27 #include <linux/mmc/host.h> 29 28 #include <linux/mtd/physmap.h> 30 29 #include <linux/mtd/sh_flctl.h> 30 + #include <linux/platform_data/tmio.h> 31 31 #include <linux/platform_device.h> 32 32 #include <linux/regulator/fixed.h> 33 33 #include <linux/regulator/machine.h>
+1 -1
arch/sh/boards/mach-ecovec24/setup.c
··· 17 17 #include <linux/input/sh_keysc.h> 18 18 #include <linux/interrupt.h> 19 19 #include <linux/memblock.h> 20 - #include <linux/mfd/tmio.h> 21 20 #include <linux/mmc/host.h> 22 21 #include <linux/platform_data/sh_mmcif.h> 23 22 #include <linux/mtd/physmap.h> 24 23 #include <linux/gpio.h> 25 24 #include <linux/gpio/machine.h> 26 25 #include <linux/platform_data/gpio_backlight.h> 26 + #include <linux/platform_data/tmio.h> 27 27 #include <linux/platform_data/tsc2007.h> 28 28 #include <linux/platform_device.h> 29 29 #include <linux/regulator/fixed.h>
+1 -1
arch/sh/boards/mach-kfr2r09/setup.c
··· 22 22 #include <linux/input/sh_keysc.h> 23 23 #include <linux/interrupt.h> 24 24 #include <linux/memblock.h> 25 - #include <linux/mfd/tmio.h> 26 25 #include <linux/mmc/host.h> 27 26 #include <linux/mtd/physmap.h> 28 27 #include <linux/platform_data/lv5207lp.h> 28 + #include <linux/platform_data/tmio.h> 29 29 #include <linux/platform_device.h> 30 30 #include <linux/regulator/fixed.h> 31 31 #include <linux/regulator/machine.h>
+1 -1
arch/sh/boards/mach-migor/setup.c
··· 7 7 #include <linux/clkdev.h> 8 8 #include <linux/dma-map-ops.h> 9 9 #include <linux/init.h> 10 + #include <linux/platform_data/tmio.h> 10 11 #include <linux/platform_device.h> 11 12 #include <linux/interrupt.h> 12 13 #include <linux/input.h> ··· 15 14 #include <linux/memblock.h> 16 15 #include <linux/mmc/host.h> 17 16 #include <linux/mtd/physmap.h> 18 - #include <linux/mfd/tmio.h> 19 17 #include <linux/mtd/platnand.h> 20 18 #include <linux/i2c.h> 21 19 #include <linux/regulator/fixed.h>
+1 -1
arch/sh/boards/mach-se/7724/setup.c
··· 21 21 #include <linux/input/sh_keysc.h> 22 22 #include <linux/interrupt.h> 23 23 #include <linux/memblock.h> 24 - #include <linux/mfd/tmio.h> 25 24 #include <linux/mmc/host.h> 26 25 #include <linux/mtd/physmap.h> 26 + #include <linux/platform_data/tmio.h> 27 27 #include <linux/platform_device.h> 28 28 #include <linux/regulator/fixed.h> 29 29 #include <linux/regulator/machine.h>
+278
drivers/firmware/cirrus/cs_dsp.c
··· 275 275 #define HALO_MPU_VIO_ERR_SRC_MASK 0x00007fff 276 276 #define HALO_MPU_VIO_ERR_SRC_SHIFT 0 277 277 278 + /* 279 + * Write Sequence 280 + */ 281 + #define WSEQ_OP_MAX_WORDS 3 282 + #define WSEQ_END_OF_SCRIPT 0xFFFFFF 283 + 278 284 struct cs_dsp_ops { 279 285 bool (*validate_version)(struct cs_dsp *dsp, unsigned int version); 280 286 unsigned int (*parse_sizes)(struct cs_dsp *dsp, ··· 3500 3494 return result; 3501 3495 } 3502 3496 EXPORT_SYMBOL_NS_GPL(cs_dsp_chunk_read, FW_CS_DSP); 3497 + 3498 + 3499 + struct cs_dsp_wseq_op { 3500 + struct list_head list; 3501 + u32 address; 3502 + u32 data; 3503 + u16 offset; 3504 + u8 operation; 3505 + }; 3506 + 3507 + static void cs_dsp_wseq_clear(struct cs_dsp *dsp, struct cs_dsp_wseq *wseq) 3508 + { 3509 + struct cs_dsp_wseq_op *op, *op_tmp; 3510 + 3511 + list_for_each_entry_safe(op, op_tmp, &wseq->ops, list) { 3512 + list_del(&op->list); 3513 + devm_kfree(dsp->dev, op); 3514 + } 3515 + } 3516 + 3517 + static int cs_dsp_populate_wseq(struct cs_dsp *dsp, struct cs_dsp_wseq *wseq) 3518 + { 3519 + struct cs_dsp_wseq_op *op = NULL; 3520 + struct cs_dsp_chunk chunk; 3521 + u8 *words; 3522 + int ret; 3523 + 3524 + if (!wseq->ctl) { 3525 + cs_dsp_err(dsp, "No control for write sequence\n"); 3526 + return -EINVAL; 3527 + } 3528 + 3529 + words = kzalloc(wseq->ctl->len, GFP_KERNEL); 3530 + if (!words) 3531 + return -ENOMEM; 3532 + 3533 + ret = cs_dsp_coeff_read_ctrl(wseq->ctl, 0, words, wseq->ctl->len); 3534 + if (ret) { 3535 + cs_dsp_err(dsp, "Failed to read %s: %d\n", wseq->ctl->subname, ret); 3536 + goto err_free; 3537 + } 3538 + 3539 + INIT_LIST_HEAD(&wseq->ops); 3540 + 3541 + chunk = cs_dsp_chunk(words, wseq->ctl->len); 3542 + 3543 + while (!cs_dsp_chunk_end(&chunk)) { 3544 + op = devm_kzalloc(dsp->dev, sizeof(*op), GFP_KERNEL); 3545 + if (!op) { 3546 + ret = -ENOMEM; 3547 + goto err_free; 3548 + } 3549 + 3550 + op->offset = cs_dsp_chunk_bytes(&chunk); 3551 + op->operation = cs_dsp_chunk_read(&chunk, 8); 3552 + 3553 + switch (op->operation) { 3554 + case CS_DSP_WSEQ_END: 3555 + op->data = WSEQ_END_OF_SCRIPT; 3556 + break; 3557 + case CS_DSP_WSEQ_UNLOCK: 3558 + op->data = cs_dsp_chunk_read(&chunk, 16); 3559 + break; 3560 + case CS_DSP_WSEQ_ADDR8: 3561 + op->address = cs_dsp_chunk_read(&chunk, 8); 3562 + op->data = cs_dsp_chunk_read(&chunk, 32); 3563 + break; 3564 + case CS_DSP_WSEQ_H16: 3565 + case CS_DSP_WSEQ_L16: 3566 + op->address = cs_dsp_chunk_read(&chunk, 24); 3567 + op->data = cs_dsp_chunk_read(&chunk, 16); 3568 + break; 3569 + case CS_DSP_WSEQ_FULL: 3570 + op->address = cs_dsp_chunk_read(&chunk, 32); 3571 + op->data = cs_dsp_chunk_read(&chunk, 32); 3572 + break; 3573 + default: 3574 + ret = -EINVAL; 3575 + cs_dsp_err(dsp, "Unsupported op: %X\n", op->operation); 3576 + devm_kfree(dsp->dev, op); 3577 + goto err_free; 3578 + } 3579 + 3580 + list_add_tail(&op->list, &wseq->ops); 3581 + 3582 + if (op->operation == CS_DSP_WSEQ_END) 3583 + break; 3584 + } 3585 + 3586 + if (op && op->operation != CS_DSP_WSEQ_END) { 3587 + cs_dsp_err(dsp, "%s missing end terminator\n", wseq->ctl->subname); 3588 + ret = -ENOENT; 3589 + } 3590 + 3591 + err_free: 3592 + kfree(words); 3593 + 3594 + return ret; 3595 + } 3596 + 3597 + /** 3598 + * cs_dsp_wseq_init() - Initialize write sequences contained within the loaded DSP firmware 3599 + * @dsp: Pointer to DSP structure 3600 + * @wseqs: List of write sequences to initialize 3601 + * @num_wseqs: Number of write sequences to initialize 3602 + * 3603 + * Return: Zero for success, a negative number on error. 3604 + */ 3605 + int cs_dsp_wseq_init(struct cs_dsp *dsp, struct cs_dsp_wseq *wseqs, unsigned int num_wseqs) 3606 + { 3607 + int i, ret; 3608 + 3609 + lockdep_assert_held(&dsp->pwr_lock); 3610 + 3611 + for (i = 0; i < num_wseqs; i++) { 3612 + ret = cs_dsp_populate_wseq(dsp, &wseqs[i]); 3613 + if (ret) { 3614 + cs_dsp_wseq_clear(dsp, &wseqs[i]); 3615 + return ret; 3616 + } 3617 + } 3618 + 3619 + return 0; 3620 + } 3621 + EXPORT_SYMBOL_NS_GPL(cs_dsp_wseq_init, FW_CS_DSP); 3622 + 3623 + static struct cs_dsp_wseq_op *cs_dsp_wseq_find_op(u32 addr, u8 op_code, 3624 + struct list_head *wseq_ops) 3625 + { 3626 + struct cs_dsp_wseq_op *op; 3627 + 3628 + list_for_each_entry(op, wseq_ops, list) { 3629 + if (op->operation == op_code && op->address == addr) 3630 + return op; 3631 + } 3632 + 3633 + return NULL; 3634 + } 3635 + 3636 + /** 3637 + * cs_dsp_wseq_write() - Add or update an entry in a write sequence 3638 + * @dsp: Pointer to a DSP structure 3639 + * @wseq: Write sequence to write to 3640 + * @addr: Address of the register to be written to 3641 + * @data: Data to be written 3642 + * @op_code: The type of operation of the new entry 3643 + * @update: If true, searches for the first entry in the write sequence with 3644 + * the same address and op_code, and replaces it. If false, creates a new entry 3645 + * at the tail 3646 + * 3647 + * This function formats register address and value pairs into the format 3648 + * required for write sequence entries, and either updates or adds the 3649 + * new entry into the write sequence. 3650 + * 3651 + * If update is set to true and no matching entry is found, it will add a new entry. 3652 + * 3653 + * Return: Zero for success, a negative number on error. 3654 + */ 3655 + int cs_dsp_wseq_write(struct cs_dsp *dsp, struct cs_dsp_wseq *wseq, 3656 + u32 addr, u32 data, u8 op_code, bool update) 3657 + { 3658 + struct cs_dsp_wseq_op *op_end, *op_new = NULL; 3659 + u32 words[WSEQ_OP_MAX_WORDS]; 3660 + struct cs_dsp_chunk chunk; 3661 + int new_op_size, ret; 3662 + 3663 + if (update) 3664 + op_new = cs_dsp_wseq_find_op(addr, op_code, &wseq->ops); 3665 + 3666 + /* If entry to update is not found, treat it as a new operation */ 3667 + if (!op_new) { 3668 + op_end = cs_dsp_wseq_find_op(0, CS_DSP_WSEQ_END, &wseq->ops); 3669 + if (!op_end) { 3670 + cs_dsp_err(dsp, "Missing terminator for %s\n", wseq->ctl->subname); 3671 + return -EINVAL; 3672 + } 3673 + 3674 + op_new = devm_kzalloc(dsp->dev, sizeof(*op_new), GFP_KERNEL); 3675 + if (!op_new) 3676 + return -ENOMEM; 3677 + 3678 + op_new->operation = op_code; 3679 + op_new->address = addr; 3680 + op_new->offset = op_end->offset; 3681 + update = false; 3682 + } 3683 + 3684 + op_new->data = data; 3685 + 3686 + chunk = cs_dsp_chunk(words, sizeof(words)); 3687 + cs_dsp_chunk_write(&chunk, 8, op_new->operation); 3688 + 3689 + switch (op_code) { 3690 + case CS_DSP_WSEQ_FULL: 3691 + cs_dsp_chunk_write(&chunk, 32, op_new->address); 3692 + cs_dsp_chunk_write(&chunk, 32, op_new->data); 3693 + break; 3694 + case CS_DSP_WSEQ_L16: 3695 + case CS_DSP_WSEQ_H16: 3696 + cs_dsp_chunk_write(&chunk, 24, op_new->address); 3697 + cs_dsp_chunk_write(&chunk, 16, op_new->data); 3698 + break; 3699 + default: 3700 + ret = -EINVAL; 3701 + cs_dsp_err(dsp, "Operation %X not supported\n", op_code); 3702 + goto op_new_free; 3703 + } 3704 + 3705 + new_op_size = cs_dsp_chunk_bytes(&chunk); 3706 + 3707 + if (!update) { 3708 + if (wseq->ctl->len - op_end->offset < new_op_size) { 3709 + cs_dsp_err(dsp, "Not enough memory in %s for entry\n", wseq->ctl->subname); 3710 + ret = -E2BIG; 3711 + goto op_new_free; 3712 + } 3713 + 3714 + op_end->offset += new_op_size; 3715 + 3716 + ret = cs_dsp_coeff_write_ctrl(wseq->ctl, op_end->offset / sizeof(u32), 3717 + &op_end->data, sizeof(u32)); 3718 + if (ret) 3719 + goto op_new_free; 3720 + 3721 + list_add_tail(&op_new->list, &op_end->list); 3722 + } 3723 + 3724 + ret = cs_dsp_coeff_write_ctrl(wseq->ctl, op_new->offset / sizeof(u32), 3725 + words, new_op_size); 3726 + if (ret) 3727 + goto op_new_free; 3728 + 3729 + return 0; 3730 + 3731 + op_new_free: 3732 + devm_kfree(dsp->dev, op_new); 3733 + 3734 + return ret; 3735 + } 3736 + EXPORT_SYMBOL_NS_GPL(cs_dsp_wseq_write, FW_CS_DSP); 3737 + 3738 + /** 3739 + * cs_dsp_wseq_multi_write() - Add or update multiple entries in a write sequence 3740 + * @dsp: Pointer to a DSP structure 3741 + * @wseq: Write sequence to write to 3742 + * @reg_seq: List of address-data pairs 3743 + * @num_regs: Number of address-data pairs 3744 + * @op_code: The types of operations of the new entries 3745 + * @update: If true, searches for the first entry in the write sequence with 3746 + * the same address and op_code, and replaces it. If false, creates a new entry 3747 + * at the tail 3748 + * 3749 + * This function calls cs_dsp_wseq_write() for multiple address-data pairs. 3750 + * 3751 + * Return: Zero for success, a negative number on error. 3752 + */ 3753 + int cs_dsp_wseq_multi_write(struct cs_dsp *dsp, struct cs_dsp_wseq *wseq, 3754 + const struct reg_sequence *reg_seq, int num_regs, 3755 + u8 op_code, bool update) 3756 + { 3757 + int i, ret; 3758 + 3759 + for (i = 0; i < num_regs; i++) { 3760 + ret = cs_dsp_wseq_write(dsp, wseq, reg_seq[i].reg, 3761 + reg_seq[i].def, op_code, update); 3762 + if (ret) 3763 + return ret; 3764 + } 3765 + 3766 + return 0; 3767 + } 3768 + EXPORT_SYMBOL_NS_GPL(cs_dsp_wseq_multi_write, FW_CS_DSP); 3503 3769 3504 3770 MODULE_DESCRIPTION("Cirrus Logic DSP Support"); 3505 3771 MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
+98
drivers/input/misc/88pm886-onkey.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + #include <linux/input.h> 3 + #include <linux/interrupt.h> 4 + #include <linux/irq.h> 5 + #include <linux/platform_device.h> 6 + #include <linux/regmap.h> 7 + 8 + #include <linux/mfd/88pm886.h> 9 + 10 + struct pm886_onkey { 11 + struct input_dev *idev; 12 + struct pm886_chip *chip; 13 + }; 14 + 15 + static irqreturn_t pm886_onkey_irq_handler(int irq, void *data) 16 + { 17 + struct pm886_onkey *onkey = data; 18 + struct regmap *regmap = onkey->chip->regmap; 19 + struct input_dev *idev = onkey->idev; 20 + struct device *parent = idev->dev.parent; 21 + unsigned int val; 22 + int err; 23 + 24 + err = regmap_read(regmap, PM886_REG_STATUS1, &val); 25 + if (err) { 26 + dev_err(parent, "Failed to read status: %d\n", err); 27 + return IRQ_NONE; 28 + } 29 + val &= PM886_ONKEY_STS1; 30 + 31 + input_report_key(idev, KEY_POWER, val); 32 + input_sync(idev); 33 + 34 + return IRQ_HANDLED; 35 + } 36 + 37 + static int pm886_onkey_probe(struct platform_device *pdev) 38 + { 39 + struct pm886_chip *chip = dev_get_drvdata(pdev->dev.parent); 40 + struct device *dev = &pdev->dev; 41 + struct pm886_onkey *onkey; 42 + struct input_dev *idev; 43 + int irq, err; 44 + 45 + onkey = devm_kzalloc(dev, sizeof(*onkey), GFP_KERNEL); 46 + if (!onkey) 47 + return -ENOMEM; 48 + 49 + onkey->chip = chip; 50 + 51 + irq = platform_get_irq(pdev, 0); 52 + if (irq < 0) 53 + return dev_err_probe(dev, irq, "Failed to get IRQ\n"); 54 + 55 + idev = devm_input_allocate_device(dev); 56 + if (!idev) { 57 + dev_err(dev, "Failed to allocate input device\n"); 58 + return -ENOMEM; 59 + } 60 + onkey->idev = idev; 61 + 62 + idev->name = "88pm886-onkey"; 63 + idev->phys = "88pm886-onkey/input0"; 64 + idev->id.bustype = BUS_I2C; 65 + 66 + input_set_capability(idev, EV_KEY, KEY_POWER); 67 + 68 + err = devm_request_threaded_irq(dev, irq, NULL, pm886_onkey_irq_handler, 69 + IRQF_ONESHOT | IRQF_NO_SUSPEND, "onkey", 70 + onkey); 71 + if (err) 72 + return dev_err_probe(dev, err, "Failed to request IRQ\n"); 73 + 74 + err = input_register_device(idev); 75 + if (err) 76 + return dev_err_probe(dev, err, "Failed to register input device\n"); 77 + 78 + return 0; 79 + } 80 + 81 + static const struct platform_device_id pm886_onkey_id_table[] = { 82 + { "88pm886-onkey", }, 83 + { } 84 + }; 85 + MODULE_DEVICE_TABLE(platform, pm886_onkey_id_table); 86 + 87 + static struct platform_driver pm886_onkey_driver = { 88 + .driver = { 89 + .name = "88pm886-onkey", 90 + }, 91 + .probe = pm886_onkey_probe, 92 + .id_table = pm886_onkey_id_table, 93 + }; 94 + module_platform_driver(pm886_onkey_driver); 95 + 96 + MODULE_DESCRIPTION("Marvell 88PM886 onkey driver"); 97 + MODULE_AUTHOR("Karel Balej <balejk@matfyz.cz>"); 98 + MODULE_LICENSE("GPL");
+17
drivers/input/misc/Kconfig
··· 33 33 To compile this driver as a module, choose M here: the module 34 34 will be called 88pm80x_onkey. 35 35 36 + config INPUT_88PM886_ONKEY 37 + tristate "Marvell 88PM886 onkey support" 38 + depends on MFD_88PM886_PMIC 39 + help 40 + Support the onkey of Marvell 88PM886 PMIC as an input device 41 + reporting power button status. 42 + 36 43 config INPUT_AB8500_PONKEY 37 44 tristate "AB8500 Pon (PowerOn) Key" 38 45 depends on AB8500_CORE ··· 146 139 147 140 To compile this driver as a module, choose M here: the 148 141 module will be called bma150. 142 + 143 + config INPUT_CS40L50_VIBRA 144 + tristate "CS40L50 Haptic Driver support" 145 + depends on MFD_CS40L50_CORE 146 + help 147 + Say Y here to enable support for Cirrus Logic's CS40L50 148 + haptic driver. 149 + 150 + To compile this driver as a module, choose M here: the 151 + module will be called cs40l50-vibra. 149 152 150 153 config INPUT_E3X0_BUTTON 151 154 tristate "NI Ettus Research USRP E3xx Button support."
+2
drivers/input/misc/Makefile
··· 7 7 8 8 obj-$(CONFIG_INPUT_88PM860X_ONKEY) += 88pm860x_onkey.o 9 9 obj-$(CONFIG_INPUT_88PM80X_ONKEY) += 88pm80x_onkey.o 10 + obj-$(CONFIG_INPUT_88PM886_ONKEY) += 88pm886-onkey.o 10 11 obj-$(CONFIG_INPUT_AB8500_PONKEY) += ab8500-ponkey.o 11 12 obj-$(CONFIG_INPUT_AD714X) += ad714x.o 12 13 obj-$(CONFIG_INPUT_AD714X_I2C) += ad714x-i2c.o ··· 29 28 obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o 30 29 obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o 31 30 obj-$(CONFIG_INPUT_CPCAP_PWRBUTTON) += cpcap-pwrbutton.o 31 + obj-$(CONFIG_INPUT_CS40L50_VIBRA) += cs40l50-vibra.o 32 32 obj-$(CONFIG_INPUT_DA7280_HAPTICS) += da7280.o 33 33 obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o 34 34 obj-$(CONFIG_INPUT_DA9055_ONKEY) += da9055_onkey.o
+555
drivers/input/misc/cs40l50-vibra.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * CS40L50 Advanced Haptic Driver with waveform memory, 4 + * integrated DSP, and closed-loop algorithms 5 + * 6 + * Copyright 2024 Cirrus Logic, Inc. 7 + * 8 + * Author: James Ogletree <james.ogletree@cirrus.com> 9 + */ 10 + 11 + #include <linux/bitfield.h> 12 + #include <linux/input.h> 13 + #include <linux/mfd/cs40l50.h> 14 + #include <linux/platform_device.h> 15 + #include <linux/pm_runtime.h> 16 + 17 + /* Wavetables */ 18 + #define CS40L50_RAM_INDEX_START 0x1000000 19 + #define CS40L50_RAM_INDEX_END 0x100007F 20 + #define CS40L50_RTH_INDEX_START 0x1400000 21 + #define CS40L50_RTH_INDEX_END 0x1400001 22 + #define CS40L50_ROM_INDEX_START 0x1800000 23 + #define CS40L50_ROM_INDEX_END 0x180001A 24 + #define CS40L50_TYPE_PCM 8 25 + #define CS40L50_TYPE_PWLE 12 26 + #define CS40L50_PCM_ID 0x0 27 + #define CS40L50_OWT_CUSTOM_DATA_SIZE 2 28 + #define CS40L50_CUSTOM_DATA_MASK 0xFFFFU 29 + 30 + /* DSP */ 31 + #define CS40L50_GPIO_BASE 0x2804140 32 + #define CS40L50_OWT_BASE 0x2805C34 33 + #define CS40L50_OWT_SIZE 0x2805C38 34 + #define CS40L50_OWT_NEXT 0x2805C3C 35 + #define CS40L50_EFFECTS_MAX 1 36 + 37 + /* GPIO */ 38 + #define CS40L50_GPIO_NUM_MASK GENMASK(14, 12) 39 + #define CS40L50_GPIO_EDGE_MASK BIT(15) 40 + #define CS40L50_GPIO_MAPPING_NONE 0 41 + #define CS40L50_GPIO_DISABLE 0x1FF 42 + 43 + enum cs40l50_bank_type { 44 + CS40L50_WVFRM_BANK_RAM, 45 + CS40L50_WVFRM_BANK_ROM, 46 + CS40L50_WVFRM_BANK_OWT, 47 + CS40L50_WVFRM_BANK_NUM, 48 + }; 49 + 50 + /* Describes an area in DSP memory populated by effects */ 51 + struct cs40l50_bank { 52 + enum cs40l50_bank_type type; 53 + u32 base_index; 54 + u32 max_index; 55 + }; 56 + 57 + struct cs40l50_effect { 58 + enum cs40l50_bank_type type; 59 + struct list_head list; 60 + u32 gpio_reg; 61 + u32 index; 62 + int id; 63 + }; 64 + 65 + /* Describes haptic interface of loaded DSP firmware */ 66 + struct cs40l50_vibra_dsp { 67 + struct cs40l50_bank *banks; 68 + u32 gpio_base_reg; 69 + u32 owt_offset_reg; 70 + u32 owt_size_reg; 71 + u32 owt_base_reg; 72 + u32 push_owt_cmd; 73 + u32 delete_owt_cmd; 74 + u32 stop_cmd; 75 + int (*write)(struct device *dev, struct regmap *regmap, u32 val); 76 + }; 77 + 78 + /* Describes configuration and state of haptic operations */ 79 + struct cs40l50_vibra { 80 + struct device *dev; 81 + struct regmap *regmap; 82 + struct input_dev *input; 83 + struct workqueue_struct *vib_wq; 84 + struct list_head effect_head; 85 + struct cs40l50_vibra_dsp dsp; 86 + }; 87 + 88 + struct cs40l50_work { 89 + struct cs40l50_vibra *vib; 90 + struct ff_effect *effect; 91 + struct work_struct work; 92 + s16 *custom_data; 93 + int custom_len; 94 + int count; 95 + int error; 96 + }; 97 + 98 + static struct cs40l50_bank cs40l50_banks[] = { 99 + { 100 + .type = CS40L50_WVFRM_BANK_RAM, 101 + .base_index = CS40L50_RAM_INDEX_START, 102 + .max_index = CS40L50_RAM_INDEX_END, 103 + }, 104 + { 105 + .type = CS40L50_WVFRM_BANK_ROM, 106 + .base_index = CS40L50_ROM_INDEX_START, 107 + .max_index = CS40L50_ROM_INDEX_END, 108 + }, 109 + { 110 + .type = CS40L50_WVFRM_BANK_OWT, 111 + .base_index = CS40L50_RTH_INDEX_START, 112 + .max_index = CS40L50_RTH_INDEX_END, 113 + }, 114 + }; 115 + 116 + static struct cs40l50_vibra_dsp cs40l50_dsp = { 117 + .banks = cs40l50_banks, 118 + .gpio_base_reg = CS40L50_GPIO_BASE, 119 + .owt_base_reg = CS40L50_OWT_BASE, 120 + .owt_offset_reg = CS40L50_OWT_NEXT, 121 + .owt_size_reg = CS40L50_OWT_SIZE, 122 + .push_owt_cmd = CS40L50_OWT_PUSH, 123 + .delete_owt_cmd = CS40L50_OWT_DELETE, 124 + .stop_cmd = CS40L50_STOP_PLAYBACK, 125 + .write = cs40l50_dsp_write, 126 + }; 127 + 128 + static struct cs40l50_effect *cs40l50_find_effect(int id, struct list_head *effect_head) 129 + { 130 + struct cs40l50_effect *effect; 131 + 132 + list_for_each_entry(effect, effect_head, list) 133 + if (effect->id == id) 134 + return effect; 135 + 136 + return NULL; 137 + } 138 + 139 + static int cs40l50_effect_bank_set(struct cs40l50_work *work_data, 140 + struct cs40l50_effect *effect) 141 + { 142 + s16 bank_type = work_data->custom_data[0] & CS40L50_CUSTOM_DATA_MASK; 143 + 144 + if (bank_type >= CS40L50_WVFRM_BANK_NUM) { 145 + dev_err(work_data->vib->dev, "Invalid bank (%d)\n", bank_type); 146 + return -EINVAL; 147 + } 148 + 149 + if (work_data->custom_len > CS40L50_OWT_CUSTOM_DATA_SIZE) 150 + effect->type = CS40L50_WVFRM_BANK_OWT; 151 + else 152 + effect->type = bank_type; 153 + 154 + return 0; 155 + } 156 + 157 + static int cs40l50_effect_index_set(struct cs40l50_work *work_data, 158 + struct cs40l50_effect *effect) 159 + { 160 + struct cs40l50_vibra *vib = work_data->vib; 161 + struct cs40l50_effect *owt_effect; 162 + u32 base_index, max_index; 163 + 164 + base_index = vib->dsp.banks[effect->type].base_index; 165 + max_index = vib->dsp.banks[effect->type].max_index; 166 + 167 + effect->index = base_index; 168 + 169 + switch (effect->type) { 170 + case CS40L50_WVFRM_BANK_OWT: 171 + list_for_each_entry(owt_effect, &vib->effect_head, list) 172 + if (owt_effect->type == CS40L50_WVFRM_BANK_OWT) 173 + effect->index++; 174 + break; 175 + case CS40L50_WVFRM_BANK_ROM: 176 + case CS40L50_WVFRM_BANK_RAM: 177 + effect->index += work_data->custom_data[1] & CS40L50_CUSTOM_DATA_MASK; 178 + break; 179 + default: 180 + dev_err(vib->dev, "Bank type %d not supported\n", effect->type); 181 + return -EINVAL; 182 + } 183 + 184 + if (effect->index > max_index || effect->index < base_index) { 185 + dev_err(vib->dev, "Index out of bounds: %u\n", effect->index); 186 + return -ENOSPC; 187 + } 188 + 189 + return 0; 190 + } 191 + 192 + static int cs40l50_effect_gpio_mapping_set(struct cs40l50_work *work_data, 193 + struct cs40l50_effect *effect) 194 + { 195 + u16 gpio_edge, gpio_num, button = work_data->effect->trigger.button; 196 + struct cs40l50_vibra *vib = work_data->vib; 197 + 198 + if (button) { 199 + gpio_num = FIELD_GET(CS40L50_GPIO_NUM_MASK, button); 200 + gpio_edge = FIELD_GET(CS40L50_GPIO_EDGE_MASK, button); 201 + effect->gpio_reg = vib->dsp.gpio_base_reg + (gpio_num * 8) - gpio_edge; 202 + 203 + return regmap_write(vib->regmap, effect->gpio_reg, button); 204 + } 205 + 206 + effect->gpio_reg = CS40L50_GPIO_MAPPING_NONE; 207 + 208 + return 0; 209 + } 210 + 211 + struct cs40l50_owt_header { 212 + u32 type; 213 + u32 data_words; 214 + u32 offset; 215 + } __packed; 216 + 217 + static int cs40l50_upload_owt(struct cs40l50_work *work_data) 218 + { 219 + u8 *new_owt_effect_data __free(kfree) = NULL; 220 + struct cs40l50_vibra *vib = work_data->vib; 221 + size_t len = work_data->custom_len * 2; 222 + struct cs40l50_owt_header header; 223 + u32 offset, size; 224 + int error; 225 + 226 + error = regmap_read(vib->regmap, vib->dsp.owt_size_reg, &size); 227 + if (error) 228 + return error; 229 + 230 + if ((size * sizeof(u32)) < sizeof(header) + len) { 231 + dev_err(vib->dev, "No space in open wavetable for effect\n"); 232 + return -ENOSPC; 233 + } 234 + 235 + header.type = work_data->custom_data[0] == CS40L50_PCM_ID ? CS40L50_TYPE_PCM : 236 + CS40L50_TYPE_PWLE; 237 + header.offset = sizeof(header) / sizeof(u32); 238 + header.data_words = len / sizeof(u32); 239 + 240 + new_owt_effect_data = kmalloc(sizeof(header) + len, GFP_KERNEL); 241 + 242 + memcpy(new_owt_effect_data, &header, sizeof(header)); 243 + memcpy(new_owt_effect_data + sizeof(header), work_data->custom_data, len); 244 + 245 + error = regmap_read(vib->regmap, vib->dsp.owt_offset_reg, &offset); 246 + if (error) 247 + return error; 248 + 249 + error = regmap_bulk_write(vib->regmap, vib->dsp.owt_base_reg + 250 + (offset * sizeof(u32)), new_owt_effect_data, 251 + sizeof(header) + len); 252 + if (error) 253 + return error; 254 + 255 + error = vib->dsp.write(vib->dev, vib->regmap, vib->dsp.push_owt_cmd); 256 + if (error) 257 + return error; 258 + 259 + return 0; 260 + } 261 + 262 + static void cs40l50_add_worker(struct work_struct *work) 263 + { 264 + struct cs40l50_work *work_data = container_of(work, struct cs40l50_work, work); 265 + struct cs40l50_vibra *vib = work_data->vib; 266 + struct cs40l50_effect *effect; 267 + bool is_new = false; 268 + int error; 269 + 270 + error = pm_runtime_resume_and_get(vib->dev); 271 + if (error) 272 + goto err_exit; 273 + 274 + /* Update effect if already uploaded, otherwise create new effect */ 275 + effect = cs40l50_find_effect(work_data->effect->id, &vib->effect_head); 276 + if (!effect) { 277 + effect = kzalloc(sizeof(*effect), GFP_KERNEL); 278 + if (!effect) { 279 + error = -ENOMEM; 280 + goto err_pm; 281 + } 282 + 283 + effect->id = work_data->effect->id; 284 + is_new = true; 285 + } 286 + 287 + error = cs40l50_effect_bank_set(work_data, effect); 288 + if (error) 289 + goto err_free; 290 + 291 + error = cs40l50_effect_index_set(work_data, effect); 292 + if (error) 293 + goto err_free; 294 + 295 + error = cs40l50_effect_gpio_mapping_set(work_data, effect); 296 + if (error) 297 + goto err_free; 298 + 299 + if (effect->type == CS40L50_WVFRM_BANK_OWT) 300 + error = cs40l50_upload_owt(work_data); 301 + err_free: 302 + if (is_new) { 303 + if (error) 304 + kfree(effect); 305 + else 306 + list_add(&effect->list, &vib->effect_head); 307 + } 308 + err_pm: 309 + pm_runtime_mark_last_busy(vib->dev); 310 + pm_runtime_put_autosuspend(vib->dev); 311 + err_exit: 312 + work_data->error = error; 313 + } 314 + 315 + static int cs40l50_add(struct input_dev *dev, struct ff_effect *effect, 316 + struct ff_effect *old) 317 + { 318 + struct ff_periodic_effect *periodic = &effect->u.periodic; 319 + struct cs40l50_vibra *vib = input_get_drvdata(dev); 320 + struct cs40l50_work work_data; 321 + 322 + if (effect->type != FF_PERIODIC || periodic->waveform != FF_CUSTOM) { 323 + dev_err(vib->dev, "Type (%#X) or waveform (%#X) unsupported\n", 324 + effect->type, periodic->waveform); 325 + return -EINVAL; 326 + } 327 + 328 + work_data.custom_data = memdup_array_user(effect->u.periodic.custom_data, 329 + effect->u.periodic.custom_len, 330 + sizeof(s16)); 331 + if (IS_ERR(work_data.custom_data)) 332 + return PTR_ERR(work_data.custom_data); 333 + 334 + work_data.custom_len = effect->u.periodic.custom_len; 335 + work_data.vib = vib; 336 + work_data.effect = effect; 337 + INIT_WORK(&work_data.work, cs40l50_add_worker); 338 + 339 + /* Push to the workqueue to serialize with playbacks */ 340 + queue_work(vib->vib_wq, &work_data.work); 341 + flush_work(&work_data.work); 342 + 343 + kfree(work_data.custom_data); 344 + 345 + return work_data.error; 346 + } 347 + 348 + static void cs40l50_start_worker(struct work_struct *work) 349 + { 350 + struct cs40l50_work *work_data = container_of(work, struct cs40l50_work, work); 351 + struct cs40l50_vibra *vib = work_data->vib; 352 + struct cs40l50_effect *start_effect; 353 + 354 + if (pm_runtime_resume_and_get(vib->dev) < 0) 355 + goto err_free; 356 + 357 + start_effect = cs40l50_find_effect(work_data->effect->id, &vib->effect_head); 358 + if (start_effect) { 359 + while (--work_data->count >= 0) { 360 + vib->dsp.write(vib->dev, vib->regmap, start_effect->index); 361 + usleep_range(work_data->effect->replay.length, 362 + work_data->effect->replay.length + 100); 363 + } 364 + } else { 365 + dev_err(vib->dev, "Effect to play not found\n"); 366 + } 367 + 368 + pm_runtime_mark_last_busy(vib->dev); 369 + pm_runtime_put_autosuspend(vib->dev); 370 + err_free: 371 + kfree(work_data); 372 + } 373 + 374 + static void cs40l50_stop_worker(struct work_struct *work) 375 + { 376 + struct cs40l50_work *work_data = container_of(work, struct cs40l50_work, work); 377 + struct cs40l50_vibra *vib = work_data->vib; 378 + 379 + if (pm_runtime_resume_and_get(vib->dev) < 0) 380 + return; 381 + 382 + vib->dsp.write(vib->dev, vib->regmap, vib->dsp.stop_cmd); 383 + 384 + pm_runtime_mark_last_busy(vib->dev); 385 + pm_runtime_put_autosuspend(vib->dev); 386 + 387 + kfree(work_data); 388 + } 389 + 390 + static int cs40l50_playback(struct input_dev *dev, int effect_id, int val) 391 + { 392 + struct cs40l50_vibra *vib = input_get_drvdata(dev); 393 + struct cs40l50_work *work_data; 394 + 395 + work_data = kzalloc(sizeof(*work_data), GFP_ATOMIC); 396 + if (!work_data) 397 + return -ENOMEM; 398 + 399 + work_data->vib = vib; 400 + 401 + if (val > 0) { 402 + work_data->effect = &dev->ff->effects[effect_id]; 403 + work_data->count = val; 404 + INIT_WORK(&work_data->work, cs40l50_start_worker); 405 + } else { 406 + /* Stop the amplifier as device drives only one effect */ 407 + INIT_WORK(&work_data->work, cs40l50_stop_worker); 408 + } 409 + 410 + queue_work(vib->vib_wq, &work_data->work); 411 + 412 + return 0; 413 + } 414 + 415 + static void cs40l50_erase_worker(struct work_struct *work) 416 + { 417 + struct cs40l50_work *work_data = container_of(work, struct cs40l50_work, work); 418 + struct cs40l50_effect *erase_effect, *owt_effect; 419 + struct cs40l50_vibra *vib = work_data->vib; 420 + int error; 421 + 422 + error = pm_runtime_resume_and_get(vib->dev); 423 + if (error) 424 + goto err_exit; 425 + 426 + erase_effect = cs40l50_find_effect(work_data->effect->id, &vib->effect_head); 427 + if (!erase_effect) { 428 + dev_err(vib->dev, "Effect to erase not found\n"); 429 + error = -EINVAL; 430 + goto err_pm; 431 + } 432 + 433 + if (erase_effect->gpio_reg != CS40L50_GPIO_MAPPING_NONE) { 434 + error = regmap_write(vib->regmap, erase_effect->gpio_reg, 435 + CS40L50_GPIO_DISABLE); 436 + if (error) 437 + goto err_pm; 438 + } 439 + 440 + if (erase_effect->type == CS40L50_WVFRM_BANK_OWT) { 441 + error = vib->dsp.write(vib->dev, vib->regmap, 442 + vib->dsp.delete_owt_cmd | 443 + (erase_effect->index & 0xFF)); 444 + if (error) 445 + goto err_pm; 446 + 447 + list_for_each_entry(owt_effect, &vib->effect_head, list) 448 + if (owt_effect->type == CS40L50_WVFRM_BANK_OWT && 449 + owt_effect->index > erase_effect->index) 450 + owt_effect->index--; 451 + } 452 + 453 + list_del(&erase_effect->list); 454 + kfree(erase_effect); 455 + err_pm: 456 + pm_runtime_mark_last_busy(vib->dev); 457 + pm_runtime_put_autosuspend(vib->dev); 458 + err_exit: 459 + work_data->error = error; 460 + } 461 + 462 + static int cs40l50_erase(struct input_dev *dev, int effect_id) 463 + { 464 + struct cs40l50_vibra *vib = input_get_drvdata(dev); 465 + struct cs40l50_work work_data; 466 + 467 + work_data.vib = vib; 468 + work_data.effect = &dev->ff->effects[effect_id]; 469 + 470 + INIT_WORK(&work_data.work, cs40l50_erase_worker); 471 + 472 + /* Push to workqueue to serialize with playbacks */ 473 + queue_work(vib->vib_wq, &work_data.work); 474 + flush_work(&work_data.work); 475 + 476 + return work_data.error; 477 + } 478 + 479 + static void cs40l50_remove_wq(void *data) 480 + { 481 + flush_workqueue(data); 482 + destroy_workqueue(data); 483 + } 484 + 485 + static int cs40l50_vibra_probe(struct platform_device *pdev) 486 + { 487 + struct cs40l50 *cs40l50 = dev_get_drvdata(pdev->dev.parent); 488 + struct cs40l50_vibra *vib; 489 + int error; 490 + 491 + vib = devm_kzalloc(pdev->dev.parent, sizeof(*vib), GFP_KERNEL); 492 + if (!vib) 493 + return -ENOMEM; 494 + 495 + vib->dev = cs40l50->dev; 496 + vib->regmap = cs40l50->regmap; 497 + vib->dsp = cs40l50_dsp; 498 + 499 + vib->input = devm_input_allocate_device(vib->dev); 500 + if (!vib->input) 501 + return -ENOMEM; 502 + 503 + vib->input->id.product = cs40l50->devid; 504 + vib->input->id.version = cs40l50->revid; 505 + vib->input->name = "cs40l50_vibra"; 506 + 507 + input_set_drvdata(vib->input, vib); 508 + input_set_capability(vib->input, EV_FF, FF_PERIODIC); 509 + input_set_capability(vib->input, EV_FF, FF_CUSTOM); 510 + 511 + error = input_ff_create(vib->input, CS40L50_EFFECTS_MAX); 512 + if (error) { 513 + dev_err(vib->dev, "Failed to create input device\n"); 514 + return error; 515 + } 516 + 517 + vib->input->ff->upload = cs40l50_add; 518 + vib->input->ff->playback = cs40l50_playback; 519 + vib->input->ff->erase = cs40l50_erase; 520 + 521 + INIT_LIST_HEAD(&vib->effect_head); 522 + 523 + vib->vib_wq = alloc_ordered_workqueue("vib_wq", WQ_HIGHPRI); 524 + if (!vib->vib_wq) 525 + return -ENOMEM; 526 + 527 + error = devm_add_action_or_reset(vib->dev, cs40l50_remove_wq, vib->vib_wq); 528 + if (error) 529 + return error; 530 + 531 + error = input_register_device(vib->input); 532 + if (error) 533 + return error; 534 + 535 + return 0; 536 + } 537 + 538 + static const struct platform_device_id cs40l50_vibra_id_match[] = { 539 + { "cs40l50-vibra", }, 540 + {} 541 + }; 542 + MODULE_DEVICE_TABLE(platform, cs40l50_vibra_id_match); 543 + 544 + static struct platform_driver cs40l50_vibra_driver = { 545 + .probe = cs40l50_vibra_probe, 546 + .id_table = cs40l50_vibra_id_match, 547 + .driver = { 548 + .name = "cs40l50-vibra", 549 + }, 550 + }; 551 + module_platform_driver(cs40l50_vibra_driver); 552 + 553 + MODULE_DESCRIPTION("CS40L50 Advanced Haptic Driver"); 554 + MODULE_AUTHOR("James Ogletree, Cirrus Logic Inc. <james.ogletree@cirrus.com>"); 555 + MODULE_LICENSE("GPL");
+15
drivers/leds/Kconfig
··· 179 179 To compile this driver as a module, choose M here: the module 180 180 will be called leds-cr0014114. 181 181 182 + config LEDS_CROS_EC 183 + tristate "LED Support for ChromeOS EC" 184 + depends on MFD_CROS_EC_DEV 185 + depends on LEDS_CLASS_MULTICOLOR 186 + select LEDS_TRIGGERS 187 + default MFD_CROS_EC_DEV 188 + help 189 + This option enables support for LEDs managed by ChromeOS ECs. 190 + All LEDs exposed by the EC are supported in multicolor mode. 191 + A hardware trigger to switch back to the automatic behaviour is 192 + provided. 193 + 194 + To compile this driver as a module, choose M here: the module 195 + will be called leds-cros_ec. 196 + 182 197 config LEDS_EL15203000 183 198 tristate "LED Support for Crane EL15203000" 184 199 depends on LEDS_CLASS
+1
drivers/leds/Makefile
··· 26 26 obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o 27 27 obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o 28 28 obj-$(CONFIG_LEDS_CPCAP) += leds-cpcap.o 29 + obj-$(CONFIG_LEDS_CROS_EC) += leds-cros_ec.o 29 30 obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o 30 31 obj-$(CONFIG_LEDS_DA9052) += leds-da9052.o 31 32 obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
+1 -1
drivers/leds/led-class-multicolor.c
··· 101 101 102 102 for (i = 0; i < mcled_cdev->num_colors; i++) { 103 103 index = mcled_cdev->subled_info[i].color_index; 104 - len += sprintf(buf + len, "%s", led_colors[index]); 104 + len += sprintf(buf + len, "%s", led_get_color_name(index)); 105 105 if (i < mcled_cdev->num_colors - 1) 106 106 len += sprintf(buf + len, " "); 107 107 }
+5 -4
drivers/leds/led-class.c
··· 503 503 ret = led_classdev_next_name(proposed_name, final_name, sizeof(final_name)); 504 504 if (ret < 0) 505 505 return ret; 506 + else if (ret && led_cdev->flags & LED_REJECT_NAME_CONFLICT) 507 + return -EEXIST; 508 + else if (ret) 509 + dev_warn(parent, "Led %s renamed to %s due to name collision\n", 510 + proposed_name, final_name); 506 511 507 512 if (led_cdev->color >= LED_COLOR_ID_MAX) 508 513 dev_warn(parent, "LED %s color identifier out of range\n", final_name); ··· 522 517 } 523 518 if (init_data && init_data->fwnode) 524 519 device_set_node(led_cdev->dev, init_data->fwnode); 525 - 526 - if (ret) 527 - dev_warn(parent, "Led %s renamed to %s due to name collision", 528 - proposed_name, dev_name(led_cdev->dev)); 529 520 530 521 if (led_cdev->flags & LED_BRIGHT_HW_CHANGED) { 531 522 ret = led_add_brightness_hw_changed(led_cdev);
+10 -2
drivers/leds/led-core.c
··· 25 25 LIST_HEAD(leds_list); 26 26 EXPORT_SYMBOL_GPL(leds_list); 27 27 28 - const char * const led_colors[LED_COLOR_ID_MAX] = { 28 + static const char * const led_colors[LED_COLOR_ID_MAX] = { 29 29 [LED_COLOR_ID_WHITE] = "white", 30 30 [LED_COLOR_ID_RED] = "red", 31 31 [LED_COLOR_ID_GREEN] = "green", ··· 42 42 [LED_COLOR_ID_CYAN] = "cyan", 43 43 [LED_COLOR_ID_LIME] = "lime", 44 44 }; 45 - EXPORT_SYMBOL_GPL(led_colors); 46 45 47 46 static int __led_set_brightness(struct led_classdev *led_cdev, unsigned int value) 48 47 { ··· 532 533 return 0; 533 534 } 534 535 EXPORT_SYMBOL_GPL(led_compose_name); 536 + 537 + const char *led_get_color_name(u8 color_id) 538 + { 539 + if (color_id >= ARRAY_SIZE(led_colors)) 540 + return NULL; 541 + 542 + return led_colors[color_id]; 543 + } 544 + EXPORT_SYMBOL_GPL(led_get_color_name); 535 545 536 546 enum led_default_state led_init_default_state_get(struct fwnode_handle *fwnode) 537 547 {
+277
drivers/leds/leds-cros_ec.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * ChromeOS EC LED Driver 4 + * 5 + * Copyright (C) 2024 Thomas Weißschuh <linux@weissschuh.net> 6 + */ 7 + 8 + #include <linux/device.h> 9 + #include <linux/leds.h> 10 + #include <linux/led-class-multicolor.h> 11 + #include <linux/mod_devicetable.h> 12 + #include <linux/module.h> 13 + #include <linux/platform_device.h> 14 + #include <linux/platform_data/cros_ec_commands.h> 15 + #include <linux/platform_data/cros_ec_proto.h> 16 + 17 + static const char * const cros_ec_led_functions[] = { 18 + [EC_LED_ID_BATTERY_LED] = LED_FUNCTION_CHARGING, 19 + [EC_LED_ID_POWER_LED] = LED_FUNCTION_POWER, 20 + [EC_LED_ID_ADAPTER_LED] = "adapter", 21 + [EC_LED_ID_LEFT_LED] = "left", 22 + [EC_LED_ID_RIGHT_LED] = "right", 23 + [EC_LED_ID_RECOVERY_HW_REINIT_LED] = "recovery-hw-reinit", 24 + [EC_LED_ID_SYSRQ_DEBUG_LED] = "sysrq-debug", 25 + }; 26 + 27 + static_assert(ARRAY_SIZE(cros_ec_led_functions) == EC_LED_ID_COUNT); 28 + 29 + static const int cros_ec_led_to_linux_id[] = { 30 + [EC_LED_COLOR_RED] = LED_COLOR_ID_RED, 31 + [EC_LED_COLOR_GREEN] = LED_COLOR_ID_GREEN, 32 + [EC_LED_COLOR_BLUE] = LED_COLOR_ID_BLUE, 33 + [EC_LED_COLOR_YELLOW] = LED_COLOR_ID_YELLOW, 34 + [EC_LED_COLOR_WHITE] = LED_COLOR_ID_WHITE, 35 + [EC_LED_COLOR_AMBER] = LED_COLOR_ID_AMBER, 36 + }; 37 + 38 + static_assert(ARRAY_SIZE(cros_ec_led_to_linux_id) == EC_LED_COLOR_COUNT); 39 + 40 + static const int cros_ec_linux_to_ec_id[] = { 41 + [LED_COLOR_ID_RED] = EC_LED_COLOR_RED, 42 + [LED_COLOR_ID_GREEN] = EC_LED_COLOR_GREEN, 43 + [LED_COLOR_ID_BLUE] = EC_LED_COLOR_BLUE, 44 + [LED_COLOR_ID_YELLOW] = EC_LED_COLOR_YELLOW, 45 + [LED_COLOR_ID_WHITE] = EC_LED_COLOR_WHITE, 46 + [LED_COLOR_ID_AMBER] = EC_LED_COLOR_AMBER, 47 + }; 48 + 49 + struct cros_ec_led_priv { 50 + struct led_classdev_mc led_mc_cdev; 51 + struct cros_ec_device *cros_ec; 52 + enum ec_led_id led_id; 53 + }; 54 + 55 + static inline struct cros_ec_led_priv *cros_ec_led_cdev_to_priv(struct led_classdev *led_cdev) 56 + { 57 + return container_of(lcdev_to_mccdev(led_cdev), struct cros_ec_led_priv, led_mc_cdev); 58 + } 59 + 60 + union cros_ec_led_cmd_data { 61 + struct ec_params_led_control req; 62 + struct ec_response_led_control resp; 63 + } __packed; 64 + 65 + static int cros_ec_led_send_cmd(struct cros_ec_device *cros_ec, 66 + union cros_ec_led_cmd_data *arg) 67 + { 68 + int ret; 69 + struct { 70 + struct cros_ec_command msg; 71 + union cros_ec_led_cmd_data data; 72 + } __packed buf = { 73 + .msg = { 74 + .version = 1, 75 + .command = EC_CMD_LED_CONTROL, 76 + .insize = sizeof(arg->resp), 77 + .outsize = sizeof(arg->req), 78 + }, 79 + .data.req = arg->req 80 + }; 81 + 82 + ret = cros_ec_cmd_xfer_status(cros_ec, &buf.msg); 83 + if (ret < 0) 84 + return ret; 85 + 86 + arg->resp = buf.data.resp; 87 + 88 + return 0; 89 + } 90 + 91 + static int cros_ec_led_trigger_activate(struct led_classdev *led_cdev) 92 + { 93 + struct cros_ec_led_priv *priv = cros_ec_led_cdev_to_priv(led_cdev); 94 + union cros_ec_led_cmd_data arg = {}; 95 + 96 + arg.req.led_id = priv->led_id; 97 + arg.req.flags = EC_LED_FLAGS_AUTO; 98 + 99 + return cros_ec_led_send_cmd(priv->cros_ec, &arg); 100 + } 101 + 102 + static struct led_hw_trigger_type cros_ec_led_trigger_type; 103 + 104 + static struct led_trigger cros_ec_led_trigger = { 105 + .name = "chromeos-auto", 106 + .trigger_type = &cros_ec_led_trigger_type, 107 + .activate = cros_ec_led_trigger_activate, 108 + }; 109 + 110 + static int cros_ec_led_brightness_set_blocking(struct led_classdev *led_cdev, 111 + enum led_brightness brightness) 112 + { 113 + struct cros_ec_led_priv *priv = cros_ec_led_cdev_to_priv(led_cdev); 114 + union cros_ec_led_cmd_data arg = {}; 115 + enum ec_led_colors led_color; 116 + struct mc_subled *subled; 117 + size_t i; 118 + 119 + led_mc_calc_color_components(&priv->led_mc_cdev, brightness); 120 + 121 + arg.req.led_id = priv->led_id; 122 + 123 + for (i = 0; i < priv->led_mc_cdev.num_colors; i++) { 124 + subled = &priv->led_mc_cdev.subled_info[i]; 125 + led_color = cros_ec_linux_to_ec_id[subled->color_index]; 126 + arg.req.brightness[led_color] = subled->brightness; 127 + } 128 + 129 + return cros_ec_led_send_cmd(priv->cros_ec, &arg); 130 + } 131 + 132 + static int cros_ec_led_count_subleds(struct device *dev, 133 + struct ec_response_led_control *resp, 134 + unsigned int *max_brightness) 135 + { 136 + unsigned int range, common_range = 0; 137 + int num_subleds = 0; 138 + size_t i; 139 + 140 + for (i = 0; i < EC_LED_COLOR_COUNT; i++) { 141 + range = resp->brightness_range[i]; 142 + 143 + if (!range) 144 + continue; 145 + 146 + num_subleds++; 147 + 148 + if (!common_range) 149 + common_range = range; 150 + 151 + if (common_range != range) { 152 + /* The multicolor LED API expects a uniform max_brightness */ 153 + dev_err(dev, "Inconsistent LED brightness values\n"); 154 + return -EINVAL; 155 + } 156 + } 157 + 158 + if (!num_subleds) 159 + return -EINVAL; 160 + 161 + *max_brightness = common_range; 162 + return num_subleds; 163 + } 164 + 165 + static const char *cros_ec_led_get_color_name(struct led_classdev_mc *led_mc_cdev) 166 + { 167 + int color; 168 + 169 + if (led_mc_cdev->num_colors == 1) 170 + color = led_mc_cdev->subled_info[0].color_index; 171 + else 172 + color = LED_COLOR_ID_MULTI; 173 + 174 + return led_get_color_name(color); 175 + } 176 + 177 + static int cros_ec_led_probe_one(struct device *dev, struct cros_ec_device *cros_ec, 178 + enum ec_led_id id) 179 + { 180 + union cros_ec_led_cmd_data arg = {}; 181 + struct cros_ec_led_priv *priv; 182 + struct led_classdev *led_cdev; 183 + struct mc_subled *subleds; 184 + int i, ret, num_subleds; 185 + size_t subled; 186 + 187 + arg.req.led_id = id; 188 + arg.req.flags = EC_LED_FLAGS_QUERY; 189 + ret = cros_ec_led_send_cmd(cros_ec, &arg); 190 + if (ret == -EINVAL) 191 + return 0; /* Unknown LED, skip */ 192 + if (ret == -EOPNOTSUPP) 193 + return -ENODEV; 194 + if (ret < 0) 195 + return ret; 196 + 197 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 198 + if (!priv) 199 + return -ENOMEM; 200 + 201 + num_subleds = cros_ec_led_count_subleds(dev, &arg.resp, 202 + &priv->led_mc_cdev.led_cdev.max_brightness); 203 + if (num_subleds < 0) 204 + return num_subleds; 205 + 206 + priv->cros_ec = cros_ec; 207 + priv->led_id = id; 208 + 209 + subleds = devm_kcalloc(dev, num_subleds, sizeof(*subleds), GFP_KERNEL); 210 + if (!subleds) 211 + return -ENOMEM; 212 + 213 + subled = 0; 214 + for (i = 0; i < EC_LED_COLOR_COUNT; i++) { 215 + if (!arg.resp.brightness_range[i]) 216 + continue; 217 + 218 + subleds[subled].color_index = cros_ec_led_to_linux_id[i]; 219 + if (subled == 0) 220 + subleds[subled].intensity = 100; 221 + subled++; 222 + } 223 + 224 + priv->led_mc_cdev.subled_info = subleds; 225 + priv->led_mc_cdev.num_colors = num_subleds; 226 + 227 + led_cdev = &priv->led_mc_cdev.led_cdev; 228 + led_cdev->brightness_set_blocking = cros_ec_led_brightness_set_blocking; 229 + led_cdev->trigger_type = &cros_ec_led_trigger_type; 230 + led_cdev->default_trigger = cros_ec_led_trigger.name; 231 + led_cdev->hw_control_trigger = cros_ec_led_trigger.name; 232 + 233 + led_cdev->name = devm_kasprintf(dev, GFP_KERNEL, "chromeos:%s:%s", 234 + cros_ec_led_get_color_name(&priv->led_mc_cdev), 235 + cros_ec_led_functions[id]); 236 + if (!led_cdev->name) 237 + return -ENOMEM; 238 + 239 + return devm_led_classdev_multicolor_register(dev, &priv->led_mc_cdev); 240 + } 241 + 242 + static int cros_ec_led_probe(struct platform_device *pdev) 243 + { 244 + struct device *dev = &pdev->dev; 245 + struct cros_ec_dev *ec_dev = dev_get_drvdata(dev->parent); 246 + struct cros_ec_device *cros_ec = ec_dev->ec_dev; 247 + int i, ret = 0; 248 + 249 + ret = devm_led_trigger_register(dev, &cros_ec_led_trigger); 250 + if (ret) 251 + return ret; 252 + 253 + for (i = 0; i < EC_LED_ID_COUNT; i++) { 254 + ret = cros_ec_led_probe_one(dev, cros_ec, i); 255 + if (ret) 256 + break; 257 + } 258 + 259 + return ret; 260 + } 261 + 262 + static const struct platform_device_id cros_ec_led_id[] = { 263 + { "cros-ec-led", 0 }, 264 + {} 265 + }; 266 + 267 + static struct platform_driver cros_ec_led_driver = { 268 + .driver.name = "cros-ec-led", 269 + .probe = cros_ec_led_probe, 270 + .id_table = cros_ec_led_id, 271 + }; 272 + module_platform_driver(cros_ec_led_driver); 273 + 274 + MODULE_DEVICE_TABLE(platform, cros_ec_led_id); 275 + MODULE_DESCRIPTION("ChromeOS EC LED Driver"); 276 + MODULE_AUTHOR("Thomas Weißschuh <linux@weissschuh.net"); 277 + MODULE_LICENSE("GPL");
-1
drivers/leds/leds.h
··· 30 30 31 31 extern struct rw_semaphore leds_list_lock; 32 32 extern struct list_head leds_list; 33 - extern const char * const led_colors[LED_COLOR_ID_MAX]; 34 33 35 34 #endif /* __LEDS_H_INCLUDED */
+1 -1
drivers/mfd/88pm800.c
··· 116 116 #define PM800_CHIP_GEN_ID_NUM 0x3 117 117 118 118 static const struct i2c_device_id pm80x_id_table[] = { 119 - {"88PM800", 0}, 119 + { "88PM800" }, 120 120 {} /* NULL terminated */ 121 121 }; 122 122 MODULE_DEVICE_TABLE(i2c, pm80x_id_table);
+1 -1
drivers/mfd/88pm805.c
··· 30 30 #include <linux/delay.h> 31 31 32 32 static const struct i2c_device_id pm80x_id_table[] = { 33 - {"88PM805", 0}, 33 + { "88PM805" }, 34 34 {} /* NULL terminated */ 35 35 }; 36 36 MODULE_DEVICE_TABLE(i2c, pm80x_id_table);
+1 -1
drivers/mfd/88pm860x-core.c
··· 1233 1233 static DEFINE_SIMPLE_DEV_PM_OPS(pm860x_pm_ops, pm860x_suspend, pm860x_resume); 1234 1234 1235 1235 static const struct i2c_device_id pm860x_id_table[] = { 1236 - { "88PM860x", 0 }, 1236 + { "88PM860x" }, 1237 1237 {} 1238 1238 }; 1239 1239 MODULE_DEVICE_TABLE(i2c, pm860x_id_table);
+148
drivers/mfd/88pm886.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + #include <linux/i2c.h> 3 + #include <linux/mfd/core.h> 4 + #include <linux/module.h> 5 + #include <linux/notifier.h> 6 + #include <linux/of.h> 7 + #include <linux/platform_device.h> 8 + #include <linux/reboot.h> 9 + #include <linux/regmap.h> 10 + 11 + #include <linux/mfd/88pm886.h> 12 + 13 + static const struct regmap_config pm886_regmap_config = { 14 + .reg_bits = 8, 15 + .val_bits = 8, 16 + .max_register = PM886_REG_RTC_SPARE6, 17 + }; 18 + 19 + static struct regmap_irq pm886_regmap_irqs[] = { 20 + REGMAP_IRQ_REG(PM886_IRQ_ONKEY, 0, PM886_INT_ENA1_ONKEY), 21 + }; 22 + 23 + static struct regmap_irq_chip pm886_regmap_irq_chip = { 24 + .name = "88pm886", 25 + .irqs = pm886_regmap_irqs, 26 + .num_irqs = ARRAY_SIZE(pm886_regmap_irqs), 27 + .num_regs = 4, 28 + .status_base = PM886_REG_INT_STATUS1, 29 + .ack_base = PM886_REG_INT_STATUS1, 30 + .unmask_base = PM886_REG_INT_ENA_1, 31 + }; 32 + 33 + static struct resource pm886_onkey_resources[] = { 34 + DEFINE_RES_IRQ_NAMED(PM886_IRQ_ONKEY, "88pm886-onkey"), 35 + }; 36 + 37 + static struct mfd_cell pm886_devs[] = { 38 + MFD_CELL_RES("88pm886-onkey", pm886_onkey_resources), 39 + MFD_CELL_NAME("88pm886-regulator"), 40 + }; 41 + 42 + static int pm886_power_off_handler(struct sys_off_data *sys_off_data) 43 + { 44 + struct pm886_chip *chip = sys_off_data->cb_data; 45 + struct regmap *regmap = chip->regmap; 46 + struct device *dev = &chip->client->dev; 47 + int err; 48 + 49 + err = regmap_update_bits(regmap, PM886_REG_MISC_CONFIG1, PM886_SW_PDOWN, PM886_SW_PDOWN); 50 + if (err) { 51 + dev_err(dev, "Failed to power off the device: %d\n", err); 52 + return NOTIFY_BAD; 53 + } 54 + return NOTIFY_DONE; 55 + } 56 + 57 + static int pm886_setup_irq(struct pm886_chip *chip, 58 + struct regmap_irq_chip_data **irq_data) 59 + { 60 + struct regmap *regmap = chip->regmap; 61 + struct device *dev = &chip->client->dev; 62 + int err; 63 + 64 + /* Set interrupt clearing mode to clear on write. */ 65 + err = regmap_update_bits(regmap, PM886_REG_MISC_CONFIG2, 66 + PM886_INT_INV | PM886_INT_CLEAR | PM886_INT_MASK_MODE, 67 + PM886_INT_WC); 68 + if (err) { 69 + dev_err(dev, "Failed to set interrupt clearing mode: %d\n", err); 70 + return err; 71 + } 72 + 73 + err = devm_regmap_add_irq_chip(dev, regmap, chip->client->irq, 74 + IRQF_ONESHOT, 0, &pm886_regmap_irq_chip, 75 + irq_data); 76 + if (err) { 77 + dev_err(dev, "Failed to request IRQ: %d\n", err); 78 + return err; 79 + } 80 + 81 + return 0; 82 + } 83 + 84 + static int pm886_probe(struct i2c_client *client) 85 + { 86 + struct regmap_irq_chip_data *irq_data; 87 + struct device *dev = &client->dev; 88 + struct pm886_chip *chip; 89 + struct regmap *regmap; 90 + unsigned int chip_id; 91 + int err; 92 + 93 + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 94 + if (!chip) 95 + return -ENOMEM; 96 + 97 + chip->client = client; 98 + chip->chip_id = (uintptr_t)device_get_match_data(dev); 99 + i2c_set_clientdata(client, chip); 100 + 101 + regmap = devm_regmap_init_i2c(client, &pm886_regmap_config); 102 + if (IS_ERR(regmap)) 103 + return dev_err_probe(dev, PTR_ERR(regmap), "Failed to initialize regmap\n"); 104 + chip->regmap = regmap; 105 + 106 + err = regmap_read(regmap, PM886_REG_ID, &chip_id); 107 + if (err) 108 + return dev_err_probe(dev, err, "Failed to read chip ID\n"); 109 + 110 + if (chip->chip_id != chip_id) 111 + return dev_err_probe(dev, -EINVAL, "Unsupported chip: 0x%x\n", chip_id); 112 + 113 + err = pm886_setup_irq(chip, &irq_data); 114 + if (err) 115 + return err; 116 + 117 + err = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, pm886_devs, ARRAY_SIZE(pm886_devs), 118 + NULL, 0, regmap_irq_get_domain(irq_data)); 119 + if (err) 120 + return dev_err_probe(dev, err, "Failed to add devices\n"); 121 + 122 + err = devm_register_power_off_handler(dev, pm886_power_off_handler, chip); 123 + if (err) 124 + return dev_err_probe(dev, err, "Failed to register power off handler\n"); 125 + 126 + device_init_wakeup(dev, device_property_read_bool(dev, "wakeup-source")); 127 + 128 + return 0; 129 + } 130 + 131 + static const struct of_device_id pm886_of_match[] = { 132 + { .compatible = "marvell,88pm886-a1", .data = (void *)PM886_A1_CHIP_ID }, 133 + { } 134 + }; 135 + MODULE_DEVICE_TABLE(of, pm886_of_match); 136 + 137 + static struct i2c_driver pm886_i2c_driver = { 138 + .driver = { 139 + .name = "88pm886", 140 + .of_match_table = pm886_of_match, 141 + }, 142 + .probe = pm886_probe, 143 + }; 144 + module_i2c_driver(pm886_i2c_driver); 145 + 146 + MODULE_DESCRIPTION("Marvell 88PM886 PMIC driver"); 147 + MODULE_AUTHOR("Karel Balej <balejk@matfyz.cz>"); 148 + MODULE_LICENSE("GPL");
+56
drivers/mfd/Kconfig
··· 794 794 select individual components like voltage regulators, RTC and 795 795 battery-charger under the corresponding menus. 796 796 797 + config MFD_88PM886_PMIC 798 + bool "Marvell 88PM886 PMIC" 799 + depends on I2C=y 800 + depends on OF 801 + select REGMAP_I2C 802 + select REGMAP_IRQ 803 + select MFD_CORE 804 + help 805 + This enables support for Marvell 88PM886 Power Management IC. 806 + This includes the I2C driver and the core APIs _only_, you have to 807 + select individual components like onkey under the corresponding menus. 808 + 797 809 config MFD_MAX14577 798 810 tristate "Maxim Semiconductor MAX14577/77836 MUIC + Charger Support" 799 811 depends on I2C ··· 2101 2089 BD9573MUF Power Management ICs. BD9576 and BD9573 are primarily 2102 2090 designed to be used to power R-Car series processors. 2103 2091 2092 + config MFD_ROHM_BD96801 2093 + tristate "ROHM BD96801 Power Management IC" 2094 + depends on I2C=y 2095 + depends on OF 2096 + select REGMAP_I2C 2097 + select REGMAP_IRQ 2098 + select MFD_CORE 2099 + help 2100 + Select this option to get support for the ROHM BD96801 Power 2101 + Management IC. The ROHM BD96801 is a highly scalable Power Management 2102 + IC for industrial and automotive use. The BD96801 can be used as a 2103 + master PMIC in a chained PMIC solution with suitable companion PMICs. 2104 + 2104 2105 config MFD_STM32_LPTIMER 2105 2106 tristate "Support for STM32 Low-Power Timer" 2106 2107 depends on (ARCH_STM32 && OF) || COMPILE_TEST ··· 2233 2208 config MFD_QCOM_PM8008 2234 2209 tristate "QCOM PM8008 Power Management IC" 2235 2210 depends on I2C && OF 2211 + select MFD_CORE 2236 2212 select REGMAP_I2C 2237 2213 select REGMAP_IRQ 2238 2214 help ··· 2268 2242 depends on MCP_UCB1200 && INPUT 2269 2243 2270 2244 endmenu 2245 + 2246 + config MFD_CS40L50_CORE 2247 + tristate 2248 + select MFD_CORE 2249 + select FW_CS_DSP 2250 + select REGMAP_IRQ 2251 + 2252 + config MFD_CS40L50_I2C 2253 + tristate "Cirrus Logic CS40L50 (I2C)" 2254 + select REGMAP_I2C 2255 + select MFD_CS40L50_CORE 2256 + depends on I2C 2257 + help 2258 + Select this to support the Cirrus Logic CS40L50 Haptic 2259 + Driver over I2C. 2260 + 2261 + This driver can be built as a module. If built as a module it will be 2262 + called "cs40l50-i2c". 2263 + 2264 + config MFD_CS40L50_SPI 2265 + tristate "Cirrus Logic CS40L50 (SPI)" 2266 + select REGMAP_SPI 2267 + select MFD_CS40L50_CORE 2268 + depends on SPI 2269 + help 2270 + Select this to support the Cirrus Logic CS40L50 Haptic 2271 + Driver over SPI. 2272 + 2273 + This driver can be built as a module. If built as a module it will be 2274 + called "cs40l50-spi". 2271 2275 2272 2276 config MFD_VEXPRESS_SYSREG 2273 2277 tristate "Versatile Express System Registers"
+8 -4
drivers/mfd/Makefile
··· 7 7 obj-$(CONFIG_MFD_88PM860X) += 88pm860x.o 8 8 obj-$(CONFIG_MFD_88PM800) += 88pm800.o 88pm80x.o 9 9 obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o 10 + obj-$(CONFIG_MFD_88PM886_PMIC) += 88pm886.o 10 11 obj-$(CONFIG_MFD_ACT8945A) += act8945a.o 11 12 obj-$(CONFIG_MFD_SM501) += sm501.o 12 13 obj-$(CONFIG_ARCH_BCM2835) += bcm2835-pm.o ··· 88 87 obj-$(CONFIG_MFD_MADERA) += madera.o 89 88 obj-$(CONFIG_MFD_MADERA_I2C) += madera-i2c.o 90 89 obj-$(CONFIG_MFD_MADERA_SPI) += madera-spi.o 90 + 91 + obj-$(CONFIG_MFD_CS40L50_CORE) += cs40l50-core.o 92 + obj-$(CONFIG_MFD_CS40L50_I2C) += cs40l50-i2c.o 93 + obj-$(CONFIG_MFD_CS40L50_SPI) += cs40l50-spi.o 91 94 92 95 obj-$(CONFIG_TPS6105X) += tps6105x.o 93 96 obj-$(CONFIG_TPS65010) += tps65010.o ··· 269 264 obj-$(CONFIG_MFD_ROHM_BD71828) += rohm-bd71828.o 270 265 obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o 271 266 obj-$(CONFIG_MFD_ROHM_BD957XMUF) += rohm-bd9576.o 267 + obj-$(CONFIG_MFD_ROHM_BD96801) += rohm-bd96801.o 272 268 obj-$(CONFIG_MFD_STMFX) += stmfx.o 273 269 obj-$(CONFIG_MFD_KHADAS_MCU) += khadas-mcu.o 274 270 obj-$(CONFIG_MFD_ACER_A500_EC) += acer-ec-a500.o ··· 286 280 obj-$(CONFIG_MFD_ATC260X) += atc260x-core.o 287 281 obj-$(CONFIG_MFD_ATC260X_I2C) += atc260x-i2c.o 288 282 289 - rsmu-i2c-objs := rsmu_core.o rsmu_i2c.o 290 - rsmu-spi-objs := rsmu_core.o rsmu_spi.o 291 - obj-$(CONFIG_MFD_RSMU_I2C) += rsmu-i2c.o 292 - obj-$(CONFIG_MFD_RSMU_SPI) += rsmu-spi.o 283 + obj-$(CONFIG_MFD_RSMU_I2C) += rsmu_i2c.o rsmu_core.o 284 + obj-$(CONFIG_MFD_RSMU_SPI) += rsmu_spi.o rsmu_core.o
+1 -1
drivers/mfd/aat2870-core.c
··· 439 439 aat2870_i2c_resume); 440 440 441 441 static const struct i2c_device_id aat2870_i2c_id_table[] = { 442 - { "aat2870", 0 }, 442 + { "aat2870" }, 443 443 { } 444 444 }; 445 445
+1 -1
drivers/mfd/act8945a.c
··· 54 54 } 55 55 56 56 static const struct i2c_device_id act8945a_i2c_id[] = { 57 - { "act8945a", 0 }, 57 + { "act8945a" }, 58 58 {} 59 59 }; 60 60 MODULE_DEVICE_TABLE(i2c, act8945a_i2c_id);
+1
drivers/mfd/arizona-core.c
··· 1429 1429 } 1430 1430 EXPORT_SYMBOL_GPL(arizona_dev_exit); 1431 1431 1432 + MODULE_DESCRIPTION("Wolfson Arizona core driver"); 1432 1433 MODULE_LICENSE("GPL v2");
+1 -8
drivers/mfd/arizona-spi.c
··· 190 190 191 191 static int arizona_spi_probe(struct spi_device *spi) 192 192 { 193 - const struct spi_device_id *id = spi_get_device_id(spi); 194 - const void *match_data; 195 193 struct arizona *arizona; 196 194 const struct regmap_config *regmap_config = NULL; 197 195 unsigned long type = 0; 198 196 int ret; 199 197 200 - match_data = device_get_match_data(&spi->dev); 201 - if (match_data) 202 - type = (unsigned long)match_data; 203 - else if (id) 204 - type = id->driver_data; 205 - 198 + type = (unsigned long)spi_get_device_match_data(spi); 206 199 switch (type) { 207 200 case WM5102: 208 201 if (IS_ENABLED(CONFIG_MFD_WM5102))
+2 -2
drivers/mfd/as3722.c
··· 430 430 MODULE_DEVICE_TABLE(of, as3722_of_match); 431 431 432 432 static const struct i2c_device_id as3722_i2c_id[] = { 433 - { "as3722", 0 }, 434 - {}, 433 + { "as3722" }, 434 + {} 435 435 }; 436 436 MODULE_DEVICE_TABLE(i2c, as3722_i2c_id); 437 437
+12 -12
drivers/mfd/axp20x-i2c.c
··· 75 75 #endif 76 76 77 77 static const struct i2c_device_id axp20x_i2c_id[] = { 78 - { "axp152", 0 }, 79 - { "axp192", 0 }, 80 - { "axp202", 0 }, 81 - { "axp209", 0 }, 82 - { "axp221", 0 }, 83 - { "axp223", 0 }, 84 - { "axp313a", 0 }, 85 - { "axp717", 0 }, 86 - { "axp803", 0 }, 87 - { "axp806", 0 }, 88 - { "axp15060", 0 }, 89 - { }, 78 + { "axp152" }, 79 + { "axp192" }, 80 + { "axp202" }, 81 + { "axp209" }, 82 + { "axp221" }, 83 + { "axp223" }, 84 + { "axp313a" }, 85 + { "axp717" }, 86 + { "axp803" }, 87 + { "axp806" }, 88 + { "axp15060" }, 89 + { } 90 90 }; 91 91 MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id); 92 92
+1 -1
drivers/mfd/bd9571mwv.c
··· 268 268 MODULE_DEVICE_TABLE(of, bd9571mwv_of_match_table); 269 269 270 270 static const struct i2c_device_id bd9571mwv_id_table[] = { 271 - { "bd9571mwv", 0 }, 271 + { "bd9571mwv" }, 272 272 { /* sentinel */ } 273 273 }; 274 274 MODULE_DEVICE_TABLE(i2c, bd9571mwv_id_table);
+20
drivers/mfd/cros_ec_dev.c
··· 87 87 }; 88 88 89 89 static const struct mfd_cell cros_usbpd_charger_cells[] = { 90 + { .name = "cros-charge-control", }, 90 91 { .name = "cros-usbpd-charger", }, 91 92 { .name = "cros-usbpd-logger", }, 92 93 }; ··· 98 97 99 98 static const struct mfd_cell cros_ec_wdt_cells[] = { 100 99 { .name = "cros-ec-wdt", } 100 + }; 101 + 102 + static const struct mfd_cell cros_ec_led_cells[] = { 103 + { .name = "cros-ec-led", }, 104 + }; 105 + 106 + static const struct mfd_cell cros_ec_keyboard_leds_cells[] = { 107 + { .name = "cros-keyboard-leds", }, 101 108 }; 102 109 103 110 static const struct cros_feature_to_cells cros_subdevices[] = { ··· 134 125 .mfd_cells = cros_ec_wdt_cells, 135 126 .num_cells = ARRAY_SIZE(cros_ec_wdt_cells), 136 127 }, 128 + { 129 + .id = EC_FEATURE_LED, 130 + .mfd_cells = cros_ec_led_cells, 131 + .num_cells = ARRAY_SIZE(cros_ec_led_cells), 132 + }, 133 + { 134 + .id = EC_FEATURE_PWM_KEYB, 135 + .mfd_cells = cros_ec_keyboard_leds_cells, 136 + .num_cells = ARRAY_SIZE(cros_ec_keyboard_leds_cells), 137 + }, 137 138 }; 138 139 139 140 static const struct mfd_cell cros_ec_platform_cells[] = { 140 141 { .name = "cros-ec-chardev", }, 141 142 { .name = "cros-ec-debugfs", }, 143 + { .name = "cros-ec-hwmon", }, 142 144 { .name = "cros-ec-sysfs", }, 143 145 }; 144 146
+570
drivers/mfd/cs40l50-core.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * CS40L50 Advanced Haptic Driver with waveform memory, 4 + * integrated DSP, and closed-loop algorithms 5 + * 6 + * Copyright 2024 Cirrus Logic, Inc. 7 + * 8 + * Author: James Ogletree <james.ogletree@cirrus.com> 9 + */ 10 + 11 + #include <linux/firmware/cirrus/cs_dsp.h> 12 + #include <linux/firmware/cirrus/wmfw.h> 13 + #include <linux/mfd/core.h> 14 + #include <linux/mfd/cs40l50.h> 15 + #include <linux/pm_runtime.h> 16 + #include <linux/regulator/consumer.h> 17 + 18 + static const struct mfd_cell cs40l50_devs[] = { 19 + { .name = "cs40l50-codec", }, 20 + { .name = "cs40l50-vibra", }, 21 + }; 22 + 23 + const struct regmap_config cs40l50_regmap = { 24 + .reg_bits = 32, 25 + .reg_stride = 4, 26 + .val_bits = 32, 27 + .reg_format_endian = REGMAP_ENDIAN_BIG, 28 + .val_format_endian = REGMAP_ENDIAN_BIG, 29 + }; 30 + EXPORT_SYMBOL_GPL(cs40l50_regmap); 31 + 32 + static const char * const cs40l50_supplies[] = { 33 + "vdd-io", 34 + }; 35 + 36 + static const struct regmap_irq cs40l50_reg_irqs[] = { 37 + REGMAP_IRQ_REG(CS40L50_DSP_QUEUE_IRQ, CS40L50_IRQ1_INT_2_OFFSET, 38 + CS40L50_DSP_QUEUE_MASK), 39 + REGMAP_IRQ_REG(CS40L50_AMP_SHORT_IRQ, CS40L50_IRQ1_INT_1_OFFSET, 40 + CS40L50_AMP_SHORT_MASK), 41 + REGMAP_IRQ_REG(CS40L50_TEMP_ERR_IRQ, CS40L50_IRQ1_INT_8_OFFSET, 42 + CS40L50_TEMP_ERR_MASK), 43 + REGMAP_IRQ_REG(CS40L50_BST_UVP_IRQ, CS40L50_IRQ1_INT_9_OFFSET, 44 + CS40L50_BST_UVP_MASK), 45 + REGMAP_IRQ_REG(CS40L50_BST_SHORT_IRQ, CS40L50_IRQ1_INT_9_OFFSET, 46 + CS40L50_BST_SHORT_MASK), 47 + REGMAP_IRQ_REG(CS40L50_BST_ILIMIT_IRQ, CS40L50_IRQ1_INT_9_OFFSET, 48 + CS40L50_BST_ILIMIT_MASK), 49 + REGMAP_IRQ_REG(CS40L50_UVLO_VDDBATT_IRQ, CS40L50_IRQ1_INT_10_OFFSET, 50 + CS40L50_UVLO_VDDBATT_MASK), 51 + REGMAP_IRQ_REG(CS40L50_GLOBAL_ERROR_IRQ, CS40L50_IRQ1_INT_18_OFFSET, 52 + CS40L50_GLOBAL_ERROR_MASK), 53 + }; 54 + 55 + static struct regmap_irq_chip cs40l50_irq_chip = { 56 + .name = "cs40l50", 57 + .status_base = CS40L50_IRQ1_INT_1, 58 + .mask_base = CS40L50_IRQ1_MASK_1, 59 + .ack_base = CS40L50_IRQ1_INT_1, 60 + .num_regs = 22, 61 + .irqs = cs40l50_reg_irqs, 62 + .num_irqs = ARRAY_SIZE(cs40l50_reg_irqs), 63 + .runtime_pm = true, 64 + }; 65 + 66 + int cs40l50_dsp_write(struct device *dev, struct regmap *regmap, u32 val) 67 + { 68 + int i, ret; 69 + u32 ack; 70 + 71 + /* Device NAKs if hibernating, so optionally retry */ 72 + for (i = 0; i < CS40L50_DSP_TIMEOUT_COUNT; i++) { 73 + ret = regmap_write(regmap, CS40L50_DSP_QUEUE, val); 74 + if (!ret) 75 + break; 76 + 77 + usleep_range(CS40L50_DSP_POLL_US, CS40L50_DSP_POLL_US + 100); 78 + } 79 + 80 + /* If the write never took place, no need to check for the ACK */ 81 + if (i == CS40L50_DSP_TIMEOUT_COUNT) { 82 + dev_err(dev, "Timed out writing %#X to DSP: %d\n", val, ret); 83 + return ret; 84 + } 85 + 86 + ret = regmap_read_poll_timeout(regmap, CS40L50_DSP_QUEUE, ack, !ack, 87 + CS40L50_DSP_POLL_US, 88 + CS40L50_DSP_POLL_US * CS40L50_DSP_TIMEOUT_COUNT); 89 + if (ret) 90 + dev_err(dev, "DSP failed to ACK %#X: %d\n", val, ret); 91 + 92 + return ret; 93 + } 94 + EXPORT_SYMBOL_GPL(cs40l50_dsp_write); 95 + 96 + static const struct cs_dsp_region cs40l50_dsp_regions[] = { 97 + { .type = WMFW_HALO_PM_PACKED, .base = CS40L50_PMEM_0 }, 98 + { .type = WMFW_HALO_XM_PACKED, .base = CS40L50_XMEM_PACKED_0 }, 99 + { .type = WMFW_HALO_YM_PACKED, .base = CS40L50_YMEM_PACKED_0 }, 100 + { .type = WMFW_ADSP2_XM, .base = CS40L50_XMEM_UNPACKED24_0 }, 101 + { .type = WMFW_ADSP2_YM, .base = CS40L50_YMEM_UNPACKED24_0 }, 102 + }; 103 + 104 + static const struct reg_sequence cs40l50_internal_vamp_config[] = { 105 + { CS40L50_BST_LPMODE_SEL, CS40L50_DCM_LOW_POWER }, 106 + { CS40L50_BLOCK_ENABLES2, CS40L50_OVERTEMP_WARN }, 107 + }; 108 + 109 + static const struct reg_sequence cs40l50_irq_mask_override[] = { 110 + { CS40L50_IRQ1_MASK_2, CS40L50_IRQ_MASK_2_OVERRIDE }, 111 + { CS40L50_IRQ1_MASK_20, CS40L50_IRQ_MASK_20_OVERRIDE }, 112 + }; 113 + 114 + static int cs40l50_wseq_init(struct cs40l50 *cs40l50) 115 + { 116 + struct cs_dsp *dsp = &cs40l50->dsp; 117 + 118 + cs40l50->wseqs[CS40L50_STANDBY].ctl = cs_dsp_get_ctl(dsp, "STANDBY_SEQUENCE", 119 + WMFW_ADSP2_XM, 120 + CS40L50_PM_ALGO); 121 + if (!cs40l50->wseqs[CS40L50_STANDBY].ctl) { 122 + dev_err(cs40l50->dev, "Control not found for standby sequence\n"); 123 + return -ENOENT; 124 + } 125 + 126 + cs40l50->wseqs[CS40L50_ACTIVE].ctl = cs_dsp_get_ctl(dsp, "ACTIVE_SEQUENCE", 127 + WMFW_ADSP2_XM, 128 + CS40L50_PM_ALGO); 129 + if (!cs40l50->wseqs[CS40L50_ACTIVE].ctl) { 130 + dev_err(cs40l50->dev, "Control not found for active sequence\n"); 131 + return -ENOENT; 132 + } 133 + 134 + cs40l50->wseqs[CS40L50_PWR_ON].ctl = cs_dsp_get_ctl(dsp, "PM_PWR_ON_SEQ", 135 + WMFW_ADSP2_XM, 136 + CS40L50_PM_ALGO); 137 + if (!cs40l50->wseqs[CS40L50_PWR_ON].ctl) { 138 + dev_err(cs40l50->dev, "Control not found for power-on sequence\n"); 139 + return -ENOENT; 140 + } 141 + 142 + return cs_dsp_wseq_init(&cs40l50->dsp, cs40l50->wseqs, ARRAY_SIZE(cs40l50->wseqs)); 143 + } 144 + 145 + static int cs40l50_dsp_config(struct cs40l50 *cs40l50) 146 + { 147 + int ret; 148 + 149 + /* Configure internal V_AMP supply */ 150 + ret = regmap_multi_reg_write(cs40l50->regmap, cs40l50_internal_vamp_config, 151 + ARRAY_SIZE(cs40l50_internal_vamp_config)); 152 + if (ret) 153 + return ret; 154 + 155 + ret = cs_dsp_wseq_multi_write(&cs40l50->dsp, &cs40l50->wseqs[CS40L50_PWR_ON], 156 + cs40l50_internal_vamp_config, CS_DSP_WSEQ_FULL, 157 + ARRAY_SIZE(cs40l50_internal_vamp_config), false); 158 + if (ret) 159 + return ret; 160 + 161 + /* Override firmware defaults for IRQ masks */ 162 + ret = regmap_multi_reg_write(cs40l50->regmap, cs40l50_irq_mask_override, 163 + ARRAY_SIZE(cs40l50_irq_mask_override)); 164 + if (ret) 165 + return ret; 166 + 167 + return cs_dsp_wseq_multi_write(&cs40l50->dsp, &cs40l50->wseqs[CS40L50_PWR_ON], 168 + cs40l50_irq_mask_override, CS_DSP_WSEQ_FULL, 169 + ARRAY_SIZE(cs40l50_irq_mask_override), false); 170 + } 171 + 172 + static int cs40l50_dsp_post_run(struct cs_dsp *dsp) 173 + { 174 + struct cs40l50 *cs40l50 = container_of(dsp, struct cs40l50, dsp); 175 + int ret; 176 + 177 + ret = cs40l50_wseq_init(cs40l50); 178 + if (ret) 179 + return ret; 180 + 181 + ret = cs40l50_dsp_config(cs40l50); 182 + if (ret) { 183 + dev_err(cs40l50->dev, "Failed to configure DSP: %d\n", ret); 184 + return ret; 185 + } 186 + 187 + ret = devm_mfd_add_devices(cs40l50->dev, PLATFORM_DEVID_NONE, cs40l50_devs, 188 + ARRAY_SIZE(cs40l50_devs), NULL, 0, NULL); 189 + if (ret) 190 + dev_err(cs40l50->dev, "Failed to add child devices: %d\n", ret); 191 + 192 + return ret; 193 + } 194 + 195 + static const struct cs_dsp_client_ops client_ops = { 196 + .post_run = cs40l50_dsp_post_run, 197 + }; 198 + 199 + static void cs40l50_dsp_remove(void *data) 200 + { 201 + cs_dsp_remove(data); 202 + } 203 + 204 + static int cs40l50_dsp_init(struct cs40l50 *cs40l50) 205 + { 206 + int ret; 207 + 208 + cs40l50->dsp.num = 1; 209 + cs40l50->dsp.type = WMFW_HALO; 210 + cs40l50->dsp.dev = cs40l50->dev; 211 + cs40l50->dsp.regmap = cs40l50->regmap; 212 + cs40l50->dsp.base = CS40L50_CORE_BASE; 213 + cs40l50->dsp.base_sysinfo = CS40L50_SYS_INFO_ID; 214 + cs40l50->dsp.mem = cs40l50_dsp_regions; 215 + cs40l50->dsp.num_mems = ARRAY_SIZE(cs40l50_dsp_regions); 216 + cs40l50->dsp.no_core_startstop = true; 217 + cs40l50->dsp.client_ops = &client_ops; 218 + 219 + ret = cs_dsp_halo_init(&cs40l50->dsp); 220 + if (ret) 221 + return ret; 222 + 223 + return devm_add_action_or_reset(cs40l50->dev, cs40l50_dsp_remove, 224 + &cs40l50->dsp); 225 + } 226 + 227 + static int cs40l50_reset_dsp(struct cs40l50 *cs40l50) 228 + { 229 + int ret; 230 + 231 + mutex_lock(&cs40l50->lock); 232 + 233 + if (cs40l50->dsp.running) 234 + cs_dsp_stop(&cs40l50->dsp); 235 + 236 + if (cs40l50->dsp.booted) 237 + cs_dsp_power_down(&cs40l50->dsp); 238 + 239 + ret = cs40l50_dsp_write(cs40l50->dev, cs40l50->regmap, CS40L50_SHUTDOWN); 240 + if (ret) 241 + goto err_mutex; 242 + 243 + ret = cs_dsp_power_up(&cs40l50->dsp, cs40l50->fw, "cs40l50.wmfw", 244 + cs40l50->bin, "cs40l50.bin", "cs40l50"); 245 + if (ret) 246 + goto err_mutex; 247 + 248 + ret = cs40l50_dsp_write(cs40l50->dev, cs40l50->regmap, CS40L50_SYSTEM_RESET); 249 + if (ret) 250 + goto err_mutex; 251 + 252 + ret = cs40l50_dsp_write(cs40l50->dev, cs40l50->regmap, CS40L50_PREVENT_HIBER); 253 + if (ret) 254 + goto err_mutex; 255 + 256 + ret = cs_dsp_run(&cs40l50->dsp); 257 + err_mutex: 258 + mutex_unlock(&cs40l50->lock); 259 + 260 + return ret; 261 + } 262 + 263 + static void cs40l50_dsp_power_down(void *data) 264 + { 265 + cs_dsp_power_down(data); 266 + } 267 + 268 + static void cs40l50_dsp_stop(void *data) 269 + { 270 + cs_dsp_stop(data); 271 + } 272 + 273 + static void cs40l50_dsp_bringup(const struct firmware *bin, void *context) 274 + { 275 + struct cs40l50 *cs40l50 = context; 276 + u32 nwaves; 277 + int ret; 278 + 279 + /* Wavetable is optional; bringup DSP regardless */ 280 + cs40l50->bin = bin; 281 + 282 + ret = cs40l50_reset_dsp(cs40l50); 283 + if (ret) { 284 + dev_err(cs40l50->dev, "Failed to reset DSP: %d\n", ret); 285 + goto err_fw; 286 + } 287 + 288 + ret = regmap_read(cs40l50->regmap, CS40L50_NUM_WAVES, &nwaves); 289 + if (ret) 290 + goto err_fw; 291 + 292 + dev_info(cs40l50->dev, "%u RAM effects loaded\n", nwaves); 293 + 294 + /* Add teardown actions for first-time bringup */ 295 + ret = devm_add_action_or_reset(cs40l50->dev, cs40l50_dsp_power_down, 296 + &cs40l50->dsp); 297 + if (ret) { 298 + dev_err(cs40l50->dev, "Failed to add power down action: %d\n", ret); 299 + goto err_fw; 300 + } 301 + 302 + ret = devm_add_action_or_reset(cs40l50->dev, cs40l50_dsp_stop, &cs40l50->dsp); 303 + if (ret) 304 + dev_err(cs40l50->dev, "Failed to add stop action: %d\n", ret); 305 + err_fw: 306 + release_firmware(cs40l50->bin); 307 + release_firmware(cs40l50->fw); 308 + } 309 + 310 + static void cs40l50_request_firmware(const struct firmware *fw, void *context) 311 + { 312 + struct cs40l50 *cs40l50 = context; 313 + int ret; 314 + 315 + if (!fw) { 316 + dev_err(cs40l50->dev, "No firmware file found\n"); 317 + return; 318 + } 319 + 320 + cs40l50->fw = fw; 321 + 322 + ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT, CS40L50_WT, 323 + cs40l50->dev, GFP_KERNEL, cs40l50, 324 + cs40l50_dsp_bringup); 325 + if (ret) { 326 + dev_err(cs40l50->dev, "Failed to request %s: %d\n", CS40L50_WT, ret); 327 + release_firmware(cs40l50->fw); 328 + } 329 + } 330 + 331 + struct cs40l50_irq { 332 + const char *name; 333 + int virq; 334 + }; 335 + 336 + static struct cs40l50_irq cs40l50_irqs[] = { 337 + { "DSP", }, 338 + { "Global", }, 339 + { "Boost UVLO", }, 340 + { "Boost current limit", }, 341 + { "Boost short", }, 342 + { "Boost undervolt", }, 343 + { "Overtemp", }, 344 + { "Amp short", }, 345 + }; 346 + 347 + static const struct reg_sequence cs40l50_err_rls[] = { 348 + { CS40L50_ERR_RLS, CS40L50_GLOBAL_ERR_RLS_SET }, 349 + { CS40L50_ERR_RLS, CS40L50_GLOBAL_ERR_RLS_CLEAR }, 350 + }; 351 + 352 + static irqreturn_t cs40l50_hw_err(int irq, void *data) 353 + { 354 + struct cs40l50 *cs40l50 = data; 355 + int ret = 0, i; 356 + 357 + mutex_lock(&cs40l50->lock); 358 + 359 + /* Log hardware interrupt and execute error release sequence */ 360 + for (i = 1; i < ARRAY_SIZE(cs40l50_irqs); i++) { 361 + if (cs40l50_irqs[i].virq == irq) { 362 + dev_err(cs40l50->dev, "%s error\n", cs40l50_irqs[i].name); 363 + ret = regmap_multi_reg_write(cs40l50->regmap, cs40l50_err_rls, 364 + ARRAY_SIZE(cs40l50_err_rls)); 365 + break; 366 + } 367 + } 368 + 369 + mutex_unlock(&cs40l50->lock); 370 + return IRQ_RETVAL(!ret); 371 + } 372 + 373 + static irqreturn_t cs40l50_dsp_queue(int irq, void *data) 374 + { 375 + struct cs40l50 *cs40l50 = data; 376 + u32 rd_ptr, val, wt_ptr; 377 + int ret = 0; 378 + 379 + mutex_lock(&cs40l50->lock); 380 + 381 + /* Read from DSP queue, log, and update read pointer */ 382 + while (!ret) { 383 + ret = regmap_read(cs40l50->regmap, CS40L50_DSP_QUEUE_WT, &wt_ptr); 384 + if (ret) 385 + break; 386 + 387 + ret = regmap_read(cs40l50->regmap, CS40L50_DSP_QUEUE_RD, &rd_ptr); 388 + if (ret) 389 + break; 390 + 391 + /* Check if queue is empty */ 392 + if (wt_ptr == rd_ptr) 393 + break; 394 + 395 + ret = regmap_read(cs40l50->regmap, rd_ptr, &val); 396 + if (ret) 397 + break; 398 + 399 + dev_dbg(cs40l50->dev, "DSP payload: %#X", val); 400 + 401 + rd_ptr += sizeof(u32); 402 + 403 + if (rd_ptr > CS40L50_DSP_QUEUE_END) 404 + rd_ptr = CS40L50_DSP_QUEUE_BASE; 405 + 406 + ret = regmap_write(cs40l50->regmap, CS40L50_DSP_QUEUE_RD, rd_ptr); 407 + } 408 + 409 + mutex_unlock(&cs40l50->lock); 410 + 411 + return IRQ_RETVAL(!ret); 412 + } 413 + 414 + static int cs40l50_irq_init(struct cs40l50 *cs40l50) 415 + { 416 + int ret, i, virq; 417 + 418 + ret = devm_regmap_add_irq_chip(cs40l50->dev, cs40l50->regmap, cs40l50->irq, 419 + IRQF_ONESHOT | IRQF_SHARED, 0, 420 + &cs40l50_irq_chip, &cs40l50->irq_data); 421 + if (ret) { 422 + dev_err(cs40l50->dev, "Failed adding IRQ chip\n"); 423 + return ret; 424 + } 425 + 426 + for (i = 0; i < ARRAY_SIZE(cs40l50_irqs); i++) { 427 + virq = regmap_irq_get_virq(cs40l50->irq_data, i); 428 + if (virq < 0) { 429 + dev_err(cs40l50->dev, "Failed getting virq for %s\n", 430 + cs40l50_irqs[i].name); 431 + return virq; 432 + } 433 + 434 + cs40l50_irqs[i].virq = virq; 435 + 436 + /* Handle DSP and hardware interrupts separately */ 437 + ret = devm_request_threaded_irq(cs40l50->dev, virq, NULL, 438 + i ? cs40l50_hw_err : cs40l50_dsp_queue, 439 + IRQF_ONESHOT | IRQF_SHARED, 440 + cs40l50_irqs[i].name, cs40l50); 441 + if (ret) { 442 + return dev_err_probe(cs40l50->dev, ret, 443 + "Failed requesting %s IRQ\n", 444 + cs40l50_irqs[i].name); 445 + } 446 + } 447 + 448 + return 0; 449 + } 450 + 451 + static int cs40l50_get_model(struct cs40l50 *cs40l50) 452 + { 453 + int ret; 454 + 455 + ret = regmap_read(cs40l50->regmap, CS40L50_DEVID, &cs40l50->devid); 456 + if (ret) 457 + return ret; 458 + 459 + if (cs40l50->devid != CS40L50_DEVID_A) 460 + return -EINVAL; 461 + 462 + ret = regmap_read(cs40l50->regmap, CS40L50_REVID, &cs40l50->revid); 463 + if (ret) 464 + return ret; 465 + 466 + if (cs40l50->revid < CS40L50_REVID_B0) 467 + return -EINVAL; 468 + 469 + dev_dbg(cs40l50->dev, "Cirrus Logic CS40L50 rev. %02X\n", cs40l50->revid); 470 + 471 + return 0; 472 + } 473 + 474 + static int cs40l50_pm_runtime_setup(struct device *dev) 475 + { 476 + int ret; 477 + 478 + pm_runtime_set_autosuspend_delay(dev, CS40L50_AUTOSUSPEND_MS); 479 + pm_runtime_use_autosuspend(dev); 480 + pm_runtime_get_noresume(dev); 481 + ret = pm_runtime_set_active(dev); 482 + if (ret) 483 + return ret; 484 + 485 + return devm_pm_runtime_enable(dev); 486 + } 487 + 488 + int cs40l50_probe(struct cs40l50 *cs40l50) 489 + { 490 + struct device *dev = cs40l50->dev; 491 + int ret; 492 + 493 + mutex_init(&cs40l50->lock); 494 + 495 + cs40l50->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); 496 + if (IS_ERR(cs40l50->reset_gpio)) 497 + return dev_err_probe(dev, PTR_ERR(cs40l50->reset_gpio), 498 + "Failed getting reset GPIO\n"); 499 + 500 + ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(cs40l50_supplies), 501 + cs40l50_supplies); 502 + if (ret) 503 + return dev_err_probe(dev, ret, "Failed getting supplies\n"); 504 + 505 + /* Ensure minimum reset pulse width */ 506 + usleep_range(CS40L50_RESET_PULSE_US, CS40L50_RESET_PULSE_US + 100); 507 + 508 + gpiod_set_value_cansleep(cs40l50->reset_gpio, 0); 509 + 510 + /* Wait for control port to be ready */ 511 + usleep_range(CS40L50_CP_READY_US, CS40L50_CP_READY_US + 100); 512 + 513 + ret = cs40l50_get_model(cs40l50); 514 + if (ret) 515 + return dev_err_probe(dev, ret, "Failed to get part number\n"); 516 + 517 + ret = cs40l50_dsp_init(cs40l50); 518 + if (ret) 519 + return dev_err_probe(dev, ret, "Failed to initialize DSP\n"); 520 + 521 + ret = cs40l50_pm_runtime_setup(dev); 522 + if (ret) 523 + return dev_err_probe(dev, ret, "Failed to initialize runtime PM\n"); 524 + 525 + ret = cs40l50_irq_init(cs40l50); 526 + if (ret) 527 + return ret; 528 + 529 + ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT, CS40L50_FW, 530 + dev, GFP_KERNEL, cs40l50, cs40l50_request_firmware); 531 + if (ret) 532 + return dev_err_probe(dev, ret, "Failed to request %s\n", CS40L50_FW); 533 + 534 + pm_runtime_mark_last_busy(dev); 535 + pm_runtime_put_autosuspend(dev); 536 + 537 + return 0; 538 + } 539 + EXPORT_SYMBOL_GPL(cs40l50_probe); 540 + 541 + int cs40l50_remove(struct cs40l50 *cs40l50) 542 + { 543 + gpiod_set_value_cansleep(cs40l50->reset_gpio, 1); 544 + 545 + return 0; 546 + } 547 + EXPORT_SYMBOL_GPL(cs40l50_remove); 548 + 549 + static int cs40l50_runtime_suspend(struct device *dev) 550 + { 551 + struct cs40l50 *cs40l50 = dev_get_drvdata(dev); 552 + 553 + return regmap_write(cs40l50->regmap, CS40L50_DSP_QUEUE, CS40L50_ALLOW_HIBER); 554 + } 555 + 556 + static int cs40l50_runtime_resume(struct device *dev) 557 + { 558 + struct cs40l50 *cs40l50 = dev_get_drvdata(dev); 559 + 560 + return cs40l50_dsp_write(dev, cs40l50->regmap, CS40L50_PREVENT_HIBER); 561 + } 562 + 563 + EXPORT_GPL_DEV_PM_OPS(cs40l50_pm_ops) = { 564 + RUNTIME_PM_OPS(cs40l50_runtime_suspend, cs40l50_runtime_resume, NULL) 565 + }; 566 + 567 + MODULE_DESCRIPTION("CS40L50 Advanced Haptic Driver"); 568 + MODULE_AUTHOR("James Ogletree, Cirrus Logic Inc. <james.ogletree@cirrus.com>"); 569 + MODULE_LICENSE("GPL"); 570 + MODULE_IMPORT_NS(FW_CS_DSP);
+68
drivers/mfd/cs40l50-i2c.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * CS40L50 Advanced Haptic Driver with waveform memory, 4 + * integrated DSP, and closed-loop algorithms 5 + * 6 + * Copyright 2024 Cirrus Logic, Inc. 7 + * 8 + * Author: James Ogletree <james.ogletree@cirrus.com> 9 + */ 10 + 11 + #include <linux/i2c.h> 12 + #include <linux/mfd/cs40l50.h> 13 + 14 + static int cs40l50_i2c_probe(struct i2c_client *i2c) 15 + { 16 + struct cs40l50 *cs40l50; 17 + 18 + cs40l50 = devm_kzalloc(&i2c->dev, sizeof(*cs40l50), GFP_KERNEL); 19 + if (!cs40l50) 20 + return -ENOMEM; 21 + 22 + i2c_set_clientdata(i2c, cs40l50); 23 + 24 + cs40l50->dev = &i2c->dev; 25 + cs40l50->irq = i2c->irq; 26 + 27 + cs40l50->regmap = devm_regmap_init_i2c(i2c, &cs40l50_regmap); 28 + if (IS_ERR(cs40l50->regmap)) 29 + return dev_err_probe(cs40l50->dev, PTR_ERR(cs40l50->regmap), 30 + "Failed to initialize register map\n"); 31 + 32 + return cs40l50_probe(cs40l50); 33 + } 34 + 35 + static void cs40l50_i2c_remove(struct i2c_client *i2c) 36 + { 37 + struct cs40l50 *cs40l50 = i2c_get_clientdata(i2c); 38 + 39 + cs40l50_remove(cs40l50); 40 + } 41 + 42 + static const struct i2c_device_id cs40l50_id_i2c[] = { 43 + { "cs40l50" }, 44 + {} 45 + }; 46 + MODULE_DEVICE_TABLE(i2c, cs40l50_id_i2c); 47 + 48 + static const struct of_device_id cs40l50_of_match[] = { 49 + { .compatible = "cirrus,cs40l50" }, 50 + {} 51 + }; 52 + MODULE_DEVICE_TABLE(of, cs40l50_of_match); 53 + 54 + static struct i2c_driver cs40l50_i2c_driver = { 55 + .driver = { 56 + .name = "cs40l50", 57 + .of_match_table = cs40l50_of_match, 58 + .pm = pm_ptr(&cs40l50_pm_ops), 59 + }, 60 + .id_table = cs40l50_id_i2c, 61 + .probe = cs40l50_i2c_probe, 62 + .remove = cs40l50_i2c_remove, 63 + }; 64 + module_i2c_driver(cs40l50_i2c_driver); 65 + 66 + MODULE_DESCRIPTION("CS40L50 I2C Driver"); 67 + MODULE_AUTHOR("James Ogletree, Cirrus Logic Inc. <james.ogletree@cirrus.com>"); 68 + MODULE_LICENSE("GPL");
+68
drivers/mfd/cs40l50-spi.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * CS40L50 Advanced Haptic Driver with waveform memory, 4 + * integrated DSP, and closed-loop algorithms 5 + * 6 + * Copyright 2024 Cirrus Logic, Inc. 7 + * 8 + * Author: James Ogletree <james.ogletree@cirrus.com> 9 + */ 10 + 11 + #include <linux/mfd/cs40l50.h> 12 + #include <linux/spi/spi.h> 13 + 14 + static int cs40l50_spi_probe(struct spi_device *spi) 15 + { 16 + struct cs40l50 *cs40l50; 17 + 18 + cs40l50 = devm_kzalloc(&spi->dev, sizeof(*cs40l50), GFP_KERNEL); 19 + if (!cs40l50) 20 + return -ENOMEM; 21 + 22 + spi_set_drvdata(spi, cs40l50); 23 + 24 + cs40l50->dev = &spi->dev; 25 + cs40l50->irq = spi->irq; 26 + 27 + cs40l50->regmap = devm_regmap_init_spi(spi, &cs40l50_regmap); 28 + if (IS_ERR(cs40l50->regmap)) 29 + return dev_err_probe(cs40l50->dev, PTR_ERR(cs40l50->regmap), 30 + "Failed to initialize register map\n"); 31 + 32 + return cs40l50_probe(cs40l50); 33 + } 34 + 35 + static void cs40l50_spi_remove(struct spi_device *spi) 36 + { 37 + struct cs40l50 *cs40l50 = spi_get_drvdata(spi); 38 + 39 + cs40l50_remove(cs40l50); 40 + } 41 + 42 + static const struct spi_device_id cs40l50_id_spi[] = { 43 + { "cs40l50" }, 44 + {} 45 + }; 46 + MODULE_DEVICE_TABLE(spi, cs40l50_id_spi); 47 + 48 + static const struct of_device_id cs40l50_of_match[] = { 49 + { .compatible = "cirrus,cs40l50" }, 50 + {} 51 + }; 52 + MODULE_DEVICE_TABLE(of, cs40l50_of_match); 53 + 54 + static struct spi_driver cs40l50_spi_driver = { 55 + .driver = { 56 + .name = "cs40l50", 57 + .of_match_table = cs40l50_of_match, 58 + .pm = pm_ptr(&cs40l50_pm_ops), 59 + }, 60 + .id_table = cs40l50_id_spi, 61 + .probe = cs40l50_spi_probe, 62 + .remove = cs40l50_spi_remove, 63 + }; 64 + module_spi_driver(cs40l50_spi_driver); 65 + 66 + MODULE_DESCRIPTION("CS40L50 SPI Driver"); 67 + MODULE_AUTHOR("James Ogletree, Cirrus Logic Inc. <james.ogletree@cirrus.com>"); 68 + MODULE_LICENSE("GPL");
+1 -1
drivers/mfd/da9055-i2c.c
··· 54 54 * and CODEC, which must be different to operate together. 55 55 */ 56 56 static const struct i2c_device_id da9055_i2c_id[] = { 57 - {"da9055-pmic", 0}, 57 + { "da9055-pmic" }, 58 58 { } 59 59 }; 60 60 MODULE_DEVICE_TABLE(i2c, da9055_i2c_id);
+81 -81
drivers/mfd/intel-lpss-pci.c
··· 103 103 .properties = spt_spi_properties, 104 104 }; 105 105 106 - static const struct intel_lpss_platform_info spt_info = { 106 + static const struct intel_lpss_platform_info spt_spi_info = { 107 107 .clk_rate = 120000000, 108 108 .swnode = &spt_spi_node, 109 109 }; ··· 148 148 .properties = bxt_spi_properties, 149 149 }; 150 150 151 - static const struct intel_lpss_platform_info bxt_info = { 151 + static const struct intel_lpss_platform_info bxt_spi_info = { 152 152 .clk_rate = 100000000, 153 153 .swnode = &bxt_spi_node, 154 154 }; ··· 216 216 .properties = cnl_spi_properties, 217 217 }; 218 218 219 - static const struct intel_lpss_platform_info cnl_info = { 219 + static const struct intel_lpss_platform_info cnl_spi_info = { 220 220 .clk_rate = 120000000, 221 221 .swnode = &cnl_spi_node, 222 222 }; ··· 240 240 .properties = tgl_spi_properties, 241 241 }; 242 242 243 - static const struct intel_lpss_platform_info tgl_info = { 243 + static const struct intel_lpss_platform_info tgl_spi_info = { 244 244 .clk_rate = 100000000, 245 245 .swnode = &tgl_spi_node, 246 246 }; ··· 249 249 /* CML-LP */ 250 250 { PCI_VDEVICE(INTEL, 0x02a8), (kernel_ulong_t)&spt_uart_info }, 251 251 { PCI_VDEVICE(INTEL, 0x02a9), (kernel_ulong_t)&spt_uart_info }, 252 - { PCI_VDEVICE(INTEL, 0x02aa), (kernel_ulong_t)&cnl_info }, 253 - { PCI_VDEVICE(INTEL, 0x02ab), (kernel_ulong_t)&cnl_info }, 252 + { PCI_VDEVICE(INTEL, 0x02aa), (kernel_ulong_t)&cnl_spi_info }, 253 + { PCI_VDEVICE(INTEL, 0x02ab), (kernel_ulong_t)&cnl_spi_info }, 254 254 { PCI_VDEVICE(INTEL, 0x02c5), (kernel_ulong_t)&cnl_i2c_info }, 255 255 { PCI_VDEVICE(INTEL, 0x02c6), (kernel_ulong_t)&cnl_i2c_info }, 256 256 { PCI_VDEVICE(INTEL, 0x02c7), (kernel_ulong_t)&spt_uart_info }, ··· 258 258 { PCI_VDEVICE(INTEL, 0x02e9), (kernel_ulong_t)&cnl_i2c_info }, 259 259 { PCI_VDEVICE(INTEL, 0x02ea), (kernel_ulong_t)&cnl_i2c_info }, 260 260 { PCI_VDEVICE(INTEL, 0x02eb), (kernel_ulong_t)&cnl_i2c_info }, 261 - { PCI_VDEVICE(INTEL, 0x02fb), (kernel_ulong_t)&cnl_info }, 261 + { PCI_VDEVICE(INTEL, 0x02fb), (kernel_ulong_t)&cnl_spi_info }, 262 262 /* CML-H */ 263 263 { PCI_VDEVICE(INTEL, 0x06a8), (kernel_ulong_t)&spt_uart_info }, 264 264 { PCI_VDEVICE(INTEL, 0x06a9), (kernel_ulong_t)&spt_uart_info }, 265 - { PCI_VDEVICE(INTEL, 0x06aa), (kernel_ulong_t)&cnl_info }, 266 - { PCI_VDEVICE(INTEL, 0x06ab), (kernel_ulong_t)&cnl_info }, 265 + { PCI_VDEVICE(INTEL, 0x06aa), (kernel_ulong_t)&cnl_spi_info }, 266 + { PCI_VDEVICE(INTEL, 0x06ab), (kernel_ulong_t)&cnl_spi_info }, 267 267 { PCI_VDEVICE(INTEL, 0x06c7), (kernel_ulong_t)&spt_uart_info }, 268 268 { PCI_VDEVICE(INTEL, 0x06e8), (kernel_ulong_t)&cnl_i2c_info }, 269 269 { PCI_VDEVICE(INTEL, 0x06e9), (kernel_ulong_t)&cnl_i2c_info }, 270 270 { PCI_VDEVICE(INTEL, 0x06ea), (kernel_ulong_t)&cnl_i2c_info }, 271 271 { PCI_VDEVICE(INTEL, 0x06eb), (kernel_ulong_t)&cnl_i2c_info }, 272 - { PCI_VDEVICE(INTEL, 0x06fb), (kernel_ulong_t)&cnl_info }, 272 + { PCI_VDEVICE(INTEL, 0x06fb), (kernel_ulong_t)&cnl_spi_info }, 273 273 /* BXT A-Step */ 274 274 { PCI_VDEVICE(INTEL, 0x0aac), (kernel_ulong_t)&bxt_i2c_info }, 275 275 { PCI_VDEVICE(INTEL, 0x0aae), (kernel_ulong_t)&bxt_i2c_info }, ··· 282 282 { PCI_VDEVICE(INTEL, 0x0abc), (kernel_ulong_t)&bxt_uart_info }, 283 283 { PCI_VDEVICE(INTEL, 0x0abe), (kernel_ulong_t)&bxt_uart_info }, 284 284 { PCI_VDEVICE(INTEL, 0x0ac0), (kernel_ulong_t)&bxt_uart_info }, 285 - { PCI_VDEVICE(INTEL, 0x0ac2), (kernel_ulong_t)&bxt_info }, 286 - { PCI_VDEVICE(INTEL, 0x0ac4), (kernel_ulong_t)&bxt_info }, 287 - { PCI_VDEVICE(INTEL, 0x0ac6), (kernel_ulong_t)&bxt_info }, 285 + { PCI_VDEVICE(INTEL, 0x0ac2), (kernel_ulong_t)&bxt_spi_info }, 286 + { PCI_VDEVICE(INTEL, 0x0ac4), (kernel_ulong_t)&bxt_spi_info }, 287 + { PCI_VDEVICE(INTEL, 0x0ac6), (kernel_ulong_t)&bxt_spi_info }, 288 288 { PCI_VDEVICE(INTEL, 0x0aee), (kernel_ulong_t)&bxt_uart_info }, 289 289 /* BXT B-Step */ 290 290 { PCI_VDEVICE(INTEL, 0x1aac), (kernel_ulong_t)&bxt_i2c_info }, ··· 298 298 { PCI_VDEVICE(INTEL, 0x1abc), (kernel_ulong_t)&bxt_uart_info }, 299 299 { PCI_VDEVICE(INTEL, 0x1abe), (kernel_ulong_t)&bxt_uart_info }, 300 300 { PCI_VDEVICE(INTEL, 0x1ac0), (kernel_ulong_t)&bxt_uart_info }, 301 - { PCI_VDEVICE(INTEL, 0x1ac2), (kernel_ulong_t)&bxt_info }, 302 - { PCI_VDEVICE(INTEL, 0x1ac4), (kernel_ulong_t)&bxt_info }, 303 - { PCI_VDEVICE(INTEL, 0x1ac6), (kernel_ulong_t)&bxt_info }, 301 + { PCI_VDEVICE(INTEL, 0x1ac2), (kernel_ulong_t)&bxt_spi_info }, 302 + { PCI_VDEVICE(INTEL, 0x1ac4), (kernel_ulong_t)&bxt_spi_info }, 303 + { PCI_VDEVICE(INTEL, 0x1ac6), (kernel_ulong_t)&bxt_spi_info }, 304 304 { PCI_VDEVICE(INTEL, 0x1aee), (kernel_ulong_t)&bxt_uart_info }, 305 305 /* EBG */ 306 306 { PCI_VDEVICE(INTEL, 0x1bad), (kernel_ulong_t)&bxt_uart_info }, ··· 317 317 { PCI_VDEVICE(INTEL, 0x31bc), (kernel_ulong_t)&bxt_uart_info }, 318 318 { PCI_VDEVICE(INTEL, 0x31be), (kernel_ulong_t)&bxt_uart_info }, 319 319 { PCI_VDEVICE(INTEL, 0x31c0), (kernel_ulong_t)&bxt_uart_info }, 320 - { PCI_VDEVICE(INTEL, 0x31c2), (kernel_ulong_t)&bxt_info }, 321 - { PCI_VDEVICE(INTEL, 0x31c4), (kernel_ulong_t)&bxt_info }, 322 - { PCI_VDEVICE(INTEL, 0x31c6), (kernel_ulong_t)&bxt_info }, 320 + { PCI_VDEVICE(INTEL, 0x31c2), (kernel_ulong_t)&bxt_spi_info }, 321 + { PCI_VDEVICE(INTEL, 0x31c4), (kernel_ulong_t)&bxt_spi_info }, 322 + { PCI_VDEVICE(INTEL, 0x31c6), (kernel_ulong_t)&bxt_spi_info }, 323 323 { PCI_VDEVICE(INTEL, 0x31ee), (kernel_ulong_t)&bxt_uart_info }, 324 324 /* ICL-LP */ 325 325 { PCI_VDEVICE(INTEL, 0x34a8), (kernel_ulong_t)&spt_uart_info }, 326 326 { PCI_VDEVICE(INTEL, 0x34a9), (kernel_ulong_t)&spt_uart_info }, 327 - { PCI_VDEVICE(INTEL, 0x34aa), (kernel_ulong_t)&cnl_info }, 328 - { PCI_VDEVICE(INTEL, 0x34ab), (kernel_ulong_t)&cnl_info }, 327 + { PCI_VDEVICE(INTEL, 0x34aa), (kernel_ulong_t)&cnl_spi_info }, 328 + { PCI_VDEVICE(INTEL, 0x34ab), (kernel_ulong_t)&cnl_spi_info }, 329 329 { PCI_VDEVICE(INTEL, 0x34c5), (kernel_ulong_t)&bxt_i2c_info }, 330 330 { PCI_VDEVICE(INTEL, 0x34c6), (kernel_ulong_t)&bxt_i2c_info }, 331 331 { PCI_VDEVICE(INTEL, 0x34c7), (kernel_ulong_t)&spt_uart_info }, ··· 333 333 { PCI_VDEVICE(INTEL, 0x34e9), (kernel_ulong_t)&bxt_i2c_info }, 334 334 { PCI_VDEVICE(INTEL, 0x34ea), (kernel_ulong_t)&bxt_i2c_info }, 335 335 { PCI_VDEVICE(INTEL, 0x34eb), (kernel_ulong_t)&bxt_i2c_info }, 336 - { PCI_VDEVICE(INTEL, 0x34fb), (kernel_ulong_t)&cnl_info }, 336 + { PCI_VDEVICE(INTEL, 0x34fb), (kernel_ulong_t)&cnl_spi_info }, 337 337 /* ICL-N */ 338 338 { PCI_VDEVICE(INTEL, 0x38a8), (kernel_ulong_t)&spt_uart_info }, 339 339 /* TGL-H */ 340 340 { PCI_VDEVICE(INTEL, 0x43a7), (kernel_ulong_t)&bxt_uart_info }, 341 341 { PCI_VDEVICE(INTEL, 0x43a8), (kernel_ulong_t)&bxt_uart_info }, 342 342 { PCI_VDEVICE(INTEL, 0x43a9), (kernel_ulong_t)&bxt_uart_info }, 343 - { PCI_VDEVICE(INTEL, 0x43aa), (kernel_ulong_t)&tgl_info }, 344 - { PCI_VDEVICE(INTEL, 0x43ab), (kernel_ulong_t)&tgl_info }, 343 + { PCI_VDEVICE(INTEL, 0x43aa), (kernel_ulong_t)&tgl_spi_info }, 344 + { PCI_VDEVICE(INTEL, 0x43ab), (kernel_ulong_t)&tgl_spi_info }, 345 345 { PCI_VDEVICE(INTEL, 0x43ad), (kernel_ulong_t)&bxt_i2c_info }, 346 346 { PCI_VDEVICE(INTEL, 0x43ae), (kernel_ulong_t)&bxt_i2c_info }, 347 347 { PCI_VDEVICE(INTEL, 0x43d8), (kernel_ulong_t)&bxt_i2c_info }, ··· 350 350 { PCI_VDEVICE(INTEL, 0x43e9), (kernel_ulong_t)&bxt_i2c_info }, 351 351 { PCI_VDEVICE(INTEL, 0x43ea), (kernel_ulong_t)&bxt_i2c_info }, 352 352 { PCI_VDEVICE(INTEL, 0x43eb), (kernel_ulong_t)&bxt_i2c_info }, 353 - { PCI_VDEVICE(INTEL, 0x43fb), (kernel_ulong_t)&tgl_info }, 354 - { PCI_VDEVICE(INTEL, 0x43fd), (kernel_ulong_t)&tgl_info }, 353 + { PCI_VDEVICE(INTEL, 0x43fb), (kernel_ulong_t)&tgl_spi_info }, 354 + { PCI_VDEVICE(INTEL, 0x43fd), (kernel_ulong_t)&tgl_spi_info }, 355 355 /* EHL */ 356 356 { PCI_VDEVICE(INTEL, 0x4b28), (kernel_ulong_t)&bxt_uart_info }, 357 357 { PCI_VDEVICE(INTEL, 0x4b29), (kernel_ulong_t)&bxt_uart_info }, 358 - { PCI_VDEVICE(INTEL, 0x4b2a), (kernel_ulong_t)&bxt_info }, 359 - { PCI_VDEVICE(INTEL, 0x4b2b), (kernel_ulong_t)&bxt_info }, 360 - { PCI_VDEVICE(INTEL, 0x4b37), (kernel_ulong_t)&bxt_info }, 358 + { PCI_VDEVICE(INTEL, 0x4b2a), (kernel_ulong_t)&bxt_spi_info }, 359 + { PCI_VDEVICE(INTEL, 0x4b2b), (kernel_ulong_t)&bxt_spi_info }, 360 + { PCI_VDEVICE(INTEL, 0x4b37), (kernel_ulong_t)&bxt_spi_info }, 361 361 { PCI_VDEVICE(INTEL, 0x4b44), (kernel_ulong_t)&ehl_i2c_info }, 362 362 { PCI_VDEVICE(INTEL, 0x4b45), (kernel_ulong_t)&ehl_i2c_info }, 363 363 { PCI_VDEVICE(INTEL, 0x4b4b), (kernel_ulong_t)&ehl_i2c_info }, ··· 370 370 /* JSL */ 371 371 { PCI_VDEVICE(INTEL, 0x4da8), (kernel_ulong_t)&spt_uart_info }, 372 372 { PCI_VDEVICE(INTEL, 0x4da9), (kernel_ulong_t)&spt_uart_info }, 373 - { PCI_VDEVICE(INTEL, 0x4daa), (kernel_ulong_t)&cnl_info }, 374 - { PCI_VDEVICE(INTEL, 0x4dab), (kernel_ulong_t)&cnl_info }, 373 + { PCI_VDEVICE(INTEL, 0x4daa), (kernel_ulong_t)&cnl_spi_info }, 374 + { PCI_VDEVICE(INTEL, 0x4dab), (kernel_ulong_t)&cnl_spi_info }, 375 375 { PCI_VDEVICE(INTEL, 0x4dc5), (kernel_ulong_t)&bxt_i2c_info }, 376 376 { PCI_VDEVICE(INTEL, 0x4dc6), (kernel_ulong_t)&bxt_i2c_info }, 377 377 { PCI_VDEVICE(INTEL, 0x4dc7), (kernel_ulong_t)&spt_uart_info }, ··· 379 379 { PCI_VDEVICE(INTEL, 0x4de9), (kernel_ulong_t)&bxt_i2c_info }, 380 380 { PCI_VDEVICE(INTEL, 0x4dea), (kernel_ulong_t)&bxt_i2c_info }, 381 381 { PCI_VDEVICE(INTEL, 0x4deb), (kernel_ulong_t)&bxt_i2c_info }, 382 - { PCI_VDEVICE(INTEL, 0x4dfb), (kernel_ulong_t)&cnl_info }, 382 + { PCI_VDEVICE(INTEL, 0x4dfb), (kernel_ulong_t)&cnl_spi_info }, 383 383 /* ADL-P */ 384 384 { PCI_VDEVICE(INTEL, 0x51a8), (kernel_ulong_t)&bxt_uart_info }, 385 385 { PCI_VDEVICE(INTEL, 0x51a9), (kernel_ulong_t)&bxt_uart_info }, 386 - { PCI_VDEVICE(INTEL, 0x51aa), (kernel_ulong_t)&tgl_info }, 387 - { PCI_VDEVICE(INTEL, 0x51ab), (kernel_ulong_t)&tgl_info }, 386 + { PCI_VDEVICE(INTEL, 0x51aa), (kernel_ulong_t)&tgl_spi_info }, 387 + { PCI_VDEVICE(INTEL, 0x51ab), (kernel_ulong_t)&tgl_spi_info }, 388 388 { PCI_VDEVICE(INTEL, 0x51c5), (kernel_ulong_t)&bxt_i2c_info }, 389 389 { PCI_VDEVICE(INTEL, 0x51c6), (kernel_ulong_t)&bxt_i2c_info }, 390 390 { PCI_VDEVICE(INTEL, 0x51c7), (kernel_ulong_t)&bxt_uart_info }, ··· 394 394 { PCI_VDEVICE(INTEL, 0x51e9), (kernel_ulong_t)&bxt_i2c_info }, 395 395 { PCI_VDEVICE(INTEL, 0x51ea), (kernel_ulong_t)&bxt_i2c_info }, 396 396 { PCI_VDEVICE(INTEL, 0x51eb), (kernel_ulong_t)&bxt_i2c_info }, 397 - { PCI_VDEVICE(INTEL, 0x51fb), (kernel_ulong_t)&tgl_info }, 397 + { PCI_VDEVICE(INTEL, 0x51fb), (kernel_ulong_t)&tgl_spi_info }, 398 398 /* ADL-M */ 399 399 { PCI_VDEVICE(INTEL, 0x54a8), (kernel_ulong_t)&bxt_uart_info }, 400 400 { PCI_VDEVICE(INTEL, 0x54a9), (kernel_ulong_t)&bxt_uart_info }, 401 - { PCI_VDEVICE(INTEL, 0x54aa), (kernel_ulong_t)&tgl_info }, 402 - { PCI_VDEVICE(INTEL, 0x54ab), (kernel_ulong_t)&tgl_info }, 401 + { PCI_VDEVICE(INTEL, 0x54aa), (kernel_ulong_t)&tgl_spi_info }, 402 + { PCI_VDEVICE(INTEL, 0x54ab), (kernel_ulong_t)&tgl_spi_info }, 403 403 { PCI_VDEVICE(INTEL, 0x54c5), (kernel_ulong_t)&bxt_i2c_info }, 404 404 { PCI_VDEVICE(INTEL, 0x54c6), (kernel_ulong_t)&bxt_i2c_info }, 405 405 { PCI_VDEVICE(INTEL, 0x54c7), (kernel_ulong_t)&bxt_uart_info }, ··· 407 407 { PCI_VDEVICE(INTEL, 0x54e9), (kernel_ulong_t)&bxt_i2c_info }, 408 408 { PCI_VDEVICE(INTEL, 0x54ea), (kernel_ulong_t)&bxt_i2c_info }, 409 409 { PCI_VDEVICE(INTEL, 0x54eb), (kernel_ulong_t)&bxt_i2c_info }, 410 - { PCI_VDEVICE(INTEL, 0x54fb), (kernel_ulong_t)&tgl_info }, 410 + { PCI_VDEVICE(INTEL, 0x54fb), (kernel_ulong_t)&tgl_spi_info }, 411 411 /* APL */ 412 412 { PCI_VDEVICE(INTEL, 0x5aac), (kernel_ulong_t)&apl_i2c_info }, 413 413 { PCI_VDEVICE(INTEL, 0x5aae), (kernel_ulong_t)&apl_i2c_info }, ··· 420 420 { PCI_VDEVICE(INTEL, 0x5abc), (kernel_ulong_t)&bxt_uart_info }, 421 421 { PCI_VDEVICE(INTEL, 0x5abe), (kernel_ulong_t)&bxt_uart_info }, 422 422 { PCI_VDEVICE(INTEL, 0x5ac0), (kernel_ulong_t)&bxt_uart_info }, 423 - { PCI_VDEVICE(INTEL, 0x5ac2), (kernel_ulong_t)&bxt_info }, 424 - { PCI_VDEVICE(INTEL, 0x5ac4), (kernel_ulong_t)&bxt_info }, 425 - { PCI_VDEVICE(INTEL, 0x5ac6), (kernel_ulong_t)&bxt_info }, 423 + { PCI_VDEVICE(INTEL, 0x5ac2), (kernel_ulong_t)&bxt_spi_info }, 424 + { PCI_VDEVICE(INTEL, 0x5ac4), (kernel_ulong_t)&bxt_spi_info }, 425 + { PCI_VDEVICE(INTEL, 0x5ac6), (kernel_ulong_t)&bxt_spi_info }, 426 426 { PCI_VDEVICE(INTEL, 0x5aee), (kernel_ulong_t)&bxt_uart_info }, 427 427 /* RPL-S */ 428 428 { PCI_VDEVICE(INTEL, 0x7a28), (kernel_ulong_t)&bxt_uart_info }, 429 429 { PCI_VDEVICE(INTEL, 0x7a29), (kernel_ulong_t)&bxt_uart_info }, 430 - { PCI_VDEVICE(INTEL, 0x7a2a), (kernel_ulong_t)&tgl_info }, 431 - { PCI_VDEVICE(INTEL, 0x7a2b), (kernel_ulong_t)&tgl_info }, 430 + { PCI_VDEVICE(INTEL, 0x7a2a), (kernel_ulong_t)&tgl_spi_info }, 431 + { PCI_VDEVICE(INTEL, 0x7a2b), (kernel_ulong_t)&tgl_spi_info }, 432 432 { PCI_VDEVICE(INTEL, 0x7a4c), (kernel_ulong_t)&bxt_i2c_info }, 433 433 { PCI_VDEVICE(INTEL, 0x7a4d), (kernel_ulong_t)&bxt_i2c_info }, 434 434 { PCI_VDEVICE(INTEL, 0x7a4e), (kernel_ulong_t)&bxt_i2c_info }, 435 435 { PCI_VDEVICE(INTEL, 0x7a4f), (kernel_ulong_t)&bxt_i2c_info }, 436 436 { PCI_VDEVICE(INTEL, 0x7a5c), (kernel_ulong_t)&bxt_uart_info }, 437 - { PCI_VDEVICE(INTEL, 0x7a79), (kernel_ulong_t)&tgl_info }, 438 - { PCI_VDEVICE(INTEL, 0x7a7b), (kernel_ulong_t)&tgl_info }, 437 + { PCI_VDEVICE(INTEL, 0x7a79), (kernel_ulong_t)&tgl_spi_info }, 438 + { PCI_VDEVICE(INTEL, 0x7a7b), (kernel_ulong_t)&tgl_spi_info }, 439 439 { PCI_VDEVICE(INTEL, 0x7a7c), (kernel_ulong_t)&bxt_i2c_info }, 440 440 { PCI_VDEVICE(INTEL, 0x7a7d), (kernel_ulong_t)&bxt_i2c_info }, 441 441 { PCI_VDEVICE(INTEL, 0x7a7e), (kernel_ulong_t)&bxt_uart_info }, 442 442 /* ADL-S */ 443 443 { PCI_VDEVICE(INTEL, 0x7aa8), (kernel_ulong_t)&bxt_uart_info }, 444 444 { PCI_VDEVICE(INTEL, 0x7aa9), (kernel_ulong_t)&bxt_uart_info }, 445 - { PCI_VDEVICE(INTEL, 0x7aaa), (kernel_ulong_t)&tgl_info }, 446 - { PCI_VDEVICE(INTEL, 0x7aab), (kernel_ulong_t)&tgl_info }, 445 + { PCI_VDEVICE(INTEL, 0x7aaa), (kernel_ulong_t)&tgl_spi_info }, 446 + { PCI_VDEVICE(INTEL, 0x7aab), (kernel_ulong_t)&tgl_spi_info }, 447 447 { PCI_VDEVICE(INTEL, 0x7acc), (kernel_ulong_t)&bxt_i2c_info }, 448 448 { PCI_VDEVICE(INTEL, 0x7acd), (kernel_ulong_t)&bxt_i2c_info }, 449 449 { PCI_VDEVICE(INTEL, 0x7ace), (kernel_ulong_t)&bxt_i2c_info }, 450 450 { PCI_VDEVICE(INTEL, 0x7acf), (kernel_ulong_t)&bxt_i2c_info }, 451 451 { PCI_VDEVICE(INTEL, 0x7adc), (kernel_ulong_t)&bxt_uart_info }, 452 - { PCI_VDEVICE(INTEL, 0x7af9), (kernel_ulong_t)&tgl_info }, 453 - { PCI_VDEVICE(INTEL, 0x7afb), (kernel_ulong_t)&tgl_info }, 452 + { PCI_VDEVICE(INTEL, 0x7af9), (kernel_ulong_t)&tgl_spi_info }, 453 + { PCI_VDEVICE(INTEL, 0x7afb), (kernel_ulong_t)&tgl_spi_info }, 454 454 { PCI_VDEVICE(INTEL, 0x7afc), (kernel_ulong_t)&bxt_i2c_info }, 455 455 { PCI_VDEVICE(INTEL, 0x7afd), (kernel_ulong_t)&bxt_i2c_info }, 456 456 { PCI_VDEVICE(INTEL, 0x7afe), (kernel_ulong_t)&bxt_uart_info }, 457 457 /* MTL-P */ 458 458 { PCI_VDEVICE(INTEL, 0x7e25), (kernel_ulong_t)&bxt_uart_info }, 459 459 { PCI_VDEVICE(INTEL, 0x7e26), (kernel_ulong_t)&bxt_uart_info }, 460 - { PCI_VDEVICE(INTEL, 0x7e27), (kernel_ulong_t)&tgl_info }, 461 - { PCI_VDEVICE(INTEL, 0x7e30), (kernel_ulong_t)&tgl_info }, 462 - { PCI_VDEVICE(INTEL, 0x7e46), (kernel_ulong_t)&tgl_info }, 460 + { PCI_VDEVICE(INTEL, 0x7e27), (kernel_ulong_t)&tgl_spi_info }, 461 + { PCI_VDEVICE(INTEL, 0x7e30), (kernel_ulong_t)&tgl_spi_info }, 462 + { PCI_VDEVICE(INTEL, 0x7e46), (kernel_ulong_t)&tgl_spi_info }, 463 463 { PCI_VDEVICE(INTEL, 0x7e50), (kernel_ulong_t)&bxt_i2c_info }, 464 464 { PCI_VDEVICE(INTEL, 0x7e51), (kernel_ulong_t)&bxt_i2c_info }, 465 465 { PCI_VDEVICE(INTEL, 0x7e52), (kernel_ulong_t)&bxt_uart_info }, ··· 470 470 /* MTP-S */ 471 471 { PCI_VDEVICE(INTEL, 0x7f28), (kernel_ulong_t)&bxt_uart_info }, 472 472 { PCI_VDEVICE(INTEL, 0x7f29), (kernel_ulong_t)&bxt_uart_info }, 473 - { PCI_VDEVICE(INTEL, 0x7f2a), (kernel_ulong_t)&tgl_info }, 474 - { PCI_VDEVICE(INTEL, 0x7f2b), (kernel_ulong_t)&tgl_info }, 473 + { PCI_VDEVICE(INTEL, 0x7f2a), (kernel_ulong_t)&tgl_spi_info }, 474 + { PCI_VDEVICE(INTEL, 0x7f2b), (kernel_ulong_t)&tgl_spi_info }, 475 475 { PCI_VDEVICE(INTEL, 0x7f4c), (kernel_ulong_t)&bxt_i2c_info }, 476 476 { PCI_VDEVICE(INTEL, 0x7f4d), (kernel_ulong_t)&bxt_i2c_info }, 477 477 { PCI_VDEVICE(INTEL, 0x7f4e), (kernel_ulong_t)&bxt_i2c_info }, 478 478 { PCI_VDEVICE(INTEL, 0x7f4f), (kernel_ulong_t)&bxt_i2c_info }, 479 479 { PCI_VDEVICE(INTEL, 0x7f5c), (kernel_ulong_t)&bxt_uart_info }, 480 480 { PCI_VDEVICE(INTEL, 0x7f5d), (kernel_ulong_t)&bxt_uart_info }, 481 - { PCI_VDEVICE(INTEL, 0x7f5e), (kernel_ulong_t)&tgl_info }, 482 - { PCI_VDEVICE(INTEL, 0x7f5f), (kernel_ulong_t)&tgl_info }, 481 + { PCI_VDEVICE(INTEL, 0x7f5e), (kernel_ulong_t)&tgl_spi_info }, 482 + { PCI_VDEVICE(INTEL, 0x7f5f), (kernel_ulong_t)&tgl_spi_info }, 483 483 { PCI_VDEVICE(INTEL, 0x7f7a), (kernel_ulong_t)&bxt_i2c_info }, 484 484 { PCI_VDEVICE(INTEL, 0x7f7b), (kernel_ulong_t)&bxt_i2c_info }, 485 485 /* LKF */ 486 486 { PCI_VDEVICE(INTEL, 0x98a8), (kernel_ulong_t)&bxt_uart_info }, 487 487 { PCI_VDEVICE(INTEL, 0x98a9), (kernel_ulong_t)&bxt_uart_info }, 488 - { PCI_VDEVICE(INTEL, 0x98aa), (kernel_ulong_t)&bxt_info }, 488 + { PCI_VDEVICE(INTEL, 0x98aa), (kernel_ulong_t)&bxt_spi_info }, 489 489 { PCI_VDEVICE(INTEL, 0x98c5), (kernel_ulong_t)&bxt_i2c_info }, 490 490 { PCI_VDEVICE(INTEL, 0x98c6), (kernel_ulong_t)&bxt_i2c_info }, 491 491 { PCI_VDEVICE(INTEL, 0x98c7), (kernel_ulong_t)&bxt_uart_info }, ··· 496 496 /* SPT-LP */ 497 497 { PCI_VDEVICE(INTEL, 0x9d27), (kernel_ulong_t)&spt_uart_info }, 498 498 { PCI_VDEVICE(INTEL, 0x9d28), (kernel_ulong_t)&spt_uart_info }, 499 - { PCI_VDEVICE(INTEL, 0x9d29), (kernel_ulong_t)&spt_info }, 500 - { PCI_VDEVICE(INTEL, 0x9d2a), (kernel_ulong_t)&spt_info }, 499 + { PCI_VDEVICE(INTEL, 0x9d29), (kernel_ulong_t)&spt_spi_info }, 500 + { PCI_VDEVICE(INTEL, 0x9d2a), (kernel_ulong_t)&spt_spi_info }, 501 501 { PCI_VDEVICE(INTEL, 0x9d60), (kernel_ulong_t)&spt_i2c_info }, 502 502 { PCI_VDEVICE(INTEL, 0x9d61), (kernel_ulong_t)&spt_i2c_info }, 503 503 { PCI_VDEVICE(INTEL, 0x9d62), (kernel_ulong_t)&spt_i2c_info }, ··· 508 508 /* CNL-LP */ 509 509 { PCI_VDEVICE(INTEL, 0x9da8), (kernel_ulong_t)&spt_uart_info }, 510 510 { PCI_VDEVICE(INTEL, 0x9da9), (kernel_ulong_t)&spt_uart_info }, 511 - { PCI_VDEVICE(INTEL, 0x9daa), (kernel_ulong_t)&cnl_info }, 512 - { PCI_VDEVICE(INTEL, 0x9dab), (kernel_ulong_t)&cnl_info }, 511 + { PCI_VDEVICE(INTEL, 0x9daa), (kernel_ulong_t)&cnl_spi_info }, 512 + { PCI_VDEVICE(INTEL, 0x9dab), (kernel_ulong_t)&cnl_spi_info }, 513 513 { PCI_VDEVICE(INTEL, 0x9dc5), (kernel_ulong_t)&cnl_i2c_info }, 514 514 { PCI_VDEVICE(INTEL, 0x9dc6), (kernel_ulong_t)&cnl_i2c_info }, 515 515 { PCI_VDEVICE(INTEL, 0x9dc7), (kernel_ulong_t)&spt_uart_info }, ··· 517 517 { PCI_VDEVICE(INTEL, 0x9de9), (kernel_ulong_t)&cnl_i2c_info }, 518 518 { PCI_VDEVICE(INTEL, 0x9dea), (kernel_ulong_t)&cnl_i2c_info }, 519 519 { PCI_VDEVICE(INTEL, 0x9deb), (kernel_ulong_t)&cnl_i2c_info }, 520 - { PCI_VDEVICE(INTEL, 0x9dfb), (kernel_ulong_t)&cnl_info }, 520 + { PCI_VDEVICE(INTEL, 0x9dfb), (kernel_ulong_t)&cnl_spi_info }, 521 521 /* TGL-LP */ 522 522 { PCI_VDEVICE(INTEL, 0xa0a8), (kernel_ulong_t)&bxt_uart_info }, 523 523 { PCI_VDEVICE(INTEL, 0xa0a9), (kernel_ulong_t)&bxt_uart_info }, 524 - { PCI_VDEVICE(INTEL, 0xa0aa), (kernel_ulong_t)&cnl_info }, 525 - { PCI_VDEVICE(INTEL, 0xa0ab), (kernel_ulong_t)&cnl_info }, 524 + { PCI_VDEVICE(INTEL, 0xa0aa), (kernel_ulong_t)&cnl_spi_info }, 525 + { PCI_VDEVICE(INTEL, 0xa0ab), (kernel_ulong_t)&cnl_spi_info }, 526 526 { PCI_VDEVICE(INTEL, 0xa0c5), (kernel_ulong_t)&spt_i2c_info }, 527 527 { PCI_VDEVICE(INTEL, 0xa0c6), (kernel_ulong_t)&spt_i2c_info }, 528 528 { PCI_VDEVICE(INTEL, 0xa0c7), (kernel_ulong_t)&bxt_uart_info }, ··· 532 532 { PCI_VDEVICE(INTEL, 0xa0db), (kernel_ulong_t)&bxt_uart_info }, 533 533 { PCI_VDEVICE(INTEL, 0xa0dc), (kernel_ulong_t)&bxt_uart_info }, 534 534 { PCI_VDEVICE(INTEL, 0xa0dd), (kernel_ulong_t)&bxt_uart_info }, 535 - { PCI_VDEVICE(INTEL, 0xa0de), (kernel_ulong_t)&cnl_info }, 536 - { PCI_VDEVICE(INTEL, 0xa0df), (kernel_ulong_t)&cnl_info }, 535 + { PCI_VDEVICE(INTEL, 0xa0de), (kernel_ulong_t)&cnl_spi_info }, 536 + { PCI_VDEVICE(INTEL, 0xa0df), (kernel_ulong_t)&cnl_spi_info }, 537 537 { PCI_VDEVICE(INTEL, 0xa0e8), (kernel_ulong_t)&spt_i2c_info }, 538 538 { PCI_VDEVICE(INTEL, 0xa0e9), (kernel_ulong_t)&spt_i2c_info }, 539 539 { PCI_VDEVICE(INTEL, 0xa0ea), (kernel_ulong_t)&spt_i2c_info }, 540 540 { PCI_VDEVICE(INTEL, 0xa0eb), (kernel_ulong_t)&spt_i2c_info }, 541 - { PCI_VDEVICE(INTEL, 0xa0fb), (kernel_ulong_t)&cnl_info }, 542 - { PCI_VDEVICE(INTEL, 0xa0fd), (kernel_ulong_t)&cnl_info }, 543 - { PCI_VDEVICE(INTEL, 0xa0fe), (kernel_ulong_t)&cnl_info }, 541 + { PCI_VDEVICE(INTEL, 0xa0fb), (kernel_ulong_t)&cnl_spi_info }, 542 + { PCI_VDEVICE(INTEL, 0xa0fd), (kernel_ulong_t)&cnl_spi_info }, 543 + { PCI_VDEVICE(INTEL, 0xa0fe), (kernel_ulong_t)&cnl_spi_info }, 544 544 /* SPT-H */ 545 545 { PCI_VDEVICE(INTEL, 0xa127), (kernel_ulong_t)&spt_uart_info }, 546 546 { PCI_VDEVICE(INTEL, 0xa128), (kernel_ulong_t)&spt_uart_info }, 547 - { PCI_VDEVICE(INTEL, 0xa129), (kernel_ulong_t)&spt_info }, 548 - { PCI_VDEVICE(INTEL, 0xa12a), (kernel_ulong_t)&spt_info }, 547 + { PCI_VDEVICE(INTEL, 0xa129), (kernel_ulong_t)&spt_spi_info }, 548 + { PCI_VDEVICE(INTEL, 0xa12a), (kernel_ulong_t)&spt_spi_info }, 549 549 { PCI_VDEVICE(INTEL, 0xa160), (kernel_ulong_t)&spt_i2c_info }, 550 550 { PCI_VDEVICE(INTEL, 0xa161), (kernel_ulong_t)&spt_i2c_info }, 551 551 { PCI_VDEVICE(INTEL, 0xa162), (kernel_ulong_t)&spt_i2c_info }, ··· 553 553 /* KBL-H */ 554 554 { PCI_VDEVICE(INTEL, 0xa2a7), (kernel_ulong_t)&spt_uart_info }, 555 555 { PCI_VDEVICE(INTEL, 0xa2a8), (kernel_ulong_t)&spt_uart_info }, 556 - { PCI_VDEVICE(INTEL, 0xa2a9), (kernel_ulong_t)&spt_info }, 557 - { PCI_VDEVICE(INTEL, 0xa2aa), (kernel_ulong_t)&spt_info }, 556 + { PCI_VDEVICE(INTEL, 0xa2a9), (kernel_ulong_t)&spt_spi_info }, 557 + { PCI_VDEVICE(INTEL, 0xa2aa), (kernel_ulong_t)&spt_spi_info }, 558 558 { PCI_VDEVICE(INTEL, 0xa2e0), (kernel_ulong_t)&spt_i2c_info }, 559 559 { PCI_VDEVICE(INTEL, 0xa2e1), (kernel_ulong_t)&spt_i2c_info }, 560 560 { PCI_VDEVICE(INTEL, 0xa2e2), (kernel_ulong_t)&spt_i2c_info }, ··· 563 563 /* CNL-H */ 564 564 { PCI_VDEVICE(INTEL, 0xa328), (kernel_ulong_t)&spt_uart_info }, 565 565 { PCI_VDEVICE(INTEL, 0xa329), (kernel_ulong_t)&spt_uart_info }, 566 - { PCI_VDEVICE(INTEL, 0xa32a), (kernel_ulong_t)&cnl_info }, 567 - { PCI_VDEVICE(INTEL, 0xa32b), (kernel_ulong_t)&cnl_info }, 566 + { PCI_VDEVICE(INTEL, 0xa32a), (kernel_ulong_t)&cnl_spi_info }, 567 + { PCI_VDEVICE(INTEL, 0xa32b), (kernel_ulong_t)&cnl_spi_info }, 568 568 { PCI_VDEVICE(INTEL, 0xa347), (kernel_ulong_t)&spt_uart_info }, 569 569 { PCI_VDEVICE(INTEL, 0xa368), (kernel_ulong_t)&cnl_i2c_info }, 570 570 { PCI_VDEVICE(INTEL, 0xa369), (kernel_ulong_t)&cnl_i2c_info }, 571 571 { PCI_VDEVICE(INTEL, 0xa36a), (kernel_ulong_t)&cnl_i2c_info }, 572 572 { PCI_VDEVICE(INTEL, 0xa36b), (kernel_ulong_t)&cnl_i2c_info }, 573 - { PCI_VDEVICE(INTEL, 0xa37b), (kernel_ulong_t)&cnl_info }, 573 + { PCI_VDEVICE(INTEL, 0xa37b), (kernel_ulong_t)&cnl_spi_info }, 574 574 /* CML-V */ 575 575 { PCI_VDEVICE(INTEL, 0xa3a7), (kernel_ulong_t)&spt_uart_info }, 576 576 { PCI_VDEVICE(INTEL, 0xa3a8), (kernel_ulong_t)&spt_uart_info }, 577 - { PCI_VDEVICE(INTEL, 0xa3a9), (kernel_ulong_t)&spt_info }, 578 - { PCI_VDEVICE(INTEL, 0xa3aa), (kernel_ulong_t)&spt_info }, 577 + { PCI_VDEVICE(INTEL, 0xa3a9), (kernel_ulong_t)&spt_spi_info }, 578 + { PCI_VDEVICE(INTEL, 0xa3aa), (kernel_ulong_t)&spt_spi_info }, 579 579 { PCI_VDEVICE(INTEL, 0xa3e0), (kernel_ulong_t)&spt_i2c_info }, 580 580 { PCI_VDEVICE(INTEL, 0xa3e1), (kernel_ulong_t)&spt_i2c_info }, 581 581 { PCI_VDEVICE(INTEL, 0xa3e2), (kernel_ulong_t)&spt_i2c_info }, ··· 584 584 /* LNL-M */ 585 585 { PCI_VDEVICE(INTEL, 0xa825), (kernel_ulong_t)&bxt_uart_info }, 586 586 { PCI_VDEVICE(INTEL, 0xa826), (kernel_ulong_t)&bxt_uart_info }, 587 - { PCI_VDEVICE(INTEL, 0xa827), (kernel_ulong_t)&tgl_info }, 588 - { PCI_VDEVICE(INTEL, 0xa830), (kernel_ulong_t)&tgl_info }, 589 - { PCI_VDEVICE(INTEL, 0xa846), (kernel_ulong_t)&tgl_info }, 587 + { PCI_VDEVICE(INTEL, 0xa827), (kernel_ulong_t)&tgl_spi_info }, 588 + { PCI_VDEVICE(INTEL, 0xa830), (kernel_ulong_t)&tgl_spi_info }, 589 + { PCI_VDEVICE(INTEL, 0xa846), (kernel_ulong_t)&tgl_spi_info }, 590 590 { PCI_VDEVICE(INTEL, 0xa850), (kernel_ulong_t)&ehl_i2c_info }, 591 591 { PCI_VDEVICE(INTEL, 0xa851), (kernel_ulong_t)&ehl_i2c_info }, 592 592 { PCI_VDEVICE(INTEL, 0xa852), (kernel_ulong_t)&bxt_uart_info },
+1
drivers/mfd/intel_soc_pmic_bxtwc.c
··· 581 581 582 582 module_platform_driver(bxtwc_driver); 583 583 584 + MODULE_DESCRIPTION("Intel Broxton Whiskey Cove PMIC MFD core driver"); 584 585 MODULE_LICENSE("GPL v2"); 585 586 MODULE_AUTHOR("Qipeng Zha <qipeng.zha@intel.com>");
+3 -1
drivers/mfd/intel_soc_pmic_crc.c
··· 137 137 138 138 /* PWM consumed by the Intel GFX */ 139 139 static struct pwm_lookup crc_pwm_lookup[] = { 140 - PWM_LOOKUP("crystal_cove_pwm", 0, "0000:00:02.0", "pwm_pmic_backlight", 0, PWM_POLARITY_NORMAL), 140 + PWM_LOOKUP_WITH_MODULE("crystal_cove_pwm", 0, "0000:00:02.0", 141 + "pwm_pmic_backlight", 0, PWM_POLARITY_NORMAL, 142 + "pwm-crc"), 141 143 }; 142 144 143 145 struct crystal_cove_config {
+9 -19
drivers/mfd/lm3533-core.c
··· 11 11 #include <linux/init.h> 12 12 #include <linux/kernel.h> 13 13 #include <linux/err.h> 14 - #include <linux/gpio.h> 14 + #include <linux/gpio/consumer.h> 15 15 #include <linux/i2c.h> 16 16 #include <linux/mfd/core.h> 17 17 #include <linux/regmap.h> ··· 225 225 226 226 static void lm3533_enable(struct lm3533 *lm3533) 227 227 { 228 - if (gpio_is_valid(lm3533->gpio_hwen)) 229 - gpio_set_value(lm3533->gpio_hwen, 1); 228 + gpiod_set_value(lm3533->hwen, 1); 230 229 } 231 230 232 231 static void lm3533_disable(struct lm3533 *lm3533) 233 232 { 234 - if (gpio_is_valid(lm3533->gpio_hwen)) 235 - gpio_set_value(lm3533->gpio_hwen, 0); 233 + gpiod_set_value(lm3533->hwen, 0); 236 234 } 237 235 238 236 enum lm3533_attribute_type { ··· 481 483 return -EINVAL; 482 484 } 483 485 484 - lm3533->gpio_hwen = pdata->gpio_hwen; 485 - 486 - if (gpio_is_valid(lm3533->gpio_hwen)) { 487 - ret = devm_gpio_request_one(lm3533->dev, lm3533->gpio_hwen, 488 - GPIOF_OUT_INIT_LOW, "lm3533-hwen"); 489 - if (ret < 0) { 490 - dev_err(lm3533->dev, 491 - "failed to request HWEN GPIO %d\n", 492 - lm3533->gpio_hwen); 493 - return ret; 494 - } 495 - } 486 + lm3533->hwen = devm_gpiod_get(lm3533->dev, NULL, GPIOD_OUT_LOW); 487 + if (IS_ERR(lm3533->hwen)) 488 + return dev_err_probe(lm3533->dev, PTR_ERR(lm3533->hwen), "failed to request HWEN GPIO\n"); 489 + gpiod_set_consumer_name(lm3533->hwen, "lm3533-hwen"); 496 490 497 491 lm3533_enable(lm3533); 498 492 ··· 604 614 } 605 615 606 616 static const struct i2c_device_id lm3533_i2c_ids[] = { 607 - { "lm3533", 0 }, 608 - { }, 617 + { "lm3533" }, 618 + { } 609 619 }; 610 620 MODULE_DEVICE_TABLE(i2c, lm3533_i2c_ids); 611 621
+1 -1
drivers/mfd/lp3943.c
··· 126 126 } 127 127 128 128 static const struct i2c_device_id lp3943_ids[] = { 129 - { "lp3943", 0 }, 129 + { "lp3943" }, 130 130 { } 131 131 }; 132 132 MODULE_DEVICE_TABLE(i2c, lp3943_ids);
+2 -2
drivers/mfd/lp873x.c
··· 68 68 MODULE_DEVICE_TABLE(of, of_lp873x_match_table); 69 69 70 70 static const struct i2c_device_id lp873x_id_table[] = { 71 - { "lp873x", 0 }, 72 - { }, 71 + { "lp873x" }, 72 + { } 73 73 }; 74 74 MODULE_DEVICE_TABLE(i2c, lp873x_id_table); 75 75
+2 -2
drivers/mfd/lp87565.c
··· 106 106 } 107 107 108 108 static const struct i2c_device_id lp87565_id_table[] = { 109 - { "lp87565-q1", 0 }, 110 - { }, 109 + { "lp87565-q1" }, 110 + { } 111 111 }; 112 112 MODULE_DEVICE_TABLE(i2c, lp87565_id_table); 113 113
+1 -1
drivers/mfd/lp8788.c
··· 216 216 } 217 217 218 218 static const struct i2c_device_id lp8788_ids[] = { 219 - {"lp8788", 0}, 219 + { "lp8788" }, 220 220 { } 221 221 }; 222 222 MODULE_DEVICE_TABLE(i2c, lp8788_ids);
+1 -8
drivers/mfd/madera-spi.c
··· 18 18 19 19 static int madera_spi_probe(struct spi_device *spi) 20 20 { 21 - const struct spi_device_id *id = spi_get_device_id(spi); 22 21 struct madera *madera; 23 22 const struct regmap_config *regmap_16bit_config = NULL; 24 23 const struct regmap_config *regmap_32bit_config = NULL; 25 - const void *of_data; 26 24 unsigned long type; 27 25 const char *name; 28 26 int ret; 29 27 30 - of_data = of_device_get_match_data(&spi->dev); 31 - if (of_data) 32 - type = (unsigned long)of_data; 33 - else 34 - type = id->driver_data; 35 - 28 + type = (unsigned long)spi_get_device_match_data(spi); 36 29 switch (type) { 37 30 case CS47L15: 38 31 if (IS_ENABLED(CONFIG_MFD_CS47L15)) {
+1 -1
drivers/mfd/max14577.c
··· 397 397 return ret; 398 398 } 399 399 400 - max14577->dev_type = (enum maxim_device_type)i2c_get_match_data(i2c); 400 + max14577->dev_type = (kernel_ulong_t)i2c_get_match_data(i2c); 401 401 402 402 max14577_print_dev_type(max14577); 403 403
+1 -1
drivers/mfd/max8907.c
··· 300 300 #endif 301 301 302 302 static const struct i2c_device_id max8907_i2c_id[] = { 303 - {"max8907", 0}, 303 + { "max8907" }, 304 304 {} 305 305 }; 306 306 MODULE_DEVICE_TABLE(i2c, max8907_i2c_id);
+2 -2
drivers/mfd/max8925-i2c.c
··· 127 127 128 128 129 129 static const struct i2c_device_id max8925_id_table[] = { 130 - { "max8925", 0 }, 131 - { }, 130 + { "max8925" }, 131 + { } 132 132 }; 133 133 134 134 static int max8925_dt_init(struct device_node *np, struct device *dev,
+1 -2
drivers/mfd/menelaus.c
··· 29 29 #include <linux/bcd.h> 30 30 #include <linux/slab.h> 31 31 #include <linux/mfd/menelaus.h> 32 - #include <linux/gpio.h> 33 32 34 33 #include <asm/mach/irq.h> 35 34 ··· 1230 1231 } 1231 1232 1232 1233 static const struct i2c_device_id menelaus_id[] = { 1233 - { "menelaus", 0 }, 1234 + { "menelaus" }, 1234 1235 { } 1235 1236 }; 1236 1237 MODULE_DEVICE_TABLE(i2c, menelaus_id);
+3 -3
drivers/mfd/mfd-core.c
··· 87 87 } 88 88 } 89 89 90 - ACPI_COMPANION_SET(&pdev->dev, adev ?: parent); 90 + device_set_node(&pdev->dev, acpi_fwnode_handle(adev ?: parent)); 91 91 } 92 92 #else 93 93 static inline void mfd_acpi_add_device(const struct mfd_cell *cell, ··· 131 131 of_entry->np = np; 132 132 list_add_tail(&of_entry->list, &mfd_of_node_list); 133 133 134 - pdev->dev.of_node = np; 135 - pdev->dev.fwnode = &np->fwnode; 134 + device_set_node(&pdev->dev, of_fwnode_handle(np)); 136 135 #endif 137 136 return 0; 138 137 } ··· 436 437 } 437 438 EXPORT_SYMBOL(devm_mfd_add_devices); 438 439 440 + MODULE_DESCRIPTION("Core MFD support"); 439 441 MODULE_LICENSE("GPL"); 440 442 MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov");
+10
drivers/mfd/mt6397-core.c
··· 135 135 136 136 static const struct mfd_cell mt6357_devs[] = { 137 137 { 138 + .name = "mt6359-auxadc", 139 + .of_compatible = "mediatek,mt6357-auxadc" 140 + }, { 138 141 .name = "mt6357-regulator", 139 142 }, { 140 143 .name = "mt6357-rtc", ··· 178 175 179 176 static const struct mfd_cell mt6358_devs[] = { 180 177 { 178 + .name = "mt6359-auxadc", 179 + .of_compatible = "mediatek,mt6358-auxadc" 180 + }, { 181 181 .name = "mt6358-regulator", 182 182 .of_compatible = "mediatek,mt6358-regulator" 183 183 }, { ··· 200 194 }; 201 195 202 196 static const struct mfd_cell mt6359_devs[] = { 197 + { 198 + .name = "mt6359-auxadc", 199 + .of_compatible = "mediatek,mt6359-auxadc" 200 + }, 203 201 { .name = "mt6359-regulator", }, 204 202 { 205 203 .name = "mt6359-rtc",
+1 -1
drivers/mfd/mxs-lradc.c
··· 137 137 if (!lradc) 138 138 return -ENOMEM; 139 139 140 - lradc->soc = (enum mxs_lradc_id)device_get_match_data(&pdev->dev); 140 + lradc->soc = (kernel_ulong_t)device_get_match_data(&pdev->dev); 141 141 142 142 lradc->clk = devm_clk_get(&pdev->dev, NULL); 143 143 if (IS_ERR(lradc->clk)) {
-1
drivers/mfd/omap-usb-host.c
··· 13 13 #include <linux/delay.h> 14 14 #include <linux/clk.h> 15 15 #include <linux/dma-mapping.h> 16 - #include <linux/gpio.h> 17 16 #include <linux/platform_device.h> 18 17 #include <linux/platform_data/usb-omap.h> 19 18 #include <linux/pm_runtime.h>
+3 -4
drivers/mfd/omap-usb-tll.c
··· 98 98 99 99 struct usbtll_omap { 100 100 void __iomem *base; 101 - int nch; /* num. of channels */ 102 - struct clk *ch_clk[]; /* must be the last member */ 101 + int nch; 102 + struct clk *ch_clk[] __counted_by(nch); 103 103 }; 104 104 105 105 /*-------------------------------------------------------------------------*/ ··· 230 230 break; 231 231 } 232 232 233 - tll = devm_kzalloc(dev, sizeof(*tll) + sizeof(tll->ch_clk[nch]), 234 - GFP_KERNEL); 233 + tll = devm_kzalloc(dev, struct_size(tll, ch_clk, nch), GFP_KERNEL); 235 234 if (!tll) { 236 235 pm_runtime_put_sync(dev); 237 236 pm_runtime_disable(dev);
+1
drivers/mfd/pcf50633-gpio.c
··· 88 88 } 89 89 EXPORT_SYMBOL_GPL(pcf50633_gpio_power_supply_set); 90 90 91 + MODULE_DESCRIPTION("NXP PCF50633 GPIO Driver"); 91 92 MODULE_LICENSE("GPL");
+120 -54
drivers/mfd/qcom-pm8008.c
··· 4 4 */ 5 5 6 6 #include <linux/bitops.h> 7 + #include <linux/gpio/consumer.h> 7 8 #include <linux/i2c.h> 8 9 #include <linux/interrupt.h> 10 + #include <linux/ioport.h> 9 11 #include <linux/irq.h> 10 12 #include <linux/irqdomain.h> 13 + #include <linux/mfd/core.h> 11 14 #include <linux/module.h> 12 15 #include <linux/of.h> 13 16 #include <linux/of_platform.h> 14 17 #include <linux/pinctrl/consumer.h> 15 18 #include <linux/regmap.h> 16 19 #include <linux/slab.h> 17 - 18 - #include <dt-bindings/mfd/qcom-pm8008.h> 19 20 20 21 #define I2C_INTR_STATUS_BASE 0x0550 21 22 #define INT_RT_STS_OFFSET 0x10 ··· 38 37 39 38 #define PM8008_PERIPH_0_BASE 0x900 40 39 #define PM8008_PERIPH_1_BASE 0x2400 41 - #define PM8008_PERIPH_2_BASE 0xC000 42 - #define PM8008_PERIPH_3_BASE 0xC100 40 + #define PM8008_PERIPH_2_BASE 0xc000 41 + #define PM8008_PERIPH_3_BASE 0xc100 43 42 44 43 #define PM8008_TEMP_ALARM_ADDR PM8008_PERIPH_1_BASE 45 44 #define PM8008_GPIO1_ADDR PM8008_PERIPH_2_BASE 46 45 #define PM8008_GPIO2_ADDR PM8008_PERIPH_3_BASE 46 + 47 + /* PM8008 IRQ numbers */ 48 + #define PM8008_IRQ_MISC_UVLO 0 49 + #define PM8008_IRQ_MISC_OVLO 1 50 + #define PM8008_IRQ_MISC_OTST2 2 51 + #define PM8008_IRQ_MISC_OTST3 3 52 + #define PM8008_IRQ_MISC_LDO_OCP 4 53 + #define PM8008_IRQ_TEMP_ALARM 5 54 + #define PM8008_IRQ_GPIO1 6 55 + #define PM8008_IRQ_GPIO2 7 47 56 48 57 enum { 49 58 SET_TYPE_INDEX, ··· 61 50 POLARITY_LO_INDEX, 62 51 }; 63 52 64 - static unsigned int pm8008_config_regs[] = { 53 + static const unsigned int pm8008_config_regs[] = { 65 54 INT_SET_TYPE_OFFSET, 66 55 INT_POL_HIGH_OFFSET, 67 56 INT_POL_LOW_OFFSET, 68 57 }; 69 58 70 - static struct regmap_irq pm8008_irqs[] = { 71 - REGMAP_IRQ_REG(PM8008_IRQ_MISC_UVLO, PM8008_MISC, BIT(0)), 72 - REGMAP_IRQ_REG(PM8008_IRQ_MISC_OVLO, PM8008_MISC, BIT(1)), 73 - REGMAP_IRQ_REG(PM8008_IRQ_MISC_OTST2, PM8008_MISC, BIT(2)), 74 - REGMAP_IRQ_REG(PM8008_IRQ_MISC_OTST3, PM8008_MISC, BIT(3)), 75 - REGMAP_IRQ_REG(PM8008_IRQ_MISC_LDO_OCP, PM8008_MISC, BIT(4)), 76 - REGMAP_IRQ_REG(PM8008_IRQ_TEMP_ALARM, PM8008_TEMP_ALARM, BIT(0)), 77 - REGMAP_IRQ_REG(PM8008_IRQ_GPIO1, PM8008_GPIO1, BIT(0)), 78 - REGMAP_IRQ_REG(PM8008_IRQ_GPIO2, PM8008_GPIO2, BIT(0)), 59 + #define _IRQ(_irq, _off, _mask, _types) \ 60 + [_irq] = { \ 61 + .reg_offset = (_off), \ 62 + .mask = (_mask), \ 63 + .type = { \ 64 + .type_reg_offset = (_off), \ 65 + .types_supported = (_types), \ 66 + }, \ 67 + } 68 + 69 + static const struct regmap_irq pm8008_irqs[] = { 70 + _IRQ(PM8008_IRQ_MISC_UVLO, PM8008_MISC, BIT(0), IRQ_TYPE_EDGE_RISING), 71 + _IRQ(PM8008_IRQ_MISC_OVLO, PM8008_MISC, BIT(1), IRQ_TYPE_EDGE_RISING), 72 + _IRQ(PM8008_IRQ_MISC_OTST2, PM8008_MISC, BIT(2), IRQ_TYPE_EDGE_RISING), 73 + _IRQ(PM8008_IRQ_MISC_OTST3, PM8008_MISC, BIT(3), IRQ_TYPE_EDGE_RISING), 74 + _IRQ(PM8008_IRQ_MISC_LDO_OCP, PM8008_MISC, BIT(4), IRQ_TYPE_EDGE_RISING), 75 + _IRQ(PM8008_IRQ_TEMP_ALARM, PM8008_TEMP_ALARM,BIT(0), IRQ_TYPE_SENSE_MASK), 76 + _IRQ(PM8008_IRQ_GPIO1, PM8008_GPIO1, BIT(0), IRQ_TYPE_SENSE_MASK), 77 + _IRQ(PM8008_IRQ_GPIO2, PM8008_GPIO2, BIT(0), IRQ_TYPE_SENSE_MASK), 79 78 }; 80 79 81 80 static const unsigned int pm8008_periph_base[] = { ··· 139 118 return 0; 140 119 } 141 120 142 - static struct regmap_irq_chip pm8008_irq_chip = { 143 - .name = "pm8008_irq", 121 + static const struct regmap_irq_chip pm8008_irq_chip = { 122 + .name = "pm8008", 144 123 .main_status = I2C_INTR_STATUS_BASE, 145 124 .num_main_regs = 1, 146 125 .irqs = pm8008_irqs, ··· 158 137 .get_irq_reg = pm8008_get_irq_reg, 159 138 }; 160 139 161 - static struct regmap_config qcom_mfd_regmap_cfg = { 140 + static const struct regmap_config qcom_mfd_regmap_cfg = { 141 + .name = "primary", 162 142 .reg_bits = 16, 163 143 .val_bits = 8, 164 - .max_register = 0xFFFF, 144 + .max_register = 0xffff, 165 145 }; 166 146 167 - static int pm8008_probe_irq_peripherals(struct device *dev, 168 - struct regmap *regmap, 169 - int client_irq) 147 + static const struct regmap_config pm8008_regmap_cfg_2 = { 148 + .name = "secondary", 149 + .reg_bits = 16, 150 + .val_bits = 8, 151 + .max_register = 0xffff, 152 + }; 153 + 154 + static const struct resource pm8008_temp_res[] = { 155 + DEFINE_RES_MEM(PM8008_TEMP_ALARM_ADDR, 0x100), 156 + DEFINE_RES_IRQ(PM8008_IRQ_TEMP_ALARM), 157 + }; 158 + 159 + static const struct mfd_cell pm8008_cells[] = { 160 + MFD_CELL_NAME("pm8008-regulator"), 161 + MFD_CELL_RES("qpnp-temp-alarm", pm8008_temp_res), 162 + MFD_CELL_NAME("pm8008-gpio"), 163 + }; 164 + 165 + static void devm_irq_domain_fwnode_release(void *data) 170 166 { 171 - int rc, i; 172 - struct regmap_irq_type *type; 173 - struct regmap_irq_chip_data *irq_data; 167 + struct fwnode_handle *fwnode = data; 174 168 175 - for (i = 0; i < ARRAY_SIZE(pm8008_irqs); i++) { 176 - type = &pm8008_irqs[i].type; 177 - 178 - type->type_reg_offset = pm8008_irqs[i].reg_offset; 179 - 180 - if (type->type_reg_offset == PM8008_MISC) 181 - type->types_supported = IRQ_TYPE_EDGE_RISING; 182 - else 183 - type->types_supported = (IRQ_TYPE_EDGE_BOTH | 184 - IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW); 185 - } 186 - 187 - rc = devm_regmap_add_irq_chip(dev, regmap, client_irq, 188 - IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data); 189 - if (rc) { 190 - dev_err(dev, "Failed to add IRQ chip: %d\n", rc); 191 - return rc; 192 - } 193 - 194 - return 0; 169 + irq_domain_free_fwnode(fwnode); 195 170 } 196 171 197 172 static int pm8008_probe(struct i2c_client *client) 198 173 { 199 - int rc; 200 - struct device *dev; 201 - struct regmap *regmap; 174 + struct regmap_irq_chip_data *irq_data; 175 + struct device *dev = &client->dev; 176 + struct regmap *regmap, *regmap2; 177 + struct fwnode_handle *fwnode; 178 + struct i2c_client *dummy; 179 + struct gpio_desc *reset; 180 + char *name; 181 + int ret; 202 182 203 - dev = &client->dev; 183 + dummy = devm_i2c_new_dummy_device(dev, client->adapter, client->addr + 1); 184 + if (IS_ERR(dummy)) { 185 + ret = PTR_ERR(dummy); 186 + dev_err(dev, "failed to claim second address: %d\n", ret); 187 + return ret; 188 + } 189 + 190 + regmap2 = devm_regmap_init_i2c(dummy, &qcom_mfd_regmap_cfg); 191 + if (IS_ERR(regmap2)) 192 + return PTR_ERR(regmap2); 193 + 194 + ret = regmap_attach_dev(dev, regmap2, &pm8008_regmap_cfg_2); 195 + if (ret) 196 + return ret; 197 + 198 + /* Default regmap must be attached last. */ 204 199 regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg); 205 200 if (IS_ERR(regmap)) 206 201 return PTR_ERR(regmap); 207 202 208 - i2c_set_clientdata(client, regmap); 203 + reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 204 + if (IS_ERR(reset)) 205 + return PTR_ERR(reset); 209 206 210 - if (of_property_read_bool(dev->of_node, "interrupt-controller")) { 211 - rc = pm8008_probe_irq_peripherals(dev, regmap, client->irq); 212 - if (rc) 213 - dev_err(dev, "Failed to probe irq periphs: %d\n", rc); 207 + /* 208 + * The PMIC does not appear to require a post-reset delay, but wait 209 + * for a millisecond for now anyway. 210 + */ 211 + usleep_range(1000, 2000); 212 + 213 + name = devm_kasprintf(dev, GFP_KERNEL, "%pOF-internal", dev->of_node); 214 + if (!name) 215 + return -ENOMEM; 216 + 217 + name = strreplace(name, '/', ':'); 218 + 219 + fwnode = irq_domain_alloc_named_fwnode(name); 220 + if (!fwnode) 221 + return -ENOMEM; 222 + 223 + ret = devm_add_action_or_reset(dev, devm_irq_domain_fwnode_release, fwnode); 224 + if (ret) 225 + return ret; 226 + 227 + ret = devm_regmap_add_irq_chip_fwnode(dev, fwnode, regmap, client->irq, 228 + IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data); 229 + if (ret) { 230 + dev_err(dev, "failed to add IRQ chip: %d\n", ret); 231 + return ret; 214 232 } 215 233 216 - return devm_of_platform_populate(dev); 234 + /* Needed by GPIO driver. */ 235 + dev_set_drvdata(dev, regmap_irq_get_domain(irq_data)); 236 + 237 + return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, pm8008_cells, 238 + ARRAY_SIZE(pm8008_cells), NULL, 0, 239 + regmap_irq_get_domain(irq_data)); 217 240 } 218 241 219 242 static const struct of_device_id pm8008_match[] = { ··· 275 210 }; 276 211 module_i2c_driver(pm8008_mfd_driver); 277 212 213 + MODULE_DESCRIPTION("QCOM PM8008 Power Management IC driver"); 278 214 MODULE_LICENSE("GPL v2");
+2 -2
drivers/mfd/retu-mfd.c
··· 300 300 } 301 301 302 302 static const struct i2c_device_id retu_id[] = { 303 - { "retu", 0 }, 304 - { "tahvo", 0 }, 303 + { "retu" }, 304 + { "tahvo" }, 305 305 { } 306 306 }; 307 307 MODULE_DEVICE_TABLE(i2c, retu_id);
+273
drivers/mfd/rohm-bd96801.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Copyright (C) 2024 ROHM Semiconductors 4 + * 5 + * ROHM BD96801 PMIC driver 6 + * 7 + * This version of the "BD86801 scalable PMIC"'s driver supports only very 8 + * basic set of the PMIC features. Most notably, there is no support for 9 + * the ERRB interrupt and the configurations which should be done when the 10 + * PMIC is in STBY mode. 11 + * 12 + * Supporting the ERRB interrupt would require dropping the regmap-IRQ 13 + * usage or working around (or accepting a presense of) a naming conflict 14 + * in debugFS IRQs. 15 + * 16 + * Being able to reliably do the configurations like changing the 17 + * regulator safety limits (like limits for the over/under -voltages, over 18 + * current, thermal protection) would require the configuring driver to be 19 + * synchronized with entity causing the PMIC state transitions. Eg, one 20 + * should be able to ensure the PMIC is in STBY state when the 21 + * configurations are applied to the hardware. How and when the PMIC state 22 + * transitions are to be done is likely to be very system specific, as will 23 + * be the need to configure these safety limits. Hence it's not simple to 24 + * come up with a generic solution. 25 + * 26 + * Users who require the ERRB handling and STBY state configurations can 27 + * have a look at the original RFC: 28 + * https://lore.kernel.org/all/cover.1712920132.git.mazziesaccount@gmail.com/ 29 + * which implements a workaround to debugFS naming conflict and some of 30 + * the safety limit configurations - but leaves the state change handling 31 + * and synchronization to be implemented. 32 + * 33 + * It would be great to hear (and receive a patch!) if you implement the 34 + * STBY configuration support or a proper fix to the debugFS naming 35 + * conflict in your downstream driver ;) 36 + */ 37 + 38 + #include <linux/i2c.h> 39 + #include <linux/interrupt.h> 40 + #include <linux/mfd/core.h> 41 + #include <linux/module.h> 42 + #include <linux/property.h> 43 + #include <linux/regmap.h> 44 + #include <linux/types.h> 45 + 46 + #include <linux/mfd/rohm-bd96801.h> 47 + #include <linux/mfd/rohm-generic.h> 48 + 49 + static const struct resource regulator_intb_irqs[] = { 50 + DEFINE_RES_IRQ_NAMED(BD96801_TW_STAT, "bd96801-core-thermal"), 51 + 52 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPH_STAT, "bd96801-buck1-overcurr-h"), 53 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPL_STAT, "bd96801-buck1-overcurr-l"), 54 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPN_STAT, "bd96801-buck1-overcurr-n"), 55 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OVD_STAT, "bd96801-buck1-overvolt"), 56 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_UVD_STAT, "bd96801-buck1-undervolt"), 57 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_TW_CH_STAT, "bd96801-buck1-thermal"), 58 + 59 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPH_STAT, "bd96801-buck2-overcurr-h"), 60 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPL_STAT, "bd96801-buck2-overcurr-l"), 61 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPN_STAT, "bd96801-buck2-overcurr-n"), 62 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OVD_STAT, "bd96801-buck2-overvolt"), 63 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_UVD_STAT, "bd96801-buck2-undervolt"), 64 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_TW_CH_STAT, "bd96801-buck2-thermal"), 65 + 66 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPH_STAT, "bd96801-buck3-overcurr-h"), 67 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPL_STAT, "bd96801-buck3-overcurr-l"), 68 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPN_STAT, "bd96801-buck3-overcurr-n"), 69 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OVD_STAT, "bd96801-buck3-overvolt"), 70 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_UVD_STAT, "bd96801-buck3-undervolt"), 71 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_TW_CH_STAT, "bd96801-buck3-thermal"), 72 + 73 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPH_STAT, "bd96801-buck4-overcurr-h"), 74 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPL_STAT, "bd96801-buck4-overcurr-l"), 75 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPN_STAT, "bd96801-buck4-overcurr-n"), 76 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OVD_STAT, "bd96801-buck4-overvolt"), 77 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_UVD_STAT, "bd96801-buck4-undervolt"), 78 + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_TW_CH_STAT, "bd96801-buck4-thermal"), 79 + 80 + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_OCPH_STAT, "bd96801-ldo5-overcurr"), 81 + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_OVD_STAT, "bd96801-ldo5-overvolt"), 82 + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_UVD_STAT, "bd96801-ldo5-undervolt"), 83 + 84 + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_OCPH_STAT, "bd96801-ldo6-overcurr"), 85 + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_OVD_STAT, "bd96801-ldo6-overvolt"), 86 + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_UVD_STAT, "bd96801-ldo6-undervolt"), 87 + 88 + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_OCPH_STAT, "bd96801-ldo7-overcurr"), 89 + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_OVD_STAT, "bd96801-ldo7-overvolt"), 90 + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_UVD_STAT, "bd96801-ldo7-undervolt"), 91 + }; 92 + 93 + static const struct resource wdg_intb_irqs[] = { 94 + DEFINE_RES_IRQ_NAMED(BD96801_WDT_ERR_STAT, "bd96801-wdg"), 95 + }; 96 + 97 + static struct mfd_cell bd96801_cells[] = { 98 + { 99 + .name = "bd96801-wdt", 100 + .resources = wdg_intb_irqs, 101 + .num_resources = ARRAY_SIZE(wdg_intb_irqs), 102 + }, { 103 + .name = "bd96801-regulator", 104 + .resources = regulator_intb_irqs, 105 + .num_resources = ARRAY_SIZE(regulator_intb_irqs), 106 + }, 107 + }; 108 + 109 + static const struct regmap_range bd96801_volatile_ranges[] = { 110 + /* Status registers */ 111 + regmap_reg_range(BD96801_REG_WD_FEED, BD96801_REG_WD_FAILCOUNT), 112 + regmap_reg_range(BD96801_REG_WD_ASK, BD96801_REG_WD_ASK), 113 + regmap_reg_range(BD96801_REG_WD_STATUS, BD96801_REG_WD_STATUS), 114 + regmap_reg_range(BD96801_REG_PMIC_STATE, BD96801_REG_INT_LDO7_INTB), 115 + /* Registers which do not update value unless PMIC is in STBY */ 116 + regmap_reg_range(BD96801_REG_SSCG_CTRL, BD96801_REG_SHD_INTB), 117 + regmap_reg_range(BD96801_REG_BUCK_OVP, BD96801_REG_BOOT_OVERTIME), 118 + /* 119 + * LDO control registers have single bit (LDO MODE) which does not 120 + * change when we write it unless PMIC is in STBY. It's safer to not 121 + * cache it. 122 + */ 123 + regmap_reg_range(BD96801_LDO5_VOL_LVL_REG, BD96801_LDO7_VOL_LVL_REG), 124 + }; 125 + 126 + static const struct regmap_access_table volatile_regs = { 127 + .yes_ranges = bd96801_volatile_ranges, 128 + .n_yes_ranges = ARRAY_SIZE(bd96801_volatile_ranges), 129 + }; 130 + 131 + static const struct regmap_irq bd96801_intb_irqs[] = { 132 + /* STATUS SYSTEM INTB */ 133 + REGMAP_IRQ_REG(BD96801_TW_STAT, 0, BD96801_TW_STAT_MASK), 134 + REGMAP_IRQ_REG(BD96801_WDT_ERR_STAT, 0, BD96801_WDT_ERR_STAT_MASK), 135 + REGMAP_IRQ_REG(BD96801_I2C_ERR_STAT, 0, BD96801_I2C_ERR_STAT_MASK), 136 + REGMAP_IRQ_REG(BD96801_CHIP_IF_ERR_STAT, 0, BD96801_CHIP_IF_ERR_STAT_MASK), 137 + /* STATUS BUCK1 INTB */ 138 + REGMAP_IRQ_REG(BD96801_BUCK1_OCPH_STAT, 1, BD96801_BUCK_OCPH_STAT_MASK), 139 + REGMAP_IRQ_REG(BD96801_BUCK1_OCPL_STAT, 1, BD96801_BUCK_OCPL_STAT_MASK), 140 + REGMAP_IRQ_REG(BD96801_BUCK1_OCPN_STAT, 1, BD96801_BUCK_OCPN_STAT_MASK), 141 + REGMAP_IRQ_REG(BD96801_BUCK1_OVD_STAT, 1, BD96801_BUCK_OVD_STAT_MASK), 142 + REGMAP_IRQ_REG(BD96801_BUCK1_UVD_STAT, 1, BD96801_BUCK_UVD_STAT_MASK), 143 + REGMAP_IRQ_REG(BD96801_BUCK1_TW_CH_STAT, 1, BD96801_BUCK_TW_CH_STAT_MASK), 144 + /* BUCK 2 INTB */ 145 + REGMAP_IRQ_REG(BD96801_BUCK2_OCPH_STAT, 2, BD96801_BUCK_OCPH_STAT_MASK), 146 + REGMAP_IRQ_REG(BD96801_BUCK2_OCPL_STAT, 2, BD96801_BUCK_OCPL_STAT_MASK), 147 + REGMAP_IRQ_REG(BD96801_BUCK2_OCPN_STAT, 2, BD96801_BUCK_OCPN_STAT_MASK), 148 + REGMAP_IRQ_REG(BD96801_BUCK2_OVD_STAT, 2, BD96801_BUCK_OVD_STAT_MASK), 149 + REGMAP_IRQ_REG(BD96801_BUCK2_UVD_STAT, 2, BD96801_BUCK_UVD_STAT_MASK), 150 + REGMAP_IRQ_REG(BD96801_BUCK2_TW_CH_STAT, 2, BD96801_BUCK_TW_CH_STAT_MASK), 151 + /* BUCK 3 INTB */ 152 + REGMAP_IRQ_REG(BD96801_BUCK3_OCPH_STAT, 3, BD96801_BUCK_OCPH_STAT_MASK), 153 + REGMAP_IRQ_REG(BD96801_BUCK3_OCPL_STAT, 3, BD96801_BUCK_OCPL_STAT_MASK), 154 + REGMAP_IRQ_REG(BD96801_BUCK3_OCPN_STAT, 3, BD96801_BUCK_OCPN_STAT_MASK), 155 + REGMAP_IRQ_REG(BD96801_BUCK3_OVD_STAT, 3, BD96801_BUCK_OVD_STAT_MASK), 156 + REGMAP_IRQ_REG(BD96801_BUCK3_UVD_STAT, 3, BD96801_BUCK_UVD_STAT_MASK), 157 + REGMAP_IRQ_REG(BD96801_BUCK3_TW_CH_STAT, 3, BD96801_BUCK_TW_CH_STAT_MASK), 158 + /* BUCK 4 INTB */ 159 + REGMAP_IRQ_REG(BD96801_BUCK4_OCPH_STAT, 4, BD96801_BUCK_OCPH_STAT_MASK), 160 + REGMAP_IRQ_REG(BD96801_BUCK4_OCPL_STAT, 4, BD96801_BUCK_OCPL_STAT_MASK), 161 + REGMAP_IRQ_REG(BD96801_BUCK4_OCPN_STAT, 4, BD96801_BUCK_OCPN_STAT_MASK), 162 + REGMAP_IRQ_REG(BD96801_BUCK4_OVD_STAT, 4, BD96801_BUCK_OVD_STAT_MASK), 163 + REGMAP_IRQ_REG(BD96801_BUCK4_UVD_STAT, 4, BD96801_BUCK_UVD_STAT_MASK), 164 + REGMAP_IRQ_REG(BD96801_BUCK4_TW_CH_STAT, 4, BD96801_BUCK_TW_CH_STAT_MASK), 165 + /* LDO5 INTB */ 166 + REGMAP_IRQ_REG(BD96801_LDO5_OCPH_STAT, 5, BD96801_LDO_OCPH_STAT_MASK), 167 + REGMAP_IRQ_REG(BD96801_LDO5_OVD_STAT, 5, BD96801_LDO_OVD_STAT_MASK), 168 + REGMAP_IRQ_REG(BD96801_LDO5_UVD_STAT, 5, BD96801_LDO_UVD_STAT_MASK), 169 + /* LDO6 INTB */ 170 + REGMAP_IRQ_REG(BD96801_LDO6_OCPH_STAT, 6, BD96801_LDO_OCPH_STAT_MASK), 171 + REGMAP_IRQ_REG(BD96801_LDO6_OVD_STAT, 6, BD96801_LDO_OVD_STAT_MASK), 172 + REGMAP_IRQ_REG(BD96801_LDO6_UVD_STAT, 6, BD96801_LDO_UVD_STAT_MASK), 173 + /* LDO7 INTB */ 174 + REGMAP_IRQ_REG(BD96801_LDO7_OCPH_STAT, 7, BD96801_LDO_OCPH_STAT_MASK), 175 + REGMAP_IRQ_REG(BD96801_LDO7_OVD_STAT, 7, BD96801_LDO_OVD_STAT_MASK), 176 + REGMAP_IRQ_REG(BD96801_LDO7_UVD_STAT, 7, BD96801_LDO_UVD_STAT_MASK), 177 + }; 178 + 179 + static struct regmap_irq_chip bd96801_irq_chip_intb = { 180 + .name = "bd96801-irq-intb", 181 + .main_status = BD96801_REG_INT_MAIN, 182 + .num_main_regs = 1, 183 + .irqs = &bd96801_intb_irqs[0], 184 + .num_irqs = ARRAY_SIZE(bd96801_intb_irqs), 185 + .status_base = BD96801_REG_INT_SYS_INTB, 186 + .mask_base = BD96801_REG_MASK_SYS_INTB, 187 + .ack_base = BD96801_REG_INT_SYS_INTB, 188 + .init_ack_masked = true, 189 + .num_regs = 8, 190 + .irq_reg_stride = 1, 191 + }; 192 + 193 + static const struct regmap_config bd96801_regmap_config = { 194 + .reg_bits = 8, 195 + .val_bits = 8, 196 + .volatile_table = &volatile_regs, 197 + .cache_type = REGCACHE_RBTREE, 198 + }; 199 + 200 + static int bd96801_i2c_probe(struct i2c_client *i2c) 201 + { 202 + struct regmap_irq_chip_data *intb_irq_data; 203 + const struct fwnode_handle *fwnode; 204 + struct irq_domain *intb_domain; 205 + struct regmap *regmap; 206 + int ret, intb_irq; 207 + 208 + fwnode = dev_fwnode(&i2c->dev); 209 + if (!fwnode) 210 + return dev_err_probe(&i2c->dev, -EINVAL, "Failed to find fwnode\n"); 211 + 212 + intb_irq = fwnode_irq_get_byname(fwnode, "intb"); 213 + if (intb_irq < 0) 214 + return dev_err_probe(&i2c->dev, intb_irq, "INTB IRQ not configured\n"); 215 + 216 + regmap = devm_regmap_init_i2c(i2c, &bd96801_regmap_config); 217 + if (IS_ERR(regmap)) 218 + return dev_err_probe(&i2c->dev, PTR_ERR(regmap), 219 + "Regmap initialization failed\n"); 220 + 221 + ret = regmap_write(regmap, BD96801_LOCK_REG, BD96801_UNLOCK); 222 + if (ret) 223 + return dev_err_probe(&i2c->dev, ret, "Failed to unlock PMIC\n"); 224 + 225 + ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, intb_irq, 226 + IRQF_ONESHOT, 0, &bd96801_irq_chip_intb, 227 + &intb_irq_data); 228 + if (ret) 229 + return dev_err_probe(&i2c->dev, ret, "Failed to add INTB IRQ chip\n"); 230 + 231 + intb_domain = regmap_irq_get_domain(intb_irq_data); 232 + 233 + ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, 234 + bd96801_cells, 235 + ARRAY_SIZE(bd96801_cells), NULL, 0, 236 + intb_domain); 237 + if (ret) 238 + dev_err(&i2c->dev, "Failed to create subdevices\n"); 239 + 240 + return ret; 241 + } 242 + 243 + static const struct of_device_id bd96801_of_match[] = { 244 + { .compatible = "rohm,bd96801", }, 245 + { } 246 + }; 247 + MODULE_DEVICE_TABLE(of, bd96801_of_match); 248 + 249 + static struct i2c_driver bd96801_i2c_driver = { 250 + .driver = { 251 + .name = "rohm-bd96801", 252 + .of_match_table = bd96801_of_match, 253 + }, 254 + .probe = bd96801_i2c_probe, 255 + }; 256 + 257 + static int __init bd96801_i2c_init(void) 258 + { 259 + return i2c_add_driver(&bd96801_i2c_driver); 260 + } 261 + 262 + /* Initialise early so consumer devices can complete system boot */ 263 + subsys_initcall(bd96801_i2c_init); 264 + 265 + static void __exit bd96801_i2c_exit(void) 266 + { 267 + i2c_del_driver(&bd96801_i2c_driver); 268 + } 269 + module_exit(bd96801_i2c_exit); 270 + 271 + MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); 272 + MODULE_DESCRIPTION("ROHM BD96801 Power Management IC driver"); 273 + MODULE_LICENSE("GPL");
+2
drivers/mfd/rsmu_core.c
··· 78 78 79 79 return ret; 80 80 } 81 + EXPORT_SYMBOL_GPL(rsmu_core_init); 81 82 82 83 void rsmu_core_exit(struct rsmu_ddata *rsmu) 83 84 { 84 85 mutex_destroy(&rsmu->lock); 85 86 } 87 + EXPORT_SYMBOL_GPL(rsmu_core_exit); 86 88 87 89 MODULE_DESCRIPTION("Renesas SMU core driver"); 88 90 MODULE_LICENSE("GPL");
+1
drivers/mfd/rt4831.c
··· 115 115 module_i2c_driver(rt4831_driver); 116 116 117 117 MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>"); 118 + MODULE_DESCRIPTION("Richtek RT4831 core driver"); 118 119 MODULE_LICENSE("GPL v2");
+1
drivers/mfd/ssbi.c
··· 319 319 }; 320 320 module_platform_driver(ssbi_driver); 321 321 322 + MODULE_DESCRIPTION("Qualcomm Single-wire Serial Bus Interface (SSBI) driver"); 322 323 MODULE_LICENSE("GPL v2"); 323 324 MODULE_VERSION("1.0"); 324 325 MODULE_ALIAS("platform:ssbi");
+2 -2
drivers/mfd/stw481x.c
··· 222 222 * the structure of the I2C core. 223 223 */ 224 224 static const struct i2c_device_id stw481x_id[] = { 225 - { "stw481x", 0 }, 226 - { }, 225 + { "stw481x" }, 226 + { } 227 227 }; 228 228 MODULE_DEVICE_TABLE(i2c, stw481x_id); 229 229
+48
drivers/mfd/syscon.c
··· 192 192 return syscon->regmap; 193 193 } 194 194 195 + /** 196 + * of_syscon_register_regmap() - Register regmap for specified device node 197 + * @np: Device tree node 198 + * @regmap: Pointer to regmap object 199 + * 200 + * Register an externally created regmap object with syscon for the specified 201 + * device tree node. This regmap will then be returned to client drivers using 202 + * the syscon_regmap_lookup_by_phandle() API. 203 + * 204 + * Return: 0 on success, negative error code on failure. 205 + */ 206 + int of_syscon_register_regmap(struct device_node *np, struct regmap *regmap) 207 + { 208 + struct syscon *entry, *syscon = NULL; 209 + int ret; 210 + 211 + if (!np || !regmap) 212 + return -EINVAL; 213 + 214 + syscon = kzalloc(sizeof(*syscon), GFP_KERNEL); 215 + if (!syscon) 216 + return -ENOMEM; 217 + 218 + /* check if syscon entry already exists */ 219 + spin_lock(&syscon_list_slock); 220 + 221 + list_for_each_entry(entry, &syscon_list, list) 222 + if (entry->np == np) { 223 + ret = -EEXIST; 224 + goto err_unlock; 225 + } 226 + 227 + syscon->regmap = regmap; 228 + syscon->np = np; 229 + 230 + /* register the regmap in syscon list */ 231 + list_add_tail(&syscon->list, &syscon_list); 232 + spin_unlock(&syscon_list_slock); 233 + 234 + return 0; 235 + 236 + err_unlock: 237 + spin_unlock(&syscon_list_slock); 238 + kfree(syscon); 239 + return ret; 240 + } 241 + EXPORT_SYMBOL_GPL(of_syscon_register_regmap); 242 + 195 243 struct regmap *device_node_to_regmap(struct device_node *np) 196 244 { 197 245 return device_node_get_regmap(np, false);
+12 -6
drivers/mfd/timberdale.c
··· 12 12 #include <linux/module.h> 13 13 #include <linux/pci.h> 14 14 #include <linux/mfd/core.h> 15 + #include <linux/property.h> 15 16 #include <linux/slab.h> 16 17 17 18 #include <linux/timb_gpio.h> ··· 26 25 #include <linux/spi/max7301.h> 27 26 #include <linux/spi/mc33880.h> 28 27 29 - #include <linux/platform_data/tsc2007.h> 30 28 #include <linux/platform_data/media/timb_radio.h> 31 29 #include <linux/platform_data/media/timb_video.h> 32 30 ··· 49 49 50 50 /*--------------------------------------------------------------------------*/ 51 51 52 - static struct tsc2007_platform_data timberdale_tsc2007_platform_data = { 53 - .model = 2003, 54 - .x_plate_ohms = 100 52 + static const struct property_entry timberdale_tsc2007_properties[] = { 53 + PROPERTY_ENTRY_U32("ti,x-plate-ohms", 100), 54 + { } 55 + }; 56 + 57 + static const struct software_node timberdale_tsc2007_node = { 58 + .name = "tsc2007", 59 + .properties = timberdale_tsc2007_properties, 55 60 }; 56 61 57 62 static struct i2c_board_info timberdale_i2c_board_info[] = { 58 63 { 59 64 I2C_BOARD_INFO("tsc2007", 0x48), 60 - .platform_data = &timberdale_tsc2007_platform_data, 61 - .irq = IRQ_TIMBERDALE_TSC_INT 65 + .irq = IRQ_TIMBERDALE_TSC_INT, 66 + .swnode = &timberdale_tsc2007_node, 62 67 }, 63 68 }; 64 69 ··· 858 853 859 854 MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>"); 860 855 MODULE_VERSION(DRV_VERSION); 856 + MODULE_DESCRIPTION("Timberdale FPGA MFD driver"); 861 857 MODULE_LICENSE("GPL v2");
+2 -2
drivers/mfd/tps6105x.c
··· 191 191 } 192 192 193 193 static const struct i2c_device_id tps6105x_id[] = { 194 - { "tps61050", 0 }, 195 - { "tps61052", 0 }, 194 + { "tps61050" }, 195 + { "tps61052" }, 196 196 { } 197 197 }; 198 198 MODULE_DEVICE_TABLE(i2c, tps6105x_id);
+1 -1
drivers/mfd/tps6507x.c
··· 103 103 } 104 104 105 105 static const struct i2c_device_id tps6507x_i2c_id[] = { 106 - { "tps6507x", 0 }, 106 + { "tps6507x" }, 107 107 { } 108 108 }; 109 109 MODULE_DEVICE_TABLE(i2c, tps6507x_i2c_id);
+1 -1
drivers/mfd/tps65086.c
··· 127 127 } 128 128 129 129 static const struct i2c_device_id tps65086_id_table[] = { 130 - { "tps65086", 0 }, 130 + { "tps65086" }, 131 131 { /* sentinel */ } 132 132 }; 133 133 MODULE_DEVICE_TABLE(i2c, tps65086_id_table);
+2 -2
drivers/mfd/tps65090.c
··· 225 225 226 226 227 227 static const struct i2c_device_id tps65090_id_table[] = { 228 - { "tps65090", 0 }, 229 - { }, 228 + { "tps65090" }, 229 + { } 230 230 }; 231 231 232 232 static struct i2c_driver tps65090_driver = {
+2 -2
drivers/mfd/tps6586x.c
··· 642 642 tps6586x_i2c_resume); 643 643 644 644 static const struct i2c_device_id tps6586x_id_table[] = { 645 - { "tps6586x", 0 }, 646 - { }, 645 + { "tps6586x" }, 646 + { } 647 647 }; 648 648 MODULE_DEVICE_TABLE(i2c, tps6586x_id_table); 649 649
+7 -14
drivers/mfd/tps65912-core.c
··· 90 90 { 91 91 int ret; 92 92 93 - ret = regmap_add_irq_chip(tps->regmap, tps->irq, IRQF_ONESHOT, 0, 94 - &tps65912_irq_chip, &tps->irq_data); 93 + ret = devm_regmap_add_irq_chip(tps->dev, tps->regmap, tps->irq, 94 + IRQF_ONESHOT, 0, &tps65912_irq_chip, 95 + &tps->irq_data); 95 96 if (ret) 96 97 return ret; 97 98 98 - ret = mfd_add_devices(tps->dev, PLATFORM_DEVID_AUTO, tps65912_cells, 99 - ARRAY_SIZE(tps65912_cells), NULL, 0, 100 - regmap_irq_get_domain(tps->irq_data)); 101 - if (ret) { 102 - regmap_del_irq_chip(tps->irq, tps->irq_data); 99 + ret = devm_mfd_add_devices(tps->dev, PLATFORM_DEVID_AUTO, tps65912_cells, 100 + ARRAY_SIZE(tps65912_cells), NULL, 0, 101 + regmap_irq_get_domain(tps->irq_data)); 102 + if (ret) 103 103 return ret; 104 - } 105 104 106 105 return 0; 107 106 } 108 107 EXPORT_SYMBOL_GPL(tps65912_device_init); 109 - 110 - void tps65912_device_exit(struct tps65912 *tps) 111 - { 112 - regmap_del_irq_chip(tps->irq, tps->irq_data); 113 - } 114 - EXPORT_SYMBOL_GPL(tps65912_device_exit); 115 108 116 109 MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>"); 117 110 MODULE_DESCRIPTION("TPS65912x MFD Driver");
+1 -9
drivers/mfd/tps65912-i2c.c
··· 42 42 return tps65912_device_init(tps); 43 43 } 44 44 45 - static void tps65912_i2c_remove(struct i2c_client *client) 46 - { 47 - struct tps65912 *tps = i2c_get_clientdata(client); 48 - 49 - tps65912_device_exit(tps); 50 - } 51 - 52 45 static const struct i2c_device_id tps65912_i2c_id_table[] = { 53 - { "tps65912", 0 }, 46 + { "tps65912" }, 54 47 { /* sentinel */ } 55 48 }; 56 49 MODULE_DEVICE_TABLE(i2c, tps65912_i2c_id_table); ··· 54 61 .of_match_table = tps65912_i2c_of_match_table, 55 62 }, 56 63 .probe = tps65912_i2c_probe, 57 - .remove = tps65912_i2c_remove, 58 64 .id_table = tps65912_i2c_id_table, 59 65 }; 60 66 module_i2c_driver(tps65912_i2c_driver);
-8
drivers/mfd/tps65912-spi.c
··· 42 42 return tps65912_device_init(tps); 43 43 } 44 44 45 - static void tps65912_spi_remove(struct spi_device *spi) 46 - { 47 - struct tps65912 *tps = spi_get_drvdata(spi); 48 - 49 - tps65912_device_exit(tps); 50 - } 51 - 52 45 static const struct spi_device_id tps65912_spi_id_table[] = { 53 46 { "tps65912", 0 }, 54 47 { /* sentinel */ } ··· 54 61 .of_match_table = tps65912_spi_of_match_table, 55 62 }, 56 63 .probe = tps65912_spi_probe, 57 - .remove = tps65912_spi_remove, 58 64 .id_table = tps65912_spi_id_table, 59 65 }; 60 66 module_spi_driver(tps65912_spi_driver);
+1 -1
drivers/mfd/tps6594-core.c
··· 513 513 } else { 514 514 regmap_reg = TPS6594_REG_SERIAL_IF_CONFIG; 515 515 mask_val = TPS6594_BIT_I2C1_SPI_CRC_EN; 516 - }; 516 + } 517 517 518 518 /* 519 519 * Check if CRC is enabled.
+3 -3
drivers/mfd/twl6040.c
··· 817 817 } 818 818 819 819 static const struct i2c_device_id twl6040_i2c_id[] = { 820 - { "twl6040", 0, }, 821 - { "twl6041", 0, }, 822 - { }, 820 + { "twl6040" }, 821 + { "twl6041" }, 822 + { } 823 823 }; 824 824 MODULE_DEVICE_TABLE(i2c, twl6040_i2c_id); 825 825
+1
drivers/mfd/vexpress-sysreg.c
··· 132 132 }; 133 133 134 134 module_platform_driver(vexpress_sysreg_driver); 135 + MODULE_DESCRIPTION("Versatile Express system registers driver"); 135 136 MODULE_LICENSE("GPL v2");
+1 -1
drivers/mfd/wl1273-core.c
··· 13 13 #define DRIVER_DESC "WL1273 FM Radio Core" 14 14 15 15 static const struct i2c_device_id wl1273_driver_id_table[] = { 16 - { WL1273_FM_DRIVER_NAME, 0 }, 16 + { WL1273_FM_DRIVER_NAME }, 17 17 { } 18 18 }; 19 19 MODULE_DEVICE_TABLE(i2c, wl1273_driver_id_table);
+3 -3
drivers/mfd/wm8350-i2c.c
··· 41 41 } 42 42 43 43 static const struct i2c_device_id wm8350_i2c_id[] = { 44 - { "wm8350", 0 }, 45 - { "wm8351", 0 }, 46 - { "wm8352", 0 }, 44 + { "wm8350" }, 45 + { "wm8351" }, 46 + { "wm8352" }, 47 47 { } 48 48 }; 49 49
+1 -1
drivers/mfd/wm8400-core.c
··· 135 135 } 136 136 137 137 static const struct i2c_device_id wm8400_i2c_id[] = { 138 - { "wm8400", 0 }, 138 + { "wm8400" }, 139 139 { } 140 140 }; 141 141
+1 -1
drivers/mfd/wm8994-core.c
··· 622 622 wm8994->dev = &i2c->dev; 623 623 wm8994->irq = i2c->irq; 624 624 625 - wm8994->type = (enum wm8994_type)i2c_get_match_data(i2c); 625 + wm8994->type = (kernel_ulong_t)i2c_get_match_data(i2c); 626 626 627 627 wm8994->regmap = devm_regmap_init_i2c(i2c, &wm8994_base_regmap_config); 628 628 if (IS_ERR(wm8994->regmap)) {
+1 -1
drivers/mmc/host/renesas_sdhi_core.c
··· 22 22 #include <linux/delay.h> 23 23 #include <linux/iopoll.h> 24 24 #include <linux/kernel.h> 25 - #include <linux/mfd/tmio.h> 26 25 #include <linux/mmc/host.h> 27 26 #include <linux/mmc/mmc.h> 28 27 #include <linux/mmc/slot-gpio.h> 29 28 #include <linux/module.h> 30 29 #include <linux/pinctrl/consumer.h> 31 30 #include <linux/pinctrl/pinctrl-state.h> 31 + #include <linux/platform_data/tmio.h> 32 32 #include <linux/platform_device.h> 33 33 #include <linux/pm_domain.h> 34 34 #include <linux/regulator/consumer.h>
+3 -2
drivers/mmc/host/renesas_sdhi_internal_dmac.c
··· 11 11 #include <linux/device.h> 12 12 #include <linux/dma-mapping.h> 13 13 #include <linux/io-64-nonatomic-hi-lo.h> 14 - #include <linux/mfd/tmio.h> 15 14 #include <linux/mmc/host.h> 16 15 #include <linux/mod_devicetable.h> 17 16 #include <linux/module.h> 18 17 #include <linux/of.h> 19 - #include <linux/platform_device.h> 20 18 #include <linux/pagemap.h> 19 + #include <linux/platform_data/tmio.h> 20 + #include <linux/platform_device.h> 21 + #include <linux/pm_runtime.h> 21 22 #include <linux/scatterlist.h> 22 23 #include <linux/sys_soc.h> 23 24
+3 -2
drivers/mmc/host/renesas_sdhi_sys_dmac.c
··· 11 11 #include <linux/device.h> 12 12 #include <linux/dma-mapping.h> 13 13 #include <linux/dmaengine.h> 14 - #include <linux/mfd/tmio.h> 15 14 #include <linux/mmc/host.h> 16 15 #include <linux/mod_devicetable.h> 17 16 #include <linux/module.h> 18 17 #include <linux/of.h> 19 - #include <linux/platform_device.h> 20 18 #include <linux/pagemap.h> 19 + #include <linux/platform_data/tmio.h> 20 + #include <linux/platform_device.h> 21 + #include <linux/pm_runtime.h> 21 22 #include <linux/scatterlist.h> 22 23 #include <linux/sys_soc.h> 23 24
+2 -1
drivers/mmc/host/tmio_mmc_core.c
··· 31 31 #include <linux/interrupt.h> 32 32 #include <linux/io.h> 33 33 #include <linux/irq.h> 34 - #include <linux/mfd/tmio.h> 35 34 #include <linux/mmc/card.h> 36 35 #include <linux/mmc/host.h> 37 36 #include <linux/mmc/mmc.h> 38 37 #include <linux/mmc/slot-gpio.h> 39 38 #include <linux/module.h> 39 + #include <linux/of.h> 40 40 #include <linux/pagemap.h> 41 + #include <linux/platform_data/tmio.h> 41 42 #include <linux/platform_device.h> 42 43 #include <linux/pm_qos.h> 43 44 #include <linux/pm_runtime.h>
+1 -1
drivers/mmc/host/uniphier-sd.c
··· 9 9 #include <linux/delay.h> 10 10 #include <linux/dma-mapping.h> 11 11 #include <linux/mfd/syscon.h> 12 - #include <linux/mfd/tmio.h> 13 12 #include <linux/mmc/host.h> 14 13 #include <linux/module.h> 15 14 #include <linux/of.h> 16 15 #include <linux/pinctrl/consumer.h> 16 + #include <linux/platform_data/tmio.h> 17 17 #include <linux/platform_device.h> 18 18 #include <linux/regmap.h> 19 19 #include <linux/reset.h>
+1 -1
drivers/platform/chrome/Kconfig
··· 150 150 151 151 config CROS_KBD_LED_BACKLIGHT 152 152 tristate "Backlight LED support for Chrome OS keyboards" 153 - depends on LEDS_CLASS && (ACPI || CROS_EC) 153 + depends on LEDS_CLASS && (ACPI || CROS_EC || MFD_CROS_EC_DEV) 154 154 help 155 155 This option enables support for the keyboard backlight LEDs on 156 156 select Chrome OS systems.
+38 -2
drivers/platform/chrome/cros_kbd_led_backlight.c
··· 9 9 #include <linux/init.h> 10 10 #include <linux/kernel.h> 11 11 #include <linux/leds.h> 12 + #include <linux/mfd/core.h> 12 13 #include <linux/mod_devicetable.h> 13 14 #include <linux/module.h> 14 15 #include <linux/of.h> ··· 195 194 196 195 #endif /* IS_ENABLED(CONFIG_CROS_EC) */ 197 196 197 + #if IS_ENABLED(CONFIG_MFD_CROS_EC_DEV) 198 + static int keyboard_led_init_ec_pwm_mfd(struct platform_device *pdev) 199 + { 200 + struct cros_ec_dev *ec_dev = dev_get_drvdata(pdev->dev.parent); 201 + struct cros_ec_device *cros_ec = ec_dev->ec_dev; 202 + struct keyboard_led *keyboard_led = platform_get_drvdata(pdev); 203 + 204 + keyboard_led->ec = cros_ec; 205 + 206 + return 0; 207 + } 208 + 209 + static const struct keyboard_led_drvdata keyboard_led_drvdata_ec_pwm_mfd = { 210 + .init = keyboard_led_init_ec_pwm_mfd, 211 + .brightness_set_blocking = keyboard_led_set_brightness_ec_pwm, 212 + .brightness_get = keyboard_led_get_brightness_ec_pwm, 213 + .max_brightness = KEYBOARD_BACKLIGHT_MAX, 214 + }; 215 + 216 + #else /* IS_ENABLED(CONFIG_MFD_CROS_EC_DEV) */ 217 + 218 + static const struct keyboard_led_drvdata keyboard_led_drvdata_ec_pwm_mfd = {}; 219 + 220 + #endif /* IS_ENABLED(CONFIG_MFD_CROS_EC_DEV) */ 221 + 222 + static int keyboard_led_is_mfd_device(struct platform_device *pdev) 223 + { 224 + return IS_ENABLED(CONFIG_MFD_CROS_EC_DEV) && mfd_get_cell(pdev); 225 + } 226 + 198 227 static int keyboard_led_probe(struct platform_device *pdev) 199 228 { 200 229 const struct keyboard_led_drvdata *drvdata; 201 230 struct keyboard_led *keyboard_led; 202 231 int error; 203 232 204 - drvdata = device_get_match_data(&pdev->dev); 233 + if (keyboard_led_is_mfd_device(pdev)) 234 + drvdata = &keyboard_led_drvdata_ec_pwm_mfd; 235 + else 236 + drvdata = device_get_match_data(&pdev->dev); 205 237 if (!drvdata) 206 238 return -EINVAL; 207 239 ··· 250 216 } 251 217 252 218 keyboard_led->cdev.name = "chromeos::kbd_backlight"; 253 - keyboard_led->cdev.flags |= LED_CORE_SUSPENDRESUME; 219 + keyboard_led->cdev.flags |= LED_CORE_SUSPENDRESUME | LED_REJECT_NAME_CONFLICT; 254 220 keyboard_led->cdev.max_brightness = drvdata->max_brightness; 255 221 keyboard_led->cdev.brightness_set = drvdata->brightness_set; 256 222 keyboard_led->cdev.brightness_set_blocking = drvdata->brightness_set_blocking; 257 223 keyboard_led->cdev.brightness_get = drvdata->brightness_get; 258 224 259 225 error = devm_led_classdev_register(&pdev->dev, &keyboard_led->cdev); 226 + if (error == -EEXIST) /* Already bound via other mechanism */ 227 + return -ENODEV; 260 228 if (error) 261 229 return error; 262 230
+392
drivers/regulator/88pm886-regulator.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + #include <linux/i2c.h> 3 + #include <linux/module.h> 4 + #include <linux/platform_device.h> 5 + #include <linux/regmap.h> 6 + #include <linux/regulator/driver.h> 7 + 8 + #include <linux/mfd/88pm886.h> 9 + 10 + static const struct regmap_config pm886_regulator_regmap_config = { 11 + .reg_bits = 8, 12 + .val_bits = 8, 13 + .max_register = PM886_REG_BUCK5_VOUT, 14 + }; 15 + 16 + static const struct regulator_ops pm886_ldo_ops = { 17 + .list_voltage = regulator_list_voltage_table, 18 + .map_voltage = regulator_map_voltage_iterate, 19 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 20 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 21 + .enable = regulator_enable_regmap, 22 + .disable = regulator_disable_regmap, 23 + .is_enabled = regulator_is_enabled_regmap, 24 + }; 25 + 26 + static const struct regulator_ops pm886_buck_ops = { 27 + .list_voltage = regulator_list_voltage_linear_range, 28 + .map_voltage = regulator_map_voltage_linear_range, 29 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 30 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 31 + .enable = regulator_enable_regmap, 32 + .disable = regulator_disable_regmap, 33 + .is_enabled = regulator_is_enabled_regmap, 34 + }; 35 + 36 + static const unsigned int pm886_ldo_volt_table1[] = { 37 + 1700000, 1800000, 1900000, 2500000, 2800000, 2900000, 3100000, 3300000, 38 + }; 39 + 40 + static const unsigned int pm886_ldo_volt_table2[] = { 41 + 1200000, 1250000, 1700000, 1800000, 1850000, 1900000, 2500000, 2600000, 42 + 2700000, 2750000, 2800000, 2850000, 2900000, 3000000, 3100000, 3300000, 43 + }; 44 + 45 + static const unsigned int pm886_ldo_volt_table3[] = { 46 + 1700000, 1800000, 1900000, 2000000, 2100000, 2500000, 2700000, 2800000, 47 + }; 48 + 49 + static const struct linear_range pm886_buck_volt_ranges1[] = { 50 + REGULATOR_LINEAR_RANGE(600000, 0, 79, 12500), 51 + REGULATOR_LINEAR_RANGE(1600000, 80, 84, 50000), 52 + }; 53 + 54 + static const struct linear_range pm886_buck_volt_ranges2[] = { 55 + REGULATOR_LINEAR_RANGE(600000, 0, 79, 12500), 56 + REGULATOR_LINEAR_RANGE(1600000, 80, 114, 50000), 57 + }; 58 + 59 + static struct regulator_desc pm886_regulators[] = { 60 + { 61 + .name = "LDO1", 62 + .regulators_node = "regulators", 63 + .of_match = "ldo1", 64 + .ops = &pm886_ldo_ops, 65 + .type = REGULATOR_VOLTAGE, 66 + .enable_reg = PM886_REG_LDO_EN1, 67 + .enable_mask = BIT(0), 68 + .volt_table = pm886_ldo_volt_table1, 69 + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table1), 70 + .vsel_reg = PM886_REG_LDO1_VOUT, 71 + .vsel_mask = PM886_LDO_VSEL_MASK, 72 + }, 73 + { 74 + .name = "LDO2", 75 + .regulators_node = "regulators", 76 + .of_match = "ldo2", 77 + .ops = &pm886_ldo_ops, 78 + .type = REGULATOR_VOLTAGE, 79 + .enable_reg = PM886_REG_LDO_EN1, 80 + .enable_mask = BIT(1), 81 + .volt_table = pm886_ldo_volt_table1, 82 + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table1), 83 + .vsel_reg = PM886_REG_LDO2_VOUT, 84 + .vsel_mask = PM886_LDO_VSEL_MASK, 85 + }, 86 + { 87 + .name = "LDO3", 88 + .regulators_node = "regulators", 89 + .of_match = "ldo3", 90 + .ops = &pm886_ldo_ops, 91 + .type = REGULATOR_VOLTAGE, 92 + .enable_reg = PM886_REG_LDO_EN1, 93 + .enable_mask = BIT(2), 94 + .volt_table = pm886_ldo_volt_table1, 95 + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table1), 96 + .vsel_reg = PM886_REG_LDO3_VOUT, 97 + .vsel_mask = PM886_LDO_VSEL_MASK, 98 + }, 99 + { 100 + .name = "LDO4", 101 + .regulators_node = "regulators", 102 + .of_match = "ldo4", 103 + .ops = &pm886_ldo_ops, 104 + .type = REGULATOR_VOLTAGE, 105 + .enable_reg = PM886_REG_LDO_EN1, 106 + .enable_mask = BIT(3), 107 + .volt_table = pm886_ldo_volt_table2, 108 + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table2), 109 + .vsel_reg = PM886_REG_LDO4_VOUT, 110 + .vsel_mask = PM886_LDO_VSEL_MASK, 111 + }, 112 + { 113 + .name = "LDO5", 114 + .regulators_node = "regulators", 115 + .of_match = "ldo5", 116 + .ops = &pm886_ldo_ops, 117 + .type = REGULATOR_VOLTAGE, 118 + .enable_reg = PM886_REG_LDO_EN1, 119 + .enable_mask = BIT(4), 120 + .volt_table = pm886_ldo_volt_table2, 121 + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table2), 122 + .vsel_reg = PM886_REG_LDO5_VOUT, 123 + .vsel_mask = PM886_LDO_VSEL_MASK, 124 + }, 125 + { 126 + .name = "LDO6", 127 + .regulators_node = "regulators", 128 + .of_match = "ldo6", 129 + .ops = &pm886_ldo_ops, 130 + .type = REGULATOR_VOLTAGE, 131 + .enable_reg = PM886_REG_LDO_EN1, 132 + .enable_mask = BIT(5), 133 + .volt_table = pm886_ldo_volt_table2, 134 + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table2), 135 + .vsel_reg = PM886_REG_LDO6_VOUT, 136 + .vsel_mask = PM886_LDO_VSEL_MASK, 137 + }, 138 + { 139 + .name = "LDO7", 140 + .regulators_node = "regulators", 141 + .of_match = "ldo7", 142 + .ops = &pm886_ldo_ops, 143 + .type = REGULATOR_VOLTAGE, 144 + .enable_reg = PM886_REG_LDO_EN1, 145 + .enable_mask = BIT(6), 146 + .volt_table = pm886_ldo_volt_table2, 147 + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table2), 148 + .vsel_reg = PM886_REG_LDO7_VOUT, 149 + .vsel_mask = PM886_LDO_VSEL_MASK, 150 + }, 151 + { 152 + .name = "LDO8", 153 + .regulators_node = "regulators", 154 + .of_match = "ldo8", 155 + .ops = &pm886_ldo_ops, 156 + .type = REGULATOR_VOLTAGE, 157 + .enable_reg = PM886_REG_LDO_EN1, 158 + .enable_mask = BIT(7), 159 + .volt_table = pm886_ldo_volt_table2, 160 + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table2), 161 + .vsel_reg = PM886_REG_LDO8_VOUT, 162 + .vsel_mask = PM886_LDO_VSEL_MASK, 163 + }, 164 + { 165 + .name = "LDO9", 166 + .regulators_node = "regulators", 167 + .of_match = "ldo9", 168 + .ops = &pm886_ldo_ops, 169 + .type = REGULATOR_VOLTAGE, 170 + .enable_reg = PM886_REG_LDO_EN2, 171 + .enable_mask = BIT(0), 172 + .volt_table = pm886_ldo_volt_table2, 173 + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table2), 174 + .vsel_reg = PM886_REG_LDO9_VOUT, 175 + .vsel_mask = PM886_LDO_VSEL_MASK, 176 + }, 177 + { 178 + .name = "LDO10", 179 + .regulators_node = "regulators", 180 + .of_match = "ldo10", 181 + .ops = &pm886_ldo_ops, 182 + .type = REGULATOR_VOLTAGE, 183 + .enable_reg = PM886_REG_LDO_EN2, 184 + .enable_mask = BIT(1), 185 + .volt_table = pm886_ldo_volt_table2, 186 + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table2), 187 + .vsel_reg = PM886_REG_LDO10_VOUT, 188 + .vsel_mask = PM886_LDO_VSEL_MASK, 189 + }, 190 + { 191 + .name = "LDO11", 192 + .regulators_node = "regulators", 193 + .of_match = "ldo11", 194 + .ops = &pm886_ldo_ops, 195 + .type = REGULATOR_VOLTAGE, 196 + .enable_reg = PM886_REG_LDO_EN2, 197 + .enable_mask = BIT(2), 198 + .volt_table = pm886_ldo_volt_table2, 199 + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table2), 200 + .vsel_reg = PM886_REG_LDO11_VOUT, 201 + .vsel_mask = PM886_LDO_VSEL_MASK, 202 + }, 203 + { 204 + .name = "LDO12", 205 + .regulators_node = "regulators", 206 + .of_match = "ldo12", 207 + .ops = &pm886_ldo_ops, 208 + .type = REGULATOR_VOLTAGE, 209 + .enable_reg = PM886_REG_LDO_EN2, 210 + .enable_mask = BIT(3), 211 + .volt_table = pm886_ldo_volt_table2, 212 + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table2), 213 + .vsel_reg = PM886_REG_LDO12_VOUT, 214 + .vsel_mask = PM886_LDO_VSEL_MASK, 215 + }, 216 + { 217 + .name = "LDO13", 218 + .regulators_node = "regulators", 219 + .of_match = "ldo13", 220 + .ops = &pm886_ldo_ops, 221 + .type = REGULATOR_VOLTAGE, 222 + .enable_reg = PM886_REG_LDO_EN2, 223 + .enable_mask = BIT(4), 224 + .volt_table = pm886_ldo_volt_table2, 225 + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table2), 226 + .vsel_reg = PM886_REG_LDO13_VOUT, 227 + .vsel_mask = PM886_LDO_VSEL_MASK, 228 + }, 229 + { 230 + .name = "LDO14", 231 + .regulators_node = "regulators", 232 + .of_match = "ldo14", 233 + .ops = &pm886_ldo_ops, 234 + .type = REGULATOR_VOLTAGE, 235 + .enable_reg = PM886_REG_LDO_EN2, 236 + .enable_mask = BIT(5), 237 + .volt_table = pm886_ldo_volt_table2, 238 + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table2), 239 + .vsel_reg = PM886_REG_LDO14_VOUT, 240 + .vsel_mask = PM886_LDO_VSEL_MASK, 241 + }, 242 + { 243 + .name = "LDO15", 244 + .regulators_node = "regulators", 245 + .of_match = "ldo15", 246 + .ops = &pm886_ldo_ops, 247 + .type = REGULATOR_VOLTAGE, 248 + .enable_reg = PM886_REG_LDO_EN2, 249 + .enable_mask = BIT(6), 250 + .volt_table = pm886_ldo_volt_table2, 251 + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table2), 252 + .vsel_reg = PM886_REG_LDO15_VOUT, 253 + .vsel_mask = PM886_LDO_VSEL_MASK, 254 + }, 255 + { 256 + .name = "LDO16", 257 + .regulators_node = "regulators", 258 + .of_match = "ldo16", 259 + .ops = &pm886_ldo_ops, 260 + .type = REGULATOR_VOLTAGE, 261 + .enable_reg = PM886_REG_LDO_EN2, 262 + .enable_mask = BIT(7), 263 + .volt_table = pm886_ldo_volt_table3, 264 + .n_voltages = ARRAY_SIZE(pm886_ldo_volt_table3), 265 + .vsel_reg = PM886_REG_LDO16_VOUT, 266 + .vsel_mask = PM886_LDO_VSEL_MASK, 267 + }, 268 + { 269 + .name = "buck1", 270 + .regulators_node = "regulators", 271 + .of_match = "buck1", 272 + .ops = &pm886_buck_ops, 273 + .type = REGULATOR_VOLTAGE, 274 + .n_voltages = 85, 275 + .linear_ranges = pm886_buck_volt_ranges1, 276 + .n_linear_ranges = ARRAY_SIZE(pm886_buck_volt_ranges1), 277 + .vsel_reg = PM886_REG_BUCK1_VOUT, 278 + .vsel_mask = PM886_BUCK_VSEL_MASK, 279 + .enable_reg = PM886_REG_BUCK_EN, 280 + .enable_mask = BIT(0), 281 + }, 282 + { 283 + .name = "buck2", 284 + .regulators_node = "regulators", 285 + .of_match = "buck2", 286 + .ops = &pm886_buck_ops, 287 + .type = REGULATOR_VOLTAGE, 288 + .n_voltages = 115, 289 + .linear_ranges = pm886_buck_volt_ranges2, 290 + .n_linear_ranges = ARRAY_SIZE(pm886_buck_volt_ranges2), 291 + .vsel_reg = PM886_REG_BUCK2_VOUT, 292 + .vsel_mask = PM886_BUCK_VSEL_MASK, 293 + .enable_reg = PM886_REG_BUCK_EN, 294 + .enable_mask = BIT(1), 295 + }, 296 + { 297 + .name = "buck3", 298 + .regulators_node = "regulators", 299 + .of_match = "buck3", 300 + .ops = &pm886_buck_ops, 301 + .type = REGULATOR_VOLTAGE, 302 + .n_voltages = 115, 303 + .linear_ranges = pm886_buck_volt_ranges2, 304 + .n_linear_ranges = ARRAY_SIZE(pm886_buck_volt_ranges2), 305 + .vsel_reg = PM886_REG_BUCK3_VOUT, 306 + .vsel_mask = PM886_BUCK_VSEL_MASK, 307 + .enable_reg = PM886_REG_BUCK_EN, 308 + .enable_mask = BIT(2), 309 + }, 310 + { 311 + .name = "buck4", 312 + .regulators_node = "regulators", 313 + .of_match = "buck4", 314 + .ops = &pm886_buck_ops, 315 + .type = REGULATOR_VOLTAGE, 316 + .n_voltages = 115, 317 + .linear_ranges = pm886_buck_volt_ranges2, 318 + .n_linear_ranges = ARRAY_SIZE(pm886_buck_volt_ranges2), 319 + .vsel_reg = PM886_REG_BUCK4_VOUT, 320 + .vsel_mask = PM886_BUCK_VSEL_MASK, 321 + .enable_reg = PM886_REG_BUCK_EN, 322 + .enable_mask = BIT(3), 323 + }, 324 + { 325 + .name = "buck5", 326 + .regulators_node = "regulators", 327 + .of_match = "buck5", 328 + .ops = &pm886_buck_ops, 329 + .type = REGULATOR_VOLTAGE, 330 + .n_voltages = 115, 331 + .linear_ranges = pm886_buck_volt_ranges2, 332 + .n_linear_ranges = ARRAY_SIZE(pm886_buck_volt_ranges2), 333 + .vsel_reg = PM886_REG_BUCK5_VOUT, 334 + .vsel_mask = PM886_BUCK_VSEL_MASK, 335 + .enable_reg = PM886_REG_BUCK_EN, 336 + .enable_mask = BIT(4), 337 + }, 338 + }; 339 + 340 + static int pm886_regulator_probe(struct platform_device *pdev) 341 + { 342 + struct pm886_chip *chip = dev_get_drvdata(pdev->dev.parent); 343 + struct regulator_config rcfg = { }; 344 + struct device *dev = &pdev->dev; 345 + struct regulator_desc *rdesc; 346 + struct regulator_dev *rdev; 347 + struct i2c_client *page; 348 + struct regmap *regmap; 349 + 350 + page = devm_i2c_new_dummy_device(dev, chip->client->adapter, 351 + chip->client->addr + PM886_PAGE_OFFSET_REGULATORS); 352 + if (IS_ERR(page)) 353 + return dev_err_probe(dev, PTR_ERR(page), 354 + "Failed to initialize regulators client\n"); 355 + 356 + regmap = devm_regmap_init_i2c(page, &pm886_regulator_regmap_config); 357 + if (IS_ERR(regmap)) 358 + return dev_err_probe(dev, PTR_ERR(regmap), 359 + "Failed to initialize regulators regmap\n"); 360 + rcfg.regmap = regmap; 361 + 362 + rcfg.dev = dev->parent; 363 + 364 + for (int i = 0; i < ARRAY_SIZE(pm886_regulators); i++) { 365 + rdesc = &pm886_regulators[i]; 366 + rdev = devm_regulator_register(dev, rdesc, &rcfg); 367 + if (IS_ERR(rdev)) 368 + return dev_err_probe(dev, PTR_ERR(rdev), 369 + "Failed to register %s\n", rdesc->name); 370 + } 371 + 372 + return 0; 373 + } 374 + 375 + static const struct platform_device_id pm886_regulator_id_table[] = { 376 + { "88pm886-regulator", }, 377 + { } 378 + }; 379 + MODULE_DEVICE_TABLE(platform, pm886_regulator_id_table); 380 + 381 + static struct platform_driver pm886_regulator_driver = { 382 + .driver = { 383 + .name = "88pm886-regulator", 384 + }, 385 + .probe = pm886_regulator_probe, 386 + .id_table = pm886_regulator_id_table, 387 + }; 388 + module_platform_driver(pm886_regulator_driver); 389 + 390 + MODULE_DESCRIPTION("Marvell 88PM886 PMIC regulator driver"); 391 + MODULE_AUTHOR("Karel Balej <balejk@matfyz.cz>"); 392 + MODULE_LICENSE("GPL");
+25
drivers/regulator/Kconfig
··· 91 91 help 92 92 This driver supports 88PM8607 voltage regulator chips. 93 93 94 + config REGULATOR_88PM886 95 + tristate "Marvell 88PM886 voltage regulators" 96 + depends on MFD_88PM886_PMIC 97 + help 98 + This driver implements support for Marvell 88PM886 voltage regulators. 99 + 94 100 config REGULATOR_ACT8865 95 101 tristate "Active-semi act8865 voltage regulator" 96 102 depends on I2C ··· 273 267 274 268 This driver can also be built as a module. If so, the module 275 269 will be called bd9576-regulator. 270 + 271 + config REGULATOR_BD96801 272 + tristate "ROHM BD96801 Power Regulator" 273 + depends on MFD_ROHM_BD96801 274 + select REGULATOR_ROHM 275 + help 276 + This driver supports voltage regulators on ROHM BD96801 PMIC. 277 + This will enable support for the software controllable buck 278 + and LDO regulators. 279 + 280 + This driver can also be built as a module. If so, the module 281 + will be called bd96801-regulator. 276 282 277 283 config REGULATOR_CPCAP 278 284 tristate "Motorola CPCAP regulator" ··· 1044 1026 help 1045 1027 This driver supports PWM controlled voltage regulators. PWM 1046 1028 duty cycle can increase or decrease the voltage. 1029 + 1030 + config REGULATOR_QCOM_PM8008 1031 + tristate "Qualcomm PM8008 PMIC regulators" 1032 + depends on MFD_QCOM_PM8008 1033 + help 1034 + Select this option to enable support for the voltage regulators in 1035 + Qualcomm PM8008 PMICs. 1047 1036 1048 1037 config REGULATOR_QCOM_REFGEN 1049 1038 tristate "Qualcomm REFGEN regulator driver"
+3
drivers/regulator/Makefile
··· 14 14 obj-$(CONFIG_REGULATOR_88PG86X) += 88pg86x.o 15 15 obj-$(CONFIG_REGULATOR_88PM800) += 88pm800-regulator.o 16 16 obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o 17 + obj-$(CONFIG_REGULATOR_88PM886) += 88pm886-regulator.o 17 18 obj-$(CONFIG_REGULATOR_CROS_EC) += cros-ec-regulator.o 18 19 obj-$(CONFIG_REGULATOR_CPCAP) += cpcap-regulator.o 19 20 obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o ··· 38 37 obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o 39 38 obj-$(CONFIG_REGULATOR_BD957XMUF) += bd9576-regulator.o 40 39 obj-$(CONFIG_REGULATOR_DA903X) += da903x-regulator.o 40 + obj-$(CONFIG_REGULATOR_BD96801) += bd96801-regulator.o 41 41 obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o 42 42 obj-$(CONFIG_REGULATOR_DA9055) += da9055-regulator.o 43 43 obj-$(CONFIG_REGULATOR_DA9062) += da9062-regulator.o ··· 114 112 obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o 115 113 obj-$(CONFIG_REGULATOR_MTK_DVFSRC) += mtk-dvfsrc-regulator.o 116 114 obj-$(CONFIG_REGULATOR_QCOM_LABIBB) += qcom-labibb-regulator.o 115 + obj-$(CONFIG_REGULATOR_QCOM_PM8008) += qcom-pm8008-regulator.o 117 116 obj-$(CONFIG_REGULATOR_QCOM_REFGEN) += qcom-refgen-regulator.o 118 117 obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o 119 118 obj-$(CONFIG_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o
+908
drivers/regulator/bd96801-regulator.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2024 ROHM Semiconductors 3 + // bd96801-regulator.c ROHM BD96801 regulator driver 4 + 5 + /* 6 + * This version of the "BD86801 scalable PMIC"'s driver supports only very 7 + * basic set of the PMIC features. Most notably, there is no support for 8 + * the ERRB interrupt and the configurations which should be done when the 9 + * PMIC is in STBY mode. 10 + * 11 + * Supporting the ERRB interrupt would require dropping the regmap-IRQ 12 + * usage or working around (or accepting a presense of) a naming conflict 13 + * in debugFS IRQs. 14 + * 15 + * Being able to reliably do the configurations like changing the 16 + * regulator safety limits (like limits for the over/under -voltages, over 17 + * current, thermal protection) would require the configuring driver to be 18 + * synchronized with entity causing the PMIC state transitions. Eg, one 19 + * should be able to ensure the PMIC is in STBY state when the 20 + * configurations are applied to the hardware. How and when the PMIC state 21 + * transitions are to be done is likely to be very system specific, as will 22 + * be the need to configure these safety limits. Hence it's not simple to 23 + * come up with a generic solution. 24 + * 25 + * Users who require the ERRB handling and STBY state configurations can 26 + * have a look at the original RFC: 27 + * https://lore.kernel.org/all/cover.1712920132.git.mazziesaccount@gmail.com/ 28 + * which implements a workaround to debugFS naming conflict and some of 29 + * the safety limit configurations - but leaves the state change handling 30 + * and synchronization to be implemented. 31 + * 32 + * It would be great to hear (and receive a patch!) if you implement the 33 + * STBY configuration support or a proper fix to the debugFS naming 34 + * conflict in your downstream driver ;) 35 + */ 36 + 37 + #include <linux/delay.h> 38 + #include <linux/err.h> 39 + #include <linux/interrupt.h> 40 + #include <linux/kernel.h> 41 + #include <linux/linear_range.h> 42 + #include <linux/mfd/rohm-generic.h> 43 + #include <linux/mfd/rohm-bd96801.h> 44 + #include <linux/module.h> 45 + #include <linux/of.h> 46 + #include <linux/platform_device.h> 47 + #include <linux/regmap.h> 48 + #include <linux/regulator/coupler.h> 49 + #include <linux/regulator/driver.h> 50 + #include <linux/regulator/machine.h> 51 + #include <linux/regulator/of_regulator.h> 52 + #include <linux/slab.h> 53 + #include <linux/timer.h> 54 + 55 + enum { 56 + BD96801_BUCK1, 57 + BD96801_BUCK2, 58 + BD96801_BUCK3, 59 + BD96801_BUCK4, 60 + BD96801_LDO5, 61 + BD96801_LDO6, 62 + BD96801_LDO7, 63 + BD96801_REGULATOR_AMOUNT, 64 + }; 65 + 66 + enum { 67 + BD96801_PROT_OVP, 68 + BD96801_PROT_UVP, 69 + BD96801_PROT_OCP, 70 + BD96801_PROT_TEMP, 71 + BD96801_NUM_PROT, 72 + }; 73 + 74 + #define BD96801_ALWAYS_ON_REG 0x3c 75 + #define BD96801_REG_ENABLE 0x0b 76 + #define BD96801_BUCK1_EN_MASK BIT(0) 77 + #define BD96801_BUCK2_EN_MASK BIT(1) 78 + #define BD96801_BUCK3_EN_MASK BIT(2) 79 + #define BD96801_BUCK4_EN_MASK BIT(3) 80 + #define BD96801_LDO5_EN_MASK BIT(4) 81 + #define BD96801_LDO6_EN_MASK BIT(5) 82 + #define BD96801_LDO7_EN_MASK BIT(6) 83 + 84 + #define BD96801_BUCK1_VSEL_REG 0x28 85 + #define BD96801_BUCK2_VSEL_REG 0x29 86 + #define BD96801_BUCK3_VSEL_REG 0x2a 87 + #define BD96801_BUCK4_VSEL_REG 0x2b 88 + #define BD96801_LDO5_VSEL_REG 0x25 89 + #define BD96801_LDO6_VSEL_REG 0x26 90 + #define BD96801_LDO7_VSEL_REG 0x27 91 + #define BD96801_BUCK_VSEL_MASK 0x1F 92 + #define BD96801_LDO_VSEL_MASK 0xff 93 + 94 + #define BD96801_MASK_RAMP_DELAY 0xc0 95 + #define BD96801_INT_VOUT_BASE_REG 0x21 96 + #define BD96801_BUCK_INT_VOUT_MASK 0xff 97 + 98 + #define BD96801_BUCK_VOLTS 256 99 + #define BD96801_LDO_VOLTS 256 100 + 101 + #define BD96801_OVP_MASK 0x03 102 + #define BD96801_MASK_BUCK1_OVP_SHIFT 0x00 103 + #define BD96801_MASK_BUCK2_OVP_SHIFT 0x02 104 + #define BD96801_MASK_BUCK3_OVP_SHIFT 0x04 105 + #define BD96801_MASK_BUCK4_OVP_SHIFT 0x06 106 + #define BD96801_MASK_LDO5_OVP_SHIFT 0x00 107 + #define BD96801_MASK_LDO6_OVP_SHIFT 0x02 108 + #define BD96801_MASK_LDO7_OVP_SHIFT 0x04 109 + 110 + #define BD96801_PROT_LIMIT_OCP_MIN 0x00 111 + #define BD96801_PROT_LIMIT_LOW 0x01 112 + #define BD96801_PROT_LIMIT_MID 0x02 113 + #define BD96801_PROT_LIMIT_HI 0x03 114 + 115 + #define BD96801_REG_BUCK1_OCP 0x32 116 + #define BD96801_REG_BUCK2_OCP 0x32 117 + #define BD96801_REG_BUCK3_OCP 0x33 118 + #define BD96801_REG_BUCK4_OCP 0x33 119 + 120 + #define BD96801_MASK_BUCK1_OCP_SHIFT 0x00 121 + #define BD96801_MASK_BUCK2_OCP_SHIFT 0x04 122 + #define BD96801_MASK_BUCK3_OCP_SHIFT 0x00 123 + #define BD96801_MASK_BUCK4_OCP_SHIFT 0x04 124 + 125 + #define BD96801_REG_LDO5_OCP 0x34 126 + #define BD96801_REG_LDO6_OCP 0x34 127 + #define BD96801_REG_LDO7_OCP 0x34 128 + 129 + #define BD96801_MASK_LDO5_OCP_SHIFT 0x00 130 + #define BD96801_MASK_LDO6_OCP_SHIFT 0x02 131 + #define BD96801_MASK_LDO7_OCP_SHIFT 0x04 132 + 133 + #define BD96801_MASK_SHD_INTB BIT(7) 134 + #define BD96801_INTB_FATAL BIT(7) 135 + 136 + #define BD96801_NUM_REGULATORS 7 137 + #define BD96801_NUM_LDOS 4 138 + 139 + /* 140 + * Ramp rates for bucks are controlled by bits [7:6] as follows: 141 + * 00 => 1 mV/uS 142 + * 01 => 5 mV/uS 143 + * 10 => 10 mV/uS 144 + * 11 => 20 mV/uS 145 + */ 146 + static const unsigned int buck_ramp_table[] = { 1000, 5000, 10000, 20000 }; 147 + 148 + /* 149 + * This is a voltage range that get's appended to selected 150 + * bd96801_buck_init_volts value. The range from 0x0 to 0xF is actually 151 + * bd96801_buck_init_volts + 0 ... bd96801_buck_init_volts + 150mV 152 + * and the range from 0x10 to 0x1f is bd96801_buck_init_volts - 150mV ... 153 + * bd96801_buck_init_volts - 0. But as the members of linear_range 154 + * are all unsigned I will apply offset of -150 mV to value in 155 + * linear_range - which should increase these ranges with 156 + * 150 mV getting all the values to >= 0. 157 + */ 158 + static const struct linear_range bd96801_tune_volts[] = { 159 + REGULATOR_LINEAR_RANGE(150000, 0x00, 0xF, 10000), 160 + REGULATOR_LINEAR_RANGE(0, 0x10, 0x1F, 10000), 161 + }; 162 + 163 + static const struct linear_range bd96801_buck_init_volts[] = { 164 + REGULATOR_LINEAR_RANGE(500000 - 150000, 0x00, 0xc8, 5000), 165 + REGULATOR_LINEAR_RANGE(1550000 - 150000, 0xc9, 0xec, 50000), 166 + REGULATOR_LINEAR_RANGE(3300000 - 150000, 0xed, 0xff, 0), 167 + }; 168 + 169 + static const struct linear_range bd96801_ldo_int_volts[] = { 170 + REGULATOR_LINEAR_RANGE(300000, 0x00, 0x78, 25000), 171 + REGULATOR_LINEAR_RANGE(3300000, 0x79, 0xff, 0), 172 + }; 173 + 174 + #define BD96801_LDO_SD_VOLT_MASK 0x1 175 + #define BD96801_LDO_MODE_MASK 0x6 176 + #define BD96801_LDO_MODE_INT 0x0 177 + #define BD96801_LDO_MODE_SD 0x2 178 + #define BD96801_LDO_MODE_DDR 0x4 179 + 180 + static int ldo_ddr_volt_table[] = {500000, 300000}; 181 + static int ldo_sd_volt_table[] = {3300000, 1800000}; 182 + 183 + /* Constant IRQ initialization data (templates) */ 184 + struct bd96801_irqinfo { 185 + int type; 186 + struct regulator_irq_desc irq_desc; 187 + int err_cfg; 188 + int wrn_cfg; 189 + const char *irq_name; 190 + }; 191 + 192 + #define BD96801_IRQINFO(_type, _name, _irqoff_ms, _irqname) \ 193 + { \ 194 + .type = (_type), \ 195 + .err_cfg = -1, \ 196 + .wrn_cfg = -1, \ 197 + .irq_name = (_irqname), \ 198 + .irq_desc = { \ 199 + .name = (_name), \ 200 + .irq_off_ms = (_irqoff_ms), \ 201 + .map_event = regulator_irq_map_event_simple, \ 202 + }, \ 203 + } 204 + 205 + static const struct bd96801_irqinfo buck1_irqinfo[] = { 206 + BD96801_IRQINFO(BD96801_PROT_OCP, "buck1-over-curr-h", 500, 207 + "bd96801-buck1-overcurr-h"), 208 + BD96801_IRQINFO(BD96801_PROT_OCP, "buck1-over-curr-l", 500, 209 + "bd96801-buck1-overcurr-l"), 210 + BD96801_IRQINFO(BD96801_PROT_OCP, "buck1-over-curr-n", 500, 211 + "bd96801-buck1-overcurr-n"), 212 + BD96801_IRQINFO(BD96801_PROT_OVP, "buck1-over-voltage", 500, 213 + "bd96801-buck1-overvolt"), 214 + BD96801_IRQINFO(BD96801_PROT_UVP, "buck1-under-voltage", 500, 215 + "bd96801-buck1-undervolt"), 216 + BD96801_IRQINFO(BD96801_PROT_TEMP, "buck1-over-temp", 500, 217 + "bd96801-buck1-thermal") 218 + }; 219 + 220 + static const struct bd96801_irqinfo buck2_irqinfo[] = { 221 + BD96801_IRQINFO(BD96801_PROT_OCP, "buck2-over-curr-h", 500, 222 + "bd96801-buck2-overcurr-h"), 223 + BD96801_IRQINFO(BD96801_PROT_OCP, "buck2-over-curr-l", 500, 224 + "bd96801-buck2-overcurr-l"), 225 + BD96801_IRQINFO(BD96801_PROT_OCP, "buck2-over-curr-n", 500, 226 + "bd96801-buck2-overcurr-n"), 227 + BD96801_IRQINFO(BD96801_PROT_OVP, "buck2-over-voltage", 500, 228 + "bd96801-buck2-overvolt"), 229 + BD96801_IRQINFO(BD96801_PROT_UVP, "buck2-under-voltage", 500, 230 + "bd96801-buck2-undervolt"), 231 + BD96801_IRQINFO(BD96801_PROT_TEMP, "buck2-over-temp", 500, 232 + "bd96801-buck2-thermal") 233 + }; 234 + 235 + static const struct bd96801_irqinfo buck3_irqinfo[] = { 236 + BD96801_IRQINFO(BD96801_PROT_OCP, "buck3-over-curr-h", 500, 237 + "bd96801-buck3-overcurr-h"), 238 + BD96801_IRQINFO(BD96801_PROT_OCP, "buck3-over-curr-l", 500, 239 + "bd96801-buck3-overcurr-l"), 240 + BD96801_IRQINFO(BD96801_PROT_OCP, "buck3-over-curr-n", 500, 241 + "bd96801-buck3-overcurr-n"), 242 + BD96801_IRQINFO(BD96801_PROT_OVP, "buck3-over-voltage", 500, 243 + "bd96801-buck3-overvolt"), 244 + BD96801_IRQINFO(BD96801_PROT_UVP, "buck3-under-voltage", 500, 245 + "bd96801-buck3-undervolt"), 246 + BD96801_IRQINFO(BD96801_PROT_TEMP, "buck3-over-temp", 500, 247 + "bd96801-buck3-thermal") 248 + }; 249 + 250 + static const struct bd96801_irqinfo buck4_irqinfo[] = { 251 + BD96801_IRQINFO(BD96801_PROT_OCP, "buck4-over-curr-h", 500, 252 + "bd96801-buck4-overcurr-h"), 253 + BD96801_IRQINFO(BD96801_PROT_OCP, "buck4-over-curr-l", 500, 254 + "bd96801-buck4-overcurr-l"), 255 + BD96801_IRQINFO(BD96801_PROT_OCP, "buck4-over-curr-n", 500, 256 + "bd96801-buck4-overcurr-n"), 257 + BD96801_IRQINFO(BD96801_PROT_OVP, "buck4-over-voltage", 500, 258 + "bd96801-buck4-overvolt"), 259 + BD96801_IRQINFO(BD96801_PROT_UVP, "buck4-under-voltage", 500, 260 + "bd96801-buck4-undervolt"), 261 + BD96801_IRQINFO(BD96801_PROT_TEMP, "buck4-over-temp", 500, 262 + "bd96801-buck4-thermal") 263 + }; 264 + 265 + static const struct bd96801_irqinfo ldo5_irqinfo[] = { 266 + BD96801_IRQINFO(BD96801_PROT_OCP, "ldo5-overcurr", 500, 267 + "bd96801-ldo5-overcurr"), 268 + BD96801_IRQINFO(BD96801_PROT_OVP, "ldo5-over-voltage", 500, 269 + "bd96801-ldo5-overvolt"), 270 + BD96801_IRQINFO(BD96801_PROT_UVP, "ldo5-under-voltage", 500, 271 + "bd96801-ldo5-undervolt"), 272 + }; 273 + 274 + static const struct bd96801_irqinfo ldo6_irqinfo[] = { 275 + BD96801_IRQINFO(BD96801_PROT_OCP, "ldo6-overcurr", 500, 276 + "bd96801-ldo6-overcurr"), 277 + BD96801_IRQINFO(BD96801_PROT_OVP, "ldo6-over-voltage", 500, 278 + "bd96801-ldo6-overvolt"), 279 + BD96801_IRQINFO(BD96801_PROT_UVP, "ldo6-under-voltage", 500, 280 + "bd96801-ldo6-undervolt"), 281 + }; 282 + 283 + static const struct bd96801_irqinfo ldo7_irqinfo[] = { 284 + BD96801_IRQINFO(BD96801_PROT_OCP, "ldo7-overcurr", 500, 285 + "bd96801-ldo7-overcurr"), 286 + BD96801_IRQINFO(BD96801_PROT_OVP, "ldo7-over-voltage", 500, 287 + "bd96801-ldo7-overvolt"), 288 + BD96801_IRQINFO(BD96801_PROT_UVP, "ldo7-under-voltage", 500, 289 + "bd96801-ldo7-undervolt"), 290 + }; 291 + 292 + struct bd96801_irq_desc { 293 + struct bd96801_irqinfo *irqinfo; 294 + int num_irqs; 295 + }; 296 + 297 + struct bd96801_regulator_data { 298 + struct regulator_desc desc; 299 + const struct linear_range *init_ranges; 300 + int num_ranges; 301 + struct bd96801_irq_desc irq_desc; 302 + int initial_voltage; 303 + int ldo_vol_lvl; 304 + int ldo_errs; 305 + }; 306 + 307 + struct bd96801_pmic_data { 308 + struct bd96801_regulator_data regulator_data[BD96801_NUM_REGULATORS]; 309 + struct regmap *regmap; 310 + int fatal_ind; 311 + }; 312 + 313 + static int ldo_map_notif(int irq, struct regulator_irq_data *rid, 314 + unsigned long *dev_mask) 315 + { 316 + int i; 317 + 318 + for (i = 0; i < rid->num_states; i++) { 319 + struct bd96801_regulator_data *rdata; 320 + struct regulator_dev *rdev; 321 + 322 + rdev = rid->states[i].rdev; 323 + rdata = container_of(rdev->desc, struct bd96801_regulator_data, 324 + desc); 325 + rid->states[i].notifs = regulator_err2notif(rdata->ldo_errs); 326 + rid->states[i].errors = rdata->ldo_errs; 327 + *dev_mask |= BIT(i); 328 + } 329 + return 0; 330 + } 331 + 332 + static int bd96801_list_voltage_lr(struct regulator_dev *rdev, 333 + unsigned int selector) 334 + { 335 + int voltage; 336 + struct bd96801_regulator_data *data; 337 + 338 + data = container_of(rdev->desc, struct bd96801_regulator_data, desc); 339 + 340 + /* 341 + * The BD096801 has voltage setting in two registers. One giving the 342 + * "initial voltage" (can be changed only when regulator is disabled. 343 + * This driver caches the value and sets it only at startup. The other 344 + * register is voltage tuning value which applies -150 mV ... +150 mV 345 + * offset to the voltage. 346 + * 347 + * Note that the cached initial voltage stored in regulator data is 348 + * 'scaled down' by the 150 mV so that all of our tuning values are 349 + * >= 0. This is done because the linear_ranges uses unsigned values. 350 + * 351 + * As a result, we increase the tuning voltage which we get based on 352 + * the selector by the stored initial_voltage. 353 + */ 354 + voltage = regulator_list_voltage_linear_range(rdev, selector); 355 + if (voltage < 0) 356 + return voltage; 357 + 358 + return voltage + data->initial_voltage; 359 + } 360 + 361 + 362 + static const struct regulator_ops bd96801_ldo_table_ops = { 363 + .is_enabled = regulator_is_enabled_regmap, 364 + .list_voltage = regulator_list_voltage_table, 365 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 366 + }; 367 + 368 + static const struct regulator_ops bd96801_buck_ops = { 369 + .is_enabled = regulator_is_enabled_regmap, 370 + .list_voltage = bd96801_list_voltage_lr, 371 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 372 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 373 + .set_voltage_time_sel = regulator_set_voltage_time_sel, 374 + .set_ramp_delay = regulator_set_ramp_delay_regmap, 375 + }; 376 + 377 + static const struct regulator_ops bd96801_ldo_ops = { 378 + .is_enabled = regulator_is_enabled_regmap, 379 + .list_voltage = regulator_list_voltage_linear_range, 380 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 381 + }; 382 + 383 + static int buck_get_initial_voltage(struct regmap *regmap, struct device *dev, 384 + struct bd96801_regulator_data *data) 385 + { 386 + int ret = 0, sel, initial_uv; 387 + int reg = BD96801_INT_VOUT_BASE_REG + data->desc.id; 388 + 389 + if (data->num_ranges) { 390 + ret = regmap_read(regmap, reg, &sel); 391 + sel &= BD96801_BUCK_INT_VOUT_MASK; 392 + 393 + ret = linear_range_get_value_array(data->init_ranges, 394 + data->num_ranges, sel, 395 + &initial_uv); 396 + if (ret) 397 + return ret; 398 + 399 + data->initial_voltage = initial_uv; 400 + dev_dbg(dev, "Tune-scaled initial voltage %u\n", 401 + data->initial_voltage); 402 + } 403 + 404 + return 0; 405 + } 406 + 407 + static int get_ldo_initial_voltage(struct regmap *regmap, 408 + struct device *dev, 409 + struct bd96801_regulator_data *data) 410 + { 411 + int ret; 412 + int cfgreg; 413 + 414 + ret = regmap_read(regmap, data->ldo_vol_lvl, &cfgreg); 415 + if (ret) 416 + return ret; 417 + 418 + switch (cfgreg & BD96801_LDO_MODE_MASK) { 419 + case BD96801_LDO_MODE_DDR: 420 + data->desc.volt_table = ldo_ddr_volt_table; 421 + data->desc.n_voltages = ARRAY_SIZE(ldo_ddr_volt_table); 422 + break; 423 + case BD96801_LDO_MODE_SD: 424 + data->desc.volt_table = ldo_sd_volt_table; 425 + data->desc.n_voltages = ARRAY_SIZE(ldo_sd_volt_table); 426 + break; 427 + default: 428 + dev_info(dev, "Leaving LDO to normal mode"); 429 + return 0; 430 + } 431 + 432 + /* SD or DDR mode => override default ops */ 433 + data->desc.ops = &bd96801_ldo_table_ops, 434 + data->desc.vsel_mask = 1; 435 + data->desc.vsel_reg = data->ldo_vol_lvl; 436 + 437 + return 0; 438 + } 439 + 440 + static int get_initial_voltage(struct device *dev, struct regmap *regmap, 441 + struct bd96801_regulator_data *data) 442 + { 443 + /* BUCK */ 444 + if (data->desc.id <= BD96801_BUCK4) 445 + return buck_get_initial_voltage(regmap, dev, data); 446 + 447 + /* LDO */ 448 + return get_ldo_initial_voltage(regmap, dev, data); 449 + } 450 + 451 + static int bd96801_walk_regulator_dt(struct device *dev, struct regmap *regmap, 452 + struct bd96801_regulator_data *data, 453 + int num) 454 + { 455 + int i, ret; 456 + struct device_node *np; 457 + struct device_node *nproot = dev->parent->of_node; 458 + 459 + nproot = of_get_child_by_name(nproot, "regulators"); 460 + if (!nproot) { 461 + dev_err(dev, "failed to find regulators node\n"); 462 + return -ENODEV; 463 + } 464 + for_each_child_of_node(nproot, np) 465 + for (i = 0; i < num; i++) { 466 + if (!of_node_name_eq(np, data[i].desc.of_match)) 467 + continue; 468 + /* 469 + * If STBY configs are supported, we must pass node 470 + * here to extract the initial voltages from the DT. 471 + * Thus we do the initial voltage getting in this 472 + * loop. 473 + */ 474 + ret = get_initial_voltage(dev, regmap, &data[i]); 475 + if (ret) { 476 + dev_err(dev, 477 + "Initializing voltages for %s failed\n", 478 + data[i].desc.name); 479 + of_node_put(np); 480 + of_node_put(nproot); 481 + 482 + return ret; 483 + } 484 + if (of_property_read_bool(np, "rohm,keep-on-stby")) { 485 + ret = regmap_set_bits(regmap, 486 + BD96801_ALWAYS_ON_REG, 487 + 1 << data[i].desc.id); 488 + if (ret) { 489 + dev_err(dev, 490 + "failed to set %s on-at-stby\n", 491 + data[i].desc.name); 492 + of_node_put(np); 493 + of_node_put(nproot); 494 + 495 + return ret; 496 + } 497 + } 498 + } 499 + of_node_put(nproot); 500 + 501 + return 0; 502 + } 503 + 504 + /* 505 + * Template for regulator data. Probe will allocate dynamic / driver instance 506 + * struct so we should be on a safe side even if there were multiple PMICs to 507 + * control. Note that there is a plan to allow multiple PMICs to be used so 508 + * systems can scale better. I am however still slightly unsure how the 509 + * multi-PMIC case will be handled. I don't know if the processor will have I2C 510 + * acces to all of the PMICs or only the first one. I'd guess there will be 511 + * access provided to all PMICs for voltage scaling - but the errors will only 512 + * be informed via the master PMIC. Eg, we should prepare to support multiple 513 + * driver instances - either with or without the IRQs... Well, let's first 514 + * just support the simple and clear single-PMIC setup and ponder the multi PMIC 515 + * case later. What we can easly do for preparing is to not use static global 516 + * data for regulators though. 517 + */ 518 + static const struct bd96801_pmic_data bd96801_data = { 519 + .regulator_data = { 520 + { 521 + .desc = { 522 + .name = "buck1", 523 + .of_match = of_match_ptr("buck1"), 524 + .regulators_node = of_match_ptr("regulators"), 525 + .id = BD96801_BUCK1, 526 + .ops = &bd96801_buck_ops, 527 + .type = REGULATOR_VOLTAGE, 528 + .linear_ranges = bd96801_tune_volts, 529 + .n_linear_ranges = ARRAY_SIZE(bd96801_tune_volts), 530 + .n_voltages = BD96801_BUCK_VOLTS, 531 + .enable_reg = BD96801_REG_ENABLE, 532 + .enable_mask = BD96801_BUCK1_EN_MASK, 533 + .enable_is_inverted = true, 534 + .vsel_reg = BD96801_BUCK1_VSEL_REG, 535 + .vsel_mask = BD96801_BUCK_VSEL_MASK, 536 + .ramp_reg = BD96801_BUCK1_VSEL_REG, 537 + .ramp_mask = BD96801_MASK_RAMP_DELAY, 538 + .ramp_delay_table = &buck_ramp_table[0], 539 + .n_ramp_values = ARRAY_SIZE(buck_ramp_table), 540 + .owner = THIS_MODULE, 541 + }, 542 + .init_ranges = bd96801_buck_init_volts, 543 + .num_ranges = ARRAY_SIZE(bd96801_buck_init_volts), 544 + .irq_desc = { 545 + .irqinfo = (struct bd96801_irqinfo *)&buck1_irqinfo[0], 546 + .num_irqs = ARRAY_SIZE(buck1_irqinfo), 547 + }, 548 + }, { 549 + .desc = { 550 + .name = "buck2", 551 + .of_match = of_match_ptr("buck2"), 552 + .regulators_node = of_match_ptr("regulators"), 553 + .id = BD96801_BUCK2, 554 + .ops = &bd96801_buck_ops, 555 + .type = REGULATOR_VOLTAGE, 556 + .linear_ranges = bd96801_tune_volts, 557 + .n_linear_ranges = ARRAY_SIZE(bd96801_tune_volts), 558 + .n_voltages = BD96801_BUCK_VOLTS, 559 + .enable_reg = BD96801_REG_ENABLE, 560 + .enable_mask = BD96801_BUCK2_EN_MASK, 561 + .enable_is_inverted = true, 562 + .vsel_reg = BD96801_BUCK2_VSEL_REG, 563 + .vsel_mask = BD96801_BUCK_VSEL_MASK, 564 + .ramp_reg = BD96801_BUCK2_VSEL_REG, 565 + .ramp_mask = BD96801_MASK_RAMP_DELAY, 566 + .ramp_delay_table = &buck_ramp_table[0], 567 + .n_ramp_values = ARRAY_SIZE(buck_ramp_table), 568 + .owner = THIS_MODULE, 569 + }, 570 + .irq_desc = { 571 + .irqinfo = (struct bd96801_irqinfo *)&buck2_irqinfo[0], 572 + .num_irqs = ARRAY_SIZE(buck2_irqinfo), 573 + }, 574 + .init_ranges = bd96801_buck_init_volts, 575 + .num_ranges = ARRAY_SIZE(bd96801_buck_init_volts), 576 + }, { 577 + .desc = { 578 + .name = "buck3", 579 + .of_match = of_match_ptr("buck3"), 580 + .regulators_node = of_match_ptr("regulators"), 581 + .id = BD96801_BUCK3, 582 + .ops = &bd96801_buck_ops, 583 + .type = REGULATOR_VOLTAGE, 584 + .linear_ranges = bd96801_tune_volts, 585 + .n_linear_ranges = ARRAY_SIZE(bd96801_tune_volts), 586 + .n_voltages = BD96801_BUCK_VOLTS, 587 + .enable_reg = BD96801_REG_ENABLE, 588 + .enable_mask = BD96801_BUCK3_EN_MASK, 589 + .enable_is_inverted = true, 590 + .vsel_reg = BD96801_BUCK3_VSEL_REG, 591 + .vsel_mask = BD96801_BUCK_VSEL_MASK, 592 + .ramp_reg = BD96801_BUCK3_VSEL_REG, 593 + .ramp_mask = BD96801_MASK_RAMP_DELAY, 594 + .ramp_delay_table = &buck_ramp_table[0], 595 + .n_ramp_values = ARRAY_SIZE(buck_ramp_table), 596 + .owner = THIS_MODULE, 597 + }, 598 + .irq_desc = { 599 + .irqinfo = (struct bd96801_irqinfo *)&buck3_irqinfo[0], 600 + .num_irqs = ARRAY_SIZE(buck3_irqinfo), 601 + }, 602 + .init_ranges = bd96801_buck_init_volts, 603 + .num_ranges = ARRAY_SIZE(bd96801_buck_init_volts), 604 + }, { 605 + .desc = { 606 + .name = "buck4", 607 + .of_match = of_match_ptr("buck4"), 608 + .regulators_node = of_match_ptr("regulators"), 609 + .id = BD96801_BUCK4, 610 + .ops = &bd96801_buck_ops, 611 + .type = REGULATOR_VOLTAGE, 612 + .linear_ranges = bd96801_tune_volts, 613 + .n_linear_ranges = ARRAY_SIZE(bd96801_tune_volts), 614 + .n_voltages = BD96801_BUCK_VOLTS, 615 + .enable_reg = BD96801_REG_ENABLE, 616 + .enable_mask = BD96801_BUCK4_EN_MASK, 617 + .enable_is_inverted = true, 618 + .vsel_reg = BD96801_BUCK4_VSEL_REG, 619 + .vsel_mask = BD96801_BUCK_VSEL_MASK, 620 + .ramp_reg = BD96801_BUCK4_VSEL_REG, 621 + .ramp_mask = BD96801_MASK_RAMP_DELAY, 622 + .ramp_delay_table = &buck_ramp_table[0], 623 + .n_ramp_values = ARRAY_SIZE(buck_ramp_table), 624 + .owner = THIS_MODULE, 625 + }, 626 + .irq_desc = { 627 + .irqinfo = (struct bd96801_irqinfo *)&buck4_irqinfo[0], 628 + .num_irqs = ARRAY_SIZE(buck4_irqinfo), 629 + }, 630 + .init_ranges = bd96801_buck_init_volts, 631 + .num_ranges = ARRAY_SIZE(bd96801_buck_init_volts), 632 + }, { 633 + .desc = { 634 + .name = "ldo5", 635 + .of_match = of_match_ptr("ldo5"), 636 + .regulators_node = of_match_ptr("regulators"), 637 + .id = BD96801_LDO5, 638 + .ops = &bd96801_ldo_ops, 639 + .type = REGULATOR_VOLTAGE, 640 + .linear_ranges = bd96801_ldo_int_volts, 641 + .n_linear_ranges = ARRAY_SIZE(bd96801_ldo_int_volts), 642 + .n_voltages = BD96801_LDO_VOLTS, 643 + .enable_reg = BD96801_REG_ENABLE, 644 + .enable_mask = BD96801_LDO5_EN_MASK, 645 + .enable_is_inverted = true, 646 + .vsel_reg = BD96801_LDO5_VSEL_REG, 647 + .vsel_mask = BD96801_LDO_VSEL_MASK, 648 + .owner = THIS_MODULE, 649 + }, 650 + .irq_desc = { 651 + .irqinfo = (struct bd96801_irqinfo *)&ldo5_irqinfo[0], 652 + .num_irqs = ARRAY_SIZE(ldo5_irqinfo), 653 + }, 654 + .ldo_vol_lvl = BD96801_LDO5_VOL_LVL_REG, 655 + }, { 656 + .desc = { 657 + .name = "ldo6", 658 + .of_match = of_match_ptr("ldo6"), 659 + .regulators_node = of_match_ptr("regulators"), 660 + .id = BD96801_LDO6, 661 + .ops = &bd96801_ldo_ops, 662 + .type = REGULATOR_VOLTAGE, 663 + .linear_ranges = bd96801_ldo_int_volts, 664 + .n_linear_ranges = ARRAY_SIZE(bd96801_ldo_int_volts), 665 + .n_voltages = BD96801_LDO_VOLTS, 666 + .enable_reg = BD96801_REG_ENABLE, 667 + .enable_mask = BD96801_LDO6_EN_MASK, 668 + .enable_is_inverted = true, 669 + .vsel_reg = BD96801_LDO6_VSEL_REG, 670 + .vsel_mask = BD96801_LDO_VSEL_MASK, 671 + .owner = THIS_MODULE, 672 + }, 673 + .irq_desc = { 674 + .irqinfo = (struct bd96801_irqinfo *)&ldo6_irqinfo[0], 675 + .num_irqs = ARRAY_SIZE(ldo6_irqinfo), 676 + }, 677 + .ldo_vol_lvl = BD96801_LDO6_VOL_LVL_REG, 678 + }, { 679 + .desc = { 680 + .name = "ldo7", 681 + .of_match = of_match_ptr("ldo7"), 682 + .regulators_node = of_match_ptr("regulators"), 683 + .id = BD96801_LDO7, 684 + .ops = &bd96801_ldo_ops, 685 + .type = REGULATOR_VOLTAGE, 686 + .linear_ranges = bd96801_ldo_int_volts, 687 + .n_linear_ranges = ARRAY_SIZE(bd96801_ldo_int_volts), 688 + .n_voltages = BD96801_LDO_VOLTS, 689 + .enable_reg = BD96801_REG_ENABLE, 690 + .enable_mask = BD96801_LDO7_EN_MASK, 691 + .enable_is_inverted = true, 692 + .vsel_reg = BD96801_LDO7_VSEL_REG, 693 + .vsel_mask = BD96801_LDO_VSEL_MASK, 694 + .owner = THIS_MODULE, 695 + }, 696 + .irq_desc = { 697 + .irqinfo = (struct bd96801_irqinfo *)&ldo7_irqinfo[0], 698 + .num_irqs = ARRAY_SIZE(ldo7_irqinfo), 699 + }, 700 + .ldo_vol_lvl = BD96801_LDO7_VOL_LVL_REG, 701 + }, 702 + }, 703 + }; 704 + 705 + static int initialize_pmic_data(struct device *dev, 706 + struct bd96801_pmic_data *pdata) 707 + { 708 + int r, i; 709 + 710 + /* 711 + * Allocate and initialize IRQ data for all of the regulators. We 712 + * wish to modify IRQ information independently for each driver 713 + * instance. 714 + */ 715 + for (r = 0; r < BD96801_NUM_REGULATORS; r++) { 716 + const struct bd96801_irqinfo *template; 717 + struct bd96801_irqinfo *new; 718 + int num_infos; 719 + 720 + template = pdata->regulator_data[r].irq_desc.irqinfo; 721 + num_infos = pdata->regulator_data[r].irq_desc.num_irqs; 722 + 723 + new = devm_kcalloc(dev, num_infos, sizeof(*new), GFP_KERNEL); 724 + if (!new) 725 + return -ENOMEM; 726 + 727 + pdata->regulator_data[r].irq_desc.irqinfo = new; 728 + 729 + for (i = 0; i < num_infos; i++) 730 + new[i] = template[i]; 731 + } 732 + 733 + return 0; 734 + } 735 + 736 + static int bd96801_rdev_intb_irqs(struct platform_device *pdev, 737 + struct bd96801_pmic_data *pdata, 738 + struct bd96801_irqinfo *iinfo, 739 + struct regulator_dev *rdev) 740 + { 741 + struct regulator_dev *rdev_arr[1]; 742 + void *retp; 743 + int err = 0; 744 + int irq; 745 + int err_flags[] = { 746 + [BD96801_PROT_OVP] = REGULATOR_ERROR_REGULATION_OUT, 747 + [BD96801_PROT_UVP] = REGULATOR_ERROR_UNDER_VOLTAGE, 748 + [BD96801_PROT_OCP] = REGULATOR_ERROR_OVER_CURRENT, 749 + [BD96801_PROT_TEMP] = REGULATOR_ERROR_OVER_TEMP, 750 + 751 + }; 752 + int wrn_flags[] = { 753 + [BD96801_PROT_OVP] = REGULATOR_ERROR_OVER_VOLTAGE_WARN, 754 + [BD96801_PROT_UVP] = REGULATOR_ERROR_UNDER_VOLTAGE_WARN, 755 + [BD96801_PROT_OCP] = REGULATOR_ERROR_OVER_CURRENT_WARN, 756 + [BD96801_PROT_TEMP] = REGULATOR_ERROR_OVER_TEMP_WARN, 757 + }; 758 + 759 + /* 760 + * Don't install IRQ handler if both error and warning 761 + * notifications are explicitly disabled 762 + */ 763 + if (!iinfo->err_cfg && !iinfo->wrn_cfg) 764 + return 0; 765 + 766 + if (WARN_ON(iinfo->type >= BD96801_NUM_PROT)) 767 + return -EINVAL; 768 + 769 + if (iinfo->err_cfg) 770 + err = err_flags[iinfo->type]; 771 + else if (iinfo->wrn_cfg) 772 + err = wrn_flags[iinfo->type]; 773 + 774 + iinfo->irq_desc.data = pdata; 775 + irq = platform_get_irq_byname(pdev, iinfo->irq_name); 776 + if (irq < 0) 777 + return irq; 778 + /* Find notifications for this IRQ (WARN/ERR) */ 779 + 780 + rdev_arr[0] = rdev; 781 + retp = devm_regulator_irq_helper(&pdev->dev, 782 + &iinfo->irq_desc, irq, 783 + 0, err, NULL, rdev_arr, 784 + 1); 785 + if (IS_ERR(retp)) 786 + return PTR_ERR(retp); 787 + 788 + return 0; 789 + } 790 + 791 + 792 + 793 + static int bd96801_probe(struct platform_device *pdev) 794 + { 795 + struct regulator_dev *ldo_errs_rdev_arr[BD96801_NUM_LDOS]; 796 + struct bd96801_regulator_data *rdesc; 797 + struct regulator_config config = {}; 798 + int ldo_errs_arr[BD96801_NUM_LDOS]; 799 + struct bd96801_pmic_data *pdata; 800 + int temp_notif_ldos = 0; 801 + struct device *parent; 802 + int i, ret; 803 + void *retp; 804 + 805 + parent = pdev->dev.parent; 806 + 807 + pdata = devm_kmemdup(&pdev->dev, &bd96801_data, sizeof(bd96801_data), 808 + GFP_KERNEL); 809 + if (!pdata) 810 + return -ENOMEM; 811 + 812 + if (initialize_pmic_data(&pdev->dev, pdata)) 813 + return -ENOMEM; 814 + 815 + pdata->regmap = dev_get_regmap(parent, NULL); 816 + if (!pdata->regmap) { 817 + dev_err(&pdev->dev, "No register map found\n"); 818 + return -ENODEV; 819 + } 820 + 821 + rdesc = &pdata->regulator_data[0]; 822 + 823 + config.driver_data = pdata; 824 + config.regmap = pdata->regmap; 825 + config.dev = parent; 826 + 827 + ret = bd96801_walk_regulator_dt(&pdev->dev, pdata->regmap, rdesc, 828 + BD96801_NUM_REGULATORS); 829 + if (ret) 830 + return ret; 831 + 832 + for (i = 0; i < ARRAY_SIZE(pdata->regulator_data); i++) { 833 + struct regulator_dev *rdev; 834 + struct bd96801_irq_desc *idesc = &rdesc[i].irq_desc; 835 + int j; 836 + 837 + rdev = devm_regulator_register(&pdev->dev, 838 + &rdesc[i].desc, &config); 839 + if (IS_ERR(rdev)) { 840 + dev_err(&pdev->dev, 841 + "failed to register %s regulator\n", 842 + rdesc[i].desc.name); 843 + return PTR_ERR(rdev); 844 + } 845 + /* 846 + * LDOs don't have own temperature monitoring. If temperature 847 + * notification was requested for this LDO from DT then we will 848 + * add the regulator to be notified if central IC temperature 849 + * exceeds threshold. 850 + */ 851 + if (rdesc[i].ldo_errs) { 852 + ldo_errs_rdev_arr[temp_notif_ldos] = rdev; 853 + ldo_errs_arr[temp_notif_ldos] = rdesc[i].ldo_errs; 854 + temp_notif_ldos++; 855 + } 856 + if (!idesc) 857 + continue; 858 + 859 + /* Register INTB handlers for configured protections */ 860 + for (j = 0; j < idesc->num_irqs; j++) { 861 + ret = bd96801_rdev_intb_irqs(pdev, pdata, 862 + &idesc->irqinfo[j], rdev); 863 + if (ret) 864 + return ret; 865 + } 866 + } 867 + if (temp_notif_ldos) { 868 + int irq; 869 + struct regulator_irq_desc tw_desc = { 870 + .name = "bd96801-core-thermal", 871 + .irq_off_ms = 500, 872 + .map_event = ldo_map_notif, 873 + }; 874 + 875 + irq = platform_get_irq_byname(pdev, "bd96801-core-thermal"); 876 + if (irq < 0) 877 + return irq; 878 + 879 + retp = devm_regulator_irq_helper(&pdev->dev, &tw_desc, irq, 0, 880 + 0, &ldo_errs_arr[0], 881 + &ldo_errs_rdev_arr[0], 882 + temp_notif_ldos); 883 + if (IS_ERR(retp)) 884 + return PTR_ERR(retp); 885 + } 886 + 887 + return 0; 888 + } 889 + 890 + static const struct platform_device_id bd96801_pmic_id[] = { 891 + { "bd96801-regulator", }, 892 + { } 893 + }; 894 + MODULE_DEVICE_TABLE(platform, bd96801_pmic_id); 895 + 896 + static struct platform_driver bd96801_regulator = { 897 + .driver = { 898 + .name = "bd96801-pmic" 899 + }, 900 + .probe = bd96801_probe, 901 + .id_table = bd96801_pmic_id, 902 + }; 903 + 904 + module_platform_driver(bd96801_regulator); 905 + 906 + MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); 907 + MODULE_DESCRIPTION("BD96801 voltage regulator driver"); 908 + MODULE_LICENSE("GPL");
+198
drivers/regulator/qcom-pm8008-regulator.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. 4 + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. 5 + * Copyright (c) 2024 Linaro Limited 6 + */ 7 + 8 + #include <linux/array_size.h> 9 + #include <linux/bits.h> 10 + #include <linux/device.h> 11 + #include <linux/math.h> 12 + #include <linux/module.h> 13 + #include <linux/of.h> 14 + #include <linux/platform_device.h> 15 + #include <linux/regmap.h> 16 + #include <linux/regulator/driver.h> 17 + 18 + #include <asm/byteorder.h> 19 + 20 + #define DEFAULT_VOLTAGE_STEPPER_RATE 38400 21 + 22 + #define LDO_STEPPER_CTL_REG 0x3b 23 + #define STEP_RATE_MASK GENMASK(1, 0) 24 + 25 + #define LDO_VSET_LB_REG 0x40 26 + 27 + #define LDO_ENABLE_REG 0x46 28 + #define ENABLE_BIT BIT(7) 29 + 30 + struct pm8008_regulator { 31 + struct regmap *regmap; 32 + struct regulator_desc desc; 33 + unsigned int base; 34 + }; 35 + 36 + struct pm8008_regulator_data { 37 + const char *name; 38 + const char *supply_name; 39 + unsigned int base; 40 + int min_dropout_uV; 41 + const struct linear_range *voltage_range; 42 + }; 43 + 44 + static const struct linear_range nldo_ranges[] = { 45 + REGULATOR_LINEAR_RANGE(528000, 0, 122, 8000), 46 + }; 47 + 48 + static const struct linear_range pldo_ranges[] = { 49 + REGULATOR_LINEAR_RANGE(1504000, 0, 237, 8000), 50 + }; 51 + 52 + static const struct pm8008_regulator_data pm8008_reg_data[] = { 53 + { "ldo1", "vdd-l1-l2", 0x4000, 225000, nldo_ranges, }, 54 + { "ldo2", "vdd-l1-l2", 0x4100, 225000, nldo_ranges, }, 55 + { "ldo3", "vdd-l3-l4", 0x4200, 300000, pldo_ranges, }, 56 + { "ldo4", "vdd-l3-l4", 0x4300, 300000, pldo_ranges, }, 57 + { "ldo5", "vdd-l5", 0x4400, 200000, pldo_ranges, }, 58 + { "ldo6", "vdd-l6", 0x4500, 200000, pldo_ranges, }, 59 + { "ldo7", "vdd-l7", 0x4600, 200000, pldo_ranges, }, 60 + }; 61 + 62 + static int pm8008_regulator_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel) 63 + { 64 + struct pm8008_regulator *preg = rdev_get_drvdata(rdev); 65 + unsigned int mV; 66 + __le16 val; 67 + int ret; 68 + 69 + ret = regulator_list_voltage_linear_range(rdev, sel); 70 + if (ret < 0) 71 + return ret; 72 + 73 + mV = DIV_ROUND_UP(ret, 1000); 74 + 75 + val = cpu_to_le16(mV); 76 + 77 + ret = regmap_bulk_write(preg->regmap, preg->base + LDO_VSET_LB_REG, 78 + &val, sizeof(val)); 79 + if (ret < 0) 80 + return ret; 81 + 82 + return 0; 83 + } 84 + 85 + static int pm8008_regulator_get_voltage_sel(struct regulator_dev *rdev) 86 + { 87 + struct pm8008_regulator *preg = rdev_get_drvdata(rdev); 88 + unsigned int uV; 89 + __le16 val; 90 + int ret; 91 + 92 + ret = regmap_bulk_read(preg->regmap, preg->base + LDO_VSET_LB_REG, 93 + &val, sizeof(val)); 94 + if (ret < 0) 95 + return ret; 96 + 97 + uV = le16_to_cpu(val) * 1000; 98 + 99 + return (uV - preg->desc.min_uV) / preg->desc.uV_step; 100 + } 101 + 102 + static const struct regulator_ops pm8008_regulator_ops = { 103 + .list_voltage = regulator_list_voltage_linear, 104 + .set_voltage_sel = pm8008_regulator_set_voltage_sel, 105 + .get_voltage_sel = pm8008_regulator_get_voltage_sel, 106 + .enable = regulator_enable_regmap, 107 + .disable = regulator_disable_regmap, 108 + .is_enabled = regulator_is_enabled_regmap, 109 + }; 110 + 111 + static int pm8008_regulator_probe(struct platform_device *pdev) 112 + { 113 + const struct pm8008_regulator_data *data; 114 + struct regulator_config config = {}; 115 + struct device *dev = &pdev->dev; 116 + struct pm8008_regulator *preg; 117 + struct regulator_desc *desc; 118 + struct regulator_dev *rdev; 119 + struct regmap *regmap; 120 + unsigned int val; 121 + int ret, i; 122 + 123 + regmap = dev_get_regmap(dev->parent, "secondary"); 124 + if (!regmap) 125 + return -EINVAL; 126 + 127 + for (i = 0; i < ARRAY_SIZE(pm8008_reg_data); i++) { 128 + data = &pm8008_reg_data[i]; 129 + 130 + preg = devm_kzalloc(dev, sizeof(*preg), GFP_KERNEL); 131 + if (!preg) 132 + return -ENOMEM; 133 + 134 + preg->regmap = regmap; 135 + preg->base = data->base; 136 + 137 + desc = &preg->desc; 138 + 139 + desc->name = data->name; 140 + desc->supply_name = data->supply_name; 141 + desc->of_match = data->name; 142 + desc->regulators_node = of_match_ptr("regulators"); 143 + desc->ops = &pm8008_regulator_ops; 144 + desc->type = REGULATOR_VOLTAGE; 145 + desc->owner = THIS_MODULE; 146 + 147 + desc->linear_ranges = data->voltage_range; 148 + desc->n_linear_ranges = 1; 149 + desc->uV_step = desc->linear_ranges[0].step; 150 + desc->min_uV = desc->linear_ranges[0].min; 151 + desc->n_voltages = linear_range_values_in_range(&desc->linear_ranges[0]); 152 + 153 + ret = regmap_read(regmap, preg->base + LDO_STEPPER_CTL_REG, &val); 154 + if (ret < 0) { 155 + dev_err(dev, "failed to read step rate: %d\n", ret); 156 + return ret; 157 + } 158 + val &= STEP_RATE_MASK; 159 + desc->ramp_delay = DEFAULT_VOLTAGE_STEPPER_RATE >> val; 160 + 161 + desc->min_dropout_uV = data->min_dropout_uV; 162 + 163 + desc->enable_reg = preg->base + LDO_ENABLE_REG; 164 + desc->enable_mask = ENABLE_BIT; 165 + 166 + config.dev = dev->parent; 167 + config.driver_data = preg; 168 + config.regmap = regmap; 169 + 170 + rdev = devm_regulator_register(dev, desc, &config); 171 + if (IS_ERR(rdev)) { 172 + ret = PTR_ERR(rdev); 173 + dev_err(dev, "failed to register regulator %s: %d\n", 174 + desc->name, ret); 175 + return ret; 176 + } 177 + } 178 + 179 + return 0; 180 + } 181 + 182 + static const struct platform_device_id pm8008_regulator_id_table[] = { 183 + { "pm8008-regulator" }, 184 + { } 185 + }; 186 + MODULE_DEVICE_TABLE(platform, pm8008_regulator_id_table); 187 + 188 + static struct platform_driver pm8008_regulator_driver = { 189 + .driver = { 190 + .name = "qcom-pm8008-regulator", 191 + }, 192 + .probe = pm8008_regulator_probe, 193 + .id_table = pm8008_regulator_id_table, 194 + }; 195 + module_platform_driver(pm8008_regulator_driver); 196 + 197 + MODULE_DESCRIPTION("Qualcomm PM8008 PMIC regulator driver"); 198 + MODULE_LICENSE("GPL");
+15 -25
drivers/soc/samsung/exynos-pmu.c
··· 220 220 .reg_update_bits = tensor_sec_update_bits, 221 221 }; 222 222 223 - static const struct regmap_config regmap_mmiocfg = { 224 - .name = "pmu_regs", 225 - .reg_bits = 32, 226 - .reg_stride = 4, 227 - .val_bits = 32, 228 - .fast_io = true, 229 - .use_single_read = true, 230 - .use_single_write = true, 231 - }; 232 - 233 223 static const struct exynos_pmu_data gs101_pmu_data = { 234 224 .pmu_secure = true 235 225 }; ··· 296 306 struct regmap *exynos_get_pmu_regmap_by_phandle(struct device_node *np, 297 307 const char *propname) 298 308 { 299 - struct exynos_pmu_context *ctx; 300 309 struct device_node *pmu_np; 301 310 struct device *dev; 302 311 ··· 321 332 if (!dev) 322 333 return ERR_PTR(-EPROBE_DEFER); 323 334 324 - ctx = dev_get_drvdata(dev); 325 - 326 - return ctx->pmureg; 335 + return syscon_node_to_regmap(pmu_np); 327 336 } 328 337 EXPORT_SYMBOL_GPL(exynos_get_pmu_regmap_by_phandle); 329 338 ··· 358 371 regmap = devm_regmap_init(dev, NULL, 359 372 (void *)(uintptr_t)res->start, 360 373 &pmu_regmcfg); 361 - } else { 362 - /* All other SoCs use a MMIO regmap */ 363 - pmu_regmcfg = regmap_mmiocfg; 364 - pmu_regmcfg.max_register = resource_size(res) - 365 - pmu_regmcfg.reg_stride; 366 - regmap = devm_regmap_init_mmio(dev, pmu_base_addr, 367 - &pmu_regmcfg); 368 - } 369 374 370 - if (IS_ERR(regmap)) 371 - return dev_err_probe(&pdev->dev, PTR_ERR(regmap), 372 - "regmap init failed\n"); 375 + if (IS_ERR(regmap)) 376 + return dev_err_probe(&pdev->dev, PTR_ERR(regmap), 377 + "regmap init failed\n"); 378 + 379 + ret = of_syscon_register_regmap(dev->of_node, regmap); 380 + if (ret) 381 + return ret; 382 + } else { 383 + /* let syscon create mmio regmap */ 384 + regmap = syscon_node_to_regmap(dev->of_node); 385 + if (IS_ERR(regmap)) 386 + return dev_err_probe(&pdev->dev, PTR_ERR(regmap), 387 + "syscon_node_to_regmap failed\n"); 388 + } 373 389 374 390 pmu_context->pmureg = regmap; 375 391 pmu_context->dev = dev;
+13
drivers/watchdog/Kconfig
··· 181 181 watchdog. Alternatively say M to compile the driver as a module, 182 182 which will be called bd9576_wdt. 183 183 184 + config BD96801_WATCHDOG 185 + tristate "ROHM BD96801 PMIC Watchdog" 186 + depends on MFD_ROHM_BD96801 187 + select WATCHDOG_CORE 188 + help 189 + Support for the watchdog in the ROHM BD96801 PMIC. Watchdog can be 190 + configured to only generate IRQ or to trigger system reset via reset 191 + pin. 192 + 193 + Say Y here to include support for the ROHM BD96801 watchdog. 194 + Alternatively say M to compile the driver as a module, 195 + which will be called bd96801_wdt. 196 + 184 197 config CROS_EC_WATCHDOG 185 198 tristate "ChromeOS EC-based watchdog" 186 199 select WATCHDOG_CORE
+1
drivers/watchdog/Makefile
··· 218 218 219 219 # Architecture Independent 220 220 obj-$(CONFIG_BD957XMUF_WATCHDOG) += bd9576_wdt.o 221 + obj-$(CONFIG_BD96801_WATCHDOG) += bd96801_wdt.o 221 222 obj-$(CONFIG_CROS_EC_WATCHDOG) += cros_ec_wdt.o 222 223 obj-$(CONFIG_DA9052_WATCHDOG) += da9052_wdt.o 223 224 obj-$(CONFIG_DA9055_WATCHDOG) += da9055_wdt.o
+417
drivers/watchdog/bd96801_wdt.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (C) 2024 ROHM Semiconductors 4 + * 5 + * ROHM BD96801 watchdog driver 6 + */ 7 + 8 + #include <linux/bitfield.h> 9 + #include <linux/interrupt.h> 10 + #include <linux/kernel.h> 11 + #include <linux/mfd/rohm-bd96801.h> 12 + #include <linux/mfd/rohm-generic.h> 13 + #include <linux/module.h> 14 + #include <linux/of.h> 15 + #include <linux/platform_device.h> 16 + #include <linux/reboot.h> 17 + #include <linux/regmap.h> 18 + #include <linux/watchdog.h> 19 + 20 + static bool nowayout; 21 + module_param(nowayout, bool, 0); 22 + MODULE_PARM_DESC(nowayout, 23 + "Watchdog cannot be stopped once started (default=\"false\")"); 24 + 25 + #define BD96801_WD_TMO_SHORT_MASK 0x70 26 + #define BD96801_WD_RATIO_MASK 0x3 27 + #define BD96801_WD_TYPE_MASK 0x4 28 + #define BD96801_WD_TYPE_SLOW 0x4 29 + #define BD96801_WD_TYPE_WIN 0x0 30 + 31 + #define BD96801_WD_EN_MASK 0x3 32 + #define BD96801_WD_IF_EN 0x1 33 + #define BD96801_WD_QA_EN 0x2 34 + #define BD96801_WD_DISABLE 0x0 35 + 36 + #define BD96801_WD_ASSERT_MASK 0x8 37 + #define BD96801_WD_ASSERT_RST 0x8 38 + #define BD96801_WD_ASSERT_IRQ 0x0 39 + 40 + #define BD96801_WD_FEED_MASK 0x1 41 + #define BD96801_WD_FEED 0x1 42 + 43 + /* 1.1 mS */ 44 + #define FASTNG_MIN 11 45 + #define FASTNG_MAX_US (100 * FASTNG_MIN << 7) 46 + #define SLOWNG_MAX_US (16 * FASTNG_MAX_US) 47 + 48 + #define BD96801_WDT_DEFAULT_MARGIN_MS 1843 49 + /* Unit is seconds */ 50 + #define DEFAULT_TIMEOUT 30 51 + 52 + /* 53 + * BD96801 WDG supports window mode so the TMO consists of SHORT and LONG 54 + * timeout values. SHORT time is meaningful only in window mode where feeding 55 + * period shorter than SHORT would be an error. LONG time is used to detect if 56 + * feeding is not occurring within given time limit (SoC SW hangs). The LONG 57 + * timeout time is a multiple of (2, 4, 8 or 16 times) the SHORT timeout. 58 + */ 59 + 60 + struct wdtbd96801 { 61 + struct device *dev; 62 + struct regmap *regmap; 63 + struct watchdog_device wdt; 64 + }; 65 + 66 + static int bd96801_wdt_ping(struct watchdog_device *wdt) 67 + { 68 + struct wdtbd96801 *w = watchdog_get_drvdata(wdt); 69 + 70 + return regmap_update_bits(w->regmap, BD96801_REG_WD_FEED, 71 + BD96801_WD_FEED_MASK, BD96801_WD_FEED); 72 + } 73 + 74 + static int bd96801_wdt_start(struct watchdog_device *wdt) 75 + { 76 + struct wdtbd96801 *w = watchdog_get_drvdata(wdt); 77 + 78 + return regmap_update_bits(w->regmap, BD96801_REG_WD_CONF, 79 + BD96801_WD_EN_MASK, BD96801_WD_IF_EN); 80 + } 81 + 82 + static int bd96801_wdt_stop(struct watchdog_device *wdt) 83 + { 84 + struct wdtbd96801 *w = watchdog_get_drvdata(wdt); 85 + 86 + return regmap_update_bits(w->regmap, BD96801_REG_WD_CONF, 87 + BD96801_WD_EN_MASK, BD96801_WD_DISABLE); 88 + } 89 + 90 + static const struct watchdog_info bd96801_wdt_info = { 91 + .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | 92 + WDIOF_SETTIMEOUT, 93 + .identity = "BD96801 Watchdog", 94 + }; 95 + 96 + static const struct watchdog_ops bd96801_wdt_ops = { 97 + .start = bd96801_wdt_start, 98 + .stop = bd96801_wdt_stop, 99 + .ping = bd96801_wdt_ping, 100 + }; 101 + 102 + static int find_closest_fast(unsigned int target, int *sel, unsigned int *val) 103 + { 104 + unsigned int window = FASTNG_MIN; 105 + int i; 106 + 107 + for (i = 0; i < 8 && window < target; i++) 108 + window <<= 1; 109 + 110 + if (i == 8) 111 + return -EINVAL; 112 + 113 + *val = window; 114 + *sel = i; 115 + 116 + return 0; 117 + } 118 + 119 + static int find_closest_slow_by_fast(unsigned int fast_val, unsigned int *target, 120 + int *slowsel) 121 + { 122 + static const int multipliers[] = {2, 4, 8, 16}; 123 + int sel; 124 + 125 + for (sel = 0; sel < ARRAY_SIZE(multipliers) && 126 + multipliers[sel] * fast_val < *target; sel++) 127 + ; 128 + 129 + if (sel == ARRAY_SIZE(multipliers)) 130 + return -EINVAL; 131 + 132 + *slowsel = sel; 133 + *target = multipliers[sel] * fast_val; 134 + 135 + return 0; 136 + } 137 + 138 + static int find_closest_slow(unsigned int *target, int *slow_sel, int *fast_sel) 139 + { 140 + static const int multipliers[] = {2, 4, 8, 16}; 141 + unsigned int window = FASTNG_MIN; 142 + unsigned int val = 0; 143 + int i, j; 144 + 145 + for (i = 0; i < 8; i++) { 146 + for (j = 0; j < ARRAY_SIZE(multipliers); j++) { 147 + unsigned int slow; 148 + 149 + slow = window * multipliers[j]; 150 + if (slow >= *target && (!val || slow < val)) { 151 + val = slow; 152 + *fast_sel = i; 153 + *slow_sel = j; 154 + } 155 + } 156 + window <<= 1; 157 + } 158 + if (!val) 159 + return -EINVAL; 160 + 161 + *target = val; 162 + 163 + return 0; 164 + } 165 + 166 + static int bd96801_set_wdt_mode(struct wdtbd96801 *w, unsigned int hw_margin, 167 + unsigned int hw_margin_min) 168 + { 169 + int fastng, slowng, type, ret, reg, mask; 170 + struct device *dev = w->dev; 171 + 172 + 173 + if (hw_margin_min * 1000 > FASTNG_MAX_US) { 174 + dev_err(dev, "Unsupported fast timeout %u uS [max %u]\n", 175 + hw_margin_min * 1000, FASTNG_MAX_US); 176 + 177 + return -EINVAL; 178 + } 179 + 180 + if (hw_margin * 1000 > SLOWNG_MAX_US) { 181 + dev_err(dev, "Unsupported slow timeout %u uS [max %u]\n", 182 + hw_margin * 1000, SLOWNG_MAX_US); 183 + 184 + return -EINVAL; 185 + } 186 + 187 + /* 188 + * Convert to 100uS to guarantee reasonable timeouts fit in 189 + * 32bit maintaining also a decent accuracy. 190 + */ 191 + hw_margin *= 10; 192 + hw_margin_min *= 10; 193 + 194 + if (hw_margin_min) { 195 + unsigned int min; 196 + 197 + type = BD96801_WD_TYPE_WIN; 198 + dev_dbg(dev, "Setting type WINDOW 0x%x\n", type); 199 + ret = find_closest_fast(hw_margin_min, &fastng, &min); 200 + if (ret) 201 + return ret; 202 + 203 + ret = find_closest_slow_by_fast(min, &hw_margin, &slowng); 204 + if (ret) { 205 + dev_err(dev, 206 + "can't support slow timeout %u uS using fast %u uS. [max slow %u uS]\n", 207 + hw_margin * 100, min * 100, min * 100 * 16); 208 + 209 + return ret; 210 + } 211 + w->wdt.min_hw_heartbeat_ms = min / 10; 212 + } else { 213 + type = BD96801_WD_TYPE_SLOW; 214 + dev_dbg(dev, "Setting type SLOW 0x%x\n", type); 215 + ret = find_closest_slow(&hw_margin, &slowng, &fastng); 216 + if (ret) 217 + return ret; 218 + } 219 + 220 + w->wdt.max_hw_heartbeat_ms = hw_margin / 10; 221 + 222 + fastng = FIELD_PREP(BD96801_WD_TMO_SHORT_MASK, fastng); 223 + 224 + reg = slowng | fastng; 225 + mask = BD96801_WD_RATIO_MASK | BD96801_WD_TMO_SHORT_MASK; 226 + ret = regmap_update_bits(w->regmap, BD96801_REG_WD_TMO, 227 + mask, reg); 228 + if (ret) 229 + return ret; 230 + 231 + ret = regmap_update_bits(w->regmap, BD96801_REG_WD_CONF, 232 + BD96801_WD_TYPE_MASK, type); 233 + 234 + return ret; 235 + } 236 + 237 + static int bd96801_set_heartbeat_from_hw(struct wdtbd96801 *w, 238 + unsigned int conf_reg) 239 + { 240 + int ret; 241 + unsigned int val, sel, fast; 242 + 243 + /* 244 + * The BD96801 supports a somewhat peculiar QA-mode, which we do not 245 + * support in this driver. If the QA-mode is enabled then we just 246 + * warn and bail-out. 247 + */ 248 + if ((conf_reg & BD96801_WD_EN_MASK) != BD96801_WD_IF_EN) { 249 + dev_err(w->dev, "watchdog set to Q&A mode - exiting\n"); 250 + return -EINVAL; 251 + } 252 + 253 + ret = regmap_read(w->regmap, BD96801_REG_WD_TMO, &val); 254 + if (ret) 255 + return ret; 256 + 257 + sel = FIELD_GET(BD96801_WD_TMO_SHORT_MASK, val); 258 + fast = FASTNG_MIN << sel; 259 + 260 + sel = (val & BD96801_WD_RATIO_MASK) + 1; 261 + w->wdt.max_hw_heartbeat_ms = (fast << sel) / USEC_PER_MSEC; 262 + 263 + if ((conf_reg & BD96801_WD_TYPE_MASK) == BD96801_WD_TYPE_WIN) 264 + w->wdt.min_hw_heartbeat_ms = fast / USEC_PER_MSEC; 265 + 266 + return 0; 267 + } 268 + 269 + static int init_wdg_hw(struct wdtbd96801 *w) 270 + { 271 + u32 hw_margin[2]; 272 + int count, ret; 273 + u32 hw_margin_max = BD96801_WDT_DEFAULT_MARGIN_MS, hw_margin_min = 0; 274 + 275 + count = device_property_count_u32(w->dev->parent, "rohm,hw-timeout-ms"); 276 + if (count < 0 && count != -EINVAL) 277 + return count; 278 + 279 + if (count > 0) { 280 + if (count > ARRAY_SIZE(hw_margin)) 281 + return -EINVAL; 282 + 283 + ret = device_property_read_u32_array(w->dev->parent, 284 + "rohm,hw-timeout-ms", 285 + &hw_margin[0], count); 286 + if (ret < 0) 287 + return ret; 288 + 289 + if (count == 1) 290 + hw_margin_max = hw_margin[0]; 291 + 292 + if (count == 2) { 293 + if (hw_margin[1] > hw_margin[0]) { 294 + hw_margin_max = hw_margin[1]; 295 + hw_margin_min = hw_margin[0]; 296 + } else { 297 + hw_margin_max = hw_margin[0]; 298 + hw_margin_min = hw_margin[1]; 299 + } 300 + } 301 + } 302 + 303 + ret = bd96801_set_wdt_mode(w, hw_margin_max, hw_margin_min); 304 + if (ret) 305 + return ret; 306 + 307 + ret = device_property_match_string(w->dev->parent, "rohm,wdg-action", 308 + "prstb"); 309 + if (ret >= 0) { 310 + ret = regmap_update_bits(w->regmap, BD96801_REG_WD_CONF, 311 + BD96801_WD_ASSERT_MASK, 312 + BD96801_WD_ASSERT_RST); 313 + return ret; 314 + } 315 + 316 + ret = device_property_match_string(w->dev->parent, "rohm,wdg-action", 317 + "intb-only"); 318 + if (ret >= 0) { 319 + ret = regmap_update_bits(w->regmap, BD96801_REG_WD_CONF, 320 + BD96801_WD_ASSERT_MASK, 321 + BD96801_WD_ASSERT_IRQ); 322 + return ret; 323 + } 324 + 325 + return 0; 326 + } 327 + 328 + static irqreturn_t bd96801_irq_hnd(int irq, void *data) 329 + { 330 + emergency_restart(); 331 + 332 + return IRQ_NONE; 333 + } 334 + 335 + static int bd96801_wdt_probe(struct platform_device *pdev) 336 + { 337 + struct wdtbd96801 *w; 338 + int ret, irq; 339 + unsigned int val; 340 + 341 + w = devm_kzalloc(&pdev->dev, sizeof(*w), GFP_KERNEL); 342 + if (!w) 343 + return -ENOMEM; 344 + 345 + w->regmap = dev_get_regmap(pdev->dev.parent, NULL); 346 + w->dev = &pdev->dev; 347 + 348 + w->wdt.info = &bd96801_wdt_info; 349 + w->wdt.ops = &bd96801_wdt_ops; 350 + w->wdt.parent = pdev->dev.parent; 351 + w->wdt.timeout = DEFAULT_TIMEOUT; 352 + watchdog_set_drvdata(&w->wdt, w); 353 + 354 + ret = regmap_read(w->regmap, BD96801_REG_WD_CONF, &val); 355 + if (ret) 356 + return dev_err_probe(&pdev->dev, ret, 357 + "Failed to get the watchdog state\n"); 358 + 359 + /* 360 + * If the WDG is already enabled we assume it is configured by boot. 361 + * In this case we just update the hw-timeout based on values set to 362 + * the timeout / mode registers and leave the hardware configs 363 + * untouched. 364 + */ 365 + if ((val & BD96801_WD_EN_MASK) != BD96801_WD_DISABLE) { 366 + dev_dbg(&pdev->dev, "watchdog was running during probe\n"); 367 + ret = bd96801_set_heartbeat_from_hw(w, val); 368 + if (ret) 369 + return ret; 370 + 371 + set_bit(WDOG_HW_RUNNING, &w->wdt.status); 372 + } else { 373 + /* If WDG is not running so we will initializate it */ 374 + ret = init_wdg_hw(w); 375 + if (ret) 376 + return ret; 377 + } 378 + 379 + dev_dbg(w->dev, "heartbeat set to %u - %u\n", 380 + w->wdt.min_hw_heartbeat_ms, w->wdt.max_hw_heartbeat_ms); 381 + 382 + watchdog_init_timeout(&w->wdt, 0, pdev->dev.parent); 383 + watchdog_set_nowayout(&w->wdt, nowayout); 384 + watchdog_stop_on_reboot(&w->wdt); 385 + 386 + irq = platform_get_irq_byname(pdev, "bd96801-wdg"); 387 + if (irq > 0) { 388 + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, 389 + bd96801_irq_hnd, 390 + IRQF_ONESHOT, "bd96801-wdg", 391 + NULL); 392 + if (ret) 393 + return dev_err_probe(&pdev->dev, ret, 394 + "Failed to register IRQ\n"); 395 + } 396 + 397 + return devm_watchdog_register_device(&pdev->dev, &w->wdt); 398 + } 399 + 400 + static const struct platform_device_id bd96801_wdt_id[] = { 401 + { "bd96801-wdt", }, 402 + { } 403 + }; 404 + MODULE_DEVICE_TABLE(platform, bd96801_wdt_id); 405 + 406 + static struct platform_driver bd96801_wdt = { 407 + .driver = { 408 + .name = "bd96801-wdt" 409 + }, 410 + .probe = bd96801_wdt_probe, 411 + .id_table = bd96801_wdt_id, 412 + }; 413 + module_platform_driver(bd96801_wdt); 414 + 415 + MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); 416 + MODULE_DESCRIPTION("BD96801 watchdog driver"); 417 + MODULE_LICENSE("GPL");
-19
include/dt-bindings/mfd/qcom-pm8008.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0-only */ 2 - /* 3 - * Copyright (c) 2021 The Linux Foundation. All rights reserved. 4 - */ 5 - 6 - #ifndef __DT_BINDINGS_MFD_QCOM_PM8008_H 7 - #define __DT_BINDINGS_MFD_QCOM_PM8008_H 8 - 9 - /* PM8008 IRQ numbers */ 10 - #define PM8008_IRQ_MISC_UVLO 0 11 - #define PM8008_IRQ_MISC_OVLO 1 12 - #define PM8008_IRQ_MISC_OTST2 2 13 - #define PM8008_IRQ_MISC_OTST3 3 14 - #define PM8008_IRQ_MISC_LDO_OCP 4 15 - #define PM8008_IRQ_TEMP_ALARM 5 16 - #define PM8008_IRQ_GPIO1 6 17 - #define PM8008_IRQ_GPIO2 7 18 - 19 - #endif
+1 -1
include/dt-bindings/mfd/st,stpmic1.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0 */ 1 + /* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ 2 2 /* 3 3 * Copyright (C) STMicroelectronics 2018 - All Rights Reserved 4 4 * Author: Philippe Peurichard <philippe.peurichard@st.com>,
+27
include/linux/firmware/cirrus/cs_dsp.h
··· 42 42 #define CS_DSP_ACKED_CTL_MIN_VALUE 0 43 43 #define CS_DSP_ACKED_CTL_MAX_VALUE 0xFFFFFF 44 44 45 + /* 46 + * Write sequence operation codes 47 + */ 48 + #define CS_DSP_WSEQ_FULL 0x00 49 + #define CS_DSP_WSEQ_ADDR8 0x02 50 + #define CS_DSP_WSEQ_L16 0x04 51 + #define CS_DSP_WSEQ_H16 0x05 52 + #define CS_DSP_WSEQ_UNLOCK 0xFD 53 + #define CS_DSP_WSEQ_END 0xFF 54 + 45 55 /** 46 56 * struct cs_dsp_region - Describes a logical memory region in DSP address space 47 57 * @type: Memory region type ··· 267 257 int type, unsigned int id); 268 258 269 259 const char *cs_dsp_mem_region_name(unsigned int type); 260 + 261 + /** 262 + * struct cs_dsp_wseq - Describes a write sequence 263 + * @ctl: Write sequence cs_dsp control 264 + * @ops: Operations contained within 265 + */ 266 + struct cs_dsp_wseq { 267 + struct cs_dsp_coeff_ctl *ctl; 268 + struct list_head ops; 269 + }; 270 + 271 + int cs_dsp_wseq_init(struct cs_dsp *dsp, struct cs_dsp_wseq *wseqs, unsigned int num_wseqs); 272 + int cs_dsp_wseq_write(struct cs_dsp *dsp, struct cs_dsp_wseq *wseq, u32 addr, u32 data, 273 + u8 op_code, bool update); 274 + int cs_dsp_wseq_multi_write(struct cs_dsp *dsp, struct cs_dsp_wseq *wseq, 275 + const struct reg_sequence *reg_seq, int num_regs, 276 + u8 op_code, bool update); 270 277 271 278 /** 272 279 * struct cs_dsp_chunk - Describes a buffer holding data formatted for the DSP
+11
include/linux/leds.h
··· 107 107 #define LED_BRIGHT_HW_CHANGED BIT(21) 108 108 #define LED_RETAIN_AT_SHUTDOWN BIT(22) 109 109 #define LED_INIT_DEFAULT_TRIGGER BIT(23) 110 + #define LED_REJECT_NAME_CONFLICT BIT(24) 110 111 111 112 /* set_brightness_work / blink_timer flags, atomic, private. */ 112 113 unsigned long work_flags; ··· 427 426 */ 428 427 int led_compose_name(struct device *dev, struct led_init_data *init_data, 429 428 char *led_classdev_name); 429 + 430 + /** 431 + * led_get_color_name - get string representation of color ID 432 + * @color_id: The LED_COLOR_ID_* constant 433 + * 434 + * Get the string name of a LED_COLOR_ID_* constant. 435 + * 436 + * Returns: A string constant or NULL on an invalid ID. 437 + */ 438 + const char *led_get_color_name(u8 color_id); 430 439 431 440 /** 432 441 * led_sysfs_is_disabled - check if LED sysfs interface is disabled
+69
include/linux/mfd/88pm886.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + #ifndef __MFD_88PM886_H 3 + #define __MFD_88PM886_H 4 + 5 + #include <linux/i2c.h> 6 + #include <linux/regmap.h> 7 + 8 + #define PM886_A1_CHIP_ID 0xa1 9 + 10 + #define PM886_IRQ_ONKEY 0 11 + 12 + #define PM886_PAGE_OFFSET_REGULATORS 1 13 + 14 + #define PM886_REG_ID 0x00 15 + 16 + #define PM886_REG_STATUS1 0x01 17 + #define PM886_ONKEY_STS1 BIT(0) 18 + 19 + #define PM886_REG_INT_STATUS1 0x05 20 + 21 + #define PM886_REG_INT_ENA_1 0x0a 22 + #define PM886_INT_ENA1_ONKEY BIT(0) 23 + 24 + #define PM886_REG_MISC_CONFIG1 0x14 25 + #define PM886_SW_PDOWN BIT(5) 26 + 27 + #define PM886_REG_MISC_CONFIG2 0x15 28 + #define PM886_INT_INV BIT(0) 29 + #define PM886_INT_CLEAR BIT(1) 30 + #define PM886_INT_RC 0x00 31 + #define PM886_INT_WC BIT(1) 32 + #define PM886_INT_MASK_MODE BIT(2) 33 + 34 + #define PM886_REG_RTC_SPARE6 0xef 35 + 36 + #define PM886_REG_BUCK_EN 0x08 37 + #define PM886_REG_LDO_EN1 0x09 38 + #define PM886_REG_LDO_EN2 0x0a 39 + #define PM886_REG_LDO1_VOUT 0x20 40 + #define PM886_REG_LDO2_VOUT 0x26 41 + #define PM886_REG_LDO3_VOUT 0x2c 42 + #define PM886_REG_LDO4_VOUT 0x32 43 + #define PM886_REG_LDO5_VOUT 0x38 44 + #define PM886_REG_LDO6_VOUT 0x3e 45 + #define PM886_REG_LDO7_VOUT 0x44 46 + #define PM886_REG_LDO8_VOUT 0x4a 47 + #define PM886_REG_LDO9_VOUT 0x50 48 + #define PM886_REG_LDO10_VOUT 0x56 49 + #define PM886_REG_LDO11_VOUT 0x5c 50 + #define PM886_REG_LDO12_VOUT 0x62 51 + #define PM886_REG_LDO13_VOUT 0x68 52 + #define PM886_REG_LDO14_VOUT 0x6e 53 + #define PM886_REG_LDO15_VOUT 0x74 54 + #define PM886_REG_LDO16_VOUT 0x7a 55 + #define PM886_REG_BUCK1_VOUT 0xa5 56 + #define PM886_REG_BUCK2_VOUT 0xb3 57 + #define PM886_REG_BUCK3_VOUT 0xc1 58 + #define PM886_REG_BUCK4_VOUT 0xcf 59 + #define PM886_REG_BUCK5_VOUT 0xdd 60 + 61 + #define PM886_LDO_VSEL_MASK 0x0f 62 + #define PM886_BUCK_VSEL_MASK 0x7f 63 + 64 + struct pm886_chip { 65 + struct i2c_client *client; 66 + unsigned int chip_id; 67 + struct regmap *regmap; 68 + }; 69 + #endif /* __MFD_88PM886_H */
+137
include/linux/mfd/cs40l50.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 2 + * 3 + * CS40L50 Advanced Haptic Driver with waveform memory, 4 + * integrated DSP, and closed-loop algorithms 5 + * 6 + * Copyright 2024 Cirrus Logic, Inc. 7 + * 8 + * Author: James Ogletree <james.ogletree@cirrus.com> 9 + */ 10 + 11 + #ifndef __MFD_CS40L50_H__ 12 + #define __MFD_CS40L50_H__ 13 + 14 + #include <linux/firmware/cirrus/cs_dsp.h> 15 + #include <linux/gpio/consumer.h> 16 + #include <linux/pm.h> 17 + #include <linux/regmap.h> 18 + 19 + /* Power Supply Configuration */ 20 + #define CS40L50_BLOCK_ENABLES2 0x201C 21 + #define CS40L50_ERR_RLS 0x2034 22 + #define CS40L50_BST_LPMODE_SEL 0x3810 23 + #define CS40L50_DCM_LOW_POWER 0x1 24 + #define CS40L50_OVERTEMP_WARN 0x4000010 25 + 26 + /* Interrupts */ 27 + #define CS40L50_IRQ1_INT_1 0xE010 28 + #define CS40L50_IRQ1_BASE CS40L50_IRQ1_INT_1 29 + #define CS40L50_IRQ1_INT_2 0xE014 30 + #define CS40L50_IRQ1_INT_8 0xE02C 31 + #define CS40L50_IRQ1_INT_9 0xE030 32 + #define CS40L50_IRQ1_INT_10 0xE034 33 + #define CS40L50_IRQ1_INT_18 0xE054 34 + #define CS40L50_IRQ1_MASK_1 0xE090 35 + #define CS40L50_IRQ1_MASK_2 0xE094 36 + #define CS40L50_IRQ1_MASK_20 0xE0DC 37 + #define CS40L50_IRQ1_INT_1_OFFSET (CS40L50_IRQ1_INT_1 - CS40L50_IRQ1_BASE) 38 + #define CS40L50_IRQ1_INT_2_OFFSET (CS40L50_IRQ1_INT_2 - CS40L50_IRQ1_BASE) 39 + #define CS40L50_IRQ1_INT_8_OFFSET (CS40L50_IRQ1_INT_8 - CS40L50_IRQ1_BASE) 40 + #define CS40L50_IRQ1_INT_9_OFFSET (CS40L50_IRQ1_INT_9 - CS40L50_IRQ1_BASE) 41 + #define CS40L50_IRQ1_INT_10_OFFSET (CS40L50_IRQ1_INT_10 - CS40L50_IRQ1_BASE) 42 + #define CS40L50_IRQ1_INT_18_OFFSET (CS40L50_IRQ1_INT_18 - CS40L50_IRQ1_BASE) 43 + #define CS40L50_IRQ_MASK_2_OVERRIDE 0xFFDF7FFF 44 + #define CS40L50_IRQ_MASK_20_OVERRIDE 0x15C01000 45 + #define CS40L50_AMP_SHORT_MASK BIT(31) 46 + #define CS40L50_DSP_QUEUE_MASK BIT(21) 47 + #define CS40L50_TEMP_ERR_MASK BIT(31) 48 + #define CS40L50_BST_UVP_MASK BIT(6) 49 + #define CS40L50_BST_SHORT_MASK BIT(7) 50 + #define CS40L50_BST_ILIMIT_MASK BIT(18) 51 + #define CS40L50_UVLO_VDDBATT_MASK BIT(16) 52 + #define CS40L50_GLOBAL_ERROR_MASK BIT(15) 53 + 54 + enum cs40l50_irq_list { 55 + CS40L50_DSP_QUEUE_IRQ, 56 + CS40L50_GLOBAL_ERROR_IRQ, 57 + CS40L50_UVLO_VDDBATT_IRQ, 58 + CS40L50_BST_ILIMIT_IRQ, 59 + CS40L50_BST_SHORT_IRQ, 60 + CS40L50_BST_UVP_IRQ, 61 + CS40L50_TEMP_ERR_IRQ, 62 + CS40L50_AMP_SHORT_IRQ, 63 + }; 64 + 65 + /* DSP */ 66 + #define CS40L50_XMEM_PACKED_0 0x2000000 67 + #define CS40L50_XMEM_UNPACKED24_0 0x2800000 68 + #define CS40L50_SYS_INFO_ID 0x25E0000 69 + #define CS40L50_DSP_QUEUE_WT 0x28042C8 70 + #define CS40L50_DSP_QUEUE_RD 0x28042CC 71 + #define CS40L50_NUM_WAVES 0x2805C18 72 + #define CS40L50_CORE_BASE 0x2B80000 73 + #define CS40L50_YMEM_PACKED_0 0x2C00000 74 + #define CS40L50_YMEM_UNPACKED24_0 0x3400000 75 + #define CS40L50_PMEM_0 0x3800000 76 + #define CS40L50_DSP_POLL_US 1000 77 + #define CS40L50_DSP_TIMEOUT_COUNT 100 78 + #define CS40L50_RESET_PULSE_US 2200 79 + #define CS40L50_CP_READY_US 3100 80 + #define CS40L50_AUTOSUSPEND_MS 2000 81 + #define CS40L50_PM_ALGO 0x9F206 82 + #define CS40L50_GLOBAL_ERR_RLS_SET BIT(11) 83 + #define CS40L50_GLOBAL_ERR_RLS_CLEAR 0 84 + 85 + enum cs40l50_wseqs { 86 + CS40L50_PWR_ON, 87 + CS40L50_STANDBY, 88 + CS40L50_ACTIVE, 89 + CS40L50_NUM_WSEQS, 90 + }; 91 + 92 + /* DSP Queue */ 93 + #define CS40L50_DSP_QUEUE_BASE 0x11004 94 + #define CS40L50_DSP_QUEUE_END 0x1101C 95 + #define CS40L50_DSP_QUEUE 0x11020 96 + #define CS40L50_PREVENT_HIBER 0x2000003 97 + #define CS40L50_ALLOW_HIBER 0x2000004 98 + #define CS40L50_SHUTDOWN 0x2000005 99 + #define CS40L50_SYSTEM_RESET 0x2000007 100 + #define CS40L50_START_I2S 0x3000002 101 + #define CS40L50_OWT_PUSH 0x3000008 102 + #define CS40L50_STOP_PLAYBACK 0x5000000 103 + #define CS40L50_OWT_DELETE 0xD000000 104 + 105 + /* Firmware files */ 106 + #define CS40L50_FW "cs40l50.wmfw" 107 + #define CS40L50_WT "cs40l50.bin" 108 + 109 + /* Device */ 110 + #define CS40L50_DEVID 0x0 111 + #define CS40L50_REVID 0x4 112 + #define CS40L50_DEVID_A 0x40A50 113 + #define CS40L50_REVID_B0 0xB0 114 + 115 + struct cs40l50 { 116 + struct device *dev; 117 + struct regmap *regmap; 118 + struct mutex lock; 119 + struct cs_dsp dsp; 120 + struct gpio_desc *reset_gpio; 121 + struct regmap_irq_chip_data *irq_data; 122 + const struct firmware *fw; 123 + const struct firmware *bin; 124 + struct cs_dsp_wseq wseqs[CS40L50_NUM_WSEQS]; 125 + int irq; 126 + u32 devid; 127 + u32 revid; 128 + }; 129 + 130 + int cs40l50_dsp_write(struct device *dev, struct regmap *regmap, u32 val); 131 + int cs40l50_probe(struct cs40l50 *cs40l50); 132 + int cs40l50_remove(struct cs40l50 *cs40l50); 133 + 134 + extern const struct regmap_config cs40l50_regmap; 135 + extern const struct dev_pm_ops cs40l50_pm_ops; 136 + 137 + #endif /* __MFD_CS40L50_H__ */
+4 -4
include/linux/mfd/idt8a340_reg.h
··· 61 61 #define HW_Q8_CTRL_SPARE (0xa7d4) 62 62 #define HW_Q11_CTRL_SPARE (0xa7ec) 63 63 64 - /** 64 + /* 65 65 * Select FOD5 as sync_trigger for Q8 divider. 66 66 * Transition from logic zero to one 67 67 * sets trigger to sync Q8 divider. ··· 70 70 */ 71 71 #define Q9_TO_Q8_SYNC_TRIG BIT(1) 72 72 73 - /** 73 + /* 74 74 * Enable FOD5 as driver for clock and sync for Q8 divider. 75 75 * Enable fanout buffer for FOD5. 76 76 * ··· 78 78 */ 79 79 #define Q9_TO_Q8_FANOUT_AND_CLOCK_SYNC_ENABLE_MASK (BIT(0) | BIT(2)) 80 80 81 - /** 81 + /* 82 82 * Select FOD6 as sync_trigger for Q11 divider. 83 83 * Transition from logic zero to one 84 84 * sets trigger to sync Q11 divider. ··· 87 87 */ 88 88 #define Q10_TO_Q11_SYNC_TRIG BIT(1) 89 89 90 - /** 90 + /* 91 91 * Enable FOD6 as driver for clock and sync for Q11 divider. 92 92 * Enable fanout buffer for FOD6. 93 93 *
+2 -3
include/linux/mfd/lm3533.h
··· 16 16 DEVICE_ATTR(_name, S_IRUGO | S_IWUSR , show_##_name, store_##_name) 17 17 18 18 struct device; 19 + struct gpio_desc; 19 20 struct regmap; 20 21 21 22 struct lm3533 { ··· 24 23 25 24 struct regmap *regmap; 26 25 27 - int gpio_hwen; 26 + struct gpio_desc *hwen; 28 27 int irq; 29 28 30 29 unsigned have_als:1; ··· 70 69 }; 71 70 72 71 struct lm3533_platform_data { 73 - int gpio_hwen; 74 - 75 72 enum lm3533_boost_ovp boost_ovp; 76 73 enum lm3533_boost_freq boost_freq; 77 74
+215
include/linux/mfd/rohm-bd96801.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + /* Copyright (C) 2024 ROHM Semiconductors */ 3 + 4 + #ifndef __MFD_BD96801_H__ 5 + #define __MFD_BD96801_H__ 6 + 7 + #define BD96801_REG_SSCG_CTRL 0x09 8 + #define BD96801_REG_SHD_INTB 0x20 9 + #define BD96801_LDO5_VOL_LVL_REG 0x2c 10 + #define BD96801_LDO6_VOL_LVL_REG 0x2d 11 + #define BD96801_LDO7_VOL_LVL_REG 0x2e 12 + #define BD96801_REG_BUCK_OVP 0x30 13 + #define BD96801_REG_BUCK_OVD 0x35 14 + #define BD96801_REG_LDO_OVP 0x31 15 + #define BD96801_REG_LDO_OVD 0x36 16 + #define BD96801_REG_BOOT_OVERTIME 0x3a 17 + #define BD96801_REG_WD_TMO 0x40 18 + #define BD96801_REG_WD_CONF 0x41 19 + #define BD96801_REG_WD_FEED 0x42 20 + #define BD96801_REG_WD_FAILCOUNT 0x43 21 + #define BD96801_REG_WD_ASK 0x46 22 + #define BD96801_REG_WD_STATUS 0x4a 23 + #define BD96801_REG_PMIC_STATE 0x4f 24 + #define BD96801_REG_EXT_STATE 0x50 25 + 26 + #define BD96801_STATE_STBY 0x09 27 + 28 + #define BD96801_LOCK_REG 0x04 29 + #define BD96801_UNLOCK 0x9d 30 + #define BD96801_LOCK 0x00 31 + 32 + /* IRQ register area */ 33 + #define BD96801_REG_INT_MAIN 0x51 34 + 35 + /* 36 + * The BD96801 has two physical IRQ lines, INTB and ERRB. 37 + * 38 + * The 'main status register' is located at 0x51. 39 + * The ERRB status registers are located at 0x52 ... 0x5B 40 + * INTB status registers are at range 0x5c ... 0x63 41 + */ 42 + #define BD96801_REG_INT_SYS_ERRB1 0x52 43 + #define BD96801_REG_INT_SYS_INTB 0x5c 44 + #define BD96801_REG_INT_LDO7_INTB 0x63 45 + 46 + /* MASK registers */ 47 + #define BD96801_REG_MASK_SYS_INTB 0x73 48 + #define BD96801_REG_MASK_SYS_ERRB 0x69 49 + 50 + #define BD96801_MAX_REGISTER 0x7a 51 + 52 + #define BD96801_OTP_ERR_MASK BIT(0) 53 + #define BD96801_DBIST_ERR_MASK BIT(1) 54 + #define BD96801_EEP_ERR_MASK BIT(2) 55 + #define BD96801_ABIST_ERR_MASK BIT(3) 56 + #define BD96801_PRSTB_ERR_MASK BIT(4) 57 + #define BD96801_DRMOS1_ERR_MASK BIT(5) 58 + #define BD96801_DRMOS2_ERR_MASK BIT(6) 59 + #define BD96801_SLAVE_ERR_MASK BIT(7) 60 + #define BD96801_VREF_ERR_MASK BIT(0) 61 + #define BD96801_TSD_ERR_MASK BIT(1) 62 + #define BD96801_UVLO_ERR_MASK BIT(2) 63 + #define BD96801_OVLO_ERR_MASK BIT(3) 64 + #define BD96801_OSC_ERR_MASK BIT(4) 65 + #define BD96801_PON_ERR_MASK BIT(5) 66 + #define BD96801_POFF_ERR_MASK BIT(6) 67 + #define BD96801_CMD_SHDN_ERR_MASK BIT(7) 68 + #define BD96801_INT_PRSTB_WDT_ERR_MASK BIT(0) 69 + #define BD96801_INT_CHIP_IF_ERR_MASK BIT(3) 70 + #define BD96801_INT_SHDN_ERR_MASK BIT(7) 71 + #define BD96801_OUT_PVIN_ERR_MASK BIT(0) 72 + #define BD96801_OUT_OVP_ERR_MASK BIT(1) 73 + #define BD96801_OUT_UVP_ERR_MASK BIT(2) 74 + #define BD96801_OUT_SHDN_ERR_MASK BIT(7) 75 + 76 + /* ERRB IRQs */ 77 + enum { 78 + /* Reg 0x52, 0x53, 0x54 - ERRB system IRQs */ 79 + BD96801_OTP_ERR_STAT, 80 + BD96801_DBIST_ERR_STAT, 81 + BD96801_EEP_ERR_STAT, 82 + BD96801_ABIST_ERR_STAT, 83 + BD96801_PRSTB_ERR_STAT, 84 + BD96801_DRMOS1_ERR_STAT, 85 + BD96801_DRMOS2_ERR_STAT, 86 + BD96801_SLAVE_ERR_STAT, 87 + BD96801_VREF_ERR_STAT, 88 + BD96801_TSD_ERR_STAT, 89 + BD96801_UVLO_ERR_STAT, 90 + BD96801_OVLO_ERR_STAT, 91 + BD96801_OSC_ERR_STAT, 92 + BD96801_PON_ERR_STAT, 93 + BD96801_POFF_ERR_STAT, 94 + BD96801_CMD_SHDN_ERR_STAT, 95 + BD96801_INT_PRSTB_WDT_ERR, 96 + BD96801_INT_CHIP_IF_ERR, 97 + BD96801_INT_SHDN_ERR_STAT, 98 + 99 + /* Reg 0x55 BUCK1 ERR IRQs */ 100 + BD96801_BUCK1_PVIN_ERR_STAT, 101 + BD96801_BUCK1_OVP_ERR_STAT, 102 + BD96801_BUCK1_UVP_ERR_STAT, 103 + BD96801_BUCK1_SHDN_ERR_STAT, 104 + 105 + /* Reg 0x56 BUCK2 ERR IRQs */ 106 + BD96801_BUCK2_PVIN_ERR_STAT, 107 + BD96801_BUCK2_OVP_ERR_STAT, 108 + BD96801_BUCK2_UVP_ERR_STAT, 109 + BD96801_BUCK2_SHDN_ERR_STAT, 110 + 111 + /* Reg 0x57 BUCK3 ERR IRQs */ 112 + BD96801_BUCK3_PVIN_ERR_STAT, 113 + BD96801_BUCK3_OVP_ERR_STAT, 114 + BD96801_BUCK3_UVP_ERR_STAT, 115 + BD96801_BUCK3_SHDN_ERR_STAT, 116 + 117 + /* Reg 0x58 BUCK4 ERR IRQs */ 118 + BD96801_BUCK4_PVIN_ERR_STAT, 119 + BD96801_BUCK4_OVP_ERR_STAT, 120 + BD96801_BUCK4_UVP_ERR_STAT, 121 + BD96801_BUCK4_SHDN_ERR_STAT, 122 + 123 + /* Reg 0x59 LDO5 ERR IRQs */ 124 + BD96801_LDO5_PVIN_ERR_STAT, 125 + BD96801_LDO5_OVP_ERR_STAT, 126 + BD96801_LDO5_UVP_ERR_STAT, 127 + BD96801_LDO5_SHDN_ERR_STAT, 128 + 129 + /* Reg 0x5a LDO6 ERR IRQs */ 130 + BD96801_LDO6_PVIN_ERR_STAT, 131 + BD96801_LDO6_OVP_ERR_STAT, 132 + BD96801_LDO6_UVP_ERR_STAT, 133 + BD96801_LDO6_SHDN_ERR_STAT, 134 + 135 + /* Reg 0x5b LDO7 ERR IRQs */ 136 + BD96801_LDO7_PVIN_ERR_STAT, 137 + BD96801_LDO7_OVP_ERR_STAT, 138 + BD96801_LDO7_UVP_ERR_STAT, 139 + BD96801_LDO7_SHDN_ERR_STAT, 140 + }; 141 + 142 + /* INTB IRQs */ 143 + enum { 144 + /* Reg 0x5c (System INTB) */ 145 + BD96801_TW_STAT, 146 + BD96801_WDT_ERR_STAT, 147 + BD96801_I2C_ERR_STAT, 148 + BD96801_CHIP_IF_ERR_STAT, 149 + 150 + /* Reg 0x5d (BUCK1 INTB) */ 151 + BD96801_BUCK1_OCPH_STAT, 152 + BD96801_BUCK1_OCPL_STAT, 153 + BD96801_BUCK1_OCPN_STAT, 154 + BD96801_BUCK1_OVD_STAT, 155 + BD96801_BUCK1_UVD_STAT, 156 + BD96801_BUCK1_TW_CH_STAT, 157 + 158 + /* Reg 0x5e (BUCK2 INTB) */ 159 + BD96801_BUCK2_OCPH_STAT, 160 + BD96801_BUCK2_OCPL_STAT, 161 + BD96801_BUCK2_OCPN_STAT, 162 + BD96801_BUCK2_OVD_STAT, 163 + BD96801_BUCK2_UVD_STAT, 164 + BD96801_BUCK2_TW_CH_STAT, 165 + 166 + /* Reg 0x5f (BUCK3 INTB)*/ 167 + BD96801_BUCK3_OCPH_STAT, 168 + BD96801_BUCK3_OCPL_STAT, 169 + BD96801_BUCK3_OCPN_STAT, 170 + BD96801_BUCK3_OVD_STAT, 171 + BD96801_BUCK3_UVD_STAT, 172 + BD96801_BUCK3_TW_CH_STAT, 173 + 174 + /* Reg 0x60 (BUCK4 INTB)*/ 175 + BD96801_BUCK4_OCPH_STAT, 176 + BD96801_BUCK4_OCPL_STAT, 177 + BD96801_BUCK4_OCPN_STAT, 178 + BD96801_BUCK4_OVD_STAT, 179 + BD96801_BUCK4_UVD_STAT, 180 + BD96801_BUCK4_TW_CH_STAT, 181 + 182 + /* Reg 0x61 (LDO5 INTB) */ 183 + BD96801_LDO5_OCPH_STAT, /* bit [0] */ 184 + BD96801_LDO5_OVD_STAT, /* bit [3] */ 185 + BD96801_LDO5_UVD_STAT, /* bit [4] */ 186 + 187 + /* Reg 0x62 (LDO6 INTB) */ 188 + BD96801_LDO6_OCPH_STAT, /* bit [0] */ 189 + BD96801_LDO6_OVD_STAT, /* bit [3] */ 190 + BD96801_LDO6_UVD_STAT, /* bit [4] */ 191 + 192 + /* Reg 0x63 (LDO7 INTB) */ 193 + BD96801_LDO7_OCPH_STAT, /* bit [0] */ 194 + BD96801_LDO7_OVD_STAT, /* bit [3] */ 195 + BD96801_LDO7_UVD_STAT, /* bit [4] */ 196 + }; 197 + 198 + /* IRQ MASKs */ 199 + #define BD96801_TW_STAT_MASK BIT(0) 200 + #define BD96801_WDT_ERR_STAT_MASK BIT(1) 201 + #define BD96801_I2C_ERR_STAT_MASK BIT(2) 202 + #define BD96801_CHIP_IF_ERR_STAT_MASK BIT(3) 203 + 204 + #define BD96801_BUCK_OCPH_STAT_MASK BIT(0) 205 + #define BD96801_BUCK_OCPL_STAT_MASK BIT(1) 206 + #define BD96801_BUCK_OCPN_STAT_MASK BIT(2) 207 + #define BD96801_BUCK_OVD_STAT_MASK BIT(3) 208 + #define BD96801_BUCK_UVD_STAT_MASK BIT(4) 209 + #define BD96801_BUCK_TW_CH_STAT_MASK BIT(5) 210 + 211 + #define BD96801_LDO_OCPH_STAT_MASK BIT(0) 212 + #define BD96801_LDO_OVD_STAT_MASK BIT(3) 213 + #define BD96801_LDO_UVD_STAT_MASK BIT(4) 214 + 215 + #endif
+1
include/linux/mfd/rohm-generic.h
··· 16 16 ROHM_CHIP_TYPE_BD71828, 17 17 ROHM_CHIP_TYPE_BD71837, 18 18 ROHM_CHIP_TYPE_BD71847, 19 + ROHM_CHIP_TYPE_BD96801, 19 20 ROHM_CHIP_TYPE_AMOUNT 20 21 }; 21 22
+8
include/linux/mfd/syscon.h
··· 28 28 unsigned int *out_args); 29 29 struct regmap *syscon_regmap_lookup_by_phandle_optional(struct device_node *np, 30 30 const char *property); 31 + int of_syscon_register_regmap(struct device_node *np, 32 + struct regmap *regmap); 31 33 #else 32 34 static inline struct regmap *device_node_to_regmap(struct device_node *np) 33 35 { ··· 67 65 const char *property) 68 66 { 69 67 return NULL; 68 + } 69 + 70 + static inline int of_syscon_register_regmap(struct device_node *np, 71 + struct regmap *regmap) 72 + { 73 + return -EOPNOTSUPP; 70 74 } 71 75 72 76 #endif
-131
include/linux/mfd/tmio.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0 */ 2 - #ifndef MFD_TMIO_H 3 - #define MFD_TMIO_H 4 - 5 - #include <linux/device.h> 6 - #include <linux/fb.h> 7 - #include <linux/io.h> 8 - #include <linux/jiffies.h> 9 - #include <linux/mmc/card.h> 10 - #include <linux/platform_device.h> 11 - #include <linux/pm_runtime.h> 12 - 13 - #define tmio_ioread8(addr) readb(addr) 14 - #define tmio_ioread16(addr) readw(addr) 15 - #define tmio_ioread16_rep(r, b, l) readsw(r, b, l) 16 - #define tmio_ioread32(addr) \ 17 - (((u32)readw((addr))) | (((u32)readw((addr) + 2)) << 16)) 18 - 19 - #define tmio_iowrite8(val, addr) writeb((val), (addr)) 20 - #define tmio_iowrite16(val, addr) writew((val), (addr)) 21 - #define tmio_iowrite16_rep(r, b, l) writesw(r, b, l) 22 - #define tmio_iowrite32(val, addr) \ 23 - do { \ 24 - writew((val), (addr)); \ 25 - writew((val) >> 16, (addr) + 2); \ 26 - } while (0) 27 - 28 - #define sd_config_write8(base, shift, reg, val) \ 29 - tmio_iowrite8((val), (base) + ((reg) << (shift))) 30 - #define sd_config_write16(base, shift, reg, val) \ 31 - tmio_iowrite16((val), (base) + ((reg) << (shift))) 32 - #define sd_config_write32(base, shift, reg, val) \ 33 - do { \ 34 - tmio_iowrite16((val), (base) + ((reg) << (shift))); \ 35 - tmio_iowrite16((val) >> 16, (base) + ((reg + 2) << (shift))); \ 36 - } while (0) 37 - 38 - /* tmio MMC platform flags */ 39 - /* 40 - * Some controllers can support a 2-byte block size when the bus width 41 - * is configured in 4-bit mode. 42 - */ 43 - #define TMIO_MMC_BLKSZ_2BYTES BIT(1) 44 - /* 45 - * Some controllers can support SDIO IRQ signalling. 46 - */ 47 - #define TMIO_MMC_SDIO_IRQ BIT(2) 48 - 49 - /* Some features are only available or tested on R-Car Gen2 or later */ 50 - #define TMIO_MMC_MIN_RCAR2 BIT(3) 51 - 52 - /* 53 - * Some controllers require waiting for the SD bus to become 54 - * idle before writing to some registers. 55 - */ 56 - #define TMIO_MMC_HAS_IDLE_WAIT BIT(4) 57 - 58 - /* 59 - * Use the busy timeout feature. Probably all TMIO versions support it. Yet, 60 - * we don't have documentation for old variants, so we enable only known good 61 - * variants with this flag. Can be removed once all variants are known good. 62 - */ 63 - #define TMIO_MMC_USE_BUSY_TIMEOUT BIT(5) 64 - 65 - /* 66 - * Some controllers have CMD12 automatically 67 - * issue/non-issue register 68 - */ 69 - #define TMIO_MMC_HAVE_CMD12_CTRL BIT(7) 70 - 71 - /* Controller has some SDIO status bits which must be 1 */ 72 - #define TMIO_MMC_SDIO_STATUS_SETBITS BIT(8) 73 - 74 - /* 75 - * Some controllers have a 32-bit wide data port register 76 - */ 77 - #define TMIO_MMC_32BIT_DATA_PORT BIT(9) 78 - 79 - /* 80 - * Some controllers allows to set SDx actual clock 81 - */ 82 - #define TMIO_MMC_CLK_ACTUAL BIT(10) 83 - 84 - /* Some controllers have a CBSY bit */ 85 - #define TMIO_MMC_HAVE_CBSY BIT(11) 86 - 87 - struct dma_chan; 88 - 89 - /* 90 - * data for the MMC controller 91 - */ 92 - struct tmio_mmc_data { 93 - void *chan_priv_tx; 94 - void *chan_priv_rx; 95 - unsigned int hclk; 96 - unsigned long capabilities; 97 - unsigned long capabilities2; 98 - unsigned long flags; 99 - u32 ocr_mask; /* available voltages */ 100 - dma_addr_t dma_rx_offset; 101 - unsigned int max_blk_count; 102 - unsigned short max_segs; 103 - }; 104 - 105 - /* 106 - * data for the NAND controller 107 - */ 108 - struct tmio_nand_data { 109 - struct nand_bbt_descr *badblock_pattern; 110 - struct mtd_partition *partition; 111 - unsigned int num_partitions; 112 - const char *const *part_parsers; 113 - }; 114 - 115 - #define FBIO_TMIO_ACC_WRITE 0x7C639300 116 - #define FBIO_TMIO_ACC_SYNC 0x7C639301 117 - 118 - struct tmio_fb_data { 119 - int (*lcd_set_power)(struct platform_device *fb_dev, 120 - bool on); 121 - int (*lcd_mode)(struct platform_device *fb_dev, 122 - const struct fb_videomode *mode); 123 - int num_modes; 124 - struct fb_videomode *modes; 125 - 126 - /* in mm: size of screen */ 127 - int height; 128 - int width; 129 - }; 130 - 131 - #endif
-1
include/linux/mfd/tps65912.h
··· 314 314 extern const struct regmap_config tps65912_regmap_config; 315 315 316 316 int tps65912_device_init(struct tps65912 *tps); 317 - void tps65912_device_exit(struct tps65912 *tps); 318 317 319 318 #endif /* __LINUX_MFD_TPS65912_H */
+62
include/linux/platform_data/tmio.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef MFD_TMIO_H 3 + #define MFD_TMIO_H 4 + 5 + #include <linux/platform_device.h> 6 + #include <linux/types.h> 7 + 8 + /* TMIO MMC platform flags */ 9 + 10 + /* 11 + * Some controllers can support a 2-byte block size when the bus width is 12 + * configured in 4-bit mode. 13 + */ 14 + #define TMIO_MMC_BLKSZ_2BYTES BIT(1) 15 + 16 + /* Some controllers can support SDIO IRQ signalling */ 17 + #define TMIO_MMC_SDIO_IRQ BIT(2) 18 + 19 + /* Some features are only available or tested on R-Car Gen2 or later */ 20 + #define TMIO_MMC_MIN_RCAR2 BIT(3) 21 + 22 + /* 23 + * Some controllers require waiting for the SD bus to become idle before 24 + * writing to some registers. 25 + */ 26 + #define TMIO_MMC_HAS_IDLE_WAIT BIT(4) 27 + 28 + /* 29 + * Use the busy timeout feature. Probably all TMIO versions support it. Yet, 30 + * we don't have documentation for old variants, so we enable only known good 31 + * variants with this flag. Can be removed once all variants are known good. 32 + */ 33 + #define TMIO_MMC_USE_BUSY_TIMEOUT BIT(5) 34 + 35 + /* Some controllers have CMD12 automatically issue/non-issue register */ 36 + #define TMIO_MMC_HAVE_CMD12_CTRL BIT(7) 37 + 38 + /* Controller has some SDIO status bits which must be 1 */ 39 + #define TMIO_MMC_SDIO_STATUS_SETBITS BIT(8) 40 + 41 + /* Some controllers have a 32-bit wide data port register */ 42 + #define TMIO_MMC_32BIT_DATA_PORT BIT(9) 43 + 44 + /* Some controllers allows to set SDx actual clock */ 45 + #define TMIO_MMC_CLK_ACTUAL BIT(10) 46 + 47 + /* Some controllers have a CBSY bit */ 48 + #define TMIO_MMC_HAVE_CBSY BIT(11) 49 + 50 + struct tmio_mmc_data { 51 + void *chan_priv_tx; 52 + void *chan_priv_rx; 53 + unsigned int hclk; 54 + unsigned long capabilities; 55 + unsigned long capabilities2; 56 + unsigned long flags; 57 + u32 ocr_mask; /* available voltages */ 58 + dma_addr_t dma_rx_offset; 59 + unsigned int max_blk_count; 60 + unsigned short max_segs; 61 + }; 62 + #endif
+11
sound/soc/codecs/Kconfig
··· 75 75 imply SND_SOC_CS35L56_I2C 76 76 imply SND_SOC_CS35L56_SPI 77 77 imply SND_SOC_CS35L56_SDW 78 + imply SND_SOC_CS40L50 78 79 imply SND_SOC_CS42L42 79 80 imply SND_SOC_CS42L42_SDW 80 81 imply SND_SOC_CS42L43 ··· 847 846 select SND_SOC_CS35L56_SHARED 848 847 help 849 848 Enable support for Cirrus Logic CS35L56 boosted amplifier with SoundWire control 849 + 850 + config SND_SOC_CS40L50 851 + tristate "Cirrus Logic CS40L50 CODEC" 852 + depends on MFD_CS40L50_CORE 853 + help 854 + This option enables support for I2S streaming to Cirrus Logic CS40L50. 855 + 856 + CS40L50 is a haptic driver with waveform memory, an integrated 857 + DSP, and closed-loop algorithms. If built as a module, it will be 858 + called snd-soc-cs40l50. 850 859 851 860 config SND_SOC_CS42L42_CORE 852 861 tristate
+2
sound/soc/codecs/Makefile
··· 78 78 snd-soc-cs35l56-i2c-y := cs35l56-i2c.o 79 79 snd-soc-cs35l56-spi-y := cs35l56-spi.o 80 80 snd-soc-cs35l56-sdw-y := cs35l56-sdw.o 81 + snd-soc-cs40l50-objs := cs40l50-codec.o 81 82 snd-soc-cs42l42-y := cs42l42.o 82 83 snd-soc-cs42l42-i2c-y := cs42l42-i2c.o 83 84 snd-soc-cs42l42-sdw-y := cs42l42-sdw.o ··· 476 475 obj-$(CONFIG_SND_SOC_CS35L56_I2C) += snd-soc-cs35l56-i2c.o 477 476 obj-$(CONFIG_SND_SOC_CS35L56_SPI) += snd-soc-cs35l56-spi.o 478 477 obj-$(CONFIG_SND_SOC_CS35L56_SDW) += snd-soc-cs35l56-sdw.o 478 + obj-$(CONFIG_SND_SOC_CS40L50) += snd-soc-cs40l50.o 479 479 obj-$(CONFIG_SND_SOC_CS42L42_CORE) += snd-soc-cs42l42.o 480 480 obj-$(CONFIG_SND_SOC_CS42L42) += snd-soc-cs42l42-i2c.o 481 481 obj-$(CONFIG_SND_SOC_CS42L42_SDW) += snd-soc-cs42l42-sdw.o
+307
sound/soc/codecs/cs40l50-codec.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // 3 + // CS40L50 Advanced Haptic Driver with waveform memory, 4 + // integrated DSP, and closed-loop algorithms 5 + // 6 + // Copyright 2024 Cirrus Logic, Inc. 7 + // 8 + // Author: James Ogletree <james.ogletree@cirrus.com> 9 + 10 + #include <linux/bitfield.h> 11 + #include <linux/mfd/cs40l50.h> 12 + #include <sound/pcm_params.h> 13 + #include <sound/soc.h> 14 + 15 + #define CS40L50_REFCLK_INPUT 0x2C04 16 + #define CS40L50_ASP_CONTROL2 0x4808 17 + #define CS40L50_ASP_DATA_CONTROL5 0x4840 18 + 19 + /* PLL Config */ 20 + #define CS40L50_PLL_REFCLK_BCLK 0x0 21 + #define CS40L50_PLL_REFCLK_MCLK 0x5 22 + #define CS40L50_PLL_REEFCLK_MCLK_CFG 0x00 23 + #define CS40L50_PLL_REFCLK_LOOP_MASK BIT(11) 24 + #define CS40L50_PLL_REFCLK_OPEN_LOOP 1 25 + #define CS40L50_PLL_REFCLK_CLOSED_LOOP 0 26 + #define CS40L50_PLL_REFCLK_LOOP_SHIFT 11 27 + #define CS40L50_PLL_REFCLK_FREQ_MASK GENMASK(10, 5) 28 + #define CS40L50_PLL_REFCLK_FREQ_SHIFT 5 29 + #define CS40L50_PLL_REFCLK_SEL_MASK GENMASK(2, 0) 30 + #define CS40L50_BCLK_RATIO_DEFAULT 32 31 + 32 + /* ASP Config */ 33 + #define CS40L50_ASP_RX_WIDTH_SHIFT 24 34 + #define CS40L50_ASP_RX_WIDTH_MASK GENMASK(31, 24) 35 + #define CS40L50_ASP_RX_WL_MASK GENMASK(5, 0) 36 + #define CS40L50_ASP_FSYNC_INV_MASK BIT(2) 37 + #define CS40L50_ASP_BCLK_INV_MASK BIT(6) 38 + #define CS40L50_ASP_FMT_MASK GENMASK(10, 8) 39 + #define CS40L50_ASP_FMT_I2S 0x2 40 + 41 + struct cs40l50_pll_config { 42 + unsigned int freq; 43 + unsigned int cfg; 44 + }; 45 + 46 + struct cs40l50_codec { 47 + struct device *dev; 48 + struct regmap *regmap; 49 + unsigned int daifmt; 50 + unsigned int bclk_ratio; 51 + unsigned int rate; 52 + }; 53 + 54 + static const struct cs40l50_pll_config cs40l50_pll_cfg[] = { 55 + { 32768, 0x00 }, 56 + { 1536000, 0x1B }, 57 + { 3072000, 0x21 }, 58 + { 6144000, 0x28 }, 59 + { 9600000, 0x30 }, 60 + { 12288000, 0x33 }, 61 + }; 62 + 63 + static int cs40l50_get_clk_config(const unsigned int freq, unsigned int *cfg) 64 + { 65 + int i; 66 + 67 + for (i = 0; i < ARRAY_SIZE(cs40l50_pll_cfg); i++) { 68 + if (cs40l50_pll_cfg[i].freq == freq) { 69 + *cfg = cs40l50_pll_cfg[i].cfg; 70 + return 0; 71 + } 72 + } 73 + 74 + return -EINVAL; 75 + } 76 + 77 + static int cs40l50_swap_ext_clk(struct cs40l50_codec *codec, const unsigned int clk_src) 78 + { 79 + unsigned int cfg; 80 + int ret; 81 + 82 + switch (clk_src) { 83 + case CS40L50_PLL_REFCLK_BCLK: 84 + ret = cs40l50_get_clk_config(codec->bclk_ratio * codec->rate, &cfg); 85 + if (ret) 86 + return ret; 87 + break; 88 + case CS40L50_PLL_REFCLK_MCLK: 89 + cfg = CS40L50_PLL_REEFCLK_MCLK_CFG; 90 + break; 91 + default: 92 + return -EINVAL; 93 + } 94 + 95 + ret = regmap_update_bits(codec->regmap, CS40L50_REFCLK_INPUT, 96 + CS40L50_PLL_REFCLK_LOOP_MASK, 97 + CS40L50_PLL_REFCLK_OPEN_LOOP << 98 + CS40L50_PLL_REFCLK_LOOP_SHIFT); 99 + if (ret) 100 + return ret; 101 + 102 + ret = regmap_update_bits(codec->regmap, CS40L50_REFCLK_INPUT, 103 + CS40L50_PLL_REFCLK_FREQ_MASK | 104 + CS40L50_PLL_REFCLK_SEL_MASK, 105 + (cfg << CS40L50_PLL_REFCLK_FREQ_SHIFT) | clk_src); 106 + if (ret) 107 + return ret; 108 + 109 + return regmap_update_bits(codec->regmap, CS40L50_REFCLK_INPUT, 110 + CS40L50_PLL_REFCLK_LOOP_MASK, 111 + CS40L50_PLL_REFCLK_CLOSED_LOOP << 112 + CS40L50_PLL_REFCLK_LOOP_SHIFT); 113 + } 114 + 115 + static int cs40l50_clk_en(struct snd_soc_dapm_widget *w, 116 + struct snd_kcontrol *kcontrol, 117 + int event) 118 + { 119 + struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); 120 + struct cs40l50_codec *codec = snd_soc_component_get_drvdata(comp); 121 + int ret; 122 + 123 + switch (event) { 124 + case SND_SOC_DAPM_POST_PMU: 125 + ret = cs40l50_dsp_write(codec->dev, codec->regmap, CS40L50_STOP_PLAYBACK); 126 + if (ret) 127 + return ret; 128 + 129 + ret = cs40l50_dsp_write(codec->dev, codec->regmap, CS40L50_START_I2S); 130 + if (ret) 131 + return ret; 132 + 133 + ret = cs40l50_swap_ext_clk(codec, CS40L50_PLL_REFCLK_BCLK); 134 + if (ret) 135 + return ret; 136 + break; 137 + case SND_SOC_DAPM_PRE_PMD: 138 + ret = cs40l50_swap_ext_clk(codec, CS40L50_PLL_REFCLK_MCLK); 139 + if (ret) 140 + return ret; 141 + break; 142 + default: 143 + return -EINVAL; 144 + } 145 + 146 + return 0; 147 + } 148 + 149 + static const struct snd_soc_dapm_widget cs40l50_dapm_widgets[] = { 150 + SND_SOC_DAPM_SUPPLY_S("ASP PLL", 0, SND_SOC_NOPM, 0, 0, cs40l50_clk_en, 151 + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 152 + SND_SOC_DAPM_AIF_IN("ASPRX1", NULL, 0, SND_SOC_NOPM, 0, 0), 153 + SND_SOC_DAPM_AIF_IN("ASPRX2", NULL, 0, SND_SOC_NOPM, 0, 0), 154 + SND_SOC_DAPM_OUTPUT("OUT"), 155 + }; 156 + 157 + static const struct snd_soc_dapm_route cs40l50_dapm_routes[] = { 158 + { "ASP Playback", NULL, "ASP PLL" }, 159 + { "ASPRX1", NULL, "ASP Playback" }, 160 + { "ASPRX2", NULL, "ASP Playback" }, 161 + 162 + { "OUT", NULL, "ASPRX1" }, 163 + { "OUT", NULL, "ASPRX2" }, 164 + }; 165 + 166 + static int cs40l50_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) 167 + { 168 + struct cs40l50_codec *codec = snd_soc_component_get_drvdata(codec_dai->component); 169 + 170 + if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBC_CFC) 171 + return -EINVAL; 172 + 173 + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 174 + case SND_SOC_DAIFMT_NB_NF: 175 + codec->daifmt = 0; 176 + break; 177 + case SND_SOC_DAIFMT_NB_IF: 178 + codec->daifmt = CS40L50_ASP_FSYNC_INV_MASK; 179 + break; 180 + case SND_SOC_DAIFMT_IB_NF: 181 + codec->daifmt = CS40L50_ASP_BCLK_INV_MASK; 182 + break; 183 + case SND_SOC_DAIFMT_IB_IF: 184 + codec->daifmt = CS40L50_ASP_FSYNC_INV_MASK | CS40L50_ASP_BCLK_INV_MASK; 185 + break; 186 + default: 187 + dev_err(codec->dev, "Invalid clock invert\n"); 188 + return -EINVAL; 189 + } 190 + 191 + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 192 + case SND_SOC_DAIFMT_I2S: 193 + codec->daifmt |= FIELD_PREP(CS40L50_ASP_FMT_MASK, CS40L50_ASP_FMT_I2S); 194 + break; 195 + default: 196 + dev_err(codec->dev, "Unsupported DAI format\n"); 197 + return -EINVAL; 198 + } 199 + 200 + return 0; 201 + } 202 + 203 + static int cs40l50_hw_params(struct snd_pcm_substream *substream, 204 + struct snd_pcm_hw_params *params, 205 + struct snd_soc_dai *dai) 206 + { 207 + struct cs40l50_codec *codec = snd_soc_component_get_drvdata(dai->component); 208 + unsigned int asp_rx_wl = params_width(params); 209 + int ret; 210 + 211 + codec->rate = params_rate(params); 212 + 213 + ret = regmap_update_bits(codec->regmap, CS40L50_ASP_DATA_CONTROL5, 214 + CS40L50_ASP_RX_WL_MASK, asp_rx_wl); 215 + if (ret) 216 + return ret; 217 + 218 + codec->daifmt |= (asp_rx_wl << CS40L50_ASP_RX_WIDTH_SHIFT); 219 + 220 + return regmap_update_bits(codec->regmap, CS40L50_ASP_CONTROL2, 221 + CS40L50_ASP_FSYNC_INV_MASK | 222 + CS40L50_ASP_BCLK_INV_MASK | 223 + CS40L50_ASP_FMT_MASK | 224 + CS40L50_ASP_RX_WIDTH_MASK, codec->daifmt); 225 + } 226 + 227 + static int cs40l50_set_dai_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) 228 + { 229 + struct cs40l50_codec *codec = snd_soc_component_get_drvdata(dai->component); 230 + 231 + codec->bclk_ratio = ratio; 232 + 233 + return 0; 234 + } 235 + 236 + static const struct snd_soc_dai_ops cs40l50_dai_ops = { 237 + .set_fmt = cs40l50_set_dai_fmt, 238 + .set_bclk_ratio = cs40l50_set_dai_bclk_ratio, 239 + .hw_params = cs40l50_hw_params, 240 + }; 241 + 242 + static struct snd_soc_dai_driver cs40l50_dai[] = { 243 + { 244 + .name = "cs40l50-pcm", 245 + .id = 0, 246 + .playback = { 247 + .stream_name = "ASP Playback", 248 + .channels_min = 1, 249 + .channels_max = 2, 250 + .rates = SNDRV_PCM_RATE_48000, 251 + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, 252 + }, 253 + .ops = &cs40l50_dai_ops, 254 + }, 255 + }; 256 + 257 + static int cs40l50_codec_probe(struct snd_soc_component *component) 258 + { 259 + struct cs40l50_codec *codec = snd_soc_component_get_drvdata(component); 260 + 261 + codec->bclk_ratio = CS40L50_BCLK_RATIO_DEFAULT; 262 + 263 + return 0; 264 + } 265 + 266 + static const struct snd_soc_component_driver soc_codec_dev_cs40l50 = { 267 + .probe = cs40l50_codec_probe, 268 + .dapm_widgets = cs40l50_dapm_widgets, 269 + .num_dapm_widgets = ARRAY_SIZE(cs40l50_dapm_widgets), 270 + .dapm_routes = cs40l50_dapm_routes, 271 + .num_dapm_routes = ARRAY_SIZE(cs40l50_dapm_routes), 272 + }; 273 + 274 + static int cs40l50_codec_driver_probe(struct platform_device *pdev) 275 + { 276 + struct cs40l50 *cs40l50 = dev_get_drvdata(pdev->dev.parent); 277 + struct cs40l50_codec *codec; 278 + 279 + codec = devm_kzalloc(&pdev->dev, sizeof(*codec), GFP_KERNEL); 280 + if (!codec) 281 + return -ENOMEM; 282 + 283 + codec->regmap = cs40l50->regmap; 284 + codec->dev = &pdev->dev; 285 + 286 + return devm_snd_soc_register_component(&pdev->dev, &soc_codec_dev_cs40l50, 287 + cs40l50_dai, ARRAY_SIZE(cs40l50_dai)); 288 + } 289 + 290 + static const struct platform_device_id cs40l50_id[] = { 291 + { "cs40l50-codec", }, 292 + {} 293 + }; 294 + MODULE_DEVICE_TABLE(platform, cs40l50_id); 295 + 296 + static struct platform_driver cs40l50_codec_driver = { 297 + .probe = cs40l50_codec_driver_probe, 298 + .id_table = cs40l50_id, 299 + .driver = { 300 + .name = "cs40l50-codec", 301 + }, 302 + }; 303 + module_platform_driver(cs40l50_codec_driver); 304 + 305 + MODULE_DESCRIPTION("ASoC CS40L50 driver"); 306 + MODULE_AUTHOR("James Ogletree <james.ogletree@cirrus.com>"); 307 + MODULE_LICENSE("GPL");