180 lines
4.7 KiB
C
180 lines
4.7 KiB
C
/*
|
|
* Copyright 2019 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.
|
|
*/
|
|
|
|
/* Type-C port manager for Nuvoton NCT38XX. */
|
|
|
|
#include "common.h"
|
|
#include "console.h"
|
|
#include "hooks.h"
|
|
#include "nct38xx.h"
|
|
#include "task.h"
|
|
#include "tcpci.h"
|
|
#include "usb_common.h"
|
|
|
|
#if !defined(CONFIG_USB_PD_TCPM_TCPCI)
|
|
#error "NCT38XX is using part of standard TCPCI control"
|
|
#error "Please upgrade your board configuration"
|
|
#endif
|
|
|
|
#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
|
|
#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args)
|
|
|
|
static int nct38xx_tcpm_init(int port)
|
|
{
|
|
int rv = 0;
|
|
int reg;
|
|
|
|
rv = tcpci_tcpm_init(port);
|
|
if (rv)
|
|
return rv;
|
|
|
|
/*
|
|
* Write to the CONTROL_OUT_EN register to enable:
|
|
* [6] - CONNDIREN : Connector direction indication output enable
|
|
* [2] - SNKEN : VBUS sink enable output enable
|
|
* [0] - SRCEN : VBUS source voltage enable output enable
|
|
*/
|
|
reg = NCT38XX_REG_CTRL_OUT_EN_SRCEN |
|
|
NCT38XX_REG_CTRL_OUT_EN_SNKEN |
|
|
NCT38XX_REG_CTRL_OUT_EN_CONNDIREN;
|
|
|
|
rv = tcpc_write(port, NCT38XX_REG_CTRL_OUT_EN, reg);
|
|
if (rv)
|
|
return rv;
|
|
|
|
/* Disable OVP */
|
|
rv = tcpc_update8(port,
|
|
TCPC_REG_FAULT_CTRL,
|
|
TCPC_REG_FAULT_CTRL_VBUS_OVP_FAULT_DIS,
|
|
MASK_SET);
|
|
if (rv)
|
|
return rv;
|
|
|
|
/* Enable VBus monitor and Disable FRS */
|
|
rv = tcpc_update8(port,
|
|
TCPC_REG_POWER_CTRL,
|
|
(TCPC_REG_POWER_CTRL_VBUS_VOL_MONITOR_DIS |
|
|
TCPC_REG_POWER_CTRL_FRS_ENABLE),
|
|
MASK_CLR);
|
|
if (rv)
|
|
return rv;
|
|
|
|
/* Set FRS direction for SNK detect, if FRS is enabled */
|
|
if (IS_ENABLED(CONFIG_USB_TYPEC_PD_FAST_ROLE_SWAP)) {
|
|
reg = TCPC_REG_DEV_CAP_2_SNK_FR_SWAP;
|
|
rv = tcpc_write(port, TCPC_REG_DEV_CAP_2, reg);
|
|
if (rv)
|
|
return rv;
|
|
|
|
reg = TCPC_REG_CONFIG_EXT_1_FR_SWAP_SNK_DIR;
|
|
rv = tcpc_write(port, TCPC_REG_CONFIG_EXT_1, reg);
|
|
if (rv)
|
|
return rv;
|
|
}
|
|
|
|
/* Start VBus monitor */
|
|
rv = tcpc_write(port, TCPC_REG_COMMAND,
|
|
TCPC_REG_COMMAND_ENABLE_VBUS_DETECT);
|
|
if (rv)
|
|
return rv;
|
|
|
|
/*
|
|
* Enable the Vendor Define alert event only when the IO expander
|
|
* feature is defined
|
|
*/
|
|
if (IS_ENABLED(CONFIG_IO_EXPANDER_NCT38XX))
|
|
rv = tcpc_update16(port,
|
|
TCPC_REG_ALERT_MASK,
|
|
TCPC_REG_ALERT_VENDOR_DEF,
|
|
MASK_SET);
|
|
|
|
return rv;
|
|
}
|
|
|
|
static void nct38xx_tcpc_alert(int port)
|
|
{
|
|
int alert, rv;
|
|
|
|
/*
|
|
* If IO expander feature is defined, read the ALERT register first to
|
|
* keep the status of Vendor Define bit. Otherwise, the status of ALERT
|
|
* register will be cleared after tcpci_tcpc_alert() is executed.
|
|
*/
|
|
if (IS_ENABLED(CONFIG_IO_EXPANDER_NCT38XX))
|
|
rv = tcpc_read16(port, TCPC_REG_ALERT, &alert);
|
|
|
|
/* Process normal TCPC ALERT event and clear status */
|
|
tcpci_tcpc_alert(port);
|
|
|
|
/*
|
|
* If IO expander feature is defined, check the Vendor Define bit to
|
|
* handle the IOEX IO's interrupt event
|
|
*/
|
|
if (IS_ENABLED(CONFIG_IO_EXPANDER_NCT38XX))
|
|
if (!rv && (alert & TCPC_REG_ALERT_VENDOR_DEF))
|
|
nct38xx_ioex_event_handler(port);
|
|
|
|
}
|
|
|
|
static __maybe_unused int nct3807_tcpc_drp_toggle(int port)
|
|
{
|
|
int rv;
|
|
|
|
/* DRP will already be set with the correct pull on both CC lines */
|
|
|
|
/* Set up to catch LOOK4CONNECTION alerts */
|
|
rv = tcpc_update8(port,
|
|
TCPC_REG_TCPC_CTRL,
|
|
TCPC_REG_TCPC_CTRL_EN_LOOK4CONNECTION_ALERT,
|
|
MASK_SET);
|
|
if (rv)
|
|
return rv;
|
|
|
|
/* Set Look4Connection command */
|
|
rv = tcpc_write(port, TCPC_REG_COMMAND,
|
|
TCPC_REG_COMMAND_LOOK4CONNECTION);
|
|
|
|
return rv;
|
|
}
|
|
|
|
const struct tcpm_drv nct38xx_tcpm_drv = {
|
|
.init = &nct38xx_tcpm_init,
|
|
.release = &tcpci_tcpm_release,
|
|
.get_cc = &tcpci_tcpm_get_cc,
|
|
#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC
|
|
.get_vbus_level = &tcpci_tcpm_get_vbus_level,
|
|
#endif
|
|
.select_rp_value = &tcpci_tcpm_select_rp_value,
|
|
.set_cc = &tcpci_tcpm_set_cc,
|
|
.set_polarity = &tcpci_tcpm_set_polarity,
|
|
.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 = &nct38xx_tcpc_alert,
|
|
#ifdef CONFIG_USB_PD_DISCHARGE_TCPC
|
|
.tcpc_discharge_vbus = &tcpci_tcpc_discharge_vbus,
|
|
#endif
|
|
.tcpc_enable_auto_discharge_disconnect =
|
|
&tcpci_tcpc_enable_auto_discharge_disconnect,
|
|
#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE
|
|
.drp_toggle = &nct3807_tcpc_drp_toggle,
|
|
.set_connection = &tcpci_tcpc_set_connection,
|
|
#endif
|
|
#ifdef CONFIG_USBC_PPC
|
|
.set_snk_ctrl = &tcpci_tcpm_set_snk_ctrl,
|
|
.set_src_ctrl = &tcpci_tcpm_set_src_ctrl,
|
|
#endif
|
|
.get_chip_info = &tcpci_get_chip_info,
|
|
#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
|
|
.enter_low_power_mode = &tcpci_enter_low_power_mode,
|
|
#endif
|
|
#ifdef CONFIG_USB_TYPEC_PD_FAST_ROLE_SWAP
|
|
.set_frs_enable = &tcpci_tcpc_fast_role_swap_enable,
|
|
#endif
|
|
};
|