diff options
author | Shawn Nematbakhsh <shawnn@chromium.org> | 2014-10-06 15:19:50 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-10-22 19:44:08 +0000 |
commit | de3ef9fa6e384dd5ab80185c9067009c17411164 (patch) | |
tree | c3dcd9cf2285b034cdbc5d0d60056c1f574c66f3 | |
parent | a12efa99c40a60b72eb4289deb48359b933625fa (diff) | |
download | chrome-ec-de3ef9fa6e384dd5ab80185c9067009c17411164.tar.gz |
samus_pd: Add BC1.2 charging and charge port + current limit selection
On an interrupt from the Pericom charger detection IC, check the current
limit of the attached charger. Charge manager is informed of available
charge from BC1.2 source and PD sources and selects the proper port + charge
limit in each case.
BUG=chrome-os-partner:32003
TEST=Manual on samus. Insert Apple charger, verify charge limit is
selected appropriately. Insert PD charger, verify that charge port
switches to PD port. Remove + reinsert chargers, verify that port /
limit is selected appropriately.
BRANCH=samus
Change-Id: I47e1e3be1c522f1e11529a0b4ac665e695f33e14
Signed-off-by: Shawn Nematbakhsh <shawnn@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/221791
Reviewed-by: Alec Berg <alecaberg@chromium.org>
-rw-r--r-- | board/samus_pd/board.c | 116 | ||||
-rw-r--r-- | board/samus_pd/board.h | 26 | ||||
-rw-r--r-- | board/samus_pd/gpio.inc | 8 | ||||
-rw-r--r-- | board/samus_pd/usb_pd_config.h | 10 | ||||
-rw-r--r-- | board/samus_pd/usb_pd_policy.c | 14 |
5 files changed, 163 insertions, 11 deletions
diff --git a/board/samus_pd/board.c b/board/samus_pd/board.c index deca02675e..9c46b97952 100644 --- a/board/samus_pd/board.c +++ b/board/samus_pd/board.c @@ -7,26 +7,39 @@ #include "adc.h" #include "adc_chip.h" #include "battery.h" +#include "charge_manager.h" #include "common.h" #include "console.h" #include "gpio.h" #include "hooks.h" #include "i2c.h" +#include "pi3usb9281.h" #include "power.h" +#include "pwm.h" +#include "pwm_chip.h" #include "registers.h" #include "switch.h" #include "system.h" #include "task.h" +#include "usb.h" #include "usb_pd.h" #include "usb_pd_config.h" #include "util.h" +#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) + /* Chipset power state */ static enum power_state ps; /* Battery state of charge */ int batt_soc; +/* PWM channels. Must be in the exact same order as in enum pwm_channel. */ +const struct pwm_t pwm_channels[] = { + {STM32_TIM(15), STM32_TIM_CH(2), 0, GPIO_ILIM_ADJ_PWM, GPIO_ALT_F1}, +}; +BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT); + void vbus0_evt(enum gpio_signal signal) { ccprintf("VBUS %d, %d!\n", signal, gpio_get_level(signal)); @@ -39,9 +52,54 @@ void vbus1_evt(enum gpio_signal signal) task_wake(TASK_ID_PD_C1); } -void bc12_evt(enum gpio_signal signal) +/* + * Update available charge. Called from deferred task, queued on Pericom + * interrupt. + */ +static void board_usb_charger_update(int port) +{ + int device_type, charger_status; + struct charge_port_info charge; + charge.voltage = USB_BC12_CHARGE_VOLTAGE; + + /* Read interrupt register to clear*/ + pi3usb9281_get_interrupts(port); + device_type = pi3usb9281_get_device_type(port); + charger_status = pi3usb9281_get_charger_status(port); + + /* Attachment: decode + update available charge */ + if (device_type || (charger_status & 0x1f)) + charge.current = pi3usb9281_get_ilim(device_type, + charger_status); + /* Detachment: update available charge to 0 */ + else + charge.current = 0; + + charge_manager_update(CHARGE_SUPPLIER_BC12, port, &charge); + +} + +/* Pericom USB deferred tasks -- called after USB device insert / removal */ +static void usb_port0_charger_update(void) +{ + board_usb_charger_update(0); +} +DECLARE_DEFERRED(usb_port0_charger_update); + +static void usb_port1_charger_update(void) +{ + board_usb_charger_update(1); +} +DECLARE_DEFERRED(usb_port1_charger_update); + +void usb0_evt(enum gpio_signal signal) { - ccprintf("PERICOM %d!\n", signal); + hook_call_deferred(usb_port0_charger_update, 0); +} + +void usb1_evt(enum gpio_signal signal) +{ + hook_call_deferred(usb_port1_charger_update, 0); } void pch_evt(enum gpio_signal signal) @@ -121,6 +179,14 @@ static void board_init(void) gpio_enable_interrupt(GPIO_USB_C0_VBUS_WAKE); gpio_enable_interrupt(GPIO_USB_C1_VBUS_WAKE); + /* Enable pericom BC1.2 interrupts. */ + gpio_enable_interrupt(GPIO_USB_C0_BC12_INT_L); + gpio_enable_interrupt(GPIO_USB_C1_BC12_INT_L); + pi3usb9281_set_interrupt_mask(0, 0xff); + pi3usb9281_set_interrupt_mask(1, 0xff); + pi3usb9281_enable_interrupts(0); + pi3usb9281_enable_interrupts(1); + /* Determine initial chipset state */ if (slp_s5 && slp_s3) { disable_sleep(SLEEP_MASK_AP_RUN); @@ -155,6 +221,18 @@ static void board_init(void) pd_enable = 1; } pd_comm_enable(pd_enable); + + /* Enable ILIM PWM: initial duty cycle 0% = 500mA limit. */ + pwm_enable(PWM_CH_ILIM, 1); + pwm_set_duty(PWM_CH_ILIM, 0); + + /* + * Initialize BC1.2 USB charging, so that charge manager will assign + * charge port based upon charger actually present. Charger detection + * can take up to 200ms after power-on, so delay the initialization. + */ + hook_call_deferred(usb_port0_charger_update, 200 * MSEC); + hook_call_deferred(usb_port1_charger_update, 200 * MSEC); } DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT); @@ -305,3 +383,37 @@ enum battery_present battery_is_present(void) return BP_YES; return BP_NOT_SURE; } + +/** + * Set active charge port -- only one port can be active at a time. + * + * @param charge_port Charge port to enable. + */ +void board_set_active_charge_port(int charge_port) +{ + if (charge_port >= 0 && charge_port < PD_PORT_COUNT && + pd_get_role(charge_port) != PD_ROLE_SINK) { + CPRINTS("Port %d is not a sink, skipping enable", charge_port); + charge_port = CHARGE_PORT_NONE; + } + gpio_set_level(GPIO_USB_C0_CHARGE_EN_L, !(charge_port == 0)); + gpio_set_level(GPIO_USB_C1_CHARGE_EN_L, !(charge_port == 1)); + CPRINTS("Set active charge port %d", charge_port); +} + +/** + * Set the charge limit based upon desired maximum. + * + * @param charge_ma Desired charge limit (mA). + */ +void board_set_charge_limit(int charge_ma) +{ + int pwm_duty = MA_TO_PWM(charge_ma); + if (pwm_duty < 0) + pwm_duty = 0; + else if (pwm_duty > 100) + pwm_duty = 100; + + pwm_set_duty(PWM_CH_ILIM, pwm_duty); + CPRINTS("Set ilim duty %d", pwm_duty); +} diff --git a/board/samus_pd/board.h b/board/samus_pd/board.h index be1dad7f8d..8729cdc2a2 100644 --- a/board/samus_pd/board.h +++ b/board/samus_pd/board.h @@ -18,12 +18,14 @@ /* Optional features */ #define CONFIG_ADC #define CONFIG_BOARD_PRE_INIT +#define CONFIG_CHARGE_MANAGER #define CONFIG_FORCE_CONSOLE_RESUME #define CONFIG_HIBERNATE_WAKEUP_PINS (STM32_PWR_CSR_EWUP3|STM32_PWR_CSR_EWUP8) #define CONFIG_HW_CRC #define CONFIG_I2C #undef CONFIG_LID_SWITCH #define CONFIG_LOW_POWER_IDLE +#define CONFIG_PWM #define CONFIG_STM_HWTIMER32 #undef CONFIG_TASK_PROFILING #define CONFIG_USB_POWER_DELIVERY @@ -35,9 +37,11 @@ #define CONFIG_USB_PD_DUAL_ROLE #define CONFIG_USB_PD_FLASH_ERASE_CHECK #define CONFIG_USB_PD_INTERNAL_COMP +#define CONFIG_USB_SWITCH_PI3USB9281 +#undef CONFIG_USB_SWITCH_PI3USB9281_MUX_GPIO +#define CONFIG_USB_SWITCH_PI3USB9281_MUX_GPIO GPIO_USB_C_BC12_SEL #define CONFIG_USBC_SS_MUX #define CONFIG_USBC_VCONN -#define CONFIG_USB_SWITCH_TSU6721 #define CONFIG_VBOOT_HASH #undef CONFIG_WATCHDOG_HELP @@ -63,6 +67,7 @@ #define TIM_CLOCK32 2 #define TIM_ADC 3 +#include "charge_manager.h" #include "gpio_signal.h" /* ADC signal */ @@ -76,12 +81,31 @@ enum adc_channel { ADC_CH_COUNT }; +enum pwm_channel { + PWM_CH_ILIM = 0, + /* Number of PWM channels */ + PWM_CH_COUNT +}; + +/* Charge current limit min / max, based on PWM duty cycle */ +#define PWM_0_MA 500 +#define PWM_100_MA 4000 + +/* Map current in milli-amps to PWM duty cycle percentage */ +#define MA_TO_PWM(curr) (((curr) - PWM_0_MA) * 100 / (PWM_100_MA - PWM_0_MA)) + /* Called when we receive battery level info from the EC. */ void board_update_battery_soc(int soc); /* Get the last received battery level. */ int board_get_battery_soc(void); +/* Set the active charge port. */ +void board_set_active_charge_port(int charge_port); + +/* Set the charge current limit. */ +void board_set_charge_limit(int charge_ma); + #endif /* !__ASSEMBLER__ */ #endif /* __BOARD_H */ diff --git a/board/samus_pd/gpio.inc b/board/samus_pd/gpio.inc index 9d38f94e68..6345b7b365 100644 --- a/board/samus_pd/gpio.inc +++ b/board/samus_pd/gpio.inc @@ -8,8 +8,8 @@ /* Interrupts */ GPIO(USB_C0_VBUS_WAKE, E, 6, GPIO_INT_BOTH, vbus0_evt) GPIO(USB_C1_VBUS_WAKE, F, 2, GPIO_INT_BOTH, vbus1_evt) -GPIO(USB_C0_BC12_INT_L, B, 0, GPIO_INT_FALLING, bc12_evt) -GPIO(USB_C1_BC12_INT_L, C, 11, GPIO_INT_FALLING, bc12_evt) +GPIO(USB_C0_BC12_INT_L, B, 0, GPIO_INT_FALLING, usb0_evt) +GPIO(USB_C1_BC12_INT_L, C, 11, GPIO_INT_FALLING, usb1_evt) GPIO(PCH_SLP_S0_L, C, 14, GPIO_INT_BOTH, pch_evt) GPIO(PCH_SLP_S3_L, C, 15, GPIO_INT_BOTH, pch_evt) GPIO(PCH_SLP_S5_L, D, 7, GPIO_INT_BOTH, pch_evt) @@ -42,8 +42,8 @@ GPIO(USB_C0_TX_CLKIN, B, 13, GPIO_OUT_LOW, NULL) /* Power and muxes control */ GPIO(PPVAR_BOOSTIN_SENSE, C, 1, GPIO_ANALOG, NULL) GPIO(PP3300_USB_PD_EN, A, 8, GPIO_OUT_HIGH, NULL) -GPIO(USB_C0_CHARGE_EN_L, D, 12, GPIO_OUT_LOW, NULL) -GPIO(USB_C1_CHARGE_EN_L, D, 13, GPIO_OUT_LOW, NULL) +GPIO(USB_C0_CHARGE_EN_L, D, 12, GPIO_OUT_LOW, NULL) +GPIO(USB_C1_CHARGE_EN_L, D, 13, GPIO_OUT_LOW, NULL) GPIO(USB_C0_5V_EN, D, 14, GPIO_OUT_LOW, NULL) GPIO(USB_C1_5V_EN, D, 15, GPIO_OUT_LOW, NULL) GPIO(USB_C0_CC1_VCONN1_EN_L, D, 8, GPIO_OUT_HIGH, NULL) diff --git a/board/samus_pd/usb_pd_config.h b/board/samus_pd/usb_pd_config.h index 083606c413..62b699f3c0 100644 --- a/board/samus_pd/usb_pd_config.h +++ b/board/samus_pd/usb_pd_config.h @@ -3,6 +3,10 @@ * found in the LICENSE file. */ +#include "adc.h" +#include "chip/stm32/registers.h" +#include "gpio.h" + /* USB Power delivery board configuration */ #ifndef __USB_PD_CONFIG_H @@ -200,8 +204,7 @@ static inline void pd_set_host_mode(int port, int enable) /* Pull low for device mode. */ gpio_set_level(GPIO_USB_C0_CC1_ODL, 0); gpio_set_level(GPIO_USB_C0_CC2_ODL, 0); - /* Enable the charging path*/ - gpio_set_level(GPIO_USB_C0_CHARGE_EN_L, 0); + /* Let charge_manager decide to enable the port */ } } else { if (enable) { @@ -216,8 +219,7 @@ static inline void pd_set_host_mode(int port, int enable) /* Pull low for device mode. */ gpio_set_level(GPIO_USB_C1_CC1_ODL, 0); gpio_set_level(GPIO_USB_C1_CC2_ODL, 0); - /* Enable the charging path*/ - gpio_set_level(GPIO_USB_C1_CHARGE_EN_L, 0); + /* Let charge_manager decide to enable the port */ } } } diff --git a/board/samus_pd/usb_pd_policy.c b/board/samus_pd/usb_pd_policy.c index 680895ae72..378c04033c 100644 --- a/board/samus_pd/usb_pd_policy.c +++ b/board/samus_pd/usb_pd_policy.c @@ -146,10 +146,24 @@ static void pd_send_ec_int(void) void pd_set_input_current_limit(int port, uint32_t max_ma, uint32_t supply_voltage) { + struct charge_port_info charge; + charge.current = max_ma; + charge.voltage = supply_voltage; + charge_manager_update(CHARGE_SUPPLIER_PD, port, &charge); + pd_status.curr_lim_ma = max_ma; pd_send_ec_int(); } +void typec_set_input_current_limit(int port, uint32_t max_ma, + uint32_t supply_voltage) +{ + struct charge_port_info charge; + charge.current = max_ma; + charge.voltage = supply_voltage; + charge_manager_update(CHARGE_SUPPLIER_TYPEC, port, &charge); +} + int pd_board_checks(void) { return EC_SUCCESS; |