summaryrefslogtreecommitdiff
path: root/drivers/usb/typec
diff options
context:
space:
mode:
authorDmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>2025-06-21 21:12:58 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2025-06-24 15:40:50 +0100
commite0c48e42d818aba4ffadf4735352844fd7e0ec9e (patch)
tree7496b648750766450018a272a0e51edc587fbec1 /drivers/usb/typec
parenta669133d971fddbdf4b3bf1be9e0069f650717e7 (diff)
usb: typec: ucsi: yoga-c630: remove duplicate AltModes
On Lenovo Yoga C630 the EC firmware is buggy and it returns duplicate AltModes over and over again instead of returning an empty one, as demanded by the spec. Ignore extra altmodes by zeroing them in the update_altmodes() callback. It is not possible to shortcut that in the sync_control() callback since we need to know if the AltMode matches the first reported AltMode or not. Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Link: https://lore.kernel.org/r/20250621-c630-ucsi-v1-3-a86de5e11361@oss.qualcomm.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/typec')
-rw-r--r--drivers/usb/typec/ucsi/ucsi_yoga_c630.c23
1 files changed, 23 insertions, 0 deletions
diff --git a/drivers/usb/typec/ucsi/ucsi_yoga_c630.c b/drivers/usb/typec/ucsi/ucsi_yoga_c630.c
index 47e8dd5b255b..7cc1342d6e2f 100644
--- a/drivers/usb/typec/ucsi/ucsi_yoga_c630.c
+++ b/drivers/usb/typec/ucsi/ucsi_yoga_c630.c
@@ -71,6 +71,28 @@ static int yoga_c630_ucsi_async_control(struct ucsi *ucsi, u64 command)
return yoga_c630_ec_ucsi_write(uec->ec, (u8*)&command);
}
+static bool yoga_c630_ucsi_update_altmodes(struct ucsi *ucsi,
+ u8 recipient,
+ struct ucsi_altmode *orig,
+ struct ucsi_altmode *updated)
+{
+ int i;
+
+ if (orig[0].svid == 0 || recipient != UCSI_RECIPIENT_SOP)
+ return false;
+
+ /* EC is nice and repeats altmodes again and again. Ignore copies. */
+ for (i = 1; i < UCSI_MAX_ALTMODES; i++) {
+ if (orig[i].svid == orig[0].svid) {
+ dev_dbg(ucsi->dev, "Found duplicate altmodes, starting from %d\n", i);
+ memset(&orig[i], 0, (UCSI_MAX_ALTMODES - i) * sizeof(*orig));
+ break;
+ }
+ }
+
+ return false;
+}
+
static const struct ucsi_operations yoga_c630_ucsi_ops = {
.read_version = yoga_c630_ucsi_read_version,
.read_cci = yoga_c630_ucsi_read_cci,
@@ -78,6 +100,7 @@ static const struct ucsi_operations yoga_c630_ucsi_ops = {
.read_message_in = yoga_c630_ucsi_read_message_in,
.sync_control = ucsi_sync_control_common,
.async_control = yoga_c630_ucsi_async_control,
+ .update_altmodes = yoga_c630_ucsi_update_altmodes,
};
static int yoga_c630_ucsi_notify(struct notifier_block *nb,