// SPDX-License-Identifier: GPL-2.0 #include <linux/bitfield.h>#include <linux/completion.h>#include <linux/i2c.h>#include <linux/interrupt.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/power_supply.h>#include <linux/regmap.h>#include <linux/usb/pd.h>#include <linux/usb/role.h>#include <linux/usb/typec.h> #define RT1719_REG_TXCTRL1 0x03#define RT1719_REG_TXCTRL2 0x04#define RT1719_REG_POLICYINFO 0x0E#define RT1719_REG_SRCPDO1 0x11#define RT1719_REG_MASKS 0x2D#define RT1719_REG_EVENTS 0x33#define RT1719_REG_STATS 0x37#define RT1719_REG_PSELINFO 0x3C#define RT1719_REG_USBSETINFO 0x3E#define RT1719_REG_VENID 0x82 #define RT1719_UNIQUE_PID 0x1719#define RT1719_REQDRSWAP_MASK BIT(7)#define RT1719_EVALMODE_MASK BIT(4)#define RT1719_REQSRCPDO_MASK GENMASK(2, 0)#define RT1719_TXSPDOREQ_MASK BIT(7)#define RT1719_INT_DRSW_ACCEPT BIT(23)#define RT1719_INT_RX_SRCCAP BIT(21)#define RT1719_INT_VBUS_DCT BIT(6)#define RT1719_INT_VBUS_PRESENT BIT(5)#define RT1719_INT_PE_SNK_RDY BIT(2)#define RT1719_CC1_STAT GENMASK(9, 8)#define RT1719_CC2_STAT GENMASK(11, 10)#define RT1719_POLARITY_MASK BIT(23)#define RT1719_DATAROLE_MASK BIT(22)#define RT1719_PDSPECREV_MASK GENMASK(21, 20)#define RT1719_SPDOSEL_MASK GENMASK(18, 16)#define RT1719_SPDONUM_MASK GENMASK(15, 13)#define RT1719_ATTACH_VBUS BIT(12)#define RT1719_ATTACH_DBG BIT(10)#define RT1719_ATTACH_SNK BIT(9)#define RT1719_ATTACHDEV_MASK (RT1719_ATTACH_VBUS | RT1719_ATTACH_DBG | \ RT1719_ATTACH_SNK)#define RT1719_PE_EXP_CONTRACT BIT(2)#define RT1719_PSEL_SUPPORT BIT(15)#define RT1719_TBLSEL_MASK BIT(6)#define RT1719_LATPSEL_MASK GENMASK(5, 0)#define RT1719_USBINFO_MASK GENMASK(1, 0)#define RT1719_USB_DFPUFP 3#define RT1719_MAX_SRCPDO 7 enum { SNK_PWR_OPEN = 0, SNK_PWR_DEF, SNK_PWR_1P5A, SNK_PWR_3A}; enum { USBPD_SPECREV_1_0 = 0, USBPD_SPECREV_2_0, USBPD_SPECREV_3_0}; enum rt1719_snkcap { RT1719_SNKCAP_5V = 0, RT1719_SNKCAP_9V, RT1719_SNKCAP_12V, RT1719_SNKCAP_15V, RT1719_SNKCAP_20V, RT1719_MAX_SNKCAP}; struct rt1719_psel_cap { u8 lomask; u8 himask; u32 milliwatt; u32 milliamp;}; struct rt1719_data { struct device *dev; struct regmap *regmap; struct typec_port *port; struct usb_role_switch *role_sw; struct power_supply *psy; struct typec_partner *partner; struct power_supply_desc psy_desc; struct usb_pd_identity partner_ident; struct typec_partner_desc partner_desc; struct completion req_completion; enum power_supply_usb_type usb_type; bool attached; bool pd_capable; bool drswap_support; u32 voltage; u32 req_voltage; u32 max_current; u32 op_current; u32 spdos[RT1719_MAX_SRCPDO]; u16 snkcaps[RT1719_MAX_SNKCAP]; int spdo_num; int spdo_sel; u32 conn_info; u16 conn_stat;}; static const enum power_supply_property rt1719_psy_properties[] = { POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_USB_TYPE, POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_CURRENT_MAX, POWER_SUPPLY_PROP_CURRENT_NOW}; static int rt1719_read16(struct rt1719_data *data, unsigned int reg, u16 *val){ __le16 regval; int ret; ret = regmap_raw_read(data->regmap, reg, ®val, sizeof(regval)); if (ret) return ret; *val = le16_to_cpu(regval); return 0;} static int rt1719_read32(struct rt1719_data *data, unsigned int reg, u32 *val){ __le32 regval; int ret; ret = regmap_raw_read(data->regmap, reg, ®val, sizeof(regval)); if (ret) return ret; *val = le32_to_cpu(regval); return 0;} static int rt1719_write32(struct rt1719_data *data, unsigned int reg, u32 val){ __le32 regval = cpu_to_le32(val); return regmap_raw_write(data->regmap, reg, ®val, sizeof(regval));} static enum typec_pwr_opmode rt1719_get_pwr_opmode(u32 conn, u16 stat){ u16 cc1, cc2, cc_stat; cc1 = FIELD_GET(RT1719_CC1_STAT, stat); cc2 = FIELD_GET(RT1719_CC2_STAT, stat); if (conn & RT1719_ATTACH_SNK) { if (conn & RT1719_POLARITY_MASK) cc_stat = cc2; else cc_stat = cc1; switch (cc_stat) { case SNK_PWR_3A: return TYPEC_PWR_MODE_3_0A; case SNK_PWR_1P5A: return TYPEC_PWR_MODE_1_5A; } } else if (conn & RT1719_ATTACH_DBG) { if ((cc1 == SNK_PWR_1P5A && cc2 == SNK_PWR_DEF) || (cc1 == SNK_PWR_DEF && cc2 == SNK_PWR_1P5A)) return TYPEC_PWR_MODE_1_5A; else if ((cc1 == SNK_PWR_3A && cc2 == SNK_PWR_DEF) || (cc1 == SNK_PWR_DEF && cc2 == SNK_PWR_3A)) return TYPEC_PWR_MODE_3_0A; } return TYPEC_PWR_MODE_USB;} static enum typec_data_role rt1719_get_data_role(u32 conn){ if (conn & RT1719_DATAROLE_MASK) return TYPEC_HOST; return TYPEC_DEVICE;} static void rt1719_set_data_role(struct rt1719_data *data, enum typec_data_role data_role, bool attached){ enum usb_role usb_role = USB_ROLE_NONE; if (attached) { if (data_role == TYPEC_HOST) usb_role = USB_ROLE_HOST; else usb_role = USB_ROLE_DEVICE; } usb_role_switch_set_role(data->role_sw, usb_role); typec_set_data_role(data->port, data_role);} static void rt1719_update_data_role(struct rt1719_data *data){ if (!data->attached) return; rt1719_set_data_role(data, rt1719_get_data_role(data->conn_info), true);} static void rt1719_register_partner(struct rt1719_data *data){ u16 spec_rev = 0; if (data->pd_capable) { u32 rev; rev = FIELD_GET(RT1719_PDSPECREV_MASK, data->conn_info); switch (rev) { case USBPD_SPECREV_3_0: spec_rev = 0x0300; break; case USBPD_SPECREV_2_0: spec_rev = 0x0200; break; default: spec_rev = 0x0100; break; } } /* Just to prevent multiple times attach */ if (data->partner) typec_unregister_partner(data->partner); memset(&data->partner_ident, 0, sizeof(data->partner_ident)); data->partner_desc.usb_pd = data->pd_capable; data->partner_desc.pd_revision = spec_rev; if (data->conn_info & RT1719_ATTACH_DBG) data->partner_desc.accessory = TYPEC_ACCESSORY_DEBUG; else data->partner_desc.accessory = TYPEC_ACCESSORY_NONE; data->partner = typec_register_partner(data->port, &data->partner_desc);} static void rt1719_attach(struct rt1719_data *data){ enum typec_pwr_opmode pwr_opmode; enum typec_data_role data_role; u32 volt = 5000, curr = 500; if (!(data->conn_info & RT1719_ATTACHDEV_MASK)) return; pwr_opmode = rt1719_get_pwr_opmode(data->conn_info, data->conn_stat); data_role = rt1719_get_data_role(data->conn_info); typec_set_pwr_opmode(data->port, pwr_opmode); rt1719_set_data_role(data, data_role, true); if (data->conn_info & RT1719_ATTACH_SNK) rt1719_register_partner(data); if (pwr_opmode == TYPEC_PWR_MODE_3_0A) curr = 3000; else if (pwr_opmode == TYPEC_PWR_MODE_1_5A) curr = 1500; data->voltage = volt * 1000; data->max_current = data->op_current = curr * 1000; data->attached = true; power_supply_changed(data->psy);} static void rt1719_detach(struct rt1719_data *data){ if (!data->attached || (data->conn_info & RT1719_ATTACHDEV_MASK)) return; typec_unregister_partner(data->partner); data->partner = NULL; typec_set_pwr_opmode(data->port, TYPEC_PWR_MODE_USB); rt1719_set_data_role(data, TYPEC_DEVICE, false); memset32(data->spdos, 0, RT1719_MAX_SRCPDO); data->spdo_num = 0; data->voltage = data->max_current = data->op_current = 0; data->attached = data->pd_capable = false; data->usb_type = POWER_SUPPLY_USB_TYPE_C; power_supply_changed(data->psy);} static void rt1719_update_operating_status(struct rt1719_data *data){ enum power_supply_usb_type usb_type = POWER_SUPPLY_USB_TYPE_PD; u32 voltage, max_current, op_current; int i, snk_sel; for (i = 0; i < data->spdo_num; i++) { u32 pdo = data->spdos[i]; enum pd_pdo_type type = pdo_type(pdo); if (type == PDO_TYPE_APDO) { usb_type = POWER_SUPPLY_USB_TYPE_PD_PPS; break; } } data->spdo_sel = FIELD_GET(RT1719_SPDOSEL_MASK, data->conn_info); if (data->spdo_sel <= 0) return; data->usb_type = usb_type; voltage = pdo_fixed_voltage(data->spdos[data->spdo_sel - 1]); max_current = pdo_max_current(data->spdos[data->spdo_sel - 1]); switch (voltage) { case 5000: snk_sel = RT1719_SNKCAP_5V; break; case 9000: snk_sel = RT1719_SNKCAP_9V; break; case 12000: snk_sel = RT1719_SNKCAP_12V; break; case 15000: snk_sel = RT1719_SNKCAP_15V; break; case 20000: snk_sel = RT1719_SNKCAP_20V; break; default: return; } op_current = min(max_current, pdo_max_current(data->snkcaps[snk_sel])); /* covert mV/mA to uV/uA */ data->voltage = voltage * 1000; data->max_current = max_current * 1000; data->op_current = op_current * 1000; power_supply_changed(data->psy);} static void rt1719_update_pwr_opmode(struct rt1719_data *data){ if (!data->attached) return; if (!data->pd_capable) { data->pd_capable = true; typec_set_pwr_opmode(data->port, TYPEC_PWR_MODE_PD); rt1719_register_partner(data); } rt1719_update_operating_status(data);} static void rt1719_update_source_pdos(struct rt1719_data *data){ int spdo_num = FIELD_GET(RT1719_SPDONUM_MASK, data->conn_info); __le32 src_pdos[RT1719_MAX_SRCPDO] = { }; int i, ret; if (!data->attached) return; ret = regmap_raw_read(data->regmap, RT1719_REG_SRCPDO1, src_pdos, sizeof(__le32) * spdo_num); if (ret) return; data->spdo_num = spdo_num; for (i = 0; i < spdo_num; i++) data->spdos[i] = le32_to_cpu(src_pdos[i]);} static int rt1719_dr_set(struct typec_port *port, enum typec_data_role role){ struct rt1719_data *data = typec_get_drvdata(port); enum typec_data_role cur_role; int ret; if (!data->attached || !data->pd_capable || !data->drswap_support) return -EOPNOTSUPP; if (data->spdo_num > 0 && !(data->spdos[0] & PDO_FIXED_DATA_SWAP)) return -EINVAL; cur_role = rt1719_get_data_role(data->conn_info); if (cur_role == role) return 0; ret = regmap_update_bits(data->regmap, RT1719_REG_TXCTRL1, RT1719_REQDRSWAP_MASK, RT1719_REQDRSWAP_MASK); if (ret) return ret; reinit_completion(&data->req_completion); ret = wait_for_completion_timeout(&data->req_completion, msecs_to_jiffies(400)); if (ret == 0) return -ETIMEDOUT; cur_role = rt1719_get_data_role(data->conn_info); if (cur_role != role) return -EAGAIN; rt1719_set_data_role(data, role, true); return 0;} static const struct typec_operations rt1719_port_ops = { .dr_set = rt1719_dr_set,}; static int rt1719_usbpd_request_voltage(struct rt1719_data *data){ u32 src_voltage; int snk_sel, src_sel = -1; int i, ret; if (!data->attached || !data->pd_capable || data->spdo_sel <= 0) return -EINVAL; src_voltage = pdo_fixed_voltage(data->spdos[data->spdo_sel - 1]); if (src_voltage == data->req_voltage) return 0; switch (data->req_voltage) { case 5000: snk_sel = RT1719_SNKCAP_5V; break; case 9000: snk_sel = RT1719_SNKCAP_9V; break; case 12000: snk_sel = RT1719_SNKCAP_12V; break; case 15000: snk_sel = RT1719_SNKCAP_15V; break; case 20000: snk_sel = RT1719_SNKCAP_20V; break; default: return -EINVAL; } if (!(data->snkcaps[snk_sel] & RT1719_PSEL_SUPPORT)) return -EINVAL; for (i = 0; i < data->spdo_num; i++) { enum pd_pdo_type type = pdo_type(data->spdos[i]); if (type != PDO_TYPE_FIXED) continue; src_voltage = pdo_fixed_voltage(data->spdos[i]); if (src_voltage == data->req_voltage) { src_sel = i; break; } } if (src_sel == -1) return -EOPNOTSUPP; ret = regmap_update_bits(data->regmap, RT1719_REG_TXCTRL1, RT1719_EVALMODE_MASK | RT1719_REQSRCPDO_MASK, RT1719_EVALMODE_MASK | (src_sel + 1)); ret |= regmap_update_bits(data->regmap, RT1719_REG_TXCTRL2, RT1719_TXSPDOREQ_MASK, RT1719_TXSPDOREQ_MASK); if (ret) return ret; reinit_completion(&data->req_completion); ret = wait_for_completion_timeout(&data->req_completion, msecs_to_jiffies(400)); if (!ret) return -ETIMEDOUT; return 0;} Lines 1–500 of 954. Load more
// SPDX-License-Identifier: GPL-2.0 #include <linux/bitfield.h> #include <linux/completion.h> #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/power_supply.h> #include <linux/regmap.h> #include <linux/usb/pd.h> #include <linux/usb/role.h> #include <linux/usb/typec.h> #define RT1719_REG_TXCTRL1 0x03 #define RT1719_REG_TXCTRL2 0x04 #define RT1719_REG_POLICYINFO 0x0E #define RT1719_REG_SRCPDO1 0x11 #define RT1719_REG_MASKS 0x2D #define RT1719_REG_EVENTS 0x33 #define RT1719_REG_STATS 0x37 #define RT1719_REG_PSELINFO 0x3C #define RT1719_REG_USBSETINFO 0x3E #define RT1719_REG_VENID 0x82 #define RT1719_UNIQUE_PID 0x1719 #define RT1719_REQDRSWAP_MASK BIT(7) #define RT1719_EVALMODE_MASK BIT(4) #define RT1719_REQSRCPDO_MASK GENMASK(2, 0) #define RT1719_TXSPDOREQ_MASK BIT(7) #define RT1719_INT_DRSW_ACCEPT BIT(23) #define RT1719_INT_RX_SRCCAP BIT(21) #define RT1719_INT_VBUS_DCT BIT(6) #define RT1719_INT_VBUS_PRESENT BIT(5) #define RT1719_INT_PE_SNK_RDY BIT(2) #define RT1719_CC1_STAT GENMASK(9, 8) #define RT1719_CC2_STAT GENMASK(11, 10) #define RT1719_POLARITY_MASK BIT(23) #define RT1719_DATAROLE_MASK BIT(22) #define RT1719_PDSPECREV_MASK GENMASK(21, 20) #define RT1719_SPDOSEL_MASK GENMASK(18, 16) #define RT1719_SPDONUM_MASK GENMASK(15, 13) #define RT1719_ATTACH_VBUS BIT(12) #define RT1719_ATTACH_DBG BIT(10) #define RT1719_ATTACH_SNK BIT(9) #define RT1719_ATTACHDEV_MASK (RT1719_ATTACH_VBUS | RT1719_ATTACH_DBG | \ RT1719_ATTACH_SNK) #define RT1719_PE_EXP_CONTRACT BIT(2) #define RT1719_PSEL_SUPPORT BIT(15) #define RT1719_TBLSEL_MASK BIT(6) #define RT1719_LATPSEL_MASK GENMASK(5, 0) #define RT1719_USBINFO_MASK GENMASK(1, 0) #define RT1719_USB_DFPUFP 3 #define RT1719_MAX_SRCPDO 7 enum { SNK_PWR_OPEN = 0, SNK_PWR_DEF, SNK_PWR_1P5A, SNK_PWR_3A }; enum { USBPD_SPECREV_1_0 = 0, USBPD_SPECREV_2_0, USBPD_SPECREV_3_0 }; enum rt1719_snkcap { RT1719_SNKCAP_5V = 0, RT1719_SNKCAP_9V, RT1719_SNKCAP_12V, RT1719_SNKCAP_15V, RT1719_SNKCAP_20V, RT1719_MAX_SNKCAP }; struct rt1719_psel_cap { u8 lomask; u8 himask; u32 milliwatt; u32 milliamp; }; struct rt1719_data { struct device *dev; struct regmap *regmap; struct typec_port *port; struct usb_role_switch *role_sw; struct power_supply *psy; struct typec_partner *partner; struct power_supply_desc psy_desc; struct usb_pd_identity partner_ident; struct typec_partner_desc partner_desc; struct completion req_completion; enum power_supply_usb_type usb_type; bool attached; bool pd_capable; bool drswap_support; u32 voltage; u32 req_voltage; u32 max_current; u32 op_current; u32 spdos[RT1719_MAX_SRCPDO]; u16 snkcaps[RT1719_MAX_SNKCAP]; int spdo_num; int spdo_sel; u32 conn_info; u16 conn_stat; }; static const enum power_supply_property rt1719_psy_properties[] = { POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_USB_TYPE, POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_CURRENT_MAX, POWER_SUPPLY_PROP_CURRENT_NOW }; static int rt1719_read16(struct rt1719_data *data, unsigned int reg, u16 *val) { __le16 regval; int ret; ret = regmap_raw_read(data->regmap, reg, ®val, sizeof(regval)); if (ret) return ret; *val = le16_to_cpu(regval); return 0; } static int rt1719_read32(struct rt1719_data *data, unsigned int reg, u32 *val) { __le32 regval; int ret; ret = regmap_raw_read(data->regmap, reg, ®val, sizeof(regval)); if (ret) return ret; *val = le32_to_cpu(regval); return 0; } static int rt1719_write32(struct rt1719_data *data, unsigned int reg, u32 val) { __le32 regval = cpu_to_le32(val); return regmap_raw_write(data->regmap, reg, ®val, sizeof(regval)); } static enum typec_pwr_opmode rt1719_get_pwr_opmode(u32 conn, u16 stat) { u16 cc1, cc2, cc_stat; cc1 = FIELD_GET(RT1719_CC1_STAT, stat); cc2 = FIELD_GET(RT1719_CC2_STAT, stat); if (conn & RT1719_ATTACH_SNK) { if (conn & RT1719_POLARITY_MASK) cc_stat = cc2; else cc_stat = cc1; switch (cc_stat) { case SNK_PWR_3A: return TYPEC_PWR_MODE_3_0A; case SNK_PWR_1P5A: return TYPEC_PWR_MODE_1_5A; } } else if (conn & RT1719_ATTACH_DBG) { if ((cc1 == SNK_PWR_1P5A && cc2 == SNK_PWR_DEF) || (cc1 == SNK_PWR_DEF && cc2 == SNK_PWR_1P5A)) return TYPEC_PWR_MODE_1_5A; else if ((cc1 == SNK_PWR_3A && cc2 == SNK_PWR_DEF) || (cc1 == SNK_PWR_DEF && cc2 == SNK_PWR_3A)) return TYPEC_PWR_MODE_3_0A; } return TYPEC_PWR_MODE_USB; } static enum typec_data_role rt1719_get_data_role(u32 conn) { if (conn & RT1719_DATAROLE_MASK) return TYPEC_HOST; return TYPEC_DEVICE; } static void rt1719_set_data_role(struct rt1719_data *data, enum typec_data_role data_role, bool attached) { enum usb_role usb_role = USB_ROLE_NONE; if (attached) { if (data_role == TYPEC_HOST) usb_role = USB_ROLE_HOST; else usb_role = USB_ROLE_DEVICE; } usb_role_switch_set_role(data->role_sw, usb_role); typec_set_data_role(data->port, data_role); } static void rt1719_update_data_role(struct rt1719_data *data) { if (!data->attached) return; rt1719_set_data_role(data, rt1719_get_data_role(data->conn_info), true); } static void rt1719_register_partner(struct rt1719_data *data) { u16 spec_rev = 0; if (data->pd_capable) { u32 rev; rev = FIELD_GET(RT1719_PDSPECREV_MASK, data->conn_info); switch (rev) { case USBPD_SPECREV_3_0: spec_rev = 0x0300; break; case USBPD_SPECREV_2_0: spec_rev = 0x0200; break; default: spec_rev = 0x0100; break; } } /* Just to prevent multiple times attach */ if (data->partner) typec_unregister_partner(data->partner); memset(&data->partner_ident, 0, sizeof(data->partner_ident)); data->partner_desc.usb_pd = data->pd_capable; data->partner_desc.pd_revision = spec_rev; if (data->conn_info & RT1719_ATTACH_DBG) data->partner_desc.accessory = TYPEC_ACCESSORY_DEBUG; else data->partner_desc.accessory = TYPEC_ACCESSORY_NONE; data->partner = typec_register_partner(data->port, &data->partner_desc); } static void rt1719_attach(struct rt1719_data *data) { enum typec_pwr_opmode pwr_opmode; enum typec_data_role data_role; u32 volt = 5000, curr = 500; if (!(data->conn_info & RT1719_ATTACHDEV_MASK)) return; pwr_opmode = rt1719_get_pwr_opmode(data->conn_info, data->conn_stat); data_role = rt1719_get_data_role(data->conn_info); typec_set_pwr_opmode(data->port, pwr_opmode); rt1719_set_data_role(data, data_role, true); if (data->conn_info & RT1719_ATTACH_SNK) rt1719_register_partner(data); if (pwr_opmode == TYPEC_PWR_MODE_3_0A) curr = 3000; else if (pwr_opmode == TYPEC_PWR_MODE_1_5A) curr = 1500; data->voltage = volt * 1000; data->max_current = data->op_current = curr * 1000; data->attached = true; power_supply_changed(data->psy); } static void rt1719_detach(struct rt1719_data *data) { if (!data->attached || (data->conn_info & RT1719_ATTACHDEV_MASK)) return; typec_unregister_partner(data->partner); data->partner = NULL; typec_set_pwr_opmode(data->port, TYPEC_PWR_MODE_USB); rt1719_set_data_role(data, TYPEC_DEVICE, false); memset32(data->spdos, 0, RT1719_MAX_SRCPDO); data->spdo_num = 0; data->voltage = data->max_current = data->op_current = 0; data->attached = data->pd_capable = false; data->usb_type = POWER_SUPPLY_USB_TYPE_C; power_supply_changed(data->psy); } static void rt1719_update_operating_status(struct rt1719_data *data) { enum power_supply_usb_type usb_type = POWER_SUPPLY_USB_TYPE_PD; u32 voltage, max_current, op_current; int i, snk_sel; for (i = 0; i < data->spdo_num; i++) { u32 pdo = data->spdos[i]; enum pd_pdo_type type = pdo_type(pdo); if (type == PDO_TYPE_APDO) { usb_type = POWER_SUPPLY_USB_TYPE_PD_PPS; break; } } data->spdo_sel = FIELD_GET(RT1719_SPDOSEL_MASK, data->conn_info); if (data->spdo_sel <= 0) return; data->usb_type = usb_type; voltage = pdo_fixed_voltage(data->spdos[data->spdo_sel - 1]); max_current = pdo_max_current(data->spdos[data->spdo_sel - 1]); switch (voltage) { case 5000: snk_sel = RT1719_SNKCAP_5V; break; case 9000: snk_sel = RT1719_SNKCAP_9V; break; case 12000: snk_sel = RT1719_SNKCAP_12V; break; case 15000: snk_sel = RT1719_SNKCAP_15V; break; case 20000: snk_sel = RT1719_SNKCAP_20V; break; default: return; } op_current = min(max_current, pdo_max_current(data->snkcaps[snk_sel])); /* covert mV/mA to uV/uA */ data->voltage = voltage * 1000; data->max_current = max_current * 1000; data->op_current = op_current * 1000; power_supply_changed(data->psy); } static void rt1719_update_pwr_opmode(struct rt1719_data *data) { if (!data->attached) return; if (!data->pd_capable) { data->pd_capable = true; typec_set_pwr_opmode(data->port, TYPEC_PWR_MODE_PD); rt1719_register_partner(data); } rt1719_update_operating_status(data); } static void rt1719_update_source_pdos(struct rt1719_data *data) { int spdo_num = FIELD_GET(RT1719_SPDONUM_MASK, data->conn_info); __le32 src_pdos[RT1719_MAX_SRCPDO] = { }; int i, ret; if (!data->attached) return; ret = regmap_raw_read(data->regmap, RT1719_REG_SRCPDO1, src_pdos, sizeof(__le32) * spdo_num); if (ret) return; data->spdo_num = spdo_num; for (i = 0; i < spdo_num; i++) data->spdos[i] = le32_to_cpu(src_pdos[i]); } static int rt1719_dr_set(struct typec_port *port, enum typec_data_role role) { struct rt1719_data *data = typec_get_drvdata(port); enum typec_data_role cur_role; int ret; if (!data->attached || !data->pd_capable || !data->drswap_support) return -EOPNOTSUPP; if (data->spdo_num > 0 && !(data->spdos[0] & PDO_FIXED_DATA_SWAP)) return -EINVAL; cur_role = rt1719_get_data_role(data->conn_info); if (cur_role == role) return 0; ret = regmap_update_bits(data->regmap, RT1719_REG_TXCTRL1, RT1719_REQDRSWAP_MASK, RT1719_REQDRSWAP_MASK); if (ret) return ret; reinit_completion(&data->req_completion); ret = wait_for_completion_timeout(&data->req_completion, msecs_to_jiffies(400)); if (ret == 0) return -ETIMEDOUT; cur_role = rt1719_get_data_role(data->conn_info); if (cur_role != role) return -EAGAIN; rt1719_set_data_role(data, role, true); return 0; } static const struct typec_operations rt1719_port_ops = { .dr_set = rt1719_dr_set, }; static int rt1719_usbpd_request_voltage(struct rt1719_data *data) { u32 src_voltage; int snk_sel, src_sel = -1; int i, ret; if (!data->attached || !data->pd_capable || data->spdo_sel <= 0) return -EINVAL; src_voltage = pdo_fixed_voltage(data->spdos[data->spdo_sel - 1]); if (src_voltage == data->req_voltage) return 0; switch (data->req_voltage) { case 5000: snk_sel = RT1719_SNKCAP_5V; break; case 9000: snk_sel = RT1719_SNKCAP_9V; break; case 12000: snk_sel = RT1719_SNKCAP_12V; break; case 15000: snk_sel = RT1719_SNKCAP_15V; break; case 20000: snk_sel = RT1719_SNKCAP_20V; break; default: return -EINVAL; } if (!(data->snkcaps[snk_sel] & RT1719_PSEL_SUPPORT)) return -EINVAL; for (i = 0; i < data->spdo_num; i++) { enum pd_pdo_type type = pdo_type(data->spdos[i]); if (type != PDO_TYPE_FIXED) continue; src_voltage = pdo_fixed_voltage(data->spdos[i]); if (src_voltage == data->req_voltage) { src_sel = i; break; } } if (src_sel == -1) return -EOPNOTSUPP; ret = regmap_update_bits(data->regmap, RT1719_REG_TXCTRL1, RT1719_EVALMODE_MASK | RT1719_REQSRCPDO_MASK, RT1719_EVALMODE_MASK | (src_sel + 1)); ret |= regmap_update_bits(data->regmap, RT1719_REG_TXCTRL2, RT1719_TXSPDOREQ_MASK, RT1719_TXSPDOREQ_MASK); if (ret) return ret; reinit_completion(&data->req_completion); ret = wait_for_completion_timeout(&data->req_completion, msecs_to_jiffies(400)); if (!ret) return -ETIMEDOUT; return 0; }