diff options
Diffstat (limited to 'drivers/usb/typec')
-rw-r--r-- | drivers/usb/typec/altmodes/displayport.c | 1 | ||||
-rw-r--r-- | drivers/usb/typec/altmodes/nvidia.c | 1 | ||||
-rw-r--r-- | drivers/usb/typec/mux/Kconfig | 2 | ||||
-rw-r--r-- | drivers/usb/typec/mux/gpio-sbu-mux.c | 8 | ||||
-rw-r--r-- | drivers/usb/typec/mux/it5205.c | 2 | ||||
-rw-r--r-- | drivers/usb/typec/mux/ptn36502.c | 44 | ||||
-rw-r--r-- | drivers/usb/typec/stusb160x.c | 2 | ||||
-rw-r--r-- | drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c | 18 | ||||
-rw-r--r-- | drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c | 11 | ||||
-rw-r--r-- | drivers/usb/typec/tcpm/tcpm.c | 46 | ||||
-rw-r--r-- | drivers/usb/typec/tipd/core.c | 56 | ||||
-rw-r--r-- | drivers/usb/typec/tipd/tps6598x.h | 11 | ||||
-rw-r--r-- | drivers/usb/typec/ucsi/displayport.c | 4 | ||||
-rw-r--r-- | drivers/usb/typec/ucsi/ucsi.c | 231 | ||||
-rw-r--r-- | drivers/usb/typec/ucsi/ucsi.h | 8 | ||||
-rw-r--r-- | drivers/usb/typec/ucsi/ucsi_acpi.c | 56 | ||||
-rw-r--r-- | drivers/usb/typec/ucsi/ucsi_glink.c | 92 | ||||
-rw-r--r-- | drivers/usb/typec/ucsi/ucsi_stm32g0.c | 1 |
18 files changed, 291 insertions, 303 deletions
diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c index 038dc51f429d..596cd4806018 100644 --- a/drivers/usb/typec/altmodes/displayport.c +++ b/drivers/usb/typec/altmodes/displayport.c @@ -802,7 +802,6 @@ static struct typec_altmode_driver dp_altmode_driver = { .remove = dp_altmode_remove, .driver = { .name = "typec_displayport", - .owner = THIS_MODULE, .dev_groups = displayport_groups, }, }; diff --git a/drivers/usb/typec/altmodes/nvidia.c b/drivers/usb/typec/altmodes/nvidia.c index c36769736405..fe70b36f078f 100644 --- a/drivers/usb/typec/altmodes/nvidia.c +++ b/drivers/usb/typec/altmodes/nvidia.c @@ -35,7 +35,6 @@ static struct typec_altmode_driver nvidia_altmode_driver = { .remove = nvidia_altmode_remove, .driver = { .name = "typec_nvidia", - .owner = THIS_MODULE, }, }; module_typec_altmode_driver(nvidia_altmode_driver); diff --git a/drivers/usb/typec/mux/Kconfig b/drivers/usb/typec/mux/Kconfig index 399c7b0983df..ce7db6ad3057 100644 --- a/drivers/usb/typec/mux/Kconfig +++ b/drivers/usb/typec/mux/Kconfig @@ -60,7 +60,7 @@ config TYPEC_MUX_PTN36502 tristate "NXP PTN36502 Type-C redriver driver" depends on I2C depends on DRM || DRM=n - select DRM_PANEL_BRIDGE if DRM + select DRM_AUX_BRIDGE if DRM_BRIDGE && OF select REGMAP_I2C help Say Y or M if your system has a NXP PTN36502 Type-C redriver chip diff --git a/drivers/usb/typec/mux/gpio-sbu-mux.c b/drivers/usb/typec/mux/gpio-sbu-mux.c index ad60fd4e8431..374168482d36 100644 --- a/drivers/usb/typec/mux/gpio-sbu-mux.c +++ b/drivers/usb/typec/mux/gpio-sbu-mux.c @@ -48,10 +48,10 @@ static int gpio_sbu_switch_set(struct typec_switch_dev *sw, } if (enabled != sbu_mux->enabled) - gpiod_set_value(sbu_mux->enable_gpio, enabled); + gpiod_set_value_cansleep(sbu_mux->enable_gpio, enabled); if (swapped != sbu_mux->swapped) - gpiod_set_value(sbu_mux->select_gpio, swapped); + gpiod_set_value_cansleep(sbu_mux->select_gpio, swapped); sbu_mux->enabled = enabled; sbu_mux->swapped = swapped; @@ -82,7 +82,7 @@ static int gpio_sbu_mux_set(struct typec_mux_dev *mux, break; } - gpiod_set_value(sbu_mux->enable_gpio, sbu_mux->enabled); + gpiod_set_value_cansleep(sbu_mux->enable_gpio, sbu_mux->enabled); mutex_unlock(&sbu_mux->lock); @@ -141,7 +141,7 @@ static void gpio_sbu_mux_remove(struct platform_device *pdev) { struct gpio_sbu_mux *sbu_mux = platform_get_drvdata(pdev); - gpiod_set_value(sbu_mux->enable_gpio, 0); + gpiod_set_value_cansleep(sbu_mux->enable_gpio, 0); typec_mux_unregister(sbu_mux->mux); typec_switch_unregister(sbu_mux->sw); diff --git a/drivers/usb/typec/mux/it5205.c b/drivers/usb/typec/mux/it5205.c index 5535932e42cd..4357cc67a867 100644 --- a/drivers/usb/typec/mux/it5205.c +++ b/drivers/usb/typec/mux/it5205.c @@ -22,7 +22,7 @@ #include <linux/usb/typec_mux.h> #define IT5205_REG_CHIP_ID(x) (0x4 + (x)) -#define IT5205FN_CHIP_ID 0x35323035 /* "5205" */ +#define IT5205FN_CHIP_ID 0x35303235 /* "5025" -> "5205" */ /* MUX power down register */ #define IT5205_REG_MUXPDR 0x10 diff --git a/drivers/usb/typec/mux/ptn36502.c b/drivers/usb/typec/mux/ptn36502.c index 72ae38a1b2be..0ec86ef32a87 100644 --- a/drivers/usb/typec/mux/ptn36502.c +++ b/drivers/usb/typec/mux/ptn36502.c @@ -8,7 +8,7 @@ * Copyright (C) 2023 Dmitry Baryshkov <dmitry.baryshkov@linaro.org> */ -#include <drm/drm_bridge.h> +#include <drm/bridge/aux-bridge.h> #include <linux/bitfield.h> #include <linux/i2c.h> #include <linux/kernel.h> @@ -68,8 +68,6 @@ struct ptn36502 { struct typec_switch *typec_switch; - struct drm_bridge bridge; - struct mutex lock; /* protect non-concurrent retimer & switch */ enum typec_orientation orientation; @@ -283,44 +281,6 @@ static int ptn36502_detect(struct ptn36502 *ptn) return 0; } -#if IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_DRM_PANEL_BRIDGE) -static int ptn36502_bridge_attach(struct drm_bridge *bridge, - enum drm_bridge_attach_flags flags) -{ - struct ptn36502 *ptn = container_of(bridge, struct ptn36502, bridge); - struct drm_bridge *next_bridge; - - if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) - return -EINVAL; - - next_bridge = devm_drm_of_get_bridge(&ptn->client->dev, ptn->client->dev.of_node, 0, 0); - if (IS_ERR(next_bridge)) { - dev_err(&ptn->client->dev, "failed to acquire drm_bridge: %pe\n", next_bridge); - return PTR_ERR(next_bridge); - } - - return drm_bridge_attach(bridge->encoder, next_bridge, bridge, - DRM_BRIDGE_ATTACH_NO_CONNECTOR); -} - -static const struct drm_bridge_funcs ptn36502_bridge_funcs = { - .attach = ptn36502_bridge_attach, -}; - -static int ptn36502_register_bridge(struct ptn36502 *ptn) -{ - ptn->bridge.funcs = &ptn36502_bridge_funcs; - ptn->bridge.of_node = ptn->client->dev.of_node; - - return devm_drm_bridge_add(&ptn->client->dev, &ptn->bridge); -} -#else -static int ptn36502_register_bridge(struct ptn36502 *ptn) -{ - return 0; -} -#endif - static const struct regmap_config ptn36502_regmap = { .max_register = 0x0d, .reg_bits = 8, @@ -369,7 +329,7 @@ static int ptn36502_probe(struct i2c_client *client) if (ret) goto err_disable_regulator; - ret = ptn36502_register_bridge(ptn); + ret = drm_aux_bridge_register(dev); if (ret) goto err_disable_regulator; diff --git a/drivers/usb/typec/stusb160x.c b/drivers/usb/typec/stusb160x.c index 3ab118df1bd4..f3140fc04c12 100644 --- a/drivers/usb/typec/stusb160x.c +++ b/drivers/usb/typec/stusb160x.c @@ -234,7 +234,7 @@ static const struct regmap_config stusb1600_regmap_config = { .readable_reg = stusb160x_reg_readable, .volatile_reg = stusb160x_reg_volatile, .precious_reg = stusb160x_reg_precious, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static bool stusb160x_get_vconn(struct stusb160x *chip) diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c index e48412cdcb0f..501eddb294e4 100644 --- a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c +++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c @@ -41,7 +41,7 @@ static int qcom_pmic_typec_probe(struct platform_device *pdev) struct device_node *np = dev->of_node; const struct pmic_typec_resources *res; struct regmap *regmap; - struct device *bridge_dev; + struct auxiliary_device *bridge_dev; u32 base; int ret; @@ -92,7 +92,7 @@ static int qcom_pmic_typec_probe(struct platform_device *pdev) if (!tcpm->tcpc.fwnode) return -EINVAL; - bridge_dev = drm_dp_hpd_bridge_register(tcpm->dev, to_of_node(tcpm->tcpc.fwnode)); + bridge_dev = devm_drm_dp_hpd_bridge_alloc(tcpm->dev, to_of_node(tcpm->tcpc.fwnode)); if (IS_ERR(bridge_dev)) return PTR_ERR(bridge_dev); @@ -104,14 +104,24 @@ static int qcom_pmic_typec_probe(struct platform_device *pdev) ret = tcpm->port_start(tcpm, tcpm->tcpm_port); if (ret) - goto fwnode_remove; + goto port_unregister; ret = tcpm->pdphy_start(tcpm, tcpm->tcpm_port); if (ret) - goto fwnode_remove; + goto port_stop; + + ret = devm_drm_dp_hpd_bridge_add(tcpm->dev, bridge_dev); + if (ret) + goto pdphy_stop; return 0; +pdphy_stop: + tcpm->pdphy_stop(tcpm); +port_stop: + tcpm->port_stop(tcpm); +port_unregister: + tcpm_unregister_port(tcpm->tcpm_port); fwnode_remove: fwnode_remove_software_node(tcpm->tcpc.fwnode); diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c index 6560f4fc98d5..5b7f52b74a40 100644 --- a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c +++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c @@ -475,10 +475,8 @@ static int qcom_pmic_typec_pdphy_enable(struct pmic_typec_pdphy *pmic_typec_pdph qcom_pmic_typec_pdphy_reset_off(pmic_typec_pdphy); done: - if (ret) { - regulator_disable(pmic_typec_pdphy->vdd_pdphy); + if (ret) dev_err(dev, "pdphy_enable fail %d\n", ret); - } return ret; } @@ -524,12 +522,17 @@ static int qcom_pmic_typec_pdphy_start(struct pmic_typec *tcpm, ret = pmic_typec_pdphy_reset(pmic_typec_pdphy); if (ret) - return ret; + goto err_disable_vdd_pdhy; for (i = 0; i < pmic_typec_pdphy->nr_irqs; i++) enable_irq(pmic_typec_pdphy->irq_data[i].irq); return 0; + +err_disable_vdd_pdhy: + regulator_disable(pmic_typec_pdphy->vdd_pdphy); + + return ret; } static void qcom_pmic_typec_pdphy_stop(struct pmic_typec *tcpm) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index c26fb70c3ec6..8a1af08f71b6 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -1564,8 +1564,12 @@ static void tcpm_queue_vdm(struct tcpm_port *port, const u32 header, static void tcpm_queue_vdm_unlocked(struct tcpm_port *port, const u32 header, const u32 *data, int cnt, enum tcpm_transmit_type tx_sop_type) { + if (port->state != SRC_READY && port->state != SNK_READY && + port->state != SRC_VDM_IDENTITY_REQUEST) + return; + mutex_lock(&port->lock); - tcpm_queue_vdm(port, header, data, cnt, TCPC_TX_SOP); + tcpm_queue_vdm(port, header, data, cnt, tx_sop_type); mutex_unlock(&port->lock); } @@ -1580,7 +1584,8 @@ static void svdm_consume_identity(struct tcpm_port *port, const u32 *p, int cnt) port->partner_ident.cert_stat = p[VDO_INDEX_CSTAT]; port->partner_ident.product = product; - typec_partner_set_identity(port->partner); + if (port->partner) + typec_partner_set_identity(port->partner); tcpm_log(port, "Identity: %04x:%04x.%04x", PD_IDH_VID(vdo), @@ -1742,6 +1747,9 @@ static void tcpm_register_partner_altmodes(struct tcpm_port *port) struct typec_altmode *altmode; int i; + if (!port->partner) + return; + for (i = 0; i < modep->altmodes; i++) { altmode = typec_partner_register_altmode(port->partner, &modep->altmode_desc[i]); @@ -2996,7 +3004,7 @@ static int tcpm_register_source_caps(struct tcpm_port *port) { struct usb_power_delivery_desc desc = { port->negotiated_rev }; struct usb_power_delivery_capabilities_desc caps = { }; - struct usb_power_delivery_capabilities *cap; + struct usb_power_delivery_capabilities *cap = port->partner_source_caps; if (!port->partner_pd) port->partner_pd = usb_power_delivery_register(NULL, &desc); @@ -3006,6 +3014,9 @@ static int tcpm_register_source_caps(struct tcpm_port *port) memcpy(caps.pdo, port->source_caps, sizeof(u32) * port->nr_source_caps); caps.role = TYPEC_SOURCE; + if (cap) + usb_power_delivery_unregister_capabilities(cap); + cap = usb_power_delivery_register_capabilities(port->partner_pd, &caps); if (IS_ERR(cap)) return PTR_ERR(cap); @@ -4231,7 +4242,10 @@ static int tcpm_init_vconn(struct tcpm_port *port) static void tcpm_typec_connect(struct tcpm_port *port) { + struct typec_partner *partner; + if (!port->connected) { + port->connected = true; /* Make sure we don't report stale identity information */ memset(&port->partner_ident, 0, sizeof(port->partner_ident)); port->partner_desc.usb_pd = port->pd_capable; @@ -4241,9 +4255,13 @@ static void tcpm_typec_connect(struct tcpm_port *port) port->partner_desc.accessory = TYPEC_ACCESSORY_AUDIO; else port->partner_desc.accessory = TYPEC_ACCESSORY_NONE; - port->partner = typec_register_partner(port->typec_port, - &port->partner_desc); - port->connected = true; + partner = typec_register_partner(port->typec_port, &port->partner_desc); + if (IS_ERR(partner)) { + dev_err(port->dev, "Failed to register partner (%ld)\n", PTR_ERR(partner)); + return; + } + + port->partner = partner; typec_partner_set_usb_power_delivery(port->partner, port->partner_pd); } } @@ -4323,9 +4341,11 @@ static void tcpm_typec_disconnect(struct tcpm_port *port) port->plug_prime = NULL; port->cable = NULL; if (port->connected) { - typec_partner_set_usb_power_delivery(port->partner, NULL); - typec_unregister_partner(port->partner); - port->partner = NULL; + if (port->partner) { + typec_partner_set_usb_power_delivery(port->partner, NULL); + typec_unregister_partner(port->partner); + port->partner = NULL; + } port->connected = false; } } @@ -4549,6 +4569,9 @@ static enum typec_cc_status tcpm_pwr_opmode_to_rp(enum typec_pwr_opmode opmode) static void tcpm_set_initial_svdm_version(struct tcpm_port *port) { + if (!port->partner) + return; + switch (port->negotiated_rev) { case PD_REV30: break; @@ -5605,6 +5628,7 @@ static void run_state_machine(struct tcpm_port *port) break; case PORT_RESET: tcpm_reset_port(port); + port->pd_events = 0; if (port->self_powered) tcpm_set_cc(port, TYPEC_CC_OPEN); else @@ -6855,14 +6879,14 @@ static int tcpm_pd_set(struct typec_port *p, struct usb_power_delivery *pd) if (data->sink_desc.pdo[0]) { for (i = 0; i < PDO_MAX_OBJECTS && data->sink_desc.pdo[i]; i++) port->snk_pdo[i] = data->sink_desc.pdo[i]; - port->nr_snk_pdo = i + 1; + port->nr_snk_pdo = i; port->operating_snk_mw = data->operating_snk_mw; } if (data->source_desc.pdo[0]) { for (i = 0; i < PDO_MAX_OBJECTS && data->source_desc.pdo[i]; i++) port->src_pdo[i] = data->source_desc.pdo[i]; - port->nr_src_pdo = i + 1; + port->nr_src_pdo = i; } switch (port->state) { diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c index 0717cfcd9f8c..ad76dbd20e65 100644 --- a/drivers/usb/typec/tipd/core.c +++ b/drivers/usb/typec/tipd/core.c @@ -28,6 +28,7 @@ #define TPS_REG_MODE 0x03 #define TPS_REG_CMD1 0x08 #define TPS_REG_DATA1 0x09 +#define TPS_REG_VERSION 0x0F #define TPS_REG_INT_EVENT1 0x14 #define TPS_REG_INT_EVENT2 0x15 #define TPS_REG_INT_MASK1 0x16 @@ -604,11 +605,11 @@ static irqreturn_t tps25750_interrupt(int irq, void *data) if (!tps6598x_read_status(tps, &status)) goto err_clear_ints; - if ((event[0] | event[1]) & TPS_REG_INT_POWER_STATUS_UPDATE) + if (event[0] & TPS_REG_INT_POWER_STATUS_UPDATE) if (!tps6598x_read_power_status(tps)) goto err_clear_ints; - if ((event[0] | event[1]) & TPS_REG_INT_DATA_STATUS_UPDATE) + if (event[0] & TPS_REG_INT_DATA_STATUS_UPDATE) if (!tps6598x_read_data_status(tps)) goto err_clear_ints; @@ -617,7 +618,7 @@ static irqreturn_t tps25750_interrupt(int irq, void *data) * a plug event. Therefore, we need to check * for pr/dr status change to set TypeC dr/pr accordingly. */ - if ((event[0] | event[1]) & TPS_REG_INT_PLUG_EVENT || + if (event[0] & TPS_REG_INT_PLUG_EVENT || tps6598x_has_role_changed(tps, status)) tps6598x_handle_plug_event(tps, status); @@ -636,49 +637,67 @@ err_unlock: static irqreturn_t tps6598x_interrupt(int irq, void *data) { + int intev_len = TPS_65981_2_6_INTEVENT_LEN; struct tps6598x *tps = data; - u64 event1 = 0; - u64 event2 = 0; + u64 event1[2] = { }; + u64 event2[2] = { }; + u32 version; u32 status; int ret; mutex_lock(&tps->lock); - ret = tps6598x_read64(tps, TPS_REG_INT_EVENT1, &event1); - ret |= tps6598x_read64(tps, TPS_REG_INT_EVENT2, &event2); + ret = tps6598x_read32(tps, TPS_REG_VERSION, &version); + if (ret) + dev_warn(tps->dev, "%s: failed to read version (%d)\n", + __func__, ret); + + if (TPS_VERSION_HW_VERSION(version) == TPS_VERSION_HW_65987_8_DH || + TPS_VERSION_HW_VERSION(version) == TPS_VERSION_HW_65987_8_DK) + intev_len = TPS_65987_8_INTEVENT_LEN; + + ret = tps6598x_block_read(tps, TPS_REG_INT_EVENT1, event1, intev_len); + + ret = tps6598x_block_read(tps, TPS_REG_INT_EVENT1, event1, intev_len); if (ret) { - dev_err(tps->dev, "%s: failed to read events\n", __func__); + dev_err(tps->dev, "%s: failed to read event1\n", __func__); goto err_unlock; } - trace_tps6598x_irq(event1, event2); + ret = tps6598x_block_read(tps, TPS_REG_INT_EVENT2, event2, intev_len); + if (ret) { + dev_err(tps->dev, "%s: failed to read event2\n", __func__); + goto err_unlock; + } + trace_tps6598x_irq(event1[0], event2[0]); - if (!(event1 | event2)) + if (!(event1[0] | event1[1] | event2[0] | event2[1])) goto err_unlock; if (!tps6598x_read_status(tps, &status)) goto err_clear_ints; - if ((event1 | event2) & TPS_REG_INT_POWER_STATUS_UPDATE) + if ((event1[0] | event2[0]) & TPS_REG_INT_POWER_STATUS_UPDATE) if (!tps6598x_read_power_status(tps)) goto err_clear_ints; - if ((event1 | event2) & TPS_REG_INT_DATA_STATUS_UPDATE) + if ((event1[0] | event2[0]) & TPS_REG_INT_DATA_STATUS_UPDATE) if (!tps6598x_read_data_status(tps)) goto err_clear_ints; /* Handle plug insert or removal */ - if ((event1 | event2) & TPS_REG_INT_PLUG_EVENT) + if ((event1[0] | event2[0]) & TPS_REG_INT_PLUG_EVENT) tps6598x_handle_plug_event(tps, status); err_clear_ints: - tps6598x_write64(tps, TPS_REG_INT_CLEAR1, event1); - tps6598x_write64(tps, TPS_REG_INT_CLEAR2, event2); + tps6598x_block_write(tps, TPS_REG_INT_CLEAR1, event1, intev_len); + tps6598x_block_write(tps, TPS_REG_INT_CLEAR2, event2, intev_len); err_unlock: mutex_unlock(&tps->lock); - if (event1 | event2) + if (event1[0] | event1[1] | event2[0] | event2[1]) return IRQ_HANDLED; + return IRQ_NONE; } @@ -1346,10 +1365,7 @@ static int tps6598x_probe(struct i2c_client *client) TPS_REG_INT_PLUG_EVENT; } - if (dev_fwnode(tps->dev)) - tps->data = device_get_match_data(tps->dev); - else - tps->data = i2c_get_match_data(client); + tps->data = i2c_get_match_data(client); if (!tps->data) return -EINVAL; diff --git a/drivers/usb/typec/tipd/tps6598x.h b/drivers/usb/typec/tipd/tps6598x.h index 89b24519463a..9b23e9017452 100644 --- a/drivers/usb/typec/tipd/tps6598x.h +++ b/drivers/usb/typec/tipd/tps6598x.h @@ -253,4 +253,15 @@ #define TPS_PTCC_DEV 2 #define TPS_PTCC_APP 3 +/* Version Register */ +#define TPS_VERSION_HW_VERSION_MASK GENMASK(31, 24) +#define TPS_VERSION_HW_VERSION(x) TPS_FIELD_GET(TPS_VERSION_HW_VERSION_MASK, (x)) +#define TPS_VERSION_HW_65981_2_6 0x00 +#define TPS_VERSION_HW_65987_8_DH 0xF7 +#define TPS_VERSION_HW_65987_8_DK 0xF9 + +/* Int Event Register length */ +#define TPS_65981_2_6_INTEVENT_LEN 8 +#define TPS_65987_8_INTEVENT_LEN 11 + #endif /* __TPS6598X_H__ */ diff --git a/drivers/usb/typec/ucsi/displayport.c b/drivers/usb/typec/ucsi/displayport.c index d9d3c91125ca..8be92fc1d12c 100644 --- a/drivers/usb/typec/ucsi/displayport.c +++ b/drivers/usb/typec/ucsi/displayport.c @@ -275,8 +275,6 @@ static void ucsi_displayport_work(struct work_struct *work) struct ucsi_dp *dp = container_of(work, struct ucsi_dp, work); int ret; - mutex_lock(&dp->con->lock); - ret = typec_altmode_vdm(dp->alt, dp->header, dp->vdo_data, dp->vdo_size); if (ret) @@ -285,8 +283,6 @@ static void ucsi_displayport_work(struct work_struct *work) dp->vdo_data = NULL; dp->vdo_size = 0; dp->header = 0; - - mutex_unlock(&dp->con->lock); } void ucsi_displayport_remove_partner(struct typec_altmode *alt) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 31d8a46ae5e7..cb52e7b0a2c5 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -49,22 +49,16 @@ static int ucsi_read_message_in(struct ucsi *ucsi, void *buf, return ucsi->ops->read(ucsi, UCSI_MESSAGE_IN, buf, buf_size); } -static int ucsi_acknowledge_command(struct ucsi *ucsi) +static int ucsi_acknowledge(struct ucsi *ucsi, bool conn_ack) { u64 ctrl; ctrl = UCSI_ACK_CC_CI; ctrl |= UCSI_ACK_COMMAND_COMPLETE; - - return ucsi->ops->sync_write(ucsi, UCSI_CONTROL, &ctrl, sizeof(ctrl)); -} - -static int ucsi_acknowledge_connector_change(struct ucsi *ucsi) -{ - u64 ctrl; - - ctrl = UCSI_ACK_CC_CI; - ctrl |= UCSI_ACK_CONNECTOR_CHANGE; + if (conn_ack) { + clear_bit(EVENT_PENDING, &ucsi->flags); + ctrl |= UCSI_ACK_CONNECTOR_CHANGE; + } return ucsi->ops->sync_write(ucsi, UCSI_CONTROL, &ctrl, sizeof(ctrl)); } @@ -77,7 +71,7 @@ static int ucsi_read_error(struct ucsi *ucsi) int ret; /* Acknowledge the command that failed */ - ret = ucsi_acknowledge_command(ucsi); + ret = ucsi_acknowledge(ucsi, false); if (ret) return ret; @@ -89,7 +83,7 @@ static int ucsi_read_error(struct ucsi *ucsi) if (ret) return ret; - ret = ucsi_acknowledge_command(ucsi); + ret = ucsi_acknowledge(ucsi, false); if (ret) return ret; @@ -152,7 +146,7 @@ static int ucsi_exec_command(struct ucsi *ucsi, u64 cmd) return -EIO; if (cci & UCSI_CCI_NOT_SUPPORTED) { - if (ucsi_acknowledge_command(ucsi) < 0) + if (ucsi_acknowledge(ucsi, false) < 0) dev_err(ucsi->dev, "ACK of unsupported command failed\n"); return -EOPNOTSUPP; @@ -165,15 +159,15 @@ static int ucsi_exec_command(struct ucsi *ucsi, u64 cmd) } if (cmd == UCSI_CANCEL && cci & UCSI_CCI_CANCEL_COMPLETE) { - ret = ucsi_acknowledge_command(ucsi); + ret = ucsi_acknowledge(ucsi, false); return ret ? ret : -EBUSY; } return UCSI_CCI_LENGTH(cci); } -int ucsi_send_command(struct ucsi *ucsi, u64 command, - void *data, size_t size) +static int ucsi_send_command_common(struct ucsi *ucsi, u64 command, + void *data, size_t size, bool conn_ack) { u8 length; int ret; @@ -192,7 +186,7 @@ int ucsi_send_command(struct ucsi *ucsi, u64 command, goto out; } - ret = ucsi_acknowledge_command(ucsi); + ret = ucsi_acknowledge(ucsi, conn_ack); if (ret) goto out; @@ -201,6 +195,12 @@ out: mutex_unlock(&ucsi->ppm_lock); return ret; } + +int ucsi_send_command(struct ucsi *ucsi, u64 command, + void *data, size_t size) +{ + return ucsi_send_command_common(ucsi, command, data, size, false); +} EXPORT_SYMBOL_GPL(ucsi_send_command); /* -------------------------------------------------------------------------- */ @@ -619,7 +619,10 @@ static int ucsi_read_pdos(struct ucsi_connector *con, u64 command; int ret; - if (ucsi->quirks & UCSI_NO_PARTNER_PDOS) + if (is_partner && + ucsi->quirks & UCSI_NO_PARTNER_PDOS && + ((con->status.flags & UCSI_CONSTAT_PWR_DIR) || + !is_source(role))) return 0; command = UCSI_COMMAND(UCSI_GET_PDOS) | UCSI_CONNECTOR_NUMBER(con->num); @@ -674,6 +677,26 @@ static int ucsi_get_src_pdos(struct ucsi_connector *con) return ret; } +static struct usb_power_delivery_capabilities *ucsi_get_pd_caps(struct ucsi_connector *con, + enum typec_role role, + bool is_partner) +{ + struct usb_power_delivery_capabilities_desc pd_caps; + int ret; + + ret = ucsi_get_pdos(con, role, is_partner, pd_caps.pdo); + if (ret <= 0) + return ERR_PTR(ret); + + if (ret < PDO_MAX_OBJECTS) + pd_caps.pdo[ret] = 0; + + pd_caps.role = role; + + return usb_power_delivery_register_capabilities(is_partner ? con->partner_pd : con->pd, + &pd_caps); +} + static int ucsi_read_identity(struct ucsi_connector *con, u8 recipient, u8 offset, u8 bytes, void *resp) { @@ -798,60 +821,53 @@ static int ucsi_check_altmodes(struct ucsi_connector *con) return ret; } +static void ucsi_register_device_pdos(struct ucsi_connector *con) +{ + struct ucsi *ucsi = con->ucsi; + struct usb_power_delivery_desc desc = { ucsi->cap.pd_version }; + struct usb_power_delivery_capabilities *pd_cap; + + if (con->pd) + return; + + con->pd = usb_power_delivery_register(ucsi->dev, &desc); + + pd_cap = ucsi_get_pd_caps(con, TYPEC_SOURCE, false); + if (!IS_ERR(pd_cap)) + con->port_source_caps = pd_cap; + + pd_cap = ucsi_get_pd_caps(con, TYPEC_SINK, false); + if (!IS_ERR(pd_cap)) + con->port_sink_caps = pd_cap; + + typec_port_set_usb_power_delivery(con->port, con->pd); +} + static int ucsi_register_partner_pdos(struct ucsi_connector *con) { struct usb_power_delivery_desc desc = { con->ucsi->cap.pd_version }; - struct usb_power_delivery_capabilities_desc caps; struct usb_power_delivery_capabilities *cap; - int ret; if (con->partner_pd) return 0; - con->partner_pd = usb_power_delivery_register(NULL, &desc); + con->partner_pd = typec_partner_usb_power_delivery_register(con->partner, &desc); if (IS_ERR(con->partner_pd)) return PTR_ERR(con->partner_pd); - ret = ucsi_get_pdos(con, TYPEC_SOURCE, 1, caps.pdo); - if (ret > 0) { - if (ret < PDO_MAX_OBJECTS) - caps.pdo[ret] = 0; - - caps.role = TYPEC_SOURCE; - cap = usb_power_delivery_register_capabilities(con->partner_pd, &caps); - if (IS_ERR(cap)) - return PTR_ERR(cap); - - con->partner_source_caps = cap; - - ret = typec_partner_set_usb_power_delivery(con->partner, con->partner_pd); - if (ret) { - usb_power_delivery_unregister_capabilities(con->partner_source_caps); - return ret; - } - } - - ret = ucsi_get_pdos(con, TYPEC_SINK, 1, caps.pdo); - if (ret > 0) { - if (ret < PDO_MAX_OBJECTS) - caps.pdo[ret] = 0; + cap = ucsi_get_pd_caps(con, TYPEC_SOURCE, true); + if (IS_ERR(cap)) + return PTR_ERR(cap); - caps.role = TYPEC_SINK; + con->partner_source_caps = cap; - cap = usb_power_delivery_register_capabilities(con->partner_pd, &caps); - if (IS_ERR(cap)) - return PTR_ERR(cap); + cap = ucsi_get_pd_caps(con, TYPEC_SINK, true); + if (IS_ERR(cap)) + return PTR_ERR(cap); - con->partner_sink_caps = cap; + con->partner_sink_caps = cap; - ret = typec_partner_set_usb_power_delivery(con->partner, con->partner_pd); - if (ret) { - usb_power_delivery_unregister_capabilities(con->partner_sink_caps); - return ret; - } - } - - return 0; + return typec_partner_set_usb_power_delivery(con->partner, con->partner_pd); } static void ucsi_unregister_partner_pdos(struct ucsi_connector *con) @@ -987,6 +1003,9 @@ static int ucsi_register_partner(struct ucsi_connector *con) break; } + if (pwr_opmode == UCSI_CONSTAT_PWR_OPMODE_PD) + ucsi_register_device_pdos(con); + desc.identity = &con->partner_identity; desc.usb_pd = pwr_opmode == UCSI_CONSTAT_PWR_OPMODE_PD; desc.pd_revision = UCSI_CONCAP_FLAG_PARTNER_PD_MAJOR_REV_AS_BCD(con->cap.flags); @@ -1168,7 +1187,9 @@ static void ucsi_handle_connector_change(struct work_struct *work) mutex_lock(&con->lock); command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num); - ret = ucsi_send_command(ucsi, command, &con->status, sizeof(con->status)); + + ret = ucsi_send_command_common(ucsi, command, &con->status, + sizeof(con->status), true); if (ret < 0) { dev_err(ucsi->dev, "%s: GET_CONNECTOR_STATUS failed (%d)\n", __func__, ret); @@ -1178,6 +1199,9 @@ static void ucsi_handle_connector_change(struct work_struct *work) trace_ucsi_connector_change(con->num, &con->status); + if (ucsi->ops->connector_status) + ucsi->ops->connector_status(con); + role = !!(con->status.flags & UCSI_CONSTAT_PWR_DIR); if (con->status.change & UCSI_CONSTAT_POWER_DIR_CHANGE) { @@ -1225,14 +1249,6 @@ static void ucsi_handle_connector_change(struct work_struct *work) if (con->status.change & UCSI_CONSTAT_CAM_CHANGE) ucsi_partner_task(con, ucsi_check_altmodes, 1, 0); - mutex_lock(&ucsi->ppm_lock); - clear_bit(EVENT_PENDING, &con->ucsi->flags); - ret = ucsi_acknowledge_connector_change(ucsi); - mutex_unlock(&ucsi->ppm_lock); - - if (ret) - dev_err(ucsi->dev, "%s: ACK failed (%d)", __func__, ret); - out_unlock: mutex_unlock(&con->lock); } @@ -1324,6 +1340,9 @@ static int ucsi_reset_ppm(struct ucsi *ucsi) goto out; } + /* Give the PPM time to process a reset before reading CCI */ + msleep(20); + ret = ucsi->ops->read(ucsi, UCSI_CCI, &cci, sizeof(cci)); if (ret) goto out; @@ -1337,7 +1356,6 @@ static int ucsi_reset_ppm(struct ucsi *ucsi) goto out; } - msleep(20); } while (!(cci & UCSI_CCI_RESET_COMPLETE)); out: @@ -1477,9 +1495,6 @@ static struct fwnode_handle *ucsi_find_fwnode(struct ucsi_connector *con) static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) { - struct usb_power_delivery_desc desc = { ucsi->cap.pd_version}; - struct usb_power_delivery_capabilities_desc pd_caps; - struct usb_power_delivery_capabilities *pd_cap; struct typec_capability *cap = &con->typec_cap; enum typec_accessory *accessory = cap->accessory; enum usb_role u_role = USB_ROLE_NONE; @@ -1546,6 +1561,9 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) cap->driver_data = con; cap->ops = &ucsi_ops; + if (ucsi->ops->update_connector) + ucsi->ops->update_connector(con); + ret = ucsi_register_port_psy(con); if (ret) goto out; @@ -1557,40 +1575,8 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) goto out; } - con->pd = usb_power_delivery_register(ucsi->dev, &desc); - - ret = ucsi_get_pdos(con, TYPEC_SOURCE, 0, pd_caps.pdo); - if (ret > 0) { - if (ret < PDO_MAX_OBJECTS) - pd_caps.pdo[ret] = 0; - - pd_caps.role = TYPEC_SOURCE; - pd_cap = usb_power_delivery_register_capabilities(con->pd, &pd_caps); - if (IS_ERR(pd_cap)) { - ret = PTR_ERR(pd_cap); - goto out; - } - - con->port_source_caps = pd_cap; - typec_port_set_usb_power_delivery(con->port, con->pd); - } - - memset(&pd_caps, 0, sizeof(pd_caps)); - ret = ucsi_get_pdos(con, TYPEC_SINK, 0, pd_caps.pdo); - if (ret > 0) { - if (ret < PDO_MAX_OBJECTS) - pd_caps.pdo[ret] = 0; - - pd_caps.role = TYPEC_SINK; - pd_cap = usb_power_delivery_register_capabilities(con->pd, &pd_caps); - if (IS_ERR(pd_cap)) { - ret = PTR_ERR(pd_cap); - goto out; - } - - con->port_sink_caps = pd_cap; - typec_port_set_usb_power_delivery(con->port, con->pd); - } + if (!(ucsi->quirks & UCSI_DELAY_DEVICE_PDOS)) + ucsi_register_device_pdos(con); /* Alternate modes */ ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_CON); @@ -1610,6 +1596,9 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) } ret = 0; /* ucsi_send_command() returns length on success */ + if (ucsi->ops->connector_status) + ucsi->ops->connector_status(con); + switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) { case UCSI_CONSTAT_PARTNER_TYPE_UFP: case UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP: @@ -1653,6 +1642,7 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) if (con->partner && UCSI_CONSTAT_PWR_OPMODE(con->status.flags) == UCSI_CONSTAT_PWR_OPMODE_PD) { + ucsi_register_device_pdos(con); ucsi_get_src_pdos(con); ucsi_check_altmodes(con); } @@ -1672,6 +1662,27 @@ out_unlock: return ret; } +static u64 ucsi_get_supported_notifications(struct ucsi *ucsi) +{ + u8 features = ucsi->cap.features; + u64 ntfy = UCSI_ENABLE_NTFY_ALL; + + if (!(features & UCSI_CAP_ALT_MODE_DETAILS)) + ntfy &= ~UCSI_ENABLE_NTFY_CAM_CHANGE; + + if (!(features & UCSI_CAP_PDO_DETAILS)) + ntfy &= ~(UCSI_ENABLE_NTFY_PWR_LEVEL_CHANGE | + UCSI_ENABLE_NTFY_CAP_CHANGE); + + if (!(features & UCSI_CAP_EXT_SUPPLY_NOTIFICATIONS)) + ntfy &= ~UCSI_ENABLE_NTFY_EXT_PWR_SRC_CHANGE; + + if (!(features & UCSI_CAP_PD_RESET)) + ntfy &= ~UCSI_ENABLE_NTFY_PD_RESET_COMPLETE; + + return ntfy; +} + /** * ucsi_init - Initialize UCSI interface * @ucsi: UCSI to be initialized @@ -1726,8 +1737,8 @@ static int ucsi_init(struct ucsi *ucsi) goto err_unregister; } - /* Enable all notifications */ - ntfy = UCSI_ENABLE_NTFY_ALL; + /* Enable all supported notifications */ + ntfy = ucsi_get_supported_notifications(ucsi); command = UCSI_SET_NOTIFICATION_ENABLE | ntfy; ret = ucsi_send_command(ucsi, command, NULL, 0); if (ret < 0) @@ -1736,11 +1747,13 @@ static int ucsi_init(struct ucsi *ucsi) ucsi->connector = connector; ucsi->ntfy = ntfy; + mutex_lock(&ucsi->ppm_lock); ret = ucsi->ops->read(ucsi, UCSI_CCI, &cci, sizeof(cci)); + mutex_unlock(&ucsi->ppm_lock); if (ret) return ret; - if (UCSI_CCI_CONNECTOR(READ_ONCE(cci))) - ucsi_connector_change(ucsi, cci); + if (UCSI_CCI_CONNECTOR(cci)) + ucsi_connector_change(ucsi, UCSI_CCI_CONNECTOR(cci)); return 0; diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index 0e7c92eb1b22..c4d103db9d0f 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -16,6 +16,7 @@ struct ucsi; struct ucsi_altmode; +struct ucsi_connector; struct dentry; /* UCSI offsets (Bytes) */ @@ -59,6 +60,8 @@ struct dentry; * @sync_write: Blocking write operation * @async_write: Non-blocking write operation * @update_altmodes: Squashes duplicate DP altmodes + * @update_connector: Update connector capabilities before registering + * @connector_status: Updates connector status, called holding connector lock * * Read and write routines for UCSI interface. @sync_write must wait for the * Command Completion Event from the PPM before returning, and @async_write must @@ -73,6 +76,8 @@ struct ucsi_operations { const void *val, size_t val_len); bool (*update_altmodes)(struct ucsi *ucsi, struct ucsi_altmode *orig, struct ucsi_altmode *updated); + void (*update_connector)(struct ucsi_connector *con); + void (*connector_status)(struct ucsi_connector *con); }; struct ucsi *ucsi_create(struct device *dev, const struct ucsi_operations *ops); @@ -403,11 +408,10 @@ struct ucsi { /* PPM communication flags */ unsigned long flags; #define EVENT_PENDING 0 -#define COMMAND_PENDING 1 -#define ACK_PENDING 2 unsigned long quirks; #define UCSI_NO_PARTNER_PDOS BIT(0) /* Don't read partner's PDOs */ +#define UCSI_DELAY_DEVICE_PDOS BIT(1) /* Reading PDOs fails until the parter is in PD mode */ }; #define UCSI_MAX_SVID 5 diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c index 7b3ac133ef86..8d112c3edae5 100644 --- a/drivers/usb/typec/ucsi/ucsi_acpi.c +++ b/drivers/usb/typec/ucsi/ucsi_acpi.c @@ -23,7 +23,6 @@ struct ucsi_acpi { void *base; struct completion complete; unsigned long flags; -#define UCSI_ACPI_SUPPRESS_EVENT 0 #define UCSI_ACPI_COMMAND_PENDING 1 #define UCSI_ACPI_ACK_PENDING 2 guid_t guid; @@ -129,49 +128,6 @@ static const struct ucsi_operations ucsi_zenbook_ops = { .async_write = ucsi_acpi_async_write }; -/* - * Some Dell laptops don't like ACK commands with the - * UCSI_ACK_CONNECTOR_CHANGE but not the UCSI_ACK_COMMAND_COMPLETE - * bit set. To work around this send a dummy command and bundle the - * UCSI_ACK_CONNECTOR_CHANGE with the UCSI_ACK_COMMAND_COMPLETE - * for the dummy command. - */ -static int -ucsi_dell_sync_write(struct ucsi *ucsi, unsigned int offset, - const void *val, size_t val_len) -{ - struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); - u64 cmd = *(u64 *)val; - u64 dummycmd = UCSI_GET_CAPABILITY; - int ret; - - if (cmd == (UCSI_ACK_CC_CI | UCSI_ACK_CONNECTOR_CHANGE)) { - cmd |= UCSI_ACK_COMMAND_COMPLETE; - - /* - * The UCSI core thinks it is sending a connector change ack - * and will accept new connector change events. We don't want - * this to happen for the dummy command as its response will - * still report the very event that the core is trying to clear. - */ - set_bit(UCSI_ACPI_SUPPRESS_EVENT, &ua->flags); - ret = ucsi_acpi_sync_write(ucsi, UCSI_CONTROL, &dummycmd, - sizeof(dummycmd)); - clear_bit(UCSI_ACPI_SUPPRESS_EVENT, &ua->flags); - - if (ret < 0) - return ret; - } - - return ucsi_acpi_sync_write(ucsi, UCSI_CONTROL, &cmd, sizeof(cmd)); -} - -static const struct ucsi_operations ucsi_dell_ops = { - .read = ucsi_acpi_read, - .sync_write = ucsi_dell_sync_write, - .async_write = ucsi_acpi_async_write -}; - static const struct dmi_system_id ucsi_acpi_quirks[] = { { .matches = { @@ -180,12 +136,6 @@ static const struct dmi_system_id ucsi_acpi_quirks[] = { }, .driver_data = (void *)&ucsi_zenbook_ops, }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - }, - .driver_data = (void *)&ucsi_dell_ops, - }, { } }; @@ -199,11 +149,11 @@ static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data) if (ret) return; - if (UCSI_CCI_CONNECTOR(cci) && - !test_bit(UCSI_ACPI_SUPPRESS_EVENT, &ua->flags)) + if (UCSI_CCI_CONNECTOR(cci)) ucsi_connector_change(ua->ucsi, UCSI_CCI_CONNECTOR(cci)); - if (cci & UCSI_CCI_ACK_COMPLETE && test_bit(ACK_PENDING, &ua->flags)) + if (cci & UCSI_CCI_ACK_COMPLETE && + test_bit(UCSI_ACPI_ACK_PENDING, &ua->flags)) complete(&ua->complete); if (cci & UCSI_CCI_COMMAND_COMPLETE && test_bit(UCSI_ACPI_COMMAND_PENDING, &ua->flags)) diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c index ce08eb33e5be..f7546bb488c3 100644 --- a/drivers/usb/typec/ucsi/ucsi_glink.c +++ b/drivers/usb/typec/ucsi/ucsi_glink.c @@ -58,7 +58,6 @@ struct pmic_glink_ucsi { struct device *dev; struct gpio_desc *port_orientation[PMIC_GLINK_MAX_PORTS]; - struct typec_switch *port_switch[PMIC_GLINK_MAX_PORTS]; struct pmic_glink_client *client; @@ -176,7 +175,8 @@ static int pmic_glink_ucsi_sync_write(struct ucsi *__ucsi, unsigned int offset, left = wait_for_completion_timeout(&ucsi->sync_ack, 5 * HZ); if (!left) { dev_err(ucsi->dev, "timeout waiting for UCSI sync write response\n"); - ret = -ETIMEDOUT; + /* return 0 here and let core UCSI code handle the CCI_BUSY */ + ret = 0; } else if (ucsi->sync_val) { dev_err(ucsi->dev, "sync write returned: %d\n", ucsi->sync_val); } @@ -186,10 +186,41 @@ static int pmic_glink_ucsi_sync_write(struct ucsi *__ucsi, unsigned int offset, return ret; } +static void pmic_glink_ucsi_update_connector(struct ucsi_connector *con) +{ + struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(con->ucsi); + int i; + + for (i = 0; i < PMIC_GLINK_MAX_PORTS; i++) { + if (ucsi->port_orientation[i]) + con->typec_cap.orientation_aware = true; + } +} + +static void pmic_glink_ucsi_connector_status(struct ucsi_connector *con) +{ + struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(con->ucsi); + int orientation; + + if (con->num >= PMIC_GLINK_MAX_PORTS || + !ucsi->port_orientation[con->num - 1]) + return; + + orientation = gpiod_get_value(ucsi->port_orientation[con->num - 1]); + if (orientation >= 0) { + typec_set_orientation(con->port, + orientation ? + TYPEC_ORIENTATION_REVERSE : + TYPEC_ORIENTATION_NORMAL); + } +} + static const struct ucsi_operations pmic_glink_ucsi_ops = { .read = pmic_glink_ucsi_read, .sync_write = pmic_glink_ucsi_sync_write, - .async_write = pmic_glink_ucsi_async_write + .async_write = pmic_glink_ucsi_async_write, + .update_connector = pmic_glink_ucsi_update_connector, + .connector_status = pmic_glink_ucsi_connector_status, }; static void pmic_glink_ucsi_read_ack(struct pmic_glink_ucsi *ucsi, const void *data, int len) @@ -228,25 +259,10 @@ static void pmic_glink_ucsi_notify(struct work_struct *work) } con_num = UCSI_CCI_CONNECTOR(cci); - if (con_num) { - if (con_num <= PMIC_GLINK_MAX_PORTS && - ucsi->port_orientation[con_num - 1]) { - int orientation = gpiod_get_value(ucsi->port_orientation[con_num - 1]); - - if (orientation >= 0) { - typec_switch_set(ucsi->port_switch[con_num - 1], - orientation ? TYPEC_ORIENTATION_REVERSE - : TYPEC_ORIENTATION_NORMAL); - } - } - + if (con_num) ucsi_connector_change(ucsi->ucsi, con_num); - } - if (ucsi->sync_pending && cci & UCSI_CCI_BUSY) { - ucsi->sync_val = -EBUSY; - complete(&ucsi->sync_ack); - } else if (ucsi->sync_pending && + if (ucsi->sync_pending && (cci & (UCSI_CCI_ACK_COMPLETE | UCSI_CCI_COMMAND_COMPLETE))) { complete(&ucsi->sync_ack); } @@ -255,20 +271,6 @@ static void pmic_glink_ucsi_notify(struct work_struct *work) static void pmic_glink_ucsi_register(struct work_struct *work) { struct pmic_glink_ucsi *ucsi = container_of(work, struct pmic_glink_ucsi, register_work); - int orientation; - int i; - - for (i = 0; i < PMIC_GLINK_MAX_PORTS; i++) { - if (!ucsi->port_orientation[i]) - continue; - orientation = gpiod_get_value(ucsi->port_orientation[i]); - - if (orientation >= 0) { - typec_switch_set(ucsi->port_switch[i], - orientation ? TYPEC_ORIENTATION_REVERSE - : TYPEC_ORIENTATION_NORMAL); - } - } ucsi_register(ucsi->ucsi); } @@ -311,12 +313,17 @@ static void pmic_glink_ucsi_destroy(void *data) mutex_unlock(&ucsi->lock); } +static unsigned long quirk_sc8180x = UCSI_NO_PARTNER_PDOS; +static unsigned long quirk_sc8280xp = UCSI_NO_PARTNER_PDOS | UCSI_DELAY_DEVICE_PDOS; +static unsigned long quirk_sm8450 = UCSI_DELAY_DEVICE_PDOS; + static const struct of_device_id pmic_glink_ucsi_of_quirks[] = { - { .compatible = "qcom,qcm6490-pmic-glink", .data = (void *)UCSI_NO_PARTNER_PDOS, }, - { .compatible = "qcom,sc8180x-pmic-glink", .data = (void *)UCSI_NO_PARTNER_PDOS, }, - { .compatible = "qcom,sc8280xp-pmic-glink", .data = (void *)UCSI_NO_PARTNER_PDOS, }, - { .compatible = "qcom,sm8350-pmic-glink", .data = (void *)UCSI_NO_PARTNER_PDOS, }, - { .compatible = "qcom,sm8550-pmic-glink", .data = (void *)UCSI_NO_PARTNER_PDOS, }, + { .compatible = "qcom,qcm6490-pmic-glink", .data = &quirk_sc8280xp, }, + { .compatible = "qcom,sc8180x-pmic-glink", .data = &quirk_sc8180x, }, + { .compatible = "qcom,sc8280xp-pmic-glink", .data = &quirk_sc8280xp, }, + { .compatible = "qcom,sm8350-pmic-glink", .data = &quirk_sc8180x, }, + { .compatible = "qcom,sm8450-pmic-glink", .data = &quirk_sm8450, }, + { .compatible = "qcom,sm8550-pmic-glink", .data = &quirk_sm8450, }, {} }; @@ -354,7 +361,7 @@ static int pmic_glink_ucsi_probe(struct auxiliary_device *adev, match = of_match_device(pmic_glink_ucsi_of_quirks, dev->parent); if (match) - ucsi->ucsi->quirks = (unsigned long)match->data; + ucsi->ucsi->quirks = *(unsigned long *)match->data; ucsi_set_drvdata(ucsi->ucsi, ucsi); @@ -383,11 +390,6 @@ static int pmic_glink_ucsi_probe(struct auxiliary_device *adev, return dev_err_probe(dev, PTR_ERR(desc), "unable to acquire orientation gpio\n"); ucsi->port_orientation[port] = desc; - - ucsi->port_switch[port] = fwnode_typec_switch_get(fwnode); - if (IS_ERR(ucsi->port_switch[port])) - return dev_err_probe(dev, PTR_ERR(ucsi->port_switch[port]), - "failed to acquire orientation-switch\n"); } ucsi->client = devm_pmic_glink_register_client(dev, diff --git a/drivers/usb/typec/ucsi/ucsi_stm32g0.c b/drivers/usb/typec/ucsi/ucsi_stm32g0.c index 93d7806681cf..ac48b7763114 100644 --- a/drivers/usb/typec/ucsi/ucsi_stm32g0.c +++ b/drivers/usb/typec/ucsi/ucsi_stm32g0.c @@ -64,6 +64,7 @@ struct ucsi_stm32g0 { struct completion complete; struct device *dev; unsigned long flags; +#define COMMAND_PENDING 1 const char *fw_name; struct ucsi *ucsi; bool suspended; |