summaryrefslogtreecommitdiff
path: root/drivers/usb/typec
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/typec')
-rw-r--r--drivers/usb/typec/altmodes/displayport.c1
-rw-r--r--drivers/usb/typec/altmodes/nvidia.c1
-rw-r--r--drivers/usb/typec/mux/Kconfig2
-rw-r--r--drivers/usb/typec/mux/gpio-sbu-mux.c8
-rw-r--r--drivers/usb/typec/mux/it5205.c2
-rw-r--r--drivers/usb/typec/mux/ptn36502.c44
-rw-r--r--drivers/usb/typec/stusb160x.c2
-rw-r--r--drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c18
-rw-r--r--drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c11
-rw-r--r--drivers/usb/typec/tcpm/tcpm.c46
-rw-r--r--drivers/usb/typec/tipd/core.c56
-rw-r--r--drivers/usb/typec/tipd/tps6598x.h11
-rw-r--r--drivers/usb/typec/ucsi/displayport.c4
-rw-r--r--drivers/usb/typec/ucsi/ucsi.c231
-rw-r--r--drivers/usb/typec/ucsi/ucsi.h8
-rw-r--r--drivers/usb/typec/ucsi/ucsi_acpi.c56
-rw-r--r--drivers/usb/typec/ucsi/ucsi_glink.c92
-rw-r--r--drivers/usb/typec/ucsi/ucsi_stm32g0.c1
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;