Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- commit 14910f9f2fc0b6f703693cf772da366e1615accb
- Author: Dmitry Smirnov <divis1969@gmail.com>
- Date: Sun Jan 7 21:50:51 2018 +0300
- Thermal sensor
- diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi
- index a384b766f..dca724527 100644
- --- a/arch/arm/boot/dts/sun8i-a83t.dtsi
- +++ b/arch/arm/boot/dts/sun8i-a83t.dtsi
- @@ -48,6 +48,7 @@
- #include <dt-bindings/clock/sun8i-r-ccu.h>
- #include <dt-bindings/reset/sun8i-a83t-ccu.h>
- #include <dt-bindings/reset/sun8i-r-ccu.h>
- +#include <dt-bindings/thermal/thermal.h>
- / {
- interrupt-parent = <&gic>;
- @@ -55,55 +56,224 @@
- #size-cells = <1>;
- cpus {
- + enable-method = "allwinner,sun8i-a23";
- #address-cells = <1>;
- #size-cells = <0>;
- - cpu@0 {
- + cpu0: cpu@0 {
- compatible = "arm,cortex-a7";
- device_type = "cpu";
- reg = <0>;
- + clocks = <&ccu CLK_C0CPUX>;
- + clock-names = "c0cpux";
- + operating-points-v2 = <&cluster0_opp_table>;
- + #cooling-cells = <2>;
- };
- cpu@1 {
- compatible = "arm,cortex-a7";
- device_type = "cpu";
- reg = <1>;
- + operating-points-v2 = <&cluster0_opp_table>;
- };
- cpu@2 {
- compatible = "arm,cortex-a7";
- device_type = "cpu";
- reg = <2>;
- + operating-points-v2 = <&cluster0_opp_table>;
- };
- cpu@3 {
- compatible = "arm,cortex-a7";
- device_type = "cpu";
- reg = <3>;
- + operating-points-v2 = <&cluster0_opp_table>;
- };
- - cpu@100 {
- + cpu100: cpu@100 {
- compatible = "arm,cortex-a7";
- device_type = "cpu";
- reg = <0x100>;
- + clocks = <&ccu CLK_C1CPUX>;
- + clock-names = "c1cpux";
- + operating-points-v2 = <&cluster1_opp_table>;
- + #cooling-cells = <2>;
- };
- cpu@101 {
- compatible = "arm,cortex-a7";
- device_type = "cpu";
- reg = <0x101>;
- + operating-points-v2 = <&cluster1_opp_table>;
- };
- cpu@102 {
- compatible = "arm,cortex-a7";
- device_type = "cpu";
- reg = <0x102>;
- + operating-points-v2 = <&cluster1_opp_table>;
- };
- cpu@103 {
- compatible = "arm,cortex-a7";
- device_type = "cpu";
- reg = <0x103>;
- + operating-points-v2 = <&cluster1_opp_table>;
- + };
- + };
- +
- + cluster0_opp_table: opp_table0 {
- + compatible = "operating-points-v2";
- + opp-shared;
- +
- + opp-120000000 {
- + opp-hz = /bits/ 64 <120000000>;
- + opp-microvolt = <1040000>;
- + clock-latency-ns = <244144>; /* 8 32k periods */
- + };
- +
- + opp-240000000 {
- + opp-hz = /bits/ 64 <240000000>;
- + opp-microvolt = <1040000>;
- + clock-latency-ns = <244144>; /* 8 32k periods */
- + };
- +
- + opp-312000000 {
- + opp-hz = /bits/ 64 <312000000>;
- + opp-microvolt = <1040000>;
- + clock-latency-ns = <244144>; /* 8 32k periods */
- + };
- +
- + opp-408000000 {
- + opp-hz = /bits/ 64 <408000000>;
- + opp-microvolt = <1040000>;
- + clock-latency-ns = <244144>; /* 8 32k periods */
- + };
- +
- + opp-480000000 {
- + opp-hz = /bits/ 64 <480000000>;
- + opp-microvolt = <1040000>;
- + clock-latency-ns = <244144>; /* 8 32k periods */
- + };
- +
- + opp-504000000 {
- + opp-hz = /bits/ 64 <504000000>;
- + opp-microvolt = <1040000>;
- + clock-latency-ns = <244144>; /* 8 32k periods */
- + };
- +
- + opp-600000000 {
- + opp-hz = /bits/ 64 <600000000>;
- + opp-microvolt = <1040000>;
- + clock-latency-ns = <244144>; /* 8 32k periods */
- + };
- +
- + opp-648000000 {
- + opp-hz = /bits/ 64 <648000000>;
- + opp-microvolt = <1040000>;
- + clock-latency-ns = <244144>; /* 8 32k periods */
- + };
- +
- + opp-720000000 {
- + opp-hz = /bits/ 64 <720000000>;
- + opp-microvolt = <1100000>;
- + clock-latency-ns = <244144>; /* 8 32k periods */
- + };
- +
- + opp-816000000 {
- + opp-hz = /bits/ 64 <816000000>;
- + opp-microvolt = <1100000>;
- + clock-latency-ns = <244144>; /* 8 32k periods */
- + };
- +
- + opp-912000000 {
- + opp-hz = /bits/ 64 <912000000>;
- + opp-microvolt = <1200000>;
- + clock-latency-ns = <244144>; /* 8 32k periods */
- + };
- +
- + opp-1008000000 {
- + opp-hz = /bits/ 64 <1008000000>;
- + opp-microvolt = <1200000>;
- + clock-latency-ns = <244144>; /* 8 32k periods */
- + };
- + };
- +
- + cluster1_opp_table: opp_table1 {
- + compatible = "operating-points-v2";
- + opp-shared;
- +
- + opp-120000000 {
- + opp-hz = /bits/ 64 <120000000>;
- + opp-microvolt = <1040000>;
- + clock-latency-ns = <244144>; /* 8 32k periods */
- + };
- +
- + opp-240000000 {
- + opp-hz = /bits/ 64 <240000000>;
- + opp-microvolt = <1040000>;
- + clock-latency-ns = <244144>; /* 8 32k periods */
- + };
- +
- + opp-312000000 {
- + opp-hz = /bits/ 64 <312000000>;
- + opp-microvolt = <1040000>;
- + clock-latency-ns = <244144>; /* 8 32k periods */
- + };
- +
- + opp-408000000 {
- + opp-hz = /bits/ 64 <408000000>;
- + opp-microvolt = <1040000>;
- + clock-latency-ns = <244144>; /* 8 32k periods */
- + };
- +
- + opp-480000000 {
- + opp-hz = /bits/ 64 <480000000>;
- + opp-microvolt = <1040000>;
- + clock-latency-ns = <244144>; /* 8 32k periods */
- + };
- +
- + opp-504000000 {
- + opp-hz = /bits/ 64 <504000000>;
- + opp-microvolt = <1040000>;
- + clock-latency-ns = <244144>; /* 8 32k periods */
- + };
- +
- + opp-600000000 {
- + opp-hz = /bits/ 64 <600000000>;
- + opp-microvolt = <1040000>;
- + clock-latency-ns = <244144>; /* 8 32k periods */
- + };
- +
- + opp-648000000 {
- + opp-hz = /bits/ 64 <648000000>;
- + opp-microvolt = <1040000>;
- + clock-latency-ns = <244144>; /* 8 32k periods */
- + };
- +
- + opp-720000000 {
- + opp-hz = /bits/ 64 <720000000>;
- + opp-microvolt = <1100000>;
- + clock-latency-ns = <244144>; /* 8 32k periods */
- + };
- +
- + opp-816000000 {
- + opp-hz = /bits/ 64 <816000000>;
- + opp-microvolt = <1100000>;
- + clock-latency-ns = <244144>; /* 8 32k periods */
- + };
- +
- + opp-912000000 {
- + opp-hz = /bits/ 64 <912000000>;
- + opp-microvolt = <1200000>;
- + clock-latency-ns = <244144>; /* 8 32k periods */
- + };
- +
- + opp-1008000000 {
- + opp-hz = /bits/ 64 <1008000000>;
- + opp-microvolt = <1200000>;
- + clock-latency-ns = <244144>; /* 8 32k periods */
- };
- };
- @@ -537,5 +707,135 @@
- #address-cells = <1>;
- #size-cells = <0>;
- };
- +
- + ths: ths@1f04000 {
- + compatible = "allwinner,sun8i-a83t-ths";
- + reg = <0x1f04000 0x100>;
- + #thermal-sensor-cells = <1>;
- + #io-channel-cells = <1>;
- + };
- +
- };
- +
- + thermal-zones {
- + cpu0x_thermal {
- + /* milliseconds */
- + polling-delay-passive = <250>;
- + polling-delay = <1000>;
- + thermal-sensors = <&ths 0>;
- +
- + trips {
- + cpu_alert0: cpu_alert0 {
- + /* milliCelsius */
- + temperature = <75000>;
- + hysteresis = <2000>;
- + type = "passive";
- + };
- +
- + cpu_alert1: cpu_alert1 {
- + /* milliCelsius */
- + temperature = <90000>;
- + hysteresis = <2000>;
- + type = "hot";
- + };
- +
- + cpu_crit0: cpu_crit0 {
- + /* milliCelsius */
- + temperature = <110000>;
- + hysteresis = <2000>;
- + type = "critical";
- + };
- + };
- +
- + cooling-maps {
- + map0 {
- + trip = <&cpu_alert0>;
- + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
- + };
- + map1 {
- + trip = <&cpu_alert1>;
- + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
- + };
- + };
- + };
- +
- + cpu1x_thermal {
- + /* milliseconds */
- + polling-delay-passive = <250>;
- + polling-delay = <1000>;
- + thermal-sensors = <&ths 1>;
- +
- + trips {
- + cpu_alert100: cpu_alert100 {
- + /* milliCelsius */
- + temperature = <75000>;
- + hysteresis = <2000>;
- + type = "passive";
- + };
- +
- + cpu_alert101: cpu_alert101 {
- + /* milliCelsius */
- + temperature = <90000>;
- + hysteresis = <2000>;
- + type = "hot";
- + };
- +
- + cpu_crit1: cpu_crit1 {
- + /* milliCelsius */
- + temperature = <110000>;
- + hysteresis = <2000>;
- + type = "critical";
- + };
- + };
- +
- + cooling-maps {
- + map0 {
- + trip = <&cpu_alert100>;
- + cooling-device = <&cpu100 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
- + };
- + map1 {
- + trip = <&cpu_alert101>;
- + cooling-device = <&cpu100 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
- + };
- + };
- +
- + };
- +
- + gpu_thermal {
- + /* milliseconds */
- + polling-delay-passive = <250>;
- + polling-delay = <1000>;
- + thermal-sensors = <&ths 2>;
- +
- + trips {
- + gpu_alert0: gpu_alert0 {
- + /* milliCelsius */
- + temperature = <85000>;
- + hysteresis = <2000>;
- + type = "passive";
- + };
- +
- + gpu_alert1: gpu_alert1 {
- + /* milliCelsius */
- + temperature = <95000>;
- + hysteresis = <2000>;
- + type = "hot";
- + };
- +
- + };
- +
- +/* cooling-maps {
- + map0 {
- + trip = <&gpu_alert0>;
- + cooling-device = <&mali 1 THERMAL_NO_LIMIT>;
- + };
- +
- + map1 {
- + trip = <&gpu_alert1>;
- + cooling-device = <&mali 2 THERMAL_NO_LIMIT>;
- + };
- + };*/
- +
- + };
- + };
- };
- diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
- index 315ae2926..0ed8ed0b0 100644
- --- a/drivers/thermal/Kconfig
- +++ b/drivers/thermal/Kconfig
- @@ -482,4 +482,17 @@ config UNIPHIER_THERMAL
- Enable this to plug in UniPhier on-chip PVT thermal driver into the
- thermal framework. The driver supports CPU thermal zone temperature
- reporting and a couple of trip points.
- +
- +config SUN8I_A83T_THERMAL
- + tristate "Allwinner A83T SoC Thermal Sensor"
- + depends on MACH_SUN8I
- + depends on THERMAL || !THERMAL_OF
- + help
- + Say yes here to build support for Allwinner (A83T) SoC
- + Thermal Controller. This controller provides 3 thermal sensors
- + (2 for CPU clusters and 1 for GPU).
- +
- + To compile this driver as a module, choose M here: the module will be
- + called sun8i-thermal-iio.
- +
- endif
- diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
- index 610344eb3..6bdae87d4 100644
- --- a/drivers/thermal/Makefile
- +++ b/drivers/thermal/Makefile
- @@ -61,3 +61,5 @@ obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o
- obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o
- obj-$(CONFIG_ZX2967_THERMAL) += zx2967_thermal.o
- obj-$(CONFIG_UNIPHIER_THERMAL) += uniphier_thermal.o
- +obj-$(CONFIG_SUN8I_A83T_THERMAL) += sun8i-soc-thermal.o
- +
- diff --git a/drivers/thermal/sun8i-soc-thermal.c b/drivers/thermal/sun8i-soc-thermal.c
- new file mode 100644
- index 000000000..e56e19371
- --- /dev/null
- +++ b/drivers/thermal/sun8i-soc-thermal.c
- @@ -0,0 +1,870 @@
- +/* Thermal sensor driver for sunxi platforms' (A83T)
- + *
- + * Copyright (c) 2017 Dmitry Smirnov <divis1969@gmail.com>
- + *
- + * This program is free software; you can redistribute it and/or modify it under
- + * the terms of the GNU General Public License version 2 as published by the
- + * Free Software Foundation.
- + *
- + * The Allwinner SoCs all have an ADC that can also act as a touchscreen
- + * controller and a thermal sensor.
- + * The thermal sensor works only when the ADC acts as a touchscreen controller
- + * and is configured to throw an interrupt every fixed periods of time (let say
- + * every X seconds).
- + * One would be tempted to disable the IP on the hardware side rather than
- + * disabling interrupts to save some power but that resets the internal clock of
- + * the IP, resulting in having to wait X seconds every time we want to read the
- + * value of the thermal sensor.
- + * This is also the reason of using autosuspend in pm_runtime. If there was no
- + * autosuspend, the thermal sensor would need X seconds after every
- + * pm_runtime_get_sync to get a value from the ADC. The autosuspend allows the
- + * thermal sensor to be requested again in a certain time span before it gets
- + * shutdown for not being used.
- + */
- +
- +#include <linux/completion.h>
- +#include <linux/interrupt.h>
- +#include <linux/io.h>
- +#include <linux/module.h>
- +#include <linux/of.h>
- +#include <linux/of_device.h>
- +#include <linux/platform_device.h>
- +#include <linux/pm_runtime.h>
- +#include <linux/regmap.h>
- +#include <linux/thermal.h>
- +#include <linux/delay.h>
- +
- +#include <linux/iio/iio.h>
- +#include <linux/iio/driver.h>
- +#include <linux/iio/machine.h>
- +#include <linux/soc/sunxi/sun8i-soc-thermal.h>
- +
- +//static unsigned int sun8i_gpadc_chan_select(unsigned int chan)
- +//{
- +// return SUN8I_GPADC_CTRL1_ADC_CHAN_SELECT(chan);
- +//}
- +//
- +//static unsigned int sun6i_gpadc_chan_select(unsigned int chan)
- +//{
- +// return SUN6I_GPADC_CTRL1_ADC_CHAN_SELECT(chan);
- +//}
- +
- +struct ths_data {
- + int temp_offset;
- + int temp_scale;
- + 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 sun8i_gpadc_data = {
- +// .temp_offset = -1932,
- +// .temp_scale = 133,
- +// .tp_mode_en = SUN8I_GPADC_CTRL1_TP_MODE_EN,
- +// .tp_adc_select = SUN8I_GPADC_CTRL1_TP_ADC_SELECT,
- +// .adc_chan_select = &sun8i_gpadc_chan_select,
- +// .adc_chan_mask = SUN8I_GPADC_CTRL1_ADC_CHAN_MASK,
- +//};
- +//
- +//static const struct gpadc_data sun5i_gpadc_data = {
- +// .temp_offset = -1447,
- +// .temp_scale = 100,
- +// .tp_mode_en = SUN8I_GPADC_CTRL1_TP_MODE_EN,
- +// .tp_adc_select = SUN8I_GPADC_CTRL1_TP_ADC_SELECT,
- +// .adc_chan_select = &sun8i_gpadc_chan_select,
- +// .adc_chan_mask = SUN8I_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,
- +//};
- +
- +
- +/*
- + * T = (2719-Tem)/14.186
- + */
- +static const struct ths_data sun8i_a83t_ths_data = {
- + .temp_offset = -2719,
- + .temp_scale = -70,
- +// .tp_mode_en = SUN8I_GPADC_CTRL1_CHOP_TEMP_EN,
- +};
- +
- +struct sun8i_soc_thermal_dev;
- +
- +struct sun8i_soc_thermal_sensor {
- + struct sun8i_soc_thermal_dev *device;
- + struct iio_dev *indio_dev;
- + struct thermal_zone_device *tzd;
- + const struct ths_data *ths_data;
- +};
- +
- +struct sun8i_soc_thermal_dev {
- + struct platform_device *pdev;
- + struct sun8i_soc_thermal_sensor sensors[3];
- + struct regmap *regmap;
- +};
- +
- +//struct sun8i_ths_iio {
- +// struct iio_dev *indio_dev;
- +// struct completion completion;
- +// int temp_data;
- +// u32 adc_data;
- +// struct regmap *regmap;
- +// unsigned int fifo_data_irq;
- +// atomic_t ignore_fifo_data_irq;
- +// unsigned int temp_data_irq;
- +// atomic_t ignore_temp_data_irq;
- +// const struct ths_data *data;
- +// bool no_irq;
- +// /* prevents concurrent reads of temperature and ADC */
- +// struct mutex mutex;
- +// struct sun8i_thermal_sensor sensors[3];
- +// struct device *sensor_device;
- +//};
- +
- +//#define SUN8I_GPADC_ADC_CHANNEL(_channel, _name) { \
- +// .type = IIO_VOLTAGE, \
- +// .indexed = 1, \
- +// .channel = _channel, \
- +// .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
- +// .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
- +// .datasheet_name = _name, \
- +//}
- +
- +//static struct iio_map sun8i_gpadc_hwmon_maps[] = {
- +// {
- +// .adc_channel_label = "temp_adc",
- +// .consumer_dev_name = "iio_hwmon.0",
- +// },
- +// { /* sentinel */ },
- +//};
- +
- +//static const struct iio_chan_spec sun8i_gpadc_channels[] = {
- +// SUN8I_GPADC_ADC_CHANNEL(0, "adc_chan0"),
- +// SUN8I_GPADC_ADC_CHANNEL(1, "adc_chan1"),
- +// SUN8I_GPADC_ADC_CHANNEL(2, "adc_chan2"),
- +// SUN8I_GPADC_ADC_CHANNEL(3, "adc_chan3"),
- +// {
- +// .type = IIO_TEMP,
- +// .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
- +// BIT(IIO_CHAN_INFO_SCALE) |
- +// BIT(IIO_CHAN_INFO_OFFSET),
- +// .datasheet_name = "temp_adc",
- +// },
- +//};
- +
- +//static const struct iio_chan_spec sun8i_gpadc_channels_no_temp[] = {
- +// SUN8I_GPADC_ADC_CHANNEL(0, "adc_chan0"),
- +// SUN8I_GPADC_ADC_CHANNEL(1, "adc_chan1"),
- +// SUN8I_GPADC_ADC_CHANNEL(2, "adc_chan2"),
- +// SUN8I_GPADC_ADC_CHANNEL(3, "adc_chan3"),
- +//};
- +
- +static const struct iio_chan_spec sun8i_a83t_ths_channels[] = {
- + {
- + .type = IIO_TEMP,
- + .channel = 0,
- + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
- + BIT(IIO_CHAN_INFO_SCALE) |
- + BIT(IIO_CHAN_INFO_OFFSET),
- + .datasheet_name = "temp_cluster0",
- + },
- + {
- + .type = IIO_TEMP,
- + .channel = 1,
- + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
- + BIT(IIO_CHAN_INFO_SCALE) |
- + BIT(IIO_CHAN_INFO_OFFSET),
- + .datasheet_name = "temp_cluster1",
- + },
- + {
- + .type = IIO_TEMP,
- + .channel = 2,
- + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
- + BIT(IIO_CHAN_INFO_SCALE) |
- + BIT(IIO_CHAN_INFO_OFFSET),
- + .datasheet_name = "temp_gpu",
- + },
- +};
- +
- +static const struct regmap_config sun8i_ths_regmap_config = {
- + .reg_bits = 32,
- + .val_bits = 32,
- + .reg_stride = 4,
- + .fast_io = true,
- +};
- +
- +//static int sun8i_prepare_for_irq(struct iio_dev *indio_dev, int channel,
- +// unsigned int irq)
- +//{
- +// struct sun8i_gpadc_iio *info = iio_priv(indio_dev);
- +// int ret;
- +// u32 reg;
- +//
- +// pm_runtime_get_sync(indio_dev->dev.parent);
- +//
- +// reinit_completion(&info->completion);
- +//
- +// ret = regmap_write(info->regmap, SUN8I_GPADC_INT_FIFOC,
- +// SUN8I_GPADC_INT_FIFOC_TP_FIFO_TRIG_LEVEL(1) |
- +// SUN8I_GPADC_INT_FIFOC_TP_FIFO_FLUSH);
- +// if (ret)
- +// return ret;
- +//
- +// ret = regmap_read(info->regmap, SUN8I_GPADC_CTRL1, ®);
- +// if (ret)
- +// return ret;
- +//
- +// if (irq == info->fifo_data_irq) {
- +// ret = regmap_write(info->regmap, SUN8I_GPADC_CTRL1,
- +// info->data->tp_mode_en |
- +// info->data->tp_adc_select |
- +// info->data->adc_chan_select(channel));
- +// /*
- +// * When the IP changes channel, it needs a bit of time to get
- +// * correct values.
- +// */
- +// if ((reg & info->data->adc_chan_mask) !=
- +// info->data->adc_chan_select(channel))
- +// mdelay(10);
- +//
- +// } else {
- +// /*
- +// * The temperature sensor returns valid data only when the ADC
- +// * operates in touchscreen mode.
- +// */
- +// ret = regmap_write(info->regmap, SUN8I_GPADC_CTRL1,
- +// info->data->tp_mode_en);
- +// }
- +//
- +// if (ret)
- +// return ret;
- +//
- +// /*
- +// * When the IP changes mode between ADC or touchscreen, it
- +// * needs a bit of time to get correct values.
- +// */
- +// if ((reg & info->data->tp_adc_select) != info->data->tp_adc_select)
- +// mdelay(100);
- +//
- +// return 0;
- +//}
- +
- +//static int sun8i_gpadc_read(struct iio_dev *indio_dev, int channel, int *val,
- +// unsigned int irq)
- +//{
- +// struct sun8i_gpadc_iio *info = iio_priv(indio_dev);
- +// int ret;
- +//
- +// mutex_lock(&info->mutex);
- +//
- +// ret = sun8i_prepare_for_irq(indio_dev, channel, irq);
- +// if (ret)
- +// goto err;
- +//
- +// enable_irq(irq);
- +//
- +// /*
- +// * The temperature sensor throws an interruption periodically (currently
- +// * set at periods of ~0.6s in sun8i_gpadc_runtime_resume). A 1s delay
- +// * makes sure an interruption occurs in normal conditions. If it doesn't
- +// * occur, then there is a timeout.
- +// */
- +// if (!wait_for_completion_timeout(&info->completion,
- +// msecs_to_jiffies(1000))) {
- +// ret = -ETIMEDOUT;
- +// goto err;
- +// }
- +//
- +// if (irq == info->fifo_data_irq)
- +// *val = info->adc_data;
- +// else
- +// *val = info->temp_data;
- +//
- +// ret = 0;
- +// pm_runtime_mark_last_busy(indio_dev->dev.parent);
- +//
- +//err:
- +// pm_runtime_put_autosuspend(indio_dev->dev.parent);
- +// disable_irq(irq);
- +// mutex_unlock(&info->mutex);
- +//
- +// return ret;
- +//}
- +
- +//static int sun8i_gpadc_adc_read(struct iio_dev *indio_dev, int channel,
- +// int *val)
- +//{
- +// struct sun8i_gpadc_iio *info = iio_priv(indio_dev);
- +//
- +// return sun8i_gpadc_read(indio_dev, channel, val, info->fifo_data_irq);
- +//}
- +
- +static int sun8i_ths_temp_read(struct sun8i_soc_thermal_dev *sensor_dev, int sensor, int *val)
- +{
- +// struct sun8i_ths_iio *info = iio_priv(indio_dev);
- + static const int reg[] = { SUN8I_THS_DATA0, SUN8I_THS_DATA1, SUN8I_THS_DATA2 };
- +
- +// if (sensor >= indio_dev->num_channels) {
- +// return -1;
- +// }
- +
- +// if (info->no_irq) {
- +
- + pm_runtime_get_sync(&(sensor_dev->pdev->dev));
- +
- + regmap_read(sensor_dev->regmap, reg[sensor], val);
- +
- + pm_runtime_mark_last_busy(&(sensor_dev->pdev->dev));
- + pm_runtime_put_autosuspend(&(sensor_dev->pdev->dev));
- +
- + return 0;
- +// }
- +
- + //return sun8i_gpadc_read(indio_dev, 0, val, info->temp_data_irq);
- +// return -1;
- +}
- +
- +static int sun8i_ths_temp_offset(struct sun8i_soc_thermal_sensor *sensor, int *val)
- +{
- +// struct sun8i_ths_iio *info = iio_priv(indio_dev);
- +
- + *val = sensor->ths_data->temp_offset;
- +
- + return 0;
- +}
- +
- +static int sun8i_ths_temp_scale(struct sun8i_soc_thermal_sensor *sensor, int *val)
- +{
- +// struct sun8i_ths_iio *info = iio_priv(indio_dev);
- +
- + *val = sensor->ths_data->temp_scale;
- +
- + return 0;
- +}
- +
- +//static int sun8i_ths_read_raw(struct iio_dev *indio_dev,
- +// struct iio_chan_spec const *chan, int *val,
- +// int *val2, long mask)
- +//{
- +// int ret;
- +//// struct sun8i_ths_iio *info = iio_priv(indio_dev);
- +// if (chan->channel > indio_dev->num_channels) {
- +// return -EINVAL;
- +// }
- +//
- +// switch (mask) {
- +// case IIO_CHAN_INFO_OFFSET:
- +// ret = sun8i_ths_temp_offset(indio_dev, val);
- +// if (ret)
- +// return ret;
- +//
- +// return IIO_VAL_INT;
- +// case IIO_CHAN_INFO_RAW:
- +// if (chan->type == IIO_VOLTAGE)
- +// ret = sun8i_gpadc_adc_read(indio_dev, chan->channel,
- +// val);
- +// else
- +// ret = sun8i_ths_temp_read(indio_dev, chan->channel, val);
- +//
- +// if (ret)
- +// return ret;
- +//
- +// return IIO_VAL_INT;
- +// case IIO_CHAN_INFO_SCALE:
- +// if (chan->type == IIO_VOLTAGE) {
- +// /* 3000mV / 4096 * raw */
- +// *val = 0;
- +// *val2 = 732421875;
- +// return IIO_VAL_INT_PLUS_NANO;
- +// }
- +//
- +// ret = sun8i_ths_temp_scale(indio_dev, val);
- +// if (ret)
- +// return ret;
- +//
- +// return IIO_VAL_INT;
- +// default:
- +// return -EINVAL;
- +// }
- +//
- +// return -EINVAL;
- +//}
- +
- +//static const struct iio_info sun8i_ths_iio_info = {
- +// .read_raw = sun8i_ths_read_raw,
- +//// .driver_module = THIS_MODULE,
- +//};
- +
- +//static irqreturn_t sun8i_gpadc_temp_data_irq_handler(int irq, void *dev_id)
- +//{
- +// struct sun8i_gpadc_iio *info = dev_id;
- +//
- +// if (atomic_read(&info->ignore_temp_data_irq))
- +// goto out;
- +//
- +// if (!regmap_read(info->regmap, SUN8I_GPADC_TEMP_DATA, &info->temp_data))
- +// complete(&info->completion);
- +//
- +//out:
- +// return IRQ_HANDLED;
- +//}
- +
- +//static irqreturn_t sun8i_gpadc_fifo_data_irq_handler(int irq, void *dev_id)
- +//{
- +// struct sun8i_gpadc_iio *info = dev_id;
- +//
- +// if (atomic_read(&info->ignore_fifo_data_irq))
- +// goto out;
- +//
- +// if (!regmap_read(info->regmap, SUN8I_GPADC_DATA, &info->adc_data))
- +// complete(&info->completion);
- +//
- +//out:
- +// return IRQ_HANDLED;
- +//}
- +
- +static int sun8i_ths_runtime_suspend(struct device *dev)
- +{
- +// struct sun8i_ths_iio *info = iio_priv(dev_get_drvdata(dev));
- + struct sun8i_soc_thermal_dev *sensor_dev = (struct sun8i_soc_thermal_dev *)dev_get_drvdata(dev);
- +
- + /* Disable temperature sensors */
- + regmap_write(sensor_dev->regmap, SUN8I_THS_CTRL2, 0);
- +
- + return 0;
- +}
- +
- +static int sun8i_ths_runtime_resume(struct device *dev)
- +{
- +// struct sun8i_ths_iio *info = iio_priv(dev_get_drvdata(dev));
- + struct sun8i_soc_thermal_dev *sensor_dev = (struct sun8i_soc_thermal_dev *)dev_get_drvdata(dev);
- +#ifdef SUN8IW6_SID_CALIBRATION
- + int reg_value = 0;
- +#endif
- +
- + regmap_write(sensor_dev->regmap, SUN8I_THS_CTRL1, SUN8I_THS_CTRL1_ADC_CALI_EN);
- +
- +#ifdef SUN8IW6_SID_CALIBRATION
- + reg_value = readl(SID_THERMAL_CDATA1_SRAM);
- + if (0 != reg_value)
- + writel(reg_value, thermal_data->base_addr + THS_0_1_CDATA_REG);
- + reg_value = readl(SID_THERMAL_CDATA2_SRAM);
- + if (0 != reg_value)
- + writel(reg_value, thermal_data->base_addr + THS_2_CDATA_REG);
- +#endif
- +
- + regmap_write(sensor_dev->regmap, SUN8I_THS_CTRL0, SUN8I_THS_CTRL0_ACQ0_VALUE);
- + regmap_write(sensor_dev->regmap, SUN8I_THS_CTRL2,
- + SUN8I_THS_CTRL2_ACQ1_VALUE | SUN8I_THS_CTRL2_SENSE2_EN |
- + SUN8I_THS_CTRL2_SENSE1_EN | SUN8I_THS_CTRL2_SENSE0_EN);
- + regmap_write(sensor_dev->regmap, SUN8I_THS_INT_CTRL,
- + SUN8I_THS_INT_CTRL_THERMAL_PER_VALUE | SUN8I_THS_INT_CTRL_SHUT_INT2_EN |
- + SUN8I_THS_INT_CTRL_SHUT_INT1_EN | SUN8I_THS_INT_CTRL_SHUT_INT1_EN);
- + regmap_write(sensor_dev->regmap, SUN8I_THS_INT_STA, SUN8I_THS_INT_CTRL_RESET_ALL);
- + regmap_write(sensor_dev->regmap, SUN8I_THS_FILT_CTRL,
- + SUN8I_THS_FILT_CTRL_FILTER_EN | SUN8I_THS_FILT_CTRL_FILTER_TYPE_4);
- +
- +// reg_value = temperature_to_reg(ths_zone_2.sunxi_ths_sensor_conf->trip_data->trip_val[0], 14186, 2794);
- +// reg_value = (reg_value<<16);
- +//
- +// writel(reg_value, thermal_data->base_addr + THS_INT_SHUT_TH_REG0);
- +// writel(reg_value, thermal_data->base_addr + THS_INT_SHUT_TH_REG1);
- +// writel(reg_value, thermal_data->base_addr + THS_INT_SHUT_TH_REG2);
- +
- + return 0;
- +}
- +
- +static int sun8i_ths_get_temp(void *data, int *temp)
- +{
- + struct sun8i_soc_thermal_sensor *sensor = (struct sun8i_soc_thermal_sensor *)data;
- + //struct iio_dev *iio_dev = sensor->indio_dev;
- + //struct sun8i_ths_iio *info = iio_priv(iio_dev);
- + struct sun8i_soc_thermal_dev *sensor_dev = sensor->device;
- + int val, scale, offset, i;
- +
- + for (i = 0; i < 3; i++) {
- + if (&(sensor_dev->sensors[i]) == sensor) {
- + break;
- + }
- + }
- +
- + if (i == 3) {
- + return -1;
- + }
- +
- + if (sun8i_ths_temp_read(sensor_dev, i, &val))
- + return -ETIMEDOUT;
- +
- + sun8i_ths_temp_scale(sensor, &scale);
- + sun8i_ths_temp_offset(sensor, &offset);
- +
- + *temp = (val + offset) * scale;
- + pr_debug("sun8i_ths_get_temp: %d = (%d + %d) * %d\n", *temp, val, offset, scale);
- +
- + return 0;
- +}
- +
- +static const struct thermal_zone_of_device_ops sun8i_ts_tz_ops = {
- + .get_temp = &sun8i_ths_get_temp,
- +};
- +
- +static const struct dev_pm_ops sun8i_ths_pm_ops = {
- + .runtime_suspend = &sun8i_ths_runtime_suspend,
- + .runtime_resume = &sun8i_ths_runtime_resume,
- +};
- +
- +//static int sun8i_irq_init(struct platform_device *pdev, const char *name,
- +// irq_handler_t handler, const char *devname,
- +// unsigned int *irq, atomic_t *atomic)
- +//{
- +// int ret;
- +// struct sun8i_gpadc_dev *mfd_dev = dev_get_drvdata(pdev->dev.parent);
- +// struct sun8i_gpadc_iio *info = iio_priv(dev_get_drvdata(&pdev->dev));
- +//
- +// /*
- +// * Once the interrupt is activated, the IP continuously performs
- +// * conversions thus throws interrupts. The interrupt is activated right
- +// * after being requested but we want to control when these interrupts
- +// * occur thus we disable it right after being requested. However, an
- +// * interrupt might occur between these two instructions and we have to
- +// * make sure that does not happen, by using atomic flags. We set the
- +// * flag before requesting the interrupt and unset it right after
- +// * disabling the interrupt. When an interrupt occurs between these two
- +// * instructions, reading the atomic flag will tell us to ignore the
- +// * interrupt.
- +// */
- +// atomic_set(atomic, 1);
- +//
- +// ret = platform_get_irq_byname(pdev, name);
- +// if (ret < 0) {
- +// dev_err(&pdev->dev, "no %s interrupt registered\n", name);
- +// return ret;
- +// }
- +//
- +// ret = regmap_irq_get_virq(mfd_dev->regmap_irqc, ret);
- +// if (ret < 0) {
- +// dev_err(&pdev->dev, "failed to get virq for irq %s\n", name);
- +// return ret;
- +// }
- +//
- +// *irq = ret;
- +// ret = devm_request_any_context_irq(&pdev->dev, *irq, handler, 0,
- +// devname, info);
- +// if (ret < 0) {
- +// dev_err(&pdev->dev, "could not request %s interrupt: %d\n",
- +// name, ret);
- +// return ret;
- +// }
- +//
- +// disable_irq(*irq);
- +// atomic_set(atomic, 0);
- +//
- +// return 0;
- +//}
- +
- +static const struct of_device_id sun8i_ths_of_id[] = {
- + {
- + .compatible = "allwinner,sun8i-a83t-ths",
- + .data = &sun8i_a83t_ths_data,
- + },
- + { /* sentinel */ }
- +};
- +
- +//static int sun8i_ths_probe_dt(struct platform_device *pdev,
- +// struct iio_dev *indio_dev)
- +//{
- +// struct sun8i_ths_iio *info = iio_priv(indio_dev);
- +// const struct of_device_id *of_dev;
- +// struct resource *mem;
- +// void __iomem *base;
- +// int ret, i;
- +//
- +// of_dev = of_match_device(sun8i_ths_of_id, &pdev->dev);
- +// if (!of_dev)
- +// return -ENODEV;
- +//
- +// info->no_irq = true;
- +// info->data = (struct ths_data *)of_dev->data;
- +// indio_dev->num_channels = ARRAY_SIZE(sun8i_a83t_ths_channels);
- +// indio_dev->channels = sun8i_a83t_ths_channels;
- +//
- +// mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- +// base = devm_ioremap_resource(&pdev->dev, mem);
- +// if (IS_ERR(base))
- +// return PTR_ERR(base);
- +//
- +// info->regmap = devm_regmap_init_mmio(&pdev->dev, base,
- +// &sun8i_ths_regmap_config);
- +// if (IS_ERR(info->regmap)) {
- +// ret = PTR_ERR(info->regmap);
- +// dev_err(&pdev->dev, "failed to init regmap: %d\n", ret);
- +// return ret;
- +// }
- +//
- +// if (!IS_ENABLED(CONFIG_THERMAL_OF))
- +// return 0;
- +//
- +// info->sensor_device = &pdev->dev;
- +// for (i = 0; i < indio_dev->num_channels; i++) {
- +// info->sensors[i].indio_dev = indio_dev;
- +// info->sensors[i].cell = i;
- +// info->sensors[i].tzd = thermal_zone_of_sensor_register(info->sensor_device, i,
- +// &(info->sensors[i]), &sun8i_ts_tz_ops);
- +// if (IS_ERR(info->sensors[i].tzd)) {
- +// dev_err(&pdev->dev, "could not register thermal sensor: %ld\n",
- +// PTR_ERR(info->sensors[i].tzd));
- +// return PTR_ERR_OR_ZERO(info->sensors[i].tzd);
- +// }
- +// }
- +//
- +// return 0;
- +//}
- +
- +//static int sun8i_gpadc_probe_mfd(struct platform_device *pdev,
- +// struct iio_dev *indio_dev)
- +//{
- +// struct sun8i_gpadc_iio *info = iio_priv(indio_dev);
- +// struct sun8i_gpadc_dev *sun8i_gpadc_dev =
- +// dev_get_drvdata(pdev->dev.parent);
- +// int ret;
- +//
- +// info->no_irq = false;
- +// info->regmap = sun8i_gpadc_dev->regmap;
- +//
- +// indio_dev->num_channels = ARRAY_SIZE(sun8i_gpadc_channels);
- +// indio_dev->channels = sun8i_gpadc_channels;
- +//
- +// info->data = (struct gpadc_data *)platform_get_device_id(pdev)->driver_data;
- +//
- +// /*
- +// * Since the controller needs to be in touchscreen mode for its thermal
- +// * sensor to operate properly, and that switching between the two modes
- +// * needs a delay, always registering in the thermal framework will
- +// * significantly slow down the conversion rate of the ADCs.
- +// *
- +// * Therefore, instead of depending on THERMAL_OF in Kconfig, we only
- +// * register the sensor if that option is enabled, eventually leaving
- +// * that choice to the user.
- +// */
- +//
- +// if (IS_ENABLED(CONFIG_THERMAL_OF)) {
- +// /*
- +// * This driver is a child of an MFD which has a node in the DT
- +// * but not its children, because of DT backward compatibility
- +// * for A10, A13 and A31 SoCs. Therefore, the resulting devices
- +// * of this driver do not have an of_node variable.
- +// * However, its parent (the MFD driver) has an of_node variable
- +// * and since devm_thermal_zone_of_sensor_register uses its first
- +// * argument to match the phandle defined in the node of the
- +// * thermal driver with the of_node of the device passed as first
- +// * argument and the third argument to call ops from
- +// * thermal_zone_of_device_ops, the solution is to use the parent
- +// * device as first argument to match the phandle with its
- +// * of_node, and the device from this driver as third argument to
- +// * return the temperature.
- +// */
- +// info->sensor_device = pdev->dev.parent;
- +// info->tzd = thermal_zone_of_sensor_register(info->sensor_device,
- +// 0, info,
- +// &sun8i_ts_tz_ops);
- +// if (IS_ERR(info->tzd)) {
- +// dev_err(&pdev->dev,
- +// "could not register thermal sensor: %ld\n",
- +// PTR_ERR(info->tzd));
- +// return PTR_ERR(info->tzd);
- +// }
- +// } else {
- +// indio_dev->num_channels =
- +// ARRAY_SIZE(sun8i_gpadc_channels_no_temp);
- +// indio_dev->channels = sun8i_gpadc_channels_no_temp;
- +// }
- +//
- +// if (IS_ENABLED(CONFIG_THERMAL_OF)) {
- +// ret = sun8i_irq_init(pdev, "TEMP_DATA_PENDING",
- +// sun8i_gpadc_temp_data_irq_handler,
- +// "temp_data", &info->temp_data_irq,
- +// &info->ignore_temp_data_irq);
- +// if (ret < 0)
- +// return ret;
- +// }
- +//
- +// ret = sun8i_irq_init(pdev, "FIFO_DATA_PENDING",
- +// sun8i_gpadc_fifo_data_irq_handler, "fifo_data",
- +// &info->fifo_data_irq, &info->ignore_fifo_data_irq);
- +// if (ret < 0)
- +// return ret;
- +//
- +// if (IS_ENABLED(CONFIG_THERMAL_OF)) {
- +// ret = iio_map_array_register(indio_dev, sun8i_gpadc_hwmon_maps);
- +// if (ret < 0) {
- +// dev_err(&pdev->dev,
- +// "failed to register iio map array\n");
- +// return ret;
- +// }
- +// }
- +//
- +// return 0;
- +//}
- +
- +static int sun8i_ths_probe(struct platform_device *pdev)
- +{
- + //struct sun8i_ths_iio *info;
- + //struct iio_dev *indio_dev;
- + struct sun8i_soc_thermal_dev *sensor_dev;
- + int ret, i;
- + struct resource *mem;
- + void __iomem *base;
- + const struct of_device_id *of_dev;
- +
- + pr_err("sun8i_ths_probe ++\n");
- + of_dev = of_match_device(sun8i_ths_of_id, &pdev->dev);
- + if (!of_dev) {
- + dev_err(&pdev->dev, "cannot find a matching device in device tree\n");
- + return -ENODEV;
- + }
- +
- + sensor_dev = (struct sun8i_soc_thermal_dev *) devm_kzalloc(&(pdev->dev), sizeof(struct sun8i_soc_thermal_dev), GFP_KERNEL);
- + if (!sensor_dev) {
- + dev_err(&pdev->dev, "cannot allocate memory\n");
- + ret = -ENOMEM;
- + goto alloc_fail;
- + }
- +
- + platform_set_drvdata(pdev, sensor_dev);
- + sensor_dev->pdev = pdev;
- +
- + //mutex_init(&info->mutex);
- + //info->indio_dev = indio_dev;
- + //init_completion(&info->completion);
- + //indio_dev->name = dev_name(&pdev->dev);
- + //indio_dev->dev.parent = &pdev->dev;
- + //indio_dev->dev.of_node = pdev->dev.of_node;
- + //indio_dev->info = &sun8i_ths_iio_info;
- + //indio_dev->modes = INDIO_DIRECT_MODE;
- +
- +// if (pdev->dev.of_node)
- +// ret = sun8i_ths_probe_dt(pdev, indio_dev);
- +// else
- +// ret = sun8i_gpadc_probe_mfd(pdev, indio_dev);
- +// ret = -1;
- +//
- +// if (ret) {
- +// pr_err("sun8i_ths_probe failed 2 --\n");
- +// return ret;
- +// }
- +
- + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- + base = devm_ioremap_resource(&pdev->dev, mem);
- + if (IS_ERR(base)) {
- + dev_err(&pdev->dev, "failed to allocate io map\n");
- + ret = PTR_ERR(base);
- + goto resource_fail;
- + }
- +
- + sensor_dev->regmap = devm_regmap_init_mmio(&pdev->dev, base,
- + &sun8i_ths_regmap_config);
- + if (IS_ERR(sensor_dev->regmap)) {
- + ret = PTR_ERR(sensor_dev->regmap);
- + dev_err(&pdev->dev, "failed to init io map: %d\n", ret);
- + goto regmap_init_fail;
- + }
- +
- + //if (!IS_ENABLED(CONFIG_THERMAL_OF))
- + // return 0;
- +
- + for (i = 0; i < 3; i++) {
- + sensor_dev->sensors[i].device = sensor_dev;
- + sensor_dev->sensors[i].ths_data = of_dev->data;
- + sensor_dev->sensors[i].tzd = thermal_zone_of_sensor_register(&pdev->dev, i,
- + &(sensor_dev->sensors[i]), &sun8i_ts_tz_ops);
- + if (IS_ERR(sensor_dev->sensors[i].tzd)) {
- + dev_err(&pdev->dev, "could not register thermal sensor: %ld\n",
- + PTR_ERR(sensor_dev->sensors[i].tzd));
- + ret = PTR_ERR_OR_ZERO(sensor_dev->sensors[i].tzd);
- + sensor_dev->sensors[i].tzd = NULL;
- + goto tzd_fail;
- + }
- + }
- +
- + pm_runtime_set_autosuspend_delay(&pdev->dev,
- + SUN8I_THS_AUTOSUSPEND_DELAY);
- + pm_runtime_use_autosuspend(&pdev->dev);
- + pm_runtime_set_suspended(&pdev->dev);
- + pm_runtime_enable(&pdev->dev);
- +
- + //ret = devm_iio_device_register(&pdev->dev, indio_dev);
- + //if (ret < 0) {
- + // pr_err("sun8i_ths_probe failed 3 --\n");
- + // goto err_map;
- + //}
- + pr_err("sun8i_ths_probe succeded");
- + return 0;
- +
- +tzd_fail:
- + for (i = 0; i < 3; i++) {
- + if (sensor_dev->sensors[i].tzd)
- + thermal_zone_of_sensor_unregister(&pdev->dev, sensor_dev->sensors[i].tzd);
- + }
- +regmap_init_fail:
- +resource_fail:
- + devm_kfree(&(pdev->dev), sensor_dev);
- +alloc_fail:
- + pr_err("sun8i_ths_probe failed: %d --\n", ret);
- + return ret;
- +
- +//err_map:
- +// if (!info->no_irq && IS_ENABLED(CONFIG_THERMAL_OF))
- +// iio_map_array_unregister(indio_dev);
- +//
- +// pm_runtime_put(&pdev->dev);
- +// pm_runtime_disable(&pdev->dev);
- +//
- +// return ret;
- +}
- +
- +static int sun8i_ths_remove(struct platform_device *pdev)
- +{
- + struct sun8i_soc_thermal_dev *sensor_dev = platform_get_drvdata(pdev);
- +// struct sun8i_ths_iio *info = iio_priv(indio_dev);
- + int i;
- +
- + pm_runtime_put(&pdev->dev);
- + pm_runtime_disable(&pdev->dev);
- +
- +// if (!IS_ENABLED(CONFIG_THERMAL_OF))
- +// return 0;
- +
- + for (i = 0; i < 3; i++) {
- + thermal_zone_of_sensor_unregister(&pdev->dev, sensor_dev->sensors[i].tzd);
- + }
- +
- + devm_kfree(&(pdev->dev), sensor_dev);
- +// if (!info->no_irq)
- +// iio_map_array_unregister(indio_dev);
- +
- + return 0;
- +}
- +
- +static struct platform_driver sun8i_ths_driver = {
- + .driver = {
- + .name = "sun8i-soc-ths",
- + .of_match_table = sun8i_ths_of_id,
- + .pm = &sun8i_ths_pm_ops,
- + },
- + .probe = sun8i_ths_probe,
- + .remove = sun8i_ths_remove,
- +};
- +MODULE_DEVICE_TABLE(of, sun8i_ths_of_id);
- +
- +module_platform_driver(sun8i_ths_driver);
- +
- +MODULE_DESCRIPTION("Thermal sensor controller driver for sunxi platforms");
- +MODULE_AUTHOR("Dmitry Smirnov <divis1969@gmail.com>");
- +MODULE_LICENSE("GPL v2");
- diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
- index 2b1b0ba39..9f88645d0 100644
- --- a/drivers/thermal/thermal_core.c
- +++ b/drivers/thermal/thermal_core.c
- @@ -1186,20 +1186,30 @@ thermal_zone_device_register(const char *type, int trips, int mask,
- int count;
- struct thermal_governor *governor;
- - if (!type || strlen(type) == 0)
- + if (!type || strlen(type) == 0) {
- + pr_err("thermal_zone_device_register EINVAL type\n");
- return ERR_PTR(-EINVAL);
- + }
- - if (type && strlen(type) >= THERMAL_NAME_LENGTH)
- + if (type && strlen(type) >= THERMAL_NAME_LENGTH) {
- + pr_err("thermal_zone_device_register EINVAL type2\n");
- return ERR_PTR(-EINVAL);
- + }
- - if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips)
- + if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips) {
- + pr_err("thermal_zone_device_register EINVAL trips\n");
- return ERR_PTR(-EINVAL);
- + }
- - if (!ops)
- + if (!ops) {
- + pr_err("thermal_zone_device_register EINVAL ops\n");
- return ERR_PTR(-EINVAL);
- + }
- - if (trips > 0 && (!ops->get_trip_type || !ops->get_trip_temp))
- + if (trips > 0 && (!ops->get_trip_type || !ops->get_trip_temp)) {
- + pr_err("thermal_zone_device_register EINVAL trips&ops\n");
- return ERR_PTR(-EINVAL);
- + }
- tz = kzalloc(sizeof(*tz), GFP_KERNEL);
- if (!tz)
- diff --git a/include/linux/soc/sunxi/sun8i-soc-thermal.h b/include/linux/soc/sunxi/sun8i-soc-thermal.h
- new file mode 100644
- index 000000000..91ceed01f
- --- /dev/null
- +++ b/include/linux/soc/sunxi/sun8i-soc-thermal.h
- @@ -0,0 +1,158 @@
- +/* Header of thermal sensor controller core driver for sunxi platforms
- + *
- + * Copyright (c) 2017 Dmitry Smirnov <divis1969@gmail.com>
- + *
- + * This program is free software; you can redistribute it and/or modify it under
- + * the terms of the GNU General Public License version 2 as published by the
- + * Free Software Foundation.
- + */
- +
- +#ifndef __SUN8I_THS__H__
- +#define __SUN8I_THS__H__
- +
- +#define SUN8I_THS_CTRL0 0x00
- +#define SUN8I_THS_CTRL0_ACQ0_VALUE 0x17 // default value
- +
- +#define SUN8I_THS_CTRL1 0x04
- +#define SUN8I_THS_CTRL1_ADC_CALI_EN BIT(17)
- +
- +//#define SUN8I_THS_CTRL1_STYLUS_UP_DEBOUNCE(x) ((GENMASK(7, 0) & (x)) << 12)
- +//#define SUN8I_THS_CTRL1_STYLUS_UP_DEBOUNCE_EN BIT(9)
- +//#define SUN8I_THS_CTRL1_TOUCH_PAN_CALI_EN BIT(6)
- +//#define SUN8I_THS_CTRL1_TP_DUAL_EN BIT(5)
- +//#define SUN8I_THS_CTRL1_TP_MODE_EN BIT(4)
- +//#define SUN8I_THS_CTRL1_TP_ADC_SELECT BIT(3)
- +//#define SUN8I_THS_CTRL1_ADC_CHAN_SELECT(x) (GENMASK(2, 0) & (x))
- +//#define SUN8I_THS_CTRL1_ADC_CHAN_MASK GENMASK(2, 0)
- +//
- +///* TP_CTRL1 bits for sun6i SOCs */
- +//#define SUN6I_THS_CTRL1_TOUCH_PAN_CALI_EN BIT(7)
- +//#define SUN6I_THS_CTRL1_TP_DUAL_EN BIT(6)
- +//#define SUN6I_THS_CTRL1_TP_MODE_EN BIT(5)
- +//#define SUN6I_THS_CTRL1_TP_ADC_SELECT BIT(4)
- +//#define SUN6I_THS_CTRL1_ADC_CHAN_SELECT(x) (GENMASK(3, 0) & BIT(x))
- +//#define SUN6I_THS_CTRL1_ADC_CHAN_MASK GENMASK(3, 0)
- +//
- +///* TP_CTRL1 bits for sun8i SoCs */
- +//#define SUN8I_THS_CTRL1_CHOP_TEMP_EN BIT(8)
- +//#define SUN8I_THS_CTRL1_THS_CALI_EN BIT(7)
- +//
- +//#define SUN8I_THS_CTRL2 0x08
- +//
- +//#define SUN8I_THS_CTRL2_TP_SENSITIVE_ADJUST(x) ((GENMASK(3, 0) & (x)) << 28)
- +//#define SUN8I_THS_CTRL2_TP_MODE_SELECT(x) ((GENMASK(1, 0) & (x)) << 26)
- +//#define SUN8I_THS_CTRL2_PRE_MEA_EN BIT(24)
- +//#define SUN8I_THS_CTRL2_PRE_MEA_THRE_CNT(x) (GENMASK(23, 0) & (x))
- +//
- +//#define SUN8I_THS_CTRL3 0x0c
- +//
- +//#define SUN8I_THS_CTRL3_FILTER_EN BIT(2)
- +//#define SUN8I_THS_CTRL3_FILTER_TYPE(x) (GENMASK(1, 0) & (x))
- +
- +#define SUN8I_THS_ADC_CDAT 0x14
- +
- +#define SUN8I_THS_CTRL2 0x40
- +#define SUN8I_THS_CTRL2_ACQ1_VALUE (0x17 << 16) /* default value */
- +#define SUN8I_THS_CTRL2_SENSE2_EN BIT(2)
- +#define SUN8I_THS_CTRL2_SENSE1_EN BIT(1)
- +#define SUN8I_THS_CTRL2_SENSE0_EN BIT(0)
- +
- +#define SUN8I_THS_INT_CTRL 0x44
- +#define SUN8I_THS_INT_CTRL_THERMAL_PER_VALUE (1 << 12) /* default value */
- +#define SUN8I_THS_INT_CTRL_THS2_DATA_IRQ_EN BIT(10)
- +#define SUN8I_THS_INT_CTRL_THS1_DATA_IRQ_EN BIT(9)
- +#define SUN8I_THS_INT_CTRL_THS0_DATA_IRQ_EN BIT(8)
- +#define SUN8I_THS_INT_CTRL_SHUT_INT2_EN BIT(6)
- +#define SUN8I_THS_INT_CTRL_SHUT_INT1_EN BIT(5)
- +#define SUN8I_THS_INT_CTRL_SHUT_INT0_EN BIT(4)
- +#define SUN8I_THS_INT_CTRL_ALARM_INT2_EN BIT(2)
- +#define SUN8I_THS_INT_CTRL_ALARM_INT1_EN BIT(1)
- +#define SUN8I_THS_INT_CTRL_ALARM_INT0_EN BIT(0)
- +
- +#define SUN8I_THS_INT_STA 0x48
- +#define SUN8I_THS_INT_CTRL_THS2_DATA_IRQ_STS BIT(10)
- +#define SUN8I_THS_INT_CTRL_THS1_DATA_IRQ_STS BIT(9)
- +#define SUN8I_THS_INT_CTRL_THS0_DATA_IRQ_STS BIT(8)
- +#define SUN8I_THS_INT_CTRL_SHUT_INT2_STS BIT(6)
- +#define SUN8I_THS_INT_CTRL_SHUT_INT1_STS BIT(5)
- +#define SUN8I_THS_INT_CTRL_SHUT_INT0_STS BIT(4)
- +#define SUN8I_THS_INT_CTRL_ALARM_INT2_STS BIT(2)
- +#define SUN8I_THS_INT_CTRL_ALARM_INT1_STS BIT(1)
- +#define SUN8I_THS_INT_CTRL_ALARM_INT0_STS BIT(0)
- +#define SUN8I_THS_INT_CTRL_RESET_ALL ( \
- + SUN8I_THS_INT_CTRL_THS2_DATA_IRQ_STS | \
- + SUN8I_THS_INT_CTRL_THS1_DATA_IRQ_STS | \
- + SUN8I_THS_INT_CTRL_THS0_DATA_IRQ_STS | \
- + SUN8I_THS_INT_CTRL_SHUT_INT2_STS | \
- + SUN8I_THS_INT_CTRL_SHUT_INT1_STS | \
- + SUN8I_THS_INT_CTRL_SHUT_INT0_STS | \
- + SUN8I_THS_INT_CTRL_ALARM_INT2_STS | \
- + SUN8I_THS_INT_CTRL_ALARM_INT1_STS | \
- + SUN8I_THS_INT_CTRL_ALARM_INT0_STS \
- + )
- +
- +#define SUN8I_THS_INT_ALM_TH0 0x50
- +#define SUN8I_THS_INT_ALM_TH1 0x54
- +#define SUN8I_THS_INT_ALM_TH2 0x58
- +#define SUN8I_THS_INT_SHUT_TH0 0x60
- +#define SUN8I_THS_INT_SHUT_TH1 0x64
- +#define SUN8I_THS_INT_SHUT_TH2 0x68
- +
- +#define SUN8I_THS_FILT_CTRL 0x70
- +#define SUN8I_THS_FILT_CTRL_FILTER_EN BIT(2)
- +#define SUN8I_THS_FILT_CTRL_FILTER_TYPE_2 0
- +#define SUN8I_THS_FILT_CTRL_FILTER_TYPE_4 1
- +#define SUN8I_THS_FILT_CTRL_FILTER_TYPE_8 2
- +#define SUN8I_THS_FILT_CTRL_FILTER_TYPE_16 3
- +
- +
- +#define SUN8I_THS_0_1_CDATA 0x74
- +#define SUN8I_THS_2_CDATA 0x78
- +#define SUN8I_THS_DATA0 0x80
- +#define SUN8I_THS_DATA1 0x84
- +#define SUN8I_THS_DATA2 0x88
- +
- +//#define SUN8I_THS_TPR 0x18
- +//
- +//#define SUN8I_THS_TPR_TEMP_ENABLE BIT(16)
- +//#define SUN8I_THS_TPR_TEMP_PERIOD(x) (GENMASK(15, 0) & (x))
- +//
- +//#define SUN8I_THS_INT_FIFOC 0x10
- +//
- +//#define SUN8I_THS_INT_FIFOC_TEMP_IRQ_EN BIT(18)
- +//#define SUN8I_THS_INT_FIFOC_TP_OVERRUN_IRQ_EN BIT(17)
- +//#define SUN8I_THS_INT_FIFOC_TP_DATA_IRQ_EN BIT(16)
- +//#define SUN8I_THS_INT_FIFOC_TP_DATA_XY_CHANGE BIT(13)
- +//#define SUN8I_THS_INT_FIFOC_TP_FIFO_TRIG_LEVEL(x) ((GENMASK(4, 0) & (x)) << 8)
- +//#define SUN8I_THS_INT_FIFOC_TP_DATA_DRQ_EN BIT(7)
- +//#define SUN8I_THS_INT_FIFOC_TP_FIFO_FLUSH BIT(4)
- +//#define SUN8I_THS_INT_FIFOC_TP_UP_IRQ_EN BIT(1)
- +//#define SUN8I_THS_INT_FIFOC_TP_DOWN_IRQ_EN BIT(0)
- +//
- +//#define SUN8I_THS_INT_FIFOS 0x14
- +//
- +//#define SUN8I_THS_INT_FIFOS_TEMP_DATA_PENDING BIT(18)
- +//#define SUN8I_THS_INT_FIFOS_FIFO_OVERRUN_PENDING BIT(17)
- +//#define SUN8I_THS_INT_FIFOS_FIFO_DATA_PENDING BIT(16)
- +//#define SUN8I_THS_INT_FIFOS_TP_IDLE_FLG BIT(2)
- +//#define SUN8I_THS_INT_FIFOS_TP_UP_PENDING BIT(1)
- +//#define SUN8I_THS_INT_FIFOS_TP_DOWN_PENDING BIT(0)
- +//
- +//#define SUN8I_THS_CDAT 0x1c
- +//#define SUN8I_THS_TEMP_DATA 0x20
- +//#define SUN8I_THS_DATA 0x24
- +//
- +//#define SUN8I_THS_IRQ_FIFO_DATA 0
- +//#define SUN8I_THS_IRQ_TEMP_DATA 1
- +
- +/* 10s delay before suspending the IP */
- +#define SUN8I_THS_AUTOSUSPEND_DELAY 10000
- +
- +struct sun8i_gpadc_dev {
- + struct device *dev;
- + struct regmap *regmap;
- + struct regmap_irq_chip_data *regmap_irqc;
- + void __iomem *base;
- +};
- +
- +#endif
- diff --git a/kernel/cpu.c b/kernel/cpu.c
- index 41376c3ac..006544d88 100644
- --- a/kernel/cpu.c
- +++ b/kernel/cpu.c
- @@ -170,6 +170,7 @@ static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state state,
- if (!(bringup ? step->startup.single : step->teardown.single))
- return 0;
- + pr_err("cpuhp_invoke_callback %d: state == fail\n", cpu);
- return -EAGAIN;
- }
- @@ -181,6 +182,7 @@ static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state state,
- trace_cpuhp_enter(cpu, st->target, state, cb);
- ret = cb(cpu);
- trace_cpuhp_exit(cpu, st->state, state, ret);
- + pr_err("cpuhp_invoke_callback %d: single (target %d, state %d) %d\n", cpu, st->target, state, ret);
- return ret;
- }
- cbm = bringup ? step->startup.multi : step->teardown.multi;
- @@ -193,6 +195,7 @@ static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state state,
- trace_cpuhp_multi_enter(cpu, st->target, state, cbm, node);
- ret = cbm(cpu, node);
- trace_cpuhp_exit(cpu, st->state, state, ret);
- + pr_err("cpuhp_invoke_callback %d: multi %d\n", cpu, ret);
- return ret;
- }
- @@ -206,6 +209,7 @@ static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state state,
- ret = cbm(cpu, node);
- trace_cpuhp_exit(cpu, st->state, state, ret);
- if (ret) {
- + pr_err("cpuhp_invoke_callback %d: multi %d\n", cpu, ret);
- if (!lastp)
- goto err;
- @@ -990,6 +994,7 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen, enum cpuhp_state target)
- cpus_write_lock();
- if (!cpu_present(cpu)) {
- + pr_err("_cpu_up %d: !cpu_present\n", cpu);
- ret = -EINVAL;
- goto out;
- }
- @@ -998,14 +1003,17 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen, enum cpuhp_state target)
- * The caller of do_cpu_up might have raced with another
- * caller. Ignore it for now.
- */
- - if (st->state >= target)
- + if (st->state >= target) {
- + pr_err("_cpu_up %d: race? %d <> %d\n", cpu, st->state, target);
- goto out;
- + }
- if (st->state == CPUHP_OFFLINE) {
- /* Let it fail before we try to bring the cpu up */
- idle = idle_thread_get(cpu);
- if (IS_ERR(idle)) {
- ret = PTR_ERR(idle);
- + pr_err("_cpu_up %d: idle_thread_get %d\n", cpu, ret);
- goto out;
- }
- }
- @@ -1023,8 +1031,10 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen, enum cpuhp_state target)
- * The AP side has done the error rollback already. Just
- * return the error code..
- */
- - if (ret)
- + if (ret) {
- + pr_err("_cpu_up %d: cpuhp_kick_ap_work %d\n", cpu, ret);
- goto out;
- + }
- }
- /*
- @@ -1034,6 +1044,7 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen, enum cpuhp_state target)
- */
- target = min((int)target, CPUHP_BRINGUP_CPU);
- ret = cpuhp_up_callbacks(cpu, st, target);
- + pr_err("_cpu_up %d: cpuhp_up_callbacks %d\n", cpu, ret);
- out:
- cpus_write_unlock();
- return ret;
- @@ -1053,17 +1064,21 @@ static int do_cpu_up(unsigned int cpu, enum cpuhp_state target)
- }
- err = try_online_node(cpu_to_node(cpu));
- - if (err)
- + if (err) {
- + pr_err("do_cpu_up %d: try_online_node %d\n", cpu, err);
- return err;
- + }
- cpu_maps_update_begin();
- if (cpu_hotplug_disabled) {
- + pr_err("do_cpu_up %d: cpu_hotplug_disabled %d\n", cpu, cpu_hotplug_disabled);
- err = -EBUSY;
- goto out;
- }
- err = _cpu_up(cpu, 0, target);
- + pr_err("do_cpu_up %d: _cpu_up %d\n", cpu, err);
- out:
- cpu_maps_update_done();
- return err;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement