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_event(void);
void usbpd_disable_charging(void);
void usbpd_enable_charging(void);
#endif // _BOARD_USBPD_H

View File

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

View File

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

View File

@ -5,3 +5,7 @@
void usbpd_init(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
#include <board/battery.h>
#include <board/gpio.h>
#include <board/power.h>
#include <board/usbpd.h>
#include <common/debug.h>
#include <ec/i2c.h>
@ -16,9 +18,9 @@ void usbpd_init(void) {
i2c_reset(&I2C_USBPD, true);
}
int16_t usbpd_current_limit(void) {
static 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);
int16_t res = i2c_get(&I2C_USBPD, USBPD_ADDRESS, REG_ACTIVE_CONTRACT_PDO, value, sizeof(value));
if (res == 7) {
if (value[0] == 6) {
uint32_t pdo =
@ -26,40 +28,39 @@ int16_t usbpd_current_limit(void) {
(((uint32_t)value[2]) << 8) |
(((uint32_t)value[3]) << 16) |
(((uint32_t)value[4]) << 24);
TRACE("USBPD PDO %08lX\n", pdo);
DEBUG("USBPD PDO %08lX ", pdo);
uint8_t kind = (uint8_t)((pdo >> 30) & 0b11);
if (kind == 0b00) {
TRACE(" FIX");
DEBUG("FIX ");
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;
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;
} else if (kind == 0b01) {
TRACE(" BAT");
DEBUG("BAT ");
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;
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;
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
return -0x5000;
} else if (kind == 0b10) {
TRACE(" VAR");
DEBUG("VAR ");
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;
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;
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;
} else {
TRACE(" AUG");
DEBUG("AUG\n");
//TODO
return -0x4000;
}
TRACE("\n");
} else {
return -(0x3000 | (int16_t)value[0]);
}
@ -70,11 +71,11 @@ int16_t usbpd_current_limit(void) {
}
}
void usbpd_event(void) {
/* Dump all registers for debugging
for(uint8_t reg = 0x00; reg < 0x80; reg+=1) {
static void usbpd_dump(void) {
/* Dump all registers for debugging */
for(uint8_t reg = 0x00; reg < 0x40; reg+=1) {
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) {
DEBUG("USBPD %02X ERROR %04X\n", reg, res);
} else {
@ -85,24 +86,171 @@ void usbpd_event(void) {
DEBUG("\n");
}
}
*/
}
DEBUG("USBPD LIMIT ");
void usbpd_event(void) {
bool update = false;
static bool last_ac_in = false;
bool ac_in = !gpio_get(&ACIN_N);
if (ac_in != last_ac_in) {
last_ac_in = ac_in;
update = true;
DEBUG("AC_IN %d\n", ac_in);
}
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);
//TODO: determine if USB-PD is actually plugged (SINK_CTRL_EC)
battery_charger_input_current = CHARGER_INPUT_CURRENT;
} else {
if (res < CHARGER_INPUT_CURRENT) {
} else if (res < CHARGER_INPUT_CURRENT) {
// Use USB-PD charger current if it provides less than AC adapter
battery_charger_input_current = (uint16_t)res;
next_input_current = (uint16_t)res;
} else {
// Use AC adapter current if USB-PD charger supports more
battery_charger_input_current = CHARGER_INPUT_CURRENT;
// 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?)
}
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_RSMRST_N = GPIO(E, 5);
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 LED_ACIN = GPIO(H, 2);
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 PWR_BTN_N = GPIO(D, 5);
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 VA_EC_EN = GPIO(J, 4);
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_RSMRST_N;
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 LED_ACIN;
#define HAVE_LED_AIRPLANE_N 0
@ -35,6 +36,7 @@ extern struct Gpio __code PD_EN;
#define HAVE_PM_PWROK 0
extern struct Gpio __code PWR_BTN_N;
extern struct Gpio __code PWR_SW_N;
extern struct Gpio __code SINK_CTRL;
extern struct Gpio __code SLP_SUS_N;
#define HAVE_SUS_PWR_ACK 0
extern struct Gpio __code VA_EC_EN;