From 2f947d8acb134ae9236e3a224265af6b3eacb9c9 Mon Sep 17 00:00:00 2001 From: Jun Yang Date: Sat, 13 Jul 2019 22:24:32 -0700 Subject: [PATCH 1/6] drivers/camera/image_sensor: Add image sensor framework Add I2C image sensor framework to support multiple image sensors. Software goes through the image sensor support list to identify the image sensor present on board. In general, image sensor is only accessed by camera drivers. Signed-off-by: Jun Yang --- CODEOWNERS | 1 + drivers/CMakeLists.txt | 1 + drivers/Kconfig | 2 + drivers/camera/CMakeLists.txt | 5 + drivers/camera/Kconfig | 29 +++ drivers/camera/image_sensor_dev.c | 305 +++++++++++++++++++++++++ drivers/camera/image_sensor_handlers.c | 76 ++++++ dts/bindings/camera/image-sensor.yaml | 25 ++ include/drivers/camera_generic.h | 64 ++++++ include/drivers/display.h | 2 + include/drivers/image_sensor.h | 253 ++++++++++++++++++++ 11 files changed, 763 insertions(+) create mode 100644 drivers/camera/CMakeLists.txt create mode 100644 drivers/camera/Kconfig create mode 100644 drivers/camera/image_sensor_dev.c create mode 100644 drivers/camera/image_sensor_handlers.c create mode 100644 dts/bindings/camera/image-sensor.yaml create mode 100644 include/drivers/camera_generic.h create mode 100644 include/drivers/image_sensor.h diff --git a/CODEOWNERS b/CODEOWNERS index 145d90e4b718..bd2187ddaa64 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -171,6 +171,7 @@ /drivers/*/*xec* @franciscomunoz @albertofloyd @scottwcpg /drivers/wifi/ @jukkar @tbursztyka @pfalcon /drivers/wifi/eswifi/ @loicpoulain +/drivers/camera/ @JunYangNXP /dts/arm/atmel/samr21.dtsi @benpicco /dts/arm/st/ @erwango /dts/arm/ti/cc13?2* @bwitherspoon diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index 57acca6826c1..24ff216f8590 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -33,6 +33,7 @@ add_subdirectory_if_kconfig(wifi) add_subdirectory_if_kconfig(can) add_subdirectory_if_kconfig(audio) add_subdirectory_if_kconfig(hwinfo) +add_subdirectory_if_kconfig(camera) add_subdirectory_ifdef(CONFIG_FLASH_HAS_DRIVER_ENABLED flash) add_subdirectory_ifdef(CONFIG_SERIAL_HAS_DRIVER serial) diff --git a/drivers/Kconfig b/drivers/Kconfig index 662c02f7baa2..921ed184526d 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -89,4 +89,6 @@ source "drivers/neural_net/Kconfig" source "drivers/hwinfo/Kconfig" +source "drivers/camera/Kconfig" + endmenu diff --git a/drivers/camera/CMakeLists.txt b/drivers/camera/CMakeLists.txt new file mode 100644 index 000000000000..e3724f4233fe --- /dev/null +++ b/drivers/camera/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources(image_sensor_dev.c) + +zephyr_sources_ifdef(CONFIG_USERSPACE image_sensor_handlers.c) diff --git a/drivers/camera/Kconfig b/drivers/camera/Kconfig new file mode 100644 index 000000000000..a453bb559df8 --- /dev/null +++ b/drivers/camera/Kconfig @@ -0,0 +1,29 @@ +# Kconfig - Camera drivers + +# +# Copyright (c) 2019 NXP Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +menuconfig CAMERA + bool "Camera Drivers" + help + Enable camera drivers + +if CAMERA + +module = CAMERA +module-str = camera + +config IMAGE_SENSOR_INIT_PRIO + int "Image sensor initalization priority level" + default 70 + range 70 80 + help + Image sensor initialization priority level. + This number tells how early in the boot + the image sensor driver and image sensor vendor + driver are initialized. + +endif diff --git a/drivers/camera/image_sensor_dev.c b/drivers/camera/image_sensor_dev.c new file mode 100644 index 000000000000..4fc912be15cd --- /dev/null +++ b/drivers/camera/image_sensor_dev.c @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2019 NXP Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include + +#define LOG_LEVEL LOG_LEVEL_ERR +#include +LOG_MODULE_REGISTER(IMAGE_SENSOR_DEV); + +#undef LOG_ERR +#define LOG_ERR printk + +#undef LOG_INF +#define LOG_INF printk + +/*Contain all the CMOS sensors + * supported in current Zephyr. + */ +static bool z_img_sensor_support_list_init; +static sys_dlist_t z_img_sensor_support_list; + +static K_MUTEX_DEFINE(z_img_sensor_support_lock); + +void img_sensor_support_add(struct img_sensor_info *img_sensor) +{ + (void)k_mutex_lock(&z_img_sensor_support_lock, K_FOREVER); + + if (!z_img_sensor_support_list_init) { + z_img_sensor_support_list_init = true; + sys_dlist_init(&z_img_sensor_support_list); + } + + sys_dlist_append(&z_img_sensor_support_list, &img_sensor->node); + + LOG_INF("Add image sensor (id %d) into support list\r\n", + img_sensor->sensor_client.sensor_id); + + k_mutex_unlock(&z_img_sensor_support_lock); +} + +/*Image sensors present on the device. + * Image sensors devices are populated + * in board DTS. + */ +static int z_img_sensor_num; +static struct device *z_img_sensor_dev[CAMERA_MAX_NUMBER]; + +static K_MUTEX_DEFINE(z_img_sensor_lock); + +static inline int img_sensor_register(struct device *dev) +{ + int i; + + (void)k_mutex_lock(&z_img_sensor_lock, K_FOREVER); + + for (i = 0; i < z_img_sensor_num; i++) { + if (z_img_sensor_dev[i] == dev) { + k_mutex_unlock(&z_img_sensor_lock); + return -EINVAL; + } + } + if (z_img_sensor_num < CAMERA_MAX_NUMBER) { + z_img_sensor_dev[z_img_sensor_num] = dev; + z_img_sensor_num++; + + k_mutex_unlock(&z_img_sensor_lock); + + return 0; + } + + k_mutex_unlock(&z_img_sensor_lock); + + return -ENOSPC; +} + +struct device *img_sensor_get_by_id(enum camera_id id) +{ + int i; + + (void)k_mutex_lock(&z_img_sensor_lock, K_FOREVER); + for (i = 0; i < z_img_sensor_num; i++) { + struct img_sensor_data *drv_data = + z_img_sensor_dev[i]->driver_data; + + if (drv_data->host_info.id == id) { + k_mutex_unlock(&z_img_sensor_lock); + return z_img_sensor_dev[i]; + } + } + + k_mutex_unlock(&z_img_sensor_lock); + return 0; +} + +struct device *img_sensor_get_prime(void) +{ + return img_sensor_get_by_id(CAMERA_PRIMARY_ID); +} + +static const struct img_sensor_info *img_sensor_scan_one( + struct device *i2c_dev) +{ + int ret; + sys_dnode_t *node, *next_node; + + (void)k_mutex_lock(&z_img_sensor_support_lock, K_FOREVER); + + SYS_DLIST_FOR_EACH_NODE_SAFE(&z_img_sensor_support_list, + node, next_node) { + const struct img_sensor_info *sensor_info = + CONTAINER_OF(node, const struct img_sensor_info, + node); + const struct img_sensor_client *sensor_client = + &sensor_info->sensor_client; + u32_t sensor_id = 0; + + ret = i2c_write_read(i2c_dev, sensor_client->i2c_addr, + &sensor_client->id_reg, + sensor_client->w_id_reg, + &sensor_id, + sensor_client->w_sensor_id); + if (!ret && sensor_id == sensor_client->sensor_id) { + k_mutex_unlock(&z_img_sensor_support_lock); + + return sensor_info; + } + } + k_mutex_unlock(&z_img_sensor_support_lock); + + return 0; +} + +#if defined(DT_ZEPHYR_IMAGE_SENSOR_0) || defined(DT_ZEPHYR_IMAGE_SENSOR_1) +static int img_sensor_dev_init(struct device *dev) +{ + struct img_sensor_data *drv_data = dev->driver_data; + int ret = -EINVAL; + + memset(drv_data, 0, sizeof(struct img_sensor_data)); + drv_data->host_info.id = CAMERA_NULL_ID; + +#ifdef DT_ZEPHYR_IMAGE_SENSOR_0 + if (!strcmp(dev->config->name, IMAGE_SENSOR0_NAME)) { + drv_data->host_info.i2c = + device_get_binding( + DT_INST_0_ZEPHYR_IMAGE_SENSOR_BUS_NAME); + drv_data->host_info.pwr_gpio = + device_get_binding( + DT_INST_0_ZEPHYR_IMAGE_SENSOR_PWR_GPIOS_CONTROLLER); + drv_data->host_info.pin = + DT_INST_0_ZEPHYR_IMAGE_SENSOR_PWR_GPIOS_PIN; + drv_data->host_info.flag = + DT_INST_0_ZEPHYR_IMAGE_SENSOR_PWR_GPIOS_FLAGS; + ret = img_sensor_register(dev); + if (!ret) { + LOG_INF("\r\nImage sensor 0 registered.\r\n"); + } else { + LOG_ERR("\r\nImage sensor 0 un-registered.\r\n"); + } + + return ret; + } +#endif + +#ifdef DT_ZEPHYR_IMAGE_SENSOR_1 + if (!strcmp(dev->config->name, IMAGE_SENSOR1_NAME)) { + drv_data->host_info.i2c = + device_get_binding( + DT_INST_1_ZEPHYR_IMAGE_SENSOR_BUS_NAME); + drv_data->host_info.pwr_gpio = + device_get_binding( + DT_INST_1_ZEPHYR_IMAGE_SENSOR_PWR_GPIOS_CONTROLLER); + drv_data->host_info.pin = + DT_INST_1_ZEPHYR_IMAGE_SENSOR_PWR_GPIOS_PIN; + drv_data->host_info.flag = + DT_INST_1_ZEPHYR_IMAGE_SENSOR_PWR_GPIOS_FLAGS; + ret = img_sensor_register(dev); + if (!ret) { + LOG_INF("\r\nImage sensor 1 registered.\r\n"); + } else { + LOG_ERR("\r\nImage sensor 1 un-registered.\r\n"); + } + + return ret; + } +#endif + + return ret; +} +#endif + +static inline int img_sensor_power( + struct img_sensor_host *host, bool on) +{ + int ret = gpio_pin_configure(host->pwr_gpio, + host->pin, host->flag); + + if (ret) { + return -EIO; + } + + k_busy_wait(1); + + if (host->flag & GPIO_DIR_OUT) { + if (on) + ret = gpio_pin_write(host->pwr_gpio, host->pin, 1); + else + ret = gpio_pin_write(host->pwr_gpio, host->pin, 0); + + if (ret) { + return -EIO; + } + } + k_busy_wait(1000); + + return 0; +} + +static inline void img_sensor_client_dup( + struct img_sensor_client *drv_client, + const struct img_sensor_client *scan_client) +{ + memcpy((char *)drv_client, + (const char *)scan_client, sizeof(struct img_sensor_client)); +} +struct device *img_sensor_scan(enum camera_id id) +{ + int i, ret; + struct device *dev; + struct img_sensor_data *drv_data; + const struct img_sensor_info *scan_info; + + (void)k_mutex_lock(&z_img_sensor_lock, K_FOREVER); + + for (i = 0; i < z_img_sensor_num; i++) { + dev = z_img_sensor_dev[i]; + drv_data = dev->driver_data; + if (drv_data->host_info.id == CAMERA_NULL_ID) { + if (drv_data->host_info.pwr_gpio) { + ret = img_sensor_power( + &drv_data->host_info, + true); + + assert(!ret); + } + + scan_info = + img_sensor_scan_one(drv_data->host_info.i2c); + if (scan_info) { + LOG_INF("%s image sensor (id %d) is " + "probed.\r\n", + id == CAMERA_PRIMARY_ID ? + "Primary" : "Secondary", + scan_info->sensor_client.sensor_id); + img_sensor_client_dup( + &drv_data->client_info, + &scan_info->sensor_client); + + drv_data->host_info.id = id; + dev->driver_api = + scan_info->sensor_api; + + k_mutex_unlock(&z_img_sensor_lock); + + return dev; + } + if (drv_data->host_info.pwr_gpio) { + ret = img_sensor_power( + &drv_data->host_info, + false); + + assert(!ret); + } + } + } + k_mutex_unlock(&z_img_sensor_lock); + + return 0; +} + +#ifdef DT_ZEPHYR_IMAGE_SENSOR_0 +struct img_sensor_data img_sensor_data0; + +DEVICE_AND_API_INIT(img_sensor_dev0, + IMAGE_SENSOR0_NAME, img_sensor_dev_init, + &img_sensor_data0, NULL, POST_KERNEL, + CONFIG_IMAGE_SENSOR_INIT_PRIO, + 0); +#endif + +#ifdef DT_ZEPHYR_IMAGE_SENSOR_1 +struct img_sensor_data img_sensor_data1; + +DEVICE_AND_API_INIT(img_sensor_dev1, + IMAGE_SENSOR1_NAME, img_sensor_dev_init, + &img_sensor_data1, NULL, POST_KERNEL, + CONFIG_IMAGE_SENSOR_INIT_PRIO, + 0); +#endif diff --git a/drivers/camera/image_sensor_handlers.c b/drivers/camera/image_sensor_handlers.c new file mode 100644 index 000000000000..6eb38782df73 --- /dev/null +++ b/drivers/camera/image_sensor_handlers.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2019 NXP Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include + +Z_SYSCALL_HANDLER(img_sensor_reset, dev) +{ + return z_impl_img_sensor_reset((struct device *)dev); +} + +Z_SYSCALL_HANDLER(img_sensor_get_cap, dev, cap) +{ + return z_impl_img_sensor_get_cap((struct device *)dev, + (struct img_sensor_capability *)cap); +} + +Z_SYSCALL_HANDLER(img_sensor_read_reg, dev, + addr, addr_width, data, data_width) +{ + return z_impl_img_sensor_read_reg((struct device *)dev, + (u32_t)addr, (u8_t)addr_width, (u8_t *)data, (u8_t)data_width); +} + +Z_SYSCALL_HANDLER(img_sensor_write_reg, dev, + addr, addr_width, data, data_width) +{ + return z_impl_img_sensor_write_reg((struct device *)dev, + (u32_t)addr, (u8_t)addr_width, (u32_t)data, (u8_t)data_width); +} + +Z_SYSCALL_HANDLER(img_sensor_set_pixformat, dev, + pixformat) +{ + return z_impl_img_sensor_set_pixformat((struct device *)dev, + (enum img_sensor_pixel_format)pixformat); +} + +Z_SYSCALL_HANDLER(img_sensor_set_framesize, dev, + framesize) +{ + return z_impl_img_sensor_set_framesize((struct device *)dev, + (enum img_sensor_frame_size)framesize); +} + +Z_SYSCALL_HANDLER(img_sensor_set_contrast, dev, level) +{ + return z_impl_img_sensor_set_contrast((struct device *)dev, + (int)level); +} + +Z_SYSCALL_HANDLER(img_sensor_set_brightness, dev, level) +{ + return z_impl_img_sensor_set_brightness((struct device *)dev, + (int)level); +} + +Z_SYSCALL_HANDLER(img_sensor_set_gain, dev, + r_gain_db, g_gain_db, b_gain_db) +{ + return z_impl_img_sensor_set_gain((struct device *)dev, + (float)r_gain_db, (float)g_gain_db, (float)b_gain_db); +} + +Z_SYSCALL_HANDLER(img_sensor_set_effect, dev, effect) +{ + return z_impl_img_sensor_set_effect((struct device *)dev, + (enum img_sensor_effect)effect); +} + +Z_SYSCALL_HANDLER(img_sensor_configure, dev) +{ + return z_impl_img_sensor_configure((struct device *)dev); +} diff --git a/dts/bindings/camera/image-sensor.yaml b/dts/bindings/camera/image-sensor.yaml new file mode 100644 index 000000000000..b5036adb8ccb --- /dev/null +++ b/dts/bindings/camera/image-sensor.yaml @@ -0,0 +1,25 @@ +# +# Copyright (c) 2019, NXP +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +title: CMOS Image Sensor +version: 0.1 + +description: > + This is a representation of the CMOS Sensor nodes. + +inherits: + !include i2c-device.yaml + +properties: + compatible: + constraint: "zephyr,image-sensor" + + pwr-gpios: + type: compound + category: optional + description: power control + generation: define +... diff --git a/include/drivers/camera_generic.h b/include/drivers/camera_generic.h new file mode 100644 index 000000000000..6a0b55970dff --- /dev/null +++ b/include/drivers/camera_generic.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Public API for camera drivers + */ + +#ifndef ZEPHYR_INCLUDE_CAMERA_GENERIC_H_ +#define ZEPHYR_INCLUDE_CAMERA_GENERIC_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if (defined(CONFIG_IMAGE_SENSOR_INIT_PRIO) &&\ + defined(CONFIG_CAMERA_INIT_PRIO)) +#if (CONFIG_IMAGE_SENSOR_INIT_PRIO >= CONFIG_CAMERA_INIT_PRIO) +#error Image sensor initalization must be earlier than +#error camera initalization. +#endif +#endif + +/*In order to support multiple cameras on device.*/ +#define CAMERA_MAX_NUMBER 2 + +/*For multiple cameras on board, the dts LABEL of + * primary camera should be named "primary". + */ +#define CAMERA_PRIMARY_LABEL "primary" + +/*For multiple cameras on board, the dts LABEL of + * secondary camera should be named "secondary". + */ +#define CAMERA_SECONDARY_LABEL "secondary" + +/** + * @enum camera_id + * @brief Enumeration with camera id to identify + * if the camera is promary camera or secondary camera. + * + */ +enum camera_id { + CAMERA_NULL_ID = 0, + CAMERA_PRIMARY_ID = 1, + CAMERA_SECONDARY_ID = 2 +}; + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_CAMERA_GENERIC_H_*/ diff --git a/include/drivers/display.h b/include/drivers/display.h index ee287af24bde..47946a3244bd 100644 --- a/include/drivers/display.h +++ b/include/drivers/display.h @@ -33,6 +33,8 @@ enum display_pixel_format { PIXEL_FORMAT_MONO10 = BIT(2), /* 1=Black 0=White */ PIXEL_FORMAT_ARGB_8888 = BIT(3), PIXEL_FORMAT_RGB_565 = BIT(4), + PIXEL_FORMAT_YUV_420 = BIT(5), + PIXEL_FORMAT_YUV_422 = BIT(6) }; enum display_screen_info { diff --git a/include/drivers/image_sensor.h b/include/drivers/image_sensor.h new file mode 100644 index 000000000000..4499a1406b2b --- /dev/null +++ b/include/drivers/image_sensor.h @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2019 NXP Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef ZEPHYR_INCLUDE_IMG_SENSOR_H_ +#define ZEPHYR_INCLUDE_IMG_SENSOR_H_ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define IMAGE_SENSOR0_NAME "zephyr-img-sensor0" +#define IMAGE_SENSOR1_NAME "zephyr-img-sensor1" + +enum img_sensor_effect { + IMG_EFFECT_NORMAL, + IMG_EFFECT_NEGATIVE, +}; + +enum bytes_width { + W1B = 1, + W2B = 2, + W4B = 4 +}; + +struct img_sensor_reg { + u32_t reg; + enum bytes_width w_reg; + u32_t value; + enum bytes_width w_value; +}; + +/*Public data placed at the beginning of driver data of device*/ +struct img_sensor_host { + /*Camera module associated to*/ + enum camera_id id; + /*I2C device used for configuration*/ + struct device *i2c; + /*GPIO device used for Power control, optional*/ + struct device *pwr_gpio; + /*GPIO pin used for Power control, optional*/ + u32_t pin; + /*GPIO level used for Power control, optional*/ + int flag; +}; + +struct img_sensor_capability { + u32_t pixformat_support; + u16_t width_max; + u16_t height_max; +}; + +struct img_sensor_client { + u16_t i2c_addr; + u32_t sensor_id; + enum bytes_width w_sensor_id; + u32_t id_reg; + enum bytes_width w_id_reg; + int contrast_level; + int bright_level; + float r_gain_db; + float g_gain_db; + float b_gain_db; + u16_t width; + u16_t height; + enum img_sensor_effect effect; + enum display_pixel_format pixformat; + struct img_sensor_capability cap; +}; + +struct img_sensor_data { + struct img_sensor_host host_info; + struct img_sensor_client client_info; +}; + +/*Master clock could be enabled by camer driver + * before accessing CMOS. + * Or disabled by camera driver when system is + * entering sleep mode. + */ +typedef void (*img_sensor_mclk_enable)(struct device *cam_dev, bool enable); + +struct img_sensor_driver_api { + int (*img_sensor_reset_cb)(struct device *dev); + int (*img_sensor_get_cap_cb)(struct device *dev, + struct img_sensor_capability *cap); + int (*img_sensor_read_reg_cb)(struct device *dev, + u32_t addr, u8_t addr_width, u8_t *data, u8_t data_width); + int (*img_sensor_write_reg_cb)(struct device *dev, + u32_t addr, u8_t addr_width, u32_t data, u8_t data_width); + int (*img_sensor_set_pixformat_cb)(struct device *dev, + enum display_pixel_format pixformat); + int (*img_sensor_set_framesize_cb)(struct device *dev, + u16_t width, u16_t height); + int (*img_sensor_set_contrast_cb)(struct device *dev, + int level); + int (*img_sensor_set_brightness_cb)(struct device *dev, + int level); + int (*img_sensor_set_rgb_gain_cb)(struct device *dev, + float r_gain_db, float g_gain_db, float b_gain_db); + int (*img_sensor_set_effect_cb)(struct device *dev, + enum img_sensor_effect effect); + int (*img_sensor_config_cb)(struct device *dev); +}; + +struct img_sensor_info { + sys_dnode_t node; + struct img_sensor_client sensor_client; + const struct img_sensor_driver_api *sensor_api; +}; + +void img_sensor_support_add( + struct img_sensor_info *img_sensor); + +__syscall int img_sensor_reset(struct device *dev); + +static inline int z_impl_img_sensor_reset(struct device *dev) +{ + const struct img_sensor_driver_api *api = dev->driver_api; + + return api->img_sensor_reset_cb(dev); +} + +__syscall int img_sensor_get_cap(struct device *dev, + struct img_sensor_capability *cap); + +static inline int z_impl_img_sensor_get_cap(struct device *dev, + struct img_sensor_capability *cap) +{ + const struct img_sensor_driver_api *api = dev->driver_api; + + return api->img_sensor_get_cap_cb(dev, cap); +} + + +__syscall int img_sensor_read_reg(struct device *dev, + u32_t addr, u8_t addr_width, u8_t *data, u8_t data_width); + +static inline int z_impl_img_sensor_read_reg(struct device *dev, + u32_t addr, u8_t addr_width, u8_t *data, u8_t data_width) +{ + const struct img_sensor_driver_api *api = dev->driver_api; + + return api->img_sensor_read_reg_cb(dev, + addr, addr_width, data, data_width); +} + +__syscall int img_sensor_write_reg(struct device *dev, + u32_t addr, u8_t addr_width, u32_t data, u8_t data_width); + +static inline int z_impl_img_sensor_write_reg(struct device *dev, + u32_t addr, u8_t addr_width, u32_t data, u8_t data_width) +{ + const struct img_sensor_driver_api *api = dev->driver_api; + + return api->img_sensor_write_reg_cb(dev, + addr, addr_width, data, data_width); +} + +__syscall int img_sensor_set_pixformat(struct device *dev, + enum display_pixel_format pixformat); + +static inline int z_impl_img_sensor_set_pixformat(struct device *dev, + enum display_pixel_format pixformat) +{ + const struct img_sensor_driver_api *api = dev->driver_api; + + return api->img_sensor_set_pixformat_cb(dev, pixformat); +} +__syscall int img_sensor_set_framesize(struct device *dev, + u16_t width, u16_t height); + +static inline int z_impl_img_sensor_set_framesize(struct device *dev, + u16_t width, u16_t height) +{ + const struct img_sensor_driver_api *api = dev->driver_api; + + return api->img_sensor_set_framesize_cb(dev, width, height); +} +__syscall int img_sensor_set_contrast(struct device *dev, + int level); + +static inline int z_impl_img_sensor_set_contrast(struct device *dev, + int level) +{ + const struct img_sensor_driver_api *api = dev->driver_api; + + return api->img_sensor_set_contrast_cb(dev, level); +} + +__syscall int img_sensor_set_brightness(struct device *dev, + int level); + +static inline int z_impl_img_sensor_set_brightness(struct device *dev, + int level) +{ + const struct img_sensor_driver_api *api = dev->driver_api; + + return api->img_sensor_set_brightness_cb(dev, level); +} + +__syscall int img_sensor_set_gain(struct device *dev, + float r_gain_db, float g_gain_db, float b_gain_db); + +static inline int z_impl_img_sensor_set_gain(struct device *dev, + float r_gain_db, float g_gain_db, float b_gain_db) +{ + const struct img_sensor_driver_api *api = dev->driver_api; + + return api->img_sensor_set_rgb_gain_cb(dev, + r_gain_db, g_gain_db, b_gain_db); +} + +__syscall int img_sensor_set_effect(struct device *dev, + enum img_sensor_effect effect); + +static inline int z_impl_img_sensor_set_effect(struct device *dev, + enum img_sensor_effect effect) +{ + const struct img_sensor_driver_api *api = dev->driver_api; + + return api->img_sensor_set_effect_cb(dev, effect); +} + +__syscall int img_sensor_configure(struct device *dev); + +static inline int z_impl_img_sensor_configure(struct device *dev) +{ + const struct img_sensor_driver_api *api = dev->driver_api; + + return api->img_sensor_config_cb(dev); +} + +struct device *img_sensor_get_prime(void); + +struct device *img_sensor_get_by_id(enum camera_id id); + +struct device *img_sensor_scan(enum camera_id id); + +#include + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_IMG_SENSOR_H_ */ From 457518d4d2e56a5682ae1a55786f48b4a27ccc23 Mon Sep 17 00:00:00 2001 From: Jun Yang Date: Sat, 13 Jul 2019 22:35:30 -0700 Subject: [PATCH 2/6] drivers/camera: Add camera framework to support camera drivers 1) Support multiple cameras present on board. 2) Camera API for user to access camera device. 3) Each camera is associated to one image sensor present on board. 4) Image sensor is only accessed by the camera driver associated to. camera_power->camera_get_cap->camera_configure-> camera_start->camera_acquire_fb->camera_release_fb ^ | |______________________| Signed-off-by: Jun Yang --- drivers/camera/CMakeLists.txt | 2 + drivers/camera/Kconfig | 18 ++ drivers/camera/camera_dev.c | 139 +++++++++++++ drivers/camera/camera_handlers.c | 55 ++++++ dts/bindings/camera/camera.yaml | 31 +++ include/drivers/camera.h | 325 +++++++++++++++++++++++++++++++ include/drivers/camera_drv.h | 125 ++++++++++++ 7 files changed, 695 insertions(+) create mode 100644 drivers/camera/camera_dev.c create mode 100644 drivers/camera/camera_handlers.c create mode 100644 dts/bindings/camera/camera.yaml create mode 100644 include/drivers/camera.h create mode 100644 include/drivers/camera_drv.h diff --git a/drivers/camera/CMakeLists.txt b/drivers/camera/CMakeLists.txt index e3724f4233fe..dc818ada0ab4 100644 --- a/drivers/camera/CMakeLists.txt +++ b/drivers/camera/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +zephyr_sources(camera_dev.c) zephyr_sources(image_sensor_dev.c) +zephyr_sources_ifdef(CONFIG_USERSPACE camera_handlers.c) zephyr_sources_ifdef(CONFIG_USERSPACE image_sensor_handlers.c) diff --git a/drivers/camera/Kconfig b/drivers/camera/Kconfig index a453bb559df8..86d55b819bb4 100644 --- a/drivers/camera/Kconfig +++ b/drivers/camera/Kconfig @@ -16,6 +16,12 @@ if CAMERA module = CAMERA module-str = camera +config CAMERA_DISPLAY_DEV_NAME + string "Camera display device name" + default "CAMERA DISPLAY" + help + Name of the display device to display camera. + config IMAGE_SENSOR_INIT_PRIO int "Image sensor initalization priority level" default 70 @@ -26,4 +32,16 @@ config IMAGE_SENSOR_INIT_PRIO the image sensor driver and image sensor vendor driver are initialized. +config CAMERA_INIT_PRIO + int "Camera initalization priority level" + default 81 + range 81 90 + help + Camera initialization priority level. + This number tells how early in the boot + the camera vendor drivers are initialized. + Camera initalization depneds on image sensors, + so CAMERA_INIT_PRIO must be greater than + IMAGE_SENSOR_INIT_PRIO. + endif diff --git a/drivers/camera/camera_dev.c b/drivers/camera/camera_dev.c new file mode 100644 index 000000000000..40896ffb0218 --- /dev/null +++ b/drivers/camera/camera_dev.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2019 NXP Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#define LOG_LEVEL LOG_LEVEL_ERR +#include +#define CAMERA_DEV_DBG + +#undef LOG_ERR +#define LOG_ERR printk + +#ifdef CAMERA_DEV_DBG +#undef LOG_INF +#define LOG_INF printk +#endif + +static int z_camera_num; +static struct device *z_camera_dev[CAMERA_MAX_NUMBER]; + +#define CAMERA_DRV_DATA_MAX_SIZE 1024 +static u8_t z_camera_drv_data[CAMERA_MAX_NUMBER * + CAMERA_DRV_DATA_MAX_SIZE] __aligned(64); + +static K_MUTEX_DEFINE(z_camera_lock); + +int camera_dev_get_cap(struct device *cam_dev, + struct camera_capability *cap) +{ + struct camera_driver_data *data = cam_dev->driver_data; + + memcpy((char *)cap, (char *)&data->cap, + sizeof(struct camera_capability)); + + return 0; +} + +int camera_dev_configure(struct device *cam_dev, + struct camera_fb_cfg *fb_cfg) +{ + struct camera_driver_data *data = cam_dev->driver_data; + + if (fb_cfg->cfg_mode == CAMERA_DEFAULT_CFG) { + memcpy((char *)&fb_cfg->fb_attr, + (char *)&data->fb_attr, + sizeof(struct camera_fb_attr)); + } else { + memcpy((char *)&data->fb_attr, + (char *)&fb_cfg->fb_attr, + sizeof(struct camera_fb_attr)); + } + + return 0; +} + +int camera_dev_register(struct device *dev) +{ + (void)k_mutex_lock(&z_camera_lock, K_FOREVER); + + if (z_camera_num < CAMERA_MAX_NUMBER) { + z_camera_dev[z_camera_num] = dev; + z_camera_num++; + + k_mutex_unlock(&z_camera_lock); + + return 0; + } + + k_mutex_unlock(&z_camera_lock); + + return -ENOSPC; +} + +struct camera_driver_data *camera_drv_data_alloc( + u32_t priv_size, enum camera_id id, bool clear) +{ + struct camera_driver_data *data; + + if ((priv_size + sizeof(struct camera_driver_data)) > + CAMERA_DRV_DATA_MAX_SIZE) { + + LOG_ERR("Camera data alloc size %d exceeds max size\r\n", + (int)(CAMERA_DRV_DATA_MAX_SIZE - + sizeof(struct camera_driver_data))); + return 0; + } + + if (id != CAMERA_PRIMARY_ID && + id != CAMERA_SECONDARY_ID) { + + LOG_ERR("Camera data alloc id %d is illegal\r\n", id); + return 0; + } + + data = (struct camera_driver_data *) + &z_camera_drv_data[(id - CAMERA_PRIMARY_ID) * + CAMERA_DRV_DATA_MAX_SIZE]; + if (clear) { + memset((char *)data, 0, sizeof(struct camera_driver_data)); + } + data->id = id; + + return data; +} + +static struct device *camera_get_by_id(enum camera_id id) +{ + int i; + struct device *dev; + struct camera_driver_data *camera_data; + + (void)k_mutex_lock(&z_camera_lock, K_FOREVER); + + for (i = 0; i < z_camera_num; i++) { + dev = z_camera_dev[i]; + camera_data = dev->driver_data; + if (camera_data->id == id) { + + k_mutex_unlock(&z_camera_lock); + + return dev; + } + } + + k_mutex_unlock(&z_camera_lock); + + return 0; +} + +struct device *camera_get_primary(void) +{ + return camera_get_by_id(CAMERA_PRIMARY_ID); +} + +struct device *camera_get_secondary(void) +{ + return camera_get_by_id(CAMERA_SECONDARY_ID); +} diff --git a/drivers/camera/camera_handlers.c b/drivers/camera/camera_handlers.c new file mode 100644 index 000000000000..74609d9db577 --- /dev/null +++ b/drivers/camera/camera_handlers.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2019 NXP Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include + +Z_SYSCALL_HANDLER(camera_power, cam_dev, power) +{ + return z_impl_camera_power((struct device *)cam_dev, + (bool)power); +} + +Z_SYSCALL_HANDLER(camera_get_cap, cam_dev, cap) +{ + return z_impl_camera_get_cap((struct device *)cam_dev, + (struct camera_capability *)cap); +} + +Z_SYSCALL_HANDLER(camera_reset, cam_dev) +{ + return z_impl_camera_reset((struct device *)cam_dev); +} + +Z_SYSCALL_HANDLER(camera_configure, cam_dev, + width, height, pixformat) +{ + return z_impl_camera_configure((struct device *)cam_dev, + (u16_t)width, (u16_t)height, + (enum display_pixel_format)pixformat); +} + +Z_SYSCALL_HANDLER(camera_start, cam_dev, + mode, bufs, buf_num, cb) +{ + return z_impl_camera_start((struct device *)cam_dev, + (enum camera_mode)mode, (void **)bufs, (u8_t)buf_num, + (camera_capture_cb)cb); +} + +Z_SYSCALL_HANDLER(camera_acquire_fb, cam_dev, + fb, timeout) +{ + return z_impl_camera_acquire_fb((struct device *)cam_dev, + (void **)fb, (s32_t)timeout); +} + +Z_SYSCALL_HANDLER(camera_release_fb, cam_dev, + fb) +{ + return z_impl_camera_release_fb((struct device *)cam_dev, + (void *)fb); +} diff --git a/dts/bindings/camera/camera.yaml b/dts/bindings/camera/camera.yaml new file mode 100644 index 000000000000..6ec8c72684f7 --- /dev/null +++ b/dts/bindings/camera/camera.yaml @@ -0,0 +1,31 @@ +# +# Copyright (c) 2019, NXP +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +title: camera module +version: 0.1 + +description: > + This binding specifies the camera module. + If there are two cameras present, one is primary + camera and the other is secondary camera. + +inherits: + !include base.yaml + +properties: + compatible: + category: required + + clocks: + type: array + category: optional + description: Clock gate information + generation: define + + label: + category: optional + description: Primary camera("primary") or Secondary camera("secondary"). +... diff --git a/include/drivers/camera.h b/include/drivers/camera.h new file mode 100644 index 000000000000..65d6230c7406 --- /dev/null +++ b/include/drivers/camera.h @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2019, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Public API for camera applications + */ + +#ifndef ZEPHYR_INCLUDE_CAMERA_H_ +#define ZEPHYR_INCLUDE_CAMERA_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Camera work flow: + * camera_get_primary/secondary->camera_power->camera_get_cap-> + * | + * <--camera_acquire_fb<---camera_start<-camera_configure<--| + * | | + * | | + * |-->camera_release_fb-^ + * + */ + +/** + * @enum camera_mode + * @brief Enumeration with camera running mode + * + */ +enum camera_mode { + /* If selected, only one frame is captured then + * camera stream is stopped. + */ + CAMERA_CAPTURE_MODE, + /* If selected, series of frames are captured if + * there are buffers available. + */ + CAMERA_PREVIEW_MODE +}; + +/** + * @typedef camera_capture_cb + * @brief Callback API when one frame is received + * This callback is supposed to be running in + * interrupt context. + * @param fb Pointer to frame buffer + * @param w width of the frame received. + * @param h height of the frame received. + * @param bpp bits per pixel of the frame received. + */ +typedef void (*camera_capture_cb)(void *fb, int w, int h, int bpp); + +/** + * @struct camera_fb_attr + * @brief Structure to describe attribution of + * camera frame buffer + * + */ +struct camera_fb_attr { + u32_t width; + u32_t height; + u8_t bpp; + /*Align the pixel format with display device.*/ + enum display_pixel_format pixformat; +}; + +/** + * @enum camera_cfg_mode + * @brief Enumeration to configure camera + * + */ +enum camera_cfg_mode { + /* If selected, configure camera with + * default camera settings + */ + CAMERA_DEFAULT_CFG, + /* If selected, configure camera with + * camera settings defined by user + */ + CAMERA_USER_CFG +}; + +/** + * @struct camera_fb_cfg + * @brief Structure to configure camera + * Parameter of camera_configure API. + */ +struct camera_fb_cfg { + enum camera_cfg_mode cfg_mode; + struct camera_fb_attr fb_attr; +}; + +/** + * @struct camera_capability + * @brief Structure to describe capabilities of camera + */ +struct camera_capability { + /*Alignment size of point to frame buffer, + * depends on camera DMA + */ + u8_t fb_alignment; + + /*pixel format support by camera, + * partly depends on image sensor connected + */ + u32_t pixformat_support; + + /* Resolution support by camera, + * for most case, resolution support + * depends on image sensor connected. + */ + u16_t width_max; + u16_t height_max; +}; + +/** + * @struct camera_driver_api + * @brief Structure to describe API for user to access camera + */ +struct camera_driver_api { + int (*camera_power_cb)(struct device *cam_dev, + bool power); + int (*camera_reset_cb)(struct device *cam_dev); + int (*camera_get_cap_cb)(struct device *cam_dev, + struct camera_capability *cap); + int (*camera_configure_cb)(struct device *cam_dev, + struct camera_fb_cfg *fb_cfg); + int (*camera_start_cb)(struct device *cam_dev, + enum camera_mode mode, void **bufs, + u8_t buf_num, camera_capture_cb cb); + int (*camera_acquire_fb_cb)(struct device *cam_dev, + void **fb, s32_t timeout); + int (*camera_release_fb_cb)(struct device *cam_dev, + void *fb); +}; + +/** + * @brief Power on/off camera + * + * @param cam_dev Pointer to camera device structure + * + * @param power true on power on else power off + * + * @retval 0 on success else negative errno code. + */ +__syscall int camera_power(struct device *cam_dev, + bool power); + +static inline int z_impl_camera_power(struct device *cam_dev, + bool power) +{ + const struct camera_driver_api *api = cam_dev->driver_api; + + return api->camera_power_cb(cam_dev, power); +} + +/** + * @brief Power reset camera + * + * @param cam_dev Pointer to camera device structure + * + * @retval 0 on success else negative errno code. + */ +__syscall int camera_reset(struct device *cam_dev); + +static inline int z_impl_camera_reset(struct device *cam_dev) +{ + const struct camera_driver_api *api = cam_dev->driver_api; + + return api->camera_reset_cb(cam_dev); +} + +/** + * @brief Get capability of camera + * + * @param cam_dev Pointer to camera device structure + * + * @param cap Pointer to camera capability structure + * filled by camera driver + * + * @retval 0 on success else negative errno code. + */ +__syscall int camera_get_cap(struct device *cam_dev, + struct camera_capability *cap); + +static inline int z_impl_camera_get_cap(struct device *cam_dev, + struct camera_capability *cap) +{ + const struct camera_driver_api *api = cam_dev->driver_api; + + return api->camera_get_cap_cb(cam_dev, cap); +} + +/** + * @brief Configure frame buffer of camera + * + * @param cam_dev Pointer to camera device structure + * + * @param fb_cfg Pointer to frame buffer configuration + * structure of camera + * + * @retval 0 on success else negative errno code. + */ +__syscall int camera_configure(struct device *cam_dev, + struct camera_fb_cfg *fb_cfg); + +static inline int z_impl_camera_configure(struct device *cam_dev, + struct camera_fb_cfg *fb_cfg) +{ + const struct camera_driver_api *api = cam_dev->driver_api; + + return api->camera_configure_cb(cam_dev, fb_cfg); +} + +/** + * @brief Start camera to capture frames to frame buffer(s) + * + * @param cam_dev Pointer to camera device structure + * + * @param mode Select camera to work on capture mode + * or preview mode + * + * @param bufs Array of buffers for camera to store frames + * + * @param buf_num Number of elements of Array of buffers + * which at lease be one + * + * @param cb Callback function when one frame is received + * which could be NULL + * + * @retval 0 on success else negative errno code. + */ +__syscall int camera_start(struct device *cam_dev, + enum camera_mode mode, void **bufs, u8_t buf_num, + camera_capture_cb cb); + +static inline int z_impl_camera_start(struct device *cam_dev, + enum camera_mode mode, void **bufs, u8_t buf_num, + camera_capture_cb cb) +{ + const struct camera_driver_api *api = cam_dev->driver_api; + + return api->camera_start_cb(cam_dev, mode, bufs, buf_num, cb); +} + +/** + * @brief Acquire one frame from camera + * + * @param cam_dev Pointer to camera device structure + * + * @param fb Pointer to the address of pointer to frame acquired + * + * @param timeout Most ticks to wait for one frame acquired + * + * @retval 0 on frame acquired else negative errno code with + * no frame acquired. + */ +__syscall int camera_acquire_fb(struct device *cam_dev, + void **fb, s32_t timeout); + +static inline int z_impl_camera_acquire_fb( + struct device *cam_dev, void **fb, s32_t timeout) +{ + struct camera_driver_api *api = + (struct camera_driver_api *)cam_dev->driver_api; + + return api->camera_acquire_fb_cb(cam_dev, fb, timeout); +} + +/** + * @brief Release one buffer for camera to store frame to receive + * + * @param cam_dev Pointer to camera device structure + * + * @param fb Pointer to the buffer to release + * + * @retval 0 on buffer released else negative errno code with + * buffer release is rejected. + */ +__syscall int camera_release_fb(struct device *cam_dev, + void *fb); + +static inline int z_impl_camera_release_fb( + struct device *cam_dev, void *fb) +{ + struct camera_driver_api *api = + (struct camera_driver_api *)cam_dev->driver_api; + + return api->camera_release_fb_cb(cam_dev, fb); +} + +/** + * @brief Get primary camera device + * + * @retval pointer to primary camera device, NULL if not found. + */ +struct device *camera_get_primary(void); + +/** + * @brief Get secondary camera device + * + * @retval pointer to secondary camera device, NULL if not found. + */ +struct device *camera_get_secondary(void); + +#include + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_CAMERA_H_*/ diff --git a/include/drivers/camera_drv.h b/include/drivers/camera_drv.h new file mode 100644 index 000000000000..e9d7305e00e4 --- /dev/null +++ b/include/drivers/camera_drv.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2019, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Public API for camera drivers + */ + +#ifndef ZEPHYR_INCLUDE_CAMERA_DRV_H_ +#define ZEPHYR_INCLUDE_CAMERA_DRV_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @struct camera_driver_data + * @brief Structure to describe camera driver data + * Camera driver is supposed contain this data. + */ +struct camera_driver_data { + struct camera_fb_attr fb_attr; + struct camera_capability cap; + camera_capture_cb customer_cb; + enum camera_mode mode; + enum camera_id id; + + /*Image sensor device associated to + * this camera, whihc could be no present + * for USB camera, PCIe camera.. + */ + struct device *sensor_dev; + + /*Point to the camera driver priviate data*/ + u32_t priv[]; +}; + +/** + * @brief Alloc camera driver data + * This function is called by camera driver. + * + * @param priv_size size of private data of camera driver + * + * @param id Primary camera or secondary camera + * + * @param clear TRUE to clear camera driver data + * + * @retval camera driver data. + * + */ +struct camera_driver_data *camera_drv_data_alloc( + u32_t priv_size, enum camera_id id, bool clear); + + +/** + * @brief Get camera driver private data + * This function is called by camera driver. + * + * @param data Pointer to camera driver structure + * + * @retval camera driver private data. + * + */ +static inline void *camera_data_priv( + struct camera_driver_data *data) +{ + return (void *)data->priv; +} + +/** + * @brief Default function to get capability of camera + * This function is called by camera driver. + * + * @param cam_dev Pointer to camera device structure + * + * @param cap Pointer to camera capability structure + * filled by camera driver + * + * @retval 0 on success else negative errno code. + */ +int camera_dev_get_cap(struct device *cam_dev, + struct camera_capability *cap); + +/** + * @brief Default funciotn to configure frame buffer of camera + * This function is called by camera driver. + * + * @param cam_dev Pointer to camera device structure + * + * @param fb_cfg Pointer to frame buffer configuration + * structure of camera + * + * @retval 0 on success else negative errno code. + */ + +int camera_dev_configure(struct device *cam_dev, + struct camera_fb_cfg *fb_cfg); + + +/** + * @brief Register camera device to camera subsys + * This function is called by camera driver. + * + * @param cam_dev Pointer to camera device structure + * + * @retval 0 on success else negative errno code. + * + */ +int camera_dev_register(struct device *cam_dev); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_CAMERA_SRV_H_*/ From 42550efa9aa1a8b9cf2ba510c7946e1da7aa8bda Mon Sep 17 00:00:00 2001 From: Jun Yang Date: Mon, 10 Jun 2019 20:13:20 -0700 Subject: [PATCH 3/6] drivers/camera: support mt9m114 image sensor Support ON MT9M114 under image sensor framework. Signed-off-by: Jun Yang --- drivers/camera/CMakeLists.txt | 2 + drivers/camera/Kconfig | 9 + drivers/camera/mt9m114/CMakeLists.txt | 5 + drivers/camera/mt9m114/Kconfig | 17 + drivers/camera/mt9m114/mt9m114.c | 558 +++++++++++++++++++++++ drivers/camera/mt9m114/mt9m114.h | 614 ++++++++++++++++++++++++++ 6 files changed, 1205 insertions(+) create mode 100644 drivers/camera/mt9m114/CMakeLists.txt create mode 100644 drivers/camera/mt9m114/Kconfig create mode 100644 drivers/camera/mt9m114/mt9m114.c create mode 100644 drivers/camera/mt9m114/mt9m114.h diff --git a/drivers/camera/CMakeLists.txt b/drivers/camera/CMakeLists.txt index dc818ada0ab4..bd021db8e6b7 100644 --- a/drivers/camera/CMakeLists.txt +++ b/drivers/camera/CMakeLists.txt @@ -1,5 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 +add_subdirectory_ifdef(CONFIG_MT9M114 mt9m114) + zephyr_sources(camera_dev.c) zephyr_sources(image_sensor_dev.c) diff --git a/drivers/camera/Kconfig b/drivers/camera/Kconfig index 86d55b819bb4..4d80395e39f7 100644 --- a/drivers/camera/Kconfig +++ b/drivers/camera/Kconfig @@ -44,4 +44,13 @@ config CAMERA_INIT_PRIO so CAMERA_INIT_PRIO must be greater than IMAGE_SENSOR_INIT_PRIO. +menuconfig MT9M114 + bool "MT9M114 image sensor" + depends on I2C + default y + help + Enable driver for the MT9M114 image sensor. + +source "drivers/camera/mt9m114/Kconfig" + endif diff --git a/drivers/camera/mt9m114/CMakeLists.txt b/drivers/camera/mt9m114/CMakeLists.txt new file mode 100644 index 000000000000..eb943eb202f3 --- /dev/null +++ b/drivers/camera/mt9m114/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources_ifdef(CONFIG_MT9M114 mt9m114.c) diff --git a/drivers/camera/mt9m114/Kconfig b/drivers/camera/mt9m114/Kconfig new file mode 100644 index 000000000000..ac62b7ff9628 --- /dev/null +++ b/drivers/camera/mt9m114/Kconfig @@ -0,0 +1,17 @@ +# Kconfig - MT9M114 image sensor configuration options + +# +# Copyright (c) 2019 NXP Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +if MT9M114 + +config MT9M114_NAME + string "Driver name" + default "MT9M114" + help + Device name to identify the MT9M114 image sensor. + +endif diff --git a/drivers/camera/mt9m114/mt9m114.c b/drivers/camera/mt9m114/mt9m114.c new file mode 100644 index 000000000000..039dda1408d5 --- /dev/null +++ b/drivers/camera/mt9m114/mt9m114.c @@ -0,0 +1,558 @@ +/* mt9m114.c - driver for mt9m114 image sensor */ + +/* + * Copyright (c) 2019 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#define LOG_LEVEL LOG_LEVEL_ERR +#include +LOG_MODULE_REGISTER(MT9M114); + +#define MT9M114_DBG + +#undef LOG_ERR +#define LOG_ERR printk + +#ifdef MT9M114_DBG +#undef LOG_INF +#define LOG_INF printk +#endif + +#include "mt9m114.h" + +static const struct img_sensor_reg mt9m114_480_272[] = { + {MT9M114_VAR_CAM_SENSOR_CFG_Y_ADDR_START, W2B, + 0x00D4, W2B}, + /* cam_sensor_cfg_y_addr_start = 212 */ + {MT9M114_VAR_CAM_SENSOR_CFG_X_ADDR_START, W2B, + 0x00A4, W2B}, + /* cam_sensor_cfg_x_addr_start = 164 */ + {MT9M114_VAR_CAM_SENSOR_CFG_Y_ADDR_END, W2B, + 0x02FB, W2B}, + /* cam_sensor_cfg_y_addr_end = 763 */ + {MT9M114_VAR_CAM_SENSOR_CFG_X_ADDR_END, W2B, + 0x046B, W2B}, + /* cam_sensor_cfg_x_addr_end = 1131 */ + {MT9M114_VAR_CAM_SENSOR_CFG_CPIPE_LAST_ROW, W2B, + 0x0223, W2B}, + /* cam_sensor_cfg_cpipe_last_row = 547 */ + {MT9M114_VAR_CAM_CROP_WINDOW_WIDTH, W2B, + 0x03C0, W2B}, + /* cam_crop_window_width = 960 */ + {MT9M114_VAR_CAM_CROP_WINDOW_HEIGHT, W2B, + 0x0220, W2B}, + /* cam_crop_window_height = 544 */ + {MT9M114_VAR_CAM_OUTPUT_WIDTH, W2B, + 0x01E0, W2B}, + /* cam_output_width = 480 */ + {MT9M114_VAR_CAM_OUTPUT_HEIGHT, W2B, + 0x0110, W2B}, + /* cam_output_height = 272 */ + {MT9M114_VAR_CAM_STAT_AWB_CLIP_WINDOW_XEND, W2B, + 0x01DF, W2B}, + /* cam_stat_awb_clip_window_xend = 479 */ + {MT9M114_VAR_CAM_STAT_AWB_CLIP_WINDOW_YEND, W2B, + 0x010F, W2B}, + /* cam_stat_awb_clip_window_yend = 271 */ + {MT9M114_VAR_CAM_STAT_AE_INITIAL_WINDOW_XEND, W2B, + 0x005F, W2B}, + /* cam_stat_ae_initial_window_xend = 95 */ + {MT9M114_VAR_CAM_STAT_AE_INITIAL_WINDOW_YEND, W2B, + 0x0035, W2B}, + /* cam_stat_ae_initial_window_yend = 53 */ +}; + +static const struct img_sensor_reg mt9m114_init_cfg[] = { + {MT9M114_REG_LOGICAL_ADDRESS_ACCESS, W2B, + 0x1000, W2B}, + /* PLL Fout = (Fin * 2 * m) / ((n + 1) * (p + 1)) */ + {MT9M114_VAR_CAM_SYSCTL_PLL_ENABLE, W2B, + 0x01, W1B}, + /* cam_sysctl_pll_enable = 1 */ + {MT9M114_VAR_CAM_SYSCTL_PLL_DIVIDER_M_N, W2B, + 0x0120, W2B}, + /* cam_sysctl_pll_divider_m_n = 288 */ + {MT9M114_VAR_CAM_SYSCTL_PLL_DIVIDER_P, W2B, + 0x0700, W2B}, + /* cam_sysctl_pll_divider_p = 1792 */ + {MT9M114_VAR_CAM_SENSOR_CFG_PIXCLK, W2B, + 0x2DC6C00, W4B}, + /* cam_sensor_cfg_pixclk = 48000000 */ + {0x316A, W2B, + 0x8270, W2B}, + /* auto txlo_row for hot pixel and linear full well optimization */ + {0x316C, W2B, + 0x8270, W2B}, + /* auto txlo for hot pixel and linear full well optimization */ + {0x3ED0, W2B, + 0x2305, W2B}, + /* eclipse setting, ecl range=1, ecl value=2, ivln=3 */ + {0x3ED2, W2B, + 0x77CF, W2B}, + /* TX_hi=12 */ + {0x316E, W2B, + 0x8202, W2B}, + /* auto ecl , threshold 2x, ecl=0 at high gain, ecl=2 for low gain */ + {0x3180, W2B, + 0x87FF, W2B}, + /* enable delta dark */ + {0x30D4, W2B, + 0x6080, W2B}, + /* disable column correction due to AE oscillation problem */ + {0xA802, W2B, + 0x0008, W2B}, + /* RESERVED_AE_TRACK_02 */ + {0x3E14, W2B, + 0xFF39, W2B}, + /* Enabling pixout clamping to VAA during ADC streaming to + * solve column band issue + */ + {MT9M114_VAR_CAM_SENSOR_CFG_ROW_SPEED, W2B, + 0x0001, W2B}, + /* cam_sensor_cfg_row_speed = 1 */ + {MT9M114_VAR_CAM_SENSOR_CFG_FINE_INTEG_TIME_MIN, W2B, + 0x00DB, W2B}, + /* cam_sensor_cfg_fine_integ_time_min = 219 */ + {MT9M114_VAR_CAM_SENSOR_CFG_FINE_INTEG_TIME_MAX, W2B, + 0x07C2, W2B}, + /* cam_sensor_cfg_fine_integ_time_max = 1986 */ + {MT9M114_VAR_CAM_SENSOR_CFG_FRAME_LENGTH_LINES, W2B, + 0x02FE, W2B}, + /* cam_sensor_cfg_frame_length_lines = 766 */ + {MT9M114_VAR_CAM_SENSOR_CFG_LINE_LENGTH_PCK, W2B, + 0x0845, W2B}, + /* cam_sensor_cfg_line_length_pck = 2117 */ + {MT9M114_VAR_CAM_SENSOR_CFG_FINE_CORRECTION, W2B, + 0x0060, W2B}, + /* cam_sensor_cfg_fine_correction = 96 */ + {MT9M114_VAR_CAM_SENSOR_CFG_REG_0_DATA, W2B, + 0x0020, W2B}, + /* cam_sensor_cfg_reg_0_data = 32 */ + {MT9M114_VAR_CAM_SENSOR_CONTROL_READ_MODE, W2B, + 0x0000, W2B}, + /* cam_sensor_control_read_mode = 0 */ + {MT9M114_VAR_CAM_CROP_WINDOW_XOFFSET, W2B, + 0x0000, W2B}, + /* cam_crop_window_xoffset = 0 */ + {MT9M114_VAR_CAM_CROP_WINDOW_YOFFSET, W2B, + 0x0000, W2B}, + /* cam_crop_window_yoffset = 0 */ + {MT9M114_VAR_CAM_CROP_CROPMODE, W2B, + 0x03, W1B}, + /* cam_crop_cropmode = 3 */ + {MT9M114_VAR_CAM_AET_AEMODE, W2B, + 0x00, W1B}, + /* cam_aet_aemode = 0 */ + {MT9M114_VAR_CAM_AET_MAX_FRAME_RATE, W2B, + 0x1D9A, W2B}, + /* cam_aet_max_frame_rate = 7578 */ + {MT9M114_VAR_CAM_AET_MIN_FRAME_RATE, W2B, + 0x1D9A, W2B}, + /* cam_aet_min_frame_rate = 7578 */ + {MT9M114_VAR_CAM_STAT_AWB_CLIP_WINDOW_XSTART, W2B, + 0x0000, W2B}, + /* cam_stat_awb_clip_window_xstart = 0 */ + {MT9M114_VAR_CAM_STAT_AWB_CLIP_WINDOW_YSTART, W2B, + 0x0000, W2B}, + /* cam_stat_awb_clip_window_ystart = 0 */ + {MT9M114_VAR_CAM_STAT_AE_INITIAL_WINDOW_XSTART, W2B, + 0x0000, W2B}, + /* cam_stat_ae_initial_window_xstart = 0 */ + {MT9M114_VAR_CAM_STAT_AE_INITIAL_WINDOW_YSTART, W2B, + 0x0000, W2B}, + /* cam_stat_ae_initial_window_ystart = 0 */ + {MT9M114_REG_PAD_SLEW, W2B, + 0x0777, W2B}, + /* Pad slew rate */ + {MT9M114_VAR_CAM_OUTPUT_FORMAT_YUV, W2B, + 0x0038, W2B}, + /* Must set cam_output_format_yuv_clip for CSI */ +}; + +static int mt9m114_read_reg(struct device *dev, + u16_t reg_addr, u8_t *reg_data, u8_t len) +{ + int ret, i = 0; + u8_t addr_buffer[MT9M114_REG_ADDR_LEN]; + u8_t data_buffer[4]; + struct img_sensor_data *drv_data = dev->driver_data; + + assert(len <= 4); + addr_buffer[1] = reg_addr & 0xFF; + addr_buffer[0] = reg_addr >> 8; + ret = i2c_write_read(drv_data->host_info.i2c, + drv_data->client_info.i2c_addr, + addr_buffer, MT9M114_REG_ADDR_LEN, + data_buffer, len); + if (!ret) { + while (len) { + len--; + reg_data[i] = data_buffer[len]; + i++; + } + } + + return ret; +} + +static int mt9m114_write_reg(struct device *dev, + u16_t reg_addr, u32_t reg_data, u8_t len) +{ + int ret; + u8_t data[MT9M114_REG_ADDR_LEN + 4]; + u8_t data_len = len; + struct img_sensor_data *drv_data = dev->driver_data; + + assert(len <= 4); + data[1] = reg_addr & 0xFF; + data[0] = reg_addr >> 8; + while (data_len) { + data_len--; + data[data_len + MT9M114_REG_ADDR_LEN] = (u8_t)reg_data; + reg_data >>= 8; + } + ret = i2c_write(drv_data->host_info.i2c, (const u8_t *)data, + MT9M114_REG_ADDR_LEN + len, + drv_data->client_info.i2c_addr); + + return ret; +} + +static int mt9m114_read_reg_cb(struct device *dev, + u32_t reg_addr, u8_t reg_len __unused, u8_t *reg_data, u8_t data_len) +{ + return mt9m114_read_reg(dev, (u16_t)reg_addr, reg_data, data_len); +} + +static int mt9m114_write_reg_cb(struct device *dev, + u32_t reg_addr, u8_t reg_len __unused, u32_t reg_data, u8_t data_len) +{ + return mt9m114_write_reg(dev, (u16_t)reg_addr, reg_data, data_len); +} + +static int mt9m114_modify_reg(struct device *dev, + u32_t reg, u8_t data_width, u32_t clr_msk, u32_t value) +{ + int status; + u32_t regval; + + if (data_width != 1 && data_width != 2 && data_width != 4) { + return -EINVAL; + } + + status = mt9m114_read_reg(dev, reg, (u8_t *)®val, data_width); + if (status) { + return status; + } + + regval = (regval & ~(clr_msk)) | (value & clr_msk); + + status = mt9m114_write_reg(dev, reg, regval, data_width); + return status; +} + +static int mt9m114_soft_reset(struct device *dev) +{ + int ret = mt9m114_modify_reg(dev, + MT9M114_REG_RESET_AND_MISC_CONTROL, 2u, 0x01, 0x01); + + if (ret) { + return ret; + } + + k_busy_wait(1000); + ret = mt9m114_modify_reg(dev, + MT9M114_REG_RESET_AND_MISC_CONTROL, 2u, 0x01, 0x00); + k_busy_wait(45 * 1000); + + return ret; +} + +static int mt9m114_multi_write(struct device *dev, + const struct img_sensor_reg regs[], int num) +{ + int status = 0, i; + + for (i = 0; i < num; i++) { + status = mt9m114_write_reg(dev, regs[i].reg, + regs[i].value, (u8_t)regs[i].w_value); + if (status) { + break; + } + } + return status; +} + +static int mt9m114_set_state(struct device *dev, + u8_t next_state) +{ + u16_t value; + int ret; + + /* Set the desired next state. */ + ret = mt9m114_write_reg(dev, MT9M114_VAR_SYSMGR_NEXT_STATE, + next_state, 1); + if (ret) { + return ret; + } + + /* Check that the FW is ready to accept a new command. */ + while (1) { + k_busy_wait(100); + ret = mt9m114_read_reg(dev, + MT9M114_REG_COMMAND_REGISTER, + (u8_t *)&value, 2); + if (ret) + return ret; + if (!(value & MT9M114_COMMAND_SET_STATE)) { + break; + } + } + + /* Issue the Set State command. */ + ret = mt9m114_write_reg(dev, MT9M114_REG_COMMAND_REGISTER, + MT9M114_COMMAND_SET_STATE | MT9M114_COMMAND_OK, 2); + if (ret) { + return ret; + } + + /* Wait for the FW to complete the command. */ + while (1) { + k_busy_wait(100); + ret = mt9m114_read_reg(dev, + MT9M114_REG_COMMAND_REGISTER, + (u8_t *)&value, 2); + if (ret) { + return ret; + } + if (!(value & MT9M114_COMMAND_SET_STATE)) { + break; + } + } + + /* Check the 'OK' bit to see if the command was successful. */ + ret = mt9m114_read_reg(dev, + MT9M114_REG_COMMAND_REGISTER, + (u8_t *)&value, 2); + if (ret) { + return ret; + } + if (!(value & MT9M114_COMMAND_OK)) { + return -EIO; + } + + return ret; +} + +static int mt9m114_reset(struct device *dev) +{ + int ret; + + /* SW reset. */ + ret = mt9m114_soft_reset(dev); + if (ret) { + return ret; + } + + ret = mt9m114_multi_write(dev, mt9m114_init_cfg, + ARRAY_SIZE(mt9m114_init_cfg)); + if (ret) { + return ret; + } + + return ret; +} + +static int mt9m114_set_config(struct device *dev) +{ + struct img_sensor_data *drv_data = dev->driver_data; + u16_t pixformat = 0; + int ret; + + /* Pixel format. */ + if (PIXEL_FORMAT_RGB_565 == + drv_data->client_info.pixformat) { + pixformat |= ((1U << 8U) | (1U << 1U)); + } + + ret = mt9m114_write_reg(dev, + MT9M114_VAR_CAM_OUTPUT_FORMAT, pixformat, 2); + if (ret) { + return ret; + } + + ret = mt9m114_write_reg(dev, + MT9M114_VAR_CAM_PORT_OUTPUT_CONTROL, 0x8000, 2); + if (ret) { + return ret; + } + + /* Resolution 480 * 272*/ + if (drv_data->client_info.width == MT9M114_DEFAULT_WIDTH && + drv_data->client_info.height == MT9M114_DEFAULT_HEIGHT) { + ret = mt9m114_multi_write(dev, + mt9m114_480_272, ARRAY_SIZE(mt9m114_480_272)); + if (ret) { + return ret; + } + } else { + LOG_ERR("MT9M114: other than 480X272 not implemented\r\n"); + return -EINVAL; + } + + /* Execute Change-Config command. */ + ret = mt9m114_set_state(dev, MT9M114_SYS_STATE_ENTER_CONFIG_CHANGE); + if (ret) { + return ret; + } + + ret = mt9m114_set_state(dev, MT9M114_SYS_STATE_START_STREAMING); + + return ret; +} + +static int mt9m114_set_pixformat(struct device *dev, + enum display_pixel_format pixformat) +{ + struct img_sensor_data *drv_data = dev->driver_data; + + if (pixformat != PIXEL_FORMAT_RGB_565) { + LOG_ERR("Other than RGB565 not implemented on mt9m114\r\n"); + return -EINVAL; + } + drv_data->client_info.pixformat = pixformat; + + return 0; +} + +static int mt9m114_set_framesize(struct device *dev, + u16_t width, u16_t height) +{ + struct img_sensor_data *drv_data = dev->driver_data; + + if (width != MT9M114_DEFAULT_WIDTH || + height != MT9M114_DEFAULT_HEIGHT) { + LOG_ERR("Other than 480X272 not implemented" + " on mt9m114 %d X %d\r\n", + width, height); + return -EINVAL; + } + drv_data->client_info.width = width; + drv_data->client_info.height = height; + + return 0; +} + +static int mt9m114_set_contrast(struct device *dev, int level) +{ + struct img_sensor_data *drv_data = dev->driver_data; + + drv_data->client_info.contrast_level = level; + + return 0; +} + +static int mt9m114_set_brightness(struct device *dev, int level) +{ + struct img_sensor_data *drv_data = dev->driver_data; + + drv_data->client_info.bright_level = level; + + return 0; +} + +static int mt9m114_set_effect(struct device *dev, enum img_sensor_effect effect) +{ + struct img_sensor_data *drv_data = dev->driver_data; + + drv_data->client_info.effect = effect; + + return 0; +} + +static int mt9m114_set_gain(struct device *dev, float r_gain_db, + float g_gain_db, float b_gain_db) +{ + struct img_sensor_data *drv_data = dev->driver_data; + + drv_data->client_info.r_gain_db = r_gain_db; + drv_data->client_info.g_gain_db = g_gain_db; + drv_data->client_info.b_gain_db = b_gain_db; + + return 0; +} + +static int mt9m114_get_cap(struct device *dev, + struct img_sensor_capability *cap) +{ + struct img_sensor_data *drv_data = dev->driver_data; + + cap->pixformat_support = + drv_data->client_info.cap.pixformat_support; + cap->width_max = drv_data->client_info.cap.width_max; + cap->height_max = drv_data->client_info.cap.height_max; + + return 0; +} + + +const struct img_sensor_driver_api mt9m114_api = { + .img_sensor_reset_cb = mt9m114_reset, + .img_sensor_get_cap_cb = mt9m114_get_cap, + .img_sensor_read_reg_cb = mt9m114_read_reg_cb, + .img_sensor_write_reg_cb = mt9m114_write_reg_cb, + .img_sensor_set_pixformat_cb = mt9m114_set_pixformat, + .img_sensor_set_framesize_cb = mt9m114_set_framesize, + .img_sensor_set_contrast_cb = mt9m114_set_contrast, + .img_sensor_set_brightness_cb = mt9m114_set_brightness, + .img_sensor_set_rgb_gain_cb = mt9m114_set_gain, + .img_sensor_set_effect_cb = mt9m114_set_effect, + .img_sensor_config_cb = mt9m114_set_config, +}; + +struct img_sensor_info mt9m114_info = { + .sensor_client = { + .i2c_addr = MT9M114_I2C_ADDR, + .sensor_id = MT9M114_CHIP_ID, + .w_sensor_id = W1B, + .id_reg = MT9M114_REG_CHIP_ID, + .w_id_reg = W2B, + .width = MT9M114_DEFAULT_WIDTH, + .height = MT9M114_DEFAULT_HEIGHT, + .pixformat = PIXEL_FORMAT_RGB_565, + .cap = { + .width_max = MT9M114_MAX_WIDTH, + .height_max = MT9M114_MAX_HEIGHT, + .pixformat_support = ( + PIXEL_FORMAT_RGB_565 | + PIXEL_FORMAT_YUV_420 | + PIXEL_FORMAT_YUV_422), + }, + }, + .sensor_api = &mt9m114_api, +}; + +static int mt9m114_dev_init(struct device *dev) +{ + struct img_sensor_info *drv_data = dev->driver_data; + + img_sensor_support_add(drv_data); + + return 0; +} + +DEVICE_AND_API_INIT(mt9m114_dev, + CONFIG_MT9M114_NAME, mt9m114_dev_init, + &mt9m114_info, NULL, POST_KERNEL, + CONFIG_IMAGE_SENSOR_INIT_PRIO, + 0); + diff --git a/drivers/camera/mt9m114/mt9m114.h b/drivers/camera/mt9m114/mt9m114.h new file mode 100644 index 000000000000..295d43b9f201 --- /dev/null +++ b/drivers/camera/mt9m114/mt9m114.h @@ -0,0 +1,614 @@ +/* mt9m114.h - header file for mt9m114 image sensor driver */ + +/* + * Copyright (c) 2019 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_IMAGE_SENSOR_MT9M114_H_ +#define ZEPHYR_DRIVERS_IMAGE_SENSOR_MT9M114_H_ + +#include +#include +#include + +#define MT9M114_MAX_WIDTH 1296 +#define MT9M114_MAX_HEIGHT 976 + +#define MT9M114_DEFAULT_WIDTH 480 +#define MT9M114_DEFAULT_HEIGHT 272 + + +#define MT9M114_CHIP_ID 0x24 +#define MT9M114_I2C_ADDR 0x48 + +#define MT9M114_REG_ADDR_LEN W2B + +/* 1.Core registers */ +#define MT9M114_REG_Y_ADDR_START 0x3002 +#define MT9M114_REG_X_ADDR_START 0x3004 +#define MT9M114_REG_Y_ADDR_END 0x3006 +#define MT9M114_REG_X_ADDR_END 0x3008 +#define MT9M114_REG_FRAME_LENGTH_LINES 0x300A +#define MT9M114_REG_LINE_LENGTH_PCK_ 0x300C +#define MT9M114_REG_COARSE_INTEGRATION_TIME 0x3012 +#define MT9M114_REG_FINE_INTEGRATION_TIME 0x3014 +#define MT9M114_REG_RESET_REGISTER 0x301A +#define MT9M114_REG_FLASH 0x3046 +#define MT9M114_REG_FLASH_COUNT 0x3048 +#define MT9M114_REG_GREEN1_GAIN 0x3056 +#define MT9M114_REG_BLUE_GAIN 0x3058 +#define MT9M114_REG_RED_GAIN 0x305A +#define MT9M114_REG_GREEN2_GAIN 0x305C +#define MT9M114_REG_GLOBAL_GAIN 0x305E +#define MT9M114_REG_FUSE_ID1 0x31F4 +#define MT9M114_REG_FUSE_ID2 0x31F6 +#define MT9M114_REG_FUSE_ID3 0x31F8 +#define MT9M114_REG_FUSE_ID4 0x31FA +#define MT9M114_REG_CHAIN_CONTROL 0x31FC +#define MT9M114_REG_CUSTOMER_REV 0x31FE + +/* 2.SOC1 registers */ +#define MT9M114_REG_COLOR_PIPELINE_CONTROL 0x3210 + +/* 3.SOC2 registers */ +#define MT9M114_REG_P_G1_P0Q0 0x3640 +#define MT9M114_REG_P_G1_P0Q1 0x3642 +#define MT9M114_REG_P_G1_P0Q2 0x3644 +#define MT9M114_REG_P_G1_P0Q3 0x3646 +#define MT9M114_REG_P_G1_P0Q4 0x3648 +#define MT9M114_REG_P_R_P0Q0 0x364A +#define MT9M114_REG_P_R_P0Q1 0x364C +#define MT9M114_REG_P_R_P0Q2 0x364E +#define MT9M114_REG_P_R_P0Q3 0x3650 +#define MT9M114_REG_P_R_P0Q4 0x3652 +#define MT9M114_REG_P_B_P0Q0 0x3654 +#define MT9M114_REG_P_B_P0Q1 0x3656 +#define MT9M114_REG_P_B_P0Q2 0x3658 +#define MT9M114_REG_P_B_P0Q3 0x365A +#define MT9M114_REG_P_B_P0Q4 0x365C +#define MT9M114_REG_P_G2_P0Q0 0x365E +#define MT9M114_REG_P_G2_P0Q1 0x3660 +#define MT9M114_REG_P_G2_P0Q2 0x3662 +#define MT9M114_REG_P_G2_P0Q3 0x3664 +#define MT9M114_REG_P_G2_P0Q4 0x3666 +#define MT9M114_REG_P_G1_P1Q0 0x3680 +#define MT9M114_REG_P_G1_P1Q1 0x3682 +#define MT9M114_REG_P_G1_P1Q2 0x3684 +#define MT9M114_REG_P_G1_P1Q3 0x3686 +#define MT9M114_REG_P_G1_P1Q4 0x3688 +#define MT9M114_REG_P_R_P1Q0 0x368A +#define MT9M114_REG_P_R_P1Q1 0x368C +#define MT9M114_REG_P_R_P1Q2 0x368E +#define MT9M114_REG_P_R_P1Q3 0x3690 +#define MT9M114_REG_P_R_P1Q4 0x3692 +#define MT9M114_REG_P_B_P1Q0 0x3694 +#define MT9M114_REG_P_B_P1Q1 0x3696 +#define MT9M114_REG_P_B_P1Q2 0x3698 +#define MT9M114_REG_P_B_P1Q3 0x369A +#define MT9M114_REG_P_B_P1Q4 0x369C +#define MT9M114_REG_P_G2_P1Q0 0x369E +#define MT9M114_REG_P_G2_P1Q1 0x36A0 +#define MT9M114_REG_P_G2_P1Q2 0x36A2 +#define MT9M114_REG_P_G2_P1Q3 0x36A4 +#define MT9M114_REG_P_G2_P1Q4 0x36A6 +#define MT9M114_REG_P_G1_P2Q0 0x36C0 +#define MT9M114_REG_P_G1_P2Q1 0x36C2 +#define MT9M114_REG_P_G1_P2Q2 0x36C4 +#define MT9M114_REG_P_G1_P2Q3 0x36C6 +#define MT9M114_REG_P_G1_P2Q4 0x36C8 +#define MT9M114_REG_P_R_P2Q0 0x36CA +#define MT9M114_REG_P_R_P2Q1 0x36CC +#define MT9M114_REG_P_R_P2Q2 0x36CE +#define MT9M114_REG_P_R_P2Q3 0x36D0 +#define MT9M114_REG_P_R_P2Q4 0x36D2 +#define MT9M114_REG_P_B_P2Q0 0x36D4 +#define MT9M114_REG_P_B_P2Q1 0x36D6 +#define MT9M114_REG_P_B_P2Q2 0x36D8 +#define MT9M114_REG_P_B_P2Q3 0x36DA +#define MT9M114_REG_P_B_P2Q4 0x36DC +#define MT9M114_REG_P_G2_P2Q0 0x36DE +#define MT9M114_REG_P_G2_P2Q1 0x36E0 +#define MT9M114_REG_P_G2_P2Q2 0x36E2 +#define MT9M114_REG_P_G2_P2Q3 0x36E4 +#define MT9M114_REG_P_G2_P2Q4 0x36E6 +#define MT9M114_REG_P_G1_P3Q0 0x3700 +#define MT9M114_REG_P_G1_P3Q1 0x3702 +#define MT9M114_REG_P_G1_P3Q2 0x3704 +#define MT9M114_REG_P_G1_P3Q3 0x3706 +#define MT9M114_REG_P_G1_P3Q4 0x3708 +#define MT9M114_REG_P_R_P3Q0 0x370A +#define MT9M114_REG_P_R_P3Q1 0x370C +#define MT9M114_REG_P_R_P3Q2 0x370E +#define MT9M114_REG_P_R_P3Q3 0x3710 +#define MT9M114_REG_P_R_P3Q4 0x3712 +#define MT9M114_REG_P_B_P3Q0 0x3714 +#define MT9M114_REG_P_B_P3Q1 0x3716 +#define MT9M114_REG_P_B_P3Q2 0x3718 +#define MT9M114_REG_P_B_P3Q3 0x371A +#define MT9M114_REG_P_B_P3Q4 0x371C +#define MT9M114_REG_P_G2_P3Q0 0x371E +#define MT9M114_REG_P_G2_P3Q1 0x3720 +#define MT9M114_REG_P_G2_P3Q2 0x3722 +#define MT9M114_REG_P_G2_P3Q3 0x3724 +#define MT9M114_REG_P_G2_P3Q4 0x3726 +#define MT9M114_REG_P_G1_P4Q0 0x3740 +#define MT9M114_REG_P_G1_P4Q1 0x3742 +#define MT9M114_REG_P_G1_P4Q2 0x3744 +#define MT9M114_REG_P_G1_P4Q3 0x3746 +#define MT9M114_REG_P_G1_P4Q4 0x3748 +#define MT9M114_REG_P_R_P4Q0 0x374A +#define MT9M114_REG_P_R_P4Q1 0x374C +#define MT9M114_REG_P_R_P4Q2 0x374E +#define MT9M114_REG_P_R_P4Q3 0x3750 +#define MT9M114_REG_P_R_P4Q4 0x3752 +#define MT9M114_REG_P_B_P4Q0 0x3754 +#define MT9M114_REG_P_B_P4Q1 0x3756 +#define MT9M114_REG_P_B_P4Q2 0x3758 +#define MT9M114_REG_P_B_P4Q3 0x375A +#define MT9M114_REG_P_B_P4Q4 0x375C +#define MT9M114_REG_P_G2_P4Q0 0x375E +#define MT9M114_REG_P_G2_P4Q1 0x3760 +#define MT9M114_REG_P_G2_P4Q2 0x3762 +#define MT9M114_REG_P_G2_P4Q3 0x3764 +#define MT9M114_REG_P_G2_P4Q4 0x3766 +#define MT9M114_REG_CENTER_ROW 0x3782 +#define MT9M114_REG_CENTER_COLUMN 0x3784 + +/* 4.SYSCTL registers */ +#define MT9M114_REG_CHIP_ID 0x0000 +#define MT9M114_REG_CLOCKS_CONTROL 0x0016 +#define MT9M114_REG_RESET_AND_MISC_CONTROL 0x001A +#define MT9M114_REG_PAD_SLEW 0x001E +#define MT9M114_REG_USER_DEFINED_DEVICE_ADDRESS_ID 0x002E +#define MT9M114_REG_PAD_CONTROL 0x0032 +#define MT9M114_REG_COMMAND_REGISTER 0x0080 + +/* 5.XDMA registers */ +#define MT9M114_REG_ACCESS_CTL_STAT 0x0982 +#define MT9M114_REG_PHYSICAL_ADDRESS_ACCESS 0x098A +#define MT9M114_REG_LOGICAL_ADDRESS_ACCESS 0x098E +#define MT9M114_REG_MCU_VARIABLE_DATA0 0x0990 +#define MT9M114_REG_MCU_VARIABLE_DATA1 0x0992 +#define MT9M114_REG_MCU_VARIABLE_DATA2 0x0994 +#define MT9M114_REG_MCU_VARIABLE_DATA3 0x0996 +#define MT9M114_REG_MCU_VARIABLE_DATA4 0x0998 +#define MT9M114_REG_MCU_VARIABLE_DATA5 0x099A +#define MT9M114_REG_MCU_VARIABLE_DATA6 0x099C +#define MT9M114_REG_MCU_VARIABLE_DATA7 0x099E + +/*! @brief MT9M114 variables definitions.*/ + +/* 01.Monitor variables */ +#define MT9M114_VAR_MON_MAJOR_VERSION 0x8000 +#define MT9M114_VAR_MON_MINOR_VERSION 0x8002 +#define MT9M114_VAR_MON_RELEASE_VERSION 0x8004 +#define MT9M114_VAR_MON_HEARTBEAT 0x8006 + +/* 02.Sequencer variables */ +#define MT9M114_VAR_SEQ_ERROR_CODE 0x8406 + +/* 03.AE_Rule variables */ +#define MT9M114_VAR_AE_RULE_ALGO 0xA404 +#define MT9M114_VAR_AE_RULE_AVG_Y_FROM_STATS 0xA406 +#define MT9M114_VAR_AE_RULE_AE_WEIGHT_TABLE_0_0 0xA407 +#define MT9M114_VAR_AE_RULE_AE_WEIGHT_TABLE_0_1 0xA408 +#define MT9M114_VAR_AE_RULE_AE_WEIGHT_TABLE_0_2 0xA409 +#define MT9M114_VAR_AE_RULE_AE_WEIGHT_TABLE_0_3 0xA40A +#define MT9M114_VAR_AE_RULE_AE_WEIGHT_TABLE_0_4 0xA40B +#define MT9M114_VAR_AE_RULE_AE_WEIGHT_TABLE_1_0 0xA40C +#define MT9M114_VAR_AE_RULE_AE_WEIGHT_TABLE_1_1 0xA40D +#define MT9M114_VAR_AE_RULE_AE_WEIGHT_TABLE_1_2 0xA40E +#define MT9M114_VAR_AE_RULE_AE_WEIGHT_TABLE_1_3 0xA40F +#define MT9M114_VAR_AE_RULE_AE_WEIGHT_TABLE_1_4 0xA410 +#define MT9M114_VAR_AE_RULE_AE_WEIGHT_TABLE_2_0 0xA411 +#define MT9M114_VAR_AE_RULE_AE_WEIGHT_TABLE_2_1 0xA412 +#define MT9M114_VAR_AE_RULE_AE_WEIGHT_TABLE_2_2 0xA413 +#define MT9M114_VAR_AE_RULE_AE_WEIGHT_TABLE_2_3 0xA414 +#define MT9M114_VAR_AE_RULE_AE_WEIGHT_TABLE_2_4 0xA415 +#define MT9M114_VAR_AE_RULE_AE_WEIGHT_TABLE_3_0 0xA416 +#define MT9M114_VAR_AE_RULE_AE_WEIGHT_TABLE_3_1 0xA417 +#define MT9M114_VAR_AE_RULE_AE_WEIGHT_TABLE_3_2 0xA418 +#define MT9M114_VAR_AE_RULE_AE_WEIGHT_TABLE_3_3 0xA419 +#define MT9M114_VAR_AE_RULE_AE_WEIGHT_TABLE_3_4 0xA41A +#define MT9M114_VAR_AE_RULE_AE_WEIGHT_TABLE_4_0 0xA41B +#define MT9M114_VAR_AE_RULE_AE_WEIGHT_TABLE_4_1 0xA41C +#define MT9M114_VAR_AE_RULE_AE_WEIGHT_TABLE_4_2 0xA41D +#define MT9M114_VAR_AE_RULE_AE_WEIGHT_TABLE_4_3 0xA41E +#define MT9M114_VAR_AE_RULE_AE_WEIGHT_TABLE_4_4 0xA41F +#define MT9M114_VAR_AE_RULE_AE_ADAPTIVE_STRENGTH 0xA420 + +/* 04.AE_Track variables */ +#define MT9M114_VAR_AE_TRACK_STATUS 0xA800 +#define MT9M114_VAR_AE_TRACK_ALGO 0xA804 +#define MT9M114_VAR_AE_TRACK_TARGET_AVERAGE_LUMA 0xA807 +#define MT9M114_VAR_AE_TRACK_GATE_PERCENTAGE 0xA808 +#define MT9M114_VAR_AE_TRACK_CURRENT_AVERAGE_LUMA 0xA809 +#define MT9M114_VAR_AE_TRACK_AE_TRACKING_DAMPENING_SPEED 0xA80A +#define MT9M114_VAR_AE_TRACK_AE_DAMPENING_SPEED 0xA80B +#define MT9M114_VAR_AE_TRACK_SKIP_FRAMES_COUNTER 0xA80D +#define MT9M114_VAR_AE_TRACK_CURRENT_FLICKER_LINES 0xA80E +#define MT9M114_VAR_AE_TRACK_FDZONE 0xA818 +#define MT9M114_VAR_AE_TRACK_ZONE 0xA81B +#define MT9M114_VAR_AE_TRACK_FLICKER_LINES_50HZ 0xA826 +#define MT9M114_VAR_AE_TRACK_VIRT_EXPOSURE_LOG 0xA828 +#define MT9M114_VAR_AE_TRACK_MIN_VIRT_EXPOSURE_LOG_ZONE0 0xA82A +#define MT9M114_VAR_AE_TRACK_MAX_VIRT_EXPOSURE_LOG_ZONE0 0xA82C +#define MT9M114_VAR_AE_TRACK_MAX_VIRT_EXPOSURE_LOG_ZONE1 0xA82E +#define MT9M114_VAR_AE_TRACK_VIRT_GAIN 0xA838 + +/* 05.AWB variables */ +#define MT9M114_VAR_AWB_STATUS 0xAC00 +#define MT9M114_VAR_AWB_MODE 0xAC02 +#define MT9M114_VAR_AWB_R_RATIO_LOWER 0xAC06 +#define MT9M114_VAR_AWB_R_RATIO_UPPER 0xAC07 +#define MT9M114_VAR_AWB_B_RATIO_LOWER 0xAC08 +#define MT9M114_VAR_AWB_B_RATIO_UPPER 0xAC09 +#define MT9M114_VAR_AWB_R_SCENE_RATIO_LOWER 0xAC0A +#define MT9M114_VAR_AWB_R_SCENE_RATIO_UPPER 0xAC0B +#define MT9M114_VAR_AWB_B_SCENE_RATIO_LOWER 0xAC0C +#define MT9M114_VAR_AWB_B_SCENE_RATIO_UPPER 0xAC0D +#define MT9M114_VAR_AWB_R_RATIO_PRE_AWB 0xAC0E +#define MT9M114_VAR_AWB_B_RATIO_PRE_AWB 0xAC0F +#define MT9M114_VAR_AWB_R_GAIN 0xAC12 +#define MT9M114_VAR_AWB_B_GAIN 0xAC14 +#define MT9M114_VAR_AWB_PRE_AWB_RATIOS_TRACKING_SPEED 0xAC16 +#define MT9M114_VAR_AWB_PIXEL_THRESHOLD_COUNT 0xAC18 + +/* 06.BlackLevel variables */ +#define MT9M114_VAR_BLACKLEVEL_ALGO 0xB004 +#define MT9M114_VAR_BLACKLEVEL_MAX_BLACK_LEVEL 0xB00C +#define MT9M114_VAR_BLACKLEVEL_BLACK_LEVEL_DAMPENING 0xB00D + +/* 07.CCM variables */ +#define MT9M114_VAR_CCM_ALGO 0xB404 +#define MT9M114_VAR_CCM_0 0xB406 +#define MT9M114_VAR_CCM_1 0xB408 +#define MT9M114_VAR_CCM_2 0xB40A +#define MT9M114_VAR_CCM_3 0xB40C +#define MT9M114_VAR_CCM_4 0xB40E +#define MT9M114_VAR_CCM_5 0xB410 +#define MT9M114_VAR_CCM_6 0xB412 +#define MT9M114_VAR_CCM_7 0xB414 +#define MT9M114_VAR_CCM_8 0xB416 +#define MT9M114_VAR_CCM_LL_DELTA_CCM_0 0xB418 +#define MT9M114_VAR_CCM_LL_DELTA_CCM_1 0xB41A +#define MT9M114_VAR_CCM_LL_DELTA_CCM_2 0xB41C +#define MT9M114_VAR_CCM_LL_DELTA_CCM_3 0xB41E +#define MT9M114_VAR_CCM_LL_DELTA_CCM_4 0xB420 +#define MT9M114_VAR_CCM_LL_DELTA_CCM_5 0xB422 +#define MT9M114_VAR_CCM_LL_DELTA_CCM_6 0xB424 +#define MT9M114_VAR_CCM_LL_DELTA_CCM_7 0xB426 +#define MT9M114_VAR_CCM_LL_DELTA_CCM_8 0xB428 +#define MT9M114_VAR_CCM_DELTA_GAIN 0xB42A +#define MT9M114_VAR_CCM_DELTA_THRESH 0xB42B + +/* 08.LowLight variables */ +#define MT9M114_VAR_LL_MODE 0xBC02 +#define MT9M114_VAR_LL_ALGO 0xBC04 +#define MT9M114_VAR_LL_GAMMA_SELECT 0xBC07 +#define MT9M114_VAR_LL_GAMMA_CONTRAST_CURVE_0 0xBC0A +#define MT9M114_VAR_LL_GAMMA_CONTRAST_CURVE_1 0xBC0B +#define MT9M114_VAR_LL_GAMMA_CONTRAST_CURVE_2 0xBC0C +#define MT9M114_VAR_LL_GAMMA_CONTRAST_CURVE_3 0xBC0D +#define MT9M114_VAR_LL_GAMMA_CONTRAST_CURVE_4 0xBC0E +#define MT9M114_VAR_LL_GAMMA_CONTRAST_CURVE_5 0xBC0F +#define MT9M114_VAR_LL_GAMMA_CONTRAST_CURVE_6 0xBC10 +#define MT9M114_VAR_LL_GAMMA_CONTRAST_CURVE_7 0xBC11 +#define MT9M114_VAR_LL_GAMMA_CONTRAST_CURVE_8 0xBC12 +#define MT9M114_VAR_LL_GAMMA_CONTRAST_CURVE_9 0xBC13 +#define MT9M114_VAR_LL_GAMMA_CONTRAST_CURVE_10 0xBC14 +#define MT9M114_VAR_LL_GAMMA_CONTRAST_CURVE_11 0xBC15 +#define MT9M114_VAR_LL_GAMMA_CONTRAST_CURVE_12 0xBC16 +#define MT9M114_VAR_LL_GAMMA_CONTRAST_CURVE_13 0xBC17 +#define MT9M114_VAR_LL_GAMMA_CONTRAST_CURVE_14 0xBC18 +#define MT9M114_VAR_LL_GAMMA_CONTRAST_CURVE_15 0xBC19 +#define MT9M114_VAR_LL_GAMMA_CONTRAST_CURVE_16 0xBC1A +#define MT9M114_VAR_LL_GAMMA_CONTRAST_CURVE_17 0xBC1B +#define MT9M114_VAR_LL_GAMMA_CONTRAST_CURVE_18 0xBC1C +#define MT9M114_VAR_LL_GAMMA_NRCURVE_0 0xBC1D +#define MT9M114_VAR_LL_GAMMA_NRCURVE_1 0xBC1E +#define MT9M114_VAR_LL_GAMMA_NRCURVE_2 0xBC1F +#define MT9M114_VAR_LL_GAMMA_NRCURVE_3 0xBC20 +#define MT9M114_VAR_LL_GAMMA_NRCURVE_4 0xBC21 +#define MT9M114_VAR_LL_GAMMA_NRCURVE_5 0xBC22 +#define MT9M114_VAR_LL_GAMMA_NRCURVE_6 0xBC23 +#define MT9M114_VAR_LL_GAMMA_NRCURVE_7 0xBC24 +#define MT9M114_VAR_LL_GAMMA_NRCURVE_8 0xBC25 +#define MT9M114_VAR_LL_GAMMA_NRCURVE_9 0xBC26 +#define MT9M114_VAR_LL_GAMMA_NRCURVE_10 0xBC27 +#define MT9M114_VAR_LL_GAMMA_NRCURVE_11 0xBC28 +#define MT9M114_VAR_LL_GAMMA_NRCURVE_12 0xBC29 +#define MT9M114_VAR_LL_GAMMA_NRCURVE_13 0xBC2A +#define MT9M114_VAR_LL_GAMMA_NRCURVE_14 0xBC2B +#define MT9M114_VAR_LL_GAMMA_NRCURVE_15 0xBC2C +#define MT9M114_VAR_LL_GAMMA_NRCURVE_16 0xBC2D +#define MT9M114_VAR_LL_GAMMA_NRCURVE_17 0xBC2E +#define MT9M114_VAR_LL_GAMMA_NRCURVE_18 0xBC2F +#define MT9M114_VAR_LL_BM_PRECISION_BITS 0xBC31 +#define MT9M114_VAR_LL_AVERAGE_LUMA_FADE_TO_BLACK 0xBC3A +#define MT9M114_VAR_LL_FADE_TO_BLACK_DAMPENING_SPEED 0xBC3C + +/* 09.CameraControl variables */ +#define MT9M114_VAR_CAM_SENSOR_CFG_Y_ADDR_START 0xC800 +#define MT9M114_VAR_CAM_SENSOR_CFG_X_ADDR_START 0xC802 +#define MT9M114_VAR_CAM_SENSOR_CFG_Y_ADDR_END 0xC804 +#define MT9M114_VAR_CAM_SENSOR_CFG_X_ADDR_END 0xC806 +#define MT9M114_VAR_CAM_SENSOR_CFG_PIXCLK 0xC808 +#define MT9M114_VAR_CAM_SENSOR_CFG_ROW_SPEED 0xC80C +#define MT9M114_VAR_CAM_SENSOR_CFG_FINE_INTEG_TIME_MIN 0xC80E +#define MT9M114_VAR_CAM_SENSOR_CFG_FINE_INTEG_TIME_MAX 0xC810 +#define MT9M114_VAR_CAM_SENSOR_CFG_FRAME_LENGTH_LINES 0xC812 +#define MT9M114_VAR_CAM_SENSOR_CFG_LINE_LENGTH_PCK 0xC814 +#define MT9M114_VAR_CAM_SENSOR_CFG_FINE_CORRECTION 0xC816 +#define MT9M114_VAR_CAM_SENSOR_CFG_CPIPE_LAST_ROW 0xC818 +#define MT9M114_VAR_CAM_SENSOR_CFG_REG_0_DATA 0xC826 +#define MT9M114_VAR_CAM_SENSOR_CONTROL_READ_MODE 0xC834 +#define MT9M114_VAR_CAM_SENSOR_CONTROL_ANALOG_GAIN 0xC836 +#define MT9M114_VAR_CAM_SENSOR_CONTROL_VIRT_COLUMN_GAIN 0xC838 +#define MT9M114_VAR_CAM_SENSOR_CONTROL_FRAME_LENGTH_LINES 0xC83A +#define MT9M114_VAR_CAM_SENSOR_CONTROL_COARSE_INTEGRATION_TIME 0xC83C +#define MT9M114_VAR_CAM_SENSOR_CONTROL_FINE_INTEGRATION_TIME 0xC83E +#define MT9M114_VAR_CAM_CPIPE_CONTROL_DGAIN_RED 0xC840 +#define MT9M114_VAR_CAM_CPIPE_CONTROL_DGAIN_GREEN1 0xC842 +#define MT9M114_VAR_CAM_CPIPE_CONTROL_DGAIN_GREEN2 0xC844 +#define MT9M114_VAR_CAM_CPIPE_CONTROL_DGAIN_BLUE 0xC846 +#define MT9M114_VAR_CAM_CPIPE_CONTROL_DGAIN_SECOND 0xC848 +#define MT9M114_VAR_CAM_CPIPE_CONTROL_SECOND_BLACK_LEVEL 0xC84B +#define MT9M114_VAR_CAM_MODE_SELECT 0xC84C +#define MT9M114_VAR_CAM_MODE_TEST_PATTERN_SELECT 0xC84D +#define MT9M114_VAR_CAM_MODE_TEST_PATTERN_RED 0xC84E +#define MT9M114_VAR_CAM_MODE_TEST_PATTERN_GREEN 0xC850 +#define MT9M114_VAR_CAM_MODE_TEST_PATTERN_BLUE 0xC852 +#define MT9M114_VAR_CAM_CROP_WINDOW_XOFFSET 0xC854 +#define MT9M114_VAR_CAM_CROP_WINDOW_YOFFSET 0xC856 +#define MT9M114_VAR_CAM_CROP_WINDOW_WIDTH 0xC858 +#define MT9M114_VAR_CAM_CROP_WINDOW_HEIGHT 0xC85A +#define MT9M114_VAR_CAM_CROP_CROPMODE 0xC85C +#define MT9M114_VAR_CAM_SCALE_VERTICAL_TC_MODE 0xC85E +#define MT9M114_VAR_CAM_SCALE_VERTICAL_TC_PERCENTAGE 0xC860 +#define MT9M114_VAR_CAM_SCALE_VERTICAL_TC_STRETCH_FACTOR 0xC862 +#define MT9M114_VAR_CAM_OUTPUT_WIDTH 0xC868 +#define MT9M114_VAR_CAM_OUTPUT_HEIGHT 0xC86A +#define MT9M114_VAR_CAM_OUTPUT_FORMAT 0xC86C +#define MT9M114_VAR_CAM_OUTPUT_FORMAT_YUV 0xC86E +#define MT9M114_VAR_CAM_OUTPUT_Y_OFFSET 0xC870 +#define MT9M114_VAR_CAM_HUE_ANGLE 0xC873 +#define MT9M114_VAR_CAM_SFX_CONTROL 0xC874 +#define MT9M114_VAR_CAM_SFX_SOLARIZATION_THRESH 0xC875 +#define MT9M114_VAR_CAM_SFX_SEPIA_CR 0xC876 +#define MT9M114_VAR_CAM_SFX_SEPIA_CB 0xC877 +#define MT9M114_VAR_CAM_AET_AEMODE 0xC878 +#define MT9M114_VAR_CAM_AET_SKIP_FRAMES 0xC879 +#define MT9M114_VAR_CAM_AET_TARGET_AVERAGE_LUMA 0xC87A +#define MT9M114_VAR_CAM_AET_TARGET_AVERAGE_LUMA_DARK 0xC87B +#define MT9M114_VAR_CAM_AET_BLACK_CLIPPING_TARGET 0xC87C +#define MT9M114_VAR_CAM_AET_AE_MIN_VIRT_INT_TIME_PCLK 0xC87E +#define MT9M114_VAR_CAM_AET_AE_MIN_VIRT_DGAIN 0xC880 +#define MT9M114_VAR_CAM_AET_AE_MAX_VIRT_DGAIN 0xC882 +#define MT9M114_VAR_CAM_AET_AE_MIN_VIRT_AGAIN 0xC884 +#define MT9M114_VAR_CAM_AET_AE_MAX_VIRT_AGAIN 0xC886 +#define MT9M114_VAR_CAM_AET_AE_VIRT_GAIN_TH_EG 0xC888 +#define MT9M114_VAR_CAM_AET_AE_EG_GATE_PERCENTAGE 0xC88A +#define MT9M114_VAR_CAM_AET_FLICKER_FREQ_HZ 0xC88B +#define MT9M114_VAR_CAM_AET_MAX_FRAME_RATE 0xC88C +#define MT9M114_VAR_CAM_AET_MIN_FRAME_RATE 0xC88E +#define MT9M114_VAR_CAM_AET_TARGET_GAIN 0xC890 +#define MT9M114_VAR_CAM_AWB_CCM_L_0 0xC892 +#define MT9M114_VAR_CAM_AWB_CCM_L_1 0xC894 +#define MT9M114_VAR_CAM_AWB_CCM_L_2 0xC896 +#define MT9M114_VAR_CAM_AWB_CCM_L_3 0xC898 +#define MT9M114_VAR_CAM_AWB_CCM_L_4 0xC89A +#define MT9M114_VAR_CAM_AWB_CCM_L_5 0xC89C +#define MT9M114_VAR_CAM_AWB_CCM_L_6 0xC89E +#define MT9M114_VAR_CAM_AWB_CCM_L_7 0xC8A0 +#define MT9M114_VAR_CAM_AWB_CCM_L_8 0xC8A2 +#define MT9M114_VAR_CAM_AWB_CCM_M_0 0xC8A4 +#define MT9M114_VAR_CAM_AWB_CCM_M_1 0xC8A6 +#define MT9M114_VAR_CAM_AWB_CCM_M_2 0xC8A8 +#define MT9M114_VAR_CAM_AWB_CCM_M_3 0xC8AA +#define MT9M114_VAR_CAM_AWB_CCM_M_4 0xC8AC +#define MT9M114_VAR_CAM_AWB_CCM_M_5 0xC8AE +#define MT9M114_VAR_CAM_AWB_CCM_M_6 0xC8B0 +#define MT9M114_VAR_CAM_AWB_CCM_M_7 0xC8B2 +#define MT9M114_VAR_CAM_AWB_CCM_M_8 0xC8B4 +#define MT9M114_VAR_CAM_AWB_CCM_R_0 0xC8B6 +#define MT9M114_VAR_CAM_AWB_CCM_R_1 0xC8B8 +#define MT9M114_VAR_CAM_AWB_CCM_R_2 0xC8BA +#define MT9M114_VAR_CAM_AWB_CCM_R_3 0xC8BC +#define MT9M114_VAR_CAM_AWB_CCM_R_4 0xC8BE +#define MT9M114_VAR_CAM_AWB_CCM_R_5 0xC8C0 +#define MT9M114_VAR_CAM_AWB_CCM_R_6 0xC8C2 +#define MT9M114_VAR_CAM_AWB_CCM_R_7 0xC8C4 +#define MT9M114_VAR_CAM_AWB_CCM_R_8 0xC8C6 +#define MT9M114_VAR_CAM_AWB_CCM_L_RG_GAIN 0xC8C8 +#define MT9M114_VAR_CAM_AWB_CCM_L_BG_GAIN 0xC8CA +#define MT9M114_VAR_CAM_AWB_CCM_M_RG_GAIN 0xC8CC +#define MT9M114_VAR_CAM_AWB_CCM_M_BG_GAIN 0xC8CE +#define MT9M114_VAR_CAM_AWB_CCM_R_RG_GAIN 0xC8D0 +#define MT9M114_VAR_CAM_AWB_CCM_R_BG_GAIN 0xC8D2 +#define MT9M114_VAR_CAM_AWB_CCM_L_CTEMP 0xC8D4 +#define MT9M114_VAR_CAM_AWB_CCM_M_CTEMP 0xC8D6 +#define MT9M114_VAR_CAM_AWB_CCM_R_CTEMP 0xC8D8 +#define MT9M114_VAR_CAM_AWB_LL_CCM_0 0xC8DA +#define MT9M114_VAR_CAM_AWB_LL_CCM_1 0xC8DC +#define MT9M114_VAR_CAM_AWB_LL_CCM_2 0xC8DE +#define MT9M114_VAR_CAM_AWB_LL_CCM_3 0xC8E0 +#define MT9M114_VAR_CAM_AWB_LL_CCM_4 0xC8E2 +#define MT9M114_VAR_CAM_AWB_LL_CCM_5 0xC8E4 +#define MT9M114_VAR_CAM_AWB_LL_CCM_6 0xC8E6 +#define MT9M114_VAR_CAM_AWB_LL_CCM_7 0xC8E8 +#define MT9M114_VAR_CAM_AWB_LL_CCM_8 0xC8EA +#define MT9M114_VAR_CAM_AWB_COLOR_TEMPERATURE_MIN 0xC8EC +#define MT9M114_VAR_CAM_AWB_COLOR_TEMPERATURE_MAX 0xC8EE +#define MT9M114_VAR_CAM_AWB_COLOR_TEMPERATURE 0xC8F0 +#define MT9M114_VAR_CAM_AWB_AWB_XSCALE 0xC8F2 +#define MT9M114_VAR_CAM_AWB_AWB_YSCALE 0xC8F3 +#define MT9M114_VAR_CAM_AWB_AWB_WEIGHTS_0 0xC8F4 +#define MT9M114_VAR_CAM_AWB_AWB_WEIGHTS_1 0xC8F6 +#define MT9M114_VAR_CAM_AWB_AWB_WEIGHTS_2 0xC8F8 +#define MT9M114_VAR_CAM_AWB_AWB_WEIGHTS_3 0xC8FA +#define MT9M114_VAR_CAM_AWB_AWB_WEIGHTS_4 0xC8FC +#define MT9M114_VAR_CAM_AWB_AWB_WEIGHTS_5 0xC8FE +#define MT9M114_VAR_CAM_AWB_AWB_WEIGHTS_6 0xC900 +#define MT9M114_VAR_CAM_AWB_AWB_WEIGHTS_7 0xC902 +#define MT9M114_VAR_CAM_AWB_AWB_XSHIFT_PRE_ADJ 0xC904 +#define MT9M114_VAR_CAM_AWB_AWB_YSHIFT_PRE_ADJ 0xC906 +#define MT9M114_VAR_CAM_AWB_AWBMODE 0xC909 +#define MT9M114_VAR_CAM_AWB_TINTS_CTEMP_THRESHOLD 0xC90A +#define MT9M114_VAR_CAM_AWB_K_R_L 0xC90C +#define MT9M114_VAR_CAM_AWB_K_G_L 0xC90D +#define MT9M114_VAR_CAM_AWB_K_B_L 0xC90E +#define MT9M114_VAR_CAM_AWB_K_R_R 0xC90F +#define MT9M114_VAR_CAM_AWB_K_G_R 0xC910 +#define MT9M114_VAR_CAM_AWB_K_B_R 0xC911 +#define MT9M114_VAR_CAM_STAT_AWB_CLIP_WINDOW_XSTART 0xC914 +#define MT9M114_VAR_CAM_STAT_AWB_CLIP_WINDOW_YSTART 0xC916 +#define MT9M114_VAR_CAM_STAT_AWB_CLIP_WINDOW_XEND 0xC918 +#define MT9M114_VAR_CAM_STAT_AWB_CLIP_WINDOW_YEND 0xC91A +#define MT9M114_VAR_CAM_STAT_AE_INITIAL_WINDOW_XSTART 0xC91C +#define MT9M114_VAR_CAM_STAT_AE_INITIAL_WINDOW_YSTART 0xC91E +#define MT9M114_VAR_CAM_STAT_AE_INITIAL_WINDOW_XEND 0xC920 +#define MT9M114_VAR_CAM_STAT_AE_INITIAL_WINDOW_YEND 0xC922 +#define MT9M114_VAR_CAM_LL_LLMODE 0xC924 +#define MT9M114_VAR_CAM_LL_START_BRIGHTNESS 0xC926 +#define MT9M114_VAR_CAM_LL_STOP_BRIGHTNESS 0xC928 +#define MT9M114_VAR_CAM_LL_START_SATURATION 0xC92A +#define MT9M114_VAR_CAM_LL_END_SATURATION 0xC92B +#define MT9M114_VAR_CAM_LL_START_DESATURATION 0xC92C +#define MT9M114_VAR_CAM_LL_END_DESATURATION 0xC92D +#define MT9M114_VAR_CAM_LL_START_DEMOSAIC 0xC92E +#define MT9M114_VAR_CAM_LL_START_AP_GAIN 0xC92F +#define MT9M114_VAR_CAM_LL_START_AP_THRESH 0xC930 +#define MT9M114_VAR_CAM_LL_STOP_DEMOSAIC 0xC931 +#define MT9M114_VAR_CAM_LL_STOP_AP_GAIN 0xC932 +#define MT9M114_VAR_CAM_LL_STOP_AP_THRESH 0xC933 +#define MT9M114_VAR_CAM_LL_START_NR_RED 0xC934 +#define MT9M114_VAR_CAM_LL_START_NR_GREEN 0xC935 +#define MT9M114_VAR_CAM_LL_START_NR_BLUE 0xC936 +#define MT9M114_VAR_CAM_LL_START_NR_THRESH 0xC937 +#define MT9M114_VAR_CAM_LL_STOP_NR_RED 0xC938 +#define MT9M114_VAR_CAM_LL_STOP_NR_GREEN 0xC939 +#define MT9M114_VAR_CAM_LL_STOP_NR_BLUE 0xC93A +#define MT9M114_VAR_CAM_LL_STOP_NR_THRESH 0xC93B +#define MT9M114_VAR_CAM_LL_START_CONTRAST_BM 0xC93C +#define MT9M114_VAR_CAM_LL_STOP_CONTRAST_BM 0xC93E +#define MT9M114_VAR_CAM_LL_GAMMA 0xC940 +#define MT9M114_VAR_CAM_LL_START_CONTRAST_GRADIENT 0xC942 +#define MT9M114_VAR_CAM_LL_STOP_CONTRAST_GRADIENT 0xC943 +#define MT9M114_VAR_CAM_LL_START_CONTRAST_LUMA_PERCENTAGE 0xC944 +#define MT9M114_VAR_CAM_LL_STOP_CONTRAST_LUMA_PERCENTAGE 0xC945 +#define MT9M114_VAR_CAM_LL_START_GAIN_METRIC 0xC946 +#define MT9M114_VAR_CAM_LL_STOP_GAIN_METRIC 0xC948 +#define MT9M114_VAR_CAM_LL_START_FADE_TO_BLACK_LUMA 0xC94A +#define MT9M114_VAR_CAM_LL_STOP_FADE_TO_BLACK_LUMA 0xC94C +#define MT9M114_VAR_CAM_LL_CLUSTER_DC_TH_BM 0xC94E +#define MT9M114_VAR_CAM_LL_CLUSTER_DC_GATE_PERCENTAGE 0xC950 +#define MT9M114_VAR_CAM_LL_SUMMING_SENSITIVITY_FACTOR 0xC951 +#define MT9M114_VAR_CAM_LL_START_TARGET_LUMA_BM 0xC952 +#define MT9M114_VAR_CAM_LL_STOP_TARGET_LUMA_BM 0xC954 +#define MT9M114_VAR_CAM_LL_INV_BRIGHTNESS_METRIC 0xC956 +#define MT9M114_VAR_CAM_LL_GAIN_METRIC 0xC958 +#define MT9M114_VAR_CAM_SEQ_UV_COLOR_BOOST 0xC95A +#define MT9M114_VAR_CAM_PGA_PGA_CONTROL 0xC95E +#define MT9M114_VAR_CAM_PGA_L_CONFIG_COLOUR_TEMP 0xC960 +#define MT9M114_VAR_CAM_PGA_L_CONFIG_GREEN_RED_Q14 0xC962 +#define MT9M114_VAR_CAM_PGA_L_CONFIG_RED_Q14 0xC964 +#define MT9M114_VAR_CAM_PGA_L_CONFIG_GREEN_BLUE_Q14 0xC966 +#define MT9M114_VAR_CAM_PGA_L_CONFIG_BLUE_Q14 0xC968 +#define MT9M114_VAR_CAM_PGA_M_CONFIG_COLOUR_TEMP 0xC96A +#define MT9M114_VAR_CAM_PGA_M_CONFIG_GREEN_RED_Q14 0xC96C +#define MT9M114_VAR_CAM_PGA_M_CONFIG_RED_Q14 0xC96E +#define MT9M114_VAR_CAM_PGA_M_CONFIG_GREEN_BLUE_Q14 0xC970 +#define MT9M114_VAR_CAM_PGA_M_CONFIG_BLUE_Q14 0xC972 +#define MT9M114_VAR_CAM_PGA_R_CONFIG_COLOUR_TEMP 0xC974 +#define MT9M114_VAR_CAM_PGA_R_CONFIG_GREEN_RED_Q14 0xC976 +#define MT9M114_VAR_CAM_PGA_R_CONFIG_RED_Q14 0xC978 +#define MT9M114_VAR_CAM_PGA_R_CONFIG_GREEN_BLUE_Q14 0xC97A +#define MT9M114_VAR_CAM_PGA_R_CONFIG_BLUE_Q14 0xC97C +#define MT9M114_VAR_CAM_SYSCTL_PLL_ENABLE 0xC97E +#define MT9M114_VAR_CAM_SYSCTL_PLL_DIVIDER_M_N 0xC980 +#define MT9M114_VAR_CAM_SYSCTL_PLL_DIVIDER_P 0xC982 +#define MT9M114_VAR_CAM_PORT_OUTPUT_CONTROL 0xC984 +#define MT9M114_VAR_CAM_PORT_PORCH 0xC986 +#define MT9M114_VAR_CAM_PORT_MIPI_TIMING_T_HS_ZERO 0xC988 +#define MT9M114_VAR_CAM_PORT_MIPI_TIMING_T_HS_EXIT_HS_TRAIL 0xC98A +#define MT9M114_VAR_CAM_PORT_MIPI_TIMING_T_CLK_POST_CLK_PRE 0xC98C +#define MT9M114_VAR_CAM_PORT_MIPI_TIMING_T_CLK_TRAIL_CLK_ZERO 0xC98E +#define MT9M114_VAR_CAM_PORT_MIPI_TIMING_T_LPX 0xC990 +#define MT9M114_VAR_CAM_PORT_MIPI_TIMING_INIT_TIMING 0xC992 + +/* 10.UVC_Control variables */ +#define MT9M114_VAR_UVC_AE_MODE_CONTROL 0xCC00 +#define MT9M114_VAR_UVC_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL 0xCC01 +#define MT9M114_VAR_UVC_AE_PRIORITY_CONTROL 0xCC02 +#define MT9M114_VAR_UVC_POWER_LINE_FREQUENCY_CONTROL 0xCC03 +#define MT9M114_VAR_UVC_EXPOSURE_TIME_ABSOLUTE_CONTROL 0xCC04 +#define MT9M114_VAR_UVC_BACKLIGHT_COMPENSATION_CONTROL 0xCC08 +#define MT9M114_VAR_UVC_BRIGHTNESS_CONTROL 0xCC0A +#define MT9M114_VAR_UVC_CONTRAST_CONTROL 0xCC0C +#define MT9M114_VAR_UVC_GAIN_CONTROL 0xCC0E +#define MT9M114_VAR_UVC_HUE_CONTROL 0xCC10 +#define MT9M114_VAR_UVC_SATURATION_CONTROL 0xCC12 +#define MT9M114_VAR_UVC_SHARPNESS_CONTROL 0xCC14 +#define MT9M114_VAR_UVC_GAMMA_CONTROL 0xCC16 +#define MT9M114_VAR_UVC_WHITE_BALANCE_TEMPERATURE_CONTROL 0xCC18 +#define MT9M114_VAR_UVC_FRAME_INTERVAL_CONTROL 0xCC1C +#define MT9M114_VAR_UVC_MANUAL_EXPOSURE_CONFIGURATION 0xCC20 +#define MT9M114_VAR_UVC_FLICKER_AVOIDANCE_CONFIGURATION 0xCC21 +#define MT9M114_VAR_UVC_ALGO 0xCC22 +#define MT9M114_VAR_UVC_RESULT_STATUS 0xCC24 + +/* 11.SystemManager variables */ +#define MT9M114_VAR_SYSMGR_NEXT_STATE 0xDC00 +#define MT9M114_VAR_SYSMGR_CURRENT_STATE 0xDC01 +#define MT9M114_VAR_SYSMGR_CMD_STATUS 0xDC02 + +/* 12.PatchLoader variables */ +#define MT9M114_VAR_PATCHLDR_LOADER_ADDRESS 0xE000 +#define MT9M114_VAR_PATCHLDR_PATCH_ID 0xE002 +#define MT9M114_VAR_PATCHLDR_FIRMWARE_ID 0xE004 +#define MT9M114_VAR_PATCHLDR_APPLY_STATUS 0xE008 +#define MT9M114_VAR_PATCHLDR_NUM_PATCHES 0xE009 +#define MT9M114_VAR_PATCHLDR_PATCH_ID_0 0xE00A +#define MT9M114_VAR_PATCHLDR_PATCH_ID_1 0xE00C +#define MT9M114_VAR_PATCHLDR_PATCH_ID_2 0xE00E +#define MT9M114_VAR_PATCHLDR_PATCH_ID_3 0xE010 +#define MT9M114_VAR_PATCHLDR_PATCH_ID_4 0xE012 +#define MT9M114_VAR_PATCHLDR_PATCH_ID_5 0xE014 +#define MT9M114_VAR_PATCHLDR_PATCH_ID_6 0xE016 +#define MT9M114_VAR_PATCHLDR_PATCH_ID_7 0xE018 + +/* 13.Patch variables */ +#define MT9M114_VAR_PATCHVARS_DELTA_DK_CORRECTION_FACTOR 0xE400 + +/* 14.CommandHandler variables */ +#define MT9M114_VAR_CMD_HANDLER_WAIT_EVENT_ID 0xFC00 +#define MT9M114_VAR_CMD_HANDLER_NUM_EVENTS 0xFC02 + +/*! @brief MT9M114 command definitions. */ +#define MT9M114_COMMAND_APPLY_PATCH 0x0001 +#define MT9M114_COMMAND_SET_STATE 0x0002 +#define MT9M114_COMMAND_REFRESH 0x0004 +#define MT9M114_COMMAND_WAIT_FOR_EVENT 0x0008 +#define MT9M114_COMMAND_OK 0x8000 + +/*! @brief MT9M114 system state definitions. */ +#define MT9M114_SYS_STATE_ENTER_CONFIG_CHANGE 0x28 +#define MT9M114_SYS_STATE_STREAMING 0x31 +#define MT9M114_SYS_STATE_START_STREAMING 0x34 +#define MT9M114_SYS_STATE_ENTER_SUSPEND 0x40 +#define MT9M114_SYS_STATE_SUSPENDED 0x41 +#define MT9M114_SYS_STATE_ENTER_STANDBY 0x50 +#define MT9M114_SYS_STATE_STANDBY 0x52 +#define MT9M114_SYS_STATE_LEAVE_STANDBY 0x54 + +/*! @brief MT9M114 system set-state command retults. */ +#define MT9M114_SYS_STATE_SET_RESULT_ENOERR 0x00 /* command successful */ +#define MT9M114_SYS_STATE_SET_RESULTEINVAL 0x0C /* invalid configuration */ +#define MT9M114_SYS_STATE_SET_RESULTENOSPC 0x0D /* resource not available */ + +extern const struct img_sensor_driver_api mt9m114_api; + +#endif /* ZEPHYR_DRIVERS_IMAGE_SENSOR_MT9M114_H_ */ From 37b136eb4a8f5475fde14f535ff07f14b49dfec4 Mon Sep 17 00:00:00 2001 From: Jun Yang Date: Sat, 13 Jul 2019 23:26:03 -0700 Subject: [PATCH 4/6] dts/mimxrt/csi: Support mimxrt CSI on dts Add CSI node for RT chip and enable it on mimxrt1050_evk board. Signed-off-by: Jun Yang --- boards/arm/mimxrt1050_evk/mimxrt1050_evk.dts | 14 +++++++++++++ dts/arm/nxp/nxp_rt.dtsi | 8 +++++++ dts/bindings/camera/nxp,imx-csi.yaml | 22 ++++++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 dts/bindings/camera/nxp,imx-csi.yaml diff --git a/boards/arm/mimxrt1050_evk/mimxrt1050_evk.dts b/boards/arm/mimxrt1050_evk/mimxrt1050_evk.dts index 68b47eb462c7..b4b47665b4ae 100644 --- a/boards/arm/mimxrt1050_evk/mimxrt1050_evk.dts +++ b/boards/arm/mimxrt1050_evk/mimxrt1050_evk.dts @@ -101,6 +101,16 @@ arduino_serial: &uart3 {}; int1-gpios = <&gpio1 10 0>; int2-gpios = <&gpio1 11 0>; }; + + /* I2C address of image sensor is not fixed. + * Camera driver scans the image sensor support list to + * identify the image sensor present. + */ + image-senosr@3ff { + compatible = "zephyr,image-sensor"; + reg = <0x3ff>; + pwr-gpios = <&gpio1 4 1>; + }; }; &uart1 { @@ -128,3 +138,7 @@ arduino_serial: &uart3 {}; pwr-gpios = <&gpio1 5 0>; cd-gpios = <&gpio2 28 0>; }; + +&csi1 { + status = "okay"; +}; diff --git a/dts/arm/nxp/nxp_rt.dtsi b/dts/arm/nxp/nxp_rt.dtsi index 655c7b4cc4c1..1f6cc7fe99cd 100644 --- a/dts/arm/nxp/nxp_rt.dtsi +++ b/dts/arm/nxp/nxp_rt.dtsi @@ -388,6 +388,14 @@ clocks = <&ccm IMX_CCM_USDHC2_CLK 0 0>; label = "USDHC_2"; }; + + csi1: csi@402bc000 { + compatible = "nxp,imx-csi"; + reg = <0x402bc000 0x4000>; + status = "disabled"; + interrupts = <43 0>; + clocks = <&ccm IMX_CCM_CSI_CLK 0 0>; + }; }; }; diff --git a/dts/bindings/camera/nxp,imx-csi.yaml b/dts/bindings/camera/nxp,imx-csi.yaml new file mode 100644 index 000000000000..419d56f9b90b --- /dev/null +++ b/dts/bindings/camera/nxp,imx-csi.yaml @@ -0,0 +1,22 @@ +# +# Copyright (c) 2019, NXP +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +title: NXP CMOS SENSOR INTERFACE +version: 0.1 + +description: > + This binding gives a base representation of the NXP i.MX RT CSI nodes. + +inherits: + !include camera.yaml + +properties: + compatible: + constraint: "nxp,imx-csi" + + clocks: + category: required +... From 622f75a09daeef2ca6d516c51efdffad061ee955 Mon Sep 17 00:00:00 2001 From: Jun Yang Date: Sat, 13 Jul 2019 23:32:12 -0700 Subject: [PATCH 5/6] drivers/camera: Add NXP i.MXRT CSI driver Add NXP i.MXRT CSI driver under camera framework. Signed-off-by: Jun Yang --- boards/arm/mimxrt1050_evk/Kconfig.defconfig | 7 + boards/arm/mimxrt1050_evk/pinmux.c | 42 + drivers/camera/CMakeLists.txt | 1 + drivers/camera/Kconfig | 8 + drivers/camera/nxp_csi/CMakeLists.txt | 5 + drivers/camera/nxp_csi/Kconfig | 8 + drivers/camera/nxp_csi/nxp_mcux_csi.c | 820 ++++++++++++++++++ .../clock_control/clock_control_mcux_ccm.c | 35 + ext/hal/nxp/mcux/Kconfig | 5 + include/dt-bindings/clock/imx_ccm.h | 3 +- soc/arm/nxp_imx/rt/Kconfig.defconfig.series | 7 + soc/arm/nxp_imx/rt/Kconfig.soc | 5 + soc/arm/nxp_imx/rt/soc.c | 14 + soc/arm/nxp_imx/rt/soc.h | 7 + 14 files changed, 966 insertions(+), 1 deletion(-) create mode 100644 drivers/camera/nxp_csi/CMakeLists.txt create mode 100644 drivers/camera/nxp_csi/Kconfig create mode 100644 drivers/camera/nxp_csi/nxp_mcux_csi.c diff --git a/boards/arm/mimxrt1050_evk/Kconfig.defconfig b/boards/arm/mimxrt1050_evk/Kconfig.defconfig index d028f9fa4a6a..c970e8920838 100644 --- a/boards/arm/mimxrt1050_evk/Kconfig.defconfig +++ b/boards/arm/mimxrt1050_evk/Kconfig.defconfig @@ -97,4 +97,11 @@ endchoice endif # LVGL +if CAMERA + +config CAMERA_DISPLAY_DEV_NAME + default "ELCDIF_1" + +endif + endif # BOARD_MIMXRT1050_EVK || BOARD_MIMXRT1050_EVK_QSPI diff --git a/boards/arm/mimxrt1050_evk/pinmux.c b/boards/arm/mimxrt1050_evk/pinmux.c index 44d2bb44d27b..5bc628bffcc9 100644 --- a/boards/arm/mimxrt1050_evk/pinmux.c +++ b/boards/arm/mimxrt1050_evk/pinmux.c @@ -102,6 +102,43 @@ static void mimxrt1050_evk_usdhc_pinmux( } #endif +#ifdef CONFIG_CAMERA +static void mimxrt1050_evk_csi_mclk_enable(bool enable) +{ + if (enable) { + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_05_CSI_MCLK, 0U); + } else { + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_05_GPIO1_IO21, 0U); + } +} + +static void mimxrt1050_evk_csi_input_cfg(void) +{ + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_04_CSI_PIXCLK, 0U); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_06_CSI_VSYNC, 0U); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_07_CSI_HSYNC, 0U); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_08_CSI_DATA09, 0U); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_09_CSI_DATA08, 0U); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_10_CSI_DATA07, 0U); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_11_CSI_DATA06, 0U); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_12_CSI_DATA05, 0U); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_13_CSI_DATA04, 0U); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_14_CSI_DATA03, 0U); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_15_CSI_DATA02, 0U); +} + +static void mimxrt1050_evk_camera_init(void) +{ + mimxrt1050_evk_csi_mclk_enable(false); + mimxrt1050_evk_csi_input_cfg(); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_04_GPIO1_IO04, 0U); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, 1U); + IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, 1U); + IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_00_LPI2C1_SCL, 0xD8B0u); + IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_01_LPI2C1_SDA, 0xD8B0u); +} +#endif + static int mimxrt1050_evk_init(struct device *dev) { ARG_UNUSED(dev); @@ -304,6 +341,11 @@ static int mimxrt1050_evk_init(struct device *dev) imxrt_usdhc_pinmux_cb_register(mimxrt1050_evk_usdhc_pinmux); #endif +#ifdef CONFIG_CAMERA + mimxrt1050_evk_camera_init(); + imxrt_csi_mclk_cb_register(mimxrt1050_evk_csi_mclk_enable); +#endif + return 0; } diff --git a/drivers/camera/CMakeLists.txt b/drivers/camera/CMakeLists.txt index bd021db8e6b7..94c5f01aacbf 100644 --- a/drivers/camera/CMakeLists.txt +++ b/drivers/camera/CMakeLists.txt @@ -1,6 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 add_subdirectory_ifdef(CONFIG_MT9M114 mt9m114) +add_subdirectory_ifdef(CONFIG_NXP_MCUX_CSI nxp_csi) zephyr_sources(camera_dev.c) zephyr_sources(image_sensor_dev.c) diff --git a/drivers/camera/Kconfig b/drivers/camera/Kconfig index 4d80395e39f7..1dc7cf1b1d4f 100644 --- a/drivers/camera/Kconfig +++ b/drivers/camera/Kconfig @@ -44,6 +44,14 @@ config CAMERA_INIT_PRIO so CAMERA_INIT_PRIO must be greater than IMAGE_SENSOR_INIT_PRIO. +menuconfig NXP_MCUX_CSI + bool "NXP i.MXRT cmos sensor interface" + depends on HAS_MCUX_CSI + help + Enable NXP i.MXRT cmos sensor driver. + +source "drivers/camera/nxp_csi/Kconfig" + menuconfig MT9M114 bool "MT9M114 image sensor" depends on I2C diff --git a/drivers/camera/nxp_csi/CMakeLists.txt b/drivers/camera/nxp_csi/CMakeLists.txt new file mode 100644 index 000000000000..abcfaf1b2aba --- /dev/null +++ b/drivers/camera/nxp_csi/CMakeLists.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources_ifdef(CONFIG_NXP_MCUX_CSI nxp_mcux_csi.c) diff --git a/drivers/camera/nxp_csi/Kconfig b/drivers/camera/nxp_csi/Kconfig new file mode 100644 index 000000000000..e8ca3893209b --- /dev/null +++ b/drivers/camera/nxp_csi/Kconfig @@ -0,0 +1,8 @@ +# +# Copyright (c) 2019, NXP +# +# SPDX-License-Identifier: Apache-2.0 +# + +if NXP_MCUX_CSI +endif diff --git a/drivers/camera/nxp_csi/nxp_mcux_csi.c b/drivers/camera/nxp_csi/nxp_mcux_csi.c new file mode 100644 index 000000000000..a8eea73d094b --- /dev/null +++ b/drivers/camera/nxp_csi/nxp_mcux_csi.c @@ -0,0 +1,820 @@ +/* + * Copyright (c) 2019, NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "fsl_common.h" +#include +#include + +#define LOG_LEVEL LOG_LEVEL_ERR +#include +LOG_MODULE_REGISTER(NXP_MCUX_CSI); + +#define NXP_CSI_DBG + +#undef LOG_ERR +#define LOG_ERR printk + +#ifdef NXP_CSI_DBG +#undef LOG_INF +#define LOG_INF printk +#endif + +#define CSI_CSICR1_INT_EN_MASK 0xFFFF0000U +#define CSI_CSICR3_INT_EN_MASK 0x000000FFU +#define CSI_CSICR18_INT_EN_MASK 0x0000FF00U + +#define CSI_FB_DEFAULT_WIDTH 480 +#define CSI_FB_DEFAULT_HEIGHT 272 + +#define CSI_FB_DEFAULT_PIXEL_FORMAT PIXEL_FORMAT_RGB_565 + +#define CSI_FB_MAX_NUM 8 + +struct priv_csi_config { + CSI_Type *base; + int irq_num; + u32_t polarity; + bool sensor_vsync; + /* In CCIR656 progressive mode, + * set true to use external VSYNC signal, set false + * to use internal VSYNC signal decoded from SOF. + */ +}; + +enum priv_csi_polarity_flags { + CSI_HSYNC_LOW = 0U, + /* HSYNC is active low. */ + CSI_HSYNC_HIGH = CSI_CSICR1_HSYNC_POL_MASK, + /* HSYNC is active high. */ + CSI_RISING_LATCH = CSI_CSICR1_REDGE_MASK, + /* Pixel data latched at rising edge of pixel clock. */ + CSI_FALLING_LATCH = 0U, + /* Pixel data latched at falling edge of pixel clock. */ + CSI_VSYNC_HIGH = 0U, + /* VSYNC is active high. */ + CSI_VSYNC_LOW = CSI_CSICR1_SOF_POL_MASK, + /* VSYNC is active low. */ +}; + +enum priv_csi_fifo { + CSI_RXFIFO = (1U << 0U), + /* RXFIFO. */ + CSI_STATFIFO = (1U << 1U), + /* STAT FIFO. */ + CSI_ALLFIFO = (CSI_RXFIFO | CSI_STATFIFO) +}; + +enum mcux_csi_status { + MCUX_CSI_INIT, + MCUX_CSI_POWER, + MCUX_CSI_READY, + MCUX_CSI_RUNNING, + MCUX_CSI_PAUSE +}; + +struct mcux_csi_fb { + void *fb[CSI_FB_MAX_NUM]; + u8_t fb_from[CSI_FB_MAX_NUM]; + struct k_mutex sw_hmutex; + struct k_mutex sw_tmutex; + u8_t sw_head; + u8_t sw_tail; + u8_t hw_head; + u8_t hw_tail; +}; + +struct mcux_csi_priv { + struct mcux_csi_fb csi_fb; + struct priv_csi_config hw_cfg; + struct device *clk_dev; + clock_control_subsys_t clock_sys; + u32_t mclk; + enum mcux_csi_status status; +}; + +static void mcux_csi_config_irq(struct camera_driver_data *data); + +static inline void csi_irq_configure(CSI_Type *base, u32_t mask) +{ + base->CSICR1 |= (mask & CSI_CSICR1_INT_EN_MASK); + base->CSICR3 |= (mask & CSI_CSICR3_INT_EN_MASK); + base->CSICR18 |= ((mask & CSI_CSICR18_INT_EN_MASK) >> 6U); +} + +static inline void csi_hw_fifo_dma_enable(CSI_Type *base, + enum priv_csi_fifo fifo, bool enable) +{ + u32_t cr3 = 0U; + + if ((u32_t)fifo & (u32_t)CSI_RXFIFO) { + cr3 |= CSI_CSICR3_DMA_REQ_EN_RFF_MASK; + } + + if ((u32_t)fifo & (u32_t)CSI_STATFIFO) { + cr3 |= CSI_CSICR3_DMA_REQ_EN_SFF_MASK; + } + + if (enable) { + base->CSICR3 |= cr3; + } else { + base->CSICR3 &= ~cr3; + } +} + +static int csi_start(struct camera_driver_data *data) +{ + struct mcux_csi_priv *priv = camera_data_priv(data); + u32_t cr3 = 0U; + CSI_Type *base = priv->hw_cfg.base; + + base->CSICR18 = + (base->CSICR18 & ~CSI_CSICR18_MASK_OPTION_MASK) | + CSI_CSICR18_MASK_OPTION(3) | + CSI_CSICR18_BASEADDR_SWITCH_SEL_MASK | + CSI_CSICR18_BASEADDR_SWITCH_EN_MASK; + + if (data->mode == CAMERA_CAPTURE_MODE) { + base->CSIDMASA_FB1 = (u32_t)priv->csi_fb.fb[0]; + base->CSIDMASA_FB2 = (u32_t)priv->csi_fb.fb[0]; + } else { + base->CSIDMASA_FB1 = (u32_t)priv->csi_fb.fb[0]; + priv->csi_fb.hw_tail++; + if (priv->csi_fb.hw_tail != + priv->csi_fb.sw_tail) { + base->CSIDMASA_FB2 = (u32_t)priv->csi_fb.fb[1]; + priv->csi_fb.hw_tail++; + } else { + base->CSIDMASA_FB2 = (u32_t)priv->csi_fb.fb[0]; + } + } + + /* After reflash DMA, the CSI saves frame to frame buffer 0. */ + cr3 |= CSI_CSICR3_DMA_REFLASH_RFF_MASK; + base->CSICR3 |= cr3; + while (base->CSICR3 & cr3) { + ; + } + + /*Enable isr*/ + if (data->mode == CAMERA_CAPTURE_MODE) { + csi_irq_configure(base, CSI_CSICR1_FB1_DMA_DONE_INTEN_MASK); + } else { + csi_irq_configure(base, CSI_CSICR1_FB1_DMA_DONE_INTEN_MASK | + CSI_CSICR1_FB2_DMA_DONE_INTEN_MASK); + } + + irq_enable(priv->hw_cfg.irq_num); + + /*Start capture*/ + csi_hw_fifo_dma_enable(base, CSI_RXFIFO, true); + + base->CSICR18 |= CSI_CSICR18_CSI_ENABLE_MASK; + + return 0; +} + +static inline void csi_hw_stop(CSI_Type *base) +{ + base->CSICR18 &= ~CSI_CSICR18_CSI_ENABLE_MASK; + csi_hw_fifo_dma_enable(base, CSI_RXFIFO, false); +} + +static int mcux_csi_start(struct device *cam_dev, + enum camera_mode mode, void **bufs, + u8_t buf_num, + camera_capture_cb cb) +{ + struct camera_driver_data *data = cam_dev->driver_data; + struct mcux_csi_priv *priv = camera_data_priv(data); + u8_t i; + int ret; + + if (buf_num < 1 || buf_num > (CSI_FB_MAX_NUM - 1)) { + return -EINVAL; + } + + for (i = 0; i < buf_num; i++) { + priv->csi_fb.fb[i] = bufs[i]; + } + priv->csi_fb.sw_head = 0; + priv->csi_fb.sw_tail = buf_num; + priv->csi_fb.hw_head = 0; + priv->csi_fb.hw_tail = 0; + data->mode = mode; + data->customer_cb = cb; + + ret = csi_start(data); + if (!ret) { + priv->status = MCUX_CSI_RUNNING; + } + + return ret; +} + +static int mcux_csi_resume(struct device *cam_dev) +{ + struct camera_driver_data *data = cam_dev->driver_data; + struct mcux_csi_priv *priv = camera_data_priv(data); + int ret; + + ret = csi_start(data); + if (!ret) { + priv->status = MCUX_CSI_RUNNING; + } + + return ret; +} + +static int mcux_csi_acquire_fb(struct device *dev, + void **fb, s32_t timeout) +{ + struct camera_driver_data *data = dev->driver_data; + struct mcux_csi_priv *priv = camera_data_priv(data); + + if (data->mode == CAMERA_CAPTURE_MODE) { + *fb = priv->csi_fb.fb[priv->csi_fb.sw_head]; + return 0; + } + + k_mutex_lock(&priv->csi_fb.sw_hmutex, timeout); + +acquire_again: + if (priv->csi_fb.sw_head == + priv->csi_fb.hw_head) { + if (timeout == K_NO_WAIT) { + *fb = 0; + k_mutex_unlock(&priv->csi_fb.sw_hmutex); + return -ENOBUFS; + } + + k_sleep(1); + timeout--; + goto acquire_again; + } + + *fb = priv->csi_fb.fb[priv->csi_fb.sw_head]; + + if (priv->csi_fb.sw_head == + (CSI_FB_MAX_NUM - 1)) { + priv->csi_fb.sw_head = 0; + } else { + priv->csi_fb.sw_head++; + } + + k_mutex_unlock(&priv->csi_fb.sw_hmutex); + + return 0; +} + +static int mcux_csi_release_fb(struct device *dev, void *fb) +{ + struct camera_driver_data *data = dev->driver_data; + struct mcux_csi_priv *priv = camera_data_priv(data); + + k_mutex_lock(&priv->csi_fb.sw_tmutex, K_FOREVER); + if ((priv->csi_fb.sw_tail + 1) == + priv->csi_fb.sw_head || + (priv->csi_fb.sw_tail == + (CSI_FB_MAX_NUM - 1) && + priv->csi_fb.sw_head == 0)) { + k_mutex_unlock(&priv->csi_fb.sw_tmutex); + return -ENOSPC; + } + + priv->csi_fb.fb[priv->csi_fb.sw_tail] = fb; + + if (priv->csi_fb.sw_tail == + (CSI_FB_MAX_NUM - 1)) { + priv->csi_fb.sw_tail = 0; + } else { + priv->csi_fb.sw_tail++; + } + + k_mutex_unlock(&priv->csi_fb.sw_tmutex); + + if (priv->status == MCUX_CSI_PAUSE) { + mcux_csi_resume(dev); + } + + return 0; +} + +static void mcux_csi_isr(void *arg) +{ + struct device *dev = (struct device *)arg; + struct camera_driver_data *data = dev->driver_data; + struct mcux_csi_priv *priv = camera_data_priv(data); + CSI_Type *base = priv->hw_cfg.base; + u32_t csisr = base->CSISR; + void *fb; + + /* Clear the error flags. */ + base->CSISR = csisr; + + if (data->mode == CAMERA_PREVIEW_MODE) { + if (csisr & CSI_CSISR_DMA_TSF_DONE_FB1_MASK) { + fb = (void *)base->CSIDMASA_FB1; + priv->csi_fb.fb_from[priv->csi_fb.hw_head] = 1; + if (priv->csi_fb.hw_head < + (CSI_FB_MAX_NUM - 1)) { + priv->csi_fb.hw_head++; + } else { + priv->csi_fb.hw_head = 0; + } + + base->CSIDMASA_FB1 = + (u32_t)priv->csi_fb.fb[priv->csi_fb.hw_tail]; + + if (priv->csi_fb.hw_tail != + priv->csi_fb.sw_tail) { + if (priv->csi_fb.hw_tail < + (CSI_FB_MAX_NUM - 1)) { + priv->csi_fb.hw_tail++; + } else { + priv->csi_fb.hw_tail = 0; + } + } else { + csi_hw_stop(base); + priv->status = MCUX_CSI_PAUSE; + LOG_ERR("FB1 stop\r\n"); + } + if (data->customer_cb) { + data->customer_cb(fb, + data->fb_attr.width, + data->fb_attr.height, + data->fb_attr.bpp); + } + } + + if (csisr & CSI_CSISR_DMA_TSF_DONE_FB2_MASK) { + fb = (void *)base->CSIDMASA_FB2; + priv->csi_fb.fb_from[priv->csi_fb.hw_head] = 2; + if (priv->csi_fb.hw_head < + (CSI_FB_MAX_NUM - 1)) { + priv->csi_fb.hw_head++; + } else { + priv->csi_fb.hw_head = 0; + } + + base->CSIDMASA_FB2 = + (u32_t)priv->csi_fb.fb[priv->csi_fb.hw_tail]; + + if (priv->csi_fb.hw_tail != + priv->csi_fb.sw_tail) { + if (priv->csi_fb.hw_tail < + (CSI_FB_MAX_NUM - 1)) { + priv->csi_fb.hw_tail++; + } else { + priv->csi_fb.hw_tail = 0; + } + } else { + csi_hw_stop(base); + priv->status = MCUX_CSI_PAUSE; + LOG_ERR("FB2 stop\r\n"); + } + if (data->customer_cb) { + data->customer_cb(fb, + data->fb_attr.width, + data->fb_attr.height, + data->fb_attr.bpp); + } + } + + return; + } + + fb = (void *)base->CSIDMASA_FB1; + /*Stop CSI*/ + base->CSICR18 &= ~CSI_CSICR18_CSI_ENABLE_MASK; + base->CSICR3 &= ~CSI_CSICR3_DMA_REQ_EN_RFF_MASK; + + priv->status = MCUX_CSI_PAUSE; + + if (data->customer_cb) { + data->customer_cb(fb, + data->fb_attr.width, + data->fb_attr.height, + data->fb_attr.bpp); + } +} + +static void csi_hw_clear_fifo(CSI_Type *base, enum priv_csi_fifo fifo) +{ + u32_t cr1; + u32_t mask = 0U; + + /* The FIFO could only be cleared when CSICR1[FCC] = 0, + * so first clear the FCC. + */ + cr1 = base->CSICR1; + base->CSICR1 = (cr1 & ~CSI_CSICR1_FCC_MASK); + + if ((u32_t)fifo & (u32_t)CSI_RXFIFO) { + mask |= CSI_CSICR1_CLR_RXFIFO_MASK; + } + + if ((u32_t)fifo & (u32_t)CSI_STATFIFO) { + mask |= CSI_CSICR1_CLR_STATFIFO_MASK; + } + + base->CSICR1 = (cr1 & ~CSI_CSICR1_FCC_MASK) | mask; + + /* Wait clear completed. */ + while (base->CSICR1 & mask) { + ; + } + + /* Recover the FCC. */ + base->CSICR1 = cr1; +} + +static void csi_hw_reflash_fifo(CSI_Type *base, enum priv_csi_fifo fifo) +{ + u32_t cr3 = 0U; + + if ((u32_t)fifo & (u32_t)CSI_RXFIFO) { + cr3 |= CSI_CSICR3_DMA_REFLASH_RFF_MASK; + } + + if ((u32_t)fifo & (u32_t)CSI_STATFIFO) { + cr3 |= CSI_CSICR3_DMA_REFLASH_SFF_MASK; + } + + base->CSICR3 |= cr3; + + /* Wait clear completed. */ + while (base->CSICR3 & cr3) { + ; + } +} + +static void csi_hw_reset(CSI_Type *base) +{ + u32_t csisr; + + /* Disable transfer first. */ + csi_hw_stop(base); + + /* Disable DMA request. */ + base->CSICR3 = 0U; + + /* Reset the fame count. */ + base->CSICR3 |= CSI_CSICR3_FRMCNT_RST_MASK; + while (base->CSICR3 & CSI_CSICR3_FRMCNT_RST_MASK) { + ; + } + + /* Clear the RX FIFO. */ + csi_hw_clear_fifo(base, CSI_ALLFIFO); + + /* Reflash DMA. */ + csi_hw_reflash_fifo(base, CSI_ALLFIFO); + + /* Clear the status. */ + csisr = base->CSISR; + base->CSISR = csisr; + + /* Set the control registers to default value. */ + base->CSICR1 = CSI_CSICR1_HSYNC_POL_MASK | CSI_CSICR1_EXT_VSYNC_MASK; + base->CSICR2 = 0U; + base->CSICR3 = 0U; + + base->CSICR18 = CSI_CSICR18_AHB_HPROT(0x0DU); + base->CSIFBUF_PARA = 0U; + base->CSIIMAG_PARA = 0U; +} + +static int csi_hw_data_config(struct camera_driver_data *data) +{ + struct mcux_csi_priv *priv = camera_data_priv(data); + u32_t reg; + u32_t width_bytes; + CSI_Type *base = priv->hw_cfg.base; + + width_bytes = data->fb_attr.width * + data->fb_attr.bpp; + + csi_hw_reset(base); + + /*!< HSYNC, VSYNC, and PIXCLK signals are used. */ + reg = ((u32_t)CSI_CSICR1_GCLK_MODE(1U)) | + priv->hw_cfg.polarity | + CSI_CSICR1_FCC_MASK; + + if (priv->hw_cfg.sensor_vsync) { + reg |= CSI_CSICR1_EXT_VSYNC_MASK; + } + + base->CSICR1 = reg; + + /* Image parameter. */ + base->CSIIMAG_PARA = + ((u32_t)(width_bytes) << + CSI_CSIIMAG_PARA_IMAGE_WIDTH_SHIFT) | + ((u32_t)data->fb_attr.height << + CSI_CSIIMAG_PARA_IMAGE_HEIGHT_SHIFT); + + /* The CSI frame buffer bus is 8-byte width. */ + base->CSIFBUF_PARA = 0; + + /* Enable auto ECC. */ + base->CSICR3 |= CSI_CSICR3_ECC_AUTO_EN_MASK; + + if (!(width_bytes % (8 * 16))) { + base->CSICR2 = CSI_CSICR2_DMA_BURST_TYPE_RFF(3U); + base->CSICR3 = + (base->CSICR3 & ~CSI_CSICR3_RxFF_LEVEL_MASK) | + ((2U << CSI_CSICR3_RxFF_LEVEL_SHIFT)); + } else if (!(width_bytes % (8 * 8))) { + base->CSICR2 = CSI_CSICR2_DMA_BURST_TYPE_RFF(2U); + base->CSICR3 = + (base->CSICR3 & ~CSI_CSICR3_RxFF_LEVEL_MASK) | + ((1U << CSI_CSICR3_RxFF_LEVEL_SHIFT)); + } else { + base->CSICR2 = CSI_CSICR2_DMA_BURST_TYPE_RFF(1U); + base->CSICR3 = + (base->CSICR3 & ~CSI_CSICR3_RxFF_LEVEL_MASK) | + ((0U << CSI_CSICR3_RxFF_LEVEL_SHIFT)); + } + + /*Reflash DMA*/ + base->CSICR3 |= CSI_CSICR3_DMA_REFLASH_RFF_MASK; + + /* Wait clear completed. */ + while (base->CSICR3 & CSI_CSICR3_DMA_REFLASH_RFF_MASK) { + ; + } + + return 0; +} + +static int mcux_csi_sensor_cfg(struct camera_driver_data *data) +{ + struct device *img_dev = data->sensor_dev; + int ret; + + ret = img_sensor_set_framesize(img_dev, + data->fb_attr.width, + data->fb_attr.height); + if (ret) { + return ret; + } + + ret = img_sensor_set_pixformat(img_dev, + data->fb_attr.pixformat); + if (ret) { + return ret; + } + + ret = img_sensor_configure(img_dev); + + return ret; +} + +static int mcux_csi_config(struct device *cam_dev, + struct camera_fb_cfg *fb_cfg) +{ + struct camera_driver_data *data = cam_dev->driver_data; + struct mcux_csi_priv *priv = camera_data_priv(data); + int ret; + + if (priv->status != MCUX_CSI_POWER) { + LOG_ERR("CSI configuration on the fly not implemented\r\n"); + + return -EACCES; + } + + if (fb_cfg->cfg_mode == CAMERA_USER_CFG) { + if (!(fb_cfg->fb_attr.pixformat & + data->cap.pixformat_support)) { + LOG_ERR("CSI pixel format 0x%08x not supported!\r\n", + fb_cfg->fb_attr.pixformat); + + return -ENOTSUP; + } + + if (fb_cfg->fb_attr.width > + data->cap.width_max || + fb_cfg->fb_attr.height > + data->cap.height_max) { + LOG_ERR("CSI frame size exceeds!\r\n"); + + return -ENOTSUP; + } + + if (fb_cfg->fb_attr.pixformat != + PIXEL_FORMAT_RGB_565) { + LOG_ERR("CSI other than RGB565 not implemented\r\n"); + + return -ENOTSUP; + } + } + + camera_dev_configure(cam_dev, fb_cfg); + + ret = mcux_csi_sensor_cfg(data); + if (ret) { + return ret; + } + + ret = csi_hw_data_config(data); + if (ret) { + return ret; + } + + mcux_csi_config_irq(data); + + return 0; +} + +static int mcux_csi_power(struct device *cam_dev, + bool power) +{ + struct camera_driver_data *data = cam_dev->driver_data; + struct mcux_csi_priv *priv = camera_data_priv(data); + struct device *img_dev = data->sensor_dev; + int ret; + struct img_sensor_capability sensor_cap; + + if (!img_dev) { + LOG_ERR("CSI power, but CMOS sensor Not present!\r\n"); + + return -ENODEV; + } + + if (power) { + if (priv->status != MCUX_CSI_INIT) { + return 0; + } + + CLOCK_EnableClock(kCLOCK_Csi); + imxrt_csi_mclk_enable(true); + k_sleep(1); + + csi_hw_reset(priv->hw_cfg.base); + + ret = z_impl_img_sensor_reset(img_dev); + if (ret) { + LOG_ERR("CMOS sensor reset failed with error: %d\r\n", + ret); + + return ret; + } + + z_impl_img_sensor_get_cap(img_dev, &sensor_cap); + if (ret) { + LOG_ERR("CMOS sensor get capability failed" + " with error: %d\r\n", + ret); + + return ret; + } + + data->cap.pixformat_support = + data->cap.pixformat_support & + sensor_cap.pixformat_support; + data->cap.width_max = + sensor_cap.width_max; + data->cap.height_max = + sensor_cap.height_max; + + priv->status = MCUX_CSI_POWER; + + return 0; + } + + CLOCK_DisableClock(kCLOCK_Csi); + imxrt_csi_mclk_enable(false); + + priv->status = MCUX_CSI_INIT; + + return 0; +} + +static int mcux_csi_reset(struct device *cam_dev) +{ + mcux_csi_power(cam_dev, false); + + k_sleep(1); + mcux_csi_power(cam_dev, true); + + return 0; +} + +static const struct camera_driver_api mcux_camera_api = { + .camera_power_cb = mcux_csi_power, + .camera_reset_cb = mcux_csi_reset, + .camera_get_cap_cb = camera_dev_get_cap, + .camera_configure_cb = mcux_csi_config, + .camera_start_cb = mcux_csi_start, + .camera_acquire_fb_cb = mcux_csi_acquire_fb, + .camera_release_fb_cb = mcux_csi_release_fb, +}; + +static int mcux_csi_init(struct device *cam_dev) +{ + struct camera_driver_data *data; + struct mcux_csi_priv *priv; + struct device *img_dev; + enum camera_id id; + +#ifdef DT_INST_0_NXP_IMX_CSI_LABEL +#if (DT_INST_0_NXP_IMX_CSI_LABEL == CAMERA_PRIMARY_LABEL) + id = CAMERA_PRIMARY_ID; +#elif (DT_INST_0_NXP_IMX_CSI_LABEL == CAMERA_SECONDARY_LABEL) + id = CAMERA_SECONDARY_ID; +#else +#warning CSI LABEL should be "primary" or "secondary". + id = CAMERA_PRIMARY_ID; +#endif +#else + id = CAMERA_PRIMARY_ID; +#endif + + data = camera_drv_data_alloc(sizeof(struct mcux_csi_priv), id, true); + cam_dev->driver_data = data; + priv = camera_data_priv(data); + + priv->hw_cfg.base = (CSI_Type *)DT_INST_0_NXP_IMX_CSI_BASE_ADDRESS; + priv->hw_cfg.irq_num = (int)DT_INST_0_NXP_IMX_CSI_IRQ_0; + priv->hw_cfg.polarity = (CSI_HSYNC_HIGH | + CSI_RISING_LATCH); + priv->hw_cfg.sensor_vsync = true; + + k_mutex_init(&priv->csi_fb.sw_hmutex); + k_mutex_init(&priv->csi_fb.sw_tmutex); + + data->cap.fb_alignment = 64; + data->cap.pixformat_support = + PIXEL_FORMAT_RGB_565 | + PIXEL_FORMAT_RGB_888; + + data->fb_attr.width = CSI_FB_DEFAULT_WIDTH; + data->fb_attr.height = CSI_FB_DEFAULT_HEIGHT; + data->fb_attr.pixformat = CSI_FB_DEFAULT_PIXEL_FORMAT; + if (data->fb_attr.pixformat == + PIXEL_FORMAT_RGB_888) { + data->fb_attr.bpp = 3; + } else if (data->fb_attr.pixformat == + PIXEL_FORMAT_ARGB_8888) { + data->fb_attr.bpp = 4; + } else if (data->fb_attr.pixformat == + PIXEL_FORMAT_RGB_565) { + data->fb_attr.bpp = 2; + } else { + LOG_ERR("CSI does not support this pixel format %d\r\n", + data->fb_attr.pixformat); + return -EINVAL; + } + priv->status = MCUX_CSI_INIT; + + priv->clk_dev = device_get_binding( + DT_INST_0_NXP_IMX_CSI_CLOCK_CONTROLLER); + priv->clock_sys = + (clock_control_subsys_t)DT_INST_0_NXP_IMX_CSI_CLOCK_NAME; + + CLOCK_SetDiv(kCLOCK_CsiDiv, 0); + CLOCK_SetMux(kCLOCK_CsiMux, 0); + CLOCK_EnableClock(kCLOCK_Csi); + imxrt_csi_mclk_enable(true); + + if (clock_control_get_rate(priv->clk_dev, priv->clock_sys, + &priv->mclk)) { + return -EINVAL; + } + + img_dev = img_sensor_scan(data->id); + if (!img_dev) { + LOG_ERR("CSI init No CMOS sensor present!\r\n"); + + return -ENODEV; + } + + data->sensor_dev = img_dev; + + /*Power off for power saving + * Until user powers on. + */ + CLOCK_DisableClock(kCLOCK_Csi); + imxrt_csi_mclk_enable(false); + + return camera_dev_register(cam_dev); +} + +DEVICE_AND_API_INIT(mcux_csi, "MCUX_CSI", + &mcux_csi_init, + 0, 0, + POST_KERNEL, CONFIG_CAMERA_INIT_PRIO, + &mcux_camera_api); + +static void mcux_csi_config_irq(struct camera_driver_data *data) +{ + IRQ_CONNECT(DT_INST_0_NXP_IMX_CSI_IRQ_0, + 0, mcux_csi_isr, DEVICE_GET(mcux_csi), 0); + + irq_enable(DT_INST_0_NXP_IMX_CSI_IRQ_0); +} diff --git a/drivers/clock_control/clock_control_mcux_ccm.c b/drivers/clock_control/clock_control_mcux_ccm.c index 04ed92552a7e..3680e8a5001c 100644 --- a/drivers/clock_control/clock_control_mcux_ccm.c +++ b/drivers/clock_control/clock_control_mcux_ccm.c @@ -32,6 +32,15 @@ static int mcux_ccm_off(struct device *dev, return 0; } +#ifdef CONFIG_NXP_MCUX_CSI +enum mcux_csi_clk_sel { + CSI_CLK_SEL_24M = 0, + CSI_CLK_SEL_PLL2_PFD2 = 1, + CSI_CLK_SEL_120M = 2, + CSI_CLK_SEL_PLL3_PFD1 = 3, +}; +#endif + static int mcux_ccm_get_subsys_rate(struct device *dev, clock_control_subsys_t sub_system, u32_t *rate) @@ -87,6 +96,32 @@ static int mcux_ccm_get_subsys_rate(struct device *dev, (CLOCK_GetDiv(kCLOCK_Usdhc2Div) + 1U); break; #endif + +#ifdef CONFIG_NXP_MCUX_CSI + case IMX_CCM_CSI_CLK: + { + enum mcux_csi_clk_sel clk_sel = + (enum mcux_csi_clk_sel) + CLOCK_GetMux(kCLOCK_CsiMux); + + if (clk_sel == CSI_CLK_SEL_24M) { + *rate = (24 * 1024 * 1024) / + (CLOCK_GetDiv(kCLOCK_CsiDiv) + 1U); + } else if (clk_sel == CSI_CLK_SEL_PLL2_PFD2) { + *rate = CLOCK_GetSysPfdFreq(kCLOCK_Pfd2) / + (CLOCK_GetDiv(kCLOCK_CsiDiv) + 1U); + } else if (clk_sel == CSI_CLK_SEL_120M) { + *rate = (120 * 1024 * 1024) / + (CLOCK_GetDiv(kCLOCK_CsiDiv) + 1U); + } else if (clk_sel == CSI_CLK_SEL_PLL3_PFD1) { + *rate = CLOCK_GetSysPfdFreq(kCLOCK_Pfd1) / + (CLOCK_GetDiv(kCLOCK_CsiDiv) + 1U); + } else { + return -EINVAL; + } + } + break; +#endif } return 0; diff --git a/ext/hal/nxp/mcux/Kconfig b/ext/hal/nxp/mcux/Kconfig index 272cbb45dffb..848226c43317 100644 --- a/ext/hal/nxp/mcux/Kconfig +++ b/ext/hal/nxp/mcux/Kconfig @@ -144,4 +144,9 @@ config HAS_MCUX_WDOG32 help Set if the watchdog (WDOG32) module is present in the SoC. +config HAS_MCUX_CSI + bool + help + Set if the cmos sensor interface is present in the SoC. + endif # HAS_MCUX diff --git a/include/dt-bindings/clock/imx_ccm.h b/include/dt-bindings/clock/imx_ccm.h index 066c7f4881b5..54bc26078171 100644 --- a/include/dt-bindings/clock/imx_ccm.h +++ b/include/dt-bindings/clock/imx_ccm.h @@ -8,12 +8,13 @@ #define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_IMX_CCM_H_ #define IMX_CCM_CORESYS_CLK 0 -#define IMX_CCM_PLATFORM_CLK 1 +#define IMX_CCM_PLATFORM_CLK 1 #define IMX_CCM_BUS_CLK 2 #define IMX_CCM_LPUART_CLK 3 #define IMX_CCM_LPI2C_CLK 4 #define IMX_CCM_LPSPI_CLK 5 #define IMX_CCM_USDHC1_CLK 6 #define IMX_CCM_USDHC2_CLK 7 +#define IMX_CCM_CSI_CLK 8 #endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_IMX_CCM_H_ */ diff --git a/soc/arm/nxp_imx/rt/Kconfig.defconfig.series b/soc/arm/nxp_imx/rt/Kconfig.defconfig.series index 4dceeda7b6bf..05c9722d5b8f 100644 --- a/soc/arm/nxp_imx/rt/Kconfig.defconfig.series +++ b/soc/arm/nxp_imx/rt/Kconfig.defconfig.series @@ -141,6 +141,13 @@ config USB_DC_NXP_EHCI endif # USB +if CAMERA + +config NXP_MCUX_CSI + default y if HAS_MCUX_CSI + +endif # CAMERA + source "soc/arm/nxp_imx/rt/Kconfig.defconfig.mimxrt*" endif # SOC_SERIES_IMX_RT diff --git a/soc/arm/nxp_imx/rt/Kconfig.soc b/soc/arm/nxp_imx/rt/Kconfig.soc index 8ea79667d0d1..9dfb2a03b113 100644 --- a/soc/arm/nxp_imx/rt/Kconfig.soc +++ b/soc/arm/nxp_imx/rt/Kconfig.soc @@ -70,6 +70,7 @@ config SOC_MIMXRT1051 select HAS_MCUX_USB_EHCI select HAS_MCUX_USDHC1 select HAS_MCUX_USDHC2 + select HAS_MCUX_CSI config SOC_MIMXRT1052 bool "SOC_MIMXRT1052" @@ -93,6 +94,7 @@ config SOC_MIMXRT1052 select HAS_MCUX_USB_EHCI select HAS_MCUX_USDHC1 select HAS_MCUX_USDHC2 + select HAS_MCUX_CSI config SOC_MIMXRT1061 bool "SOC_MIMXRT1061" @@ -113,6 +115,7 @@ config SOC_MIMXRT1061 select HAS_MCUX_USB_EHCI select HAS_MCUX_USDHC1 select HAS_MCUX_USDHC2 + select HAS_MCUX_CSI config SOC_MIMXRT1062 bool "SOC_MIMXRT1062" @@ -135,6 +138,7 @@ config SOC_MIMXRT1062 select HAS_MCUX_USB_EHCI select HAS_MCUX_USDHC1 select HAS_MCUX_USDHC2 + select HAS_MCUX_CSI config SOC_MIMXRT1064 bool "SOC_MIMXRT1064" @@ -157,6 +161,7 @@ config SOC_MIMXRT1064 select HAS_MCUX_USB_EHCI select HAS_MCUX_USDHC1 select HAS_MCUX_USDHC2 + select HAS_MCUX_CSI endchoice diff --git a/soc/arm/nxp_imx/rt/soc.c b/soc/arm/nxp_imx/rt/soc.c index d0e4dc5f0ef1..2bd5ca4f97be 100644 --- a/soc/arm/nxp_imx/rt/soc.c +++ b/soc/arm/nxp_imx/rt/soc.c @@ -236,6 +236,20 @@ void imxrt_usdhc_pinmux(u16_t nusdhc, bool init, } #endif +#ifdef CONFIG_NXP_MCUX_CSI + +static csi_mclk_enable_cb g_csi_mclk_enable_cb; +void imxrt_csi_mclk_cb_register(csi_mclk_enable_cb cb) +{ + g_csi_mclk_enable_cb = cb; +} + +void imxrt_csi_mclk_enable(bool enable) +{ + if (g_csi_mclk_enable_cb) + g_csi_mclk_enable_cb(enable); +} +#endif /** * * @brief Perform basic hardware initialization diff --git a/soc/arm/nxp_imx/rt/soc.h b/soc/arm/nxp_imx/rt/soc.h index 9206c215aada..14b88b7cf0b2 100644 --- a/soc/arm/nxp_imx/rt/soc.h +++ b/soc/arm/nxp_imx/rt/soc.h @@ -36,6 +36,13 @@ void imxrt_usdhc_pinmux_cb_register(usdhc_pin_cfg_cb cb); #endif +#ifdef CONFIG_NXP_MCUX_CSI +typedef void (*csi_mclk_enable_cb)(bool enable); + +void imxrt_csi_mclk_enable(bool enable); + +void imxrt_csi_mclk_cb_register(csi_mclk_enable_cb cb); +#endif #endif /* !_ASMLANGUAGE */ #ifdef __cplusplus From 8fe901ecb5a1429eb567881331f7091c295112b7 Mon Sep 17 00:00:00 2001 From: Jun Yang Date: Tue, 11 Jun 2019 01:39:50 -0700 Subject: [PATCH 6/6] samples/camera: add camera sample code Camera sample code. Display camera stream in capture mode and preview mode respectively if there is display device present on board. Log frames counter per-second on both modes periodically. Signed-off-by: Jun Yang --- CODEOWNERS | 1 + samples/camera/CMakeLists.txt | 8 ++ samples/camera/README.rst | 30 +++++ samples/camera/prj.conf | 3 + samples/camera/sample.yaml | 8 ++ samples/camera/src/main.c | 246 ++++++++++++++++++++++++++++++++++ samples/index.rst | 1 + 7 files changed, 297 insertions(+) create mode 100644 samples/camera/CMakeLists.txt create mode 100644 samples/camera/README.rst create mode 100644 samples/camera/prj.conf create mode 100644 samples/camera/sample.yaml create mode 100644 samples/camera/src/main.c diff --git a/CODEOWNERS b/CODEOWNERS index bd2187ddaa64..b7646e74dc2e 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -303,6 +303,7 @@ /samples/subsys/shell/ @jakub-uC @nordic-krch /samples/subsys/usb/ @jfischer-phytec-iot @finikorg /samples/subsys/power/ @wentongwu @pizi-nordic +/samples/camera/ @JunYangNXP /scripts/coccicheck @himanshujha199640 @JuliaLawall /scripts/coccinelle/ @himanshujha199640 @JuliaLawall /scripts/kconfig/ @ulfalizer diff --git a/samples/camera/CMakeLists.txt b/samples/camera/CMakeLists.txt new file mode 100644 index 000000000000..67b0185cc0dd --- /dev/null +++ b/samples/camera/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.13.1) +include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) +project(camera) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/camera/README.rst b/samples/camera/README.rst new file mode 100644 index 000000000000..70624a55ba9f --- /dev/null +++ b/samples/camera/README.rst @@ -0,0 +1,30 @@ +.. camera: + +Camera Sample Application +################################### + +Overview +******** +This project demos camera samples. +It should work with any platform featuring a I2C peripheral interface and a CMOS sensor interface. +It does not work on QEMU. +If there is a display device on the board, the demo displays camera stream on the display device. + +Requirements +************ +This project requires a CMOS sensor connected to board. + +Building and Running +******************** +This sample can be built for a ``mimxrt1050_evk`` board with mt9m114 CMOS sensor connected. + +.. zephyr-app-commands:: + :zephyr-app: samples/camera + :board: mimxrt1050_evk + :goals: build flash + +To run this sample, a CMOS sensor should be connected to the board. +The sample outputs the FPS(frames per second) number on the console in capture +mode and preview mode periodically. +If there is a display device present on the board, the sample outputs the camera +stream on the display device. diff --git a/samples/camera/prj.conf b/samples/camera/prj.conf new file mode 100644 index 000000000000..bca536168b0a --- /dev/null +++ b/samples/camera/prj.conf @@ -0,0 +1,3 @@ +CONFIG_CAMERA=y +CONFIG_I2C=y +CONFIG_DISPLAY=y diff --git a/samples/camera/sample.yaml b/samples/camera/sample.yaml new file mode 100644 index 000000000000..038acfd7c32f --- /dev/null +++ b/samples/camera/sample.yaml @@ -0,0 +1,8 @@ +sample: + name: Camera Sample +tests: + sample.camera: + harness: camera + tags: camera + platform_whitelist: mimxrt1050_evk + depends_on: camera i2c display diff --git a/samples/camera/src/main.c b/samples/camera/src/main.c new file mode 100644 index 000000000000..69507feae539 --- /dev/null +++ b/samples/camera/src/main.c @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2019 NXP Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +/* _______ _________ + *| |<-------|head| | + *| | |____| |___________ ______ + *| | |tail|<---|__camer_IP_|<---|_CMOS_| + *| |------->|____|____| + *|_______| |____|____| + * Display Camera + */ + +#define CAMERA_DEMO_FB_MAX_SIZE 0x40000 +#define CAMERA_DEMO_FB_MAX_NUM 4 +char gfb[CAMERA_DEMO_FB_MAX_SIZE * CAMERA_DEMO_FB_MAX_NUM] __aligned(64); +struct k_sem gsem; + +static void capture_cb(void *fb, int w, int h, int bpp) +{ + k_sem_give(&gsem); +} + +void main(void) +{ + int ret, i; + struct device *camera_dev = camera_get_primary(); + struct device *display_dev = + device_get_binding(CONFIG_CAMERA_DISPLAY_DEV_NAME); + struct display_capabilities diaplay_cap; + struct display_buffer_descriptor diaplay_dsc; + struct camera_capability camera_cap; + struct camera_fb_cfg camera_cfg; + void *fb[CAMERA_DEMO_FB_MAX_NUM]; + u8_t bpp; + s64_t start_tick; + double frames = 0; + double ms; + + k_sem_init(&gsem, 0, 1); + if (camera_dev == NULL) { + printf("Failed to get camera device.\n"); + return; + } + + ret = camera_power(camera_dev, true); + if (!ret) { + printf("%s camera power on successfully!\r\n", + camera_dev->config->name); + } else { + printf("%s camera power on failed!\r\n", + camera_dev->config->name); + + return; + } + + /*camera_reset is option, just for reset API test.*/ + ret = camera_reset(camera_dev); + if (!ret) { + printf("%s camera reset successfully!\r\n", + camera_dev->config->name); + } else { + printf("%s camera reset failed!\r\n", + camera_dev->config->name); + + return; + } + + ret = camera_get_cap(camera_dev, &camera_cap); + if (!ret) { + printf("%s camera get capability successfully!\r\n", + camera_dev->config->name); + } else { + printf("%s camera get capability failed!\r\n", + camera_dev->config->name); + + return; + } + + if (display_dev == NULL) { + printf("Failed to get display device.\n"); + } else { + display_get_capabilities(display_dev, &diaplay_cap); + } + + for (i = 0; i < CAMERA_DEMO_FB_MAX_NUM; i++) { + fb[i] = &gfb[i * CAMERA_DEMO_FB_MAX_SIZE]; + } + + if (display_dev) { + if (diaplay_cap.current_pixel_format == + PIXEL_FORMAT_RGB_888) { + bpp = 3; + } else if (diaplay_cap.current_pixel_format == + PIXEL_FORMAT_ARGB_8888) { + bpp = 4; + } else if (diaplay_cap.current_pixel_format == + PIXEL_FORMAT_RGB_565) { + bpp = 2; + } else { + printf("Unsupported pix format %d for camera\n", + diaplay_cap.current_pixel_format); + return; + } + + if (!(camera_cap.pixformat_support & + diaplay_cap.current_pixel_format)) { + printf("The display pixel format 0x%08x is not" + " supported by camera format supported: 0x%08x\r\n", + diaplay_cap.current_pixel_format, + camera_cap.pixformat_support); + + return; + } + + if (diaplay_cap.x_resolution > camera_cap.width_max || + diaplay_cap.y_resolution > camera_cap.height_max) { + printf("The display resolution exceeds" + " the camera max resolution %d X %d\r\n", + camera_cap.width_max, camera_cap.height_max); + + return; + } + + camera_cfg.cfg_mode = CAMERA_USER_CFG; + camera_cfg.fb_attr.width = diaplay_cap.x_resolution; + camera_cfg.fb_attr.height = diaplay_cap.y_resolution; + camera_cfg.fb_attr.bpp = bpp; + camera_cfg.fb_attr.pixformat = diaplay_cap.current_pixel_format; + + diaplay_dsc.buf_size = camera_cfg.fb_attr.width * + camera_cfg.fb_attr.height * bpp; + diaplay_dsc.width = camera_cfg.fb_attr.width; + diaplay_dsc.height = camera_cfg.fb_attr.height; + diaplay_dsc.pitch = camera_cfg.fb_attr.width; + } else { + camera_cfg.cfg_mode = CAMERA_DEFAULT_CFG; + } + + ret = camera_configure(camera_dev, &camera_cfg); + if (!ret) { + printf("%s camera configure successfully!\r\n", + camera_dev->config->name); + } else { + printf("%s camera configure failed!\r\n", + camera_dev->config->name); + } + +loop_again: + printf("Enter capture mode\r\n"); + start_tick = z_tick_get(); + while (1) { + void *camera_fb; + + ret = camera_start(camera_dev, + CAMERA_CAPTURE_MODE, &fb[0], 1, capture_cb); + if (!ret) { + k_sem_take(&gsem, K_FOREVER); + ret = camera_acquire_fb(camera_dev, + &camera_fb, K_FOREVER); + if (!ret) { + if (display_dev) { + display_write(display_dev, 0, 0, + &diaplay_dsc, camera_fb); + } + frames++; + printf("%d", (int)frames); + printf("\b"); + if (frames >= 10) { + printf("\b"); + } + if (frames >= 100) { + printf("\b"); + } + if (unlikely(frames == 300)) { + ms = __ticks_to_ms( + z_tick_get() - start_tick); + printf("\r\nCapture mode FPS: %f\r\n", + (frames / (ms / 1000))); + start_tick = z_tick_get(); + frames = 0; + break; + } + } else { + printf("Camera get frame buffer failed!\r\n"); + } + } else { + printf("Camera capture failed!\r\n"); + } + } + + printf("Enter preview mode\r\n"); + ret = camera_start(camera_dev, CAMERA_PREVIEW_MODE, &fb[0], + CAMERA_DEMO_FB_MAX_NUM, 0); + if (ret) { + printf("Preview start failed\r\n"); + goto loop_again; + } + + start_tick = z_tick_get(); + while (1) { + void *camera_fb; + + ret = camera_acquire_fb(camera_dev, &camera_fb, K_FOREVER); + if (!ret) { + if (display_dev) { + display_write(display_dev, 0, 0, + &diaplay_dsc, camera_fb); + } + + frames++; + printf("%d", (int)frames); + printf("\b"); + if (frames >= 10) { + printf("\b"); + } + if (frames >= 100) { + printf("\b"); + } + if (unlikely(frames == 300)) { + ms = __ticks_to_ms( + z_tick_get() - start_tick); + printf("\r\nPreview mode FPS: %f\r\n", + (frames / (ms / 1000))); + start_tick = z_tick_get(); + frames = 0; + break; + } + + camera_release_fb(camera_dev, camera_fb); + } else { + printf("Preview get frame buffer failed!\r\n"); + } + } + + goto loop_again; +} diff --git a/samples/index.rst b/samples/index.rst index 792fe9c9b440..7961bd691426 100644 --- a/samples/index.rst +++ b/samples/index.rst @@ -23,6 +23,7 @@ Samples and Demos shields/* portability/* gui/* + camera/* .. comment To add a new sample document, please use the template available under