summaryrefslogtreecommitdiff
path: root/driver
diff options
context:
space:
mode:
authorAllen Chiang <allen_chiang@mediatek.corp-partner.google.com>2019-06-17 15:03:53 +0800
committerCommit Bot <commit-bot@chromium.org>2019-11-13 15:29:53 +0000
commit02dd6d5f7c632664929ee76ef75fc9fa443ef6e8 (patch)
tree379e675288404dd72c52ee5fc08c050e286e5ca7 /driver
parenta49c836634c169e408e9286ec8c741c98a11ae3e (diff)
downloadchrome-ec-02dd6d5f7c632664929ee76ef75fc9fa443ef6e8.tar.gz
rt946x: Fix MT6370 Charger back boost and INT miss issue
1. Add ADC readings. 2. Add MIVR IRQ, when trigger mivr irq then get ibus adc, if the ibus < 100mA then toggle cfo to stop LX/RX function, that can cancel the back boost voltage. 3. In order to solve the issue of missing IRQ, it is necessary to record the state of IRQs before and after reading event of IRQs. BRANCH=kukui BUG=b:134372910 TEST=boot kukui, trigger interrupt, check interrupt handler is OK. Change-Id: I695125b1c25f13ab73713304727cbb7a1d90083c Signed-off-by: Allen Chiang <allen_chiang@mediatek.corp-partner.google.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1660522 Reviewed-by: Eric Yilun Lin <yllin@chromium.org> Commit-Queue: Eric Yilun Lin <yllin@chromium.org> Tested-by: Eric Yilun Lin <yllin@chromium.org>
Diffstat (limited to 'driver')
-rw-r--r--driver/charger/rt946x.c342
-rw-r--r--driver/charger/rt946x.h44
2 files changed, 342 insertions, 44 deletions
diff --git a/driver/charger/rt946x.c b/driver/charger/rt946x.c
index cb7c36be3b..cc33a84e02 100644
--- a/driver/charger/rt946x.c
+++ b/driver/charger/rt946x.c
@@ -27,7 +27,6 @@
#define CPRINTF(format, args...) cprintf(CC_CHARGER, format, ## args)
#define CPRINTS(format, args...) cprints(CC_CHARGER, "CHG " format, ## args)
-
/* Charger parameters */
static const struct charger_info rt946x_charger_info = {
.name = CHARGER_NAME,
@@ -73,8 +72,65 @@ enum rt946x_chg_stat {
enum rt946x_adc_in_sel {
RT946X_ADC_VBUS_DIV5 = 1,
RT946X_ADC_VBUS_DIV2,
+ MT6370_ADC_TS_BAT = 6,
+ MT6370_ADC_IBUS = 8,
+ MT6370_ADC_TEMP_JC = 12,
+ MT6370_ADC_MAX,
+};
+
+static struct mutex adc_access_lock;
+
+#ifdef CONFIG_CHARGER_MT6370
+/*
+ * Unit for each ADC parameter
+ * 0 stands for reserved
+ */
+static const int mt6370_adc_unit[MT6370_ADC_MAX] = {
+ 0,
+ MT6370_ADC_UNIT_VBUS_DIV5,
+ MT6370_ADC_UNIT_VBUS_DIV2,
+ MT6370_ADC_UNIT_VSYS,
+ MT6370_ADC_UNIT_VBAT,
+ 0,
+ MT6370_ADC_UNIT_TS_BAT,
+ 0,
+ MT6370_ADC_UNIT_IBUS,
+ MT6370_ADC_UNIT_IBAT,
+ 0,
+ MT6370_ADC_UNIT_CHG_VDDP,
+ MT6370_ADC_UNIT_TEMP_JC,
};
+static const int mt6370_adc_offset[MT6370_ADC_MAX] = {
+ 0,
+ MT6370_ADC_OFFSET_VBUS_DIV5,
+ MT6370_ADC_OFFSET_VBUS_DIV2,
+ MT6370_ADC_OFFSET_VSYS,
+ MT6370_ADC_OFFSET_VBAT,
+ 0,
+ MT6370_ADC_OFFSET_TS_BAT,
+ 0,
+ MT6370_ADC_OFFSET_IBUS,
+ MT6370_ADC_OFFSET_IBAT,
+ 0,
+ MT6370_ADC_OFFSET_CHG_VDDP,
+ MT6370_ADC_OFFSET_TEMP_JC,
+};
+
+static int hidden_mode_cnt = 0;
+static struct mutex hidden_mode_lock;
+static const unsigned char mt6370_reg_en_hidden_mode[] = {
+ MT6370_REG_HIDDENPASCODE1,
+ MT6370_REG_HIDDENPASCODE2,
+ MT6370_REG_HIDDENPASCODE3,
+ MT6370_REG_HIDDENPASCODE4,
+};
+
+static const unsigned char mt6370_val_en_hidden_mode[] = {
+ 0x96, 0x69, 0xC3, 0x3C,
+};
+#endif /* CONFIG_CHARGER_MT6370 */
+
#if defined(CONFIG_CHARGER_RT9466) || defined(CONFIG_CHARGER_RT9467)
enum rt946x_irq {
RT946X_IRQ_CHGSTATC = 0,
@@ -124,7 +180,7 @@ enum rt946x_irq {
};
static uint8_t rt946x_irqmask[RT946X_IRQ_COUNT] = {
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xBF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFC, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF,
@@ -183,6 +239,20 @@ static inline int rt946x_clr_bit(int reg, int mask)
return rt946x_update_bits(reg, mask, 0x00);
}
+static inline int mt6370_pmu_reg_test_bit(int cmd, int shift, int *is_one)
+{
+ int rv, data;
+
+ rv = rt946x_read8(cmd, &data);
+ if (rv) {
+ *is_one = 0;
+ return rv;
+ }
+
+ *is_one = !!(data & BIT(shift));
+ return rv;
+}
+
static inline uint8_t rt946x_closest_reg(uint16_t min, uint16_t max,
uint16_t step, uint16_t target)
{
@@ -193,6 +263,40 @@ static inline uint8_t rt946x_closest_reg(uint16_t min, uint16_t max,
return (target - min) / step;
}
+#ifdef CONFIG_CHARGER_MT6370
+static int mt6370_enable_hidden_mode(int en)
+{
+ int rv = 0;
+
+ if (in_interrupt_context()) {
+ CPRINTS("Shouldn't use %s in IRQ", __func__);
+ return EC_ERROR_INVAL;
+ }
+
+ mutex_lock(&hidden_mode_lock);
+ if (en) {
+ if (hidden_mode_cnt == 0) {
+ rv = rt946x_block_write(mt6370_reg_en_hidden_mode[0],
+ mt6370_val_en_hidden_mode,
+ ARRAY_SIZE(mt6370_val_en_hidden_mode));
+ if (rv)
+ goto out;
+ }
+ hidden_mode_cnt++;
+ } else {
+ if (hidden_mode_cnt == 1) /* last one */
+ rv = rt946x_write8(mt6370_reg_en_hidden_mode[0], 0x00);
+ hidden_mode_cnt--;
+ if (rv)
+ goto out;
+ }
+
+out:
+ mutex_unlock(&hidden_mode_lock);
+ return rv;
+}
+#endif /* CONFIG_CHARGER_MT6370 */
+
static int rt946x_chip_rev(int *chip_rev)
{
int rv;
@@ -696,47 +800,6 @@ int charger_discharge_on_ac(int enable)
return rt946x_enable_hz(enable);
}
-int charger_get_vbus_voltage(int port)
-{
- int val;
- static int vbus_mv;
- int retries = 10;
-
- /* Set VBUS as ADC input */
- rt946x_update_bits(RT946X_REG_CHGADC, RT946X_MASK_ADC_IN_SEL,
- RT946X_ADC_VBUS_DIV5 << RT946X_SHIFT_ADC_IN_SEL);
-
- /* Start ADC conversion */
- rt946x_set_bit(RT946X_REG_CHGADC, RT946X_MASK_ADC_START);
-
- /*
- * In practice, ADC conversion rarely takes more than 35ms.
- * However, according to the datasheet, ADC conversion may take
- * up to 200ms. But we can't wait for that long, otherwise
- * host command would time out. So here we set ADC timeout as 50ms.
- * If ADC times out, we just return the last read vbus_mv.
- *
- * TODO(chromium:820335): We may handle this more gracefully with
- * EC_RES_IN_PROGRESS.
- */
- while (--retries) {
- rt946x_read8(RT946X_REG_CHGSTAT, &val);
- if (!(val & RT946X_MASK_ADC_STAT))
- break;
- msleep(5);
- }
-
- if (retries) {
- /* Read measured results if ADC finishes in time. */
- rt946x_read8(RT946X_REG_ADCDATAL, &vbus_mv);
- rt946x_read8(RT946X_REG_ADCDATAH, &val);
- vbus_mv |= (val << 8);
- vbus_mv *= 25;
- }
-
- return vbus_mv;
-}
-
/* Setup sourcing current to prevent overload */
#ifdef CONFIG_CHARGER_ILIM_PIN_DISABLED
static int rt946x_enable_ilim_pin(int en)
@@ -1080,6 +1143,195 @@ static void usb_pd_connect(void)
DECLARE_HOOK(HOOK_USB_PD_CONNECT, usb_pd_connect, HOOK_PRIO_DEFAULT);
#endif
+static int rt946x_get_adc(enum rt946x_adc_in_sel adc_sel, int *adc_val)
+{
+ int rv, i, adc_start, adc_result = 0;
+ int adc_data_h, adc_data_l, aicr;
+ const int max_wait_times = 6;
+
+ if (in_interrupt_context()) {
+ CPRINTS("Shouldn't use %s in IRQ", __func__);
+ return EC_ERROR_INVAL;
+ }
+ mutex_lock(&adc_access_lock);
+#ifdef CONFIG_CHARGER_MT6370
+ mt6370_enable_hidden_mode(1);
+#endif
+
+ /* Select ADC to desired channel */
+ rv = rt946x_update_bits(RT946X_REG_CHGADC, RT946X_MASK_ADC_IN_SEL,
+ adc_sel << RT946X_SHIFT_ADC_IN_SEL);
+ if (rv)
+ goto out;
+
+ if (adc_sel == MT6370_ADC_IBUS) {
+ rv = charger_get_input_current(&aicr);
+ if (rv)
+ goto out;
+ }
+
+ /* Start ADC conversation */
+ rv = rt946x_set_bit(RT946X_REG_CHGADC, RT946X_MASK_ADC_START);
+ if (rv)
+ goto out;
+
+ for (i = 0; i < max_wait_times; i++) {
+ msleep(35);
+ rv = mt6370_pmu_reg_test_bit(RT946X_REG_CHGADC,
+ RT946X_SHIFT_ADC_START,
+ &adc_start);
+ if (!adc_start && rv == 0)
+ break;
+ }
+ if (i == max_wait_times)
+ CPRINTS("%s: wait conversation failed, sel = %d, rv = %d",
+ __func__, adc_sel, rv);
+
+ /* Read ADC data */
+ rv = rt946x_read8(RT946X_REG_ADCDATAH, &adc_data_h);
+ rv = rt946x_read8(RT946X_REG_ADCDATAL, &adc_data_l);
+ if (rv)
+ goto out;
+
+#if defined(CONFIG_CHARGER_RT9466) || defined(CONFIG_CHARGER_RT9467)
+ if (adc_sel == RT946X_ADC_VBUS_DIV5)
+ adc_result = ((adc_data_h << 8) | adc_data_l) * 25;
+ else
+ CPRINTS("%s: RT946X not yet support channels", __func__);
+ *adc_val = adc_result;
+#elif defined(CONFIG_CHARGER_MT6370)
+ /* Calculate ADC value */
+ adc_result = (adc_data_h * 256 + adc_data_l)
+ * mt6370_adc_unit[adc_sel] + mt6370_adc_offset[adc_sel];
+
+ /* For TS_BAT/TS_BUS, the real unit is 0.25, here we use 25(unit) */
+ if (adc_sel == MT6370_ADC_TS_BAT)
+ adc_result /= 100;
+#endif
+
+out:
+#ifdef CONFIG_CHARGER_MT6370
+ if (adc_sel == MT6370_ADC_IBUS) {
+ if (aicr < 400) /* 400mA */
+ adc_result = adc_result * 67 / 100;
+ }
+
+ if (adc_sel != MT6370_ADC_TS_BAT && adc_sel != MT6370_ADC_TEMP_JC)
+ *adc_val = adc_result / 1000;
+ else
+ *adc_val = adc_result;
+ mt6370_enable_hidden_mode(0);
+#endif
+ mutex_unlock(&adc_access_lock);
+ return rv;
+}
+
+int charger_get_vbus_voltage(int port)
+{
+ static int vbus_mv;
+
+ rt946x_get_adc(RT946X_ADC_VBUS_DIV5, &vbus_mv);
+ return vbus_mv;
+}
+
+#ifdef CONFIG_CHARGER_MT6370
+static int mt6370_toggle_cfo(void)
+{
+ int rv, data;
+
+ rv = rt946x_read8(MT6370_REG_FLEDEN, &data);
+ if (rv)
+ return rv;
+
+ if (data & MT6370_STROBE_EN_MASK)
+ return rv;
+
+ /* read data */
+ rv = rt946x_read8(RT946X_REG_CHGCTRL2, &data);
+ if (rv)
+ return rv;
+
+ /* cfo off */
+ data &= ~RT946X_MASK_CFO_EN;
+ rv = rt946x_write8(RT946X_REG_CHGCTRL2, data);
+ if (rv)
+ return rv;
+
+ /* cfo on */
+ data |= RT946X_MASK_CFO_EN;
+ return rt946x_write8(RT946X_REG_CHGCTRL2, data);
+}
+
+static int mt6370_pmu_chg_mivr_irq_handler(void)
+{
+ int rv, ibus = 0, mivr_stat;
+
+ rv = mt6370_pmu_reg_test_bit(MT6370_REG_CHGSTAT1,
+ MT6370_SHIFT_MIVR_STAT, &mivr_stat);
+ if (rv)
+ return rv;
+
+ if (!mivr_stat) {
+ CPRINTS("%s: mivr stat not act", __func__);
+ return rv;
+ }
+
+ rv = rt946x_get_adc(MT6370_ADC_IBUS, &ibus);
+ if (rv)
+ return rv;
+
+ if (ibus < 100) /* 100mA */
+ rv = mt6370_toggle_cfo();
+
+ return rv;
+}
+
+static int mt6370_irq_handler(void)
+{
+ int data, mask, ret, reg_val;
+ int stat_chg, valid_chg, stat_old, stat_new;
+
+ ret = rt946x_write8(MT6370_REG_IRQMASK, MT6370_IRQ_MASK_ALL);
+ if (ret)
+ return ret;
+
+ ret = rt946x_read8(MT6370_REG_IRQIND, &reg_val);
+ if (ret)
+ return ret;
+
+ /* read stat before reading irq evt */
+ ret = rt946x_read8(MT6370_REG_CHGSTAT1, &stat_old);
+ if (ret)
+ return ret;
+
+ /* workaround for irq, divided irq event into upper and lower */
+ ret = rt946x_read8(MT6370_REG_CHGIRQ1, &data);
+ if (ret)
+ return ret;
+
+ /* read stat after reading irq evt */
+ ret = rt946x_read8(MT6370_REG_CHGSTAT1, &stat_new);
+ if (ret)
+ return ret;
+
+ ret = rt946x_read8(MT6370_REG_CHGMASK1, &mask);
+ if (ret)
+ return ret;
+
+ ret = rt946x_write8(MT6370_REG_IRQMASK, 0x00);
+ if (ret)
+ return ret;
+
+ stat_chg = stat_old ^ stat_new;
+ valid_chg = (stat_new & 0xF1) | (~stat_new & 0xF1);
+ data |= (stat_chg & valid_chg);
+ data &= ~mask;
+ if (data)
+ ret = mt6370_pmu_chg_mivr_irq_handler();
+ return ret;
+}
+#endif /* CONFIG_CHARGER_MT6370 */
+
void usb_charger_task(void *u)
{
struct charge_port_info chg;
@@ -1089,6 +1341,10 @@ void usb_charger_task(void *u)
chg.voltage = USB_CHARGER_VOLTAGE_MV;
while (1) {
+#ifdef CONFIG_CHARGER_MT6370
+ mt6370_irq_handler();
+#endif /* CONFIG_CHARGER_MT6370 */
+
rt946x_read8(RT946X_REG_DPDMIRQ, &reg);
/* VBUS attach event */
diff --git a/driver/charger/rt946x.h b/driver/charger/rt946x.h
index 9cb8b7dfd8..9797e95255 100644
--- a/driver/charger/rt946x.h
+++ b/driver/charger/rt946x.h
@@ -94,6 +94,13 @@
#define RT946X_REG_CORECTRL_RST RT946X_REG_CORECTRL2
#define MT6370_REG_RSTPASCODE1 0x03
#define MT6370_REG_RSTPASCODE2 0x04
+#define MT6370_REG_HIDDENPASCODE1 0x07
+#define MT6370_REG_HIDDENPASCODE2 0x08
+#define MT6370_REG_HIDDENPASCODE3 0x09
+#define MT6370_REG_HIDDENPASCODE4 0x0A
+#define MT6370_REG_IRQIND 0x0B
+#define MT6370_REG_IRQMASK 0x0C
+#define MT6370_REG_OSCCTRL 0x10
#define RT946X_REG_CHGCTRL1 0x11
#define RT946X_REG_CHGCTRL2 0x12
#define RT946X_REG_CHGCTRL3 0x13
@@ -117,10 +124,14 @@
#define MT6370_REG_QCSTATUS2 0x29
#define RT946X_REG_CHGCTRL17 0X2B
#define RT946X_REG_CHGCTRL18 0X2C
+#define MT6370_REG_CHGHIDDENCTRL15 0x3E
#define RT946X_REG_CHGSTAT 0X4A
#define RT946X_REG_CHGNTC 0X4B
#define RT946X_REG_ADCDATAH 0X4C
#define RT946X_REG_ADCDATAL 0X4D
+/* FLED */
+#define MT6370_REG_FLEDEN 0x7E
+/* LDO */
#define MT6370_REG_LDOCFG 0X80
#define MT6370_REG_LDOVOUT 0X81
/* RGB led */
@@ -148,7 +159,7 @@
#define MT6370_REG_DBVBST 0XB2
#define MT6370_REG_DBVPOS 0XB3
#define MT6370_REG_DBVNEG 0XB4
-
+#define MT6370_REG_CHGIRQ1 0xC0
#define RT946X_REG_DPDMIRQ 0xC6
/* status event */
@@ -348,6 +359,7 @@
/* ========== CHGCTRL12 0x0C ============ */
#define RT946X_SHIFT_TMR_EN 1
+#define MT6370_IRQ_MASK_ALL 0xFE
#define RT946X_MASK_TMR_EN BIT(RT946X_SHIFT_TMR_EN)
@@ -482,6 +494,8 @@
#define RT946X_MASK_DPDMIRQ_ATTACH BIT(RT946X_SHIFT_DPDMIRQ_ATTACH)
#endif
+/* ========== FLED EN 0x7E (mt6370) ============ */
+#define MT6370_STROBE_EN_MASK 0x04
/* ========== LDOCFG 0x80 (mt6370) ============ */
#define MT6370_SHIFT_LDOCFG_OMS 6
@@ -608,6 +622,13 @@
#define MT6370_BLDIM_DEFAULT 0x7ff
+/* ========== CHG_IRQ1 0xC0 (mt6370) ============ */
+#define MT6370_SHIFT_MIVR_EVT 6
+#define MT6370_MASK_MIVR_EVT BIT(MT6370_SHIFT_MIVR_EVT)
+
+/* ========== CHGSTAT2 0xD0 (mt6370) ============ */
+#define MT6370_SHIFT_MIVR_STAT 6
+
/* ========== CHGSTAT2 0xD1 (mt6370) ============ */
#ifdef CONFIG_CHARGER_MT6370
#define MT6370_SHIFT_CHG_VBUSOV_STAT 7
@@ -619,6 +640,27 @@
#define MT6370_MASK_CHG_VBATOV_STAT BIT(MT6370_SHIFT_CHG_VBATOV_STAT)
#endif
+/* ADC unit/offset */
+#define MT6370_ADC_UNIT_VBUS_DIV5 25000 /* uV */
+#define MT6370_ADC_UNIT_VBUS_DIV2 10000 /* uV */
+#define MT6370_ADC_UNIT_VSYS 5000 /* uV */
+#define MT6370_ADC_UNIT_VBAT 5000 /* uV */
+#define MT6370_ADC_UNIT_TS_BAT 25 /* 0.01% */
+#define MT6370_ADC_UNIT_IBUS 50000 /* uA */
+#define MT6370_ADC_UNIT_IBAT 50000 /* uA */
+#define MT6370_ADC_UNIT_CHG_VDDP 5000 /* uV */
+#define MT6370_ADC_UNIT_TEMP_JC 2 /* degree */
+
+#define MT6370_ADC_OFFSET_VBUS_DIV5 0 /* mV */
+#define MT6370_ADC_OFFSET_VBUS_DIV2 0 /* mV */
+#define MT6370_ADC_OFFSET_VSYS 0 /* mV */
+#define MT6370_ADC_OFFSET_VBAT 0 /* mV */
+#define MT6370_ADC_OFFSET_TS_BAT 0 /* % */
+#define MT6370_ADC_OFFSET_IBUS 0 /* mA */
+#define MT6370_ADC_OFFSET_IBAT 0 /* mA */
+#define MT6370_ADC_OFFSET_CHG_VDDP 0 /* mV */
+#define MT6370_ADC_OFFSET_TEMP_JC (-40) /* degree */
+
/* ========== Variant-specific configuration ============ */
#if defined(CONFIG_CHARGER_RT9466)
#define RT946X_CHARGER_NAME "rt9466"