/* * 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; }