From 7a57a31056ab4a7c170232e68cd185173030a951 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Wed, 2 Apr 2025 11:55:01 +0200 Subject: [PATCH 1/4] dts: bindings: video: imx335: addition of imx335 description Introduction of bindings for the imx335 sensor. Signed-off-by: Alain Volmat --- dts/bindings/video/sony,imx335.yaml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 dts/bindings/video/sony,imx335.yaml diff --git a/dts/bindings/video/sony,imx335.yaml b/dts/bindings/video/sony,imx335.yaml new file mode 100644 index 000000000000..94e5c6081b7c --- /dev/null +++ b/dts/bindings/video/sony,imx335.yaml @@ -0,0 +1,23 @@ +# Copyright (c) 2025 STMicroelectronics. +# SPDX-License-Identifier: Apache-2.0 + +description: IMX335 CMOS Solid-state Color Image Sensor + +compatible: "sony,imx335" + +include: i2c-device.yaml + +properties: + clocks: + description: Reference Input clock + required: true + + reset-gpios: + type: phandle-array + description: | + The XCLR pin is asserted to cause a hard reset. The sensor + receives this as an active-low signal. + +child-binding: + child-binding: + include: video-interfaces.yaml From cf9aa8ea6bb08fff6ec4cb94b1f5ed769597add0 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Wed, 2 Apr 2025 11:58:24 +0200 Subject: [PATCH 2/4] drivers: video: introduction of imx335 sensor driver Add support for the Sony IMX335 CSI sensor. This sensor supports resolution of 2592x1944 in RGGB bayer format either 10 or 12 bits and using 2 or 4 CSI lanes. For the time being only 10 bits on 2 CSI lanes is supported via this commit. Signed-off-by: Alain Volmat --- drivers/video/CMakeLists.txt | 1 + drivers/video/Kconfig | 2 + drivers/video/Kconfig.imx335 | 12 + drivers/video/imx335.c | 521 ++++++++++++++++++++++ tests/drivers/build_all/video/app.overlay | 12 + 5 files changed, 548 insertions(+) create mode 100644 drivers/video/Kconfig.imx335 create mode 100644 drivers/video/imx335.c diff --git a/drivers/video/CMakeLists.txt b/drivers/video/CMakeLists.txt index 96529ddfa75f..c74d186e03aa 100644 --- a/drivers/video/CMakeLists.txt +++ b/drivers/video/CMakeLists.txt @@ -21,5 +21,6 @@ zephyr_library_sources_ifdef(CONFIG_VIDEO_ESP32 video_esp32_dvp.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_MCUX_SDMA video_mcux_smartdma.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_EMUL_IMAGER video_emul_imager.c) zephyr_library_sources_ifdef(CONFIG_VIDEO_EMUL_RX video_emul_rx.c) +zephyr_library_sources_ifdef(CONFIG_VIDEO_IMX335 imx335.c) zephyr_linker_sources(DATA_SECTIONS video.ld) diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 3595afdcab6f..e0ec36e2c90e 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -88,4 +88,6 @@ source "drivers/video/Kconfig.emul_imager" source "drivers/video/Kconfig.emul_rx" +source "drivers/video/Kconfig.imx335" + endif # VIDEO diff --git a/drivers/video/Kconfig.imx335 b/drivers/video/Kconfig.imx335 new file mode 100644 index 000000000000..adecbce2d3ad --- /dev/null +++ b/drivers/video/Kconfig.imx335 @@ -0,0 +1,12 @@ +# IMX335 + +# Copyright (c) 2025 STMicroelectronics. +# SPDX-License-Identifier: Apache-2.0 + +config VIDEO_IMX335 + bool "IMX335 CMOS digital image sensor" + select I2C + depends on DT_HAS_SONY_IMX335_ENABLED + default y + help + Enable driver for IMX335 CMOS digital image sensor device diff --git a/drivers/video/imx335.c b/drivers/video/imx335.c new file mode 100644 index 000000000000..c2f0c37760c2 --- /dev/null +++ b/drivers/video/imx335.c @@ -0,0 +1,521 @@ +/* + * Copyright (c) 2025 STMicroelectronics. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT sony_imx335 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "video_common.h" +#include "video_ctrls.h" +#include "video_device.h" + +LOG_MODULE_REGISTER(video_imx335, CONFIG_VIDEO_LOG_LEVEL); + +#define IMX335_WIDTH 2592 +#define IMX335_HEIGHT 1944 + +#define IMX335_PIXEL_RATE 396000000 + +struct imx335_config { + struct i2c_dt_spec i2c; + struct gpio_dt_spec reset_gpio; + uint32_t input_clk; +}; + +struct imx335_ctrls { + struct video_ctrl gain; + struct video_ctrl exposure; + struct video_ctrl pixel_rate; +}; + +struct imx335_data { + struct imx335_ctrls ctrls; + struct video_format fmt; +}; + +#define IMX335_REG8(addr) ((addr) | VIDEO_REG_ADDR16_DATA8) +#define IMX335_REG16(addr) ((addr) | VIDEO_REG_ADDR16_DATA16_LE) +#define IMX335_REG24(addr) ((addr) | VIDEO_REG_ADDR16_DATA24_LE) + +#define IMX335_STANDBY IMX335_REG8(0x3000) +#define IMX335_STANDBY_OPERATING 0x00 +#define IMX335_STANDBY_STANDBY BIT(0) +#define IMX335_REGHOLD IMX335_REG8(0x3001) +#define IMX335_XMSTA IMX335_REG8(0x3002) +#define IMX335_BCWAIT_TIME IMX335_REG8(0x300c) +#define IMX335_CPWAIT_TIME IMX335_REG8(0x300d) +#define IMX335_WINMODE IMX335_REG8(0x3018) +#define IMX335_HTRIMMING_START IMX335_REG16(0x302c) +#define IMX335_HNUM IMX335_REG16(0x302e) +#define IMX335_VMAX IMX335_REG24(0x3030) +#define IMX335_VMAX_DEFAULT 4500 +#define IMX335_OPB_SIZE_V IMX335_REG8(0x304c) +#define IMX335_ADBIT IMX335_REG8(0x3050) +#define IMX335_Y_OUT_SIZE IMX335_REG16(0x3056) +#define IMX335_SHR0 IMX335_REG24(0x3058) +#define IMX335_SHR0_MIN 9 +#define IMX335_AREA3_ST_ADR_1 IMX335_REG16(0x3074) +#define IMX335_AREA3_WIDTH_1 IMX335_REG16(0x3076) +#define IMX335_GAIN IMX335_REG16(0x30e8) +#define IMX335_GAIN_MIN (0 * 1000) +#define IMX335_GAIN_MAX (72 * 1000) +#define IMX335_GAIN_UNIT_MDB 300 +#define IMX335_INCKSEL1 IMX335_REG16(0x314c) +#define IMX335_INCKSEL2_PLL_IF_GC IMX335_REG8(0x315a) +#define IMX335_INCKSEL3 IMX335_REG8(0x3168) +#define IMX335_INCKSEL4 IMX335_REG8(0x316a) +#define IMX335_MDBIT IMX335_REG8(0x319d) +#define IMX335_XVS_XHS_DRV IMX335_REG8(0x31a1) +#define IMX335_ADBIT1 IMX335_REG16(0x341c) +#define IMX335_LANEMODE IMX335_REG8(0x3a01) +static const struct video_reg imx335_init_params[] = { + {IMX335_STANDBY, 0x01}, + {IMX335_XMSTA, 0x00}, + {IMX335_WINMODE, 0x04}, + {IMX335_HTRIMMING_START, 0x3c}, + {IMX335_HNUM, 0x0a20}, + {IMX335_OPB_SIZE_V, 0x00}, + {IMX335_Y_OUT_SIZE, 0x0798}, + {IMX335_AREA3_ST_ADR_1, 0x00c8}, + {IMX335_AREA3_WIDTH_1, 0x0f30}, + {IMX335_XVS_XHS_DRV, 0x00}, +}; + +static const struct video_reg16 imx335_fixed_regs[] = { + {0x3288, 0x21}, + {0x328a, 0x02}, + {0x3414, 0x05}, + {0x3416, 0x18}, + {0x3648, 0x01}, + {0x364a, 0x04}, + {0x364c, 0x04}, + {0x3678, 0x01}, + {0x367c, 0x31}, + {0x367e, 0x31}, + {0x3706, 0x10}, + {0x3708, 0x03}, + {0x3714, 0x02}, + {0x3715, 0x02}, + {0x3716, 0x01}, + {0x3717, 0x03}, + {0x371c, 0x3d}, + {0x371d, 0x3f}, + {0x372c, 0x00}, + {0x372d, 0x00}, + {0x372e, 0x46}, + {0x372f, 0x00}, + {0x3730, 0x89}, + {0x3731, 0x00}, + {0x3732, 0x08}, + {0x3733, 0x01}, + {0x3734, 0xfe}, + {0x3735, 0x05}, + {0x3740, 0x02}, + {0x375d, 0x00}, + {0x375e, 0x00}, + {0x375f, 0x11}, + {0x3760, 0x01}, + {0x3768, 0x1b}, + {0x3769, 0x1b}, + {0x376a, 0x1b}, + {0x376b, 0x1b}, + {0x376c, 0x1a}, + {0x376d, 0x17}, + {0x376e, 0x0f}, + {0x3776, 0x00}, + {0x3777, 0x00}, + {0x3778, 0x46}, + {0x3779, 0x00}, + {0x377a, 0x89}, + {0x377b, 0x00}, + {0x377c, 0x08}, + {0x377d, 0x01}, + {0x377e, 0x23}, + {0x377f, 0x02}, + {0x3780, 0xd9}, + {0x3781, 0x03}, + {0x3782, 0xf5}, + {0x3783, 0x06}, + {0x3784, 0xa5}, + {0x3788, 0x0f}, + {0x378a, 0xd9}, + {0x378b, 0x03}, + {0x378c, 0xeb}, + {0x378d, 0x05}, + {0x378e, 0x87}, + {0x378f, 0x06}, + {0x3790, 0xf5}, + {0x3792, 0x43}, + {0x3794, 0x7a}, + {0x3796, 0xa1}, + {0x37b0, 0x36}, + {0x3a00, 0x01}, +}; + +static const struct video_reg imx335_mode_2l_10b[] = { + {IMX335_ADBIT, 0x00}, + {IMX335_MDBIT, 0x00}, + {IMX335_ADBIT1, 0x01ff}, + {IMX335_LANEMODE, 0x01}, +}; + +static const struct video_reg imx335_inck_74mhz[] = { + {IMX335_BCWAIT_TIME, 0xb6}, + {IMX335_CPWAIT_TIME, 0x7f}, + {IMX335_INCKSEL1, 0x80}, + {IMX335_INCKSEL2_PLL_IF_GC, 0x03}, + {IMX335_INCKSEL3, 0x68}, + {IMX335_INCKSEL4, 0x7f}, +}; + +static const struct video_reg imx335_inck_27mhz[] = { + {IMX335_BCWAIT_TIME, 0x42}, + {IMX335_CPWAIT_TIME, 0x2e}, + {IMX335_INCKSEL1, 0xb0}, + {IMX335_INCKSEL2_PLL_IF_GC, 0x02}, + {IMX335_INCKSEL3, 0x8f}, + {IMX335_INCKSEL4, 0x7e}, +}; + +static const struct video_reg imx335_inck_24mhz[] = { + {IMX335_BCWAIT_TIME, 0x3b}, + {IMX335_CPWAIT_TIME, 0x2a}, + {IMX335_INCKSEL1, 0xc6}, + {IMX335_INCKSEL2_PLL_IF_GC, 0x02}, + {IMX335_INCKSEL3, 0xa0}, + {IMX335_INCKSEL4, 0x7e}, +}; + +static const struct video_reg imx335_inck_18mhz[] = { + {IMX335_BCWAIT_TIME, 0x2d}, + {IMX335_CPWAIT_TIME, 0x1f}, + {IMX335_INCKSEL1, 0x84}, + {IMX335_INCKSEL2_PLL_IF_GC, 0x01}, + {IMX335_INCKSEL3, 0x6b}, + {IMX335_INCKSEL4, 0x7d}, +}; + +static const struct video_reg imx335_inck_6mhz[] = { + {IMX335_BCWAIT_TIME, 0x0f}, + {IMX335_CPWAIT_TIME, 0x0b}, + {IMX335_INCKSEL1, 0xc6}, + {IMX335_INCKSEL2_PLL_IF_GC, 0x00}, + {IMX335_INCKSEL3, 0xa0}, + {IMX335_INCKSEL4, 0x7c}, +}; + +static const struct video_format_cap imx335_fmts[] = { + { + .pixelformat = VIDEO_PIX_FMT_SRGGB10P, + .width_min = IMX335_WIDTH, + .width_max = IMX335_WIDTH, + .height_min = IMX335_HEIGHT, + .height_max = IMX335_HEIGHT, + .width_step = 0, + .height_step = 0, + }, + {0} +}; + +static int imx335_set_fmt(const struct device *dev, struct video_format *fmt) +{ + /* + * Only support RGGB10 for now and resolution is fixed hence only check + * values here + */ + if (fmt->pixelformat != VIDEO_PIX_FMT_SRGGB10P || + fmt->width != IMX335_WIDTH || + fmt->height != IMX335_HEIGHT) { + LOG_ERR("Unsupported pixel format or resolution"); + return -ENOTSUP; + } + + return 0; +} + +static int imx335_get_fmt(const struct device *dev, struct video_format *fmt) +{ + struct imx335_data *drv_data = dev->data; + + *fmt = drv_data->fmt; + + return 0; +} + +static int imx335_get_caps(const struct device *dev, struct video_caps *caps) +{ + caps->format_caps = imx335_fmts; + return 0; +} + +static int imx335_set_stream(const struct device *dev, bool enable, enum video_buf_type type) +{ + const struct imx335_config *cfg = dev->config; + int ret; + + ret = video_write_cci_reg(&cfg->i2c, IMX335_STANDBY, + enable ? IMX335_STANDBY_OPERATING : IMX335_STANDBY_STANDBY); + if (ret) { + LOG_ERR("Failed to set standby register\n"); + return ret; + } + + k_sleep(K_USEC(20)); + + return 0; +} + +static int imx335_set_ctrl_gain(const struct device *dev) +{ + const struct imx335_config *cfg = dev->config; + struct imx335_data *drv_data = dev->data; + struct imx335_ctrls *ctrls = &drv_data->ctrls; + int ret; + + ret = video_write_cci_reg(&cfg->i2c, IMX335_REGHOLD, 1); + if (ret) { + return ret; + } + + /* Apply gain upon conversion to gain unit */ + ret = video_write_cci_reg(&cfg->i2c, IMX335_GAIN, ctrls->gain.val / IMX335_GAIN_UNIT_MDB); + if (ret) { + return ret; + } + + return video_write_cci_reg(&cfg->i2c, IMX335_REGHOLD, 0); +} + +static int imx335_set_ctrl_exposure(const struct device *dev) +{ + const struct imx335_config *cfg = dev->config; + struct imx335_data *drv_data = dev->data; + struct imx335_ctrls *ctrls = &drv_data->ctrls; + int ret; + + ret = video_write_cci_reg(&cfg->i2c, IMX335_REGHOLD, 1); + if (ret) { + return ret; + } + + /* Since we never update VMAX, we can use the default value directly */ + ret = video_write_cci_reg(&cfg->i2c, IMX335_SHR0, + IMX335_VMAX_DEFAULT - ctrls->exposure.val); + if (ret) { + return ret; + } + + return video_write_cci_reg(&cfg->i2c, IMX335_REGHOLD, 0); +} + +static int imx335_set_ctrl(const struct device *dev, unsigned int cid) +{ + switch (cid) { + case VIDEO_CID_ANALOGUE_GAIN: + return imx335_set_ctrl_gain(dev); + case VIDEO_CID_EXPOSURE: + return imx335_set_ctrl_exposure(dev); + default: + return -ENOTSUP; + } +} + +static int imx335_get_frmival(const struct device *dev, struct video_frmival *frmival) +{ + /* Only 30fps is supported right now */ + frmival->numerator = 1; + frmival->denominator = 30; + + return 0; +} + +static int imx335_enum_frmival(const struct device *dev, struct video_frmival_enum *fie) +{ + if (fie->index > 0) { + return -EINVAL; + } + + fie->type = VIDEO_FRMIVAL_TYPE_DISCRETE; + fie->discrete.numerator = 1; + fie->discrete.denominator = 30; + + return 0; +} + +static DEVICE_API(video, imx335_driver_api) = { + .set_format = imx335_set_fmt, + .get_format = imx335_get_fmt, + .get_caps = imx335_get_caps, + .set_stream = imx335_set_stream, + .set_ctrl = imx335_set_ctrl, + /* frmival is fixed, hence set/get_frmival both return 30fps */ + .set_frmival = imx335_get_frmival, + .get_frmival = imx335_get_frmival, + .enum_frmival = imx335_enum_frmival, +}; + +static int imx335_set_input_clk(const struct device *dev, uint32_t rate) +{ + const struct imx335_config *cfg = dev->config; + int ret; + + switch (rate) { + case MHZ(74): + ret = video_write_cci_multiregs(&cfg->i2c, imx335_inck_74mhz, + ARRAY_SIZE(imx335_inck_74mhz)); + break; + case MHZ(27): + ret = video_write_cci_multiregs(&cfg->i2c, imx335_inck_27mhz, + ARRAY_SIZE(imx335_inck_27mhz)); + break; + case MHZ(24): + ret = video_write_cci_multiregs(&cfg->i2c, imx335_inck_24mhz, + ARRAY_SIZE(imx335_inck_24mhz)); + break; + case MHZ(18): + ret = video_write_cci_multiregs(&cfg->i2c, imx335_inck_18mhz, + ARRAY_SIZE(imx335_inck_18mhz)); + break; + case MHZ(6): + ret = video_write_cci_multiregs(&cfg->i2c, imx335_inck_6mhz, + ARRAY_SIZE(imx335_inck_6mhz)); + break; + default: + LOG_ERR("Unsupported inck freq (%d)\n", rate); + ret = -EINVAL; + } + + return ret; +} + +static int imx335_init_controls(const struct device *dev) +{ + int ret; + struct imx335_data *drv_data = dev->data; + struct imx335_ctrls *ctrls = &drv_data->ctrls; + + ret = video_init_ctrl( + &ctrls->gain, dev, VIDEO_CID_ANALOGUE_GAIN, + (struct video_ctrl_range){ + .min = IMX335_GAIN_MIN, + .max = IMX335_GAIN_MAX, + .step = IMX335_GAIN_UNIT_MDB, + .def = 0}); + if (ret) { + return ret; + } + + ret = video_init_ctrl( + &ctrls->exposure, dev, VIDEO_CID_EXPOSURE, + (struct video_ctrl_range){ + .min = 1, + .max = IMX335_VMAX_DEFAULT - IMX335_SHR0_MIN, + .step = 1, + .def = IMX335_VMAX_DEFAULT - IMX335_SHR0_MIN}); + if (ret) { + return ret; + } + + return video_init_ctrl( + &ctrls->pixel_rate, dev, VIDEO_CID_PIXEL_RATE, + (struct video_ctrl_range){ + .min64 = IMX335_PIXEL_RATE, + .max64 = IMX335_PIXEL_RATE, + .step64 = 1, + .def64 = IMX335_PIXEL_RATE}); +} + +static int imx335_init(const struct device *dev) +{ + const struct imx335_config *cfg = dev->config; + int ret; + + if (!device_is_ready(cfg->i2c.bus)) { + LOG_ERR("Bus device is not ready"); + return -ENODEV; + } + + if (!gpio_is_ready_dt(&cfg->reset_gpio)) { + LOG_ERR("%s: device %s is not ready", dev->name, cfg->reset_gpio.port->name); + return -ENODEV; + } + + /* Power up sequence */ + if (cfg->reset_gpio.port) { + ret = gpio_pin_configure_dt(&cfg->reset_gpio, GPIO_OUTPUT_ACTIVE); + if (ret) { + return ret; + } + } + + k_sleep(K_NSEC(500)); /* Tlow */ + + if (cfg->reset_gpio.port) { + gpio_pin_set_dt(&cfg->reset_gpio, 0); + } + + k_sleep(K_USEC(20)); /* T4 */ + + /* Initialize register values */ + ret = video_write_cci_multiregs(&cfg->i2c, imx335_init_params, + ARRAY_SIZE(imx335_init_params)); + if (ret) { + LOG_ERR("Unable to initialize the sensor"); + return ret; + } + + /* Apply the fixed value registers */ + ret = video_write_cci_multiregs16(&cfg->i2c, imx335_fixed_regs, + ARRAY_SIZE(imx335_fixed_regs)); + if (ret) { + LOG_ERR("Unable to initialize the sensor"); + return ret; + } + + /* TODO - Only 10bit - 2 data lanes mode is supported for the time being */ + ret = video_write_cci_multiregs(&cfg->i2c, imx335_mode_2l_10b, + ARRAY_SIZE(imx335_mode_2l_10b)); + if (ret) { + LOG_ERR("Unable to initialize the sensor"); + return ret; + } + + ret = imx335_set_input_clk(dev, cfg->input_clk); + if (ret) { + LOG_ERR("Unable to configure INCK"); + return ret; + } + + return imx335_init_controls(dev); +} + +#define IMX335_INIT(n) \ + static struct imx335_data imx335_data_##n = { \ + .fmt = { \ + .pixelformat = VIDEO_PIX_FMT_SRGGB10P, \ + .width = IMX335_WIDTH, \ + .height = IMX335_HEIGHT, \ + }, \ + }; \ + static const struct imx335_config imx335_cfg_##n = { \ + .i2c = I2C_DT_SPEC_INST_GET(n), \ + .reset_gpio = GPIO_DT_SPEC_INST_GET_OR(n, reset_gpios, {0}), \ + .input_clk = DT_INST_PROP_BY_PHANDLE(n, clocks, clock_frequency), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, &imx335_init, NULL, &imx335_data_##n, &imx335_cfg_##n, \ + POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, &imx335_driver_api); \ + \ + VIDEO_DEVICE_DEFINE(imx335_##n, DEVICE_DT_INST_GET(n), NULL); + +DT_INST_FOREACH_STATUS_OKAY(IMX335_INIT) diff --git a/tests/drivers/build_all/video/app.overlay b/tests/drivers/build_all/video/app.overlay index 84678f7ee069..a533d9433115 100644 --- a/tests/drivers/build_all/video/app.overlay +++ b/tests/drivers/build_all/video/app.overlay @@ -11,6 +11,12 @@ */ / { + imx335_input_clock: imx335-input-clock { + compatible = "fixed-clock"; + clock-frequency = <24000000>; + #clock-cells = <0>; + }; + test { #address-cells = <1>; #size-cells = <1>; @@ -77,6 +83,12 @@ }; }; + test_i2c_imx335: imx335@7 { + compatible = "sony,imx335"; + reg = <0x7>; + clocks = <&imx335_input_clock>; + reset-gpios = <&test_gpio 0 0>; + }; }; test_video_emul_rx: video_emul_rx@10003000 { From d64f4dda3f5eefe37b575347952f0e85eab44c84 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Fri, 9 May 2025 22:34:45 +0200 Subject: [PATCH 3/4] dts: bindings: addition of RaspberryPi CSI 22 pins camera connector Add RaspberryPi CSI 22 pins camera connector description. Signed-off-by: Alain Volmat --- .../raspberrypi,csi-22pins-connector.yaml | 33 +++++++++++++++++++ .../gpio/raspberrypi-csi-22pins-connector.h | 18 ++++++++++ 2 files changed, 51 insertions(+) create mode 100644 dts/bindings/gpio/raspberrypi,csi-22pins-connector.yaml create mode 100644 include/zephyr/dt-bindings/gpio/raspberrypi-csi-22pins-connector.h diff --git a/dts/bindings/gpio/raspberrypi,csi-22pins-connector.yaml b/dts/bindings/gpio/raspberrypi,csi-22pins-connector.yaml new file mode 100644 index 000000000000..dc8070e26a50 --- /dev/null +++ b/dts/bindings/gpio/raspberrypi,csi-22pins-connector.yaml @@ -0,0 +1,33 @@ +# Copyright 2025 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +description: | + GPIO pins exposed on the Raspberry Pi CSI 22pins Camera connector + Connector layout: + + 1 GND + 2 CSI_D0_N + 3 CSI_D0_P + 4 GND + 5 CSI_D1_N + 6 CSI_D1_P + 7 GND + 8 CSI_CK_N + 9 CSI_CK_P + 10 GND + 11 CSI_D2_N + 12 CSI_D2_P + 13 GND + 14 CSI_D3_N + 15 CSI_D3_P + 16 GND + 17 IO0 + 18 IO1 + 19 GND + 20 I2C_SCL + 21 I2C_SDA + 22 VCC (3v3) + +compatible: "raspberrypi,csi-22pins-connector" + +include: [gpio-nexus.yaml, base.yaml] diff --git a/include/zephyr/dt-bindings/gpio/raspberrypi-csi-22pins-connector.h b/include/zephyr/dt-bindings/gpio/raspberrypi-csi-22pins-connector.h new file mode 100644 index 000000000000..dbc83be305c8 --- /dev/null +++ b/include/zephyr/dt-bindings/gpio/raspberrypi-csi-22pins-connector.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025 STMicroelectronics + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef INCLUDE_ZEPHYR_DT_BINDINGS_GPIO_RASPBERRYPI_CSI_22PINS_CONNECTOR_H_ +#define INCLUDE_ZEPHYR_DT_BINDINGS_GPIO_RASPBERRYPI_CSI_22PINS_CONNECTOR_H_ + +/** + * @name CSI 22 pins camera connector pinout + * @{ + */ +#define CSI_22PINS_IO0 17 /**< GPIO0 */ +#define CSI_22PINS_IO1 18 /**< GPIO1 */ +#define CSI_22PINS_I2C_SCL 20 /**< I2C clock pin */ +#define CSI_22PINS_I2C_SDA 21 /**< I2C data pin */ +/** @} */ + +#endif /* INCLUDE_ZEPHYR_DT_BINDINGS_GPIO_RASPBERRYPI_CSI_22PINS_CONNECTOR_H_ */ From 83e9d4b2bbd1870a115dbbd3823f61170b1f5e47 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Wed, 2 Apr 2025 14:00:00 +0200 Subject: [PATCH 4/4] shields: st_b_cams_imx_mb1854: add imx335 based MB1854 board shield Introduce the B_CAMS_IMX camera shield for STM32 which embeds a IMX335 camera sensor. Signed-off-by: Alain Volmat --- .../st_b_cams_imx_mb1854/Kconfig.shield | 5 ++ .../st_b_cams_imx_mb1854/doc/index.rst | 51 ++++++++++++++++ .../doc/st_b_cams_imx.webp | Bin 0 -> 34298 bytes .../st_b_cams_imx_mb1854.overlay | 57 ++++++++++++++++++ 4 files changed, 113 insertions(+) create mode 100644 boards/shields/st_b_cams_imx_mb1854/Kconfig.shield create mode 100644 boards/shields/st_b_cams_imx_mb1854/doc/index.rst create mode 100644 boards/shields/st_b_cams_imx_mb1854/doc/st_b_cams_imx.webp create mode 100644 boards/shields/st_b_cams_imx_mb1854/st_b_cams_imx_mb1854.overlay diff --git a/boards/shields/st_b_cams_imx_mb1854/Kconfig.shield b/boards/shields/st_b_cams_imx_mb1854/Kconfig.shield new file mode 100644 index 000000000000..ded26fc4344c --- /dev/null +++ b/boards/shields/st_b_cams_imx_mb1854/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2025 STMicroelectronics. +# SPDX-License-Identifier: Apache-2.0 + +config SHIELD_ST_B_CAMS_IMX_MB1854 + def_bool $(shields_list_contains,st_b_cams_imx_mb1854) diff --git a/boards/shields/st_b_cams_imx_mb1854/doc/index.rst b/boards/shields/st_b_cams_imx_mb1854/doc/index.rst new file mode 100644 index 000000000000..530e769b4a46 --- /dev/null +++ b/boards/shields/st_b_cams_imx_mb1854/doc/index.rst @@ -0,0 +1,51 @@ +.. _st_b_cams_imx_mb1854: + +ST B-CAMS-IMX-MB1854 +#################### + +Overview +******** + +The B-CAMS-IMX camera module provides a compelling hardware set to +handle multiple computer vision scenarios and use cases. It features +a high-resolution 5‑Mpx RGB CMOS image sensor, an inertial motion unit, +and a Time‑of‑Flight sensor. It can be used with any STM32 boards featuring +a MIPI CSI-2® interface with a 22‑pin FFC connector to enable full-featured +computer vision on STM32 microcontrollers and microprocessors easily. + +.. figure:: st_b_cams_imx.webp + :width: 600px + :align: center + :alt: B-CAMS-IMX-MB1854 + + B-CAMS-IMX MB1854 Image (Credit: STMicroelectronics.) + +Requirements +************ + +The camera module bundle is compatible with all STM32 Discovery kits and +Evaluation boards featuring a 22 pins FFC connector, such as the STM32N6570_DK +Discovery kit. + +Usage +***** + +The shield can be used in any application by setting ``SHIELD`` to +``st_b_cams_imx_mb1854`` for boards with the necessary device tree node labels. + +Set ``--shield "st_b_cams_imx_mb1854"`` when you invoke ``west build``. For example: + +.. zephyr-app-commands:: + :zephyr-app: samples/drivers/video/capture + :board: stm32n6570_dk + :shield: st_b_cams_imx_mb1854 + :goals: build + +References +********** + +- `Product page `_ + +- `Databrief `_ + +- `User manual `_ diff --git a/boards/shields/st_b_cams_imx_mb1854/doc/st_b_cams_imx.webp b/boards/shields/st_b_cams_imx_mb1854/doc/st_b_cams_imx.webp new file mode 100644 index 0000000000000000000000000000000000000000..689f6d9f38395fa1a9ff2654606e921a20a51b99 GIT binary patch literal 34298 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 +#include + +/ { + chosen { + zephyr,camera = &csi_22pins_capture_port; + }; + + imx335_input_clock: imx335-input-clock { + compatible = "fixed-clock"; + clock-frequency = <24000000>; + #clock-cells = <0>; + }; +}; + +&csi_22pins_interface { + status = "okay"; +}; + +&csi_22pins_ep_in { + remote-endpoint-label = "imx335_ep_out"; + bus-type = ; + data-lanes = <1 2>; +}; + +&csi_22pins_i2c { + imx335: camera@1a { + compatible = "sony,imx335"; + clocks = <&imx335_input_clock>; + reg = <0x1a>; + reset-gpios = <&csi_22pins_connector CSI_22PINS_IO0 GPIO_ACTIVE_LOW>; + + port { + imx335_ep_out: endpoint { + remote-endpoint-label = "csi_22pins_ep_in"; + bus-type = ; + data-lanes = <1 2>; + }; + }; + }; +}; + +&csi_22pins_connector { + /* Power the camera module */ + en-module-gpios { + gpio-hog; + gpios = ; + output-high; + }; +};