310 lines
8.5 KiB
C
310 lines
8.5 KiB
C
/*
|
|
* KDP Camera driver for KL520
|
|
*
|
|
* Copyright (C) 2019 Kneron, Inc. All rights reserved.
|
|
*
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include "kmdw_camera.h"
|
|
#include "kmdw_sensor.h"
|
|
#include "kmdw_console.h"
|
|
#include "kdrv_clock.h"
|
|
#include "kdrv_dpi2ahb.h"
|
|
#include "kdrv_mipicsirx.h"
|
|
|
|
#define CAM_DEBUG
|
|
|
|
#ifdef CAM_DEBUG
|
|
#define cam_msg(fmt, ...) err_msg("[%s] " fmt, __func__, ##__VA_ARGS__)
|
|
#else
|
|
#define cam_msg(fmt, ...)
|
|
#endif
|
|
|
|
struct kmdw_cam_context {
|
|
uint32_t id;
|
|
uint32_t sensor_id;
|
|
uint32_t cam_input_type;
|
|
uint32_t capabilities;
|
|
struct cam_format fmt;
|
|
};
|
|
|
|
struct kmdw_cam_context cam_ctx[KDP_CAM_NUM];
|
|
|
|
/* API */
|
|
static kmdw_status_t kmdw_cam_open(uint32_t cam_idx)
|
|
{
|
|
struct kmdw_cam_context *ctx = &cam_ctx[cam_idx];
|
|
|
|
if(ctx->cam_input_type != IMGSRC_IN_PORT_MIPI)
|
|
return KMDW_STATUS_OK;
|
|
cam_msg("cam: %d\n", cam_idx);
|
|
kdrv_clock_set_csiclk(cam_idx, 1);
|
|
kdrv_csi2rx_set_power(cam_idx, 1);
|
|
kdrv_csi2rx_reset(cam_idx, ctx->sensor_id);
|
|
return KMDW_STATUS_OK;
|
|
}
|
|
|
|
static kmdw_status_t kmdw_cam_close(uint32_t cam_idx)
|
|
{
|
|
struct kmdw_cam_context *ctx = &cam_ctx[cam_idx];
|
|
if(ctx->cam_input_type != IMGSRC_IN_PORT_MIPI)
|
|
return KMDW_STATUS_OK;
|
|
cam_msg("cam: %d\n", cam_idx);
|
|
kdrv_csi2rx_set_power(cam_idx, 0);
|
|
kdrv_clock_set_csiclk(cam_idx, 0);
|
|
return KMDW_STATUS_OK;
|
|
}
|
|
|
|
static kmdw_status_t kmdw_cam_query_capability(uint32_t cam_idx, struct cam_capability *cap)
|
|
{
|
|
struct kmdw_cam_context *ctx = &cam_ctx[cam_idx];
|
|
|
|
cam_msg("cam: %d\n", cam_idx);
|
|
|
|
ctx->capabilities = CAP_VIDEO_CAPTURE | CAP_STREAMING | CAP_DEVICE_CAPS;
|
|
|
|
strcpy(cap->driver, "kl520_camera");
|
|
strcpy(cap->desc, "kl520_camera");
|
|
cap->version = 0x00010001;
|
|
cap->capabilities = ctx->capabilities;
|
|
return KMDW_STATUS_OK;
|
|
}
|
|
|
|
static kmdw_status_t kmdw_cam_set_format(uint32_t cam_idx, struct cam_format *format)
|
|
{
|
|
struct kmdw_cam_context *ctx = &cam_ctx[cam_idx];
|
|
uint32_t bpp;
|
|
|
|
ctx->fmt = *format;
|
|
|
|
if (format->pixelformat == IMG_FORMAT_RGB565)
|
|
bpp = 2;
|
|
else if (format->pixelformat == IMG_FORMAT_RAW8)
|
|
{
|
|
if(cam_ctx[cam_idx].cam_input_type == IMGSRC_IN_PORT_DPI)
|
|
bpp = 2;
|
|
else
|
|
bpp = 1;
|
|
}
|
|
|
|
ctx->fmt.sizeimage = format->width * format->height * bpp;
|
|
|
|
cam_msg("cam %d: w=%d h=%d p=0x%x f=%d b=%d s=%d c=%d\n", cam_idx,
|
|
ctx->fmt.width, ctx->fmt.height, ctx->fmt.pixelformat, ctx->fmt.field,
|
|
ctx->fmt.bytesperline, ctx->fmt.sizeimage, ctx->fmt.colorspace);
|
|
|
|
kdrv_dpi2ahb_enable(ctx->id, format);
|
|
kdrv_csi2rx_enable(ctx->cam_input_type, ctx->id, ctx->sensor_id, format);
|
|
kmdw_sensor_set_fmt(cam_idx, &ctx->fmt);
|
|
|
|
return KMDW_STATUS_OK;
|
|
}
|
|
|
|
static kmdw_status_t kmdw_cam_get_format(uint32_t cam_idx, struct cam_format *format)
|
|
{
|
|
struct kmdw_cam_context *ctx = &cam_ctx[cam_idx];
|
|
|
|
cam_msg("cam: %d\n", cam_idx);
|
|
|
|
*format = ctx->fmt;
|
|
return KMDW_STATUS_OK;
|
|
}
|
|
|
|
static kmdw_status_t kmdw_cam_buffer_init(uint32_t cam_idx, uint32_t buf_addr_0, uint32_t buf_addr_1)
|
|
{
|
|
struct kmdw_cam_context *ctx = &cam_ctx[cam_idx];
|
|
|
|
cam_msg("cam %d: size=%d\n", cam_idx, ctx->fmt.sizeimage);
|
|
|
|
kdrv_dpi2ahb_buf_init(cam_idx, buf_addr_0, buf_addr_1);
|
|
|
|
return KMDW_STATUS_OK;
|
|
}
|
|
|
|
static kmdw_status_t kmdw_cam_start_capture(uint32_t cam_idx, kmdw_camera_callback_t img_cb)
|
|
{
|
|
cam_msg("cam: %d\n", cam_idx);
|
|
kdrv_csi2rx_start(cam_ctx[cam_idx].cam_input_type, cam_idx);
|
|
kdrv_dpi2ahb_start((uint32_t)cam_idx, img_cb);
|
|
return KMDW_STATUS_OK;
|
|
}
|
|
|
|
static kmdw_status_t kmdw_cam_stop_capture(uint32_t cam_idx)
|
|
{
|
|
cam_msg("cam: %d\n", cam_idx);
|
|
kdrv_dpi2ahb_stop((uint32_t)cam_idx);
|
|
return KMDW_STATUS_OK;
|
|
}
|
|
|
|
static kmdw_status_t kmdw_cam_buffer_prepare(uint32_t cam_idx)
|
|
{
|
|
cam_msg("cam: %d\n", cam_idx);
|
|
return KMDW_STATUS_OK;
|
|
}
|
|
|
|
static kmdw_status_t kmdw_cam_buffer_capture(uint32_t cam_idx, uint32_t *addr, uint32_t *size)
|
|
{
|
|
cam_msg("cam: %d\n", cam_idx);
|
|
return KMDW_STATUS_OK;
|
|
}
|
|
|
|
static kmdw_status_t kmdw_cam_stream_on(uint32_t cam_idx)
|
|
{
|
|
cam_msg("cam: %d\n", cam_idx);
|
|
return KMDW_STATUS_OK;
|
|
}
|
|
|
|
static kmdw_status_t kmdw_cam_stream_off(uint32_t cam_idx)
|
|
{
|
|
cam_msg("cam: %d\n", cam_idx);
|
|
return KMDW_STATUS_OK;
|
|
}
|
|
|
|
static kmdw_status_t kmdw_cam_set_gain(uint32_t cam_idx, uint32_t gain1, uint32_t gain2)
|
|
{
|
|
cam_msg("cam: %d: gain1 %d, gain2 %d\n", cam_idx, gain1, gain2);
|
|
|
|
return kmdw_sensor_set_gain(cam_idx, gain1, gain2);
|
|
}
|
|
|
|
static kmdw_status_t kmdw_cam_set_aec(uint32_t cam_idx, struct cam_sensor_aec *aec_p)
|
|
{
|
|
cam_msg("cam: %d\n", cam_idx);
|
|
|
|
return kmdw_sensor_set_aec(cam_idx, aec_p);
|
|
}
|
|
|
|
static kmdw_status_t kmdw_cam_set_exp_time(uint32_t cam_idx, uint32_t gain1, uint32_t gain2)
|
|
{
|
|
cam_msg("cam: %d: gain1 %d, gain2 %d\n", cam_idx, gain1, gain2);
|
|
|
|
return kmdw_sensor_set_exp_time(cam_idx, gain1, gain2);
|
|
}
|
|
|
|
static kmdw_status_t kmdw_cam_get_lux(uint32_t cam_idx, uint16_t *expo, uint8_t *pre_gain, uint8_t *post_gain, uint8_t *global_gain, uint8_t *y_average)
|
|
{
|
|
cam_msg("cam: %d\n", cam_idx);
|
|
|
|
return kmdw_sensor_get_lux(cam_idx, expo, pre_gain, post_gain, global_gain, y_average);
|
|
}
|
|
|
|
static kmdw_status_t kmdw_cam_led_switch(uint32_t cam_idx, uint32_t on)
|
|
{
|
|
cam_msg("cam: %d\n", cam_idx);
|
|
|
|
return kmdw_sensor_led_switch(cam_idx, on);
|
|
}
|
|
|
|
static kmdw_status_t kmdw_cam_set_mirror(uint32_t cam_idx, uint32_t enable)
|
|
{
|
|
cam_msg("[%s] cam: %d\n", __func__, cam_idx);
|
|
|
|
kmdw_sensor_set_mirror(cam_idx, enable);
|
|
|
|
return KMDW_STATUS_OK;
|
|
}
|
|
|
|
static kmdw_status_t kmdw_cam_set_flip(uint32_t cam_idx, uint32_t enable)
|
|
{
|
|
cam_msg("[%s] cam: %d\n", __func__, cam_idx);
|
|
|
|
kmdw_sensor_set_flip(cam_idx, enable);
|
|
|
|
return KMDW_STATUS_OK;
|
|
}
|
|
|
|
static uint32_t kmdw_cam_get_device_id(uint32_t cam_idx)
|
|
{
|
|
cam_msg("[%s] cam: %d\n", __func__, cam_idx);
|
|
|
|
return kmdw_sensor_get_dev_id(cam_idx);
|
|
}
|
|
|
|
static struct cam_ops kdp520_camera_ops = {
|
|
.open = kmdw_cam_open,
|
|
.close = kmdw_cam_close,
|
|
.query_capability = kmdw_cam_query_capability,
|
|
.set_format = kmdw_cam_set_format,
|
|
.get_format = kmdw_cam_get_format,
|
|
.buffer_init = kmdw_cam_buffer_init,
|
|
.start_capture = kmdw_cam_start_capture,
|
|
.stop_capture = kmdw_cam_stop_capture,
|
|
.buffer_prepare = kmdw_cam_buffer_prepare,
|
|
.buffer_capture = kmdw_cam_buffer_capture,
|
|
.stream_on = kmdw_cam_stream_on,
|
|
.stream_off = kmdw_cam_stream_off,
|
|
.set_gain = kmdw_cam_set_gain,
|
|
.set_aec = kmdw_cam_set_aec,
|
|
.set_exp_time = kmdw_cam_set_exp_time,
|
|
.get_lux = kmdw_cam_get_lux,
|
|
.led_switch = kmdw_cam_led_switch,
|
|
.set_mirror = kmdw_cam_set_mirror,
|
|
.set_flip = kmdw_cam_set_flip,
|
|
.get_device_id = kmdw_cam_get_device_id,
|
|
};
|
|
|
|
static void kmdw_cam_clock_init()
|
|
{
|
|
kdrv_clock_enable(CLK_PLL3);
|
|
kdrv_clock_mgr_change_pll3_clock(/* mnp */ CAM_CLK_MS, CAM_CLK_NS, CAM_CLK_PS,
|
|
/* csi0 */ CSI0_TXESC, CSI0_CSI, CSI0_VC0,
|
|
/* csi1 */ CSI1_TXESC, CSI1_CSI, CSI1_VC0);
|
|
|
|
kdrv_delay_us(10 * 5);
|
|
kdrv_clock_enable(CLK_PLL3_OUT1);
|
|
kdrv_clock_enable(CLK_PLL3_OUT2);
|
|
}
|
|
void kmdw_cam_mipi_init(uint32_t cam_idx)
|
|
{
|
|
critical_msg("[%s] init %d\n", __func__,cam_idx);
|
|
kdrv_csi2rx_initialize(cam_idx);
|
|
}
|
|
|
|
void kmdw_cam_dpi_init(uint32_t cam_idx)
|
|
{
|
|
critical_msg("[%s] init %d\n", __func__);
|
|
if(cam_idx == KDP_CAM_0)
|
|
{
|
|
SCU_EXTREG_MISC_SET_DPI_MUX_0_sel(1);
|
|
}
|
|
else if(cam_idx == KDP_CAM_1)
|
|
{
|
|
SCU_EXTREG_MISC_SET_DPI_MUX_1_sel(1);
|
|
}
|
|
}
|
|
|
|
void kmdw_cam_port_init(uint32_t cam_idx)
|
|
{
|
|
if(cam_ctx[cam_idx].cam_input_type == IMGSRC_IN_PORT_MIPI)
|
|
{
|
|
kmdw_cam_mipi_init(cam_idx);
|
|
}
|
|
else if(cam_ctx[cam_idx].cam_input_type == IMGSRC_IN_PORT_DPI)
|
|
{
|
|
kmdw_cam_dpi_init(cam_idx);
|
|
}
|
|
}
|
|
|
|
kmdw_status_t kmdw_cam_kl520_init(void)
|
|
{
|
|
uint32_t cam_id;
|
|
cam_msg("init\n");
|
|
for(cam_id = 0; cam_id < CAM_ID_MAX ; cam_id++)
|
|
{
|
|
cam_ctx[cam_id].cam_input_type= (cam_id)? IMGSRC_IN_1_PORT : IMGSRC_IN_0_PORT;
|
|
if(cam_ctx[cam_id].cam_input_type != IMGSRC_IN_PORT_NONE)
|
|
{
|
|
cam_ctx[cam_id].id = cam_id;
|
|
cam_ctx[cam_id].sensor_id = (cam_id)?IMGSRC_1_SENSORID: IMGSRC_0_SENSORID;
|
|
kmdw_camera_controller_register(cam_id, &kdp520_camera_ops);
|
|
kmdw_sensor_register(cam_id, cam_ctx[cam_id].sensor_id);
|
|
kmdw_cam_port_init(cam_id);
|
|
kdrv_dpi2ahb_initialize(cam_id);
|
|
}
|
|
}
|
|
kmdw_cam_clock_init();
|
|
|
|
return KMDW_STATUS_OK;
|
|
}
|