diff options
Diffstat (limited to 'driver/tcpm/rt1718s.c')
-rw-r--r-- | driver/tcpm/rt1718s.c | 561 |
1 files changed, 0 insertions, 561 deletions
diff --git a/driver/tcpm/rt1718s.c b/driver/tcpm/rt1718s.c deleted file mode 100644 index 9d5a8895ad..0000000000 --- a/driver/tcpm/rt1718s.c +++ /dev/null @@ -1,561 +0,0 @@ -/* Copyright 2021 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* - * RT1718S TCPC Driver - */ - -#include "console.h" -#include "driver/tcpm/rt1718s.h" -#include "driver/tcpm/tcpci.h" -#include "driver/tcpm/tcpm.h" -#include "stdint.h" -#include "system.h" -#include "task.h" -#include "timer.h" -#include "usb_mux.h" -#include "usb_pd.h" -#include "util.h" - -#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args) - -#define RT1718S_SW_RESET_DELAY_MS 2 - -/* i2c_write function which won't wake TCPC from low power mode. */ -static int rt1718s_write(int port, int reg, int val, int len) -{ - if (reg > 0xFF) { - return i2c_write_offset16( - tcpc_config[port].i2c_info.port, - tcpc_config[port].i2c_info.addr_flags, - reg, val, len); - } else if (len == 1) { - return tcpc_write(port, reg, val); - } else { - return tcpc_write16(port, reg, val); - } -} - -static int rt1718s_read(int port, int reg, int *val, int len) -{ - if (reg > 0xFF) { - return i2c_read_offset16( - tcpc_config[port].i2c_info.port, - tcpc_config[port].i2c_info.addr_flags, - reg, val, len); - } else if (len == 1) { - return tcpc_read(port, reg, val); - } else { - return tcpc_read16(port, reg, val); - } -} - -int rt1718s_write8(int port, int reg, int val) -{ - return rt1718s_write(port, reg, val, 1); -} - -int rt1718s_read8(int port, int reg, int *val) -{ - return rt1718s_read(port, reg, val, 1); -} - -int rt1718s_update_bits8(int port, int reg, int mask, int val) -{ - int reg_val; - - if (mask == 0xFF) - return rt1718s_write8(port, reg, val); - - RETURN_ERROR(rt1718s_read8(port, reg, ®_val)); - - reg_val &= (~mask); - reg_val |= (mask & val); - return rt1718s_write8(port, reg, reg_val); -} - -int rt1718s_write16(int port, int reg, int val) -{ - return rt1718s_write(port, reg, val, 2); -} - -int rt1718s_read16(int port, int reg, int *val) -{ - return rt1718s_read(port, reg, val, 2); -} - - -static int rt1718s_sw_reset(int port) -{ - int rv; - - rv = rt1718s_update_bits8(port, RT1718S_SYS_CTRL3, - RT1718S_SWRESET_MASK, 0xFF); - - msleep(RT1718S_SW_RESET_DELAY_MS); - - 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)); - - return EC_SUCCESS; -} - -static int rt1718s_workaround(int port) -{ - int device_id; - - RETURN_ERROR(tcpc_read16(port, RT1718S_DEVICE_ID, &device_id)); - - switch (device_id) { - case RT1718S_DEVICE_ID_ES1: - RETURN_ERROR(rt1718s_update_bits8(port, RT1718S_VCONN_CONTROL_3, - RT1718S_VCONN_CONTROL_3_VCONN_OVP_DEG, - 0xFF)); - /* fallthrough */ - case RT1718S_DEVICE_ID_ES2: - RETURN_ERROR(rt1718s_update_bits8(port, TCPC_REG_FAULT_CTRL, - TCPC_REG_FAULT_CTRL_VBUS_OCP_FAULT_DIS, - 0xFF)); - RETURN_ERROR(rt1718s_update_bits8(port, RT1718S_VCON_CTRL4, - RT1718S_VCON_CTRL4_UVP_CP_EN | - RT1718S_VCON_CTRL4_OVP_CP_EN, - 0)); - RETURN_ERROR(rt1718s_update_bits8(port, RT1718S_VCONN_CONTROL_2, - RT1718S_VCONN_CONTROL_2_OVP_EN_CC1 | - RT1718S_VCONN_CONTROL_2_OVP_EN_CC2, - 0xFF)); - break; - default: - /* do nothing */ - break; - } - - return EC_SUCCESS; -} - -static int rt1718s_init(int port) -{ - static bool need_sw_reset = true; - - if (!system_jumped_late() && need_sw_reset) { - RETURN_ERROR(rt1718s_sw_reset(port)); - need_sw_reset = false; - } - - RETURN_ERROR(rt1718s_bc12_init(port)); - - /* Set VBUS_VOL_SEL to 20V */ - RETURN_ERROR(rt1718s_update_bits8(port, RT1718S_RT2_VBUS_VOL_CTRL, - RT1718S_RT2_VBUS_VOL_CTRL_VOL_SEL, - RT1718S_VBUS_VOL_TO_REG(20))); - - /* Disable FOD function */ - RETURN_ERROR(rt1718s_update_bits8(port, 0xCF, 0x40, 0x00)); - - /* Tcpc connect invalid disabled. Exit shipping mode */ - RETURN_ERROR(rt1718s_update_bits8(port, RT1718S_SYS_CTRL1, - RT1718S_SYS_CTRL1_TCPC_CONN_INVALID, 0x00)); - RETURN_ERROR(rt1718s_update_bits8(port, RT1718S_SYS_CTRL1, - RT1718S_SYS_CTRL1_SHIPPING_OFF, 0xFF)); - - /* Clear alert and fault */ - RETURN_ERROR(rt1718s_write8(port, TCPC_REG_FAULT_STATUS, 0xFF)); - RETURN_ERROR(tcpc_write16(port, TCPC_REG_ALERT, 0xFFFF)); - - RETURN_ERROR(tcpci_tcpm_init(port)); - - RETURN_ERROR(rt1718s_workaround(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; -} - -__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) { - if (current_bc12_type != CHARGE_SUPPLIER_NONE) - 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_VBUS) { - if (pd_snk_is_vbus_provided(port)) - rt1718s_enable_bc12_sink(port, true); - else - rt1718s_update_charge_manager( - port, CHARGE_SUPPLIER_NONE); - } - - /* detection done, update charge_manager and stop detection */ - if (evt & USB_CHG_EVENT_BC12) { - int type = rt1718s_get_bc12_type(port); - - rt1718s_update_charge_manager( - port, type); - rt1718s_enable_bc12_sink(port, false); - } - } -} - -void rt1718s_vendor_defined_alert(int port) -{ - int rv, value; - - if (IS_ENABLED(CONFIG_USB_PD_FRS_PPC) && - IS_ENABLED(CONFIG_USBC_PPC_RT1718S)) { - int int1; - - rv = rt1718s_read8(port, RT1718S_RT_INT1, &int1); - if (rv) - return; - rv = rt1718s_write8(port, RT1718S_RT_INT1, int1); - if (rv) - return; - - if ((int1 & RT1718S_RT_INT1_INT_RX_FRS)) { - pd_got_frs_signal(port); - - tcpc_write16(port, TCPC_REG_ALERT, - TCPC_REG_ALERT_VENDOR_DEF); - /* ignore other interrupts for faster frs handling */ - return; - } - } - - /* 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); - - /* clear the alerts from rt1718s_workaround() */ - rv = rt1718s_write8(port, RT1718S_RT_INT2, 0xFF); - if (rv) - return; - /* ES1 workaround: disable Vconn discharge */ - rv = rt1718s_update_bits8(port, RT1718S_SYS_CTRL2, - RT1718S_SYS_CTRL2_VCONN_DISCHARGE_EN, - 0); - if (rv) - return; - - tcpc_write16(port, TCPC_REG_ALERT, TCPC_REG_ALERT_VENDOR_DEF); -} - -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); - - if (alert & ~TCPC_REG_ALERT_VENDOR_DEF) - tcpci_tcpc_alert(port); -} - -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER -static int rt1718s_enter_low_power_mode(int port) -{ - /* enter low power mode */ - RETURN_ERROR(rt1718s_update_bits8(port, RT1718S_SYS_CTRL2, - RT1718S_SYS_CTRL2_LPWR_EN, 0xFF)); - RETURN_ERROR(rt1718s_update_bits8(port, RT1718S_SYS_CTRL2, - RT1718S_SYS_CTRL2_BMCIO_OSC_EN, 0)); - - /* disable DP/DM/SBU swtiches */ - RETURN_ERROR(rt1718s_write8(port, RT1718S_RT2_SBU_CTRL_01, 0)); - - return tcpci_enter_low_power_mode(port); -} -#endif - -int rt1718s_get_adc(int port, enum rt1718s_adc_channel channel, int *adc_val) -{ - static struct mutex adc_lock; - int rv; - const int max_wait_times = 30; - - if (in_interrupt_context()) { - CPRINTS("Err: use ADC in IRQ"); - return EC_ERROR_INVAL; - } - - mutex_lock(&adc_lock); - - /* Start ADC conversation */ - rv = rt1718s_write16(port, RT1718S_ADC_CTRL_01, BIT(channel)); - if (rv) - goto out; - - /* - * The expected conversion time is 85.3us * number of enabled channels. - * Polling for 3ms should be long enough. - */ - for (int i = 0; i < max_wait_times; i++) { - int adc_done; - - usleep(100); - rv = rt1718s_read8(port, RT1718S_RT_INT6, &adc_done); - if (rv) - goto out; - if (adc_done & RT1718S_RT_INT6_INT_ADC_DONE) - break; - if (i == max_wait_times - 1) { - CPRINTS("conversion fail channel=%d", channel); - rv = EC_ERROR_TIMEOUT; - goto out; - } - } - - /* Read ADC data */ - rv = rt1718s_read16(port, RT1718S_ADC_CHX_VOL_L(channel), adc_val); - if (rv) - goto out; - - /* - * The resolution of VBUS1 ADC is 12.5mV, - * other channels are 4mV. - */ - if (channel == RT1718S_ADC_VBUS1) - *adc_val = *adc_val * 125 / 10; - else - *adc_val *= 4; - -out: - /* Cleanup: disable adc and clear interrupt. Error ignored. */ - rt1718s_write16(port, RT1718S_ADC_CTRL_01, 0); - rt1718s_write8(port, RT1718S_RT_INT6, RT1718S_RT_INT6_INT_ADC_DONE); - - mutex_unlock(&adc_lock); - return rv; -} - -void rt1718s_gpio_set_flags(int port, enum rt1718s_gpio signal, uint32_t flags) -{ - int val = 0; - - if (!(flags & GPIO_OPEN_DRAIN)) - val |= RT1718S_GPIO_CTRL_OD_N; - if (flags & GPIO_PULL_UP) - val |= RT1718S_GPIO_CTRL_PU; - if (flags & GPIO_PULL_DOWN) - val |= RT1718S_GPIO_CTRL_PD; - if (flags & GPIO_HIGH) - val |= RT1718S_GPIO_CTRL_O; - if (flags & GPIO_OUTPUT) - val |= RT1718S_GPIO_CTRL_OE; - - rt1718s_write8(port, RT1718S_GPIO_CTRL(signal), val); -} - -void rt1718s_gpio_set_level(int port, enum rt1718s_gpio signal, int value) -{ - rt1718s_update_bits8(port, RT1718S_GPIO_CTRL(signal), - RT1718S_GPIO_CTRL_O, - value ? 0xFF : 0); -} - -int rt1718s_gpio_get_level(int port, enum rt1718s_gpio signal) -{ - int val; - - rt1718s_read8(port, RT1718S_GPIO_CTRL(signal), &val); - return !!(val & RT1718S_GPIO_CTRL_I); -} - -/* RT1718S is a TCPCI compatible port controller */ -const struct tcpm_drv rt1718s_tcpm_drv = { - .init = &rt1718s_init, - .release = &tcpci_tcpm_release, - .get_cc = &tcpci_tcpm_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = &tcpci_tcpm_check_vbus_level, -#endif - .select_rp_value = &tcpci_tcpm_select_rp_value, - .set_cc = &tcpci_tcpm_set_cc, - .set_polarity = &tcpci_tcpm_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &tcpci_tcpm_sop_prime_enable, -#endif - .set_vconn = &tcpci_tcpm_set_vconn, - .set_msg_header = &tcpci_tcpm_set_msg_header, - .set_rx_enable = &tcpci_tcpm_set_rx_enable, - .get_message_raw = &tcpci_tcpm_get_message_raw, - .transmit = &tcpci_tcpm_transmit, - .tcpc_alert = &rt1718s_alert, -#ifdef CONFIG_USB_PD_DISCHARGE_TCPC - .tcpc_discharge_vbus = &tcpci_tcpc_discharge_vbus, -#endif -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - .drp_toggle = &tcpci_tcpc_drp_toggle, -#endif - .get_chip_info = &tcpci_get_chip_info, -#ifdef CONFIG_USB_PD_PPC - .set_snk_ctrl = &tcpci_tcpm_set_snk_ctrl, - .set_src_ctrl = &tcpci_tcpm_set_src_ctrl, -#endif -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - .enter_low_power_mode = &rt1718s_enter_low_power_mode, -#endif -}; - -const struct bc12_drv rt1718s_bc12_drv = { - .usb_charger_task = rt1718s_bc12_usb_charger_task, -}; |