Files
luban-lite/bsp/peripheral/camera/gc0308/drv_gc0308.c

565 lines
12 KiB
C
Raw Normal View History

2024-09-30 17:06:01 +08:00
/*
2025-04-23 17:54:31 +08:00
* Copyright (c) 2024-2025, ArtInChip Technology Co., Ltd
2024-09-30 17:06:01 +08:00
*
* SPDX-License-Identifier: Apache-2.0
*
* Authors: matteo <duanmt@artinchip.com>
*/
#define LOG_TAG "gc0308"
#include <drivers/i2c.h>
#include <drivers/pin.h>
#include "aic_core.h"
#include "mpp_types.h"
#include "mpp_img_size.h"
#include "mpp_vin.h"
#include "drv_camera.h"
#include "camera_inner.h"
/* Default format configuration of GC03xx */
#define GC03_DFT_WIDTH VGA_WIDTH
#define GC03_DFT_HEIGHT VGA_HEIGHT
#define GC03_DFT_BUS_TYPE MEDIA_BUS_PARALLEL
#define GC03_DFT_CODE MEDIA_BUS_FMT_YUYV8_2X8
#define GC03_I2C_SLAVE_ID 0x21
#define GC0308_CHIP_ID 0x9B
static const struct reg8_info sensor_init_data[] = {
{0xfe, 0x00},
{0xec, 0x20},
{0x05, 0x00},
{0x06, 0x00},
{0x07, 0x00},
{0x08, 0x00},
{0x09, 0x01},
{0x0a, 0xe8},
{0x0b, 0x02},
{0x0c, 0x88},
{0x0d, 0x02},
{0x0e, 0x02},
{0x10, 0x26},
{0x11, 0x0d},
{0x12, 0x2a},
{0x13, 0x00},
{0x14, 0x10}, // bit0: mirror
{0x15, 0x0a},
{0x16, 0x05},
{0x17, 0x01},
{0x18, 0x44},
{0x19, 0x44},
{0x1a, 0x2a},
{0x1b, 0x00},
{0x1c, 0x49},
{0x1d, 0x9a},
{0x1e, 0x61},
{0x1f, 0x00}, //pad drv <=24MHz, use 0x00 is ok
{0x20, 0x7f},
{0x21, 0xfa},
{0x22, 0x57},
{0x24, 0xa2}, //YCbYCr
{0x25, 0x0f},
{0x26, 0x03}, // 0x01
{0x28, 0x00},
{0x2d, 0x0a},
{0x2f, 0x01},
{0x30, 0xf7},
{0x31, 0x50},
{0x32, 0x00},
{0x33, 0x28},
{0x34, 0x2a},
{0x35, 0x28},
{0x39, 0x04},
{0x3a, 0x20},
{0x3b, 0x20},
{0x3c, 0x00},
{0x3d, 0x00},
{0x3e, 0x00},
{0x3f, 0x00},
{0x50, 0x14}, // 0x14
{0x52, 0x41},
{0x53, 0x80},
{0x54, 0x80},
{0x55, 0x80},
{0x56, 0x80},
{0x8b, 0x20},
{0x8c, 0x20},
{0x8d, 0x20},
{0x8e, 0x14},
{0x8f, 0x10},
{0x90, 0x14},
{0x91, 0x3c},
{0x92, 0x50},
//{0x8b,0x10},
//{0x8c,0x10},
//{0x8d,0x10},
//{0x8e,0x10},
//{0x8f,0x10},
//{0x90,0x10},
//{0x91,0x3c},
//{0x92,0x50},
{0x5d, 0x12},
{0x5e, 0x1a},
{0x5f, 0x24},
{0x60, 0x07},
{0x61, 0x15},
{0x62, 0x08}, // 0x08
{0x64, 0x03}, // 0x03
{0x66, 0xe8},
{0x67, 0x86},
{0x68, 0x82},
{0x69, 0x18},
{0x6a, 0x0f},
{0x6b, 0x00},
{0x6c, 0x5f},
{0x6d, 0x8f},
{0x6e, 0x55},
{0x6f, 0x38},
{0x70, 0x15},
{0x71, 0x33},
{0x72, 0xdc},
{0x73, 0x00},
{0x74, 0x02},
{0x75, 0x3f},
{0x76, 0x02},
{0x77, 0x38}, // 0x47
{0x78, 0x88},
{0x79, 0x81},
{0x7a, 0x81},
{0x7b, 0x22},
{0x7c, 0xff},
{0x93, 0x48}, //color matrix default
{0x94, 0x02},
{0x95, 0x07},
{0x96, 0xe0},
{0x97, 0x40},
{0x98, 0xf0},
{0xb1, 0x40},
{0xb2, 0x40},
{0xb3, 0x40}, //0x40
{0xb6, 0xe0},
{0xbd, 0x38},
{0xbe, 0x36},
{0xd0, 0xCB},
{0xd1, 0x10},
{0xd2, 0x90},
{0xd3, 0x48},
{0xd5, 0xF2},
{0xd6, 0x16},
{0xdb, 0x92},
{0xdc, 0xA5},
{0xdf, 0x23},
{0xd9, 0x00},
{0xda, 0x00},
{0xe0, 0x09},
{0xed, 0x04},
{0xee, 0xa0},
{0xef, 0x40},
{0x80, 0x03},
{0x9F, 0x10},
{0xA0, 0x20},
{0xA1, 0x38},
{0xA2, 0x4e},
{0xA3, 0x63},
{0xA4, 0x76},
{0xA5, 0x87},
{0xA6, 0xa2},
{0xA7, 0xb8},
{0xA8, 0xca},
{0xA9, 0xd8},
{0xAA, 0xe3},
{0xAB, 0xeb},
{0xAC, 0xf0},
{0xAD, 0xF8},
{0xAE, 0xFd},
{0xAF, 0xFF},
{0xc0, 0x00},
{0xc1, 0x10},
{0xc2, 0x1c},
{0xc3, 0x30},
{0xc4, 0x43},
{0xc5, 0x54},
{0xc6, 0x65},
{0xc7, 0x75},
{0xc8, 0x93},
{0xc9, 0xB0},
{0xca, 0xCB},
{0xcb, 0xE6},
{0xcc, 0xFF},
{0xf0, 0x02},
{0xf1, 0x01},
{0xf2, 0x02},
{0xf3, 0x30},
{0xf7, 0x04},
{0xf8, 0x02},
{0xf9, 0x9f},
{0xfa, 0x78},
{0xfe, 0x01},
{0x00, 0xf5},
{0x02, 0x20},
{0x04, 0x10},
{0x05, 0x08},
{0x06, 0x20},
{0x08, 0x0a},
{0x0a, 0xa0},
{0x0b, 0x60},
{0x0c, 0x08},
{0x0e, 0x44},
{0x0f, 0x32},
{0x10, 0x41},
{0x11, 0x37},
{0x12, 0x22},
{0x13, 0x19},
{0x14, 0x44},
{0x15, 0x44},
{0x16, 0xc2},
{0x17, 0xA8},
{0x18, 0x18},
{0x19, 0x50},
{0x1a, 0xd8},
{0x1b, 0xf5},
{0x70, 0x40},
{0x71, 0x58},
{0x72, 0x30},
{0x73, 0x48},
{0x74, 0x20},
{0x75, 0x60},
{0x77, 0x20},
{0x78, 0x32},
{0x30, 0x03},
{0x31, 0x40},
{0x32, 0x10},
{0x33, 0xe0},
{0x34, 0xe0},
{0x35, 0x00},
{0x36, 0x80},
{0x37, 0x00},
{0x38, 0x04},
{0x39, 0x09},
{0x3a, 0x12},
{0x3b, 0x1C},
{0x3c, 0x28},
{0x3d, 0x31},
{0x3e, 0x44},
{0x3f, 0x57},
{0x40, 0x6C},
{0x41, 0x81},
{0x42, 0x94},
{0x43, 0xA7},
{0x44, 0xB8},
{0x45, 0xD6},
{0x46, 0xEE},
{0x47, 0x0d},
{0x62, 0xf7},
{0x63, 0x68},
{0x64, 0xd3},
{0x65, 0xd3},
{0x66, 0x60},
{0xfe, 0x00},
{0x01, 0x32}, //frame setting
{0x02, 0x0c},
{0x0f, 0x01},
{0xe2, 0x00},
{0xe3, 0x78},
{0xe4, 0x00},
{0xe5, 0xfe},
{0xe6, 0x01},
{0xe7, 0xe0},
{0xe8, 0x01},
{0xe9, 0xe0},
{0xea, 0x01},
{0xeb, 0xe0},
{0xfe, 0x00},
};
struct gc03_dev {
struct rt_device dev;
struct rt_i2c_bus_device *i2c;
u32 rst_pin;
u32 pwdn_pin;
struct clk *clk;
struct mpp_video_fmt fmt;
bool on;
bool streaming;
};
static struct gc03_dev g_gc03_dev = {0};
static int gc03_write_reg(struct rt_i2c_bus_device *i2c, u8 reg, u8 val)
{
2024-10-30 16:50:31 +08:00
if (rt_i2c_write_reg(i2c, GC03_I2C_SLAVE_ID, reg, &val, 1) != 1) {
2024-09-30 17:06:01 +08:00
LOG_E("%s: error: reg = 0x%x, val = 0x%x", __func__, reg, val);
return -1;
}
return 0;
}
static int gc03_read_reg(struct rt_i2c_bus_device *i2c, u8 reg, u8 *val)
{
2024-10-30 16:50:31 +08:00
if (rt_i2c_read_reg(i2c, GC03_I2C_SLAVE_ID, reg, val, 1) != 1) {
2024-09-30 17:06:01 +08:00
LOG_E("%s: error: reg = 0x%x, val = 0x%x", __func__, reg, *val);
return -1;
}
return 0;
}
static void gc0308_reset(struct gc03_dev *sensor)
{
// gc03_write_reg(sensor->i2c, 0xFE, 0xF0);
}
static int gc0308_init(struct gc03_dev *sensor)
{
int i = 0;
const struct reg8_info *info = sensor_init_data;
gc0308_reset(sensor);
aicos_udelay(1000);
for (i = 0; i < ARRAY_SIZE(sensor_init_data); i++, info++) {
if (gc03_write_reg(sensor->i2c, info->reg, info->val))
return -1;
}
return 0;
}
static int gc0308_probe(struct gc03_dev *sensor)
{
u8 id = 0;
if (gc03_read_reg(sensor->i2c, 0x0, &id))
return -1;
if (id != GC0308_CHIP_ID) {
LOG_E("Invalid chip ID: %02x\n", id);
return -1;
}
return gc0308_init(sensor);
}
2025-04-23 17:54:31 +08:00
static bool gc0308_is_open(struct gc03_dev *sensor)
{
return sensor->on;
}
2024-09-30 17:06:01 +08:00
static void gc0308_power_on(struct gc03_dev *sensor)
{
if (sensor->on)
return;
2024-10-30 16:50:31 +08:00
camera_pin_set_low(sensor->pwdn_pin);
2024-09-30 17:06:01 +08:00
aicos_udelay(1);
2024-10-30 16:50:31 +08:00
camera_pin_set_high(sensor->rst_pin);
2024-09-30 17:06:01 +08:00
2025-04-23 17:54:31 +08:00
LOG_I("Power on");
2024-09-30 17:06:01 +08:00
sensor->on = true;
}
static void gc0308_power_off(struct gc03_dev *sensor)
{
if (!sensor->on)
return;
2024-10-30 16:50:31 +08:00
camera_pin_set_high(sensor->pwdn_pin);
2024-09-30 17:06:01 +08:00
2025-04-23 17:54:31 +08:00
LOG_I("Power off");
2024-09-30 17:06:01 +08:00
sensor->on = false;
}
static rt_err_t gc03_init(rt_device_t dev)
{
struct gc03_dev *sensor = &g_gc03_dev;
sensor->i2c = camera_i2c_get();
if (!sensor->i2c)
return -RT_EINVAL;
sensor->fmt.code = GC03_DFT_CODE;
sensor->fmt.width = GC03_DFT_WIDTH;
sensor->fmt.height = GC03_DFT_HEIGHT;
sensor->fmt.bus_type = GC03_DFT_BUS_TYPE;
sensor->fmt.flags = MEDIA_SIGNAL_HSYNC_ACTIVE_HIGH |
MEDIA_SIGNAL_VSYNC_ACTIVE_LOW |
MEDIA_SIGNAL_PCLK_SAMPLE_FALLING;
sensor->rst_pin = camera_rst_pin_get();
sensor->pwdn_pin = camera_pwdn_pin_get();
if (!sensor->rst_pin || !sensor->pwdn_pin)
return -RT_EINVAL;
return RT_EOK;
}
static rt_err_t gc03_open(rt_device_t dev, rt_uint16_t oflag)
{
2025-04-23 17:54:31 +08:00
struct gc03_dev *sensor = (struct gc03_dev *)dev;
if (gc0308_is_open(sensor))
return RT_EOK;
gc0308_power_on(sensor);
if (gc0308_probe(sensor)) {
gc0308_power_off(sensor);
return -RT_ERROR;
}
LOG_I("GC0308 inited");
2024-09-30 17:06:01 +08:00
return RT_EOK;
}
static rt_err_t gc03_close(rt_device_t dev)
{
struct gc03_dev *sensor = (struct gc03_dev *)dev;
2025-04-23 17:54:31 +08:00
if (!gc0308_is_open(sensor))
return -RT_ERROR;
2024-09-30 17:06:01 +08:00
gc0308_power_off(sensor);
return RT_EOK;
}
2025-01-08 19:12:06 +08:00
static int gc03_get_fmt(struct gc03_dev *sensor, struct mpp_video_fmt *cfg)
2024-09-30 17:06:01 +08:00
{
cfg->code = sensor->fmt.code;
cfg->width = sensor->fmt.width;
cfg->height = sensor->fmt.height;
cfg->flags = sensor->fmt.flags;
cfg->bus_type = sensor->fmt.bus_type;
return RT_EOK;
}
2025-01-08 19:12:06 +08:00
static int gc03_start(struct gc03_dev *sensor)
2024-09-30 17:06:01 +08:00
{
return 0;
}
2025-01-08 19:12:06 +08:00
static int gc03_stop(struct gc03_dev *sensor)
2024-09-30 17:06:01 +08:00
{
return 0;
}
2025-04-23 17:54:31 +08:00
static int gc03_pause(rt_device_t dev)
{
return gc03_close(dev);
}
static int gc03_resume(rt_device_t dev)
{
return gc03_open(dev, 0);
}
2025-01-08 19:12:06 +08:00
/* Edge Enhancement */
static int gc03_set_ee(struct gc03_dev *sensor, u32 percent)
{
u8 cur = 0, val = PERCENT_TO_INT(0, 0xFF, percent);
if (gc03_read_reg(sensor->i2c, 0x77, &cur)) {
LOG_E("Failed to get current EE\n");
return -1;
}
LOG_I("Set Edge Enhancement 0x%02x -> 0x%02x\n", cur, val);
if (cur == val)
return 0;
return gc03_write_reg(sensor->i2c, 0x77, val);
}
static int gc03_enable_flip(struct gc03_dev *sensor, bool enable,
u8 mask, u8 shift, char *name)
{
u8 cur = 0;
if (gc03_read_reg(sensor->i2c, 0x14, &cur)) {
LOG_E("Failed to get current flip\n");
return -1;
}
LOG_I("Set %s flip %d -> %d\n", name, (cur & mask) >> shift, enable);
if ((cur & mask) >> shift == (u8)enable)
return 0;
if (enable)
return gc03_write_reg(sensor->i2c, 0x14, cur | mask);
else
return gc03_write_reg(sensor->i2c, 0x14, cur & ~mask);
}
static int gc03_enable_h_flip(struct gc03_dev *sensor, bool enable)
{
return gc03_enable_flip(sensor, enable, 1, 0, "H");
}
static int gc03_enable_v_flip(struct gc03_dev *sensor, bool enable)
{
return gc03_enable_flip(sensor, enable, 2, 1, "V");
}
2024-09-30 17:06:01 +08:00
static rt_err_t gc03_control(rt_device_t dev, int cmd, void *args)
{
2025-01-08 19:12:06 +08:00
struct gc03_dev *sensor = (struct gc03_dev *)dev;
2024-09-30 17:06:01 +08:00
switch (cmd) {
case CAMERA_CMD_START:
2025-01-08 19:12:06 +08:00
return gc03_start(sensor);
2024-09-30 17:06:01 +08:00
case CAMERA_CMD_STOP:
2025-01-08 19:12:06 +08:00
return gc03_stop(sensor);
2025-04-23 17:54:31 +08:00
case CAMERA_CMD_PAUSE:
return gc03_pause(dev);
case CAMERA_CMD_RESUME:
return gc03_resume(dev);
2024-09-30 17:06:01 +08:00
case CAMERA_CMD_GET_FMT:
2025-01-08 19:12:06 +08:00
return gc03_get_fmt(sensor, (struct mpp_video_fmt *)args);
case CAMERA_CMD_SET_SHARPNESS:
return gc03_set_ee(sensor, *(u32 *)args);
case CAMERA_CMD_SET_H_FLIP:
return gc03_enable_h_flip(sensor, *(bool *)args);
case CAMERA_CMD_SET_V_FLIP:
return gc03_enable_v_flip(sensor, *(bool *)args);
2024-09-30 17:06:01 +08:00
default:
LOG_I("Unsupported cmd: 0x%x", cmd);
return -RT_EINVAL;
}
return RT_EOK;
}
#ifdef RT_USING_DEVICE_OPS
static const struct rt_device_ops gc03_ops =
{
.init = gc03_init,
.open = gc03_open,
.close = gc03_close,
.control = gc03_control,
};
#endif
int rt_hw_gc03_init(void)
{
#ifdef RT_USING_DEVICE_OPS
g_gc03_dev.dev.ops = &gc03_ops;
#else
g_gc03_dev.dev.init = gc03_init;
g_gc03_dev.dev.open = gc03_open;
g_gc03_dev.dev.close = gc03_close;
g_gc03_dev.dev.control = gc03_control;
#endif
g_gc03_dev.dev.type = RT_Device_Class_CAMERA;
rt_device_register(&g_gc03_dev.dev, CAMERA_DEV_NAME, 0);
return 0;
}
INIT_DEVICE_EXPORT(rt_hw_gc03_init);