From 2f7c68cb55ecb7331f2381deb497c27155f32faf Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Wed, 03 Jan 2024 09:43:39 +0000
Subject: [PATCH] update kernel to 5.10.198

---
 kernel/drivers/media/i2c/maxim4c/maxim4c_drv.c |  188 +++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 159 insertions(+), 29 deletions(-)

diff --git a/kernel/drivers/media/i2c/maxim4c/maxim4c_drv.c b/kernel/drivers/media/i2c/maxim4c/maxim4c_drv.c
index 88924dc..c543c62 100644
--- a/kernel/drivers/media/i2c/maxim4c/maxim4c_drv.c
+++ b/kernel/drivers/media/i2c/maxim4c/maxim4c_drv.c
@@ -22,6 +22,26 @@
  *     5. power control: local by pwdn gpio, remote by pocen gpio
  *     6. local pwdn on/off enable depend on MAXIM4C_LOCAL_DES_ON_OFF_EN
  *
+ * V2.02.00
+ *     1. Force all MIPI clocks running Setting in csi out enable.
+ *     2. Pattern mode force_clock_out_en default enable.
+ *
+ * V2.03.00
+ *     1. remote device add the maxim4c prefix to driver name.
+ *
+ * V2.04.04
+ *     1. Add regulator supplier dependencies.
+ *     2. Add config ssc-ratio property
+ *     3. Add debugfs entry to change MIPI timing
+ *     4. Use PM runtime autosuspend feature
+ *     5. Fix unbalanced disabling for PoC regulator
+ *     6. MIPI VC count does not affected by data lane count
+ *
+ * V2.05.00
+ *     1. local device power on add some delay for i2c normal access.
+ *     2. enable hot plug detect for partial links are locked.
+ *     3. remote device hot plug init disable lock irq.
+ *
  */
 #include <linux/clk.h>
 #include <linux/i2c.h>
@@ -51,9 +71,14 @@
 
 #include "maxim4c_api.h"
 
-#define DRIVER_VERSION			KERNEL_VERSION(2, 0x01, 0x00)
+#define DRIVER_VERSION			KERNEL_VERSION(2, 0x05, 0x00)
 
 #define MAXIM4C_XVCLK_FREQ		25000000
+
+static const char *const maxim4c_supply_names[MAXIM4C_NUM_SUPPLIES] = {
+	"vcc1v2",
+	"vcc1v8",
+};
 
 static int maxim4c_check_local_chipid(maxim4c_t *maxim4c)
 {
@@ -83,8 +108,8 @@
 					return 0;
 				}
 			} else {
+				// if chipid is unexpected, retry
 				dev_err(dev, "Unexpected maxim chipid = %02x\n", chipid);
-				return -ENODEV;
 			}
 		}
 	}
@@ -115,7 +140,7 @@
 
 		queue_delayed_work(maxim4c->hot_plug_work.state_check_wq,
 					&maxim4c->hot_plug_work.state_d_work,
-					msecs_to_jiffies(50));
+					msecs_to_jiffies(100));
 	}
 	mutex_unlock(&maxim4c->mutex);
 
@@ -189,7 +214,13 @@
 		if (curr_lock_state & MAXIM4C_LINK_MASK_A) {
 			dev_info(dev, "Link A plug in\n");
 
+			if (maxim4c->hot_plug_irq > 0)
+				disable_irq(maxim4c->hot_plug_irq);
+
 			maxim4c_remote_devices_init(maxim4c, MAXIM4C_LINK_MASK_A);
+
+			if (maxim4c->hot_plug_irq > 0)
+				enable_irq(maxim4c->hot_plug_irq);
 
 			maxim4c_video_pipe_linkid_enable(maxim4c, link_id, true);
 		} else {
@@ -205,7 +236,13 @@
 		if (curr_lock_state & MAXIM4C_LINK_MASK_B) {
 			dev_info(dev, "Link B plug in\n");
 
+			if (maxim4c->hot_plug_irq > 0)
+				disable_irq(maxim4c->hot_plug_irq);
+
 			maxim4c_remote_devices_init(maxim4c, MAXIM4C_LINK_MASK_B);
+
+			if (maxim4c->hot_plug_irq > 0)
+				enable_irq(maxim4c->hot_plug_irq);
 
 			maxim4c_video_pipe_linkid_enable(maxim4c, link_id, true);
 		} else {
@@ -221,7 +258,13 @@
 		if (curr_lock_state & MAXIM4C_LINK_MASK_C) {
 			dev_info(dev, "Link C plug in\n");
 
+			if (maxim4c->hot_plug_irq > 0)
+				disable_irq(maxim4c->hot_plug_irq);
+
 			maxim4c_remote_devices_init(maxim4c, MAXIM4C_LINK_MASK_C);
+
+			if (maxim4c->hot_plug_irq > 0)
+				enable_irq(maxim4c->hot_plug_irq);
 
 			maxim4c_video_pipe_linkid_enable(maxim4c, link_id, true);
 		} else {
@@ -237,7 +280,13 @@
 		if (curr_lock_state & MAXIM4C_LINK_MASK_D) {
 			dev_info(dev, "Link D plug in\n");
 
+			if (maxim4c->hot_plug_irq > 0)
+				disable_irq(maxim4c->hot_plug_irq);
+
 			maxim4c_remote_devices_init(maxim4c, MAXIM4C_LINK_MASK_D);
+
+			if (maxim4c->hot_plug_irq > 0)
+				enable_irq(maxim4c->hot_plug_irq);
 
 			maxim4c_video_pipe_linkid_enable(maxim4c, link_id, true);
 		} else {
@@ -253,10 +302,32 @@
 	} else {
 		queue_delayed_work(maxim4c->hot_plug_work.state_check_wq,
 				&maxim4c->hot_plug_work.state_d_work,
-				msecs_to_jiffies(100));
+				msecs_to_jiffies(200));
 	}
 
 	mutex_unlock(&maxim4c->mutex);
+}
+
+int maxim4c_hot_plug_detect_work_start(maxim4c_t *maxim4c)
+{
+	struct device *dev = &maxim4c->client->dev;
+	u8 link_lock_state = 0, link_enable_mask = 0;
+
+	link_lock_state = maxim4c->link_lock_state;
+	link_enable_mask = maxim4c->gmsl_link.link_enable_mask;
+
+	if (link_lock_state != link_enable_mask) {
+		dev_info(dev, "%s: link_lock = 0x%02x, link_mask = 0x%02x\n",
+			__func__, link_lock_state, link_enable_mask);
+
+		maxim4c->hot_plug_state = MAXIM4C_HOT_PLUG_OUT;
+
+		queue_delayed_work(maxim4c->hot_plug_work.state_check_wq,
+				&maxim4c->hot_plug_work.state_d_work,
+				msecs_to_jiffies(200));
+	}
+
+	return 0;
 }
 
 static int maxim4c_lock_state_work_init(maxim4c_t *maxim4c)
@@ -295,13 +366,20 @@
 static int maxim4c_local_device_power_on(maxim4c_t *maxim4c)
 {
 	struct device *dev = &maxim4c->client->dev;
+	int ret;
+
+	ret = regulator_bulk_enable(MAXIM4C_NUM_SUPPLIES, maxim4c->supplies);
+	if (ret < 0) {
+		dev_err(dev, "Failed to enable regulators\n");
+		return -EINVAL;
+	}
 
 	if (!IS_ERR(maxim4c->pwdn_gpio)) {
 		dev_info(dev, "local device pwdn gpio on\n");
 
 		gpiod_set_value_cansleep(maxim4c->pwdn_gpio, 1);
 
-		usleep_range(5000, 10000);
+		usleep_range(10000, 11000);
 	}
 
 	return 0;
@@ -310,24 +388,30 @@
 static void maxim4c_local_device_power_off(maxim4c_t *maxim4c)
 {
 	struct device *dev = &maxim4c->client->dev;
+	int ret;
 
 	if (!IS_ERR(maxim4c->pwdn_gpio)) {
 		dev_info(dev, "local device pwdn gpio off\n");
 
 		gpiod_set_value_cansleep(maxim4c->pwdn_gpio, 0);
 	}
+
+	ret = regulator_bulk_disable(MAXIM4C_NUM_SUPPLIES, maxim4c->supplies);
+	if (ret < 0) {
+		dev_warn(dev, "Failed to disable regulators\n");
+	}
 }
 
 static int maxim4c_remote_device_power_on(maxim4c_t *maxim4c)
 {
 	struct device *dev = &maxim4c->client->dev;
+	int ret;
 
-	// remote PoC enable
-	if (!IS_ERR(maxim4c->pocen_gpio)) {
-		dev_info(dev, "remote device pocen gpio on\n");
-
-		gpiod_set_value_cansleep(maxim4c->pocen_gpio, 1);
-		usleep_range(5000, 10000);
+	dev_dbg(dev, "Turn PoC on\n");
+	ret = regulator_enable(maxim4c->poc_regulator);
+	if (ret < 0) {
+		dev_err(dev, "Unable to turn PoC on\n");
+		return ret;
 	}
 
 	return 0;
@@ -336,13 +420,12 @@
 static int maxim4c_remote_device_power_off(maxim4c_t *maxim4c)
 {
 	struct device *dev = &maxim4c->client->dev;
+	int ret;
 
-	// remote PoC enable
-	if (!IS_ERR(maxim4c->pocen_gpio)) {
-		dev_info(dev, "remote device pocen gpio off\n");
-
-		gpiod_set_value_cansleep(maxim4c->pocen_gpio, 0);
-	}
+	dev_dbg(dev, "Turn PoC off\n");
+	ret = regulator_disable(maxim4c->poc_regulator);
+	if (ret < 0)
+		dev_warn(dev, "Unable to turn PoC off\n");
 
 	return 0;
 }
@@ -574,6 +657,7 @@
 	maxim4c_t *maxim4c = NULL;
 	u32 chip_id;
 	int ret = 0;
+	unsigned int i;
 
 	dev_info(dev, "driver version: %02x.%02x.%02x", DRIVER_VERSION >> 16,
 		 (DRIVER_VERSION & 0xff00) >> 8, DRIVER_VERSION & 0x00ff);
@@ -613,20 +697,53 @@
 	maxim4c->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW);
 	if (IS_ERR(maxim4c->pwdn_gpio))
 		dev_warn(dev, "Failed to get pwdn-gpios, maybe no use\n");
-
-	maxim4c->pocen_gpio = devm_gpiod_get(dev, "pocen", GPIOD_OUT_LOW);
-	if (IS_ERR(maxim4c->pocen_gpio))
-		dev_warn(dev, "Failed to get pocen-gpios\n");
+	else
+		usleep_range(1000, 1100);
 
 	maxim4c->lock_gpio = devm_gpiod_get(dev, "lock", GPIOD_IN);
 	if (IS_ERR(maxim4c->lock_gpio))
 		dev_warn(dev, "Failed to get lock-gpios\n");
+
+	for (i = 0; i < MAXIM4C_NUM_SUPPLIES; i++)
+		maxim4c->supplies[i].supply = maxim4c_supply_names[i];
+
+	ret = devm_regulator_bulk_get(dev, MAXIM4C_NUM_SUPPLIES,
+				      maxim4c->supplies);
+	if (ret < 0) {
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "Unable to get supply regulators\n");
+		else
+			dev_warn(dev, "Get PoC regulator deferred\n");
+		return ret;
+	}
+
+	maxim4c->poc_regulator = devm_regulator_get(dev, "poc");
+	if (IS_ERR(maxim4c->poc_regulator)) {
+		if (PTR_ERR(maxim4c->poc_regulator) != -EPROBE_DEFER)
+			dev_err(dev, "Unable to get PoC regulator (%ld)\n",
+				PTR_ERR(maxim4c->poc_regulator));
+		else
+			dev_err(dev, "Get PoC regulator deferred\n");
+
+		ret = PTR_ERR(maxim4c->poc_regulator);
+#if !MAXIM4C_TEST_PATTERN
+		return ret;
+#endif
+	}
 
 	mutex_init(&maxim4c->mutex);
 
 	ret = maxim4c_local_device_power_on(maxim4c);
 	if (ret)
 		goto err_destroy_mutex;
+
+	ret = maxim4c_remote_device_power_on(maxim4c);
+	if (ret)
+		dev_warn(dev, "Power on PoC regulator failed\n");
+
+	pm_runtime_set_active(dev);
+	pm_runtime_get_noresume(dev);
+	pm_runtime_enable(dev);
 
 	ret = maxim4c_check_local_chipid(maxim4c);
 	if (ret)
@@ -651,9 +768,10 @@
 		goto err_power_off;
 #endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */
 
-	pm_runtime_set_active(dev);
-	pm_runtime_enable(dev);
-	pm_runtime_idle(dev);
+	pm_runtime_set_autosuspend_delay(dev, 1000);
+	pm_runtime_use_autosuspend(dev);
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 
 	return 0;
 #endif /* MAXIM4C_TEST_PATTERN */
@@ -661,28 +779,38 @@
 	maxim4c_module_data_init(maxim4c);
 	maxim4c_module_parse_dt(maxim4c);
 
+	ret = maxim4c_dbgfs_init(maxim4c);
+	if (ret)
+		goto err_subdev_deinit;
+
 #if (MAXIM4C_LOCAL_DES_ON_OFF_EN == 0)
 	ret = maxim4c_module_hw_init(maxim4c);
 	if (ret)
-		goto err_subdev_deinit;
+		goto err_dbgfs_deinit;
 #endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */
 
 	ret = maxim4c_remote_mfd_add_devices(maxim4c);
 	if (ret)
-		goto err_subdev_deinit;
+		goto err_dbgfs_deinit;
 
 	maxim4c_lock_irq_init(maxim4c);
 	maxim4c_lock_state_work_init(maxim4c);
 
-	pm_runtime_set_active(dev);
-	pm_runtime_enable(dev);
-	pm_runtime_idle(dev);
+	pm_runtime_set_autosuspend_delay(dev, 1000);
+	pm_runtime_use_autosuspend(dev);
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
 
 	return 0;
 
+err_dbgfs_deinit:
+	maxim4c_dbgfs_deinit(maxim4c);
 err_subdev_deinit:
 	maxim4c_v4l2_subdev_deinit(maxim4c);
 err_power_off:
+	pm_runtime_disable(dev);
+	pm_runtime_put_noidle(dev);
+	maxim4c_remote_device_power_off(maxim4c);
 	maxim4c_local_device_power_off(maxim4c);
 err_destroy_mutex:
 	mutex_destroy(&maxim4c->mutex);
@@ -696,6 +824,8 @@
 
 	maxim4c_lock_state_work_deinit(maxim4c);
 
+	maxim4c_dbgfs_deinit(maxim4c);
+
 	maxim4c_v4l2_subdev_deinit(maxim4c);
 
 	mutex_destroy(&maxim4c->mutex);

--
Gitblit v1.6.2