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