media: i2c: maxim: driver version v3.08.00

Signed-off-by: Cai Wenzhong <cwz@rock-chips.com>
Change-Id: Ibec66444cfa38d5f0caca064a5b663b030a430d9
This commit is contained in:
Cai Wenzhong
2024-07-19 14:43:51 +08:00
committed by Tao Huang
parent 1039ad08c2
commit f4760e0891
4 changed files with 154 additions and 22 deletions

View File

@@ -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 <linux/clk.h>
#include <linux/i2c.h>
@@ -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);

View File

@@ -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);

View File

@@ -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 <linux/clk.h>
#include <linux/i2c.h>
@@ -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);

View File

@@ -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);