drivers: video: Add NXP MIPI CSI-2 Rx driver
Add driver to support NXP MIPI CSI-2 Rx which is a MIPI CSI-2 receiver connecting a camera sensor to the NXP CSI. This IP is present in the i.MX RT11XX series. Signed-off-by: Phi Bang Nguyen <phibang.nguyen@nxp.com>
This commit is contained in:
parent
fd157a81be
commit
f1846eca02
4 changed files with 231 additions and 0 deletions
|
|
@ -5,6 +5,7 @@ zephyr_library()
|
|||
zephyr_library_sources(video_common.c)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_VIDEO_MCUX_CSI video_mcux_csi.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_VIDEO_MCUX_MIPI_CSI2RX video_mcux_mipi_csi2rx.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_VIDEO_SW_GENERATOR video_sw_generator.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_VIDEO_MT9M114 mt9m114.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_VIDEO_OV7725 ov7725.c)
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ config VIDEO_BUFFER_POOL_ALIGN
|
|||
|
||||
source "drivers/video/Kconfig.mcux_csi"
|
||||
|
||||
source "drivers/video/Kconfig.mcux_mipi_csi2rx"
|
||||
|
||||
source "drivers/video/Kconfig.sw_generator"
|
||||
|
||||
source "drivers/video/Kconfig.mt9m114"
|
||||
|
|
|
|||
10
drivers/video/Kconfig.mcux_mipi_csi2rx
Normal file
10
drivers/video/Kconfig.mcux_mipi_csi2rx
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# NXP MIPI CSI-2 Rx driver configuration option
|
||||
|
||||
# Copyright 2024 NXP
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config VIDEO_MCUX_MIPI_CSI2RX
|
||||
bool "NXP MIPI CSI-2 Rx driver"
|
||||
default y
|
||||
depends on DT_HAS_NXP_MIPI_CSI2RX_ENABLED
|
||||
select VIDEO_MCUX_CSI
|
||||
218
drivers/video/video_mcux_mipi_csi2rx.c
Normal file
218
drivers/video/video_mcux_mipi_csi2rx.c
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
* Copyright 2024 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT nxp_mipi_csi2rx
|
||||
|
||||
#include <fsl_mipi_csi2rx.h>
|
||||
|
||||
#include <zephyr/drivers/video.h>
|
||||
#include <zephyr/kernel.h>
|
||||
|
||||
#define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(mipi_csi);
|
||||
|
||||
/*
|
||||
* Two data lanes are set by default as 2-lanes camera sensors are
|
||||
* more common and more performant but single lane is also supported.
|
||||
*/
|
||||
#define DEFAULT_MIPI_CSI_NUM_LANES 2
|
||||
#define DEFAULT_CAMERA_FRAME_RATE 30
|
||||
|
||||
struct mipi_csi2rx_config {
|
||||
const MIPI_CSI2RX_Type *base;
|
||||
const struct device *sensor_dev;
|
||||
};
|
||||
|
||||
struct mipi_csi2rx_data {
|
||||
csi2rx_config_t csi2rxConfig;
|
||||
};
|
||||
|
||||
static int mipi_csi2rx_set_fmt(const struct device *dev, enum video_endpoint_id ep,
|
||||
struct video_format *fmt)
|
||||
{
|
||||
const struct mipi_csi2rx_config *config = dev->config;
|
||||
struct mipi_csi2rx_data *drv_data = dev->data;
|
||||
csi2rx_config_t csi2rxConfig = {0};
|
||||
uint8_t i = 0;
|
||||
|
||||
/*
|
||||
* Initialize the MIPI CSI2
|
||||
*
|
||||
* From D-PHY specification, the T-HSSETTLE should in the range of 85ns+6*UI to 145ns+10*UI
|
||||
* UI is Unit Interval, equal to the duration of any HS state on the Clock Lane
|
||||
*
|
||||
* T-HSSETTLE = csi2rxConfig.tHsSettle_EscClk * (Tperiod of RxClkInEsc)
|
||||
*
|
||||
* csi2rxConfig.tHsSettle_EscClk setting for camera:
|
||||
*
|
||||
* Resolution | frame rate | T_HS_SETTLE
|
||||
* =============================================
|
||||
* 720P | 30 | 0x12
|
||||
* ---------------------------------------------
|
||||
* 720P | 15 | 0x17
|
||||
* ---------------------------------------------
|
||||
* VGA | 30 | 0x1F
|
||||
* ---------------------------------------------
|
||||
* VGA | 15 | 0x24
|
||||
* ---------------------------------------------
|
||||
* QVGA | 30 | 0x1F
|
||||
* ---------------------------------------------
|
||||
* QVGA | 15 | 0x24
|
||||
* ---------------------------------------------
|
||||
*/
|
||||
static const uint32_t csi2rxHsSettle[][4] = {
|
||||
{
|
||||
1280,
|
||||
720,
|
||||
30,
|
||||
0x12,
|
||||
},
|
||||
{
|
||||
1280,
|
||||
720,
|
||||
15,
|
||||
0x17,
|
||||
},
|
||||
{
|
||||
640,
|
||||
480,
|
||||
30,
|
||||
0x1F,
|
||||
},
|
||||
{
|
||||
640,
|
||||
480,
|
||||
15,
|
||||
0x24,
|
||||
},
|
||||
{
|
||||
320,
|
||||
240,
|
||||
30,
|
||||
0x1F,
|
||||
},
|
||||
{
|
||||
320,
|
||||
240,
|
||||
15,
|
||||
0x24,
|
||||
},
|
||||
};
|
||||
|
||||
csi2rxConfig.laneNum = DEFAULT_MIPI_CSI_NUM_LANES;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(csi2rxHsSettle); i++) {
|
||||
if ((fmt->width == csi2rxHsSettle[i][0]) && (fmt->height == csi2rxHsSettle[i][1]) &&
|
||||
(DEFAULT_CAMERA_FRAME_RATE == csi2rxHsSettle[i][2])) {
|
||||
csi2rxConfig.tHsSettle_EscClk = csi2rxHsSettle[i][3];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(csi2rxHsSettle)) {
|
||||
LOG_ERR("Unsupported resolution");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
drv_data->csi2rxConfig = csi2rxConfig;
|
||||
|
||||
if (video_set_format(config->sensor_dev, ep, fmt)) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mipi_csi2rx_get_fmt(const struct device *dev, enum video_endpoint_id ep,
|
||||
struct video_format *fmt)
|
||||
{
|
||||
const struct mipi_csi2rx_config *config = dev->config;
|
||||
|
||||
if (fmt == NULL || ep != VIDEO_EP_OUT) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (video_get_format(config->sensor_dev, ep, fmt)) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mipi_csi2rx_stream_start(const struct device *dev)
|
||||
{
|
||||
const struct mipi_csi2rx_config *config = dev->config;
|
||||
struct mipi_csi2rx_data *drv_data = dev->data;
|
||||
|
||||
CSI2RX_Init((MIPI_CSI2RX_Type *)config->base, &drv_data->csi2rxConfig);
|
||||
|
||||
if (video_stream_start(config->sensor_dev)) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mipi_csi2rx_stream_stop(const struct device *dev)
|
||||
{
|
||||
const struct mipi_csi2rx_config *config = dev->config;
|
||||
|
||||
if (video_stream_stop(config->sensor_dev)) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
CSI2RX_Deinit((MIPI_CSI2RX_Type *)config->base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mipi_csi2rx_get_caps(const struct device *dev, enum video_endpoint_id ep,
|
||||
struct video_caps *caps)
|
||||
{
|
||||
const struct mipi_csi2rx_config *config = dev->config;
|
||||
|
||||
if (ep != VIDEO_EP_OUT) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Just forward to sensor dev for now */
|
||||
return video_get_caps(config->sensor_dev, ep, caps);
|
||||
}
|
||||
|
||||
static const struct video_driver_api mipi_csi2rx_driver_api = {
|
||||
.get_caps = mipi_csi2rx_get_caps,
|
||||
.get_format = mipi_csi2rx_get_fmt,
|
||||
.set_format = mipi_csi2rx_set_fmt,
|
||||
.stream_start = mipi_csi2rx_stream_start,
|
||||
.stream_stop = mipi_csi2rx_stream_stop,
|
||||
};
|
||||
|
||||
static int mipi_csi2rx_init(const struct device *dev)
|
||||
{
|
||||
const struct mipi_csi2rx_config *config = dev->config;
|
||||
|
||||
/* Check if there is any sensor device */
|
||||
if (!device_is_ready(config->sensor_dev)) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MIPI_CSI2RX_INIT(n) \
|
||||
static struct mipi_csi2rx_data mipi_csi2rx_data_##n; \
|
||||
\
|
||||
static const struct mipi_csi2rx_config mipi_csi2rx_config_##n = { \
|
||||
.base = (MIPI_CSI2RX_Type *)DT_INST_REG_ADDR(n), \
|
||||
.sensor_dev = DEVICE_DT_GET(DT_INST_PHANDLE(n, sensor)), \
|
||||
}; \
|
||||
\
|
||||
DEVICE_DT_INST_DEFINE(n, &mipi_csi2rx_init, NULL, &mipi_csi2rx_data_##n, \
|
||||
&mipi_csi2rx_config_##n, POST_KERNEL, CONFIG_VIDEO_INIT_PRIORITY, \
|
||||
&mipi_csi2rx_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(MIPI_CSI2RX_INIT)
|
||||
Loading…
Reference in a new issue