diff mbox

[06/16] iio: adc: sun4i-gpadc-iio: rework: support multible sensors

Message ID 20180126151941.12183-7-embed3d@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Philipp Rossak Jan. 26, 2018, 3:19 p.m. UTC
For adding newer sensor some basic rework of the code is necessary.

This patch reworks the driver to be able to handle more than one
thermal sensor. Newer SoC like the A80 have 4 thermal sensors.
Because of this the maximal sensor count value was set to 4.

The sensor_id value is set during sensor registration and is for each
registered sensor indiviual. This makes it able to differntiate the
sensors when the value is read from the register.

Signed-off-by: Philipp Rossak <embed3d@gmail.com>
---
 drivers/iio/adc/sun4i-gpadc-iio.c | 36 +++++++++++++++++++++++-------------
 include/linux/mfd/sun4i-gpadc.h   |  6 ++++++
 2 files changed, 29 insertions(+), 13 deletions(-)

Comments

Jonathan Cameron Jan. 28, 2018, 9:08 a.m. UTC | #1
On Fri, 26 Jan 2018 16:19:31 +0100
Philipp Rossak <embed3d@gmail.com> wrote:

multible -> multiple

> For adding newer sensor some basic rework of the code is necessary.
> 
> This patch reworks the driver to be able to handle more than one
> thermal sensor. Newer SoC like the A80 have 4 thermal sensors.
> Because of this the maximal sensor count value was set to 4.
> 
> The sensor_id value is set during sensor registration and is for each
> registered sensor indiviual. This makes it able to differntiate the
> sensors when the value is read from the register.
> 
> Signed-off-by: Philipp Rossak <embed3d@gmail.com>
Question inline about why you aren't exposing the additional temperature
sensors as IIO channels?

Fine to not do so I suppose, but needs justifying.

Jonathan

> ---
>  drivers/iio/adc/sun4i-gpadc-iio.c | 36 +++++++++++++++++++++++-------------
>  include/linux/mfd/sun4i-gpadc.h   |  6 ++++++
>  2 files changed, 29 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
> index 1a80744bd472..bff06f2798e8 100644
> --- a/drivers/iio/adc/sun4i-gpadc-iio.c
> +++ b/drivers/iio/adc/sun4i-gpadc-iio.c
> @@ -70,7 +70,7 @@ struct gpadc_data {
>  	unsigned int	tp_adc_select;
>  	unsigned int	(*adc_chan_select)(unsigned int chan);
>  	unsigned int	adc_chan_mask;
> -	unsigned int	temp_data;
> +	unsigned int	temp_data[MAX_SENSOR_COUNT];
>  	int		(*sample_start)(struct sun4i_gpadc_iio *info);
>  	int		(*sample_end)(struct sun4i_gpadc_iio *info);
>  	u32		ctrl0_map;
> @@ -80,6 +80,7 @@ struct gpadc_data {
>  	bool		has_bus_clk;
>  	bool		has_bus_rst;
>  	bool		has_mod_clk;
> +	int		sensor_count;
>  };
>  
>  static const struct gpadc_data sun4i_gpadc_data = {
> @@ -89,9 +90,10 @@ static const struct gpadc_data sun4i_gpadc_data = {
>  	.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,
> +	.temp_data = {SUN4I_GPADC_TEMP_DATA, 0, 0, 0},
>  	.sample_start = sun4i_gpadc_sample_start,
>  	.sample_end = sun4i_gpadc_sample_end,
> +	.sensor_count = 1,
>  };
>  
>  static const struct gpadc_data sun5i_gpadc_data = {
> @@ -101,9 +103,10 @@ static const struct gpadc_data sun5i_gpadc_data = {
>  	.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,
> +	.temp_data = {SUN4I_GPADC_TEMP_DATA, 0, 0, 0},
>  	.sample_start = sun4i_gpadc_sample_start,
>  	.sample_end = sun4i_gpadc_sample_end,
> +	.sensor_count = 1,
>  };
>  
>  static const struct gpadc_data sun6i_gpadc_data = {
> @@ -113,18 +116,20 @@ static const struct gpadc_data sun6i_gpadc_data = {
>  	.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,
> +	.temp_data = {SUN4I_GPADC_TEMP_DATA, 0, 0, 0},
>  	.sample_start = sun4i_gpadc_sample_start,
>  	.sample_end = sun4i_gpadc_sample_end,
> +	.sensor_count = 1,
>  };
>  
>  static const struct gpadc_data sun8i_a33_gpadc_data = {
>  	.temp_offset = -1662,
>  	.temp_scale = 162,
>  	.tp_mode_en = SUN8I_A33_GPADC_CTRL1_CHOP_TEMP_EN,
> -	.temp_data = SUN4I_GPADC_TEMP_DATA,
> +	.temp_data = {SUN4I_GPADC_TEMP_DATA, 0, 0, 0},
>  	.sample_start = sun4i_gpadc_sample_start,
>  	.sample_end = sun4i_gpadc_sample_end,
> +	.sensor_count = 1,
>  };
>  
>  struct sun4i_gpadc_iio {
> @@ -142,6 +147,7 @@ struct sun4i_gpadc_iio {
>  	struct clk			*bus_clk;
>  	struct clk			*mod_clk;
>  	struct reset_control		*reset;
> +	int				sensor_id;
>  	/* prevents concurrent reads of temperature and ADC */
>  	struct mutex			mutex;
>  	struct thermal_zone_device	*tzd;
> @@ -309,14 +315,15 @@ static int sun4i_gpadc_adc_read(struct iio_dev *indio_dev, int channel,
>  	return sun4i_gpadc_read(indio_dev, channel, val, info->fifo_data_irq);
>  }
>  
> -static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val)
> +static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val,
> +				int sensor)
>  {
>  	struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
>  
>  	if (info->no_irq) {
>  		pm_runtime_get_sync(indio_dev->dev.parent);
>  
> -		regmap_read(info->regmap, info->data->temp_data, val);
> +		regmap_read(info->regmap, info->data->temp_data[sensor], val);
>  
>  		pm_runtime_mark_last_busy(indio_dev->dev.parent);
>  		pm_runtime_put_autosuspend(indio_dev->dev.parent);
> @@ -363,7 +370,7 @@ static int sun4i_gpadc_read_raw(struct iio_dev *indio_dev,
>  			ret = sun4i_gpadc_adc_read(indio_dev, chan->channel,
>  						   val);
>  		else
> -			ret = sun4i_gpadc_temp_read(indio_dev, val);
> +			ret = sun4i_gpadc_temp_read(indio_dev, val, 0);

Wouldn't it make more sense to pass the channel number in here?

Looking at it, seems you only expose the first temperature sensor
as an IIO channel?   Perhaps fair enough, but please justify that
decision in the patch description.


>  
>  		if (ret)
>  			return ret;
> @@ -511,7 +518,7 @@ static int sun4i_gpadc_get_temp(void *data, int *temp)
>  	struct sun4i_gpadc_iio *info = data;
>  	int val, scale, offset;
>  
> -	if (sun4i_gpadc_temp_read(info->indio_dev, &val))
> +	if (sun4i_gpadc_temp_read(info->indio_dev, &val, info->sensor_id))
>  		return -ETIMEDOUT;
>  
>  	sun4i_gpadc_temp_scale(info->indio_dev, &scale);
> @@ -755,7 +762,7 @@ static int sun4i_gpadc_probe(struct platform_device *pdev)
>  {
>  	struct sun4i_gpadc_iio *info;
>  	struct iio_dev *indio_dev;
> -	int ret;
> +	int ret, i;
>  
>  	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
>  	if (!indio_dev)
> @@ -788,9 +795,12 @@ static int sun4i_gpadc_probe(struct platform_device *pdev)
>  	pm_runtime_enable(&pdev->dev);
>  
>  	if (IS_ENABLED(CONFIG_THERMAL_OF)) {
> -		info->tzd = thermal_zone_of_sensor_register(info->sensor_device,
> -							    0, info,
> -							    &sun4i_ts_tz_ops);
> +		for (i = 0; i < info->data->sensor_count; i++) {
> +			info->sensor_id = i;
> +			info->tzd = thermal_zone_of_sensor_register(
> +					info->sensor_device,
> +					i, info, &sun4i_ts_tz_ops);
> +		}
>  		/*
>  		 * Do not fail driver probing when failing to register in
>  		 * thermal because no thermal DT node is found.
> diff --git a/include/linux/mfd/sun4i-gpadc.h b/include/linux/mfd/sun4i-gpadc.h
> index 39e096c3ddac..40b4dd9d2405 100644
> --- a/include/linux/mfd/sun4i-gpadc.h
> +++ b/include/linux/mfd/sun4i-gpadc.h
> @@ -90,6 +90,10 @@
>  #define SUNXI_THS_CTRL0					0x00
>  #define SUNXI_THS_CTRL2					0x40
>  #define SUNXI_THS_FILTER				0x70
> +#define SUNXI_THS_TDATA0				0x80
> +#define SUNXI_THS_TDATA1				0x84
> +#define SUNXI_THS_TDATA2				0x88
> +#define SUNXI_THS_TDATA3				0x8c
>  
>  #define SUNXI_THS_FILTER_EN				BIT(2)
>  #define SUNXI_THS_FILTER_TYPE(x)			(GENMASK(1, 0) & (x))
> @@ -101,6 +105,8 @@
>  #define SUNXI_THS_TEMP_SENSE_EN2			BIT(2)
>  #define SUNXI_THS_TEMP_SENSE_EN3			BIT(3)
>  
> +#define MAX_SENSOR_COUNT				4
> +
>  struct sun4i_gpadc_dev {
>  	struct device			*dev;
>  	struct regmap			*regmap;
Philipp Rossak Jan. 28, 2018, 2:10 p.m. UTC | #2
On 28.01.2018 10:08, Jonathan Cameron wrote:
> On Fri, 26 Jan 2018 16:19:31 +0100
> Philipp Rossak <embed3d@gmail.com> wrote:
> 
> multible -> multiple
> 
^^ Ok, I will fix that.

>> For adding newer sensor some basic rework of the code is necessary.
>>
>> This patch reworks the driver to be able to handle more than one
>> thermal sensor. Newer SoC like the A80 have 4 thermal sensors.
>> Because of this the maximal sensor count value was set to 4.
>>
>> The sensor_id value is set during sensor registration and is for each
>> registered sensor indiviual. This makes it able to differntiate the
>> sensors when the value is read from the register.
>>
>> Signed-off-by: Philipp Rossak <embed3d@gmail.com>
> Question inline about why you aren't exposing the additional temperature
> sensors as IIO channels?
> 
> Fine to not do so I suppose, but needs justifying.
> 

^^ Ok, I will rework the commit mesage. Detailed explanation see below.
> Jonathan
> 
>> ---
>>   drivers/iio/adc/sun4i-gpadc-iio.c | 36 +++++++++++++++++++++++-------------
>>   include/linux/mfd/sun4i-gpadc.h   |  6 ++++++
>>   2 files changed, 29 insertions(+), 13 deletions(-)
>>
>> diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
>> index 1a80744bd472..bff06f2798e8 100644
>> --- a/drivers/iio/adc/sun4i-gpadc-iio.c
>> +++ b/drivers/iio/adc/sun4i-gpadc-iio.c
>> @@ -70,7 +70,7 @@ struct gpadc_data {
>>   	unsigned int	tp_adc_select;
>>   	unsigned int	(*adc_chan_select)(unsigned int chan);
>>   	unsigned int	adc_chan_mask;
>> -	unsigned int	temp_data;
>> +	unsigned int	temp_data[MAX_SENSOR_COUNT];
>>   	int		(*sample_start)(struct sun4i_gpadc_iio *info);
>>   	int		(*sample_end)(struct sun4i_gpadc_iio *info);
>>   	u32		ctrl0_map;
>> @@ -80,6 +80,7 @@ struct gpadc_data {
>>   	bool		has_bus_clk;
>>   	bool		has_bus_rst;
>>   	bool		has_mod_clk;
>> +	int		sensor_count;
>>   };
>>   
>>   static const struct gpadc_data sun4i_gpadc_data = {
>> @@ -89,9 +90,10 @@ static const struct gpadc_data sun4i_gpadc_data = {
>>   	.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,
>> +	.temp_data = {SUN4I_GPADC_TEMP_DATA, 0, 0, 0},
>>   	.sample_start = sun4i_gpadc_sample_start,
>>   	.sample_end = sun4i_gpadc_sample_end,
>> +	.sensor_count = 1,
>>   };
>>   
>>   static const struct gpadc_data sun5i_gpadc_data = {
>> @@ -101,9 +103,10 @@ static const struct gpadc_data sun5i_gpadc_data = {
>>   	.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,
>> +	.temp_data = {SUN4I_GPADC_TEMP_DATA, 0, 0, 0},
>>   	.sample_start = sun4i_gpadc_sample_start,
>>   	.sample_end = sun4i_gpadc_sample_end,
>> +	.sensor_count = 1,
>>   };
>>   
>>   static const struct gpadc_data sun6i_gpadc_data = {
>> @@ -113,18 +116,20 @@ static const struct gpadc_data sun6i_gpadc_data = {
>>   	.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,
>> +	.temp_data = {SUN4I_GPADC_TEMP_DATA, 0, 0, 0},
>>   	.sample_start = sun4i_gpadc_sample_start,
>>   	.sample_end = sun4i_gpadc_sample_end,
>> +	.sensor_count = 1,
>>   };
>>   
>>   static const struct gpadc_data sun8i_a33_gpadc_data = {
>>   	.temp_offset = -1662,
>>   	.temp_scale = 162,
>>   	.tp_mode_en = SUN8I_A33_GPADC_CTRL1_CHOP_TEMP_EN,
>> -	.temp_data = SUN4I_GPADC_TEMP_DATA,
>> +	.temp_data = {SUN4I_GPADC_TEMP_DATA, 0, 0, 0},

			[*] ^^
>>   	.sample_start = sun4i_gpadc_sample_start,
>>   	.sample_end = sun4i_gpadc_sample_end,
>> +	.sensor_count = 1,
>>   };
>>   
>>   struct sun4i_gpadc_iio {
>> @@ -142,6 +147,7 @@ struct sun4i_gpadc_iio {
>>   	struct clk			*bus_clk;
>>   	struct clk			*mod_clk;
>>   	struct reset_control		*reset;
>> +	int				sensor_id;
>>   	/* prevents concurrent reads of temperature and ADC */
>>   	struct mutex			mutex;
>>   	struct thermal_zone_device	*tzd;
>> @@ -309,14 +315,15 @@ static int sun4i_gpadc_adc_read(struct iio_dev *indio_dev, int channel,
>>   	return sun4i_gpadc_read(indio_dev, channel, val, info->fifo_data_irq);
>>   }
>>   
>> -static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val)
>> +static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val,
>> +				int sensor)
>>   {
>>   	struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
>>   
>>   	if (info->no_irq) {
>>   		pm_runtime_get_sync(indio_dev->dev.parent);
>>   
>> -		regmap_read(info->regmap, info->data->temp_data, val);
>> +		regmap_read(info->regmap, info->data->temp_data[sensor], val);
>>   
>>   		pm_runtime_mark_last_busy(indio_dev->dev.parent);
>>   		pm_runtime_put_autosuspend(indio_dev->dev.parent);
>> @@ -363,7 +370,7 @@ static int sun4i_gpadc_read_raw(struct iio_dev *indio_dev,
>>   			ret = sun4i_gpadc_adc_read(indio_dev, chan->channel,
>>   						   val);
>>   		else
>> -			ret = sun4i_gpadc_temp_read(indio_dev, val);
>> +			ret = sun4i_gpadc_temp_read(indio_dev, val, 0);
> 
> Wouldn't it make more sense to pass the channel number in here?
> 
> Looking at it, seems you only expose the first temperature sensor
> as an IIO channel?   Perhaps fair enough, but please justify that
> decision in the patch description.
> 

The "old" thermal sensors only have one ths sensor. This function is 
only used with the older sensors when the adc and the ths is used. The 
channel number is not related to that. This here is related to the 
temp_data. register selection above (marked with [*]).


> 
>>   
>>   		if (ret)
>>   			return ret;
>> @@ -511,7 +518,7 @@ static int sun4i_gpadc_get_temp(void *data, int *temp)
>>   	struct sun4i_gpadc_iio *info = data;
>>   	int val, scale, offset;
>>   
>> -	if (sun4i_gpadc_temp_read(info->indio_dev, &val))
>> +	if (sun4i_gpadc_temp_read(info->indio_dev, &val, info->sensor_id))
>>   		return -ETIMEDOUT;
>>   
>>   	sun4i_gpadc_temp_scale(info->indio_dev, &scale);
>> @@ -755,7 +762,7 @@ static int sun4i_gpadc_probe(struct platform_device *pdev)
>>   {
>>   	struct sun4i_gpadc_iio *info;
>>   	struct iio_dev *indio_dev;
>> -	int ret;
>> +	int ret, i;
>>   
>>   	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
>>   	if (!indio_dev)
>> @@ -788,9 +795,12 @@ static int sun4i_gpadc_probe(struct platform_device *pdev)
>>   	pm_runtime_enable(&pdev->dev);
>>   
>>   	if (IS_ENABLED(CONFIG_THERMAL_OF)) {
>> -		info->tzd = thermal_zone_of_sensor_register(info->sensor_device,
>> -							    0, info,
>> -							    &sun4i_ts_tz_ops);
>> +		for (i = 0; i < info->data->sensor_count; i++) {
>> +			info->sensor_id = i;
>> +			info->tzd = thermal_zone_of_sensor_register(
>> +					info->sensor_device,
>> +					i, info, &sun4i_ts_tz_ops);
>> +		}
>>   		/*
>>   		 * Do not fail driver probing when failing to register in
>>   		 * thermal because no thermal DT node is found.
>> diff --git a/include/linux/mfd/sun4i-gpadc.h b/include/linux/mfd/sun4i-gpadc.h
>> index 39e096c3ddac..40b4dd9d2405 100644
>> --- a/include/linux/mfd/sun4i-gpadc.h
>> +++ b/include/linux/mfd/sun4i-gpadc.h
>> @@ -90,6 +90,10 @@
>>   #define SUNXI_THS_CTRL0					0x00
>>   #define SUNXI_THS_CTRL2					0x40
>>   #define SUNXI_THS_FILTER				0x70
>> +#define SUNXI_THS_TDATA0				0x80
>> +#define SUNXI_THS_TDATA1				0x84
>> +#define SUNXI_THS_TDATA2				0x88
>> +#define SUNXI_THS_TDATA3				0x8c
>>   
>>   #define SUNXI_THS_FILTER_EN				BIT(2)
>>   #define SUNXI_THS_FILTER_TYPE(x)			(GENMASK(1, 0) & (x))
>> @@ -101,6 +105,8 @@
>>   #define SUNXI_THS_TEMP_SENSE_EN2			BIT(2)
>>   #define SUNXI_THS_TEMP_SENSE_EN3			BIT(3)
>>   
>> +#define MAX_SENSOR_COUNT				4
>> +
>>   struct sun4i_gpadc_dev {
>>   	struct device			*dev;
>>   	struct regmap			*regmap;
> 

Thanks,
Philipp
diff mbox

Patch

diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
index 1a80744bd472..bff06f2798e8 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -70,7 +70,7 @@  struct gpadc_data {
 	unsigned int	tp_adc_select;
 	unsigned int	(*adc_chan_select)(unsigned int chan);
 	unsigned int	adc_chan_mask;
-	unsigned int	temp_data;
+	unsigned int	temp_data[MAX_SENSOR_COUNT];
 	int		(*sample_start)(struct sun4i_gpadc_iio *info);
 	int		(*sample_end)(struct sun4i_gpadc_iio *info);
 	u32		ctrl0_map;
@@ -80,6 +80,7 @@  struct gpadc_data {
 	bool		has_bus_clk;
 	bool		has_bus_rst;
 	bool		has_mod_clk;
+	int		sensor_count;
 };
 
 static const struct gpadc_data sun4i_gpadc_data = {
@@ -89,9 +90,10 @@  static const struct gpadc_data sun4i_gpadc_data = {
 	.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,
+	.temp_data = {SUN4I_GPADC_TEMP_DATA, 0, 0, 0},
 	.sample_start = sun4i_gpadc_sample_start,
 	.sample_end = sun4i_gpadc_sample_end,
+	.sensor_count = 1,
 };
 
 static const struct gpadc_data sun5i_gpadc_data = {
@@ -101,9 +103,10 @@  static const struct gpadc_data sun5i_gpadc_data = {
 	.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,
+	.temp_data = {SUN4I_GPADC_TEMP_DATA, 0, 0, 0},
 	.sample_start = sun4i_gpadc_sample_start,
 	.sample_end = sun4i_gpadc_sample_end,
+	.sensor_count = 1,
 };
 
 static const struct gpadc_data sun6i_gpadc_data = {
@@ -113,18 +116,20 @@  static const struct gpadc_data sun6i_gpadc_data = {
 	.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,
+	.temp_data = {SUN4I_GPADC_TEMP_DATA, 0, 0, 0},
 	.sample_start = sun4i_gpadc_sample_start,
 	.sample_end = sun4i_gpadc_sample_end,
+	.sensor_count = 1,
 };
 
 static const struct gpadc_data sun8i_a33_gpadc_data = {
 	.temp_offset = -1662,
 	.temp_scale = 162,
 	.tp_mode_en = SUN8I_A33_GPADC_CTRL1_CHOP_TEMP_EN,
-	.temp_data = SUN4I_GPADC_TEMP_DATA,
+	.temp_data = {SUN4I_GPADC_TEMP_DATA, 0, 0, 0},
 	.sample_start = sun4i_gpadc_sample_start,
 	.sample_end = sun4i_gpadc_sample_end,
+	.sensor_count = 1,
 };
 
 struct sun4i_gpadc_iio {
@@ -142,6 +147,7 @@  struct sun4i_gpadc_iio {
 	struct clk			*bus_clk;
 	struct clk			*mod_clk;
 	struct reset_control		*reset;
+	int				sensor_id;
 	/* prevents concurrent reads of temperature and ADC */
 	struct mutex			mutex;
 	struct thermal_zone_device	*tzd;
@@ -309,14 +315,15 @@  static int sun4i_gpadc_adc_read(struct iio_dev *indio_dev, int channel,
 	return sun4i_gpadc_read(indio_dev, channel, val, info->fifo_data_irq);
 }
 
-static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val)
+static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val,
+				int sensor)
 {
 	struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
 
 	if (info->no_irq) {
 		pm_runtime_get_sync(indio_dev->dev.parent);
 
-		regmap_read(info->regmap, info->data->temp_data, val);
+		regmap_read(info->regmap, info->data->temp_data[sensor], val);
 
 		pm_runtime_mark_last_busy(indio_dev->dev.parent);
 		pm_runtime_put_autosuspend(indio_dev->dev.parent);
@@ -363,7 +370,7 @@  static int sun4i_gpadc_read_raw(struct iio_dev *indio_dev,
 			ret = sun4i_gpadc_adc_read(indio_dev, chan->channel,
 						   val);
 		else
-			ret = sun4i_gpadc_temp_read(indio_dev, val);
+			ret = sun4i_gpadc_temp_read(indio_dev, val, 0);
 
 		if (ret)
 			return ret;
@@ -511,7 +518,7 @@  static int sun4i_gpadc_get_temp(void *data, int *temp)
 	struct sun4i_gpadc_iio *info = data;
 	int val, scale, offset;
 
-	if (sun4i_gpadc_temp_read(info->indio_dev, &val))
+	if (sun4i_gpadc_temp_read(info->indio_dev, &val, info->sensor_id))
 		return -ETIMEDOUT;
 
 	sun4i_gpadc_temp_scale(info->indio_dev, &scale);
@@ -755,7 +762,7 @@  static int sun4i_gpadc_probe(struct platform_device *pdev)
 {
 	struct sun4i_gpadc_iio *info;
 	struct iio_dev *indio_dev;
-	int ret;
+	int ret, i;
 
 	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
 	if (!indio_dev)
@@ -788,9 +795,12 @@  static int sun4i_gpadc_probe(struct platform_device *pdev)
 	pm_runtime_enable(&pdev->dev);
 
 	if (IS_ENABLED(CONFIG_THERMAL_OF)) {
-		info->tzd = thermal_zone_of_sensor_register(info->sensor_device,
-							    0, info,
-							    &sun4i_ts_tz_ops);
+		for (i = 0; i < info->data->sensor_count; i++) {
+			info->sensor_id = i;
+			info->tzd = thermal_zone_of_sensor_register(
+					info->sensor_device,
+					i, info, &sun4i_ts_tz_ops);
+		}
 		/*
 		 * Do not fail driver probing when failing to register in
 		 * thermal because no thermal DT node is found.
diff --git a/include/linux/mfd/sun4i-gpadc.h b/include/linux/mfd/sun4i-gpadc.h
index 39e096c3ddac..40b4dd9d2405 100644
--- a/include/linux/mfd/sun4i-gpadc.h
+++ b/include/linux/mfd/sun4i-gpadc.h
@@ -90,6 +90,10 @@ 
 #define SUNXI_THS_CTRL0					0x00
 #define SUNXI_THS_CTRL2					0x40
 #define SUNXI_THS_FILTER				0x70
+#define SUNXI_THS_TDATA0				0x80
+#define SUNXI_THS_TDATA1				0x84
+#define SUNXI_THS_TDATA2				0x88
+#define SUNXI_THS_TDATA3				0x8c
 
 #define SUNXI_THS_FILTER_EN				BIT(2)
 #define SUNXI_THS_FILTER_TYPE(x)			(GENMASK(1, 0) & (x))
@@ -101,6 +105,8 @@ 
 #define SUNXI_THS_TEMP_SENSE_EN2			BIT(2)
 #define SUNXI_THS_TEMP_SENSE_EN3			BIT(3)
 
+#define MAX_SENSOR_COUNT				4
+
 struct sun4i_gpadc_dev {
 	struct device			*dev;
 	struct regmap			*regmap;