soc/mediatek/mt8196: Add PMIC MT6363 ADC driver

Add MT6363 AUXADC driver support, which is essential for handling the
Analog-to-Digital Conversion (ADC) functionalities in the MT8196 SoC.

TEST=build pass
BUG=b:317009620

Change-Id: Ice3c286cd207e445392d5f0126a07ce4f40dcf8a
Signed-off-by: Hope Wang <hope.wang@mediatek.corp-partner.google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/85128
Reviewed-by: Yidi Lin <yidilin@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Yu-Ping Wu <yupingso@google.com>
This commit is contained in:
Jarried Lin 2024-10-23 19:46:42 +08:00 committed by Yidi Lin
commit a1c50f233d
3 changed files with 203 additions and 0 deletions

View file

@ -0,0 +1,90 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __MT6363_SDMADC_H__
#define __MT6363_SDMADC_H__
#include <soc/spmi.h>
#include <types.h>
enum {
PMIC_AUXADC_ADC_OUT_CH12_L_ADDR = 0x10d2,
MT6363_AUXADC_RQST1 = 0x1109,
PMIC_SDMADC_EXT_THR_SRC_SEL_ADDR = 0x11c4,
};
/*
* enum auxadc_channels - enumeration of auxadc channels
*/
enum auxadc_channel {
AUXADC_CHAN_VIN1,
AUXADC_CHAN_VIN2,
AUXADC_CHAN_VIN3,
AUXADC_CHAN_VIN4,
AUXADC_CHAN_VIN5,
AUXADC_CHAN_VIN6,
AUXADC_CHAN_VIN7,
AUXADC_CHAN_MAX,
};
/*
* enum sdmadc_pures - enumeration of sdmadc pull up resistor
*/
enum sdmadc_pures {
SDMADC_100K,
SDMADC_30K,
SDMADC_400K,
SDMADC_OPEN,
};
/**
* enum auxadc_val_type - enumeration of auxadc value's type
*/
enum auxadc_val_type {
AUXADC_VAL_PROCESSED,
AUXADC_VAL_RAW,
};
/**
* struct auxadc_chan_spec - specification of an auxadc channel
* @channel: What auxadc_channel is it.
* @hw_info: Hardware design level information
* @hw_info.ref_volt Reference voltage
* @hw_info.ratio: Resistor Ratio.
* If read operation is not provided, the processed
* value will be calculated as following:
* (raw value * ratio[0] * ref_volt) / ratio[1]
* @hw_info.max_time: Maximum wait time(us).
* @hw_info.min_time: Minimum wait time(us).
* @hw_info.poll_time: Wait time(us) between every polling during retry.
* @hw_info.enable_reg Register address of enable control.
* @hw_info.enable_mask Mask of enable control.
* @hw_info.ready_reg Register address of channel's ready status.
* @hw_info.ready_mask Mask of ready status.
* @hw_info.value_reg Register address of raw value.
* @hw_info.res Resolution of this channel (number of valid bits).
*/
struct auxadc_chan_spec {
int channel;
struct {
u32 ref_volt;
u32 ratio[2];
u32 max_time;
u32 min_time;
u32 poll_time;
u32 enable_reg;
u32 enable_mask;
u32 ready_reg;
u32 ready_mask;
u32 value_reg;
u8 res;
} hw_info;
struct {
u32 set_reg;
u32 cmd;
} sdmadc_hw_info;
};
int mt6363_sdmadc_read(enum auxadc_channel channel, int *val, enum sdmadc_pures pures,
enum auxadc_val_type type);
#endif /* __MT6363_SDMADC_H__ */

View file

@ -0,0 +1,112 @@
/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
/*
* These values are used by MediaTek internally.
* We can find these registers in "MT6363TP_PMIC_Design_Notice_for_MT8196G_V0.2"
* Chapter number: 2.15.
* The setting values are provided by MeidaTek designers.
*/
#include <assert.h>
#include <console/console.h>
#include <delay.h>
#include <soc/mt6363.h>
#include <soc/mt6363_sdmadc.h>
#include <soc/pmif.h>
#include <timer.h>
#define ERR_INVALID_ARGS (-8)
#define ERR_TIMED_OUT (-13)
#define AUXADC_RDY_BIT BIT(15)
/* 0.385us(2.89MHz) x 42T (SPL(100K=29T)+ADC_compare(12T)+sync(1T)) ~= 16us */
#define AUXADC_AVG_TIME_US 16
#define AUXADC_POLL_TIME_US 100
#define AUXADC_TIMEOUT_US 32000
#define VOLT_FULL 1840
#define EXT_THR_SEL_DEF_VALUE 0x80
#define EXT_THR_PURES_SHIFT 3
#define SDMADC_CHAN_SPEC(src_sel) \
{ \
.hw_info = { \
.ref_volt = VOLT_FULL, \
.min_time = 128 * AUXADC_AVG_TIME_US, \
.max_time = AUXADC_TIMEOUT_US, \
.poll_time = AUXADC_POLL_TIME_US, \
.ratio = { 1, 1 }, \
.enable_reg = MT6363_AUXADC_RQST1, \
.enable_mask = BIT(4), \
.ready_reg = PMIC_AUXADC_ADC_OUT_CH12_L_ADDR, \
.ready_mask = AUXADC_RDY_BIT, \
.res = 15, \
}, \
.sdmadc_hw_info = { \
.set_reg = PMIC_SDMADC_EXT_THR_SRC_SEL_ADDR, \
.cmd = EXT_THR_SEL_DEF_VALUE | src_sel, \
}, \
}
static const struct auxadc_chan_spec mt6363_sdmadc_chan_specs[] = {
[AUXADC_CHAN_VIN1] = SDMADC_CHAN_SPEC(1),
[AUXADC_CHAN_VIN2] = SDMADC_CHAN_SPEC(2),
[AUXADC_CHAN_VIN3] = SDMADC_CHAN_SPEC(3),
[AUXADC_CHAN_VIN4] = SDMADC_CHAN_SPEC(4),
[AUXADC_CHAN_VIN5] = SDMADC_CHAN_SPEC(5),
[AUXADC_CHAN_VIN6] = SDMADC_CHAN_SPEC(6),
[AUXADC_CHAN_VIN7] = SDMADC_CHAN_SPEC(7),
};
_Static_assert(ARRAY_SIZE(mt6363_sdmadc_chan_specs) == AUXADC_CHAN_MAX,
"Wrong array size for mt6363_sdmadc_chan_specs");
int mt6363_sdmadc_read(enum auxadc_channel channel, int *val,
enum sdmadc_pures pures, enum auxadc_val_type type)
{
u8 wdata;
u32 regval;
u32 elapsed = 0;
const struct auxadc_chan_spec *chan;
if (channel < AUXADC_CHAN_VIN1 || channel >= AUXADC_CHAN_MAX) {
printk(BIOS_ERR, "[%s] Invalid channel %d\n", __func__, channel);
return ERR_INVALID_ARGS;
}
mt6363_init_pmif_arb();
chan = &mt6363_sdmadc_chan_specs[channel];
wdata = chan->sdmadc_hw_info.cmd | (pures << EXT_THR_PURES_SHIFT);
mt6363_write8(chan->sdmadc_hw_info.set_reg, wdata);
wdata = chan->hw_info.enable_mask;
mt6363_write8(chan->hw_info.enable_reg, wdata);
udelay(chan->hw_info.min_time);
elapsed += chan->hw_info.min_time;
while (1) {
regval = mt6363_read16(chan->hw_info.ready_reg);
if (regval & chan->hw_info.ready_mask)
break;
if (elapsed > chan->hw_info.max_time) {
printk(BIOS_ERR, "[%s] Auxadc read time out", __func__);
return ERR_TIMED_OUT;
}
udelay(chan->hw_info.poll_time);
elapsed += chan->hw_info.poll_time;
}
regval &= (BIT(chan->hw_info.res) - 1);
switch (type) {
case AUXADC_VAL_RAW:
*val = regval;
break;
case AUXADC_VAL_PROCESSED:
*val = ((regval * chan->hw_info.ratio[0] * chan->hw_info.ref_volt) /
chan->hw_info.ratio[1]) >> chan->hw_info.res;
break;
}
return 0;
}

View file

@ -45,6 +45,7 @@ ramstage-y += ../common/mcu.c
ramstage-y += ../common/mmu_operations.c ../common/mmu_cmops.c
ramstage-$(CONFIG_PCI) += ../common/pcie.c pcie.c
ramstage-y += ../common/mt6363.c mt6363.c
ramstage-y += ../common/mt6363_sdmadc.c
ramstage-y += soc.c
ramstage-y += ../common/pmif_clk.c pmif_clk.c
ramstage-y += ../common/pmif.c pmif_init.c