diff options
-rw-r--r-- | driver/charger/bd9995x.c | 80 | ||||
-rw-r--r-- | driver/charger/bd9995x.h | 11 |
2 files changed, 56 insertions, 35 deletions
diff --git a/driver/charger/bd9995x.c b/driver/charger/bd9995x.c index 9e35f273ee..cd9b60d759 100644 --- a/driver/charger/bd9995x.c +++ b/driver/charger/bd9995x.c @@ -52,6 +52,7 @@ static const struct charger_info bd9995x_charger_info = { /* Charge command code map */ static enum bd9995x_command charger_map_cmd = BD9995X_INVALID_COMMAND; +/* Mutex for active register set control. */ static struct mutex bd9995x_map_mutex; #ifdef HAS_TASK_USB_CHG @@ -307,6 +308,8 @@ static int bd9995x_get_charger_op_status(int *status) #ifdef HAS_TASK_USB_CHG static int bc12_detected_type[CONFIG_USB_PD_PORT_COUNT]; +/* Mutex for UCD_SET regsiters, lock before read / mask / write. */ +static struct mutex ucd_set_mutex[BD9995X_CHARGE_PORT_COUNT]; static int bd9995x_get_bc12_device_type(int port) { @@ -337,25 +340,32 @@ static int bd9995x_get_bc12_device_type(int port) } } -static int bd9995x_enable_usb_switch(int port, enum usb_switch setting) +/* + * Do safe read / mask / write of BD9995X_CMD_*_UCD_SET register. + * The USB charger task owns all bits of this register, except for bit 0 + * (BD9995X_CMD_UCD_SET_USB_SW), which is controlled by + * usb_charger_set_switches(). + */ +static int bd9995x_update_ucd_set_reg(int port, uint16_t mask, int set) { int rv; int reg; - int port_reg; - - port_reg = (port == BD9995X_CHARGE_PORT_VBUS) ? + int port_reg = (port == BD9995X_CHARGE_PORT_VBUS) ? BD9995X_CMD_VBUS_UCD_SET : BD9995X_CMD_VCC_UCD_SET; + mutex_lock(&ucd_set_mutex[port]); rv = ch_raw_read16(port_reg, ®, BD9995X_EXTENDED_COMMAND); - if (rv) - return rv; + if (!rv) { + if (set) + reg |= mask; + else + reg &= ~mask; - if (setting == USB_SWITCH_CONNECT) - reg |= BD9995X_CMD_UCD_SET_USB_SW_EN; - else - reg &= ~BD9995X_CMD_UCD_SET_USB_SW_EN; + rv = ch_raw_write16(port_reg, reg, BD9995X_EXTENDED_COMMAND); + } - return ch_raw_write16(port_reg, reg, BD9995X_EXTENDED_COMMAND); + mutex_unlock(&ucd_set_mutex[port]); + return rv; } static int bd9995x_bc12_check_type(int port) @@ -473,6 +483,20 @@ static int bd9995x_get_interrupts(int port) return reg; } +/* + * Set or clear registers necessary to do one-time BC1.2 detection. + * Pass enable = 1 to trigger BC1.2 detection, and enable = 0 once + * BC1.2 detection has completed. + */ +static int bd9995x_bc12_detect(int port, int enable) +{ + return bd9995x_update_ucd_set_reg(port, + BD9995X_CMD_UCD_SET_BCSRETRY | + BD9995X_CMD_UCD_SET_USBDETEN | + BD9995X_CMD_UCD_SET_USB_SW_EN, + enable); +} + static int usb_charger_process(int port) { int vbus_provided = bd9995x_is_vbus_provided(port) && @@ -481,8 +505,12 @@ static int usb_charger_process(int port) /* Inform other modules about VBUS level */ usb_charger_vbus_change(port, vbus_provided); - /* Do BC1.2 detection */ - if (vbus_provided) { + /* + * Do BC1.2 detection, if we have VBUS and our port is not known + * to speak PD. + */ + if (vbus_provided && !pd_capable(port)) { + bd9995x_bc12_detect(port, 1); /* * Need to give the charger time (~312 mSec) before the * bc12_type is available. The main task loop will schedule a @@ -491,6 +519,9 @@ static int usb_charger_process(int port) return 1; } + /* Reset BC1.2 regs so we don't do auto-detection. */ + bd9995x_bc12_detect(port, 0); + /* * VBUS is no longer being provided, if the bc12_type had been * previously determined, then need to detach. @@ -817,24 +848,6 @@ static void bd9995x_init(void) { int reg; - /* Enable BC1.2 detection on VCC */ - if (ch_raw_read16(BD9995X_CMD_VCC_UCD_SET, ®, - BD9995X_EXTENDED_COMMAND)) - return; - reg |= BD9995X_CMD_UCD_SET_USBDETEN; - reg &= ~BD9995X_CMD_UCD_SET_USB_SW_EN; - ch_raw_write16(BD9995X_CMD_VCC_UCD_SET, reg, - BD9995X_EXTENDED_COMMAND); - - /* Enable BC1.2 detection on VBUS */ - if (ch_raw_read16(BD9995X_CMD_VBUS_UCD_SET, ®, - BD9995X_EXTENDED_COMMAND)) - return; - reg |= BD9995X_CMD_UCD_SET_USBDETEN; - reg &= ~BD9995X_CMD_UCD_SET_USB_SW_EN; - ch_raw_write16(BD9995X_CMD_VBUS_UCD_SET, reg, - BD9995X_EXTENDED_COMMAND); - /* * Disable charging trigger by BC1.2 on VCC & VBUS and * automatic limitation of the input current. @@ -1119,7 +1132,8 @@ void usb_charger_set_switches(int port, enum usb_switch setting) ? CONFIG_BD9995X_POWER_SAVE_MODE : BD9995X_PWR_SAVE_OFF); #endif - bd9995x_enable_usb_switch(port, usb_switch_state[port]); + bd9995x_update_ucd_set_reg(port, BD9995X_CMD_UCD_SET_USB_SW, + usb_switch_state[port] == USB_SWITCH_CONNECT); } void bd9995x_vbus_interrupt(enum gpio_signal signal) @@ -1191,6 +1205,8 @@ void usb_charger_task(void *u) bc12_det_mark[port] = bd9995x_bc12_check_type(port) ? get_time().val + 100 * MSEC : 0; + /* Reset BC1.2 regs to skip auto-detection. */ + bd9995x_bc12_detect(port, 0); } /* diff --git a/driver/charger/bd9995x.h b/driver/charger/bd9995x.h index 7b10dbde99..f9fb092b24 100644 --- a/driver/charger/bd9995x.h +++ b/driver/charger/bd9995x.h @@ -180,9 +180,14 @@ enum bd9995x_charge_port { #define BD9995X_CMD_IOUT_DACIN_VAL 0x27 #define BD9995X_CMD_VCC_UCD_SET 0x28 /* Bits for both VCC_UCD_SET and VBUS_UCD_SET regs */ -#define BD9995X_CMD_UCD_SET_BCSRETRY (1 << 12) -#define BD9995X_CMD_UCD_SET_USBDETEN (1 << 7) -#define BD9995X_CMD_UCD_SET_USB_SW_EN (1 << 1) +/* Retry BC1.2 detection on set */ +#define BD9995X_CMD_UCD_SET_BCSRETRY (1 << 12) +/* Enable BC1.2 detection, will automatically occur on VBUS detect */ +#define BD9995X_CMD_UCD_SET_USBDETEN (1 << 7) +/* USB switch state auto-control */ +#define BD9995X_CMD_UCD_SET_USB_SW_EN (1 << 1) +/* USB switch state, 1 = ON, only meaningful when USB_SW_EN = 0 */ +#define BD9995X_CMD_UCD_SET_USB_SW (1 << 0) #define BD9995X_CMD_VCC_UCD_STATUS 0x29 /* Bits for both VCC_UCD_STATUS and VBUS_UCD_STATUS regs */ |