Commit 15807765 authored by Vladik Aranov's avatar Vladik Aranov Committed by Mauro Carvalho Chehab

[media] gscpa_ov534_9: Add support for ov3610 sensor

Dear Hans de Goede, I have Ubuntu (raring) and recently bought digital
microscope eyepiece Lomo MD300. It is the same device as Future Optics MVV3000.
Unfortunately it does not work out of box. Moreover drivers refused to work
under Windows 7 as well leaving me only with Win Xp working system. I have had
no choice but to examine what happened in USB bus and attempt to reproduce the
sequence. So, i have download the source(3.8.0-30 kernel) and made required
changes to driver to make my hardware work.
I submit my changed files to you as maintainer of the driver so you can
integrade my changes into main stream. Thanx. Hopefully my Ubuntu will work
with my hardware out of box.
Sincerely yours Vladik Aranov
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarMauro Carvalho Chehab <m.chehab@samsung.com>
parent de0fc463
...@@ -59,6 +59,7 @@ enum sensors { ...@@ -59,6 +59,7 @@ enum sensors {
SENSOR_OV965x, /* ov9657 */ SENSOR_OV965x, /* ov9657 */
SENSOR_OV971x, /* ov9712 */ SENSOR_OV971x, /* ov9712 */
SENSOR_OV562x, /* ov5621 */ SENSOR_OV562x, /* ov5621 */
SENSOR_OV361x, /* ov3610 */
NSENSORS NSENSORS
}; };
...@@ -106,6 +107,274 @@ static const struct v4l2_pix_format ov562x_mode[] = { ...@@ -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] = { static const u8 bridge_init[][2] = {
{0x88, 0xf8}, {0x88, 0xf8},
{0x89, 0xff}, {0x89, 0xff},
...@@ -898,7 +1167,7 @@ static int sccb_check_status(struct gspca_dev *gspca_dev) ...@@ -898,7 +1167,7 @@ static int sccb_check_status(struct gspca_dev *gspca_dev)
int i; int i;
for (i = 0; i < 5; i++) { for (i = 0; i < 5; i++) {
msleep(10); msleep(20);
data = reg_r(gspca_dev, OV534_REG_STATUS); data = reg_r(gspca_dev, OV534_REG_STATUS);
switch (data) { switch (data) {
...@@ -1221,6 +1490,13 @@ static int sd_init(struct gspca_dev *gspca_dev) ...@@ -1221,6 +1490,13 @@ static int sd_init(struct gspca_dev *gspca_dev)
sccb_w_array(gspca_dev, ov562x_init_2, sccb_w_array(gspca_dev, ov562x_init_2,
ARRAY_SIZE(ov562x_init_2)); ARRAY_SIZE(ov562x_init_2));
reg_w(gspca_dev, 0xe0, 0x00); 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 { } else {
pr_err("Unknown sensor %04x", sensor_id); pr_err("Unknown sensor %04x", sensor_id);
return -EINVAL; return -EINVAL;
...@@ -1229,6 +1505,53 @@ static int sd_init(struct gspca_dev *gspca_dev) ...@@ -1229,6 +1505,53 @@ static int sd_init(struct gspca_dev *gspca_dev)
return gspca_dev->usb_err; 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) static int sd_start(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
...@@ -1237,6 +1560,8 @@ static int sd_start(struct gspca_dev *gspca_dev) ...@@ -1237,6 +1560,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
return gspca_dev->usb_err; return gspca_dev->usb_err;
if (sd->sensor == SENSOR_OV562x) if (sd->sensor == SENSOR_OV562x)
return gspca_dev->usb_err; return gspca_dev->usb_err;
if (sd->sensor == SENSOR_OV361x)
return sd_start_ov361x(gspca_dev);
switch (gspca_dev->curr_mode) { switch (gspca_dev->curr_mode) {
case QVGA_MODE: /* 320x240 */ case QVGA_MODE: /* 320x240 */
...@@ -1290,6 +1615,11 @@ static int sd_start(struct gspca_dev *gspca_dev) ...@@ -1290,6 +1615,11 @@ static int sd_start(struct gspca_dev *gspca_dev)
static void sd_stopN(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); reg_w(gspca_dev, 0xe0, 0x01);
set_led(gspca_dev, 0); set_led(gspca_dev, 0);
reg_w(gspca_dev, 0xe0, 0x00); reg_w(gspca_dev, 0xe0, 0x00);
...@@ -1425,6 +1755,8 @@ static int sd_init_controls(struct gspca_dev *gspca_dev) ...@@ -1425,6 +1755,8 @@ static int sd_init_controls(struct gspca_dev *gspca_dev)
if (sd->sensor == SENSOR_OV971x) if (sd->sensor == SENSOR_OV971x)
return 0; return 0;
if (sd->sensor == SENSOR_OV361x)
return 0;
gspca_dev->vdev.ctrl_handler = hdl; gspca_dev->vdev.ctrl_handler = hdl;
v4l2_ctrl_handler_init(hdl, 7); v4l2_ctrl_handler_init(hdl, 7);
if (sd->sensor == SENSOR_OV562x) { if (sd->sensor == SENSOR_OV562x) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment