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