422 lines
11 KiB
C
422 lines
11 KiB
C
/*
|
|
* Copyright (c) 2022 Semidrive Semiconductor.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#include "camera/sdrv-cam-baremetal-def.h"
|
|
#include "ex_ti926.h"
|
|
|
|
#define TI926_DEVICE_ID 0x58
|
|
#define TI926_DESER_ADDR 0x2C
|
|
|
|
enum ti926_status {
|
|
DESER_IDLE,
|
|
DESER_STREAM_ON,
|
|
};
|
|
|
|
struct ti926_dev {
|
|
struct vdev_device vdev;
|
|
void *i2c_handle;
|
|
uint8_t deser_addr;
|
|
|
|
uint32_t gpio_pwn;
|
|
uint32_t gpio_intn;
|
|
|
|
osMutexId_t lock;
|
|
uint32_t status;
|
|
};
|
|
|
|
static struct ti926_dev g_ti926_dev;
|
|
|
|
int test_pattern = 0;
|
|
|
|
static int ti926_write_reg(struct ti926_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\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\n", __func__, reg, val);
|
|
return ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int ti926_read_reg(struct ti926_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%02x\n", __func__, reg);
|
|
return ret;
|
|
}
|
|
|
|
*val = buf[0];
|
|
return 0;
|
|
}
|
|
|
|
uint8_t reg_list[] = {
|
|
0x3A, 0x41, 0x44, 0x56, 0x64, 0x65, 0x66,
|
|
0x67, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5,
|
|
};
|
|
|
|
static int read_all_reg(struct ti926_dev *deser)
|
|
{
|
|
int cnt, j;
|
|
uint8_t reg, val;
|
|
for (reg = 0x00; reg <= 0x17; reg++) {
|
|
ti926_read_reg(deser, reg, &val);
|
|
sensor_debug("ti926 [0x%02x]=0x%02x\n", reg, val);
|
|
}
|
|
|
|
for (reg = 0x1c; reg <= 0x2c; reg++) {
|
|
ti926_read_reg(deser, reg, &val);
|
|
sensor_debug("ti926 [0x%02x]=0x%02x\n", reg, val);
|
|
}
|
|
|
|
cnt = sizeof(reg_list);
|
|
for (j = 0; j < cnt; j++) {
|
|
reg = reg_list[j];
|
|
ti926_read_reg(deser, reg, &val);
|
|
sensor_debug("ti926 [0x%02x]=0x%02x\n", reg, val);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int ti926_check_chip_id(struct ti926_dev *deser)
|
|
{
|
|
int ret;
|
|
int i = 0;
|
|
uint8_t chip_id = 0;
|
|
|
|
deser_info("%s\n", __func__);
|
|
while (i++ < 30) {
|
|
ret = ti926_read_reg(deser, 0x00, &chip_id);
|
|
if (ret) {
|
|
deser_err("%s: failed to read chip identifier\n", __func__);
|
|
continue;
|
|
}
|
|
|
|
if (chip_id != TI926_DEVICE_ID) {
|
|
deser_err("%s: wrong chip identifier, expected 0x%x(ti926), got "
|
|
"0x%x\n",
|
|
__func__, TI926_DEVICE_ID, chip_id);
|
|
ret = -1;
|
|
continue;
|
|
} else {
|
|
deser_info("%s: chip identifier, expected 0x%x(ti926), got 0x%x\n",
|
|
__func__, TI926_DEVICE_ID, chip_id);
|
|
break;
|
|
}
|
|
}
|
|
if (ret == 0)
|
|
read_all_reg(deser);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int ti926_init_setup(struct ti926_dev *deser)
|
|
{
|
|
uint8_t val;
|
|
int ret;
|
|
|
|
ret = ti926_read_reg(deser, 0x01, &val);
|
|
if (ret < 0) {
|
|
deser_err("ti926 fail to read 0x01, ret=%d\n", ret);
|
|
return ret;
|
|
}
|
|
deser_err("ti926 read [0x01]=0x%02x\n", val);
|
|
|
|
if (test_pattern) {
|
|
// 1280x480 test pattern
|
|
ti926_write_reg(deser, 0x66, 0x0e); // config,b'0000|[Ve|He|Vp|Hp]
|
|
ti926_write_reg(deser, 0x67, 0x02);
|
|
ti926_write_reg(deser, 0x66, 0x03); // clock divider
|
|
ti926_write_reg(deser, 0x67, 0x03);
|
|
ti926_write_reg(deser, 0x66, 0x04); // HT 8least
|
|
ti926_write_reg(deser, 0x67, 0x54);
|
|
ti926_write_reg(deser, 0x66, 0x05); // VT 4least|HT 4most
|
|
ti926_write_reg(deser, 0x67, 0xb5);
|
|
ti926_write_reg(deser, 0x66, 0x06); // VT 8most
|
|
ti926_write_reg(deser, 0x67, 0x20);
|
|
ti926_write_reg(deser, 0x66, 0x07); // H 8least
|
|
ti926_write_reg(deser, 0x67, 0x00);
|
|
ti926_write_reg(deser, 0x66, 0x08); // V 4least|H 4most
|
|
ti926_write_reg(deser, 0x67, 0x05);
|
|
ti926_write_reg(deser, 0x66, 0x09); // V 8most
|
|
ti926_write_reg(deser, 0x67, 0x1e);
|
|
ti926_write_reg(deser, 0x66, 0x0a); // HS
|
|
ti926_write_reg(deser, 0x67, 0x1c);
|
|
ti926_write_reg(deser, 0x66, 0x0b); // VS
|
|
ti926_write_reg(deser, 0x67, 0x0d);
|
|
ti926_write_reg(deser, 0x66, 0x0c); // HBP
|
|
ti926_write_reg(deser, 0x67, 0x38);
|
|
ti926_write_reg(deser, 0x66, 0x0d); // VBP
|
|
ti926_write_reg(deser, 0x67, 0x1c);
|
|
ti926_write_reg(deser, 0x65, 0x04);
|
|
ti926_write_reg(deser, 0x64, 0x11);
|
|
} else {
|
|
ti926_write_reg(deser, 0x64, 0x10);
|
|
ti926_write_reg(deser, 0x29, 0xA0);
|
|
}
|
|
|
|
deser_info("ti926 init setup done\n");
|
|
|
|
read_all_reg(deser);
|
|
|
|
return 0;
|
|
}
|
|
|
|
//extern gpio_dev_t g_gpio_safety;
|
|
|
|
static int ti926_s_power(struct vdev_device *vdev, int enable)
|
|
{
|
|
struct ti926_dev *deser;
|
|
uint32_t pin;
|
|
// gpio_dev_t *gpio_dev = &g_gpio_safety;
|
|
|
|
if (!vdev) {
|
|
return -1;
|
|
}
|
|
deser = (struct ti926_dev *)vdev->priv_data;
|
|
pin = deser->gpio_pwn; /* GPIO_C14 */
|
|
deser_info("%s: pin %d, enable %d\n", __func__, pin, enable);
|
|
gpio_set(NULL, pin, enable ? true : false);
|
|
usleep_range(10000, 11000);
|
|
return 0;
|
|
}
|
|
|
|
static int ti926_enum_mbus_fmt(struct vdev_device *vdev,
|
|
struct vdev_mbus_framefmt *fme)
|
|
{
|
|
struct ti926_dev *deser;
|
|
|
|
if ((vdev == NULL) || (fme == NULL)) {
|
|
return -1;
|
|
}
|
|
|
|
deser = (struct ti926_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 ti926_enum_frame_size(struct vdev_device *vdev,
|
|
struct vdev_frame_size_enum *fse)
|
|
{
|
|
struct ti926_dev *deser;
|
|
|
|
if (!vdev || !fse) {
|
|
return -1;
|
|
}
|
|
|
|
deser = (struct ti926_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 ti926_enum_frame_interval(struct vdev_device *vdev,
|
|
struct vdev_frame_interval_enum *fie)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int ti926_get_frame_interval(struct vdev_device *vdev,
|
|
struct vdev_fract *fi)
|
|
{
|
|
if (!vdev || !fi) {
|
|
return -1;
|
|
}
|
|
|
|
*fi = vdev->frame_interval;
|
|
return 0;
|
|
}
|
|
|
|
static int ti926_set_frame_interval(struct vdev_device *vdev,
|
|
struct vdev_fract fi)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int ti926_get_fmt(struct vdev_device *vdev,
|
|
struct vdev_mbus_framefmt *fmt)
|
|
{
|
|
if (!vdev) {
|
|
return -1;
|
|
}
|
|
|
|
*fmt = vdev->fmt;
|
|
return 0;
|
|
}
|
|
|
|
static int ti926_set_fmt(struct vdev_device *vdev,
|
|
struct vdev_mbus_framefmt fmt)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int ti926_s_stream(struct vdev_device *vdev, int enable)
|
|
{
|
|
int ret = 0;
|
|
struct ti926_dev *deser;
|
|
|
|
if (!vdev) {
|
|
return -1;
|
|
}
|
|
|
|
deser = (struct ti926_dev *)vdev->priv_data;
|
|
osMutexAcquire(deser->lock, 0);
|
|
|
|
if (enable == 1) {
|
|
if (deser->status == DESER_STREAM_ON) {
|
|
deser_info("%s: already stream on\n", __func__);
|
|
goto exit;
|
|
}
|
|
|
|
ret = ti926_init_setup(deser);
|
|
if (ret < 0)
|
|
goto exit;
|
|
|
|
deser->status = DESER_STREAM_ON;
|
|
|
|
} else {
|
|
deser->status = DESER_IDLE;
|
|
ti926_write_reg(deser, 0x64, 0x10);
|
|
ti926_write_reg(deser, 0x65, 0x00);
|
|
}
|
|
|
|
exit:
|
|
osMutexRelease(deser->lock);
|
|
return ret;
|
|
}
|
|
|
|
static int ti926_deinit(struct vdev_device *vdev)
|
|
{
|
|
struct ti926_dev *deser;
|
|
|
|
if (!vdev) {
|
|
return -1;
|
|
}
|
|
|
|
deser = (struct ti926_dev *)vdev->priv_data;
|
|
osMutexDelete(deser->lock);
|
|
free(deser);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct vdev_dev_ops ti926_vdev_ops = {
|
|
.s_power = ti926_s_power,
|
|
.enum_mbus_fmt = ti926_enum_mbus_fmt,
|
|
.enum_frame_size = ti926_enum_frame_size,
|
|
.enum_frame_interval = ti926_enum_frame_interval,
|
|
.g_frame_interval = ti926_get_frame_interval,
|
|
.s_frame_interval = ti926_set_frame_interval,
|
|
.get_fmt = ti926_get_fmt,
|
|
.set_fmt = ti926_set_fmt,
|
|
.s_stream = ti926_s_stream,
|
|
.close = ti926_deinit,
|
|
};
|
|
|
|
struct ti926_dev *g_deser = NULL;
|
|
struct vdev_device *ti926_init(void *init_data)
|
|
{
|
|
int ret;
|
|
struct ti926_dev *deser;
|
|
struct camera_res_cfg *cfg = (struct camera_res_cfg *)init_data;
|
|
|
|
// deser = malloc(sizeof(struct ti926_dev));
|
|
deser = &g_ti926_dev;
|
|
if (!deser || !cfg || !cfg->i2c_handle)
|
|
return NULL;
|
|
|
|
memset(deser, 0, sizeof(struct ti926_dev));
|
|
deser->i2c_handle = cfg->i2c_handle;
|
|
deser->deser_addr = TI926_DESER_ADDR;
|
|
|
|
deser->gpio_pwn = cfg->gpio[0];
|
|
deser->gpio_intn = cfg->gpio[1];
|
|
|
|
deser->vdev.priv_data = (void *)deser;
|
|
deser->lock = osMutexNew(NULL);
|
|
|
|
ti926_s_power(&deser->vdev, 1);
|
|
ret = ti926_check_chip_id(deser);
|
|
if (ret == 0)
|
|
ti926_s_stream(&deser->vdev, 0);
|
|
|
|
ti926_s_power(&deser->vdev, 0);
|
|
if (ret < 0)
|
|
goto err;
|
|
|
|
deser->vdev.ep.bus_type = VDEV_MBUS_PARALLEL;
|
|
deser->vdev.frame_interval.numerator = 1;
|
|
if (test_pattern) {
|
|
deser->vdev.frame_interval.denominator = 83;
|
|
deser->vdev.fmt.width = 1280;
|
|
deser->vdev.fmt.height = 480;
|
|
} else {
|
|
deser->vdev.frame_interval.denominator = 56;
|
|
deser->vdev.fmt.width = 1920;
|
|
deser->vdev.fmt.height = 720;
|
|
}
|
|
deser->vdev.fmt.code = VDEV_MBUS_FMT_RGB24;
|
|
deser->vdev.fmt.field = VDEV_FIELD_NONE;
|
|
deser->vdev.fmt.colorspace = VDEV_COLORSPACE_SRGB;
|
|
deser->vdev.ops = ti926_vdev_ops;
|
|
|
|
g_deser = deser;
|
|
|
|
return &deser->vdev;
|
|
|
|
err:
|
|
free(deser);
|
|
return NULL;
|
|
}
|
|
|
|
int user_test(int read, uint8_t reg, uint8_t *val)
|
|
{
|
|
if (g_deser == NULL || val == NULL)
|
|
return 0;
|
|
|
|
if (reg > 0xf8) {
|
|
read_all_reg(g_deser);
|
|
return 0;
|
|
}
|
|
|
|
if (read) {
|
|
ti926_read_reg(g_deser, reg, val);
|
|
sensor_debug("user read reg[0x%02x]=0x%02x\n", reg, *val);
|
|
} else {
|
|
sensor_debug("user write reg[0x%02x]=0x%02x\n", reg, *val);
|
|
ti926_write_reg(g_deser, reg, *val);
|
|
}
|
|
return 0;
|
|
}
|