diff mbox

[v2,08/16] iio: adc: sun4i-gpadc-iio: rework: add interrupt support

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

Commit Message

Philipp Rossak Jan. 28, 2018, 11:29 p.m. UTC
This patch rewors the driver to support interrupts for the thermal part
of the sensor.

This is only available for the newer sensor (currently H3 and A83T).
The interrupt will be trigerd on data available and triggers the update
for the thermal sensors. All newer sensors have different amount of
sensors and different interrupts for each device the reset of the
interrupts need to be done different

For the newer sensors is the autosuspend disabled.

Signed-off-by: Philipp Rossak <embed3d@gmail.com>
Acked-by: Jonathan  Cameron <jonathan.cameron@huawei.com>
---
 drivers/iio/adc/sun4i-gpadc-iio.c | 60 +++++++++++++++++++++++++++++++++++----
 include/linux/mfd/sun4i-gpadc.h   |  2 ++
 2 files changed, 56 insertions(+), 6 deletions(-)

Comments

Quentin Schulz Jan. 31, 2018, 7:07 p.m. UTC | #1
Hi Philipp,

On Mon, Jan 29, 2018 at 12:29:11AM +0100, Philipp Rossak wrote:
> This patch rewors the driver to support interrupts for the thermal part
> of the sensor.
> 
> This is only available for the newer sensor (currently H3 and A83T).
> The interrupt will be trigerd on data available and triggers the update
> for the thermal sensors. All newer sensors have different amount of
> sensors and different interrupts for each device the reset of the
> interrupts need to be done different
> 
> For the newer sensors is the autosuspend disabled.
> 
> Signed-off-by: Philipp Rossak <embed3d@gmail.com>
> Acked-by: Jonathan  Cameron <jonathan.cameron@huawei.com>
> ---
>  drivers/iio/adc/sun4i-gpadc-iio.c | 60 +++++++++++++++++++++++++++++++++++----
>  include/linux/mfd/sun4i-gpadc.h   |  2 ++
>  2 files changed, 56 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
> index 74eeb5cd5218..b7b5451226b0 100644
> --- a/drivers/iio/adc/sun4i-gpadc-iio.c
> +++ b/drivers/iio/adc/sun4i-gpadc-iio.c
> @@ -71,11 +71,14 @@ struct gpadc_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		irq_clear_map;
> +	u32		irq_control_map;

I would say to use a regmap_irq_chip for controlling IRQs.

>  	bool		has_bus_clk;
>  	bool		has_bus_rst;
>  	bool		has_mod_clk;
>  	int		sensor_count;
>  	bool		supports_nvmem;
> +	bool		support_irq;
>  };
>  
>  static const struct gpadc_data sun4i_gpadc_data = {
> @@ -90,6 +93,7 @@ static const struct gpadc_data sun4i_gpadc_data = {
>  	.sample_end = sun4i_gpadc_sample_end,
>  	.sensor_count = 1,
>  	.supports_nvmem = false,
> +	.support_irq = false,

False is the default, no need to set support_irq.

[...]

>  struct sun4i_gpadc_iio {
> @@ -332,6 +339,11 @@ static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val,
>  		return 0;
>  	}
>  
> +	if (info->data->support_irq) {
> +		regmap_read(info->regmap, info->data->temp_data[sensor], val);
> +		return 0;
> +	}
> +

Maybe you could define a new thermal_zone_of_device_ops for these new
thermal sensors? That way, you don't even need the boolean support_irq.

>  	return sun4i_gpadc_read(indio_dev, 0, val, info->temp_data_irq);
>  }
>  
> @@ -429,6 +441,17 @@ static irqreturn_t sun4i_gpadc_fifo_data_irq_handler(int irq, void *dev_id)
>  	return IRQ_HANDLED;
>  }
>  
> +static irqreturn_t sunxi_irq_thread(int irq, void *data)

I think we're trying to avoid sunxi mentions but rather using the name
of the first IP (in term of product release, not support) using this
function.

> +{
> +	struct sun4i_gpadc_iio *info = data;
> +
> +	regmap_write(info->regmap, SUN8I_H3_THS_STAT, info->data->irq_clear_map);
> +

Will be handled by regmap_irq_chip.
[...]
> -	info->no_irq = true;
> +	if (info->data->support_irq) {
> +		/* only the new versions of ths support right now irqs */
> +		irq = platform_get_irq(pdev, 0);
> +		if (irq < 0) {
> +			dev_err(&pdev->dev, "failed to get IRQ: %d\n", irq);
> +			return irq;
> +		}
> +
> +		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
> +				sunxi_irq_thread, IRQF_ONESHOT,
> +				dev_name(&pdev->dev), info);
> +		if (ret)
> +			return ret;
> +
> +	} else
> +		info->no_irq = true;
> +

That's a bit funny to have two booleans named no_irq and support_irq :)

>  	indio_dev->num_channels = ARRAY_SIZE(sun8i_a33_gpadc_channels);
>  	indio_dev->channels = sun8i_a33_gpadc_channels;
>  
> @@ -789,11 +829,13 @@ static int sun4i_gpadc_probe(struct platform_device *pdev)
>  	if (ret)
>  		return ret;
>  
> -	pm_runtime_set_autosuspend_delay(&pdev->dev,
> -					 SUN4I_GPADC_AUTOSUSPEND_DELAY);
> -	pm_runtime_use_autosuspend(&pdev->dev);
> -	pm_runtime_set_suspended(&pdev->dev);
> -	pm_runtime_enable(&pdev->dev);
> +	if (!info->data->support_irq) {
> +		pm_runtime_set_autosuspend_delay(&pdev->dev,
> +						 SUN4I_GPADC_AUTOSUSPEND_DELAY);
> +		pm_runtime_use_autosuspend(&pdev->dev);
> +		pm_runtime_set_suspended(&pdev->dev);
> +		pm_runtime_enable(&pdev->dev);
> +	}

Why would you not want your IP to do runtime PM?

Quentin
kernel test robot Jan. 31, 2018, 9:47 p.m. UTC | #2
Hi Philipp,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on robh/for-next]
[also build test ERROR on v4.15 next-20180126]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Philipp-Rossak/IIO-based-thermal-sensor-driver-for-Allwinner-H3-and-A83T-SoC/20180201-043415
base:   https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git for-next
config: xtensa-allmodconfig (attached as .config)
compiler: xtensa-linux-gcc (GCC) 7.2.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=xtensa 

Note: the linux-review/Philipp-Rossak/IIO-based-thermal-sensor-driver-for-Allwinner-H3-and-A83T-SoC/20180201-043415 HEAD e571c3ced84a9d7f150cb2d239919d31d25114e2 builds fine.
      It only hurts bisectibility.

All errors (new ones prefixed by >>):

   drivers/iio/adc/sun4i-gpadc-iio.c: In function 'sunxi_irq_thread':
>> drivers/iio/adc/sun4i-gpadc-iio.c:448:29: error: 'SUN8I_H3_THS_STAT' undeclared (first use in this function); did you mean 'SUN8I_H3_THS_INTC'?
     regmap_write(info->regmap, SUN8I_H3_THS_STAT, info->data->irq_clear_map);
                                ^~~~~~~~~~~~~~~~~
                                SUN8I_H3_THS_INTC
   drivers/iio/adc/sun4i-gpadc-iio.c:448:29: note: each undeclared identifier is reported only once for each function it appears in

vim +448 drivers/iio/adc/sun4i-gpadc-iio.c

   443	
   444	static irqreturn_t sunxi_irq_thread(int irq, void *data)
   445	{
   446		struct sun4i_gpadc_iio *info = data;
   447	
 > 448		regmap_write(info->regmap, SUN8I_H3_THS_STAT, info->data->irq_clear_map);
   449	
   450		thermal_zone_device_update(info->tzd, THERMAL_EVENT_TEMP_SAMPLE);
   451	
   452		return IRQ_HANDLED;
   453	}
   454	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
Philipp Rossak Feb. 2, 2018, 2:30 p.m. UTC | #3
On 31.01.2018 20:07, Quentin Schulz wrote:
> Hi Philipp,
> 
> On Mon, Jan 29, 2018 at 12:29:11AM +0100, Philipp Rossak wrote:
>> This patch rewors the driver to support interrupts for the thermal part
>> of the sensor.
>>
>> This is only available for the newer sensor (currently H3 and A83T).
>> The interrupt will be trigerd on data available and triggers the update
>> for the thermal sensors. All newer sensors have different amount of
>> sensors and different interrupts for each device the reset of the
>> interrupts need to be done different
>>
>> For the newer sensors is the autosuspend disabled.
>>
>> Signed-off-by: Philipp Rossak <embed3d@gmail.com>
>> Acked-by: Jonathan  Cameron <jonathan.cameron@huawei.com>
>> ---
>>   drivers/iio/adc/sun4i-gpadc-iio.c | 60 +++++++++++++++++++++++++++++++++++----
>>   include/linux/mfd/sun4i-gpadc.h   |  2 ++
>>   2 files changed, 56 insertions(+), 6 deletions(-)
>>
>> diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
>> index 74eeb5cd5218..b7b5451226b0 100644
>> --- a/drivers/iio/adc/sun4i-gpadc-iio.c
>> +++ b/drivers/iio/adc/sun4i-gpadc-iio.c
>> @@ -71,11 +71,14 @@ struct gpadc_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		irq_clear_map;
>> +	u32		irq_control_map;
> 
> I would say to use a regmap_irq_chip for controlling IRQs.
> 
Sounds good for me! I will rework that in the next version.
>>   	bool		has_bus_clk;
>>   	bool		has_bus_rst;
>>   	bool		has_mod_clk;
>>   	int		sensor_count;
>>   	bool		supports_nvmem;
>> +	bool		support_irq;
>>   };
>>   
>>   static const struct gpadc_data sun4i_gpadc_data = {
>> @@ -90,6 +93,7 @@ static const struct gpadc_data sun4i_gpadc_data = {
>>   	.sample_end = sun4i_gpadc_sample_end,
>>   	.sensor_count = 1,
>>   	.supports_nvmem = false,
>> +	.support_irq = false,
> 
> False is the default, no need to set support_irq.
> 
> [...]
> 
>>   struct sun4i_gpadc_iio {
>> @@ -332,6 +339,11 @@ static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val,
>>   		return 0;
>>   	}
>>   
>> +	if (info->data->support_irq) {
>> +		regmap_read(info->regmap, info->data->temp_data[sensor], val);
>> +		return 0;
>> +	}
>> +
> 
> Maybe you could define a new thermal_zone_of_device_ops for these new
> thermal sensors? That way, you don't even need the boolean support_irq.
> 
Sounds good for me! I will rework that in the next version.

>>   	return sun4i_gpadc_read(indio_dev, 0, val, info->temp_data_irq);
>>   }
>>   
>> @@ -429,6 +441,17 @@ static irqreturn_t sun4i_gpadc_fifo_data_irq_handler(int irq, void *dev_id)
>>   	return IRQ_HANDLED;
>>   }
>>   
>> +static irqreturn_t sunxi_irq_thread(int irq, void *data)
> 
> I think we're trying to avoid sunxi mentions but rather using the name
> of the first IP (in term of product release, not support) using this
> function.
> 
>> +{
>> +	struct sun4i_gpadc_iio *info = data;
>> +
>> +	regmap_write(info->regmap, SUN8I_H3_THS_STAT, info->data->irq_clear_map);
>> +
> 
> Will be handled by regmap_irq_chip.
> [...]
>> -	info->no_irq = true;
>> +	if (info->data->support_irq) {
>> +		/* only the new versions of ths support right now irqs */
>> +		irq = platform_get_irq(pdev, 0);
>> +		if (irq < 0) {
>> +			dev_err(&pdev->dev, "failed to get IRQ: %d\n", irq);
>> +			return irq;
>> +		}
>> +
>> +		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
>> +				sunxi_irq_thread, IRQF_ONESHOT,
>> +				dev_name(&pdev->dev), info);
>> +		if (ret)
>> +			return ret;
>> +
>> +	} else
>> +		info->no_irq = true;
>> +
> 
> That's a bit funny to have two booleans named no_irq and support_irq :)
> 
I know this looks very funny. I thought this would be better to keep, to 
_not_ break anything. Since I will rework the whole driver and integrate 
the mfd part I hope I can remove both.

>>   	indio_dev->num_channels = ARRAY_SIZE(sun8i_a33_gpadc_channels);
>>   	indio_dev->channels = sun8i_a33_gpadc_channels;
>>   
>> @@ -789,11 +829,13 @@ static int sun4i_gpadc_probe(struct platform_device *pdev)
>>   	if (ret)
>>   		return ret;
>>   
>> -	pm_runtime_set_autosuspend_delay(&pdev->dev,
>> -					 SUN4I_GPADC_AUTOSUSPEND_DELAY);
>> -	pm_runtime_use_autosuspend(&pdev->dev);
>> -	pm_runtime_set_suspended(&pdev->dev);
>> -	pm_runtime_enable(&pdev->dev);
>> +	if (!info->data->support_irq) {
>> +		pm_runtime_set_autosuspend_delay(&pdev->dev,
>> +						 SUN4I_GPADC_AUTOSUSPEND_DELAY);
>> +		pm_runtime_use_autosuspend(&pdev->dev);
>> +		pm_runtime_set_suspended(&pdev->dev);
>> +		pm_runtime_enable(&pdev->dev);
>> +	}
> 
> Why would you not want your IP to do runtime PM?

I will enable this again, in the next version! I had some issues with 
this, thus I disabled this, but I know now what I did wrong!

Thanks,
Philipp
diff mbox

Patch

diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
index 74eeb5cd5218..b7b5451226b0 100644
--- a/drivers/iio/adc/sun4i-gpadc-iio.c
+++ b/drivers/iio/adc/sun4i-gpadc-iio.c
@@ -71,11 +71,14 @@  struct gpadc_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		irq_clear_map;
+	u32		irq_control_map;
 	bool		has_bus_clk;
 	bool		has_bus_rst;
 	bool		has_mod_clk;
 	int		sensor_count;
 	bool		supports_nvmem;
+	bool		support_irq;
 };
 
 static const struct gpadc_data sun4i_gpadc_data = {
@@ -90,6 +93,7 @@  static const struct gpadc_data sun4i_gpadc_data = {
 	.sample_end = sun4i_gpadc_sample_end,
 	.sensor_count = 1,
 	.supports_nvmem = false,
+	.support_irq = false,
 };
 
 static const struct gpadc_data sun5i_gpadc_data = {
@@ -104,6 +108,7 @@  static const struct gpadc_data sun5i_gpadc_data = {
 	.sample_end = sun4i_gpadc_sample_end,
 	.sensor_count = 1,
 	.supports_nvmem = false,
+	.support_irq = false,
 };
 
 static const struct gpadc_data sun6i_gpadc_data = {
@@ -118,6 +123,7 @@  static const struct gpadc_data sun6i_gpadc_data = {
 	.sample_end = sun4i_gpadc_sample_end,
 	.sensor_count = 1,
 	.supports_nvmem = false,
+	.support_irq = false,
 };
 
 static const struct gpadc_data sun8i_a33_gpadc_data = {
@@ -129,6 +135,7 @@  static const struct gpadc_data sun8i_a33_gpadc_data = {
 	.sample_end = sun4i_gpadc_sample_end,
 	.sensor_count = 1,
 	.supports_nvmem = false,
+	.support_irq = false,
 };
 
 struct sun4i_gpadc_iio {
@@ -332,6 +339,11 @@  static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val,
 		return 0;
 	}
 
+	if (info->data->support_irq) {
+		regmap_read(info->regmap, info->data->temp_data[sensor], val);
+		return 0;
+	}
+
 	return sun4i_gpadc_read(indio_dev, 0, val, info->temp_data_irq);
 }
 
@@ -429,6 +441,17 @@  static irqreturn_t sun4i_gpadc_fifo_data_irq_handler(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t sunxi_irq_thread(int irq, void *data)
+{
+	struct sun4i_gpadc_iio *info = data;
+
+	regmap_write(info->regmap, SUN8I_H3_THS_STAT, info->data->irq_clear_map);
+
+	thermal_zone_device_update(info->tzd, THERMAL_EVENT_TEMP_SAMPLE);
+
+	return IRQ_HANDLED;
+}
+
 static int sun4i_gpadc_sample_end(struct sun4i_gpadc_iio *info)
 {
 	/* Disable the ADC on IP */
@@ -572,12 +595,29 @@  static int sun4i_gpadc_probe_dt(struct platform_device *pdev,
 	struct nvmem_cell *cell;
 	ssize_t cell_size;
 	u64 *cell_data;
+	int irq;
 
 	info->data = of_device_get_match_data(&pdev->dev);
 	if (!info->data)
 		return -ENODEV;
 
-	info->no_irq = true;
+	if (info->data->support_irq) {
+		/* only the new versions of ths support right now irqs */
+		irq = platform_get_irq(pdev, 0);
+		if (irq < 0) {
+			dev_err(&pdev->dev, "failed to get IRQ: %d\n", irq);
+			return irq;
+		}
+
+		ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+				sunxi_irq_thread, IRQF_ONESHOT,
+				dev_name(&pdev->dev), info);
+		if (ret)
+			return ret;
+
+	} else
+		info->no_irq = true;
+
 	indio_dev->num_channels = ARRAY_SIZE(sun8i_a33_gpadc_channels);
 	indio_dev->channels = sun8i_a33_gpadc_channels;
 
@@ -789,11 +829,13 @@  static int sun4i_gpadc_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	pm_runtime_set_autosuspend_delay(&pdev->dev,
-					 SUN4I_GPADC_AUTOSUSPEND_DELAY);
-	pm_runtime_use_autosuspend(&pdev->dev);
-	pm_runtime_set_suspended(&pdev->dev);
-	pm_runtime_enable(&pdev->dev);
+	if (!info->data->support_irq) {
+		pm_runtime_set_autosuspend_delay(&pdev->dev,
+						 SUN4I_GPADC_AUTOSUSPEND_DELAY);
+		pm_runtime_use_autosuspend(&pdev->dev);
+		pm_runtime_set_suspended(&pdev->dev);
+		pm_runtime_enable(&pdev->dev);
+	}
 
 	if (IS_ENABLED(CONFIG_THERMAL_OF)) {
 		for (i = 0; i < info->data->sensor_count; i++) {
@@ -814,6 +856,9 @@  static int sun4i_gpadc_probe(struct platform_device *pdev)
 		}
 	}
 
+	if (info->data->support_irq)
+		info->data->sample_start(info);
+
 	ret = devm_iio_device_register(&pdev->dev, indio_dev);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "could not register the device\n");
@@ -843,6 +888,9 @@  static int sun4i_gpadc_remove(struct platform_device *pdev)
 	if (!IS_ENABLED(CONFIG_THERMAL_OF))
 		return 0;
 
+	if (info->data->support_irq)
+		info->data->sample_end(info);
+
 	thermal_zone_of_sensor_unregister(info->sensor_device, info->tzd);
 
 	if (!info->no_irq)
diff --git a/include/linux/mfd/sun4i-gpadc.h b/include/linux/mfd/sun4i-gpadc.h
index 20fa02040007..458f2159a95a 100644
--- a/include/linux/mfd/sun4i-gpadc.h
+++ b/include/linux/mfd/sun4i-gpadc.h
@@ -91,6 +91,8 @@ 
 #define SUN4I_GPADC_AUTOSUSPEND_DELAY			10000
 
 /* SUNXI_THS COMMON REGISTERS + DEFINES */
+#define SUN8I_H3_THS_INTC				0x44
+
 #define MAX_SENSOR_COUNT				4
 
 struct sun4i_gpadc_dev {