Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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 /*
 31  * The spec file for the PB-0100 suggests the following for best quality
 32  * images after the sensor has been reset :
 33  *
 34  * PB_ADCGAINL      = R60 = 0x03 (3 dec)      : sets low reference of ADC
 35                                                 to produce good black level
 36  * PB_PREADCTRL     = R32 = 0x1400 (5120 dec) : Enables global gain changes
 37                                                 through R53
 38  * PB_ADCMINGAIN    = R52 = 0x10 (16 dec)     : Sets the minimum gain for
 39                                                 auto-exposure
 40  * PB_ADCGLOBALGAIN = R53 = 0x10 (16 dec)     : Sets the global gain
 41  * PB_EXPGAIN       = R14 = 0x11 (17 dec)     : Sets the auto-exposure value
 42  * PB_UPDATEINT     = R23 = 0x02 (2 dec)      : Sets the speed on
 43                                                 auto-exposure routine
 44  * PB_CFILLIN       = R5  = 0x0E (14 dec)     : Sets the frame rate
 45  */
 46 
 47 #include "stv06xx_pb0100.h"
 48 
 49 static const struct ctrl pb0100_ctrl[] = {
 50 #define GAIN_IDX 0
 51         {
 52                 {
 53                         .id             = V4L2_CID_GAIN,
 54                         .type           = V4L2_CTRL_TYPE_INTEGER,
 55                         .name           = "Gain",
 56                         .minimum        = 0,
 57                         .maximum        = 255,
 58                         .step           = 1,
 59                         .default_value  = 128
 60                 },
 61                 .set = pb0100_set_gain,
 62                 .get = pb0100_get_gain
 63         },
 64 #define RED_BALANCE_IDX 1
 65         {
 66                 {
 67                         .id             = V4L2_CID_RED_BALANCE,
 68                         .type           = V4L2_CTRL_TYPE_INTEGER,
 69                         .name           = "Red Balance",
 70                         .minimum        = -255,
 71                         .maximum        = 255,
 72                         .step           = 1,
 73                         .default_value  = 0
 74                 },
 75                 .set = pb0100_set_red_balance,
 76                 .get = pb0100_get_red_balance
 77         },
 78 #define BLUE_BALANCE_IDX 2
 79         {
 80                 {
 81                         .id             = V4L2_CID_BLUE_BALANCE,
 82                         .type           = V4L2_CTRL_TYPE_INTEGER,
 83                         .name           = "Blue Balance",
 84                         .minimum        = -255,
 85                         .maximum        = 255,
 86                         .step           = 1,
 87                         .default_value  = 0
 88                 },
 89                 .set = pb0100_set_blue_balance,
 90                 .get = pb0100_get_blue_balance
 91         },
 92 #define EXPOSURE_IDX 3
 93         {
 94                 {
 95                         .id             = V4L2_CID_EXPOSURE,
 96                         .type           = V4L2_CTRL_TYPE_INTEGER,
 97                         .name           = "Exposure",
 98                         .minimum        = 0,
 99                         .maximum        = 511,
100                         .step           = 1,
101                         .default_value  = 12
102                 },
103                 .set = pb0100_set_exposure,
104                 .get = pb0100_get_exposure
105         },
106 #define AUTOGAIN_IDX 4
107         {
108                 {
109                         .id             = V4L2_CID_AUTOGAIN,
110                         .type           = V4L2_CTRL_TYPE_BOOLEAN,
111                         .name           = "Automatic Gain and Exposure",
112                         .minimum        = 0,
113                         .maximum        = 1,
114                         .step           = 1,
115                         .default_value  = 1
116                 },
117                 .set = pb0100_set_autogain,
118                 .get = pb0100_get_autogain
119         },
120 #define AUTOGAIN_TARGET_IDX 5
121         {
122                 {
123                         .id             = V4L2_CTRL_CLASS_USER + 0x1000,
124                         .type           = V4L2_CTRL_TYPE_INTEGER,
125                         .name           = "Automatic Gain Target",
126                         .minimum        = 0,
127                         .maximum        = 255,
128                         .step           = 1,
129                         .default_value  = 128
130                 },
131                 .set = pb0100_set_autogain_target,
132                 .get = pb0100_get_autogain_target
133         },
134 #define NATURAL_IDX 6
135         {
136                 {
137                         .id             = V4L2_CTRL_CLASS_USER + 0x1001,
138                         .type           = V4L2_CTRL_TYPE_BOOLEAN,
139                         .name           = "Natural Light Source",
140                         .minimum        = 0,
141                         .maximum        = 1,
142                         .step           = 1,
143                         .default_value  = 1
144                 },
145                 .set = pb0100_set_natural,
146                 .get = pb0100_get_natural
147         }
148 };
149 
150 static struct v4l2_pix_format pb0100_mode[] = {
151 /* low res / subsample modes disabled as they are only half res horizontal,
152    halving the vertical resolution does not seem to work */
153         {
154                 320,
155                 240,
156                 V4L2_PIX_FMT_SGRBG8,
157                 V4L2_FIELD_NONE,
158                 .sizeimage = 320 * 240,
159                 .bytesperline = 320,
160                 .colorspace = V4L2_COLORSPACE_SRGB,
161                 .priv = PB0100_CROP_TO_VGA
162         },
163         {
164                 352,
165                 288,
166                 V4L2_PIX_FMT_SGRBG8,
167                 V4L2_FIELD_NONE,
168                 .sizeimage = 352 * 288,
169                 .bytesperline = 352,
170                 .colorspace = V4L2_COLORSPACE_SRGB,
171                 .priv = 0
172         }
173 };
174 
175 static int pb0100_probe(struct sd *sd)
176 {
177         u16 sensor;
178         int i, err;
179         s32 *sensor_settings;
180 
181         err = stv06xx_read_sensor(sd, PB_IDENT, &sensor);
182 
183         if (err < 0)
184                 return -ENODEV;
185 
186         if ((sensor >> 8) == 0x64) {
187                 sensor_settings = kmalloc(
188                                 ARRAY_SIZE(pb0100_ctrl) * sizeof(s32),
189                                 GFP_KERNEL);
190                 if (!sensor_settings)
191                         return -ENOMEM;
192 
193                 info("Photobit pb0100 sensor detected");
194 
195                 sd->gspca_dev.cam.cam_mode = pb0100_mode;
196                 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(pb0100_mode);
197                 sd->desc.ctrls = pb0100_ctrl;
198                 sd->desc.nctrls = ARRAY_SIZE(pb0100_ctrl);
199                 for (i = 0; i < sd->desc.nctrls; i++)
200                         sensor_settings[i] = pb0100_ctrl[i].qctrl.default_value;
201                 sd->sensor_priv = sensor_settings;
202 
203                 return 0;
204         }
205 
206         return -ENODEV;
207 }
208 
209 static int pb0100_start(struct sd *sd)
210 {
211         int err;
212         struct cam *cam = &sd->gspca_dev.cam;
213         s32 *sensor_settings = sd->sensor_priv;
214         u32 mode = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
215 
216         /* Setup sensor window */
217         if (mode & PB0100_CROP_TO_VGA) {
218                 stv06xx_write_sensor(sd, PB_RSTART, 30);
219                 stv06xx_write_sensor(sd, PB_CSTART, 20);
220                 stv06xx_write_sensor(sd, PB_RWSIZE, 240 - 1);
221                 stv06xx_write_sensor(sd, PB_CWSIZE, 320 - 1);
222         } else {
223                 stv06xx_write_sensor(sd, PB_RSTART, 8);
224                 stv06xx_write_sensor(sd, PB_CSTART, 4);
225                 stv06xx_write_sensor(sd, PB_RWSIZE, 288 - 1);
226                 stv06xx_write_sensor(sd, PB_CWSIZE, 352 - 1);
227         }
228 
229         if (mode & PB0100_SUBSAMPLE) {
230                 stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02); /* Wrong, FIXME */
231                 stv06xx_write_bridge(sd, STV_X_CTRL, 0x06);
232 
233                 stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x10);
234         } else {
235                 stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01);
236                 stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a);
237                 /* larger -> slower */
238                 stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20);
239         }
240 
241         /* set_gain also sets red and blue balance */
242         pb0100_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
243         pb0100_set_exposure(&sd->gspca_dev, sensor_settings[EXPOSURE_IDX]);
244         pb0100_set_autogain_target(&sd->gspca_dev,
245                                    sensor_settings[AUTOGAIN_TARGET_IDX]);
246         pb0100_set_autogain(&sd->gspca_dev, sensor_settings[AUTOGAIN_IDX]);
247 
248         err = stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3)|BIT(1));
249         PDEBUG(D_STREAM, "Started stream, status: %d", err);
250 
251         return (err < 0) ? err : 0;
252 }
253 
254 static int pb0100_stop(struct sd *sd)
255 {
256         int err;
257 
258         err = stv06xx_write_sensor(sd, PB_ABORTFRAME, 1);
259 
260         if (err < 0)
261                 goto out;
262 
263         /* Set bit 1 to zero */
264         err = stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3));
265 
266         PDEBUG(D_STREAM, "Halting stream");
267 out:
268         return (err < 0) ? err : 0;
269 }
270 
271 static void pb0100_disconnect(struct sd *sd)
272 {
273         sd->sensor = NULL;
274         kfree(sd->sensor_priv);
275 }
276 
277 /* FIXME: Sort the init commands out and put them into tables,
278           this is only for getting the camera to work */
279 /* FIXME: No error handling for now,
280           add this once the init has been converted to proper tables */
281 static int pb0100_init(struct sd *sd)
282 {
283         stv06xx_write_bridge(sd, STV_REG00, 1);
284         stv06xx_write_bridge(sd, STV_SCAN_RATE, 0);
285 
286         /* Reset sensor */
287         stv06xx_write_sensor(sd, PB_RESET, 1);
288         stv06xx_write_sensor(sd, PB_RESET, 0);
289 
290         /* Disable chip */
291         stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3));
292 
293         /* Gain stuff...*/
294         stv06xx_write_sensor(sd, PB_PREADCTRL, BIT(12)|BIT(10)|BIT(6));
295         stv06xx_write_sensor(sd, PB_ADCGLOBALGAIN, 12);
296 
297         /* Set up auto-exposure */
298         /* ADC VREF_HI new setting for a transition
299           from the Expose1 to the Expose2 setting */
300         stv06xx_write_sensor(sd, PB_R28, 12);
301         /* gain max for autoexposure */
302         stv06xx_write_sensor(sd, PB_ADCMAXGAIN, 180);
303         /* gain min for autoexposure  */
304         stv06xx_write_sensor(sd, PB_ADCMINGAIN, 12);
305         /* Maximum frame integration time (programmed into R8)
306            allowed for auto-exposure routine */
307         stv06xx_write_sensor(sd, PB_R54, 3);
308         /* Minimum frame integration time (programmed into R8)
309            allowed for auto-exposure routine */
310         stv06xx_write_sensor(sd, PB_R55, 0);
311         stv06xx_write_sensor(sd, PB_UPDATEINT, 1);
312         /* R15  Expose0 (maximum that auto-exposure may use) */
313         stv06xx_write_sensor(sd, PB_R15, 800);
314         /* R17  Expose2 (minimum that auto-exposure may use) */
315         stv06xx_write_sensor(sd, PB_R17, 10);
316 
317         stv06xx_write_sensor(sd, PB_EXPGAIN, 0);
318 
319         /* 0x14 */
320         stv06xx_write_sensor(sd, PB_VOFFSET, 0);
321         /* 0x0D */
322         stv06xx_write_sensor(sd, PB_ADCGAINH, 11);
323         /* Set black level (important!) */
324         stv06xx_write_sensor(sd, PB_ADCGAINL, 0);
325 
326         /* ??? */
327         stv06xx_write_bridge(sd, STV_REG00, 0x11);
328         stv06xx_write_bridge(sd, STV_REG03, 0x45);
329         stv06xx_write_bridge(sd, STV_REG04, 0x07);
330 
331         /* ISO-Size (0x27b: 635... why? - HDCS uses 847) */
332         stv06xx_write_bridge(sd, STV_ISO_SIZE_L, 847);
333 
334         /* Scan/timing for the sensor */
335         stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(4)|BIT(3)|BIT(1));
336         stv06xx_write_sensor(sd, PB_CFILLIN, 14);
337         stv06xx_write_sensor(sd, PB_VBL, 0);
338         stv06xx_write_sensor(sd, PB_FINTTIME, 0);
339         stv06xx_write_sensor(sd, PB_RINTTIME, 123);
340 
341         stv06xx_write_bridge(sd, STV_REG01, 0xc2);
342         stv06xx_write_bridge(sd, STV_REG02, 0xb0);
343         return 0;
344 }
345 
346 static int pb0100_dump(struct sd *sd)
347 {
348         return 0;
349 }
350 
351 static int pb0100_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
352 {
353         struct sd *sd = (struct sd *) gspca_dev;
354         s32 *sensor_settings = sd->sensor_priv;
355 
356         *val = sensor_settings[GAIN_IDX];
357 
358         return 0;
359 }
360 
361 static int pb0100_set_gain(struct gspca_dev *gspca_dev, __s32 val)
362 {
363         int err;
364         struct sd *sd = (struct sd *) gspca_dev;
365         s32 *sensor_settings = sd->sensor_priv;
366 
367         if (sensor_settings[AUTOGAIN_IDX])
368                 return -EBUSY;
369 
370         sensor_settings[GAIN_IDX] = val;
371         err = stv06xx_write_sensor(sd, PB_G1GAIN, val);
372         if (!err)
373                 err = stv06xx_write_sensor(sd, PB_G2GAIN, val);
374         PDEBUG(D_V4L2, "Set green gain to %d, status: %d", val, err);
375 
376         if (!err)
377                 err = pb0100_set_red_balance(gspca_dev,
378                                              sensor_settings[RED_BALANCE_IDX]);
379         if (!err)
380                 err = pb0100_set_blue_balance(gspca_dev,
381                                             sensor_settings[BLUE_BALANCE_IDX]);
382 
383         return err;
384 }
385 
386 static int pb0100_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
387 {
388         struct sd *sd = (struct sd *) gspca_dev;
389         s32 *sensor_settings = sd->sensor_priv;
390 
391         *val = sensor_settings[RED_BALANCE_IDX];
392 
393         return 0;
394 }
395 
396 static int pb0100_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
397 {
398         int err;
399         struct sd *sd = (struct sd *) gspca_dev;
400         s32 *sensor_settings = sd->sensor_priv;
401 
402         if (sensor_settings[AUTOGAIN_IDX])
403                 return -EBUSY;
404 
405         sensor_settings[RED_BALANCE_IDX] = val;
406         val += sensor_settings[GAIN_IDX];
407         if (val < 0)
408                 val = 0;
409         else if (val > 255)
410                 val = 255;
411 
412         err = stv06xx_write_sensor(sd, PB_RGAIN, val);
413         PDEBUG(D_V4L2, "Set red gain to %d, status: %d", val, err);
414 
415         return err;
416 }
417 
418 static int pb0100_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
419 {
420         struct sd *sd = (struct sd *) gspca_dev;
421         s32 *sensor_settings = sd->sensor_priv;
422 
423         *val = sensor_settings[BLUE_BALANCE_IDX];
424 
425         return 0;
426 }
427 
428 static int pb0100_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
429 {
430         int err;
431         struct sd *sd = (struct sd *) gspca_dev;
432         s32 *sensor_settings = sd->sensor_priv;
433 
434         if (sensor_settings[AUTOGAIN_IDX])
435                 return -EBUSY;
436 
437         sensor_settings[BLUE_BALANCE_IDX] = val;
438         val += sensor_settings[GAIN_IDX];
439         if (val < 0)
440                 val = 0;
441         else if (val > 255)
442                 val = 255;
443 
444         err = stv06xx_write_sensor(sd, PB_BGAIN, val);
445         PDEBUG(D_V4L2, "Set blue gain to %d, status: %d", val, err);
446 
447         return err;
448 }
449 
450 static int pb0100_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
451 {
452         struct sd *sd = (struct sd *) gspca_dev;
453         s32 *sensor_settings = sd->sensor_priv;
454 
455         *val = sensor_settings[EXPOSURE_IDX];
456 
457         return 0;
458 }
459 
460 static int pb0100_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
461 {
462         int err;
463         struct sd *sd = (struct sd *) gspca_dev;
464         s32 *sensor_settings = sd->sensor_priv;
465 
466         if (sensor_settings[AUTOGAIN_IDX])
467                 return -EBUSY;
468 
469         sensor_settings[EXPOSURE_IDX] = val;
470         err = stv06xx_write_sensor(sd, PB_RINTTIME, val);
471         PDEBUG(D_V4L2, "Set exposure to %d, status: %d", val, err);
472 
473         return err;
474 }
475 
476 static int pb0100_get_autogain(struct gspca_dev *gspca_dev, __s32 *val)
477 {
478         struct sd *sd = (struct sd *) gspca_dev;
479         s32 *sensor_settings = sd->sensor_priv;
480 
481         *val = sensor_settings[AUTOGAIN_IDX];
482 
483         return 0;
484 }
485 
486 static int pb0100_set_autogain(struct gspca_dev *gspca_dev, __s32 val)
487 {
488         int err;
489         struct sd *sd = (struct sd *) gspca_dev;
490         s32 *sensor_settings = sd->sensor_priv;
491 
492         sensor_settings[AUTOGAIN_IDX] = val;
493         if (sensor_settings[AUTOGAIN_IDX]) {
494                 if (sensor_settings[NATURAL_IDX])
495                         val = BIT(6)|BIT(4)|BIT(0);
496                 else
497                         val = BIT(4)|BIT(0);
498         } else
499                 val = 0;
500 
501         err = stv06xx_write_sensor(sd, PB_EXPGAIN, val);
502         PDEBUG(D_V4L2, "Set autogain to %d (natural: %d), status: %d",
503                sensor_settings[AUTOGAIN_IDX], sensor_settings[NATURAL_IDX],
504                err);
505 
506         return err;
507 }
508 
509 static int pb0100_get_autogain_target(struct gspca_dev *gspca_dev, __s32 *val)
510 {
511         struct sd *sd = (struct sd *) gspca_dev;
512         s32 *sensor_settings = sd->sensor_priv;
513 
514         *val = sensor_settings[AUTOGAIN_TARGET_IDX];
515 
516         return 0;
517 }
518 
519 static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val)
520 {
521         int err, totalpixels, brightpixels, darkpixels;
522         struct sd *sd = (struct sd *) gspca_dev;
523         s32 *sensor_settings = sd->sensor_priv;
524 
525         sensor_settings[AUTOGAIN_TARGET_IDX] = val;
526 
527         /* Number of pixels counted by the sensor when subsampling the pixels.
528          * Slightly larger than the real value to avoid oscillation */
529         totalpixels = gspca_dev->width * gspca_dev->height;
530         totalpixels = totalpixels/(8*8) + totalpixels/(64*64);
531 
532         brightpixels = (totalpixels * val) >> 8;
533         darkpixels   = totalpixels - brightpixels;
534         err = stv06xx_write_sensor(sd, PB_R21, brightpixels);
535         if (!err)
536                 err = stv06xx_write_sensor(sd, PB_R22, darkpixels);
537 
538         PDEBUG(D_V4L2, "Set autogain target to %d, status: %d", val, err);
539 
540         return err;
541 }
542 
543 static int pb0100_get_natural(struct gspca_dev *gspca_dev, __s32 *val)
544 {
545         struct sd *sd = (struct sd *) gspca_dev;
546         s32 *sensor_settings = sd->sensor_priv;
547 
548         *val = sensor_settings[NATURAL_IDX];
549 
550         return 0;
551 }
552 
553 static int pb0100_set_natural(struct gspca_dev *gspca_dev, __s32 val)
554 {
555         struct sd *sd = (struct sd *) gspca_dev;
556         s32 *sensor_settings = sd->sensor_priv;
557 
558         sensor_settings[NATURAL_IDX] = val;
559 
560         return pb0100_set_autogain(gspca_dev, sensor_settings[AUTOGAIN_IDX]);
561 }
562 
  This page was automatically generated by the LXR engine.