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
7title: ST LED1202 LED controllers
8
9maintainers:
10 - Vicentiu Galanopulo <vicentiu.galanopulo@remote-tech.co.uk>
11
12description: |
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
19properties:
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
32patternProperties:
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
46required:
47 - compatible
48 - reg
49 - "#address-cells"
50 - "#size-cells"
51
52additionalProperties: false
53
54examples:
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
7title: Microchip AT91 General Purpose Backup Registers
8
9maintainers:
10 - Nicolas Ferre <nicolas.ferre@microchip.com>
11
12description:
13 The system controller embeds 256 bits of General Purpose Backup
14 registers organized as 8 32-bit registers.
15
16properties:
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
33required:
34 - compatible
35 - reg
36
37additionalProperties: false
38
39examples:
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
7title: Microchip AT91 Bus Matrix
8
9maintainers:
10 - Nicolas Ferre <nicolas.ferre@microchip.com>
11
12description:
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
17properties:
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
41required:
42 - compatible
43 - reg
44
45additionalProperties: false
46
47examples:
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
3The GPBR are a set of battery-backed registers.
4
5Required 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
13Example:
14
15gpbr: 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
3The Bus Matrix registers are used to configure Atmel SoCs internal bus
4behavior (master/slave priorities, undefined burst length type, ...)
5
6Required 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
21Example:
22
23matrix: 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
42 - qcom,tcsr-apq806442 - qcom,tcsr-apq8064
43 - qcom,tcsr-apq808443 - qcom,tcsr-apq8084
44 - qcom,tcsr-ipq533244 - qcom,tcsr-ipq5332
45 - qcom,tcsr-ipq5424
45 - qcom,tcsr-ipq601846 - qcom,tcsr-ipq6018
46 - qcom,tcsr-ipq806447 - qcom,tcsr-ipq8064
47 - qcom,tcsr-ipq807448 - 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
7title: QNAP NAS on-board Microcontroller
8
9maintainers:
10 - Heiko Stuebner <heiko@sntech.de>
11
12description:
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
16properties:
17 compatible:
18 enum:
19 - qnap,ts433-mcu
20
21patternProperties:
22 "^fan-[0-9]+$":
23 $ref: /schemas/hwmon/fan-common.yaml#
24 unevaluatedProperties: false
25
26required:
27 - compatible
28
29additionalProperties: false
30
31examples:
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
50 minimum: 050 minimum: 0
51 maximum: 151 maximum: 1
52 52
53 rohm,charger-sense-resistor-ohms:53 rohm,charger-sense-resistor-micro-ohms:
54 minimum: 1000000054 minimum: 10000
55 maximum: 5000000055 maximum: 50000
56 description: |56 description: |
57 BD71827 and BD71828 have SAR ADC for measuring charging currents.57 BD71815 has SAR ADC for measuring charging currents. External sense
58 External sense resistor (RSENSE in data sheet) should be used. If58 resistor (RSENSE in data sheet) should be used. If something other
59 something other but 30MOhm resistor is used the resistance value59 but a 30 mOhm resistor is used the resistance value should be given
60 should be given here in Ohms.60 here in micro Ohms.
61 default: 3000000061 default: 30000
62 62
63 regulators:63 regulators:
64 $ref: /schemas/regulator/rohm,bd71815-regulator.yaml64 $ref: /schemas/regulator/rohm,bd71815-regulator.yaml
@@ -67,7 +67,7 @@ properties: · 2 unmodified lines
67 67
68 gpio-reserved-ranges:68 gpio-reserved-ranges:
69 description: |69 description: |
70 Usage of BD71828 GPIO pins can be changed via OTP. This property can be70 Usage of BD71815 GPIO pins can be changed via OTP. This property can be
71 used to mark the pins which should not be configured for GPIO. Please see71 used to mark the pins which should not be configured for GPIO. Please see
72 the ../gpio/gpio.txt for more information.72 the ../gpio/gpio.txt for more information.
73 73
@@ -113,7 +113,7 @@ examples: · 39 unmodified lines
113 gpio-controller;113 gpio-controller;
114 #gpio-cells = <2>;114 #gpio-cells = <2>;
115 115
116 rohm,charger-sense-resistor-ohms = <10000000>;116 rohm,charger-sense-resistor-micro-ohms = <10000>;
117 117
118 regulators {118 regulators {
119 buck1: buck1 {119 buck1: buck1 {
Documentation/devicetree/bindings/mfd/sprd,sc2731.yaml+2−10
@@ -67,15 +67,7 @@ patternProperties: · 66 unmodified lines
67 67
68 "^efuse@[0-9a-f]+$":68 "^efuse@[0-9a-f]+$":
69 type: object69 type: object
70 additionalProperties: true70 $ref: /schemas/nvmem/sprd,sc2731-efuse.yaml#
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
79 71
80 "^fuel-gauge@[0-9a-f]+$":72 "^fuel-gauge@[0-9a-f]+$":
81 type: object73 type: object
@@ -199,7 +191,7 @@ examples: · 117 unmodified lines
199 };191 };
200 };192 };
201 193
202 adc@480 {194 pmic_adc: adc@480 {
203 compatible = "sprd,sc2731-adc";195 compatible = "sprd,sc2731-adc";
204 reg = <0x480>;196 reg = <0x480>;
205 interrupt-parent = <&sc2731_pmic>;197 interrupt-parent = <&sc2731_pmic>;
Documentation/devicetree/bindings/mfd/syscon.yaml+4−1
@@ -27,7 +27,7 @@ select: · 26 unmodified lines
27 compatible:27 compatible:
28 contains:28 contains:
29 enum:29 enum:
30 - al,alpine-sysfabric-servic30 - al,alpine-sysfabric-service
31 - allwinner,sun8i-a83t-system-controller31 - allwinner,sun8i-a83t-system-controller
32 - allwinner,sun8i-h3-system-controller32 - allwinner,sun8i-h3-system-controller
33 - allwinner,sun8i-v3s-system-controller33 - allwinner,sun8i-v3s-system-controller
@@ -103,6 +103,7 @@ select: · 69 unmodified lines
103 - rockchip,rk3288-qos103 - rockchip,rk3288-qos
104 - rockchip,rk3368-qos104 - rockchip,rk3368-qos
105 - rockchip,rk3399-qos105 - rockchip,rk3399-qos
106 - rockchip,rk3562-qos
106 - rockchip,rk3568-qos107 - rockchip,rk3568-qos
107 - rockchip,rk3576-qos108 - rockchip,rk3576-qos
108 - rockchip,rk3588-qos109 - rockchip,rk3588-qos
@@ -201,6 +202,7 @@ properties: · 92 unmodified lines
201 - rockchip,rk3288-qos202 - rockchip,rk3288-qos
202 - rockchip,rk3368-qos203 - rockchip,rk3368-qos
203 - rockchip,rk3399-qos204 - rockchip,rk3399-qos
205 - rockchip,rk3562-qos
204 - rockchip,rk3568-qos206 - rockchip,rk3568-qos
205 - rockchip,rk3576-qos207 - rockchip,rk3576-qos
206 - rockchip,rk3588-qos208 - rockchip,rk3588-qos
@@ -213,6 +215,7 @@ properties: · 6 unmodified lines
213 - ti,am625-dss-oldi-io-ctrl215 - ti,am625-dss-oldi-io-ctrl
214 - ti,am62p-cpsw-mac-efuse216 - ti,am62p-cpsw-mac-efuse
215 - ti,am654-dss-oldi-io-ctrl217 - ti,am654-dss-oldi-io-ctrl
218 - ti,j784s4-acspcie-proxy-ctrl
216 - ti,j784s4-pcie-ctrl219 - ti,j784s4-pcie-ctrl
217 - ti,keystone-pllctrl220 - ti,keystone-pllctrl
218 - const: syscon221 - const: syscon
Documentation/devicetree/bindings/nvmem/sprd,sc2731-efuse.yaml+0−29
@@ -36,33 +36,4 @@ allOf: · 35 unmodified lines
36 - $ref: nvmem-deprecated-cells.yaml#36 - $ref: nvmem-deprecated-cells.yaml#
37 37
38unevaluatedProperties: false38unevaluatedProperties: false
39
40examples:
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 };
68...39...
Documentation/hwmon/index.rst+1−0
@@ -201,6 +201,7 @@ Hardware Monitoring Kernel Drivers · 200 unmodified lines
201 pxe1610201 pxe1610
202 pwm-fan202 pwm-fan
203 q54sj108a2203 q54sj108a2
204 qnap-mcu-hwmon
204 raspberrypi-hwmon205 raspberrypi-hwmon
205 sbrmi206 sbrmi
206 sbtsi_temp207 sbtsi_temp
Documentation/hwmon/qnap-mcu-hwmon.rst+27−0
@@ -0,0 +1,27 @@
1.. SPDX-License-Identifier: GPL-2.0-or-later
2
3Kernel driver qnap-mcu-hwmon
4============================
5
6This driver enables the use of the hardware monitoring and fan control
7of the MCU used on some QNAP network attached storage devices.
8
9Author: Heiko Stuebner <heiko@sntech.de>
10
11Description
12-----------
13
14The driver implements a simple interface for driving the fan controlled by
15setting its PWM output value and exposes the fan rpm and case-temperature
16to user space through hwmon's sysfs interface.
17
18The fan rotation speed returned via the optional 'fan1_input' is calculated
19inside the MCU device.
20
21The driver provides the following sensor accesses in sysfs:
22
23=============== ======= =======================================================
24fan1_input ro fan tachometer speed in RPM
25pwm1 rw relative speed (0-255), 255=max. speed.
26temp1_input ro Measured temperature in millicelsius
27=============== ======= =======================================================
Documentation/leds/index.rst+1−0
@@ -28,4 +28,5 @@ LEDs · 27 unmodified lines
28 leds-mlxcpld28 leds-mlxcpld
29 leds-mt6370-rgb29 leds-mt6370-rgb
30 leds-sc27xx30 leds-sc27xx
31 leds-st1202.rst
31 leds-qcom-lpg32 leds-qcom-lpg
Documentation/leds/leds-st1202.rst+34−0
@@ -0,0 +1,34 @@
1.. SPDX-License-Identifier: GPL-2.0
2
3============================================
4Kernel driver for STMicroelectronics LED1202
5============================================
6
7/sys/class/leds/<led>/hw_pattern
8--------------------------------
9
10Specify a hardware pattern for the ST1202 LED. The LED controller
11implements 12 low-side current generators with independent dimming
12control. Internal volatile memory allows the user to store up to 8
13different patterns. Each pattern is a particular output configuration
14in terms of PWM duty-cycle and duration (ms).
15
16To be compatible with the hardware pattern format, maximum 8 tuples of
17brightness (PWM) and duration must be written to hw_pattern.
18
19- Min pattern duration: 22 ms
20- Max pattern duration: 5660 ms
21
22The format of the hardware pattern values should be:
23"brightness duration brightness duration ..."
24
25/sys/class/leds/<led>/repeat
26----------------------------
27
28Specify a pattern repeat number, which is common for all channels.
29Default is 1; negative numbers and 0 are invalid.
30
31This file will always return the originally written repeat number.
32
33When the 255 value is written to it, all patterns will repeat
34indefinitely.
MAINTAINERS+9−0
@@ -19158,6 +19158,15 @@ L: linux-media@vger.kernel.org · 19157 unmodified lines
19158S: Odd Fixes19158S: Odd Fixes
19159F: drivers/media/tuners/qm1d1c0042*19159F: drivers/media/tuners/qm1d1c0042*
19160 19160
19161QNAP MCU DRIVER
19162M: Heiko Stuebner <heiko@sntech.de>
19163S: Maintained
19164F: drivers/hwmon/qnap-mcu-hwmon.c
19165F: drivers/input/misc/qnap-mcu-input.c
19166F: drivers/leds/leds-qnap-mcu.c
19167F: drivers/mfd/qnap-mcu.c
19168F: include/linux/mfd/qnap-mcu.h
19169
19161QNX4 FILESYSTEM19170QNX4 FILESYSTEM
19162M: Anders Larsen <al@alarsen.net>19171M: Anders Larsen <al@alarsen.net>
19163S: Maintained19172S: Maintained
drivers/hid/hid-sensor-hub.c+14−7
@@ -730,23 +730,30 @@ err_stop_hw: · 729 unmodified lines
730 return ret;730 return ret;
731}731}
732 732
733static 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
733static void sensor_hub_remove(struct hid_device *hdev)743static void sensor_hub_remove(struct hid_device *hdev)
734{744{
735 struct sensor_hub_data *data = hid_get_drvdata(hdev);745 struct sensor_hub_data *data = hid_get_drvdata(hdev);
736 unsigned long flags;746 unsigned long flags;
737 int i;
738 747
739 hid_dbg(hdev, " hardware removed\n");748 hid_dbg(hdev, " hardware removed\n");
740 hid_hw_close(hdev);749 hid_hw_close(hdev);
741 hid_hw_stop(hdev);750 hid_hw_stop(hdev);
751
742 spin_lock_irqsave(&data->lock, flags);752 spin_lock_irqsave(&data->lock, flags);
743 for (i = 0; i < data->hid_sensor_client_cnt; ++i) {753 device_for_each_child(&hdev->dev, NULL,
744 struct hid_sensor_hub_device *hsdev =754 sensor_hub_finalize_pending_fn);
745 data->hid_sensor_hub_client_devs[i].platform_data;
746 if (hsdev->pending.status)
747 complete(&hsdev->pending.ready);
748 }
749 spin_unlock_irqrestore(&data->lock, flags);755 spin_unlock_irqrestore(&data->lock, flags);
756
750 mfd_remove_devices(&hdev->dev);757 mfd_remove_devices(&hdev->dev);
751 mutex_destroy(&data->mutex);758 mutex_destroy(&data->mutex);
752}759}
drivers/hwmon/Kconfig+12−0
@@ -1822,6 +1822,18 @@ config SENSORS_PWM_FAN · 1821 unmodified lines
1822 This driver can also be built as a module. If so, the module1822 This driver can also be built as a module. If so, the module
1823 will be called pwm-fan.1823 will be called pwm-fan.
1824 1824
1825config 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
1825config SENSORS_RASPBERRYPI_HWMON1837config SENSORS_RASPBERRYPI_HWMON
1826 tristate "Raspberry Pi voltage monitor"1838 tristate "Raspberry Pi voltage monitor"
1827 depends on RASPBERRYPI_FIRMWARE || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE)1839 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
189obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o189obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o
190obj-$(CONFIG_SENSORS_PT5161L) += pt5161l.o190obj-$(CONFIG_SENSORS_PT5161L) += pt5161l.o
191obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o191obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o
192obj-$(CONFIG_SENSORS_QNAP_MCU_HWMON) += qnap-mcu-hwmon.o
192obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o193obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o
193obj-$(CONFIG_SENSORS_SBTSI) += sbtsi_temp.o194obj-$(CONFIG_SENSORS_SBTSI) += sbtsi_temp.o
194obj-$(CONFIG_SENSORS_SBRMI) += sbrmi.o195obj-$(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
17struct 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
33static 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
51static 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
69static 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
77static 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
100static 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
121static 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
159static 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
178static 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 */
185static 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
198static 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
211static 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
232static 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
238static 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
245static 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
286static 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
293static 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
353static struct platform_driver qnap_mcu_hwmon_driver = {
354 .probe = qnap_mcu_hwmon_probe,
355 .driver = {
356 .name = "qnap-mcu-hwmon",
357 },
358};
359module_platform_driver(qnap_mcu_hwmon_driver);
360
361MODULE_ALIAS("platform:qnap-mcu-hwmon");
362MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
363MODULE_DESCRIPTION("QNAP MCU hwmon driver");
364MODULE_LICENSE("GPL");
drivers/input/misc/Kconfig+12−0
@@ -917,6 +917,18 @@ config INPUT_HISI_POWERKEY · 916 unmodified lines
917 To compile this driver as a module, choose M here: the917 To compile this driver as a module, choose M here: the
918 module will be called hisi_powerkey.918 module will be called hisi_powerkey.
919 919
920config 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
920config INPUT_RAVE_SP_PWRBUTTON932config INPUT_RAVE_SP_PWRBUTTON
921 tristate "RAVE SP Power button Driver"933 tristate "RAVE SP Power button Driver"
922 depends on RAVE_SP_CORE934 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
68obj-$(CONFIG_INPUT_POWERMATE) += powermate.o68obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
69obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o69obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o
70obj-$(CONFIG_INPUT_PWM_VIBRA) += pwm-vibra.o70obj-$(CONFIG_INPUT_PWM_VIBRA) += pwm-vibra.o
71obj-$(CONFIG_INPUT_QNAP_MCU) += qnap-mcu-input.o
71obj-$(CONFIG_INPUT_RAVE_SP_PWRBUTTON) += rave-sp-pwrbutton.o72obj-$(CONFIG_INPUT_RAVE_SP_PWRBUTTON) += rave-sp-pwrbutton.o
72obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o73obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o
73obj-$(CONFIG_INPUT_REGULATOR_HAPTIC) += regulator-haptic.o74obj-$(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
22struct 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
31static 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
54static 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
63static 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
85static 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
92static 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
142static struct platform_driver qnap_mcu_input_driver = {
143 .probe = qnap_mcu_input_probe,
144 .driver = {
145 .name = "qnap-mcu-input",
146 },
147};
148module_platform_driver(qnap_mcu_input_driver);
149
150MODULE_ALIAS("platform:qnap-mcu-input");
151MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
152MODULE_DESCRIPTION("QNAP MCU input driver");
153MODULE_LICENSE("GPL");
drivers/leds/Kconfig+21−0
@@ -580,6 +580,17 @@ config LEDS_PCA995X · 579 unmodified lines
580 LED driver chips accessed via the I2C bus. Supported580 LED driver chips accessed via the I2C bus. Supported
581 devices include PCA9955BTW, PCA9952TW and PCA9955TW.581 devices include PCA9955BTW, PCA9952TW and PCA9955TW.
582 582
583config 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
583config LEDS_WM831X_STATUS594config LEDS_WM831X_STATUS
584 tristate "LED support for status LEDs on WM831x PMICs"595 tristate "LED support for status LEDs on WM831x PMICs"
585 depends on LEDS_CLASS596 depends on LEDS_CLASS
@@ -931,6 +942,16 @@ config LEDS_LM36274 · 345 unmodified lines
931 Say Y to enable the LM36274 LED driver for TI LMU devices.942 Say Y to enable the LM36274 LED driver for TI LMU devices.
932 This supports the LED device LM36274.943 This supports the LED device LM36274.
933 944
945config 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
934config LEDS_TPS6105X955config LEDS_TPS6105X
935 tristate "LED support for TI TPS6105X"956 tristate "LED support for TI TPS6105X"
936 depends on LEDS_CLASS957 depends on LEDS_CLASS
drivers/leds/Makefile+1−0
@@ -79,6 +79,7 @@ obj-$(CONFIG_LEDS_PCA995X) += leds-pca995x.o · 78 unmodified lines
79obj-$(CONFIG_LEDS_PM8058) += leds-pm8058.o79obj-$(CONFIG_LEDS_PM8058) += leds-pm8058.o
80obj-$(CONFIG_LEDS_POWERNV) += leds-powernv.o80obj-$(CONFIG_LEDS_POWERNV) += leds-powernv.o
81obj-$(CONFIG_LEDS_PWM) += leds-pwm.o81obj-$(CONFIG_LEDS_PWM) += leds-pwm.o
82obj-$(CONFIG_LEDS_QNAP_MCU) += leds-qnap-mcu.o
82obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o83obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o
83obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o84obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o
84obj-$(CONFIG_LEDS_SUN50I_A100) += leds-sun50i-a100.o85obj-$(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
15enum 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
22struct 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
30static 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
36static 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
52static 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
78static 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
106enum 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
112struct qnap_mcu_usb_led {
113 struct qnap_mcu *mcu;
114 struct led_classdev cdev;
115 u8 mode;
116};
117
118static 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
124static 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
145static 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
169static 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
193static 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
216static struct platform_driver qnap_mcu_leds_driver = {
217 .probe = qnap_mcu_leds_probe,
218 .driver = {
219 .name = "qnap-mcu-leds",
220 },
221};
222module_platform_driver(qnap_mcu_leds_driver);
223
224MODULE_ALIAS("platform:qnap-mcu-leds");
225MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
226MODULE_DESCRIPTION("QNAP MCU LEDs driver");
227MODULE_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
41struct 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
49struct st1202_chip {
50 struct i2c_client *client;
51 struct mutex lock;
52 struct st1202_led leds[ST1202_MAX_LEDS];
53};
54
55static struct st1202_led *cdev_to_st1202_led(struct led_classdev *cdev)
56{
57 return container_of(cdev, struct st1202_led, led_cdev);
58}
59
60static 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
75static 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
87static uint8_t st1202_prescalar_to_miliseconds(unsigned int value)
88{
89 return value / ST1202_MILLIS_PATTERN_DUR_MIN - 1;
90}
91
92static 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
124static 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
131static 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
142static 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
155static 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
189static 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
197static 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
218static 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
257static 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
295static 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
346static 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
392static const struct i2c_device_id st1202_id[] = {
393 { "st1202-i2c" },
394 { /* sentinel */ }
395};
396MODULE_DEVICE_TABLE(i2c, st1202_id);
397
398static const struct of_device_id st1202_dt_ids[] = {
399 { .compatible = "st,led1202" },
400 { /* sentinel */ }
401};
402MODULE_DEVICE_TABLE(of, st1202_dt_ids);
403
404static 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};
412module_i2c_driver(st1202_driver);
413
414MODULE_AUTHOR("Remote Tech LTD");
415MODULE_DESCRIPTION("STMicroelectronics LED1202 : 12-channel constant current LED driver");
416MODULE_LICENSE("GPL");
drivers/mfd/Kconfig+25−0
@@ -2386,6 +2386,19 @@ config MFD_INTEL_M10_BMC_PMCI · 2385 unmodified lines
2386 additional drivers must be enabled in order to use the functionality2386 additional drivers must be enabled in order to use the functionality
2387 of the device.2387 of the device.
2388 2388
2389config 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
2389config MFD_RSMU_I2C2402config MFD_RSMU_I2C
2390 tristate "Renesas Synchronization Management Unit with I2C"2403 tristate "Renesas Synchronization Management Unit with I2C"
2391 depends on I2C && OF2404 depends on I2C && OF
@@ -2414,5 +2427,17 @@ config MFD_RSMU_SPI · 22 unmodified lines
2414 Additional drivers must be enabled in order to use the functionality2427 Additional drivers must be enabled in order to use the functionality
2415 of the device.2428 of the device.
2416 2429
2430config 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
2417endmenu2442endmenu
2418endif2443endif
drivers/mfd/Makefile+4−0
@@ -288,5 +288,9 @@ obj-$(CONFIG_MFD_INTEL_M10_BMC_PMCI) += intel-m10-bmc-pmci.o · 287 unmodified lines
288obj-$(CONFIG_MFD_ATC260X) += atc260x-core.o288obj-$(CONFIG_MFD_ATC260X) += atc260x-core.o
289obj-$(CONFIG_MFD_ATC260X_I2C) += atc260x-i2c.o289obj-$(CONFIG_MFD_ATC260X_I2C) += atc260x-i2c.o
290 290
291obj-$(CONFIG_MFD_QNAP_MCU) += qnap-mcu.o
292
291obj-$(CONFIG_MFD_RSMU_I2C) += rsmu_i2c.o rsmu_core.o293obj-$(CONFIG_MFD_RSMU_I2C) += rsmu_i2c.o rsmu_core.o
292obj-$(CONFIG_MFD_RSMU_SPI) += rsmu_spi.o rsmu_core.o294obj-$(CONFIG_MFD_RSMU_SPI) += rsmu_spi.o rsmu_core.o
295
296obj-$(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
1445 }1445 }
1446 }1446 }
1447 1447
1448 ret = mfd_add_devices(axp20x->dev, PLATFORM_DEVID_AUTO, axp20x->cells,1448 ret = mfd_add_devices(axp20x->dev, PLATFORM_DEVID_NONE, axp20x->cells,
1449 axp20x->nr_cells, NULL, 0, NULL);1449 axp20x->nr_cells, NULL, 0, NULL);
1450 1450
1451 if (ret) {1451 if (ret) {
@@ -1455,10 +1455,7 @@ int axp20x_device_probe(struct axp20x_dev *axp20x) · 3 unmodified lines
1455 }1455 }
1456 1456
1457 if (axp20x->variant != AXP288_ID)1457 if (axp20x->variant != AXP288_ID)
1458 devm_register_sys_off_handler(axp20x->dev,1458 devm_register_power_off_handler(axp20x->dev, axp20x_power_off, axp20x);
1459 SYS_OFF_MODE_POWER_OFF,
1460 SYS_OFF_PRIO_DEFAULT,
1461 axp20x_power_off, axp20x);
1462 1459
1463 dev_info(axp20x->dev, "AXP20X driver loaded\n");1460 dev_info(axp20x->dev, "AXP20X driver loaded\n");
1464 1461
drivers/mfd/cs42l43-i2c.c+0−8
@@ -56,13 +56,6 @@ static int cs42l43_i2c_probe(struct i2c_client *i2c) · 55 unmodified lines
56 return cs42l43_dev_probe(cs42l43);56 return cs42l43_dev_probe(cs42l43);
57}57}
58 58
59static 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
66#if IS_ENABLED(CONFIG_OF)59#if IS_ENABLED(CONFIG_OF)
67static const struct of_device_id cs42l43_of_match[] = {60static const struct of_device_id cs42l43_of_match[] = {
68 { .compatible = "cirrus,cs42l43", },61 { .compatible = "cirrus,cs42l43", },
@@ -88,7 +81,6 @@ static struct i2c_driver cs42l43_i2c_driver = { · 19 unmodified lines
88 },81 },
89 82
90 .probe = cs42l43_i2c_probe,83 .probe = cs42l43_i2c_probe,
91 .remove = cs42l43_i2c_remove,
92};84};
93module_i2c_driver(cs42l43_i2c_driver);85module_i2c_driver(cs42l43_i2c_driver);
94 86
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
187 return cs42l43_dev_probe(cs42l43);187 return cs42l43_dev_probe(cs42l43);
188}188}
189 189
190static 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
199static const struct sdw_device_id cs42l43_sdw_id[] = {190static const struct sdw_device_id cs42l43_sdw_id[] = {
200 SDW_SLAVE_ENTRY(0x01FA, 0x4243, 0),191 SDW_SLAVE_ENTRY(0x01FA, 0x4243, 0),
201 {}192 {}
@@ -209,7 +200,6 @@ static struct sdw_driver cs42l43_sdw_driver = { · 7 unmodified lines
209 },200 },
210 201
211 .probe = cs42l43_sdw_probe,202 .probe = cs42l43_sdw_probe,
212 .remove = cs42l43_sdw_remove,
213 .id_table = cs42l43_sdw_id,203 .id_table = cs42l43_sdw_id,
214 .ops = &cs42l43_sdw_ops,204 .ops = &cs42l43_sdw_ops,
215};205};
drivers/mfd/cs42l43.c+23−14
@@ -29,7 +29,7 @@ · 28 unmodified lines
29 29
30#define CS42L43_RESET_DELAY_MS 2030#define CS42L43_RESET_DELAY_MS 20
31 31
32#define CS42L43_SDW_ATTACH_TIMEOUT_MS 50032#define CS42L43_SDW_ATTACH_TIMEOUT_MS 5000
33#define CS42L43_SDW_DETACH_TIMEOUT_MS 10033#define CS42L43_SDW_DETACH_TIMEOUT_MS 100
34 34
35#define CS42L43_MCU_BOOT_STAGE1 135#define CS42L43_MCU_BOOT_STAGE1 1
@@ -48,6 +48,7 @@ · 12 unmodified lines
48 48
49#define CS42L43_MCU_SUPPORTED_REV 0x210549#define CS42L43_MCU_SUPPORTED_REV 0x2105
50#define CS42L43_MCU_SHADOW_REGS_REQUIRED_REV 0x220050#define CS42L43_MCU_SHADOW_REGS_REQUIRED_REV 0x2200
51#define CS42L43_BIOS_SHADOW_REGS_REQUIRED_REV 0x1002
51#define CS42L43_MCU_SUPPORTED_BIOS_REV 0x000152#define CS42L43_MCU_SUPPORTED_BIOS_REV 0x0001
52 53
53#define CS42L43_VDDP_DELAY_US 5054#define CS42L43_VDDP_DELAY_US 50
@@ -773,7 +774,8 @@ static int cs42l43_mcu_update_step(struct cs42l43 *cs42l43) · 719 unmodified lines
773 * Later versions of the firmwware require the driver to access some774 * Later versions of the firmwware require the driver to access some
774 * features through a set of shadow registers.775 * features through a set of shadow registers.
775 */776 */
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);
777 779
778 ret = regmap_read(cs42l43->regmap, CS42L43_BOOT_CONTROL, &secure_cfg);780 ret = regmap_read(cs42l43->regmap, CS42L43_BOOT_CONTROL, &secure_cfg);
779 if (ret) {781 if (ret) {
@@ -982,7 +984,7 @@ static int cs42l43_power_up(struct cs42l43 *cs42l43) · 202 unmodified lines
982 /* vdd-p must be on for 50uS before any other supply */984 /* vdd-p must be on for 50uS before any other supply */
983 usleep_range(CS42L43_VDDP_DELAY_US, 2 * CS42L43_VDDP_DELAY_US);985 usleep_range(CS42L43_VDDP_DELAY_US, 2 * CS42L43_VDDP_DELAY_US);
984 986
985 gpiod_set_value_cansleep(cs42l43->reset, 1);987 gpiod_set_raw_value_cansleep(cs42l43->reset, 1);
986 988
987 ret = regulator_bulk_enable(CS42L43_N_SUPPLIES, cs42l43->core_supplies);989 ret = regulator_bulk_enable(CS42L43_N_SUPPLIES, cs42l43->core_supplies);
988 if (ret) {990 if (ret) {
@@ -1003,7 +1005,7 @@ static int cs42l43_power_up(struct cs42l43 *cs42l43) · 14 unmodified lines
1003err_core_supplies:1005err_core_supplies:
1004 regulator_bulk_disable(CS42L43_N_SUPPLIES, cs42l43->core_supplies);1006 regulator_bulk_disable(CS42L43_N_SUPPLIES, cs42l43->core_supplies);
1005err_reset:1007err_reset:
1006 gpiod_set_value_cansleep(cs42l43->reset, 0);1008 gpiod_set_raw_value_cansleep(cs42l43->reset, 0);
1007 regulator_disable(cs42l43->vdd_p);1009 regulator_disable(cs42l43->vdd_p);
1008 1010
1009 return ret;1011 return ret;
@@ -1025,7 +1027,7 @@ static int cs42l43_power_down(struct cs42l43 *cs42l43) · 15 unmodified lines
1025 return ret;1027 return ret;
1026 }1028 }
1027 1029
1028 gpiod_set_value_cansleep(cs42l43->reset, 0);1030 gpiod_set_raw_value_cansleep(cs42l43->reset, 0);
1029 1031
1030 ret = regulator_disable(cs42l43->vdd_p);1032 ret = regulator_disable(cs42l43->vdd_p);
1031 if (ret) {1033 if (ret) {
@@ -1036,6 +1038,15 @@ static int cs42l43_power_down(struct cs42l43 *cs42l43) · 4 unmodified lines
1036 return 0;1038 return 0;
1037}1039}
1038 1040
1041static 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
1039int cs42l43_dev_probe(struct cs42l43 *cs42l43)1050int cs42l43_dev_probe(struct cs42l43 *cs42l43)
1040{1051{
1041 int i, ret;1052 int i, ret;
@@ -1050,11 +1061,13 @@ int cs42l43_dev_probe(struct cs42l43 *cs42l43) · 8 unmodified lines
1050 1061
1051 regcache_cache_only(cs42l43->regmap, true);1062 regcache_cache_only(cs42l43->regmap, true);
1052 1063
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);
1054 if (IS_ERR(cs42l43->reset))1065 if (IS_ERR(cs42l43->reset))
1055 return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->reset),1066 return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->reset),
1056 "Failed to get reset\n");1067 "Failed to get reset\n");
1057 1068
1069 gpiod_set_raw_value_cansleep(cs42l43->reset, 0);
1070
1058 cs42l43->vdd_p = devm_regulator_get(cs42l43->dev, "vdd-p");1071 cs42l43->vdd_p = devm_regulator_get(cs42l43->dev, "vdd-p");
1059 if (IS_ERR(cs42l43->vdd_p))1072 if (IS_ERR(cs42l43->vdd_p))
1060 return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->vdd_p),1073 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
1080 if (ret)1093 if (ret)
1081 return ret;1094 return ret;
1082 1095
1096 ret = devm_add_action_or_reset(cs42l43->dev, cs42l43_dev_remove, cs42l43);
1097 if (ret)
1098 return ret;
1099
1083 pm_runtime_set_autosuspend_delay(cs42l43->dev, CS42L43_AUTOSUSPEND_TIME_MS);1100 pm_runtime_set_autosuspend_delay(cs42l43->dev, CS42L43_AUTOSUSPEND_TIME_MS);
1084 pm_runtime_use_autosuspend(cs42l43->dev);1101 pm_runtime_use_autosuspend(cs42l43->dev);
1085 pm_runtime_set_active(cs42l43->dev);1102 pm_runtime_set_active(cs42l43->dev);
@@ -1098,14 +1115,6 @@ int cs42l43_dev_probe(struct cs42l43 *cs42l43) · 12 unmodified lines
1098}1115}
1099EXPORT_SYMBOL_NS_GPL(cs42l43_dev_probe, "MFD_CS42L43");1116EXPORT_SYMBOL_NS_GPL(cs42l43_dev_probe, "MFD_CS42L43");
1100 1117
1101void cs42l43_dev_remove(struct cs42l43 *cs42l43)
1102{
1103 cancel_work_sync(&cs42l43->boot_work);
1104
1105 cs42l43_power_down(cs42l43);
1106}
1107EXPORT_SYMBOL_NS_GPL(cs42l43_dev_remove, "MFD_CS42L43");
1108
1109static int cs42l43_suspend(struct device *dev)1118static int cs42l43_suspend(struct device *dev)
1110{1119{
1111 struct cs42l43 *cs42l43 = dev_get_drvdata(dev);1120 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
25bool cs42l43_volatile_register(struct device *dev, unsigned int reg);25bool cs42l43_volatile_register(struct device *dev, unsigned int reg);
26 26
27int cs42l43_dev_probe(struct cs42l43 *cs42l43);27int cs42l43_dev_probe(struct cs42l43 *cs42l43);
28void cs42l43_dev_remove(struct cs42l43 *cs42l43);
29 28
30#endif /* CS42L43_CORE_INT_H */29#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
585 "Cannot reset FAULT_LOG values %d\n", ret);585 "Cannot reset FAULT_LOG values %d\n", ret);
586 }586 }
587 587
588 da9052->fault_log = fault_log;
588 return ret;589 return ret;
589}590}
590 591
drivers/mfd/intel_soc_pmic_chtdc_ti.c+1−1
@@ -81,7 +81,7 @@ static struct mfd_cell chtdc_ti_dev[] = { · 80 unmodified lines
81static const struct regmap_config chtdc_ti_regmap_config = {81static const struct regmap_config chtdc_ti_regmap_config = {
82 .reg_bits = 8,82 .reg_bits = 8,
83 .val_bits = 8,83 .val_bits = 8,
84 .max_register = 128,84 .max_register = 0xff,
85 .cache_type = REGCACHE_NONE,85 .cache_type = REGCACHE_NONE,
86};86};
87 87
drivers/mfd/lpc_ich.c+2−1
@@ -834,8 +834,9 @@ static const struct pci_device_id lpc_ich_ids[] = { · 833 unmodified lines
834 { PCI_VDEVICE(INTEL, 0x2917), LPC_ICH9ME},834 { PCI_VDEVICE(INTEL, 0x2917), LPC_ICH9ME},
835 { PCI_VDEVICE(INTEL, 0x2918), LPC_ICH9},835 { PCI_VDEVICE(INTEL, 0x2918), LPC_ICH9},
836 { PCI_VDEVICE(INTEL, 0x2919), LPC_ICH9M},836 { PCI_VDEVICE(INTEL, 0x2919), LPC_ICH9M},
837 { PCI_VDEVICE(INTEL, 0x3197), LPC_GLK},
838 { PCI_VDEVICE(INTEL, 0x2b9c), LPC_COUGARMOUNTAIN},837 { PCI_VDEVICE(INTEL, 0x2b9c), LPC_COUGARMOUNTAIN},
838 { PCI_VDEVICE(INTEL, 0x3197), LPC_GLK},
839 { PCI_VDEVICE(INTEL, 0x31e8), LPC_GLK},
839 { PCI_VDEVICE(INTEL, 0x3a14), LPC_ICH10DO},840 { PCI_VDEVICE(INTEL, 0x3a14), LPC_ICH10DO},
840 { PCI_VDEVICE(INTEL, 0x3a16), LPC_ICH10R},841 { PCI_VDEVICE(INTEL, 0x3a16), LPC_ICH10R},
841 { PCI_VDEVICE(INTEL, 0x3a18), LPC_ICH10},842 { 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 */
43struct 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 */
59struct 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 */
71static 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
81static 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
99static 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
140static 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
145int 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}
188EXPORT_SYMBOL_GPL(qnap_mcu_exec);
189
190int 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}
208EXPORT_SYMBOL_GPL(qnap_mcu_exec_with_ack);
209
210static 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 */
235static 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
250static 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
258static struct mfd_cell qnap_mcu_cells[] = {
259 { .name = "qnap-mcu-input", },
260 { .name = "qnap-mcu-leds", },
261 { .name = "qnap-mcu-hwmon", }
262};
263
264static 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
321static const struct of_device_id qnap_mcu_dt_ids[] = {
322 { .compatible = "qnap,ts433-mcu", .data = &qnap_ts433_mcu },
323 { /* sentinel */ }
324};
325MODULE_DEVICE_TABLE(of, qnap_mcu_dt_ids);
326
327static 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};
334module_serdev_device_driver(qnap_mcu_drv);
335
336MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
337MODULE_DESCRIPTION("QNAP MCU core driver");
338MODULE_LICENSE("GPL");
drivers/mfd/stpmic1.c+1−5
@@ -170,11 +170,7 @@ static int stpmic1_probe(struct i2c_client *i2c) · 169 unmodified lines
170 return ret;170 return ret;
171 }171 }
172 172
173 ret = devm_register_sys_off_handler(ddata->dev,173 ret = devm_register_power_off_handler(ddata->dev, stpmic1_power_off, ddata);
174 SYS_OFF_MODE_POWER_OFF,
175 SYS_OFF_PRIO_DEFAULT,
176 stpmic1_power_off,
177 ddata);
178 if (ret) {174 if (ret) {
179 dev_err(ddata->dev, "failed to register sys-off handler: %d\n", ret);175 dev_err(ddata->dev, "failed to register sys-off handler: %d\n", ret);
180 return ret;176 return ret;
drivers/mfd/syscon.c+15−80
@@ -12,22 +12,16 @@ · 11 unmodified lines
12#include <linux/clk.h>12#include <linux/clk.h>
13#include <linux/err.h>13#include <linux/err.h>
14#include <linux/hwspinlock.h>14#include <linux/hwspinlock.h>
15#include <linux/io.h>
16#include <linux/init.h>
17#include <linux/list.h>15#include <linux/list.h>
16#include <linux/mutex.h>
18#include <linux/of.h>17#include <linux/of.h>
19#include <linux/of_address.h>18#include <linux/of_address.h>
20#include <linux/of_platform.h>
21#include <linux/platform_data/syscon.h>
22#include <linux/platform_device.h>
23#include <linux/regmap.h>19#include <linux/regmap.h>
24#include <linux/reset.h>20#include <linux/reset.h>
25#include <linux/mfd/syscon.h>21#include <linux/mfd/syscon.h>
26#include <linux/slab.h>22#include <linux/slab.h>
27 23
28static struct platform_driver syscon_driver;24static DEFINE_MUTEX(syscon_list_lock);
29
30static DEFINE_SPINLOCK(syscon_list_slock);
31static LIST_HEAD(syscon_list);25static LIST_HEAD(syscon_list);
32 26
33struct syscon {27struct syscon {
@@ -54,6 +48,8 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_res) · 20 unmodified lines
54 struct resource res;48 struct resource res;
55 struct reset_control *reset;49 struct reset_control *reset;
56 50
51 WARN_ON(!mutex_is_locked(&syscon_list_lock));
52
57 struct syscon *syscon __free(kfree) = kzalloc(sizeof(*syscon), GFP_KERNEL);53 struct syscon *syscon __free(kfree) = kzalloc(sizeof(*syscon), GFP_KERNEL);
58 if (!syscon)54 if (!syscon)
59 return ERR_PTR(-ENOMEM);55 return ERR_PTR(-ENOMEM);
@@ -146,9 +142,7 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_res) · 86 unmodified lines
146 syscon->regmap = regmap;142 syscon->regmap = regmap;
147 syscon->np = np;143 syscon->np = np;
148 144
149 spin_lock(&syscon_list_slock);
150 list_add_tail(&syscon->list, &syscon_list);145 list_add_tail(&syscon->list, &syscon_list);
151 spin_unlock(&syscon_list_slock);
152 146
153 return_ptr(syscon);147 return_ptr(syscon);
154 148
@@ -169,7 +163,7 @@ static struct regmap *device_node_get_regmap(struct device_node *np, · 14 unmodified lines
169{163{
170 struct syscon *entry, *syscon = NULL;164 struct syscon *entry, *syscon = NULL;
171 165
172 spin_lock(&syscon_list_slock);166 mutex_lock(&syscon_list_lock);
173 167
174 list_for_each_entry(entry, &syscon_list, list)168 list_for_each_entry(entry, &syscon_list, list)
175 if (entry->np == np) {169 if (entry->np == np) {
@@ -177,10 +171,13 @@ static struct regmap *device_node_get_regmap(struct device_node *np, · 1 unmodified line
177 break;171 break;
178 }172 }
179 173
180 spin_unlock(&syscon_list_slock);174 if (!syscon) {
181 175 if (of_device_is_compatible(np, "syscon"))
182 if (!syscon)176 syscon = of_syscon_register(np, check_res);
183 syscon = of_syscon_register(np, check_res);177 else
178 syscon = ERR_PTR(-EINVAL);
179 }
180 mutex_unlock(&syscon_list_lock);
184 181
185 if (IS_ERR(syscon))182 if (IS_ERR(syscon))
186 return ERR_CAST(syscon);183 return ERR_CAST(syscon);
@@ -212,7 +209,7 @@ int of_syscon_register_regmap(struct device_node *np, struct regmap *regmap) · 25 unmodified lines
212 return -ENOMEM;209 return -ENOMEM;
213 210
214 /* check if syscon entry already exists */211 /* check if syscon entry already exists */
215 spin_lock(&syscon_list_slock);212 mutex_lock(&syscon_list_lock);
216 213
217 list_for_each_entry(entry, &syscon_list, list)214 list_for_each_entry(entry, &syscon_list, list)
218 if (entry->np == np) {215 if (entry->np == np) {
@@ -225,12 +222,12 @@ int of_syscon_register_regmap(struct device_node *np, struct regmap *regmap) · 6 unmodified lines
225 222
226 /* register the regmap in syscon list */223 /* register the regmap in syscon list */
227 list_add_tail(&syscon->list, &syscon_list);224 list_add_tail(&syscon->list, &syscon_list);
228 spin_unlock(&syscon_list_slock);225 mutex_unlock(&syscon_list_lock);
229 226
230 return 0;227 return 0;
231 228
232err_unlock:229err_unlock:
233 spin_unlock(&syscon_list_slock);230 mutex_unlock(&syscon_list_lock);
234 kfree(syscon);231 kfree(syscon);
235 return ret;232 return ret;
236}233}
@@ -244,9 +241,6 @@ EXPORT_SYMBOL_GPL(device_node_to_regmap); · 7 unmodified lines
244 241
245struct regmap *syscon_node_to_regmap(struct device_node *np)242struct regmap *syscon_node_to_regmap(struct device_node *np)
246{243{
247 if (!of_device_is_compatible(np, "syscon"))
248 return ERR_PTR(-EINVAL);
249
250 return device_node_get_regmap(np, true);244 return device_node_get_regmap(np, true);
251}245}
252EXPORT_SYMBOL_GPL(syscon_node_to_regmap);246EXPORT_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
336 return regmap;330 return regmap;
337}331}
338EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle_optional);332EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle_optional);
339
340static 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
380static const struct platform_device_id syscon_ids[] = {
381 { "syscon", },
382 { }
383};
384
385static struct platform_driver syscon_driver = {
386 .driver = {
387 .name = "syscon",
388 },
389 .probe = syscon_probe,
390 .id_table = syscon_ids,
391};
392
393static int __init syscon_init(void)
394{
395 return platform_driver_register(&syscon_driver);
396}
397postcore_initcall(syscon_init);
drivers/mfd/tps65219.c+4−11
@@ -110,19 +110,12 @@ static const struct resource tps65219_regulator_resources[] = { · 109 unmodified lines
110};110};
111 111
112static const struct mfd_cell tps65219_cells[] = {112static const struct mfd_cell tps65219_cells[] = {
113 {113 MFD_CELL_RES("tps65219-regulator", tps65219_regulator_resources),
114 .name = "tps65219-regulator",114 MFD_CELL_NAME("tps65219-gpio"),
115 .resources = tps65219_regulator_resources,
116 .num_resources = ARRAY_SIZE(tps65219_regulator_resources),
117 },
118 { .name = "tps65219-gpio", },
119};115};
120 116
121static const struct mfd_cell tps65219_pwrbutton_cell = {117static const struct mfd_cell tps65219_pwrbutton_cell =
122 .name = "tps65219-pwrbutton",118 MFD_CELL_RES("tps65219-pwrbutton", tps65219_pwrbutton_resources);
123 .resources = tps65219_pwrbutton_resources,
124 .num_resources = ARRAY_SIZE(tps65219_pwrbutton_resources),
125};
126 119
127static const struct regmap_config tps65219_regmap_config = {120static const struct regmap_config tps65219_regmap_config = {
128 .reg_bits = 8,121 .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
43static 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
76static 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
106static 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
113static 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
119static 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
124static 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
129static 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
141static 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
148static 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
154static 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
159static 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
164static 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
176static const struct mfd_cell upboard_up_mfd_cells[] = {
177 { .name = "upboard-pinctrl" },
178 { .name = "upboard-leds" },
179};
180
181static const struct upboard_fpga_data upboard_up_fpga_data = {
182 .type = UPBOARD_UP_FPGA,
183 .regmap_config = &upboard_up_regmap_config,
184};
185
186static const struct upboard_fpga_data upboard_up2_fpga_data = {
187 .type = UPBOARD_UP2_FPGA,
188 .regmap_config = &upboard_up2_regmap_config,
189};
190
191static 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
218static 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
251static 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
263static DEVICE_ATTR_RO(upboard_fpga_version);
264
265static struct attribute *upboard_fpga_attrs[] = {
266 &dev_attr_upboard_fpga_version.attr,
267 NULL
268};
269
270ATTRIBUTE_GROUPS(upboard_fpga);
271
272static 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
304static 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};
309MODULE_DEVICE_TABLE(acpi, upboard_fpga_acpi_match);
310
311static 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
320module_platform_driver(upboard_fpga_driver);
321
322MODULE_AUTHOR("Gary Wang <garywang@aaeon.com.tw>");
323MODULE_AUTHOR("Thomas Richard <thomas.richard@bootlin.com>");
324MODULE_DESCRIPTION("UP Board FPGA driver");
325MODULE_LICENSE("GPL");
drivers/mfd/vexpress-sysreg.c+0−1
@@ -10,7 +10,6 @@ · 9 unmodified lines
10#include <linux/mfd/core.h>10#include <linux/mfd/core.h>
11#include <linux/module.h>11#include <linux/module.h>
12#include <linux/of_platform.h>12#include <linux/of_platform.h>
13#include <linux/platform_data/syscon.h>
14#include <linux/platform_device.h>13#include <linux/platform_device.h>
15#include <linux/slab.h>14#include <linux/slab.h>
16#include <linux/stat.h>15#include <linux/stat.h>
include/linux/mfd/core.h+1−1
@@ -72,7 +72,7 @@ struct mfd_cell { · 71 unmodified lines
72 int (*resume)(struct platform_device *dev);72 int (*resume)(struct platform_device *dev);
73 73
74 /* platform data passed to the sub devices drivers */74 /* platform data passed to the sub devices drivers */
75 void *platform_data;75 const void *platform_data;
76 size_t pdata_size;76 size_t pdata_size;
77 77
78 /* Matches ACPI */78 /* Matches ACPI */
include/linux/mfd/da9052/da9052.h+2−0
@@ -93,6 +93,8 @@ struct da9052 { · 92 unmodified lines
93 93
94 int chip_irq;94 int chip_irq;
95 95
96 int fault_log;
97
96 /* SOC I/O transfer related fixes for DA9052/53 */98 /* SOC I/O transfer related fixes for DA9052/53 */
97 int (*fix_io) (struct da9052 *da9052, unsigned char reg);99 int (*fix_io) (struct da9052 *da9052, unsigned char reg);
98};100};
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
10struct qnap_mcu;
11
12struct 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
20int 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);
23int 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
10 10
11#include <linux/bitops.h>11#include <linux/bitops.h>
12#include <linux/notifier.h>12#include <linux/notifier.h>
13#include <linux/regmap.h>
13#include <linux/regulator/driver.h>14#include <linux/regulator/driver.h>
14 15
15struct regmap;
16struct regmap_irq_chip_data;
17
18#define TPS65219_1V35 1350000
19#define TPS65219_1V8 1800000
20
21/* TPS chip id list */16/* TPS chip id list */
22#define TPS65219 0xF017#define TPS65219 0xF0
23 18
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
18enum 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
32enum upboard_fpga_type {
33 UPBOARD_UP_FPGA,
34 UPBOARD_UP2_FPGA,
35};
36
37struct upboard_fpga_data {
38 enum upboard_fpga_type type;
39 const struct regmap_config *regmap_config;
40};
41
42struct 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
5struct 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