summaryrefslogtreecommitdiff
path: root/drivers/media/video/gspca/m5602
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/gspca/m5602')
-rw-r--r--drivers/media/video/gspca/m5602/Makefile3
-rw-r--r--drivers/media/video/gspca/m5602/m5602_bridge.h8
-rw-r--r--drivers/media/video/gspca/m5602/m5602_core.c43
-rw-r--r--drivers/media/video/gspca/m5602/m5602_mt9m111.c77
-rw-r--r--drivers/media/video/gspca/m5602/m5602_mt9m111.h61
-rw-r--r--drivers/media/video/gspca/m5602/m5602_ov9650.c570
-rw-r--r--drivers/media/video/gspca/m5602/m5602_ov9650.h239
-rw-r--r--drivers/media/video/gspca/m5602/m5602_po1030.c114
-rw-r--r--drivers/media/video/gspca/m5602/m5602_po1030.h98
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k4aa.c173
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k4aa.h134
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k83a.c154
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k83a.h94
-rw-r--r--drivers/media/video/gspca/m5602/m5602_sensor.h17
14 files changed, 980 insertions, 805 deletions
diff --git a/drivers/media/video/gspca/m5602/Makefile b/drivers/media/video/gspca/m5602/Makefile
index 226ab4fc9d60..9fa3644f4869 100644
--- a/drivers/media/video/gspca/m5602/Makefile
+++ b/drivers/media/video/gspca/m5602/Makefile
@@ -7,5 +7,4 @@ gspca_m5602-objs := m5602_core.o \
m5602_s5k83a.o \
m5602_s5k4aa.o
-EXTRA_CFLAGS += -Idrivers/media/video/gspca
-
+EXTRA_CFLAGS += -Idrivers/media/video/gspca \ No newline at end of file
diff --git a/drivers/media/video/gspca/m5602/m5602_bridge.h b/drivers/media/video/gspca/m5602/m5602_bridge.h
index a3f3b7a0c7e7..8f1cea6fd3bf 100644
--- a/drivers/media/video/gspca/m5602/m5602_bridge.h
+++ b/drivers/media/video/gspca/m5602/m5602_bridge.h
@@ -112,14 +112,14 @@ static const unsigned char sensor_urb_skeleton[] = {
struct sd {
struct gspca_dev gspca_dev;
- /* The name of the m5602 camera */
- char *name;
-
/* A pointer to the currently connected sensor */
- struct m5602_sensor *sensor;
+ const struct m5602_sensor *sensor;
struct sd_desc *desc;
+ /* Sensor private data */
+ void *sensor_priv;
+
/* The current frame's id, used to detect frame boundaries */
u8 frame_id;
diff --git a/drivers/media/video/gspca/m5602/m5602_core.c b/drivers/media/video/gspca/m5602/m5602_core.c
index ed906fe31287..1aac2985fee6 100644
--- a/drivers/media/video/gspca/m5602/m5602_core.c
+++ b/drivers/media/video/gspca/m5602/m5602_core.c
@@ -51,7 +51,7 @@ int m5602_read_bridge(struct sd *sd, u8 address, u8 *i2c_data)
address, *i2c_data);
/* usb_control_msg(...) returns the number of bytes sent upon success,
- mask that and return zero upon success instead*/
+ mask that and return zero instead*/
return (err < 0) ? err : 0;
}
@@ -76,7 +76,7 @@ int m5602_write_bridge(struct sd *sd, u8 address, u8 i2c_data)
4, M5602_URB_MSG_TIMEOUT);
/* usb_control_msg(...) returns the number of bytes sent upon success,
- mask that and return zero upon success instead */
+ mask that and return zero instead */
return (err < 0) ? err : 0;
}
@@ -92,29 +92,29 @@ int m5602_read_sensor(struct sd *sd, const u8 address,
err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
} while ((*i2c_data & I2C_BUSY) && !err);
if (err < 0)
- goto out;
+ return err;
err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
sd->sensor->i2c_slave_id);
if (err < 0)
- goto out;
+ return err;
err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
if (err < 0)
- goto out;
+ return err;
if (sd->sensor->i2c_regW == 1) {
err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, len);
if (err < 0)
- goto out;
+ return err;
err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x08);
if (err < 0)
- goto out;
+ return err;
} else {
err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x18 + len);
if (err < 0)
- goto out;
+ return err;
}
for (i = 0; (i < len) && !err; i++) {
@@ -123,7 +123,6 @@ int m5602_read_sensor(struct sd *sd, const u8 address,
PDEBUG(D_CONF, "Reading sensor register "
"0x%x containing 0x%x ", address, *i2c_data);
}
-out:
return err;
}
@@ -310,7 +309,11 @@ static void m5602_urb_complete(struct gspca_dev *gspca_dev,
static void m5602_stop_transfer(struct gspca_dev *gspca_dev)
{
- /* Is there are a command to stop a data transfer? */
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ /* Run the sensor specific end transfer sequence */
+ if (sd->sensor->stop)
+ sd->sensor->stop(sd);
}
/* sub-driver description, the ctrl and nctrl is filled at probe time */
@@ -332,7 +335,6 @@ static int m5602_configure(struct gspca_dev *gspca_dev,
int err;
cam = &gspca_dev->cam;
- cam->epaddr = M5602_ISOC_ENDPOINT_ADDR;
sd->desc = &sd_desc;
if (dump_bridge)
@@ -360,6 +362,17 @@ static int m5602_probe(struct usb_interface *intf,
THIS_MODULE);
}
+void m5602_disconnect(struct usb_interface *intf)
+{
+ struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->sensor->disconnect)
+ sd->sensor->disconnect(sd);
+
+ gspca_disconnect(intf);
+}
+
static struct usb_driver sd_driver = {
.name = MODULE_NAME,
.id_table = m5602_table,
@@ -368,14 +381,16 @@ static struct usb_driver sd_driver = {
.suspend = gspca_suspend,
.resume = gspca_resume,
#endif
- .disconnect = gspca_disconnect
+ .disconnect = m5602_disconnect
};
/* -- module insert / remove -- */
static int __init mod_m5602_init(void)
{
- if (usb_register(&sd_driver) < 0)
- return -1;
+ int ret;
+ ret = usb_register(&sd_driver);
+ if (ret < 0)
+ return ret;
PDEBUG(D_PROBE, "registered");
return 0;
}
diff --git a/drivers/media/video/gspca/m5602/m5602_mt9m111.c b/drivers/media/video/gspca/m5602/m5602_mt9m111.c
index c0e71c331454..7d3f9e348ef4 100644
--- a/drivers/media/video/gspca/m5602/m5602_mt9m111.c
+++ b/drivers/media/video/gspca/m5602/m5602_mt9m111.c
@@ -18,6 +18,61 @@
#include "m5602_mt9m111.h"
+static struct v4l2_pix_format mt9m111_modes[] = {
+ {
+ 640,
+ 480,
+ V4L2_PIX_FMT_SBGGR8,
+ V4L2_FIELD_NONE,
+ .sizeimage = 640 * 480,
+ .bytesperline = 640,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0
+ }
+};
+
+const static struct ctrl mt9m111_ctrls[] = {
+ {
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "vertical flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0
+ },
+ .set = mt9m111_set_vflip,
+ .get = mt9m111_get_vflip
+ }, {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "horizontal flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0
+ },
+ .set = mt9m111_set_hflip,
+ .get = mt9m111_get_hflip
+ }, {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "gain",
+ .minimum = 0,
+ .maximum = (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2,
+ .step = 1,
+ .default_value = DEFAULT_GAIN,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = mt9m111_set_gain,
+ .get = mt9m111_get_gain
+ }
+};
+
+
static void mt9m111_dump_registers(struct sd *sd);
int mt9m111_probe(struct sd *sd)
@@ -62,10 +117,10 @@ int mt9m111_probe(struct sd *sd)
return -ENODEV;
sensor_found:
- sd->gspca_dev.cam.cam_mode = mt9m111.modes;
- sd->gspca_dev.cam.nmodes = mt9m111.nmodes;
- sd->desc->ctrls = mt9m111.ctrls;
- sd->desc->nctrls = mt9m111.nctrls;
+ sd->gspca_dev.cam.cam_mode = mt9m111_modes;
+ sd->gspca_dev.cam.nmodes = ARRAY_SIZE(mt9m111_modes);
+ sd->desc->ctrls = mt9m111_ctrls;
+ sd->desc->nctrls = ARRAY_SIZE(mt9m111_ctrls);
return 0;
}
@@ -125,16 +180,15 @@ int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
/* Set the correct page map */
err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
if (err < 0)
- goto out;
+ return err;
err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
if (err < 0)
- goto out;
+ return err;
data[0] = (data[0] & 0xfe) | val;
err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
data, 2);
-out:
return err;
}
@@ -163,16 +217,15 @@ int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
/* Set the correct page map */
err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
if (err < 0)
- goto out;
+ return err;
err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
if (err < 0)
- goto out;
+ return err;
data[0] = (data[0] & 0xfd) | ((val << 1) & 0x02);
err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
data, 2);
-out:
return err;
}
@@ -204,7 +257,7 @@ int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
/* Set the correct page map */
err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
if (err < 0)
- goto out;
+ return err;
if (val >= INITIAL_MAX_GAIN * 2 * 2 * 2)
return -EINVAL;
@@ -229,7 +282,7 @@ int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
err = m5602_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN,
data, 2);
-out:
+
return err;
}
diff --git a/drivers/media/video/gspca/m5602/m5602_mt9m111.h b/drivers/media/video/gspca/m5602/m5602_mt9m111.h
index e795ab7a36c9..00c6db02bdb7 100644
--- a/drivers/media/video/gspca/m5602/m5602_mt9m111.h
+++ b/drivers/media/video/gspca/m5602/m5602_mt9m111.h
@@ -94,7 +94,7 @@ int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-static struct m5602_sensor mt9m111 = {
+const static struct m5602_sensor mt9m111 = {
.name = "MT9M111",
.i2c_slave_id = 0xba,
@@ -102,64 +102,7 @@ static struct m5602_sensor mt9m111 = {
.probe = mt9m111_probe,
.init = mt9m111_init,
- .power_down = mt9m111_power_down,
-
- .nctrls = 3,
- .ctrls = {
- {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = mt9m111_set_vflip,
- .get = mt9m111_get_vflip
- }, {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = mt9m111_set_hflip,
- .get = mt9m111_get_hflip
- }, {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "gain",
- .minimum = 0,
- .maximum = (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2,
- .step = 1,
- .default_value = DEFAULT_GAIN,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = mt9m111_set_gain,
- .get = mt9m111_get_gain
- }
- },
-
- .nmodes = 1,
- .modes = {
- {
- M5602_DEFAULT_FRAME_WIDTH,
- M5602_DEFAULT_FRAME_HEIGHT,
- V4L2_PIX_FMT_SBGGR8,
- V4L2_FIELD_NONE,
- .sizeimage =
- M5602_DEFAULT_FRAME_WIDTH * M5602_DEFAULT_FRAME_HEIGHT,
- .bytesperline = M5602_DEFAULT_FRAME_WIDTH,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 1
- }
- }
+ .power_down = mt9m111_power_down
};
static const unsigned char preinit_mt9m111[][4] =
diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.c b/drivers/media/video/gspca/m5602/m5602_ov9650.c
index c908a8d6970a..fc4548fd441d 100644
--- a/drivers/media/video/gspca/m5602/m5602_ov9650.c
+++ b/drivers/media/video/gspca/m5602/m5602_ov9650.c
@@ -65,14 +65,177 @@ static
DMI_MATCH(DMI_PRODUCT_NAME, "Aurora m9700")
}
},
- { }
+ {}
+};
+
+const static struct ctrl ov9650_ctrls[] = {
+#define EXPOSURE_IDX 0
+ {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "exposure",
+ .minimum = 0x00,
+ .maximum = 0x1ff,
+ .step = 0x4,
+ .default_value = EXPOSURE_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = ov9650_set_exposure,
+ .get = ov9650_get_exposure
+ },
+#define GAIN_IDX 1
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "gain",
+ .minimum = 0x00,
+ .maximum = 0x3ff,
+ .step = 0x1,
+ .default_value = GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = ov9650_set_gain,
+ .get = ov9650_get_gain
+ },
+#define RED_BALANCE_IDX 2
+ {
+ {
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "red balance",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 0x1,
+ .default_value = RED_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = ov9650_set_red_balance,
+ .get = ov9650_get_red_balance
+ },
+#define BLUE_BALANCE_IDX 3
+ {
+ {
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "blue balance",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 0x1,
+ .default_value = BLUE_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = ov9650_set_blue_balance,
+ .get = ov9650_get_blue_balance
+ },
+#define HFLIP_IDX 4
+ {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "horizontal flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0
+ },
+ .set = ov9650_set_hflip,
+ .get = ov9650_get_hflip
+ },
+#define VFLIP_IDX 5
+ {
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "vertical flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0
+ },
+ .set = ov9650_set_vflip,
+ .get = ov9650_get_vflip
+ },
+#define AUTO_WHITE_BALANCE_IDX 6
+ {
+ {
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "auto white balance",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1
+ },
+ .set = ov9650_set_auto_white_balance,
+ .get = ov9650_get_auto_white_balance
+ },
+#define AUTO_GAIN_CTRL_IDX 7
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "auto gain control",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1
+ },
+ .set = ov9650_set_auto_gain,
+ .get = ov9650_get_auto_gain
+ }
+};
+
+static struct v4l2_pix_format ov9650_modes[] = {
+ {
+ 176,
+ 144,
+ V4L2_PIX_FMT_SBGGR8,
+ V4L2_FIELD_NONE,
+ .sizeimage =
+ 176 * 144,
+ .bytesperline = 176,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 9
+ }, {
+ 320,
+ 240,
+ V4L2_PIX_FMT_SBGGR8,
+ V4L2_FIELD_NONE,
+ .sizeimage =
+ 320 * 240,
+ .bytesperline = 320,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 8
+ }, {
+ 352,
+ 288,
+ V4L2_PIX_FMT_SBGGR8,
+ V4L2_FIELD_NONE,
+ .sizeimage =
+ 352 * 288,
+ .bytesperline = 352,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 9
+ }, {
+ 640,
+ 480,
+ V4L2_PIX_FMT_SBGGR8,
+ V4L2_FIELD_NONE,
+ .sizeimage =
+ 640 * 480,
+ .bytesperline = 640,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 9
+ }
};
static void ov9650_dump_registers(struct sd *sd);
int ov9650_probe(struct sd *sd)
{
+ int err = 0;
u8 prod_id = 0, ver_id = 0, i;
+ s32 *sensor_settings;
if (force_sensor) {
if (force_sensor == OV9650_SENSOR) {
@@ -86,16 +249,20 @@ int ov9650_probe(struct sd *sd)
info("Probing for an ov9650 sensor");
- /* Run the pre-init to actually probe the unit */
- for (i = 0; i < ARRAY_SIZE(preinit_ov9650); i++) {
+ /* Run the pre-init before probing the sensor */
+ for (i = 0; i < ARRAY_SIZE(preinit_ov9650) && !err; i++) {
u8 data = preinit_ov9650[i][2];
if (preinit_ov9650[i][0] == SENSOR)
- m5602_write_sensor(sd,
- preinit_ov9650[i][1], &data, 1);
+ err = m5602_write_sensor(sd,
+ preinit_ov9650[i][1], &data, 1);
else
- m5602_write_bridge(sd, preinit_ov9650[i][1], data);
+ err = m5602_write_bridge(sd,
+ preinit_ov9650[i][1], data);
}
+ if (err < 0)
+ return err;
+
if (m5602_read_sensor(sd, OV9650_PID, &prod_id, 1))
return -ENODEV;
@@ -106,14 +273,28 @@ int ov9650_probe(struct sd *sd)
info("Detected an ov9650 sensor");
goto sensor_found;
}
-
return -ENODEV;
sensor_found:
- sd->gspca_dev.cam.cam_mode = ov9650.modes;
- sd->gspca_dev.cam.nmodes = ov9650.nmodes;
- sd->desc->ctrls = ov9650.ctrls;
- sd->desc->nctrls = ov9650.nctrls;
+ sensor_settings = kmalloc(
+ ARRAY_SIZE(ov9650_ctrls) * sizeof(s32), GFP_KERNEL);
+ if (!sensor_settings)
+ return -ENOMEM;
+
+ sd->gspca_dev.cam.cam_mode = ov9650_modes;
+ sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov9650_modes);
+ sd->desc->ctrls = ov9650_ctrls;
+ sd->desc->nctrls = ARRAY_SIZE(ov9650_ctrls);
+
+ for (i = 0; i < ARRAY_SIZE(ov9650_ctrls); i++)
+ sensor_settings[i] = ov9650_ctrls[i].qctrl.default_value;
+ sd->sensor_priv = sensor_settings;
+
+ if (dmi_check_system(ov9650_flip_dmi_table) && !err) {
+ info("vflip quirk active");
+ sensor_settings[VFLIP_IDX] = 1;
+ }
+
return 0;
}
@@ -121,6 +302,7 @@ int ov9650_init(struct sd *sd)
{
int i, err = 0;
u8 data;
+ s32 *sensor_settings = sd->sensor_priv;
if (dump_sensor)
ov9650_dump_registers(sd);
@@ -134,70 +316,157 @@ int ov9650_init(struct sd *sd)
err = m5602_write_bridge(sd, init_ov9650[i][1], data);
}
- if (dmi_check_system(ov9650_flip_dmi_table) && !err) {
- info("vflip quirk active");
- data = 0x30;
- err = m5602_write_sensor(sd, OV9650_MVFP, &data, 1);
- }
+ err = ov9650_set_exposure(&sd->gspca_dev, sensor_settings[EXPOSURE_IDX]);
+ if (err < 0)
+ return err;
+
+ err = ov9650_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
+ if (err < 0)
+ return err;
+
+ err = ov9650_set_red_balance(&sd->gspca_dev, sensor_settings[RED_BALANCE_IDX]);
+ if (err < 0)
+ return err;
+
+ err = ov9650_set_blue_balance(&sd->gspca_dev, sensor_settings[BLUE_BALANCE_IDX]);
+ if (err < 0)
+ return err;
+
+ err = ov9650_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
+ if (err < 0)
+ return err;
+
+ err = ov9650_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
+ if (err < 0)
+ return err;
+
+ err = ov9650_set_auto_white_balance(&sd->gspca_dev, sensor_settings[AUTO_WHITE_BALANCE_IDX]);
+ if (err < 0)
+ return err;
+
+ err = ov9650_set_auto_gain(&sd->gspca_dev, sensor_settings[AUTO_GAIN_CTRL_IDX]);
return err;
}
int ov9650_start(struct sd *sd)
{
+ u8 data;
int i, err = 0;
struct cam *cam = &sd->gspca_dev.cam;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ int width = cam->cam_mode[sd->gspca_dev.curr_mode].width;
+ int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
+ int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
+ int hor_offs = OV9650_LEFT_OFFSET;
+
+ if (sensor_settings[VFLIP_IDX])
+ ver_offs--;
+ if (width <= 320)
+ hor_offs /= 2;
+
+ /* Synthesize the vsync/hsync setup */
for (i = 0; i < ARRAY_SIZE(res_init_ov9650) && !err; i++) {
- u8 data = res_init_ov9650[i][1];
- err = m5602_write_bridge(sd, res_init_ov9650[i][0], data);
+ if (res_init_ov9650[i][0] == BRIDGE)
+ err = m5602_write_bridge(sd, res_init_ov9650[i][1],
+ res_init_ov9650[i][2]);
+ else if (res_init_ov9650[i][0] == SENSOR) {
+ u8 data = res_init_ov9650[i][2];
+ err = m5602_write_sensor(sd,
+ res_init_ov9650[i][1], &data, 1);
+ }
}
if (err < 0)
return err;
- switch (cam->cam_mode[sd->gspca_dev.curr_mode].width)
- {
+ err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA,
+ ((ver_offs >> 8) & 0xff));
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (ver_offs & 0xff));
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff);
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff));
+ if (err < 0)
+ return err;
+
+ for (i = 0; i < 2 && !err; i++)
+ err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
+ (hor_offs >> 8) & 0xff);
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, hor_offs & 0xff);
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
+ ((width + hor_offs) >> 8) & 0xff);
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
+ ((width + hor_offs) & 0xff));
+ if (err < 0)
+ return err;
+
+ switch (width) {
case 640:
PDEBUG(D_V4L2, "Configuring camera for VGA mode");
- for (i = 0; i < ARRAY_SIZE(VGA_ov9650) && !err; i++) {
- u8 data = VGA_ov9650[i][2];
- if (VGA_ov9650[i][0] == SENSOR)
- err = m5602_write_sensor(sd,
- VGA_ov9650[i][1], &data, 1);
- else
- err = m5602_write_bridge(sd, VGA_ov9650[i][1], data);
- }
+ data = OV9650_VGA_SELECT | OV9650_RGB_SELECT |
+ OV9650_RAW_RGB_SELECT;
+ err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
break;
case 352:
PDEBUG(D_V4L2, "Configuring camera for CIF mode");
- for (i = 0; i < ARRAY_SIZE(CIF_ov9650) && !err; i++) {
- u8 data = CIF_ov9650[i][2];
- if (CIF_ov9650[i][0] == SENSOR)
- err = m5602_write_sensor(sd,
- CIF_ov9650[i][1], &data, 1);
- else
- err = m5602_write_bridge(sd, CIF_ov9650[i][1], data);
- }
+ data = OV9650_CIF_SELECT | OV9650_RGB_SELECT |
+ OV9650_RAW_RGB_SELECT;
+ err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
break;
case 320:
PDEBUG(D_V4L2, "Configuring camera for QVGA mode");
- for (i = 0; i < ARRAY_SIZE(QVGA_ov9650) && !err; i++) {
- u8 data = QVGA_ov9650[i][2];
- if (QVGA_ov9650[i][0] == SENSOR)
- err = m5602_write_sensor(sd,
- QVGA_ov9650[i][1], &data, 1);
- else
- err = m5602_write_bridge(sd, QVGA_ov9650[i][1], data);
- }
+ data = OV9650_QVGA_SELECT | OV9650_RGB_SELECT |
+ OV9650_RAW_RGB_SELECT;
+ err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
+ break;
+
+ case 176:
+ PDEBUG(D_V4L2, "Configuring camera for QCIF mode");
+
+ data = OV9650_QCIF_SELECT | OV9650_RGB_SELECT |
+ OV9650_RAW_RGB_SELECT;
+ err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
break;
}
return err;
}
+int ov9650_stop(struct sd *sd)
+{
+ u8 data = OV9650_SOFT_SLEEP | OV9650_OUTPUT_DRIVE_2X;
+ return m5602_write_sensor(sd, OV9650_COM2, &data, 1);
+}
+
int ov9650_power_down(struct sd *sd)
{
int i, err = 0;
@@ -214,76 +483,63 @@ int ov9650_power_down(struct sd *sd)
return err;
}
-int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+void ov9650_disconnect(struct sd *sd)
{
- struct sd *sd = (struct sd *) gspca_dev;
- u8 i2c_data;
- int err;
-
- err = m5602_read_sensor(sd, OV9650_COM1, &i2c_data, 1);
- if (err < 0)
- goto out;
- *val = i2c_data & 0x03;
+ ov9650_stop(sd);
+ ov9650_power_down(sd);
- err = m5602_read_sensor(sd, OV9650_AECH, &i2c_data, 1);
- if (err < 0)
- goto out;
- *val |= (i2c_data << 2);
+ sd->sensor = NULL;
+ kfree(sd->sensor_priv);
+}
- err = m5602_read_sensor(sd, OV9650_AECHM, &i2c_data, 1);
- if (err < 0)
- goto out;
- *val |= (i2c_data & 0x3f) << 10;
+int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+ *val = sensor_settings[EXPOSURE_IDX];
PDEBUG(D_V4L2, "Read exposure %d", *val);
-out:
- return err;
+ return 0;
}
int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
- PDEBUG(D_V4L2, "Set exposure to %d",
- val & 0xffff);
+ PDEBUG(D_V4L2, "Set exposure to %d", val);
+ sensor_settings[EXPOSURE_IDX] = val;
/* The 6 MSBs */
i2c_data = (val >> 10) & 0x3f;
err = m5602_write_sensor(sd, OV9650_AECHM,
&i2c_data, 1);
if (err < 0)
- goto out;
+ return err;
/* The 8 middle bits */
i2c_data = (val >> 2) & 0xff;
err = m5602_write_sensor(sd, OV9650_AECH,
&i2c_data, 1);
if (err < 0)
- goto out;
+ return err;
/* The 2 LSBs */
i2c_data = val & 0x03;
err = m5602_write_sensor(sd, OV9650_COM1, &i2c_data, 1);
-
-out:
return err;
}
int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
{
- int err;
- u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
- m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
- *val = (i2c_data & 0x03) << 8;
-
- err = m5602_read_sensor(sd, OV9650_GAIN, &i2c_data, 1);
- *val |= i2c_data;
+ *val = sensor_settings[GAIN_IDX];
PDEBUG(D_V4L2, "Read gain %d", *val);
- return err;
+ return 0;
}
int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
@@ -291,15 +547,25 @@ int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ PDEBUG(D_V4L2, "Setting gain to %d", val);
+
+ sensor_settings[GAIN_IDX] = val;
/* The 2 MSB */
/* Read the OV9650_VREF register first to avoid
corrupting the VREF high and low bits */
- m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
+ err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
+ if (err < 0)
+ return err;
+
/* Mask away all uninteresting bits */
i2c_data = ((val & 0x0300) >> 2) |
(i2c_data & 0x3F);
err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1);
+ if (err < 0)
+ return err;
/* The 8 LSBs */
i2c_data = val & 0xff;
@@ -309,16 +575,12 @@ int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
{
- int err;
- u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
- err = m5602_read_sensor(sd, OV9650_RED, &i2c_data, 1);
- *val = i2c_data;
-
+ *val = sensor_settings[RED_BALANCE_IDX];
PDEBUG(D_V4L2, "Read red gain %d", *val);
-
- return err;
+ return 0;
}
int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
@@ -326,28 +588,26 @@ int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
- PDEBUG(D_V4L2, "Set red gain to %d",
- val & 0xff);
+ PDEBUG(D_V4L2, "Set red gain to %d", val);
+
+ sensor_settings[RED_BALANCE_IDX] = val;
i2c_data = val & 0xff;
err = m5602_write_sensor(sd, OV9650_RED, &i2c_data, 1);
-
return err;
}
int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
{
- int err;
- u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
- err = m5602_read_sensor(sd, OV9650_BLUE, &i2c_data, 1);
- *val = i2c_data;
-
+ *val = sensor_settings[BLUE_BALANCE_IDX];
PDEBUG(D_V4L2, "Read blue gain %d", *val);
- return err;
+ return 0;
}
int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
@@ -355,30 +615,25 @@ int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ PDEBUG(D_V4L2, "Set blue gain to %d", val);
- PDEBUG(D_V4L2, "Set blue gain to %d",
- val & 0xff);
+ sensor_settings[BLUE_BALANCE_IDX] = val;
i2c_data = val & 0xff;
err = m5602_write_sensor(sd, OV9650_BLUE, &i2c_data, 1);
-
return err;
}
int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
{
- int err;
- u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
- err = m5602_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
- if (dmi_check_system(ov9650_flip_dmi_table))
- *val = ((i2c_data & OV9650_HFLIP) >> 5) ? 0 : 1;
- else
- *val = (i2c_data & OV9650_HFLIP) >> 5;
+ *val = sensor_settings[HFLIP_IDX];
PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
-
- return err;
+ return 0;
}
int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
@@ -386,38 +641,26 @@ int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
- err = m5602_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
- if (err < 0)
- goto out;
-
- if (dmi_check_system(ov9650_flip_dmi_table))
- i2c_data = ((i2c_data & 0xdf) |
- (((val ? 0 : 1) & 0x01) << 5));
- else
- i2c_data = ((i2c_data & 0xdf) |
- ((val & 0x01) << 5));
+ sensor_settings[HFLIP_IDX] = val;
+ i2c_data = ((val & 0x01) << 5) | (sensor_settings[VFLIP_IDX] << 4);
err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
-out:
+
return err;
}
int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
{
- int err;
- u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
- err = m5602_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
- if (dmi_check_system(ov9650_flip_dmi_table))
- *val = ((i2c_data & 0x10) >> 4) ? 0 : 1;
- else
- *val = (i2c_data & 0x10) >> 4;
+ *val = sensor_settings[VFLIP_IDX];
PDEBUG(D_V4L2, "Read vertical flip %d", *val);
- return err;
+ return 0;
}
int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
@@ -425,40 +668,32 @@ int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
PDEBUG(D_V4L2, "Set vertical flip to %d", val);
- err = m5602_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
+ sensor_settings[VFLIP_IDX] = val;
+
+ i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5);
+ err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
if (err < 0)
- goto out;
+ return err;
- if (dmi_check_system(ov9650_flip_dmi_table))
- i2c_data = ((i2c_data & 0xef) |
- (((val ? 0 : 1) & 0x01) << 4));
- else
- i2c_data = ((i2c_data & 0xef) |
- ((val & 0x01) << 4));
+ /* When vflip is toggled we need to readjust the bridge hsync/vsync */
+ if (gspca_dev->streaming)
+ err = ov9650_start(sd);
- err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
-out:
return err;
}
int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
{
- int err;
- u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
- err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
- if (err < 0)
- goto out;
- *val = (i2c_data & 0x03) << 8;
-
- err = m5602_read_sensor(sd, OV9650_GAIN, &i2c_data, 1);
- *val |= i2c_data;
+ *val = sensor_settings[GAIN_IDX];
PDEBUG(D_V4L2, "Read gain %d", *val);
-out:
- return err;
+
+ return 0;
}
int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
@@ -466,40 +701,38 @@ int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
- PDEBUG(D_V4L2, "Set gain to %d", val & 0x3ff);
+ PDEBUG(D_V4L2, "Set gain to %d", val);
+
+ sensor_settings[GAIN_IDX] = val;
/* Read the OV9650_VREF register first to avoid
corrupting the VREF high and low bits */
err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
if (err < 0)
- goto out;
+ return err;
/* Mask away all uninteresting bits */
i2c_data = ((val & 0x0300) >> 2) | (i2c_data & 0x3F);
err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1);
if (err < 0)
- goto out;
+ return err;
/* The 8 LSBs */
i2c_data = val & 0xff;
err = m5602_write_sensor(sd, OV9650_GAIN, &i2c_data, 1);
-out:
return err;
}
int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val)
{
- int err;
- u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
- err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
- *val = (i2c_data & OV9650_AWB_EN) >> 1;
- PDEBUG(D_V4L2, "Read auto white balance %d", *val);
-
- return err;
+ *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
+ return 0;
}
int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val)
@@ -507,29 +740,29 @@ int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val)
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
PDEBUG(D_V4L2, "Set auto white balance to %d", val);
+
+ sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
if (err < 0)
- goto out;
+ return err;
i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1));
err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
-out:
+
return err;
}
int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
{
- int err;
- u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
- err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
- *val = (i2c_data & OV9650_AGC_EN) >> 2;
+ *val = sensor_settings[AUTO_GAIN_CTRL_IDX];
PDEBUG(D_V4L2, "Read auto gain control %d", *val);
-
- return err;
+ return 0;
}
int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
@@ -537,15 +770,18 @@ int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
PDEBUG(D_V4L2, "Set auto gain control to %d", val);
+
+ sensor_settings[AUTO_GAIN_CTRL_IDX] = val;
err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
if (err < 0)
- goto out;
+ return err;
i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2));
err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
-out:
+
return err;
}
diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.h b/drivers/media/video/gspca/m5602/m5602_ov9650.h
index f4b33b8e8dae..fcc54e4c0f4f 100644
--- a/drivers/media/video/gspca/m5602/m5602_ov9650.h
+++ b/drivers/media/video/gspca/m5602/m5602_ov9650.h
@@ -32,6 +32,7 @@
#define OV9650_BAVE 0x05
#define OV9650_GEAVE 0x06
#define OV9650_RSVD7 0x07
+#define OV9650_COM2 0x09
#define OV9650_PID 0x0a
#define OV9650_VER 0x0b
#define OV9650_COM3 0x0c
@@ -96,6 +97,7 @@
#define OV9650_VGA_SELECT (1 << 6)
#define OV9650_CIF_SELECT (1 << 5)
#define OV9650_QVGA_SELECT (1 << 4)
+#define OV9650_QCIF_SELECT (1 << 3)
#define OV9650_RGB_SELECT (1 << 2)
#define OV9650_RAW_RGB_SELECT (1 << 0)
@@ -115,10 +117,15 @@
#define OV9650_VFLIP (1 << 4)
#define OV9650_HFLIP (1 << 5)
+#define OV9650_SOFT_SLEEP (1 << 4)
+#define OV9650_OUTPUT_DRIVE_2X (1 << 0)
+
+#define OV9650_LEFT_OFFSET 0x62
+
#define GAIN_DEFAULT 0x14
#define RED_GAIN_DEFAULT 0x70
#define BLUE_GAIN_DEFAULT 0x20
-#define EXPOSURE_DEFAULT 0x5003
+#define EXPOSURE_DEFAULT 0x1ff
/*****************************************************************************/
@@ -129,7 +136,9 @@ extern int dump_sensor;
int ov9650_probe(struct sd *sd);
int ov9650_init(struct sd *sd);
int ov9650_start(struct sd *sd);
+int ov9650_stop(struct sd *sd);
int ov9650_power_down(struct sd *sd);
+void ov9650_disconnect(struct sd *sd);
int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
@@ -150,152 +159,16 @@ int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val);
int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
-static struct m5602_sensor ov9650 = {
+const static struct m5602_sensor ov9650 = {
.name = "OV9650",
.i2c_slave_id = 0x60,
.i2c_regW = 1,
.probe = ov9650_probe,
.init = ov9650_init,
.start = ov9650_start,
+ .stop = ov9650_stop,
.power_down = ov9650_power_down,
-
- .nctrls = 8,
- .ctrls = {
- {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x00,
- .maximum = 0xffff,
- .step = 0x1,
- .default_value = EXPOSURE_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = ov9650_set_exposure,
- .get = ov9650_get_exposure
- }, {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "gain",
- .minimum = 0x00,
- .maximum = 0x3ff,
- .step = 0x1,
- .default_value = GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = ov9650_set_gain,
- .get = ov9650_get_gain
- }, {
- {
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = RED_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = ov9650_set_red_balance,
- .get = ov9650_get_red_balance
- }, {
- {
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = BLUE_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = ov9650_set_blue_balance,
- .get = ov9650_get_blue_balance
- }, {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = ov9650_set_hflip,
- .get = ov9650_get_hflip
- }, {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = ov9650_set_vflip,
- .get = ov9650_get_vflip
- }, {
- {
- .id = V4L2_CID_AUTO_WHITE_BALANCE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto white balance",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = ov9650_set_auto_white_balance,
- .get = ov9650_get_auto_white_balance
- }, {
- {
- .id = V4L2_CID_AUTOGAIN,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto gain control",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = ov9650_set_auto_gain,
- .get = ov9650_get_auto_gain
- }
- },
-
- .nmodes = 3,
- .modes = {
- {
- 320,
- 240,
- V4L2_PIX_FMT_SBGGR8,
- V4L2_FIELD_NONE,
- .sizeimage =
- 320 * 240,
- .bytesperline = 320,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 0
- }, {
- 352,
- 288,
- V4L2_PIX_FMT_SBGGR8,
- V4L2_FIELD_NONE,
- .sizeimage =
- 352 * 288,
- .bytesperline = 352,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 0
- }, {
- 640,
- 480,
- V4L2_PIX_FMT_SBGGR8,
- V4L2_FIELD_NONE,
- .sizeimage =
- 640 * 480,
- .bytesperline = 640,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 0
- }
- }
+ .disconnect = ov9650_disconnect,
};
static const unsigned char preinit_ov9650[][3] =
@@ -345,6 +218,10 @@ static const unsigned char init_ov9650[][3] =
/* Reset chip */
{SENSOR, OV9650_COM7, OV9650_REGISTER_RESET},
+ /* One extra reset is needed in order to make the sensor behave
+ properly when resuming from ram */
+ {SENSOR, OV9650_COM7, OV9650_REGISTER_RESET},
+
/* Enable double clock */
{SENSOR, OV9650_CLKRC, 0x80},
/* Do something out of spec with the power */
@@ -427,18 +304,12 @@ static const unsigned char init_ov9650[][3] =
/* Enable denoise, and white-pixel erase */
{SENSOR, OV9650_COM22, 0x23},
- /* Set the high bits of the exposure value */
- {SENSOR, OV9650_AECH, ((EXPOSURE_DEFAULT & 0xff00) >> 8)},
-
/* Enable VARIOPIXEL */
{SENSOR, OV9650_COM3, OV9650_VARIOPIXEL},
{SENSOR, OV9650_COM4, OV9650_QVGA_VARIOPIXEL},
- /* Set the low bits of the exposure value */
- {SENSOR, OV9650_COM1, (EXPOSURE_DEFAULT & 0xff)},
- {SENSOR, OV9650_GAIN, GAIN_DEFAULT},
- {SENSOR, OV9650_BLUE, BLUE_GAIN_DEFAULT},
- {SENSOR, OV9650_RED, RED_GAIN_DEFAULT},
+ /* Put the sensor in soft sleep mode */
+ {SENSOR, OV9650_COM2, OV9650_SOFT_SLEEP | OV9650_OUTPUT_DRIVE_2X},
};
static const unsigned char power_down_ov9650[][3] =
@@ -461,73 +332,15 @@ static const unsigned char power_down_ov9650[][3] =
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
};
-static const unsigned char res_init_ov9650[][2] =
-{
- {M5602_XB_LINE_OF_FRAME_H, 0x82},
- {M5602_XB_LINE_OF_FRAME_L, 0x00},
- {M5602_XB_PIX_OF_LINE_H, 0x82},
- {M5602_XB_PIX_OF_LINE_L, 0x00},
- {M5602_XB_SIG_INI, 0x01}
-};
-
-static const unsigned char VGA_ov9650[][3] =
+static const unsigned char res_init_ov9650[][3] =
{
- /* Moves the view window in a vertical orientation */
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x09},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0}, /* 480 */
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x62}, /* 98 */
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x02}, /* 640 + 98 */
- {BRIDGE, M5602_XB_HSYNC_PARA, 0xe2},
-
- {SENSOR, OV9650_COM7, OV9650_VGA_SELECT |
- OV9650_RGB_SELECT |
- OV9650_RAW_RGB_SELECT},
-};
+ {SENSOR, OV9650_COM2, OV9650_OUTPUT_DRIVE_2X},
-static const unsigned char CIF_ov9650[][3] =
-{
- /* Moves the view window in a vertical orientation */
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x09},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x20}, /* 288 */
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x62}, /* 98 */
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x01}, /* 352 + 98 */
- {BRIDGE, M5602_XB_HSYNC_PARA, 0xc2},
-
- {SENSOR, OV9650_COM7, OV9650_CIF_SELECT |
- OV9650_RGB_SELECT |
- OV9650_RAW_RGB_SELECT},
-};
-
-static const unsigned char QVGA_ov9650[][3] =
-{
- /* Moves the view window in a vertical orientation */
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x08},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0xf0}, /* 240 */
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x31}, /* 50 */
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x01}, /* 320 + 50 */
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x71},
-
- {SENSOR, OV9650_COM7, OV9650_QVGA_SELECT |
- OV9650_RGB_SELECT |
- OV9650_RAW_RGB_SELECT},
+ {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x82},
+ {BRIDGE, M5602_XB_LINE_OF_FRAME_L, 0x00},
+ {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82},
+ {BRIDGE, M5602_XB_PIX_OF_LINE_L, 0x00},
+ {BRIDGE, M5602_XB_SIG_INI, 0x01}
};
#endif
diff --git a/drivers/media/video/gspca/m5602/m5602_po1030.c b/drivers/media/video/gspca/m5602/m5602_po1030.c
index 2e7fb91673cf..eaddf488bad1 100644
--- a/drivers/media/video/gspca/m5602/m5602_po1030.c
+++ b/drivers/media/video/gspca/m5602/m5602_po1030.c
@@ -18,6 +18,99 @@
#include "m5602_po1030.h"
+static struct v4l2_pix_format po1030_modes[] = {
+ {
+ 640,
+ 480,
+ V4L2_PIX_FMT_SBGGR8,
+ V4L2_FIELD_NONE,
+ .sizeimage = 640 * 480,
+ .bytesperline = 640,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0
+ }
+};
+
+const static struct ctrl po1030_ctrls[] = {
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "gain",
+ .minimum = 0x00,
+ .maximum = 0x4f,
+ .step = 0x1,
+ .default_value = PO1030_GLOBAL_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = po1030_set_gain,
+ .get = po1030_get_gain
+ }, {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "exposure",
+ .minimum = 0x00,
+ .maximum = 0x02ff,
+ .step = 0x1,
+ .default_value = PO1030_EXPOSURE_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = po1030_set_exposure,
+ .get = po1030_get_exposure
+ }, {
+ {
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "red balance",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 0x1,
+ .default_value = PO1030_RED_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = po1030_set_red_balance,
+ .get = po1030_get_red_balance
+ }, {
+ {
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "blue balance",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 0x1,
+ .default_value = PO1030_BLUE_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = po1030_set_blue_balance,
+ .get = po1030_get_blue_balance
+ }, {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "horizontal flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ .set = po1030_set_hflip,
+ .get = po1030_get_hflip
+ }, {
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "vertical flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ .set = po1030_set_vflip,
+ .get = po1030_get_vflip
+ }
+};
+
static void po1030_dump_registers(struct sd *sd);
int po1030_probe(struct sd *sd)
@@ -59,10 +152,10 @@ int po1030_probe(struct sd *sd)
return -ENODEV;
sensor_found:
- sd->gspca_dev.cam.cam_mode = po1030.modes;
- sd->gspca_dev.cam.nmodes = po1030.nmodes;
- sd->desc->ctrls = po1030.ctrls;
- sd->desc->nctrls = po1030.nctrls;
+ sd->gspca_dev.cam.cam_mode = po1030_modes;
+ sd->gspca_dev.cam.nmodes = ARRAY_SIZE(po1030_modes);
+ sd->desc->ctrls = po1030_ctrls;
+ sd->desc->nctrls = ARRAY_SIZE(po1030_ctrls);
return 0;
}
@@ -108,7 +201,7 @@ int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
err = m5602_read_sensor(sd, PO1030_REG_INTEGLINES_H,
&i2c_data, 1);
if (err < 0)
- goto out;
+ return err;
*val = (i2c_data << 8);
err = m5602_read_sensor(sd, PO1030_REG_INTEGLINES_M,
@@ -116,7 +209,7 @@ int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
*val |= i2c_data;
PDEBUG(D_V4L2, "Exposure read as %d", *val);
-out:
+
return err;
}
@@ -135,7 +228,7 @@ int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
err = m5602_write_sensor(sd, PO1030_REG_INTEGLINES_H,
&i2c_data, 1);
if (err < 0)
- goto out;
+ return err;
i2c_data = (val & 0xff);
PDEBUG(D_V4L2, "Set exposure to low byte to 0x%x",
@@ -143,7 +236,6 @@ int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
err = m5602_write_sensor(sd, PO1030_REG_INTEGLINES_M,
&i2c_data, 1);
-out:
return err;
}
@@ -186,14 +278,13 @@ int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
PDEBUG(D_V4L2, "Set hflip %d", val);
err = m5602_read_sensor(sd, PO1030_REG_CONTROL2, &i2c_data, 1);
if (err < 0)
- goto out;
+ return err;
i2c_data = (0x7f & i2c_data) | ((val & 0x01) << 7);
err = m5602_write_sensor(sd, PO1030_REG_CONTROL2,
&i2c_data, 1);
-out:
return err;
}
@@ -222,14 +313,13 @@ int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
PDEBUG(D_V4L2, "Set vflip %d", val);
err = m5602_read_sensor(sd, PO1030_REG_CONTROL2, &i2c_data, 1);
if (err < 0)
- goto out;
+ return err;
i2c_data = (i2c_data & 0xbf) | ((val & 0x01) << 6);
err = m5602_write_sensor(sd, PO1030_REG_CONTROL2,
&i2c_data, 1);
-out:
return err;
}
diff --git a/drivers/media/video/gspca/m5602/m5602_po1030.h b/drivers/media/video/gspca/m5602/m5602_po1030.h
index def39d5bcec6..c10b12335818 100644
--- a/drivers/media/video/gspca/m5602/m5602_po1030.h
+++ b/drivers/media/video/gspca/m5602/m5602_po1030.h
@@ -141,7 +141,7 @@ int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-static struct m5602_sensor po1030 = {
+static const struct m5602_sensor po1030 = {
.name = "PO1030",
.i2c_slave_id = 0xdc,
@@ -150,102 +150,6 @@ static struct m5602_sensor po1030 = {
.probe = po1030_probe,
.init = po1030_init,
.power_down = po1030_power_down,
-
- .nctrls = 6,
- .ctrls = {
- {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "gain",
- .minimum = 0x00,
- .maximum = 0x4f,
- .step = 0x1,
- .default_value = PO1030_GLOBAL_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = po1030_set_gain,
- .get = po1030_get_gain
- }, {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x00,
- .maximum = 0x02ff,
- .step = 0x1,
- .default_value = PO1030_EXPOSURE_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = po1030_set_exposure,
- .get = po1030_get_exposure
- }, {
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = PO1030_RED_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = po1030_set_red_balance,
- .get = po1030_get_red_balance
- }, {
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = PO1030_BLUE_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = po1030_set_blue_balance,
- .get = po1030_get_blue_balance
- }, {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- .set = po1030_set_hflip,
- .get = po1030_get_hflip
- }, {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- .set = po1030_set_vflip,
- .get = po1030_get_vflip
- }
- },
-
- .nmodes = 1,
- .modes = {
- {
- M5602_DEFAULT_FRAME_WIDTH,
- M5602_DEFAULT_FRAME_HEIGHT,
- V4L2_PIX_FMT_SBGGR8,
- V4L2_FIELD_NONE,
- .sizeimage =
- M5602_DEFAULT_FRAME_WIDTH * M5602_DEFAULT_FRAME_HEIGHT,
- .bytesperline = M5602_DEFAULT_FRAME_WIDTH,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 1
- }
- }
};
static const unsigned char preinit_po1030[][3] =
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
index 48892b5715d5..4306d596056d 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
+++ b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
@@ -50,6 +50,76 @@ static
{ }
};
+static struct v4l2_pix_format s5k4aa_modes[] = {
+ {
+ 640,
+ 480,
+ V4L2_PIX_FMT_SBGGR8,
+ V4L2_FIELD_NONE,
+ .sizeimage =
+ 640 * 480,
+ .bytesperline = 640,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0
+ }
+};
+
+const static struct ctrl s5k4aa_ctrls[] = {
+ {
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "vertical flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0
+ },
+ .set = s5k4aa_set_vflip,
+ .get = s5k4aa_get_vflip
+
+ }, {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "horizontal flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0
+ },
+ .set = s5k4aa_set_hflip,
+ .get = s5k4aa_get_hflip
+
+ }, {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = 0,
+ .maximum = 127,
+ .step = 1,
+ .default_value = 0xa0,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = s5k4aa_set_gain,
+ .get = s5k4aa_get_gain
+ }, {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+ .minimum = 13,
+ .maximum = 0xfff,
+ .step = 1,
+ .default_value = 0x100,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = s5k4aa_set_exposure,
+ .get = s5k4aa_get_exposure
+ }
+};
+
static void s5k4aa_dump_registers(struct sd *sd);
int s5k4aa_probe(struct sd *sd)
@@ -115,14 +185,56 @@ int s5k4aa_probe(struct sd *sd)
info("Detected a s5k4aa sensor");
sensor_found:
- sd->gspca_dev.cam.cam_mode = s5k4aa.modes;
- sd->gspca_dev.cam.nmodes = s5k4aa.nmodes;
- sd->desc->ctrls = s5k4aa.ctrls;
- sd->desc->nctrls = s5k4aa.nctrls;
-
+ sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
+ sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
+ sd->desc->ctrls = s5k4aa_ctrls;
+ sd->desc->nctrls = ARRAY_SIZE(s5k4aa_ctrls);
return 0;
}
+int s5k4aa_start(struct sd *sd)
+{
+ int i, err = 0;
+ u8 data[2];
+ struct cam *cam = &sd->gspca_dev.cam;
+
+ switch (cam->cam_mode[sd->gspca_dev.curr_mode].width)
+ {
+ case 640:
+ PDEBUG(D_V4L2, "Configuring camera for VGA mode");
+
+ for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) {
+ switch (VGA_s5k4aa[i][0]) {
+ case BRIDGE:
+ err = m5602_write_bridge(sd,
+ VGA_s5k4aa[i][1],
+ VGA_s5k4aa[i][2]);
+ break;
+
+ case SENSOR:
+ data[0] = VGA_s5k4aa[i][2];
+ err = m5602_write_sensor(sd,
+ VGA_s5k4aa[i][1],
+ data, 1);
+ break;
+
+ case SENSOR_LONG:
+ data[0] = VGA_s5k4aa[i][2];
+ data[1] = VGA_s5k4aa[i][3];
+ err = m5602_write_sensor(sd,
+ VGA_s5k4aa[i][1],
+ data, 2);
+ break;
+
+ default:
+ err("Invalid stream command, exiting init");
+ return -EINVAL;
+ }
+ }
+ }
+ return err;
+}
+
int s5k4aa_init(struct sd *sd)
{
int i, err = 0;
@@ -194,17 +306,17 @@ int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
- goto out;
+ return err;
err = m5602_read_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
if (err < 0)
- goto out;
+ return err;
*val = data << 8;
err = m5602_read_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
*val |= data;
PDEBUG(D_V4L2, "Read exposure %d", *val);
-out:
+
return err;
}
@@ -217,14 +329,14 @@ int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
PDEBUG(D_V4L2, "Set exposure to %d", val);
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
- goto out;
+ return err;
data = (val >> 8) & 0xff;
err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
if (err < 0)
- goto out;
+ return err;
data = val & 0xff;
err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
-out:
+
return err;
}
@@ -236,13 +348,12 @@ int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
- goto out;
+ return err;
err = m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
*val = (data & S5K4AA_RM_V_FLIP) >> 7;
PDEBUG(D_V4L2, "Read vertical flip %d", *val);
-out:
return err;
}
@@ -255,32 +366,32 @@ int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
PDEBUG(D_V4L2, "Set vertical flip to %d", val);
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
- goto out;
+ return err;
err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
if (err < 0)
- goto out;
+ return err;
data = ((data & ~S5K4AA_RM_V_FLIP)
| ((val & 0x01) << 7));
err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
if (err < 0)
- goto out;
+ return err;
if (val) {
err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
if (err < 0)
- goto out;
+ return err;
data++;
err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
} else {
err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
if (err < 0)
- goto out;
+ return err;
data--;
err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
}
-out:
+
return err;
}
@@ -292,12 +403,12 @@ int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
- goto out;
+ return err;
err = m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
*val = (data & S5K4AA_RM_H_FLIP) >> 6;
PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
-out:
+
return err;
}
@@ -311,32 +422,32 @@ int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
val);
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
- goto out;
+ return err;
err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
if (err < 0)
- goto out;
+ return err;
data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
if (err < 0)
- goto out;
+ return err;
if (val) {
err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
if (err < 0)
- goto out;
+ return err;
data++;
err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
if (err < 0)
- goto out;
+ return err;
} else {
err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
if (err < 0)
- goto out;
+ return err;
data--;
err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
}
-out:
+
return err;
}
@@ -348,13 +459,12 @@ int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
- goto out;
+ return err;
err = m5602_read_sensor(sd, S5K4AA_GAIN_2, &data, 1);
*val = data;
PDEBUG(D_V4L2, "Read gain %d", *val);
-out:
return err;
}
@@ -367,12 +477,11 @@ int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
PDEBUG(D_V4L2, "Set gain to %d", val);
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
- goto out;
+ return err;
data = val & 0xff;
err = m5602_write_sensor(sd, S5K4AA_GAIN_2, &data, 1);
-out:
return err;
}
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.h b/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
index 1f88b0d040c4..ca854d4f9475 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
+++ b/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
@@ -65,6 +65,7 @@ extern int dump_sensor;
int s5k4aa_probe(struct sd *sd);
int s5k4aa_init(struct sd *sd);
+int s5k4aa_start(struct sd *sd);
int s5k4aa_power_down(struct sd *sd);
int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
@@ -76,84 +77,14 @@ int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-static struct m5602_sensor s5k4aa = {
+static const struct m5602_sensor s5k4aa = {
.name = "S5K4AA",
.probe = s5k4aa_probe,
.init = s5k4aa_init,
+ .start = s5k4aa_start,
.power_down = s5k4aa_power_down,
.i2c_slave_id = 0x5a,
.i2c_regW = 2,
- .nctrls = 4,
- .ctrls = {
- {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = s5k4aa_set_vflip,
- .get = s5k4aa_get_vflip
-
- }, {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = s5k4aa_set_hflip,
- .get = s5k4aa_get_hflip
-
- }, {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 0xa0,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = s5k4aa_set_gain,
- .get = s5k4aa_get_gain
- }, {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Exposure",
- .minimum = 13,
- .maximum = 0xfff,
- .step = 1,
- .default_value = 0x100,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = s5k4aa_set_exposure,
- .get = s5k4aa_get_exposure
- }
- },
-
- .nmodes = 1,
- .modes = {
- {
- M5602_DEFAULT_FRAME_WIDTH,
- M5602_DEFAULT_FRAME_HEIGHT,
- V4L2_PIX_FMT_SBGGR8,
- V4L2_FIELD_NONE,
- .sizeimage =
- M5602_DEFAULT_FRAME_WIDTH * M5602_DEFAULT_FRAME_HEIGHT,
- .bytesperline = M5602_DEFAULT_FRAME_WIDTH,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 1
- }
- }
};
static const unsigned char preinit_s5k4aa[][4] =
@@ -329,4 +260,63 @@ static const unsigned char init_s5k4aa[][4] =
{SENSOR, S5K4AA_GAIN_2, 0xa0, 0x00}
};
+static const unsigned char VGA_s5k4aa[][4] =
+{
+ {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
+ {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+ {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+ {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00},
+ {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
+ {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
+ {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+ /* VSYNC_PARA, VSYNC_PARA : img height 480 = 0x01e0 */
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+ {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+ {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
+ {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+ {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+ /* HSYNC_PARA, HSYNC_PARA : img width 640 = 0x0280 */
+ {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
+ {BRIDGE, M5602_XB_HSYNC_PARA, 0x80, 0x00},
+ {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+ {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+ {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, /* 48 MHz */
+
+ {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
+ {SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP | S5K4AA_RM_ROW_SKIP_2X
+ | S5K4AA_RM_COL_SKIP_2X, 0x00},
+ /* 0x37 : Fix image stability when light is too bright and improves
+ * image quality in 640x480, but worsens it in 1280x1024 */
+ {SENSOR, 0x37, 0x01, 0x00},
+ /* ROWSTART_HI, ROWSTART_LO : 10 + (1024-960)/2 = 42 = 0x002a */
+ {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00},
+ {SENSOR, S5K4AA_ROWSTART_LO, 0x2a, 0x00},
+ {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00},
+ {SENSOR, S5K4AA_COLSTART_LO, 0x0c, 0x00},
+ /* window_height_hi, window_height_lo : 960 = 0x03c0 */
+ {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x03, 0x00},
+ {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0xc0, 0x00},
+ /* window_width_hi, window_width_lo : 1280 = 0x0500 */
+ {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00},
+ {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x00, 0x00},
+ {SENSOR, S5K4AA_H_BLANK_HI__, 0x00, 0x00},
+ {SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00}, /* helps to sync... */
+ {SENSOR, S5K4AA_EXPOSURE_HI, 0x01, 0x00},
+ {SENSOR, S5K4AA_EXPOSURE_LO, 0x00, 0x00},
+ {SENSOR, 0x11, 0x04, 0x00},
+ {SENSOR, 0x12, 0xc3, 0x00},
+ {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
+ {SENSOR, 0x02, 0x0e, 0x00},
+ {SENSOR_LONG, S5K4AA_GLOBAL_GAIN__, 0x0f, 0x00},
+ {SENSOR, S5K4AA_GAIN_1, 0x0b, 0x00},
+ {SENSOR, S5K4AA_GAIN_2, 0xa0, 0x00}
+};
+
#endif
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.c b/drivers/media/video/gspca/m5602/m5602_s5k83a.c
index ccea4a758464..42c86aa4dc8d 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k83a.c
+++ b/drivers/media/video/gspca/m5602/m5602_s5k83a.c
@@ -18,6 +18,88 @@
#include "m5602_s5k83a.h"
+static struct v4l2_pix_format s5k83a_modes[] = {
+ {
+ 640,
+ 480,
+ V4L2_PIX_FMT_SBGGR8,
+ V4L2_FIELD_NONE,
+ .sizeimage =
+ 640 * 480,
+ .bytesperline = 640,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0
+ }
+};
+
+const static struct ctrl s5k83a_ctrls[] = {
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "brightness",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 0x01,
+ .default_value = S5K83A_DEFAULT_BRIGHTNESS,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = s5k83a_set_brightness,
+ .get = s5k83a_get_brightness
+
+ }, {
+ {
+ .id = V4L2_CID_WHITENESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "whiteness",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 0x01,
+ .default_value = S5K83A_DEFAULT_WHITENESS,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = s5k83a_set_whiteness,
+ .get = s5k83a_get_whiteness,
+ }, {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "gain",
+ .minimum = 0x00,
+ .maximum = S5K83A_MAXIMUM_GAIN,
+ .step = 0x01,
+ .default_value = S5K83A_DEFAULT_GAIN,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = s5k83a_set_gain,
+ .get = s5k83a_get_gain
+ }, {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "horizontal flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0
+ },
+ .set = s5k83a_set_hflip,
+ .get = s5k83a_get_hflip
+ }, {
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "vertical flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0
+ },
+ .set = s5k83a_set_vflip,
+ .get = s5k83a_get_vflip
+ }
+};
+
static void s5k83a_dump_registers(struct sd *sd);
int s5k83a_probe(struct sd *sd)
@@ -63,10 +145,10 @@ int s5k83a_probe(struct sd *sd)
info("Detected a s5k83a sensor");
sensor_found:
- sd->gspca_dev.cam.cam_mode = s5k83a.modes;
- sd->gspca_dev.cam.nmodes = s5k83a.nmodes;
- sd->desc->ctrls = s5k83a.ctrls;
- sd->desc->nctrls = s5k83a.nctrls;
+ sd->gspca_dev.cam.cam_mode = s5k83a_modes;
+ sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes);
+ sd->desc->ctrls = s5k83a_ctrls;
+ sd->desc->nctrls = ARRAY_SIZE(s5k83a_ctrls);
return 0;
}
@@ -108,6 +190,16 @@ int s5k83a_init(struct sd *sd)
return (err < 0) ? err : 0;
}
+int s5k83a_start(struct sd *sd)
+{
+ return s5k83a_set_led_indication(sd, 1);
+}
+
+int s5k83a_stop(struct sd *sd)
+{
+ return s5k83a_set_led_indication(sd, 0);
+}
+
int s5k83a_power_down(struct sd *sd)
{
return 0;
@@ -163,12 +255,11 @@ int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
err = m5602_read_sensor(sd, S5K83A_BRIGHTNESS, data, 2);
if (err < 0)
- goto out;
+ return err;
data[1] = data[1] << 1;
*val = data[1];
-out:
return err;
}
@@ -182,13 +273,13 @@ int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
data[1] = 0x20;
err = m5602_write_sensor(sd, 0x14, data, 2);
if (err < 0)
- goto out;
+ return err;
data[0] = 0x01;
data[1] = 0x00;
err = m5602_write_sensor(sd, 0x0d, data, 2);
if (err < 0)
- goto out;
+ return err;
/* FIXME: This is not sane, we need to figure out the composition
of these registers */
@@ -196,7 +287,6 @@ int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
data[1] = val >> 1; /* brightness, high 7 bits */
err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 2);
-out:
return err;
}
@@ -208,11 +298,10 @@ int s5k83a_get_whiteness(struct gspca_dev *gspca_dev, __s32 *val)
err = m5602_read_sensor(sd, S5K83A_WHITENESS, &data, 1);
if (err < 0)
- goto out;
+ return err;
*val = data;
-out:
return err;
}
@@ -236,7 +325,7 @@ int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
err = m5602_read_sensor(sd, S5K83A_GAIN, data, 2);
if (err < 0)
- goto out;
+ return err;
data[1] = data[1] & 0x3f;
if (data[1] > S5K83A_MAXIMUM_GAIN)
@@ -244,7 +333,6 @@ int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
*val = data[1];
-out:
return err;
}
@@ -269,12 +357,11 @@ int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
data[0] = 0x05;
err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
if (err < 0)
- goto out;
+ return err;
err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
*val = (data[0] | 0x40) ? 1 : 0;
-out:
return err;
}
@@ -287,23 +374,22 @@ int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
data[0] = 0x05;
err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
if (err < 0)
- goto out;
+ return err;
err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
if (err < 0)
- goto out;
+ return err;
/* set or zero six bit, seven is hflip */
data[0] = (val) ? (data[0] & 0x80) | 0x40 | S5K83A_FLIP_MASK
: (data[0] & 0x80) | S5K83A_FLIP_MASK;
err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
if (err < 0)
- goto out;
+ return err;
data[0] = (val) ? 0x0b : 0x0a;
err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1);
-out:
return err;
}
@@ -316,12 +402,11 @@ int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
data[0] = 0x05;
err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
if (err < 0)
- goto out;
+ return err;
err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
*val = (data[0] | 0x80) ? 1 : 0;
-out:
return err;
}
@@ -334,21 +419,40 @@ int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
data[0] = 0x05;
err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
if (err < 0)
- goto out;
+ return err;
err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
if (err < 0)
- goto out;
+ return err;
/* set or zero seven bit, six is vflip */
data[0] = (val) ? (data[0] & 0x40) | 0x80 | S5K83A_FLIP_MASK
: (data[0] & 0x40) | S5K83A_FLIP_MASK;
err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
if (err < 0)
- goto out;
+ return err;
data[0] = (val) ? 0x0a : 0x0b;
err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
-out:
+
return err;
}
+
+int s5k83a_set_led_indication(struct sd *sd, u8 val)
+{
+ int err = 0;
+ u8 data[1];
+
+ err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, data);
+ if (err < 0)
+ return err;
+
+ if (val)
+ data[0] = data[0] | S5K83A_GPIO_LED_MASK;
+ else
+ data[0] = data[0] & ~S5K83A_GPIO_LED_MASK;
+
+ err = m5602_write_bridge(sd, M5602_XB_GPIO_DAT, data[0]);
+
+ return (err < 0) ? err : 0;
+}
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.h b/drivers/media/video/gspca/m5602/m5602_s5k83a.h
index 05ccb5b57a88..819ab25272be 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k83a.h
+++ b/drivers/media/video/gspca/m5602/m5602_s5k83a.h
@@ -34,7 +34,7 @@
#define S5K83A_DEFAULT_GAIN 0x00
#define S5K83A_MAXIMUM_GAIN 0x3c
#define S5K83A_FLIP_MASK 0x10
-
+#define S5K83A_GPIO_LED_MASK 0x10
/*****************************************************************************/
@@ -44,8 +44,12 @@ extern int dump_sensor;
int s5k83a_probe(struct sd *sd);
int s5k83a_init(struct sd *sd);
+int s5k83a_start(struct sd *sd);
+int s5k83a_stop(struct sd *sd);
int s5k83a_power_down(struct sd *sd);
+int s5k83a_set_led_indication(struct sd *sd, u8 val);
+
int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val);
@@ -57,95 +61,15 @@ int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-static struct m5602_sensor s5k83a = {
+static const struct m5602_sensor s5k83a = {
.name = "S5K83A",
.probe = s5k83a_probe,
.init = s5k83a_init,
+ .start = s5k83a_start,
+ .stop = s5k83a_stop,
.power_down = s5k83a_power_down,
.i2c_slave_id = 0x5a,
.i2c_regW = 2,
- .nctrls = 5,
- .ctrls = {
- {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "brightness",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x01,
- .default_value = S5K83A_DEFAULT_BRIGHTNESS,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = s5k83a_set_brightness,
- .get = s5k83a_get_brightness
-
- }, {
- {
- .id = V4L2_CID_WHITENESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "whiteness",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x01,
- .default_value = S5K83A_DEFAULT_WHITENESS,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = s5k83a_set_whiteness,
- .get = s5k83a_get_whiteness,
- }, {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "gain",
- .minimum = 0x00,
- .maximum = S5K83A_MAXIMUM_GAIN,
- .step = 0x01,
- .default_value = S5K83A_DEFAULT_GAIN,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = s5k83a_set_gain,
- .get = s5k83a_get_gain
- }, {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = s5k83a_set_hflip,
- .get = s5k83a_get_hflip
- }, {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = s5k83a_set_vflip,
- .get = s5k83a_get_vflip
- }
- },
- .nmodes = 1,
- .modes = {
- {
- M5602_DEFAULT_FRAME_WIDTH,
- M5602_DEFAULT_FRAME_HEIGHT,
- V4L2_PIX_FMT_SBGGR8,
- V4L2_FIELD_NONE,
- .sizeimage =
- M5602_DEFAULT_FRAME_WIDTH * M5602_DEFAULT_FRAME_HEIGHT,
- .bytesperline = M5602_DEFAULT_FRAME_WIDTH,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 1
- }
- }
};
static const unsigned char preinit_s5k83a[][4] =
@@ -381,7 +305,7 @@ static const unsigned char init_s5k83a[][4] =
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
- {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
+ {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
{BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
{BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
diff --git a/drivers/media/video/gspca/m5602/m5602_sensor.h b/drivers/media/video/gspca/m5602/m5602_sensor.h
index 261623f0da48..0d3026936f2e 100644
--- a/drivers/media/video/gspca/m5602/m5602_sensor.h
+++ b/drivers/media/video/gspca/m5602/m5602_sensor.h
@@ -21,11 +21,6 @@
#include "m5602_bridge.h"
-#define M5602_DEFAULT_FRAME_WIDTH 640
-#define M5602_DEFAULT_FRAME_HEIGHT 480
-
-#define M5602_MAX_CTRLS (V4L2_CID_LASTP1 - V4L2_CID_BASE + 10)
-
/* Enumerates all supported sensors */
enum sensors {
OV9650_SENSOR = 1,
@@ -61,14 +56,14 @@ struct m5602_sensor {
/* Executed when the camera starts to send data */
int (*start)(struct sd *sd);
- /* Performs a power down sequence */
- int (*power_down)(struct sd *sd);
+ /* Executed when the camera ends to send data */
+ int (*stop)(struct sd *sd);
- int nctrls;
- struct ctrl ctrls[M5602_MAX_CTRLS];
+ /* Executed when the device is disconnected */
+ void (*disconnect)(struct sd *sd);
- char nmodes;
- struct v4l2_pix_format modes[];
+ /* Performs a power down sequence */
+ int (*power_down)(struct sd *sd);
};
#endif