Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-2.6
[sfrench/cifs-2.6.git] / drivers / media / video / gspca / m5602 / m5602_s5k4aa.c
1 /*
2  * Driver for the s5k4aa sensor
3  *
4  * Copyright (C) 2008 Erik AndrĂ©n
5  * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
6  * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
7  *
8  * Portions of code to USB interface and ALi driver software,
9  * Copyright (c) 2006 Willem Duinker
10  * v4l2 interface modeled after the V4L2 driver
11  * for SN9C10x PC Camera Controllers
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License as
15  * published by the Free Software Foundation, version 2.
16  *
17  */
18
19 #include "m5602_s5k4aa.h"
20
21 static
22     const
23         struct dmi_system_id s5k4aa_vflip_dmi_table[] = {
24         {
25                 .ident = "Fujitsu-Siemens Amilo Xa 2528",
26                 .matches = {
27                         DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
28                         DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528")
29                 }
30         }, {
31                 .ident = "Fujitsu-Siemens Amilo Xi 2550",
32                 .matches = {
33                         DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
34                         DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550")
35                 }
36         }, {
37                 .ident = "MSI GX700",
38                 .matches = {
39                         DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
40                         DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
41                         DMI_MATCH(DMI_BIOS_DATE, "07/26/2007")
42                 }
43         }, {
44                 .ident = "MSI GX700/GX705/EX700",
45                 .matches = {
46                         DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
47                         DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700")
48                 }
49         },
50         { }
51 };
52
53 static struct v4l2_pix_format s5k4aa_modes[] = {
54         {
55                 640,
56                 480,
57                 V4L2_PIX_FMT_SBGGR8,
58                 V4L2_FIELD_NONE,
59                 .sizeimage =
60                         640 * 480,
61                 .bytesperline = 640,
62                 .colorspace = V4L2_COLORSPACE_SRGB,
63                 .priv = 0
64         }
65 };
66
67 const static struct ctrl s5k4aa_ctrls[] = {
68         {
69                 {
70                         .id             = V4L2_CID_VFLIP,
71                         .type           = V4L2_CTRL_TYPE_BOOLEAN,
72                         .name           = "vertical flip",
73                         .minimum        = 0,
74                         .maximum        = 1,
75                         .step           = 1,
76                         .default_value  = 0
77                 },
78                 .set = s5k4aa_set_vflip,
79                 .get = s5k4aa_get_vflip
80
81         }, {
82                 {
83                         .id             = V4L2_CID_HFLIP,
84                         .type           = V4L2_CTRL_TYPE_BOOLEAN,
85                         .name           = "horizontal flip",
86                         .minimum        = 0,
87                         .maximum        = 1,
88                         .step           = 1,
89                         .default_value  = 0
90                 },
91                 .set = s5k4aa_set_hflip,
92                 .get = s5k4aa_get_hflip
93
94         }, {
95                 {
96                         .id             = V4L2_CID_GAIN,
97                         .type           = V4L2_CTRL_TYPE_INTEGER,
98                         .name           = "Gain",
99                         .minimum        = 0,
100                         .maximum        = 127,
101                         .step           = 1,
102                         .default_value  = 0xa0,
103                         .flags          = V4L2_CTRL_FLAG_SLIDER
104                 },
105                 .set = s5k4aa_set_gain,
106                 .get = s5k4aa_get_gain
107         }, {
108                 {
109                         .id             = V4L2_CID_EXPOSURE,
110                         .type           = V4L2_CTRL_TYPE_INTEGER,
111                         .name           = "Exposure",
112                         .minimum        = 13,
113                         .maximum        = 0xfff,
114                         .step           = 1,
115                         .default_value  = 0x100,
116                         .flags          = V4L2_CTRL_FLAG_SLIDER
117                 },
118                 .set = s5k4aa_set_exposure,
119                 .get = s5k4aa_get_exposure
120         }
121 };
122
123 static void s5k4aa_dump_registers(struct sd *sd);
124
125 int s5k4aa_probe(struct sd *sd)
126 {
127         u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
128         const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
129         int i, err = 0;
130
131         if (force_sensor) {
132                 if (force_sensor == S5K4AA_SENSOR) {
133                         info("Forcing a %s sensor", s5k4aa.name);
134                         goto sensor_found;
135                 }
136                 /* If we want to force another sensor, don't try to probe this
137                  * one */
138                 return -ENODEV;
139         }
140
141         info("Probing for a s5k4aa sensor");
142
143         /* Preinit the sensor */
144         for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) {
145                 u8 data[2] = {0x00, 0x00};
146
147                 switch (preinit_s5k4aa[i][0]) {
148                 case BRIDGE:
149                         err = m5602_write_bridge(sd,
150                                                  preinit_s5k4aa[i][1],
151                                                  preinit_s5k4aa[i][2]);
152                         break;
153
154                 case SENSOR:
155                         data[0] = preinit_s5k4aa[i][2];
156                         err = m5602_write_sensor(sd,
157                                                   preinit_s5k4aa[i][1],
158                                                   data, 1);
159                         break;
160
161                 case SENSOR_LONG:
162                         data[0] = preinit_s5k4aa[i][2];
163                         data[1] = preinit_s5k4aa[i][3];
164                         err = m5602_write_sensor(sd,
165                                                   preinit_s5k4aa[i][1],
166                                                   data, 2);
167                         break;
168                 default:
169                         info("Invalid stream command, exiting init");
170                         return -EINVAL;
171                 }
172         }
173
174         /* Test some registers, but we don't know their exact meaning yet */
175         if (m5602_read_sensor(sd, 0x00, prod_id, 2))
176                 return -ENODEV;
177         if (m5602_read_sensor(sd, 0x02, prod_id+2, 2))
178                 return -ENODEV;
179         if (m5602_read_sensor(sd, 0x04, prod_id+4, 2))
180                 return -ENODEV;
181
182         if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
183                 return -ENODEV;
184         else
185                 info("Detected a s5k4aa sensor");
186
187 sensor_found:
188         sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
189         sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
190         sd->desc->ctrls = s5k4aa_ctrls;
191         sd->desc->nctrls = ARRAY_SIZE(s5k4aa_ctrls);
192         return 0;
193 }
194
195 int s5k4aa_start(struct sd *sd)
196 {
197         int i, err = 0;
198         u8 data[2];
199         struct cam *cam = &sd->gspca_dev.cam;
200
201         switch (cam->cam_mode[sd->gspca_dev.curr_mode].width)
202         {
203         case 640:
204                 PDEBUG(D_V4L2, "Configuring camera for VGA mode");
205
206                 for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) {
207                         switch (VGA_s5k4aa[i][0]) {
208                         case BRIDGE:
209                                 err = m5602_write_bridge(sd,
210                                                  VGA_s5k4aa[i][1],
211                                                  VGA_s5k4aa[i][2]);
212                         break;
213
214                         case SENSOR:
215                                 data[0] = VGA_s5k4aa[i][2];
216                                 err = m5602_write_sensor(sd,
217                                                  VGA_s5k4aa[i][1],
218                                                  data, 1);
219                         break;
220
221                         case SENSOR_LONG:
222                                 data[0] = VGA_s5k4aa[i][2];
223                                 data[1] = VGA_s5k4aa[i][3];
224                                 err = m5602_write_sensor(sd,
225                                                   VGA_s5k4aa[i][1],
226                                                   data, 2);
227                         break;
228
229                         default:
230                                 err("Invalid stream command, exiting init");
231                                 return -EINVAL;
232                         }
233                 }
234         }
235         return err;
236 }
237
238 int s5k4aa_init(struct sd *sd)
239 {
240         int i, err = 0;
241
242         for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) {
243                 u8 data[2] = {0x00, 0x00};
244
245                 switch (init_s5k4aa[i][0]) {
246                 case BRIDGE:
247                         err = m5602_write_bridge(sd,
248                                 init_s5k4aa[i][1],
249                                 init_s5k4aa[i][2]);
250                         break;
251
252                 case SENSOR:
253                         data[0] = init_s5k4aa[i][2];
254                         err = m5602_write_sensor(sd,
255                                 init_s5k4aa[i][1], data, 1);
256                         break;
257
258                 case SENSOR_LONG:
259                         data[0] = init_s5k4aa[i][2];
260                         data[1] = init_s5k4aa[i][3];
261                         err = m5602_write_sensor(sd,
262                                 init_s5k4aa[i][1], data, 2);
263                         break;
264                 default:
265                         info("Invalid stream command, exiting init");
266                         return -EINVAL;
267                 }
268         }
269
270         if (dump_sensor)
271                 s5k4aa_dump_registers(sd);
272
273         if (!err && dmi_check_system(s5k4aa_vflip_dmi_table)) {
274                 u8 data = 0x02;
275                 info("vertical flip quirk active");
276                 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
277                 m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
278                 data |= S5K4AA_RM_V_FLIP;
279                 data &= ~S5K4AA_RM_H_FLIP;
280                 m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
281
282                 /* Decrement COLSTART to preserve color order (BGGR) */
283                 m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
284                 data--;
285                 m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
286
287                 /* Increment ROWSTART to preserve color order (BGGR) */
288                 m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
289                 data++;
290                 m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
291         }
292
293         return (err < 0) ? err : 0;
294 }
295
296 int s5k4aa_power_down(struct sd *sd)
297 {
298         return 0;
299 }
300
301 int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
302 {
303         struct sd *sd = (struct sd *) gspca_dev;
304         u8 data = S5K4AA_PAGE_MAP_2;
305         int err;
306
307         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
308         if (err < 0)
309                 return err;
310
311         err = m5602_read_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
312         if (err < 0)
313                 return err;
314
315         *val = data << 8;
316         err = m5602_read_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
317         *val |= data;
318         PDEBUG(D_V4L2, "Read exposure %d", *val);
319
320         return err;
321 }
322
323 int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
324 {
325         struct sd *sd = (struct sd *) gspca_dev;
326         u8 data = S5K4AA_PAGE_MAP_2;
327         int err;
328
329         PDEBUG(D_V4L2, "Set exposure to %d", val);
330         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
331         if (err < 0)
332                 return err;
333         data = (val >> 8) & 0xff;
334         err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
335         if (err < 0)
336                 return err;
337         data = val & 0xff;
338         err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
339
340         return err;
341 }
342
343 int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
344 {
345         struct sd *sd = (struct sd *) gspca_dev;
346         u8 data = S5K4AA_PAGE_MAP_2;
347         int err;
348
349         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
350         if (err < 0)
351                 return err;
352
353         err = m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
354         *val = (data & S5K4AA_RM_V_FLIP) >> 7;
355         PDEBUG(D_V4L2, "Read vertical flip %d", *val);
356
357         return err;
358 }
359
360 int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
361 {
362         struct sd *sd = (struct sd *) gspca_dev;
363         u8 data = S5K4AA_PAGE_MAP_2;
364         int err;
365
366         PDEBUG(D_V4L2, "Set vertical flip to %d", val);
367         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
368         if (err < 0)
369                 return err;
370         err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
371         if (err < 0)
372                 return err;
373         data = ((data & ~S5K4AA_RM_V_FLIP)
374                         | ((val & 0x01) << 7));
375         err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
376         if (err < 0)
377                 return err;
378
379         if (val) {
380                 err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
381                 if (err < 0)
382                         return err;
383
384                 data++;
385                 err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
386         } else {
387                 err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
388                 if (err < 0)
389                         return err;
390
391                 data--;
392                 err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
393         }
394
395         return err;
396 }
397
398 int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
399 {
400         struct sd *sd = (struct sd *) gspca_dev;
401         u8 data = S5K4AA_PAGE_MAP_2;
402         int err;
403
404         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
405         if (err < 0)
406                 return err;
407
408         err = m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
409         *val = (data & S5K4AA_RM_H_FLIP) >> 6;
410         PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
411
412         return err;
413 }
414
415 int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
416 {
417         struct sd *sd = (struct sd *) gspca_dev;
418         u8 data = S5K4AA_PAGE_MAP_2;
419         int err;
420
421         PDEBUG(D_V4L2, "Set horizontal flip to %d",
422                val);
423         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
424         if (err < 0)
425                 return err;
426         err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
427         if (err < 0)
428                 return err;
429
430         data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
431         err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
432         if (err < 0)
433                 return err;
434
435         if (val) {
436                 err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
437                 if (err < 0)
438                         return err;
439                 data++;
440                 err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
441                 if (err < 0)
442                         return err;
443         } else {
444                 err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
445                 if (err < 0)
446                         return err;
447                 data--;
448                 err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
449         }
450
451         return err;
452 }
453
454 int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
455 {
456         struct sd *sd = (struct sd *) gspca_dev;
457         u8 data = S5K4AA_PAGE_MAP_2;
458         int err;
459
460         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
461         if (err < 0)
462                 return err;
463
464         err = m5602_read_sensor(sd, S5K4AA_GAIN_2, &data, 1);
465         *val = data;
466         PDEBUG(D_V4L2, "Read gain %d", *val);
467
468         return err;
469 }
470
471 int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
472 {
473         struct sd *sd = (struct sd *) gspca_dev;
474         u8 data = S5K4AA_PAGE_MAP_2;
475         int err;
476
477         PDEBUG(D_V4L2, "Set gain to %d", val);
478         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
479         if (err < 0)
480                 return err;
481
482         data = val & 0xff;
483         err = m5602_write_sensor(sd, S5K4AA_GAIN_2, &data, 1);
484
485         return err;
486 }
487
488 static void s5k4aa_dump_registers(struct sd *sd)
489 {
490         int address;
491         u8 page, old_page;
492         m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
493         for (page = 0; page < 16; page++) {
494                 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
495                 info("Dumping the s5k4aa register state for page 0x%x", page);
496                 for (address = 0; address <= 0xff; address++) {
497                         u8 value = 0;
498                         m5602_read_sensor(sd, address, &value, 1);
499                         info("register 0x%x contains 0x%x",
500                              address, value);
501                 }
502         }
503         info("s5k4aa register state dump complete");
504
505         for (page = 0; page < 16; page++) {
506                 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
507                 info("Probing for which registers that are "
508                      "read/write for page 0x%x", page);
509                 for (address = 0; address <= 0xff; address++) {
510                         u8 old_value, ctrl_value, test_value = 0xff;
511
512                         m5602_read_sensor(sd, address, &old_value, 1);
513                         m5602_write_sensor(sd, address, &test_value, 1);
514                         m5602_read_sensor(sd, address, &ctrl_value, 1);
515
516                         if (ctrl_value == test_value)
517                                 info("register 0x%x is writeable", address);
518                         else
519                                 info("register 0x%x is read only", address);
520
521                         /* Restore original value */
522                         m5602_write_sensor(sd, address, &old_value, 1);
523                 }
524         }
525         info("Read/write register probing complete");
526         m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
527 }