diff mbox series

[26/30,SRU,Jammy] UBUNTU: SAUCE: ljca: add multi ACPI HID support

Message ID 20220117151928.954829-27-vicamo.yang@canonical.com
State New
Headers show
Series Support Intel IPU6 MIPI camera on Alder Lake platforms | expand

Commit Message

You-Sheng Yang Jan. 17, 2022, 3:19 p.m. UTC
From: Ye Xiang <xiang.ye@intel.com>

BugLink: https://bugs.launchpad.net/bugs/1955383

Precheck GPIO/I2C/SPI ACPI Device HID before
enumeration.

Signed-off-by: Ye Xiang <xiang.ye@intel.com>
(cherry picked from commit 11f55ee365786229f6a77885a817ead89e5e5a56 github.com/intel/ivsc-driver)
Signed-off-by: You-Sheng Yang <vicamo.yang@canonical.com>
---
 drivers/i2c/busses/i2c-ljca.c | 43 +++++++++++++++++-
 drivers/mfd/ljca.c            | 82 +++++++++++++++++++++++++++++------
 2 files changed, 111 insertions(+), 14 deletions(-)
diff mbox series

Patch

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 <linux/acpi.h>
 #include <linux/i2c.h>
 #include <linux/mfd/ljca.h>
 #include <linux/module.h>
@@ -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 <linux/acpi.h>
 #include <linux/kernel.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/ljca.h>
@@ -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)