[PATCH v2 08/11] iio: adc: sun4i-gpadc-iio: add support for A33 thermal sensor
Icenowy Zheng
icenowy at aosc.xyz
Mon Mar 13 22:18:37 PDT 2017
14.03.2017, 05:08, "Jonathan Cameron" <jic23 at kernel.org>:
> 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 at free-electrons.com>
>
> 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.
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 at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
More information about the linux-arm-kernel
mailing list