新增所有文件
This commit is contained in:
349
drivers/source/camera/csi-rtos/excam/ex_max9276.c
Normal file
349
drivers/source/camera/csi-rtos/excam/ex_max9276.c
Normal file
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Semidrive Semiconductor.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#include "ex_max96706.h"
|
||||
|
||||
|
||||
/* ========================================================================================================================= */
|
||||
#define max9276_DEVICE_ID (0x90U)
|
||||
#define max9276_DESER_ADDR (0x48U)
|
||||
|
||||
|
||||
enum max9276_status {
|
||||
DESER_IDLE,
|
||||
DESER_STREAM_ON,
|
||||
};
|
||||
|
||||
struct max9276_dev {
|
||||
struct vdev_device vdev;
|
||||
void *i2c_handle;
|
||||
uint8_t deser_addr;
|
||||
|
||||
uint32_t gpio_pwn;
|
||||
uint32_t gpio_gpi;
|
||||
uint32_t gpio_poc;
|
||||
|
||||
void *port_handle;
|
||||
void *dio_handle;
|
||||
|
||||
uint32_t status;
|
||||
};
|
||||
|
||||
|
||||
/* ========================================================================================================================= */
|
||||
static int max9276_write_reg(struct max9276_dev *deser, uint8_t reg,
|
||||
uint8_t val)
|
||||
{
|
||||
uint8_t buf[2];
|
||||
int ret = 0;
|
||||
|
||||
deser_info("%s: addr=0x%x, reg=0x%x, val=0x%x\r\n", __func__,
|
||||
deser->deser_addr, reg, val);
|
||||
buf[0] = reg;
|
||||
buf[1] = val;
|
||||
ret = i2c_write(deser->i2c_handle, deser->deser_addr, buf, 2);
|
||||
if (ret < 0) {
|
||||
deser_err("%s: error: reg=0x%x, val=%x\r\n", __func__, reg, val);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ========================================================================================================================= */
|
||||
static int max9276_read_reg(struct max9276_dev *deser, uint8_t reg,
|
||||
uint8_t *val)
|
||||
{
|
||||
uint8_t buf[1];
|
||||
int ret = 0;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
ret = i2c_write_read(deser->i2c_handle, deser->deser_addr, ®, 1, buf, 1);
|
||||
if (ret < 0) {
|
||||
deser_err("%s: error: read reg=0x%x\r\n", __func__, reg);
|
||||
return ret;
|
||||
}
|
||||
deser_info("%s: addr=0x%x, reg=0x%x, val=0x%x\r\n", __func__,
|
||||
deser->deser_addr, reg, buf[0]);
|
||||
|
||||
*val = buf[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max9276_check_chip_id(struct max9276_dev *deser)
|
||||
{
|
||||
int ret;
|
||||
int i = 0;
|
||||
uint8_t chip_id = 0;
|
||||
|
||||
deser_info("%s\r\n", __func__);
|
||||
while (i++ < 32) {
|
||||
deser_err("%s: slave addr %x\r\n", __func__, deser->deser_addr);
|
||||
ret = max9276_read_reg(deser, 0x01, &chip_id);
|
||||
if (ret) {
|
||||
deser_err("%s: failed to read chip identifier\r\n", __func__);
|
||||
continue;
|
||||
}
|
||||
udelay(10000); // 10ms
|
||||
if (chip_id != max9276_DEVICE_ID) {
|
||||
deser_err("%s: wrong chip identifier, expected 0x%x(max9276), got "
|
||||
"0x%x\r\n",
|
||||
__func__, max9276_DEVICE_ID, chip_id);
|
||||
continue;
|
||||
} else {
|
||||
deser_info(
|
||||
"%s: chip identifier, expected 0x%x(max9276), got 0x%x\r\n",
|
||||
__func__, max9276_DEVICE_ID, chip_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max9276_init_setup(struct max9276_dev *deser)
|
||||
{
|
||||
int i = 0;
|
||||
uint8_t reg;
|
||||
|
||||
/* Add Init Setting Here */
|
||||
max9276_write_reg(deser, 0x04, 0x00);
|
||||
udelay(1000); // 1ms
|
||||
|
||||
max9276_write_reg(deser, 0x02, 0x0F);
|
||||
udelay(1000); // 1ms
|
||||
|
||||
max9276_write_reg(deser, 0x05, 0x05);
|
||||
udelay(1000); // 1ms
|
||||
|
||||
max9276_write_reg(deser, 0x0C, 0xFF);
|
||||
udelay(1000); // 1ms
|
||||
|
||||
max9276_write_reg(deser, 0x11, 0xA2);
|
||||
udelay(1000); // 1ms
|
||||
|
||||
max9276_write_reg(deser, 0x14, 0x05);
|
||||
udelay(1000); // 1ms
|
||||
|
||||
max9276_write_reg(deser, 0x15, 0xF1);
|
||||
udelay(1000); // 1ms
|
||||
|
||||
max9276_write_reg(deser, 0x16, 0xDA);
|
||||
udelay(1000); // 1ms
|
||||
|
||||
max9276_write_reg(deser, 0x04, 0x03);
|
||||
udelay(1000); // 1ms
|
||||
|
||||
/*
|
||||
for (reg = 0x00; reg < 0x20; reg++) {
|
||||
uint8_t val = 0;
|
||||
max9276_read_reg(deser, reg, &val);
|
||||
ssdk_printf(SSDK_INFO, "reg 0x%02x: 0x%02x", reg, val);
|
||||
}
|
||||
*/
|
||||
for (i = 0; i < 500; i++) {
|
||||
uint8_t val;
|
||||
max9276_read_reg(deser, 0x04, &val);
|
||||
if (val >> 7) {
|
||||
ssdk_printf(SSDK_INFO, "max9276 locked done: %d\r\n", i);
|
||||
break;
|
||||
}
|
||||
ssdk_printf(SSDK_INFO, "max9276 try lock for %d\r\n", i+1);
|
||||
udelay(2000); // 2ms
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max9276_s_power(struct vdev_device *vdev, int enable)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max9276_enum_mbus_fmt(struct vdev_device *vdev,
|
||||
struct vdev_mbus_framefmt *fme)
|
||||
{
|
||||
struct max9276_dev *deser;
|
||||
|
||||
if ((vdev == NULL) || (fme == NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
deser = (struct max9276_dev *)vdev->priv_data;
|
||||
|
||||
if (fme->index > 0) {
|
||||
fme->index = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
fme->code = deser->vdev.fmt.code;
|
||||
fme->field = deser->vdev.fmt.field;
|
||||
fme->colorspace = deser->vdev.fmt.colorspace;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max9276_enum_frame_size(struct vdev_device *vdev,
|
||||
struct vdev_frame_size_enum *fse)
|
||||
{
|
||||
struct max9276_dev *deser;
|
||||
|
||||
if (!vdev || !fse) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
deser = (struct max9276_dev *)vdev->priv_data;
|
||||
|
||||
if (fse->index > 0) {
|
||||
fse->index = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
fse->min_width = deser->vdev.fmt.width;
|
||||
fse->max_width = deser->vdev.fmt.width;
|
||||
fse->min_height = deser->vdev.fmt.height;
|
||||
fse->max_height = deser->vdev.fmt.height;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max9276_enum_frame_interval(struct vdev_device *vdev,
|
||||
struct vdev_frame_interval_enum *fie)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max9276_get_frame_interval(struct vdev_device *vdev,
|
||||
struct vdev_fract *fi)
|
||||
{
|
||||
if (!vdev || !fi) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*fi = vdev->frame_interval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max9276_set_frame_interval(struct vdev_device *vdev,
|
||||
struct vdev_fract fi)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max9276_get_fmt(struct vdev_device *vdev,
|
||||
struct vdev_mbus_framefmt *fmt)
|
||||
{
|
||||
if (!vdev) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*fmt = vdev->fmt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max9276_set_fmt(struct vdev_device *vdev,
|
||||
struct vdev_mbus_framefmt fmt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max9276_s_stream(struct vdev_device *vdev, int enable)
|
||||
{
|
||||
int ret = 0;
|
||||
uint8_t val;
|
||||
struct max9276_dev *deser;
|
||||
|
||||
if (!vdev) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
deser = (struct max9276_dev *)vdev->priv_data;
|
||||
|
||||
if (enable == 1) {
|
||||
if (deser->status == DESER_STREAM_ON) {
|
||||
deser_info("%s: already stream on\r\n", __func__);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = max9276_init_setup(deser);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
||||
deser->status = DESER_STREAM_ON;
|
||||
} else {
|
||||
max9276_read_reg(deser, 0x04, &val);
|
||||
val |= 0x40;
|
||||
max9276_write_reg(deser, 0x04, val);
|
||||
usleep_range(1000, 1100);
|
||||
deser->status = DESER_IDLE;
|
||||
}
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ========================================================================================================================= */
|
||||
static int max9276_deinit(struct vdev_device *vdev)
|
||||
{
|
||||
struct max9276_dev *deser;
|
||||
|
||||
if (!vdev) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
deser = (struct max9276_dev *)vdev->priv_data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ========================================================================================================================= */
|
||||
static const struct vdev_dev_ops max9276_vdev_ops = {
|
||||
.s_power = max9276_s_power,
|
||||
.enum_mbus_fmt = max9276_enum_mbus_fmt,
|
||||
.enum_frame_size = max9276_enum_frame_size,
|
||||
.enum_frame_interval = max9276_enum_frame_interval,
|
||||
.g_frame_interval = max9276_get_frame_interval,
|
||||
.s_frame_interval = max9276_set_frame_interval,
|
||||
.get_fmt = max9276_get_fmt,
|
||||
.set_fmt = max9276_set_fmt,
|
||||
.s_stream = max9276_s_stream,
|
||||
.close = max9276_deinit,
|
||||
};
|
||||
|
||||
/* ========================================================================================================================= */
|
||||
struct vdev_device *max9276_init(void *init_data)
|
||||
{
|
||||
int ret;
|
||||
struct max9276_dev *deser;
|
||||
struct camera_res_cfg *cfg = (struct camera_res_cfg *)init_data;
|
||||
|
||||
deser = pvPortMalloc(sizeof(struct max9276_dev));
|
||||
if (!deser || !cfg || !cfg->i2c_handle)
|
||||
return NULL;
|
||||
|
||||
memset(deser, 0, sizeof(struct max9276_dev));
|
||||
deser->i2c_handle = cfg->i2c_handle;
|
||||
deser->deser_addr = max9276_DESER_ADDR;
|
||||
|
||||
deser->gpio_pwn = cfg->gpio[0];
|
||||
deser->gpio_gpi = cfg->gpio[1];
|
||||
deser->gpio_poc = cfg->gpio[2];
|
||||
deser->vdev.priv_data = (void *)deser;
|
||||
|
||||
max9276_s_power(&deser->vdev, 1);
|
||||
ret = max9276_check_chip_id(deser);
|
||||
max9276_s_power(&deser->vdev, 0);
|
||||
|
||||
deser->vdev.ep.bus_type = VDEV_MBUS_PARALLEL;
|
||||
deser->vdev.frame_interval.numerator = 1;
|
||||
deser->vdev.frame_interval.denominator = 60;
|
||||
deser->vdev.fmt.width = 1920;
|
||||
deser->vdev.fmt.height = 720;
|
||||
deser->vdev.fmt.code = VDEV_MBUS_FMT_BGR24;
|
||||
deser->vdev.fmt.field = VDEV_FIELD_NONE;
|
||||
deser->vdev.fmt.colorspace = VDEV_COLORSPACE_SRGB;
|
||||
deser->vdev.ops = max9276_vdev_ops;
|
||||
|
||||
return &deser->vdev;
|
||||
}
|
||||
Reference in New Issue
Block a user