summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/usb/gspca/ov534_9.c334
1 files changed, 333 insertions, 1 deletions
diff --git a/drivers/media/usb/gspca/ov534_9.c b/drivers/media/usb/gspca/ov534_9.c
index c4cd028fe0b..47085cf2d72 100644
--- a/drivers/media/usb/gspca/ov534_9.c
+++ b/drivers/media/usb/gspca/ov534_9.c
@@ -59,6 +59,7 @@ enum sensors {
SENSOR_OV965x, /* ov9657 */
SENSOR_OV971x, /* ov9712 */
SENSOR_OV562x, /* ov5621 */
+ SENSOR_OV361x, /* ov3610 */
NSENSORS
};
@@ -106,6 +107,274 @@ static const struct v4l2_pix_format ov562x_mode[] = {
}
};
+enum ov361x {
+ ov361x_2048 = 0,
+ ov361x_1600,
+ ov361x_1024,
+ ov361x_640,
+ ov361x_320,
+ ov361x_160,
+ ov361x_last
+};
+
+static const struct v4l2_pix_format ov361x_mode[] = {
+ {0x800, 0x600, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 0x800,
+ .sizeimage = 0x800 * 0x600,
+ .colorspace = V4L2_COLORSPACE_SRGB},
+ {1600, 1200, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 1600,
+ .sizeimage = 1600 * 1200,
+ .colorspace = V4L2_COLORSPACE_SRGB},
+ {1024, 768, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 768,
+ .sizeimage = 1024 * 768,
+ .colorspace = V4L2_COLORSPACE_SRGB},
+ {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480,
+ .colorspace = V4L2_COLORSPACE_SRGB},
+ {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240,
+ .colorspace = V4L2_COLORSPACE_SRGB},
+ {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120,
+ .colorspace = V4L2_COLORSPACE_SRGB}
+};
+
+static const u8 ov361x_start_2048[][2] = {
+ {0x12, 0x80},
+ {0x13, 0xcf},
+ {0x14, 0x40},
+ {0x15, 0x00},
+ {0x01, 0x80},
+ {0x02, 0x80},
+ {0x04, 0x70},
+ {0x0d, 0x40},
+ {0x0f, 0x47},
+ {0x11, 0x81},
+ {0x32, 0x36},
+ {0x33, 0x0c},
+ {0x34, 0x00},
+ {0x35, 0x90},
+ {0x12, 0x00},
+ {0x17, 0x10},
+ {0x18, 0x90},
+ {0x19, 0x00},
+ {0x1a, 0xc0},
+};
+static const u8 ov361x_bridge_start_2048[][2] = {
+ {0xf1, 0x60},
+ {0x88, 0x00},
+ {0x89, 0x08},
+ {0x8a, 0x00},
+ {0x8b, 0x06},
+ {0x8c, 0x01},
+ {0x8d, 0x10},
+ {0x1c, 0x00},
+ {0x1d, 0x48},
+ {0x1d, 0x00},
+ {0x1d, 0xff},
+ {0x1c, 0x0a},
+ {0x1d, 0x2e},
+ {0x1d, 0x1e},
+};
+
+static const u8 ov361x_start_1600[][2] = {
+ {0x12, 0x80},
+ {0x13, 0xcf},
+ {0x14, 0x40},
+ {0x15, 0x00},
+ {0x01, 0x80},
+ {0x02, 0x80},
+ {0x04, 0x70},
+ {0x0d, 0x40},
+ {0x0f, 0x47},
+ {0x11, 0x81},
+ {0x32, 0x36},
+ {0x33, 0x0C},
+ {0x34, 0x00},
+ {0x35, 0x90},
+ {0x12, 0x00},
+ {0x17, 0x10},
+ {0x18, 0x90},
+ {0x19, 0x00},
+ {0x1a, 0xc0},
+};
+static const u8 ov361x_bridge_start_1600[][2] = {
+ {0xf1, 0x60}, /* Hsize[7:0] */
+ {0x88, 0x00}, /* Hsize[15:8] Write Only, can't read */
+ {0x89, 0x08}, /* Vsize[7:0] */
+ {0x8a, 0x00}, /* Vsize[15:8] Write Only, can't read */
+ {0x8b, 0x06}, /* for Iso */
+ {0x8c, 0x01}, /* RAW input */
+ {0x8d, 0x10},
+ {0x1c, 0x00}, /* RAW output, Iso transfer */
+ {0x1d, 0x48},
+ {0x1d, 0x00},
+ {0x1d, 0xff},
+ {0x1c, 0x0a}, /* turn off JPEG, Iso mode */
+ {0x1d, 0x2e}, /* for Iso */
+ {0x1d, 0x1e},
+};
+
+static const u8 ov361x_start_1024[][2] = {
+ {0x12, 0x80},
+ {0x13, 0xcf},
+ {0x14, 0x40},
+ {0x15, 0x00},
+ {0x01, 0x80},
+ {0x02, 0x80},
+ {0x04, 0x70},
+ {0x0d, 0x40},
+ {0x0f, 0x47},
+ {0x11, 0x81},
+ {0x32, 0x36},
+ {0x33, 0x0C},
+ {0x34, 0x00},
+ {0x35, 0x90},
+ {0x12, 0x40},
+ {0x17, 0x1f},
+ {0x18, 0x5f},
+ {0x19, 0x00},
+ {0x1a, 0x68},
+};
+static const u8 ov361x_bridge_start_1024[][2] = {
+ {0xf1, 0x60}, /* Hsize[7:0] */
+ {0x88, 0x00}, /* Hsize[15:8] Write Only, can't read */
+ {0x89, 0x04}, /* Vsize[7:0] */
+ {0x8a, 0x00}, /* Vsize[15:8] Write Only, can't read */
+ {0x8b, 0x03}, /* for Iso */
+ {0x8c, 0x01}, /* RAW input */
+ {0x8d, 0x10},
+ {0x1c, 0x00}, /* RAW output, Iso transfer */
+ {0x1d, 0x48},
+ {0x1d, 0x00},
+ {0x1d, 0xff},
+ {0x1c, 0x0a}, /* turn off JPEG, Iso mode */
+ {0x1d, 0x2e}, /* for Iso */
+ {0x1d, 0x1e},
+};
+
+static const u8 ov361x_start_640[][2] = {
+ {0x12, 0x80},
+ {0x13, 0xcf},
+ {0x14, 0x40},
+ {0x15, 0x00},
+ {0x01, 0x80},
+ {0x02, 0x80},
+ {0x04, 0x70},
+ {0x0d, 0x40},
+ {0x0f, 0x47},
+ {0x11, 0x81},
+ {0x32, 0x36},
+ {0x33, 0x0C},
+ {0x34, 0x00},
+ {0x35, 0x90},
+ {0x12, 0x40},
+ {0x17, 0x1f},
+ {0x18, 0x5f},
+ {0x19, 0x00},
+ {0x1a, 0x68},
+};
+
+static const u8 ov361x_bridge_start_640[][2] = {
+ {0xf1, 0x60}, /* Hsize[7:0]*/
+ {0x88, 0x00}, /* Hsize[15:8] Write Only, can't read */
+ {0x89, 0x04}, /* Vsize[7:0] */
+ {0x8a, 0x00}, /* Vsize[15:8] Write Only, can't read */
+ {0x8b, 0x03}, /* for Iso */
+ {0x8c, 0x01}, /* RAW input */
+ {0x8d, 0x10},
+ {0x1c, 0x00}, /* RAW output, Iso transfer */
+ {0x1d, 0x48},
+ {0x1d, 0x00},
+ {0x1d, 0xff},
+ {0x1c, 0x0a}, /* turn off JPEG, Iso mode */
+ {0x1d, 0x2e}, /* for Iso */
+ {0x1d, 0x1e},
+};
+
+static const u8 ov361x_start_320[][2] = {
+ {0x12, 0x80},
+ {0x13, 0xcf},
+ {0x14, 0x40},
+ {0x15, 0x00},
+ {0x01, 0x80},
+ {0x02, 0x80},
+ {0x04, 0x70},
+ {0x0d, 0x40},
+ {0x0f, 0x47},
+ {0x11, 0x81},
+ {0x32, 0x36},
+ {0x33, 0x0C},
+ {0x34, 0x00},
+ {0x35, 0x90},
+ {0x12, 0x40},
+ {0x17, 0x1f},
+ {0x18, 0x5f},
+ {0x19, 0x00},
+ {0x1a, 0x68},
+};
+
+static const u8 ov361x_bridge_start_320[][2] = {
+ {0xf1, 0x60}, /* Hsize[7:0] */
+ {0x88, 0x00}, /* Hsize[15:8] Write Only, can't read */
+ {0x89, 0x04}, /* Vsize[7:0] */
+ {0x8a, 0x00}, /* Vsize[15:8] Write Only, can't read */
+ {0x8b, 0x03}, /* for Iso */
+ {0x8c, 0x01}, /* RAW input */
+ {0x8d, 0x10},
+ {0x1c, 0x00}, /* RAW output, Iso transfer; */
+ {0x1d, 0x48},
+ {0x1d, 0x00},
+ {0x1d, 0xff},
+ {0x1c, 0x0a}, /* turn off JPEG, Iso mode */
+ {0x1d, 0x2e}, /* for Iso */
+ {0x1d, 0x1e},
+};
+
+static const u8 ov361x_start_160[][2] = {
+ {0x12, 0x80},
+ {0x13, 0xcf},
+ {0x14, 0x40},
+ {0x15, 0x00},
+ {0x01, 0x80},
+ {0x02, 0x80},
+ {0x04, 0x70},
+ {0x0d, 0x40},
+ {0x0f, 0x47},
+ {0x11, 0x81},
+ {0x32, 0x36},
+ {0x33, 0x0C},
+ {0x34, 0x00},
+ {0x35, 0x90},
+ {0x12, 0x40},
+ {0x17, 0x1f},
+ {0x18, 0x5f},
+ {0x19, 0x00},
+ {0x1a, 0x68},
+};
+
+static const u8 ov361x_bridge_start_160[][2] = {
+ {0xf1, 0x60}, /* Hsize[7:0] */
+ {0x88, 0x00}, /* Hsize[15:8] Write Only, can't read */
+ {0x89, 0x04}, /* Vsize[7:0] */
+ {0x8a, 0x00}, /* Vsize[15:8] Write Only, can't read */
+ {0x8b, 0x03}, /* for Iso */
+ {0x8c, 0x01}, /* RAW input */
+ {0x8d, 0x10},
+ {0x1c, 0x00}, /* RAW output, Iso transfer */
+ {0x1d, 0x48},
+ {0x1d, 0x00},
+ {0x1d, 0xff},
+ {0x1c, 0x0a}, /* turn off JPEG, Iso mode */
+ {0x1d, 0x2e}, /* for Iso */
+ {0x1d, 0x1e},
+};
+
static const u8 bridge_init[][2] = {
{0x88, 0xf8},
{0x89, 0xff},
@@ -898,7 +1167,7 @@ static int sccb_check_status(struct gspca_dev *gspca_dev)
int i;
for (i = 0; i < 5; i++) {
- msleep(10);
+ msleep(20);
data = reg_r(gspca_dev, OV534_REG_STATUS);
switch (data) {
@@ -1221,6 +1490,13 @@ static int sd_init(struct gspca_dev *gspca_dev)
sccb_w_array(gspca_dev, ov562x_init_2,
ARRAY_SIZE(ov562x_init_2));
reg_w(gspca_dev, 0xe0, 0x00);
+ } else if ((sensor_id & 0xfff0) == 0x3610) {
+ sd->sensor = SENSOR_OV361x;
+ gspca_dev->cam.cam_mode = ov361x_mode;
+ gspca_dev->cam.nmodes = ARRAY_SIZE(ov361x_mode);
+ reg_w(gspca_dev, 0xe7, 0x3a);
+ reg_w(gspca_dev, 0xf1, 0x60);
+ sccb_write(gspca_dev, 0x12, 0x80);
} else {
pr_err("Unknown sensor %04x", sensor_id);
return -EINVAL;
@@ -1229,6 +1505,53 @@ static int sd_init(struct gspca_dev *gspca_dev)
return gspca_dev->usb_err;
}
+static int sd_start_ov361x(struct gspca_dev *gspca_dev)
+{
+ sccb_write(gspca_dev, 0x12, 0x80);
+ msleep(20);
+ switch (gspca_dev->curr_mode % (ov361x_last)) {
+ case ov361x_2048:
+ reg_w_array(gspca_dev, ov361x_bridge_start_2048,
+ ARRAY_SIZE(ov361x_bridge_start_2048));
+ sccb_w_array(gspca_dev, ov361x_start_2048,
+ ARRAY_SIZE(ov361x_start_2048));
+ break;
+ case ov361x_1600:
+ reg_w_array(gspca_dev, ov361x_bridge_start_1600,
+ ARRAY_SIZE(ov361x_bridge_start_1600));
+ sccb_w_array(gspca_dev, ov361x_start_1600,
+ ARRAY_SIZE(ov361x_start_1600));
+ break;
+ case ov361x_1024:
+ reg_w_array(gspca_dev, ov361x_bridge_start_1024,
+ ARRAY_SIZE(ov361x_bridge_start_1024));
+ sccb_w_array(gspca_dev, ov361x_start_1024,
+ ARRAY_SIZE(ov361x_start_1024));
+ break;
+ case ov361x_640:
+ reg_w_array(gspca_dev, ov361x_bridge_start_640,
+ ARRAY_SIZE(ov361x_bridge_start_640));
+ sccb_w_array(gspca_dev, ov361x_start_640,
+ ARRAY_SIZE(ov361x_start_640));
+ break;
+ case ov361x_320:
+ reg_w_array(gspca_dev, ov361x_bridge_start_320,
+ ARRAY_SIZE(ov361x_bridge_start_320));
+ sccb_w_array(gspca_dev, ov361x_start_320,
+ ARRAY_SIZE(ov361x_start_320));
+ break;
+ case ov361x_160:
+ reg_w_array(gspca_dev, ov361x_bridge_start_160,
+ ARRAY_SIZE(ov361x_bridge_start_160));
+ sccb_w_array(gspca_dev, ov361x_start_160,
+ ARRAY_SIZE(ov361x_start_160));
+ break;
+ }
+ reg_w(gspca_dev, 0xe0, 0x00); /* start transfer */
+
+ return gspca_dev->usb_err;
+}
+
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -1237,6 +1560,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
return gspca_dev->usb_err;
if (sd->sensor == SENSOR_OV562x)
return gspca_dev->usb_err;
+ if (sd->sensor == SENSOR_OV361x)
+ return sd_start_ov361x(gspca_dev);
switch (gspca_dev->curr_mode) {
case QVGA_MODE: /* 320x240 */
@@ -1290,6 +1615,11 @@ static int sd_start(struct gspca_dev *gspca_dev)
static void sd_stopN(struct gspca_dev *gspca_dev)
{
+ if (((struct sd *)gspca_dev)->sensor == SENSOR_OV361x) {
+ reg_w(gspca_dev, 0xe0, 0x01); /* stop transfer */
+ /* reg_w(gspca_dev, 0x31, 0x09); */
+ return;
+ }
reg_w(gspca_dev, 0xe0, 0x01);
set_led(gspca_dev, 0);
reg_w(gspca_dev, 0xe0, 0x00);
@@ -1425,6 +1755,8 @@ static int sd_init_controls(struct gspca_dev *gspca_dev)
if (sd->sensor == SENSOR_OV971x)
return 0;
+ if (sd->sensor == SENSOR_OV361x)
+ return 0;
gspca_dev->vdev.ctrl_handler = hdl;
v4l2_ctrl_handler_init(hdl, 7);
if (sd->sensor == SENSOR_OV562x) {