Hack and slash until it is done
This commit is contained in:
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -5,3 +5,7 @@
|
||||
void usbpd_init(void) {}
|
||||
|
||||
void usbpd_event(void) {}
|
||||
|
||||
void usbpd_disable_charging(void) {}
|
||||
|
||||
void usbpd_enable_charging(void) {}
|
||||
|
@ -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 ");
|
||||
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) {
|
||||
// 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;
|
||||
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);
|
||||
} 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?)
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
Reference in New Issue
Block a user