From 1543e317f1da31b75942316931e8f491a8920811 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Thu, 04 Jan 2024 10:08:02 +0000
Subject: [PATCH] disable FB
---
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