From 04a82bed12cef8a27c2d76f229e0292bd0357f0c Mon Sep 17 00:00:00 2001 From: Cai Wenzhong Date: Tue, 7 Nov 2023 14:22:13 +0800 Subject: [PATCH] media: i2c: maxim4c: driver version 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. Signed-off-by: Cai Wenzhong Change-Id: I3424421395601266c0c2a787bedbd5028a786aab --- drivers/media/i2c/maxim4c/maxim4c_api.h | 2 + drivers/media/i2c/maxim4c/maxim4c_drv.c | 63 +++++++++++++++++++-- drivers/media/i2c/maxim4c/maxim4c_link.c | 12 +++- drivers/media/i2c/maxim4c/maxim4c_v4l2.c | 5 ++ drivers/media/i2c/maxim4c/remote_max96715.c | 15 +---- 5 files changed, 77 insertions(+), 20 deletions(-) diff --git a/drivers/media/i2c/maxim4c/maxim4c_api.h b/drivers/media/i2c/maxim4c/maxim4c_api.h index 25f261c84a44..a2968a30646f 100644 --- a/drivers/media/i2c/maxim4c/maxim4c_api.h +++ b/drivers/media/i2c/maxim4c/maxim4c_api.h @@ -90,7 +90,9 @@ int maxim4c_remote_device_register(maxim4c_t *maxim4c, int maxim4c_v4l2_subdev_init(maxim4c_t *maxim4c); void maxim4c_v4l2_subdev_deinit(maxim4c_t *maxim4c); +/* maxim4c driver api */ int maxim4c_module_hw_init(maxim4c_t *maxim4c); +int maxim4c_hot_plug_detect_work_start(maxim4c_t *maxim4c); /* maxim4c pattern api */ int maxim4c_pattern_hw_init(maxim4c_t *maxim4c); diff --git a/drivers/media/i2c/maxim4c/maxim4c_drv.c b/drivers/media/i2c/maxim4c/maxim4c_drv.c index 65650eeb5387..c543c6297ab2 100644 --- a/drivers/media/i2c/maxim4c/maxim4c_drv.c +++ b/drivers/media/i2c/maxim4c/maxim4c_drv.c @@ -37,6 +37,11 @@ * 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 #include @@ -66,7 +71,7 @@ #include "maxim4c_api.h" -#define DRIVER_VERSION KERNEL_VERSION(2, 0x04, 0x04) +#define DRIVER_VERSION KERNEL_VERSION(2, 0x05, 0x00) #define MAXIM4C_XVCLK_FREQ 25000000 @@ -103,8 +108,8 @@ static int maxim4c_check_local_chipid(maxim4c_t *maxim4c) return 0; } } else { + // if chipid is unexpected, retry dev_err(dev, "Unexpected maxim chipid = %02x\n", chipid); - return -ENODEV; } } } @@ -135,7 +140,7 @@ static irqreturn_t maxim4c_hot_plug_detect_irq_handler(int irq, void *dev_id) 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); @@ -209,8 +214,14 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work) 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 { dev_info(dev, "Link A plug out\n"); @@ -225,8 +236,14 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work) 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 { dev_info(dev, "Link B plug out\n"); @@ -241,8 +258,14 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work) 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 { dev_info(dev, "Link C plug out\n"); @@ -257,8 +280,14 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work) 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 { dev_info(dev, "Link D plug out\n"); @@ -273,12 +302,34 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work) } 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) { struct device *dev = &maxim4c->client->dev; @@ -328,7 +379,7 @@ static int maxim4c_local_device_power_on(maxim4c_t *maxim4c) gpiod_set_value_cansleep(maxim4c->pwdn_gpio, 1); - usleep_range(5000, 10000); + usleep_range(10000, 11000); } return 0; @@ -646,6 +697,8 @@ static int maxim4c_probe(struct i2c_client *client, 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"); + else + usleep_range(1000, 1100); maxim4c->lock_gpio = devm_gpiod_get(dev, "lock", GPIOD_IN); if (IS_ERR(maxim4c->lock_gpio)) diff --git a/drivers/media/i2c/maxim4c/maxim4c_link.c b/drivers/media/i2c/maxim4c/maxim4c_link.c index 688dfe85abee..26f986edfb00 100644 --- a/drivers/media/i2c/maxim4c/maxim4c_link.c +++ b/drivers/media/i2c/maxim4c/maxim4c_link.c @@ -463,7 +463,17 @@ int maxim4c_link_select_remote_enable(struct maxim4c *maxim4c, u8 link_mask) 0x0006, MAXIM4C_I2C_REG_ADDR_16BITS, link_enable, link_enable); - ret |= maxim4c_link_wait_linklock(maxim4c, link_mask); + if (ret) { + dev_err(dev, "%s: link oneshot reset or enable error, link mask = 0x%x\n", + __func__, link_mask); + return ret; + } + + maxim4c_link_wait_linklock(maxim4c, link_mask); + dev_info(dev, "link_mask = 0x%02x, link_lock = 0x%02x\n", + link_mask, maxim4c->link_lock_state); + + return 0; } return ret; diff --git a/drivers/media/i2c/maxim4c/maxim4c_v4l2.c b/drivers/media/i2c/maxim4c/maxim4c_v4l2.c index a331023da0d4..908045e89abf 100644 --- a/drivers/media/i2c/maxim4c/maxim4c_v4l2.c +++ b/drivers/media/i2c/maxim4c/maxim4c_v4l2.c @@ -532,6 +532,11 @@ static int __maxim4c_start_stream(struct maxim4c *maxim4c) if (maxim4c->hot_plug_irq > 0) enable_irq(maxim4c->hot_plug_irq); + if (maxim4c->link_lock_state != maxim4c->gmsl_link.link_enable_mask) { + dev_info(dev, "partial links are locked, start hot plug detect work.\n"); + maxim4c_hot_plug_detect_work_start(maxim4c); + } + return 0; } diff --git a/drivers/media/i2c/maxim4c/remote_max96715.c b/drivers/media/i2c/maxim4c/remote_max96715.c index 53c44d70ec5f..11aa30831acc 100644 --- a/drivers/media/i2c/maxim4c/remote_max96715.c +++ b/drivers/media/i2c/maxim4c/remote_max96715.c @@ -190,7 +190,6 @@ static int max96715_module_init(maxim4c_remote_t *max96715) { struct device *dev = max96715->dev; struct i2c_client *client = max96715->client; - struct maxim4c *maxim4c = max96715->local; int ret = 0; ret = maxim4c_remote_i2c_addr_select(max96715, MAXIM4C_I2C_SER_DEF); @@ -206,16 +205,9 @@ static int max96715_module_init(maxim4c_remote_t *max96715) return ret; #if MAX96715_MODE_SWITCH - if (maxim4c->hot_plug_irq > 0) - disable_irq(maxim4c->hot_plug_irq); - ret = max96715_link_mode_select(max96715, LINK_MODE_CONFIG); - if (ret) { - if (maxim4c->hot_plug_irq > 0) - enable_irq(maxim4c->hot_plug_irq); - + if (ret) return ret; - } #endif ret = maxim4c_i2c_run_init_seq(client, @@ -225,16 +217,11 @@ static int max96715_module_init(maxim4c_remote_t *max96715) dev_err(dev, "remote id = %d init sequence error\n", max96715->remote_id); - if (maxim4c->hot_plug_irq > 0) - enable_irq(maxim4c->hot_plug_irq); - return ret; } #if MAX96715_MODE_SWITCH ret = max96715_link_mode_select(max96715, LINK_MODE_VIDEO); - if (maxim4c->hot_plug_irq > 0) - enable_irq(maxim4c->hot_plug_irq); if (ret) return ret; #endif