/* * Copyright (c) 2022 Semidrive Semiconductor. * All rights reserved. */ #include "ex_tc9591.h" #include "camera/sdrv-cam-os-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; }; int test_pattern = 0; 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 usleep_range(10000, 11000); 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 usleep_range(1000, 1100); 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 #if 1 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" #endif 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); vPortFree(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_deser = NULL; 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 = pvPortMalloc(sizeof(struct tc9591_dev)); 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; g_deser = deser; return &deser->vdev; err: vPortFree(deser); return NULL; } void read_tc9591_regs(void) { read_all_reg(g_deser); }