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