diff --git a/src/board/system76/common/usbpd/tps65987.c b/src/board/system76/common/usbpd/tps65987.c index 7087f78..aa3df13 100644 --- a/src/board/system76/common/usbpd/tps65987.c +++ b/src/board/system76/common/usbpd/tps65987.c @@ -3,6 +3,7 @@ // USB-PD driver for TPS65987 and the mostly compatible TPS65993 and TPS65994. // I2C register reference: https://www.ti.com/lit/ug/slvubh2b/slvubh2b.pdf +#include #include #include #include @@ -15,6 +16,60 @@ void usbpd_init(void) { i2c_reset(&I2C_USBPD, true); } +int16_t usbpd_current_limit(void) { + uint8_t value[7] = { 0 }; + int16_t res = i2c_get(&I2C_USBPD, USBPD_ADDRESS, REG_ACTIVE_CONTRACT_PDO, value, 7); + if (res == 7) { + if (value[0] == 6) { + uint32_t pdo = + ((uint32_t)value[1]) | + (((uint32_t)value[2]) << 8) | + (((uint32_t)value[3]) << 16) | + (((uint32_t)value[4]) << 24); + TRACE("USBPD PDO %08lX\n", pdo); + uint8_t kind = (uint8_t)((pdo >> 30) & 0b11); + if (kind == 0b00) { + TRACE(" FIX"); + uint32_t current_ma = (pdo & 0x3FF) * 10; + TRACE(" %ld.%03ld A", current_ma / 1000, current_ma % 1000); + uint32_t voltage_mv = ((pdo >> 10) & 0x3FF) * 50; + TRACE(" %ld.%03ld V", voltage_mv / 1000, voltage_mv % 1000); + return (int16_t)current_ma; + } else if (kind == 0b01) { + TRACE(" BAT"); + uint32_t power_mw = (pdo & 0x3FF) * 250; + TRACE(" %ld.%03ld W", power_mw / 1000, power_mw % 1000); + uint32_t min_voltage_mv = ((pdo >> 10) & 0x3FF) * 50; + TRACE(" %ld.%03ld Vmin", min_voltage_mv / 1000, min_voltage_mv % 1000); + uint32_t max_voltage_mv = ((pdo >> 20) & 0x3FF) * 50; + TRACE(" %ld.%03ld Vax", max_voltage_mv / 1000, max_voltage_mv % 1000); + //TODO + return -0x5000; + } else if (kind == 0b10) { + TRACE(" VAR"); + uint32_t current_ma = (pdo & 0x3FF) * 10; + TRACE(" %ld.%03ld A", current_ma / 1000, current_ma % 1000); + uint32_t min_voltage_mv = ((pdo >> 10) & 0x3FF) * 50; + TRACE(" %ld.%03ld Vmin", min_voltage_mv / 1000, min_voltage_mv % 1000); + uint32_t max_voltage_mv = ((pdo >> 20) & 0x3FF) * 50; + TRACE(" %ld.%03ld Vax", max_voltage_mv / 1000, max_voltage_mv % 1000); + return (int16_t)current_ma; + } else { + TRACE(" AUG"); + //TODO + return -0x4000; + } + TRACE("\n"); + } else { + return -(0x3000 | (int16_t)value[0]); + } + } else if (res < 0) { + return res; + } else { + return -(0x2000 | res); + } +} + void usbpd_event(void) { /* Dump all registers for debugging for(uint8_t reg = 0x00; reg < 0x80; reg+=1) { @@ -32,50 +87,22 @@ void usbpd_event(void) { } */ - uint8_t value[7] = { 0 }; - int16_t res = i2c_get(&I2C_USBPD, USBPD_ADDRESS, REG_ACTIVE_CONTRACT_PDO, value, 7); - if (res == 7) { - if (value[0] == 6) { - uint32_t pdo = - ((uint32_t)value[1]) | - (((uint32_t)value[2]) << 8) | - (((uint32_t)value[3]) << 16) | - (((uint32_t)value[4]) << 24); - DEBUG("USBPD PDO %08lX\n", pdo); - uint8_t kind = (uint8_t)((pdo >> 30) & 0b11); - if (kind == 0b00) { - DEBUG(" FIX"); - uint32_t current_ma = (pdo & 0x3FF) * 10; - DEBUG(" %ld.%03ld A", current_ma / 1000, current_ma % 1000); - uint32_t voltage_mv = ((pdo >> 10) & 0x3FF) * 50; - DEBUG(" %ld.%03ld V", voltage_mv / 1000, voltage_mv % 1000); - } else if (kind == 0b01) { - DEBUG(" BAT"); - uint32_t power_mw = (pdo & 0x3FF) * 250; - DEBUG(" %ld.%03ld W", power_mw / 1000, power_mw % 1000); - uint32_t min_voltage_mv = ((pdo >> 10) & 0x3FF) * 50; - DEBUG(" %ld.%03ld Vmin", min_voltage_mv / 1000, min_voltage_mv % 1000); - uint32_t max_voltage_mv = ((pdo >> 20) & 0x3FF) * 50; - DEBUG(" %ld.%03ld Vax", max_voltage_mv / 1000, max_voltage_mv % 1000); - } else if (kind == 0b10) { - DEBUG(" VAR"); - uint32_t current_ma = (pdo & 0x3FF) * 10; - DEBUG(" %ld.%03ld A", current_ma / 1000, current_ma % 1000); - uint32_t min_voltage_mv = ((pdo >> 10) & 0x3FF) * 50; - DEBUG(" %ld.%03ld Vmin", min_voltage_mv / 1000, min_voltage_mv % 1000); - uint32_t max_voltage_mv = ((pdo >> 20) & 0x3FF) * 50; - DEBUG(" %ld.%03ld Vax", max_voltage_mv / 1000, max_voltage_mv % 1000); - } else { - //TODO - DEBUG(" AUG"); - } - DEBUG("\n"); - } else { - DEBUG("USBPD PDO LEN %d\n", value[0]); - } - } else if (res < 0) { - DEBUG("USBPD ERR %04X\n", -res); + DEBUG("USBPD LIMIT "); + int16_t res = usbpd_current_limit(); + if (res < 0) { + DEBUG("ERR %04X\n", -res); + //TODO: determine if USB-PD is actually plugged (SINK_CTRL_EC) + battery_charger_input_current = CHARGER_INPUT_CURRENT; } else { - DEBUG("USBPD I2C LEN %d\n", res); + if (res < CHARGER_INPUT_CURRENT) { + // Use USB-PD charger current if it provides less than AC adapter + battery_charger_input_current = (uint16_t)res; + } else { + // Use AC adapter current if USB-PD charger supports more + battery_charger_input_current = CHARGER_INPUT_CURRENT; + } + DEBUG("%d mA\n", battery_charger_input_current); } + + //TODO: dynamically set charger current (is this needed?) }