struct mt6360_adc_data { struct device *dev; struct regmap *regmap; /* Due to only one set of ADC control, this lock is used to prevent the race condition */ struct mutex adc_lock;
ktime_t last_off_timestamps[MT6360_CHAN_MAX];
};
staticint mt6360_adc_read_channel(struct mt6360_adc_data *mad, int channel, int *val)
{
__be16 adc_enable;
u8 rpt[3];
ktime_t predict_end_t, timeout; unsignedint pre_wait_time; int ret;
mutex_lock(&mad->adc_lock);
/* Select the preferred ADC channel */
ret = regmap_update_bits(mad->regmap, MT6360_REG_PMUADCRPT1, MT6360_PREFERCH_MASK,
channel << MT6360_PREFERCH_SHFT); if (ret) goto out_adc_lock;
adc_enable = cpu_to_be16(MT6360_ADCEN_MASK | BIT(channel));
ret = regmap_raw_write(mad->regmap, MT6360_REG_PMUADCCFG, &adc_enable, sizeof(adc_enable)); if (ret) goto out_adc_lock;
if (msleep_interruptible(pre_wait_time)) {
ret = -ERESTARTSYS; goto out_adc_conv;
}
timeout = ktime_add_ms(ktime_get(), ADC_CONV_TIMEOUT_MS); while (true) {
ret = regmap_raw_read(mad->regmap, MT6360_REG_PMUADCRPT1, rpt, sizeof(rpt)); if (ret) goto out_adc_conv;
/* * There are two functions, ZCV and TypeC OTP, running ADC VBAT and TS in * background, and ADC samples are taken on a fixed frequency no matter read the * previous one or not. * To avoid conflict, We set minimum time threshold after enable ADC and * check report channel is the same. * The worst case is run the same ADC twice and background function is also running, * ADC conversion sequence is desire channel before start ADC, background ADC, * desire channel after start ADC. * So the minimum correct data is three times of typical conversion time.
*/ if ((rpt[0] & MT6360_RPTCH_MASK) == channel) break;
if (ktime_compare(ktime_get(), timeout) > 0) {
ret = -ETIMEDOUT; goto out_adc_conv;
}
staticint mt6360_adc_read_scale(struct mt6360_adc_data *mad, int channel, int *val, int *val2)
{ unsignedint regval; int ret;
switch (channel) { case MT6360_CHAN_USBID: case MT6360_CHAN_VSYS: case MT6360_CHAN_VBAT: case MT6360_CHAN_CHG_VDDP: case MT6360_CHAN_VREF_TS: case MT6360_CHAN_TS:
*val = 1250; return IIO_VAL_INT; case MT6360_CHAN_VBUSDIV5:
*val = 6250; return IIO_VAL_INT; case MT6360_CHAN_VBUSDIV2: case MT6360_CHAN_IBUS: case MT6360_CHAN_IBAT:
*val = 2500;
if (channel == MT6360_CHAN_IBUS) { /* IBUS will be affected by input current limit for the different Ron */ /* Check whether the config is <400mA or not */
ret = regmap_read(mad->regmap, MT6360_REG_PMUCHGCTRL3, ®val); if (ret) return ret;
staticinlineint mt6360_adc_reset(struct mt6360_adc_data *info)
{
__be16 adc_enable;
ktime_t all_off_time; int i, ret;
/* Clear ADC idle wait time to 0 */
ret = regmap_write(info->regmap, MT6360_REG_PMUADCIDLET, 0); if (ret) return ret;
/* Only keep ADC enable, but keep all channels off */
adc_enable = cpu_to_be16(MT6360_ADCEN_MASK);
ret = regmap_raw_write(info->regmap, MT6360_REG_PMUADCCFG, &adc_enable, sizeof(adc_enable)); if (ret) return ret;
/* Reset all channel off time to the current one */
all_off_time = ktime_get(); for (i = 0; i < MT6360_CHAN_MAX; i++)
info->last_off_timestamps[i] = all_off_time;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.