Transaction: Use high priority workqueues for I2C

Transactions sometimes can be preempted by other threads (even threads
from Lyric nodes and drivers) which causes delay in register programming
that leads to frame drops. Sensor driver, especially, has shown
significant performance improvement after switching to high priority
workqueues. This change is only declared by device tree.

Bug: 212324606
Test: CTS, GCA, ITS. Validations are complete.
Signed-off-by: Nick Chung <nickchung@google.com>
Change-Id: I17e69b6692cc2e805a0d38156b5b00416f8ea074
diff --git a/lwis_device.h b/lwis_device.h
index 6ecfb44..e97f257 100644
--- a/lwis_device.h
+++ b/lwis_device.h
@@ -247,6 +247,8 @@
 	int pm_hibernation;
 	/* Is device read only */
 	bool is_read_only;
+	/* Adjust thread priority */
+	int adjust_thread_priority;
 };
 
 /*
diff --git a/lwis_dt.c b/lwis_dt.c
index b31e043..76fac6e 100644
--- a/lwis_dt.c
+++ b/lwis_dt.c
@@ -815,11 +815,9 @@
 
 static int parse_pm_hibernation(struct lwis_device *lwis_dev)
 {
-	struct device *dev;
 	struct device_node *dev_node;
 
-	dev = &(lwis_dev->plat_dev->dev);
-	dev_node = dev->of_node;
+	dev_node = lwis_dev->plat_dev->dev.of_node;
 	lwis_dev->pm_hibernation = 1;
 
 	of_property_read_u32(dev_node, "pm-hibernation", &lwis_dev->pm_hibernation);
@@ -838,6 +836,18 @@
 	return 0;
 }
 
+static int parse_thread_priority(struct lwis_device *lwis_dev)
+{
+	struct device_node *dev_node;
+
+	dev_node = lwis_dev->plat_dev->dev.of_node;
+	lwis_dev->adjust_thread_priority = 0;
+
+	of_property_read_u32(dev_node, "thread-priority", &lwis_dev->adjust_thread_priority);
+
+	return 0;
+}
+
 int lwis_base_parse_dt(struct lwis_device *lwis_dev)
 {
 	struct device *dev;
@@ -940,6 +950,8 @@
 
 	parse_access_mode(lwis_dev);
 
+	parse_thread_priority(lwis_dev);
+
 	parse_bitwidths(lwis_dev);
 
 	iommus = of_find_property(dev_node, "iommus", &iommus_len);
diff --git a/lwis_transaction.c b/lwis_transaction.c
index ba1d41d..0895123 100644
--- a/lwis_transaction.c
+++ b/lwis_transaction.c
@@ -370,7 +370,14 @@
 	INIT_LIST_HEAD(&client->transaction_process_queue_tasklet);
 	tasklet_init(&client->transaction_tasklet, transaction_tasklet_func, (unsigned long)client);
 	INIT_LIST_HEAD(&client->transaction_process_queue);
-	client->transaction_wq = create_workqueue("lwistran");
+	if (client->lwis_dev->adjust_thread_priority != 0) {
+		/* Since I2C transactions can only be executed in workqueues, putting them in high
+		 * priority to avoid scheduling delays. */
+		client->transaction_wq = alloc_ordered_workqueue(
+			"lwistran-i2c", __WQ_LEGACY | WQ_MEM_RECLAIM | WQ_HIGHPRI);
+	} else {
+		client->transaction_wq = create_workqueue("lwistran");
+	}
 	INIT_WORK(&client->transaction_work, transaction_work_func);
 	client->transaction_counter = 0;
 	hash_init(client->transaction_list);