1 --- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi
2 +++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
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";
18 compatible = "allwinner,sun4i-a10-timer";
19 reg = <0x01c20c00 0xa0>;
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>;
38 codec_analog: codec-analog@01f015c0 {
39 compatible = "allwinner,sun8i-h3-codec-analog";
40 reg = <0x01f015c0 0x4>;
43 function = "s_cir_rx";
47 + pins = "PL0", "PL1";
54 --- a/arch/arm/boot/dts/sun8i-h3.dtsi
55 +++ b/arch/arm/boot/dts/sun8i-h3.dtsi
57 #include "sunxi-h3-h5.dtsi"
60 + cpu0_opp_table: opp_table0 {
61 + compatible = "operating-points-v2";
65 + opp-hz = /bits/ 64 <480000000>;
66 + opp-microvolt = <1040000 1040000 1100000>;
67 + clock-latency-ns = <244144>; /* 8 32k periods */
72 + opp-hz = /bits/ 64 <648000000>;
73 + opp-microvolt = <1040000 1040000 1300000>;
74 + clock-latency-ns = <244144>; /* 8 32k periods */
78 + opp-hz = /bits/ 64 <816000000>;
79 + opp-microvolt = <1100000 1100000 1300000>;
80 + clock-latency-ns = <244144>; /* 8 32k periods */
84 + opp-hz = /bits/ 64 <1008000000>;
85 + opp-microvolt = <1140000 1140000 1300000>;
86 + clock-latency-ns = <244144>; /* 8 32k periods */
90 + opp-hz = /bits/ 64 <1200000000>;
91 + opp-microvolt = <1200000 1200000 1300000>;
92 + clock-latency-ns = <244144>; /* 8 32k periods */
102 compatible = "arm,cortex-a7";
105 + clocks = <&ccu CLK_CPUX>;
106 + clock-names = "cpu";
107 + operating-points-v2 = <&cpu0_opp_table>;
108 + clock-frequency = <1200000000>;
109 + #cooling-cells = <0x2>;
113 compatible = "arm,cortex-a7";
116 + operating-points-v2 = <&cpu0_opp_table>;
117 + clock-frequency = <1200000000>;
121 compatible = "arm,cortex-a7";
124 + operating-points-v2 = <&cpu0_opp_table>;
125 + clock-frequency = <1200000000>;
129 compatible = "arm,cortex-a7";
132 + operating-points-v2 = <&cpu0_opp_table>;
133 + clock-frequency = <1200000000>;
138 + compatible = "iio-hwmon";
139 + io-channels = <&ths>;
143 + cpu_thermal: cpu-thermal {
145 + polling-delay-passive = <250>;
146 + polling-delay = <1000>;
147 + thermal-sensors = <&ths 0>;
152 compatible = "arm,armv7-timer";
158 + compatible = "allwinner,sun8i-h3-ths";
159 + #thermal-sensor-cells = <0>;
160 + #io-channel-cells = <0>;
164 compatible = "allwinner,sun8i-h3-pinctrl";
167 --- a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
168 +++ b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
172 #include "sun8i-h3.dtsi"
173 -#include "sunxi-common-regulators.dtsi"
175 #include <dt-bindings/gpio/gpio.h>
176 #include <dt-bindings/input/input.h>
177 +#include <dt-bindings/thermal/thermal.h>
180 model = "Xunlong Orange Pi PC";
182 gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
186 + reg_vcc3v3: vcc3v3 {
187 + compatible = "regulator-fixed";
188 + regulator-name = "vcc3v3";
189 + regulator-min-microvolt = <3300000>;
190 + regulator-max-microvolt = <3300000>;
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 */
206 + opp-hz = /bits/ 64 <1368000000>;
207 + opp-microvolt = <1340000 1340000 1400000>;
208 + clock-latency-ns = <244144>; /* 8 32k periods */
212 + opp-hz = /bits/ 64 <1440000000>;
213 + opp-microvolt = <1400000 1400000 1400000>;
214 + clock-latency-ns = <244144>; /* 8 32k periods */
218 + opp-hz = /bits/ 64 <1512000000>;
219 + opp-microvolt = <1400000 1400000 1400000>;
220 + clock-latency-ns = <244144>; /* 8 32k periods */
225 + cooling-min-level = <0>;
226 + cooling-max-level = <15>;
227 + cpu-supply = <®_sy8106a>;
232 + cpu_warm: cpu_warm {
233 + temperature = <65000>;
234 + hysteresis = <2000>;
239 + temperature = <75000>;
240 + hysteresis = <2000>;
244 + cpu_very_hot: cpu_very_hot {
245 + temperature = <90000>;
246 + hysteresis = <2000>;
250 + cpu_crit: cpu_crit {
251 + temperature = <105000>;
252 + hysteresis = <2000>;
258 + cpu_warm_limit_cpu {
259 + trip = <&cpu_warm>;
260 + cooling-device = <&cpu0 THERMAL_NO_LIMIT 10>;
263 + cpu_hot_limit_cpu {
265 + cooling-device = <&cpu0 12 12>;
268 + cpu_very_hot_limit_cpu {
269 + trip = <&cpu_very_hot>;
270 + cooling-device = <&cpu0 14 THERMAL_NO_LIMIT>;
278 + reg_sy8106a: regulator@65 {
279 + compatible = "silergy,sy8106a";
281 + regulator-name = "vdd-cpux";
282 + regulator-min-microvolt = <1000000>;
283 + regulator-max-microvolt = <1400000>;
284 + regulator-ramp-delay = <200>;
286 + regulator-always-on;
292 --- a/arch/arm/configs/sunxi_defconfig
293 +++ b/arch/arm/configs/sunxi_defconfig
299 # CONFIG_NET_VENDOR_ARC is not set
300 # CONFIG_NET_CADENCE is not set
301 # CONFIG_NET_VENDOR_BROADCOM is not set
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
311 --- a/drivers/regulator/Kconfig
312 +++ b/drivers/regulator/Kconfig
314 This driver supports the internal VMMC regulator in the STw481x
317 +config REGULATOR_SY8106A
318 + tristate "Silergy SY8106A regulator"
319 + depends on I2C && (OF || COMPILE_TEST)
322 + This driver supports SY8106A single output regulator.
324 config REGULATOR_TPS51632
325 tristate "TI TPS51632 Power Regulator"
328 --- a/drivers/regulator/Makefile
329 +++ b/drivers/regulator/Makefile
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
339 --- a/drivers/thermal/Kconfig
340 +++ b/drivers/thermal/Kconfig
342 Enable this option if you want to have support for thermal management
343 controller present in Mediatek SoCs
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
351 + depends on RESET_CONTROLLER
353 + Enable this options for support thermal reporting on some Allwinner SoCs.
355 menu "Broadcom thermal drivers"
356 depends on ARCH_BCM || COMPILE_TEST
357 source "drivers/thermal/broadcom/Kconfig"
359 --- a/drivers/thermal/Makefile
360 +++ b/drivers/thermal/Makefile
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
371 +++ b/drivers/regulator/sy8106a-regulator.c
374 + * sy8106a-regulator.c - Regulator device driver for SY8106A
376 + * Copyright (C) 2016 Ondřej Jirman <megous@megous.com>
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.
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.
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>
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)
401 + * The I2C controlled voltage will only work when this bit is set; otherwise
402 + * it will behave like a fixed regulator.
404 +#define SY8106A_GO_BIT BIT(7)
407 + struct regulator_dev *rdev;
408 + struct regmap *regmap;
411 +static const struct regmap_config sy8106a_regmap_config = {
416 +static int sy8106a_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel)
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.
423 + return regmap_write(rdev->regmap, rdev->desc->vsel_reg,
424 + sel | SY8106A_GO_BIT);
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 */
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
440 +static const struct regulator_desc sy8106a_reg = {
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,
451 + * This ramp_delay is a conservative default value which works on
452 + * H3/H5 boards VDD-CPUX situations.
455 + .owner = THIS_MODULE,
459 + * I2C driver interface functions
461 +static int sy8106a_i2c_probe(struct i2c_client *i2c,
462 + const struct i2c_device_id *id)
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;
471 + chip = devm_kzalloc(&i2c->dev, sizeof(struct sy8106a), GFP_KERNEL);
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",
483 + config.dev = &i2c->dev;
484 + config.regmap = chip->regmap;
485 + config.driver_data = chip;
487 + config.of_node = dev->of_node;
488 + config.init_data = of_get_regulator_init_data(dev, dev->of_node,
491 + if (!config.init_data)
494 + /* Probe regulator */
495 + error = regmap_read(chip->regmap, SY8106A_REG_VOUT1_SEL, &selector);
497 + dev_err(&i2c->dev, "Failed to read voltage at probe time: %d\n", error);
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);
510 + i2c_set_clientdata(i2c, chip);
515 +static const struct of_device_id sy8106a_i2c_of_match[] = {
516 + { .compatible = "silergy,sy8106a" },
519 +MODULE_DEVICE_TABLE(of, sy8106a_i2c_of_match);
521 +static const struct i2c_device_id sy8106a_i2c_id[] = {
525 +MODULE_DEVICE_TABLE(i2c, sy8106a_i2c_id);
527 +static struct i2c_driver sy8106a_regulator_driver = {
530 + .of_match_table = of_match_ptr(sy8106a_i2c_of_match),
532 + .probe = sy8106a_i2c_probe,
533 + .id_table = sy8106a_i2c_id,
536 +module_i2c_driver(sy8106a_regulator_driver);
538 +MODULE_AUTHOR("Ondřej Jirman <megous@megous.com>");
539 +MODULE_DESCRIPTION("Regulator device driver for Silergy SY8106A");
540 +MODULE_LICENSE("GPL");
543 +++ b/drivers/thermal/sun8i_ths.c
546 + * Thermal sensor driver for Allwinner new SoCs
548 + * Copyright (C) 2016 Ondřej Jirman
549 + * Based on the work of Josef Gajdusek <atx@atx.name>
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.
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.
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>
574 +#define THS_H3_MAX_SENSOR_NUM 4
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))
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)
594 +#define THS_H3_CLK_IN 40000000 /* Hz */
595 +#define THS_H3_DATA_PERIOD 330 /* ms */
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
604 +struct sun8i_ths_data;
606 +struct sun8i_ths_sensor {
607 + struct sun8i_ths_data *data;
609 + struct thermal_zone_device *tzd;
613 +struct sun8i_ths_cfg {
615 + int (*calc_temp)(u32 val);
618 +struct sun8i_ths_data {
619 + struct reset_control *reset;
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];
628 +static int sun8i_ths_calc_temp_h3(u32 val)
630 + return (217000 - (int)((val * 1000000) / 8253));
633 +static int sun8i_ths_get_temp(void *_data, int *out)
635 + struct sun8i_ths_sensor *sensor = _data;
637 + if (sensor->val == 0)
640 + /* Formula and parameters from the Allwinner 3.4 kernel */
641 + *out = sensor->data->cfg->calc_temp(sensor->val);
645 +static irqreturn_t sun8i_ths_irq_thread(int irq, void *_data)
647 + struct sun8i_ths_data *data = _data;
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)))
655 + writel(THS_H3_STAT_DATA_IRQ_STS(i), data->regs + THS_H3_STAT);
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);
663 + return IRQ_HANDLED;
666 +static void sun8i_ths_init(struct sun8i_ths_data *data)
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);
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);
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);
687 +static int sun8i_ths_calibrate(struct sun8i_ths_data *data)
692 + caldata = nvmem_cell_read(data->calcell, &callen);
693 + if (IS_ERR(caldata))
694 + return PTR_ERR(caldata);
696 + writel(be32_to_cpu(caldata[0]), data->regs + THS_H3_CDATA0);
698 + writel(be32_to_cpu(caldata[1]), data->regs + THS_H3_CDATA1);
704 +static const struct thermal_zone_of_device_ops sun8i_ths_thermal_ops = {
705 + .get_temp = sun8i_ths_get_temp,
708 +static int sun8i_ths_probe(struct platform_device *pdev)
710 + struct sun8i_ths_data *data;
711 + struct resource *res;
714 + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
718 + data->cfg = of_device_get_match_data(&pdev->dev);
722 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
724 + dev_err(&pdev->dev, "no memory resources defined\n");
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);
735 + irq = platform_get_irq(pdev, 0);
737 + dev_err(&pdev->dev, "failed to get IRQ: %d\n", irq);
741 + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
742 + sun8i_ths_irq_thread, IRQF_ONESHOT,
743 + dev_name(&pdev->dev), data);
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);
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);
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);
768 + ret = reset_control_deassert(data->reset);
770 + dev_err(&pdev->dev, "reset deassert failed: %d\n", ret);
774 + ret = clk_prepare_enable(data->busclk);
776 + dev_err(&pdev->dev, "failed to enable bus clk: %d\n", ret);
777 + goto err_assert_reset;
780 + ret = clk_prepare_enable(data->clk);
782 + dev_err(&pdev->dev, "failed to enable ths clk: %d\n", ret);
783 + goto err_disable_bus;
786 + ret = clk_set_rate(data->clk, THS_H3_CLK_IN);
788 + goto err_disable_ths;
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;
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
804 + * So here we do not return if the calibartion data is not
805 + * available, except the probe needs deferring.
808 + ret = sun8i_ths_calibrate(data);
810 + goto err_disable_ths;
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",
824 + goto err_disable_ths;
828 + sun8i_ths_init(data);
830 + platform_set_drvdata(pdev, data);
834 + clk_disable_unprepare(data->clk);
836 + clk_disable_unprepare(data->busclk);
838 + reset_control_assert(data->reset);
842 +static int sun8i_ths_remove(struct platform_device *pdev)
844 + struct sun8i_ths_data *data = platform_get_drvdata(pdev);
846 + reset_control_assert(data->reset);
847 + clk_disable_unprepare(data->clk);
848 + clk_disable_unprepare(data->busclk);
852 +static const struct sun8i_ths_cfg sun8i_h3_ths_cfg = {
854 + .calc_temp = sun8i_ths_calc_temp_h3,
857 +static const struct of_device_id sun8i_ths_id_table[] = {
858 + { .compatible = "allwinner,sun8i-h3-ths", .data = &sun8i_h3_ths_cfg },
859 + { /* sentinel */ },
861 +MODULE_DEVICE_TABLE(of, sun8i_ths_id_table);
863 +static struct platform_driver sun8i_ths_driver = {
864 + .probe = sun8i_ths_probe,
865 + .remove = sun8i_ths_remove,
867 + .name = "sun8i_ths",
868 + .of_match_table = sun8i_ths_id_table,
872 +module_platform_driver(sun8i_ths_driver);
874 +MODULE_AUTHOR("Ondřej Jirman <megous@megous.com>");
875 +MODULE_DESCRIPTION("Thermal sensor driver for new Allwinner SoCs");
876 +MODULE_LICENSE("GPL v2");