Add improved A64 THS

throttling is still broken
This commit is contained in:
zador-blood-stained
2017-08-25 23:22:08 +03:00
parent 4f08c97d74
commit f86828d89c
5 changed files with 740 additions and 45 deletions

View File

@@ -2613,7 +2613,7 @@ CONFIG_SENSORS_ARM_SCPI=y
# CONFIG_SENSORS_G762 is not set
# CONFIG_SENSORS_GPIO_FAN is not set
# CONFIG_SENSORS_HIH6130 is not set
# CONFIG_SENSORS_IIO_HWMON is not set
CONFIG_SENSORS_IIO_HWMON=m
# CONFIG_SENSORS_IT87 is not set
# CONFIG_SENSORS_JC42 is not set
# CONFIG_SENSORS_POWR1220 is not set
@@ -2665,7 +2665,7 @@ CONFIG_SENSORS_LM90=m
# CONFIG_SENSORS_NCT7904 is not set
# CONFIG_SENSORS_PCF8591 is not set
# CONFIG_PMBUS is not set
# CONFIG_SENSORS_PWM_FAN is not set
CONFIG_SENSORS_PWM_FAN=m
CONFIG_SENSORS_SHT15=m
CONFIG_SENSORS_SHT21=m
CONFIG_SENSORS_SHT3x=m
@@ -2723,7 +2723,7 @@ CONFIG_THERMAL_GOV_USER_SPACE=y
CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y
CONFIG_CPU_THERMAL=y
CONFIG_CLOCK_THERMAL=y
# CONFIG_DEVFREQ_THERMAL is not set
CONFIG_DEVFREQ_THERMAL=y
CONFIG_THERMAL_EMULATION=y
# CONFIG_QORIQ_THERMAL is not set

View File

@@ -0,0 +1,15 @@
diff --git a/plat/sun50iw1p1/sunxi_security.c b/plat/sun50iw1p1/sunxi_security.c
index c0036c12..76d296bd 100644
--- a/plat/sun50iw1p1/sunxi_security.c
+++ b/plat/sun50iw1p1/sunxi_security.c
@@ -58,8 +58,9 @@ void sunxi_security_setup(void)
for (i = 0; i < 6; i++)
mmio_write_32(SPC_DECPORT_SET_REG(i), 0xff);
- /* switch RSB to secure */
+ /* switch RSB to secure
mmio_write_32(SPC_DECPORT_CLR_REG(3), 0x08);
+ */
/* set CCMU mbus_sec, bus_sec, pll_sec to non-secure */
mmio_write_32(0x01c20000+0x2f0, 0x7);

View File

@@ -1,5 +1,5 @@
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
index c8e7afa0..435e8f62 100644
index c8e7afa0..dc36bc38 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
@@ -50,12 +50,72 @@
@@ -88,27 +88,30 @@ index c8e7afa0..435e8f62 100644
};
cpu1: cpu@1 {
@@ -72,6 +138,7 @@
@@ -72,6 +138,8 @@
device_type = "cpu";
reg = <1>;
enable-method = "psci";
+ clocks = <&ccu 21>;
+ operating-points-v2 = <&cpu0_opp_table>;
};
cpu2: cpu@2 {
@@ -79,6 +146,7 @@
@@ -79,6 +147,8 @@
device_type = "cpu";
reg = <2>;
enable-method = "psci";
+ clocks = <&ccu 21>;
+ operating-points-v2 = <&cpu0_opp_table>;
};
cpu3: cpu@3 {
@@ -86,6 +154,58 @@
@@ -86,6 +156,59 @@
device_type = "cpu";
reg = <3>;
enable-method = "psci";
+ clocks = <&ccu 21>;
+ operating-points-v2 = <&cpu0_opp_table>;
+ };
+ };
+
@@ -116,7 +119,7 @@ index c8e7afa0..435e8f62 100644
+ cpu_thermal: cpu_thermal {
+ polling-delay-passive = <330>;
+ polling-delay = <1000>;
+ thermal-sensors = <&scpi_cpu_thermal 0>;
+ thermal-sensors = <&ths>;
+
+ trips {
+ cpu_warm: cpu_warm {
@@ -163,50 +166,32 @@ index c8e7afa0..435e8f62 100644
};
};
@@ -149,6 +269,37 @@
@@ -149,6 +272,11 @@
(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
};
+ mailbox: mbox@0 {
+ compatible = "arm,smc-mbox";
+ #mbox-cells = <1>;
+ arm,smc-func-ids = <0x82000001>;
+ };
+
+ sram: sram@10000{
+ compatible = "mmio-sram";
+ reg = <0x10000 0x8000>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x10000 0x8000>;
+
+ cpu_scp_mem: scp-shmem@7e00 {
+ compatible = "mmio-sram";
+ reg = <0x7e00 0x200>;
+ };
+ };
+
+ scpi {
+ compatible = "arm,scpi";
+ mboxes = <&mailbox 0>;
+ shmem = <&cpu_scp_mem>;
+
+ scpi_cpu_thermal: sensors {
+ compatible = "arm,scpi-sensors";
+ #thermal-sensor-cells = <1>;
+ };
+ iio-hwmon {
+ compatible = "iio-hwmon";
+ io-channels = <&ths>;
+ };
+
soc {
compatible = "simple-bus";
#address-cells = <1>;
@@ -477,6 +628,8 @@
clock-names = "hosc", "losc";
#clock-cells = <1>;
#reset-cells = <1>;
+ assigned-clocks = <&ccu CLK_THS>;
+ assigned-clock-rates = <4000000>;
@@ -594,6 +722,16 @@
status = "disabled";
};
pio: pinctrl@1c20800 {
+ ths: thermal-sensor@1c25000 {
+ compatible = "allwinner,sun50i-a64-ths";
+ reg = <0x01c25000 0x100>;
+ clocks = <&ccu CLK_BUS_THS>, <&ccu CLK_THS>;
+ clock-names = "bus", "mod";
+ resets = <&ccu RST_BUS_THS>;
+ #thermal-sensor-cells = <0>;
+ #io-channel-cells = <0>;
+ };
+
uart0: serial@1c28000 {
compatible = "snps,dw-apb-uart";
reg = <0x01c28000 0x400>;

View File

@@ -0,0 +1,212 @@
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
index c8e7afa0..435e8f62 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
@@ -50,12 +50,72 @@
#include <dt-bindings/reset/sun8i-de2.h>
#include <dt-bindings/clock/sun8i-r-ccu.h>
#include <dt-bindings/reset/sun8i-r-ccu.h>
+#include <dt-bindings/thermal/thermal.h>
/ {
interrupt-parent = <&gic>;
#address-cells = <1>;
#size-cells = <1>;
+ cpu0_opp_table: opp_table0 {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+ opp@408000000 {
+ opp-hz = /bits/ 64 <408000000>;
+ opp-microvolt = <1000000 1000000 1300000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ 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 = <1080000 1080000 1300000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp@912000000 {
+ opp-hz = /bits/ 64 <912000000>;
+ opp-microvolt = <1120000 1120000 1300000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp@960000000 {
+ opp-hz = /bits/ 64 <960000000>;
+ opp-microvolt = <1160000 1160000 1300000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp@1008000000 {
+ opp-hz = /bits/ 64 <1008000000>;
+ opp-microvolt = <1200000 1200000 1300000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp@1056000000 {
+ opp-hz = /bits/ 64 <1056000000>;
+ opp-microvolt = <1240000 1240000 1300000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp@1104000000 {
+ opp-hz = /bits/ 64 <1104000000>;
+ opp-microvolt = <1260000 1260000 1300000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+
+ opp@1152000000 {
+ opp-hz = /bits/ 64 <1152000000>;
+ opp-microvolt = <1300000 1300000 1300000>;
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ };
+ };
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
@@ -65,6 +125,12 @@
device_type = "cpu";
reg = <0>;
enable-method = "psci";
+ clocks = <&ccu 21>;
+ clock-names = "cpu";
+ operating-points-v2 = <&cpu0_opp_table>;
+ #cooling-cells = <2>;
+ cooling-min-level = <0>;
+ cooling-max-level = <8>;
};
cpu1: cpu@1 {
@@ -72,6 +138,7 @@
device_type = "cpu";
reg = <1>;
enable-method = "psci";
+ clocks = <&ccu 21>;
};
cpu2: cpu@2 {
@@ -79,6 +146,7 @@
device_type = "cpu";
reg = <2>;
enable-method = "psci";
+ clocks = <&ccu 21>;
};
cpu3: cpu@3 {
@@ -86,6 +154,58 @@
device_type = "cpu";
reg = <3>;
enable-method = "psci";
+ clocks = <&ccu 21>;
+ };
+ };
+
+ thermal-zones {
+ cpu_thermal: cpu_thermal {
+ polling-delay-passive = <330>;
+ polling-delay = <1000>;
+ thermal-sensors = <&scpi_cpu_thermal 0>;
+
+ 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 2>;
+ };
+
+ cpu_hot_limit_cpu {
+ trip = <&cpu_hot>;
+ cooling-device = <&cpu0 3 5>;
+ };
+
+ cpu_very_hot_limit_cpu {
+ trip = <&cpu_very_hot>;
+ cooling-device = <&cpu0 6 THERMAL_NO_LIMIT>;
+ };
+ };
};
};
@@ -149,6 +269,37 @@
(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
};
+ mailbox: mbox@0 {
+ compatible = "arm,smc-mbox";
+ #mbox-cells = <1>;
+ arm,smc-func-ids = <0x82000001>;
+ };
+
+ sram: sram@10000{
+ compatible = "mmio-sram";
+ reg = <0x10000 0x8000>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x10000 0x8000>;
+
+ cpu_scp_mem: scp-shmem@7e00 {
+ compatible = "mmio-sram";
+ reg = <0x7e00 0x200>;
+ };
+ };
+
+ scpi {
+ compatible = "arm,scpi";
+ mboxes = <&mailbox 0>;
+ shmem = <&cpu_scp_mem>;
+
+ scpi_cpu_thermal: sensors {
+ compatible = "arm,scpi-sensors";
+ #thermal-sensor-cells = <1>;
+ };
+ };
+
soc {
compatible = "simple-bus";
#address-cells = <1>;
@@ -477,6 +628,8 @@
clock-names = "hosc", "losc";
#clock-cells = <1>;
#reset-cells = <1>;
+ assigned-clocks = <&ccu CLK_THS>;
+ assigned-clock-rates = <4000000>;
};
pio: pinctrl@1c20800 {

View File

@@ -0,0 +1,483 @@
diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
index 137f577d..b0b231da 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -22,6 +22,7 @@
* shutdown for not being used.
*/
+#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -31,6 +32,7 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
+#include <linux/reset.h>
#include <linux/thermal.h>
#include <linux/delay.h>
@@ -49,46 +51,22 @@ static unsigned int sun6i_gpadc_chan_select(unsigned int chan)
return SUN6I_GPADC_CTRL1_ADC_CHAN_SELECT(chan);
}
+struct sun4i_gpadc_iio;
+
struct gpadc_data {
int temp_offset;
int temp_scale;
+ int temp_divider;
unsigned int tp_mode_en;
unsigned int tp_adc_select;
unsigned int (*adc_chan_select)(unsigned int chan);
unsigned int adc_chan_mask;
-};
-
-static const struct gpadc_data sun4i_gpadc_data = {
- .temp_offset = -1932,
- .temp_scale = 133,
- .tp_mode_en = SUN4I_GPADC_CTRL1_TP_MODE_EN,
- .tp_adc_select = SUN4I_GPADC_CTRL1_TP_ADC_SELECT,
- .adc_chan_select = &sun4i_gpadc_chan_select,
- .adc_chan_mask = SUN4I_GPADC_CTRL1_ADC_CHAN_MASK,
-};
-
-static const struct gpadc_data sun5i_gpadc_data = {
- .temp_offset = -1447,
- .temp_scale = 100,
- .tp_mode_en = SUN4I_GPADC_CTRL1_TP_MODE_EN,
- .tp_adc_select = SUN4I_GPADC_CTRL1_TP_ADC_SELECT,
- .adc_chan_select = &sun4i_gpadc_chan_select,
- .adc_chan_mask = SUN4I_GPADC_CTRL1_ADC_CHAN_MASK,
-};
-
-static const struct gpadc_data sun6i_gpadc_data = {
- .temp_offset = -1623,
- .temp_scale = 167,
- .tp_mode_en = SUN6I_GPADC_CTRL1_TP_MODE_EN,
- .tp_adc_select = SUN6I_GPADC_CTRL1_TP_ADC_SELECT,
- .adc_chan_select = &sun6i_gpadc_chan_select,
- .adc_chan_mask = SUN6I_GPADC_CTRL1_ADC_CHAN_MASK,
-};
-
-static const struct gpadc_data sun8i_a33_gpadc_data = {
- .temp_offset = -1662,
- .temp_scale = 162,
- .tp_mode_en = SUN8I_GPADC_CTRL1_CHOP_TEMP_EN,
+ unsigned int temp_data;
+ int (*sample_start)(struct sun4i_gpadc_iio *info);
+ int (*sample_end)(struct sun4i_gpadc_iio *info);
+ bool has_bus_clk;
+ bool has_bus_rst;
+ bool has_mod_clk;
};
struct sun4i_gpadc_iio {
@@ -103,6 +81,9 @@ struct sun4i_gpadc_iio {
atomic_t ignore_temp_data_irq;
const struct gpadc_data *data;
bool no_irq;
+ struct clk *ths_bus_clk;
+ struct clk *mod_clk;
+ struct reset_control *reset;
/* prevents concurrent reads of temperature and ADC */
struct mutex mutex;
struct thermal_zone_device *tzd;
@@ -277,7 +258,7 @@ static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val)
if (info->no_irq) {
pm_runtime_get_sync(indio_dev->dev.parent);
- regmap_read(info->regmap, SUN4I_GPADC_TEMP_DATA, val);
+ regmap_read(info->regmap, info->data->temp_data, val);
pm_runtime_mark_last_busy(indio_dev->dev.parent);
pm_runtime_put_autosuspend(indio_dev->dev.parent);
@@ -306,6 +287,15 @@ static int sun4i_gpadc_temp_scale(struct iio_dev *indio_dev, int *val)
return 0;
}
+static int sun4i_gpadc_temp_divider(struct iio_dev *indio_dev, int *val)
+{
+ struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
+
+ *val = info->data->temp_divider;
+
+ return 0;
+}
+
static int sun4i_gpadc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
@@ -383,10 +373,8 @@ static irqreturn_t sun4i_gpadc_fifo_data_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int sun4i_gpadc_runtime_suspend(struct device *dev)
+static int sun4i_gpadc_sample_end(struct sun4i_gpadc_iio *info)
{
- struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(dev));
-
/* Disable the ADC on IP */
regmap_write(info->regmap, SUN4I_GPADC_CTRL1, 0);
/* Disable temperature sensor on IP */
@@ -395,10 +383,23 @@ static int sun4i_gpadc_runtime_suspend(struct device *dev)
return 0;
}
-static int sun4i_gpadc_runtime_resume(struct device *dev)
+static int sun8i_h3_gpadc_sample_end(struct sun4i_gpadc_iio *info)
+{
+ /* Disable temperature sensor */
+ regmap_write(info->regmap, SUN8I_H3_GPADC_CTRL2, 0);
+
+ return 0;
+}
+
+static int sun4i_gpadc_runtime_suspend(struct device *dev)
{
struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(dev));
+ return info->data->sample_end(info);
+}
+
+static int sun4i_gpadc_sample_start(struct sun4i_gpadc_iio *info)
+{
/* clkin = 6MHz */
regmap_write(info->regmap, SUN4I_GPADC_CTRL0,
SUN4I_GPADC_CTRL0_ADC_CLK_DIVIDER(2) |
@@ -416,18 +417,52 @@ static int sun4i_gpadc_runtime_resume(struct device *dev)
return 0;
}
+static int sun8i_h3_gpadc_sample_start(struct sun4i_gpadc_iio *info)
+{
+ regmap_write(info->regmap, SUN8I_H3_GPADC_CTRL2,
+ SUN8I_H3_GPADC_CTRL2_TEMP_SENSE_EN |
+ SUN8I_H3_GPADC_CTRL2_T_ACQ1(31));
+ regmap_write(info->regmap, SUN4I_GPADC_CTRL0,
+ SUN4I_GPADC_CTRL0_T_ACQ(31));
+ regmap_write(info->regmap, SUN8I_H3_GPADC_CTRL3,
+ SUN4I_GPADC_CTRL3_FILTER_EN |
+ SUN4I_GPADC_CTRL3_FILTER_TYPE(1));
+ regmap_write(info->regmap, SUN8I_H3_GPADC_INTC,
+ SUN8I_H3_GPADC_INTC_TEMP_PERIOD(800));
+
+ return 0;
+}
+
+static int sun4i_gpadc_runtime_resume(struct device *dev)
+{
+ struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(dev));
+
+ return info->data->sample_start(info);
+}
+
+/* temperature = ( MINUPA - reg * MULPA) / DIVPA
+#define MULPA 25000
+#define DIVPA 214
+#define MINUPA 2170
+static int sun50_th_reg_to_temp(uint32_t reg_data)
+{
+ return ((MINUPA - (int)reg_data) * MULPA) / DIVPA;
+}
+*/
+
static int sun4i_gpadc_get_temp(void *data, int *temp)
{
struct sun4i_gpadc_iio *info = data;
- int val, scale, offset;
+ int val, scale, offset, divider;
if (sun4i_gpadc_temp_read(info->indio_dev, &val))
return -ETIMEDOUT;
sun4i_gpadc_temp_scale(info->indio_dev, &scale);
sun4i_gpadc_temp_offset(info->indio_dev, &offset);
+ sun4i_gpadc_temp_divider(info->indio_dev, &divider);
- *temp = (val + offset) * scale;
+ *temp = ((val + offset) * scale) / divider;
return 0;
}
@@ -490,11 +525,116 @@ static int sun4i_irq_init(struct platform_device *pdev, const char *name,
return 0;
}
+static const struct gpadc_data sun4i_gpadc_data = {
+ .temp_offset = -1932,
+ .temp_scale = 133,
+ .temp_divider = 1,
+ .tp_mode_en = SUN4I_GPADC_CTRL1_TP_MODE_EN,
+ .tp_adc_select = SUN4I_GPADC_CTRL1_TP_ADC_SELECT,
+ .adc_chan_select = &sun4i_gpadc_chan_select,
+ .adc_chan_mask = SUN4I_GPADC_CTRL1_ADC_CHAN_MASK,
+ .temp_data = SUN4I_GPADC_TEMP_DATA,
+ .sample_start = sun4i_gpadc_sample_start,
+ .sample_end = sun4i_gpadc_sample_end,
+};
+
+static const struct gpadc_data sun5i_gpadc_data = {
+ .temp_offset = -1447,
+ .temp_scale = 100,
+ .temp_divider = 1,
+ .tp_mode_en = SUN4I_GPADC_CTRL1_TP_MODE_EN,
+ .tp_adc_select = SUN4I_GPADC_CTRL1_TP_ADC_SELECT,
+ .adc_chan_select = &sun4i_gpadc_chan_select,
+ .adc_chan_mask = SUN4I_GPADC_CTRL1_ADC_CHAN_MASK,
+ .temp_data = SUN4I_GPADC_TEMP_DATA,
+ .sample_start = sun4i_gpadc_sample_start,
+ .sample_end = sun4i_gpadc_sample_end,
+};
+
+static const struct gpadc_data sun6i_gpadc_data = {
+ .temp_offset = -1623,
+ .temp_scale = 167,
+ .temp_divider = 1,
+ .tp_mode_en = SUN6I_GPADC_CTRL1_TP_MODE_EN,
+ .tp_adc_select = SUN6I_GPADC_CTRL1_TP_ADC_SELECT,
+ .adc_chan_select = &sun6i_gpadc_chan_select,
+ .adc_chan_mask = SUN6I_GPADC_CTRL1_ADC_CHAN_MASK,
+ .temp_data = SUN4I_GPADC_TEMP_DATA,
+ .sample_start = sun4i_gpadc_sample_start,
+ .sample_end = sun4i_gpadc_sample_end,
+};
+
+static const struct gpadc_data sun8i_a33_gpadc_data = {
+ .temp_offset = -1662,
+ .temp_scale = 162,
+ .temp_divider = 1,
+ .tp_mode_en = SUN8I_A23_GPADC_CTRL1_CHOP_TEMP_EN,
+ .temp_data = SUN4I_GPADC_TEMP_DATA,
+ .sample_start = sun4i_gpadc_sample_start,
+ .sample_end = sun4i_gpadc_sample_end,
+};
+
+static const struct gpadc_data sun8i_h3_gpadc_data = {
+ /*
+ * The original formula on the datasheet seems to be wrong.
+ * These factors are calculated based on the formula in the BSP
+ * kernel, which is originally Tem = 217 - (T / 8.253), in which Tem
+ * is the temperature in Celsius degree and T is the raw value
+ * from the sensor.
+ */
+ .temp_offset = -1791,
+ .temp_scale = -121,
+ .temp_divider = 1,
+ .temp_data = SUN8I_H3_GPADC_TEMP_DATA,
+ .sample_start = sun8i_h3_gpadc_sample_start,
+ .sample_end = sun8i_h3_gpadc_sample_end,
+ .has_bus_clk = true,
+ .has_bus_rst = true,
+ .has_mod_clk = true,
+};
+
+static const struct gpadc_data sun50i_a64_gpadc_data = {
+ .temp_offset = -2170,
+ .temp_scale = -1000,
+ .temp_divider = 8560,
+ .temp_data = SUN8I_H3_GPADC_TEMP_DATA,
+ .sample_start = sun8i_h3_gpadc_sample_start,
+ .sample_end = sun8i_h3_gpadc_sample_end,
+ .has_bus_clk = true,
+ .has_bus_rst = true,
+ .has_mod_clk = true,
+};
+
+static const struct gpadc_data sun50i_h5_gpadc_data = {
+ /* Not done for now since requires 2 sets of offset+scale */
+ .temp_offset = -1321,
+ .temp_scale = -121,
+ .temp_divider = 1,
+ .temp_data = SUN8I_H3_GPADC_TEMP_DATA,
+ .sample_start = sun8i_h3_gpadc_sample_start,
+ .sample_end = sun8i_h3_gpadc_sample_end,
+ .has_bus_clk = true,
+ .has_bus_rst = true,
+ .has_mod_clk = true,
+};
+
static const struct of_device_id sun4i_gpadc_of_id[] = {
{
.compatible = "allwinner,sun8i-a33-ths",
.data = &sun8i_a33_gpadc_data,
},
+ {
+ .compatible = "allwinner,sun8i-h3-ths",
+ .data = &sun8i_h3_gpadc_data,
+ },
+ {
+ .compatible = "allwinner,sun50i-a64-ths",
+ .data = &sun50i_a64_gpadc_data,
+ },
+ {
+ .compatible = "allwinner,sun50i-h5-ths",
+ .data = &sun50i_h5_gpadc_data,
+ },
{ /* sentinel */ }
};
@@ -529,17 +669,75 @@ static int sun4i_gpadc_probe_dt(struct platform_device *pdev,
return ret;
}
+ if (info->data->has_bus_rst) {
+ info->reset = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(info->reset)) {
+ ret = PTR_ERR(info->reset);
+ return ret;
+ }
+
+ ret = reset_control_deassert(info->reset);
+ if (ret)
+ return ret;
+ }
+
+ if (info->data->has_bus_clk) {
+ info->ths_bus_clk = devm_clk_get(&pdev->dev, "bus");
+ if (IS_ERR(info->ths_bus_clk)) {
+ ret = PTR_ERR(info->ths_bus_clk);
+ goto assert_reset;
+ }
+
+ ret = clk_prepare_enable(info->ths_bus_clk);
+ if (ret)
+ goto assert_reset;
+ }
+
+ if (info->data->has_mod_clk) {
+ info->mod_clk = devm_clk_get(&pdev->dev, "mod");
+ if (IS_ERR(info->mod_clk)) {
+ ret = PTR_ERR(info->mod_clk);
+ goto disable_bus_clk;
+ }
+
+ /* Running at 6MHz */
+ ret = clk_set_rate(info->mod_clk, 6000000);
+ if (ret)
+ goto disable_bus_clk;
+
+ ret = clk_prepare_enable(info->mod_clk);
+ if (ret)
+ goto disable_bus_clk;
+ }
+
if (!IS_ENABLED(CONFIG_THERMAL_OF))
return 0;
info->sensor_device = &pdev->dev;
info->tzd = thermal_zone_of_sensor_register(info->sensor_device, 0,
info, &sun4i_ts_tz_ops);
- if (IS_ERR(info->tzd))
+ if (IS_ERR(info->tzd)) {
dev_err(&pdev->dev, "could not register thermal sensor: %ld\n",
PTR_ERR(info->tzd));
+ ret = PTR_ERR(info->tzd);
+ goto disable_mod_clk;
+ }
- return PTR_ERR_OR_ZERO(info->tzd);
+ return 0;
+
+disable_mod_clk:
+ if (info->data->has_mod_clk)
+ clk_disable_unprepare(info->mod_clk);
+
+disable_bus_clk:
+ if (info->data->has_bus_clk)
+ clk_disable_unprepare(info->ths_bus_clk);
+
+assert_reset:
+ if (info->data->has_bus_rst)
+ reset_control_assert(info->reset);
+
+ return ret;
}
static int sun4i_gpadc_probe_mfd(struct platform_device *pdev,
@@ -698,6 +896,15 @@ static int sun4i_gpadc_remove(struct platform_device *pdev)
if (!info->no_irq)
iio_map_array_unregister(indio_dev);
+ if (info->data->has_mod_clk)
+ clk_disable_unprepare(info->mod_clk);
+
+ if (info->data->has_bus_clk)
+ clk_disable_unprepare(info->ths_bus_clk);
+
+ if (info->data->has_bus_rst)
+ reset_control_assert(info->reset);
+
return 0;
}
diff --git a/include/linux/mfd/sun4i-gpadc.h b/include/linux/mfd/sun4i-gpadc.h
index 139872c2..f794a298 100644
--- a/include/linux/mfd/sun4i-gpadc.h
+++ b/include/linux/mfd/sun4i-gpadc.h
@@ -38,9 +38,12 @@
#define SUN6I_GPADC_CTRL1_ADC_CHAN_SELECT(x) (GENMASK(3, 0) & BIT(x))
#define SUN6I_GPADC_CTRL1_ADC_CHAN_MASK GENMASK(3, 0)
-/* TP_CTRL1 bits for sun8i SoCs */
-#define SUN8I_GPADC_CTRL1_CHOP_TEMP_EN BIT(8)
-#define SUN8I_GPADC_CTRL1_GPADC_CALI_EN BIT(7)
+/* TP_CTRL1 bits for sun8i A23/A33 SoCs */
+#define SUN8I_A23_GPADC_CTRL1_CHOP_TEMP_EN BIT(8)
+#define SUN8I_A23_GPADC_CTRL1_GPADC_CALI_EN BIT(7)
+
+/* TP_CTRL1 bits for SoCs after H3 */
+#define SUN8I_H3_GPADC_CTRL1_GPADC_CALI_EN BIT(17)
#define SUN4I_GPADC_CTRL2 0x08
@@ -49,7 +52,17 @@
#define SUN4I_GPADC_CTRL2_PRE_MEA_EN BIT(24)
#define SUN4I_GPADC_CTRL2_PRE_MEA_THRE_CNT(x) (GENMASK(23, 0) & (x))
+#define SUN8I_H3_GPADC_CTRL2 0x40
+
+#define SUN8I_H3_GPADC_CTRL2_TEMP_SENSE_EN BIT(0)
+#define SUN8I_H3_GPADC_CTRL2_T_ACQ1(x) ((GENMASK(15, 0) * (x)) << 16)
+
#define SUN4I_GPADC_CTRL3 0x0c
+/*
+ * This register is named "Average filter Control Register" in H3 Datasheet,
+ * but the register's definition is the same as the old CTRL3 register.
+ */
+#define SUN8I_H3_GPADC_CTRL3 0x70
#define SUN4I_GPADC_CTRL3_FILTER_EN BIT(2)
#define SUN4I_GPADC_CTRL3_FILTER_TYPE(x) (GENMASK(1, 0) & (x))
@@ -71,6 +84,13 @@
#define SUN4I_GPADC_INT_FIFOC_TP_UP_IRQ_EN BIT(1)
#define SUN4I_GPADC_INT_FIFOC_TP_DOWN_IRQ_EN BIT(0)
+#define SUN8I_H3_GPADC_INTC 0x44
+
+#define SUN8I_H3_GPADC_INTC_TEMP_PERIOD(x) ((GENMASK(19, 0) & (x)) << 12)
+#define SUN8I_H3_GPADC_INTC_TEMP_DATA BIT(8)
+#define SUN8I_H3_GPADC_INTC_TEMP_SHUT BIT(4)
+#define SUN8I_H3_GPADC_INTC_TEMP_ALARM BIT(0)
+
#define SUN4I_GPADC_INT_FIFOS 0x14
#define SUN4I_GPADC_INT_FIFOS_TEMP_DATA_PENDING BIT(18)
@@ -80,9 +100,16 @@
#define SUN4I_GPADC_INT_FIFOS_TP_UP_PENDING BIT(1)
#define SUN4I_GPADC_INT_FIFOS_TP_DOWN_PENDING BIT(0)
+#define SUN8I_H3_GPADC_INTS 0x44
+
+#define SUN8I_H3_GPADC_INTS_TEMP_DATA BIT(8)
+#define SUN8I_H3_GPADC_INTS_TEMP_SHUT BIT(4)
+#define SUN8I_H3_GPADC_INTS_TEMP_ALARM BIT(0)
+
#define SUN4I_GPADC_CDAT 0x1c
#define SUN4I_GPADC_TEMP_DATA 0x20
#define SUN4I_GPADC_DATA 0x24
+#define SUN8I_H3_GPADC_TEMP_DATA 0x80
#define SUN4I_GPADC_IRQ_FIFO_DATA 0
#define SUN4I_GPADC_IRQ_TEMP_DATA 1