[PATCH 15/16] iio: adc: at91-sama5d2_adc: add runtime pm support

Claudiu.Beznea at microchip.com Claudiu.Beznea at microchip.com
Tue Jun 14 03:40:41 PDT 2022


On 11.06.2022 19:48, Jonathan Cameron wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
> On Thu, 9 Jun 2022 11:32:12 +0300
> Claudiu Beznea <claudiu.beznea at microchip.com> wrote:
> 
>> Add runtime PM support by disabling/enabling ADC's peripheral clock.
>> On simple conversion the ADC's clock is kept enabled just while the
>> conversion is in progress. This includes also temperature conversion.
>> For triggers and touch conversions the ADC clock is kept enabled while
>> the triggers or touch are enabled.
>>
>> Signed-off-by: Claudiu Beznea <claudiu.beznea at microchip.com>
> 
> Various comments inline.
> 
> Thanks,
> 
> Jonathan
> 
>> ---
>>  drivers/iio/adc/at91-sama5d2_adc.c | 201 +++++++++++++++++++++++++----
>>  1 file changed, 173 insertions(+), 28 deletions(-)
>>
>> diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
>> index 1a6788566969..5d9ad51d0920 100644
>> --- a/drivers/iio/adc/at91-sama5d2_adc.c
>> +++ b/drivers/iio/adc/at91-sama5d2_adc.c
>> @@ -28,6 +28,7 @@
>>  #include <linux/iio/triggered_buffer.h>
>>  #include <linux/nvmem-consumer.h>
>>  #include <linux/pinctrl/consumer.h>
>> +#include <linux/pm_runtime.h>
>>  #include <linux/regulator/consumer.h>
>>
>>  #include <dt-bindings/iio/adc/at91-sama5d2_adc.h>
>> @@ -600,6 +601,7 @@ struct at91_adc_state {
>>       struct at91_adc_touch           touch_st;
>>       struct at91_adc_temp            temp_st;
>>       struct iio_dev                  *indio_dev;
>> +     struct device                   *dev;
>>       /* Ensure naturally aligned timestamp */
>>       u16                             buffer[AT91_BUFFER_MAX_HWORDS] __aligned(8);
>>       /*
>> @@ -844,10 +846,16 @@ static int at91_adc_config_emr(struct at91_adc_state *st,
>>                              u32 oversampling_ratio, u32 trackx)
>>  {
>>       /* configure the extended mode register */
>> -     unsigned int emr = at91_adc_readl(st, EMR);
>> +     unsigned int emr;
>>       unsigned int osr_mask = st->soc_info.platform->osr_mask;
>>       unsigned int osr_vals = st->soc_info.platform->osr_vals;
>> +     int ret;
>> +
>> +     ret = pm_runtime_resume_and_get(st->dev);
>> +     if (ret < 0)
>> +             return ret;
> 
> In this particular case, it might be cleaner to introduce a wrapper
> function that deals with the power management and then calls this one.
> Gets rid of the ugly gotos out of the switch statement.

Hm.. I'll see how I can do it.

> 
>>
>> +     emr = at91_adc_readl(st, EMR);
>>       /* select oversampling per single trigger event */
>>       emr |= AT91_SAMA5D2_EMR_ASTE(1);
>>
>> @@ -857,32 +865,42 @@ static int at91_adc_config_emr(struct at91_adc_state *st,
>>       /* select oversampling ratio from configuration */
>>       switch (oversampling_ratio) {
>>       case AT91_OSR_1SAMPLES:
>> -             if (!(osr_vals & BIT(AT91_SAMA5D2_EMR_OSR_1SAMPLES)))
>> -                     return -EINVAL;
>> +             if (!(osr_vals & BIT(AT91_SAMA5D2_EMR_OSR_1SAMPLES))) {
>> +                     ret = -EINVAL;
>> +                     goto pm_runtime_put;
>> +             }
>>               emr |= AT91_SAMA5D2_EMR_OSR(AT91_SAMA5D2_EMR_OSR_1SAMPLES,
>>                                           osr_mask);
>>               break;
>>       case AT91_OSR_4SAMPLES:
>> -             if (!(osr_vals & BIT(AT91_SAMA5D2_EMR_OSR_4SAMPLES)))
>> -                     return -EINVAL;
>> +             if (!(osr_vals & BIT(AT91_SAMA5D2_EMR_OSR_4SAMPLES))) {
>> +                     ret = -EINVAL;
>> +                     goto pm_runtime_put;
>> +             }
>>               emr |= AT91_SAMA5D2_EMR_OSR(AT91_SAMA5D2_EMR_OSR_4SAMPLES,
>>                                           osr_mask);
>>               break;
>>       case AT91_OSR_16SAMPLES:
>> -             if (!(osr_vals & BIT(AT91_SAMA5D2_EMR_OSR_16SAMPLES)))
>> -                     return -EINVAL;
>> +             if (!(osr_vals & BIT(AT91_SAMA5D2_EMR_OSR_16SAMPLES))) {
>> +                     ret = -EINVAL;
>> +                     goto pm_runtime_put;
>> +             }
>>               emr |= AT91_SAMA5D2_EMR_OSR(AT91_SAMA5D2_EMR_OSR_16SAMPLES,
>>                                           osr_mask);
>>               break;
>>       case AT91_OSR_64SAMPLES:
>> -             if (!(osr_vals & BIT(AT91_SAMA5D2_EMR_OSR_64SAMPLES)))
>> -                     return -EINVAL;
>> +             if (!(osr_vals & BIT(AT91_SAMA5D2_EMR_OSR_64SAMPLES))) {
>> +                     ret = -EINVAL;
>> +                     goto pm_runtime_put;
>> +             }
>>               emr |= AT91_SAMA5D2_EMR_OSR(AT91_SAMA5D2_EMR_OSR_64SAMPLES,
>>                                           osr_mask);
>>               break;
>>       case AT91_OSR_256SAMPLES:
>> -             if (!(osr_vals & BIT(AT91_SAMA5D2_EMR_OSR_256SAMPLES)))
>> -                     return -EINVAL;
>> +             if (!(osr_vals & BIT(AT91_SAMA5D2_EMR_OSR_256SAMPLES))) {
>> +                     ret = -EINVAL;
>> +                     goto pm_runtime_put;
>> +             }
>>               emr |= AT91_SAMA5D2_EMR_OSR(AT91_SAMA5D2_EMR_OSR_256SAMPLES,
>>                                           osr_mask);
>>               break;
>> @@ -894,7 +912,10 @@ static int at91_adc_config_emr(struct at91_adc_state *st,
>>
>>       st->oversampling_ratio = oversampling_ratio;
>>
>> -     return 0;
>> +pm_runtime_put:
>> +     pm_runtime_mark_last_busy(st->dev);
>> +     pm_runtime_put_autosuspend(st->dev);
>> +     return ret;
>>  }
>>
>>  static int at91_adc_adjust_val_osr(struct at91_adc_state *st, int *val)
>> @@ -947,15 +968,22 @@ static void at91_adc_adjust_val_osr_array(struct at91_adc_state *st, void *buf,
>>  static int at91_adc_configure_touch(struct at91_adc_state *st, bool state)
>>  {
>>       u32 clk_khz = st->current_sample_rate / 1000;
>> -     int i = 0;
>> +     int i = 0, ret;
>>       u16 pendbc;
>>       u32 tsmr, acr;
>>
>> -     if (!state) {
>> +     if (state) {
>> +             ret = pm_runtime_resume_and_get(st->dev);
>> +             if (ret < 0)
>> +                     return ret;
>> +     } else {
>>               /* disabling touch IRQs and setting mode to no touch enabled */
>>               at91_adc_writel(st, IDR,
>>                               AT91_SAMA5D2_IER_PEN | AT91_SAMA5D2_IER_NOPEN);
>>               at91_adc_writel(st, TSMR, 0);
>> +
>> +             pm_runtime_mark_last_busy(st->dev);
>> +             pm_runtime_put_autosuspend(st->dev);
>>               return 0;
>>       }
>>       /*
>> @@ -1100,8 +1128,16 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
>>  {
>>       struct iio_dev *indio = iio_trigger_get_drvdata(trig);
>>       struct at91_adc_state *st = iio_priv(indio);
>> -     u32 status = at91_adc_readl(st, TRGR);
>> +     u32 status;
>> +     int ret;
>> +
>> +     if (state) {
>> +             ret = pm_runtime_resume_and_get(st->dev);
>> +             if (ret < 0)
>> +                     return ret;
>> +     }
>>
>> +     status = at91_adc_readl(st, TRGR);
>>       /* clear TRGMOD */
>>       status &= ~AT91_SAMA5D2_TRGR_TRGMOD_MASK;
>>
>> @@ -1111,6 +1147,11 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
>>       /* set/unset hw trigger */
>>       at91_adc_writel(st, TRGR, status);
>>
>> +     if (!state) {
>> +             pm_runtime_mark_last_busy(st->dev);
>> +             pm_runtime_put_autosuspend(st->dev);
>> +     }
>> +
>>       return 0;
>>  }
>>
>> @@ -1268,11 +1309,15 @@ static int at91_adc_buffer_prepare(struct iio_dev *indio_dev)
>>       if (!(iio_device_get_current_mode(indio_dev) & INDIO_ALL_TRIGGERED_MODES))
>>               return -EINVAL;
>>
>> +     ret = pm_runtime_resume_and_get(st->dev);
> 
> This seems unusual.  I'd normally expect to see runtime pm left on whenever
> a buffer is in use, but in this case you seem to let it autosuspend.
> 
> That 'might' be fine as you might hit it often enough that it stays up whilst
> doing DMA but it certainly seems odd and less than efficient.
> Or possibly the use of the trigger is enough to keep it up.

This is here because at91_adc_buffer_prepare() is called though
.hwfifo_set_watermark which is called in iio_enable_buffers() before
iio_trigger_attach_poll_func() which calls in turn
at91_adc_configure_trigger() that turns on the power for the whole duration
the buffers are enabled.

It is necessary to have runtime resume here to be able to do proper
register settings.

> 
>> +     if (ret < 0)
>> +             return ret;
>> +
>>       /* we continue with the triggered buffer */
>>       ret = at91_adc_dma_start(indio_dev);
>>       if (ret) {
>>               dev_err(&indio_dev->dev, "buffer prepare failed\n");
>> -             return ret;
>> +             goto pm_runtime_put;
>>       }
>>
>>       for_each_set_bit(bit, indio_dev->active_scan_mask,
>> @@ -1295,12 +1340,16 @@ static int at91_adc_buffer_prepare(struct iio_dev *indio_dev)
>>       if (at91_adc_buffer_check_use_irq(indio_dev, st))
>>               at91_adc_writel(st, IER, AT91_SAMA5D2_IER_DRDY);
>>
>> -     return 0;
>> +pm_runtime_put:
>> +     pm_runtime_mark_last_busy(st->dev);
>> +     pm_runtime_put_autosuspend(st->dev);
>> +     return ret;
>>  }
>>
>>  static int at91_adc_buffer_postdisable(struct iio_dev *indio_dev)
>>  {
>>       struct at91_adc_state *st = iio_priv(indio_dev);
>> +     int ret;
>>       u8 bit;
>>
>>       /* check if we are disabling triggered buffer or the touchscreen */
>> @@ -1311,6 +1360,10 @@ static int at91_adc_buffer_postdisable(struct iio_dev *indio_dev)
>>       if (!(iio_device_get_current_mode(indio_dev) & INDIO_ALL_TRIGGERED_MODES))
>>               return -EINVAL;
>>
>> +     ret = pm_runtime_resume_and_get(st->dev);
>> +     if (ret < 0)
>> +             return ret;
>> +
>>       /*
>>        * For each enable channel we must disable it in hardware.
>>        * In the case of DMA, we must read the last converted value
>> @@ -1346,6 +1399,9 @@ static int at91_adc_buffer_postdisable(struct iio_dev *indio_dev)
>>       if (st->dma_st.dma_chan)
>>               dmaengine_terminate_sync(st->dma_st.dma_chan);
>>
>> +     pm_runtime_mark_last_busy(st->dev);
>> +     pm_runtime_put_autosuspend(st->dev);
>> +
>>       return 0;
>>  }
>>
>> @@ -1534,12 +1590,17 @@ static void at91_adc_setup_samp_freq(struct iio_dev *indio_dev, unsigned freq,
>>  {
>>       struct at91_adc_state *st = iio_priv(indio_dev);
>>       unsigned f_per, prescal, startup, mr;
>> +     int ret;
>>
>>       f_per = clk_get_rate(st->per_clk);
>>       prescal = (f_per / (2 * freq)) - 1;
>>
>>       startup = at91_adc_startup_time(startup_time, freq / 1000);
>>
>> +     ret = pm_runtime_resume_and_get(st->dev);
>> +     if (ret < 0)
>> +             return;
>> +
>>       mr = at91_adc_readl(st, MR);
>>       mr &= ~(AT91_SAMA5D2_MR_STARTUP_MASK | AT91_SAMA5D2_MR_PRESCAL_MASK);
>>       mr |= AT91_SAMA5D2_MR_STARTUP(startup);
>> @@ -1547,6 +1608,9 @@ static void at91_adc_setup_samp_freq(struct iio_dev *indio_dev, unsigned freq,
>>       mr |= AT91_SAMA5D2_MR_TRACKTIM(tracktim);
>>       at91_adc_writel(st, MR, mr);
>>
>> +     pm_runtime_mark_last_busy(st->dev);
>> +     pm_runtime_put_autosuspend(st->dev);
>> +
>>       dev_dbg(&indio_dev->dev, "freq: %u, startup: %u, prescal: %u, tracktim=%u\n",
>>               freq, startup, prescal, tracktim);
>>       st->current_sample_rate = freq;
>> @@ -1684,6 +1748,10 @@ static int at91_adc_read_info_raw(struct iio_dev *indio_dev,
>>       u16 tmp_val;
>>       int ret;
>>
>> +     ret = pm_runtime_resume_and_get(st->dev);
>> +     if (ret < 0)
>> +             return ret;
>> +
>>       /*
>>        * Keep in mind that we cannot use software trigger or touchscreen
>>        * if external trigger is enabled
>> @@ -1695,7 +1763,7 @@ static int at91_adc_read_info_raw(struct iio_dev *indio_dev,
>>
>>       ret = iio_device_claim_direct_mode(indio_dev);
>>       if (ret)
>> -             return ret;
>> +             goto pm_runtime_put;
>>       if (lock)
>>               mutex_lock(&st->lock);
>>
>> @@ -1707,7 +1775,7 @@ static int at91_adc_read_info_raw(struct iio_dev *indio_dev,
>>                       mutex_unlock(&st->lock);
>>               iio_device_release_direct_mode(indio_dev);
>>
>> -             return ret;
>> +             goto pm_runtime_put;
>>       }
>>
>>       /* in this case we have a voltage or temperature channel */
>> @@ -1753,6 +1821,11 @@ static int at91_adc_read_info_raw(struct iio_dev *indio_dev,
>>               mutex_unlock(&st->lock);
>>
>>       iio_device_release_direct_mode(indio_dev);
>> +
>> +pm_runtime_put:
>> +     pm_runtime_mark_last_busy(st->dev);
>> +     pm_runtime_put_autosuspend(st->dev);
>> +
>>       return ret;
>>  }
>>
>> @@ -1804,6 +1877,10 @@ static int at91_adc_read_temp(struct iio_dev *indio_dev,
>>       if (iio_buffer_enabled(indio_dev))
>>               return -EBUSY;
>>
>> +     ret = pm_runtime_resume_and_get(st->dev);
>> +     if (ret < 0)
>> +             return ret;
>> +
>>       mutex_lock(&st->lock);
>>
>>       at91_adc_temp_sensor_configure(st, true);
>> @@ -1825,6 +1902,10 @@ static int at91_adc_read_temp(struct iio_dev *indio_dev,
>>       /* Revert previous settings. */
>>       at91_adc_temp_sensor_configure(st, false);
>>       mutex_unlock(&st->lock);
>> +
>> +     pm_runtime_mark_last_busy(st->dev);
>> +     pm_runtime_put_autosuspend(st->dev);
>> +
>>       if (ret < 0)
>>               return ret;
>>
>> @@ -2363,13 +2444,19 @@ static int at91_adc_probe(struct platform_device *pdev)
>>
>>       at91_adc_temp_sensor_init(st, &pdev->dev);
>>
>> -     at91_adc_hw_init(indio_dev);
>> -
>>       platform_set_drvdata(pdev, indio_dev);
>> +     st->dev = &pdev->dev;
>> +     pm_runtime_set_autosuspend_delay(st->dev, 500);
>> +     pm_runtime_use_autosuspend(st->dev);
>> +     pm_runtime_set_active(st->dev);
>> +     pm_runtime_enable(st->dev);
>> +     pm_runtime_get_noresume(st->dev);
>> +
>> +     at91_adc_hw_init(indio_dev);
>>
>>       ret = at91_adc_buffer_and_trigger_init(&pdev->dev, indio_dev);
>>       if (ret < 0)
>> -             goto per_clk_disable_unprepare;
>> +             goto err_pm_disable;
>>
>>       if (dma_coerce_mask_and_coherent(&indio_dev->dev, DMA_BIT_MASK(32)))
>>               dev_info(&pdev->dev, "cannot set DMA mask to 32-bit\n");
>> @@ -2385,10 +2472,18 @@ static int at91_adc_probe(struct platform_device *pdev)
>>       dev_info(&pdev->dev, "version: %x\n",
>>                readl_relaxed(st->base + st->soc_info.platform->layout->VERSION));
>>
>> +     pm_runtime_mark_last_busy(st->dev);
>> +     pm_runtime_put_autosuspend(st->dev);
>> +
>>       return 0;
>>
>>  dma_disable:
>>       at91_adc_dma_disable(st);
>> +err_pm_disable:
>> +     pm_runtime_put_noidle(st->dev);
>> +     pm_runtime_disable(st->dev);
>> +     pm_runtime_set_suspended(st->dev);
>> +     pm_runtime_dont_use_autosuspend(st->dev);
>>  per_clk_disable_unprepare:
>>       clk_disable_unprepare(st->per_clk);
>>  vref_disable:
>> @@ -2402,11 +2497,18 @@ static int at91_adc_remove(struct platform_device *pdev)
>>  {
>>       struct iio_dev *indio_dev = platform_get_drvdata(pdev);
>>       struct at91_adc_state *st = iio_priv(indio_dev);
>> +     int ret;
>> +
>> +     ret = pm_runtime_resume_and_get(st->dev);
>> +     if (ret < 0)
>> +             return ret;
> 
> There isn't much useful that can be done with a return of error from
> a remove() function. Uwe Klein-Konig is busy removing all these returns
> (and eventually changing the prototypes to return void), so don't introduce a new one
> or Uwe will be grumpy :)

Ah, right. Thanks for pointing it.

> 
>>
>>       iio_device_unregister(indio_dev);
>>
>>       at91_adc_dma_disable(st);
>>
>> +     pm_runtime_disable(st->dev);
>> +     pm_runtime_put_noidle(st->dev);
>>       clk_disable_unprepare(st->per_clk);
>>
>>       regulator_disable(st->vref);
>> @@ -2419,6 +2521,11 @@ static __maybe_unused int at91_adc_suspend(struct device *dev)
>>  {
>>       struct iio_dev *indio_dev = dev_get_drvdata(dev);
>>       struct at91_adc_state *st = iio_priv(indio_dev);
>> +     int ret;
>> +
>> +     ret = pm_runtime_resume_and_get(st->dev);
>> +     if (ret < 0)
>> +             return ret;
>>
>>       /*
>>        * Do a sofware reset of the ADC before we go to suspend.
>> @@ -2428,7 +2535,8 @@ static __maybe_unused int at91_adc_suspend(struct device *dev)
>>        */
>>       at91_adc_writel(st, CR, AT91_SAMA5D2_CR_SWRST);
>>
>> -     clk_disable_unprepare(st->per_clk);
>> +     pm_runtime_force_suspend(st->dev);
> 
> This confuses me a bit because we know we are already awake (because of
> the pm_runtime_resume_and_get() so we will definitely suspend here and
> I'm fairly sure that means we definitely resume in the _resume()
> below.  Basically our usage counters are I think off by one. If you
> could verify that it doesn't turn back on if we don't have the buffered
> enabled and were previously in runtime suspend state that would
> prove me wrong (which is more than possible - this stuff always gives
> me a headache)

I remember I checked this with continuous suspend/resume having buffers
disabled and no conversion in progress and all went good. I'll double check
it again to be sure all good.

> 
> 
>> +     clk_unprepare(st->per_clk);
>>       regulator_disable(st->vref);
>>       regulator_disable(st->reg);
>>
>> @@ -2453,25 +2561,40 @@ static __maybe_unused int at91_adc_resume(struct device *dev)
>>       if (ret)
>>               goto reg_disable_resume;
>>
>> -     ret = clk_prepare_enable(st->per_clk);
>> +     ret = clk_prepare(st->per_clk);
>>       if (ret)
>>               goto vref_disable_resume;
>>
>> +     ret = pm_runtime_force_resume(st->dev);
>> +     if (ret < 0)
>> +             goto clk_unprepare_resume;
>> +
>>       at91_adc_hw_init(indio_dev);
>>
>>       /* reconfiguring trigger hardware state */
>>       if (!iio_buffer_enabled(indio_dev))
> (see below)
>         flip this check so the next block is indented givne
>         exit path will be shared (thus removing the goto).
>         if (iio_buffer_enabled(indio_dev)) {
>                 /* check ...

ok

> 
> 
>> -             return 0;
>> +             goto pm_runtime_put;
>>
>>       /* check if we are enabling triggered buffer or the touchscreen */
>>       if (at91_adc_current_chan_is_touch(indio_dev))
>> -             return at91_adc_configure_touch(st, true);
>> +             ret = at91_adc_configure_touch(st, true);
>>       else
>> -             return at91_adc_configure_trigger(st->trig, true);
>> +             ret = at91_adc_configure_trigger(st->trig, true);
>> +
> (see below)
> 
>                 if (ret < 0)
>                         goto pm_runtime_put;
>         }
> 
>         pm_runtime_mark_last_busy(st->dev);
>         pm_runtime_put_autosuspend(st->dev);
>         return 0;
> 
>> +pm_runtime_put:
> 
> I think this would be easier to follow if you break this up into the
> different cases.

I'll check it.

> 
> pm_runtime_put:
>         pm_runtime_mark_last_busy(st->dev);
>         pm_runtime_put_sync_suspend(st->dev);
> clk_unprepare_resume:
>         ...
> 
>> +     pm_runtime_mark_last_busy(st->dev);
>> +     if (ret < 0) {
>> +             pm_runtime_put_sync_suspend(st->dev);
>> +             goto clk_unprepare_resume;
>> +     } else {
>> +             pm_runtime_put_autosuspend(st->dev);
>> +     }
>>
>>       /* not needed but more explicit */
>>       return 0;
>>
>> +clk_unprepare_resume:
>> +     clk_unprepare(st->per_clk);
>>  vref_disable_resume:
>>       regulator_disable(st->vref);
>>  reg_disable_resume:
>> @@ -2481,7 +2604,29 @@ static __maybe_unused int at91_adc_resume(struct device *dev)
>>       return ret;
>>  }
>>
>> -static SIMPLE_DEV_PM_OPS(at91_adc_pm_ops, at91_adc_suspend, at91_adc_resume);
>> +static int __maybe_unused at91_adc_runtime_suspend(struct device *dev)
> 
> See below, but these no longer need to be marked __maybe_unused.
> 
>> +{
>> +     struct iio_dev *indio_dev = dev_get_drvdata(dev);
>> +     struct at91_adc_state *st = iio_priv(indio_dev);
>> +
>> +     clk_disable(st->per_clk);
>> +
>> +     return 0;
>> +}
>> +
>> +static int __maybe_unused at91_adc_runtime_resume(struct device *dev)
>> +{
>> +     struct iio_dev *indio_dev = dev_get_drvdata(dev);
>> +     struct at91_adc_state *st = iio_priv(indio_dev);
>> +
>> +     return clk_enable(st->per_clk);
>> +}
>> +
>> +static const struct dev_pm_ops __maybe_unused at91_adc_pm_ops = {
>> +     SET_SYSTEM_SLEEP_PM_OPS(at91_adc_suspend, at91_adc_resume)
>> +     SET_RUNTIME_PM_OPS(at91_adc_runtime_suspend, at91_adc_runtime_resume,
>> +                        NULL)
> Use the new SYSTEM_SLEEP_PM_OPS() and RUNTIME_PM_OPS() + drop the __maybe_unused.
> 
> Squash the next patch into here so that the pm_ptr() magic will allow the compiler
> to clean these out if not used.
> 
> Paul Cercueil recently did some work to simplify all this stuff.
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/include/linux/pm.h?id=0ae101fdd3297b7165755340e05386f1e1379709

Nice, thanks for poining it.

> 
>> +};
>>
>>  static const struct of_device_id at91_adc_dt_match[] = {
>>       {
> 



More information about the linux-arm-kernel mailing list