1/* 2 * Support for the sensor part which is integrated (I think) into the 3 * st6422 stv06xx alike bridge, as its integrated there are no i2c writes 4 * but instead direct bridge writes. 5 * 6 * Copyright (c) 2009 Hans de Goede <hdegoede@redhat.com> 7 * 8 * Strongly based on qc-usb-messenger, which is: 9 * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher 10 * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland 11 * Copyright (c) 2002, 2003 Tuukka Toivonen 12 * 13 * This program is free software; you can redistribute it and/or modify 14 * it under the terms of the GNU General Public License as published by 15 * the Free Software Foundation; either version 2 of the License, or 16 * (at your option) any later version. 17 * 18 * This program is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * GNU General Public License for more details. 22 * 23 * You should have received a copy of the GNU General Public License 24 * along with this program; if not, write to the Free Software 25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 26 * 27 */ 28 29#include "stv06xx_st6422.h" 30 31static struct v4l2_pix_format st6422_mode[] = { 32 /* Note we actually get 124 lines of data, of which we skip the 4st 33 4 as they are garbage */ 34 { 35 162, 36 120, 37 V4L2_PIX_FMT_SGRBG8, 38 V4L2_FIELD_NONE, 39 .sizeimage = 162 * 120, 40 .bytesperline = 162, 41 .colorspace = V4L2_COLORSPACE_SRGB, 42 .priv = 1 43 }, 44 /* Note we actually get 248 lines of data, of which we skip the 4st 45 4 as they are garbage, and we tell the app it only gets the 46 first 240 of the 244 lines it actually gets, so that it ignores 47 the last 4. */ 48 { 49 324, 50 240, 51 V4L2_PIX_FMT_SGRBG8, 52 V4L2_FIELD_NONE, 53 .sizeimage = 324 * 244, 54 .bytesperline = 324, 55 .colorspace = V4L2_COLORSPACE_SRGB, 56 .priv = 0 57 }, 58}; 59 60static const struct ctrl st6422_ctrl[] = { 61#define BRIGHTNESS_IDX 0 62 { 63 { 64 .id = V4L2_CID_BRIGHTNESS, 65 .type = V4L2_CTRL_TYPE_INTEGER, 66 .name = "Brightness", 67 .minimum = 0, 68 .maximum = 31, 69 .step = 1, 70 .default_value = 3 71 }, 72 .set = st6422_set_brightness, 73 .get = st6422_get_brightness 74 }, 75#define CONTRAST_IDX 1 76 { 77 { 78 .id = V4L2_CID_CONTRAST, 79 .type = V4L2_CTRL_TYPE_INTEGER, 80 .name = "Contrast", 81 .minimum = 0, 82 .maximum = 15, 83 .step = 1, 84 .default_value = 11 85 }, 86 .set = st6422_set_contrast, 87 .get = st6422_get_contrast 88 }, 89#define GAIN_IDX 2 90 { 91 { 92 .id = V4L2_CID_GAIN, 93 .type = V4L2_CTRL_TYPE_INTEGER, 94 .name = "Gain", 95 .minimum = 0, 96 .maximum = 255, 97 .step = 1, 98 .default_value = 64 99 }, 100 .set = st6422_set_gain, 101 .get = st6422_get_gain 102 }, 103#define EXPOSURE_IDX 3 104 { 105 { 106 .id = V4L2_CID_EXPOSURE, 107 .type = V4L2_CTRL_TYPE_INTEGER, 108 .name = "Exposure", 109 .minimum = 0, 110 .maximum = 1023, 111 .step = 1, 112 .default_value = 256 113 }, 114 .set = st6422_set_exposure, 115 .get = st6422_get_exposure 116 }, 117}; 118 119static int st6422_probe(struct sd *sd) 120{ 121 int i; 122 s32 *sensor_settings; 123 124 if (sd->bridge != BRIDGE_ST6422) 125 return -ENODEV; 126 127 info("st6422 sensor detected"); 128 129 sensor_settings = kmalloc(ARRAY_SIZE(st6422_ctrl) * sizeof(s32), 130 GFP_KERNEL); 131 if (!sensor_settings) 132 return -ENOMEM; 133 134 sd->gspca_dev.cam.cam_mode = st6422_mode; 135 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(st6422_mode); 136 sd->desc.ctrls = st6422_ctrl; 137 sd->desc.nctrls = ARRAY_SIZE(st6422_ctrl); 138 sd->sensor_priv = sensor_settings; 139 140 for (i = 0; i < sd->desc.nctrls; i++) 141 sensor_settings[i] = st6422_ctrl[i].qctrl.default_value; 142 143 return 0; 144} 145 146static int st6422_init(struct sd *sd) 147{ 148 int err = 0, i; 149 150 const u16 st6422_bridge_init[][2] = { 151 { STV_ISO_ENABLE, 0x00 }, /* disable capture */ 152 { 0x1436, 0x00 }, 153 { 0x1432, 0x03 }, /* 0x00-0x1F brightness */ 154 { 0x143a, 0xF9 }, /* 0x00-0x0F contrast */ 155 { 0x0509, 0x38 }, /* R */ 156 { 0x050a, 0x38 }, /* G */ 157 { 0x050b, 0x38 }, /* B */ 158 { 0x050c, 0x2A }, 159 { 0x050d, 0x01 }, 160 161 162 { 0x1431, 0x00 }, /* 0x00-0x07 ??? */ 163 { 0x1433, 0x34 }, /* 160x120, 0x00-0x01 night filter */ 164 { 0x1438, 0x18 }, /* 640x480 */ 165/* 18 bayes */ 166/* 10 compressed? */ 167 168 { 0x1439, 0x00 }, 169/* anti-noise? 0xa2 gives a perfect image */ 170 171 { 0x143b, 0x05 }, 172 { 0x143c, 0x00 }, /* 0x00-0x01 - ??? */ 173 174 175/* shutter time 0x0000-0x03FF */ 176/* low value give good picures on moving objects (but requires much light) */ 177/* high value gives good picures in darkness (but tends to be overexposed) */ 178 { 0x143e, 0x01 }, 179 { 0x143d, 0x00 }, 180 181 { 0x1442, 0xe2 }, 182/* bit 5 == button pressed and hold if 0 */ 183/* write 0xe2,0xea */ 184 185/* 0x144a */ 186/* 0x00 init */ 187/* bit 7 == button has been pressed, but not handled */ 188 189/* interrupt */ 190/* if(urb->iso_frame_desc[i].status == 0x80) { */ 191/* if(urb->iso_frame_desc[i].status == 0x88) { */ 192 193 { 0x1500, 0xd0 }, 194 { 0x1500, 0xd0 }, 195 { 0x1500, 0x50 }, /* 0x00 - 0xFF 0x80 == compr ? */ 196 197 { 0x1501, 0xaf }, 198/* high val-> light area gets darker */ 199/* low val -> light area gets lighter */ 200 { 0x1502, 0xc2 }, 201/* high val-> light area gets darker */ 202/* low val -> light area gets lighter */ 203 { 0x1503, 0x45 }, 204/* high val-> light area gets darker */ 205/* low val -> light area gets lighter */ 206 { 0x1505, 0x02 }, 207/* 2 : 324x248 80352 bytes */ 208/* 7 : 248x162 40176 bytes */ 209/* c+f: 162*124 20088 bytes */ 210 211 { 0x150e, 0x8e }, 212 { 0x150f, 0x37 }, 213 { 0x15c0, 0x00 }, 214 { 0x15c1, 1023 }, /* 160x120, ISOC_PACKET_SIZE */ 215 { 0x15c3, 0x08 }, /* 0x04/0x14 ... test pictures ??? */ 216 217 218 { 0x143f, 0x01 }, /* commit settings */ 219 220 }; 221 222 for (i = 0; i < ARRAY_SIZE(st6422_bridge_init) && !err; i++) { 223 err = stv06xx_write_bridge(sd, st6422_bridge_init[i][0], 224 st6422_bridge_init[i][1]); 225 } 226 227 return err; 228} 229 230static void st6422_disconnect(struct sd *sd) 231{ 232 sd->sensor = NULL; 233 kfree(sd->sensor_priv); 234} 235 236static int st6422_start(struct sd *sd) 237{ 238 int err, packet_size; 239 struct cam *cam = &sd->gspca_dev.cam; 240 s32 *sensor_settings = sd->sensor_priv; 241 struct usb_host_interface *alt; 242 struct usb_interface *intf; 243 244 intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); 245 alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); 246 if (!alt) { 247 PDEBUG(D_ERR, "Couldn't get altsetting"); 248 return -EIO; 249 } 250 251 packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); 252 err = stv06xx_write_bridge(sd, 0x15c1, packet_size); 253 if (err < 0) 254 return err; 255 256 if (cam->cam_mode[sd->gspca_dev.curr_mode].priv) 257 err = stv06xx_write_bridge(sd, 0x1505, 0x0f); 258 else 259 err = stv06xx_write_bridge(sd, 0x1505, 0x02); 260 if (err < 0) 261 return err; 262 263 err = st6422_set_brightness(&sd->gspca_dev, 264 sensor_settings[BRIGHTNESS_IDX]); 265 if (err < 0) 266 return err; 267 268 err = st6422_set_contrast(&sd->gspca_dev, 269 sensor_settings[CONTRAST_IDX]); 270 if (err < 0) 271 return err; 272 273 err = st6422_set_exposure(&sd->gspca_dev, 274 sensor_settings[EXPOSURE_IDX]); 275 if (err < 0) 276 return err; 277 278 err = st6422_set_gain(&sd->gspca_dev, 279 sensor_settings[GAIN_IDX]); 280 if (err < 0) 281 return err; 282 283 PDEBUG(D_STREAM, "Starting stream"); 284 285 return 0; 286} 287 288static int st6422_stop(struct sd *sd) 289{ 290 PDEBUG(D_STREAM, "Halting stream"); 291 292 return 0; 293} 294 295static int st6422_get_brightness(struct gspca_dev *gspca_dev, __s32 *val) 296{ 297 struct sd *sd = (struct sd *) gspca_dev; 298 s32 *sensor_settings = sd->sensor_priv; 299 300 *val = sensor_settings[BRIGHTNESS_IDX]; 301 302 PDEBUG(D_V4L2, "Read brightness %d", *val); 303 304 return 0; 305} 306 307static int st6422_set_brightness(struct gspca_dev *gspca_dev, __s32 val) 308{ 309 int err; 310 struct sd *sd = (struct sd *) gspca_dev; 311 s32 *sensor_settings = sd->sensor_priv; 312 313 sensor_settings[BRIGHTNESS_IDX] = val; 314 315 if (!gspca_dev->streaming) 316 return 0; 317 318 /* val goes from 0 -> 31 */ 319 PDEBUG(D_V4L2, "Set brightness to %d", val); 320 err = stv06xx_write_bridge(sd, 0x1432, val); 321 if (err < 0) 322 return err; 323 324 /* commit settings */ 325 err = stv06xx_write_bridge(sd, 0x143f, 0x01); 326 return (err < 0) ? err : 0; 327} 328 329static int st6422_get_contrast(struct gspca_dev *gspca_dev, __s32 *val) 330{ 331 struct sd *sd = (struct sd *) gspca_dev; 332 s32 *sensor_settings = sd->sensor_priv; 333 334 *val = sensor_settings[CONTRAST_IDX]; 335 336 PDEBUG(D_V4L2, "Read contrast %d", *val); 337 338 return 0; 339} 340 341static int st6422_set_contrast(struct gspca_dev *gspca_dev, __s32 val) 342{ 343 int err; 344 struct sd *sd = (struct sd *) gspca_dev; 345 s32 *sensor_settings = sd->sensor_priv; 346 347 sensor_settings[CONTRAST_IDX] = val; 348 349 if (!gspca_dev->streaming) 350 return 0; 351 352 /* Val goes from 0 -> 15 */ 353 PDEBUG(D_V4L2, "Set contrast to %d\n", val); 354 err = stv06xx_write_bridge(sd, 0x143a, 0xf0 | val); 355 if (err < 0) 356 return err; 357 358 /* commit settings */ 359 err = stv06xx_write_bridge(sd, 0x143f, 0x01); 360 return (err < 0) ? err : 0; 361} 362 363static int st6422_get_gain(struct gspca_dev *gspca_dev, __s32 *val) 364{ 365 struct sd *sd = (struct sd *) gspca_dev; 366 s32 *sensor_settings = sd->sensor_priv; 367 368 *val = sensor_settings[GAIN_IDX]; 369 370 PDEBUG(D_V4L2, "Read gain %d", *val); 371 372 return 0; 373} 374 375static int st6422_set_gain(struct gspca_dev *gspca_dev, __s32 val) 376{ 377 int err; 378 struct sd *sd = (struct sd *) gspca_dev; 379 s32 *sensor_settings = sd->sensor_priv; 380 381 sensor_settings[GAIN_IDX] = val; 382 383 if (!gspca_dev->streaming) 384 return 0; 385 386 PDEBUG(D_V4L2, "Set gain to %d", val); 387 388 /* Set red, green, blue, gain */ 389 err = stv06xx_write_bridge(sd, 0x0509, val); 390 if (err < 0) 391 return err; 392 393 err = stv06xx_write_bridge(sd, 0x050a, val); 394 if (err < 0) 395 return err; 396 397 err = stv06xx_write_bridge(sd, 0x050b, val); 398 if (err < 0) 399 return err; 400 401 /* 2 mystery writes */ 402 err = stv06xx_write_bridge(sd, 0x050c, 0x2a); 403 if (err < 0) 404 return err; 405 406 err = stv06xx_write_bridge(sd, 0x050d, 0x01); 407 if (err < 0) 408 return err; 409 410 /* commit settings */ 411 err = stv06xx_write_bridge(sd, 0x143f, 0x01); 412 return (err < 0) ? err : 0; 413} 414 415static int st6422_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) 416{ 417 struct sd *sd = (struct sd *) gspca_dev; 418 s32 *sensor_settings = sd->sensor_priv; 419 420 *val = sensor_settings[EXPOSURE_IDX]; 421 422 PDEBUG(D_V4L2, "Read exposure %d", *val); 423 424 return 0; 425} 426 427static int st6422_set_exposure(struct gspca_dev *gspca_dev, __s32 val) 428{ 429 int err; 430 struct sd *sd = (struct sd *) gspca_dev; 431 s32 *sensor_settings = sd->sensor_priv; 432 433 sensor_settings[EXPOSURE_IDX] = val; 434 435 if (!gspca_dev->streaming) 436 return 0; 437 438 PDEBUG(D_V4L2, "Set exposure to %d\n", val); 439 err = stv06xx_write_bridge(sd, 0x143d, val & 0xff); 440 if (err < 0) 441 return err; 442 443 err = stv06xx_write_bridge(sd, 0x143e, val >> 8); 444 if (err < 0) 445 return err; 446 447 /* commit settings */ 448 err = stv06xx_write_bridge(sd, 0x143f, 0x01); 449 return (err < 0) ? err : 0; 450} 451