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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 30 31#include "stv06xx_st6422.h" 32 33/* controls */ 34enum e_ctrl { 35 BRIGHTNESS, 36 CONTRAST, 37 GAIN, 38 EXPOSURE, 39 NCTRLS /* number of controls */ 40}; 41 42/* sensor settings */ 43struct st6422_settings { 44 struct gspca_ctrl ctrls[NCTRLS]; 45}; 46 47static struct v4l2_pix_format st6422_mode[] = { 48 /* Note we actually get 124 lines of data, of which we skip the 4st 49 4 as they are garbage */ 50 { 51 162, 52 120, 53 V4L2_PIX_FMT_SGRBG8, 54 V4L2_FIELD_NONE, 55 .sizeimage = 162 * 120, 56 .bytesperline = 162, 57 .colorspace = V4L2_COLORSPACE_SRGB, 58 .priv = 1 59 }, 60 /* Note we actually get 248 lines of data, of which we skip the 4st 61 4 as they are garbage, and we tell the app it only gets the 62 first 240 of the 244 lines it actually gets, so that it ignores 63 the last 4. */ 64 { 65 324, 66 240, 67 V4L2_PIX_FMT_SGRBG8, 68 V4L2_FIELD_NONE, 69 .sizeimage = 324 * 244, 70 .bytesperline = 324, 71 .colorspace = V4L2_COLORSPACE_SRGB, 72 .priv = 0 73 }, 74}; 75 76/* V4L2 controls supported by the driver */ 77static void st6422_set_brightness(struct gspca_dev *gspca_dev); 78static void st6422_set_contrast(struct gspca_dev *gspca_dev); 79static void st6422_set_gain(struct gspca_dev *gspca_dev); 80static void st6422_set_exposure(struct gspca_dev *gspca_dev); 81 82static const struct ctrl st6422_ctrl[NCTRLS] = { 83[BRIGHTNESS] = { 84 { 85 .id = V4L2_CID_BRIGHTNESS, 86 .type = V4L2_CTRL_TYPE_INTEGER, 87 .name = "Brightness", 88 .minimum = 0, 89 .maximum = 31, 90 .step = 1, 91 .default_value = 3 92 }, 93 .set_control = st6422_set_brightness 94 }, 95[CONTRAST] = { 96 { 97 .id = V4L2_CID_CONTRAST, 98 .type = V4L2_CTRL_TYPE_INTEGER, 99 .name = "Contrast", 100 .minimum = 0, 101 .maximum = 15, 102 .step = 1, 103 .default_value = 11 104 }, 105 .set_control = st6422_set_contrast 106 }, 107[GAIN] = { 108 { 109 .id = V4L2_CID_GAIN, 110 .type = V4L2_CTRL_TYPE_INTEGER, 111 .name = "Gain", 112 .minimum = 0, 113 .maximum = 255, 114 .step = 1, 115 .default_value = 64 116 }, 117 .set_control = st6422_set_gain 118 }, 119[EXPOSURE] = { 120 { 121 .id = V4L2_CID_EXPOSURE, 122 .type = V4L2_CTRL_TYPE_INTEGER, 123 .name = "Exposure", 124 .minimum = 0, 125#define EXPOSURE_MAX 1023 126 .maximum = EXPOSURE_MAX, 127 .step = 1, 128 .default_value = 256 129 }, 130 .set_control = st6422_set_exposure 131 }, 132}; 133 134static int st6422_probe(struct sd *sd) 135{ 136 struct st6422_settings *sensor_settings; 137 138 if (sd->bridge != BRIDGE_ST6422) 139 return -ENODEV; 140 141 pr_info("st6422 sensor detected\n"); 142 143 sensor_settings = kmalloc(sizeof *sensor_settings, GFP_KERNEL); 144 if (!sensor_settings) 145 return -ENOMEM; 146 147 sd->gspca_dev.cam.cam_mode = st6422_mode; 148 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(st6422_mode); 149 sd->gspca_dev.cam.ctrls = sensor_settings->ctrls; 150 sd->desc.ctrls = st6422_ctrl; 151 sd->desc.nctrls = ARRAY_SIZE(st6422_ctrl); 152 sd->sensor_priv = sensor_settings; 153 154 return 0; 155} 156 157static int st6422_init(struct sd *sd) 158{ 159 int err = 0, i; 160 161 const u16 st6422_bridge_init[][2] = { 162 { STV_ISO_ENABLE, 0x00 }, /* disable capture */ 163 { 0x1436, 0x00 }, 164 { 0x1432, 0x03 }, /* 0x00-0x1F brightness */ 165 { 0x143a, 0xf9 }, /* 0x00-0x0F contrast */ 166 { 0x0509, 0x38 }, /* R */ 167 { 0x050a, 0x38 }, /* G */ 168 { 0x050b, 0x38 }, /* B */ 169 { 0x050c, 0x2a }, 170 { 0x050d, 0x01 }, 171 172 173 { 0x1431, 0x00 }, /* 0x00-0x07 ??? */ 174 { 0x1433, 0x34 }, /* 160x120, 0x00-0x01 night filter */ 175 { 0x1438, 0x18 }, /* 640x480 */ 176/* 18 bayes */ 177/* 10 compressed? */ 178 179 { 0x1439, 0x00 }, 180/* anti-noise? 0xa2 gives a perfect image */ 181 182 { 0x143b, 0x05 }, 183 { 0x143c, 0x00 }, /* 0x00-0x01 - ??? */ 184 185 186/* shutter time 0x0000-0x03FF */ 187/* low value give good picures on moving objects (but requires much light) */ 188/* high value gives good picures in darkness (but tends to be overexposed) */ 189 { 0x143e, 0x01 }, 190 { 0x143d, 0x00 }, 191 192 { 0x1442, 0xe2 }, 193/* write: 1x1x xxxx */ 194/* read: 1x1x xxxx */ 195/* bit 5 == button pressed and hold if 0 */ 196/* write 0xe2,0xea */ 197 198/* 0x144a */ 199/* 0x00 init */ 200/* bit 7 == button has been pressed, but not handled */ 201 202/* interrupt */ 203/* if(urb->iso_frame_desc[i].status == 0x80) { */ 204/* if(urb->iso_frame_desc[i].status == 0x88) { */ 205 206 { 0x1500, 0xd0 }, 207 { 0x1500, 0xd0 }, 208 { 0x1500, 0x50 }, /* 0x00 - 0xFF 0x80 == compr ? */ 209 210 { 0x1501, 0xaf }, 211/* high val-> light area gets darker */ 212/* low val -> light area gets lighter */ 213 { 0x1502, 0xc2 }, 214/* high val-> light area gets darker */ 215/* low val -> light area gets lighter */ 216 { 0x1503, 0x45 }, 217/* high val-> light area gets darker */ 218/* low val -> light area gets lighter */ 219 { 0x1505, 0x02 }, 220/* 2 : 324x248 80352 bytes */ 221/* 7 : 248x162 40176 bytes */ 222/* c+f: 162*124 20088 bytes */ 223 224 { 0x150e, 0x8e }, 225 { 0x150f, 0x37 }, 226 { 0x15c0, 0x00 }, 227 { 0x15c3, 0x08 }, /* 0x04/0x14 ... test pictures ??? */ 228 229 230 { 0x143f, 0x01 }, /* commit settings */ 231 232 }; 233 234 for (i = 0; i < ARRAY_SIZE(st6422_bridge_init) && !err; i++) { 235 err = stv06xx_write_bridge(sd, st6422_bridge_init[i][0], 236 st6422_bridge_init[i][1]); 237 } 238 239 return err; 240} 241 242static void st6422_disconnect(struct sd *sd) 243{ 244 sd->sensor = NULL; 245 kfree(sd->sensor_priv); 246} 247 248static int setbrightness(struct sd *sd) 249{ 250 struct st6422_settings *sensor_settings = sd->sensor_priv; 251 252 /* val goes from 0 -> 31 */ 253 return stv06xx_write_bridge(sd, 0x1432, 254 sensor_settings->ctrls[BRIGHTNESS].val); 255} 256 257static int setcontrast(struct sd *sd) 258{ 259 struct st6422_settings *sensor_settings = sd->sensor_priv; 260 261 /* Val goes from 0 -> 15 */ 262 return stv06xx_write_bridge(sd, 0x143a, 263 sensor_settings->ctrls[CONTRAST].val | 0xf0); 264} 265 266static int setgain(struct sd *sd) 267{ 268 struct st6422_settings *sensor_settings = sd->sensor_priv; 269 u8 gain; 270 int err; 271 272 gain = sensor_settings->ctrls[GAIN].val; 273 274 /* Set red, green, blue, gain */ 275 err = stv06xx_write_bridge(sd, 0x0509, gain); 276 if (err < 0) 277 return err; 278 279 err = stv06xx_write_bridge(sd, 0x050a, gain); 280 if (err < 0) 281 return err; 282 283 err = stv06xx_write_bridge(sd, 0x050b, gain); 284 if (err < 0) 285 return err; 286 287 /* 2 mystery writes */ 288 err = stv06xx_write_bridge(sd, 0x050c, 0x2a); 289 if (err < 0) 290 return err; 291 292 return stv06xx_write_bridge(sd, 0x050d, 0x01); 293} 294 295static int setexposure(struct sd *sd) 296{ 297 struct st6422_settings *sensor_settings = sd->sensor_priv; 298 u16 expo; 299 int err; 300 301 expo = sensor_settings->ctrls[EXPOSURE].val; 302 err = stv06xx_write_bridge(sd, 0x143d, expo & 0xff); 303 if (err < 0) 304 return err; 305 306 return stv06xx_write_bridge(sd, 0x143e, expo >> 8); 307} 308 309static int st6422_start(struct sd *sd) 310{ 311 int err; 312 struct cam *cam = &sd->gspca_dev.cam; 313 314 if (cam->cam_mode[sd->gspca_dev.curr_mode].priv) 315 err = stv06xx_write_bridge(sd, 0x1505, 0x0f); 316 else 317 err = stv06xx_write_bridge(sd, 0x1505, 0x02); 318 if (err < 0) 319 return err; 320 321 err = setbrightness(sd); 322 if (err < 0) 323 return err; 324 325 err = setcontrast(sd); 326 if (err < 0) 327 return err; 328 329 err = setexposure(sd); 330 if (err < 0) 331 return err; 332 333 err = setgain(sd); 334 if (err < 0) 335 return err; 336 337 /* commit settings */ 338 err = stv06xx_write_bridge(sd, 0x143f, 0x01); 339 return (err < 0) ? err : 0; 340} 341 342static int st6422_stop(struct sd *sd) 343{ 344 PDEBUG(D_STREAM, "Halting stream"); 345 346 return 0; 347} 348 349static void st6422_set_brightness(struct gspca_dev *gspca_dev) 350{ 351 int err; 352 struct sd *sd = (struct sd *) gspca_dev; 353 354 err = setbrightness(sd); 355 356 /* commit settings */ 357 if (err >= 0) 358 err = stv06xx_write_bridge(sd, 0x143f, 0x01); 359 360 gspca_dev->usb_err = err; 361} 362 363static void st6422_set_contrast(struct gspca_dev *gspca_dev) 364{ 365 int err; 366 struct sd *sd = (struct sd *) gspca_dev; 367 368 err = setcontrast(sd); 369 370 /* commit settings */ 371 if (err >= 0) 372 err = stv06xx_write_bridge(sd, 0x143f, 0x01); 373 374 gspca_dev->usb_err = err; 375} 376 377static void st6422_set_gain(struct gspca_dev *gspca_dev) 378{ 379 int err; 380 struct sd *sd = (struct sd *) gspca_dev; 381 382 err = setgain(sd); 383 384 /* commit settings */ 385 if (err >= 0) 386 err = stv06xx_write_bridge(sd, 0x143f, 0x01); 387 388 gspca_dev->usb_err = err; 389} 390 391static void st6422_set_exposure(struct gspca_dev *gspca_dev) 392{ 393 int err; 394 struct sd *sd = (struct sd *) gspca_dev; 395 396 err = setexposure(sd); 397 398 /* commit settings */ 399 if (err >= 0) 400 err = stv06xx_write_bridge(sd, 0x143f, 0x01); 401 402 gspca_dev->usb_err = err; 403} 404