Revert "sunxi: Add OPP table, cpu voltage control, cpu thermal sensor for Xunlong...
authorHauke Mehrtens <hauke@hauke-m.de>
Sat, 28 Apr 2018 15:26:54 +0000 (17:26 +0200)
committerHauke Mehrtens <hauke@hauke-m.de>
Sat, 22 Sep 2018 19:29:21 +0000 (21:29 +0200)
This reverts commit 139d0a6cb37bca7ccc5584468e884e452181e431.

target/linux/sunxi/cortexa7/config-default
target/linux/sunxi/patches-4.14/050-sun8i-H3-Orange-Pi-PC-cpufreq-thermal.patch [deleted file]

index e49607ec6eedeb9b24b1868d6a16a74f4f70e700..cf41ddb4e65a2856d191910b24bc3f246ec22902 100644 (file)
@@ -8,5 +8,3 @@ CONFIG_DWMAC_SUN8I=y
 CONFIG_MDIO_BUS_MUX=y
 # CONFIG_PINCTRL_SUN5I is not set
 # CONFIG_SUN4I_A10_CCU is not set
-CONFIG_REGULATOR_SY8106A=y
-CONFIG_SUN8I_THS=y
diff --git a/target/linux/sunxi/patches-4.14/050-sun8i-H3-Orange-Pi-PC-cpufreq-thermal.patch b/target/linux/sunxi/patches-4.14/050-sun8i-H3-Orange-Pi-PC-cpufreq-thermal.patch
deleted file mode 100644 (file)
index d5dcf22..0000000
+++ /dev/null
@@ -1,876 +0,0 @@
---- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi
-+++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
-@@ -383,6 +383,16 @@
-                       };
-               };
-+              ths: thermal-sensor@1c25000 {
-+                      reg = <0x01c25000 0x400>, <0x01c14234 0x4>;
-+                      reg-names = "ths", "calibration";
-+                      interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
-+                      clocks = <&ccu CLK_BUS_THS>, <&ccu CLK_THS>;
-+                      clock-names = "ahb", "ths";
-+                      resets = <&ccu RST_BUS_THS>;
-+                      reset-names = "ahb";
-+              };
-+
-               timer@01c20c00 {
-                       compatible = "allwinner,sun4i-a10-timer";
-                       reg = <0x01c20c00 0xa0>;
-@@ -632,6 +642,20 @@
-                       #reset-cells = <1>;
-               };
-+              r_i2c: i2c@1f02400 {
-+                      compatible = "allwinner,sun6i-a31-i2c";
-+                      reg = <0x01f02400 0x400>;
-+                      interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
-+                      pinctrl-names = "default";
-+                      pinctrl-0 = <&r_i2c_pins>;
-+                      clocks = <&r_ccu CLK_APB0_I2C>;
-+                      clock-frequency = <100000>;
-+                      resets = <&r_ccu RST_APB0_I2C>;
-+                      status = "disabled";
-+                      #address-cells = <1>;
-+                      #size-cells = <0>;
-+              };
-+
-               codec_analog: codec-analog@01f015c0 {
-                       compatible = "allwinner,sun8i-h3-codec-analog";
-                       reg = <0x01f015c0 0x4>;
-@@ -662,6 +686,11 @@
-                               pins = "PL11";
-                               function = "s_cir_rx";
-                       };
-+
-+                      r_i2c_pins: r-i2c {
-+                              pins = "PL0", "PL1";
-+                              function = "s_i2c";
-+                      };
-               };
-       };
- };
-
---- a/arch/arm/boot/dts/sun8i-h3.dtsi
-+++ b/arch/arm/boot/dts/sun8i-h3.dtsi
-@@ -43,34 +43,95 @@
- #include "sunxi-h3-h5.dtsi"
- / {
-+      cpu0_opp_table: opp_table0 {
-+              compatible = "operating-points-v2";
-+              opp-shared;
-+
-+              opp@480000000 {
-+                      opp-hz = /bits/ 64 <480000000>;
-+                      opp-microvolt = <1040000 1040000 1100000>;
-+                      clock-latency-ns = <244144>; /* 8 32k periods */
-+                      opp-suspend;
-+              };
-+
-+              opp@648000000 {
-+                      opp-hz = /bits/ 64 <648000000>;
-+                      opp-microvolt = <1040000 1040000 1300000>;
-+                      clock-latency-ns = <244144>; /* 8 32k periods */
-+              };
-+
-+              opp@816000000 {
-+                      opp-hz = /bits/ 64 <816000000>;
-+                      opp-microvolt = <1100000 1100000 1300000>;
-+                      clock-latency-ns = <244144>; /* 8 32k periods */
-+              };
-+
-+              opp@1008000000 {
-+                      opp-hz = /bits/ 64 <1008000000>;
-+                      opp-microvolt = <1140000 1140000 1300000>;
-+                      clock-latency-ns = <244144>; /* 8 32k periods */
-+              };
-+
-+              opp@1200000000 {
-+                      opp-hz = /bits/ 64 <1200000000>;
-+                      opp-microvolt = <1200000 1200000 1300000>;
-+                      clock-latency-ns = <244144>; /* 8 32k periods */
-+              };
-+      };
-+
-       cpus {
-               #address-cells = <1>;
-               #size-cells = <0>;
--              cpu@0 {
-+              cpu0: cpu@0 {
-                       compatible = "arm,cortex-a7";
-                       device_type = "cpu";
-                       reg = <0>;
-+                      clocks = <&ccu CLK_CPUX>;
-+                      clock-names = "cpu";
-+                      operating-points-v2 = <&cpu0_opp_table>;
-+                      clock-frequency = <1200000000>;
-+                      #cooling-cells = <0x2>;
-               };
-               cpu@1 {
-                       compatible = "arm,cortex-a7";
-                       device_type = "cpu";
-                       reg = <1>;
-+                      operating-points-v2 = <&cpu0_opp_table>;
-+                      clock-frequency = <1200000000>;
-               };
-               cpu@2 {
-                       compatible = "arm,cortex-a7";
-                       device_type = "cpu";
-                       reg = <2>;
-+                      operating-points-v2 = <&cpu0_opp_table>;
-+                      clock-frequency = <1200000000>;
-               };
-               cpu@3 {
-                       compatible = "arm,cortex-a7";
-                       device_type = "cpu";
-                       reg = <3>;
-+                      operating-points-v2 = <&cpu0_opp_table>;
-+                      clock-frequency = <1200000000>;
-               };
-       };
-+
-+      iio-hwmon {
-+              compatible = "iio-hwmon";
-+              io-channels = <&ths>;
-+      };
-+
-+      thermal-zones {
-+              cpu_thermal: cpu-thermal {
-+                      /* milliseconds */
-+                      polling-delay-passive = <250>;
-+                      polling-delay = <1000>;
-+                      thermal-sensors = <&ths 0>;
-+              };
-+      };
-       timer {
-               compatible = "arm,armv7-timer";
-@@ -121,6 +177,12 @@
-                     "sample";
- };
-+&ths {
-+      compatible = "allwinner,sun8i-h3-ths";
-+      #thermal-sensor-cells = <0>;
-+      #io-channel-cells = <0>;
-+};
-+
- &pio {
-       compatible = "allwinner,sun8i-h3-pinctrl";
- };
-
---- a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
-+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
-@@ -42,10 +42,10 @@
- /dts-v1/;
- #include "sun8i-h3.dtsi"
--#include "sunxi-common-regulators.dtsi"
- #include <dt-bindings/gpio/gpio.h>
- #include <dt-bindings/input/input.h>
-+#include <dt-bindings/thermal/thermal.h>
- / {
-       model = "Xunlong Orange Pi PC";
-@@ -88,6 +88,109 @@
-                       gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
-               };
-       };
-+
-+      reg_vcc3v3: vcc3v3 {
-+              compatible = "regulator-fixed";
-+              regulator-name = "vcc3v3";
-+              regulator-min-microvolt = <3300000>;
-+              regulator-max-microvolt = <3300000>;
-+      };
-+
-+      reg_usb0_vbus: usb0-vbus {
-+              compatible = "regulator-fixed";
-+              regulator-name = "usb0-vbus";
-+              regulator-min-microvolt = <5000000>;
-+              regulator-max-microvolt = <5000000>;
-+              enable-active-high;
-+              gpio = <&r_pio 0 2 GPIO_ACTIVE_HIGH>; /* PL2 */
-+              status = "okay";
-+      };
-+};
-+
-+&cpu0_opp_table {
-+              1368000000 {
-+                      opp-hz = /bits/ 64 <1368000000>;
-+                      opp-microvolt = <1340000 1340000 1400000>;
-+                      clock-latency-ns = <244144>; /* 8 32k periods */
-+              };
-+
-+              1440000000 {
-+                      opp-hz = /bits/ 64 <1440000000>;
-+                      opp-microvolt = <1400000 1400000 1400000>;
-+                      clock-latency-ns = <244144>; /* 8 32k periods */
-+              };
-+
-+              1512000000 {
-+                      opp-hz = /bits/ 64 <1512000000>;
-+                      opp-microvolt = <1400000 1400000 1400000>;
-+                      clock-latency-ns = <244144>; /* 8 32k periods */
-+              };
-+};
-+
-+&cpu0 {
-+      cooling-min-level = <0>;
-+      cooling-max-level = <15>;
-+      cpu-supply = <&reg_sy8106a>;
-+};
-+
-+&cpu_thermal {
-+      trips {
-+              cpu_warm: cpu_warm {
-+                      temperature = <65000>;
-+                      hysteresis = <2000>;
-+                      type = "passive";
-+              };
-+
-+              cpu_hot: cpu_hot {
-+                      temperature = <75000>;
-+                      hysteresis = <2000>;
-+                      type = "passive";
-+              };
-+
-+              cpu_very_hot: cpu_very_hot {
-+                      temperature = <90000>;
-+                      hysteresis = <2000>;
-+                      type = "passive";
-+              };
-+
-+              cpu_crit: cpu_crit {
-+                      temperature = <105000>;
-+                      hysteresis = <2000>;
-+                      type = "critical";
-+              };
-+      };
-+
-+      cooling-maps {
-+              cpu_warm_limit_cpu {
-+                      trip = <&cpu_warm>;
-+                      cooling-device = <&cpu0 THERMAL_NO_LIMIT 10>;
-+              };
-+
-+              cpu_hot_limit_cpu {
-+                      trip = <&cpu_hot>;
-+                      cooling-device = <&cpu0 12 12>;
-+              };
-+
-+              cpu_very_hot_limit_cpu {
-+                      trip = <&cpu_very_hot>;
-+                      cooling-device = <&cpu0 14 THERMAL_NO_LIMIT>;
-+              };
-+      };
-+};
-+
-+&r_i2c {
-+      status = "okay";
-+
-+      reg_sy8106a: regulator@65 {
-+              compatible = "silergy,sy8106a";
-+              reg = <0x65>;
-+              regulator-name = "vdd-cpux";
-+              regulator-min-microvolt = <1000000>;
-+              regulator-max-microvolt = <1400000>;
-+              regulator-ramp-delay = <200>;
-+              regulator-boot-on;
-+              regulator-always-on;
-+      };
- };
- &codec {
-
---- a/arch/arm/configs/sunxi_defconfig
-+++ b/arch/arm/configs/sunxi_defconfig
-@@ -40,6 +40,7 @@
- CONFIG_AHCI_SUNXI=y
- CONFIG_NETDEVICES=y
- CONFIG_SUN4I_EMAC=y
-+CONFIG_SUN8I_THS=y
- # CONFIG_NET_VENDOR_ARC is not set
- # CONFIG_NET_CADENCE is not set
- # CONFIG_NET_VENDOR_BROADCOM is not set
-@@ -93,6 +94,7 @@
- CONFIG_REGULATOR_FIXED_VOLTAGE=y
- CONFIG_REGULATOR_AXP20X=y
- CONFIG_REGULATOR_GPIO=y
-+CONFIG_REGULATOR_SY8106A=y
- CONFIG_MEDIA_SUPPORT=y
- CONFIG_RC_CORE=y
- CONFIG_RC_DEVICES=y
-
---- a/drivers/regulator/Kconfig
-+++ b/drivers/regulator/Kconfig
-@@ -785,6 +785,13 @@
-         This driver supports the internal VMMC regulator in the STw481x
-         PMIC chips.
-+config REGULATOR_SY8106A
-+      tristate "Silergy SY8106A regulator"
-+      depends on I2C && (OF || COMPILE_TEST)
-+      select REGMAP_I2C
-+      help
-+        This driver supports SY8106A single output regulator.
-+
- config REGULATOR_TPS51632
-       tristate "TI TPS51632 Power Regulator"
-       depends on I2C
-
---- a/drivers/regulator/Makefile
-+++ b/drivers/regulator/Makefile
-@@ -98,6 +98,7 @@
- obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o
- obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
- obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
-+obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o
- obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
- obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
- obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o
-
---- a/drivers/thermal/Kconfig
-+++ b/drivers/thermal/Kconfig
-@@ -407,6 +407,16 @@
-         Enable this option if you want to have support for thermal management
-         controller present in Mediatek SoCs
-+config SUN8I_THS
-+      tristate "Thermal sensor driver for Allwinner H3"
-+      depends on MACH_SUN8I || COMPILE_TEST
-+      depends on HAS_IOMEM
-+      depends on NVMEM_SUNXI_SID
-+      depends on OF
-+      depends on RESET_CONTROLLER
-+      help
-+        Enable this options for support thermal reporting on some Allwinner SoCs.
-+
- menu "Broadcom thermal drivers"
- depends on ARCH_BCM || COMPILE_TEST
- source "drivers/thermal/broadcom/Kconfig"
-
---- a/drivers/thermal/Makefile
-+++ b/drivers/thermal/Makefile
-@@ -58,6 +58,7 @@
- obj-$(CONFIG_TEGRA_SOCTHERM)  += tegra/
- obj-$(CONFIG_HISI_THERMAL)     += hisi_thermal.o
- obj-$(CONFIG_MTK_THERMAL)     += mtk_thermal.o
-+obj-$(CONFIG_SUN8I_THS)       += sun8i_ths.o
- obj-$(CONFIG_GENERIC_ADC_THERMAL)     += thermal-generic-adc.o
- obj-$(CONFIG_ZX2967_THERMAL)  += zx2967_thermal.o
- obj-$(CONFIG_UNIPHIER_THERMAL)        += uniphier_thermal.o
-
---- /dev/null
-+++ b/drivers/regulator/sy8106a-regulator.c
-@@ -0,0 +1,168 @@ 
-+/*
-+ * sy8106a-regulator.c - Regulator device driver for SY8106A
-+ *
-+ * Copyright (C) 2016 Ondřej Jirman <megous@megous.com>
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Library General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2 of the License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+ * Library General Public License for more details.
-+ */
-+
-+#include <linux/err.h>
-+#include <linux/i2c.h>
-+#include <linux/module.h>
-+#include <linux/regmap.h>
-+#include <linux/regulator/driver.h>
-+#include <linux/regulator/of_regulator.h>
-+
-+#define SY8106A_REG_VOUT1_SEL         0x01
-+#define SY8106A_REG_VOUT_COM          0x02
-+#define SY8106A_REG_VOUT1_SEL_MASK    0x7f
-+#define SY8106A_DISABLE_REG           BIT(0)
-+/*
-+ * The I2C controlled voltage will only work when this bit is set; otherwise
-+ * it will behave like a fixed regulator.
-+ */
-+#define SY8106A_GO_BIT                        BIT(7)
-+
-+struct sy8106a {
-+      struct regulator_dev *rdev;
-+      struct regmap *regmap;
-+};
-+
-+static const struct regmap_config sy8106a_regmap_config = {
-+      .reg_bits = 8,
-+      .val_bits = 8,
-+};
-+
-+static int sy8106a_set_voltage_sel(struct regulator_dev *rdev, unsigned int sel)
-+{
-+      /* We use our set_voltage_sel in order to avoid unnecessary I2C
-+       * chatter, because the regulator_get_voltage_sel_regmap using
-+       * apply_bit would perform 4 unnecessary transfers instead of one,
-+       * increasing the chance of error.
-+       */
-+      return regmap_write(rdev->regmap, rdev->desc->vsel_reg,
-+                          sel | SY8106A_GO_BIT);
-+}
-+
-+static const struct regulator_ops sy8106a_ops = {
-+      .set_voltage_sel = sy8106a_set_voltage_sel,
-+      .set_voltage_time_sel = regulator_set_voltage_time_sel,
-+      .get_voltage_sel = regulator_get_voltage_sel_regmap,
-+      .list_voltage = regulator_list_voltage_linear,
-+      /* Enabling/disabling the regulator is not yet implemented */
-+};
-+
-+/* Default limits measured in millivolts and milliamps */
-+#define SY8106A_MIN_MV                680
-+#define SY8106A_MAX_MV                1950
-+#define SY8106A_STEP_MV               10
-+
-+static const struct regulator_desc sy8106a_reg = {
-+      .name = "SY8106A",
-+      .id = 0,
-+      .ops = &sy8106a_ops,
-+      .type = REGULATOR_VOLTAGE,
-+      .n_voltages = ((SY8106A_MAX_MV - SY8106A_MIN_MV) / SY8106A_STEP_MV) + 1,
-+      .min_uV = (SY8106A_MIN_MV * 1000),
-+      .uV_step = (SY8106A_STEP_MV * 1000),
-+      .vsel_reg = SY8106A_REG_VOUT1_SEL,
-+      .vsel_mask = SY8106A_REG_VOUT1_SEL_MASK,
-+      /*
-+       * This ramp_delay is a conservative default value which works on
-+       * H3/H5 boards VDD-CPUX situations.
-+       */
-+      .ramp_delay = 200,
-+      .owner = THIS_MODULE,
-+};
-+
-+/*
-+ * I2C driver interface functions
-+ */
-+static int sy8106a_i2c_probe(struct i2c_client *i2c,
-+                          const struct i2c_device_id *id)
-+{
-+      struct sy8106a *chip;
-+      struct device *dev = &i2c->dev;
-+      struct regulator_dev *rdev = NULL;
-+      struct regulator_config config = { };
-+      unsigned int selector;
-+      int error;
-+
-+      chip = devm_kzalloc(&i2c->dev, sizeof(struct sy8106a), GFP_KERNEL);
-+      if (!chip)
-+              return -ENOMEM;
-+
-+      chip->regmap = devm_regmap_init_i2c(i2c, &sy8106a_regmap_config);
-+      if (IS_ERR(chip->regmap)) {
-+              error = PTR_ERR(chip->regmap);
-+              dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
-+                      error);
-+              return error;
-+      }
-+
-+      config.dev = &i2c->dev;
-+      config.regmap = chip->regmap;
-+      config.driver_data = chip;
-+
-+      config.of_node = dev->of_node;
-+      config.init_data = of_get_regulator_init_data(dev, dev->of_node,
-+                                                    &sy8106a_reg);
-+
-+      if (!config.init_data)
-+              return -ENOMEM;
-+
-+      /* Probe regulator */
-+      error = regmap_read(chip->regmap, SY8106A_REG_VOUT1_SEL, &selector);
-+      if (error) {
-+              dev_err(&i2c->dev, "Failed to read voltage at probe time: %d\n", error);
-+              return error;
-+      }
-+
-+      rdev = devm_regulator_register(&i2c->dev, &sy8106a_reg, &config);
-+      if (IS_ERR(rdev)) {
-+              error = PTR_ERR(rdev);
-+              dev_err(&i2c->dev, "Failed to register SY8106A regulator: %d\n", error);
-+              return error;
-+      }
-+
-+      chip->rdev = rdev;
-+
-+      i2c_set_clientdata(i2c, chip);
-+
-+      return 0;
-+}
-+
-+static const struct of_device_id sy8106a_i2c_of_match[] = {
-+      { .compatible = "silergy,sy8106a" },
-+      { },
-+};
-+MODULE_DEVICE_TABLE(of, sy8106a_i2c_of_match);
-+
-+static const struct i2c_device_id sy8106a_i2c_id[] = {
-+      { "sy8106a", 0 },
-+      { },
-+};
-+MODULE_DEVICE_TABLE(i2c, sy8106a_i2c_id);
-+
-+static struct i2c_driver sy8106a_regulator_driver = {
-+      .driver = {
-+              .name = "sy8106a",
-+              .of_match_table = of_match_ptr(sy8106a_i2c_of_match),
-+      },
-+      .probe = sy8106a_i2c_probe,
-+      .id_table = sy8106a_i2c_id,
-+};
-+
-+module_i2c_driver(sy8106a_regulator_driver);
-+
-+MODULE_AUTHOR("Ondřej Jirman <megous@megous.com>");
-+MODULE_DESCRIPTION("Regulator device driver for Silergy SY8106A");
-+MODULE_LICENSE("GPL");
-
---- /dev/null
-+++ b/drivers/thermal/sun8i_ths.c
-@@ -0,0 +1,332 @@ 
-+/*
-+ * Thermal sensor driver for Allwinner new SoCs
-+ *
-+ * Copyright (C) 2016 Ondřej Jirman
-+ * Based on the work of Josef Gajdusek <atx@atx.name>
-+ *
-+ * This software is licensed under the terms of the GNU General Public
-+ * License version 2, as published by the Free Software Foundation, and
-+ * may be copied, distributed, and modified under those terms.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/interrupt.h>
-+#include <linux/io.h>
-+#include <linux/module.h>
-+#include <linux/nvmem-consumer.h>
-+#include <linux/of_device.h>
-+#include <linux/platform_device.h>
-+#include <linux/reset.h>
-+#include <linux/slab.h>
-+#include <linux/thermal.h>
-+#include <linux/printk.h>
-+
-+#define THS_H3_MAX_SENSOR_NUM 4
-+
-+#define THS_H3_CTRL0          0x00
-+#define THS_H3_CTRL2          0x40
-+#define THS_H3_INT_CTRL               0x44
-+#define THS_H3_STAT           0x48
-+#define THS_H3_FILTER         0x70
-+#define THS_H3_CDATA0         0x74
-+#define THS_H3_CDATA1         0x74
-+#define THS_H3_DATA(n)                (0x80 + 4 * (n))
-+
-+#define THS_H3_CTRL0_SENSOR_ACQ0(x)   (x)
-+#define THS_H3_CTRL2_SENSE_EN(n)      BIT(0 + (n))
-+#define THS_H3_CTRL2_SENSOR_ACQ1(x)   ((x) << 16)
-+#define THS_H3_INT_CTRL_DATA_IRQ_EN(n)        BIT(8 + (n))
-+#define THS_H3_INT_CTRL_THERMAL_PER(x)        ((x) << 12)
-+#define THS_H3_STAT_DATA_IRQ_STS(n)   BIT(8 + (n))
-+#define THS_H3_FILTER_TYPE(x)         ((x) << 0)
-+#define THS_H3_FILTER_EN              BIT(2)
-+
-+#define THS_H3_CLK_IN         40000000 /* Hz */
-+#define THS_H3_DATA_PERIOD    330 /* ms */
-+
-+#define THS_H3_FILTER_TYPE_VALUE      2 /* average over 2^(n+1) samples */
-+#define THS_H3_FILTER_DIV             (1 << (THS_H3_FILTER_TYPE_VALUE + 1))
-+#define THS_H3_INT_CTRL_THERMAL_PER_VALUE \
-+      (THS_H3_DATA_PERIOD * (THS_H3_CLK_IN / 1000) / THS_H3_FILTER_DIV / 4096 - 1)
-+#define THS_H3_CTRL0_SENSOR_ACQ0_VALUE        0x3f /* 16us */
-+#define THS_H3_CTRL2_SENSOR_ACQ1_VALUE        0x3f
-+
-+struct sun8i_ths_data;
-+
-+struct sun8i_ths_sensor {
-+      struct sun8i_ths_data *data;
-+      int id;
-+      struct thermal_zone_device *tzd;
-+      u32 val;
-+};
-+
-+struct sun8i_ths_cfg {
-+      int sensor_num;
-+      int (*calc_temp)(u32 val);
-+};
-+
-+struct sun8i_ths_data {
-+      struct reset_control *reset;
-+      struct clk *clk;
-+      struct clk *busclk;
-+      void __iomem *regs;
-+      struct nvmem_cell *calcell;
-+      const struct sun8i_ths_cfg *cfg;
-+      struct sun8i_ths_sensor sensors[THS_H3_MAX_SENSOR_NUM];
-+};
-+
-+static int sun8i_ths_calc_temp_h3(u32 val)
-+{
-+      return (217000 - (int)((val * 1000000) / 8253));
-+}
-+
-+static int sun8i_ths_get_temp(void *_data, int *out)
-+{
-+      struct sun8i_ths_sensor *sensor = _data;
-+
-+      if (sensor->val == 0)
-+              return -EBUSY;
-+
-+      /* Formula and parameters from the Allwinner 3.4 kernel */
-+      *out = sensor->data->cfg->calc_temp(sensor->val);
-+      return 0;
-+}
-+
-+static irqreturn_t sun8i_ths_irq_thread(int irq, void *_data)
-+{
-+      struct sun8i_ths_data *data = _data;
-+      int i;
-+
-+      for (i = 0; i < data->cfg->sensor_num; i++) {
-+              if (!(readl(data->regs + THS_H3_STAT) &
-+                    THS_H3_STAT_DATA_IRQ_STS(i)))
-+                      continue;
-+
-+              writel(THS_H3_STAT_DATA_IRQ_STS(i), data->regs + THS_H3_STAT);
-+
-+              data->sensors[i].val = readl(data->regs + THS_H3_DATA(i));
-+              if (data->sensors[i].val)
-+                      thermal_zone_device_update(data->sensors[i].tzd,
-+                                                 THERMAL_EVENT_TEMP_SAMPLE);
-+      }
-+
-+      return IRQ_HANDLED;
-+}
-+
-+static void sun8i_ths_init(struct sun8i_ths_data *data)
-+{
-+      u32 val;
-+      int i;
-+
-+      writel(THS_H3_CTRL0_SENSOR_ACQ0(THS_H3_CTRL0_SENSOR_ACQ0_VALUE),
-+              data->regs + THS_H3_CTRL0);
-+      writel(THS_H3_FILTER_EN | THS_H3_FILTER_TYPE(THS_H3_FILTER_TYPE_VALUE),
-+              data->regs + THS_H3_FILTER);
-+
-+      val = THS_H3_CTRL2_SENSOR_ACQ1(THS_H3_CTRL2_SENSOR_ACQ1_VALUE);
-+      for (i = 0; i < data->cfg->sensor_num; i++)
-+              val |= THS_H3_CTRL2_SENSE_EN(i);
-+      writel(val, data->regs + THS_H3_CTRL2);
-+
-+      val = THS_H3_INT_CTRL_THERMAL_PER(THS_H3_INT_CTRL_THERMAL_PER_VALUE);
-+      for (i = 0; i < data->cfg->sensor_num; i++)
-+              val |= THS_H3_INT_CTRL_DATA_IRQ_EN(i);
-+      writel(val, data->regs + THS_H3_INT_CTRL);
-+}
-+
-+static int sun8i_ths_calibrate(struct sun8i_ths_data *data)
-+{
-+      u32 *caldata;
-+      size_t callen;
-+
-+      caldata = nvmem_cell_read(data->calcell, &callen);
-+      if (IS_ERR(caldata))
-+              return PTR_ERR(caldata);
-+
-+      writel(be32_to_cpu(caldata[0]), data->regs + THS_H3_CDATA0);
-+      if (callen > 4)
-+              writel(be32_to_cpu(caldata[1]), data->regs + THS_H3_CDATA1);
-+
-+      kfree(caldata);
-+      return 0;
-+}
-+
-+static const struct thermal_zone_of_device_ops sun8i_ths_thermal_ops = {
-+      .get_temp = sun8i_ths_get_temp,
-+};
-+
-+static int sun8i_ths_probe(struct platform_device *pdev)
-+{
-+      struct sun8i_ths_data *data;
-+      struct resource *res;
-+      int ret, irq, i;
-+
-+      data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
-+      if (!data)
-+              return -ENOMEM;
-+
-+      data->cfg = of_device_get_match_data(&pdev->dev);
-+      if (!data->cfg)
-+              return -EINVAL;
-+
-+      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+      if (!res) {
-+              dev_err(&pdev->dev, "no memory resources defined\n");
-+              return -EINVAL;
-+      }
-+
-+      data->regs = devm_ioremap_resource(&pdev->dev, res);
-+      if (IS_ERR(data->regs)) {
-+              ret = PTR_ERR(data->regs);
-+              dev_err(&pdev->dev, "failed to ioremap THS registers: %d\n", ret);
-+              return ret;
-+      }
-+
-+      irq = platform_get_irq(pdev, 0);
-+      if (irq < 0) {
-+              dev_err(&pdev->dev, "failed to get IRQ: %d\n", irq);
-+              return irq;
-+      }
-+
-+      ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
-+                                      sun8i_ths_irq_thread, IRQF_ONESHOT,
-+                                      dev_name(&pdev->dev), data);
-+      if (ret)
-+              return ret;
-+
-+      data->busclk = devm_clk_get(&pdev->dev, "ahb");
-+      if (IS_ERR(data->busclk)) {
-+              ret = PTR_ERR(data->busclk);
-+              dev_err(&pdev->dev, "failed to get ahb clk: %d\n", ret);
-+              return ret;
-+      }
-+
-+      data->clk = devm_clk_get(&pdev->dev, "ths");
-+      if (IS_ERR(data->clk)) {
-+              ret = PTR_ERR(data->clk);
-+              dev_err(&pdev->dev, "failed to get ths clk: %d\n", ret);
-+              return ret;
-+      }
-+
-+      data->reset = devm_reset_control_get(&pdev->dev, "ahb");
-+      if (IS_ERR(data->reset)) {
-+              ret = PTR_ERR(data->reset);
-+              dev_err(&pdev->dev, "failed to get reset: %d\n", ret);
-+              return ret;
-+      }
-+
-+      ret = reset_control_deassert(data->reset);
-+      if (ret) {
-+              dev_err(&pdev->dev, "reset deassert failed: %d\n", ret);
-+              return ret;
-+      }
-+
-+      ret = clk_prepare_enable(data->busclk);
-+      if (ret) {
-+              dev_err(&pdev->dev, "failed to enable bus clk: %d\n", ret);
-+              goto err_assert_reset;
-+      }
-+
-+      ret = clk_prepare_enable(data->clk);
-+      if (ret) {
-+              dev_err(&pdev->dev, "failed to enable ths clk: %d\n", ret);
-+              goto err_disable_bus;
-+      }
-+
-+      ret = clk_set_rate(data->clk, THS_H3_CLK_IN);
-+      if (ret)
-+              goto err_disable_ths;
-+
-+      data->calcell = devm_nvmem_cell_get(&pdev->dev, "cal");
-+      if (IS_ERR(data->calcell)) {
-+              if (PTR_ERR(data->calcell) == -EPROBE_DEFER) {
-+                      ret = PTR_ERR(data->calcell);
-+                      goto err_disable_ths;
-+              }
-+              /*
-+               * Even if the external calibration data stored in eFUSE is
-+               * not accessible, the THS hardware can still work, although
-+               * the data won't be so accurate.
-+               * The default value of calibration register is 0x800 for
-+               * every sensor, and the calibration value is usually 0x7xx
-+               * or 0x8xx, so they won't be away from the default value
-+               * for a lot.
-+               * So here we do not return if the calibartion data is not
-+               * available, except the probe needs deferring.
-+               */
-+      } else {
-+              ret = sun8i_ths_calibrate(data);
-+              if (ret)
-+                      goto err_disable_ths;
-+      }
-+
-+      for (i = 0; i < data->cfg->sensor_num; i++) {
-+              data->sensors[i].data = data;
-+              data->sensors[i].id = i;
-+              data->sensors[i].tzd =
-+                      devm_thermal_zone_of_sensor_register(&pdev->dev,
-+                              i, &data->sensors[i], &sun8i_ths_thermal_ops);
-+              if (IS_ERR(data->sensors[i].tzd)) {
-+                      ret = PTR_ERR(data->sensors[i].tzd);
-+                      dev_err(&pdev->dev,
-+                              "failed to register thermal zone %d: %d\n",
-+                              i, ret);
-+                      goto err_disable_ths;
-+              }
-+      }
-+
-+      sun8i_ths_init(data);
-+
-+      platform_set_drvdata(pdev, data);
-+      return 0;
-+
-+err_disable_ths:
-+      clk_disable_unprepare(data->clk);
-+err_disable_bus:
-+      clk_disable_unprepare(data->busclk);
-+err_assert_reset:
-+      reset_control_assert(data->reset);
-+      return ret;
-+}
-+
-+static int sun8i_ths_remove(struct platform_device *pdev)
-+{
-+      struct sun8i_ths_data *data = platform_get_drvdata(pdev);
-+
-+      reset_control_assert(data->reset);
-+      clk_disable_unprepare(data->clk);
-+      clk_disable_unprepare(data->busclk);
-+      return 0;
-+}
-+
-+static const struct sun8i_ths_cfg sun8i_h3_ths_cfg = {
-+      .sensor_num = 1,
-+      .calc_temp = sun8i_ths_calc_temp_h3,
-+};
-+
-+static const struct of_device_id sun8i_ths_id_table[] = {
-+      { .compatible = "allwinner,sun8i-h3-ths", .data = &sun8i_h3_ths_cfg },
-+      { /* sentinel */ },
-+};
-+MODULE_DEVICE_TABLE(of, sun8i_ths_id_table);
-+
-+static struct platform_driver sun8i_ths_driver = {
-+      .probe = sun8i_ths_probe,
-+      .remove = sun8i_ths_remove,
-+      .driver = {
-+              .name = "sun8i_ths",
-+              .of_match_table = sun8i_ths_id_table,
-+      },
-+};
-+
-+module_platform_driver(sun8i_ths_driver);
-+
-+MODULE_AUTHOR("Ondřej Jirman <megous@megous.com>");
-+MODULE_DESCRIPTION("Thermal sensor driver for new Allwinner SoCs");
-+MODULE_LICENSE("GPL v2");