-
Notifications
You must be signed in to change notification settings - Fork 30
Enhance DS5 sensor configuration with retry logic for I2C operations and caching of parameters #348
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -419,6 +419,17 @@ struct ds5_sensor { | |||||||||||||||||||||
| const struct ds5_format *formats; | ||||||||||||||||||||||
| unsigned int n_formats; | ||||||||||||||||||||||
| int pipe_id; | ||||||||||||||||||||||
| int last_pipe_id; | ||||||||||||||||||||||
| u16 pipe_data_type1; | ||||||||||||||||||||||
| u16 pipe_data_type2; | ||||||||||||||||||||||
| u32 pipe_vc_id; | ||||||||||||||||||||||
| bool pipe_configured; | ||||||||||||||||||||||
| u16 cached_dt_value; | ||||||||||||||||||||||
| u16 cached_md_value; | ||||||||||||||||||||||
| u16 cached_override_value; | ||||||||||||||||||||||
| u16 cached_fps_value; | ||||||||||||||||||||||
| u16 cached_width_value; | ||||||||||||||||||||||
| u16 cached_height_value; | ||||||||||||||||||||||
| }; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| #ifdef CONFIG_TEGRA_CAMERA_PLATFORM | ||||||||||||||||||||||
|
|
@@ -536,6 +547,8 @@ static int ds5_write(struct ds5 *state, u16 reg, u16 val) | |||||||||||||||||||||
| { | ||||||||||||||||||||||
| int ret; | ||||||||||||||||||||||
| u8 value[2]; | ||||||||||||||||||||||
| int retry; | ||||||||||||||||||||||
| int delay_ms = 10; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| value[1] = val >> 8; | ||||||||||||||||||||||
| value[0] = val & 0x00FF; | ||||||||||||||||||||||
|
|
@@ -544,7 +557,28 @@ static int ds5_write(struct ds5 *state, u16 reg, u16 val) | |||||||||||||||||||||
| "%s(): writing to register: 0x%04x, value1: 0x%x, value2:0x%x\n", | ||||||||||||||||||||||
| __func__, reg, value[1], value[0]); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| ret = regmap_raw_write(state->regmap, reg, value, sizeof(value)); | ||||||||||||||||||||||
| for (retry = 0; retry < 3; retry++) { | ||||||||||||||||||||||
| ret = regmap_raw_write(state->regmap, reg, value, sizeof(value)); | ||||||||||||||||||||||
| if (ret == 0) | ||||||||||||||||||||||
| break; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /* Retry only on timeout/remote IO errors */ | ||||||||||||||||||||||
| if (ret != -ETIMEDOUT && ret != -EREMOTEIO) { | ||||||||||||||||||||||
| dev_err(&state->client->dev, | ||||||||||||||||||||||
| "%s(): i2c write failed %d, 0x%04x = 0x%x\n", | ||||||||||||||||||||||
| __func__, ret, reg, val); | ||||||||||||||||||||||
| return ret; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if (retry < 2) { | ||||||||||||||||||||||
| dev_dbg(&state->client->dev, | ||||||||||||||||||||||
| "%s(): retry %d after %dms delay, 0x%04x\n", | ||||||||||||||||||||||
| __func__, retry + 1, delay_ms, reg); | ||||||||||||||||||||||
| msleep(delay_ms); | ||||||||||||||||||||||
| delay_ms *= 2; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if (ret < 0) | ||||||||||||||||||||||
| dev_err(&state->client->dev, | ||||||||||||||||||||||
| "%s(): i2c write failed %d, 0x%04x = 0x%x\n", | ||||||||||||||||||||||
|
|
@@ -560,7 +594,32 @@ static int ds5_write(struct ds5 *state, u16 reg, u16 val) | |||||||||||||||||||||
| static int ds5_raw_write(struct ds5 *state, u16 reg, | ||||||||||||||||||||||
| const void *val, size_t val_len) | ||||||||||||||||||||||
| { | ||||||||||||||||||||||
| int ret = regmap_raw_write(state->regmap, reg, val, val_len); | ||||||||||||||||||||||
| int ret; | ||||||||||||||||||||||
| int retry; | ||||||||||||||||||||||
| int delay_ms = 10; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| for (retry = 0; retry < 3; retry++) { | ||||||||||||||||||||||
| ret = regmap_raw_write(state->regmap, reg, val, val_len); | ||||||||||||||||||||||
| if (ret == 0) | ||||||||||||||||||||||
| break; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /* Retry only on timeout/remote IO errors */ | ||||||||||||||||||||||
| if (ret != -ETIMEDOUT && ret != -EREMOTEIO) { | ||||||||||||||||||||||
| dev_err(&state->client->dev, | ||||||||||||||||||||||
| "%s(): i2c raw write failed %d, %04x size(%d) bytes\n", | ||||||||||||||||||||||
| __func__, ret, reg, (int)val_len); | ||||||||||||||||||||||
| return ret; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if (retry < 2) { | ||||||||||||||||||||||
| dev_dbg(&state->client->dev, | ||||||||||||||||||||||
| "%s(): retry %d after %dms delay, 0x%04x\n", | ||||||||||||||||||||||
| __func__, retry + 1, delay_ms, reg); | ||||||||||||||||||||||
| msleep(delay_ms); | ||||||||||||||||||||||
| delay_ms *= 2; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if (ret < 0) | ||||||||||||||||||||||
| dev_err(&state->client->dev, | ||||||||||||||||||||||
| "%s(): i2c raw write failed %d, %04x size(%d) bytes\n", | ||||||||||||||||||||||
|
|
@@ -576,7 +635,31 @@ static int ds5_raw_write(struct ds5 *state, u16 reg, | |||||||||||||||||||||
|
|
||||||||||||||||||||||
| static int ds5_read(struct ds5 *state, u16 reg, u16 *val) | ||||||||||||||||||||||
| { | ||||||||||||||||||||||
| int ret = regmap_raw_read(state->regmap, reg, val, 2); | ||||||||||||||||||||||
| int ret; | ||||||||||||||||||||||
| int retry; | ||||||||||||||||||||||
| int delay_ms = 10; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| for (retry = 0; retry < 3; retry++) { | ||||||||||||||||||||||
| ret = regmap_raw_read(state->regmap, reg, val, 2); | ||||||||||||||||||||||
| if (ret == 0) | ||||||||||||||||||||||
| break; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /* Retry only on timeout/remote IO errors */ | ||||||||||||||||||||||
| if (ret != -ETIMEDOUT && ret != -EREMOTEIO) { | ||||||||||||||||||||||
| dev_err(&state->client->dev, "%s(): i2c read failed %d, 0x%04x\n", | ||||||||||||||||||||||
| __func__, ret, reg); | ||||||||||||||||||||||
| return ret; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if (retry < 2) { | ||||||||||||||||||||||
| dev_dbg(&state->client->dev, | ||||||||||||||||||||||
| "%s(): retry %d after %dms delay, 0x%04x\n", | ||||||||||||||||||||||
| __func__, retry + 1, delay_ms, reg); | ||||||||||||||||||||||
| msleep(delay_ms); | ||||||||||||||||||||||
| delay_ms *= 2; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if (ret < 0) | ||||||||||||||||||||||
| dev_err(&state->client->dev, "%s(): i2c read failed %d, 0x%04x\n", | ||||||||||||||||||||||
| __func__, ret, reg); | ||||||||||||||||||||||
|
|
@@ -1827,6 +1910,11 @@ static int ds5_configure(struct ds5 *state) | |||||||||||||||||||||
| u16 data_type1, data_type2; | ||||||||||||||||||||||
| #endif | ||||||||||||||||||||||
| u16 dt_addr, md_addr, override_addr, fps_addr, width_addr, height_addr; | ||||||||||||||||||||||
| u16 dt_value = 0; | ||||||||||||||||||||||
| u16 md_value = 0; | ||||||||||||||||||||||
| u16 fps_value = 0; | ||||||||||||||||||||||
| u16 width_value = 0; | ||||||||||||||||||||||
| u16 height_value = 0; | ||||||||||||||||||||||
| int ret; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if (state->is_depth) { | ||||||||||||||||||||||
|
|
@@ -1878,14 +1966,31 @@ static int ds5_configure(struct ds5 *state) | |||||||||||||||||||||
| data_type2 = state->is_imu ? 0x00 : md_fmt; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| vc_id = state->g_ctx.dst_vc; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| ret = ds5_setup_pipeline(state, data_type1, data_type2, sensor->pipe_id, | ||||||||||||||||||||||
| vc_id); | ||||||||||||||||||||||
| // reset data path when switching to Y12I | ||||||||||||||||||||||
| if (state->is_y8 && data_type1 == GMSL_CSI_DT_RGB_888) | ||||||||||||||||||||||
| max9296_reset_oneshot(state->dser_dev); | ||||||||||||||||||||||
| if (ret < 0) | ||||||||||||||||||||||
| return ret; | ||||||||||||||||||||||
| if (!sensor->pipe_configured || | ||||||||||||||||||||||
| sensor->pipe_id != sensor->last_pipe_id || | ||||||||||||||||||||||
| sensor->pipe_data_type1 != data_type1 || | ||||||||||||||||||||||
| sensor->pipe_data_type2 != data_type2 || | ||||||||||||||||||||||
| sensor->pipe_vc_id != vc_id) { | ||||||||||||||||||||||
| ret = ds5_setup_pipeline(state, data_type1, data_type2, | ||||||||||||||||||||||
| sensor->pipe_id, vc_id); | ||||||||||||||||||||||
| // reset data path when switching to Y12I | ||||||||||||||||||||||
| if (state->is_y8 && data_type1 == GMSL_CSI_DT_RGB_888) | ||||||||||||||||||||||
| max9296_reset_oneshot(state->dser_dev); | ||||||||||||||||||||||
| if (ret < 0) | ||||||||||||||||||||||
| return ret; | ||||||||||||||||||||||
| sensor->pipe_configured = true; | ||||||||||||||||||||||
| sensor->last_pipe_id = sensor->pipe_id; | ||||||||||||||||||||||
| sensor->pipe_data_type1 = data_type1; | ||||||||||||||||||||||
| sensor->pipe_data_type2 = data_type2; | ||||||||||||||||||||||
| sensor->pipe_vc_id = vc_id; | ||||||||||||||||||||||
| dev_warn(&state->client->dev, | ||||||||||||||||||||||
| "pipe %d configured (dt1=0x%x dt2=0x%x vc=%u)\n", | ||||||||||||||||||||||
| sensor->pipe_id, data_type1, data_type2, vc_id); | ||||||||||||||||||||||
| } else { | ||||||||||||||||||||||
| dev_warn(&state->client->dev, | ||||||||||||||||||||||
|
Comment on lines
+1986
to
+1990
|
||||||||||||||||||||||
| dev_warn(&state->client->dev, | |
| "pipe %d configured (dt1=0x%x dt2=0x%x vc=%u)\n", | |
| sensor->pipe_id, data_type1, data_type2, vc_id); | |
| } else { | |
| dev_warn(&state->client->dev, | |
| dev_dbg(&state->client->dev, | |
| "pipe %d configured (dt1=0x%x dt2=0x%x vc=%u)\n", | |
| sensor->pipe_id, data_type1, data_type2, vc_id); | |
| } else { | |
| dev_dbg(&state->client->dev, |
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cache fields appear to rely on default initialization, which can cause the very first write to be skipped when the desired value is 0 (e.g., dt_value == 0 and cached_dt_value defaults to 0). That changes behavior from always writing to potentially never programming the register. Fix by initializing cached_* to an invalid sentinel (e.g., 0xFFFF for u16, 0xFFFFFFFF for u32) or by adding per-field 'valid' flags so the first configuration always writes.
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On stream stop / pipe release you invalidate pipe_configured/last_pipe_id, but the cached register values (cached_dt_value, cached_md_value, cached_override_value, cached_fps_value, cached_width_value, cached_height_value) are left intact. If the device/firmware loses state across stop/start (or if registers are reset elsewhere), ds5_configure() may skip required writes and leave hardware misconfigured. Consider explicitly invalidating all cached_* fields here (and in the corresponding stream-on reset path) by setting them back to the sentinel/invalid state (or clearing 'valid' flags).
| sensor->pipe_configured = false; | |
| sensor->pipe_configured = false; | |
| sensor->cached_dt_value = -1; | |
| sensor->cached_md_value = -1; | |
| sensor->cached_override_value = -1; | |
| sensor->cached_fps_value = -1; | |
| sensor->cached_width_value = -1; | |
| sensor->cached_height_value = -1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The retry/backoff logic is duplicated across ds5_write(), ds5_raw_write(), and ds5_read(). To reduce the chance of these drifting (different retry counts, delays, error handling, log messages), consider factoring the common retry policy into a shared helper (e.g., a small internal function that accepts an op callback or separate helpers for read/write) and reuse it in all three call sites.