Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-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 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         if (val)
529                 data &= 0xfe;
530         else
531                 data |= 0x01;
532         err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
533         return err;
534 }
535
536 static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
537 {
538         struct sd *sd = (struct sd *) gspca_dev;
539         s32 *sensor_settings = sd->sensor_priv;
540
541         *val = sensor_settings[HFLIP_IDX];
542         PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
543
544         return 0;
545 }
546
547 static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
548 {
549         struct sd *sd = (struct sd *) gspca_dev;
550         s32 *sensor_settings = sd->sensor_priv;
551         u8 data = S5K4AA_PAGE_MAP_2;
552         int err;
553
554         sensor_settings[HFLIP_IDX] = val;
555
556         PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
557         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
558         if (err < 0)
559                 return err;
560
561         err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
562         if (err < 0)
563                 return err;
564
565         if (dmi_check_system(s5k4aa_vflip_dmi_table))
566                 val = !val;
567
568         data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
569         err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
570         if (err < 0)
571                 return err;
572
573         err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
574         if (err < 0)
575                 return err;
576         if (val)
577                 data &= 0xfe;
578         else
579                 data |= 0x01;
580         err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
581         return err;
582 }
583
584 static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
585 {
586         struct sd *sd = (struct sd *) gspca_dev;
587         s32 *sensor_settings = sd->sensor_priv;
588
589         *val = sensor_settings[GAIN_IDX];
590         PDEBUG(D_V4L2, "Read gain %d", *val);
591         return 0;
592 }
593
594 static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
595 {
596         struct sd *sd = (struct sd *) gspca_dev;
597         s32 *sensor_settings = sd->sensor_priv;
598         u8 data = S5K4AA_PAGE_MAP_2;
599         int err;
600
601         sensor_settings[GAIN_IDX] = val;
602
603         PDEBUG(D_V4L2, "Set gain to %d", val);
604         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
605         if (err < 0)
606                 return err;
607
608         data = val & 0xff;
609         err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1);
610
611         return err;
612 }
613
614 static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
615 {
616         struct sd *sd = (struct sd *) gspca_dev;
617         s32 *sensor_settings = sd->sensor_priv;
618
619         *val = sensor_settings[BRIGHTNESS_IDX];
620         PDEBUG(D_V4L2, "Read brightness %d", *val);
621         return 0;
622 }
623
624 static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
625 {
626         struct sd *sd = (struct sd *) gspca_dev;
627         s32 *sensor_settings = sd->sensor_priv;
628         u8 data = S5K4AA_PAGE_MAP_2;
629         int err;
630
631         sensor_settings[BRIGHTNESS_IDX] = val;
632
633         PDEBUG(D_V4L2, "Set brightness to %d", val);
634         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
635         if (err < 0)
636                 return err;
637
638         data = val & 0xff;
639         return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
640 }
641
642 static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val)
643 {
644         struct sd *sd = (struct sd *) gspca_dev;
645         s32 *sensor_settings = sd->sensor_priv;
646
647         *val = sensor_settings[NOISE_SUPP_IDX];
648         PDEBUG(D_V4L2, "Read noise %d", *val);
649         return 0;
650 }
651
652 static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
653 {
654         struct sd *sd = (struct sd *) gspca_dev;
655         s32 *sensor_settings = sd->sensor_priv;
656         u8 data = S5K4AA_PAGE_MAP_2;
657         int err;
658
659         sensor_settings[NOISE_SUPP_IDX] = val;
660
661         PDEBUG(D_V4L2, "Set noise to %d", val);
662         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
663         if (err < 0)
664                 return err;
665
666         data = val & 0x01;
667         return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
668 }
669
670 void s5k4aa_disconnect(struct sd *sd)
671 {
672         sd->sensor = NULL;
673         kfree(sd->sensor_priv);
674 }
675
676 static void s5k4aa_dump_registers(struct sd *sd)
677 {
678         int address;
679         u8 page, old_page;
680         m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
681         for (page = 0; page < 16; page++) {
682                 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
683                 info("Dumping the s5k4aa register state for page 0x%x", page);
684                 for (address = 0; address <= 0xff; address++) {
685                         u8 value = 0;
686                         m5602_read_sensor(sd, address, &value, 1);
687                         info("register 0x%x contains 0x%x",
688                              address, value);
689                 }
690         }
691         info("s5k4aa register state dump complete");
692
693         for (page = 0; page < 16; page++) {
694                 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
695                 info("Probing for which registers that are "
696                      "read/write for page 0x%x", page);
697                 for (address = 0; address <= 0xff; address++) {
698                         u8 old_value, ctrl_value, test_value = 0xff;
699
700                         m5602_read_sensor(sd, address, &old_value, 1);
701                         m5602_write_sensor(sd, address, &test_value, 1);
702                         m5602_read_sensor(sd, address, &ctrl_value, 1);
703
704                         if (ctrl_value == test_value)
705                                 info("register 0x%x is writeable", address);
706                         else
707                                 info("register 0x%x is read only", address);
708
709                         /* Restore original value */
710                         m5602_write_sensor(sd, address, &old_value, 1);
711                 }
712         }
713         info("Read/write register probing complete");
714         m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
715 }