From a50ce5b004d865c4ed0665bbebe21f030b7ba98a Mon Sep 17 00:00:00 2001 From: Ye Xiang Date: Fri, 12 Nov 2021 00:41:22 +0800 Subject: [PATCH] UBUNTU: SAUCE: ljca: add multi ACPI HID support BugLink: https://bugs.launchpad.net/bugs/1955383 Precheck GPIO/I2C/SPI ACPI Device HID before enumeration. Signed-off-by: Ye Xiang (cherry picked from commit 11f55ee365786229f6a77885a817ead89e5e5a56 github.com/intel/ivsc-driver) Signed-off-by: You-Sheng Yang Acked-by: Andrea Righi Acked-by: Kleber Sacilotto de Souza Signed-off-by: Kleber Sacilotto de Souza --- drivers/i2c/busses/i2c-ljca.c | 43 +++++++++++++++++- drivers/mfd/ljca.c | 82 +++++++++++++++++++++++++++++------ 2 files changed, 111 insertions(+), 14 deletions(-) diff --git a/drivers/i2c/busses/i2c-ljca.c b/drivers/i2c/busses/i2c-ljca.c index de66a41f61ae..bec6d8a02ae8 100644 --- a/drivers/i2c/busses/i2c-ljca.c +++ b/drivers/i2c/busses/i2c-ljca.c @@ -5,6 +5,7 @@ * Copyright (c) 2021, Intel Corporation. */ +#include #include #include #include @@ -321,6 +322,44 @@ static const struct i2c_algorithm ljca_i2c_algo = { .functionality = ljca_i2c_func, }; +static void try_bind_acpi(struct platform_device *pdev, + struct ljca_i2c_dev *ljca_i2c) +{ + struct acpi_device *parent, *child; + struct acpi_device *cur = ACPI_COMPANION(&pdev->dev); + const char *hid1; + const char *uid1; + char uid2[2] = { 0 }; + + if (!cur) + return; + + hid1 = acpi_device_hid(cur); + uid1 = acpi_device_uid(cur); + snprintf(uid2, sizeof(uid2), "%d", ljca_i2c->ctr_info->id); + + dev_dbg(&pdev->dev, "hid %s uid %s new uid%s\n", hid1, uid1, uid2); + /* + * If the pdev is bound to the right acpi device, just forward it to the + * adapter. Otherwise, we find that of current adapter manually. + */ + if (!strcmp(uid1, uid2)) { + ACPI_COMPANION_SET(&ljca_i2c->adap.dev, cur); + return; + } + + parent = ACPI_COMPANION(pdev->dev.parent); + if (!parent) + return; + + list_for_each_entry(child, &parent->children, node) { + if (acpi_dev_hid_uid_match(child, hid1, uid2)) { + ACPI_COMPANION_SET(&ljca_i2c->adap.dev, child); + return; + } + } +} + static int ljca_i2c_probe(struct platform_device *pdev) { struct ljca_i2c_dev *ljca_i2c; @@ -338,7 +377,9 @@ static int ljca_i2c_probe(struct platform_device *pdev) ljca_i2c->adap.class = I2C_CLASS_HWMON; ljca_i2c->adap.algo = &ljca_i2c_algo; ljca_i2c->adap.dev.parent = &pdev->dev; - ACPI_COMPANION_SET(&ljca_i2c->adap.dev, ACPI_COMPANION(&pdev->dev)); + + try_bind_acpi(pdev, ljca_i2c); + ljca_i2c->adap.dev.of_node = pdev->dev.of_node; i2c_set_adapdata(&ljca_i2c->adap, ljca_i2c); snprintf(ljca_i2c->adap.name, sizeof(ljca_i2c->adap.name), "%s-%s-%d", diff --git a/drivers/mfd/ljca.c b/drivers/mfd/ljca.c index 64d4b48565e4..aace699de53a 100644 --- a/drivers/mfd/ljca.c +++ b/drivers/mfd/ljca.c @@ -5,6 +5,7 @@ * Copyright (c) 2021, Intel Corporation. */ +#include #include #include #include @@ -23,24 +24,23 @@ enum ljca_acpi_match_adr { LJCA_ACPI_MATCH_SPI1, }; -static struct mfd_cell_acpi_match ljca_acpi_match_gpio = { - .pnpid = "INTC1074", +static char *gpio_hids[] = { + "INTC1074", + "INTC1096", }; +static struct mfd_cell_acpi_match ljca_acpi_match_gpio; -static struct mfd_cell_acpi_match ljca_acpi_match_i2cs[] = { - { - .pnpid = "INTC1075", - }, - { - .pnpid = "INTC1076", - }, +static char *i2c_hids[] = { + "INTC1075", + "INTC1097", }; +static struct mfd_cell_acpi_match ljca_acpi_match_i2cs[2]; -static struct mfd_cell_acpi_match ljca_acpi_match_spis[] = { - { - .pnpid = "INTC1091", - }, +static char *spi_hids[] = { + "INTC1091", + "INTC1098", }; +static struct mfd_cell_acpi_match ljca_acpi_match_spis[1]; struct ljca_msg { u8 type; @@ -206,6 +206,50 @@ struct ljca_dev { int cell_count; }; +static int try_match_acpi_hid(struct acpi_device *child, + struct mfd_cell_acpi_match *match, char **hids, + int hids_num) +{ + struct acpi_device_id ids[2] = {}; + int i; + + for (i = 0; i < hids_num; i++) { + strlcpy(ids[0].id, hids[i], sizeof(ids[0].id)); + if (!acpi_match_device_ids(child, ids)) { + match->pnpid = hids[i]; + break; + } + } + + return 0; +} + +static int precheck_acpi_hid(struct usb_interface *intf) +{ + struct acpi_device *parent, *child; + + parent = ACPI_COMPANION(&intf->dev); + if (!parent) + return -ENODEV; + + list_for_each_entry (child, &parent->children, node) { + try_match_acpi_hid(child, + &ljca_acpi_match_gpio, + gpio_hids, ARRAY_SIZE(gpio_hids)); + try_match_acpi_hid(child, + &ljca_acpi_match_i2cs[0], + i2c_hids, ARRAY_SIZE(i2c_hids)); + try_match_acpi_hid(child, + &ljca_acpi_match_i2cs[1], + i2c_hids, ARRAY_SIZE(i2c_hids)); + try_match_acpi_hid(child, + &ljca_acpi_match_spis[0], + spi_hids, ARRAY_SIZE(spi_hids)); + } + + return 0; +} + static bool ljca_validate(void *data, u32 data_len) { struct ljca_msg *header = (struct ljca_msg *)data; @@ -568,6 +612,13 @@ static inline int ljca_mng_reset(struct ljca_stub *stub) static int ljca_add_mfd_cell(struct ljca_dev *ljca, struct mfd_cell *cell) { struct mfd_cell *new_cells; + + /* Enumerate the device even if it does not appear in DSDT */ + if (!cell->acpi_match->pnpid) + dev_warn(&ljca->intf->dev, + "The HID of cell %s does not exist in DSDT\n", + cell->name); + new_cells = krealloc_array(ljca->cells, (ljca->cell_count + 1), sizeof(struct mfd_cell), GFP_KERNEL); if (!new_cells) @@ -1000,6 +1051,11 @@ static int ljca_probe(struct usb_interface *intf, struct usb_endpoint_descriptor *bulk_in, *bulk_out; int ret; + ret = precheck_acpi_hid(intf); + if(ret) + return ret; + + /* allocate memory for our device state and initialize it */ ljca = kzalloc(sizeof(*ljca), GFP_KERNEL); if (!ljca) -- 2.39.2