Re: [PATCH v2 08/11] iio: adc: sun4i-gpadc-iio: add support for A33 thermal sensor

From: Jonathan Cameron
Date: Sat Mar 18 2017 - 10:23:52 EST


On 14/03/17 07:15, Quentin Schulz wrote:
> Hi Jonathan,
>
> On 14/03/2017 06:18, Icenowy Zheng wrote:
>>
>>
>> 14.03.2017, 05:08, "Jonathan Cameron" <jic23@xxxxxxxxxx>:
>>> On 10/03/17 10:39, Quentin Schulz wrote:
>>>> This adds support for the Allwinner A33 thermal sensor.
>>>>
>>>> Unlike the A10, A13 and A31, the Allwinner A33 only has one channel
>>>> which is dedicated to the thermal sensor. Moreover, its thermal sensor
>>>> does not generate interruptions, thus we only need to directly read the
>>>> register storing the temperature value.
>>>>
>>>> The MFD used by the A10, A13 and A31, was created to avoid breaking the
>>>> DT binding, but since the nodes for the ADC weren't there for the A33,
>>>> it is not needed.
>>>>
>>>> Signed-off-by: Quentin Schulz <quentin.schulz@xxxxxxxxxxxxxxxxxx>
>>>
>>> Talk me through why it makes sense to do this rather than simply spin out
>>> a really simple thermal driver for the A33?
>>
>> According to him the A33 thermal sensor is a simplified version of the GPADC.
>>
>
> Same registers with almost same bits for the same purpose (temperature).
> Some SoCs have an ADC and one or more thermal sensors (A10, A13, A31,
> H3) while others have only one thermal sensor (A23, A33). Same IP with
> or without ADC/Touchscreen so same driver, that was my mindset.
>
> The thermal part behaves the same except for the presence of interrupts
> or not. (A33 has bits for interrupts in the datasheet but that just does
> not work).
Hmm. I'm just about convinced by this argument, please make it in the patch
description going forward.

Jonathan
>
> Thanks,
> Quentin
>
>> I have already did a simple thermal driver ~8 months ago, but is rejected for
>> this reason.
>>
>>>
>>> I'm not against what you have here, but don't feel it has been fully argued.
>>>
>>> Jonathan
>>>> ---
>>>>
>>>> v2:
>>>> - removed added comments in Kconfig,
>>>> - simplified Kconfig depends on condition,
>>>> - removed THERMAL_OF requirement for sun8i,
>>>> - renamed sun8i_gpadc_channels to sun8i_a33_gpadc_channels,
>>>> - renamed use_dt boolean in no_irq as it reflects better why we need it,
>>>> - removed spurious/unneeded modifications done in v1,
>>>>
>>>> drivers/iio/adc/Kconfig | 2 +-
>>>> drivers/iio/adc/sun4i-gpadc-iio.c | 100 ++++++++++++++++++++++++++++++++++++--
>>>> include/linux/mfd/sun4i-gpadc.h | 4 ++
>>>> 3 files changed, 102 insertions(+), 4 deletions(-)
>>>>
>>>> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
>>>> index 9f8b4b1..8c8ead6 100644
>>>> --- a/drivers/iio/adc/Kconfig
>>>> +++ b/drivers/iio/adc/Kconfig
>>>> @@ -562,7 +562,7 @@ config STX104
>>>> config SUN4I_GPADC
>>>> tristate "Support for the Allwinner SoCs GPADC"
>>>> depends on IIO
>>>> - depends on MFD_SUN4I_GPADC
>>>> + depends on MFD_SUN4I_GPADC || MACH_SUN8I
>>>> help
>>>> Say yes here to build support for Allwinner (A10, A13 and A31) SoCs
>>>> GPADC. This ADC provides 4 channels which can be used as an ADC or as
>>>> diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
>>>> index 7cb997a..70684cd 100644
>>>> --- a/drivers/iio/adc/sun4i-gpadc-iio.c
>>>> +++ b/drivers/iio/adc/sun4i-gpadc-iio.c
>>>> @@ -85,6 +85,12 @@ static const struct gpadc_data sun6i_gpadc_data = {
>>>> .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,
>>>> +};
>>>> +
>>>> struct sun4i_gpadc_iio {
>>>> struct iio_dev *indio_dev;
>>>> struct completion completion;
>>>> @@ -96,6 +102,7 @@ struct sun4i_gpadc_iio {
>>>> unsigned int temp_data_irq;
>>>> atomic_t ignore_temp_data_irq;
>>>> const struct gpadc_data *data;
>>>> + bool no_irq;
>>>> /* prevents concurrent reads of temperature and ADC */
>>>> struct mutex mutex;
>>>> };
>>>> @@ -138,6 +145,23 @@ static const struct iio_chan_spec sun4i_gpadc_channels_no_temp[] = {
>>>> SUN4I_GPADC_ADC_CHANNEL(3, "adc_chan3"),
>>>> };
>>>>
>>>> +static const struct iio_chan_spec sun8i_a33_gpadc_channels[] = {
>>>> + {
>>>> + .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 regmap_config sun4i_gpadc_regmap_config = {
>>>> + .reg_bits = 32,
>>>> + .val_bits = 32,
>>>> + .reg_stride = 4,
>>>> + .fast_io = true,
>>>> +};
>>>> +
>>>> static int sun4i_prepare_for_irq(struct iio_dev *indio_dev, int channel,
>>>> unsigned int irq)
>>>> {
>>>> @@ -247,6 +271,17 @@ static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val)
>>>> {
>>>> 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, SUN4I_GPADC_TEMP_DATA, val);
>>>> +
>>>> + pm_runtime_mark_last_busy(indio_dev->dev.parent);
>>>> + pm_runtime_put_autosuspend(indio_dev->dev.parent);
>>>> +
>>>> + return 0;
>>>> + }
>>>> +
>>>> return sun4i_gpadc_read(indio_dev, 0, val, info->temp_data_irq);
>>>> }
>>>>
>>>> @@ -454,6 +489,58 @@ static int sun4i_irq_init(struct platform_device *pdev, const char *name,
>>>> return 0;
>>>> }
>>>>
>>>> +static const struct of_device_id sun4i_gpadc_of_id[] = {
>>>> + {
>>>> + .compatible = "allwinner,sun8i-a33-gpadc-iio",
>>>> + .data = &sun8i_a33_gpadc_data,
>>>> + },
>>>> + { /* sentinel */ }
>>>> +};
>>>> +
>>>> +static int sun4i_gpadc_probe_dt(struct platform_device *pdev,
>>>> + struct iio_dev *indio_dev)
>>>> +{
>>>> + struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
>>>> + const struct of_device_id *of_dev;
>>>> + struct thermal_zone_device *tzd;
>>>> + struct resource *mem;
>>>> + void __iomem *base;
>>>> + int ret;
>>>> +
>>>> + of_dev = of_match_device(sun4i_gpadc_of_id, &pdev->dev);
>>>> + if (!of_dev)
>>>> + return -ENODEV;
>>>> +
>>>> + info->no_irq = true;
>>>> + info->data = (struct gpadc_data *)of_dev->data;
>>>> + indio_dev->num_channels = ARRAY_SIZE(sun8i_a33_gpadc_channels);
>>>> + indio_dev->channels = sun8i_a33_gpadc_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,
>>>> + &sun4i_gpadc_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(THERMAL_OF))
>>>> + return 0;
>>>> +
>>>> + tzd = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, info,
>>>> + &sun4i_ts_tz_ops);
>>>> + if (IS_ERR(tzd))
>>>> + dev_err(&pdev->dev, "could not register thermal sensor: %ld\n",
>>>> + PTR_ERR(tzd));
>>>> +
>>>> + return PTR_ERR_OR_ZERO(tzd);
>>>> +}
>>>> +
>>>> static int sun4i_gpadc_probe_mfd(struct platform_device *pdev,
>>>> struct iio_dev *indio_dev)
>>>> {
>>>> @@ -462,6 +549,7 @@ static int sun4i_gpadc_probe_mfd(struct platform_device *pdev,
>>>> dev_get_drvdata(pdev->dev.parent);
>>>> int ret;
>>>>
>>>> + info->no_irq = false;
>>>> info->regmap = sun4i_gpadc_dev->regmap;
>>>>
>>>> indio_dev->num_channels = ARRAY_SIZE(sun4i_gpadc_channels);
>>>> @@ -561,7 +649,11 @@ static int sun4i_gpadc_probe(struct platform_device *pdev)
>>>> indio_dev->info = &sun4i_gpadc_iio_info;
>>>> indio_dev->modes = INDIO_DIRECT_MODE;
>>>>
>>>> - ret = sun4i_gpadc_probe_mfd(pdev, indio_dev);
>>>> + if (pdev->dev.of_node)
>>>> + ret = sun4i_gpadc_probe_dt(pdev, indio_dev);
>>>> + else
>>>> + ret = sun4i_gpadc_probe_mfd(pdev, indio_dev);
>>>> +
>>>> if (ret)
>>>> return ret;
>>>>
>>>> @@ -580,7 +672,7 @@ static int sun4i_gpadc_probe(struct platform_device *pdev)
>>>> return 0;
>>>>
>>>> err_map:
>>>> - if (IS_ENABLED(CONFIG_THERMAL_OF))
>>>> + if (!info->no_irq && IS_ENABLED(CONFIG_THERMAL_OF))
>>>> iio_map_array_unregister(indio_dev);
>>>>
>>>> pm_runtime_put(&pdev->dev);
>>>> @@ -592,10 +684,11 @@ static int sun4i_gpadc_probe(struct platform_device *pdev)
>>>> static int sun4i_gpadc_remove(struct platform_device *pdev)
>>>> {
>>>> struct iio_dev *indio_dev = platform_get_drvdata(pdev);
>>>> + struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
>>>>
>>>> pm_runtime_put(&pdev->dev);
>>>> pm_runtime_disable(&pdev->dev);
>>>> - if (IS_ENABLED(CONFIG_THERMAL_OF))
>>>> + if (!info->no_irq && IS_ENABLED(CONFIG_THERMAL_OF))
>>>> iio_map_array_unregister(indio_dev);
>>>>
>>>> return 0;
>>>> @@ -611,6 +704,7 @@ static const struct platform_device_id sun4i_gpadc_id[] = {
>>>> static struct platform_driver sun4i_gpadc_driver = {
>>>> .driver = {
>>>> .name = "sun4i-gpadc-iio",
>>>> + .of_match_table = sun4i_gpadc_of_id,
>>>> .pm = &sun4i_gpadc_pm_ops,
>>>> },
>>>> .id_table = sun4i_gpadc_id,
>>>> diff --git a/include/linux/mfd/sun4i-gpadc.h b/include/linux/mfd/sun4i-gpadc.h
>>>> index 509e736..139872c 100644
>>>> --- a/include/linux/mfd/sun4i-gpadc.h
>>>> +++ b/include/linux/mfd/sun4i-gpadc.h
>>>> @@ -38,6 +38,10 @@
>>>> #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)
>>>> +
>>>> #define SUN4I_GPADC_CTRL2 0x08
>>>>
>>>> #define SUN4I_GPADC_CTRL2_TP_SENSITIVE_ADJUST(x) ((GENMASK(3, 0) & (x)) << 28)
>>>
>>> _______________________________________________
>>> linux-arm-kernel mailing list
>>> linux-arm-kernel@xxxxxxxxxxxxxxxxxxx
>>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>