Skip to content

Commit 9e3caa9

Browse files
diogoivogregkh
authored andcommitted
usb: typec: ucsi_acpi: Add LG Gram quirk
Some LG Gram laptops report a bogus connector change event after a GET_PDOS command for the partner's source PDOs, which disappears from the CCI after acknowledging the command. However, the subsequent GET_CONNECTOR_STATUS in ucsi_handle_connector_change() still reports this bogus change in bits 5 and 6, leading to the UCSI core re-checking the partner's source PDOs and thus to an infinite loop. Fix this by adding a quirk that signals when a potentially buggy GET_PDOS command is used, checks the status change report and clears it if it is a bogus event before sending it to the UCSI core. Signed-off-by: Diogo Ivo <[email protected]> Reviewed-by: Heikki Krogerus <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 8e1ec11 commit 9e3caa9

File tree

1 file changed

+61
-0
lines changed

1 file changed

+61
-0
lines changed

drivers/usb/typec/ucsi/ucsi_acpi.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ struct ucsi_acpi {
2525
unsigned long flags;
2626
#define UCSI_ACPI_COMMAND_PENDING 1
2727
#define UCSI_ACPI_ACK_PENDING 2
28+
#define UCSI_ACPI_CHECK_BOGUS_EVENT 3
2829
guid_t guid;
2930
u64 cmd;
3031
};
@@ -128,6 +129,58 @@ static const struct ucsi_operations ucsi_zenbook_ops = {
128129
.async_write = ucsi_acpi_async_write
129130
};
130131

132+
static int ucsi_gram_read(struct ucsi *ucsi, unsigned int offset,
133+
void *val, size_t val_len)
134+
{
135+
u16 bogus_change = UCSI_CONSTAT_POWER_LEVEL_CHANGE |
136+
UCSI_CONSTAT_PDOS_CHANGE;
137+
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
138+
struct ucsi_connector_status *status;
139+
int ret;
140+
141+
ret = ucsi_acpi_read(ucsi, offset, val, val_len);
142+
if (ret < 0)
143+
return ret;
144+
145+
if (UCSI_COMMAND(ua->cmd) == UCSI_GET_CONNECTOR_STATUS &&
146+
test_bit(UCSI_ACPI_CHECK_BOGUS_EVENT, &ua->flags) &&
147+
offset == UCSI_MESSAGE_IN) {
148+
status = (struct ucsi_connector_status *)val;
149+
150+
/* Clear the bogus change */
151+
if (status->change == bogus_change)
152+
status->change = 0;
153+
154+
clear_bit(UCSI_ACPI_CHECK_BOGUS_EVENT, &ua->flags);
155+
}
156+
157+
return ret;
158+
}
159+
160+
static int ucsi_gram_sync_write(struct ucsi *ucsi, unsigned int offset,
161+
const void *val, size_t val_len)
162+
{
163+
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
164+
int ret;
165+
166+
ret = ucsi_acpi_sync_write(ucsi, offset, val, val_len);
167+
if (ret < 0)
168+
return ret;
169+
170+
if (UCSI_COMMAND(ua->cmd) == UCSI_GET_PDOS &&
171+
ua->cmd & UCSI_GET_PDOS_PARTNER_PDO(1) &&
172+
ua->cmd & UCSI_GET_PDOS_SRC_PDOS)
173+
set_bit(UCSI_ACPI_CHECK_BOGUS_EVENT, &ua->flags);
174+
175+
return ret;
176+
}
177+
178+
static const struct ucsi_operations ucsi_gram_ops = {
179+
.read = ucsi_gram_read,
180+
.sync_write = ucsi_gram_sync_write,
181+
.async_write = ucsi_acpi_async_write
182+
};
183+
131184
static const struct dmi_system_id ucsi_acpi_quirks[] = {
132185
{
133186
.matches = {
@@ -136,6 +189,14 @@ static const struct dmi_system_id ucsi_acpi_quirks[] = {
136189
},
137190
.driver_data = (void *)&ucsi_zenbook_ops,
138191
},
192+
{
193+
.matches = {
194+
DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"),
195+
DMI_MATCH(DMI_PRODUCT_FAMILY, "LG gram PC"),
196+
DMI_MATCH(DMI_PRODUCT_NAME, "90Q"),
197+
},
198+
.driver_data = (void *)&ucsi_gram_ops,
199+
},
139200
{ }
140201
};
141202

0 commit comments

Comments
 (0)