return !!(reg & TCPC_POWER_STATUS_VBUS_PRES);
}
+static unsigned int tcpci_get_vbus_vol(struct tcpc_dev *tcpc)
+{
+ struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+ unsigned int reg, ret = 0;
+
+ ret = regmap_read(tcpci->regmap, TCPC_VBUS_VOLTAGE, ®);
+
+ /* Convert it to be the vol number(mv) */
+ ret = ((reg & TCPC_VBUS_VOL_MASK) <<
+ ((reg & TCPC_VBUS_VOL_SCALE_FACTOR_MASK) >>
+ TCPC_VBUS_VOL_SCALE_FACTOR_SHIFT)) * TCPC_VBUS_VOL_MV_UNIT;
+
+ return ret;
+}
+
static int tcpci_set_vbus(struct tcpc_dev *tcpc, bool source, bool sink)
{
struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
tcpci->tcpc.start_drp_toggling = tcpci_start_drp_toggling;
tcpci->tcpc.vbus_detect = tcpci_vbus_detect;
tcpci->tcpc.vbus_discharge = tcpci_vbus_force_discharge;
+ tcpci->tcpc.get_vbus_vol = tcpci_get_vbus_vol;
tcpci->tcpc.set_pd_rx = tcpci_set_pd_rx;
tcpci->tcpc.set_roles = tcpci_set_roles;
#define TCPC_TX_DATA 0x54 /* through 0x6f */
#define TCPC_VBUS_VOLTAGE 0x70
+#define TCPC_VBUS_VOL_MASK 0x3ff
+#define TCPC_VBUS_VOL_SCALE_FACTOR_MASK 0xc00
+#define TCPC_VBUS_VOL_SCALE_FACTOR_SHIFT 10
+#define TCPC_VBUS_VOL_MV_UNIT 25
+
#define TCPC_VBUS_SINK_DISCONNECT_THRESH 0x72
#define TCPC_VBUS_STOP_DISCHARGE_THRESH 0x74
#define TCPC_VBUS_VOLTAGE_ALARM_HI_CFG 0x76
return false;
}
+static bool tcpm_vbus_is_low(struct tcpm_port *port)
+{
+ if (port->tcpc->get_vbus_vol &&
+ port->tcpc->get_vbus_vol(port->tcpc) > TCPM_VBUS_PRESENT_LEVEL)
+ return false;
+ else
+ return true;
+}
+
static void tcpm_set_cc(struct tcpm_port *port, enum typec_cc_status cc)
{
tcpm_log(port, "cc:=%d", cc);
break;
case SRC_ATTACHED:
- ret = tcpm_src_attach(port);
- tcpm_set_state(port, SRC_UNATTACHED,
+ if (tcpm_vbus_is_low(port)) {
+ ret = tcpm_src_attach(port);
+ tcpm_set_state(port, SRC_UNATTACHED,
ret < 0 ? 0 : PD_T_PS_SOURCE_ON);
+ } else {
+ tcpm_log(port, "Sink shouldn't provide vbus!");
+ tcpm_set_state(port, SRC_UNATTACHED, 10);
+ }
break;
case SRC_STARTUP:
typec_set_pwr_opmode(port->typec_port, TYPEC_PWR_MODE_USB);
#include <linux/usb/typec.h>
#include "pd.h"
+/* VBUS off level should be lower than it */
+#define TCPM_VBUS_PRESENT_LEVEL 600
+
enum typec_cc_status {
TYPEC_CC_OPEN,
TYPEC_CC_RA,
int (*init)(struct tcpc_dev *dev);
int (*get_vbus)(struct tcpc_dev *dev);
+ /* Optional, get the vbus voltage(mv) */
+ unsigned int (*get_vbus_vol)(struct tcpc_dev *dev);
int (*set_cc)(struct tcpc_dev *dev, enum typec_cc_status cc);
int (*get_cc)(struct tcpc_dev *dev, enum typec_cc_status *cc1,
enum typec_cc_status *cc2);