sunxi: add THS and DVFS support for selected H3/H5 boards THS and DVFS code is WIP...
[openwrt/staging/hauke.git] / target / linux / sunxi / patches-4.14 / 401-allwinner-h3-h5-dvfs-ths.patch
1 diff '--exclude=scripts' -Naur a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
2 --- a/arch/arm/boot/dts/sun8i-h3.dtsi 2018-02-16 20:23:12.000000000 +0100
3 +++ b/arch/arm/boot/dts/sun8i-h3.dtsi 2018-03-02 10:13:21.608352001 +0100
4 @@ -47,28 +47,34 @@
5 #address-cells = <1>;
6 #size-cells = <0>;
7
8 - cpu@0 {
9 + cpu0: cpu@0 {
10 compatible = "arm,cortex-a7";
11 device_type = "cpu";
12 reg = <0>;
13 + clocks = <&ccu CLK_CPUX>;
14 + clock-latency = <244144>; /* 8 32k periods */
15 + clock-frequency = <1200000000>;
16 };
17
18 cpu@1 {
19 compatible = "arm,cortex-a7";
20 device_type = "cpu";
21 reg = <1>;
22 + clock-frequency = <1200000000>;
23 };
24
25 cpu@2 {
26 compatible = "arm,cortex-a7";
27 device_type = "cpu";
28 reg = <2>;
29 + clock-frequency = <1200000000>;
30 };
31
32 cpu@3 {
33 compatible = "arm,cortex-a7";
34 device_type = "cpu";
35 reg = <3>;
36 + clock-frequency = <1200000000>;
37 };
38 };
39
40 diff '--exclude=scripts' -Naur a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
41 --- a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts 2018-03-02 10:10:46.450811999 +0100
42 +++ b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts 2018-03-02 10:12:25.156140000 +0100
43 @@ -46,6 +46,7 @@
44
45 #include <dt-bindings/gpio/gpio.h>
46 #include <dt-bindings/input/input.h>
47 +#include <dt-bindings/thermal/thermal.h>
48
49 / {
50 model = "Xunlong Orange Pi One";
51 @@ -88,6 +89,82 @@
52 gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
53 };
54 };
55 +
56 + vdd_cpux: gpio-regulator {
57 + compatible = "regulator-gpio";
58 +
59 + pinctrl-names = "default";
60 + pinctrl-0 = <&vdd_cpux_r_opc>;
61 +
62 + regulator-name = "vdd-cpux";
63 + regulator-type = "voltage";
64 + regulator-boot-on;
65 + regulator-always-on;
66 + regulator-min-microvolt = <1100000>;
67 + regulator-max-microvolt = <1300000>;
68 + regulator-ramp-delay = <50>; /* 4ms */
69 +
70 + gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>;
71 + gpios-states = <0x1>;
72 + states = <1100000 0x0
73 + 1300000 0x1>;
74 + };
75 +};
76 +
77 +&cpu0 {
78 + operating-points = <
79 + 1008000 1300000
80 + 816000 1100000
81 + 624000 1100000
82 + 480000 1100000
83 + 312000 1100000
84 + 240000 1100000
85 + 120000 1100000
86 + >;
87 + #cooling-cells = <2>;
88 + cooling-min-level = <0>;
89 + cooling-max-level = <6>;
90 + cpu0-supply = <&vdd_cpux>;
91 +};
92 +
93 +&cpu_thermal {
94 + trips {
95 + cpu_warm: cpu_warm {
96 + temperature = <65000>;
97 + hysteresis = <2000>;
98 + type = "passive";
99 + };
100 + cpu_hot: cpu_hot {
101 + temperature = <75000>;
102 + hysteresis = <2000>;
103 + type = "passive";
104 + };
105 + cpu_very_hot: cpu_very_hot {
106 + temperature = <90000>;
107 + hysteresis = <2000>;
108 + type = "passive";
109 + };
110 + cpu_crit: cpu_crit {
111 + temperature = <105000>;
112 + hysteresis = <2000>;
113 + type = "critical";
114 + };
115 + };
116 +
117 + cooling-maps {
118 + cpu_warm_limit_cpu {
119 + trip = <&cpu_warm>;
120 + cooling-device = <&cpu0 THERMAL_NO_LIMIT 1>;
121 + };
122 + cpu_hot_limit_cpu {
123 + trip = <&cpu_hot>;
124 + cooling-device = <&cpu0 2 3>;
125 + };
126 + cpu_very_hot_limit_cpu {
127 + trip = <&cpu_very_hot>;
128 + cooling-device = <&cpu0 5 THERMAL_NO_LIMIT>;
129 + };
130 + };
131 };
132
133 &ehci0 {
134 @@ -140,6 +217,11 @@
135 pins = "PL3";
136 function = "gpio_in";
137 };
138 +
139 + vdd_cpux_r_opc: regulator_pins@0 {
140 + pins = "PL6";
141 + function = "gpio_out";
142 + };
143 };
144
145 &reg_usb0_vbus {
146 diff '--exclude=scripts' -Naur a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
147 --- a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts 2018-03-02 10:10:46.458816000 +0100
148 +++ b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts 2018-03-02 10:14:00.351714000 +0100
149 @@ -46,6 +46,7 @@
150
151 #include <dt-bindings/gpio/gpio.h>
152 #include <dt-bindings/input/input.h>
153 +#include <dt-bindings/thermal/thermal.h>
154
155 / {
156 model = "Xunlong Orange Pi PC";
157 @@ -102,6 +103,72 @@
158 status = "okay";
159 };
160
161 +&cpu0 {
162 + operating-points = <
163 + /* kHz uV */
164 + 1368000 1400000
165 + 1344000 1400000
166 + 1296000 1340000
167 + 1248000 1340000
168 + 1224000 1340000
169 + 1200000 1320000
170 + 1152000 1320000
171 + 1104000 1320000
172 + 1056000 1320000
173 + 1008000 1200000
174 + 960000 1200000
175 + 816000 1100000
176 + 648000 1100000
177 + 480000 1100000
178 + 240000 1100000
179 + 120000 1100000
180 + >;
181 + #cooling-cells = <2>;
182 + cooling-min-level = <0>;
183 + cooling-max-level = <15>;
184 + cpu0-supply = <&vdd_cpu>;
185 +};
186 +
187 +&cpu_thermal {
188 + trips {
189 + cpu_warm: cpu_warm {
190 + temperature = <65000>;
191 + hysteresis = <2000>;
192 + type = "passive";
193 + };
194 + cpu_hot: cpu_hot {
195 + temperature = <75000>;
196 + hysteresis = <2000>;
197 + type = "passive";
198 + };
199 + cpu_very_hot: cpu_very_hot {
200 + temperature = <90000>;
201 + hysteresis = <2000>;
202 + type = "passive";
203 + };
204 + cpu_crit: cpu_crit {
205 + temperature = <105000>;
206 + hysteresis = <2000>;
207 + type = "critical";
208 + };
209 + };
210 +
211 + cooling-maps {
212 + cpu_warm_limit_cpu {
213 + trip = <&cpu_warm>;
214 + cooling-device = <&cpu0 THERMAL_NO_LIMIT 10>;
215 + };
216 + cpu_hot_limit_cpu {
217 + trip = <&cpu_hot>;
218 + cooling-device = <&cpu0 12 12>;
219 + };
220 + cpu_very_hot_limit_cpu {
221 + trip = <&cpu_very_hot>;
222 + cooling-device = <&cpu0 14 THERMAL_NO_LIMIT>;
223 + };
224 + };
225 +};
226 +
227 &ehci1 {
228 status = "okay";
229 };
230 @@ -160,6 +227,20 @@
231 };
232 };
233
234 +&r_i2c {
235 + status = "okay";
236 +
237 + vdd_cpu: regulator@65 {
238 + compatible = "silergy,sy8106a";
239 + reg = <0x65>;
240 + regulator-min-microvolt = <1000000>;
241 + regulator-max-microvolt = <1400000>;
242 + regulator-ramp-delay = <200>;
243 + regulator-boot-on;
244 + regulator-always-on;
245 + };
246 +};
247 +
248 &r_pio {
249 leds_r_opc: led_pins@0 {
250 pins = "PL10";
251 diff '--exclude=scripts' -Naur a/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts
252 --- a/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts 2018-03-02 10:10:46.458816000 +0100
253 +++ b/arch/arm/boot/dts/sun8i-h3-orangepi-plus.dts 2018-03-02 10:13:32.561826000 +0100
254 @@ -42,6 +42,7 @@
255
256 /* The Orange Pi Plus is an extended version of the Orange Pi 2 */
257 #include "sun8i-h3-orangepi-2.dts"
258 +#include <dt-bindings/thermal/thermal.h>
259
260 / {
261 model = "Xunlong Orange Pi Plus / Plus 2";
262 @@ -74,6 +75,86 @@
263 };
264 };
265
266 +&cpu0 {
267 + operating-points = <
268 + /* kHz uV */
269 + 1368000 1500000
270 + 1344000 1500000
271 + 1296000 1340000
272 + 1248000 1340000
273 + 1224000 1340000
274 + 1200000 1340000
275 + 1152000 1320000
276 + 1104000 1320000
277 + 1056000 1320000
278 + 1008000 1200000
279 + 960000 1200000
280 + 816000 1100000
281 + 648000 1100000
282 + 480000 1040000
283 + 240000 1040000
284 + 120000 1040000
285 + >;
286 + #cooling-cells = <2>;
287 + cooling-min-level = <0>;
288 + cooling-max-level = <15>;
289 + cpu0-supply = <&vdd_cpu>;
290 +};
291 +
292 +&cpu_thermal {
293 + trips {
294 + cpu_warm: cpu_warm {
295 + temperature = <65000>;
296 + hysteresis = <2000>;
297 + type = "passive";
298 + };
299 + cpu_hot: cpu_hot {
300 + temperature = <75000>;
301 + hysteresis = <2000>;
302 + type = "passive";
303 + };
304 + cpu_very_hot: cpu_very_hot {
305 + temperature = <90000>;
306 + hysteresis = <2000>;
307 + type = "passive";
308 + };
309 + cpu_crit: cpu_crit {
310 + temperature = <105000>;
311 + hysteresis = <2000>;
312 + type = "critical";
313 + };
314 + };
315 +
316 + cooling-maps {
317 + cpu_warm_limit_cpu {
318 + trip = <&cpu_warm>;
319 + cooling-device = <&cpu0 THERMAL_NO_LIMIT 10>;
320 + };
321 + cpu_hot_limit_cpu {
322 + trip = <&cpu_hot>;
323 + cooling-device = <&cpu0 12 12>;
324 + };
325 + cpu_very_hot_limit_cpu {
326 + trip = <&cpu_very_hot>;
327 + cooling-device = <&cpu0 14 THERMAL_NO_LIMIT>;
328 + };
329 + };
330 +};
331 +
332 +&r_i2c {
333 + status = "okay";
334 +
335 + vdd_cpu: regulator@65 {
336 + compatible = "silergy,sy8106a";
337 + reg = <0x65>;
338 + regulator-min-microvolt = <1040000>;
339 + regulator-max-microvolt = <1500000>;
340 + regulator-ramp-delay = <200>;
341 + regulator-boot-on;
342 + regulator-always-on;
343 + };
344 +};
345 +
346 &ehci3 {
347 status = "okay";
348 };
349 diff '--exclude=scripts' -Naur a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
350 --- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi 2018-03-02 10:10:46.462818000 +0100
351 +++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi 2018-03-02 10:14:12.845958001 +0100
352 @@ -383,6 +383,18 @@
353 };
354 };
355
356 + ths: ths@01c25000 {
357 + #thermal-sensor-cells = <0>;
358 + compatible = "allwinner,sun8i-h3-ths";
359 + reg = <0x01c25000 0x400>,
360 + <0x01c14234 0x4>;
361 + interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
362 + resets = <&ccu RST_BUS_THS>;
363 + reset-names = "ahb";
364 + clocks = <&ccu CLK_BUS_THS>, <&ccu CLK_THS>;
365 + clock-names = "ahb", "ths";
366 + };
367 +
368 timer@01c20c00 {
369 compatible = "allwinner,sun4i-a10-timer";
370 reg = <0x01c20c00 0xa0>;
371 @@ -647,6 +659,20 @@
372 status = "disabled";
373 };
374
375 + r_i2c: i2c@01f02400 {
376 + compatible = "allwinner,sun6i-a31-i2c";
377 + reg = <0x01f02400 0x400>;
378 + interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
379 + pinctrl-names = "default";
380 + pinctrl-0 = <&r_i2c_pins_a>;
381 + clocks = <&r_ccu CLK_APB0_I2C>;
382 + clock-frequency = <100000>;
383 + resets = <&r_ccu RST_APB0_I2C>;
384 + status = "disabled";
385 + #address-cells = <1>;
386 + #size-cells = <0>;
387 + };
388 +
389 r_pio: pinctrl@01f02c00 {
390 compatible = "allwinner,sun8i-h3-r-pinctrl";
391 reg = <0x01f02c00 0x400>;
392 @@ -662,6 +688,19 @@
393 pins = "PL11";
394 function = "s_cir_rx";
395 };
396 +
397 + r_i2c_pins_a: r_i2c@0 {
398 + pins = "PL0", "PL1";
399 + function = "s_i2c";
400 + };
401 + };
402 + };
403 +
404 + thermal-zones {
405 + cpu_thermal: cpu_thermal {
406 + polling-delay-passive = <330>;
407 + polling-delay = <1000>;
408 + thermal-sensors = <&ths 0>;
409 };
410 };
411 };
412 diff '--exclude=scripts' -Naur a/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
413 --- a/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi 2018-02-16 20:23:12.000000000 +0100
414 +++ b/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi 2018-03-02 10:12:17.444286000 +0100
415 @@ -47,11 +47,14 @@
416 #address-cells = <1>;
417 #size-cells = <0>;
418
419 - cpu@0 {
420 + cpu0: cpu@0 {
421 compatible = "arm,cortex-a53", "arm,armv8";
422 device_type = "cpu";
423 reg = <0>;
424 enable-method = "psci";
425 + clocks = <&ccu CLK_CPUX>;
426 + clock-latency = <244144>; /* 8 32k periods */
427 + clock-frequency = <1200000000>;
428 };
429
430 cpu@1 {
431 @@ -59,6 +62,7 @@
432 device_type = "cpu";
433 reg = <1>;
434 enable-method = "psci";
435 + clock-frequency = <1200000000>;
436 };
437
438 cpu@2 {
439 @@ -66,6 +70,7 @@
440 device_type = "cpu";
441 reg = <2>;
442 enable-method = "psci";
443 + clock-frequency = <1200000000>;
444 };
445
446 cpu@3 {
447 @@ -73,6 +78,7 @@
448 device_type = "cpu";
449 reg = <3>;
450 enable-method = "psci";
451 + clock-frequency = <1200000000>;
452 };
453 };
454
455 diff '--exclude=scripts' -Naur a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts
456 --- a/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts 2018-03-02 10:10:46.502838000 +0100
457 +++ b/arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-pc2.dts 2018-03-02 10:12:19.757442001 +0100
458 @@ -46,6 +46,7 @@
459 #include <dt-bindings/gpio/gpio.h>
460 #include <dt-bindings/input/input.h>
461 #include <dt-bindings/pinctrl/sun4i-a10.h>
462 +#include <dt-bindings/thermal/thermal.h>
463
464 / {
465 model = "Xunlong Orange Pi PC 2";
466 @@ -113,6 +114,72 @@
467 };
468 };
469
470 +&cpu0 {
471 + operating-points = <
472 + /* kHz uV */
473 + 1368000 1400000
474 + 1344000 1400000
475 + 1296000 1340000
476 + 1248000 1340000
477 + 1224000 1340000
478 + 1200000 1320000
479 + 1152000 1320000
480 + 1104000 1320000
481 + 1056000 1320000
482 + 1008000 1200000
483 + 960000 1200000
484 + 816000 1100000
485 + 648000 1100000
486 + 480000 1100000
487 + 240000 1100000
488 + 120000 1100000
489 + >;
490 + #cooling-cells = <2>;
491 + cooling-min-level = <0>;
492 + cooling-max-level = <15>;
493 + cpu0-supply = <&vdd_cpu>;
494 +};
495 +
496 +&cpu_thermal {
497 + trips {
498 + cpu_warm: cpu_warm {
499 + temperature = <65000>;
500 + hysteresis = <2000>;
501 + type = "passive";
502 + };
503 + cpu_hot: cpu_hot {
504 + temperature = <75000>;
505 + hysteresis = <2000>;
506 + type = "passive";
507 + };
508 + cpu_very_hot: cpu_very_hot {
509 + temperature = <90000>;
510 + hysteresis = <2000>;
511 + type = "passive";
512 + };
513 + cpu_crit: cpu_crit {
514 + temperature = <105000>;
515 + hysteresis = <2000>;
516 + type = "critical";
517 + };
518 + };
519 +
520 + cooling-maps {
521 + cpu_warm_limit_cpu {
522 + trip = <&cpu_warm>;
523 + cooling-device = <&cpu0 THERMAL_NO_LIMIT 10>;
524 + };
525 + cpu_hot_limit_cpu {
526 + trip = <&cpu_hot>;
527 + cooling-device = <&cpu0 12 12>;
528 + };
529 + cpu_very_hot_limit_cpu {
530 + trip = <&cpu_very_hot>;
531 + cooling-device = <&cpu0 14 THERMAL_NO_LIMIT>;
532 + };
533 + };
534 +};
535 +
536 &codec {
537 allwinner,audio-routing =
538 "Line Out", "LINEOUT",
539 @@ -184,6 +251,20 @@
540 status = "okay";
541 };
542
543 +&r_i2c {
544 + status = "okay";
545 +
546 + vdd_cpu: regulator@65 {
547 + compatible = "silergy,sy8106a";
548 + reg = <0x65>;
549 + regulator-min-microvolt = <1000000>;
550 + regulator-max-microvolt = <1400000>;
551 + regulator-ramp-delay = <200>;
552 + regulator-boot-on;
553 + regulator-always-on;
554 + };
555 +};
556 +
557 &uart0 {
558 pinctrl-names = "default";
559 pinctrl-0 = <&uart0_pins_a>;
560 diff '--exclude=scripts' -Naur a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
561 --- a/arch/arm64/Kconfig.platforms 2018-02-16 20:23:12.000000000 +0100
562 +++ b/arch/arm64/Kconfig.platforms 2018-03-02 10:15:32.982006000 +0100
563 @@ -12,8 +12,11 @@
564 select GENERIC_IRQ_CHIP
565 select PINCTRL
566 select RESET_CONTROLLER
567 + select PINCTRL_SUN50I_H5
568 + select PINCTRL_SUN8I_H3_R
569 help
570 - This enables support for Allwinner sunxi based SoCs like the A64.
571 + This enables support for Allwinner sunxi based SoCs like the A64
572 + and H5.
573
574 config ARCH_ALPINE
575 bool "Annapurna Labs Alpine platform"
576 diff '--exclude=scripts' -Naur a/Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt b/Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt
577 --- a/Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt 1970-01-01 01:00:00.000000000 +0100
578 +++ b/Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt 2018-03-02 10:14:31.935498001 +0100
579 @@ -0,0 +1,21 @@
580 +SY8106A Voltage regulator
581 +
582 +Required properties:
583 +- compatible: Must be "silergy,sy8106a"
584 +- reg: I2C slave address - must be <0x65>
585 +
586 +Any property defined as part of the core regulator binding, defined in
587 +regulator.txt, can also be used.
588 +
589 +Example:
590 +
591 + sy8106a {
592 + compatible = "silergy,sy8106a";
593 + reg = <0x65>;
594 + regulator-name = "sy8106a-vdd";
595 + regulator-min-microvolt = <1000000>;
596 + regulator-max-microvolt = <1400000>;
597 + regulator-ramp-delay = <200>;
598 + regulator-boot-on;
599 + regulator-always-on;
600 + };
601 diff '--exclude=scripts' -Naur a/Documentation/devicetree/bindings/thermal/sun8i-ths.txt b/Documentation/devicetree/bindings/thermal/sun8i-ths.txt
602 --- a/Documentation/devicetree/bindings/thermal/sun8i-ths.txt 1970-01-01 01:00:00.000000000 +0100
603 +++ b/Documentation/devicetree/bindings/thermal/sun8i-ths.txt 2018-03-02 10:14:49.344198000 +0100
604 @@ -0,0 +1,24 @@
605 +* Thermal sensor driver for Allwinner H3 SoC
606 +
607 +Required properties:
608 +- compatible : "allwinner,sun8i-h3-ths"
609 +- reg : Address range of the thermal sensor registers
610 +- resets : Must contain phandles to reset controls matching the entries
611 + of the names
612 +- reset-names : Must include the name "ahb"
613 +- clocks : Must contain phandles to clock controls matching the entries
614 + of the names
615 +- clock-names : Must contain "ahb" for the bus gate and "ths" for the THS
616 + clock
617 +
618 +Example:
619 +ths: ths@01c25000 {
620 + #thermal-sensor-cells = <0>;
621 + compatible = "allwinner,sun8i-h3-ths";
622 + reg = <0x01c25000 0x400>;
623 + interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
624 + resets = <&bus_rst 136>;
625 + reset-names = "ahb";
626 + clocks = <&bus_gates 72>, <&ths_clk>;
627 + clock-names = "ahb", "ths";
628 +};
629 diff '--exclude=scripts' -Naur a/drivers/clk/sunxi-ng/ccu_nkmp.c b/drivers/clk/sunxi-ng/ccu_nkmp.c
630 --- a/drivers/clk/sunxi-ng/ccu_nkmp.c 2018-02-16 20:23:12.000000000 +0100
631 +++ b/drivers/clk/sunxi-ng/ccu_nkmp.c 2018-03-02 10:15:14.204622000 +0100
632 @@ -21,16 +21,19 @@
633 };
634
635 static void ccu_nkmp_find_best(unsigned long parent, unsigned long rate,
636 - struct _ccu_nkmp *nkmp)
637 + struct _ccu_nkmp *nkmp, struct ccu_nkmp *_nkmp)
638 {
639 unsigned long best_rate = 0;
640 unsigned long best_n = 0, best_k = 0, best_m = 0, best_p = 0;
641 - unsigned long _n, _k, _m, _p;
642 + unsigned long _n, _k, _m, _p, _max_p;
643 +
644 + _max_p = (_nkmp->max_rate_for_p == 0 || rate <= _nkmp->max_rate_for_p) ?
645 + nkmp->max_p : nkmp->min_p;
646
647 for (_k = nkmp->min_k; _k <= nkmp->max_k; _k++) {
648 for (_n = nkmp->min_n; _n <= nkmp->max_n; _n++) {
649 for (_m = nkmp->min_m; _m <= nkmp->max_m; _m++) {
650 - for (_p = nkmp->min_p; _p <= nkmp->max_p; _p <<= 1) {
651 + for (_p = nkmp->min_p; _p <= _max_p; _p <<= 1) {
652 unsigned long tmp_rate;
653
654 tmp_rate = parent * _n * _k / (_m * _p);
655 @@ -125,7 +128,7 @@
656 _nkmp.min_p = 1;
657 _nkmp.max_p = nkmp->p.max ?: 1 << ((1 << nkmp->p.width) - 1);
658
659 - ccu_nkmp_find_best(*parent_rate, rate, &_nkmp);
660 + ccu_nkmp_find_best(*parent_rate, rate, &_nkmp, nkmp);
661
662 return *parent_rate * _nkmp.n * _nkmp.k / (_nkmp.m * _nkmp.p);
663 }
664 @@ -147,7 +150,7 @@
665 _nkmp.min_p = 1;
666 _nkmp.max_p = nkmp->p.max ?: 1 << ((1 << nkmp->p.width) - 1);
667
668 - ccu_nkmp_find_best(parent_rate, rate, &_nkmp);
669 + ccu_nkmp_find_best(parent_rate, rate, &_nkmp, nkmp);
670
671 spin_lock_irqsave(nkmp->common.lock, flags);
672
673 diff '--exclude=scripts' -Naur a/drivers/clk/sunxi-ng/ccu_nkmp.h b/drivers/clk/sunxi-ng/ccu_nkmp.h
674 --- a/drivers/clk/sunxi-ng/ccu_nkmp.h 2018-02-16 20:23:12.000000000 +0100
675 +++ b/drivers/clk/sunxi-ng/ccu_nkmp.h 2018-03-02 10:15:14.204622000 +0100
676 @@ -33,6 +33,7 @@
677 struct ccu_mult_internal k;
678 struct ccu_div_internal m;
679 struct ccu_div_internal p;
680 + unsigned long max_rate_for_p;
681
682 struct ccu_common common;
683 };
684 diff '--exclude=scripts' -Naur a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
685 --- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c 2018-02-16 20:23:12.000000000 +0100
686 +++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c 2018-03-02 10:15:23.565300000 +0100
687 @@ -29,15 +29,22 @@
688
689 #include "ccu-sun8i-h3.h"
690
691 -static SUNXI_CCU_NKMP_WITH_GATE_LOCK(pll_cpux_clk, "pll-cpux",
692 - "osc24M", 0x000,
693 - 8, 5, /* N */
694 - 4, 2, /* K */
695 - 0, 2, /* M */
696 - 16, 2, /* P */
697 - BIT(31), /* gate */
698 - BIT(28), /* lock */
699 - 0);
700 +static struct ccu_nkmp pll_cpux_clk = {
701 + .enable = BIT(31),
702 + .lock = BIT(28),
703 + .n = _SUNXI_CCU_MULT(8, 5),
704 + .k = _SUNXI_CCU_MULT(4, 2),
705 + .m = _SUNXI_CCU_DIV_MAX(0, 2, 1),
706 + .p = _SUNXI_CCU_DIV(16, 2),
707 + .max_rate_for_p = 288000000,
708 + .common = {
709 + .reg = 0x000,
710 + .hw.init = CLK_HW_INIT("pll-cpux",
711 + "osc24M",
712 + &ccu_nkmp_ops,
713 + 0),
714 + },
715 +};
716
717 /*
718 * The Audio PLL is supposed to have 4 outputs: 3 fixed factors from
719 diff '--exclude=scripts' -Naur a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c
720 --- a/drivers/cpufreq/cpufreq-dt-platdev.c 2018-02-16 20:23:12.000000000 +0100
721 +++ b/drivers/cpufreq/cpufreq-dt-platdev.c 2018-03-02 10:14:21.826446000 +0100
722 @@ -29,6 +29,7 @@
723 { .compatible = "allwinner,sun8i-a23", },
724 { .compatible = "allwinner,sun8i-a83t", },
725 { .compatible = "allwinner,sun8i-h3", },
726 + { .compatible = "allwinner,sun50i-h5", },
727
728 { .compatible = "apm,xgene-shadowcat", },
729
730 diff '--exclude=scripts' -Naur a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
731 --- a/drivers/regulator/Kconfig 2018-02-16 20:23:12.000000000 +0100
732 +++ b/drivers/regulator/Kconfig 2018-03-02 10:14:35.421240000 +0100
733 @@ -785,6 +785,13 @@
734 This driver supports the internal VMMC regulator in the STw481x
735 PMIC chips.
736
737 +config REGULATOR_SY8106A
738 + tristate "Silergy SY8106A"
739 + depends on I2C && (OF || COMPILE_TEST)
740 + select REGMAP_I2C
741 + help
742 + This driver provides support for SY8106A voltage regulator.
743 +
744 config REGULATOR_TPS51632
745 tristate "TI TPS51632 Power Regulator"
746 depends on I2C
747 @@ -959,4 +966,3 @@
748 WM8994 CODEC.
749
750 endif
751 -
752 diff '--exclude=scripts' -Naur a/drivers/regulator/Makefile b/drivers/regulator/Makefile
753 --- a/drivers/regulator/Makefile 2018-02-16 20:23:12.000000000 +0100
754 +++ b/drivers/regulator/Makefile 2018-03-02 10:14:35.421240000 +0100
755 @@ -98,6 +98,7 @@
756 obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o
757 obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
758 obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
759 +obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o
760 obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
761 obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
762 obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o
763 @@ -123,5 +124,4 @@
764 obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
765 obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o
766
767 -
768 ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
769 diff '--exclude=scripts' -Naur a/drivers/regulator/sy8106a-regulator.c b/drivers/regulator/sy8106a-regulator.c
770 --- a/drivers/regulator/sy8106a-regulator.c 1970-01-01 01:00:00.000000000 +0100
771 +++ b/drivers/regulator/sy8106a-regulator.c 2018-03-02 10:14:35.421240000 +0100
772 @@ -0,0 +1,167 @@
773 +/*
774 + * sy8106a-regulator.c - Regulator device driver for SY8106A
775 + *
776 + * Copyright (C) 2016 Ondřej Jirman <megous@megous.com>
777 + *
778 + * This library is free software; you can redistribute it and/or
779 + * modify it under the terms of the GNU Library General Public
780 + * License as published by the Free Software Foundation; either
781 + * version 2 of the License, or (at your option) any later version.
782 + *
783 + * This library is distributed in the hope that it will be useful,
784 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
785 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
786 + * Library General Public License for more details.
787 + *
788 + * You should have received a copy of the GNU Library General Public
789 + * License along with this library; if not, write to the
790 + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
791 + * Boston, MA 02110-1301, USA.
792 + */
793 +
794 +#include <linux/err.h>
795 +#include <linux/i2c.h>
796 +#include <linux/module.h>
797 +#include <linux/regmap.h>
798 +#include <linux/regulator/driver.h>
799 +#include <linux/regulator/of_regulator.h>
800 +
801 +#define SY8106A_REG_VOUT1_SEL 0x01
802 +#define SY8106A_REG_VOUT_COM 0x02
803 +#define SY8106A_REG_VOUT1_SEL_MASK 0x7f
804 +#define SY8106A_DISABLE_REG BIT(0)
805 +#define SY8106A_GO_BIT BIT(7)
806 +
807 +struct sy8106a {
808 + struct regulator_dev *rdev;
809 + struct regmap *regmap;
810 +};
811 +
812 +static const struct regmap_config sy8106a_regmap_config = {
813 + .reg_bits = 8,
814 + .val_bits = 8,
815 +};
816 +
817 +static int sy8106a_set_voltage_sel(struct regulator_dev *rdev, unsigned sel)
818 +{
819 + /* We use our set_voltage_sel in order to avoid unnecessary I2C chatter,
820 + * because the regulator_get_voltage_sel_regmap using apply_bit
821 + * would perform 4 unnecessary transfers instead of one, increasing the
822 + * chance of error.
823 + */
824 + return regmap_write(rdev->regmap, rdev->desc->vsel_reg,
825 + sel | SY8106A_GO_BIT);
826 +}
827 +
828 +static const struct regulator_ops sy8106a_ops = {
829 + .is_enabled = regulator_is_enabled_regmap,
830 + .set_voltage_sel = sy8106a_set_voltage_sel,
831 + .set_voltage_time_sel = regulator_set_voltage_time_sel,
832 + .get_voltage_sel = regulator_get_voltage_sel_regmap,
833 + .list_voltage = regulator_list_voltage_linear,
834 +};
835 +
836 +/* Default limits measured in millivolts and milliamps */
837 +#define SY8106A_MIN_MV 680
838 +#define SY8106A_MAX_MV 1950
839 +#define SY8106A_STEP_MV 10
840 +
841 +static const struct regulator_desc sy8106a_reg = {
842 + .name = "SY8106A",
843 + .id = 0,
844 + .ops = &sy8106a_ops,
845 + .type = REGULATOR_VOLTAGE,
846 + .n_voltages = ((SY8106A_MAX_MV - SY8106A_MIN_MV) / SY8106A_STEP_MV) + 1,
847 + .min_uV = (SY8106A_MIN_MV * 1000),
848 + .uV_step = (SY8106A_STEP_MV * 1000),
849 + .vsel_reg = SY8106A_REG_VOUT1_SEL,
850 + .vsel_mask = SY8106A_REG_VOUT1_SEL_MASK,
851 + .enable_reg = SY8106A_REG_VOUT_COM,
852 + .enable_mask = SY8106A_DISABLE_REG,
853 + .disable_val = SY8106A_DISABLE_REG,
854 + .enable_is_inverted = 1,
855 + .owner = THIS_MODULE,
856 +};
857 +
858 +/*
859 + * I2C driver interface functions
860 + */
861 +static int sy8106a_i2c_probe(struct i2c_client *i2c,
862 + const struct i2c_device_id *id)
863 +{
864 + struct sy8106a *chip;
865 + struct device *dev = &i2c->dev;
866 + struct regulator_dev *rdev = NULL;
867 + struct regulator_config config = { };
868 + unsigned int selector;
869 + int error;
870 +
871 + chip = devm_kzalloc(&i2c->dev, sizeof(struct sy8106a), GFP_KERNEL);
872 + if (!chip)
873 + return -ENOMEM;
874 +
875 + chip->regmap = devm_regmap_init_i2c(i2c, &sy8106a_regmap_config);
876 + if (IS_ERR(chip->regmap)) {
877 + error = PTR_ERR(chip->regmap);
878 + dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
879 + error);
880 + return error;
881 + }
882 +
883 + config.dev = &i2c->dev;
884 + config.regmap = chip->regmap;
885 + config.driver_data = chip;
886 +
887 + config.of_node = dev->of_node;
888 + config.init_data = of_get_regulator_init_data(dev, dev->of_node, &sy8106a_reg);
889 + if (!config.init_data) {
890 + return -ENOMEM;
891 + }
892 +
893 + /* Probe regulator */
894 + error = regmap_read(chip->regmap, SY8106A_REG_VOUT1_SEL, &selector);
895 + if (error) {
896 + dev_err(&i2c->dev, "Failed to read voltage at probe time: %d\n", error);
897 + return error;
898 + }
899 +
900 + rdev = devm_regulator_register(&i2c->dev, &sy8106a_reg, &config);
901 + if (IS_ERR(rdev)) {
902 + error = PTR_ERR(rdev);
903 + dev_err(&i2c->dev, "Failed to register SY8106A regulator: %d\n", error);
904 + return error;
905 + }
906 +
907 + chip->rdev = rdev;
908 +
909 + i2c_set_clientdata(i2c, chip);
910 +
911 + return 0;
912 +}
913 +
914 +static const struct of_device_id sy8106a_i2c_of_match[] = {
915 + { .compatible = "silergy,sy8106a" },
916 + { },
917 +};
918 +MODULE_DEVICE_TABLE(of, sy8106a_i2c_of_match);
919 +
920 +static const struct i2c_device_id sy8106a_i2c_id[] = {
921 + { "sy8106a", 0 },
922 + { },
923 +};
924 +MODULE_DEVICE_TABLE(i2c, sy8106a_i2c_id);
925 +
926 +static struct i2c_driver sy8106a_regulator_driver = {
927 + .driver = {
928 + .name = "sy8106a",
929 + .of_match_table = of_match_ptr(sy8106a_i2c_of_match),
930 + },
931 + .probe = sy8106a_i2c_probe,
932 + .id_table = sy8106a_i2c_id,
933 +};
934 +
935 +module_i2c_driver(sy8106a_regulator_driver);
936 +
937 +MODULE_AUTHOR("Ondřej Jirman <megous@megous.com>");
938 +MODULE_DESCRIPTION("Regulator device driver for Silergy SY8106A");
939 +MODULE_LICENSE("GPL v2");
940 diff '--exclude=scripts' -Naur a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
941 --- a/drivers/thermal/Kconfig 2018-02-16 20:23:12.000000000 +0100
942 +++ b/drivers/thermal/Kconfig 2018-03-02 10:14:59.889468000 +0100
943 @@ -412,6 +412,13 @@
944 source "drivers/thermal/broadcom/Kconfig"
945 endmenu
946
947 +config SUN8I_THS
948 + tristate "Thermal sensor driver for Allwinner H3"
949 + depends on MACH_SUN8I || (ARM64 && ARCH_SUNXI)
950 + depends on OF
951 + help
952 + Enable this to support thermal reporting on some newer Allwinner SoCs.
953 +
954 menu "Texas Instruments thermal drivers"
955 depends on ARCH_HAS_BANDGAP || COMPILE_TEST
956 depends on HAS_IOMEM
957 diff '--exclude=scripts' -Naur a/drivers/thermal/Makefile b/drivers/thermal/Makefile
958 --- a/drivers/thermal/Makefile 2018-02-16 20:23:12.000000000 +0100
959 +++ b/drivers/thermal/Makefile 2018-03-02 10:14:52.021536000 +0100
960 @@ -61,3 +61,4 @@
961 obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o
962 obj-$(CONFIG_ZX2967_THERMAL) += zx2967_thermal.o
963 obj-$(CONFIG_UNIPHIER_THERMAL) += uniphier_thermal.o
964 +obj-$(CONFIG_SUN8I_THS) += sun8i_ths.o
965 diff '--exclude=scripts' -Naur a/drivers/thermal/sun8i_ths.c b/drivers/thermal/sun8i_ths.c
966 --- a/drivers/thermal/sun8i_ths.c 1970-01-01 01:00:00.000000000 +0100
967 +++ b/drivers/thermal/sun8i_ths.c 2018-03-02 10:14:52.021536000 +0100
968 @@ -0,0 +1,239 @@
969 +/*
970 + * Thermal sensor driver for Allwinner H3 SoC
971 + *
972 + * Copyright (C) 2016 Ondřej Jirman
973 + * Based on the work of Josef Gajdusek <atx@atx.name>
974 + *
975 + * This software is licensed under the terms of the GNU General Public
976 + * License version 2, as published by the Free Software Foundation, and
977 + * may be copied, distributed, and modified under those terms.
978 + *
979 + * This program is distributed in the hope that it will be useful,
980 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
981 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
982 + * GNU General Public License for more details.
983 + *
984 + */
985 +
986 +#include <linux/clk.h>
987 +#include <linux/interrupt.h>
988 +#include <linux/io.h>
989 +#include <linux/module.h>
990 +#include <linux/of_device.h>
991 +#include <linux/platform_device.h>
992 +#include <linux/reset.h>
993 +#include <linux/slab.h>
994 +#include <linux/thermal.h>
995 +#include <linux/printk.h>
996 +
997 +#define THS_H3_CTRL0 0x00
998 +#define THS_H3_CTRL2 0x40
999 +#define THS_H3_INT_CTRL 0x44
1000 +#define THS_H3_STAT 0x48
1001 +#define THS_H3_FILTER 0x70
1002 +#define THS_H3_CDATA 0x74
1003 +#define THS_H3_DATA 0x80
1004 +
1005 +#define THS_H3_CTRL0_SENSOR_ACQ0(x) (x)
1006 +#define THS_H3_CTRL2_SENSE_EN BIT(0)
1007 +#define THS_H3_CTRL2_SENSOR_ACQ1(x) ((x) << 16)
1008 +#define THS_H3_INT_CTRL_DATA_IRQ_EN BIT(8)
1009 +#define THS_H3_INT_CTRL_THERMAL_PER(x) ((x) << 12)
1010 +#define THS_H3_STAT_DATA_IRQ_STS BIT(8)
1011 +#define THS_H3_FILTER_TYPE(x) ((x) << 0)
1012 +#define THS_H3_FILTER_EN BIT(2)
1013 +
1014 +#define THS_H3_CLK_IN 40000000 /* Hz */
1015 +#define THS_H3_DATA_PERIOD 330 /* ms */
1016 +
1017 +#define THS_H3_FILTER_TYPE_VALUE 2 /* average over 2^(n+1) samples */
1018 +#define THS_H3_FILTER_DIV (1 << (THS_H3_FILTER_TYPE_VALUE + 1))
1019 +#define THS_H3_INT_CTRL_THERMAL_PER_VALUE \
1020 + (THS_H3_DATA_PERIOD * (THS_H3_CLK_IN / 1000) / THS_H3_FILTER_DIV / 4096 - 1)
1021 +#define THS_H3_CTRL0_SENSOR_ACQ0_VALUE 0x3f /* 16us */
1022 +#define THS_H3_CTRL2_SENSOR_ACQ1_VALUE 0x3f
1023 +
1024 +struct sun8i_ths_data {
1025 + struct reset_control *reset;
1026 + struct clk *clk;
1027 + struct clk *busclk;
1028 + void __iomem *regs;
1029 + struct thermal_zone_device *tzd;
1030 + u32 temp;
1031 +};
1032 +
1033 +static int sun8i_ths_get_temp(void *_data, int *out)
1034 +{
1035 + struct sun8i_ths_data *data = _data;
1036 +
1037 + if (data->temp == 0)
1038 + return -EBUSY;
1039 +
1040 + /* Formula and parameters from the Allwinner 3.4 kernel */
1041 + *out = 217000 - (int)((data->temp * 1000000) / 8253);
1042 + return 0;
1043 +}
1044 +
1045 +static irqreturn_t sun8i_ths_irq_thread(int irq, void *_data)
1046 +{
1047 + struct sun8i_ths_data *data = _data;
1048 +
1049 + writel(THS_H3_STAT_DATA_IRQ_STS, data->regs + THS_H3_STAT);
1050 +
1051 + data->temp = readl(data->regs + THS_H3_DATA);
1052 + if (data->temp)
1053 + thermal_zone_device_update(data->tzd, THERMAL_EVENT_TEMP_SAMPLE);
1054 +
1055 + return IRQ_HANDLED;
1056 +}
1057 +
1058 +static void sun8i_ths_h3_init(struct sun8i_ths_data *data)
1059 +{
1060 + writel(THS_H3_CTRL0_SENSOR_ACQ0(THS_H3_CTRL0_SENSOR_ACQ0_VALUE),
1061 + data->regs + THS_H3_CTRL0);
1062 + writel(THS_H3_FILTER_EN | THS_H3_FILTER_TYPE(THS_H3_FILTER_TYPE_VALUE),
1063 + data->regs + THS_H3_FILTER);
1064 + writel(THS_H3_CTRL2_SENSOR_ACQ1(THS_H3_CTRL2_SENSOR_ACQ1_VALUE) |
1065 + THS_H3_CTRL2_SENSE_EN,
1066 + data->regs + THS_H3_CTRL2);
1067 + writel(THS_H3_INT_CTRL_THERMAL_PER(THS_H3_INT_CTRL_THERMAL_PER_VALUE) |
1068 + THS_H3_INT_CTRL_DATA_IRQ_EN,
1069 + data->regs + THS_H3_INT_CTRL);
1070 +}
1071 +
1072 +static const struct thermal_zone_of_device_ops sun8i_ths_thermal_ops = {
1073 + .get_temp = sun8i_ths_get_temp,
1074 +};
1075 +
1076 +static int sun8i_ths_probe(struct platform_device *pdev)
1077 +{
1078 + struct sun8i_ths_data *data;
1079 + struct resource *res;
1080 + int ret;
1081 + int irq;
1082 +
1083 + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
1084 + if (!data)
1085 + return -ENOMEM;
1086 +
1087 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1088 + if (!res) {
1089 + dev_err(&pdev->dev, "no memory resources defined\n");
1090 + return -EINVAL;
1091 + }
1092 +
1093 + data->regs = devm_ioremap_resource(&pdev->dev, res);
1094 + if (IS_ERR(data->regs)) {
1095 + ret = PTR_ERR(data->regs);
1096 + dev_err(&pdev->dev, "failed to ioremap THS registers: %d\n", ret);
1097 + return ret;
1098 + }
1099 +
1100 + irq = platform_get_irq(pdev, 0);
1101 + if (irq < 0) {
1102 + dev_err(&pdev->dev, "failed to get IRQ: %d\n", irq);
1103 + return irq;
1104 + }
1105 +
1106 + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
1107 + sun8i_ths_irq_thread, IRQF_ONESHOT,
1108 + dev_name(&pdev->dev), data);
1109 + if (ret)
1110 + return ret;
1111 +
1112 + data->busclk = devm_clk_get(&pdev->dev, "ahb");
1113 + if (IS_ERR(data->busclk)) {
1114 + ret = PTR_ERR(data->busclk);
1115 + dev_err(&pdev->dev, "failed to get ahb clk: %d\n", ret);
1116 + return ret;
1117 + }
1118 +
1119 + data->clk = devm_clk_get(&pdev->dev, "ths");
1120 + if (IS_ERR(data->clk)) {
1121 + ret = PTR_ERR(data->clk);
1122 + dev_err(&pdev->dev, "failed to get ths clk: %d\n", ret);
1123 + return ret;
1124 + }
1125 +
1126 + data->reset = devm_reset_control_get(&pdev->dev, "ahb");
1127 + if (IS_ERR(data->reset)) {
1128 + ret = PTR_ERR(data->reset);
1129 + dev_err(&pdev->dev, "failed to get reset: %d\n", ret);
1130 + return ret;
1131 + }
1132 +
1133 + ret = reset_control_deassert(data->reset);
1134 + if (ret) {
1135 + dev_err(&pdev->dev, "reset deassert failed: %d\n", ret);
1136 + return ret;
1137 + }
1138 +
1139 + ret = clk_prepare_enable(data->busclk);
1140 + if (ret) {
1141 + dev_err(&pdev->dev, "failed to enable bus clk: %d\n", ret);
1142 + goto err_assert_reset;
1143 + }
1144 +
1145 + ret = clk_prepare_enable(data->clk);
1146 + if (ret) {
1147 + dev_err(&pdev->dev, "failed to enable ths clk: %d\n", ret);
1148 + goto err_disable_bus;
1149 + }
1150 +
1151 + ret = clk_set_rate(data->clk, THS_H3_CLK_IN);
1152 + if (ret)
1153 + goto err_disable_ths;
1154 +
1155 + data->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, data,
1156 + &sun8i_ths_thermal_ops);
1157 + if (IS_ERR(data->tzd)) {
1158 + ret = PTR_ERR(data->tzd);
1159 + dev_err(&pdev->dev, "failed to register thermal zone: %d\n",
1160 + ret);
1161 + goto err_disable_ths;
1162 + }
1163 +
1164 + sun8i_ths_h3_init(data);
1165 +
1166 + platform_set_drvdata(pdev, data);
1167 + return 0;
1168 +
1169 +err_disable_ths:
1170 + clk_disable_unprepare(data->clk);
1171 +err_disable_bus:
1172 + clk_disable_unprepare(data->busclk);
1173 +err_assert_reset:
1174 + reset_control_assert(data->reset);
1175 + return ret;
1176 +}
1177 +
1178 +static int sun8i_ths_remove(struct platform_device *pdev)
1179 +{
1180 + struct sun8i_ths_data *data = platform_get_drvdata(pdev);
1181 +
1182 + reset_control_assert(data->reset);
1183 + clk_disable_unprepare(data->clk);
1184 + clk_disable_unprepare(data->busclk);
1185 + return 0;
1186 +}
1187 +
1188 +static const struct of_device_id sun8i_ths_id_table[] = {
1189 + { .compatible = "allwinner,sun8i-h3-ths", },
1190 + { /* sentinel */ },
1191 +};
1192 +MODULE_DEVICE_TABLE(of, sun8i_ths_id_table);
1193 +
1194 +static struct platform_driver sun8i_ths_driver = {
1195 + .probe = sun8i_ths_probe,
1196 + .remove = sun8i_ths_remove,
1197 + .driver = {
1198 + .name = "sun8i_ths",
1199 + .of_match_table = sun8i_ths_id_table,
1200 + },
1201 +};
1202 +
1203 +module_platform_driver(sun8i_ths_driver);
1204 +
1205 +MODULE_AUTHOR("Ondřej Jirman <megous@megous.com>");
1206 +MODULE_DESCRIPTION("Thermal sensor driver for Allwinner H3 SoC");
1207 +MODULE_LICENSE("GPL v2");