On 23 November 2008 17:42:16 GWater wrote: > And here comes the final version (note the slightly different name ;) ). > > Please test it - I hope to get this into origin/development soon - this > stuff is the base for new sensors, formats etc. > > GWater
Breaks nothing for me. Here's one more small patch to disable AGC for ov9650 sensor. With AGC enabled image became too noisy, as result compression ratio in videoconf apps are low. It's better to increase exposure value than use AGC. Regards Vasily
From 15eee946f0ede17b6a7be34d2643b5dfd6b42879 Mon Sep 17 00:00:00 2001
From: GWater <[EMAIL PROTECTED]>
Date: Sat, 22 Nov 2008 13:39:43 +0100
Subject: [PATCH] New sensor assignment system
Sensors are now assigned using the dev_microdia_assign_sensor() function.
Sensor initilization is seperated from that and probing has been removed
- new probing mechanism for 6270 and 67b0.
Brian Johnson's new "struct microdia_video_format" is introduced with all
the necessary changes to resolution checking and applying. It will allow
support for YUV422 in the future.
For sensors which support bayer and YUV422 output special functions can
be stored in the sensor_info struct under .set_bayer and .set_yuv422 .
(Example in MT9M111 sensor_info)
Signed-off-by: GWater <[EMAIL PROTECTED]>
Signed-off-by: Vasily Khoruzhick <[EMAIL PROTECTED]>
---
microdia-dev.c | 244 ++++++++++++++++++++++++++++++++++++++++++++-----------
microdia-v4l.c | 3 +
microdia.h | 58 ++++++++-----
micron.c | 221 +++++++-------------------------------------------
micron.h | 9 +--
omnivision.c | 218 +++++++++++---------------------------------------
omnivision.h | 3 +-
sn9c20x.c | 106 ++++++++++++------------
8 files changed, 367 insertions(+), 495 deletions(-)
diff --git a/microdia-dev.c b/microdia-dev.c
index f3cdf4d..c8cb7fc 100644
--- a/microdia-dev.c
+++ b/microdia-dev.c
@@ -33,63 +33,235 @@
#include "omnivision.h"
#include "micron.h"
-struct sensor_info sensors[] = {
+static struct sensor_info sensors[] = {
{
.id = OV9650_SENSOR,
.name = "OV9650",
.address = 0x30,
- .probe = ov_probe
+ .initialize = ov_initialize,
+ .hstart = 0,
+ .vstart = 7,
+ .set_hvflip = ov965x_set_hvflip,
+ .set_exposure = ov965x_set_exposure,
+ .set_auto_exposure = ov965x_set_autoexposure,
+ .flip_detect = ov965x_flip_detect,
},
{
.id = OV9655_SENSOR,
.name = "OV9655",
.address = 0x30,
- .probe = ov_probe
+ .initialize = ov_initialize,
+ .hstart = 0,
+ .vstart = 7,
},
{
.id = SOI968_SENSOR,
.name = "SOI968",
.address = 0x30,
- .probe = ov_probe
+ .initialize = ov_initialize,
+ .set_exposure = soi968_set_exposure,
+ .set_auto_exposure = ov965x_set_autoexposure,
+ .hstart = 60,
+ .vstart = 11,
},
{
.id = OV7660_SENSOR,
.name = "OV7660",
.address = 0x21,
- .probe = ov_probe
+ .initialize = ov_initialize,
+ .set_exposure = ov7660_set_exposure,
+ .set_auto_exposure = ov7660_set_autoexposure,
+ .hstart = 1,
+ .vstart = 1,
},
{
.id = OV7670_SENSOR,
.name = "OV7670",
.address = 0x21,
- .probe = ov_probe
- },
- {
- .id = MT9M111_SENSOR,
- .name = "MT9M111",
- .address = 0x5d,
- .probe = mt9m111_probe
+ .initialize = ov_initialize,
+ .flip_detect = ov7670_flip_detect,
+ .hstart = 0,
+ .vstart = 1,
},
{
.id = MT9V111_SENSOR,
.name = "MT9V111",
.address = 0x5c,
- .probe = mt9v111_probe
+ .initialize = mt9v111_initialize,
+ .set_hvflip = mt9v111_set_hvflip,
+ .set_exposure = mt9v111_set_exposure,
+ .set_auto_exposure = mt9v111_set_autoexposure,
+ .hstart = 2,
+ .vstart = 2,
+ },
+ {
+ .id = MT9M111_SENSOR,
+ .name = "MT9M111",
+ .address = 0x5d,
+ .initialize = mt9m111_initialize,
+ .set_yuv422 = mt9m111_set_yuv422,
+ .set_bayer = mt9m111_set_raw,
+ .hstart = 6,
+ .vstart = 2,
},
{
.id = MT9V011_SENSOR,
.name = "MT9V011",
.address = 0x5d,
- .probe = mt9v011_probe
+ .initialize = mt9v011_initialize,
+ .set_hvflip = mt9v011_set_hvflip,
+ .set_exposure = mt9v011_set_exposure,
+ .hstart = 2,
+ .vstart = 2,
},
{
.id = MT9M001_SENSOR,
.name = "MT9M001",
.address = 0x5d,
- .probe = mt9m001_probe
+ .initialize = mt9m001_initialize,
+ .hstart = 2,
+ .vstart = 2,
},
};
+static __u16 known_cams[][2] = {
+ {0x6240, MT9M001_SENSOR},
+ {0x6242, MT9M111_SENSOR},
+ {0x6248, OV9655_SENSOR},
+ {0x624e, SOI968_SENSOR},
+ {0x624f, OV9650_SENSOR},
+ {0x6253, OV9650_SENSOR},
+ {0x6260, OV7670_SENSOR},
+ {0x627b, OV7660_SENSOR},
+ {0x627f, OV9650_SENSOR},
+ {0x6288, OV9655_SENSOR},
+ {0x628e, SOI968_SENSOR},
+ {0x62a0, OV7670_SENSOR},
+ {0x62b3, OV9655_SENSOR},
+ {0x62bb, OV7660_SENSOR},
+};
+
+int dev_microdia_assign_sensor(struct usb_microdia *dev)
+{
+ int i, j, ret;
+ __u16 pid = le16_to_cpu(dev->udev->descriptor.idProduct);
+
+ for (i = 0; i < ARRAY_SIZE(known_cams); i++) {
+ if (pid == known_cams[i][0]) {
+ for (j = 0; j < ARRAY_SIZE(sensors); j++) {
+ if (known_cams[i][1] == sensors[j].id) {
+ dev->camera.sensor = &(sensors[j]);
+ return 0;
+ }
+ }
+ }
+ }
+
+ if ((pid == 0x6270) || (pid == 0x62b0)) {
+ ret = micron_probe(dev);
+ for (j = 0; j < ARRAY_SIZE(sensors); j++) {
+ if (ret == sensors[j].id) {
+ dev->camera.sensor = &(sensors[j]);
+ return 0;
+ }
+ }
+ }
+
+ UDIA_ERROR("Could not assign sensor: "
+ "Please report to [email protected] .\n");
+
+ return -EINVAL;
+}
+
+int dev_microdia_initialize_sensor(struct usb_microdia *dev)
+{
+ int ret = -ENODEV;
+ if (dev && dev->camera.sensor->initialize)
+ ret = dev->camera.sensor->initialize(dev);
+ return ret;
+}
+
+static struct microdia_video_format default_fmts[] = {
+ {
+ .pix_fmt = V4L2_PIX_FMT_SBGGR8,
+ .desc = "Bayer 8bit (BGGR)",
+ .depth = 8,
+ .modes = {
+ {160, 120, SN9C20X_1_4_SCALE,
+ {0, 0, 640, 480},
+ {0, 0, 160, 120} },
+ {320, 240, SN9C20X_1_2_SCALE,
+ {0, 0, 640, 480},
+ {0, 0, 320, 240} },
+ {640, 480, SN9C20X_NO_SCALE,
+ {0, 0, 640, 480},
+ {0, 0, 640, 480} },
+ },
+ .set_format = sn9c20x_set_raw
+ },
+ {
+ .pix_fmt = V4L2_PIX_FMT_JPEG,
+ .desc = "JPEG (YUV 4:2:2)",
+ .depth = 16,
+ .modes = {
+ {160, 120, SN9C20X_1_4_SCALE,
+ {0, 0, 640, 480},
+ {0, 0, 160, 120} },
+ {320, 240, SN9C20X_1_2_SCALE,
+ {0, 0, 640, 480},
+ {0, 0, 320, 240} },
+ {640, 480, SN9C20X_NO_SCALE,
+ {0, 0, 640, 480},
+ {0, 0, 640, 480} },
+ },
+ .set_format = sn9c20x_set_jpeg
+ },
+ {
+ .pix_fmt = V4L2_PIX_FMT_YUYV,
+ .desc = "YUV 4:2:2 (YUYV)",
+ .depth = 16,
+ .modes = {
+ {160, 120, SN9C20X_1_4_SCALE,
+ {0, 0, 1280, 480},
+ {0, 0, 320, 120} },
+ {320, 240, SN9C20X_1_2_SCALE,
+ {0, 0, 1280, 480},
+ {0, 0, 640, 240} },
+ {640, 480, SN9C20X_NO_SCALE,
+ {0, 0, 1280, 480},
+ {0, 0, 1280, 480} },
+ },
+ .set_format = NULL
+ },
+};
+
+int dev_microdia_assign_fmts(struct usb_microdia *dev)
+{
+ int i, j;
+
+ dev->camera.fmts = default_fmts;
+ dev->camera.nfmts = ARRAY_SIZE(default_fmts);
+
+ for (i = 0; i < ARRAY_SIZE(default_fmts); i++) {
+ if ((dev->camera.sensor->set_yuv422 != NULL) &&
+ (dev->camera.fmts[i].pix_fmt == V4L2_PIX_FMT_YUYV))
+ dev->camera.fmts[i].set_format =
+ dev->camera.sensor->set_yuv422;
+ if ((dev->camera.sensor->set_bayer != NULL) &&
+ (dev->camera.fmts[i].pix_fmt == V4L2_PIX_FMT_SBGGR8))
+ dev->camera.fmts[i].set_format =
+ dev->camera.sensor->set_bayer;
+ for (j = 0; j < N_MODES; j++) {
+ dev->camera.fmts[i].modes[j].hw_window[0] =
+ dev->camera.sensor->hstart;
+ dev->camera.fmts[i].modes[j].hw_window[1] =
+ dev->camera.sensor->vstart;
+ }
+ }
+
+ return 0;
+}
+
/**
* @brief Wrapper function for camera-setting functions
*
@@ -169,8 +341,8 @@ int dev_microdia_camera_set_gamma(struct usb_microdia *dev)
*/
int dev_microdia_camera_set_exposure(struct usb_microdia *dev)
{
- if (dev && dev->camera.set_exposure != NULL)
- return dev->camera.set_exposure(dev);
+ if (dev && dev->camera.sensor->set_exposure != NULL)
+ return dev->camera.sensor->set_exposure(dev);
return 0;
}
@@ -186,8 +358,8 @@ int dev_microdia_camera_set_exposure(struct usb_microdia *dev)
int dev_microdia_camera_set_hvflip(struct usb_microdia *dev)
{
int ret = -ENODEV;
- if (dev && dev->camera.set_hvflip)
- ret = dev->camera.set_hvflip(dev);
+ if (dev && dev->camera.sensor->set_hvflip)
+ ret = dev->camera.sensor->set_hvflip(dev);
return ret;
}
@@ -237,8 +409,8 @@ int dev_microdia_camera_set_rgb_gain(struct usb_microdia *dev)
int dev_microdia_camera_set_auto_exposure(struct usb_microdia *dev)
{
int ret = -ENODEV;
- if (dev && dev->camera.set_auto_exposure)
- ret = dev->camera.set_auto_exposure(dev);
+ if (dev && dev->camera.sensor->set_auto_exposure)
+ ret = dev->camera.sensor->set_auto_exposure(dev);
return ret;
}
@@ -254,39 +426,13 @@ int dev_microdia_camera_set_auto_exposure(struct usb_microdia *dev)
int dev_microdia_camera_set_auto_whitebalance(struct usb_microdia *dev)
{
int ret = -ENODEV;
- if (dev && dev->camera.set_auto_whitebalance)
- ret = dev->camera.set_auto_whitebalance(dev);
+ if (dev && dev->camera.sensor->set_auto_whitebalance)
+ ret = dev->camera.sensor->set_auto_whitebalance(dev);
return ret;
}
/**
- * @brief function to probe sensor attached to bridge
- *
- * @param dev pointer to device structure
- *
- * @returns 0 or negative error value
- *
- * This function will probe the bridge for the proper sensor
- */
-int dev_microdia_probe_sensor(struct usb_microdia *dev)
-{
- int i, ret;
- dev->camera.sensor_flags = SN9C20X_I2C_2WIRE;
-
- for (i = 0; i < ARRAY_SIZE(sensors); i++) {
- dev->camera.sensor_slave_address = sensors[i].address;
- ret = sensors[i].probe(dev);
- if (ret == sensors[i].id) {
- UDIA_INFO("Detected sensor: %s\n", sensors[i].name);
- return ret;
- }
- }
-
- return UNKNOWN_SENSOR;
-}
-
-/**
* @brief Wrapper function for device-specific initialization functions
*
* @param dev Pointer to device structure
diff --git a/microdia-v4l.c b/microdia-v4l.c
index 8ecb94e..b8d965a 100644
--- a/microdia-v4l.c
+++ b/microdia-v4l.c
@@ -965,6 +965,9 @@ int microdia_vidioc_try_fmt_cap(struct file *file, void *priv,
if (index >= dev->camera.nfmts)
return -EINVAL;
+ if (dev->camera.fmts[index].set_format == NULL)
+ return -EINVAL;
+
sn9c20x_get_closest_resolution(dev, &fmt->fmt.pix.width,
&fmt->fmt.pix.height);
diff --git a/microdia.h b/microdia.h
index 09f3e9f..86eb11f 100644
--- a/microdia.h
+++ b/microdia.h
@@ -317,58 +317,70 @@ enum microdia_sensors {
struct usb_microdia;
+#define N_MODES 3
+
+struct microdia_video_mode {
+ __u16 width;
+ __u16 height;
+ __u8 scale;
+ __u16 hw_window[4];
+ __u16 clr_window[4];
+};
+
struct microdia_video_format {
__u32 pix_fmt;
char desc[32];
__u8 depth;
+ struct microdia_video_mode modes[N_MODES];
int (*set_format) (struct usb_microdia *dev);
};
-struct microdia_video_resolution {
- __u16 width;
- __u16 height;
- __u8 scale;
- __u16 window[4];
-};
-
struct sensor_info {
__u8 id;
__u8 *name;
__u8 address;
- int (*probe) (struct usb_microdia *dev);
+
+ int vstart;
+ int hstart;
+
+/* sensor specific functions */
+ int (*initialize) (struct usb_microdia *dev);
+ int (*set_exposure) (struct usb_microdia *dev);
+ int (*set_auto_exposure) (struct usb_microdia *dev);
+ int (*set_auto_whitebalance) (struct usb_microdia *dev);
+ int (*flip_detect) (struct usb_microdia *dev);
+ int (*set_hvflip) (struct usb_microdia *dev);
+ int (*set_bayer) (struct usb_microdia *dev);
+ int (*set_yuv422) (struct usb_microdia *dev);
};
-extern struct sensor_info sensors[];
+static struct sensor_info sensors[];
struct microdia_camera {
- __u8 sensor_slave_address;
- __u8 sensor_flags;
- __u8 sensor;
-
/* supported resolutions */
__u8 nmodes;
- struct microdia_video_resolution *modes;
+ struct microdia_video_mode *modes;
+
/* supported video formats */
__u8 nfmts;
struct microdia_video_format *fmts;
+/* image sensor */
+ struct sensor_info *sensor;
+
+/* SCCB/I2C interface */
+ __u8 i2c_flags;
+
/* bridge functions */
- int (*initialize) (struct usb_microdia *dev);
int (*enable_video) (struct usb_microdia *dev, int enable);
/* image quality functions */
-
int (*set_contrast) (struct usb_microdia *dev);
int (*set_brightness) (struct usb_microdia *dev);
int (*set_gamma) (struct usb_microdia *dev);
- int (*set_exposure) (struct usb_microdia *dev);
- int (*flip_detect) (struct usb_microdia *dev);
- int (*set_hvflip) (struct usb_microdia *dev);
int (*set_sharpness) (struct usb_microdia *dev);
int (*set_rgb_gain) (struct usb_microdia *dev);
- int (*set_auto_exposure) (struct usb_microdia *dev);
- int (*set_auto_whitebalance) (struct usb_microdia *dev);
};
/**
@@ -424,7 +436,9 @@ void usb_microdia_delete(struct kref *);
int dev_microdia_initialize_device(struct usb_microdia *, __u32 flags);
-int dev_microdia_probe_sensor(struct usb_microdia *);
+int dev_microdia_assign_sensor(struct usb_microdia *dev);
+int dev_microdia_assign_fmts(struct usb_microdia *dev);
+int dev_microdia_initialize_sensor(struct usb_microdia *dev);
int dev_microdia_enable_video(struct usb_microdia *, int);
int dev_microdia_camera_settings(struct usb_microdia *);
int dev_microdia_camera_set_contrast(struct usb_microdia *);
diff --git a/micron.c b/micron.c
index cc70fec..664bbba 100644
--- a/micron.c
+++ b/micron.c
@@ -29,100 +29,6 @@
#include "sn9c20x.h"
#include "micron.h"
-
-struct microdia_video_format mt9x0xx_fmts[] = {
- {
- .pix_fmt = V4L2_PIX_FMT_SBGGR8,
- .desc = "Bayer 8bit (BGGR)",
- .depth = 8,
- .set_format = sn9c20x_set_raw
- },
- {
- .pix_fmt = V4L2_PIX_FMT_JPEG,
- .desc = "JPEG (YUV 4:2:2)",
- .depth = 16,
- .set_format = sn9c20x_set_jpeg
- }
-};
-
-struct microdia_video_format mt9m111_fmts[] = {
- {
- .pix_fmt = V4L2_PIX_FMT_SBGGR8,
- .desc = "Bayer 8bit (BGGR)",
- .depth = 8,
- .set_format = mt9m111_set_raw
- },
- {
- .pix_fmt = V4L2_PIX_FMT_YUYV,
- .desc = "YUV 4:2:2",
- .depth = 16,
- .set_format = mt9m111_set_yuv422
- },
- {
- .pix_fmt = V4L2_PIX_FMT_JPEG,
- .desc = "JPEG (YUV 4:2:2)",
- .depth = 16,
- .set_format = sn9c20x_set_jpeg
- }
-};
-
-struct microdia_video_format mt9v111_fmts[] = {
- {
- .pix_fmt = V4L2_PIX_FMT_SBGGR8,
- .desc = "Bayer 8bit (BGGR)",
- .depth = 8,
- .set_format = sn9c20x_set_raw
- },
- {
- .pix_fmt = V4L2_PIX_FMT_JPEG,
- .desc = "JPEG (YUV 4:2:2)",
- .depth = 16,
- .set_format = sn9c20x_set_jpeg
- }
-};
-
-struct microdia_video_resolution micron_resolutions[] = {
- {
- .width = 160,
- .height = 120,
- .scale = SN9C20X_1_4_SCALE,
- .window = {2, 2, 640, 480}
- },
- {
- .width = 320,
- .height = 240,
- .scale = SN9C20X_1_2_SCALE,
- .window = {2, 2, 640, 480}
- },
- {
- .width = 640,
- .height = 480,
- .scale = SN9C20X_NO_SCALE,
- .window = {2, 2, 640, 480}
- },
-};
-
-struct microdia_video_resolution mt9m111_resolutions[] = {
- {
- .width = 160,
- .height = 120,
- .scale = SN9C20X_1_4_SCALE,
- .window = {6, 2, 640, 480}
- },
- {
- .width = 320,
- .height = 240,
- .scale = SN9C20X_1_2_SCALE,
- .window = {6, 2, 640, 480}
- },
- {
- .width = 640,
- .height = 480,
- .scale = SN9C20X_NO_SCALE,
- .window = {6, 2, 640, 480}
- },
-};
-
static __u8 mt9v111_init[][3] = {
/* 0x0d: Color Correction Register 8 */
{0x0d, 0x00, 0x01},
@@ -481,35 +387,6 @@ int mt9v111_initialize(struct usb_microdia *dev)
return ret;
}
-int mt9v011_probe(struct usb_microdia *dev)
-{
- __u8 buf[2];
- int ret;
-
- ret = sn9c20x_read_i2c_data(dev, 2, 0xff, buf);
- if (ret == 0) {
- if (buf[0] != 0x82)
- return -EINVAL;
- if (buf[1] == 0x43) {
- mt9v011_initialize(dev);
- dev->camera.set_hvflip = mt9v011_set_hvflip;
- dev->camera.set_exposure = mt9v011_set_exposure;
- dev->camera.modes = micron_resolutions;
- dev->camera.nmodes = ARRAY_SIZE(micron_resolutions);
- dev->camera.fmts = mt9x0xx_fmts;
- dev->camera.nfmts = ARRAY_SIZE(mt9x0xx_fmts);
- return MT9V011_SENSOR;
- }
- }
-
- /** NOTE: DNT DigiMicro 1.3 (microscope camera):
- * This device uses sensor MT9V111, but slave 0x5d is also successfully
- * read. Registers 0x00, 0x36 and 0xff of slave 0x5d return chip version
- * 0x0000. */
-
- return -EINVAL;
-}
-
int mt9v111_select_address_space(struct usb_microdia *dev, __u8 address_space)
{
__u8 buf[2];
@@ -564,36 +441,46 @@ int mt9v111_select_address_space(struct usb_microdia *dev, __u8 address_space)
return 0;
}
-int mt9v111_probe(struct usb_microdia *dev)
+int micron_probe(struct usb_microdia *dev)
{
- __u8 buf[2];
+ __u16 buf, old;
int ret;
+ static struct sensor_info dummy;
+ dev->camera.sensor = &dummy;
+
+ dev->camera.sensor->address = 0x5d;
+
+ ret = sn9c20x_read_i2c_data16(dev, 2, 0xff, &buf);
+
+ if ((ret == 0) || (buf == 0x8243))
+ return MT9V011_SENSOR;
+
+ /** NOTE: DNT DigiMicro 1.3 (microscope camera):
+ * This device uses sensor MT9V111, but slave 0x5d is also successfully
+ * read. Registers 0x00, 0x36 and 0xff of slave 0x5d return chip version
+ * 0x0000. */
+
+ /* MT9V111 has a different address */
+ dev->camera.sensor->address = 0x5c;
+
+ /* Store old address-space */
+ ret = sn9c20x_read_i2c_data16(dev, 2, 0x01, &old);
+ if (ret != 0)
+ return ret;
+
/* Select address-space: sensor */
- buf[0] = 0x00; buf[1] = MT9V111_ADDRESSSPACE_SENSOR;
- ret = sn9c20x_write_i2c_data(dev, 2, 0x01, buf);
+ buf = MT9V111_ADDRESSSPACE_SENSOR & 0x00ff;
+ ret = sn9c20x_write_i2c_data16(dev, 2, 0x01, &buf);
if (ret != 0)
return ret;
- ret = sn9c20x_read_i2c_data(dev, 2, 0xff, buf);
- if (ret == 0) {
- if (buf[0] != 0x82)
- return -EINVAL;
- if (buf[1] == 0x3a) {
- mt9v111_initialize(dev);
- dev->camera.set_hvflip = mt9v111_set_hvflip;
- dev->camera.set_exposure = mt9v111_set_exposure;
- dev->camera.set_auto_exposure = mt9v111_set_autoexposure;
- dev->camera.modes = micron_resolutions;
- dev->camera.nmodes = ARRAY_SIZE(micron_resolutions);
- dev->camera.fmts = mt9v111_fmts;
- dev->camera.nfmts = ARRAY_SIZE(mt9v111_fmts);
- return MT9V111_SENSOR;
- }
+ ret = sn9c20x_read_i2c_data16(dev, 2, 0xff, &buf);
+ if ((ret == 0) || (buf == 0x823a)) {
+ sn9c20x_write_i2c_data16(dev, 2, 0x01, &old);
+ return MT9V111_SENSOR;
}
- /** FIXME: always switch back to last register address space */
-
return -EINVAL;
}
@@ -626,27 +513,6 @@ int mt9m001_initialize(struct usb_microdia *dev)
return ret;
}
-int mt9m001_probe(struct usb_microdia *dev)
-{
- int ret;
- __u8 buf[2];
- ret = sn9c20x_read_i2c_data(dev, 2, 0x00, buf);
- if (ret == 0) {
- if (buf[0] != 0x84)
- return -EINVAL;
- if (buf[1] == 0x31) {
- mt9m001_initialize(dev);
- dev->camera.modes = micron_resolutions;
- dev->camera.nmodes = ARRAY_SIZE(micron_resolutions);
- dev->camera.fmts = mt9x0xx_fmts;
- dev->camera.nfmts = ARRAY_SIZE(mt9x0xx_fmts);
- return MT9M001_SENSOR;
- }
- }
-
- return -EINVAL;
-}
-
/**
* @brief Initialize mt9m111 sensors
*
@@ -680,31 +546,6 @@ int mt9m111_initialize(struct usb_microdia *dev)
return ret;
}
-int mt9m111_probe(struct usb_microdia *dev)
-{
- int ret;
- __u8 buf[2] = {0x00, 0x00};
-
- /* Select address-space: Sensor */
- sn9c20x_write_i2c_data(dev, 2, 0xf0, buf);
-
- ret = sn9c20x_read_i2c_data(dev, 2, 0x00, buf);
- if (ret == 0) {
- if (buf[0] != 0x14)
- return -EINVAL;
- if (buf[1] == 0x3a) {
- mt9m111_initialize(dev);
- dev->camera.modes = mt9m111_resolutions;
- dev->camera.nmodes = ARRAY_SIZE(mt9m111_resolutions);
- dev->camera.fmts = mt9m111_fmts;
- dev->camera.nfmts = ARRAY_SIZE(mt9m111_fmts);
- return MT9M111_SENSOR;
- }
- }
-
- return -EINVAL;
-}
-
int mt9m111_set_raw(struct usb_microdia *dev)
{
__u16 buf;
diff --git a/micron.h b/micron.h
index 4e2ee99..ea3cac6 100644
--- a/micron.h
+++ b/micron.h
@@ -98,7 +98,6 @@
#define MT9V111_IFP_AWB_WINBOUNDARY_BOTTOM(x) (((x/32) & 0xf) << 12) /* bottom boundary of AWB meas. window */
int mt9v111_select_address_space(struct usb_microdia *dev, __u8 address_space);
-int mt9v111_probe(struct usb_microdia *dev);
int mt9v111_initialize(struct usb_microdia *dev);
int mt9v111_setup_autoexposure(struct usb_microdia *dev);
int mt9v111_setup_autowhitebalance(struct usb_microdia *dev);
@@ -107,18 +106,16 @@ int mt9v111_set_hvflip(struct usb_microdia *dev);
int mt9v111_set_autoexposure(struct usb_microdia *dev);
int mt9v111_set_autowhitebalance(struct usb_microdia *dev);
int mt9v111_set_autocorrections(struct usb_microdia *dev, int enable);
-int mt9v111_set_yuv422(struct usb_microdia *dev);
-int mt9v111_set_raw(struct usb_microdia *dev);
int mt9v011_set_exposure(struct usb_microdia *dev);
int mt9v011_set_hvflip(struct usb_microdia *dev);
int mt9v011_initialize(struct usb_microdia *dev);
-int mt9v011_probe(struct usb_microdia *dev);
-int mt9m111_probe(struct usb_microdia *dev);
int mt9m111_set_raw(struct usb_microdia *dev);
int mt9m111_set_yuv422(struct usb_microdia *dev);
+int mt9m111_initialize(struct usb_microdia *dev);
-int mt9m001_probe(struct usb_microdia *dev);
+int mt9m001_initialize(struct usb_microdia *dev);
+int micron_probe(struct usb_microdia *dev);
#endif
diff --git a/omnivision.c b/omnivision.c
index 36eb280..2553df7 100644
--- a/omnivision.c
+++ b/omnivision.c
@@ -499,195 +499,69 @@ static __u8 ov9655_init[][2] = {
{0x00, 0x03}, {0x00, 0x0a}, {0x00, 0x10}, {0x00, 0x13},
};
-struct microdia_video_format ov_fmts[] = {
- {
- .pix_fmt = V4L2_PIX_FMT_SBGGR8,
- .desc = "Bayer 8bit (BGGR)",
- .depth = 8,
- .set_format = sn9c20x_set_raw
- },
- {
- .pix_fmt = V4L2_PIX_FMT_JPEG,
- .desc = "JPEG (YUV 4:2:2)",
- .depth = 16,
- .set_format = sn9c20x_set_jpeg
- }
-};
-
-struct microdia_video_resolution ov965x_resolutions[] = {
- {
- .width = 160,
- .height = 120,
- .scale = SN9C20X_1_4_SCALE,
- .window = {0, 17, 640, 480}
- },
- {
- .width = 320,
- .height = 240,
- .scale = SN9C20X_1_2_SCALE,
- .window = {0, 7, 640, 480}
- },
- {
- .width = 640,
- .height = 480,
- .scale = SN9C20X_NO_SCALE,
- .window = {0, 7, 640, 480}
- },
-};
-
-struct microdia_video_resolution soi968_resolutions[] = {
- {
- .width = 160,
- .height = 120,
- .scale = SN9C20X_1_4_SCALE,
- .window = {60, 17, 640, 480}
- },
- {
- .width = 320,
- .height = 240,
- .scale = SN9C20X_1_2_SCALE,
- .window = {60, 11, 640, 480}
- },
- {
- .width = 640,
- .height = 480,
- .scale = SN9C20X_NO_SCALE,
- .window = {60, 11, 640, 480}
- },
-};
-
-struct microdia_video_resolution ov7670_resolutions[] = {
- {
- .width = 160,
- .height = 120,
- .scale = SN9C20X_1_4_SCALE,
- .window = {0, 1, 640, 480}
- },
- {
- .width = 320,
- .height = 240,
- .scale = SN9C20X_1_2_SCALE,
- .window = {0, 1, 640, 480}
- },
- {
- .width = 640,
- .height = 480,
- .scale = SN9C20X_NO_SCALE,
- .window = {0, 1, 640, 480}
- },
-};
-
-struct microdia_video_resolution ov7660_resolutions[] = {
- {
- .width = 160,
- .height = 120,
- .scale = SN9C20X_1_4_SCALE,
- .window = {1, 1, 640, 480}
- },
- {
- .width = 320,
- .height = 240,
- .scale = SN9C20X_1_2_SCALE,
- .window = {1, 1, 640, 480}
- },
- {
- .width = 640,
- .height = 480,
- .scale = SN9C20X_NO_SCALE,
- .window = {1, 1, 640, 480}
- },
-};
-
-int ov_probe(struct usb_microdia *dev)
-{
- int ret;
- __u8 buf[2];
- ret = sn9c20x_read_i2c_data(dev, 2, 0x0a, buf);
- if (ret == 0) {
- if (buf[0] != 0x76 && buf[0] != 0x96)
- return -EINVAL;
- if (buf[1] == 0x60) {
- ov_initialize(dev, ov7660_init, ARRAY_SIZE(ov7660_init));
- dev->camera.set_exposure = ov7660_set_exposure;
- dev->camera.set_auto_exposure = ov7660_set_autoexposure;
- dev->camera.modes = ov7660_resolutions;
- dev->camera.nmodes = ARRAY_SIZE(ov7660_resolutions);
- dev->camera.fmts = ov_fmts;
- dev->camera.nfmts = ARRAY_SIZE(ov_fmts);
- return OV7660_SENSOR;
- }
- if (buf[1] == 0x70) {
- ov_initialize(dev, ov7670_init, ARRAY_SIZE(ov7670_init));
- dev->camera.flip_detect = ov7670_flip_detect;
- dev->camera.modes = ov7670_resolutions;
- dev->camera.nmodes = ARRAY_SIZE(ov7670_resolutions);
- dev->camera.fmts = ov_fmts;
- dev->camera.nfmts = ARRAY_SIZE(ov_fmts);
- return OV7670_SENSOR;
- }
- if (buf[1] == 0x52) {
- ov_initialize(dev, ov9650_init, ARRAY_SIZE(ov9650_init));
- dev->camera.set_hvflip = ov965x_set_hvflip;
- dev->camera.set_exposure = ov965x_set_exposure;
- dev->camera.set_auto_exposure = ov965x_set_autoexposure;
- dev->camera.flip_detect = ov965x_flip_detect;
- dev->camera.modes = ov965x_resolutions;
- dev->camera.nmodes = ARRAY_SIZE(ov965x_resolutions);
- dev->camera.fmts = ov_fmts;
- dev->camera.nfmts = ARRAY_SIZE(ov_fmts);
- return OV9650_SENSOR;
- }
- if (buf[1] == 0x56 || buf[1] == 0x57) {
- ov_initialize(dev, ov9655_init, ARRAY_SIZE(ov9655_init));
- dev->camera.modes = ov7670_resolutions;
- dev->camera.nmodes = ARRAY_SIZE(ov7670_resolutions);
- dev->camera.fmts = ov_fmts;
- dev->camera.nfmts = ARRAY_SIZE(ov_fmts);
- return OV9655_SENSOR;
- }
- if (buf[1] == 0x28) {
- ov_initialize(dev, soi968_init, ARRAY_SIZE(soi968_init));
- dev->camera.set_exposure = soi968_set_exposure;
- dev->camera.set_auto_exposure = ov965x_set_autoexposure;
- dev->camera.modes = soi968_resolutions;
- dev->camera.nmodes = ARRAY_SIZE(soi968_resolutions);
- dev->camera.fmts = ov_fmts;
- dev->camera.nfmts = ARRAY_SIZE(ov_fmts);
- return SOI968_SENSOR;
- }
- }
-
- return -EINVAL;
-}
-
/**
* @brief Initialize ov sensors
*
* @param dev Pointer to device structure
- * @param ov_init Data array for initialization
- * @param array_size size of ov_init
*
* @return 0 or negative error code
*
*/
-int ov_initialize(struct usb_microdia *dev, __u8 ov_init[][2], int array_size)
+int ov_initialize(struct usb_microdia *dev)
{
int i;
int ret = 0;
- __u8 value, reg;
- for (i = 0; i < array_size; i++) {
- reg = ov_init[i][0];
- value = ov_init[i][1];
- ret = sn9c20x_write_i2c_data(dev, 1, reg, &value);
- if (ret < 0) {
- UDIA_INFO("Sensor Init Error (%d). line %d\n", ret, i);
- break;
+ switch (dev->camera.sensor->id) {
+ case SOI968_SENSOR:
+ for (i = 0; i < ARRAY_SIZE(soi968_init); i++) {
+ ret = sn9c20x_write_i2c_data(dev, 1,
+ soi968_init[i][0], &soi968_init[i][1]);
+ if (ret < 0)
+ goto err;
+ }
+ break;
+ case OV9650_SENSOR:
+ for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) {
+ ret = sn9c20x_write_i2c_data(dev, 1,
+ ov9650_init[i][0], &ov9650_init[i][1]);
+ if (ret < 0)
+ goto err;
+ }
+ break;
+ case OV9655_SENSOR:
+ for (i = 0; i < ARRAY_SIZE(ov9655_init); i++) {
+ ret = sn9c20x_write_i2c_data(dev, 1,
+ ov9655_init[i][0], &ov9655_init[i][1]);
+ if (ret < 0)
+ goto err;
+ }
+ break;
+ case OV7670_SENSOR:
+ for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) {
+ ret = sn9c20x_write_i2c_data(dev, 1,
+ ov7670_init[i][0], &ov7670_init[i][1]);
+ if (ret < 0)
+ goto err;
}
+ break;
+ case OV7660_SENSOR:
+ for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) {
+ ret = sn9c20x_write_i2c_data(dev, 1,
+ ov7660_init[i][0], &ov7660_init[i][1]);
+ if (ret < 0)
+ goto err;
+ }
+ break;
+ default:
+ return -EINVAL;
}
return ret;
+err:
+ UDIA_ERROR("Sensor Init failed (%d)! - line %d\n", ret, i);
+ return ret;
}
/**
diff --git a/omnivision.h b/omnivision.h
index e08092a..1403a18 100644
--- a/omnivision.h
+++ b/omnivision.h
@@ -547,7 +547,6 @@ int ov965x_set_exposure(struct usb_microdia *);
int ov965x_set_autoexposure(struct usb_microdia *dev);
int ov965x_flip_detect(struct usb_microdia *dev);
-int ov_probe(struct usb_microdia *dev);
-int ov_initialize(struct usb_microdia *dev, __u8 ov_init[][2], int array_size);
+int ov_initialize(struct usb_microdia *dev);
#endif
diff --git a/sn9c20x.c b/sn9c20x.c
index a26ae01..df364d4 100644
--- a/sn9c20x.c
+++ b/sn9c20x.c
@@ -44,7 +44,7 @@
*/
int sn9c20x_initialize(struct usb_microdia *dev)
{
- int ret, i, sensor;
+ int ret, i;
__u16 reg;
__u8 value;
@@ -77,7 +77,7 @@ int sn9c20x_initialize(struct usb_microdia *dev)
{0x10f8, 0x14},
{0x10fa, 0xff},
{0x10f9, 0x00},
- {0x11ba, 0x0e},
+ {0x11ba, 0x0a},
{0x11a5, 0x2d},
{0x11a6, 0x2d},
{0x11a7, 0x3a},
@@ -99,15 +99,6 @@ int sn9c20x_initialize(struct usb_microdia *dev)
{0x11bf, 0x00},
};
- __u8 lens_gain[48] = {
- 0x10, 0x21, 0x34, 0x40, 0x47, 0x4f, 0x57, 0x5f,
- 0x64, 0x68, 0x6d, 0x73, 0x79, 0x80, 0x89, 0x97,
- 0x0d, 0x1c, 0x2a, 0x33, 0x38, 0x3d, 0x44, 0x4a,
- 0x4e, 0x52, 0x56, 0x5b, 0x61, 0x68, 0x6f, 0x7a,
- 0x0d, 0x1a, 0x2a, 0x31, 0x36, 0x3b, 0x41, 0x47,
- 0x4a, 0x4e, 0x53, 0x58, 0x5d, 0x64, 0x6b, 0x76
- };
-
__u8 qtable1[64] = {
0x0d, 0x08, 0x08, 0x0d, 0x08, 0x08, 0x0d, 0x0d,
0x0d, 0x0d, 0x11, 0x0d, 0x0d, 0x11, 0x15, 0x21,
@@ -148,10 +139,6 @@ int sn9c20x_initialize(struct usb_microdia *dev)
if (ret < 0)
goto err;
- ret = sn9c20x_i2c_initialize(dev);
- if (ret < 0)
- goto err;
-
dev->camera.enable_video = sn9c20x_enable_video;
dev->camera.set_contrast = sn9c20x_set_contrast;
@@ -160,21 +147,23 @@ int sn9c20x_initialize(struct usb_microdia *dev)
dev->camera.set_sharpness = sn9c20x_set_sharpness;
dev->camera.set_rgb_gain = sn9c20x_set_rgb_gain;
- sensor = dev_microdia_probe_sensor(dev);
- if (sensor == UNKNOWN_SENSOR) {
- UDIA_ERROR("Failed to detect sensor.\n");
- ret = -ENODEV;
+ ret = dev_microdia_assign_sensor(dev);
+ if (ret < 0)
goto err;
- }
- dev->camera.sensor = sensor;
- if (!(sensor == OV9650_SENSOR || sensor == OV9655_SENSOR))
- memset(lens_gain, 0x00, 48);
+ ret = sn9c20x_i2c_initialize(dev);
+ if (ret < 0)
+ goto err;
- ret = usb_microdia_control_write(dev, 0x11c0, lens_gain, 48);
+ ret = dev_microdia_initialize_sensor(dev);
if (ret < 0)
goto err;
+ /** FIXME: Assign sensor-specific reslutions and formats
+ * Brian developed a new system for that with his YUV422
+ * patch for OV sensors. */
+ dev_microdia_assign_fmts(dev);
+
return 0;
err:
@@ -231,7 +220,7 @@ int sn9c20x_set_LEDs(struct usb_microdia *dev, int enable)
int ret;
__u8 led[2];
- int sensor = dev->camera.sensor;
+ int sensor = dev->camera.sensor->id;
if (enable) {
switch (sensor) {
@@ -303,8 +292,10 @@ int sn9c20x_i2c_initialize(struct usb_microdia *dev)
__u8 buf[9];
int ret;
- buf[0] = dev->camera.sensor_flags;
- buf[1] = dev->camera.sensor_slave_address;
+ dev->camera.i2c_flags = SN9C20X_I2C_2WIRE;
+
+ buf[0] = dev->camera.i2c_flags;
+ buf[1] = dev->camera.sensor->address;
buf[2] = 0x00;
buf[3] = 0x00;
buf[4] = 0x00;
@@ -383,9 +374,9 @@ int sn9c20x_read_i2c_data(struct usb_microdia *dev, __u8 nbytes,
memset(row, 0, 5);
/* now we issue the same command but with the read bit set
* and no slave register address */
- dev->camera.sensor_flags |= SN9C20X_I2C_READ;
+ dev->camera.i2c_flags |= SN9C20X_I2C_READ;
ret = sn9c20x_write_i2c_data(dev, nbytes - 1, 0, row);
- dev->camera.sensor_flags &= ~SN9C20X_I2C_READ;
+ dev->camera.i2c_flags &= ~SN9C20X_I2C_READ;
if (ret < 0)
return ret;
@@ -455,8 +446,8 @@ int sn9c20x_write_i2c_data(struct usb_microdia *dev, __u8 nbytes,
/* from the point of view of the bridge, the length
* includes the address */
- row[0] = dev->camera.sensor_flags | ((nbytes + 1) << 4);
- row[1] = dev->camera.sensor_slave_address;
+ row[0] = dev->camera.i2c_flags | ((nbytes + 1) << 4);
+ row[1] = dev->camera.sensor->address;
row[2] = address;
row[7] = 0x10; /* I think this means we want an ack */
@@ -464,20 +455,20 @@ int sn9c20x_write_i2c_data(struct usb_microdia *dev, __u8 nbytes,
row[i + 3] = i < nbytes ? data[i] : 0;
UDIA_DEBUG("I2C %s %02x: %02x %02x %02x %02x %02x %02x %02x %02x\n",
- (dev->camera.sensor_flags & SN9C20X_I2C_READ ? wasread : waswrite), address,
- row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7]);
+ (dev->camera.i2c_flags & SN9C20X_I2C_READ ? wasread : waswrite),
+ address, row[0], row[1], row[2], row[3], row[4], row[5], row[6],
+ row[7]);
ret = usb_microdia_control_write(dev, 0x10c0, row, 8);
if (ret >= 0)
ret = sn9c20x_i2c_ack_wait(dev,
- dev->camera.sensor_flags & SN9C20X_I2C_400KHZ,
+ dev->camera.i2c_flags & SN9C20X_I2C_400KHZ,
&slave_error);
if (slave_error) {
UDIA_ERROR("I2C slave 0x%02x returned error during %s address 0x%02x\n",
- dev->camera.sensor_slave_address,
- (dev->camera.sensor_flags & SN9C20X_I2C_READ ? wasread : waswrite),
- address);
+ dev->camera.sensor->address, (dev->camera.i2c_flags &
+ SN9C20X_I2C_READ ? wasread : waswrite), address);
return -1000;
/* there should be no interference with USB errors */
}
@@ -485,9 +476,8 @@ int sn9c20x_write_i2c_data(struct usb_microdia *dev, __u8 nbytes,
if (ret < 0) {
/* we got no ack */
UDIA_ERROR("No ack from I2C slave 0x%02x for %s address 0x%02x\n",
- dev->camera.sensor_slave_address,
- (dev->camera.sensor_flags & SN9C20X_I2C_READ ? wasread : waswrite),
- address);
+ dev->camera.sensor->address, (dev->camera.i2c_flags &
+ SN9C20X_I2C_READ ? wasread : waswrite), address);
return ret;
}
@@ -678,15 +668,17 @@ int sn9c20x_get_closest_resolution(struct usb_microdia *dev,
int *width, int *height)
{
int i;
+ int fmt_index = dev->vsettings.format.priv;
+ struct microdia_video_mode *modes = dev->camera.fmts[fmt_index].modes;
- for (i = dev->camera.nmodes - 1; i >= 0; i--) {
- if (*width >= dev->camera.modes[i].width
- && *height >= dev->camera.modes[i].height)
+ for (i = N_MODES - 1; i >= 0; i--) {
+ if (*width >= modes[i].width
+ && *height >= modes[i].height)
break;
}
- *width = dev->camera.modes[i].width;
- *height = dev->camera.modes[i].height;
+ *width = modes[i].width;
+ *height = modes[i].height;
return i;
}
@@ -710,27 +702,33 @@ int sn9c20x_set_resolution(struct usb_microdia *dev,
__u8 scale;
__u8 window[6];
__u8 clrwindow[6];
- struct microdia_video_resolution *mode;
+ struct microdia_video_mode *mode;
+ int fmt_index = dev->vsettings.format.priv;
ret = sn9c20x_get_closest_resolution(dev, &width, &height);
- mode = &dev->camera.modes[ret];
+ mode = &dev->camera.fmts[fmt_index].modes[ret];
dev->vsettings.format.width = mode->width;
dev->vsettings.format.height = mode->height;
- clrwindow[0] = 0; clrwindow[1] = mode->width >> 2;
- clrwindow[2] = 0; clrwindow[3] = mode->height >> 1;
- clrwindow[4] = ((mode->width >> 10) & 0x01) |
- ((mode->height >> 10) & 0x06);
+ clrwindow[0] = mode->clr_window[0];
+ clrwindow[1] = mode->clr_window[2] >> 2;
+ clrwindow[2] = mode->clr_window[1];
+ clrwindow[3] = mode->clr_window[3] >> 1;
+ clrwindow[4] = ((mode->clr_window[2] >> 10) & 0x01) |
+ ((mode->clr_window[3] >> 10) & 0x06);
scale = mode->scale;
if (clrwindow[4] & 0x01)
scale += 0x40;
- window[0] = mode->window[0] & 0xff; window[1] = mode->window[0] >> 8;
- window[2] = mode->window[1] & 0xff; window[3] = mode->window[1] >> 8;
- window[4] = mode->window[2] >> 4; window[5] = mode->window[3] >> 3;
+ window[0] = mode->hw_window[0] & 0xff;
+ window[1] = mode->hw_window[0] >> 8;
+ window[2] = mode->hw_window[1] & 0xff;
+ window[3] = mode->hw_window[1] >> 8;
+ window[4] = mode->hw_window[2] >> 4;
+ window[5] = mode->hw_window[3] >> 3;
usb_microdia_control_write(dev, 0x10fb, clrwindow, 5);
usb_microdia_control_write(dev, 0x1180, window, 6);
--
1.6.0.3
From fc6c9ee39084758aea4ebe6fcf33cc1f9ead89a6 Mon Sep 17 00:00:00 2001
From: Vasily Khoruzhick <[EMAIL PROTECTED]>
Date: Sun, 23 Nov 2008 17:51:28 +0200
Subject: [PATCH] Disable AGC for ov9650 sensor
Signed-off-by: Vasily Khoruzhick <[EMAIL PROTECTED]>
---
omnivision.c | 4 +---
1 files changed, 1 insertions(+), 3 deletions(-)
diff --git a/omnivision.c b/omnivision.c
index 2553df7..e07fad9 100644
--- a/omnivision.c
+++ b/omnivision.c
@@ -313,11 +313,9 @@ static __u8 ov9650_init[][2] = {
{OV965X_CTL_COM7, OV965X_COM7_OUTPUT_VGA | OV965X_COM7_OUTPUT_RAW_RGB},
{OV965X_CTL_COM8, OV965X_COM8_FAST_AGC_AEC |
OV965X_COM8_AEC_STEP_SIZE_NOLIMIT |
- OV965X_COM8_AGC_ENABLE |
OV965X_COM8_AEC_ENABLE |
OV965X_COM8_AWB_ENABLE},
- {OV965X_CTL_COM9, OV965X_COM9_MAX_AGC_8X |
- OV965X_COM9_RELAX_EXPOSURE_TIMING |
+ {OV965X_CTL_COM9, OV965X_COM9_RELAX_EXPOSURE_TIMING |
OV965X_COM9_DROP_VSYNC_ON_FRAME_DROP |
OV965X_COM9_DROP_FRAME_ON_BIG_AEC},
{OV965X_CTL_COM10, 0x00},
--
1.6.0.3
signature.asc
Description: This is a digitally signed message part.
