diff --git a/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.c b/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.c index 1023f607886a..2d51167a1b66 100644 --- a/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.c +++ b/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.c @@ -56,6 +56,10 @@ * 1. v4l2 ioctl add command to support quick stream setting * 2. dev_pm_ops add suspend and resume for system sleep * + * V3.08.00 + * 1. wait link lock stable when hot plug is detected + * 2. link get lock state retry if i2c error + * */ #include #include @@ -83,7 +87,7 @@ #include "maxim2c_api.h" -#define DRIVER_VERSION KERNEL_VERSION(3, 0x07, 0x00) +#define DRIVER_VERSION KERNEL_VERSION(3, 0x08, 0x00) #define MAXIM2C_NAME "maxim2c" @@ -210,7 +214,7 @@ static void maxim2c_hot_plug_state_check_work(struct work_struct *work) maxim2c_t *maxim2c = container_of(hot_plug_work, struct maxim2c, hot_plug_work); struct device *dev = &maxim2c->client->dev; - u8 curr_lock_state = 0, last_lock_state = 0, link_lock_change = 0; + u8 curr_lock_state = 0, retry_lock_state = 0, last_lock_state = 0, link_lock_change = 0; u8 link_enable_mask = 0, link_id = 0; dev_dbg(dev, "%s\n", __func__); @@ -226,13 +230,25 @@ static void maxim2c_hot_plug_state_check_work(struct work_struct *work) if ((maxim2c->hot_plug_state == MAXIM2C_HOT_PLUG_OUT) && (last_lock_state == link_enable_mask)) { // i2c mux enable: disable all remote channel + dev_info(dev, "disable all remote channel\n"); maxim2c_i2c_mux_enable(maxim2c, 0x00); } curr_lock_state = maxim2c_link_get_lock_state(maxim2c, link_enable_mask); + // Link lock state maybe detect error when hot plug, first check i2c io status + if (curr_lock_state != last_lock_state) { + // delay 100ms for link lock stable + usleep_range(100000, 110000); + retry_lock_state = maxim2c_link_get_lock_state(maxim2c, link_enable_mask); + if (retry_lock_state != curr_lock_state) { + dev_info(dev, "link lock retry: 0x%02x -> 0x%02x\n", + curr_lock_state, retry_lock_state); + curr_lock_state = retry_lock_state; + } + } link_lock_change = (last_lock_state ^ curr_lock_state); if (link_lock_change) { - dev_dbg(dev, "lock state: current = 0x%02x, last = 0x%02x\n", + dev_info(dev, "lock state: current = 0x%02x, last = 0x%02x\n", curr_lock_state, last_lock_state); maxim2c_hot_plug_event_report(maxim2c, curr_lock_state); diff --git a/drivers/media/i2c/maxim/local/maxim2c/maxim2c_link.c b/drivers/media/i2c/maxim/local/maxim2c/maxim2c_link.c index 3aa775fba366..68e00c0ddf7b 100644 --- a/drivers/media/i2c/maxim/local/maxim2c/maxim2c_link.c +++ b/drivers/media/i2c/maxim/local/maxim2c/maxim2c_link.c @@ -152,22 +152,37 @@ u8 maxim2c_link_get_lock_state(maxim2c_t *maxim2c, u8 link_mask) struct device *dev = &client->dev; maxim2c_gmsl_link_t *gmsl_link = &maxim2c->gmsl_link; u8 link_type = 0, link_lock = 0, lock_state = 0; - - dev_dbg(dev, "%s, link_mask = 0x%x\n", __func__, link_mask); + int ret = 0, i = 0; // Link A if (link_mask & MAXIM2C_LINK_MASK_A) { link_type = gmsl_link->link_cfg[MAXIM2C_LINK_ID_A].link_type; if (link_type == MAXIM2C_GMSL2) { // GMSL2 Link A - maxim2c_i2c_read_reg(client, 0x0013, &link_lock); + for (i = 0; i < 3; i++) { + ret = maxim2c_i2c_read_reg(client, 0x0013, &link_lock); + if (ret) { + dev_info(dev, "GMSL2 Link A get lock retry (%d)", i); + usleep_range(10000, 10100); + } else { + break; + } + } if (link_lock & BIT(3)) { lock_state |= MAXIM2C_LINK_MASK_A; dev_dbg(dev, "GMSL2 Link A locked\n"); } } else { // GMSL1 Link A - maxim2c_i2c_read_reg(client, 0x0BCB, &link_lock); + for (i = 0; i < 3; i++) { + ret = maxim2c_i2c_read_reg(client, 0x0BCB, &link_lock); + if (ret) { + dev_info(dev, "GMSL1 Link A get lock retry (%d)", i); + usleep_range(10000, 10100); + } else { + break; + } + } if (link_lock & BIT(0)) { lock_state |= MAXIM2C_LINK_MASK_A; dev_dbg(dev, "GMSL1 Link A locked\n"); @@ -186,14 +201,30 @@ u8 maxim2c_link_get_lock_state(maxim2c_t *maxim2c, u8 link_mask) link_type = gmsl_link->link_cfg[MAXIM2C_LINK_ID_B].link_type; if (link_type == MAXIM2C_GMSL2) { // GMSL2 Link B - maxim2c_i2c_read_reg(client, 0x5009, &link_lock); + for (i = 0; i < 3; i++) { + ret = maxim2c_i2c_read_reg(client, 0x5009, &link_lock); + if (ret) { + dev_info(dev, "GMSL2 Link B get lock retry (%d)", i); + usleep_range(10000, 10100); + } else { + break; + } + } if (link_lock & BIT(3)) { lock_state |= MAXIM2C_LINK_MASK_B; dev_dbg(dev, "GMSL2 Link B locked\n"); } } else { // GMSL1 Link B - maxim2c_i2c_read_reg(client, 0x0CCB, &link_lock); + for (i = 0; i < 3; i++) { + ret = maxim2c_i2c_read_reg(client, 0x0CCB, &link_lock); + if (ret) { + dev_info(dev, "GMSL1 Link B get lock retry (%d)", i); + usleep_range(10000, 10100); + } else { + break; + } + } if (link_lock & BIT(0)) { lock_state |= MAXIM2C_LINK_MASK_B; dev_dbg(dev, "GMSL1 Link B locked\n"); @@ -207,6 +238,9 @@ u8 maxim2c_link_get_lock_state(maxim2c_t *maxim2c, u8 link_mask) gmsl_link->link_locked_mask &= ~MAXIM2C_LINK_MASK_B; } + dev_dbg(dev, "%s, link_mask = 0x%02x, lock_state = 0x%02x\n", + __func__, link_mask, lock_state); + return lock_state; } EXPORT_SYMBOL(maxim2c_link_get_lock_state); diff --git a/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.c b/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.c index 6e15578fb1d9..7cabbf794a83 100644 --- a/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.c +++ b/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.c @@ -79,6 +79,10 @@ * 1. v4l2 ioctl add command to support quick stream setting * 2. dev_pm_ops add suspend and resume for system sleep * + * V3.08.00 + * 1. wait link lock stable when hot plug is detected + * 2. link get lock state retry if i2c error + * */ #include #include @@ -106,7 +110,7 @@ #include "maxim4c_api.h" -#define DRIVER_VERSION KERNEL_VERSION(3, 0x07, 0x00) +#define DRIVER_VERSION KERNEL_VERSION(3, 0x08, 0x00) #define MAXIM4C_NAME "maxim4c" @@ -233,7 +237,7 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work) maxim4c_t *maxim4c = container_of(hot_plug_work, struct maxim4c, hot_plug_work); struct device *dev = &maxim4c->client->dev; - u8 curr_lock_state = 0, last_lock_state = 0, link_lock_change = 0; + u8 curr_lock_state = 0, retry_lock_state = 0, last_lock_state = 0, link_lock_change = 0; u8 link_enable_mask = 0, link_id = 0; dev_dbg(dev, "%s\n", __func__); @@ -249,13 +253,25 @@ static void maxim4c_hot_plug_state_check_work(struct work_struct *work) if ((maxim4c->hot_plug_state == MAXIM4C_HOT_PLUG_OUT) && (last_lock_state == link_enable_mask)) { // i2c mux enable: disable all remote channel + dev_info(dev, "disable all remote channel\n"); maxim4c_i2c_mux_enable(maxim4c, 0x00); } curr_lock_state = maxim4c_link_get_lock_state(maxim4c, link_enable_mask); + // Link lock state maybe detect error when hot plug, first check i2c io status + if (curr_lock_state != last_lock_state) { + // delay 100ms for link lock stable + usleep_range(100000, 110000); + retry_lock_state = maxim4c_link_get_lock_state(maxim4c, link_enable_mask); + if (retry_lock_state != curr_lock_state) { + dev_info(dev, "link lock retry: 0x%02x -> 0x%02x\n", + curr_lock_state, retry_lock_state); + curr_lock_state = retry_lock_state; + } + } link_lock_change = (last_lock_state ^ curr_lock_state); if (link_lock_change) { - dev_dbg(dev, "lock state: current = 0x%02x, last = 0x%02x\n", + dev_info(dev, "lock state: current = 0x%02x, last = 0x%02x\n", curr_lock_state, last_lock_state); maxim4c_hot_plug_event_report(maxim4c, curr_lock_state); diff --git a/drivers/media/i2c/maxim/local/maxim4c/maxim4c_link.c b/drivers/media/i2c/maxim/local/maxim4c/maxim4c_link.c index b01e45ccf1d1..f2ea80e28166 100644 --- a/drivers/media/i2c/maxim/local/maxim4c/maxim4c_link.c +++ b/drivers/media/i2c/maxim/local/maxim4c/maxim4c_link.c @@ -174,22 +174,37 @@ u8 maxim4c_link_get_lock_state(maxim4c_t *maxim4c, u8 link_mask) struct device *dev = &client->dev; maxim4c_gmsl_link_t *gmsl_link = &maxim4c->gmsl_link; u8 link_type = 0, link_lock = 0, lock_state = 0; - - dev_dbg(dev, "%s, link_mask = 0x%x\n", __func__, link_mask); + int ret = 0, i = 0; // Link A if (link_mask & MAXIM4C_LINK_MASK_A) { link_type = gmsl_link->link_cfg[MAXIM4C_LINK_ID_A].link_type; if (link_type == MAXIM4C_GMSL2) { // GMSL2 Link A - maxim4c_i2c_read_reg(client, 0x001A, &link_lock); + for (i = 0; i < 3; i++) { + ret = maxim4c_i2c_read_reg(client, 0x001A, &link_lock); + if (ret) { + dev_info(dev, "GMSL2 Link A get lock retry (%d)", i); + usleep_range(10000, 10100); + } else { + break; + } + } if (link_lock & BIT(3)) { lock_state |= MAXIM4C_LINK_MASK_A; dev_dbg(dev, "GMSL2 Link A locked\n"); } } else { // GMSL1 Link A - maxim4c_i2c_read_reg(client, 0x0BCB, &link_lock); + for (i = 0; i < 3; i++) { + ret = maxim4c_i2c_read_reg(client, 0x0BCB, &link_lock); + if (ret) { + dev_info(dev, "GMSL1 Link A get lock retry (%d)", i); + usleep_range(10000, 10100); + } else { + break; + } + } if (link_lock & BIT(0)) { lock_state |= MAXIM4C_LINK_MASK_A; dev_dbg(dev, "GMSL1 Link A locked\n"); @@ -208,14 +223,30 @@ u8 maxim4c_link_get_lock_state(maxim4c_t *maxim4c, u8 link_mask) link_type = gmsl_link->link_cfg[MAXIM4C_LINK_ID_B].link_type; if (link_type == MAXIM4C_GMSL2) { // GMSL2 Link B - maxim4c_i2c_read_reg(client, 0x000A, &link_lock); + for (i = 0; i < 3; i++) { + ret = maxim4c_i2c_read_reg(client, 0x000A, &link_lock); + if (ret) { + dev_info(dev, "GMSL2 Link B get lock retry (%d)", i); + usleep_range(10000, 10100); + } else { + break; + } + } if (link_lock & BIT(3)) { lock_state |= MAXIM4C_LINK_MASK_B; dev_dbg(dev, "GMSL2 Link B locked\n"); } } else { // GMSL1 Link B - maxim4c_i2c_read_reg(client, 0x0CCB, &link_lock); + for (i = 0; i < 3; i++) { + ret = maxim4c_i2c_read_reg(client, 0x0CCB, &link_lock); + if (ret) { + dev_info(dev, "GMSL1 Link B get lock retry (%d)", i); + usleep_range(10000, 10100); + } else { + break; + } + } if (link_lock & BIT(0)) { lock_state |= MAXIM4C_LINK_MASK_B; dev_dbg(dev, "GMSL1 Link B locked\n"); @@ -234,14 +265,30 @@ u8 maxim4c_link_get_lock_state(maxim4c_t *maxim4c, u8 link_mask) link_type = gmsl_link->link_cfg[MAXIM4C_LINK_ID_C].link_type; if (link_type == MAXIM4C_GMSL2) { // GMSL2 Link C - maxim4c_i2c_read_reg(client, 0x000B, &link_lock); + for (i = 0; i < 3; i++) { + ret = maxim4c_i2c_read_reg(client, 0x000B, &link_lock); + if (ret) { + dev_info(dev, "GMSL2 Link C get lock retry (%d)", i); + usleep_range(10000, 10100); + } else { + break; + } + } if (link_lock & BIT(3)) { lock_state |= MAXIM4C_LINK_MASK_C; dev_dbg(dev, "GMSL2 Link C locked\n"); } } else { // GMSL1 Link C - maxim4c_i2c_read_reg(client, 0x0DCB, &link_lock); + for (i = 0; i < 3; i++) { + ret = maxim4c_i2c_read_reg(client, 0x0DCB, &link_lock); + if (ret) { + dev_info(dev, "GMSL1 Link C get lock retry (%d)", i); + usleep_range(10000, 10100); + } else { + break; + } + } if (link_lock & BIT(0)) { lock_state |= MAXIM4C_LINK_MASK_C; dev_dbg(dev, "GMSL1 Link C locked\n"); @@ -260,14 +307,30 @@ u8 maxim4c_link_get_lock_state(maxim4c_t *maxim4c, u8 link_mask) link_type = gmsl_link->link_cfg[MAXIM4C_LINK_ID_D].link_type; if (link_type == MAXIM4C_GMSL2) { // GMSL2 Link D - maxim4c_i2c_read_reg(client, 0x000C, &link_lock); + for (i = 0; i < 3; i++) { + ret = maxim4c_i2c_read_reg(client, 0x000C, &link_lock); + if (ret) { + dev_info(dev, "GMSL2 Link D get lock retry (%d)", i); + usleep_range(10000, 10100); + } else { + break; + } + } if (link_lock & BIT(3)) { lock_state |= MAXIM4C_LINK_MASK_D; dev_dbg(dev, "GMSL2 Link D locked\n"); } } else { // GMSL1 Link D - maxim4c_i2c_read_reg(client, 0x0ECB, &link_lock); + for (i = 0; i < 3; i++) { + ret = maxim4c_i2c_read_reg(client, 0x0ECB, &link_lock); + if (ret) { + dev_info(dev, "GMSL1 Link D get lock retry (%d)", i); + usleep_range(10000, 10100); + } else { + break; + } + } if (link_lock & BIT(0)) { lock_state |= MAXIM4C_LINK_MASK_D; dev_dbg(dev, "GMSL1 Link D locked\n"); @@ -281,6 +344,9 @@ u8 maxim4c_link_get_lock_state(maxim4c_t *maxim4c, u8 link_mask) gmsl_link->link_locked_mask &= ~MAXIM4C_LINK_MASK_D; } + dev_dbg(dev, "%s, link_mask = 0x%02x, lock_state = 0x%02x\n", + __func__, link_mask, lock_state); + return lock_state; } EXPORT_SYMBOL(maxim4c_link_get_lock_state);