diff options
-rw-r--r-- | driver/tcpm/rt1718s.c | 205 | ||||
-rw-r--r-- | driver/tcpm/rt1718s.h | 60 |
2 files changed, 264 insertions, 1 deletions
diff --git a/driver/tcpm/rt1718s.c b/driver/tcpm/rt1718s.c index 3c2e6e6c0b..0275d9cc96 100644 --- a/driver/tcpm/rt1718s.c +++ b/driver/tcpm/rt1718s.c @@ -73,6 +73,88 @@ static int rt1718s_sw_reset(int port) return rv; } +/* enable bc 1.2 sink function */ +static int rt1718s_enable_bc12_sink(int port, bool en) +{ + return rt1718s_update_bits8(port, RT1718S_RT2_BC12_SNK_FUNC, + RT1718S_RT2_BC12_SNK_FUNC_BC12_SNK_EN, + en ? 0xFF : 0); +} + +static int rt1718s_set_bc12_sink_spec_ta(int port, bool en) +{ + return rt1718s_update_bits8(port, + RT1718S_RT2_BC12_SNK_FUNC, + RT1718S_RT2_BC12_SNK_FUNC_SPEC_TA_EN, en ? 0xFF : 0); +} + +static int rt1718s_set_bc12_sink_dcdt_sel(int port, uint8_t dcdt_sel) +{ + return rt1718s_update_bits8(port, + RT1718S_RT2_BC12_SNK_FUNC, + RT1718S_RT2_BC12_SNK_FUNC_DCDT_SEL_MASK, dcdt_sel); +} + +static int rt1718s_set_bc12_sink_vlgc_option(int port, bool en) +{ + return rt1718s_update_bits8(port, + RT1718S_RT2_BC12_SNK_FUNC, + RT1718S_RT2_BC12_SNK_FUNC_VLGC_OPT, en ? 0xFF : 0); +} + +static int rt1718s_set_bc12_sink_vport_sel(int port, uint8_t sel) +{ + return rt1718s_update_bits8(port, + RT1718S_RT2_DPDM_CTR1_DPDM_SET, + RT1718S_RT2_DPDM_CTR1_DPDM_SET_DPDM_VSRC_SEL_MASK, sel); +} + +static int rt1718s_set_bc12_sink_wait_vbus(int port, bool en) +{ + return rt1718s_update_bits8(port, + RT1718S_RT2_BC12_SNK_FUNC, + RT1718S_RT2_BC12_SNK_FUNC_BC12_WAIT_VBUS, + en ? 0xFF : 0); +} + +/* + * rt1718s BC12 function initial + */ +static int rt1718s_bc12_init(int port) +{ + /* Enable vendor defined BC12 function */ + RETURN_ERROR(rt1718s_write8(port, RT1718S_RT_MASK6, + RT1718S_RT_MASK6_M_BC12_SNK_DONE | + RT1718S_RT_MASK6_M_BC12_TA_CHG)); + + RETURN_ERROR(rt1718s_write8(port, RT1718S_RT2_SBU_CTRL_01, + RT1718S_RT2_SBU_CTRL_01_DPDM_VIEN | + RT1718S_RT2_SBU_CTRL_01_DM_SWEN | + RT1718S_RT2_SBU_CTRL_01_DP_SWEN)); + + /* Disable 2.7v mode */ + RETURN_ERROR(rt1718s_set_bc12_sink_spec_ta(port, false)); + + /* DCDT select 600ms timeout */ + RETURN_ERROR(rt1718s_set_bc12_sink_dcdt_sel(port, + RT1718S_RT2_BC12_SNK_FUNC_DCDT_SEL_600MS)); + + /* Disable vlgc option */ + RETURN_ERROR(rt1718s_set_bc12_sink_vlgc_option(port, false)); + + /* DPDM voltage selection */ + RETURN_ERROR(rt1718s_set_bc12_sink_vport_sel(port, + RT1718S_RT2_DPDM_CTR1_DPDM_SET_DPDM_VSRC_SEL_0_65V)); + + /* Disable sink wait vbus */ + RETURN_ERROR(rt1718s_set_bc12_sink_wait_vbus(port, false)); + + /* Disable bc 1.2 sink function */ + RETURN_ERROR(rt1718s_enable_bc12_sink(port, false)); + + return EC_SUCCESS; +} + static int rt1718s_init(int port) { static bool need_sw_reset = true; @@ -90,6 +172,8 @@ static int rt1718s_init(int port) 0xFF)); + RETURN_ERROR(rt1718s_bc12_init(port)); + /* Disable FOD function */ RETURN_ERROR(rt1718s_update_bits8(port, 0xCF, 0x40, 0x00)); @@ -105,6 +189,14 @@ static int rt1718s_init(int port) RETURN_ERROR(tcpci_tcpm_init(port)); + /* + * Set vendor defined alert unmasked, this must be done after + * tcpci_tcpm_init. + */ + RETURN_ERROR(tcpc_update16(port, TCPC_REG_ALERT_MASK, + TCPC_REG_ALERT_MASK_VENDOR_DEF, + MASK_SET)); + RETURN_ERROR(board_rt1718s_init(port)); return EC_SUCCESS; @@ -115,6 +207,115 @@ __overridable int board_rt1718s_init(int port) return EC_SUCCESS; } +static enum charge_supplier rt1718s_get_bc12_type(int port) +{ + int data; + + if (rt1718s_read8(port, RT1718S_RT2_BC12_STAT, &data)) + return CHARGE_SUPPLIER_OTHER; + + switch (data & RT1718S_RT2_BC12_STAT_PORT_STATUS_MASK) { + case RT1718S_RT2_BC12_STAT_PORT_STATUS_NONE: + return CHARGE_SUPPLIER_NONE; + case RT1718S_RT2_BC12_STAT_PORT_STATUS_SDP: + return CHARGE_SUPPLIER_BC12_SDP; + case RT1718S_RT2_BC12_STAT_PORT_STATUS_CDP: + return CHARGE_SUPPLIER_BC12_CDP; + case RT1718S_RT2_BC12_STAT_PORT_STATUS_DCP: + return CHARGE_SUPPLIER_BC12_DCP; + } + + return CHARGE_SUPPLIER_OTHER; +} + +static int rt1718s_get_bc12_ilim(enum charge_supplier supplier) +{ + switch (supplier) { + case CHARGE_SUPPLIER_BC12_DCP: + case CHARGE_SUPPLIER_BC12_CDP: + return USB_CHARGER_MAX_CURR_MA; + case CHARGE_SUPPLIER_BC12_SDP: + default: + return USB_CHARGER_MIN_CURR_MA; + } +} + +static void rt1718s_update_charge_manager(int port, + enum charge_supplier new_bc12_type) +{ + static enum charge_supplier current_bc12_type = CHARGE_SUPPLIER_NONE; + + if (new_bc12_type != current_bc12_type) { + charge_manager_update_charge(current_bc12_type, port, NULL); + + if (new_bc12_type != CHARGE_SUPPLIER_NONE) { + struct charge_port_info chg = { + .current = rt1718s_get_bc12_ilim(new_bc12_type), + .voltage = USB_CHARGER_VOLTAGE_MV, + }; + + charge_manager_update_charge(new_bc12_type, port, &chg); + } + + current_bc12_type = new_bc12_type; + } +} + +static void rt1718s_bc12_usb_charger_task(const int port) +{ + rt1718s_enable_bc12_sink(port, false); + + while (1) { + uint32_t evt = task_wait_event(-1); + + if (evt & USB_CHG_EVENT_DR_UFP) + rt1718s_enable_bc12_sink(port, true); + + if ((evt & USB_CHG_EVENT_DR_DFP) || + (evt & USB_CHG_EVENT_CC_OPEN)) { + rt1718s_update_charge_manager( + port, CHARGE_SUPPLIER_NONE); + } + + /* detection done, update charge_manager and stop detection */ + if (evt & USB_CHG_EVENT_BC12) { + rt1718s_update_charge_manager( + port, rt1718s_get_bc12_type(port)); + rt1718s_enable_bc12_sink(port, false); + } + } +} + +void rt1718s_vendor_defined_alert(int port) +{ + int rv, value; + + /* Process BC12 alert */ + rv = rt1718s_read8(port, RT1718S_RT_INT6, &value); + if (rv) + return; + + /* clear BC12 alert */ + rv = rt1718s_write8(port, RT1718S_RT_INT6, value); + if (rv) + return; + + /* check snk done */ + if (value & RT1718S_RT_INT6_INT_BC12_SNK_DONE) + task_set_event(USB_CHG_PORT_TO_TASK_ID(port), + USB_CHG_EVENT_BC12); +} + +static void rt1718s_alert(int port) +{ + int alert; + + tcpc_read16(port, TCPC_REG_ALERT, &alert); + if (alert & TCPC_REG_ALERT_VENDOR_DEF) + rt1718s_vendor_defined_alert(port); + tcpci_tcpc_alert(port); +} + /* RT1718S is a TCPCI compatible port controller */ const struct tcpm_drv rt1718s_tcpm_drv = { .init = &rt1718s_init, @@ -150,3 +351,7 @@ const struct tcpm_drv rt1718s_tcpm_drv = { .enter_low_power_mode = &tcpci_enter_low_power_mode, #endif }; + +const struct bc12_drv rt1718s_bc12_drv = { + .usb_charger_task = rt1718s_bc12_usb_charger_task, +}; diff --git a/driver/tcpm/rt1718s.h b/driver/tcpm/rt1718s.h index 0f868f0598..daaab5935c 100644 --- a/driver/tcpm/rt1718s.h +++ b/driver/tcpm/rt1718s.h @@ -2,10 +2,10 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ - #ifndef __CROS_EC_USB_PD_TCPM_RT1718S_H #define __CROS_EC_USB_PD_TCPM_RT1718S_H +#include "usb_charge.h" #include "usb_pd_tcpm.h" /* RT1718S Private RegMap */ @@ -32,8 +32,21 @@ #define RT1718S_RT_MASK4 0x94 #define RT1718S_RT_MASK5 0x95 #define RT1718S_RT_MASK6 0x96 +#define RT1718S_RT_MASK6_M_BC12_SNK_DONE BIT(7) +#define RT1718S_RT_MASK6_M_HVDCP_CHK_DONE BIT(6) +#define RT1718S_RT_MASK6_M_BC12_TA_CHG BIT(5) #define RT1718S_RT_MASK7 0x97 +#define RT1718S_RT_INT6 0x9D +#define RT1718S_RT_INT6_INT_BC12_SNK_DONE BIT(7) +#define RT1718S_RT_INT6_INT_HVDCP_CHK_DONE BIT(6) +#define RT1718S_RT_INT6_INT_BC12_TA_CHG BIT(5) + +#define RT1718S_RT_ST6 0xA4 +#define RT1718S_RT_ST6_BC12_SNK_DONE BIT(7) +#define RT1718S_RT_ST6_HVDCP_CHK_DONE BIT(6) +#define RT1718S_RT_ST6_BC12_TA_CHG BIT(5) + #define RT1718S_PHYCTRL9 0xAC #define RT1718S_SYS_CTRL3 0xB0 @@ -65,7 +78,52 @@ #define RT1718S_RT2_VBUS_OCP_CTRL1 0xF216 #define RT1718S_RT2_VBUS_OCP_CTRL4 0xF219 +#define RT1718S_RT2_SBU_CTRL_01 0xF23A +#define RT1718S_RT2_SBU_CTRL_01_SBU_VIEN BIT(7) +#define RT1718S_RT2_SBU_CTRL_01_DPDM_VIEN BIT(6) +#define RT1718S_RT2_SBU_CTRL_01_SBU2_SWEN BIT(3) +#define RT1718S_RT2_SBU_CTRL_01_SBU1_SWEN BIT(2) +#define RT1718S_RT2_SBU_CTRL_01_DM_SWEN BIT(1) +#define RT1718S_RT2_SBU_CTRL_01_DP_SWEN BIT(0) + +#define RT1718S_RT2_BC12_SNK_FUNC 0xF260 +#define RT1718S_RT2_BC12_SNK_FUNC_BC12_SNK_EN BIT(7) +#define RT1718S_RT2_BC12_SNK_FUNC_SPEC_TA_EN BIT(6) +#define RT1718S_RT2_BC12_SNK_FUNC_DCDT_SEL_MASK 0x30 +#define RT1718S_RT2_BC12_SNK_FUNC_DCDT_SEL_DISABLE 0x00 +#define RT1718S_RT2_BC12_SNK_FUNC_DCDT_SEL_300MS 0x10 +#define RT1718S_RT2_BC12_SNK_FUNC_DCDT_SEL_600MS 0x20 +#define RT1718S_RT2_BC12_SNK_FUNC_DCDT_SEL_WAIT_DATA 0x30 +#define RT1718S_RT2_BC12_SNK_FUNC_VLGC_OPT BIT(3) +#define RT1718S_RT2_BC12_SNK_FUNC_VPORT_SEL BIT(2) +#define RT1718S_RT2_BC12_SNK_FUNC_BC12_WAIT_VBUS BIT(1) + +#define RT1718S_RT2_BC12_STAT 0xF261 +#define RT1718S_RT2_BC12_STAT_DCDT BIT(4) +#define RT1718S_RT2_BC12_STAT_PORT_STATUS_MASK 0x0F +#define RT1718S_RT2_BC12_STAT_PORT_STATUS_NONE 0x00 +#define RT1718S_RT2_BC12_STAT_PORT_STATUS_SDP 0x0D +#define RT1718S_RT2_BC12_STAT_PORT_STATUS_CDP 0x0E +#define RT1718S_RT2_BC12_STAT_PORT_STATUS_DCP 0x0F + + +#define RT1718S_RT2_DPDM_CTR1_DPDM_SET 0xF263 +#define RT1718S_RT2_DPDM_CTR1_DPDM_SET_DPDM_VSRC_SEL_MASK 0x03 +#define RT1718S_RT2_DPDM_CTR1_DPDM_SET_DPDM_VSRC_SEL_0_55V 0x00 +#define RT1718S_RT2_DPDM_CTR1_DPDM_SET_DPDM_VSRC_SEL_0_60V 0x01 +#define RT1718S_RT2_DPDM_CTR1_DPDM_SET_DPDM_VSRC_SEL_0_65V 0x02 +#define RT1718S_RT2_DPDM_CTR1_DPDM_SET_DPDM_VSRC_SEL_0_70V 0x03 + +#define RT1718S_RT2_BC12_SRC_FUNC 0xF26D +#define RT1718S_RT2_BC12_SRC_FUNC_BC12_SRC_EN BIT(7) +#define RT1718S_RT2_BC12_SRC_FUNC_SRC_MODE_SEL_MASK 0x70 +#define RT1718S_RT2_BC12_SRC_FUNC_SRC_MODE_SEL_BC12_SDP 0x00 +#define RT1718S_RT2_BC12_SRC_FUNC_SRC_MODE_SEL_BC12_CDP 0x10 +#define RT1718S_RT2_BC12_SRC_FUNC_SRC_MODE_SEL_BC12_DCP 0x20 +#define RT1718S_RT2_BC12_SRC_FUNC_WAIT_VBUS_ON BIT(0) + extern const struct tcpm_drv rt1718s_tcpm_drv; +extern const struct bc12_drv rt1718s_bc12_drv; int rt1718s_write8(int port, int reg, int val); int rt1718s_read8(int port, int reg, int *val); |