diff options
Diffstat (limited to 'drivers/media/video/gspca/ov519.c')
-rw-r--r-- | drivers/media/video/gspca/ov519.c | 151 |
1 files changed, 130 insertions, 21 deletions
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index b4f96573124..bc4ced6c013 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c @@ -38,6 +38,7 @@ */ #define MODULE_NAME "ov519" +#include <linux/input.h> #include "gspca.h" MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>"); @@ -70,6 +71,9 @@ struct sd { char invert_led; #define BRIDGE_INVERT_LED 8 + char snapshot_pressed; + char snapshot_needs_reset; + /* Determined by sensor type */ __u8 sif; @@ -99,10 +103,12 @@ struct sd { #define SEN_OV66308AF 5 #define SEN_OV7610 6 #define SEN_OV7620 7 -#define SEN_OV7640 8 -#define SEN_OV7670 9 -#define SEN_OV76BE 10 -#define SEN_OV8610 11 +#define SEN_OV7620AE 8 +#define SEN_OV7640 9 +#define SEN_OV7648 10 +#define SEN_OV7670 11 +#define SEN_OV76BE 12 +#define SEN_OV8610 13 u8 sensor_addr; int sensor_width; @@ -139,6 +145,7 @@ static void setautobrightness(struct sd *sd); static void setfreq(struct sd *sd); static const struct ctrl sd_ctrls[] = { +#define BRIGHTNESS_IDX 0 { { .id = V4L2_CID_BRIGHTNESS, @@ -153,6 +160,7 @@ static const struct ctrl sd_ctrls[] = { .set = sd_setbrightness, .get = sd_getbrightness, }, +#define CONTRAST_IDX 1 { { .id = V4L2_CID_CONTRAST, @@ -167,6 +175,7 @@ static const struct ctrl sd_ctrls[] = { .set = sd_setcontrast, .get = sd_getcontrast, }, +#define COLOR_IDX 2 { { .id = V4L2_CID_SATURATION, @@ -2554,7 +2563,7 @@ static int ov7xx0_configure(struct sd *sd) /* I don't know what's different about the 76BE yet. */ if (i2c_r(sd, 0x15) & 1) { PDEBUG(D_PROBE, "Sensor is an OV7620AE"); - sd->sensor = SEN_OV7620; + sd->sensor = SEN_OV7620AE; } else { PDEBUG(D_PROBE, "Sensor is an OV76BE"); sd->sensor = SEN_OV76BE; @@ -2588,7 +2597,7 @@ static int ov7xx0_configure(struct sd *sd) break; case 0x48: PDEBUG(D_PROBE, "Sensor is an OV7648"); - sd->sensor = SEN_OV7640; /* FIXME */ + sd->sensor = SEN_OV7648; break; default: PDEBUG(D_PROBE, "Unknown sensor: 0x76%x", low); @@ -2680,6 +2689,36 @@ static void ov51x_led_control(struct sd *sd, int on) } } +static void sd_reset_snapshot(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (!sd->snapshot_needs_reset) + return; + + /* Note it is important that we clear sd->snapshot_needs_reset, + before actually clearing the snapshot state in the bridge + otherwise we might race with the pkt_scan interrupt handler */ + sd->snapshot_needs_reset = 0; + + switch (sd->bridge) { + case BRIDGE_OV511: + case BRIDGE_OV511PLUS: + reg_w(sd, R51x_SYS_SNAP, 0x02); + reg_w(sd, R51x_SYS_SNAP, 0x00); + break; + case BRIDGE_OV518: + case BRIDGE_OV518PLUS: + reg_w(sd, R51x_SYS_SNAP, 0x02); /* Reset */ + reg_w(sd, R51x_SYS_SNAP, 0x01); /* Enable */ + break; + case BRIDGE_OV519: + reg_w(sd, R51x_SYS_RESET, 0x40); + reg_w(sd, R51x_SYS_RESET, 0x00); + break; + } +} + static int ov51x_upload_quan_tables(struct sd *sd) { const unsigned char yQuanTable511[] = { @@ -3115,7 +3154,11 @@ static int sd_config(struct gspca_dev *gspca_dev, (1 << OV7670_FREQ_IDX); } sd->quality = QUALITY_DEF; - if (sd->sensor == SEN_OV7640 || sd->sensor == SEN_OV7670) + if (sd->sensor == SEN_OV7640 || + sd->sensor == SEN_OV7648) + gspca_dev->ctrl_dis |= (1 << AUTOBRIGHT_IDX) | + (1 << CONTRAST_IDX); + if (sd->sensor == SEN_OV7670) gspca_dev->ctrl_dis |= 1 << AUTOBRIGHT_IDX; /* OV8610 Frequency filter control should work but needs testing */ if (sd->sensor == SEN_OV8610) @@ -3169,10 +3212,12 @@ static int sd_init(struct gspca_dev *gspca_dev) return -EIO; break; case SEN_OV7620: + case SEN_OV7620AE: if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620))) return -EIO; break; case SEN_OV7640: + case SEN_OV7648: if (write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640))) return -EIO; break; @@ -3246,7 +3291,9 @@ static int ov511_mode_init_regs(struct sd *sd) /* Note once the FIXME's in mode_init_ov_sensor_regs() are fixed for more sensors we need to do this for them too */ case SEN_OV7620: + case SEN_OV7620AE: case SEN_OV7640: + case SEN_OV7648: case SEN_OV76BE: if (sd->gspca_dev.width == 320) interlaced = 1; @@ -3377,7 +3424,7 @@ static int ov518_mode_init_regs(struct sd *sd) if (sd->bridge == BRIDGE_OV518PLUS) { switch (sd->sensor) { - case SEN_OV7620: + case SEN_OV7620AE: if (sd->gspca_dev.width == 320) { reg_w(sd, 0x20, 0x00); reg_w(sd, 0x21, 0x19); @@ -3386,6 +3433,10 @@ static int ov518_mode_init_regs(struct sd *sd) reg_w(sd, 0x21, 0x1f); } break; + case SEN_OV7620: + reg_w(sd, 0x20, 0x00); + reg_w(sd, 0x21, 0x19); + break; default: reg_w(sd, 0x21, 0x19); } @@ -3488,7 +3539,8 @@ static int ov519_mode_init_regs(struct sd *sd) if (write_regvals(sd, mode_init_519, ARRAY_SIZE(mode_init_519))) return -EIO; - if (sd->sensor == SEN_OV7640) { + if (sd->sensor == SEN_OV7640 || + sd->sensor == SEN_OV7648) { /* Select 8-bit input mode */ reg_w_mask(sd, OV519_R20_DFR, 0x10, 0x10); } @@ -3503,6 +3555,9 @@ static int ov519_mode_init_regs(struct sd *sd) if (sd->sensor == SEN_OV7670 && sd->gspca_dev.cam.cam_mode[sd->gspca_dev.curr_mode].priv) reg_w(sd, OV519_R12_X_OFFSETL, 0x04); + else if (sd->sensor == SEN_OV7648 && + sd->gspca_dev.cam.cam_mode[sd->gspca_dev.curr_mode].priv) + reg_w(sd, OV519_R12_X_OFFSETL, 0x01); else reg_w(sd, OV519_R12_X_OFFSETL, 0x00); reg_w(sd, OV519_R13_X_OFFSETH, 0x00); @@ -3520,6 +3575,7 @@ static int ov519_mode_init_regs(struct sd *sd) sd->clockdiv = 0; switch (sd->sensor) { case SEN_OV7640: + case SEN_OV7648: switch (sd->frame_rate) { default: /* case 30: */ @@ -3649,6 +3705,7 @@ static int mode_init_ov_sensor_regs(struct sd *sd) i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */ break; case SEN_OV7620: + case SEN_OV7620AE: case SEN_OV76BE: i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20); @@ -3663,13 +3720,16 @@ static int mode_init_ov_sensor_regs(struct sd *sd) i2c_w(sd, 0x35, qvga ? 0x1e : 0x9e); break; case SEN_OV7640: + case SEN_OV7648: i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20); -/* i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a); */ -/* i2c_w(sd, 0x25, qvga ? 0x30 : 0x60); */ -/* i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40); */ -/* i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0); */ -/* i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20); */ + /* Setting this undocumented bit in qvga mode removes a very + annoying vertical shaking of the image */ + i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40); + /* Unknown */ + i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0); + /* Allow higher automatic gain (to allow higher framerates) */ + i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20); i2c_w_mask(sd, 0x12, 0x04, 0x04); /* AWB: 1 */ break; case SEN_OV7670: @@ -3795,11 +3855,13 @@ static int set_ov_sensor_window(struct sd *sd) } break; case SEN_OV7620: + case SEN_OV7620AE: hwsbase = 0x2f; /* From 7620.SET (spec is wrong) */ hwebase = 0x2f; vwsbase = vwebase = 0x05; break; case SEN_OV7640: + case SEN_OV7648: hwsbase = 0x1a; hwebase = 0x1a; vwsbase = vwebase = 0x03; @@ -3893,6 +3955,12 @@ static int sd_start(struct gspca_dev *gspca_dev) setautobrightness(sd); setfreq(sd); + /* Force clear snapshot state in case the snapshot button was + pressed while we weren't streaming */ + sd->snapshot_needs_reset = 1; + sd_reset_snapshot(gspca_dev); + sd->snapshot_pressed = 0; + ret = ov51x_restart(sd); if (ret < 0) goto out; @@ -3919,6 +3987,34 @@ static void sd_stop0(struct gspca_dev *gspca_dev) w9968cf_stop0(sd); } +static void ov51x_handle_button(struct gspca_dev *gspca_dev, u8 state) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->snapshot_pressed != state) { +#ifdef CONFIG_INPUT + input_report_key(gspca_dev->input_dev, KEY_CAMERA, state); + input_sync(gspca_dev->input_dev); +#endif + if (state) + sd->snapshot_needs_reset = 1; + + sd->snapshot_pressed = state; + } else { + /* On the ov511 / ov519 we need to reset the button state + multiple times, as resetting does not work as long as the + button stays pressed */ + switch (sd->bridge) { + case BRIDGE_OV511: + case BRIDGE_OV511PLUS: + case BRIDGE_OV519: + if (state) + sd->snapshot_needs_reset = 1; + break; + } + } +} + static void ov511_pkt_scan(struct gspca_dev *gspca_dev, u8 *in, /* isoc packet */ int len) /* iso packet length */ @@ -3940,6 +4036,7 @@ static void ov511_pkt_scan(struct gspca_dev *gspca_dev, */ if (!(in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) && (in[8] & 0x08)) { + ov51x_handle_button(gspca_dev, (in[8] >> 2) & 1); if (in[8] & 0x80) { /* Frame end */ if ((in[9] + 1) * 8 != gspca_dev->width || @@ -3977,6 +4074,7 @@ static void ov518_pkt_scan(struct gspca_dev *gspca_dev, /* A false positive here is likely, until OVT gives me * the definitive SOF/EOF format */ if ((!(data[0] | data[1] | data[2] | data[3] | data[5])) && data[6]) { + ov51x_handle_button(gspca_dev, (data[6] >> 1) & 1); gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0); sd->packet_nr = 0; @@ -4024,6 +4122,9 @@ static void ov519_pkt_scan(struct gspca_dev *gspca_dev, if (data[0] == 0xff && data[1] == 0xff && data[2] == 0xff) { switch (data[3]) { case 0x50: /* start of frame */ + /* Don't check the button state here, as the state + usually (always ?) changes at EOF and checking it + here leads to unnecessary snapshot state resets. */ #define HDRSZ 16 data += HDRSZ; len -= HDRSZ; @@ -4035,6 +4136,7 @@ static void ov519_pkt_scan(struct gspca_dev *gspca_dev, gspca_dev->last_packet_type = DISCARD_PACKET; return; case 0x51: /* end of frame */ + ov51x_handle_button(gspca_dev, data[11] & 1); if (data[9] != 0) gspca_dev->last_packet_type = DISCARD_PACKET; gspca_frame_add(gspca_dev, LAST_PACKET, @@ -4103,9 +4205,11 @@ static void setbrightness(struct gspca_dev *gspca_dev) case SEN_OV6630: case SEN_OV66308AF: case SEN_OV7640: + case SEN_OV7648: i2c_w(sd, OV7610_REG_BRT, val); break; case SEN_OV7620: + case SEN_OV7620AE: /* 7620 doesn't like manual changes when in auto mode */ if (!sd->autobrightness) i2c_w(sd, OV7610_REG_BRT, val); @@ -4142,7 +4246,8 @@ static void setcontrast(struct gspca_dev *gspca_dev) i2c_w(sd, 0x64, ctab[val >> 5]); break; } - case SEN_OV7620: { + case SEN_OV7620: + case SEN_OV7620AE: { static const __u8 ctab[] = { 0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57, 0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff @@ -4152,10 +4257,6 @@ static void setcontrast(struct gspca_dev *gspca_dev) i2c_w(sd, 0x64, ctab[val >> 4]); break; } - case SEN_OV7640: - /* Use gain control instead. */ - i2c_w(sd, OV7610_REG_GAIN, val >> 2); - break; case SEN_OV7670: /* check that this isn't just the same as ov7610 */ i2c_w(sd, OV7670_REG_CONTRAS, val >> 1); @@ -4179,6 +4280,7 @@ static void setcolors(struct gspca_dev *gspca_dev) i2c_w(sd, OV7610_REG_SAT, val); break; case SEN_OV7620: + case SEN_OV7620AE: /* Use UV gamma control instead. Bits 0 & 7 are reserved. */ /* rc = ov_i2c_write(sd->dev, 0x62, (val >> 9) & 0x7e); if (rc < 0) @@ -4186,6 +4288,7 @@ static void setcolors(struct gspca_dev *gspca_dev) i2c_w(sd, OV7610_REG_SAT, val); break; case SEN_OV7640: + case SEN_OV7648: i2c_w(sd, OV7610_REG_SAT, val & 0xf0); break; case SEN_OV7670: @@ -4198,7 +4301,8 @@ static void setcolors(struct gspca_dev *gspca_dev) static void setautobrightness(struct sd *sd) { - if (sd->sensor == SEN_OV7640 || sd->sensor == SEN_OV7670 || + if (sd->sensor == SEN_OV7640 || sd->sensor == SEN_OV7648 || + sd->sensor == SEN_OV7670 || sd->sensor == SEN_OV2610 || sd->sensor == SEN_OV3610) return; @@ -4475,9 +4579,13 @@ static const struct sd_desc sd_desc = { .stopN = sd_stopN, .stop0 = sd_stop0, .pkt_scan = sd_pkt_scan, + .dq_callback = sd_reset_snapshot, .querymenu = sd_querymenu, .get_jcomp = sd_get_jcomp, .set_jcomp = sd_set_jcomp, +#ifdef CONFIG_INPUT + .other_input = 1, +#endif }; /* -- module initialisation -- */ @@ -4494,7 +4602,8 @@ static const __devinitdata struct usb_device_id device_table[] = { .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, {USB_DEVICE(0x045e, 0x028c), .driver_info = BRIDGE_OV519 }, {USB_DEVICE(0x054c, 0x0154), .driver_info = BRIDGE_OV519 }, - {USB_DEVICE(0x054c, 0x0155), .driver_info = BRIDGE_OV519 }, + {USB_DEVICE(0x054c, 0x0155), + .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED }, {USB_DEVICE(0x05a9, 0x0511), .driver_info = BRIDGE_OV511 }, {USB_DEVICE(0x05a9, 0x0518), .driver_info = BRIDGE_OV518 }, {USB_DEVICE(0x05a9, 0x0519), .driver_info = BRIDGE_OV519 }, |