Files
test/drivers/source/camera/csi-baremetal/excam/ex_tc9591.c
2025-11-07 20:19:23 +08:00

432 lines
11 KiB
C

/*
* Copyright (c) 2022 Semidrive Semiconductor.
* All rights reserved.
*/
#include "ex_tc9591.h"
#include "camera/sdrv-cam-baremetal-def.h"
#define TC9591_DEVICE_ID 0x4401
#define TC9591_DESER_ADDR 0x0E
enum tc9591_status {
DESER_IDLE,
DESER_STREAM_ON,
};
struct tc9591_dev {
struct vdev_device vdev;
void *i2c_handle;
uint8_t deser_addr;
uint32_t gpio_rst;
uint32_t gpio_cam; //vcam 5v
uint32_t gpio_fsin;//for E3 Display 5019 Fsin pin
osMutexId_t lock;
uint32_t status;
};
static int tc9591_write_reg(struct tc9591_dev *deser, uint16_t reg, uint16_t val)
{
uint8_t buf[4];
int ret = 0;
deser_debug("%s: addr=0x%x, reg=0x%4x, val=0x%4x\n", __func__,
deser->deser_addr, reg, val);
buf[0] = reg >> 8;
buf[1] = reg & 0xff;
buf[2] = val >> 8;
buf[3] = val & 0xFF;
ret = i2c_write(deser->i2c_handle, deser->deser_addr, buf, 4);
if (ret < 0) {
printf("%s: error: reg=0x%04x, val=%04xx\n", __func__, reg, val);
return ret;
}
return ret;
}
static int tc9591_read_reg(struct tc9591_dev *deser, uint16_t reg16, uint16_t *val)
{
uint8_t buf[2], reg[2];
int ret;
reg[0] = reg16 >> 8;
reg[1] = reg16 & 0xff;
memset(buf, 0, sizeof(buf));
ret = i2c_write_read(deser->i2c_handle, deser->deser_addr, reg, 2, buf, 2);
if (ret < 0) {
printf("%s: error: read reg=0x%04x\n", __func__, reg16);
return ret;
}
//printf("%s: OK: read reg=%x, val=%02x %02x\n", __func__, reg16, buf[0], buf[1]);
*val = (buf[0] << 8);
*val |= buf[1];
return 0;
}
static uint16_t tc9591_reg_list[] = {
0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000c, 0x000e,
0x0010, 0x0012, 0x0014, 0x0016, 0x0018, 0x0020, 0x0022, 0x0032,
0x0050, 0x0056, 0x0058, 0x005a, 0x005c, 0x005e, 0x0060, 0x0062,
0x0064, 0x0066, 0x0068, 0x006a, 0x006c, 0x006e, 0x0070, 0x0080,
0x0082, 0x0084, 0x0086, 0x0088, 0x008a, 0x008c, 0x008e, 0x0090,
0x00f8,
};
static int read_all_reg(struct tc9591_dev *deser)
{
int i, j;
uint16_t reg[8], val[8];
for (j = 0; j < 40; j+=8) {
for (i = 0; i < 8; i++) {
reg[i] = tc9591_reg_list[j+i];
tc9591_read_reg(deser, reg[i], &val[i]);
usleep_range(10000, 11000);
}
printf("tc9591 read [0x%04x]=0x%04x [0x%04x]=0x%04x [0x%04x]=0x%04x [0x%04x]=0x%04x [0x%04x]=0x%04x [0x%04x]=0x%04x [0x%04x]=0x%04x [0x%04x]=0x%04x\n",
reg[0], val[0], reg[1], val[1], reg[2], val[2], reg[3], val[3],
reg[4], val[4], reg[5], val[5], reg[6], val[6], reg[7], val[7]);
}
return 0;
}
static int tc9591_check_chip_id(struct tc9591_dev *deser)
{
int ret;
int i = 0;
uint16_t chip_id = 0;
printf("%s\n", __func__);
while (i++ < 3) {
ret = tc9591_read_reg(deser, 0x0000, &chip_id);
if (ret) {
printf("%s: failed to read chip identifier\n", __func__);
continue;
}
if (chip_id != TC9591_DEVICE_ID) {
printf("%s: wrong chip identifier, expected 0x%04x(tc9591), got "
"0x%04x\n",
__func__, TC9591_DEVICE_ID, chip_id);
ret = -1;
continue;
} else {
printf("%s: chip identifier, expected 0x%04x(tc9591), got 0x%04x\n",
__func__, TC9591_DEVICE_ID, chip_id);
break;
}
}
if (ret == 0)
read_all_reg(deser);
return ret;
}
static int tc9591_init_setup(struct tc9591_dev *deser)
{
uint16_t val;
int ret;
ret = tc9591_read_reg(deser, 0x0002, &val);
if (ret < 0) {
printf("tc9591 fail to read 0x02, ret=%d\n", ret);
return ret;
}
printf("tc9591 read [0x0002]=0x%04x\n", val);
ret = tc9591_read_reg(deser, 0x0004, &val);
if (ret < 0) {
printf("tc9591 fail to read 0x04, ret=%d\n", ret);
return ret;
}
printf("tc9591 read [0x0004]=0x%04x\n", val);
tc9591_write_reg(deser, 0x0002, 0x0001); // SYSctl, S/W Reset
mdelay(10);
tc9591_write_reg(deser, 0x0002, 0x0000); // SYSctl, S/W Reset release
tc9591_write_reg(deser, 0x0016, 0x205c); // PLL Control Register 0 (PLL_PRD,PLL_FBD)
tc9591_write_reg(deser, 0x0018, 0X0403); // PLL_FRS,PLL_LBWS, PLL oscillation enable
mdelay(10);
tc9591_write_reg(deser, 0x0018, 0X0413); // PLL_FRS,PLL_LBWS, PLL clock out enable
tc9591_write_reg(deser, 0x0020, 0x0011); // CLK control register: Clock divider setting
tc9591_write_reg(deser, 0x000c, 0x101); // MCLK duty setting
tc9591_write_reg(deser, 0x0010, 0xFFF9); // GPIO Direction, GPIO2,1 output
tc9591_write_reg(deser, 0x0014, 0x0000); // GPIO output data. GPIO2="L", GPIO1="L"
tc9591_write_reg(deser, 0x000E, 0x0006); // GPIO enable. GPIO2,1 enable
tc9591_write_reg(deser, 0x0014, 0x0006); // GPIO output data. GPIO2="H", GPIO1="H"
tc9591_write_reg(deser, 0x0060, 0x800f); //PHY timing delay setting
tc9591_write_reg(deser, 0x0006, 0x0032); // FIFO control
tc9591_write_reg(deser, 0x0008, 0x0061); // DATA FORMAT: yuv422-16bit
tc9591_write_reg(deser, 0x0066, 0x00FF); // enable all error
tc9591_write_reg(deser, 0x0004, 0x141);
printf("tc9591 init setup done\n");
return 0;
}
//extern gpio_dev_t g_gpio_safety;
static int tc9591_s_power(struct vdev_device *vdev, int enable)
{
struct tc9591_dev *deser;
uint32_t pin;
if (!vdev) {
return -1;
}
printf("%s %d\r\n", __func__, enable);
deser = (struct tc9591_dev *)vdev->priv_data;
pin = deser->gpio_rst; /* GPIO_B1 */
if(enable) {
if (deser->status == DESER_STREAM_ON) {
printf("%s: already stream on\n", __func__);
goto exit;
}
printf("%s: pin %d, enable %d\n", __func__, pin, enable);
gpio_set(NULL, pin, false); // low level actice
usleep_range(1000, 1000);
gpio_set(NULL, pin, true);
} else {
gpio_set(NULL, pin, false);
}
exit:
return 0;
}
static int tc9591_enum_mbus_fmt(struct vdev_device *vdev,
struct vdev_mbus_framefmt *fme)
{
struct tc9591_dev *deser;
if ((vdev == NULL) || (fme == NULL)) {
return -1;
}
deser = (struct tc9591_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 tc9591_enum_frame_size(struct vdev_device *vdev,
struct vdev_frame_size_enum *fse)
{
struct tc9591_dev *deser;
if (!vdev || !fse) {
return -1;
}
deser = (struct tc9591_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 tc9591_enum_frame_interval(struct vdev_device *vdev,
struct vdev_frame_interval_enum *fie)
{
return 0;
}
static int tc9591_get_frame_interval(struct vdev_device *vdev,
struct vdev_fract *fi)
{
if (!vdev || !fi) {
return -1;
}
*fi = vdev->frame_interval;
return 0;
}
static int tc9591_set_frame_interval(struct vdev_device *vdev,
struct vdev_fract fi)
{
return 0;
}
static int tc9591_get_fmt(struct vdev_device *vdev,
struct vdev_mbus_framefmt *fmt)
{
if (!vdev) {
return -1;
}
*fmt = vdev->fmt;
return 0;
}
static int tc9591_set_fmt(struct vdev_device *vdev,
struct vdev_mbus_framefmt fmt)
{
return 0;
}
static int tc9591_s_stream(struct vdev_device *vdev, int enable)
{
int ret = 0;
uint32_t cam_pwr = 0;
struct tc9591_dev *deser;
if (!vdev) {
return -1;
}
printf("%s %d\r\n", __func__, enable);
deser = (struct tc9591_dev *)vdev->priv_data;
osMutexAcquire(deser->lock, 0);
cam_pwr = deser->gpio_cam;
if(cam_pwr <=0 ) {
sensor_info("%s get cam pwr pin err\n", __func__);
return -1;
}
if (enable == 1) {
if (deser->status == DESER_STREAM_ON) {
printf("%s: already stream on\n", __func__);
goto exit;
}
gpio_set(NULL, cam_pwr, false);
ret = tc9591_init_setup(deser);
if (ret < 0)
goto exit;
usleep_range(10000,11000);
gpio_set(NULL, cam_pwr, true);
deser->status = DESER_STREAM_ON;
} else {
deser->status = DESER_IDLE;
tc9591_write_reg(deser, 0x0004, 0x0147);
}
read_all_reg(deser);
exit:
osMutexRelease(deser->lock);
return ret;
}
static int tc9591_deinit(struct vdev_device *vdev)
{
struct tc9591_dev *deser;
if (!vdev) {
return -1;
}
deser = (struct tc9591_dev *)vdev->priv_data;
osMutexDelete(deser->lock);
free(deser);
return 0;
}
static const struct vdev_dev_ops tc9591_vdev_ops = {
.s_power = tc9591_s_power,
.enum_mbus_fmt = tc9591_enum_mbus_fmt,
.enum_frame_size = tc9591_enum_frame_size,
.enum_frame_interval = tc9591_enum_frame_interval,
.g_frame_interval = tc9591_get_frame_interval,
.s_frame_interval = tc9591_set_frame_interval,
.get_fmt = tc9591_get_fmt,
.set_fmt = tc9591_set_fmt,
.s_stream = tc9591_s_stream,
.close = tc9591_deinit,
};
struct tc9591_dev g_tc9591;
struct vdev_device *tc9591_init(void *init_data)
{
int ret;
struct tc9591_dev *deser;
struct camera_res_cfg *cfg = (struct camera_res_cfg *)init_data;
//deser = malloc(sizeof(struct tc9591_dev));
deser = &g_tc9591;
if (!deser || !cfg || !cfg->i2c_handle)
return NULL;
printf("%s \r\n", __func__);
memset(deser, 0, sizeof(struct tc9591_dev));
deser->i2c_handle = cfg->i2c_handle;
deser->deser_addr = TC9591_DESER_ADDR;
deser->vdev.priv_data = (void *)deser;
deser->lock = osMutexNew(NULL);
deser->gpio_rst = cfg->gpio[0]; //rst pin
deser->gpio_cam = cfg->gpio[1]; //vcam
deser->gpio_fsin = cfg->gpio[2]; //fsin
tc9591_s_power(&deser->vdev, 1); //power on
ret = tc9591_check_chip_id(deser);
if (ret == 0)
tc9591_s_stream(&deser->vdev, 1);
if (ret < 0)
goto err;
deser->vdev.ep.bus_type = VDEV_MBUS_PARALLEL2;
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_UYVY16;
deser->vdev.fmt.field = VDEV_FIELD_NONE;
deser->vdev.fmt.colorspace = VDEV_COLORSPACE_SRGB;
deser->vdev.ops = tc9591_vdev_ops;
return &deser->vdev;
err:
free(deser);
return NULL;
}
void read_tc9591_regs(void)
{
read_all_reg(&g_tc9591);
}