root/drivers/iio/adc/mt6359-auxadc.c
// SPDX-License-Identifier: GPL-2.0-only
/*
 * MediaTek MT6359 PMIC AUXADC IIO driver
 *
 * Copyright (c) 2021 MediaTek Inc.
 * Copyright (c) 2024 Collabora Ltd
 * Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
 */

#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/cleanup.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/types.h>

#include <linux/iio/iio.h>

#include <linux/mfd/mt6397/core.h>

#include <dt-bindings/iio/adc/mediatek,mt6357-auxadc.h>
#include <dt-bindings/iio/adc/mediatek,mt6358-auxadc.h>
#include <dt-bindings/iio/adc/mediatek,mt6359-auxadc.h>
#include <dt-bindings/iio/adc/mediatek,mt6363-auxadc.h>

#define AUXADC_AVG_TIME_US              10
#define AUXADC_POLL_DELAY_US            100
#define AUXADC_TIMEOUT_US               32000
#define IMP_STOP_DELAY_US               150
#define IMP_POLL_DELAY_US               1000

/* For PMIC_RG_RESET_VAL and MT6358_IMP0_CLEAR, the bits specific purpose is unknown. */
#define PMIC_RG_RESET_VAL               (BIT(0) | BIT(3))
#define PMIC_AUXADC_RDY_BIT             BIT(15)
#define MT6357_IMP_ADC_NUM              30
#define MT6358_IMP_ADC_NUM              28

#define MT6358_DCM_CK_SW_EN             GENMASK(1, 0)
#define MT6358_IMP0_CLEAR               (BIT(14) | BIT(7))
#define MT6358_IMP0_IRQ_RDY             BIT(8)
#define MT6358_IMP1_AUTOREPEAT_EN       BIT(15)

#define MT6359_IMP0_CONV_EN             BIT(0)
#define MT6359_IMP1_IRQ_RDY             BIT(15)

#define MT6363_EXT_CHAN_MASK            GENMASK(2, 0)
#define MT6363_EXT_PURES_MASK           GENMASK(4, 3)
  #define MT6363_PULLUP_RES_100K        0
  #define MT6363_PULLUP_RES_30K         1
  #define MT6363_PULLUP_RES_OPEN        3

enum mtk_pmic_auxadc_regs {
        PMIC_AUXADC_ADC0,
        PMIC_AUXADC_DCM_CON,
        PMIC_AUXADC_IMP0,
        PMIC_AUXADC_IMP1,
        PMIC_AUXADC_IMP3,
        PMIC_AUXADC_RQST0,
        PMIC_AUXADC_RQST1,
        PMIC_AUXADC_RQST3,
        PMIC_AUXADC_SDMADC_CON0,
        PMIC_HK_TOP_WKEY,
        PMIC_HK_TOP_RST_CON0,
        PMIC_FGADC_R_CON0,
        PMIC_AUXADC_REGS_MAX
};

enum mtk_pmic_auxadc_channels {
        PMIC_AUXADC_CHAN_BATADC,
        PMIC_AUXADC_CHAN_ISENSE,
        PMIC_AUXADC_CHAN_VCDT,
        PMIC_AUXADC_CHAN_BAT_TEMP,
        PMIC_AUXADC_CHAN_BATID,
        PMIC_AUXADC_CHAN_CHIP_TEMP,
        PMIC_AUXADC_CHAN_VCORE_TEMP,
        PMIC_AUXADC_CHAN_VPROC_TEMP,
        PMIC_AUXADC_CHAN_VGPU_TEMP,
        PMIC_AUXADC_CHAN_ACCDET,
        PMIC_AUXADC_CHAN_VDCXO,
        PMIC_AUXADC_CHAN_TSX_TEMP,
        PMIC_AUXADC_CHAN_HPOFS_CAL,
        PMIC_AUXADC_CHAN_DCXO_TEMP,
        PMIC_AUXADC_CHAN_VTREF,
        PMIC_AUXADC_CHAN_VBIF,
        PMIC_AUXADC_CHAN_VSYSSNS,
        PMIC_AUXADC_CHAN_VIN1,
        PMIC_AUXADC_CHAN_VIN2,
        PMIC_AUXADC_CHAN_VIN3,
        PMIC_AUXADC_CHAN_VIN4,
        PMIC_AUXADC_CHAN_VIN5,
        PMIC_AUXADC_CHAN_VIN6,
        PMIC_AUXADC_CHAN_VIN7,
        PMIC_AUXADC_CHAN_IBAT,
        PMIC_AUXADC_CHAN_VBAT,
        PMIC_AUXADC_CHAN_MAX
};

/**
 * struct mt6359_auxadc - Main driver structure
 * @dev:           Device pointer
 * @regmap:        Regmap from SoC PMIC Wrapper
 * @chip_info:     PMIC specific chip info
 * @lock:          Mutex to serialize AUXADC reading vs configuration
 * @timed_out:     Signals whether the last read timed out
 */
struct mt6359_auxadc {
        struct device *dev;
        struct regmap *regmap;
        const struct mtk_pmic_auxadc_info *chip_info;
        struct mutex lock;
        bool timed_out;
};

/**
 * struct mtk_pmic_auxadc_chan - PMIC AUXADC channel data
 * @req_idx:       Request register number
 * @req_mask:      Bitmask to activate a channel
 * @rdy_idx:       Readiness register number
 * @rdy_mask:      Bitmask to determine channel readiness
 * @ext_sel_idx:   PMIC GPIO channel register number
 * @ext_sel_ch:    PMIC GPIO number
 * @ext_sel_pu:    PMIC GPIO channel pullup resistor selector
 * @num_samples:   Number of AUXADC samples for averaging
 * @r_ratio:       Resistance ratio fractional
 */
struct mtk_pmic_auxadc_chan {
        u8 req_idx;
        u16 req_mask;
        u8 rdy_idx;
        u16 rdy_mask;
        s8 ext_sel_idx;
        u8 ext_sel_ch;
        u8 ext_sel_pu;
        u16 num_samples;
        struct u8_fract r_ratio;
};

/**
 * struct mtk_pmic_auxadc_info - PMIC specific chip info
 * @model_name:     PMIC model name
 * @channels:       IIO specification of ADC channels
 * @num_channels:   Number of ADC channels
 * @desc:           PMIC AUXADC channel data
 * @regs:           List of PMIC specific registers
 * @sec_unlock_key: Security unlock key for HK_TOP writes
 * @vref_mV:        AUXADC Reference Voltage (VREF) in millivolts
 * @imp_adc_num:    ADC channel for battery impedance readings
 * @is_spmi:        Defines whether this PMIC communicates over SPMI
 * @no_reset:       If true, this PMIC does not support ADC reset
 * @read_imp:       Callback to read impedance channels
 */
struct mtk_pmic_auxadc_info {
        const char *model_name;
        const struct iio_chan_spec *channels;
        u8 num_channels;
        const struct mtk_pmic_auxadc_chan *desc;
        const u16 *regs;
        u16 sec_unlock_key;
        u32 vref_mV;
        u8 imp_adc_num;
        bool is_spmi;
        bool no_reset;
        int (*read_imp)(struct mt6359_auxadc *adc_dev,
                        const struct iio_chan_spec *chan, int *vbat, int *ibat);
};

#define MTK_PMIC_ADC_EXT_CHAN(_ch_idx, _req_idx, _req_bit, _rdy_idx, _rdy_bit,  \
                              _ext_sel_idx, _ext_sel_ch, _ext_sel_pu,           \
                              _samples, _rnum, _rdiv)                           \
        [PMIC_AUXADC_CHAN_##_ch_idx] = {                                        \
                .req_idx = _req_idx,                                            \
                .req_mask = BIT(_req_bit),                                      \
                .rdy_idx = _rdy_idx,                                            \
                .rdy_mask = BIT(_rdy_bit),                                      \
                .ext_sel_idx = _ext_sel_idx,                                    \
                .ext_sel_ch = _ext_sel_ch,                                      \
                .ext_sel_pu = _ext_sel_pu,                                      \
                .num_samples = _samples,                                        \
                .r_ratio = { _rnum, _rdiv }                                     \
        }

#define MTK_PMIC_ADC_CHAN(_ch_idx, _req_idx, _req_bit, _rdy_idx, _rdy_bit,      \
                          _samples, _rnum, _rdiv)                               \
        MTK_PMIC_ADC_EXT_CHAN(_ch_idx, _req_idx, _req_bit, _rdy_idx, _rdy_bit,  \
                              -1, 0, 0, _samples, _rnum, _rdiv)

#define MTK_PMIC_IIO_CHAN(_model, _name, _ch_idx, _adc_idx, _nbits, _ch_type)   \
{                                                                               \
        .type = _ch_type,                                                       \
        .channel = _model##_AUXADC_##_ch_idx,                                   \
        .address = _adc_idx,                                                    \
        .scan_index = PMIC_AUXADC_CHAN_##_ch_idx,                               \
        .datasheet_name = __stringify(_name),                                   \
        .scan_type =  {                                                         \
                .sign = 'u',                                                    \
                .realbits = _nbits,                                             \
                .storagebits = 16,                                              \
                .endianness = IIO_CPU                                           \
        },                                                                      \
        .indexed = 1,                                                           \
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) \
}

static const struct iio_chan_spec mt6357_auxadc_channels[] = {
        MTK_PMIC_IIO_CHAN(MT6357, bat_adc, BATADC, 0, 15, IIO_RESISTANCE),
        MTK_PMIC_IIO_CHAN(MT6357, isense, ISENSE, 1, 12, IIO_CURRENT),
        MTK_PMIC_IIO_CHAN(MT6357, cdt_v, VCDT, 2, 12, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6357, batt_temp, BAT_TEMP, 3, 12, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6357, chip_temp, CHIP_TEMP, 4, 12, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6357, acc_det, ACCDET, 5, 12, IIO_RESISTANCE),
        MTK_PMIC_IIO_CHAN(MT6357, dcxo_v, VDCXO, 6, 12, IIO_VOLTAGE),
        MTK_PMIC_IIO_CHAN(MT6357, tsx_temp, TSX_TEMP, 7, 15, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6357, hp_ofs_cal, HPOFS_CAL, 9, 15, IIO_RESISTANCE),
        MTK_PMIC_IIO_CHAN(MT6357, dcxo_temp, DCXO_TEMP, 36, 15, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6357, vcore_temp, VCORE_TEMP, 40, 12, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6357, vproc_temp, VPROC_TEMP, 41, 12, IIO_TEMP),

        /* Battery impedance channels */
        MTK_PMIC_IIO_CHAN(MT6357, batt_v, VBAT, 0, 15, IIO_VOLTAGE),
};

static const struct mtk_pmic_auxadc_chan mt6357_auxadc_ch_desc[] = {
        MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, PMIC_AUXADC_IMP0, 8, 128, 3, 1),
        MTK_PMIC_ADC_CHAN(ISENSE, PMIC_AUXADC_RQST0, 0, PMIC_AUXADC_IMP0, 8, 128, 3, 1),
        MTK_PMIC_ADC_CHAN(VCDT, PMIC_AUXADC_RQST0, 0, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
        MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
        MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
        MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
        MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, PMIC_AUXADC_IMP0, 8, 128, 1, 1),
        MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, PMIC_AUXADC_IMP0, 8, 256, 1, 1),
        MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, PMIC_AUXADC_IMP0, 8, 16, 1, 1),
        MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
        MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 5, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
        MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 6, PMIC_AUXADC_IMP0, 8, 8, 1, 1),

        /* Battery impedance channels */
        MTK_PMIC_ADC_CHAN(VBAT, 0, 0, PMIC_AUXADC_IMP0, 8, 128, 3, 1),
};

static const u16 mt6357_auxadc_regs[] = {
        [PMIC_HK_TOP_RST_CON0]  = 0x0f90,
        [PMIC_AUXADC_DCM_CON]   = 0x122e,
        [PMIC_AUXADC_ADC0]      = 0x1088,
        [PMIC_AUXADC_IMP0]      = 0x119c,
        [PMIC_AUXADC_IMP1]      = 0x119e,
        [PMIC_AUXADC_RQST0]     = 0x110e,
        [PMIC_AUXADC_RQST1]     = 0x1114,
};

static const struct iio_chan_spec mt6358_auxadc_channels[] = {
        MTK_PMIC_IIO_CHAN(MT6358, bat_adc, BATADC, 0, 15, IIO_RESISTANCE),
        MTK_PMIC_IIO_CHAN(MT6358, cdt_v, VCDT, 2, 12, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6358, batt_temp, BAT_TEMP, 3, 12, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6358, chip_temp, CHIP_TEMP, 4, 12, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6358, acc_det, ACCDET, 5, 12, IIO_RESISTANCE),
        MTK_PMIC_IIO_CHAN(MT6358, dcxo_v, VDCXO, 6, 12, IIO_VOLTAGE),
        MTK_PMIC_IIO_CHAN(MT6358, tsx_temp, TSX_TEMP, 7, 15, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6358, hp_ofs_cal, HPOFS_CAL, 9, 15, IIO_RESISTANCE),
        MTK_PMIC_IIO_CHAN(MT6358, dcxo_temp, DCXO_TEMP, 10, 15, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6358, bif_v, VBIF, 11, 12, IIO_VOLTAGE),
        MTK_PMIC_IIO_CHAN(MT6358, vcore_temp, VCORE_TEMP, 38, 12, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6358, vproc_temp, VPROC_TEMP, 39, 12, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6358, vgpu_temp, VGPU_TEMP, 40, 12, IIO_TEMP),

        /* Battery impedance channels */
        MTK_PMIC_IIO_CHAN(MT6358, batt_v, VBAT, 0, 15, IIO_VOLTAGE),
};

static const struct mtk_pmic_auxadc_chan mt6358_auxadc_ch_desc[] = {
        MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, PMIC_AUXADC_IMP0, 8, 128, 3, 1),
        MTK_PMIC_ADC_CHAN(VCDT, PMIC_AUXADC_RQST0, 0, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
        MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, PMIC_AUXADC_IMP0, 8, 8, 2, 1),
        MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
        MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
        MTK_PMIC_ADC_CHAN(VDCXO, PMIC_AUXADC_RQST0, 6, PMIC_AUXADC_IMP0, 8, 8, 3, 2),
        MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, PMIC_AUXADC_IMP0, 8, 128, 1, 1),
        MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, PMIC_AUXADC_IMP0, 8, 256, 1, 1),
        MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, PMIC_AUXADC_IMP0, 8, 16, 1, 1),
        MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, PMIC_AUXADC_IMP0, 8, 8, 2, 1),
        MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 8, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
        MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 9, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
        MTK_PMIC_ADC_CHAN(VGPU_TEMP, PMIC_AUXADC_RQST1, 10, PMIC_AUXADC_IMP0, 8, 8, 1, 1),

        /* Battery impedance channels */
        MTK_PMIC_ADC_CHAN(VBAT, 0, 0, PMIC_AUXADC_IMP0, 8, 128, 7, 2),
};

static const u16 mt6358_auxadc_regs[] = {
        [PMIC_HK_TOP_RST_CON0]  = 0x0f90,
        [PMIC_AUXADC_DCM_CON]   = 0x1260,
        [PMIC_AUXADC_ADC0]      = 0x1088,
        [PMIC_AUXADC_IMP0]      = 0x1208,
        [PMIC_AUXADC_IMP1]      = 0x120a,
        [PMIC_AUXADC_RQST0]     = 0x1108,
        [PMIC_AUXADC_RQST1]     = 0x110a,
};

static const struct iio_chan_spec mt6359_auxadc_channels[] = {
        MTK_PMIC_IIO_CHAN(MT6359, bat_adc, BATADC, 0, 15, IIO_RESISTANCE),
        MTK_PMIC_IIO_CHAN(MT6359, batt_temp, BAT_TEMP, 3, 12, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6359, chip_temp, CHIP_TEMP, 4, 12, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6359, acc_det, ACCDET, 5, 12, IIO_RESISTANCE),
        MTK_PMIC_IIO_CHAN(MT6359, dcxo_v, VDCXO, 6, 12, IIO_VOLTAGE),
        MTK_PMIC_IIO_CHAN(MT6359, tsx_temp, TSX_TEMP, 7, 15, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6359, hp_ofs_cal, HPOFS_CAL, 9, 15, IIO_RESISTANCE),
        MTK_PMIC_IIO_CHAN(MT6359, dcxo_temp, DCXO_TEMP, 10, 15, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6359, bif_v, VBIF, 11, 12, IIO_VOLTAGE),
        MTK_PMIC_IIO_CHAN(MT6359, vcore_temp, VCORE_TEMP, 30, 12, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6359, vproc_temp, VPROC_TEMP, 31, 12, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6359, vgpu_temp, VGPU_TEMP, 32, 12, IIO_TEMP),

        /* Battery impedance channels */
        MTK_PMIC_IIO_CHAN(MT6359, batt_v, VBAT, 0, 15, IIO_VOLTAGE),
        MTK_PMIC_IIO_CHAN(MT6359, batt_i, IBAT, 0, 15, IIO_CURRENT),
};

static const struct mtk_pmic_auxadc_chan mt6359_auxadc_ch_desc[] = {
        MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, PMIC_AUXADC_IMP1, 15, 128, 7, 2),
        MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, PMIC_AUXADC_IMP1, 15, 8, 5, 2),
        MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, PMIC_AUXADC_IMP1, 15, 8, 1, 1),
        MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, PMIC_AUXADC_IMP1, 15 ,8, 1, 1),
        MTK_PMIC_ADC_CHAN(VDCXO, PMIC_AUXADC_RQST0, 6, PMIC_AUXADC_IMP1, 15, 8, 3, 2),
        MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, PMIC_AUXADC_IMP1, 15, 128, 1, 1),
        MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, PMIC_AUXADC_IMP1, 15, 256, 1, 1),
        MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, PMIC_AUXADC_IMP1, 15, 16, 1, 1),
        MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, PMIC_AUXADC_IMP1, 15, 8, 5, 2),
        MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 8, PMIC_AUXADC_IMP1, 15, 8, 1, 1),
        MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 9, PMIC_AUXADC_IMP1, 15, 8, 1, 1),
        MTK_PMIC_ADC_CHAN(VGPU_TEMP, PMIC_AUXADC_RQST1, 10, PMIC_AUXADC_IMP1, 15, 8, 1, 1),

        /* Battery impedance channels */
        MTK_PMIC_ADC_CHAN(VBAT, 0, 0, PMIC_AUXADC_IMP1, 15, 128, 7, 2),
        MTK_PMIC_ADC_CHAN(IBAT, 0, 0, PMIC_AUXADC_IMP1, 15, 128, 7, 2),
};

static const u16 mt6359_auxadc_regs[] = {
        [PMIC_FGADC_R_CON0]     = 0x0d88,
        [PMIC_HK_TOP_WKEY]      = 0x0fb4,
        [PMIC_HK_TOP_RST_CON0]  = 0x0f90,
        [PMIC_AUXADC_RQST0]     = 0x1108,
        [PMIC_AUXADC_RQST1]     = 0x110a,
        [PMIC_AUXADC_ADC0]      = 0x1088,
        [PMIC_AUXADC_IMP0]      = 0x1208,
        [PMIC_AUXADC_IMP1]      = 0x120a,
        [PMIC_AUXADC_IMP3]      = 0x120e,
};

static const struct iio_chan_spec mt6363_auxadc_channels[] = {
        MTK_PMIC_IIO_CHAN(MT6363, bat_adc, BATADC, 0, 15, IIO_RESISTANCE),
        MTK_PMIC_IIO_CHAN(MT6363, cdt_v, VCDT, 2, 12, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6363, batt_temp, BAT_TEMP, 3, 12, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6363, chip_temp, CHIP_TEMP, 4, 12, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6363, sys_sns_v, VSYSSNS, 6, 15, IIO_VOLTAGE),
        MTK_PMIC_IIO_CHAN(MT6363, tref_v, VTREF, 11, 12, IIO_VOLTAGE),
        MTK_PMIC_IIO_CHAN(MT6363, vcore_temp, VCORE_TEMP, 38, 12, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6363, vproc_temp, VPROC_TEMP, 39, 12, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6363, vgpu_temp, VGPU_TEMP, 40, 12, IIO_TEMP),

        /* For VIN, ADC12 holds the result depending on which GPIO was activated */
        MTK_PMIC_IIO_CHAN(MT6363, in1_v, VIN1, 45, 15, IIO_VOLTAGE),
        MTK_PMIC_IIO_CHAN(MT6363, in2_v, VIN2, 45, 15, IIO_VOLTAGE),
        MTK_PMIC_IIO_CHAN(MT6363, in3_v, VIN3, 45, 15, IIO_VOLTAGE),
        MTK_PMIC_IIO_CHAN(MT6363, in4_v, VIN4, 45, 15, IIO_VOLTAGE),
        MTK_PMIC_IIO_CHAN(MT6363, in5_v, VIN5, 45, 15, IIO_VOLTAGE),
        MTK_PMIC_IIO_CHAN(MT6363, in6_v, VIN6, 45, 15, IIO_VOLTAGE),
        MTK_PMIC_IIO_CHAN(MT6363, in7_v, VIN7, 45, 15, IIO_VOLTAGE),
};

static const struct mtk_pmic_auxadc_chan mt6363_auxadc_ch_desc[] = {
        MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, PMIC_AUXADC_ADC0, 15, 64, 4, 1),
        MTK_PMIC_ADC_CHAN(VCDT, PMIC_AUXADC_RQST0, 2, PMIC_AUXADC_ADC0, 15, 32, 1, 1),
        MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, PMIC_AUXADC_ADC0, 15, 32, 3, 2),
        MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, PMIC_AUXADC_ADC0, 15, 32, 1, 1),
        MTK_PMIC_ADC_CHAN(VSYSSNS, PMIC_AUXADC_RQST1, 6, PMIC_AUXADC_ADC0, 15, 64, 3, 1),
        MTK_PMIC_ADC_CHAN(VTREF, PMIC_AUXADC_RQST1, 3, PMIC_AUXADC_ADC0, 15, 32, 3, 2),
        MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST3, 0, PMIC_AUXADC_ADC0, 15, 32, 1, 1),
        MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST3, 1, PMIC_AUXADC_ADC0, 15, 32, 1, 1),
        MTK_PMIC_ADC_CHAN(VGPU_TEMP, PMIC_AUXADC_RQST3, 2, PMIC_AUXADC_ADC0, 15, 32, 1, 1),

        MTK_PMIC_ADC_EXT_CHAN(VIN1,
                              PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
                              PMIC_AUXADC_SDMADC_CON0, 1, MT6363_PULLUP_RES_100K, 32, 1, 1),
        MTK_PMIC_ADC_EXT_CHAN(VIN2,
                              PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
                              PMIC_AUXADC_SDMADC_CON0, 2, MT6363_PULLUP_RES_100K, 32, 1, 1),
        MTK_PMIC_ADC_EXT_CHAN(VIN3,
                              PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
                              PMIC_AUXADC_SDMADC_CON0, 3, MT6363_PULLUP_RES_100K, 32, 1, 1),
        MTK_PMIC_ADC_EXT_CHAN(VIN4,
                              PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
                              PMIC_AUXADC_SDMADC_CON0, 4, MT6363_PULLUP_RES_100K, 32, 1, 1),
        MTK_PMIC_ADC_EXT_CHAN(VIN5,
                              PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
                              PMIC_AUXADC_SDMADC_CON0, 5, MT6363_PULLUP_RES_100K, 32, 1, 1),
        MTK_PMIC_ADC_EXT_CHAN(VIN6,
                              PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
                              PMIC_AUXADC_SDMADC_CON0, 6, MT6363_PULLUP_RES_100K, 32, 1, 1),
        MTK_PMIC_ADC_EXT_CHAN(VIN7,
                              PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
                              PMIC_AUXADC_SDMADC_CON0, 7, MT6363_PULLUP_RES_100K, 32, 1, 1),
};

static const u16 mt6363_auxadc_regs[] = {
        [PMIC_AUXADC_RQST0]     = 0x1108,
        [PMIC_AUXADC_RQST1]     = 0x1109,
        [PMIC_AUXADC_RQST3]     = 0x110c,
        [PMIC_AUXADC_ADC0]      = 0x1088,
        [PMIC_AUXADC_IMP0]      = 0x1208,
        [PMIC_AUXADC_IMP1]      = 0x1209,
};

static const struct iio_chan_spec mt6373_auxadc_channels[] = {
        MTK_PMIC_IIO_CHAN(MT6363, chip_temp, CHIP_TEMP, 4, 12, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6363, vcore_temp, VCORE_TEMP, 38, 12, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6363, vproc_temp, VPROC_TEMP, 39, 12, IIO_TEMP),
        MTK_PMIC_IIO_CHAN(MT6363, vgpu_temp, VGPU_TEMP, 40, 12, IIO_TEMP),

        /* For VIN, ADC12 holds the result depending on which GPIO was activated */
        MTK_PMIC_IIO_CHAN(MT6363, in1_v, VIN1, 45, 15, IIO_VOLTAGE),
        MTK_PMIC_IIO_CHAN(MT6363, in2_v, VIN2, 45, 15, IIO_VOLTAGE),
        MTK_PMIC_IIO_CHAN(MT6363, in3_v, VIN3, 45, 15, IIO_VOLTAGE),
        MTK_PMIC_IIO_CHAN(MT6363, in4_v, VIN4, 45, 15, IIO_VOLTAGE),
        MTK_PMIC_IIO_CHAN(MT6363, in5_v, VIN5, 45, 15, IIO_VOLTAGE),
};

static const struct mtk_pmic_auxadc_chan mt6373_auxadc_ch_desc[] = {
        MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, PMIC_AUXADC_ADC0, 15, 32, 1, 1),
        MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST3, 0, PMIC_AUXADC_ADC0, 15, 32, 1, 1),
        MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST3, 1, PMIC_AUXADC_ADC0, 15, 32, 1, 1),
        MTK_PMIC_ADC_CHAN(VGPU_TEMP, PMIC_AUXADC_RQST3, 2, PMIC_AUXADC_ADC0, 15, 32, 1, 1),

        MTK_PMIC_ADC_EXT_CHAN(VIN1,
                              PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
                              PMIC_AUXADC_SDMADC_CON0, 1, MT6363_PULLUP_RES_30K, 32, 1, 1),
        MTK_PMIC_ADC_EXT_CHAN(VIN2,
                              PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
                              PMIC_AUXADC_SDMADC_CON0, 2, MT6363_PULLUP_RES_OPEN, 32, 1, 1),
        MTK_PMIC_ADC_EXT_CHAN(VIN3,
                              PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
                              PMIC_AUXADC_SDMADC_CON0, 3, MT6363_PULLUP_RES_OPEN, 32, 1, 1),
        MTK_PMIC_ADC_EXT_CHAN(VIN4,
                              PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
                              PMIC_AUXADC_SDMADC_CON0, 4, MT6363_PULLUP_RES_OPEN, 32, 1, 1),
        MTK_PMIC_ADC_EXT_CHAN(VIN5,
                              PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
                              PMIC_AUXADC_SDMADC_CON0, 5, MT6363_PULLUP_RES_OPEN, 32, 1, 1),
};

static void mt6358_stop_imp_conv(struct mt6359_auxadc *adc_dev)
{
        const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
        struct regmap *regmap = adc_dev->regmap;

        regmap_set_bits(regmap, cinfo->regs[PMIC_AUXADC_IMP0], MT6358_IMP0_CLEAR);
        regmap_clear_bits(regmap, cinfo->regs[PMIC_AUXADC_IMP0], MT6358_IMP0_CLEAR);
        regmap_clear_bits(regmap, cinfo->regs[PMIC_AUXADC_IMP1], MT6358_IMP1_AUTOREPEAT_EN);
        regmap_clear_bits(regmap, cinfo->regs[PMIC_AUXADC_DCM_CON], MT6358_DCM_CK_SW_EN);
}

static int mt6358_start_imp_conv(struct mt6359_auxadc *adc_dev, const struct iio_chan_spec *chan)
{
        const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
        const struct mtk_pmic_auxadc_chan *desc = &cinfo->desc[chan->scan_index];
        struct regmap *regmap = adc_dev->regmap;
        u32 val;
        int ret;

        regmap_set_bits(regmap, cinfo->regs[PMIC_AUXADC_DCM_CON], MT6358_DCM_CK_SW_EN);
        regmap_set_bits(regmap, cinfo->regs[PMIC_AUXADC_IMP1], MT6358_IMP1_AUTOREPEAT_EN);

        ret = regmap_read_poll_timeout(regmap, cinfo->regs[desc->rdy_idx],
                                       val, val & desc->rdy_mask,
                                       IMP_POLL_DELAY_US, AUXADC_TIMEOUT_US);
        if (ret) {
                mt6358_stop_imp_conv(adc_dev);
                return ret;
        }

        return 0;
}

static int mt6358_read_imp(struct mt6359_auxadc *adc_dev,
                           const struct iio_chan_spec *chan, int *vbat, int *ibat)
{
        const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
        struct regmap *regmap = adc_dev->regmap;
        u16 reg_adc0 = cinfo->regs[PMIC_AUXADC_ADC0];
        u32 val_v;
        int ret;

        ret = mt6358_start_imp_conv(adc_dev, chan);
        if (ret)
                return ret;

        /* Read the params before stopping */
        regmap_read(regmap, reg_adc0 + (cinfo->imp_adc_num << 1), &val_v);

        mt6358_stop_imp_conv(adc_dev);

        if (vbat)
                *vbat = val_v;
        if (ibat)
                *ibat = 0;

        return 0;
}

static int mt6359_read_imp(struct mt6359_auxadc *adc_dev,
                           const struct iio_chan_spec *chan, int *vbat, int *ibat)
{
        const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
        const struct mtk_pmic_auxadc_chan *desc = &cinfo->desc[chan->scan_index];
        struct regmap *regmap = adc_dev->regmap;
        u32 val, val_v, val_i;
        int ret;

        /* Start conversion */
        regmap_write(regmap, cinfo->regs[PMIC_AUXADC_IMP0], MT6359_IMP0_CONV_EN);
        ret = regmap_read_poll_timeout(regmap, cinfo->regs[desc->rdy_idx],
                                       val, val & desc->rdy_mask,
                                       IMP_POLL_DELAY_US, AUXADC_TIMEOUT_US);

        /* Stop conversion regardless of the result */
        regmap_write(regmap, cinfo->regs[PMIC_AUXADC_IMP0], 0);
        if (ret)
                return ret;

        /* If it succeeded, wait for the registers to be populated */
        fsleep(IMP_STOP_DELAY_US);

        ret = regmap_read(regmap, cinfo->regs[PMIC_AUXADC_IMP3], &val_v);
        if (ret)
                return ret;

        ret = regmap_read(regmap, cinfo->regs[PMIC_FGADC_R_CON0], &val_i);
        if (ret)
                return ret;

        if (vbat)
                *vbat = val_v;
        if (ibat)
                *ibat = val_i;

        return 0;
}

static const struct mtk_pmic_auxadc_info mt6357_chip_info = {
        .model_name = "MT6357",
        .channels = mt6357_auxadc_channels,
        .num_channels = ARRAY_SIZE(mt6357_auxadc_channels),
        .desc = mt6357_auxadc_ch_desc,
        .regs = mt6357_auxadc_regs,
        .imp_adc_num = MT6357_IMP_ADC_NUM,
        .read_imp = mt6358_read_imp,
        .vref_mV = 1800,
};

static const struct mtk_pmic_auxadc_info mt6358_chip_info = {
        .model_name = "MT6358",
        .channels = mt6358_auxadc_channels,
        .num_channels = ARRAY_SIZE(mt6358_auxadc_channels),
        .desc = mt6358_auxadc_ch_desc,
        .regs = mt6358_auxadc_regs,
        .imp_adc_num = MT6358_IMP_ADC_NUM,
        .read_imp = mt6358_read_imp,
        .vref_mV = 1800,
};

static const struct mtk_pmic_auxadc_info mt6359_chip_info = {
        .model_name = "MT6359",
        .channels = mt6359_auxadc_channels,
        .num_channels = ARRAY_SIZE(mt6359_auxadc_channels),
        .desc = mt6359_auxadc_ch_desc,
        .regs = mt6359_auxadc_regs,
        .sec_unlock_key = 0x6359,
        .read_imp = mt6359_read_imp,
        .vref_mV = 1800,
};

static const struct mtk_pmic_auxadc_info mt6363_chip_info = {
        .model_name = "MT6363",
        .channels = mt6363_auxadc_channels,
        .num_channels = ARRAY_SIZE(mt6363_auxadc_channels),
        .desc = mt6363_auxadc_ch_desc,
        .regs = mt6363_auxadc_regs,
        .is_spmi = true,
        .no_reset = true,
        .vref_mV = 1840,
};

static const struct mtk_pmic_auxadc_info mt6373_chip_info = {
        .model_name = "MT6373",
        .channels = mt6373_auxadc_channels,
        .num_channels = ARRAY_SIZE(mt6373_auxadc_channels),
        .desc = mt6373_auxadc_ch_desc,
        .regs = mt6363_auxadc_regs,
        .is_spmi = true,
        .no_reset = true,
        .vref_mV = 1840,
};

static void mt6359_auxadc_reset(struct mt6359_auxadc *adc_dev)
{
        const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
        struct regmap *regmap = adc_dev->regmap;

        /* Some PMICs do not support reset */
        if (cinfo->no_reset)
                return;

        /* Unlock HK_TOP writes */
        if (cinfo->sec_unlock_key)
                regmap_write(regmap, cinfo->regs[PMIC_HK_TOP_WKEY], cinfo->sec_unlock_key);

        /* Assert ADC reset */
        regmap_set_bits(regmap, cinfo->regs[PMIC_HK_TOP_RST_CON0], PMIC_RG_RESET_VAL);

        /* De-assert ADC reset. No wait required, as pwrap takes care of that for us. */
        regmap_clear_bits(regmap, cinfo->regs[PMIC_HK_TOP_RST_CON0], PMIC_RG_RESET_VAL);

        /* Lock HK_TOP writes again */
        if (cinfo->sec_unlock_key)
                regmap_write(regmap, cinfo->regs[PMIC_HK_TOP_WKEY], 0);
}

/**
 * mt6359_auxadc_sample_adc_val() - Start ADC channel sampling and read value
 * @adc_dev: Main driver structure
 * @chan:    IIO Channel spec for requested ADC
 * @out:     Preallocated variable to store the value read from HW
 *
 * This function starts the sampling for an ADC channel, waits until all
 * of the samples are averaged and then reads the value from the HW.
 *
 * Note that the caller must stop the ADC sampling on its own, as this
 * function *never* stops it.
 *
 * Return:
 * Negative number for error;
 * Upon success returns zero and writes the read value to *out.
 */
static int mt6359_auxadc_sample_adc_val(struct mt6359_auxadc *adc_dev,
                                        const struct iio_chan_spec *chan, u32 *out)
{
        const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
        const struct mtk_pmic_auxadc_chan *desc = &cinfo->desc[chan->scan_index];
        struct regmap *regmap = adc_dev->regmap;
        u32 reg, rdy_mask, val, lval;
        int ret;

        /* Request to start sampling for ADC channel */
        ret = regmap_write(regmap, cinfo->regs[desc->req_idx], desc->req_mask);
        if (ret)
                return ret;

        /* Wait until all samples are averaged */
        fsleep(desc->num_samples * AUXADC_AVG_TIME_US);

        reg = cinfo->regs[PMIC_AUXADC_ADC0] + (chan->address << 1);
        rdy_mask = PMIC_AUXADC_RDY_BIT;

        /*
         * Even though for both PWRAP and SPMI cases the ADC HW signals that
         * the data is ready by setting AUXADC_RDY_BIT, for SPMI the register
         * read is only 8 bits long: for this case, the check has to be done
         * on the ADC(x)_H register (high bits) and the rdy_mask needs to be
         * shifted to the right by the same 8 bits.
         */
        if (cinfo->is_spmi) {
                rdy_mask >>= 8;
                reg += 1;
        }

        ret = regmap_read_poll_timeout(regmap, reg, val, val & rdy_mask,
                                       AUXADC_POLL_DELAY_US, AUXADC_TIMEOUT_US);
        if (ret) {
                dev_dbg(adc_dev->dev, "ADC read timeout for chan %lu\n", chan->address);
                return ret;
        }

        if (cinfo->is_spmi) {
                ret = regmap_read(regmap, reg - 1, &lval);
                if (ret)
                        return ret;

                val = (val << 8) | lval;
        }

        *out = val;
        return 0;
}

static int mt6359_auxadc_read_adc(struct mt6359_auxadc *adc_dev,
                                  const struct iio_chan_spec *chan, int *out)
{
        const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
        const struct mtk_pmic_auxadc_chan *desc = &cinfo->desc[chan->scan_index];
        struct regmap *regmap = adc_dev->regmap;
        int ret, adc_stop_err;
        u8 ext_sel;
        u32 val;

        if (desc->ext_sel_idx >= 0) {
                ext_sel = FIELD_PREP(MT6363_EXT_PURES_MASK, desc->ext_sel_pu);
                ext_sel |= FIELD_PREP(MT6363_EXT_CHAN_MASK, desc->ext_sel_ch);

                ret = regmap_update_bits(regmap, cinfo->regs[desc->ext_sel_idx],
                                         MT6363_EXT_PURES_MASK | MT6363_EXT_CHAN_MASK,
                                         ext_sel);
                if (ret)
                        return ret;
        }

        /*
         * Get sampled value, then stop sampling unconditionally; the gathered
         * value is good regardless of if the ADC could be stopped.
         *
         * Note that if the ADC cannot be stopped but sampling was ok, this
         * function will not return any error, but will set the timed_out
         * status: this is not critical, as the ADC may auto recover and auto
         * stop after some time (depending on the PMIC model); if not, the next
         * read attempt will return -ETIMEDOUT and, for models that support it,
         * reset will be triggered.
         */
        ret = mt6359_auxadc_sample_adc_val(adc_dev, chan, &val);

        adc_stop_err = regmap_write(regmap, cinfo->regs[desc->req_idx], 0);
        if (adc_stop_err) {
                dev_warn(adc_dev->dev, "Could not stop the ADC: %d\n,", adc_stop_err);
                adc_dev->timed_out = true;
        }

        /* If any sampling error occurred, the retrieved value is invalid */
        if (ret)
                return ret;

        /* ...and deactivate the ADC GPIO if previously done */
        if (desc->ext_sel_idx >= 0) {
                ext_sel = FIELD_PREP(MT6363_EXT_PURES_MASK, MT6363_PULLUP_RES_OPEN);

                ret = regmap_update_bits(regmap, cinfo->regs[desc->ext_sel_idx],
                                         MT6363_EXT_PURES_MASK, ext_sel);
                if (ret)
                        return ret;
        }

        /* Everything went fine, give back the ADC reading */
        *out = val & GENMASK(chan->scan_type.realbits - 1, 0);
        return 0;
}

static int mt6359_auxadc_read_label(struct iio_dev *indio_dev,
                                    const struct iio_chan_spec *chan, char *label)
{
        return sysfs_emit(label, "%s\n", chan->datasheet_name);
}

static int mt6359_auxadc_read_raw(struct iio_dev *indio_dev,
                                  const struct iio_chan_spec *chan,
                                  int *val, int *val2, long mask)
{
        struct mt6359_auxadc *adc_dev = iio_priv(indio_dev);
        const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
        const struct mtk_pmic_auxadc_chan *desc = &cinfo->desc[chan->scan_index];
        int ret;

        if (mask == IIO_CHAN_INFO_SCALE) {
                *val = desc->r_ratio.numerator * cinfo->vref_mV;

                if (desc->r_ratio.denominator > 1) {
                        *val2 = desc->r_ratio.denominator;
                        return IIO_VAL_FRACTIONAL;
                }

                return IIO_VAL_INT;
        }

        scoped_guard(mutex, &adc_dev->lock) {
                switch (chan->scan_index) {
                case PMIC_AUXADC_CHAN_IBAT:
                        if (!adc_dev->chip_info->read_imp)
                                return -EOPNOTSUPP;

                        ret = adc_dev->chip_info->read_imp(adc_dev, chan, NULL, val);
                        break;
                case PMIC_AUXADC_CHAN_VBAT:
                        if (!adc_dev->chip_info->read_imp)
                                return -EOPNOTSUPP;

                        ret = adc_dev->chip_info->read_imp(adc_dev, chan, val, NULL);
                        break;
                default:
                        ret = mt6359_auxadc_read_adc(adc_dev, chan, val);
                        break;
                }
        }

        if (ret) {
                /*
                 * If we get more than one timeout, it's possible that the
                 * AUXADC is stuck: perform a full reset to recover it.
                 */
                if (ret == -ETIMEDOUT) {
                        if (adc_dev->timed_out) {
                                dev_warn(adc_dev->dev, "Resetting stuck ADC!\r\n");
                                mt6359_auxadc_reset(adc_dev);
                        }
                        adc_dev->timed_out = true;
                }
                return ret;
        }
        adc_dev->timed_out = false;

        return IIO_VAL_INT;
}

static const struct iio_info mt6359_auxadc_iio_info = {
        .read_label = mt6359_auxadc_read_label,
        .read_raw = mt6359_auxadc_read_raw,
};

static int mt6359_auxadc_probe(struct platform_device *pdev)
{
        const struct mtk_pmic_auxadc_info *chip_info;
        struct device *dev = &pdev->dev;
        struct device *mfd_dev = dev->parent;
        struct mt6359_auxadc *adc_dev;
        struct iio_dev *indio_dev;
        struct device *regmap_dev;
        struct regmap *regmap;
        int ret;

        chip_info = device_get_match_data(dev);
        if (!chip_info)
                return -EINVAL;
        /*
         * The regmap for this device has to be acquired differently for
         * SoC PMIC Wrapper and SPMI PMIC cases:
         *
         * If this is under SPMI, the regmap comes from the direct parent of
         * this driver: this_device->parent(mfd).
         *                            ... or ...
         * If this is under the SoC PMIC Wrapper, the regmap comes from the
         * parent of the MT6397 MFD: this_device->parent(mfd)->parent(pwrap)
         */
        if (chip_info->is_spmi)
                regmap_dev = mfd_dev;
        else
                regmap_dev = mfd_dev->parent;


        /* Regmap is from SoC PMIC Wrapper, parent of the mt6397 MFD */
        regmap = dev_get_regmap(regmap_dev, NULL);
        if (!regmap)
                return dev_err_probe(dev, -ENODEV, "Failed to get regmap\n");

        indio_dev = devm_iio_device_alloc(dev, sizeof(*adc_dev));
        if (!indio_dev)
                return -ENOMEM;

        adc_dev = iio_priv(indio_dev);
        adc_dev->regmap = regmap;
        adc_dev->dev = dev;
        adc_dev->chip_info = chip_info;

        mutex_init(&adc_dev->lock);

        mt6359_auxadc_reset(adc_dev);

        indio_dev->name = adc_dev->chip_info->model_name;
        indio_dev->info = &mt6359_auxadc_iio_info;
        indio_dev->modes = INDIO_DIRECT_MODE;
        indio_dev->channels = adc_dev->chip_info->channels;
        indio_dev->num_channels = adc_dev->chip_info->num_channels;

        ret = devm_iio_device_register(dev, indio_dev);
        if (ret)
                return dev_err_probe(dev, ret, "failed to register iio device\n");

        return 0;
}

static const struct of_device_id mt6359_auxadc_of_match[] = {
        { .compatible = "mediatek,mt6357-auxadc", .data = &mt6357_chip_info },
        { .compatible = "mediatek,mt6358-auxadc", .data = &mt6358_chip_info },
        { .compatible = "mediatek,mt6359-auxadc", .data = &mt6359_chip_info },
        { .compatible = "mediatek,mt6363-auxadc", .data = &mt6363_chip_info },
        { .compatible = "mediatek,mt6373-auxadc", .data = &mt6373_chip_info },
        { }
};
MODULE_DEVICE_TABLE(of, mt6359_auxadc_of_match);

static struct platform_driver mt6359_auxadc_driver = {
        .driver = {
                .name = "mt6359-auxadc",
                .of_match_table = mt6359_auxadc_of_match,
        },
        .probe  = mt6359_auxadc_probe,
};
module_platform_driver(mt6359_auxadc_driver);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
MODULE_DESCRIPTION("MediaTek MT6359 PMIC AUXADC Driver");