Merge branch 'imx-for-2.6.38' of git://git.pengutronix.de/git/ukl/linux-2.6 into...
[pandora-kernel.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 int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
22 static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
23 static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
24 static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
25 static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
26 static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
27 static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
28 static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val);
29 static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val);
30 static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val);
31 static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
32 static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
33
34 static
35     const
36         struct dmi_system_id s5k4aa_vflip_dmi_table[] = {
37         {
38                 .ident = "BRUNEINIT",
39                 .matches = {
40                         DMI_MATCH(DMI_SYS_VENDOR, "BRUNENIT"),
41                         DMI_MATCH(DMI_PRODUCT_NAME, "BRUNENIT"),
42                         DMI_MATCH(DMI_BOARD_VERSION, "00030D0000000001")
43                 }
44         }, {
45                 .ident = "Fujitsu-Siemens Amilo Xa 2528",
46                 .matches = {
47                         DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
48                         DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528")
49                 }
50         }, {
51                 .ident = "Fujitsu-Siemens Amilo Xi 2428",
52                 .matches = {
53                         DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
54                         DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2428")
55                 }
56         }, {
57                 .ident = "Fujitsu-Siemens Amilo Xi 2528",
58                 .matches = {
59                         DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
60                         DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2528")
61                 }
62         }, {
63                 .ident = "Fujitsu-Siemens Amilo Xi 2550",
64                 .matches = {
65                         DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
66                         DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550")
67                 }
68         }, {
69                 .ident = "Fujitsu-Siemens Amilo Pa 2548",
70                 .matches = {
71                         DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
72                         DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2548")
73                 }
74         }, {
75                 .ident = "MSI GX700",
76                 .matches = {
77                         DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
78                         DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
79                         DMI_MATCH(DMI_BIOS_DATE, "12/02/2008")
80                 }
81         }, {
82                 .ident = "MSI GX700",
83                 .matches = {
84                         DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
85                         DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
86                         DMI_MATCH(DMI_BIOS_DATE, "07/26/2007")
87                 }
88         }, {
89                 .ident = "MSI GX700",
90                 .matches = {
91                         DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
92                         DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
93                         DMI_MATCH(DMI_BIOS_DATE, "07/19/2007")
94                 }
95         }, {
96                 .ident = "MSI GX700/GX705/EX700",
97                 .matches = {
98                         DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
99                         DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700")
100                 }
101         }, {
102                 .ident = "MSI L735",
103                 .matches = {
104                         DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
105                         DMI_MATCH(DMI_PRODUCT_NAME, "MS-1717X")
106                 }
107         }, {
108                 .ident = "Lenovo Y300",
109                 .matches = {
110                         DMI_MATCH(DMI_SYS_VENDOR, "L3000 Y300"),
111                         DMI_MATCH(DMI_PRODUCT_NAME, "Y300")
112                 }
113         },
114         { }
115 };
116
117 static struct v4l2_pix_format s5k4aa_modes[] = {
118         {
119                 640,
120                 480,
121                 V4L2_PIX_FMT_SBGGR8,
122                 V4L2_FIELD_NONE,
123                 .sizeimage =
124                         640 * 480,
125                 .bytesperline = 640,
126                 .colorspace = V4L2_COLORSPACE_SRGB,
127                 .priv = 0
128         },
129         {
130                 1280,
131                 1024,
132                 V4L2_PIX_FMT_SBGGR8,
133                 V4L2_FIELD_NONE,
134                 .sizeimage =
135                         1280 * 1024,
136                 .bytesperline = 1280,
137                 .colorspace = V4L2_COLORSPACE_SRGB,
138                 .priv = 0
139         }
140 };
141
142 static const struct ctrl s5k4aa_ctrls[] = {
143 #define VFLIP_IDX 0
144         {
145                 {
146                         .id             = V4L2_CID_VFLIP,
147                         .type           = V4L2_CTRL_TYPE_BOOLEAN,
148                         .name           = "vertical flip",
149                         .minimum        = 0,
150                         .maximum        = 1,
151                         .step           = 1,
152                         .default_value  = 0
153                 },
154                 .set = s5k4aa_set_vflip,
155                 .get = s5k4aa_get_vflip
156         },
157 #define HFLIP_IDX 1
158         {
159                 {
160                         .id             = V4L2_CID_HFLIP,
161                         .type           = V4L2_CTRL_TYPE_BOOLEAN,
162                         .name           = "horizontal flip",
163                         .minimum        = 0,
164                         .maximum        = 1,
165                         .step           = 1,
166                         .default_value  = 0
167                 },
168                 .set = s5k4aa_set_hflip,
169                 .get = s5k4aa_get_hflip
170         },
171 #define GAIN_IDX 2
172         {
173                 {
174                         .id             = V4L2_CID_GAIN,
175                         .type           = V4L2_CTRL_TYPE_INTEGER,
176                         .name           = "Gain",
177                         .minimum        = 0,
178                         .maximum        = 127,
179                         .step           = 1,
180                         .default_value  = S5K4AA_DEFAULT_GAIN,
181                         .flags          = V4L2_CTRL_FLAG_SLIDER
182                 },
183                 .set = s5k4aa_set_gain,
184                 .get = s5k4aa_get_gain
185         },
186 #define EXPOSURE_IDX 3
187         {
188                 {
189                         .id             = V4L2_CID_EXPOSURE,
190                         .type           = V4L2_CTRL_TYPE_INTEGER,
191                         .name           = "Exposure",
192                         .minimum        = 13,
193                         .maximum        = 0xfff,
194                         .step           = 1,
195                         .default_value  = 0x100,
196                         .flags          = V4L2_CTRL_FLAG_SLIDER
197                 },
198                 .set = s5k4aa_set_exposure,
199                 .get = s5k4aa_get_exposure
200         },
201 #define NOISE_SUPP_IDX 4
202         {
203                 {
204                         .id             = V4L2_CID_PRIVATE_BASE,
205                         .type           = V4L2_CTRL_TYPE_BOOLEAN,
206                         .name           = "Noise suppression (smoothing)",
207                         .minimum        = 0,
208                         .maximum        = 1,
209                         .step           = 1,
210                         .default_value  = 1,
211                 },
212                         .set = s5k4aa_set_noise,
213                         .get = s5k4aa_get_noise
214         },
215 #define BRIGHTNESS_IDX 5
216         {
217                 {
218                         .id             = V4L2_CID_BRIGHTNESS,
219                         .type           = V4L2_CTRL_TYPE_INTEGER,
220                         .name           = "Brightness",
221                         .minimum        = 0,
222                         .maximum        = 0x1f,
223                         .step           = 1,
224                         .default_value  = S5K4AA_DEFAULT_BRIGHTNESS,
225                 },
226                         .set = s5k4aa_set_brightness,
227                         .get = s5k4aa_get_brightness
228         },
229
230 };
231
232 static void s5k4aa_dump_registers(struct sd *sd);
233
234 int s5k4aa_probe(struct sd *sd)
235 {
236         u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
237         const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
238         int i, err = 0;
239         s32 *sensor_settings;
240
241         if (force_sensor) {
242                 if (force_sensor == S5K4AA_SENSOR) {
243                         info("Forcing a %s sensor", s5k4aa.name);
244                         goto sensor_found;
245                 }
246                 /* If we want to force another sensor, don't try to probe this
247                  * one */
248                 return -ENODEV;
249         }
250
251         PDEBUG(D_PROBE, "Probing for a s5k4aa sensor");
252
253         /* Preinit the sensor */
254         for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) {
255                 u8 data[2] = {0x00, 0x00};
256
257                 switch (preinit_s5k4aa[i][0]) {
258                 case BRIDGE:
259                         err = m5602_write_bridge(sd,
260                                                  preinit_s5k4aa[i][1],
261                                                  preinit_s5k4aa[i][2]);
262                         break;
263
264                 case SENSOR:
265                         data[0] = preinit_s5k4aa[i][2];
266                         err = m5602_write_sensor(sd,
267                                                   preinit_s5k4aa[i][1],
268                                                   data, 1);
269                         break;
270
271                 case SENSOR_LONG:
272                         data[0] = preinit_s5k4aa[i][2];
273                         data[1] = preinit_s5k4aa[i][3];
274                         err = m5602_write_sensor(sd,
275                                                   preinit_s5k4aa[i][1],
276                                                   data, 2);
277                         break;
278                 default:
279                         info("Invalid stream command, exiting init");
280                         return -EINVAL;
281                 }
282         }
283
284         /* Test some registers, but we don't know their exact meaning yet */
285         if (m5602_read_sensor(sd, 0x00, prod_id, 2))
286                 return -ENODEV;
287         if (m5602_read_sensor(sd, 0x02, prod_id+2, 2))
288                 return -ENODEV;
289         if (m5602_read_sensor(sd, 0x04, prod_id+4, 2))
290                 return -ENODEV;
291
292         if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
293                 return -ENODEV;
294         else
295                 info("Detected a s5k4aa sensor");
296
297 sensor_found:
298         sensor_settings = kmalloc(
299                 ARRAY_SIZE(s5k4aa_ctrls) * sizeof(s32), GFP_KERNEL);
300         if (!sensor_settings)
301                 return -ENOMEM;
302
303         sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
304         sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
305         sd->desc->ctrls = s5k4aa_ctrls;
306         sd->desc->nctrls = ARRAY_SIZE(s5k4aa_ctrls);
307
308         for (i = 0; i < ARRAY_SIZE(s5k4aa_ctrls); i++)
309                 sensor_settings[i] = s5k4aa_ctrls[i].qctrl.default_value;
310         sd->sensor_priv = sensor_settings;
311
312         return 0;
313 }
314
315 int s5k4aa_start(struct sd *sd)
316 {
317         int i, err = 0;
318         u8 data[2];
319         struct cam *cam = &sd->gspca_dev.cam;
320         s32 *sensor_settings = sd->sensor_priv;
321
322         switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) {
323         case 1280:
324                 PDEBUG(D_V4L2, "Configuring camera for SXGA mode");
325
326                 for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) {
327                         switch (SXGA_s5k4aa[i][0]) {
328                         case BRIDGE:
329                                 err = m5602_write_bridge(sd,
330                                                  SXGA_s5k4aa[i][1],
331                                                  SXGA_s5k4aa[i][2]);
332                         break;
333
334                         case SENSOR:
335                                 data[0] = SXGA_s5k4aa[i][2];
336                                 err = m5602_write_sensor(sd,
337                                                  SXGA_s5k4aa[i][1],
338                                                  data, 1);
339                         break;
340
341                         case SENSOR_LONG:
342                                 data[0] = SXGA_s5k4aa[i][2];
343                                 data[1] = SXGA_s5k4aa[i][3];
344                                 err = m5602_write_sensor(sd,
345                                                   SXGA_s5k4aa[i][1],
346                                                   data, 2);
347                         break;
348
349                         default:
350                                 err("Invalid stream command, exiting init");
351                                 return -EINVAL;
352                         }
353                 }
354                 err = s5k4aa_set_noise(&sd->gspca_dev, 0);
355                 if (err < 0)
356                         return err;
357                 break;
358
359         case 640:
360                 PDEBUG(D_V4L2, "Configuring camera for VGA mode");
361
362                 for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) {
363                         switch (VGA_s5k4aa[i][0]) {
364                         case BRIDGE:
365                                 err = m5602_write_bridge(sd,
366                                                  VGA_s5k4aa[i][1],
367                                                  VGA_s5k4aa[i][2]);
368                         break;
369
370                         case SENSOR:
371                                 data[0] = VGA_s5k4aa[i][2];
372                                 err = m5602_write_sensor(sd,
373                                                  VGA_s5k4aa[i][1],
374                                                  data, 1);
375                         break;
376
377                         case SENSOR_LONG:
378                                 data[0] = VGA_s5k4aa[i][2];
379                                 data[1] = VGA_s5k4aa[i][3];
380                                 err = m5602_write_sensor(sd,
381                                                   VGA_s5k4aa[i][1],
382                                                   data, 2);
383                         break;
384
385                         default:
386                                 err("Invalid stream command, exiting init");
387                                 return -EINVAL;
388                         }
389                 }
390                 err = s5k4aa_set_noise(&sd->gspca_dev, 1);
391                 if (err < 0)
392                         return err;
393                 break;
394         }
395         if (err < 0)
396                 return err;
397
398         err = s5k4aa_set_exposure(&sd->gspca_dev,
399                                    sensor_settings[EXPOSURE_IDX]);
400         if (err < 0)
401                 return err;
402
403         err = s5k4aa_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
404         if (err < 0)
405                 return err;
406
407         err = s5k4aa_set_brightness(&sd->gspca_dev,
408                                      sensor_settings[BRIGHTNESS_IDX]);
409         if (err < 0)
410                 return err;
411
412         err = s5k4aa_set_noise(&sd->gspca_dev, sensor_settings[NOISE_SUPP_IDX]);
413         if (err < 0)
414                 return err;
415
416         err = s5k4aa_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
417         if (err < 0)
418                 return err;
419
420         return s5k4aa_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
421 }
422
423 int s5k4aa_init(struct sd *sd)
424 {
425         int i, err = 0;
426
427         for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) {
428                 u8 data[2] = {0x00, 0x00};
429
430                 switch (init_s5k4aa[i][0]) {
431                 case BRIDGE:
432                         err = m5602_write_bridge(sd,
433                                 init_s5k4aa[i][1],
434                                 init_s5k4aa[i][2]);
435                         break;
436
437                 case SENSOR:
438                         data[0] = init_s5k4aa[i][2];
439                         err = m5602_write_sensor(sd,
440                                 init_s5k4aa[i][1], data, 1);
441                         break;
442
443                 case SENSOR_LONG:
444                         data[0] = init_s5k4aa[i][2];
445                         data[1] = init_s5k4aa[i][3];
446                         err = m5602_write_sensor(sd,
447                                 init_s5k4aa[i][1], data, 2);
448                         break;
449                 default:
450                         info("Invalid stream command, exiting init");
451                         return -EINVAL;
452                 }
453         }
454
455         if (dump_sensor)
456                 s5k4aa_dump_registers(sd);
457
458         return err;
459 }
460
461 static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
462 {
463         struct sd *sd = (struct sd *) gspca_dev;
464         s32 *sensor_settings = sd->sensor_priv;
465
466         *val = sensor_settings[EXPOSURE_IDX];
467         PDEBUG(D_V4L2, "Read exposure %d", *val);
468
469         return 0;
470 }
471
472 static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
473 {
474         struct sd *sd = (struct sd *) gspca_dev;
475         s32 *sensor_settings = sd->sensor_priv;
476         u8 data = S5K4AA_PAGE_MAP_2;
477         int err;
478
479         sensor_settings[EXPOSURE_IDX] = val;
480         PDEBUG(D_V4L2, "Set exposure to %d", val);
481         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
482         if (err < 0)
483                 return err;
484         data = (val >> 8) & 0xff;
485         err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
486         if (err < 0)
487                 return err;
488         data = val & 0xff;
489         err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
490
491         return err;
492 }
493
494 static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
495 {
496         struct sd *sd = (struct sd *) gspca_dev;
497         s32 *sensor_settings = sd->sensor_priv;
498
499         *val = sensor_settings[VFLIP_IDX];
500         PDEBUG(D_V4L2, "Read vertical flip %d", *val);
501
502         return 0;
503 }
504
505 static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
506 {
507         struct sd *sd = (struct sd *) gspca_dev;
508         s32 *sensor_settings = sd->sensor_priv;
509         u8 data = S5K4AA_PAGE_MAP_2;
510         int err;
511
512         sensor_settings[VFLIP_IDX] = val;
513
514         PDEBUG(D_V4L2, "Set vertical flip to %d", val);
515         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
516         if (err < 0)
517                 return err;
518
519         err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
520         if (err < 0)
521                 return err;
522
523         if (dmi_check_system(s5k4aa_vflip_dmi_table))
524                 val = !val;
525
526         data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7));
527         err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
528         if (err < 0)
529                 return err;
530
531         err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
532         if (err < 0)
533                 return err;
534         if (val)
535                 data &= 0xfe;
536         else
537                 data |= 0x01;
538         err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
539         return err;
540 }
541
542 static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
543 {
544         struct sd *sd = (struct sd *) gspca_dev;
545         s32 *sensor_settings = sd->sensor_priv;
546
547         *val = sensor_settings[HFLIP_IDX];
548         PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
549
550         return 0;
551 }
552
553 static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
554 {
555         struct sd *sd = (struct sd *) gspca_dev;
556         s32 *sensor_settings = sd->sensor_priv;
557         u8 data = S5K4AA_PAGE_MAP_2;
558         int err;
559
560         sensor_settings[HFLIP_IDX] = val;
561
562         PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
563         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
564         if (err < 0)
565                 return err;
566
567         err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
568         if (err < 0)
569                 return err;
570
571         if (dmi_check_system(s5k4aa_vflip_dmi_table))
572                 val = !val;
573
574         data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
575         err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
576         if (err < 0)
577                 return err;
578
579         err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
580         if (err < 0)
581                 return err;
582         if (val)
583                 data &= 0xfe;
584         else
585                 data |= 0x01;
586         err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
587         return err;
588 }
589
590 static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
591 {
592         struct sd *sd = (struct sd *) gspca_dev;
593         s32 *sensor_settings = sd->sensor_priv;
594
595         *val = sensor_settings[GAIN_IDX];
596         PDEBUG(D_V4L2, "Read gain %d", *val);
597         return 0;
598 }
599
600 static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
601 {
602         struct sd *sd = (struct sd *) gspca_dev;
603         s32 *sensor_settings = sd->sensor_priv;
604         u8 data = S5K4AA_PAGE_MAP_2;
605         int err;
606
607         sensor_settings[GAIN_IDX] = val;
608
609         PDEBUG(D_V4L2, "Set gain to %d", val);
610         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
611         if (err < 0)
612                 return err;
613
614         data = val & 0xff;
615         err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1);
616
617         return err;
618 }
619
620 static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
621 {
622         struct sd *sd = (struct sd *) gspca_dev;
623         s32 *sensor_settings = sd->sensor_priv;
624
625         *val = sensor_settings[BRIGHTNESS_IDX];
626         PDEBUG(D_V4L2, "Read brightness %d", *val);
627         return 0;
628 }
629
630 static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
631 {
632         struct sd *sd = (struct sd *) gspca_dev;
633         s32 *sensor_settings = sd->sensor_priv;
634         u8 data = S5K4AA_PAGE_MAP_2;
635         int err;
636
637         sensor_settings[BRIGHTNESS_IDX] = val;
638
639         PDEBUG(D_V4L2, "Set brightness to %d", val);
640         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
641         if (err < 0)
642                 return err;
643
644         data = val & 0xff;
645         return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
646 }
647
648 static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val)
649 {
650         struct sd *sd = (struct sd *) gspca_dev;
651         s32 *sensor_settings = sd->sensor_priv;
652
653         *val = sensor_settings[NOISE_SUPP_IDX];
654         PDEBUG(D_V4L2, "Read noise %d", *val);
655         return 0;
656 }
657
658 static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
659 {
660         struct sd *sd = (struct sd *) gspca_dev;
661         s32 *sensor_settings = sd->sensor_priv;
662         u8 data = S5K4AA_PAGE_MAP_2;
663         int err;
664
665         sensor_settings[NOISE_SUPP_IDX] = val;
666
667         PDEBUG(D_V4L2, "Set noise to %d", val);
668         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
669         if (err < 0)
670                 return err;
671
672         data = val & 0x01;
673         return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
674 }
675
676 void s5k4aa_disconnect(struct sd *sd)
677 {
678         sd->sensor = NULL;
679         kfree(sd->sensor_priv);
680 }
681
682 static void s5k4aa_dump_registers(struct sd *sd)
683 {
684         int address;
685         u8 page, old_page;
686         m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
687         for (page = 0; page < 16; page++) {
688                 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
689                 info("Dumping the s5k4aa register state for page 0x%x", page);
690                 for (address = 0; address <= 0xff; address++) {
691                         u8 value = 0;
692                         m5602_read_sensor(sd, address, &value, 1);
693                         info("register 0x%x contains 0x%x",
694                              address, value);
695                 }
696         }
697         info("s5k4aa register state dump complete");
698
699         for (page = 0; page < 16; page++) {
700                 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
701                 info("Probing for which registers that are "
702                      "read/write for page 0x%x", page);
703                 for (address = 0; address <= 0xff; address++) {
704                         u8 old_value, ctrl_value, test_value = 0xff;
705
706                         m5602_read_sensor(sd, address, &old_value, 1);
707                         m5602_write_sensor(sd, address, &test_value, 1);
708                         m5602_read_sensor(sd, address, &ctrl_value, 1);
709
710                         if (ctrl_value == test_value)
711                                 info("register 0x%x is writeable", address);
712                         else
713                                 info("register 0x%x is read only", address);
714
715                         /* Restore original value */
716                         m5602_write_sensor(sd, address, &old_value, 1);
717                 }
718         }
719         info("Read/write register probing complete");
720         m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
721 }