History

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

Pull mfd updates from Lee Jones: - Fix race in device_node_get_regmap() using more extensive locking - Remove unused platform driver support for syscon - Allow syscon nodes to be registered without a "syscon" compatible string - Make `platform_data` pointer const in struct mfd_cell - Revert support for multiple AXP PMICs to avoid regressions - Increase SoundWire attach timeout and use gpiod_set_raw() for GPIO operation - Store the result from fault_log() for use by other sub-components - Fix an invalid regmap-config max_register value - Add another Gemini Lake ISA bridge PCI device ID - Use devm_register_power_off_handler() to simplify code - Add support for QNAP microcontroller units, including LEDs, input, and hwmon - Use MFD_CELL macros and remove unused code - Add support for AAEON UP board FPGA - Remove unused includes - Fix various typos and compatibility issues in multiple bindings - Add new bindings for rk3562 QoS, LED1202, and qcom,tcsr-ipq5424 - Convert several bindings to YAML schema - Update sprd,sc2731 bindings to reference sprd,sc2731-efuse bindings directly - Fix rohm,bd71815 bindings by correcting resistor values and typos - Documentation improvements: - Add documentation for LED1202 and qnap-mcu-hwmon - Adjust the file entry for the qnap-mcu header in MAINTAINERS * tag 'mfd-next-6.14' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (35 commits) MAINTAINERS: Adjust the file entry for the qnap-mcu header dt-bindings: mfd: syscon: Fix ti,j784s4-acspcie-proxy-ctrl compatible dt-bindings: mfd: syscon: Fix al,alpine-sysfabric-service compatible Revert "mfd: axp20x: Allow multiple regulators" dt-bindings: mfd: syscon: Add rk3562 QoS register compatible mfd: syscon: Allow syscon nodes without a "syscon" compatible mfd: syscon: Remove the platform driver support mfd: syscon: Fix race in device_node_get_regmap() dt-bindings: mfd: atmel: Convert to YAML schema dt-bindings: mfd: atmel,at91sam9260: Convert to YAML schema dt-bindings: mfd: sprd,sc2731: Reference sprd,sc2731-efuse bindings mfd: tps65219: Remove unused macros & add regmap.h mfd: tps65219: Use MFD_CELL macros leds: Add LED1202 I2C driver dt-bindings: leds: Add LED1202 LED Controller Documentation:leds: Add leds-st1202.rst mfd: Add support for AAEON UP board FPGA mfd: da9052: Store result from fault_log mfd: intel_soc_pmic_chtdc_ti: Fix invalid regmap-config max_register value mfd: cs42l43: Use devres for remove as well ...

Linus Torvalds committed 1 year ago

Commit 909fd2b2 parents 38f5265 2816b0c49 files · +2407 −254Browse files

Unified · Split

49 files
  1. Documentation/devicetree/bindings/leds/st,led1202.yaml +132 −0
  2. Documentation/devicetree/bindings/mfd/atmel,at91sam9260-gpbr.yaml +44 −0
  3. Documentation/devicetree/bindings/mfd/atmel,at91sam9260-matrix.yaml +52 −0
  4. Documentation/devicetree/bindings/mfd/atmel-gpbr.txt +0 −18
  5. Documentation/devicetree/bindings/mfd/atmel-matrix.txt +0 −26
  6. Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml +1 −0
  7. Documentation/devicetree/bindings/mfd/qnap,ts433-mcu.yaml +42 −0
  8. Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml +10 −10
  9. Documentation/devicetree/bindings/mfd/sprd,sc2731.yaml +2 −10
  10. Documentation/devicetree/bindings/mfd/syscon.yaml +4 −1
  11. Documentation/devicetree/bindings/nvmem/sprd,sc2731-efuse.yaml +0 −29
  12. Documentation/hwmon/index.rst +1 −0
  13. Documentation/hwmon/qnap-mcu-hwmon.rst +27 −0
  14. Documentation/leds/index.rst +1 −0
  15. Documentation/leds/leds-st1202.rst +34 −0
  16. MAINTAINERS +9 −0
  17. drivers/hid/hid-sensor-hub.c +14 −7
  18. drivers/hwmon/Kconfig +12 −0
  19. drivers/hwmon/Makefile +1 −0
  20. drivers/hwmon/qnap-mcu-hwmon.c +364 −0
  21. drivers/input/misc/Kconfig +12 −0
  22. drivers/input/misc/Makefile +1 −0
  23. drivers/input/misc/qnap-mcu-input.c +153 −0
  24. drivers/leds/Kconfig +21 −0
  25. drivers/leds/Makefile +1 −0
  26. drivers/leds/leds-qnap-mcu.c +227 −0
  27. drivers/leds/leds-st1202.c +416 −0
  28. drivers/mfd/Kconfig +25 −0
  29. drivers/mfd/Makefile +4 −0
  30. drivers/mfd/axp20x.c +2 −5
  31. drivers/mfd/cs42l43-i2c.c +0 −8
  32. drivers/mfd/cs42l43-sdw.c +0 −10
  33. drivers/mfd/cs42l43.c +23 −14
  34. drivers/mfd/cs42l43.h +0 −1
  35. drivers/mfd/da9052-core.c +1 −0
  36. drivers/mfd/intel_soc_pmic_chtdc_ti.c +1 −1
  37. drivers/mfd/lpc_ich.c +2 −1
  38. drivers/mfd/qnap-mcu.c +338 −0
  39. drivers/mfd/stpmic1.c +1 −5
  40. drivers/mfd/syscon.c +15 −80
  41. drivers/mfd/tps65219.c +4 −11
  42. drivers/mfd/upboard-fpga.c +325 −0
  43. drivers/mfd/vexpress-sysreg.c +0 −1
  44. include/linux/mfd/core.h +1 −1
  45. include/linux/mfd/da9052/da9052.h +2 −0
  46. include/linux/mfd/qnap-mcu.h +26 −0
  47. include/linux/mfd/tps65219.h +1 −6
  48. include/linux/mfd/upboard-fpga.h +55 −0
  49. include/linux/platform_data/syscon.h +0 −9
Documentation/devicetree/bindings/leds/st,led1202.yaml+132−0
@@ -0,0 +1,132 @@
1+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
2+%YAML 1.2
3+---
4+$id: http://devicetree.org/schemas/leds/st,led1202.yaml#
5+$schema: http://devicetree.org/meta-schemas/core.yaml#
6+
7+title: ST LED1202 LED controllers
8+
9+maintainers:
10+ - Vicentiu Galanopulo <vicentiu.galanopulo@remote-tech.co.uk>
11+
12+description: |
13+ The LED1202 is a 12-channel low quiescent current LED controller
14+ programmable via I2C; The output current can be adjusted separately
15+ for each channel by 8-bit analog and 12-bit digital dimming control.
16+ Datasheet available at
17+ https://www.st.com/en/power-management/led1202.html
18+
19+properties:
20+ compatible:
21+ const: st,led1202
22+
23+ reg:
24+ maxItems: 1
25+
26+ "#address-cells":
27+ const: 1
28+
29+ "#size-cells":
30+ const: 0
31+
32+patternProperties:
33+ "^led@[0-9a-f]$":
34+ type: object
35+ $ref: common.yaml#
36+ unevaluatedProperties: false
37+
38+ properties:
39+ reg:
40+ minimum: 0
41+ maximum: 11
42+
43+ required:
44+ - reg
45+
46+required:
47+ - compatible
48+ - reg
49+ - "#address-cells"
50+ - "#size-cells"
51+
52+additionalProperties: false
53+
54+examples:
55+ - |
56+ #include <dt-bindings/leds/common.h>
57+
58+ i2c {
59+ #address-cells = <1>;
60+ #size-cells = <0>;
61+
62+ led-controller@58 {
63+ compatible = "st,led1202";
64+ reg = <0x58>;
65+ #address-cells = <1>;
66+ #size-cells = <0>;
67+
68+ led@0 {
69+ reg = <0x0>;
70+ function = LED_FUNCTION_STATUS;
71+ color = <LED_COLOR_ID_RED>;
72+ function-enumerator = <1>;
73+ };
74+
75+ led@1 {
76+ reg = <0x1>;
77+ function = LED_FUNCTION_STATUS;
78+ color = <LED_COLOR_ID_GREEN>;
79+ function-enumerator = <2>;
80+ };
81+
82+ led@2 {
83+ reg = <0x2>;
84+ function = LED_FUNCTION_STATUS;
85+ color = <LED_COLOR_ID_BLUE>;
86+ function-enumerator = <3>;
87+ };
88+
89+ led@3 {
90+ reg = <0x3>;
91+ function = LED_FUNCTION_STATUS;
92+ color = <LED_COLOR_ID_RED>;
93+ function-enumerator = <4>;
94+ };
95+
96+ led@4 {
97+ reg = <0x4>;
98+ function = LED_FUNCTION_STATUS;
99+ color = <LED_COLOR_ID_GREEN>;
100+ function-enumerator = <5>;
101+ };
102+
103+ led@5 {
104+ reg = <0x5>;
105+ function = LED_FUNCTION_STATUS;
106+ color = <LED_COLOR_ID_BLUE>;
107+ function-enumerator = <6>;
108+ };
109+
110+ led@6 {
111+ reg = <0x6>;
112+ function = LED_FUNCTION_STATUS;
113+ color = <LED_COLOR_ID_RED>;
114+ function-enumerator = <7>;
115+ };
116+
117+ led@7 {
118+ reg = <0x7>;
119+ function = LED_FUNCTION_STATUS;
120+ color = <LED_COLOR_ID_GREEN>;
121+ function-enumerator = <8>;
122+ };
123+
124+ led@8 {
125+ reg = <0x8>;
126+ function = LED_FUNCTION_STATUS;
127+ color = <LED_COLOR_ID_BLUE>;
128+ function-enumerator = <9>;
129+ };
130+ };
131+ };
132+...
Documentation/devicetree/bindings/mfd/atmel,at91sam9260-gpbr.yaml+44−0
@@ -0,0 +1,44 @@
1+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2+%YAML 1.2
3+---
4+$id: http://devicetree.org/schemas/mfd/atmel,at91sam9260-gpbr.yaml#
5+$schema: http://devicetree.org/meta-schemas/core.yaml#
6+
7+title: Microchip AT91 General Purpose Backup Registers
8+
9+maintainers:
10+ - Nicolas Ferre <nicolas.ferre@microchip.com>
11+
12+description:
13+ The system controller embeds 256 bits of General Purpose Backup
14+ registers organized as 8 32-bit registers.
15+
16+properties:
17+ compatible:
18+ oneOf:
19+ - items:
20+ - enum:
21+ - atmel,at91sam9260-gpbr
22+ - const: syscon
23+ - items:
24+ - enum:
25+ - microchip,sam9x60-gpbr
26+ - microchip,sam9x7-gpbr
27+ - const: atmel,at91sam9260-gpbr
28+ - const: syscon
29+
30+ reg:
31+ maxItems: 1
32+
33+required:
34+ - compatible
35+ - reg
36+
37+additionalProperties: false
38+
39+examples:
40+ - |
41+ syscon@fffffd50 {
42+ compatible = "atmel,at91sam9260-gpbr", "syscon";
43+ reg = <0xfffffd50 0x10>;
44+ };
Documentation/devicetree/bindings/mfd/atmel,at91sam9260-matrix.yaml+52−0
@@ -0,0 +1,52 @@
1+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2+%YAML 1.2
3+---
4+$id: http://devicetree.org/schemas/mfd/atmel,at91sam9260-matrix.yaml#
5+$schema: http://devicetree.org/meta-schemas/core.yaml#
6+
7+title: Microchip AT91 Bus Matrix
8+
9+maintainers:
10+ - Nicolas Ferre <nicolas.ferre@microchip.com>
11+
12+description:
13+ The Bus Matrix (MATRIX) implements a multi-layer AHB, based on the
14+ AHB-Lite protocol, that enables parallel access paths between multiple
15+ masters and slaves in a system, thus increasing the overall bandwidth.
16+
17+properties:
18+ compatible:
19+ oneOf:
20+ - items:
21+ - enum:
22+ - atmel,at91sam9260-matrix
23+ - atmel,at91sam9261-matrix
24+ - atmel,at91sam9263-matrix
25+ - atmel,at91sam9rl-matrix
26+ - atmel,at91sam9g45-matrix
27+ - atmel,at91sam9n12-matrix
28+ - atmel,at91sam9x5-matrix
29+ - atmel,sama5d3-matrix
30+ - const: syscon
31+ - items:
32+ - enum:
33+ - microchip,sam9x60-matrix
34+ - microchip,sam9x7-matrix
35+ - const: atmel,at91sam9x5-matrix
36+ - const: syscon
37+
38+ reg:
39+ maxItems: 1
40+
41+required:
42+ - compatible
43+ - reg
44+
45+additionalProperties: false
46+
47+examples:
48+ - |
49+ syscon@ffffec00 {
50+ compatible = "atmel,sama5d3-matrix", "syscon";
51+ reg = <0xffffec00 0x200>;
52+ };
Documentation/devicetree/bindings/mfd/atmel-gpbr.txt+0−18
@@ -1,18 +0,0 @@
1−* Device tree bindings for Atmel GPBR (General Purpose Backup Registers)
2−
3−The GPBR are a set of battery-backed registers.
4−
5−Required properties:
6−- compatible: Should be one of the following:
7− "atmel,at91sam9260-gpbr", "syscon"
8− "microchip,sam9x60-gpbr", "syscon"
9− "microchip,sam9x7-gpbr", "microchip,sam9x60-gpbr", "syscon"
10−- reg: contains offset/length value of the GPBR memory
11− region.
12−
13−Example:
14−
15−gpbr: gpbr@fffffd50 {
16− compatible = "atmel,at91sam9260-gpbr", "syscon";
17− reg = <0xfffffd50 0x10>;
18−};
Documentation/devicetree/bindings/mfd/atmel-matrix.txt+0−26
@@ -1,26 +0,0 @@
1−* Device tree bindings for Atmel Bus Matrix
2−
3−The Bus Matrix registers are used to configure Atmel SoCs internal bus
4−behavior (master/slave priorities, undefined burst length type, ...)
5−
6−Required properties:
7−- compatible: Should be one of the following
8− "atmel,at91sam9260-matrix", "syscon"
9− "atmel,at91sam9261-matrix", "syscon"
10− "atmel,at91sam9263-matrix", "syscon"
11− "atmel,at91sam9rl-matrix", "syscon"
12− "atmel,at91sam9g45-matrix", "syscon"
13− "atmel,at91sam9n12-matrix", "syscon"
14− "atmel,at91sam9x5-matrix", "syscon"
15− "atmel,sama5d3-matrix", "syscon"
16− "microchip,sam9x60-matrix", "syscon"
17− "microchip,sam9x7-matrix", "atmel,at91sam9x5-matrix", "syscon"
18−- reg: Contains offset/length value of the Bus Matrix
19− memory region.
20−
21−Example:
22−
23−matrix: matrix@ffffec00 {
24− compatible = "atmel,sama5d3-matrix", "syscon";
25− reg = <0xffffec00 0x200>;
26−};
Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml+1−0
@@ -42,6 +42,7 @@ properties: · 41 unmodified lines
4242 - qcom,tcsr-apq8064
4343 - qcom,tcsr-apq8084
4444 - qcom,tcsr-ipq5332
45+ - qcom,tcsr-ipq5424
4546 - qcom,tcsr-ipq6018
4647 - qcom,tcsr-ipq8064
4748 - qcom,tcsr-ipq8074
Documentation/devicetree/bindings/mfd/qnap,ts433-mcu.yaml+42−0
@@ -0,0 +1,42 @@
1+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2+%YAML 1.2
3+---
4+$id: http://devicetree.org/schemas/mfd/qnap,ts433-mcu.yaml#
5+$schema: http://devicetree.org/meta-schemas/core.yaml#
6+
7+title: QNAP NAS on-board Microcontroller
8+
9+maintainers:
10+ - Heiko Stuebner <heiko@sntech.de>
11+
12+description:
13+ QNAP embeds a microcontroller on their NAS devices adding system feature
14+ as PWM Fan control, additional LEDs, power button status and more.
15+
16+properties:
17+ compatible:
18+ enum:
19+ - qnap,ts433-mcu
20+
21+patternProperties:
22+ "^fan-[0-9]+$":
23+ $ref: /schemas/hwmon/fan-common.yaml#
24+ unevaluatedProperties: false
25+
26+required:
27+ - compatible
28+
29+additionalProperties: false
30+
31+examples:
32+ - |
33+ uart {
34+ mcu {
35+ compatible = "qnap,ts433-mcu";
36+
37+ fan-0 {
38+ #cooling-cells = <2>;
39+ cooling-levels = <0 64 89 128 166 204 221 238>;
40+ };
41+ };
42+ };
Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml+10−10
@@ -50,15 +50,15 @@ properties: · 49 unmodified lines
5050 minimum: 0
5151 maximum: 1
5252
53− rohm,charger-sense-resistor-ohms:
54− minimum: 10000000
55− maximum: 50000000
53+ rohm,charger-sense-resistor-micro-ohms:
54+ minimum: 10000
55+ maximum: 50000
5656 description: |
57− BD71827 and BD71828 have SAR ADC for measuring charging currents.
58− External sense resistor (RSENSE in data sheet) should be used. If
59− something other but 30MOhm resistor is used the resistance value
60− should be given here in Ohms.
61− default: 30000000
57+ BD71815 has SAR ADC for measuring charging currents. External sense
58+ resistor (RSENSE in data sheet) should be used. If something other
59+ but a 30 mOhm resistor is used the resistance value should be given
60+ here in micro Ohms.
61+ default: 30000
6262
6363 regulators:
6464 $ref: /schemas/regulator/rohm,bd71815-regulator.yaml
@@ -67,7 +67,7 @@ properties: · 2 unmodified lines
6767
6868 gpio-reserved-ranges:
6969 description: |
70− Usage of BD71828 GPIO pins can be changed via OTP. This property can be
70+ Usage of BD71815 GPIO pins can be changed via OTP. This property can be
7171 used to mark the pins which should not be configured for GPIO. Please see
7272 the ../gpio/gpio.txt for more information.
7373
@@ -113,7 +113,7 @@ examples: · 39 unmodified lines
113113 gpio-controller;
114114 #gpio-cells = <2>;
115115
116− rohm,charger-sense-resistor-ohms = <10000000>;
116+ rohm,charger-sense-resistor-micro-ohms = <10000>;
117117
118118 regulators {
119119 buck1: buck1 {
Documentation/devicetree/bindings/mfd/sprd,sc2731.yaml+2−10
@@ -67,15 +67,7 @@ patternProperties: · 66 unmodified lines
6767
6868 "^efuse@[0-9a-f]+$":
6969 type: object
70− additionalProperties: true
71− properties:
72− compatible:
73− enum:
74− - sprd,sc2720-efuse
75− - sprd,sc2721-efuse
76− - sprd,sc2723-efuse
77− - sprd,sc2730-efuse
78− - sprd,sc2731-efuse
70+ $ref: /schemas/nvmem/sprd,sc2731-efuse.yaml#
7971
8072 "^fuel-gauge@[0-9a-f]+$":
8173 type: object
@@ -199,7 +191,7 @@ examples: · 117 unmodified lines
199191 };
200192 };
201193
202− adc@480 {
194+ pmic_adc: adc@480 {
203195 compatible = "sprd,sc2731-adc";
204196 reg = <0x480>;
205197 interrupt-parent = <&sc2731_pmic>;
Documentation/devicetree/bindings/mfd/syscon.yaml+4−1
@@ -27,7 +27,7 @@ select: · 26 unmodified lines
2727 compatible:
2828 contains:
2929 enum:
30− - al,alpine-sysfabric-servic
30+ - al,alpine-sysfabric-service
3131 - allwinner,sun8i-a83t-system-controller
3232 - allwinner,sun8i-h3-system-controller
3333 - allwinner,sun8i-v3s-system-controller
@@ -103,6 +103,7 @@ select: · 69 unmodified lines
103103 - rockchip,rk3288-qos
104104 - rockchip,rk3368-qos
105105 - rockchip,rk3399-qos
106+ - rockchip,rk3562-qos
106107 - rockchip,rk3568-qos
107108 - rockchip,rk3576-qos
108109 - rockchip,rk3588-qos
@@ -201,6 +202,7 @@ properties: · 92 unmodified lines
201202 - rockchip,rk3288-qos
202203 - rockchip,rk3368-qos
203204 - rockchip,rk3399-qos
205+ - rockchip,rk3562-qos
204206 - rockchip,rk3568-qos
205207 - rockchip,rk3576-qos
206208 - rockchip,rk3588-qos
@@ -213,6 +215,7 @@ properties: · 6 unmodified lines
213215 - ti,am625-dss-oldi-io-ctrl
214216 - ti,am62p-cpsw-mac-efuse
215217 - ti,am654-dss-oldi-io-ctrl
218+ - ti,j784s4-acspcie-proxy-ctrl
216219 - ti,j784s4-pcie-ctrl
217220 - ti,keystone-pllctrl
218221 - const: syscon
Documentation/devicetree/bindings/nvmem/sprd,sc2731-efuse.yaml+0−29
@@ -36,33 +36,4 @@ allOf: · 35 unmodified lines
3636 - $ref: nvmem-deprecated-cells.yaml#
3737
3838 unevaluatedProperties: false
39−
40−examples:
41− - |
42− pmic {
43− #address-cells = <1>;
44− #size-cells = <0>;
45−
46− efuse@380 {
47− compatible = "sprd,sc2731-efuse";
48− reg = <0x380>;
49− hwlocks = <&hwlock 12>;
50− #address-cells = <1>;
51− #size-cells = <1>;
52−
53− /* Data cells */
54− fgu_calib: calib@6 {
55− reg = <0x6 0x2>;
56− bits = <0 9>;
57− };
58−
59− adc_big_scale: calib@24 {
60− reg = <0x24 0x2>;
61− };
62−
63− adc_small_scale: calib@26 {
64− reg = <0x26 0x2>;
65− };
66− };
67− };
6839 ...
Documentation/hwmon/index.rst+1−0
@@ -201,6 +201,7 @@ Hardware Monitoring Kernel Drivers · 200 unmodified lines
201201 pxe1610
202202 pwm-fan
203203 q54sj108a2
204+ qnap-mcu-hwmon
204205 raspberrypi-hwmon
205206 sbrmi
206207 sbtsi_temp
Documentation/hwmon/qnap-mcu-hwmon.rst+27−0
@@ -0,0 +1,27 @@
1+.. SPDX-License-Identifier: GPL-2.0-or-later
2+
3+Kernel driver qnap-mcu-hwmon
4+============================
5+
6+This driver enables the use of the hardware monitoring and fan control
7+of the MCU used on some QNAP network attached storage devices.
8+
9+Author: Heiko Stuebner <heiko@sntech.de>
10+
11+Description
12+-----------
13+
14+The driver implements a simple interface for driving the fan controlled by
15+setting its PWM output value and exposes the fan rpm and case-temperature
16+to user space through hwmon's sysfs interface.
17+
18+The fan rotation speed returned via the optional 'fan1_input' is calculated
19+inside the MCU device.
20+
21+The driver provides the following sensor accesses in sysfs:
22+
23+=============== ======= =======================================================
24+fan1_input ro fan tachometer speed in RPM
25+pwm1 rw relative speed (0-255), 255=max. speed.
26+temp1_input ro Measured temperature in millicelsius
27+=============== ======= =======================================================
Documentation/leds/index.rst+1−0
@@ -28,4 +28,5 @@ LEDs · 27 unmodified lines
2828 leds-mlxcpld
2929 leds-mt6370-rgb
3030 leds-sc27xx
31+ leds-st1202.rst
3132 leds-qcom-lpg
Documentation/leds/leds-st1202.rst+34−0
@@ -0,0 +1,34 @@
1+.. SPDX-License-Identifier: GPL-2.0
2+
3+============================================
4+Kernel driver for STMicroelectronics LED1202
5+============================================
6+
7+/sys/class/leds/<led>/hw_pattern
8+--------------------------------
9+
10+Specify a hardware pattern for the ST1202 LED. The LED controller
11+implements 12 low-side current generators with independent dimming
12+control. Internal volatile memory allows the user to store up to 8
13+different patterns. Each pattern is a particular output configuration
14+in terms of PWM duty-cycle and duration (ms).
15+
16+To be compatible with the hardware pattern format, maximum 8 tuples of
17+brightness (PWM) and duration must be written to hw_pattern.
18+
19+- Min pattern duration: 22 ms
20+- Max pattern duration: 5660 ms
21+
22+The format of the hardware pattern values should be:
23+"brightness duration brightness duration ..."
24+
25+/sys/class/leds/<led>/repeat
26+----------------------------
27+
28+Specify a pattern repeat number, which is common for all channels.
29+Default is 1; negative numbers and 0 are invalid.
30+
31+This file will always return the originally written repeat number.
32+
33+When the 255 value is written to it, all patterns will repeat
34+indefinitely.
MAINTAINERS+9−0
@@ -19158,6 +19158,15 @@ L: linux-media@vger.kernel.org · 19157 unmodified lines
1915819158 S: Odd Fixes
1915919159 F: drivers/media/tuners/qm1d1c0042*
1916019160
19161+QNAP MCU DRIVER
19162+M: Heiko Stuebner <heiko@sntech.de>
19163+S: Maintained
19164+F: drivers/hwmon/qnap-mcu-hwmon.c
19165+F: drivers/input/misc/qnap-mcu-input.c
19166+F: drivers/leds/leds-qnap-mcu.c
19167+F: drivers/mfd/qnap-mcu.c
19168+F: include/linux/mfd/qnap-mcu.h
19169+
1916119170 QNX4 FILESYSTEM
1916219171 M: Anders Larsen <al@alarsen.net>
1916319172 S: Maintained
drivers/hid/hid-sensor-hub.c+14−7
@@ -730,23 +730,30 @@ err_stop_hw: · 729 unmodified lines
730730 return ret;
731731 }
732732
733+static int sensor_hub_finalize_pending_fn(struct device *dev, void *data)
734+{
735+ struct hid_sensor_hub_device *hsdev = dev->platform_data;
736+
737+ if (hsdev->pending.status)
738+ complete(&hsdev->pending.ready);
739+
740+ return 0;
741+}
742+
733743 static void sensor_hub_remove(struct hid_device *hdev)
734744 {
735745 struct sensor_hub_data *data = hid_get_drvdata(hdev);
736746 unsigned long flags;
737− int i;
738747
739748 hid_dbg(hdev, " hardware removed\n");
740749 hid_hw_close(hdev);
741750 hid_hw_stop(hdev);
751+
742752 spin_lock_irqsave(&data->lock, flags);
743− for (i = 0; i < data->hid_sensor_client_cnt; ++i) {
744− struct hid_sensor_hub_device *hsdev =
745− data->hid_sensor_hub_client_devs[i].platform_data;
746− if (hsdev->pending.status)
747− complete(&hsdev->pending.ready);
748− }
753+ device_for_each_child(&hdev->dev, NULL,
754+ sensor_hub_finalize_pending_fn);
749755 spin_unlock_irqrestore(&data->lock, flags);
756+
750757 mfd_remove_devices(&hdev->dev);
751758 mutex_destroy(&data->mutex);
752759 }
drivers/hwmon/Kconfig+12−0
@@ -1822,6 +1822,18 @@ config SENSORS_PWM_FAN · 1821 unmodified lines
18221822 This driver can also be built as a module. If so, the module
18231823 will be called pwm-fan.
18241824
1825+config SENSORS_QNAP_MCU_HWMON
1826+ tristate "QNAP MCU hardware monitoring"
1827+ depends on MFD_QNAP_MCU
1828+ depends on THERMAL || THERMAL=n
1829+ help
1830+ Say yes here to enable support for fan and temperature sensor
1831+ connected to a QNAP MCU, as found in a number of QNAP network
1832+ attached storage devices.
1833+
1834+ This driver can also be built as a module. If so, the module
1835+ will be called qnap-mcu-hwmon.
1836+
18251837 config SENSORS_RASPBERRYPI_HWMON
18261838 tristate "Raspberry Pi voltage monitor"
18271839 depends on RASPBERRYPI_FIRMWARE || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE)
drivers/hwmon/Makefile+1−0
@@ -189,6 +189,7 @@ obj-$(CONFIG_SENSORS_POWERZ) += powerz.o · 188 unmodified lines
189189 obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o
190190 obj-$(CONFIG_SENSORS_PT5161L) += pt5161l.o
191191 obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o
192+obj-$(CONFIG_SENSORS_QNAP_MCU_HWMON) += qnap-mcu-hwmon.o
192193 obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o
193194 obj-$(CONFIG_SENSORS_SBTSI) += sbtsi_temp.o
194195 obj-$(CONFIG_SENSORS_SBRMI) += sbrmi.o
drivers/hwmon/qnap-mcu-hwmon.c+364−0
@@ -0,0 +1,364 @@
1+// SPDX-License-Identifier: GPL-2.0-only
2+
3+/*
4+ * Driver for hwmon elements found on QNAP-MCU devices
5+ *
6+ * Copyright (C) 2024 Heiko Stuebner <heiko@sntech.de>
7+ */
8+
9+#include <linux/fwnode.h>
10+#include <linux/hwmon.h>
11+#include <linux/mfd/qnap-mcu.h>
12+#include <linux/module.h>
13+#include <linux/platform_device.h>
14+#include <linux/property.h>
15+#include <linux/thermal.h>
16+
17+struct qnap_mcu_hwmon {
18+ struct qnap_mcu *mcu;
19+ struct device *dev;
20+
21+ unsigned int pwm_min;
22+ unsigned int pwm_max;
23+
24+ struct fwnode_handle *fan_node;
25+ unsigned int fan_state;
26+ unsigned int fan_max_state;
27+ unsigned int *fan_cooling_levels;
28+
29+ struct thermal_cooling_device *cdev;
30+ struct hwmon_chip_info info;
31+};
32+
33+static int qnap_mcu_hwmon_get_rpm(struct qnap_mcu_hwmon *hwm)
34+{
35+ static const u8 cmd[] = { '@', 'F', 'A' };
36+ u8 reply[6];
37+ int ret;
38+
39+ /* poll the fan rpm */
40+ ret = qnap_mcu_exec(hwm->mcu, cmd, sizeof(cmd), reply, sizeof(reply));
41+ if (ret)
42+ return ret;
43+
44+ /* First 2 bytes must mirror the sent command */
45+ if (memcmp(cmd, reply, 2))
46+ return -EIO;
47+
48+ return reply[4] * 30;
49+}
50+
51+static int qnap_mcu_hwmon_get_pwm(struct qnap_mcu_hwmon *hwm)
52+{
53+ static const u8 cmd[] = { '@', 'F', 'Z', '0' }; /* 0 = fan-id? */
54+ u8 reply[4];
55+ int ret;
56+
57+ /* poll the fan pwm */
58+ ret = qnap_mcu_exec(hwm->mcu, cmd, sizeof(cmd), reply, sizeof(reply));
59+ if (ret)
60+ return ret;
61+
62+ /* First 3 bytes must mirror the sent command */
63+ if (memcmp(cmd, reply, 3))
64+ return -EIO;
65+
66+ return reply[3];
67+}
68+
69+static int qnap_mcu_hwmon_set_pwm(struct qnap_mcu_hwmon *hwm, u8 pwm)
70+{
71+ const u8 cmd[] = { '@', 'F', 'W', '0', pwm }; /* 0 = fan-id?, pwm 0-255 */
72+
73+ /* set the fan pwm */
74+ return qnap_mcu_exec_with_ack(hwm->mcu, cmd, sizeof(cmd));
75+}
76+
77+static int qnap_mcu_hwmon_get_temp(struct qnap_mcu_hwmon *hwm)
78+{
79+ static const u8 cmd[] = { '@', 'T', '3' };
80+ u8 reply[4];
81+ int ret;
82+
83+ /* poll the fan rpm */
84+ ret = qnap_mcu_exec(hwm->mcu, cmd, sizeof(cmd), reply, sizeof(reply));
85+ if (ret)
86+ return ret;
87+
88+ /* First bytes must mirror the sent command */
89+ if (memcmp(cmd, reply, sizeof(cmd)))
90+ return -EIO;
91+
92+ /*
93+ * There is an unknown bit set in bit7.
94+ * Bits [6:0] report the actual temperature as returned by the
95+ * original qnap firmware-tools, so just drop bit7 for now.
96+ */
97+ return (reply[3] & 0x7f) * 1000;
98+}
99+
100+static int qnap_mcu_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
101+ u32 attr, int channel, long val)
102+{
103+ struct qnap_mcu_hwmon *hwm = dev_get_drvdata(dev);
104+
105+ switch (attr) {
106+ case hwmon_pwm_input:
107+ if (val < 0 || val > 255)
108+ return -EINVAL;
109+
110+ if (val != 0)
111+ val = clamp_val(val, hwm->pwm_min, hwm->pwm_max);
112+
113+ return qnap_mcu_hwmon_set_pwm(hwm, val);
114+ default:
115+ return -EOPNOTSUPP;
116+ }
117+
118+ return 0;
119+}
120+
121+static int qnap_mcu_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
122+ u32 attr, int channel, long *val)
123+{
124+ struct qnap_mcu_hwmon *hwm = dev_get_drvdata(dev);
125+ int ret;
126+
127+ switch (type) {
128+ case hwmon_pwm:
129+ switch (attr) {
130+ case hwmon_pwm_input:
131+ ret = qnap_mcu_hwmon_get_pwm(hwm);
132+ if (ret < 0)
133+ return ret;
134+
135+ *val = ret;
136+ return 0;
137+ default:
138+ return -EOPNOTSUPP;
139+ }
140+ case hwmon_fan:
141+ ret = qnap_mcu_hwmon_get_rpm(hwm);
142+ if (ret < 0)
143+ return ret;
144+
145+ *val = ret;
146+ return 0;
147+ case hwmon_temp:
148+ ret = qnap_mcu_hwmon_get_temp(hwm);
149+ if (ret < 0)
150+ return ret;
151+
152+ *val = ret;
153+ return 0;
154+ default:
155+ return -EOPNOTSUPP;
156+ }
157+}
158+
159+static umode_t qnap_mcu_hwmon_is_visible(const void *data,
160+ enum hwmon_sensor_types type,
161+ u32 attr, int channel)
162+{
163+ switch (type) {
164+ case hwmon_temp:
165+ return 0444;
166+
167+ case hwmon_pwm:
168+ return 0644;
169+
170+ case hwmon_fan:
171+ return 0444;
172+
173+ default:
174+ return 0;
175+ }
176+}
177+
178+static const struct hwmon_ops qnap_mcu_hwmon_hwmon_ops = {
179+ .is_visible = qnap_mcu_hwmon_is_visible,
180+ .read = qnap_mcu_hwmon_read,
181+ .write = qnap_mcu_hwmon_write,
182+};
183+
184+/* thermal cooling device callbacks */
185+static int qnap_mcu_hwmon_get_max_state(struct thermal_cooling_device *cdev,
186+ unsigned long *state)
187+{
188+ struct qnap_mcu_hwmon *hwm = cdev->devdata;
189+
190+ if (!hwm)
191+ return -EINVAL;
192+
193+ *state = hwm->fan_max_state;
194+
195+ return 0;
196+}
197+
198+static int qnap_mcu_hwmon_get_cur_state(struct thermal_cooling_device *cdev,
199+ unsigned long *state)
200+{
201+ struct qnap_mcu_hwmon *hwm = cdev->devdata;
202+
203+ if (!hwm)
204+ return -EINVAL;
205+
206+ *state = hwm->fan_state;
207+
208+ return 0;
209+}
210+
211+static int qnap_mcu_hwmon_set_cur_state(struct thermal_cooling_device *cdev,
212+ unsigned long state)
213+{
214+ struct qnap_mcu_hwmon *hwm = cdev->devdata;
215+ int ret;
216+
217+ if (!hwm || state > hwm->fan_max_state)
218+ return -EINVAL;
219+
220+ if (state == hwm->fan_state)
221+ return 0;
222+
223+ ret = qnap_mcu_hwmon_set_pwm(hwm, hwm->fan_cooling_levels[state]);
224+ if (ret)
225+ return ret;
226+
227+ hwm->fan_state = state;
228+
229+ return ret;
230+}
231+
232+static const struct thermal_cooling_device_ops qnap_mcu_hwmon_cooling_ops = {
233+ .get_max_state = qnap_mcu_hwmon_get_max_state,
234+ .get_cur_state = qnap_mcu_hwmon_get_cur_state,
235+ .set_cur_state = qnap_mcu_hwmon_set_cur_state,
236+};
237+
238+static void devm_fan_node_release(void *data)
239+{
240+ struct qnap_mcu_hwmon *hwm = data;
241+
242+ fwnode_handle_put(hwm->fan_node);
243+}
244+
245+static int qnap_mcu_hwmon_get_cooling_data(struct device *dev, struct qnap_mcu_hwmon *hwm)
246+{
247+ struct fwnode_handle *fwnode;
248+ int num, i, ret;
249+
250+ fwnode = device_get_named_child_node(dev->parent, "fan-0");
251+ if (!fwnode)
252+ return 0;
253+
254+ /* if we found the fan-node, we're keeping it until device-unbind */
255+ hwm->fan_node = fwnode;
256+ ret = devm_add_action_or_reset(dev, devm_fan_node_release, hwm);
257+ if (ret)
258+ return ret;
259+
260+ num = fwnode_property_count_u32(fwnode, "cooling-levels");
261+ if (num <= 0)
262+ return dev_err_probe(dev, num ? : -EINVAL,
263+ "Failed to count elements in 'cooling-levels'\n");
264+
265+ hwm->fan_cooling_levels = devm_kcalloc(dev, num, sizeof(u32),
266+ GFP_KERNEL);
267+ if (!hwm->fan_cooling_levels)
268+ return -ENOMEM;
269+
270+ ret = fwnode_property_read_u32_array(fwnode, "cooling-levels",
271+ hwm->fan_cooling_levels, num);
272+ if (ret)
273+ return dev_err_probe(dev, ret, "Failed to read 'cooling-levels'\n");
274+
275+ for (i = 0; i < num; i++) {
276+ if (hwm->fan_cooling_levels[i] > hwm->pwm_max)
277+ return dev_err_probe(dev, -EINVAL, "fan state[%d]:%d > %d\n", i,
278+ hwm->fan_cooling_levels[i], hwm->pwm_max);
279+ }
280+
281+ hwm->fan_max_state = num - 1;
282+
283+ return 0;
284+}
285+
286+static const struct hwmon_channel_info * const qnap_mcu_hwmon_channels[] = {
287+ HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT),
288+ HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT),
289+ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
290+ NULL
291+};
292+
293+static int qnap_mcu_hwmon_probe(struct platform_device *pdev)
294+{
295+ struct qnap_mcu *mcu = dev_get_drvdata(pdev->dev.parent);
296+ const struct qnap_mcu_variant *variant = pdev->dev.platform_data;
297+ struct qnap_mcu_hwmon *hwm;
298+ struct thermal_cooling_device *cdev;
299+ struct device *dev = &pdev->dev;
300+ struct device *hwmon;
301+ int ret;
302+
303+ hwm = devm_kzalloc(dev, sizeof(*hwm), GFP_KERNEL);
304+ if (!hwm)
305+ return -ENOMEM;
306+
307+ hwm->mcu = mcu;
308+ hwm->dev = &pdev->dev;
309+ hwm->pwm_min = variant->fan_pwm_min;
310+ hwm->pwm_max = variant->fan_pwm_max;
311+
312+ platform_set_drvdata(pdev, hwm);
313+
314+ /*
315+ * Set duty cycle to maximum allowed.
316+ */
317+ ret = qnap_mcu_hwmon_set_pwm(hwm, hwm->pwm_max);
318+ if (ret)
319+ return ret;
320+
321+ hwm->info.ops = &qnap_mcu_hwmon_hwmon_ops;
322+ hwm->info.info = qnap_mcu_hwmon_channels;
323+
324+ ret = qnap_mcu_hwmon_get_cooling_data(dev, hwm);
325+ if (ret)
326+ return ret;
327+
328+ hwm->fan_state = hwm->fan_max_state;
329+
330+ hwmon = devm_hwmon_device_register_with_info(dev, "qnapmcu",
331+ hwm, &hwm->info, NULL);
332+ if (IS_ERR(hwmon))
333+ return dev_err_probe(dev, PTR_ERR(hwmon), "Failed to register hwmon device\n");
334+
335+ /*
336+ * Only register cooling device when we found cooling-levels.
337+ * qnap_mcu_hwmon_get_cooling_data() will fail when reading malformed
338+ * levels and only succeed with either no or correct cooling levels.
339+ */
340+ if (IS_ENABLED(CONFIG_THERMAL) && hwm->fan_cooling_levels) {
341+ cdev = devm_thermal_of_cooling_device_register(dev,
342+ to_of_node(hwm->fan_node), "qnap-mcu-hwmon",
343+ hwm, &qnap_mcu_hwmon_cooling_ops);
344+ if (IS_ERR(cdev))
345+ return dev_err_probe(dev, PTR_ERR(cdev),
346+ "Failed to register qnap-mcu-hwmon as cooling device\n");
347+ hwm->cdev = cdev;
348+ }
349+
350+ return 0;
351+}
352+
353+static struct platform_driver qnap_mcu_hwmon_driver = {
354+ .probe = qnap_mcu_hwmon_probe,
355+ .driver = {
356+ .name = "qnap-mcu-hwmon",
357+ },
358+};
359+module_platform_driver(qnap_mcu_hwmon_driver);
360+
361+MODULE_ALIAS("platform:qnap-mcu-hwmon");
362+MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
363+MODULE_DESCRIPTION("QNAP MCU hwmon driver");
364+MODULE_LICENSE("GPL");
drivers/input/misc/Kconfig+12−0
@@ -917,6 +917,18 @@ config INPUT_HISI_POWERKEY · 916 unmodified lines
917917 To compile this driver as a module, choose M here: the
918918 module will be called hisi_powerkey.
919919
920+config INPUT_QNAP_MCU
921+ tristate "Input Support for QNAP MCU controllers"
922+ depends on MFD_QNAP_MCU
923+ help
924+ This option enables support for input elements available on
925+ embedded controllers used in QNAP NAS devices.
926+
927+ This includes a polled power-button as well as a beeper.
928+
929+ To compile this driver as a module, choose M here: the
930+ module will be called qnap-mcu-input.
931+
920932 config INPUT_RAVE_SP_PWRBUTTON
921933 tristate "RAVE SP Power button Driver"
922934 depends on RAVE_SP_CORE
drivers/input/misc/Makefile+1−0
@@ -68,6 +68,7 @@ obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o · 67 unmodified lines
6868 obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
6969 obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o
7070 obj-$(CONFIG_INPUT_PWM_VIBRA) += pwm-vibra.o
71+obj-$(CONFIG_INPUT_QNAP_MCU) += qnap-mcu-input.o
7172 obj-$(CONFIG_INPUT_RAVE_SP_PWRBUTTON) += rave-sp-pwrbutton.o
7273 obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o
7374 obj-$(CONFIG_INPUT_REGULATOR_HAPTIC) += regulator-haptic.o
drivers/input/misc/qnap-mcu-input.c+153−0
@@ -0,0 +1,153 @@
1+// SPDX-License-Identifier: GPL-2.0-only
2+
3+/*
4+ * Driver for input events on QNAP-MCUs
5+ *
6+ * Copyright (C) 2024 Heiko Stuebner <heiko@sntech.de>
7+ */
8+
9+#include <linux/input.h>
10+#include <linux/mfd/qnap-mcu.h>
11+#include <linux/module.h>
12+#include <linux/platform_device.h>
13+#include <linux/slab.h>
14+#include <uapi/linux/input-event-codes.h>
15+
16+/*
17+ * The power-key needs to be pressed for a while to create an event,
18+ * so there is no use for overly frequent polling.
19+ */
20+#define POLL_INTERVAL 500
21+
22+struct qnap_mcu_input_dev {
23+ struct input_dev *input;
24+ struct qnap_mcu *mcu;
25+ struct device *dev;
26+
27+ struct work_struct beep_work;
28+ int beep_type;
29+};
30+
31+static void qnap_mcu_input_poll(struct input_dev *input)
32+{
33+ struct qnap_mcu_input_dev *idev = input_get_drvdata(input);
34+ static const u8 cmd[] = { '@', 'C', 'V' };
35+ u8 reply[4];
36+ int state, ret;
37+
38+ /* poll the power button */
39+ ret = qnap_mcu_exec(idev->mcu, cmd, sizeof(cmd), reply, sizeof(reply));
40+ if (ret)
41+ return;
42+
43+ /* First bytes must mirror the sent command */
44+ if (memcmp(cmd, reply, sizeof(cmd))) {
45+ dev_err(idev->dev, "malformed data received\n");
46+ return;
47+ }
48+
49+ state = reply[3] - 0x30;
50+ input_event(input, EV_KEY, KEY_POWER, state);
51+ input_sync(input);
52+}
53+
54+static void qnap_mcu_input_beeper_work(struct work_struct *work)
55+{
56+ struct qnap_mcu_input_dev *idev =
57+ container_of(work, struct qnap_mcu_input_dev, beep_work);
58+ const u8 cmd[] = { '@', 'C', (idev->beep_type == SND_TONE) ? '3' : '2' };
59+
60+ qnap_mcu_exec_with_ack(idev->mcu, cmd, sizeof(cmd));
61+}
62+
63+static int qnap_mcu_input_event(struct input_dev *input, unsigned int type,
64+ unsigned int code, int value)
65+{
66+ struct qnap_mcu_input_dev *idev = input_get_drvdata(input);
67+
68+ if (type != EV_SND || (code != SND_BELL && code != SND_TONE))
69+ return -EOPNOTSUPP;
70+
71+ if (value < 0)
72+ return -EINVAL;
73+
74+ /* beep runtime is determined by the MCU */
75+ if (value == 0)
76+ return 0;
77+
78+ /* Schedule work to actually turn the beeper on */
79+ idev->beep_type = code;
80+ schedule_work(&idev->beep_work);
81+
82+ return 0;
83+}
84+
85+static void qnap_mcu_input_close(struct input_dev *input)
86+{
87+ struct qnap_mcu_input_dev *idev = input_get_drvdata(input);
88+
89+ cancel_work_sync(&idev->beep_work);
90+}
91+
92+static int qnap_mcu_input_probe(struct platform_device *pdev)
93+{
94+ struct qnap_mcu *mcu = dev_get_drvdata(pdev->dev.parent);
95+ struct qnap_mcu_input_dev *idev;
96+ struct device *dev = &pdev->dev;
97+ struct input_dev *input;
98+ int ret;
99+
100+ idev = devm_kzalloc(dev, sizeof(*idev), GFP_KERNEL);
101+ if (!idev)
102+ return -ENOMEM;
103+
104+ input = devm_input_allocate_device(dev);
105+ if (!input)
106+ return dev_err_probe(dev, -ENOMEM, "no memory for input device\n");
107+
108+ idev->input = input;
109+ idev->dev = dev;
110+ idev->mcu = mcu;
111+
112+ input_set_drvdata(input, idev);
113+
114+ input->name = "qnap-mcu";
115+ input->phys = "qnap-mcu-input/input0";
116+ input->id.bustype = BUS_HOST;
117+ input->id.vendor = 0x0001;
118+ input->id.product = 0x0001;
119+ input->id.version = 0x0100;
120+ input->event = qnap_mcu_input_event;
121+ input->close = qnap_mcu_input_close;
122+
123+ input_set_capability(input, EV_KEY, KEY_POWER);
124+ input_set_capability(input, EV_SND, SND_BELL);
125+ input_set_capability(input, EV_SND, SND_TONE);
126+
127+ INIT_WORK(&idev->beep_work, qnap_mcu_input_beeper_work);
128+
129+ ret = input_setup_polling(input, qnap_mcu_input_poll);
130+ if (ret)
131+ return dev_err_probe(dev, ret, "unable to set up polling\n");
132+
133+ input_set_poll_interval(input, POLL_INTERVAL);
134+
135+ ret = input_register_device(input);
136+ if (ret)
137+ return dev_err_probe(dev, ret, "unable to register input device\n");
138+
139+ return 0;
140+}
141+
142+static struct platform_driver qnap_mcu_input_driver = {
143+ .probe = qnap_mcu_input_probe,
144+ .driver = {
145+ .name = "qnap-mcu-input",
146+ },
147+};
148+module_platform_driver(qnap_mcu_input_driver);
149+
150+MODULE_ALIAS("platform:qnap-mcu-input");
151+MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
152+MODULE_DESCRIPTION("QNAP MCU input driver");
153+MODULE_LICENSE("GPL");
drivers/leds/Kconfig+21−0
@@ -580,6 +580,17 @@ config LEDS_PCA995X · 579 unmodified lines
580580 LED driver chips accessed via the I2C bus. Supported
581581 devices include PCA9955BTW, PCA9952TW and PCA9955TW.
582582
583+config LEDS_QNAP_MCU
584+ tristate "LED Support for QNAP MCU controllers"
585+ depends on LEDS_CLASS
586+ depends on MFD_QNAP_MCU
587+ help
588+ This option enables support for LEDs available on embedded
589+ controllers used in QNAP NAS devices.
590+
591+ This driver can also be built as a module. If so, the module
592+ will be called qnap-mcu-leds.
593+
583594 config LEDS_WM831X_STATUS
584595 tristate "LED support for status LEDs on WM831x PMICs"
585596 depends on LEDS_CLASS
@@ -931,6 +942,16 @@ config LEDS_LM36274 · 345 unmodified lines
931942 Say Y to enable the LM36274 LED driver for TI LMU devices.
932943 This supports the LED device LM36274.
933944
945+config LEDS_ST1202
946+ tristate "LED Support for STMicroelectronics LED1202 I2C chips"
947+ depends on LEDS_CLASS
948+ depends on I2C
949+ depends on OF
950+ select LEDS_TRIGGERS
951+ help
952+ Say Y to enable support for LEDs connected to LED1202
953+ LED driver chips accessed via the I2C bus.
954+
934955 config LEDS_TPS6105X
935956 tristate "LED support for TI TPS6105X"
936957 depends on LEDS_CLASS
drivers/leds/Makefile+1−0
@@ -79,6 +79,7 @@ obj-$(CONFIG_LEDS_PCA995X) += leds-pca995x.o · 78 unmodified lines
7979 obj-$(CONFIG_LEDS_PM8058) += leds-pm8058.o
8080 obj-$(CONFIG_LEDS_POWERNV) += leds-powernv.o
8181 obj-$(CONFIG_LEDS_PWM) += leds-pwm.o
82+obj-$(CONFIG_LEDS_QNAP_MCU) += leds-qnap-mcu.o
8283 obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o
8384 obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o
8485 obj-$(CONFIG_LEDS_SUN50I_A100) += leds-sun50i-a100.o
drivers/leds/leds-qnap-mcu.c+227−0
@@ -0,0 +1,227 @@
1+// SPDX-License-Identifier: GPL-2.0-only
2+/*
3+ * Driver for LEDs found on QNAP MCU devices
4+ *
5+ * Copyright (C) 2024 Heiko Stuebner <heiko@sntech.de>
6+ */
7+
8+#include <linux/leds.h>
9+#include <linux/mfd/qnap-mcu.h>
10+#include <linux/module.h>
11+#include <linux/platform_device.h>
12+#include <linux/slab.h>
13+#include <uapi/linux/uleds.h>
14+
15+enum qnap_mcu_err_led_mode {
16+ QNAP_MCU_ERR_LED_ON = 0,
17+ QNAP_MCU_ERR_LED_OFF = 1,
18+ QNAP_MCU_ERR_LED_BLINK_FAST = 2,
19+ QNAP_MCU_ERR_LED_BLINK_SLOW = 3,
20+};
21+
22+struct qnap_mcu_err_led {
23+ struct qnap_mcu *mcu;
24+ struct led_classdev cdev;
25+ char name[LED_MAX_NAME_SIZE];
26+ u8 num;
27+ u8 mode;
28+};
29+
30+static inline struct qnap_mcu_err_led *
31+ cdev_to_qnap_mcu_err_led(struct led_classdev *led_cdev)
32+{
33+ return container_of(led_cdev, struct qnap_mcu_err_led, cdev);
34+}
35+
36+static int qnap_mcu_err_led_set(struct led_classdev *led_cdev,
37+ enum led_brightness brightness)
38+{
39+ struct qnap_mcu_err_led *err_led = cdev_to_qnap_mcu_err_led(led_cdev);
40+ u8 cmd[] = { '@', 'R', '0' + err_led->num, '0' };
41+
42+ /* Don't disturb a possible set blink-mode if LED stays on */
43+ if (brightness != 0 && err_led->mode >= QNAP_MCU_ERR_LED_BLINK_FAST)
44+ return 0;
45+
46+ err_led->mode = brightness ? QNAP_MCU_ERR_LED_ON : QNAP_MCU_ERR_LED_OFF;
47+ cmd[3] = '0' + err_led->mode;
48+
49+ return qnap_mcu_exec_with_ack(err_led->mcu, cmd, sizeof(cmd));
50+}
51+
52+static int qnap_mcu_err_led_blink_set(struct led_classdev *led_cdev,
53+ unsigned long *delay_on,
54+ unsigned long *delay_off)
55+{
56+ struct qnap_mcu_err_led *err_led = cdev_to_qnap_mcu_err_led(led_cdev);
57+ u8 cmd[] = { '@', 'R', '0' + err_led->num, '0' };
58+
59+ /* LED is off, nothing to do */
60+ if (err_led->mode == QNAP_MCU_ERR_LED_OFF)
61+ return 0;
62+
63+ if (*delay_on < 500) {
64+ *delay_on = 100;
65+ *delay_off = 100;
66+ err_led->mode = QNAP_MCU_ERR_LED_BLINK_FAST;
67+ } else {
68+ *delay_on = 500;
69+ *delay_off = 500;
70+ err_led->mode = QNAP_MCU_ERR_LED_BLINK_SLOW;
71+ }
72+
73+ cmd[3] = '0' + err_led->mode;
74+
75+ return qnap_mcu_exec_with_ack(err_led->mcu, cmd, sizeof(cmd));
76+}
77+
78+static int qnap_mcu_register_err_led(struct device *dev, struct qnap_mcu *mcu, int num_err_led)
79+{
80+ struct qnap_mcu_err_led *err_led;
81+ int ret;
82+
83+ err_led = devm_kzalloc(dev, sizeof(*err_led), GFP_KERNEL);
84+ if (!err_led)
85+ return -ENOMEM;
86+
87+ err_led->mcu = mcu;
88+ err_led->num = num_err_led;
89+ err_led->mode = QNAP_MCU_ERR_LED_OFF;
90+
91+ scnprintf(err_led->name, LED_MAX_NAME_SIZE, "hdd%d:red:status", num_err_led + 1);
92+ err_led->cdev.name = err_led->name;
93+
94+ err_led->cdev.brightness_set_blocking = qnap_mcu_err_led_set;
95+ err_led->cdev.blink_set = qnap_mcu_err_led_blink_set;
96+ err_led->cdev.brightness = 0;
97+ err_led->cdev.max_brightness = 1;
98+
99+ ret = devm_led_classdev_register(dev, &err_led->cdev);
100+ if (ret)
101+ return ret;
102+
103+ return qnap_mcu_err_led_set(&err_led->cdev, 0);
104+}
105+
106+enum qnap_mcu_usb_led_mode {
107+ QNAP_MCU_USB_LED_ON = 1,
108+ QNAP_MCU_USB_LED_OFF = 3,
109+ QNAP_MCU_USB_LED_BLINK = 2,
110+};
111+
112+struct qnap_mcu_usb_led {
113+ struct qnap_mcu *mcu;
114+ struct led_classdev cdev;
115+ u8 mode;
116+};
117+
118+static inline struct qnap_mcu_usb_led *
119+ cdev_to_qnap_mcu_usb_led(struct led_classdev *led_cdev)
120+{
121+ return container_of(led_cdev, struct qnap_mcu_usb_led, cdev);
122+}
123+
124+static int qnap_mcu_usb_led_set(struct led_classdev *led_cdev,
125+ enum led_brightness brightness)
126+{
127+ struct qnap_mcu_usb_led *usb_led = cdev_to_qnap_mcu_usb_led(led_cdev);
128+ u8 cmd[] = { '@', 'C', 0 };
129+
130+ /* Don't disturb a possible set blink-mode if LED stays on */
131+ if (brightness != 0 && usb_led->mode == QNAP_MCU_USB_LED_BLINK)
132+ return 0;
133+
134+ usb_led->mode = brightness ? QNAP_MCU_USB_LED_ON : QNAP_MCU_USB_LED_OFF;
135+
136+ /*
137+ * Byte 3 is shared between the usb led target on/off/blink
138+ * and also the buzzer control (in the input driver)
139+ */
140+ cmd[2] = 'D' + usb_led->mode;
141+
142+ return qnap_mcu_exec_with_ack(usb_led->mcu, cmd, sizeof(cmd));
143+}
144+
145+static int qnap_mcu_usb_led_blink_set(struct led_classdev *led_cdev,
146+ unsigned long *delay_on,
147+ unsigned long *delay_off)
148+{
149+ struct qnap_mcu_usb_led *usb_led = cdev_to_qnap_mcu_usb_led(led_cdev);
150+ u8 cmd[] = { '@', 'C', 0 };
151+
152+ /* LED is off, nothing to do */
153+ if (usb_led->mode == QNAP_MCU_USB_LED_OFF)
154+ return 0;
155+
156+ *delay_on = 250;
157+ *delay_off = 250;
158+ usb_led->mode = QNAP_MCU_USB_LED_BLINK;
159+
160+ /*
161+ * Byte 3 is shared between the USB LED target on/off/blink
162+ * and also the buzzer control (in the input driver)
163+ */
164+ cmd[2] = 'D' + usb_led->mode;
165+
166+ return qnap_mcu_exec_with_ack(usb_led->mcu, cmd, sizeof(cmd));
167+}
168+
169+static int qnap_mcu_register_usb_led(struct device *dev, struct qnap_mcu *mcu)
170+{
171+ struct qnap_mcu_usb_led *usb_led;
172+ int ret;
173+
174+ usb_led = devm_kzalloc(dev, sizeof(*usb_led), GFP_KERNEL);
175+ if (!usb_led)
176+ return -ENOMEM;
177+
178+ usb_led->mcu = mcu;
179+ usb_led->mode = QNAP_MCU_USB_LED_OFF;
180+ usb_led->cdev.name = "usb:blue:disk";
181+ usb_led->cdev.brightness_set_blocking = qnap_mcu_usb_led_set;
182+ usb_led->cdev.blink_set = qnap_mcu_usb_led_blink_set;
183+ usb_led->cdev.brightness = 0;
184+ usb_led->cdev.max_brightness = 1;
185+
186+ ret = devm_led_classdev_register(dev, &usb_led->cdev);
187+ if (ret)
188+ return ret;
189+
190+ return qnap_mcu_usb_led_set(&usb_led->cdev, 0);
191+}
192+
193+static int qnap_mcu_leds_probe(struct platform_device *pdev)
194+{
195+ struct qnap_mcu *mcu = dev_get_drvdata(pdev->dev.parent);
196+ const struct qnap_mcu_variant *variant = pdev->dev.platform_data;
197+ int ret;
198+
199+ for (int i = 0; i < variant->num_drives; i++) {
200+ ret = qnap_mcu_register_err_led(&pdev->dev, mcu, i);
201+ if (ret)
202+ return dev_err_probe(&pdev->dev, ret,
203+ "failed to register error LED %d\n", i);
204+ }
205+
206+ if (variant->usb_led) {
207+ ret = qnap_mcu_register_usb_led(&pdev->dev, mcu);
208+ if (ret)
209+ return dev_err_probe(&pdev->dev, ret,
210+ "failed to register USB LED\n");
211+ }
212+
213+ return 0;
214+}
215+
216+static struct platform_driver qnap_mcu_leds_driver = {
217+ .probe = qnap_mcu_leds_probe,
218+ .driver = {
219+ .name = "qnap-mcu-leds",
220+ },
221+};
222+module_platform_driver(qnap_mcu_leds_driver);
223+
224+MODULE_ALIAS("platform:qnap-mcu-leds");
225+MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
226+MODULE_DESCRIPTION("QNAP MCU LEDs driver");
227+MODULE_LICENSE("GPL");
drivers/leds/leds-st1202.c+416−0
@@ -0,0 +1,416 @@
1+// SPDX-License-Identifier: GPL-2.0-only
2+/*
3+ * LED driver for STMicroelectronics LED1202 chip
4+ *
5+ * Copyright (C) 2024 Remote-Tech Ltd. UK
6+ */
7+
8+#include <linux/cleanup.h>
9+#include <linux/ctype.h>
10+#include <linux/delay.h>
11+#include <linux/err.h>
12+#include <linux/gpio.h>
13+#include <linux/i2c.h>
14+#include <linux/leds.h>
15+#include <linux/module.h>
16+#include <linux/slab.h>
17+#include <linux/string.h>
18+
19+#define ST1202_CHAN_DISABLE_ALL 0x00
20+#define ST1202_CHAN_ENABLE_HIGH 0x03
21+#define ST1202_CHAN_ENABLE_LOW 0x02
22+#define ST1202_CONFIG_REG 0x04
23+/* PATS: Pattern sequence feature enable */
24+#define ST1202_CONFIG_REG_PATS BIT(7)
25+/* PATSR: Pattern sequence runs (self-clear when sequence is finished) */
26+#define ST1202_CONFIG_REG_PATSR BIT(6)
27+#define ST1202_CONFIG_REG_SHFT BIT(3)
28+#define ST1202_DEV_ENABLE 0x01
29+#define ST1202_DEV_ENABLE_ON BIT(0)
30+#define ST1202_DEV_ENABLE_RESET BIT(7)
31+#define ST1202_DEVICE_ID 0x00
32+#define ST1202_ILED_REG0 0x09
33+#define ST1202_MAX_LEDS 12
34+#define ST1202_MAX_PATTERNS 8
35+#define ST1202_MILLIS_PATTERN_DUR_MAX 5660
36+#define ST1202_MILLIS_PATTERN_DUR_MIN 22
37+#define ST1202_PATTERN_DUR 0x16
38+#define ST1202_PATTERN_PWM 0x1E
39+#define ST1202_PATTERN_REP 0x15
40+
41+struct st1202_led {
42+ struct fwnode_handle *fwnode;
43+ struct led_classdev led_cdev;
44+ struct st1202_chip *chip;
45+ bool is_active;
46+ int led_num;
47+};
48+
49+struct st1202_chip {
50+ struct i2c_client *client;
51+ struct mutex lock;
52+ struct st1202_led leds[ST1202_MAX_LEDS];
53+};
54+
55+static struct st1202_led *cdev_to_st1202_led(struct led_classdev *cdev)
56+{
57+ return container_of(cdev, struct st1202_led, led_cdev);
58+}
59+
60+static int st1202_read_reg(struct st1202_chip *chip, int reg, uint8_t *val)
61+{
62+ struct device *dev = &chip->client->dev;
63+ int ret;
64+
65+ ret = i2c_smbus_read_byte_data(chip->client, reg);
66+ if (ret < 0) {
67+ dev_err(dev, "Failed to read register [0x%x]: %d\n", reg, ret);
68+ return ret;
69+ }
70+
71+ *val = (uint8_t)ret;
72+ return 0;
73+}
74+
75+static int st1202_write_reg(struct st1202_chip *chip, int reg, uint8_t val)
76+{
77+ struct device *dev = &chip->client->dev;
78+ int ret;
79+
80+ ret = i2c_smbus_write_byte_data(chip->client, reg, val);
81+ if (ret != 0)
82+ dev_err(dev, "Failed to write %d to register [0x%x]: %d\n", val, reg, ret);
83+
84+ return ret;
85+}
86+
87+static uint8_t st1202_prescalar_to_miliseconds(unsigned int value)
88+{
89+ return value / ST1202_MILLIS_PATTERN_DUR_MIN - 1;
90+}
91+
92+static int st1202_pwm_pattern_write(struct st1202_chip *chip, int led_num,
93+ int pattern, unsigned int value)
94+{
95+ u8 value_l, value_h;
96+ int ret;
97+
98+ value_l = (u8)value;
99+ value_h = (u8)(value >> 8);
100+
101+ /*
102+ * Datasheet: Register address low = 1Eh + 2*(xh) + 18h*(yh),
103+ * where x is the channel number (led number) in hexadecimal (x = 00h .. 0Bh)
104+ * and y is the pattern number in hexadecimal (y = 00h .. 07h)
105+ */
106+ ret = st1202_write_reg(chip, (ST1202_PATTERN_PWM + (led_num * 2) + 0x18 * pattern),
107+ value_l);
108+ if (ret != 0)
109+ return ret;
110+
111+ /*
112+ * Datasheet: Register address high = 1Eh + 01h + 2(xh) +18h*(yh),
113+ * where x is the channel number in hexadecimal (x = 00h .. 0Bh)
114+ * and y is the pattern number in hexadecimal (y = 00h .. 07h)
115+ */
116+ ret = st1202_write_reg(chip, (ST1202_PATTERN_PWM + 0x1 + (led_num * 2) + 0x18 * pattern),
117+ value_h);
118+ if (ret != 0)
119+ return ret;
120+
121+ return 0;
122+}
123+
124+static int st1202_duration_pattern_write(struct st1202_chip *chip, int pattern,
125+ unsigned int value)
126+{
127+ return st1202_write_reg(chip, (ST1202_PATTERN_DUR + pattern),
128+ st1202_prescalar_to_miliseconds(value));
129+}
130+
131+static void st1202_brightness_set(struct led_classdev *led_cdev,
132+ enum led_brightness value)
133+{
134+ struct st1202_led *led = cdev_to_st1202_led(led_cdev);
135+ struct st1202_chip *chip = led->chip;
136+
137+ guard(mutex)(&chip->lock);
138+
139+ st1202_write_reg(chip, ST1202_ILED_REG0 + led->led_num, value);
140+}
141+
142+static enum led_brightness st1202_brightness_get(struct led_classdev *led_cdev)
143+{
144+ struct st1202_led *led = cdev_to_st1202_led(led_cdev);
145+ struct st1202_chip *chip = led->chip;
146+ u8 value = 0;
147+
148+ guard(mutex)(&chip->lock);
149+
150+ st1202_read_reg(chip, ST1202_ILED_REG0 + led->led_num, &value);
151+
152+ return value;
153+}
154+
155+static int st1202_channel_set(struct st1202_chip *chip, int led_num, bool active)
156+{
157+ u8 chan_low, chan_high;
158+ int ret;
159+
160+ guard(mutex)(&chip->lock);
161+
162+ if (led_num <= 7) {
163+ ret = st1202_read_reg(chip, ST1202_CHAN_ENABLE_LOW, &chan_low);
164+ if (ret < 0)
165+ return ret;
166+
167+ chan_low = active ? chan_low | BIT(led_num) : chan_low & ~BIT(led_num);
168+
169+ ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_LOW, chan_low);
170+ if (ret < 0)
171+ return ret;
172+
173+ } else {
174+ ret = st1202_read_reg(chip, ST1202_CHAN_ENABLE_HIGH, &chan_high);
175+ if (ret < 0)
176+ return ret;
177+
178+ chan_high = active ? chan_high | (BIT(led_num) >> 8) :
179+ chan_high & ~(BIT(led_num) >> 8);
180+
181+ ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_HIGH, chan_high);
182+ if (ret < 0)
183+ return ret;
184+ }
185+
186+ return 0;
187+}
188+
189+static int st1202_led_set(struct led_classdev *ldev, enum led_brightness value)
190+{
191+ struct st1202_led *led = cdev_to_st1202_led(ldev);
192+ struct st1202_chip *chip = led->chip;
193+
194+ return st1202_channel_set(chip, led->led_num, value == LED_OFF ? false : true);
195+}
196+
197+static int st1202_led_pattern_clear(struct led_classdev *ldev)
198+{
199+ struct st1202_led *led = cdev_to_st1202_led(ldev);
200+ struct st1202_chip *chip = led->chip;
201+ int ret;
202+
203+ guard(mutex)(&chip->lock);
204+
205+ for (int patt = 0; patt < ST1202_MAX_PATTERNS; patt++) {
206+ ret = st1202_pwm_pattern_write(chip, led->led_num, patt, LED_OFF);
207+ if (ret != 0)
208+ return ret;
209+
210+ ret = st1202_duration_pattern_write(chip, patt, ST1202_MILLIS_PATTERN_DUR_MIN);
211+ if (ret != 0)
212+ return ret;
213+ }
214+
215+ return 0;
216+}
217+
218+static int st1202_led_pattern_set(struct led_classdev *ldev,
219+ struct led_pattern *pattern,
220+ u32 len, int repeat)
221+{
222+ struct st1202_led *led = cdev_to_st1202_led(ldev);
223+ struct st1202_chip *chip = led->chip;
224+ int ret;
225+
226+ if (len > ST1202_MAX_PATTERNS)
227+ return -EINVAL;
228+
229+ guard(mutex)(&chip->lock);
230+
231+ for (int patt = 0; patt < len; patt++) {
232+ if (pattern[patt].delta_t < ST1202_MILLIS_PATTERN_DUR_MIN ||
233+ pattern[patt].delta_t > ST1202_MILLIS_PATTERN_DUR_MAX)
234+ return -EINVAL;
235+
236+ ret = st1202_pwm_pattern_write(chip, led->led_num, patt, pattern[patt].brightness);
237+ if (ret != 0)
238+ return ret;
239+
240+ ret = st1202_duration_pattern_write(chip, patt, pattern[patt].delta_t);
241+ if (ret != 0)
242+ return ret;
243+ }
244+
245+ ret = st1202_write_reg(chip, ST1202_PATTERN_REP, repeat);
246+ if (ret != 0)
247+ return ret;
248+
249+ ret = st1202_write_reg(chip, ST1202_CONFIG_REG, (ST1202_CONFIG_REG_PATSR |
250+ ST1202_CONFIG_REG_PATS | ST1202_CONFIG_REG_SHFT));
251+ if (ret != 0)
252+ return ret;
253+
254+ return 0;
255+}
256+
257+static int st1202_dt_init(struct st1202_chip *chip)
258+{
259+ struct device *dev = &chip->client->dev;
260+ struct st1202_led *led;
261+ int err, reg;
262+
263+ for_each_available_child_of_node_scoped(dev_of_node(dev), child) {
264+ struct led_init_data init_data = {};
265+
266+ err = of_property_read_u32(child, "reg", &reg);
267+ if (err)
268+ return dev_err_probe(dev, err, "Invalid register\n");
269+
270+ led = &chip->leds[reg];
271+ led->is_active = true;
272+ led->fwnode = of_fwnode_handle(child);
273+
274+ led->led_cdev.max_brightness = U8_MAX;
275+ led->led_cdev.brightness_set_blocking = st1202_led_set;
276+ led->led_cdev.pattern_set = st1202_led_pattern_set;
277+ led->led_cdev.pattern_clear = st1202_led_pattern_clear;
278+ led->led_cdev.default_trigger = "pattern";
279+
280+ init_data.fwnode = led->fwnode;
281+ init_data.devicename = "st1202";
282+ init_data.default_label = ":";
283+
284+ err = devm_led_classdev_register_ext(dev, &led->led_cdev, &init_data);
285+ if (err < 0)
286+ return dev_err_probe(dev, err, "Failed to register LED class device\n");
287+
288+ led->led_cdev.brightness_set = st1202_brightness_set;
289+ led->led_cdev.brightness_get = st1202_brightness_get;
290+ }
291+
292+ return 0;
293+}
294+
295+static int st1202_setup(struct st1202_chip *chip)
296+{
297+ int ret;
298+
299+ guard(mutex)(&chip->lock);
300+
301+ /*
302+ * Once the supply voltage is applied, the LED1202 executes some internal checks,
303+ * afterwords it stops the oscillator and puts the internal LDO in quiescent mode.
304+ * To start the device, EN bit must be set inside the “Device Enable” register at
305+ * address 01h. As soon as EN is set, the LED1202 loads the adjustment parameters
306+ * from the internal non-volatile memory and performs an auto-calibration procedure
307+ * in order to increase the output current precision.
308+ * Such initialization lasts about 6.5 ms.
309+ */
310+
311+ /* Reset the chip during setup */
312+ ret = st1202_write_reg(chip, ST1202_DEV_ENABLE, ST1202_DEV_ENABLE_RESET);
313+ if (ret < 0)
314+ return ret;
315+
316+ /* Enable phase-shift delay feature */
317+ ret = st1202_write_reg(chip, ST1202_CONFIG_REG, ST1202_CONFIG_REG_SHFT);
318+ if (ret < 0)
319+ return ret;
320+
321+ /* Enable the device */
322+ ret = st1202_write_reg(chip, ST1202_DEV_ENABLE, ST1202_DEV_ENABLE_ON);
323+ if (ret < 0)
324+ return ret;
325+
326+ /* Duration of initialization */
327+ usleep_range(6500, 10000);
328+
329+ /* Deactivate all LEDS (channels) and activate only the ones found in Device Tree */
330+ ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_LOW, ST1202_CHAN_DISABLE_ALL);
331+ if (ret < 0)
332+ return ret;
333+
334+ ret = st1202_write_reg(chip, ST1202_CHAN_ENABLE_HIGH, ST1202_CHAN_DISABLE_ALL);
335+ if (ret < 0)
336+ return ret;
337+
338+ ret = st1202_write_reg(chip, ST1202_CONFIG_REG,
339+ ST1202_CONFIG_REG_PATS | ST1202_CONFIG_REG_PATSR);
340+ if (ret < 0)
341+ return ret;
342+
343+ return 0;
344+}
345+
346+static int st1202_probe(struct i2c_client *client)
347+{
348+ struct st1202_chip *chip;
349+ struct st1202_led *led;
350+ int ret;
351+
352+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
353+ return dev_err_probe(&client->dev, -EIO, "SMBUS Byte Data not Supported\n");
354+
355+ chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
356+ if (!chip)
357+ return -ENOMEM;
358+
359+ devm_mutex_init(&client->dev, &chip->lock);
360+ chip->client = client;
361+
362+ ret = st1202_dt_init(chip);
363+ if (ret < 0)
364+ return ret;
365+
366+ ret = st1202_setup(chip);
367+ if (ret < 0)
368+ return ret;
369+
370+ for (int i = 0; i < ST1202_MAX_LEDS; i++) {
371+ led = &chip->leds[i];
372+ led->chip = chip;
373+ led->led_num = i;
374+
375+ if (!led->is_active)
376+ continue;
377+
378+ ret = st1202_channel_set(led->chip, led->led_num, true);
379+ if (ret < 0)
380+ return dev_err_probe(&client->dev, ret,
381+ "Failed to activate LED channel\n");
382+
383+ ret = st1202_led_pattern_clear(&led->led_cdev);
384+ if (ret < 0)
385+ return dev_err_probe(&client->dev, ret,
386+ "Failed to clear LED pattern\n");
387+ }
388+
389+ return 0;
390+}
391+
392+static const struct i2c_device_id st1202_id[] = {
393+ { "st1202-i2c" },
394+ { /* sentinel */ }
395+};
396+MODULE_DEVICE_TABLE(i2c, st1202_id);
397+
398+static const struct of_device_id st1202_dt_ids[] = {
399+ { .compatible = "st,led1202" },
400+ { /* sentinel */ }
401+};
402+MODULE_DEVICE_TABLE(of, st1202_dt_ids);
403+
404+static struct i2c_driver st1202_driver = {
405+ .driver = {
406+ .name = "leds-st1202",
407+ .of_match_table = of_match_ptr(st1202_dt_ids),
408+ },
409+ .probe = st1202_probe,
410+ .id_table = st1202_id,
411+};
412+module_i2c_driver(st1202_driver);
413+
414+MODULE_AUTHOR("Remote Tech LTD");
415+MODULE_DESCRIPTION("STMicroelectronics LED1202 : 12-channel constant current LED driver");
416+MODULE_LICENSE("GPL");
drivers/mfd/Kconfig+25−0
@@ -2386,6 +2386,19 @@ config MFD_INTEL_M10_BMC_PMCI · 2385 unmodified lines
23862386 additional drivers must be enabled in order to use the functionality
23872387 of the device.
23882388
2389+config MFD_QNAP_MCU
2390+ tristate "QNAP microcontroller unit core driver"
2391+ depends on SERIAL_DEV_BUS
2392+ select MFD_CORE
2393+ help
2394+ Select this to get support for the QNAP MCU device found in
2395+ several devices of QNAP network attached storage products that
2396+ implements additional functionality for the device, like fan
2397+ and LED control.
2398+
2399+ This driver implements the base serial protocol to talk to the
2400+ device and provides functions for the other parts to hook into.
2401+
23892402 config MFD_RSMU_I2C
23902403 tristate "Renesas Synchronization Management Unit with I2C"
23912404 depends on I2C && OF
@@ -2414,5 +2427,17 @@ config MFD_RSMU_SPI · 22 unmodified lines
24142427 Additional drivers must be enabled in order to use the functionality
24152428 of the device.
24162429
2430+config MFD_UPBOARD_FPGA
2431+ tristate "Support for the AAeon UP board FPGA"
2432+ depends on (X86 && ACPI)
2433+ select MFD_CORE
2434+ help
2435+ Select this option to enable the AAEON UP and UP^2 onboard FPGA.
2436+ This is the core driver of this FPGA, which has a pin controller and a
2437+ LED controller.
2438+
2439+ To compile this driver as a module, choose M here: the module will be
2440+ called upboard-fpga.
2441+
24172442 endmenu
24182443 endif
drivers/mfd/Makefile+4−0
@@ -288,5 +288,9 @@ obj-$(CONFIG_MFD_INTEL_M10_BMC_PMCI) += intel-m10-bmc-pmci.o · 287 unmodified lines
288288 obj-$(CONFIG_MFD_ATC260X) += atc260x-core.o
289289 obj-$(CONFIG_MFD_ATC260X_I2C) += atc260x-i2c.o
290290
291+obj-$(CONFIG_MFD_QNAP_MCU) += qnap-mcu.o
292+
291293 obj-$(CONFIG_MFD_RSMU_I2C) += rsmu_i2c.o rsmu_core.o
292294 obj-$(CONFIG_MFD_RSMU_SPI) += rsmu_spi.o rsmu_core.o
295+
296+obj-$(CONFIG_MFD_UPBOARD_FPGA) += upboard-fpga.o
drivers/mfd/axp20x.c+2−5
@@ -1445,7 +1445,7 @@ int axp20x_device_probe(struct axp20x_dev *axp20x) · 1444 unmodified lines
14451445 }
14461446 }
14471447
1448− ret = mfd_add_devices(axp20x->dev, PLATFORM_DEVID_AUTO, axp20x->cells,
1448+ ret = mfd_add_devices(axp20x->dev, PLATFORM_DEVID_NONE, axp20x->cells,
14491449 axp20x->nr_cells, NULL, 0, NULL);
14501450
14511451 if (ret) {
@@ -1455,10 +1455,7 @@ int axp20x_device_probe(struct axp20x_dev *axp20x) · 3 unmodified lines
14551455 }
14561456
14571457 if (axp20x->variant != AXP288_ID)
1458− devm_register_sys_off_handler(axp20x->dev,
1459− SYS_OFF_MODE_POWER_OFF,
1460− SYS_OFF_PRIO_DEFAULT,
1461− axp20x_power_off, axp20x);
1458+ devm_register_power_off_handler(axp20x->dev, axp20x_power_off, axp20x);
14621459
14631460 dev_info(axp20x->dev, "AXP20X driver loaded\n");
14641461
drivers/mfd/cs42l43-i2c.c+0−8
@@ -56,13 +56,6 @@ static int cs42l43_i2c_probe(struct i2c_client *i2c) · 55 unmodified lines
5656 return cs42l43_dev_probe(cs42l43);
5757 }
5858
59−static void cs42l43_i2c_remove(struct i2c_client *i2c)
60−{
61− struct cs42l43 *cs42l43 = dev_get_drvdata(&i2c->dev);
62−
63− cs42l43_dev_remove(cs42l43);
64−}
65−
6659 #if IS_ENABLED(CONFIG_OF)
6760 static const struct of_device_id cs42l43_of_match[] = {
6861 { .compatible = "cirrus,cs42l43", },
@@ -88,7 +81,6 @@ static struct i2c_driver cs42l43_i2c_driver = { · 19 unmodified lines
8881 },
8982
9083 .probe = cs42l43_i2c_probe,
91− .remove = cs42l43_i2c_remove,
9284 };
9385 module_i2c_driver(cs42l43_i2c_driver);
9486
drivers/mfd/cs42l43-sdw.c+0−10
@@ -187,15 +187,6 @@ static int cs42l43_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id * · 186 unmodified lines
187187 return cs42l43_dev_probe(cs42l43);
188188 }
189189
190−static int cs42l43_sdw_remove(struct sdw_slave *sdw)
191−{
192− struct cs42l43 *cs42l43 = dev_get_drvdata(&sdw->dev);
193−
194− cs42l43_dev_remove(cs42l43);
195−
196− return 0;
197−}
198−
199190 static const struct sdw_device_id cs42l43_sdw_id[] = {
200191 SDW_SLAVE_ENTRY(0x01FA, 0x4243, 0),
201192 {}
@@ -209,7 +200,6 @@ static struct sdw_driver cs42l43_sdw_driver = { · 7 unmodified lines
209200 },
210201
211202 .probe = cs42l43_sdw_probe,
212− .remove = cs42l43_sdw_remove,
213203 .id_table = cs42l43_sdw_id,
214204 .ops = &cs42l43_sdw_ops,
215205 };
drivers/mfd/cs42l43.c+23−14
@@ -29,7 +29,7 @@ · 28 unmodified lines
2929
3030 #define CS42L43_RESET_DELAY_MS 20
3131
32−#define CS42L43_SDW_ATTACH_TIMEOUT_MS 500
32+#define CS42L43_SDW_ATTACH_TIMEOUT_MS 5000
3333 #define CS42L43_SDW_DETACH_TIMEOUT_MS 100
3434
3535 #define CS42L43_MCU_BOOT_STAGE1 1
@@ -48,6 +48,7 @@ · 12 unmodified lines
4848
4949 #define CS42L43_MCU_SUPPORTED_REV 0x2105
5050 #define CS42L43_MCU_SHADOW_REGS_REQUIRED_REV 0x2200
51+#define CS42L43_BIOS_SHADOW_REGS_REQUIRED_REV 0x1002
5152 #define CS42L43_MCU_SUPPORTED_BIOS_REV 0x0001
5253
5354 #define CS42L43_VDDP_DELAY_US 50
@@ -773,7 +774,8 @@ static int cs42l43_mcu_update_step(struct cs42l43 *cs42l43) · 719 unmodified lines
773774 * Later versions of the firmwware require the driver to access some
774775 * features through a set of shadow registers.
775776 */
776− shadow = mcu_rev >= CS42L43_MCU_SHADOW_REGS_REQUIRED_REV;
777+ shadow = (mcu_rev >= CS42L43_MCU_SHADOW_REGS_REQUIRED_REV) ||
778+ (bios_rev >= CS42L43_BIOS_SHADOW_REGS_REQUIRED_REV);
777779
778780 ret = regmap_read(cs42l43->regmap, CS42L43_BOOT_CONTROL, &secure_cfg);
779781 if (ret) {
@@ -982,7 +984,7 @@ static int cs42l43_power_up(struct cs42l43 *cs42l43) · 202 unmodified lines
982984 /* vdd-p must be on for 50uS before any other supply */
983985 usleep_range(CS42L43_VDDP_DELAY_US, 2 * CS42L43_VDDP_DELAY_US);
984986
985− gpiod_set_value_cansleep(cs42l43->reset, 1);
987+ gpiod_set_raw_value_cansleep(cs42l43->reset, 1);
986988
987989 ret = regulator_bulk_enable(CS42L43_N_SUPPLIES, cs42l43->core_supplies);
988990 if (ret) {
@@ -1003,7 +1005,7 @@ static int cs42l43_power_up(struct cs42l43 *cs42l43) · 14 unmodified lines
10031005 err_core_supplies:
10041006 regulator_bulk_disable(CS42L43_N_SUPPLIES, cs42l43->core_supplies);
10051007 err_reset:
1006− gpiod_set_value_cansleep(cs42l43->reset, 0);
1008+ gpiod_set_raw_value_cansleep(cs42l43->reset, 0);
10071009 regulator_disable(cs42l43->vdd_p);
10081010
10091011 return ret;
@@ -1025,7 +1027,7 @@ static int cs42l43_power_down(struct cs42l43 *cs42l43) · 15 unmodified lines
10251027 return ret;
10261028 }
10271029
1028− gpiod_set_value_cansleep(cs42l43->reset, 0);
1030+ gpiod_set_raw_value_cansleep(cs42l43->reset, 0);
10291031
10301032 ret = regulator_disable(cs42l43->vdd_p);
10311033 if (ret) {
@@ -1036,6 +1038,15 @@ static int cs42l43_power_down(struct cs42l43 *cs42l43) · 4 unmodified lines
10361038 return 0;
10371039 }
10381040
1041+static void cs42l43_dev_remove(void *data)
1042+{
1043+ struct cs42l43 *cs42l43 = data;
1044+
1045+ cancel_work_sync(&cs42l43->boot_work);
1046+
1047+ cs42l43_power_down(cs42l43);
1048+}
1049+
10391050 int cs42l43_dev_probe(struct cs42l43 *cs42l43)
10401051 {
10411052 int i, ret;
@@ -1050,11 +1061,13 @@ int cs42l43_dev_probe(struct cs42l43 *cs42l43) · 8 unmodified lines
10501061
10511062 regcache_cache_only(cs42l43->regmap, true);
10521063
1053− cs42l43->reset = devm_gpiod_get_optional(cs42l43->dev, "reset", GPIOD_OUT_LOW);
1064+ cs42l43->reset = devm_gpiod_get_optional(cs42l43->dev, "reset", GPIOD_OUT_HIGH);
10541065 if (IS_ERR(cs42l43->reset))
10551066 return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->reset),
10561067 "Failed to get reset\n");
10571068
1069+ gpiod_set_raw_value_cansleep(cs42l43->reset, 0);
1070+
10581071 cs42l43->vdd_p = devm_regulator_get(cs42l43->dev, "vdd-p");
10591072 if (IS_ERR(cs42l43->vdd_p))
10601073 return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->vdd_p),
@@ -1080,6 +1093,10 @@ int cs42l43_dev_probe(struct cs42l43 *cs42l43) · 19 unmodified lines
10801093 if (ret)
10811094 return ret;
10821095
1096+ ret = devm_add_action_or_reset(cs42l43->dev, cs42l43_dev_remove, cs42l43);
1097+ if (ret)
1098+ return ret;
1099+
10831100 pm_runtime_set_autosuspend_delay(cs42l43->dev, CS42L43_AUTOSUSPEND_TIME_MS);
10841101 pm_runtime_use_autosuspend(cs42l43->dev);
10851102 pm_runtime_set_active(cs42l43->dev);
@@ -1098,14 +1115,6 @@ int cs42l43_dev_probe(struct cs42l43 *cs42l43) · 12 unmodified lines
10981115 }
10991116 EXPORT_SYMBOL_NS_GPL(cs42l43_dev_probe, "MFD_CS42L43");
11001117
1101−void cs42l43_dev_remove(struct cs42l43 *cs42l43)
1102−{
1103− cancel_work_sync(&cs42l43->boot_work);
1104−
1105− cs42l43_power_down(cs42l43);
1106−}
1107−EXPORT_SYMBOL_NS_GPL(cs42l43_dev_remove, "MFD_CS42L43");
1108−
11091118 static int cs42l43_suspend(struct device *dev)
11101119 {
11111120 struct cs42l43 *cs42l43 = dev_get_drvdata(dev);
drivers/mfd/cs42l43.h+0−1
@@ -25,6 +25,5 @@ bool cs42l43_precious_register(struct device *dev, unsigned int reg); · 24 unmodified lines
2525 bool cs42l43_volatile_register(struct device *dev, unsigned int reg);
2626
2727 int cs42l43_dev_probe(struct cs42l43 *cs42l43);
28−void cs42l43_dev_remove(struct cs42l43 *cs42l43);
2928
3029 #endif /* CS42L43_CORE_INT_H */
drivers/mfd/da9052-core.c+1−0
@@ -585,6 +585,7 @@ static int da9052_clear_fault_log(struct da9052 *da9052) · 584 unmodified lines
585585 "Cannot reset FAULT_LOG values %d\n", ret);
586586 }
587587
588+ da9052->fault_log = fault_log;
588589 return ret;
589590 }
590591
drivers/mfd/intel_soc_pmic_chtdc_ti.c+1−1
@@ -81,7 +81,7 @@ static struct mfd_cell chtdc_ti_dev[] = { · 80 unmodified lines
8181 static const struct regmap_config chtdc_ti_regmap_config = {
8282 .reg_bits = 8,
8383 .val_bits = 8,
84− .max_register = 128,
84+ .max_register = 0xff,
8585 .cache_type = REGCACHE_NONE,
8686 };
8787
drivers/mfd/lpc_ich.c+2−1
@@ -834,8 +834,9 @@ static const struct pci_device_id lpc_ich_ids[] = { · 833 unmodified lines
834834 { PCI_VDEVICE(INTEL, 0x2917), LPC_ICH9ME},
835835 { PCI_VDEVICE(INTEL, 0x2918), LPC_ICH9},
836836 { PCI_VDEVICE(INTEL, 0x2919), LPC_ICH9M},
837− { PCI_VDEVICE(INTEL, 0x3197), LPC_GLK},
838837 { PCI_VDEVICE(INTEL, 0x2b9c), LPC_COUGARMOUNTAIN},
838+ { PCI_VDEVICE(INTEL, 0x3197), LPC_GLK},
839+ { PCI_VDEVICE(INTEL, 0x31e8), LPC_GLK},
839840 { PCI_VDEVICE(INTEL, 0x3a14), LPC_ICH10DO},
840841 { PCI_VDEVICE(INTEL, 0x3a16), LPC_ICH10R},
841842 { PCI_VDEVICE(INTEL, 0x3a18), LPC_ICH10},
drivers/mfd/qnap-mcu.c+338−0
@@ -0,0 +1,338 @@
1+// SPDX-License-Identifier: GPL-2.0-only
2+/*
3+ * Core driver for the microcontroller unit in QNAP NAS devices that is
4+ * connected via a dedicated UART port.
5+ *
6+ * Copyright (C) 2024 Heiko Stuebner <heiko@sntech.de>
7+ */
8+
9+#include <linux/cleanup.h>
10+#include <linux/export.h>
11+#include <linux/mfd/core.h>
12+#include <linux/mfd/qnap-mcu.h>
13+#include <linux/module.h>
14+#include <linux/of.h>
15+#include <linux/reboot.h>
16+#include <linux/serdev.h>
17+#include <linux/slab.h>
18+
19+/* The longest command found so far is 5 bytes long */
20+#define QNAP_MCU_MAX_CMD_SIZE 5
21+#define QNAP_MCU_MAX_DATA_SIZE 36
22+#define QNAP_MCU_CHECKSUM_SIZE 1
23+
24+#define QNAP_MCU_RX_BUFFER_SIZE \
25+ (QNAP_MCU_MAX_DATA_SIZE + QNAP_MCU_CHECKSUM_SIZE)
26+
27+#define QNAP_MCU_TX_BUFFER_SIZE \
28+ (QNAP_MCU_MAX_CMD_SIZE + QNAP_MCU_CHECKSUM_SIZE)
29+
30+#define QNAP_MCU_ACK_LEN 2
31+#define QNAP_MCU_VERSION_LEN 4
32+
33+#define QNAP_MCU_TIMEOUT_MS 500
34+
35+/**
36+ * struct qnap_mcu_reply - Reply to a command
37+ *
38+ * @data: Buffer to store reply payload in
39+ * @length: Expected reply length, including the checksum
40+ * @received: Received number of bytes, so far
41+ * @done: Triggered when the entire reply has been received
42+ */
43+struct qnap_mcu_reply {
44+ u8 *data;
45+ size_t length;
46+ size_t received;
47+ struct completion done;
48+};
49+
50+/**
51+ * struct qnap_mcu - QNAP NAS embedded controller
52+ *
53+ * @serdev: Pointer to underlying serdev
54+ * @bus_lock: Lock to serialize access to the device
55+ * @reply: Reply data structure
56+ * @variant: Device variant specific information
57+ * @version: MCU firmware version
58+ */
59+struct qnap_mcu {
60+ struct serdev_device *serdev;
61+ struct mutex bus_lock;
62+ struct qnap_mcu_reply reply;
63+ const struct qnap_mcu_variant *variant;
64+ u8 version[QNAP_MCU_VERSION_LEN];
65+};
66+
67+/*
68+ * The QNAP-MCU uses a basic XOR checksum.
69+ * It is always the last byte and XORs the whole previous message.
70+ */
71+static u8 qnap_mcu_csum(const u8 *buf, size_t size)
72+{
73+ u8 csum = 0;
74+
75+ while (size--)
76+ csum ^= *buf++;
77+
78+ return csum;
79+}
80+
81+static int qnap_mcu_write(struct qnap_mcu *mcu, const u8 *data, u8 data_size)
82+{
83+ unsigned char tx[QNAP_MCU_TX_BUFFER_SIZE];
84+ size_t length = data_size + QNAP_MCU_CHECKSUM_SIZE;
85+
86+ if (length > sizeof(tx)) {
87+ dev_err(&mcu->serdev->dev, "data too big for transmit buffer");
88+ return -EINVAL;
89+ }
90+
91+ memcpy(tx, data, data_size);
92+ tx[data_size] = qnap_mcu_csum(data, data_size);
93+
94+ serdev_device_write_flush(mcu->serdev);
95+
96+ return serdev_device_write(mcu->serdev, tx, length, HZ);
97+}
98+
99+static size_t qnap_mcu_receive_buf(struct serdev_device *serdev, const u8 *buf, size_t size)
100+{
101+ struct device *dev = &serdev->dev;
102+ struct qnap_mcu *mcu = dev_get_drvdata(dev);
103+ struct qnap_mcu_reply *reply = &mcu->reply;
104+ const u8 *src = buf;
105+ const u8 *end = buf + size;
106+
107+ if (!reply->length) {
108+ dev_warn(dev, "Received %zu bytes, we were not waiting for\n", size);
109+ return size;
110+ }
111+
112+ while (src < end) {
113+ reply->data[reply->received] = *src++;
114+ reply->received++;
115+
116+ if (reply->received == reply->length) {
117+ /* We don't expect any characters from the device now */
118+ reply->length = 0;
119+
120+ complete(&reply->done);
121+
122+ /*
123+ * We report the consumed number of bytes. If there
124+ * are still bytes remaining (though there shouldn't)
125+ * the serdev layer will re-execute this handler with
126+ * the remainder of the Rx bytes.
127+ */
128+ return src - buf;
129+ }
130+ }
131+
132+ /*
133+ * The only way to get out of the above loop and end up here
134+ * is through consuming all of the supplied data, so here we
135+ * report that we processed it all.
136+ */
137+ return size;
138+}
139+
140+static const struct serdev_device_ops qnap_mcu_serdev_device_ops = {
141+ .receive_buf = qnap_mcu_receive_buf,
142+ .write_wakeup = serdev_device_write_wakeup,
143+};
144+
145+int qnap_mcu_exec(struct qnap_mcu *mcu,
146+ const u8 *cmd_data, size_t cmd_data_size,
147+ u8 *reply_data, size_t reply_data_size)
148+{
149+ unsigned char rx[QNAP_MCU_RX_BUFFER_SIZE];
150+ size_t length = reply_data_size + QNAP_MCU_CHECKSUM_SIZE;
151+ struct qnap_mcu_reply *reply = &mcu->reply;
152+ int ret = 0;
153+
154+ if (length > sizeof(rx)) {
155+ dev_err(&mcu->serdev->dev, "expected data too big for receive buffer");
156+ return -EINVAL;
157+ }
158+
159+ mutex_lock(&mcu->bus_lock);
160+
161+ reply->data = rx,
162+ reply->length = length,
163+ reply->received = 0,
164+ reinit_completion(&reply->done);
165+
166+ qnap_mcu_write(mcu, cmd_data, cmd_data_size);
167+
168+ serdev_device_wait_until_sent(mcu->serdev, msecs_to_jiffies(QNAP_MCU_TIMEOUT_MS));
169+
170+ if (!wait_for_completion_timeout(&reply->done, msecs_to_jiffies(QNAP_MCU_TIMEOUT_MS))) {
171+ dev_err(&mcu->serdev->dev, "Command timeout\n");
172+ ret = -ETIMEDOUT;
173+ } else {
174+ u8 crc = qnap_mcu_csum(rx, reply_data_size);
175+
176+ if (crc != rx[reply_data_size]) {
177+ dev_err(&mcu->serdev->dev,
178+ "Invalid Checksum received\n");
179+ ret = -EIO;
180+ } else {
181+ memcpy(reply_data, rx, reply_data_size);
182+ }
183+ }
184+
185+ mutex_unlock(&mcu->bus_lock);
186+ return ret;
187+}
188+EXPORT_SYMBOL_GPL(qnap_mcu_exec);
189+
190+int qnap_mcu_exec_with_ack(struct qnap_mcu *mcu,
191+ const u8 *cmd_data, size_t cmd_data_size)
192+{
193+ u8 ack[QNAP_MCU_ACK_LEN];
194+ int ret;
195+
196+ ret = qnap_mcu_exec(mcu, cmd_data, cmd_data_size, ack, sizeof(ack));
197+ if (ret)
198+ return ret;
199+
200+ /* Should return @0 */
201+ if (ack[0] != '@' || ack[1] != '0') {
202+ dev_err(&mcu->serdev->dev, "Did not receive ack\n");
203+ return -EIO;
204+ }
205+
206+ return 0;
207+}
208+EXPORT_SYMBOL_GPL(qnap_mcu_exec_with_ack);
209+
210+static int qnap_mcu_get_version(struct qnap_mcu *mcu)
211+{
212+ const u8 cmd[] = { '%', 'V' };
213+ u8 rx[14];
214+ int ret;
215+
216+ /* Reply is the 2 command-bytes + 4 bytes describing the version */
217+ ret = qnap_mcu_exec(mcu, cmd, sizeof(cmd), rx, QNAP_MCU_VERSION_LEN + 2);
218+ if (ret)
219+ return ret;
220+
221+ memcpy(mcu->version, &rx[2], QNAP_MCU_VERSION_LEN);
222+
223+ return 0;
224+}
225+
226+/*
227+ * The MCU controls power to the peripherals but not the CPU.
228+ *
229+ * So using the PMIC to power off the system keeps the MCU and hard-drives
230+ * running. This also then prevents the system from turning back on until
231+ * the MCU is turned off by unplugging the power cable.
232+ * Turning off the MCU alone on the other hand turns off the hard drives,
233+ * LEDs, etc while the main SoC stays running - including its network ports.
234+ */
235+static int qnap_mcu_power_off(struct sys_off_data *data)
236+{
237+ const u8 cmd[] = { '@', 'C', '0' };
238+ struct qnap_mcu *mcu = data->cb_data;
239+ int ret;
240+
241+ ret = qnap_mcu_exec_with_ack(mcu, cmd, sizeof(cmd));
242+ if (ret) {
243+ dev_err(&mcu->serdev->dev, "MCU poweroff failed %d\n", ret);
244+ return NOTIFY_STOP;
245+ }
246+
247+ return NOTIFY_DONE;
248+}
249+
250+static const struct qnap_mcu_variant qnap_ts433_mcu = {
251+ .baud_rate = 115200,
252+ .num_drives = 4,
253+ .fan_pwm_min = 51, /* Specified in original model.conf */
254+ .fan_pwm_max = 255,
255+ .usb_led = true,
256+};
257+
258+static struct mfd_cell qnap_mcu_cells[] = {
259+ { .name = "qnap-mcu-input", },
260+ { .name = "qnap-mcu-leds", },
261+ { .name = "qnap-mcu-hwmon", }
262+};
263+
264+static int qnap_mcu_probe(struct serdev_device *serdev)
265+{
266+ struct device *dev = &serdev->dev;
267+ struct qnap_mcu *mcu;
268+ int ret;
269+
270+ mcu = devm_kzalloc(dev, sizeof(*mcu), GFP_KERNEL);
271+ if (!mcu)
272+ return -ENOMEM;
273+
274+ mcu->serdev = serdev;
275+ dev_set_drvdata(dev, mcu);
276+
277+ mcu->variant = of_device_get_match_data(dev);
278+ if (!mcu->variant)
279+ return -ENODEV;
280+
281+ mutex_init(&mcu->bus_lock);
282+ init_completion(&mcu->reply.done);
283+
284+ serdev_device_set_client_ops(serdev, &qnap_mcu_serdev_device_ops);
285+ ret = devm_serdev_device_open(dev, serdev);
286+ if (ret)
287+ return ret;
288+
289+ serdev_device_set_baudrate(serdev, mcu->variant->baud_rate);
290+ serdev_device_set_flow_control(serdev, false);
291+
292+ ret = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE);
293+ if (ret)
294+ return dev_err_probe(dev, ret, "Failed to set parity\n");
295+
296+ ret = qnap_mcu_get_version(mcu);
297+ if (ret)
298+ return ret;
299+
300+ ret = devm_register_sys_off_handler(dev,
301+ SYS_OFF_MODE_POWER_OFF_PREPARE,
302+ SYS_OFF_PRIO_DEFAULT,
303+ &qnap_mcu_power_off, mcu);
304+ if (ret)
305+ return dev_err_probe(dev, ret,
306+ "Failed to register poweroff handler\n");
307+
308+ for (int i = 0; i < ARRAY_SIZE(qnap_mcu_cells); i++) {
309+ qnap_mcu_cells[i].platform_data = mcu->variant;
310+ qnap_mcu_cells[i].pdata_size = sizeof(*mcu->variant);
311+ }
312+
313+ ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, qnap_mcu_cells,
314+ ARRAY_SIZE(qnap_mcu_cells), NULL, 0, NULL);
315+ if (ret)
316+ return dev_err_probe(dev, ret, "Failed to add child devices\n");
317+
318+ return 0;
319+}
320+
321+static const struct of_device_id qnap_mcu_dt_ids[] = {
322+ { .compatible = "qnap,ts433-mcu", .data = &qnap_ts433_mcu },
323+ { /* sentinel */ }
324+};
325+MODULE_DEVICE_TABLE(of, qnap_mcu_dt_ids);
326+
327+static struct serdev_device_driver qnap_mcu_drv = {
328+ .probe = qnap_mcu_probe,
329+ .driver = {
330+ .name = "qnap-mcu",
331+ .of_match_table = qnap_mcu_dt_ids,
332+ },
333+};
334+module_serdev_device_driver(qnap_mcu_drv);
335+
336+MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
337+MODULE_DESCRIPTION("QNAP MCU core driver");
338+MODULE_LICENSE("GPL");
drivers/mfd/stpmic1.c+1−5
@@ -170,11 +170,7 @@ static int stpmic1_probe(struct i2c_client *i2c) · 169 unmodified lines
170170 return ret;
171171 }
172172
173− ret = devm_register_sys_off_handler(ddata->dev,
174− SYS_OFF_MODE_POWER_OFF,
175− SYS_OFF_PRIO_DEFAULT,
176− stpmic1_power_off,
177− ddata);
173+ ret = devm_register_power_off_handler(ddata->dev, stpmic1_power_off, ddata);
178174 if (ret) {
179175 dev_err(ddata->dev, "failed to register sys-off handler: %d\n", ret);
180176 return ret;
drivers/mfd/syscon.c+15−80
@@ -12,22 +12,16 @@ · 11 unmodified lines
1212 #include <linux/clk.h>
1313 #include <linux/err.h>
1414 #include <linux/hwspinlock.h>
15−#include <linux/io.h>
16−#include <linux/init.h>
1715 #include <linux/list.h>
16+#include <linux/mutex.h>
1817 #include <linux/of.h>
1918 #include <linux/of_address.h>
20−#include <linux/of_platform.h>
21−#include <linux/platform_data/syscon.h>
22−#include <linux/platform_device.h>
2319 #include <linux/regmap.h>
2420 #include <linux/reset.h>
2521 #include <linux/mfd/syscon.h>
2622 #include <linux/slab.h>
2723
28−static struct platform_driver syscon_driver;
29−
30−static DEFINE_SPINLOCK(syscon_list_slock);
24+static DEFINE_MUTEX(syscon_list_lock);
3125 static LIST_HEAD(syscon_list);
3226
3327 struct syscon {
@@ -54,6 +48,8 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_res) · 20 unmodified lines
5448 struct resource res;
5549 struct reset_control *reset;
5650
51+ WARN_ON(!mutex_is_locked(&syscon_list_lock));
52+
5753 struct syscon *syscon __free(kfree) = kzalloc(sizeof(*syscon), GFP_KERNEL);
5854 if (!syscon)
5955 return ERR_PTR(-ENOMEM);
@@ -146,9 +142,7 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_res) · 86 unmodified lines
146142 syscon->regmap = regmap;
147143 syscon->np = np;
148144
149− spin_lock(&syscon_list_slock);
150145 list_add_tail(&syscon->list, &syscon_list);
151− spin_unlock(&syscon_list_slock);
152146
153147 return_ptr(syscon);
154148
@@ -169,7 +163,7 @@ static struct regmap *device_node_get_regmap(struct device_node *np, · 14 unmodified lines
169163 {
170164 struct syscon *entry, *syscon = NULL;
171165
172− spin_lock(&syscon_list_slock);
166+ mutex_lock(&syscon_list_lock);
173167
174168 list_for_each_entry(entry, &syscon_list, list)
175169 if (entry->np == np) {
@@ -177,10 +171,13 @@ static struct regmap *device_node_get_regmap(struct device_node *np, · 1 unmodified line
177171 break;
178172 }
179173
180− spin_unlock(&syscon_list_slock);
181−
182− if (!syscon)
183− syscon = of_syscon_register(np, check_res);
174+ if (!syscon) {
175+ if (of_device_is_compatible(np, "syscon"))
176+ syscon = of_syscon_register(np, check_res);
177+ else
178+ syscon = ERR_PTR(-EINVAL);
179+ }
180+ mutex_unlock(&syscon_list_lock);
184181
185182 if (IS_ERR(syscon))
186183 return ERR_CAST(syscon);
@@ -212,7 +209,7 @@ int of_syscon_register_regmap(struct device_node *np, struct regmap *regmap) · 25 unmodified lines
212209 return -ENOMEM;
213210
214211 /* check if syscon entry already exists */
215− spin_lock(&syscon_list_slock);
212+ mutex_lock(&syscon_list_lock);
216213
217214 list_for_each_entry(entry, &syscon_list, list)
218215 if (entry->np == np) {
@@ -225,12 +222,12 @@ int of_syscon_register_regmap(struct device_node *np, struct regmap *regmap) · 6 unmodified lines
225222
226223 /* register the regmap in syscon list */
227224 list_add_tail(&syscon->list, &syscon_list);
228− spin_unlock(&syscon_list_slock);
225+ mutex_unlock(&syscon_list_lock);
229226
230227 return 0;
231228
232229 err_unlock:
233− spin_unlock(&syscon_list_slock);
230+ mutex_unlock(&syscon_list_lock);
234231 kfree(syscon);
235232 return ret;
236233 }
@@ -244,9 +241,6 @@ EXPORT_SYMBOL_GPL(device_node_to_regmap); · 7 unmodified lines
244241
245242 struct regmap *syscon_node_to_regmap(struct device_node *np)
246243 {
247− if (!of_device_is_compatible(np, "syscon"))
248− return ERR_PTR(-EINVAL);
249−
250244 return device_node_get_regmap(np, true);
251245 }
252246 EXPORT_SYMBOL_GPL(syscon_node_to_regmap);
@@ -336,62 +330,3 @@ struct regmap *syscon_regmap_lookup_by_phandle_optional(struct device_node *np, · 83 unmodified lines
336330 return regmap;
337331 }
338332 EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle_optional);
339−
340−static int syscon_probe(struct platform_device *pdev)
341−{
342− struct device *dev = &pdev->dev;
343− struct syscon_platform_data *pdata = dev_get_platdata(dev);
344− struct syscon *syscon;
345− struct regmap_config syscon_config = syscon_regmap_config;
346− struct resource *res;
347− void __iomem *base;
348−
349− syscon = devm_kzalloc(dev, sizeof(*syscon), GFP_KERNEL);
350− if (!syscon)
351− return -ENOMEM;
352−
353− res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
354− if (!res)
355− return -ENOENT;
356−
357− base = devm_ioremap(dev, res->start, resource_size(res));
358− if (!base)
359− return -ENOMEM;
360−
361− syscon_config.max_register = resource_size(res) - 4;
362− if (!syscon_config.max_register)
363− syscon_config.max_register_is_0 = true;
364−
365− if (pdata)
366− syscon_config.name = pdata->label;
367− syscon->regmap = devm_regmap_init_mmio(dev, base, &syscon_config);
368− if (IS_ERR(syscon->regmap)) {
369− dev_err(dev, "regmap init failed\n");
370− return PTR_ERR(syscon->regmap);
371− }
372−
373− platform_set_drvdata(pdev, syscon);
374−
375− dev_dbg(dev, "regmap %pR registered\n", res);
376−
377− return 0;
378−}
379−
380−static const struct platform_device_id syscon_ids[] = {
381− { "syscon", },
382− { }
383−};
384−
385−static struct platform_driver syscon_driver = {
386− .driver = {
387− .name = "syscon",
388− },
389− .probe = syscon_probe,
390− .id_table = syscon_ids,
391−};
392−
393−static int __init syscon_init(void)
394−{
395− return platform_driver_register(&syscon_driver);
396−}
397−postcore_initcall(syscon_init);
drivers/mfd/tps65219.c+4−11
@@ -110,19 +110,12 @@ static const struct resource tps65219_regulator_resources[] = { · 109 unmodified lines
110110 };
111111
112112 static const struct mfd_cell tps65219_cells[] = {
113− {
114− .name = "tps65219-regulator",
115− .resources = tps65219_regulator_resources,
116− .num_resources = ARRAY_SIZE(tps65219_regulator_resources),
117− },
118− { .name = "tps65219-gpio", },
113+ MFD_CELL_RES("tps65219-regulator", tps65219_regulator_resources),
114+ MFD_CELL_NAME("tps65219-gpio"),
119115 };
120116
121−static const struct mfd_cell tps65219_pwrbutton_cell = {
122− .name = "tps65219-pwrbutton",
123− .resources = tps65219_pwrbutton_resources,
124− .num_resources = ARRAY_SIZE(tps65219_pwrbutton_resources),
125−};
117+static const struct mfd_cell tps65219_pwrbutton_cell =
118+ MFD_CELL_RES("tps65219-pwrbutton", tps65219_pwrbutton_resources);
126119
127120 static const struct regmap_config tps65219_regmap_config = {
128121 .reg_bits = 8,
drivers/mfd/upboard-fpga.c+325−0
@@ -0,0 +1,325 @@
1+// SPDX-License-Identifier: GPL-2.0-only
2+/*
3+ * UP Board FPGA driver.
4+ *
5+ * FPGA provides more GPIO driving power, LEDS and pin mux function.
6+ *
7+ * Copyright (c) AAEON. All rights reserved.
8+ * Copyright (C) 2024 Bootlin
9+ *
10+ * Author: Gary Wang <garywang@aaeon.com.tw>
11+ * Author: Thomas Richard <thomas.richard@bootlin.com>
12+ */
13+
14+#include <linux/acpi.h>
15+#include <linux/bitfield.h>
16+#include <linux/device.h>
17+#include <linux/err.h>
18+#include <linux/gpio/consumer.h>
19+#include <linux/mfd/core.h>
20+#include <linux/mfd/upboard-fpga.h>
21+#include <linux/module.h>
22+#include <linux/mod_devicetable.h>
23+#include <linux/platform_device.h>
24+#include <linux/property.h>
25+#include <linux/regmap.h>
26+#include <linux/sysfs.h>
27+
28+#define UPBOARD_AAEON_MANUFACTURER_ID 0x01
29+#define UPBOARD_MANUFACTURER_ID_MASK GENMASK(7, 0)
30+
31+#define UPBOARD_ADDRESS_SIZE 7
32+#define UPBOARD_REGISTER_SIZE 16
33+
34+#define UPBOARD_READ_FLAG BIT(UPBOARD_ADDRESS_SIZE)
35+
36+#define UPBOARD_FW_ID_MAJOR_SUPPORTED 0x0
37+
38+#define UPBOARD_FW_ID_BUILD_MASK GENMASK(15, 12)
39+#define UPBOARD_FW_ID_MAJOR_MASK GENMASK(11, 8)
40+#define UPBOARD_FW_ID_MINOR_MASK GENMASK(7, 4)
41+#define UPBOARD_FW_ID_PATCH_MASK GENMASK(3, 0)
42+
43+static int upboard_fpga_read(void *context, unsigned int reg, unsigned int *val)
44+{
45+ struct upboard_fpga *fpga = context;
46+ int i;
47+
48+ /* Clear to start new transaction */
49+ gpiod_set_value(fpga->clear_gpio, 0);
50+ gpiod_set_value(fpga->clear_gpio, 1);
51+
52+ reg |= UPBOARD_READ_FLAG;
53+
54+ /* Send clock and addr from strobe & datain pins */
55+ for (i = UPBOARD_ADDRESS_SIZE; i >= 0; i--) {
56+ gpiod_set_value(fpga->strobe_gpio, 0);
57+ gpiod_set_value(fpga->datain_gpio, !!(reg & BIT(i)));
58+ gpiod_set_value(fpga->strobe_gpio, 1);
59+ }
60+
61+ gpiod_set_value(fpga->strobe_gpio, 0);
62+ *val = 0;
63+
64+ /* Read data from dataout pin */
65+ for (i = UPBOARD_REGISTER_SIZE - 1; i >= 0; i--) {
66+ gpiod_set_value(fpga->strobe_gpio, 1);
67+ gpiod_set_value(fpga->strobe_gpio, 0);
68+ *val |= gpiod_get_value(fpga->dataout_gpio) << i;
69+ }
70+
71+ gpiod_set_value(fpga->strobe_gpio, 1);
72+
73+ return 0;
74+}
75+
76+static int upboard_fpga_write(void *context, unsigned int reg, unsigned int val)
77+{
78+ struct upboard_fpga *fpga = context;
79+ int i;
80+
81+ /* Clear to start new transcation */
82+ gpiod_set_value(fpga->clear_gpio, 0);
83+ gpiod_set_value(fpga->clear_gpio, 1);
84+
85+ /* Send clock and addr from strobe & datain pins */
86+ for (i = UPBOARD_ADDRESS_SIZE; i >= 0; i--) {
87+ gpiod_set_value(fpga->strobe_gpio, 0);
88+ gpiod_set_value(fpga->datain_gpio, !!(reg & BIT(i)));
89+ gpiod_set_value(fpga->strobe_gpio, 1);
90+ }
91+
92+ gpiod_set_value(fpga->strobe_gpio, 0);
93+
94+ /* Write data to datain pin */
95+ for (i = UPBOARD_REGISTER_SIZE - 1; i >= 0; i--) {
96+ gpiod_set_value(fpga->datain_gpio, !!(val & BIT(i)));
97+ gpiod_set_value(fpga->strobe_gpio, 1);
98+ gpiod_set_value(fpga->strobe_gpio, 0);
99+ }
100+
101+ gpiod_set_value(fpga->strobe_gpio, 1);
102+
103+ return 0;
104+}
105+
106+static const struct regmap_range upboard_up_readable_ranges[] = {
107+ regmap_reg_range(UPBOARD_REG_PLATFORM_ID, UPBOARD_REG_FIRMWARE_ID),
108+ regmap_reg_range(UPBOARD_REG_FUNC_EN0, UPBOARD_REG_FUNC_EN0),
109+ regmap_reg_range(UPBOARD_REG_GPIO_EN0, UPBOARD_REG_GPIO_EN1),
110+ regmap_reg_range(UPBOARD_REG_GPIO_DIR0, UPBOARD_REG_GPIO_DIR1),
111+};
112+
113+static const struct regmap_range upboard_up_writable_ranges[] = {
114+ regmap_reg_range(UPBOARD_REG_FUNC_EN0, UPBOARD_REG_FUNC_EN0),
115+ regmap_reg_range(UPBOARD_REG_GPIO_EN0, UPBOARD_REG_GPIO_EN1),
116+ regmap_reg_range(UPBOARD_REG_GPIO_DIR0, UPBOARD_REG_GPIO_DIR1),
117+};
118+
119+static const struct regmap_access_table upboard_up_readable_table = {
120+ .yes_ranges = upboard_up_readable_ranges,
121+ .n_yes_ranges = ARRAY_SIZE(upboard_up_readable_ranges),
122+};
123+
124+static const struct regmap_access_table upboard_up_writable_table = {
125+ .yes_ranges = upboard_up_writable_ranges,
126+ .n_yes_ranges = ARRAY_SIZE(upboard_up_writable_ranges),
127+};
128+
129+static const struct regmap_config upboard_up_regmap_config = {
130+ .reg_bits = UPBOARD_ADDRESS_SIZE,
131+ .val_bits = UPBOARD_REGISTER_SIZE,
132+ .max_register = UPBOARD_REG_MAX,
133+ .reg_read = upboard_fpga_read,
134+ .reg_write = upboard_fpga_write,
135+ .fast_io = false,
136+ .cache_type = REGCACHE_NONE,
137+ .rd_table = &upboard_up_readable_table,
138+ .wr_table = &upboard_up_writable_table,
139+};
140+
141+static const struct regmap_range upboard_up2_readable_ranges[] = {
142+ regmap_reg_range(UPBOARD_REG_PLATFORM_ID, UPBOARD_REG_FIRMWARE_ID),
143+ regmap_reg_range(UPBOARD_REG_FUNC_EN0, UPBOARD_REG_FUNC_EN1),
144+ regmap_reg_range(UPBOARD_REG_GPIO_EN0, UPBOARD_REG_GPIO_EN2),
145+ regmap_reg_range(UPBOARD_REG_GPIO_DIR0, UPBOARD_REG_GPIO_DIR2),
146+};
147+
148+static const struct regmap_range upboard_up2_writable_ranges[] = {
149+ regmap_reg_range(UPBOARD_REG_FUNC_EN0, UPBOARD_REG_FUNC_EN1),
150+ regmap_reg_range(UPBOARD_REG_GPIO_EN0, UPBOARD_REG_GPIO_EN2),
151+ regmap_reg_range(UPBOARD_REG_GPIO_DIR0, UPBOARD_REG_GPIO_DIR2),
152+};
153+
154+static const struct regmap_access_table upboard_up2_readable_table = {
155+ .yes_ranges = upboard_up2_readable_ranges,
156+ .n_yes_ranges = ARRAY_SIZE(upboard_up2_readable_ranges),
157+};
158+
159+static const struct regmap_access_table upboard_up2_writable_table = {
160+ .yes_ranges = upboard_up2_writable_ranges,
161+ .n_yes_ranges = ARRAY_SIZE(upboard_up2_writable_ranges),
162+};
163+
164+static const struct regmap_config upboard_up2_regmap_config = {
165+ .reg_bits = UPBOARD_ADDRESS_SIZE,
166+ .val_bits = UPBOARD_REGISTER_SIZE,
167+ .max_register = UPBOARD_REG_MAX,
168+ .reg_read = upboard_fpga_read,
169+ .reg_write = upboard_fpga_write,
170+ .fast_io = false,
171+ .cache_type = REGCACHE_NONE,
172+ .rd_table = &upboard_up2_readable_table,
173+ .wr_table = &upboard_up2_writable_table,
174+};
175+
176+static const struct mfd_cell upboard_up_mfd_cells[] = {
177+ { .name = "upboard-pinctrl" },
178+ { .name = "upboard-leds" },
179+};
180+
181+static const struct upboard_fpga_data upboard_up_fpga_data = {
182+ .type = UPBOARD_UP_FPGA,
183+ .regmap_config = &upboard_up_regmap_config,
184+};
185+
186+static const struct upboard_fpga_data upboard_up2_fpga_data = {
187+ .type = UPBOARD_UP2_FPGA,
188+ .regmap_config = &upboard_up2_regmap_config,
189+};
190+
191+static int upboard_fpga_gpio_init(struct upboard_fpga *fpga)
192+{
193+ fpga->enable_gpio = devm_gpiod_get(fpga->dev, "enable", GPIOD_ASIS);
194+ if (IS_ERR(fpga->enable_gpio))
195+ return PTR_ERR(fpga->enable_gpio);
196+
197+ fpga->clear_gpio = devm_gpiod_get(fpga->dev, "clear", GPIOD_OUT_LOW);
198+ if (IS_ERR(fpga->clear_gpio))
199+ return PTR_ERR(fpga->clear_gpio);
200+
201+ fpga->strobe_gpio = devm_gpiod_get(fpga->dev, "strobe", GPIOD_OUT_LOW);
202+ if (IS_ERR(fpga->strobe_gpio))
203+ return PTR_ERR(fpga->strobe_gpio);
204+
205+ fpga->datain_gpio = devm_gpiod_get(fpga->dev, "datain", GPIOD_OUT_LOW);
206+ if (IS_ERR(fpga->datain_gpio))
207+ return PTR_ERR(fpga->datain_gpio);
208+
209+ fpga->dataout_gpio = devm_gpiod_get(fpga->dev, "dataout", GPIOD_IN);
210+ if (IS_ERR(fpga->dataout_gpio))
211+ return PTR_ERR(fpga->dataout_gpio);
212+
213+ gpiod_set_value(fpga->enable_gpio, 1);
214+
215+ return 0;
216+}
217+
218+static int upboard_fpga_get_firmware_version(struct upboard_fpga *fpga)
219+{
220+ unsigned int platform_id, manufacturer_id;
221+ int ret;
222+
223+ if (!fpga)
224+ return -ENOMEM;
225+
226+ ret = regmap_read(fpga->regmap, UPBOARD_REG_PLATFORM_ID, &platform_id);
227+ if (ret)
228+ return ret;
229+
230+ manufacturer_id = platform_id & UPBOARD_MANUFACTURER_ID_MASK;
231+ if (manufacturer_id != UPBOARD_AAEON_MANUFACTURER_ID)
232+ return dev_err_probe(fpga->dev, -ENODEV,
233+ "driver not compatible with custom FPGA FW from manufacturer id %#02x.",
234+ manufacturer_id);
235+
236+ ret = regmap_read(fpga->regmap, UPBOARD_REG_FIRMWARE_ID, &fpga->firmware_version);
237+ if (ret)
238+ return ret;
239+
240+ if (FIELD_GET(UPBOARD_FW_ID_MAJOR_MASK, fpga->firmware_version) !=
241+ UPBOARD_FW_ID_MAJOR_SUPPORTED)
242+ return dev_err_probe(fpga->dev, -ENODEV,
243+ "unsupported FPGA FW v%lu.%lu.%lu build %#02lx",
244+ FIELD_GET(UPBOARD_FW_ID_MAJOR_MASK, fpga->firmware_version),
245+ FIELD_GET(UPBOARD_FW_ID_MINOR_MASK, fpga->firmware_version),
246+ FIELD_GET(UPBOARD_FW_ID_PATCH_MASK, fpga->firmware_version),
247+ FIELD_GET(UPBOARD_FW_ID_BUILD_MASK, fpga->firmware_version));
248+ return 0;
249+}
250+
251+static ssize_t upboard_fpga_version_show(struct device *dev, struct device_attribute *attr,
252+ char *buf)
253+{
254+ struct upboard_fpga *fpga = dev_get_drvdata(dev);
255+
256+ return sysfs_emit(buf, "FPGA FW v%lu.%lu.%lu build %#02lx\n",
257+ FIELD_GET(UPBOARD_FW_ID_MAJOR_MASK, fpga->firmware_version),
258+ FIELD_GET(UPBOARD_FW_ID_MINOR_MASK, fpga->firmware_version),
259+ FIELD_GET(UPBOARD_FW_ID_PATCH_MASK, fpga->firmware_version),
260+ FIELD_GET(UPBOARD_FW_ID_BUILD_MASK, fpga->firmware_version));
261+}
262+
263+static DEVICE_ATTR_RO(upboard_fpga_version);
264+
265+static struct attribute *upboard_fpga_attrs[] = {
266+ &dev_attr_upboard_fpga_version.attr,
267+ NULL
268+};
269+
270+ATTRIBUTE_GROUPS(upboard_fpga);
271+
272+static int upboard_fpga_probe(struct platform_device *pdev)
273+{
274+ struct device *dev = &pdev->dev;
275+ struct upboard_fpga *fpga;
276+ int ret;
277+
278+ fpga = devm_kzalloc(dev, sizeof(*fpga), GFP_KERNEL);
279+ if (!fpga)
280+ return -ENOMEM;
281+
282+ fpga->fpga_data = device_get_match_data(dev);
283+
284+ fpga->dev = dev;
285+
286+ platform_set_drvdata(pdev, fpga);
287+
288+ fpga->regmap = devm_regmap_init(dev, NULL, fpga, fpga->fpga_data->regmap_config);
289+ if (IS_ERR(fpga->regmap))
290+ return PTR_ERR(fpga->regmap);
291+
292+ ret = upboard_fpga_gpio_init(fpga);
293+ if (ret)
294+ return dev_err_probe(dev, ret, "Failed to initialize FPGA common GPIOs");
295+
296+ ret = upboard_fpga_get_firmware_version(fpga);
297+ if (ret)
298+ return ret;
299+
300+ return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, upboard_up_mfd_cells,
301+ ARRAY_SIZE(upboard_up_mfd_cells), NULL, 0, NULL);
302+}
303+
304+static const struct acpi_device_id upboard_fpga_acpi_match[] = {
305+ { "AANT0F01", (kernel_ulong_t)&upboard_up2_fpga_data },
306+ { "AANT0F04", (kernel_ulong_t)&upboard_up_fpga_data },
307+ {}
308+};
309+MODULE_DEVICE_TABLE(acpi, upboard_fpga_acpi_match);
310+
311+static struct platform_driver upboard_fpga_driver = {
312+ .driver = {
313+ .name = "upboard-fpga",
314+ .acpi_match_table = ACPI_PTR(upboard_fpga_acpi_match),
315+ .dev_groups = upboard_fpga_groups,
316+ },
317+ .probe = upboard_fpga_probe,
318+};
319+
320+module_platform_driver(upboard_fpga_driver);
321+
322+MODULE_AUTHOR("Gary Wang <garywang@aaeon.com.tw>");
323+MODULE_AUTHOR("Thomas Richard <thomas.richard@bootlin.com>");
324+MODULE_DESCRIPTION("UP Board FPGA driver");
325+MODULE_LICENSE("GPL");
drivers/mfd/vexpress-sysreg.c+0−1
@@ -10,7 +10,6 @@ · 9 unmodified lines
1010 #include <linux/mfd/core.h>
1111 #include <linux/module.h>
1212 #include <linux/of_platform.h>
13−#include <linux/platform_data/syscon.h>
1413 #include <linux/platform_device.h>
1514 #include <linux/slab.h>
1615 #include <linux/stat.h>
include/linux/mfd/core.h+1−1
@@ -72,7 +72,7 @@ struct mfd_cell { · 71 unmodified lines
7272 int (*resume)(struct platform_device *dev);
7373
7474 /* platform data passed to the sub devices drivers */
75− void *platform_data;
75+ const void *platform_data;
7676 size_t pdata_size;
7777
7878 /* Matches ACPI */
include/linux/mfd/da9052/da9052.h+2−0
@@ -93,6 +93,8 @@ struct da9052 { · 92 unmodified lines
9393
9494 int chip_irq;
9595
96+ int fault_log;
97+
9698 /* SOC I/O transfer related fixes for DA9052/53 */
9799 int (*fix_io) (struct da9052 *da9052, unsigned char reg);
98100 };
include/linux/mfd/qnap-mcu.h+26−0
@@ -0,0 +1,26 @@
1+/* SPDX-License-Identifier: GPL-2.0+ */
2+/*
3+ * Core definitions for QNAP MCU MFD driver.
4+ * Copyright (C) 2024 Heiko Stuebner <heiko@sntech.de>
5+ */
6+
7+#ifndef _LINUX_QNAP_MCU_H_
8+#define _LINUX_QNAP_MCU_H_
9+
10+struct qnap_mcu;
11+
12+struct qnap_mcu_variant {
13+ u32 baud_rate;
14+ int num_drives;
15+ int fan_pwm_min;
16+ int fan_pwm_max;
17+ bool usb_led;
18+};
19+
20+int qnap_mcu_exec(struct qnap_mcu *mcu,
21+ const u8 *cmd_data, size_t cmd_data_size,
22+ u8 *reply_data, size_t reply_data_size);
23+int qnap_mcu_exec_with_ack(struct qnap_mcu *mcu,
24+ const u8 *cmd_data, size_t cmd_data_size);
25+
26+#endif /* _LINUX_QNAP_MCU_H_ */
include/linux/mfd/tps65219.h+1−6
@@ -10,14 +10,9 @@ · 9 unmodified lines
1010
1111 #include <linux/bitops.h>
1212 #include <linux/notifier.h>
13+#include <linux/regmap.h>
1314 #include <linux/regulator/driver.h>
1415
15−struct regmap;
16−struct regmap_irq_chip_data;
17−
18−#define TPS65219_1V35 1350000
19−#define TPS65219_1V8 1800000
20−
2116 /* TPS chip id list */
2217 #define TPS65219 0xF0
2318
include/linux/mfd/upboard-fpga.h+55−0
@@ -0,0 +1,55 @@
1+/* SPDX-License-Identifier: GPL-2.0-only */
2+/*
3+ * UP Board CPLD/FPGA driver
4+ *
5+ * Copyright (c) AAEON. All rights reserved.
6+ * Copyright (C) 2024 Bootlin
7+ *
8+ * Author: Gary Wang <garywang@aaeon.com.tw>
9+ * Author: Thomas Richard <thomas.richard@bootlin.com>
10+ *
11+ */
12+
13+#ifndef __LINUX_MFD_UPBOARD_FPGA_H
14+#define __LINUX_MFD_UPBOARD_FPGA_H
15+
16+#define UPBOARD_REGISTER_SIZE 16
17+
18+enum upboard_fpgareg {
19+ UPBOARD_REG_PLATFORM_ID = 0x10,
20+ UPBOARD_REG_FIRMWARE_ID = 0x11,
21+ UPBOARD_REG_FUNC_EN0 = 0x20,
22+ UPBOARD_REG_FUNC_EN1 = 0x21,
23+ UPBOARD_REG_GPIO_EN0 = 0x30,
24+ UPBOARD_REG_GPIO_EN1 = 0x31,
25+ UPBOARD_REG_GPIO_EN2 = 0x32,
26+ UPBOARD_REG_GPIO_DIR0 = 0x40,
27+ UPBOARD_REG_GPIO_DIR1 = 0x41,
28+ UPBOARD_REG_GPIO_DIR2 = 0x42,
29+ UPBOARD_REG_MAX,
30+};
31+
32+enum upboard_fpga_type {
33+ UPBOARD_UP_FPGA,
34+ UPBOARD_UP2_FPGA,
35+};
36+
37+struct upboard_fpga_data {
38+ enum upboard_fpga_type type;
39+ const struct regmap_config *regmap_config;
40+};
41+
42+struct upboard_fpga {
43+ struct device *dev;
44+ struct regmap *regmap;
45+ struct gpio_desc *enable_gpio;
46+ struct gpio_desc *reset_gpio;
47+ struct gpio_desc *clear_gpio;
48+ struct gpio_desc *strobe_gpio;
49+ struct gpio_desc *datain_gpio;
50+ struct gpio_desc *dataout_gpio;
51+ unsigned int firmware_version;
52+ const struct upboard_fpga_data *fpga_data;
53+};
54+
55+#endif /* __LINUX_MFD_UPBOARD_FPGA_H */
include/linux/platform_data/syscon.h+0−9
@@ -1,9 +0,0 @@
1−/* SPDX-License-Identifier: GPL-2.0 */
2−#ifndef PLATFORM_DATA_SYSCON_H
3−#define PLATFORM_DATA_SYSCON_H
4−
5−struct syscon_platform_data {
6− const char *label;
7−};
8−
9−#endif

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t