1 /* 2 * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher 3 * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland 4 * Copyright (c) 2002, 2003 Tuukka Toivonen 5 * Copyright (c) 2008 Erik Andrén 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * P/N 861037: Sensor HDCS1000 ASIC STV0600 18 * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 19 * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express 20 * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam 21 * P/N 861075-0040: Sensor HDCS1000 ASIC 22 * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB 23 * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web 24 */ 25 26 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 27 28 #include "stv06xx_vv6410.h" 29 30 static struct v4l2_pix_format vv6410_mode[] = { 31 { 32 356, 33 292, 34 V4L2_PIX_FMT_SGRBG8, 35 V4L2_FIELD_NONE, 36 .sizeimage = 356 * 292, 37 .bytesperline = 356, 38 .colorspace = V4L2_COLORSPACE_SRGB, 39 .priv = 0 40 } 41 }; 42 43 static int vv6410_s_ctrl(struct v4l2_ctrl *ctrl) 44 { 45 struct gspca_dev *gspca_dev = 46 container_of(ctrl->handler, struct gspca_dev, ctrl_handler); 47 int err = -EINVAL; 48 49 switch (ctrl->id) { 50 case V4L2_CID_HFLIP: 51 if (!gspca_dev->streaming) 52 return 0; 53 err = vv6410_set_hflip(gspca_dev, ctrl->val); 54 break; 55 case V4L2_CID_VFLIP: 56 if (!gspca_dev->streaming) 57 return 0; 58 err = vv6410_set_vflip(gspca_dev, ctrl->val); 59 break; 60 case V4L2_CID_GAIN: 61 err = vv6410_set_analog_gain(gspca_dev, ctrl->val); 62 break; 63 case V4L2_CID_EXPOSURE: 64 err = vv6410_set_exposure(gspca_dev, ctrl->val); 65 break; 66 } 67 return err; 68 } 69 70 static const struct v4l2_ctrl_ops vv6410_ctrl_ops = { 71 .s_ctrl = vv6410_s_ctrl, 72 }; 73 74 static int vv6410_probe(struct sd *sd) 75 { 76 u16 data; 77 int err; 78 79 err = stv06xx_read_sensor(sd, VV6410_DEVICEH, &data); 80 if (err < 0) 81 return -ENODEV; 82 83 if (data != 0x19) 84 return -ENODEV; 85 86 pr_info("vv6410 sensor detected\n"); 87 88 sd->gspca_dev.cam.cam_mode = vv6410_mode; 89 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(vv6410_mode); 90 return 0; 91 } 92 93 static int vv6410_init_controls(struct sd *sd) 94 { 95 struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler; 96 97 v4l2_ctrl_handler_init(hdl, 2); 98 /* Disable the hardware VFLIP and HFLIP as we currently lack a 99 mechanism to adjust the image offset in such a way that 100 we don't need to renegotiate the announced format */ 101 /* v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops, */ 102 /* V4L2_CID_HFLIP, 0, 1, 1, 0); */ 103 /* v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops, */ 104 /* V4L2_CID_VFLIP, 0, 1, 1, 0); */ 105 v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops, 106 V4L2_CID_EXPOSURE, 0, 32768, 1, 20000); 107 v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops, 108 V4L2_CID_GAIN, 0, 15, 1, 10); 109 return hdl->error; 110 } 111 112 static int vv6410_init(struct sd *sd) 113 { 114 int err = 0, i; 115 116 for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++) 117 stv06xx_write_bridge(sd, stv_bridge_init[i].addr, stv_bridge_init[i].data); 118 119 err = stv06xx_write_sensor_bytes(sd, (u8 *) vv6410_sensor_init, 120 ARRAY_SIZE(vv6410_sensor_init)); 121 return (err < 0) ? err : 0; 122 } 123 124 static int vv6410_start(struct sd *sd) 125 { 126 int err; 127 struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; 128 struct cam *cam = &sd->gspca_dev.cam; 129 u32 priv = cam->cam_mode[sd->gspca_dev.curr_mode].priv; 130 131 if (priv & VV6410_SUBSAMPLE) { 132 gspca_dbg(gspca_dev, D_CONF, "Enabling subsampling\n"); 133 stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02); 134 stv06xx_write_bridge(sd, STV_X_CTRL, 0x06); 135 136 stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x10); 137 } else { 138 stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01); 139 stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a); 140 stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x00); 141 142 } 143 144 /* Turn on LED */ 145 err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_ON); 146 if (err < 0) 147 return err; 148 149 err = stv06xx_write_sensor(sd, VV6410_SETUP0, 0); 150 if (err < 0) 151 return err; 152 153 gspca_dbg(gspca_dev, D_STREAM, "Starting stream\n"); 154 155 return 0; 156 } 157 158 static int vv6410_stop(struct sd *sd) 159 { 160 struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; 161 int err; 162 163 /* Turn off LED */ 164 err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_OFF); 165 if (err < 0) 166 return err; 167 168 err = stv06xx_write_sensor(sd, VV6410_SETUP0, VV6410_LOW_POWER_MODE); 169 if (err < 0) 170 return err; 171 172 gspca_dbg(gspca_dev, D_STREAM, "Halting stream\n"); 173 174 return 0; 175 } 176 177 static int vv6410_dump(struct sd *sd) 178 { 179 u8 i; 180 int err = 0; 181 182 pr_info("Dumping all vv6410 sensor registers\n"); 183 for (i = 0; i < 0xff && !err; i++) { 184 u16 data; 185 err = stv06xx_read_sensor(sd, i, &data); 186 pr_info("Register 0x%x contained 0x%x\n", i, data); 187 } 188 return (err < 0) ? err : 0; 189 } 190 191 static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val) 192 { 193 int err; 194 u16 i2c_data; 195 struct sd *sd = (struct sd *) gspca_dev; 196 197 err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data); 198 if (err < 0) 199 return err; 200 201 if (val) 202 i2c_data |= VV6410_HFLIP; 203 else 204 i2c_data &= ~VV6410_HFLIP; 205 206 gspca_dbg(gspca_dev, D_CONF, "Set horizontal flip to %d\n", val); 207 err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data); 208 209 return (err < 0) ? err : 0; 210 } 211 212 static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val) 213 { 214 int err; 215 u16 i2c_data; 216 struct sd *sd = (struct sd *) gspca_dev; 217 218 err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data); 219 if (err < 0) 220 return err; 221 222 if (val) 223 i2c_data |= VV6410_VFLIP; 224 else 225 i2c_data &= ~VV6410_VFLIP; 226 227 gspca_dbg(gspca_dev, D_CONF, "Set vertical flip to %d\n", val); 228 err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data); 229 230 return (err < 0) ? err : 0; 231 } 232 233 static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val) 234 { 235 int err; 236 struct sd *sd = (struct sd *) gspca_dev; 237 238 gspca_dbg(gspca_dev, D_CONF, "Set analog gain to %d\n", val); 239 err = stv06xx_write_sensor(sd, VV6410_ANALOGGAIN, 0xf0 | (val & 0xf)); 240 241 return (err < 0) ? err : 0; 242 } 243 244 static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val) 245 { 246 int err; 247 struct sd *sd = (struct sd *) gspca_dev; 248 unsigned int fine, coarse; 249 250 val = (val * val >> 14) + val / 4; 251 252 fine = val % VV6410_CIF_LINELENGTH; 253 coarse = min(512, val / VV6410_CIF_LINELENGTH); 254 255 gspca_dbg(gspca_dev, D_CONF, "Set coarse exposure to %d, fine exposure to %d\n", 256 coarse, fine); 257 258 err = stv06xx_write_sensor(sd, VV6410_FINEH, fine >> 8); 259 if (err < 0) 260 goto out; 261 262 err = stv06xx_write_sensor(sd, VV6410_FINEL, fine & 0xff); 263 if (err < 0) 264 goto out; 265 266 err = stv06xx_write_sensor(sd, VV6410_COARSEH, coarse >> 8); 267 if (err < 0) 268 goto out; 269 270 err = stv06xx_write_sensor(sd, VV6410_COARSEL, coarse & 0xff); 271 272 out: 273 return err; 274 } 275