Hack and slash until it is done

This commit is contained in:
Jeremy Soller
2023-03-29 13:37:26 -06:00
parent 7a5c111786
commit 658f24a8a8
7 changed files with 199 additions and 38 deletions

View File

@ -5,5 +5,7 @@
void usbpd_init(void); void usbpd_init(void);
void usbpd_event(void); void usbpd_event(void);
void usbpd_disable_charging(void);
void usbpd_enable_charging(void);
#endif // _BOARD_USBPD_H #endif // _BOARD_USBPD_H

View File

@ -104,6 +104,9 @@ void main(void) {
for (main_cycle = 0;; main_cycle++) { for (main_cycle = 0;; main_cycle++) {
switch (main_cycle % 3U) { switch (main_cycle % 3U) {
case 0: case 0:
// Handle USB-C events immediately before power states
usbpd_event();
// Handle power states // Handle power states
power_event(); power_event();
break; break;

View File

@ -244,6 +244,9 @@ void power_on(void) {
// Wait for SUSPWRDNACK validity // Wait for SUSPWRDNACK validity
tPLT01; tPLT01;
// Ensure USB-PD is disabled before turning on CPU
usbpd_disable_charging();
GPIO_SET_DEBUG(PWR_BTN_N, false); GPIO_SET_DEBUG(PWR_BTN_N, false);
delay_ms(32); // PWRBTN# must assert for at least 16 ms, we do twice that delay_ms(32); // PWRBTN# must assert for at least 16 ms, we do twice that
GPIO_SET_DEBUG(PWR_BTN_N, true); GPIO_SET_DEBUG(PWR_BTN_N, true);
@ -374,9 +377,6 @@ void power_event(void) {
//TODO: if this returns false, retry? //TODO: if this returns false, retry?
power_peci_limit(false); power_peci_limit(false);
// Check for USB-PD charger limit
usbpd_event();
// Configure smart charger // Configure smart charger
DEBUG("Power adapter "); DEBUG("Power adapter ");
if (ac_new) { if (ac_new) {

View File

@ -5,3 +5,7 @@
void usbpd_init(void) {} void usbpd_init(void) {}
void usbpd_event(void) {} void usbpd_event(void) {}
void usbpd_disable_charging(void) {}
void usbpd_enable_charging(void) {}

View File

@ -4,6 +4,8 @@
// I2C register reference: https://www.ti.com/lit/ug/slvubh2b/slvubh2b.pdf // I2C register reference: https://www.ti.com/lit/ug/slvubh2b/slvubh2b.pdf
#include <board/battery.h> #include <board/battery.h>
#include <board/gpio.h>
#include <board/power.h>
#include <board/usbpd.h> #include <board/usbpd.h>
#include <common/debug.h> #include <common/debug.h>
#include <ec/i2c.h> #include <ec/i2c.h>
@ -16,9 +18,9 @@ void usbpd_init(void) {
i2c_reset(&I2C_USBPD, true); i2c_reset(&I2C_USBPD, true);
} }
int16_t usbpd_current_limit(void) { static int16_t usbpd_current_limit(void) {
uint8_t value[7] = { 0 }; uint8_t value[7] = { 0 };
int16_t res = i2c_get(&I2C_USBPD, USBPD_ADDRESS, REG_ACTIVE_CONTRACT_PDO, value, 7); int16_t res = i2c_get(&I2C_USBPD, USBPD_ADDRESS, REG_ACTIVE_CONTRACT_PDO, value, sizeof(value));
if (res == 7) { if (res == 7) {
if (value[0] == 6) { if (value[0] == 6) {
uint32_t pdo = uint32_t pdo =
@ -26,40 +28,39 @@ int16_t usbpd_current_limit(void) {
(((uint32_t)value[2]) << 8) | (((uint32_t)value[2]) << 8) |
(((uint32_t)value[3]) << 16) | (((uint32_t)value[3]) << 16) |
(((uint32_t)value[4]) << 24); (((uint32_t)value[4]) << 24);
TRACE("USBPD PDO %08lX\n", pdo); DEBUG("USBPD PDO %08lX ", pdo);
uint8_t kind = (uint8_t)((pdo >> 30) & 0b11); uint8_t kind = (uint8_t)((pdo >> 30) & 0b11);
if (kind == 0b00) { if (kind == 0b00) {
TRACE(" FIX"); DEBUG("FIX ");
uint32_t current_ma = (pdo & 0x3FF) * 10; uint32_t current_ma = (pdo & 0x3FF) * 10;
TRACE(" %ld.%03ld A", current_ma / 1000, current_ma % 1000); DEBUG("%ld.%03ld A ", current_ma / 1000, current_ma % 1000);
uint32_t voltage_mv = ((pdo >> 10) & 0x3FF) * 50; uint32_t voltage_mv = ((pdo >> 10) & 0x3FF) * 50;
TRACE(" %ld.%03ld V", voltage_mv / 1000, voltage_mv % 1000); DEBUG("%ld.%03ld V\n", voltage_mv / 1000, voltage_mv % 1000);
return (int16_t)current_ma; return (int16_t)current_ma;
} else if (kind == 0b01) { } else if (kind == 0b01) {
TRACE(" BAT"); DEBUG("BAT ");
uint32_t power_mw = (pdo & 0x3FF) * 250; uint32_t power_mw = (pdo & 0x3FF) * 250;
TRACE(" %ld.%03ld W", power_mw / 1000, power_mw % 1000); DEBUG("%ld.%03ld W ", power_mw / 1000, power_mw % 1000);
uint32_t min_voltage_mv = ((pdo >> 10) & 0x3FF) * 50; uint32_t min_voltage_mv = ((pdo >> 10) & 0x3FF) * 50;
TRACE(" %ld.%03ld Vmin", min_voltage_mv / 1000, min_voltage_mv % 1000); DEBUG("%ld.%03ld Vmin ", min_voltage_mv / 1000, min_voltage_mv % 1000);
uint32_t max_voltage_mv = ((pdo >> 20) & 0x3FF) * 50; uint32_t max_voltage_mv = ((pdo >> 20) & 0x3FF) * 50;
TRACE(" %ld.%03ld Vax", max_voltage_mv / 1000, max_voltage_mv % 1000); DEBUG("%ld.%03ld Vax\n", max_voltage_mv / 1000, max_voltage_mv % 1000);
//TODO //TODO
return -0x5000; return -0x5000;
} else if (kind == 0b10) { } else if (kind == 0b10) {
TRACE(" VAR"); DEBUG("VAR ");
uint32_t current_ma = (pdo & 0x3FF) * 10; uint32_t current_ma = (pdo & 0x3FF) * 10;
TRACE(" %ld.%03ld A", current_ma / 1000, current_ma % 1000); DEBUG("%ld.%03ld A ", current_ma / 1000, current_ma % 1000);
uint32_t min_voltage_mv = ((pdo >> 10) & 0x3FF) * 50; uint32_t min_voltage_mv = ((pdo >> 10) & 0x3FF) * 50;
TRACE(" %ld.%03ld Vmin", min_voltage_mv / 1000, min_voltage_mv % 1000); DEBUG("%ld.%03ld Vmin ", min_voltage_mv / 1000, min_voltage_mv % 1000);
uint32_t max_voltage_mv = ((pdo >> 20) & 0x3FF) * 50; uint32_t max_voltage_mv = ((pdo >> 20) & 0x3FF) * 50;
TRACE(" %ld.%03ld Vax", max_voltage_mv / 1000, max_voltage_mv % 1000); DEBUG("%ld.%03ld Vax\n", max_voltage_mv / 1000, max_voltage_mv % 1000);
return (int16_t)current_ma; return (int16_t)current_ma;
} else { } else {
TRACE(" AUG"); DEBUG("AUG\n");
//TODO //TODO
return -0x4000; return -0x4000;
} }
TRACE("\n");
} else { } else {
return -(0x3000 | (int16_t)value[0]); return -(0x3000 | (int16_t)value[0]);
} }
@ -70,11 +71,11 @@ int16_t usbpd_current_limit(void) {
} }
} }
void usbpd_event(void) { static void usbpd_dump(void) {
/* Dump all registers for debugging /* Dump all registers for debugging */
for(uint8_t reg = 0x00; reg < 0x80; reg+=1) { for(uint8_t reg = 0x00; reg < 0x40; reg+=1) {
uint8_t value[65] = { 0 }; uint8_t value[65] = { 0 };
int16_t res = i2c_get(&I2C_DGPU, USBPD_ADDRESS, reg, value, 65); int16_t res = i2c_get(&I2C_USBPD, USBPD_ADDRESS, reg, value, sizeof(value));
if (res < 0) { if (res < 0) {
DEBUG("USBPD %02X ERROR %04X\n", reg, res); DEBUG("USBPD %02X ERROR %04X\n", reg, res);
} else { } else {
@ -85,24 +86,171 @@ void usbpd_event(void) {
DEBUG("\n"); DEBUG("\n");
} }
} }
*/ }
DEBUG("USBPD LIMIT "); void usbpd_event(void) {
int16_t res = usbpd_current_limit(); bool update = false;
if (res < 0) {
DEBUG("ERR %04X\n", -res); static bool last_ac_in = false;
//TODO: determine if USB-PD is actually plugged (SINK_CTRL_EC) bool ac_in = !gpio_get(&ACIN_N);
battery_charger_input_current = CHARGER_INPUT_CURRENT; if (ac_in != last_ac_in) {
} else { last_ac_in = ac_in;
if (res < CHARGER_INPUT_CURRENT) { update = true;
// Use USB-PD charger current if it provides less than AC adapter
battery_charger_input_current = (uint16_t)res; DEBUG("AC_IN %d\n", ac_in);
} else { }
// Use AC adapter current if USB-PD charger supports more
battery_charger_input_current = CHARGER_INPUT_CURRENT; static bool last_jack_in = false;
bool jack_in = !gpio_get(&JACK_IN_N);
if (jack_in != last_jack_in) {
last_jack_in = jack_in;
update = true;
DEBUG("JACK_IN %d\n", jack_in);
}
static bool last_sink_ctrl = false;
bool sink_ctrl = gpio_get(&SINK_CTRL);
if (sink_ctrl != last_sink_ctrl) {
last_sink_ctrl = sink_ctrl;
update = true;
DEBUG("SINK_CTRL %d\n", sink_ctrl);
}
static enum PowerState last_power_state = POWER_STATE_OFF;
update_power_state();
if (power_state != last_power_state) {
last_power_state = power_state;
update = true;
}
if (update) {
// Default to disabling input current
uint16_t next_input_current = 0;
if (ac_in) {
if (jack_in) {
// Use default input current
next_input_current = CHARGER_INPUT_CURRENT;
} else if (sink_ctrl) {
int16_t res = usbpd_current_limit();
if (res < 0) {
DEBUG("ERR %04X\n", -res);
} else if (res < CHARGER_INPUT_CURRENT) {
// Use USB-PD charger current if it provides less than AC adapter
next_input_current = (uint16_t)res;
} else {
// Use default input current if USB-PD charger provides more
next_input_current = CHARGER_INPUT_CURRENT;
}
}
}
if (sink_ctrl) {
if (jack_in || power_state == POWER_STATE_S0) {
usbpd_disable_charging();
} else {
usbpd_enable_charging();
}
}
if (next_input_current != battery_charger_input_current) {
battery_charger_input_current = next_input_current;
DEBUG("CHARGER LIMIT %d mA\n", battery_charger_input_current);
//TODO: update smart charger
} }
DEBUG("%d mA\n", battery_charger_input_current);
} }
//TODO: dynamically set charger current (is this needed?) //TODO: dynamically set charger current (is this needed?)
} }
static int16_t usbpd_aneg(void) {
int16_t res;
uint8_t cmd[5] = { 4, 'A', 'N', 'e', 'g' };
res = i2c_set(&I2C_USBPD, USBPD_ADDRESS, 0x08, cmd, sizeof(cmd));
if (res < 0) {
return res;
}
//TODO: wait on command completion
return 0;
}
void usbpd_disable_charging(void) {
int16_t res;
DEBUG("USBPD DISABLE CHARGING ");
// Read current value
uint8_t value[2] = { 0 };
res = i2c_get(&I2C_USBPD, USBPD_ADDRESS, 0x33, value, sizeof(value));
if (res < 0) {
DEBUG("ERR %04X\n", -res);
return;
}
// Charging already disabled
if (value[1] == 1) {
DEBUG("NOP\n");
return;
}
// Enable only the first TX sink PDO (5V)
value[0] = 1;
value[1] = 1;
res = i2c_set(&I2C_USBPD, USBPD_ADDRESS, 0x33, value, sizeof(value));
if (res < 0) {
DEBUG("ERR %04X\n", -res);
return;
}
// Auto negotiate sink update
res = usbpd_aneg();
if (res < 0) {
DEBUG("ERR %04X\n", -res);
return;
}
DEBUG("OK\n");
}
void usbpd_enable_charging(void) {
int16_t res;
DEBUG("USBPD ENABLE CHARGING ");
// Read current value
uint8_t value[2] = { 0 };
res = i2c_get(&I2C_USBPD, USBPD_ADDRESS, 0x33, value, sizeof(value));
if (res < 0) {
DEBUG("ERR %04X\n", -res);
return;
}
// Charging already enabled
if (value[1] == 2) {
DEBUG("NOP\n");
return;
}
// Enable the first two TX sink PDO (5V and 20V)
value[0] = 1;
value[1] = 2;
res = i2c_set(&I2C_USBPD, USBPD_ADDRESS, 0x33, value, sizeof(value));
if (res < 0) {
DEBUG("ERR %04X\n", -res);
return;
}
// Auto negotiate sink update
res = usbpd_aneg();
if (res < 0) {
DEBUG("ERR %04X\n", -res);
return;
}
DEBUG("OK\n");
}

View File

@ -15,6 +15,7 @@ struct Gpio __code DGPU_PWR_EN = GPIO(H, 4);
struct Gpio __code EC_EN = GPIO(B, 6); // renamed to SUSBC_EC# struct Gpio __code EC_EN = GPIO(B, 6); // renamed to SUSBC_EC#
struct Gpio __code EC_RSMRST_N = GPIO(E, 5); struct Gpio __code EC_RSMRST_N = GPIO(E, 5);
struct Gpio __code GC6_FB_EN = GPIO(J, 3); struct Gpio __code GC6_FB_EN = GPIO(J, 3);
struct Gpio __code JACK_IN_N = GPIO(G, 1);
struct Gpio __code LAN_WAKEUP_N = GPIO(B, 2); struct Gpio __code LAN_WAKEUP_N = GPIO(B, 2);
struct Gpio __code LED_ACIN = GPIO(H, 2); struct Gpio __code LED_ACIN = GPIO(H, 2);
struct Gpio __code LED_BAT_CHG = GPIO(H, 5); struct Gpio __code LED_BAT_CHG = GPIO(H, 5);
@ -27,6 +28,7 @@ struct Gpio __code PCH_PWROK_EC = GPIO(C, 6); // renamed to SYS_PWROK_EC
struct Gpio __code PD_EN = GPIO(F, 6); // renamed to PD_POWER_EN struct Gpio __code PD_EN = GPIO(F, 6); // renamed to PD_POWER_EN
struct Gpio __code PWR_BTN_N = GPIO(D, 5); struct Gpio __code PWR_BTN_N = GPIO(D, 5);
struct Gpio __code PWR_SW_N = GPIO(B, 3); struct Gpio __code PWR_SW_N = GPIO(B, 3);
struct Gpio __code SINK_CTRL = GPIO(H, 1);
struct Gpio __code SLP_SUS_N = GPIO(H, 7); struct Gpio __code SLP_SUS_N = GPIO(H, 7);
struct Gpio __code VA_EC_EN = GPIO(J, 4); struct Gpio __code VA_EC_EN = GPIO(J, 4);
struct Gpio __code WLAN_PWR_EN = GPIO(D, 3); struct Gpio __code WLAN_PWR_EN = GPIO(D, 3);

View File

@ -20,6 +20,7 @@ extern struct Gpio __code DGPU_PWR_EN;
extern struct Gpio __code EC_EN; extern struct Gpio __code EC_EN;
extern struct Gpio __code EC_RSMRST_N; extern struct Gpio __code EC_RSMRST_N;
extern struct Gpio __code GC6_FB_EN; extern struct Gpio __code GC6_FB_EN;
extern struct Gpio __code JACK_IN_N;
extern struct Gpio __code LAN_WAKEUP_N; extern struct Gpio __code LAN_WAKEUP_N;
extern struct Gpio __code LED_ACIN; extern struct Gpio __code LED_ACIN;
#define HAVE_LED_AIRPLANE_N 0 #define HAVE_LED_AIRPLANE_N 0
@ -35,6 +36,7 @@ extern struct Gpio __code PD_EN;
#define HAVE_PM_PWROK 0 #define HAVE_PM_PWROK 0
extern struct Gpio __code PWR_BTN_N; extern struct Gpio __code PWR_BTN_N;
extern struct Gpio __code PWR_SW_N; extern struct Gpio __code PWR_SW_N;
extern struct Gpio __code SINK_CTRL;
extern struct Gpio __code SLP_SUS_N; extern struct Gpio __code SLP_SUS_N;
#define HAVE_SUS_PWR_ACK 0 #define HAVE_SUS_PWR_ACK 0
extern struct Gpio __code VA_EC_EN; extern struct Gpio __code VA_EC_EN;