/* * Copyright 2017 NXP * * SPDX-License-Identifier: GPL-2.0+ */ #ifndef __TCPCI_H #define __TCPCI_H #include #define TCPC_VENDOR_ID 0x0 #define TCPC_PRODUCT_ID 0x2 #define TCPC_ALERT 0x10 #define TCPC_ALERT_VBUS_DISCNCT BIT(11) #define TCPC_ALERT_RX_BUF_OVF BIT(10) #define TCPC_ALERT_FAULT BIT(9) #define TCPC_ALERT_V_ALARM_LO BIT(8) #define TCPC_ALERT_V_ALARM_HI BIT(7) #define TCPC_ALERT_TX_SUCCESS BIT(6) #define TCPC_ALERT_TX_DISCARDED BIT(5) #define TCPC_ALERT_TX_FAILED BIT(4) #define TCPC_ALERT_RX_HARD_RST BIT(3) #define TCPC_ALERT_RX_STATUS BIT(2) #define TCPC_ALERT_POWER_STATUS BIT(1) #define TCPC_ALERT_CC_STATUS BIT(0) #define TCPC_TCPC_CTRL 0x19 #define TCPC_TCPC_CTRL_BIST_MODE BIT(1) #define TCPC_TCPC_CTRL_ORIENTATION BIT(0) #define TCPC_ROLE_CTRL 0x1a #define TCPC_ROLE_CTRL_DRP BIT(6) #define TCPC_ROLE_CTRL_RP_VAL_SHIFT 4 #define TCPC_ROLE_CTRL_RP_VAL_MASK 0x3 #define TCPC_ROLE_CTRL_RP_VAL_DEF 0x0 #define TCPC_ROLE_CTRL_RP_VAL_1_5 0x1 #define TCPC_ROLE_CTRL_RP_VAL_3_0 0x2 #define TCPC_ROLE_CTRL_CC2_SHIFT 2 #define TCPC_ROLE_CTRL_CC2_MASK 0x3 #define TCPC_ROLE_CTRL_CC1_SHIFT 0 #define TCPC_ROLE_CTRL_CC1_MASK 0x3 #define TCPC_ROLE_CTRL_CC_RA 0x0 #define TCPC_ROLE_CTRL_CC_RP 0x1 #define TCPC_ROLE_CTRL_CC_RD 0x2 #define TCPC_ROLE_CTRL_CC_OPEN 0x3 #define TCPC_POWER_CTRL 0x1c #define TCPC_POWER_CTRL_EN_VCONN BIT(0) #define TCPC_POWER_CTRL_VCONN_POWER BIT(1) #define TCPC_POWER_CTRL_FORCE_DISCH BIT(2) #define TCPC_POWER_CTRL_EN_BLEED_CH BIT(3) #define TCPC_POWER_CTRL_AUTO_DISCH_DISCO BIT(4) #define TCPC_POWER_CTRL_DIS_V_ALARMS BIT(5) #define TCPC_POWER_CTRL_VBUS_V_MONITOR BIT(6) #define TCPC_CC_STATUS 0x1d #define TCPC_CC_STATUS_LOOK4CONN BIT(5) #define TCPC_CC_STATUS_TERM BIT(4) #define TCPC_CC_STATUS_CC2_SHIFT 2 #define TCPC_CC_STATUS_CC2_MASK 0x3 #define TCPC_CC_STATUS_CC1_SHIFT 0 #define TCPC_CC_STATUS_CC1_MASK 0x3 #define TCPC_POWER_STATUS 0x1e #define TCPC_POWER_STATUS_UNINIT BIT(6) #define TCPC_POWER_STATUS_VBUS_DET BIT(3) #define TCPC_POWER_STATUS_VBUS_PRES BIT(2) #define TCPC_POWER_STATUS_SINKING_VBUS BIT(0) #define TCPC_FAULT_STATUS 0x1f #define TCPC_COMMAND 0x23 #define TCPC_CMD_WAKE_I2C 0x11 #define TCPC_CMD_DISABLE_VBUS_DETECT 0x22 #define TCPC_CMD_ENABLE_VBUS_DETECT 0x33 #define TCPC_CMD_DISABLE_SINK_VBUS 0x44 #define TCPC_CMD_SINK_VBUS 0x55 #define TCPC_CMD_DISABLE_SRC_VBUS 0x66 #define TCPC_CMD_SRC_VBUS_DEFAULT 0x77 #define TCPC_CMD_SRC_VBUS_HIGH 0x88 #define TCPC_CMD_LOOK4CONNECTION 0x99 #define TCPC_CMD_RXONEMORE 0xAA #define TCPC_CMD_I2C_IDLE 0xFF #define TCPC_DEV_CAP_1 0x24 #define TCPC_DEV_CAP_2 0x26 #define TCPC_STD_INPUT_CAP 0x28 #define TCPC_STD_OUTPUT_CAP 0x29 #define TCPC_MSG_HDR_INFO 0x2e #define TCPC_MSG_HDR_INFO_DATA_ROLE BIT(3) #define TCPC_MSG_HDR_INFO_PWR_ROLE BIT(0) #define TCPC_MSG_HDR_INFO_REV_SHIFT 1 #define TCPC_MSG_HDR_INFO_REV_MASK 0x3 #define TCPC_RX_DETECT 0x2f #define TCPC_RX_DETECT_HARD_RESET BIT(5) #define TCPC_RX_DETECT_SOP BIT(0) #define TCPC_RX_BYTE_CNT 0x30 #define TCPC_RX_BUF_FRAME_TYPE 0x31 #define TCPC_RX_HDR 0x32 #define TCPC_RX_DATA 0x34 /* through 0x4f */ #define TCPC_TRANSMIT 0x50 #define TCPC_TRANSMIT_RETRY_SHIFT 4 #define TCPC_TRANSMIT_RETRY_MASK 0x3 #define TCPC_TRANSMIT_TYPE_SHIFT 0 #define TCPC_TRANSMIT_TYPE_MASK 0x7 #define TCPC_TX_BYTE_CNT 0x51 #define TCPC_TX_HDR 0x52 #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 #define TCPC_VBUS_VOLTAGE_ALARM_LO_CFG 0x78 enum typec_role { TYPEC_SINK, TYPEC_SOURCE, TYPEC_ROLE_UNKNOWN, }; enum typec_data_role { TYPEC_DEVICE, TYPEC_HOST, }; enum typec_cc_polarity { TYPEC_POLARITY_CC1, TYPEC_POLARITY_CC2, }; enum typec_cc_state { TYPEC_STATE_OPEN, TYPEC_STATE_SRC_BOTH_RA, TYPEC_STATE_SRC_RD_RA, TYPEC_STATE_SRC_RD, TYPEC_STATE_SRC_RESERVED, TYPEC_STATE_SNK_DEFAULT, TYPEC_STATE_SNK_POWER15, TYPEC_STATE_SNK_POWER30, }; /* USB PD Messages */ enum pd_ctrl_msg_type { /* 0 Reserved */ PD_CTRL_GOOD_CRC = 1, PD_CTRL_GOTO_MIN = 2, PD_CTRL_ACCEPT = 3, PD_CTRL_REJECT = 4, PD_CTRL_PING = 5, PD_CTRL_PS_RDY = 6, PD_CTRL_GET_SOURCE_CAP = 7, PD_CTRL_GET_SINK_CAP = 8, PD_CTRL_DR_SWAP = 9, PD_CTRL_PR_SWAP = 10, PD_CTRL_VCONN_SWAP = 11, PD_CTRL_WAIT = 12, PD_CTRL_SOFT_RESET = 13, /* 14-15 Reserved */ }; enum pd_data_msg_type { /* 0 Reserved */ PD_DATA_SOURCE_CAP = 1, PD_DATA_REQUEST = 2, PD_DATA_BIST = 3, PD_DATA_SINK_CAP = 4, /* 5-14 Reserved */ PD_DATA_VENDOR_DEF = 15, }; enum tcpc_transmit_type { TCPC_TX_SOP = 0, TCPC_TX_SOP_PRIME = 1, TCPC_TX_SOP_PRIME_PRIME = 2, TCPC_TX_SOP_DEBUG_PRIME = 3, TCPC_TX_SOP_DEBUG_PRIME_PRIME = 4, TCPC_TX_HARD_RESET = 5, TCPC_TX_CABLE_RESET = 6, TCPC_TX_BIST_MODE_2 = 7 }; enum pd_sink_state{ UNATTACH = 0, ATTACHED, WAIT_SOURCE_CAP, WAIT_SOURCE_ACCEPT, WAIT_SOURCE_READY, SINK_READY, }; #define PD_REV10 0x0 #define PD_REV20 0x1 #define PD_HEADER_CNT_SHIFT 12 #define PD_HEADER_CNT_MASK 0x7 #define PD_HEADER_ID_SHIFT 9 #define PD_HEADER_ID_MASK 0x7 #define PD_HEADER_PWR_ROLE BIT(8) #define PD_HEADER_REV_SHIFT 6 #define PD_HEADER_REV_MASK 0x3 #define PD_HEADER_DATA_ROLE BIT(5) #define PD_HEADER_TYPE_SHIFT 0 #define PD_HEADER_TYPE_MASK 0xf #define PD_HEADER(type, pwr, data, id, cnt) \ ((((type) & PD_HEADER_TYPE_MASK) << PD_HEADER_TYPE_SHIFT) | \ ((pwr) == TYPEC_SOURCE ? PD_HEADER_PWR_ROLE : 0) | \ ((data) == TYPEC_HOST ? PD_HEADER_DATA_ROLE : 0) | \ (PD_REV20 << PD_HEADER_REV_SHIFT) | \ (((id) & PD_HEADER_ID_MASK) << PD_HEADER_ID_SHIFT) | \ (((cnt) & PD_HEADER_CNT_MASK) << PD_HEADER_CNT_SHIFT)) static inline unsigned int pd_header_cnt(uint16_t header) { return (header >> PD_HEADER_CNT_SHIFT) & PD_HEADER_CNT_MASK; } static inline unsigned int pd_header_cnt_le(__le16 header) { return pd_header_cnt(le16_to_cpu(header)); } static inline unsigned int pd_header_type(uint16_t header) { return (header >> PD_HEADER_TYPE_SHIFT) & PD_HEADER_TYPE_MASK; } static inline unsigned int pd_header_type_le(__le16 header) { return pd_header_type(le16_to_cpu(header)); } #define PD_MAX_PAYLOAD 7 struct pd_message { uint8_t frametype; uint16_t header; uint32_t payload[PD_MAX_PAYLOAD]; } __packed; enum pd_pdo_type { PDO_TYPE_FIXED = 0, PDO_TYPE_BATT = 1, PDO_TYPE_VAR = 2, }; #define PDO_TYPE_SHIFT 30 #define PDO_TYPE_MASK 0x3 #define PDO_TYPE(t) ((t) << PDO_TYPE_SHIFT) #define PDO_VOLT_MASK 0x3ff #define PDO_CURR_MASK 0x3ff #define PDO_PWR_MASK 0x3ff #define PDO_FIXED_DUAL_ROLE BIT(29) /* Power role swap supported */ #define PDO_FIXED_SUSPEND BIT(28) /* USB Suspend supported (Source) */ #define PDO_FIXED_HIGHER_CAP BIT(28) /* Requires more than vSafe5V (Sink) */ #define PDO_FIXED_EXTPOWER BIT(27) /* Externally powered */ #define PDO_FIXED_USB_COMM BIT(26) /* USB communications capable */ #define PDO_FIXED_DATA_SWAP BIT(25) /* Data role swap supported */ #define PDO_FIXED_VOLT_SHIFT 10 /* 50mV units */ #define PDO_FIXED_CURR_SHIFT 0 /* 10mA units */ #define PDO_FIXED_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_FIXED_VOLT_SHIFT) #define PDO_FIXED_CURR(ma) ((((ma) / 10) & PDO_CURR_MASK) << PDO_FIXED_CURR_SHIFT) #define PDO_FIXED(mv, ma, flags) \ (PDO_TYPE(PDO_TYPE_FIXED) | (flags) | \ PDO_FIXED_VOLT(mv) | PDO_FIXED_CURR(ma)) #define PDO_BATT_MAX_VOLT_SHIFT 20 /* 50mV units */ #define PDO_BATT_MIN_VOLT_SHIFT 10 /* 50mV units */ #define PDO_BATT_MAX_PWR_SHIFT 0 /* 250mW units */ #define PDO_BATT_MIN_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_BATT_MIN_VOLT_SHIFT) #define PDO_BATT_MAX_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_BATT_MAX_VOLT_SHIFT) #define PDO_BATT_MAX_POWER(mw) ((((mw) / 250) & PDO_PWR_MASK) << PDO_BATT_MAX_PWR_SHIFT) #define PDO_BATT(min_mv, max_mv, max_mw) \ (PDO_TYPE(PDO_TYPE_BATT) | PDO_BATT_MIN_VOLT(min_mv) | \ PDO_BATT_MAX_VOLT(max_mv) | PDO_BATT_MAX_POWER(max_mw)) #define PDO_VAR_MAX_VOLT_SHIFT 20 /* 50mV units */ #define PDO_VAR_MIN_VOLT_SHIFT 10 /* 50mV units */ #define PDO_VAR_MAX_CURR_SHIFT 0 /* 10mA units */ #define PDO_VAR_MIN_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_VAR_MIN_VOLT_SHIFT) #define PDO_VAR_MAX_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_VAR_MAX_VOLT_SHIFT) #define PDO_VAR_MAX_CURR(ma) ((((ma) / 10) & PDO_CURR_MASK) << PDO_VAR_MAX_CURR_SHIFT) #define PDO_VAR(min_mv, max_mv, max_ma) \ (PDO_TYPE(PDO_TYPE_VAR) | PDO_VAR_MIN_VOLT(min_mv) | \ PDO_VAR_MAX_VOLT(max_mv) | PDO_VAR_MAX_CURR(max_ma)) static inline enum pd_pdo_type pdo_type(uint32_t pdo) { return (pdo >> PDO_TYPE_SHIFT) & PDO_TYPE_MASK; } static inline unsigned int pdo_fixed_voltage(uint32_t pdo) { return ((pdo >> PDO_FIXED_VOLT_SHIFT) & PDO_VOLT_MASK) * 50; } static inline unsigned int pdo_min_voltage(uint32_t pdo) { return ((pdo >> PDO_VAR_MIN_VOLT_SHIFT) & PDO_VOLT_MASK) * 50; } static inline unsigned int pdo_max_voltage(uint32_t pdo) { return ((pdo >> PDO_VAR_MAX_VOLT_SHIFT) & PDO_VOLT_MASK) * 50; } static inline unsigned int pdo_max_current(uint32_t pdo) { return ((pdo >> PDO_VAR_MAX_CURR_SHIFT) & PDO_CURR_MASK) * 10; } static inline unsigned int pdo_max_power(uint32_t pdo) { return ((pdo >> PDO_BATT_MAX_PWR_SHIFT) & PDO_PWR_MASK) * 250; } /* RDO: Request Data Object */ #define RDO_OBJ_POS_SHIFT 28 #define RDO_OBJ_POS_MASK 0x7 #define RDO_GIVE_BACK BIT(27) /* Supports reduced operating current */ #define RDO_CAP_MISMATCH BIT(26) /* Not satisfied by source caps */ #define RDO_USB_COMM BIT(25) /* USB communications capable */ #define RDO_NO_SUSPEND BIT(24) /* USB Suspend not supported */ #define RDO_PWR_MASK 0x3ff #define RDO_CURR_MASK 0x3ff #define RDO_FIXED_OP_CURR_SHIFT 10 #define RDO_FIXED_MAX_CURR_SHIFT 0 #define RDO_OBJ(idx) (((idx) & RDO_OBJ_POS_MASK) << RDO_OBJ_POS_SHIFT) #define PDO_FIXED_OP_CURR(ma) ((((ma) / 10) & RDO_CURR_MASK) << RDO_FIXED_OP_CURR_SHIFT) #define PDO_FIXED_MAX_CURR(ma) ((((ma) / 10) & RDO_CURR_MASK) << RDO_FIXED_MAX_CURR_SHIFT) #define RDO_FIXED(idx, op_ma, max_ma, flags) \ (RDO_OBJ(idx) | (flags) | \ PDO_FIXED_OP_CURR(op_ma) | PDO_FIXED_MAX_CURR(max_ma)) #define RDO_BATT_OP_PWR_SHIFT 10 /* 250mW units */ #define RDO_BATT_MAX_PWR_SHIFT 0 /* 250mW units */ #define RDO_BATT_OP_PWR(mw) ((((mw) / 250) & RDO_PWR_MASK) << RDO_BATT_OP_PWR_SHIFT) #define RDO_BATT_MAX_PWR(mw) ((((mw) / 250) & RDO_PWR_MASK) << RDO_BATT_MAX_PWR_SHIFT) #define RDO_BATT(idx, op_mw, max_mw, flags) \ (RDO_OBJ(idx) | (flags) | \ RDO_BATT_OP_PWR(op_mw) | RDO_BATT_MAX_PWR(max_mw)) static inline unsigned int rdo_index(u32 rdo) { return (rdo >> RDO_OBJ_POS_SHIFT) & RDO_OBJ_POS_MASK; } static inline unsigned int rdo_op_current(u32 rdo) { return ((rdo >> RDO_FIXED_OP_CURR_SHIFT) & RDO_CURR_MASK) * 10; } static inline unsigned int rdo_max_current(u32 rdo) { return ((rdo >> RDO_FIXED_MAX_CURR_SHIFT) & RDO_CURR_MASK) * 10; } static inline unsigned int rdo_op_power(u32 rdo) { return ((rdo >> RDO_BATT_OP_PWR_SHIFT) & RDO_PWR_MASK) * 250; } static inline unsigned int rdo_max_power(u32 rdo) { return ((rdo >> RDO_BATT_MAX_PWR_SHIFT) & RDO_PWR_MASK) * 250; } #define TCPC_LOG_BUFFER_SIZE 1024 struct tcpc_port; typedef void (*ss_mux_sel)(enum typec_cc_polarity pol); typedef int (*ext_pd_switch_setup)(struct tcpc_port *port_p); enum tcpc_port_type { TYPEC_PORT_DFP, TYPEC_PORT_UFP, TYPEC_PORT_DRP, }; struct tcpc_port_config { uint8_t i2c_bus; uint8_t addr; enum tcpc_port_type port_type; uint32_t max_snk_mv; uint32_t max_snk_ma; uint32_t max_snk_mw; uint32_t op_snk_mv; bool disable_pd; ext_pd_switch_setup switch_setup_func; }; struct tcpc_port { struct tcpc_port_config cfg; struct udevice *i2c_dev; ss_mux_sel ss_sel_func; enum pd_sink_state pd_state; uint32_t tx_msg_id; uint32_t log_size; char logbuffer[TCPC_LOG_BUFFER_SIZE]; char *log_p; char *log_print; }; int tcpc_set_cc_to_source(struct tcpc_port *port); int tcpc_set_cc_to_sink(struct tcpc_port *port); int tcpc_set_plug_orientation(struct tcpc_port *port, enum typec_cc_polarity polarity); int tcpc_get_cc_status(struct tcpc_port *port, enum typec_cc_polarity *polarity, enum typec_cc_state *state); int tcpc_clear_alert(struct tcpc_port *port, uint16_t clear_mask); int tcpc_send_command(struct tcpc_port *port, uint8_t command); int tcpc_polling_reg(struct tcpc_port *port, uint8_t reg, uint8_t reg_width, uint16_t mask, uint16_t value, ulong timeout_ms); int tcpc_setup_dfp_mode(struct tcpc_port *port); int tcpc_setup_ufp_mode(struct tcpc_port *port); int tcpc_disable_src_vbus(struct tcpc_port *port); int tcpc_init(struct tcpc_port *port, struct tcpc_port_config config, ss_mux_sel ss_sel_func); bool tcpc_pd_sink_check_charging(struct tcpc_port *port); void tcpc_print_log(struct tcpc_port *port); #ifdef CONFIG_SPL_BUILD int tcpc_setup_ufp_mode(struct tcpc_port *port) { return 0; } int tcpc_setup_dfp_mode(struct tcpc_port *port) { return 0; } int tcpc_disable_src_vbus(struct tcpc_port *port) { return 0; } #endif #endif /* __TCPCI_H */