summaryrefslogtreecommitdiff
path: root/drivers/media/video/wmt_v4l2/sensors/ov3660/ov3660.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/wmt_v4l2/sensors/ov3660/ov3660.c')
-rwxr-xr-xdrivers/media/video/wmt_v4l2/sensors/ov3660/ov3660.c209
1 files changed, 209 insertions, 0 deletions
diff --git a/drivers/media/video/wmt_v4l2/sensors/ov3660/ov3660.c b/drivers/media/video/wmt_v4l2/sensors/ov3660/ov3660.c
new file mode 100755
index 00000000..3b913277
--- /dev/null
+++ b/drivers/media/video/wmt_v4l2/sensors/ov3660/ov3660.c
@@ -0,0 +1,209 @@
+/*
+ * Driver for ov3660 CMOS Image Sensor from Omnivision
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <asm/errno.h>
+#include "../cmos-subdev.h"
+#include "../../wmt-vid.h"
+#include "ov3660.h"
+
+#define sensor_write_array(sd, arr, sz) \
+ cmos_init_16bit_addr(arr, sz, (sd)->i2c_addr)
+
+#define sensor_read(sd, reg) \
+ wmt_vid_i2c_read16addr(sd->i2c_addr, reg)
+
+#define sensor_write(sd, reg, val) \
+ wmt_vid_i2c_write16addr(sd->i2c_addr, reg, val)
+
+struct cmos_win_size {
+ char *name;
+ int width;
+ int height;
+ uint32_t *regs;
+ size_t size;
+};
+
+#define CMOS_WIN_SIZE(n, w, h, r) \
+ {.name = n, .width = w , .height = h, .regs = r, .size = ARRAY_SIZE(r) }
+
+
+static const struct cmos_win_size cmos_supported_win_sizes[] = {
+ CMOS_WIN_SIZE("VGA", 640, 480, ov3660_640_480_regs),
+ CMOS_WIN_SIZE("QXGA", 2048, 1536, ov3660_2048_1536_regs),
+};
+
+static const struct cmos_win_size *cmos_select_win(u32 *width, u32 *height)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cmos_supported_win_sizes); i++) {
+ if (cmos_supported_win_sizes[i].width == *width &&
+ cmos_supported_win_sizes[i].height == *height) {
+ *width = cmos_supported_win_sizes[i].width;
+ *height = cmos_supported_win_sizes[i].height;
+ return &cmos_supported_win_sizes[i];
+ }
+ }
+ return NULL;
+}
+
+static int sensor_s_wb(struct cmos_subdev *sd, enum v4l2_wb_mode value)
+{
+ uint32_t *regs;
+ size_t size;
+
+ switch (value) {
+ case WHITE_BALANCE_AUTO:
+ regs = ov3660_wb_auto;
+ size = ARRAY_SIZE(ov3660_wb_auto);
+ break;
+ case WHITE_BALANCE_INCANDESCENCE:
+ regs = ov3660_wb_incandescent;
+ size = ARRAY_SIZE(ov3660_wb_incandescent);
+ break;
+ case WHITE_BALANCE_DAYLIGHT:
+ regs = ov3660_wb_daylight;
+ size = ARRAY_SIZE(ov3660_wb_daylight);
+ break;
+ case WHITE_BALANCE_CLOUDY:
+ regs = ov3660_wb_cloudy;
+ size = ARRAY_SIZE(ov3660_wb_cloudy);
+ break;
+ case WHITE_BALANCE_FLUORESCENT:
+ regs = ov3660_wb_fluorescent;
+ size = ARRAY_SIZE(ov3660_wb_fluorescent);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ sensor_write_array(sd, regs, size);
+ return 0;
+}
+
+static int sensor_queryctrl(struct cmos_subdev *sd, struct v4l2_queryctrl *qc)
+{
+ switch (qc->id) {
+ case V4L2_CID_VFLIP:
+ case V4L2_CID_HFLIP:
+ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
+ case V4L2_CID_DO_WHITE_BALANCE:
+ return v4l2_ctrl_query_fill(qc, 0, 3, 1, 0);
+ }
+ return -EINVAL;
+}
+
+static int sensor_s_ctrl(struct cmos_subdev *sd, struct v4l2_control *ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_VFLIP:
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_DO_WHITE_BALANCE:
+ return sensor_s_wb(sd, ctrl->value);
+ }
+ return -EINVAL;
+}
+
+static int sensor_g_mbus_fmt(struct cmos_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ return -EINVAL;
+}
+
+static int sensor_s_mbus_fmt(struct cmos_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ const struct cmos_win_size *win;
+
+ win = cmos_select_win(&mf->width, &mf->height);
+ if (!win)
+ return -EINVAL;
+
+ sensor_write_array(sd, win->regs, win->size);
+ return 0;
+}
+
+static int sensor_try_mbus_fmt(struct cmos_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ const struct cmos_win_size *win;
+
+ /*
+ * select suitable win
+ */
+ win = cmos_select_win(&mf->width, &mf->height);
+
+ return 0;
+}
+
+static int sensor_identify(struct cmos_subdev *sd)
+{
+ uint32_t data;
+
+ data = sensor_read(sd, 0x300a);
+ data <<= 8;
+ data |= sensor_read(sd, 0x300b);
+
+ return (data == sd->id) ? 0 : 1;
+}
+
+static int sensor_init(struct cmos_subdev *sd)
+{
+ if (!sensor_identify(sd))
+ return -1;
+
+ sensor_write(sd, 0x3103, 0x11);
+ sensor_write(sd, 0x3008, 0x82);
+ msleep(5);
+ sensor_write_array(sd, ov3660_default_regs_init,
+ ARRAY_SIZE(ov3660_default_regs_init));
+ return 0;
+}
+
+static int sensor_exit(struct cmos_subdev *sd)
+{
+ sensor_write(sd, 0x3017, 0x80);
+ sensor_write(sd, 0x3018, 0x03);
+ return 0;
+}
+
+static struct cmos_subdev_ops ov3660_ops = {
+ .identify = sensor_identify,
+ .init = sensor_init,
+ .exit = sensor_exit,
+ .queryctrl = sensor_queryctrl,
+ .s_ctrl = sensor_s_ctrl,
+ .s_mbus_fmt = sensor_s_mbus_fmt,
+ .g_mbus_fmt = sensor_g_mbus_fmt,
+ .try_mbus_fmt = sensor_try_mbus_fmt,
+};
+
+struct cmos_subdev ov3660 = {
+ .name = "ov3660",
+ .i2c_addr = 0x3c,
+ .id = 0x3660,
+ .max_width = 2048,
+ .max_height = 1536,
+ .ops = &ov3660_ops,
+};
+
+static int __init ov3660_init(void)
+{
+ return cmos_register_sudbdev(&ov3660);
+}
+
+static void __exit ov3660_exit(void)
+{
+ cmos_unregister_subdev(&ov3660);
+ return;
+}
+
+module_init(ov3660_init);
+module_exit(ov3660_exit);
+
+MODULE_LICENSE("GPL");