diff options
Diffstat (limited to 'drivers/media/video/gspca/m5602/m5602_ov9650.c')
-rw-r--r-- | drivers/media/video/gspca/m5602/m5602_ov9650.c | 222 |
1 files changed, 142 insertions, 80 deletions
diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.c b/drivers/media/video/gspca/m5602/m5602_ov9650.c index fc4548fd441d..c2739d6605a1 100644 --- a/drivers/media/video/gspca/m5602/m5602_ov9650.c +++ b/drivers/media/video/gspca/m5602/m5602_ov9650.c @@ -18,44 +18,87 @@ #include "m5602_ov9650.h" +static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val); +static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); +static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val); +static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val); +static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val); +static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val); +static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val); +static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val); +static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); +static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val); +static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); +static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val); +static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 *val); +static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 val); +static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val); +static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val); +static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val); +static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val); + /* Vertically and horizontally flips the image if matched, needed for machines where the sensor is mounted upside down */ static const struct dmi_system_id ov9650_flip_dmi_table[] = { { - .ident = "ASUS A6VC", + .ident = "ASUS A6Ja", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "A6VC") + DMI_MATCH(DMI_PRODUCT_NAME, "A6J") } }, { - .ident = "ASUS A6VM", + .ident = "ASUS A6JC", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "A6VM") + DMI_MATCH(DMI_PRODUCT_NAME, "A6JC") } }, { - .ident = "ASUS A6JC", + .ident = "ASUS A6K", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "A6JC") + DMI_MATCH(DMI_PRODUCT_NAME, "A6K") } }, { - .ident = "ASUS A6Ja", + .ident = "ASUS A6Kt", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "A6J") + DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt") } }, { - .ident = "ASUS A6Kt", + .ident = "ASUS A6VA", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt") + DMI_MATCH(DMI_PRODUCT_NAME, "A6VA") + } + }, + { + + .ident = "ASUS A6VC", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "A6VC") + } + }, + { + .ident = "ASUS A6VM", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "A6VM") + } + }, + { + .ident = "ASUS A7V", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "A7V") } }, { @@ -68,7 +111,7 @@ static {} }; -const static struct ctrl ov9650_ctrls[] = { +static const struct ctrl ov9650_ctrls[] = { #define EXPOSURE_IDX 0 { { @@ -102,6 +145,7 @@ const static struct ctrl ov9650_ctrls[] = { #define RED_BALANCE_IDX 2 { { + .id = V4L2_CID_RED_BALANCE, .type = V4L2_CTRL_TYPE_INTEGER, .name = "red balance", .minimum = 0x00, @@ -116,6 +160,7 @@ const static struct ctrl ov9650_ctrls[] = { #define BLUE_BALANCE_IDX 3 { { + .id = V4L2_CID_BLUE_BALANCE, .type = V4L2_CTRL_TYPE_INTEGER, .name = "blue balance", .minimum = 0x00, @@ -182,7 +227,22 @@ const static struct ctrl ov9650_ctrls[] = { }, .set = ov9650_set_auto_gain, .get = ov9650_get_auto_gain + }, +#define AUTO_EXPOSURE_IDX 8 + { + { + .id = V4L2_CID_EXPOSURE_AUTO, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "auto exposure", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1 + }, + .set = ov9650_set_auto_exposure, + .get = ov9650_get_auto_exposure } + }; static struct v4l2_pix_format ov9650_modes[] = { @@ -289,12 +349,6 @@ sensor_found: 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; } @@ -316,7 +370,8 @@ int ov9650_init(struct sd *sd) err = m5602_write_bridge(sd, init_ov9650[i][1], data); } - err = ov9650_set_exposure(&sd->gspca_dev, sensor_settings[EXPOSURE_IDX]); + err = ov9650_set_exposure(&sd->gspca_dev, + sensor_settings[EXPOSURE_IDX]); if (err < 0) return err; @@ -324,11 +379,13 @@ int ov9650_init(struct sd *sd) if (err < 0) return err; - err = ov9650_set_red_balance(&sd->gspca_dev, sensor_settings[RED_BALANCE_IDX]); + 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]); + err = ov9650_set_blue_balance(&sd->gspca_dev, + sensor_settings[BLUE_BALANCE_IDX]); if (err < 0) return err; @@ -340,11 +397,18 @@ int ov9650_init(struct sd *sd) if (err < 0) return err; - err = ov9650_set_auto_white_balance(&sd->gspca_dev, sensor_settings[AUTO_WHITE_BALANCE_IDX]); + err = ov9650_set_auto_exposure(&sd->gspca_dev, + sensor_settings[AUTO_EXPOSURE_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]); + err = ov9650_set_auto_gain(&sd->gspca_dev, + sensor_settings[AUTO_GAIN_CTRL_IDX]); return err; } @@ -360,7 +424,10 @@ int ov9650_start(struct sd *sd) int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv; int hor_offs = OV9650_LEFT_OFFSET; - if (sensor_settings[VFLIP_IDX]) + if ((!dmi_check_system(ov9650_flip_dmi_table) && + sensor_settings[VFLIP_IDX]) || + (dmi_check_system(ov9650_flip_dmi_table) && + !sensor_settings[VFLIP_IDX])) ver_offs--; if (width <= 320) @@ -406,6 +473,14 @@ int ov9650_start(struct sd *sd) if (err < 0) return err; + err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); + if (err < 0) + return err; + + err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 2); + if (err < 0) + return err; + err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (hor_offs >> 8) & 0xff); if (err < 0) @@ -425,6 +500,10 @@ int ov9650_start(struct sd *sd) if (err < 0) return err; + err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); + if (err < 0) + return err; + switch (width) { case 640: PDEBUG(D_V4L2, "Configuring camera for VGA mode"); @@ -467,32 +546,15 @@ int ov9650_stop(struct sd *sd) return m5602_write_sensor(sd, OV9650_COM2, &data, 1); } -int ov9650_power_down(struct sd *sd) -{ - int i, err = 0; - for (i = 0; i < ARRAY_SIZE(power_down_ov9650) && !err; i++) { - u8 data = power_down_ov9650[i][2]; - if (power_down_ov9650[i][0] == SENSOR) - err = m5602_write_sensor(sd, - power_down_ov9650[i][1], &data, 1); - else - err = m5602_write_bridge(sd, power_down_ov9650[i][1], - data); - } - - return err; -} - void ov9650_disconnect(struct sd *sd) { ov9650_stop(sd); - ov9650_power_down(sd); sd->sensor = NULL; kfree(sd->sensor_priv); } -int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) +static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; s32 *sensor_settings = sd->sensor_priv; @@ -502,7 +564,7 @@ int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) return 0; } -int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val) +static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; s32 *sensor_settings = sd->sensor_priv; @@ -532,7 +594,7 @@ int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val) return err; } -int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val) +static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; s32 *sensor_settings = sd->sensor_priv; @@ -542,7 +604,7 @@ int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val) return 0; } -int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val) +static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val) { int err; u8 i2c_data; @@ -573,7 +635,7 @@ int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val) return err; } -int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) +static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; s32 *sensor_settings = sd->sensor_priv; @@ -583,7 +645,7 @@ int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) return 0; } -int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) +static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) { int err; u8 i2c_data; @@ -599,7 +661,7 @@ int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) return err; } -int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) +static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; s32 *sensor_settings = sd->sensor_priv; @@ -610,7 +672,7 @@ int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) return 0; } -int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) +static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) { int err; u8 i2c_data; @@ -626,7 +688,7 @@ int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) return err; } -int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) +static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; s32 *sensor_settings = sd->sensor_priv; @@ -636,7 +698,7 @@ int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) return 0; } -int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val) +static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val) { int err; u8 i2c_data; @@ -646,13 +708,20 @@ int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val) PDEBUG(D_V4L2, "Set horizontal flip to %d", val); sensor_settings[HFLIP_IDX] = val; - i2c_data = ((val & 0x01) << 5) | (sensor_settings[VFLIP_IDX] << 4); + + if (!dmi_check_system(ov9650_flip_dmi_table)) + i2c_data = ((val & 0x01) << 5) | + (sensor_settings[VFLIP_IDX] << 4); + else + i2c_data = ((val & 0x01) << 5) | + (!sensor_settings[VFLIP_IDX] << 4); + err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1); return err; } -int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) +static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; s32 *sensor_settings = sd->sensor_priv; @@ -663,7 +732,7 @@ int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) return 0; } -int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val) +static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val) { int err; u8 i2c_data; @@ -673,6 +742,9 @@ int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val) PDEBUG(D_V4L2, "Set vertical flip to %d", val); sensor_settings[VFLIP_IDX] = val; + if (dmi_check_system(ov9650_flip_dmi_table)) + val = !val; + i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5); err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1); if (err < 0) @@ -685,48 +757,38 @@ int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val) return err; } -int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val) +static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; s32 *sensor_settings = sd->sensor_priv; - *val = sensor_settings[GAIN_IDX]; - PDEBUG(D_V4L2, "Read gain %d", *val); - + *val = sensor_settings[AUTO_EXPOSURE_IDX]; + PDEBUG(D_V4L2, "Read auto exposure control %d", *val); return 0; } -int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val) +static int ov9650_set_auto_exposure(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); - - sensor_settings[GAIN_IDX] = val; + PDEBUG(D_V4L2, "Set auto exposure control to %d", 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) - 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); + sensor_settings[AUTO_EXPOSURE_IDX] = val; + err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); if (err < 0) return err; - /* The 8 LSBs */ - i2c_data = val & 0xff; - err = m5602_write_sensor(sd, OV9650_GAIN, &i2c_data, 1); + i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0)); - return err; + return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1); } -int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val) +static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; s32 *sensor_settings = sd->sensor_priv; @@ -735,7 +797,8 @@ int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val) return 0; } -int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val) +static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, + __s32 val) { int err; u8 i2c_data; @@ -755,7 +818,7 @@ int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val) return err; } -int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val) +static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; s32 *sensor_settings = sd->sensor_priv; @@ -765,7 +828,7 @@ int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val) return 0; } -int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) +static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) { int err; u8 i2c_data; @@ -780,9 +843,8 @@ int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) return err; i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2)); - err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1); - return err; + return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1); } static void ov9650_dump_registers(struct sd *sd) |