[PATCH v3 2/3] iio: adc: mt6397-auxadc: add mt6397 PMIC AUXADC driver

AngeloGioacchino Del Regno angelogioacchino.delregno at collabora.com
Mon Sep 21 03:15:34 PDT 2026


On 9/20/26 07:31, Ryan Brue wrote:
> The mt6397 AUXADC is a 10-bit ADC behind the SoC's PMIC wrapper. On boards
> built around this PMIC it is the only way to read the battery: the SoC's
> AUXADC is wired to board thermistors and the charger ICs these boards use
> have no ADC of their own.
> 
> Add a driver exposing the battery voltage and battery temperature
> channels. Only those two are described, so a channel ID in the device tree
> indexes the driver's channel array rather than the PMIC's channel number,
> as mt6323-auxadc does. The ready bit lives in a channel's raw result
> register, but the value comes from the chip's factory-calibrated copy.
> 
> The battery voltage is measured through ISENSE, because a board with a
> switching charger in the power path leaves BATSNS on the charger's system
> rail instead of on the pack. The thermistor only reads correctly with the
> PMIC's battery-detect bias and input buffer enabled, which take 20 ms to
> settle. Both are switched back off afterwards.
> 
> Reads average sixteen conversions in software; the chip's sample
> accumulator makes no measurable difference at any setting, so it is left
> at one sample per conversion.
> 
> Assisted-by: LLM
> Signed-off-by: Ryan Brue <ryanbrue.dev at gmail.com>
> 
> ---
> 
> A new driver was created here, instead of modifying an existing driver such
> as mt6323-auxadc or mt6359-auxadc, for the following reasons:
> 
>   - Both mt6323-auxadc and mt6359-auxadc select channels through a request
>     register (1 bit per channel), while mt6397 uses a 4-bit numeric field
>     CHSEL in CON1 (10:7), and then pulses a START bit (CON1 bit 0).
> 
>   - For mt6323-auxadc, which is the closest I could find to the mt6397
>     (CON0..CON27), it has 13 more registers than the mt6397 (CON0..CON14).
>     It uses CON22 for its request register, and reads the result value
>     from the same register as the ready bit. We don't do that - the mt6397
>     has a factory-calibrated value for each channel at 0x16 higher than the
>     raw value. mt6323 also has a 1800 mV / 15 bit scale / resolution while
>     we have 1200 mV / 10 bits. We also have some per-channel preparation
>     that we have to do before the burst, that the mt6323 doesn't have to
>     do.
> 
>   - For mt6359-auxadc, it has a more generic framework for describing the
>     AUXADC, but it assumes requests are channel-per-bit, and so we would
>     have to basically ignore req_idx, req_mask, rdy_idx, and rdy_mask.
> 
>   - We also have our own software sampling, which the vendor does too
>     (Amazon Fire OS based on Linux 3.18). We'd have to have our own
>     sampling callback to do it.
> ---
>   MAINTAINERS                     |   1 +
>   drivers/iio/adc/Kconfig         |  11 ++
>   drivers/iio/adc/Makefile        |   1 +
>   drivers/iio/adc/mt6397-auxadc.c | 391 ++++++++++++++++++++++++++++++++++++++++
>   4 files changed, 404 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 41d7b3a67415..9b254f98b5d7 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -16717,6 +16717,7 @@ MEDIATEK MT6397 PMIC AUXADC DRIVER
>   M:	Ryan Brue <ryanbrue.dev at gmail.com>
>   L:	linux-iio at vger.kernel.org
>   S:	Maintained
> +F:	drivers/iio/adc/mt6397-auxadc.c
>   F:	include/dt-bindings/iio/adc/mediatek,mt6397-auxadc.h
>   
>   MEDIATEK MT6735 CLOCK & RESET DRIVERS
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 415e519ad4eb..9a1d36ed53cb 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -1233,6 +1233,17 @@ config MEDIATEK_MT6370_ADC
>   	  This driver can also be built as a module. If so, the module
>   	  will be called "mt6370-adc".
>   
> +config MEDIATEK_MT6397_AUXADC
> +	tristate "MediaTek MT6397 PMIC AUXADC driver"
> +	depends on MFD_MT6397
> +	help
> +	  Say yes here to enable support for MediaTek MT6397 PMIC Auxiliary ADC.
> +	  This driver provides the battery voltage and battery temperature
> +	  channels used by the fuel gauge on boards built around this PMIC.
> +
> +	  This driver can also be built as a module. If so, the module will be
> +	  called mt6397-auxadc.
> +
>   config MEDIATEK_MT6577_AUXADC
>   	tristate "MediaTek AUXADC driver"
>   	depends on ARCH_MEDIATEK || COMPILE_TEST
> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> index dcec0abb03b7..13cb4206bdb7 100644
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -105,6 +105,7 @@ obj-$(CONFIG_MEDIATEK_MT6323_AUXADC) += mt6323-auxadc.o
>   obj-$(CONFIG_MEDIATEK_MT6359_AUXADC) += mt6359-auxadc.o
>   obj-$(CONFIG_MEDIATEK_MT6360_ADC) += mt6360-adc.o
>   obj-$(CONFIG_MEDIATEK_MT6370_ADC) += mt6370-adc.o
> +obj-$(CONFIG_MEDIATEK_MT6397_AUXADC) += mt6397-auxadc.o
>   obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
>   obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
>   obj-$(CONFIG_MESON_SARADC) += meson_saradc.o
> diff --git a/drivers/iio/adc/mt6397-auxadc.c b/drivers/iio/adc/mt6397-auxadc.c
> new file mode 100644
> index 000000000000..d860cd3a8922
> --- /dev/null
> +++ b/drivers/iio/adc/mt6397-auxadc.c
> @@ -0,0 +1,391 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * MediaTek MT6397 PMIC AUXADC IIO driver
> + *
> + * Copyright (c) 2026 Ryan Brue <ryanbrue.dev at gmail.com>
> + *
> + * Based on drivers/iio/adc/mt6323-auxadc.c
> + */
> +

..snip..

> +
> +static int mt6397_auxadc_battemp_bias_on(struct mt6397_auxadc *adc)
> +{
> +	struct regmap *map = adc->regmap;
> +	int ret;
> +
> +	ret = regmap_set_bits(map, MT6397_AUXADC_CON0,
> +			      MT6397_AUXADC_CON0_BUF_PWD_ON);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_set_bits(map, MT6397_AUXADC_CON0,
> +			      MT6397_AUXADC_CON0_BUF_PWD_B);
> +	if (ret)
> +		return ret;
> +
> +	return regmap_set_bits(map, MT6397_CHR_CON7,
> +			       MT6397_CHR_CON7_BATON_TDET_EN);
> +}
> +
> +static int mt6397_auxadc_battemp_bias_off(struct mt6397_auxadc *adc)
> +{
> +	struct regmap *map = adc->regmap;
> +	int ret;
> +
> +	ret = regmap_clear_bits(map, MT6397_CHR_CON7, MT6397_CHR_CON7_BATON_TDET_EN);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_clear_bits(map, MT6397_AUXADC_CON0, MT6397_AUXADC_CON0_BUF_PWD_B);
> +	if (ret)
> +		return ret;

If this fails, and the internal buffers are kept enabled, are you sure that
the AUXADC won't lock up?

Should it lock up, I imagine that the best thing that could happen is a power
leakage, but can be as bad as a system lockup.

Should we unconditionally also clear the MT6397_AUXADC_CON0_BUF_PWD_ON bit
even if MT6397_AUXADC_CON0_BUF_PWD_B clearing fails?

> +
> +	return regmap_clear_bits(map, MT6397_AUXADC_CON0,
> +				 MT6397_AUXADC_CON0_BUF_PWD_ON);
> +}
> +
> +static int mt6397_auxadc_isense_enable(struct mt6397_auxadc *adc)
> +{
> +	struct regmap *map = adc->regmap;
> +	int ret;
> +
> +	/*
> +	 * Two of the five independent input enables, not a select field:
> +	 * BATSNS is cleared first so that the two inputs are never enabled
> +	 * onto the battery channel at the same time.
> +	 */
> +	ret = regmap_clear_bits(map, MT6397_CHR_CON16, MT6397_CHR_CON16_ADCIN_VBAT_EN);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_set_bits(map, MT6397_CHR_CON16, MT6397_CHR_CON16_ADCIN_VSEN_EN);
> +	if (ret)
> +		return ret;
> +
> +	return regmap_set_bits(map, MT6397_AUXADC_CON14,
> +			       MT6397_AUXADC_CON14_CH0_NORM_SEL |
> +			       MT6397_AUXADC_CON14_CH0_LBAT_SEL);
> +}
> +
> +static int mt6397_auxadc_isense_disable(struct mt6397_auxadc *adc)
> +{
> +	struct regmap *map = adc->regmap;
> +	int ret;
> +
> +	ret = regmap_clear_bits(map, MT6397_AUXADC_CON14,
> +				MT6397_AUXADC_CON14_CH0_NORM_SEL |
> +				MT6397_AUXADC_CON14_CH0_LBAT_SEL);
> +	if (ret)
> +		return ret;
> +
> +	return regmap_clear_bits(map, MT6397_CHR_CON16,
> +				 MT6397_CHR_CON16_ADCIN_VSEN_EN |
> +				 MT6397_CHR_CON16_ADCIN_VBAT_EN);

Same here, but makes even more sense: if clearing the channel selector
fails, you still want to disable the ADCIN in an effort to avoid power
leakage.

Everything else looks good, so I'm sure that you're getting my R-b on
version 4.

Cheers,
Angelo



More information about the linux-arm-kernel mailing list