Skip to content

Commit 11783a5

Browse files
committed
drivers: video: emul-imager: use the emulated I2C bus
Replace the ad-hoc register emulation by the dedicated I2C emulator, making it usable with the same APIs as every other image sensors. Signed-off-by: Josuah Demangeon <[email protected]>
1 parent c53fb67 commit 11783a5

File tree

4 files changed

+92
-55
lines changed

4 files changed

+92
-55
lines changed

drivers/video/Kconfig.emul_imager

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ config VIDEO_EMUL_IMAGER
55
bool "Software implementation of an imager"
66
depends on DT_HAS_ZEPHYR_VIDEO_EMUL_IMAGER_ENABLED
77
default y
8+
depends on EMUL
89
help
910
Enable driver for the emulated Imager. A line buffer contains
1011
the color pattern within the imager data struct, at the first

drivers/video/video_emul_imager.c

+73-32
Original file line numberDiff line numberDiff line change
@@ -15,30 +15,28 @@
1515
#include <zephyr/drivers/video.h>
1616
#include <zephyr/drivers/video-controls.h>
1717
#include <zephyr/drivers/i2c.h>
18+
#include <zephyr/drivers/i2c_emul.h>
1819
#include <zephyr/logging/log.h>
1920

2021
LOG_MODULE_REGISTER(video_emul_imager, CONFIG_VIDEO_LOG_LEVEL);
2122

22-
#define EMUL_IMAGER_REG_SENSOR_ID 0x0000
23+
#define EMUL_IMAGER_REG_SENSOR_ID 0x00
2324
#define EMUL_IMAGER_SENSOR_ID 0x99
24-
#define EMUL_IMAGER_REG_CTRL 0x0001
25-
#define EMUL_IMAGER_REG_INIT1 0x0002
26-
#define EMUL_IMAGER_REG_INIT2 0x0003
27-
#define EMUL_IMAGER_REG_TIMING1 0x0004
28-
#define EMUL_IMAGER_REG_TIMING2 0x0005
29-
#define EMUL_IMAGER_REG_TIMING3 0x0006
30-
#define EMUL_IMAGER_REG_CUSTOM 0x0007
31-
#define EMUL_IMAGER_REG_FORMAT 0x000a
25+
#define EMUL_IMAGER_REG_CTRL 0x01
26+
#define EMUL_IMAGER_REG_INIT1 0x02
27+
#define EMUL_IMAGER_REG_INIT2 0x03
28+
#define EMUL_IMAGER_REG_TIMING1 0x04
29+
#define EMUL_IMAGER_REG_TIMING2 0x05
30+
#define EMUL_IMAGER_REG_TIMING3 0x06
31+
#define EMUL_IMAGER_REG_CUSTOM 0x07
32+
#define EMUL_IMAGER_REG_FORMAT 0x0a
3233
#define EMUL_IMAGER_PATTERN_OFF 0x00
3334
#define EMUL_IMAGER_PATTERN_BARS1 0x01
3435
#define EMUL_IMAGER_PATTERN_BARS2 0x02
3536

3637
/* Custom control that is just an I2C write for example and test purpose */
3738
#define EMUL_IMAGER_CID_CUSTOM (VIDEO_CID_PRIVATE_BASE + 0x01)
3839

39-
/* Emulated register bank */
40-
uint8_t emul_imager_fake_regs[10];
41-
4240
enum emul_imager_fmt_id {
4341
RGB565_320x240,
4442
YUYV_320x240,
@@ -78,10 +76,10 @@ static const struct emul_imager_reg emul_imager_init_regs[] = {
7876
{EMUL_IMAGER_REG_INIT1, 0x10},
7977
{EMUL_IMAGER_REG_INIT2, 0x00},
8078
/* Undocumented registers from the vendor */
81-
{0x1200, 0x01},
82-
{0x1204, 0x01},
83-
{0x1205, 0x20},
84-
{0x1209, 0x7f},
79+
{0x80, 0x01},
80+
{0x84, 0x01},
81+
{0x85, 0x20},
82+
{0x89, 0x7f},
8583
{0},
8684
};
8785
static const struct emul_imager_reg emul_imager_rgb565[] = {
@@ -152,21 +150,15 @@ static const struct video_format_cap fmts[] = {
152150
/* Emulated I2C register interface, to replace with actual I2C calls for real hardware */
153151
static int emul_imager_read_reg(const struct device *const dev, uint8_t reg_addr, uint8_t *value)
154152
{
155-
LOG_DBG("Placeholder for I2C read from 0x%02x", reg_addr);
156-
switch (reg_addr) {
157-
case EMUL_IMAGER_REG_SENSOR_ID:
158-
*value = EMUL_IMAGER_SENSOR_ID;
159-
break;
160-
default:
161-
*value = emul_imager_fake_regs[reg_addr];
162-
}
163-
return 0;
153+
const struct emul_imager_config *cfg = dev->config;
154+
155+
return i2c_write_read_dt(&cfg->i2c, &reg_addr, 1, value, 1);
164156
}
165157

166158
/* Helper to read a full integer directly from a register */
167159
static int emul_imager_read_int(const struct device *const dev, uint8_t reg_addr, int *value)
168160
{
169-
uint8_t val8;
161+
uint8_t val8 = 0;
170162
int ret;
171163

172164
ret = emul_imager_read_reg(dev, reg_addr, &val8);
@@ -177,9 +169,10 @@ static int emul_imager_read_int(const struct device *const dev, uint8_t reg_addr
177169
/* Some sensors will need reg8 or reg16 variants. */
178170
static int emul_imager_write_reg(const struct device *const dev, uint8_t reg_addr, uint8_t value)
179171
{
180-
LOG_DBG("Placeholder for I2C write 0x%08x to 0x%02x", value, reg_addr);
181-
emul_imager_fake_regs[reg_addr] = value;
182-
return 0;
172+
const struct emul_imager_config *cfg = dev->config;
173+
uint8_t buf_w[] = {reg_addr, value};
174+
175+
return i2c_write_dt(&cfg->i2c, buf_w, 2);
183176
}
184177

185178
static int emul_imager_write_multi(const struct device *const dev,
@@ -383,12 +376,13 @@ static DEVICE_API(video, emul_imager_driver_api) = {
383376

384377
int emul_imager_init(const struct device *dev)
385378
{
379+
const struct emul_imager_config *cfg = dev->config;
386380
struct video_format fmt;
387381
uint8_t sensor_id;
388382
int ret;
389383

390-
if (/* !i2c_is_ready_dt(&cfg->i2c) */ false) {
391-
/* LOG_ERR("Bus %s is not ready", cfg->i2c.bus->name); */
384+
if (!i2c_is_ready_dt(&cfg->i2c)) {
385+
LOG_ERR("Bus %s is not ready", cfg->i2c.bus->name);
392386
return -ENODEV;
393387
}
394388

@@ -422,11 +416,58 @@ int emul_imager_init(const struct device *dev)
422416
static struct emul_imager_data emul_imager_data_##inst; \
423417
\
424418
static const struct emul_imager_config emul_imager_cfg_##inst = { \
425-
.i2c = /* I2C_DT_SPEC_INST_GET(inst) */ {0}, \
419+
.i2c = I2C_DT_SPEC_INST_GET(inst), \
426420
}; \
427421
\
428422
DEVICE_DT_INST_DEFINE(inst, &emul_imager_init, NULL, &emul_imager_data_##inst, \
429423
&emul_imager_cfg_##inst, POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, \
430424
&emul_imager_driver_api);
431425

432426
DT_INST_FOREACH_STATUS_OKAY(EMUL_IMAGER_DEFINE)
427+
428+
/* Simulated I2C bus */
429+
430+
static int emul_imager_transfer_i2c(const struct emul *target, struct i2c_msg msgs[], int num_msgs,
431+
int addr)
432+
{
433+
static uint8_t fake_regs[UINT8_MAX] = {
434+
[EMUL_IMAGER_REG_SENSOR_ID] = EMUL_IMAGER_SENSOR_ID,
435+
};
436+
437+
if (num_msgs == 0) {
438+
CODE_UNREACHABLE;
439+
} else if (num_msgs == 1 &&
440+
msgs[0].len == 2 && (msgs[0].flags & I2C_MSG_READ) == 0) {
441+
/* Register write */
442+
fake_regs[msgs[0].buf[0]] = msgs[0].buf[1];
443+
} else if (num_msgs == 2 &&
444+
msgs[0].len == 1 && (msgs[0].flags & I2C_MSG_READ) == 0 &&
445+
msgs[1].len == 1 && (msgs[1].flags & I2C_MSG_READ) == 0) {
446+
/* Register write */
447+
fake_regs[msgs[0].buf[0]] = msgs[1].buf[0];
448+
} else if (num_msgs == 2 &&
449+
msgs[0].len == 1 && (msgs[0].flags & I2C_MSG_READ) == 0 &&
450+
msgs[1].len == 1 && (msgs[1].flags & I2C_MSG_READ) != 0) {
451+
/* Register read */
452+
msgs[1].buf[0] = fake_regs[msgs[0].buf[0]];
453+
} else {
454+
LOG_ERR("Unsupported I2C operation of %u messages", num_msgs);
455+
return -EIO;
456+
}
457+
458+
return 0;
459+
}
460+
461+
static const struct i2c_emul_api emul_imager_i2c_api = {
462+
.transfer = emul_imager_transfer_i2c,
463+
};
464+
465+
static int emul_imager_init_i2c(const struct emul *target, const struct device *dev)
466+
{
467+
return 0;
468+
}
469+
470+
#define EMUL_I2C_DEFINE(inst) \
471+
EMUL_DT_INST_DEFINE(inst, &emul_imager_init_i2c, NULL, NULL, &emul_imager_i2c_api, NULL);
472+
473+
DT_INST_FOREACH_STATUS_OKAY(EMUL_I2C_DEFINE)

tests/drivers/video/api/app.overlay

+16-23
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2024 tinyVision.ai Inc.
2+
* Copyright (c) 2024-2025 tinyVision.ai Inc.
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

@@ -8,31 +8,9 @@
88
#address-cells = <1>;
99
#size-cells = <1>;
1010

11-
test_i2c: i2c@10002000 {
12-
#address-cells = <1>;
13-
#size-cells = <0>;
14-
compatible = "vnd,i2c";
15-
reg = <0x10002000 0x1000>;
16-
clock-frequency = <100000>;
17-
status = "okay";
18-
19-
test_video_emul_imager: video_emul_imager@6 {
20-
compatible = "zephyr,video-emul-imager";
21-
status = "okay";
22-
reg = <0x6>;
23-
24-
port {
25-
test_video_emul_imager_ep_out: endpoint {
26-
remote-endpoint-label = "test_video_emul_rx_ep_in";
27-
};
28-
};
29-
};
30-
};
31-
3211
test_video_emul_rx: video_emul_rx@10003000 {
3312
compatible = "zephyr,video-emul-rx";
3413
reg = <0x10003000 0x1000>;
35-
status = "okay";
3614

3715
port {
3816
#address-cells = <1>;
@@ -51,3 +29,18 @@
5129
};
5230
};
5331
};
32+
33+
&i2c0 {
34+
status = "okay";
35+
36+
test_video_emul_imager: video_emul_imager@6 {
37+
compatible = "zephyr,video-emul-imager";
38+
reg = <0x6>;
39+
40+
port {
41+
test_video_emul_imager_ep_out: endpoint {
42+
remote-endpoint-label = "test_video_emul_rx_ep_in";
43+
};
44+
};
45+
};
46+
};

tests/drivers/video/api/prj.conf

+2
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@ CONFIG_VIDEO_BUFFER_POOL_NUM_MAX=1
99
CONFIG_SYS_HEAP_BIG_ONLY=y
1010

1111
CONFIG_VIDEO_LOG_LEVEL_DBG=y
12+
CONFIG_EMUL=y
13+
CONFIG_I2C=y

0 commit comments

Comments
 (0)