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 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * 21 * P/N 861037: Sensor HDCS1000 ASIC STV0600 22 * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 23 * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express 24 * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam 25 * P/N 861075-0040: Sensor HDCS1000 ASIC 26 * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB 27 * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web 28 */ 29 30#include "stv06xx_vv6410.h" 31 32static struct v4l2_pix_format vv6410_mode[] = { 33 { 34 356, 35 292, 36 V4L2_PIX_FMT_SGRBG8, 37 V4L2_FIELD_NONE, 38 .sizeimage = 356 * 292, 39 .bytesperline = 356, 40 .colorspace = V4L2_COLORSPACE_SRGB, 41 .priv = 0 42 } 43}; 44 45static const struct ctrl vv6410_ctrl[] = { 46#define HFLIP_IDX 0 47 { 48 { 49 .id = V4L2_CID_HFLIP, 50 .type = V4L2_CTRL_TYPE_BOOLEAN, 51 .name = "horizontal flip", 52 .minimum = 0, 53 .maximum = 1, 54 .step = 1, 55 .default_value = 0 56 }, 57 .set = vv6410_set_hflip, 58 .get = vv6410_get_hflip 59 }, 60#define VFLIP_IDX 1 61 { 62 { 63 .id = V4L2_CID_VFLIP, 64 .type = V4L2_CTRL_TYPE_BOOLEAN, 65 .name = "vertical flip", 66 .minimum = 0, 67 .maximum = 1, 68 .step = 1, 69 .default_value = 0 70 }, 71 .set = vv6410_set_vflip, 72 .get = vv6410_get_vflip 73 }, 74#define GAIN_IDX 2 75 { 76 { 77 .id = V4L2_CID_GAIN, 78 .type = V4L2_CTRL_TYPE_INTEGER, 79 .name = "analog gain", 80 .minimum = 0, 81 .maximum = 15, 82 .step = 1, 83 .default_value = 10 84 }, 85 .set = vv6410_set_analog_gain, 86 .get = vv6410_get_analog_gain 87 }, 88#define EXPOSURE_IDX 3 89 { 90 { 91 .id = V4L2_CID_EXPOSURE, 92 .type = V4L2_CTRL_TYPE_INTEGER, 93 .name = "exposure", 94 .minimum = 0, 95 .maximum = 32768, 96 .step = 1, 97 .default_value = 20000 98 }, 99 .set = vv6410_set_exposure, 100 .get = vv6410_get_exposure 101 } 102 }; 103 104static int vv6410_probe(struct sd *sd) 105{ 106 u16 data; 107 int err, i; 108 s32 *sensor_settings; 109 110 err = stv06xx_read_sensor(sd, VV6410_DEVICEH, &data); 111 if (err < 0) 112 return -ENODEV; 113 114 if (data == 0x19) { 115 info("vv6410 sensor detected"); 116 117 sensor_settings = kmalloc(ARRAY_SIZE(vv6410_ctrl) * sizeof(s32), 118 GFP_KERNEL); 119 if (!sensor_settings) 120 return -ENOMEM; 121 122 sd->gspca_dev.cam.cam_mode = vv6410_mode; 123 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(vv6410_mode); 124 sd->desc.ctrls = vv6410_ctrl; 125 sd->desc.nctrls = ARRAY_SIZE(vv6410_ctrl); 126 127 for (i = 0; i < sd->desc.nctrls; i++) 128 sensor_settings[i] = vv6410_ctrl[i].qctrl.default_value; 129 sd->sensor_priv = sensor_settings; 130 return 0; 131 } 132 return -ENODEV; 133} 134 135static int vv6410_init(struct sd *sd) 136{ 137 int err = 0, i; 138 s32 *sensor_settings = sd->sensor_priv; 139 140 for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++) { 141 /* if NULL then len contains single value */ 142 if (stv_bridge_init[i].data == NULL) { 143 err = stv06xx_write_bridge(sd, 144 stv_bridge_init[i].start, 145 stv_bridge_init[i].len); 146 } else { 147 int j; 148 for (j = 0; j < stv_bridge_init[i].len; j++) 149 err = stv06xx_write_bridge(sd, 150 stv_bridge_init[i].start + j, 151 stv_bridge_init[i].data[j]); 152 } 153 } 154 155 if (err < 0) 156 return err; 157 158 err = stv06xx_write_sensor_bytes(sd, (u8 *) vv6410_sensor_init, 159 ARRAY_SIZE(vv6410_sensor_init)); 160 if (err < 0) 161 return err; 162 163 err = vv6410_set_exposure(&sd->gspca_dev, 164 sensor_settings[EXPOSURE_IDX]); 165 if (err < 0) 166 return err; 167 168 err = vv6410_set_analog_gain(&sd->gspca_dev, 169 sensor_settings[GAIN_IDX]); 170 171 return (err < 0) ? err : 0; 172} 173 174static void vv6410_disconnect(struct sd *sd) 175{ 176 sd->sensor = NULL; 177 kfree(sd->sensor_priv); 178} 179 180static int vv6410_start(struct sd *sd) 181{ 182 int err; 183 struct cam *cam = &sd->gspca_dev.cam; 184 u32 priv = cam->cam_mode[sd->gspca_dev.curr_mode].priv; 185 186 if (priv & VV6410_CROP_TO_QVGA) { 187 PDEBUG(D_CONF, "Cropping to QVGA"); 188 stv06xx_write_sensor(sd, VV6410_XENDH, 320 - 1); 189 stv06xx_write_sensor(sd, VV6410_YENDH, 240 - 1); 190 } else { 191 stv06xx_write_sensor(sd, VV6410_XENDH, 360 - 1); 192 stv06xx_write_sensor(sd, VV6410_YENDH, 294 - 1); 193 } 194 195 if (priv & VV6410_SUBSAMPLE) { 196 PDEBUG(D_CONF, "Enabling subsampling"); 197 stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02); 198 stv06xx_write_bridge(sd, STV_X_CTRL, 0x06); 199 200 stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x10); 201 } else { 202 stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01); 203 stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a); 204 205 stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20); 206 } 207 208 /* Turn on LED */ 209 err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_ON); 210 if (err < 0) 211 return err; 212 213 err = stv06xx_write_sensor(sd, VV6410_SETUP0, 0); 214 if (err < 0) 215 return err; 216 217 PDEBUG(D_STREAM, "Starting stream"); 218 219 return 0; 220} 221 222static int vv6410_stop(struct sd *sd) 223{ 224 int err; 225 226 /* Turn off LED */ 227 err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_OFF); 228 if (err < 0) 229 return err; 230 231 err = stv06xx_write_sensor(sd, VV6410_SETUP0, VV6410_LOW_POWER_MODE); 232 if (err < 0) 233 return err; 234 235 PDEBUG(D_STREAM, "Halting stream"); 236 237 return (err < 0) ? err : 0; 238} 239 240static int vv6410_dump(struct sd *sd) 241{ 242 u8 i; 243 int err = 0; 244 245 info("Dumping all vv6410 sensor registers"); 246 for (i = 0; i < 0xff && !err; i++) { 247 u16 data; 248 err = stv06xx_read_sensor(sd, i, &data); 249 info("Register 0x%x contained 0x%x", i, data); 250 } 251 return (err < 0) ? err : 0; 252} 253 254static int vv6410_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) 255{ 256 struct sd *sd = (struct sd *) gspca_dev; 257 s32 *sensor_settings = sd->sensor_priv; 258 259 *val = sensor_settings[HFLIP_IDX]; 260 PDEBUG(D_V4L2, "Read horizontal flip %d", *val); 261 262 return 0; 263} 264 265static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val) 266{ 267 int err; 268 u16 i2c_data; 269 struct sd *sd = (struct sd *) gspca_dev; 270 s32 *sensor_settings = sd->sensor_priv; 271 272 sensor_settings[HFLIP_IDX] = val; 273 err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data); 274 if (err < 0) 275 return err; 276 277 if (val) 278 i2c_data |= VV6410_HFLIP; 279 else 280 i2c_data &= ~VV6410_HFLIP; 281 282 PDEBUG(D_V4L2, "Set horizontal flip to %d", val); 283 err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data); 284 285 return (err < 0) ? err : 0; 286} 287 288static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) 289{ 290 struct sd *sd = (struct sd *) gspca_dev; 291 s32 *sensor_settings = sd->sensor_priv; 292 293 *val = sensor_settings[VFLIP_IDX]; 294 PDEBUG(D_V4L2, "Read vertical flip %d", *val); 295 296 return 0; 297} 298 299static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val) 300{ 301 int err; 302 u16 i2c_data; 303 struct sd *sd = (struct sd *) gspca_dev; 304 s32 *sensor_settings = sd->sensor_priv; 305 306 sensor_settings[VFLIP_IDX] = val; 307 err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data); 308 if (err < 0) 309 return err; 310 311 if (val) 312 i2c_data |= VV6410_VFLIP; 313 else 314 i2c_data &= ~VV6410_VFLIP; 315 316 PDEBUG(D_V4L2, "Set vertical flip to %d", val); 317 err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data); 318 319 return (err < 0) ? err : 0; 320} 321 322static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val) 323{ 324 struct sd *sd = (struct sd *) gspca_dev; 325 s32 *sensor_settings = sd->sensor_priv; 326 327 *val = sensor_settings[GAIN_IDX]; 328 329 PDEBUG(D_V4L2, "Read analog gain %d", *val); 330 331 return 0; 332} 333 334static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val) 335{ 336 int err; 337 struct sd *sd = (struct sd *) gspca_dev; 338 s32 *sensor_settings = sd->sensor_priv; 339 340 sensor_settings[GAIN_IDX] = val; 341 PDEBUG(D_V4L2, "Set analog gain to %d", val); 342 err = stv06xx_write_sensor(sd, VV6410_ANALOGGAIN, 0xf0 | (val & 0xf)); 343 344 return (err < 0) ? err : 0; 345} 346 347static int vv6410_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) 348{ 349 struct sd *sd = (struct sd *) gspca_dev; 350 s32 *sensor_settings = sd->sensor_priv; 351 352 *val = sensor_settings[EXPOSURE_IDX]; 353 354 PDEBUG(D_V4L2, "Read exposure %d", *val); 355 356 return 0; 357} 358 359static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val) 360{ 361 int err; 362 struct sd *sd = (struct sd *) gspca_dev; 363 s32 *sensor_settings = sd->sensor_priv; 364 unsigned int fine, coarse; 365 366 sensor_settings[EXPOSURE_IDX] = val; 367 368 val = (val * val >> 14) + val / 4; 369 370 fine = val % VV6410_CIF_LINELENGTH; 371 coarse = min(512, val / VV6410_CIF_LINELENGTH); 372 373 PDEBUG(D_V4L2, "Set coarse exposure to %d, fine expsure to %d", 374 coarse, fine); 375 376 err = stv06xx_write_sensor(sd, VV6410_FINEH, fine >> 8); 377 if (err < 0) 378 goto out; 379 380 err = stv06xx_write_sensor(sd, VV6410_FINEL, fine & 0xff); 381 if (err < 0) 382 goto out; 383 384 err = stv06xx_write_sensor(sd, VV6410_COARSEH, coarse >> 8); 385 if (err < 0) 386 goto out; 387 388 err = stv06xx_write_sensor(sd, VV6410_COARSEL, coarse & 0xff); 389 390out: 391 return err; 392} 393