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