#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define OV5645_VOLTAGE_ANALOG 2800000 #define OV5645_VOLTAGE_DIGITAL_CORE 1500000 #define OV5645_VOLTAGE_DIGITAL_IO 2800000 #define MIN_FPS 30 #define MAX_FPS 30 #define DEFAULT_FPS 30 #define OV5645_XCLK_MIN 6000000 #define OV5645_XCLK_MAX 24000000 #define OV5645_XCLK_20MHZ 20000000 #define OV5645_CHIP_ID_HIGH_BYTE 0x300A #define OV5645_CHIP_ID_LOW_BYTE 0x300B enum ov5645_mode { ov5645_mode_MIN = 0, ov5645_mode_1080P_1920_1080 = 0, ov5645_mode_MAX = 1, ov5645_mode_INIT = 0xff, /*only for sensor init*/ }; enum ov5645_frame_rate { //ov5645_60_fps, ov5645_30_fps, }; struct ov5645_datafmt { u32 code; enum v4l2_colorspace colorspace; }; /* image size under 1280 * 960 are SUBSAMPLING * image size upper 1280 * 960 are SCALING */ enum ov5645_downsize_mode { SUBSAMPLING, SCALING, }; enum ov5645_af_mode { ov5645_af_release = 0, ov5645_af_lock = 1, ov5645_af_cont = 2, }; struct reg_value { u16 u16RegAddr; u8 u8Val; u8 u8Mask; u32 u32Delay_ms; }; struct ov5645_mode_info { enum ov5645_mode mode; enum ov5645_downsize_mode dn_mode; u32 width; u32 height; struct reg_value *init_data_ptr; u32 init_data_size; }; struct ov5645 { struct v4l2_subdev subdev; struct i2c_client *i2c_client; struct v4l2_pix_format pix; const struct ov5645_datafmt *fmt; struct v4l2_captureparm streamcap; bool on; /* control settings */ int brightness; int hue; int contrast; int saturation; int red; int green; int blue; int ae_mode; u32 mclk; u8 mclk_source; struct clk *sensor_clk; int csi; void (*io_init)(void); /* Fields to keep track of loaded settings */ enum ov5645_frame_rate loaded_fps; enum ov5645_mode loaded_mode; bool initialized; }; struct ov5645_res { int width; int height; }; /*! * Maintains the information on the current state of the sesor. */ static struct ov5645 ov5645_data; static struct regulator *io_regulator; static struct regulator *core_regulator; static struct regulator *analog_regulator; static struct regulator *gpo_regulator; static int ov5645_probe(struct i2c_client *adapter, const struct i2c_device_id *device_id); static int ov5645_remove(struct i2c_client *client); static const struct i2c_device_id ov5645_id[] = { {"ov5645_mipi", 0}, {}, }; MODULE_DEVICE_TABLE(i2c, ov5645_id); static struct i2c_driver ov5645_i2c_driver = { .driver = { .owner = THIS_MODULE, .name = "ov5645_mipi", }, .probe = ov5645_probe, .remove = ov5645_remove, .id_table = ov5645_id, }; static const struct ov5645_datafmt ov5645_colour_fmts[] = { // {MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG}, // {MEDIA_BUS_FMT_YUYV8_2X8}, {MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG}, }; static struct ov5645 *to_ov5645(const struct i2c_client *client) { return container_of(i2c_get_clientdata(client), struct ov5645, subdev); } /* Find a data format by a pixel code in an array */ static const struct ov5645_datafmt *ov5645_find_datafmt(u32 code) { int i; for (i = 0; i < ARRAY_SIZE(ov5645_colour_fmts); i++) if (ov5645_colour_fmts[i].code == code) return ov5645_colour_fmts + i; return NULL; } /*! * ov5645_s_power - V4L2 sensor interface handler for VIDIOC_S_POWER ioctl * @s: pointer to standard V4L2 device structure * @on: indicates power mode (on or off) * * Turns the power on or off, depending on the value of on and returns the * appropriate error code. */ static int ov5645_s_power(struct v4l2_subdev *sd, int on) { printk("inside ov5645_s_power ODM \n"); struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov5645 *sensor = to_ov5645(client); if (on && !sensor->on) { if (io_regulator) if (regulator_enable(io_regulator) != 0) return -EIO; if (core_regulator) if (regulator_enable(core_regulator) != 0) return -EIO; if (gpo_regulator) if (regulator_enable(gpo_regulator) != 0) return -EIO; if (analog_regulator) if (regulator_enable(analog_regulator) != 0) return -EIO; } else if (!on && sensor->on) { if (analog_regulator) regulator_disable(analog_regulator); if (core_regulator) regulator_disable(core_regulator); if (io_regulator) regulator_disable(io_regulator); if (gpo_regulator) regulator_disable(gpo_regulator); } sensor->on = on; return 0; } /*! * ov5645_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl * @s: pointer to standard V4L2 sub device structure * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure * * Returns the sensor's video CAPTURE parameters. */ static int ov5645_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a) { printk("inside ov5645_g_parm ODM \n"); struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov5645 *sensor = to_ov5645(client); struct v4l2_captureparm *cparm = &a->parm.capture; int ret = 0; switch (a->type) { /* This is the only case currently handled. */ case V4L2_BUF_TYPE_VIDEO_CAPTURE: memset(a, 0, sizeof(*a)); a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; cparm->capability = sensor->streamcap.capability; cparm->timeperframe = sensor->streamcap.timeperframe; cparm->capturemode = sensor->streamcap.capturemode; ret = 0; break; /* These are all the possible cases. */ case V4L2_BUF_TYPE_VIDEO_OUTPUT: case V4L2_BUF_TYPE_VIDEO_OVERLAY: case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: ret = -EINVAL; break; default: pr_debug(" type is unknown - %d\n", a->type); ret = -EINVAL; break; } return ret; } /*! * ov5460_s_parm - V4L2 sensor interface handler for VIDIOC_S_PARM ioctl * @s: pointer to standard V4L2 sub device structure * @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure * * Configures the sensor to use the input parameters, if possible. If * not possible, reverts to the old parameters and returns the * appropriate error code. */ static int ov5645_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a) { printk("inside ov5645_s_parm ODM \n"); struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov5645 *sensor = to_ov5645(client); struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe; // u32 tgt_fps; /* target frames per secound */ int ret = 0; return 0; } static int ov5645_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { printk("inside ov5645_set_fmt ODM \n"); struct v4l2_mbus_framefmt *mf = &format->format; const struct ov5645_datafmt *fmt = ov5645_find_datafmt(mf->code); struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov5645 *sensor = to_ov5645(client); // int capturemode; printk(" -- %x - %x - %d - %d\n", mf->code, mf->colorspace, mf->width, mf->height); return 0; } static int ov5645_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { printk("inside ov5645_get_fmt ODM \n"); struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov5645 *sensor = to_ov5645(client); const struct ov5645_datafmt *fmt = sensor->fmt; if (format->pad) return -EINVAL; mf->code = fmt->code; mf->colorspace = fmt->colorspace; mf->field = V4L2_FIELD_NONE; mf->width = ov5645_data.pix.width; mf->height = ov5645_data.pix.height; return 0; } static int ov5645_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { printk("inside ov5645_enum_mbus_code ODM \n"); code->code = MEDIA_BUS_FMT_UYVY8_2X8; return 0; } /*! * ov5645_enum_framesizes - V4L2 sensor interface handler for * VIDIOC_ENUM_FRAMESIZES ioctl * @s: pointer to standard V4L2 device structure * @fsize: standard V4L2 VIDIOC_ENUM_FRAMESIZES ioctl structure * * Return 0 if successful, otherwise -EINVAL. */ static int ov5645_enum_framesizes(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { printk("inside ov5645_enum_framesizes ODM \n"); if (fse->index > ov5645_mode_MAX) return -EINVAL; fse->max_width = 1920; fse->min_width = fse->max_width; fse->max_height = 1080; fse->min_height = fse->max_height; return 0; } static int ov5645_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) { return -EINVAL; } /*! * ov5645_enum_frameintervals - V4L2 sensor interface handler for * VIDIOC_ENUM_FRAMEINTERVALS ioctl * @s: pointer to standard V4L2 device structure * @fival: standard V4L2 VIDIOC_ENUM_FRAMEINTERVALS ioctl structure * * Return 0 if successful, otherwise -EINVAL. */ static int ov5645_enum_frameintervals(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_interval_enum *fie) { printk("inside ov5645_enum_frameintervals ODM \n"); int i, j, count = 0; if (fie->index != 0) //< 0 || fie->index > ov5645_mode_MAX) return -EINVAL; fie->width = 1920; fie->height = 1080; fie->interval.numerator = 1; fie->interval.numerator = 30; return 0; } static int ov5645_s_stream(struct v4l2_subdev *sd, int enable) { printk("im here ov5645_s_stream %d\n ODM ",enable); return 0; } static struct v4l2_subdev_video_ops ov5645_subdev_video_ops = { .g_parm = ov5645_g_parm, .s_parm = ov5645_s_parm, .s_stream = ov5645_s_stream, }; static const struct v4l2_subdev_pad_ops ov5645_subdev_pad_ops = { .enum_frame_size = ov5645_enum_framesizes, .enum_frame_interval = ov5645_enum_frameintervals, .enum_mbus_code = ov5645_enum_mbus_code, .set_fmt = ov5645_set_fmt, .get_fmt = ov5645_get_fmt, }; static struct v4l2_subdev_core_ops ov5645_subdev_core_ops = { .s_power = ov5645_s_power, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = ov5645_get_register, .s_register = ov5645_set_register, #endif .queryctrl = ov5645_queryctrl, }; static struct v4l2_subdev_ops ov5645_subdev_ops = { .core = &ov5645_subdev_core_ops, .video = &ov5645_subdev_video_ops, .pad = &ov5645_subdev_pad_ops, }; /*! * ov5645 I2C probe function * * @param adapter struct i2c_adapter * * @return Error code indicating success or failure */ static int ov5645_probe(struct i2c_client *client, const struct i2c_device_id *id) { printk("inside ov5645_probe ODM \n"); struct device *dev = &client->dev; int retval; /* Set initial values for the sensor struct. */ memset(&ov5645_data, 0, sizeof(ov5645_data)); ov5645_data.i2c_client = client; ov5645_data.pix.pixelformat = V4L2_PIX_FMT_UYVY; // ----- CHANGE ----- ov5645_data.pix.width = 1920; ov5645_data.pix.height = 1080; ov5645_data.streamcap.capability = V4L2_MODE_HIGHQUALITY | V4L2_CAP_TIMEPERFRAME; ov5645_data.streamcap.capturemode = 0; ov5645_data.streamcap.timeperframe.denominator = DEFAULT_FPS; ov5645_data.streamcap.timeperframe.numerator = 1; v4l2_i2c_subdev_init(&ov5645_data.subdev, client, &ov5645_subdev_ops); pr_info("----------im next to | v4l2_i2c_subdev_init |--------------YYY\n"); ov5645_data.subdev.grp_id = 678; retval = v4l2_async_register_subdev(&ov5645_data.subdev); pr_info("----------im next to | v4l2_async_register_subdev | %d -------YYY\n",retval); if (retval < 0) dev_err(&client->dev,"%s--Async register failed, ret=%d ODM \n", __func__, retval); //OV5645_stream_off(); pr_info("camera ov5645_mipi is found---YYY\n"); ov5645_data.initialized = true; return retval; } /*! * ov5645 I2C detach function * * @param client struct i2c_client * * @return Error code indicating success or failure */ static int ov5645_remove(struct i2c_client *client) { printk("inside ov5645_remove ODM \n"); struct v4l2_subdev *sd = i2c_get_clientdata(client); v4l2_async_unregister_subdev(sd); clk_disable_unprepare(ov5645_data.sensor_clk); //ov5645_power_down(1); if (gpo_regulator) regulator_disable(gpo_regulator); if (analog_regulator) regulator_disable(analog_regulator); if (core_regulator) regulator_disable(core_regulator); if (io_regulator) regulator_disable(io_regulator); return 0; } module_i2c_driver(ov5645_i2c_driver); MODULE_AUTHOR("Freescale Semiconductor, Inc."); MODULE_DESCRIPTION("OV5645 MIPI Camera Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION("1.0"); MODULE_ALIAS("CSI");