d5dcf223b03d88e7ec6857729df4e7a849ca7b42
[openwrt/staging/hauke.git] / target / linux / sunxi / patches-4.14 / 050-sun8i-H3-Orange-Pi-PC-cpufreq-thermal.patch
1 --- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi
2 +++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
3 @@ -383,6 +383,16 @@
4 };
5 };
6
7 + ths: thermal-sensor@1c25000 {
8 + reg = <0x01c25000 0x400>, <0x01c14234 0x4>;
9 + reg-names = "ths", "calibration";
10 + interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
11 + clocks = <&ccu CLK_BUS_THS>, <&ccu CLK_THS>;
12 + clock-names = "ahb", "ths";
13 + resets = <&ccu RST_BUS_THS>;
14 + reset-names = "ahb";
15 + };
16 +
17 timer@01c20c00 {
18 compatible = "allwinner,sun4i-a10-timer";
19 reg = <0x01c20c00 0xa0>;
20 @@ -632,6 +642,20 @@
21 #reset-cells = <1>;
22 };
23
24 + r_i2c: i2c@1f02400 {
25 + compatible = "allwinner,sun6i-a31-i2c";
26 + reg = <0x01f02400 0x400>;
27 + interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
28 + pinctrl-names = "default";
29 + pinctrl-0 = <&r_i2c_pins>;
30 + clocks = <&r_ccu CLK_APB0_I2C>;
31 + clock-frequency = <100000>;
32 + resets = <&r_ccu RST_APB0_I2C>;
33 + status = "disabled";
34 + #address-cells = <1>;
35 + #size-cells = <0>;
36 + };
37 +
38 codec_analog: codec-analog@01f015c0 {
39 compatible = "allwinner,sun8i-h3-codec-analog";
40 reg = <0x01f015c0 0x4>;
41 @@ -662,6 +686,11 @@
42 pins = "PL11";
43 function = "s_cir_rx";
44 };
45 +
46 + r_i2c_pins: r-i2c {
47 + pins = "PL0", "PL1";
48 + function = "s_i2c";
49 + };
50 };
51 };
52 };
53
54 --- a/arch/arm/boot/dts/sun8i-h3.dtsi
55 +++ b/arch/arm/boot/dts/sun8i-h3.dtsi
56 @@ -43,34 +43,95 @@
57 #include "sunxi-h3-h5.dtsi"
58
59 / {
60 + cpu0_opp_table: opp_table0 {
61 + compatible = "operating-points-v2";
62 + opp-shared;
63 +
64 + opp@480000000 {
65 + opp-hz = /bits/ 64 <480000000>;
66 + opp-microvolt = <1040000 1040000 1100000>;
67 + clock-latency-ns = <244144>; /* 8 32k periods */
68 + opp-suspend;
69 + };
70 +
71 + opp@648000000 {
72 + opp-hz = /bits/ 64 <648000000>;
73 + opp-microvolt = <1040000 1040000 1300000>;
74 + clock-latency-ns = <244144>; /* 8 32k periods */
75 + };
76 +
77 + opp@816000000 {
78 + opp-hz = /bits/ 64 <816000000>;
79 + opp-microvolt = <1100000 1100000 1300000>;
80 + clock-latency-ns = <244144>; /* 8 32k periods */
81 + };
82 +
83 + opp@1008000000 {
84 + opp-hz = /bits/ 64 <1008000000>;
85 + opp-microvolt = <1140000 1140000 1300000>;
86 + clock-latency-ns = <244144>; /* 8 32k periods */
87 + };
88 +
89 + opp@1200000000 {
90 + opp-hz = /bits/ 64 <1200000000>;
91 + opp-microvolt = <1200000 1200000 1300000>;
92 + clock-latency-ns = <244144>; /* 8 32k periods */
93 + };
94 + };
95 +
96 cpus {
97 #address-cells = <1>;
98 #size-cells = <0>;
99
100 - cpu@0 {
101 + cpu0: cpu@0 {
102 compatible = "arm,cortex-a7";
103 device_type = "cpu";
104 reg = <0>;
105 + clocks = <&ccu CLK_CPUX>;
106 + clock-names = "cpu";
107 + operating-points-v2 = <&cpu0_opp_table>;
108 + clock-frequency = <1200000000>;
109 + #cooling-cells = <0x2>;
110 };
111
112 cpu@1 {
113 compatible = "arm,cortex-a7";
114 device_type = "cpu";
115 reg = <1>;
116 + operating-points-v2 = <&cpu0_opp_table>;
117 + clock-frequency = <1200000000>;
118 };
119
120 cpu@2 {
121 compatible = "arm,cortex-a7";
122 device_type = "cpu";
123 reg = <2>;
124 + operating-points-v2 = <&cpu0_opp_table>;
125 + clock-frequency = <1200000000>;
126 };
127
128 cpu@3 {
129 compatible = "arm,cortex-a7";
130 device_type = "cpu";
131 reg = <3>;
132 + operating-points-v2 = <&cpu0_opp_table>;
133 + clock-frequency = <1200000000>;
134 };
135 };
136 +
137 + iio-hwmon {
138 + compatible = "iio-hwmon";
139 + io-channels = <&ths>;
140 + };
141 +
142 + thermal-zones {
143 + cpu_thermal: cpu-thermal {
144 + /* milliseconds */
145 + polling-delay-passive = <250>;
146 + polling-delay = <1000>;
147 + thermal-sensors = <&ths 0>;
148 + };
149 + };
150
151 timer {
152 compatible = "arm,armv7-timer";
153 @@ -121,6 +177,12 @@
154 "sample";
155 };
156
157 +&ths {
158 + compatible = "allwinner,sun8i-h3-ths";
159 + #thermal-sensor-cells = <0>;
160 + #io-channel-cells = <0>;
161 +};
162 +
163 &pio {
164 compatible = "allwinner,sun8i-h3-pinctrl";
165 };
166
167 --- a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
168 +++ b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
169 @@ -42,10 +42,10 @@
170
171 /dts-v1/;
172 #include "sun8i-h3.dtsi"
173 -#include "sunxi-common-regulators.dtsi"
174
175 #include <dt-bindings/gpio/gpio.h>
176 #include <dt-bindings/input/input.h>
177 +#include <dt-bindings/thermal/thermal.h>
178
179 / {
180 model = "Xunlong Orange Pi PC";
181 @@ -88,6 +88,109 @@
182 gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
183 };
184 };
185 +
186 + reg_vcc3v3: vcc3v3 {
187 + compatible = "regulator-fixed";
188 + regulator-name = "vcc3v3";
189 + regulator-min-microvolt = <3300000>;
190 + regulator-max-microvolt = <3300000>;
191 + };
192 +
193 + reg_usb0_vbus: usb0-vbus {
194 + compatible = "regulator-fixed";
195 + regulator-name = "usb0-vbus";
196 + regulator-min-microvolt = <5000000>;
197 + regulator-max-microvolt = <5000000>;
198 + enable-active-high;
199 + gpio = <&r_pio 0 2 GPIO_ACTIVE_HIGH>; /* PL2 */
200 + status = "okay";
201 + };
202 +};
203 +
204 +&cpu0_opp_table {
205 + 1368000000 {
206 + opp-hz = /bits/ 64 <1368000000>;
207 + opp-microvolt = <1340000 1340000 1400000>;
208 + clock-latency-ns = <244144>; /* 8 32k periods */
209 + };
210 +
211 + 1440000000 {
212 + opp-hz = /bits/ 64 <1440000000>;
213 + opp-microvolt = <1400000 1400000 1400000>;
214 + clock-latency-ns = <244144>; /* 8 32k periods */
215 + };
216 +
217 + 1512000000 {
218 + opp-hz = /bits/ 64 <1512000000>;
219 + opp-microvolt = <1400000 1400000 1400000>;
220 + clock-latency-ns = <244144>; /* 8 32k periods */
221 + };
222 +};
223 +
224 +&cpu0 {
225 + cooling-min-level = <0>;
226 + cooling-max-level = <15>;
227 + cpu-supply = <&reg_sy8106a>;
228 +};
229 +
230 +&cpu_thermal {
231 + trips {
232 + cpu_warm: cpu_warm {
233 + temperature = <65000>;
234 + hysteresis = <2000>;
235 + type = "passive";
236 + };
237 +
238 + cpu_hot: cpu_hot {
239 + temperature = <75000>;
240 + hysteresis = <2000>;
241 + type = "passive";
242 + };
243 +
244 + cpu_very_hot: cpu_very_hot {
245 + temperature = <90000>;
246 + hysteresis = <2000>;
247 + type = "passive";
248 + };
249 +
250 + cpu_crit: cpu_crit {
251 + temperature = <105000>;
252 + hysteresis = <2000>;
253 + type = "critical";
254 + };
255 + };
256 +
257 + cooling-maps {
258 + cpu_warm_limit_cpu {
259 + trip = <&cpu_warm>;
260 + cooling-device = <&cpu0 THERMAL_NO_LIMIT 10>;
261 + };
262 +
263 + cpu_hot_limit_cpu {
264 + trip = <&cpu_hot>;
265 + cooling-device = <&cpu0 12 12>;
266 + };
267 +
268 + cpu_very_hot_limit_cpu {
269 + trip = <&cpu_very_hot>;
270 + cooling-device = <&cpu0 14 THERMAL_NO_LIMIT>;
271 + };
272 + };
273 +};
274 +
275 +&r_i2c {
276 + status = "okay";
277 +
278 + reg_sy8106a: regulator@65 {
279 + compatible = "silergy,sy8106a";
280 + reg = <0x65>;
281 + regulator-name = "vdd-cpux";
282 + regulator-min-microvolt = <1000000>;
283 + regulator-max-microvolt = <1400000>;
284 + regulator-ramp-delay = <200>;
285 + regulator-boot-on;
286 + regulator-always-on;
287 + };
288 };
289
290 &codec {
291
292 --- a/arch/arm/configs/sunxi_defconfig
293 +++ b/arch/arm/configs/sunxi_defconfig
294 @@ -40,6 +40,7 @@
295 CONFIG_AHCI_SUNXI=y
296 CONFIG_NETDEVICES=y
297 CONFIG_SUN4I_EMAC=y
298 +CONFIG_SUN8I_THS=y
299 # CONFIG_NET_VENDOR_ARC is not set
300 # CONFIG_NET_CADENCE is not set
301 # CONFIG_NET_VENDOR_BROADCOM is not set
302 @@ -93,6 +94,7 @@
303 CONFIG_REGULATOR_FIXED_VOLTAGE=y
304 CONFIG_REGULATOR_AXP20X=y
305 CONFIG_REGULATOR_GPIO=y
306 +CONFIG_REGULATOR_SY8106A=y
307 CONFIG_MEDIA_SUPPORT=y
308 CONFIG_RC_CORE=y
309 CONFIG_RC_DEVICES=y
310
311 --- a/drivers/regulator/Kconfig
312 +++ b/drivers/regulator/Kconfig
313 @@ -785,6 +785,13 @@
314 This driver supports the internal VMMC regulator in the STw481x
315 PMIC chips.
316
317 +config REGULATOR_SY8106A
318 + tristate "Silergy SY8106A regulator"
319 + depends on I2C && (OF || COMPILE_TEST)
320 + select REGMAP_I2C
321 + help
322 + This driver supports SY8106A single output regulator.
323 +
324 config REGULATOR_TPS51632
325 tristate "TI TPS51632 Power Regulator"
326 depends on I2C
327
328 --- a/drivers/regulator/Makefile
329 +++ b/drivers/regulator/Makefile
330 @@ -98,6 +98,7 @@
331 obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o
332 obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
333 obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
334 +obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o
335 obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
336 obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
337 obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o
338
339 --- a/drivers/thermal/Kconfig
340 +++ b/drivers/thermal/Kconfig
341 @@ -407,6 +407,16 @@
342 Enable this option if you want to have support for thermal management
343 controller present in Mediatek SoCs
344
345 +config SUN8I_THS
346 + tristate "Thermal sensor driver for Allwinner H3"
347 + depends on MACH_SUN8I || COMPILE_TEST
348 + depends on HAS_IOMEM
349 + depends on NVMEM_SUNXI_SID
350 + depends on OF
351 + depends on RESET_CONTROLLER
352 + help
353 + Enable this options for support thermal reporting on some Allwinner SoCs.
354 +
355 menu "Broadcom thermal drivers"
356 depends on ARCH_BCM || COMPILE_TEST
357 source "drivers/thermal/broadcom/Kconfig"
358
359 --- a/drivers/thermal/Makefile
360 +++ b/drivers/thermal/Makefile
361 @@ -58,6 +58,7 @@
362 obj-$(CONFIG_TEGRA_SOCTHERM) += tegra/
363 obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o
364 obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o
365 +obj-$(CONFIG_SUN8I_THS) += sun8i_ths.o
366 obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o
367 obj-$(CONFIG_ZX2967_THERMAL) += zx2967_thermal.o
368 obj-$(CONFIG_UNIPHIER_THERMAL) += uniphier_thermal.o
369
370 --- /dev/null
371 +++ b/drivers/regulator/sy8106a-regulator.c
372 @@ -0,0 +1,168 @@
373 +/*
374 + * sy8106a-regulator.c - Regulator device driver for SY8106A
375 + *
376 + * Copyright (C) 2016 Ondřej Jirman <megous@megous.com>
377 + *
378 + * This program is free software; you can redistribute it and/or
379 + * modify it under the terms of the GNU Library General Public
380 + * License as published by the Free Software Foundation; either
381 + * version 2 of the License, or (at your option) any later version.
382 + *
383 + * This program is distributed in the hope that it will be useful,
384 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
385 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
386 + * Library General Public License for more details.
387 + */
388 +
389 +#include <linux/err.h>
390 +#include <linux/i2c.h>
391 +#include <linux/module.h>
392 +#include <linux/regmap.h>
393 +#include <linux/regulator/driver.h>
394 +#include <linux/regulator/of_regulator.h>
395 +
396 +#define SY8106A_REG_VOUT1_SEL 0x01
397 +#define SY8106A_REG_VOUT_COM 0x02
398 +#define SY8106A_REG_VOUT1_SEL_MASK 0x7f
399 +#define SY8106A_DISABLE_REG BIT(0)
400 +/*
401 + * The I2C controlled voltage will only work when this bit is set; otherwise
402 + * it will behave like a fixed regulator.
403 + */
404 +#define SY8106A_GO_BIT BIT(7)
405 +
406 +struct sy8106a {
407 + struct regulator_dev *rdev;
408 + struct regmap *regmap;
409 +};
410 +
411 +static const struct regmap_config sy8106a_regmap_config = {
412 + .reg_bits = 8,
413 + .val_bits = 8,
414 +};
415 +
416 +static int sy8106a_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel)
417 +{
418 + /* We use our set_voltage_sel in order to avoid unnecessary I2C
419 + * chatter, because the regulator_get_voltage_sel_regmap using
420 + * apply_bit would perform 4 unnecessary transfers instead of one,
421 + * increasing the chance of error.
422 + */
423 + return regmap_write(rdev->regmap, rdev->desc->vsel_reg,
424 + sel | SY8106A_GO_BIT);
425 +}
426 +
427 +static const struct regulator_ops sy8106a_ops = {
428 + .set_voltage_sel = sy8106a_set_voltage_sel,
429 + .set_voltage_time_sel = regulator_set_voltage_time_sel,
430 + .get_voltage_sel = regulator_get_voltage_sel_regmap,
431 + .list_voltage = regulator_list_voltage_linear,
432 + /* Enabling/disabling the regulator is not yet implemented */
433 +};
434 +
435 +/* Default limits measured in millivolts and milliamps */
436 +#define SY8106A_MIN_MV 680
437 +#define SY8106A_MAX_MV 1950
438 +#define SY8106A_STEP_MV 10
439 +
440 +static const struct regulator_desc sy8106a_reg = {
441 + .name = "SY8106A",
442 + .id = 0,
443 + .ops = &sy8106a_ops,
444 + .type = REGULATOR_VOLTAGE,
445 + .n_voltages = ((SY8106A_MAX_MV - SY8106A_MIN_MV) / SY8106A_STEP_MV) + 1,
446 + .min_uV = (SY8106A_MIN_MV * 1000),
447 + .uV_step = (SY8106A_STEP_MV * 1000),
448 + .vsel_reg = SY8106A_REG_VOUT1_SEL,
449 + .vsel_mask = SY8106A_REG_VOUT1_SEL_MASK,
450 + /*
451 + * This ramp_delay is a conservative default value which works on
452 + * H3/H5 boards VDD-CPUX situations.
453 + */
454 + .ramp_delay = 200,
455 + .owner = THIS_MODULE,
456 +};
457 +
458 +/*
459 + * I2C driver interface functions
460 + */
461 +static int sy8106a_i2c_probe(struct i2c_client *i2c,
462 + const struct i2c_device_id *id)
463 +{
464 + struct sy8106a *chip;
465 + struct device *dev = &i2c->dev;
466 + struct regulator_dev *rdev = NULL;
467 + struct regulator_config config = { };
468 + unsigned int selector;
469 + int error;
470 +
471 + chip = devm_kzalloc(&i2c->dev, sizeof(struct sy8106a), GFP_KERNEL);
472 + if (!chip)
473 + return -ENOMEM;
474 +
475 + chip->regmap = devm_regmap_init_i2c(i2c, &sy8106a_regmap_config);
476 + if (IS_ERR(chip->regmap)) {
477 + error = PTR_ERR(chip->regmap);
478 + dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
479 + error);
480 + return error;
481 + }
482 +
483 + config.dev = &i2c->dev;
484 + config.regmap = chip->regmap;
485 + config.driver_data = chip;
486 +
487 + config.of_node = dev->of_node;
488 + config.init_data = of_get_regulator_init_data(dev, dev->of_node,
489 + &sy8106a_reg);
490 +
491 + if (!config.init_data)
492 + return -ENOMEM;
493 +
494 + /* Probe regulator */
495 + error = regmap_read(chip->regmap, SY8106A_REG_VOUT1_SEL, &selector);
496 + if (error) {
497 + dev_err(&i2c->dev, "Failed to read voltage at probe time: %d\n", error);
498 + return error;
499 + }
500 +
501 + rdev = devm_regulator_register(&i2c->dev, &sy8106a_reg, &config);
502 + if (IS_ERR(rdev)) {
503 + error = PTR_ERR(rdev);
504 + dev_err(&i2c->dev, "Failed to register SY8106A regulator: %d\n", error);
505 + return error;
506 + }
507 +
508 + chip->rdev = rdev;
509 +
510 + i2c_set_clientdata(i2c, chip);
511 +
512 + return 0;
513 +}
514 +
515 +static const struct of_device_id sy8106a_i2c_of_match[] = {
516 + { .compatible = "silergy,sy8106a" },
517 + { },
518 +};
519 +MODULE_DEVICE_TABLE(of, sy8106a_i2c_of_match);
520 +
521 +static const struct i2c_device_id sy8106a_i2c_id[] = {
522 + { "sy8106a", 0 },
523 + { },
524 +};
525 +MODULE_DEVICE_TABLE(i2c, sy8106a_i2c_id);
526 +
527 +static struct i2c_driver sy8106a_regulator_driver = {
528 + .driver = {
529 + .name = "sy8106a",
530 + .of_match_table = of_match_ptr(sy8106a_i2c_of_match),
531 + },
532 + .probe = sy8106a_i2c_probe,
533 + .id_table = sy8106a_i2c_id,
534 +};
535 +
536 +module_i2c_driver(sy8106a_regulator_driver);
537 +
538 +MODULE_AUTHOR("Ondřej Jirman <megous@megous.com>");
539 +MODULE_DESCRIPTION("Regulator device driver for Silergy SY8106A");
540 +MODULE_LICENSE("GPL");
541
542 --- /dev/null
543 +++ b/drivers/thermal/sun8i_ths.c
544 @@ -0,0 +1,332 @@
545 +/*
546 + * Thermal sensor driver for Allwinner new SoCs
547 + *
548 + * Copyright (C) 2016 Ondřej Jirman
549 + * Based on the work of Josef Gajdusek <atx@atx.name>
550 + *
551 + * This software is licensed under the terms of the GNU General Public
552 + * License version 2, as published by the Free Software Foundation, and
553 + * may be copied, distributed, and modified under those terms.
554 + *
555 + * This program is distributed in the hope that it will be useful,
556 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
557 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
558 + * GNU General Public License for more details.
559 + *
560 + */
561 +
562 +#include <linux/clk.h>
563 +#include <linux/interrupt.h>
564 +#include <linux/io.h>
565 +#include <linux/module.h>
566 +#include <linux/nvmem-consumer.h>
567 +#include <linux/of_device.h>
568 +#include <linux/platform_device.h>
569 +#include <linux/reset.h>
570 +#include <linux/slab.h>
571 +#include <linux/thermal.h>
572 +#include <linux/printk.h>
573 +
574 +#define THS_H3_MAX_SENSOR_NUM 4
575 +
576 +#define THS_H3_CTRL0 0x00
577 +#define THS_H3_CTRL2 0x40
578 +#define THS_H3_INT_CTRL 0x44
579 +#define THS_H3_STAT 0x48
580 +#define THS_H3_FILTER 0x70
581 +#define THS_H3_CDATA0 0x74
582 +#define THS_H3_CDATA1 0x74
583 +#define THS_H3_DATA(n) (0x80 + 4 * (n))
584 +
585 +#define THS_H3_CTRL0_SENSOR_ACQ0(x) (x)
586 +#define THS_H3_CTRL2_SENSE_EN(n) BIT(0 + (n))
587 +#define THS_H3_CTRL2_SENSOR_ACQ1(x) ((x) << 16)
588 +#define THS_H3_INT_CTRL_DATA_IRQ_EN(n) BIT(8 + (n))
589 +#define THS_H3_INT_CTRL_THERMAL_PER(x) ((x) << 12)
590 +#define THS_H3_STAT_DATA_IRQ_STS(n) BIT(8 + (n))
591 +#define THS_H3_FILTER_TYPE(x) ((x) << 0)
592 +#define THS_H3_FILTER_EN BIT(2)
593 +
594 +#define THS_H3_CLK_IN 40000000 /* Hz */
595 +#define THS_H3_DATA_PERIOD 330 /* ms */
596 +
597 +#define THS_H3_FILTER_TYPE_VALUE 2 /* average over 2^(n+1) samples */
598 +#define THS_H3_FILTER_DIV (1 << (THS_H3_FILTER_TYPE_VALUE + 1))
599 +#define THS_H3_INT_CTRL_THERMAL_PER_VALUE \
600 + (THS_H3_DATA_PERIOD * (THS_H3_CLK_IN / 1000) / THS_H3_FILTER_DIV / 4096 - 1)
601 +#define THS_H3_CTRL0_SENSOR_ACQ0_VALUE 0x3f /* 16us */
602 +#define THS_H3_CTRL2_SENSOR_ACQ1_VALUE 0x3f
603 +
604 +struct sun8i_ths_data;
605 +
606 +struct sun8i_ths_sensor {
607 + struct sun8i_ths_data *data;
608 + int id;
609 + struct thermal_zone_device *tzd;
610 + u32 val;
611 +};
612 +
613 +struct sun8i_ths_cfg {
614 + int sensor_num;
615 + int (*calc_temp)(u32 val);
616 +};
617 +
618 +struct sun8i_ths_data {
619 + struct reset_control *reset;
620 + struct clk *clk;
621 + struct clk *busclk;
622 + void __iomem *regs;
623 + struct nvmem_cell *calcell;
624 + const struct sun8i_ths_cfg *cfg;
625 + struct sun8i_ths_sensor sensors[THS_H3_MAX_SENSOR_NUM];
626 +};
627 +
628 +static int sun8i_ths_calc_temp_h3(u32 val)
629 +{
630 + return (217000 - (int)((val * 1000000) / 8253));
631 +}
632 +
633 +static int sun8i_ths_get_temp(void *_data, int *out)
634 +{
635 + struct sun8i_ths_sensor *sensor = _data;
636 +
637 + if (sensor->val == 0)
638 + return -EBUSY;
639 +
640 + /* Formula and parameters from the Allwinner 3.4 kernel */
641 + *out = sensor->data->cfg->calc_temp(sensor->val);
642 + return 0;
643 +}
644 +
645 +static irqreturn_t sun8i_ths_irq_thread(int irq, void *_data)
646 +{
647 + struct sun8i_ths_data *data = _data;
648 + int i;
649 +
650 + for (i = 0; i < data->cfg->sensor_num; i++) {
651 + if (!(readl(data->regs + THS_H3_STAT) &
652 + THS_H3_STAT_DATA_IRQ_STS(i)))
653 + continue;
654 +
655 + writel(THS_H3_STAT_DATA_IRQ_STS(i), data->regs + THS_H3_STAT);
656 +
657 + data->sensors[i].val = readl(data->regs + THS_H3_DATA(i));
658 + if (data->sensors[i].val)
659 + thermal_zone_device_update(data->sensors[i].tzd,
660 + THERMAL_EVENT_TEMP_SAMPLE);
661 + }
662 +
663 + return IRQ_HANDLED;
664 +}
665 +
666 +static void sun8i_ths_init(struct sun8i_ths_data *data)
667 +{
668 + u32 val;
669 + int i;
670 +
671 + writel(THS_H3_CTRL0_SENSOR_ACQ0(THS_H3_CTRL0_SENSOR_ACQ0_VALUE),
672 + data->regs + THS_H3_CTRL0);
673 + writel(THS_H3_FILTER_EN | THS_H3_FILTER_TYPE(THS_H3_FILTER_TYPE_VALUE),
674 + data->regs + THS_H3_FILTER);
675 +
676 + val = THS_H3_CTRL2_SENSOR_ACQ1(THS_H3_CTRL2_SENSOR_ACQ1_VALUE);
677 + for (i = 0; i < data->cfg->sensor_num; i++)
678 + val |= THS_H3_CTRL2_SENSE_EN(i);
679 + writel(val, data->regs + THS_H3_CTRL2);
680 +
681 + val = THS_H3_INT_CTRL_THERMAL_PER(THS_H3_INT_CTRL_THERMAL_PER_VALUE);
682 + for (i = 0; i < data->cfg->sensor_num; i++)
683 + val |= THS_H3_INT_CTRL_DATA_IRQ_EN(i);
684 + writel(val, data->regs + THS_H3_INT_CTRL);
685 +}
686 +
687 +static int sun8i_ths_calibrate(struct sun8i_ths_data *data)
688 +{
689 + u32 *caldata;
690 + size_t callen;
691 +
692 + caldata = nvmem_cell_read(data->calcell, &callen);
693 + if (IS_ERR(caldata))
694 + return PTR_ERR(caldata);
695 +
696 + writel(be32_to_cpu(caldata[0]), data->regs + THS_H3_CDATA0);
697 + if (callen > 4)
698 + writel(be32_to_cpu(caldata[1]), data->regs + THS_H3_CDATA1);
699 +
700 + kfree(caldata);
701 + return 0;
702 +}
703 +
704 +static const struct thermal_zone_of_device_ops sun8i_ths_thermal_ops = {
705 + .get_temp = sun8i_ths_get_temp,
706 +};
707 +
708 +static int sun8i_ths_probe(struct platform_device *pdev)
709 +{
710 + struct sun8i_ths_data *data;
711 + struct resource *res;
712 + int ret, irq, i;
713 +
714 + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
715 + if (!data)
716 + return -ENOMEM;
717 +
718 + data->cfg = of_device_get_match_data(&pdev->dev);
719 + if (!data->cfg)
720 + return -EINVAL;
721 +
722 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
723 + if (!res) {
724 + dev_err(&pdev->dev, "no memory resources defined\n");
725 + return -EINVAL;
726 + }
727 +
728 + data->regs = devm_ioremap_resource(&pdev->dev, res);
729 + if (IS_ERR(data->regs)) {
730 + ret = PTR_ERR(data->regs);
731 + dev_err(&pdev->dev, "failed to ioremap THS registers: %d\n", ret);
732 + return ret;
733 + }
734 +
735 + irq = platform_get_irq(pdev, 0);
736 + if (irq < 0) {
737 + dev_err(&pdev->dev, "failed to get IRQ: %d\n", irq);
738 + return irq;
739 + }
740 +
741 + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
742 + sun8i_ths_irq_thread, IRQF_ONESHOT,
743 + dev_name(&pdev->dev), data);
744 + if (ret)
745 + return ret;
746 +
747 + data->busclk = devm_clk_get(&pdev->dev, "ahb");
748 + if (IS_ERR(data->busclk)) {
749 + ret = PTR_ERR(data->busclk);
750 + dev_err(&pdev->dev, "failed to get ahb clk: %d\n", ret);
751 + return ret;
752 + }
753 +
754 + data->clk = devm_clk_get(&pdev->dev, "ths");
755 + if (IS_ERR(data->clk)) {
756 + ret = PTR_ERR(data->clk);
757 + dev_err(&pdev->dev, "failed to get ths clk: %d\n", ret);
758 + return ret;
759 + }
760 +
761 + data->reset = devm_reset_control_get(&pdev->dev, "ahb");
762 + if (IS_ERR(data->reset)) {
763 + ret = PTR_ERR(data->reset);
764 + dev_err(&pdev->dev, "failed to get reset: %d\n", ret);
765 + return ret;
766 + }
767 +
768 + ret = reset_control_deassert(data->reset);
769 + if (ret) {
770 + dev_err(&pdev->dev, "reset deassert failed: %d\n", ret);
771 + return ret;
772 + }
773 +
774 + ret = clk_prepare_enable(data->busclk);
775 + if (ret) {
776 + dev_err(&pdev->dev, "failed to enable bus clk: %d\n", ret);
777 + goto err_assert_reset;
778 + }
779 +
780 + ret = clk_prepare_enable(data->clk);
781 + if (ret) {
782 + dev_err(&pdev->dev, "failed to enable ths clk: %d\n", ret);
783 + goto err_disable_bus;
784 + }
785 +
786 + ret = clk_set_rate(data->clk, THS_H3_CLK_IN);
787 + if (ret)
788 + goto err_disable_ths;
789 +
790 + data->calcell = devm_nvmem_cell_get(&pdev->dev, "cal");
791 + if (IS_ERR(data->calcell)) {
792 + if (PTR_ERR(data->calcell) == -EPROBE_DEFER) {
793 + ret = PTR_ERR(data->calcell);
794 + goto err_disable_ths;
795 + }
796 + /*
797 + * Even if the external calibration data stored in eFUSE is
798 + * not accessible, the THS hardware can still work, although
799 + * the data won't be so accurate.
800 + * The default value of calibration register is 0x800 for
801 + * every sensor, and the calibration value is usually 0x7xx
802 + * or 0x8xx, so they won't be away from the default value
803 + * for a lot.
804 + * So here we do not return if the calibartion data is not
805 + * available, except the probe needs deferring.
806 + */
807 + } else {
808 + ret = sun8i_ths_calibrate(data);
809 + if (ret)
810 + goto err_disable_ths;
811 + }
812 +
813 + for (i = 0; i < data->cfg->sensor_num; i++) {
814 + data->sensors[i].data = data;
815 + data->sensors[i].id = i;
816 + data->sensors[i].tzd =
817 + devm_thermal_zone_of_sensor_register(&pdev->dev,
818 + i, &data->sensors[i], &sun8i_ths_thermal_ops);
819 + if (IS_ERR(data->sensors[i].tzd)) {
820 + ret = PTR_ERR(data->sensors[i].tzd);
821 + dev_err(&pdev->dev,
822 + "failed to register thermal zone %d: %d\n",
823 + i, ret);
824 + goto err_disable_ths;
825 + }
826 + }
827 +
828 + sun8i_ths_init(data);
829 +
830 + platform_set_drvdata(pdev, data);
831 + return 0;
832 +
833 +err_disable_ths:
834 + clk_disable_unprepare(data->clk);
835 +err_disable_bus:
836 + clk_disable_unprepare(data->busclk);
837 +err_assert_reset:
838 + reset_control_assert(data->reset);
839 + return ret;
840 +}
841 +
842 +static int sun8i_ths_remove(struct platform_device *pdev)
843 +{
844 + struct sun8i_ths_data *data = platform_get_drvdata(pdev);
845 +
846 + reset_control_assert(data->reset);
847 + clk_disable_unprepare(data->clk);
848 + clk_disable_unprepare(data->busclk);
849 + return 0;
850 +}
851 +
852 +static const struct sun8i_ths_cfg sun8i_h3_ths_cfg = {
853 + .sensor_num = 1,
854 + .calc_temp = sun8i_ths_calc_temp_h3,
855 +};
856 +
857 +static const struct of_device_id sun8i_ths_id_table[] = {
858 + { .compatible = "allwinner,sun8i-h3-ths", .data = &sun8i_h3_ths_cfg },
859 + { /* sentinel */ },
860 +};
861 +MODULE_DEVICE_TABLE(of, sun8i_ths_id_table);
862 +
863 +static struct platform_driver sun8i_ths_driver = {
864 + .probe = sun8i_ths_probe,
865 + .remove = sun8i_ths_remove,
866 + .driver = {
867 + .name = "sun8i_ths",
868 + .of_match_table = sun8i_ths_id_table,
869 + },
870 +};
871 +
872 +module_platform_driver(sun8i_ths_driver);
873 +
874 +MODULE_AUTHOR("Ondřej Jirman <megous@megous.com>");
875 +MODULE_DESCRIPTION("Thermal sensor driver for new Allwinner SoCs");
876 +MODULE_LICENSE("GPL v2");