]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
iio: adc: aspeed: Reserve battery sensing channel for on-demand use
authorBilly Tsai <billy_tsai@aspeedtech.com>
Fri, 20 Mar 2026 05:46:38 +0000 (13:46 +0800)
committerJonathan Cameron <Jonathan.Cameron@huawei.com>
Sat, 21 Mar 2026 15:52:22 +0000 (15:52 +0000)
For controllers with battery sensing capability (AST2600/AST2700), the
last channel uses a different circuit design optimized for battery
voltage measurement. This channel should not be enabled by default
along with other channels to avoid potential interference and power
efficiency issues.
This ensures optimal power efficiency for normal ADC operations while
maintaining full functionality when battery sensing is needed.

Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
drivers/iio/adc/aspeed_adc.c

index a1a6296d30035f16a59b918e555eff2c5171678d..9b828a3c91da9f76c3046fba1a7f443a112c24cd 100644 (file)
@@ -138,6 +138,13 @@ static inline u32 aspeed_adc_channels_mask(unsigned int num_channels)
 
 static inline unsigned int aspeed_adc_get_active_channels(const struct aspeed_adc_data *data)
 {
+       /*
+        * For controllers with battery sensing capability, the last channel
+        * is reserved for battery sensing and should not be included in
+        * normal channel operations.
+        */
+       if (data->model_data->bat_sense_sup)
+               return data->model_data->num_channels - 1;
        return data->model_data->num_channels;
 }
 
@@ -256,8 +263,8 @@ static int aspeed_adc_compensation(struct iio_dev *indio_dev)
                       ASPEED_ADC_CTRL_CHANNEL_ENABLE(0),
               data->base + ASPEED_REG_ENGINE_CONTROL);
        /*
-        * After enable compensating sensing mode need to wait some time for ADC stable
-        * Experiment result is 1ms.
+        * After enable compensating sensing mode need to wait some time for the
+        * ADC stablize. Experiment result is 1ms.
         */
        fsleep(1000);
 
@@ -305,9 +312,26 @@ static int aspeed_adc_read_raw(struct iio_dev *indio_dev,
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
+               adc_engine_control_reg_val = readl(data->base + ASPEED_REG_ENGINE_CONTROL);
+               /*
+                * For battery sensing capable controllers, we need to enable
+                * the specific channel before reading. This is required because
+                * the battery channel may not be enabled by default.
+                */
+               if (data->model_data->bat_sense_sup &&
+                   chan->channel == ASPEED_ADC_BATTERY_CHANNEL) {
+                       u32 ctrl_reg = adc_engine_control_reg_val & ~ASPEED_ADC_CTRL_CHANNEL;
+
+                       ctrl_reg |= ASPEED_ADC_CTRL_CHANNEL_ENABLE(chan->channel);
+                       writel(ctrl_reg, data->base + ASPEED_REG_ENGINE_CONTROL);
+                       /*
+                        * After enable a new channel need to wait some time for ADC stable
+                        * Experiment result is 1ms.
+                        */
+                       fsleep(1000);
+               }
+
                if (data->battery_sensing && chan->channel == ASPEED_ADC_BATTERY_CHANNEL) {
-                       adc_engine_control_reg_val =
-                               readl(data->base + ASPEED_REG_ENGINE_CONTROL);
                        writel(adc_engine_control_reg_val |
                                       FIELD_PREP(ASPEED_ADC_CH7_MODE,
                                                  ASPEED_ADC_CH7_BAT) |
@@ -321,11 +345,11 @@ static int aspeed_adc_read_raw(struct iio_dev *indio_dev,
                        *val = readw(data->base + chan->address);
                        *val = (*val * data->battery_mode_gain.mult) /
                               data->battery_mode_gain.div;
-                       /* Restore control register value */
-                       writel(adc_engine_control_reg_val,
-                              data->base + ASPEED_REG_ENGINE_CONTROL);
                } else
                        *val = readw(data->base + chan->address);
+               /* Restore control register value */
+               writel(adc_engine_control_reg_val,
+                               data->base + ASPEED_REG_ENGINE_CONTROL);
                return IIO_VAL_INT;
 
        case IIO_CHAN_INFO_OFFSET: