Merge branch 'oprofile-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[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
480         err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
481         if (err < 0)
482                 return err;
483
484         if (dmi_check_system(s5k4aa_vflip_dmi_table))
485                 val = !val;
486
487         data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7));
488         err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
489         if (err < 0)
490                 return err;
491
492         err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
493         if (err < 0)
494                 return err;
495         data = (data & 0xfe) | !val;
496         err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
497         return err;
498 }
499
500 static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
501 {
502         struct sd *sd = (struct sd *) gspca_dev;
503         s32 *sensor_settings = sd->sensor_priv;
504
505         *val = sensor_settings[HFLIP_IDX];
506         PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
507
508         return 0;
509 }
510
511 static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
512 {
513         struct sd *sd = (struct sd *) gspca_dev;
514         s32 *sensor_settings = sd->sensor_priv;
515         u8 data = S5K4AA_PAGE_MAP_2;
516         int err;
517
518         sensor_settings[HFLIP_IDX] = val;
519
520         PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
521         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
522         if (err < 0)
523                 return err;
524
525         err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
526         if (err < 0)
527                 return err;
528
529         if (dmi_check_system(s5k4aa_vflip_dmi_table))
530                 val = !val;
531
532         data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
533         err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
534         if (err < 0)
535                 return err;
536
537         err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
538         if (err < 0)
539                 return err;
540         data = (data & 0xfe) | !val;
541         err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
542         return err;
543 }
544
545 static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
546 {
547         struct sd *sd = (struct sd *) gspca_dev;
548         s32 *sensor_settings = sd->sensor_priv;
549
550         *val = sensor_settings[GAIN_IDX];
551         PDEBUG(D_V4L2, "Read gain %d", *val);
552         return 0;
553 }
554
555 static int s5k4aa_set_gain(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[GAIN_IDX] = val;
563
564         PDEBUG(D_V4L2, "Set gain to %d", val);
565         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
566         if (err < 0)
567                 return err;
568
569         data = val & 0xff;
570         err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1);
571
572         return err;
573 }
574
575 static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
576 {
577         struct sd *sd = (struct sd *) gspca_dev;
578         s32 *sensor_settings = sd->sensor_priv;
579
580         *val = sensor_settings[BRIGHTNESS_IDX];
581         PDEBUG(D_V4L2, "Read brightness %d", *val);
582         return 0;
583 }
584
585 static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
586 {
587         struct sd *sd = (struct sd *) gspca_dev;
588         s32 *sensor_settings = sd->sensor_priv;
589         u8 data = S5K4AA_PAGE_MAP_2;
590         int err;
591
592         sensor_settings[BRIGHTNESS_IDX] = val;
593
594         PDEBUG(D_V4L2, "Set brightness to %d", val);
595         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
596         if (err < 0)
597                 return err;
598
599         data = val & 0xff;
600         return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
601 }
602
603 static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val)
604 {
605         struct sd *sd = (struct sd *) gspca_dev;
606         s32 *sensor_settings = sd->sensor_priv;
607
608         *val = sensor_settings[NOISE_SUPP_IDX];
609         PDEBUG(D_V4L2, "Read noise %d", *val);
610         return 0;
611 }
612
613 static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
614 {
615         struct sd *sd = (struct sd *) gspca_dev;
616         s32 *sensor_settings = sd->sensor_priv;
617         u8 data = S5K4AA_PAGE_MAP_2;
618         int err;
619
620         sensor_settings[NOISE_SUPP_IDX] = val;
621
622         PDEBUG(D_V4L2, "Set noise to %d", val);
623         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
624         if (err < 0)
625                 return err;
626
627         data = val & 0x01;
628         return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
629 }
630
631 void s5k4aa_disconnect(struct sd *sd)
632 {
633         sd->sensor = NULL;
634         kfree(sd->sensor_priv);
635 }
636
637 static void s5k4aa_dump_registers(struct sd *sd)
638 {
639         int address;
640         u8 page, old_page;
641         m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
642         for (page = 0; page < 16; page++) {
643                 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
644                 info("Dumping the s5k4aa register state for page 0x%x", page);
645                 for (address = 0; address <= 0xff; address++) {
646                         u8 value = 0;
647                         m5602_read_sensor(sd, address, &value, 1);
648                         info("register 0x%x contains 0x%x",
649                              address, value);
650                 }
651         }
652         info("s5k4aa register state dump complete");
653
654         for (page = 0; page < 16; page++) {
655                 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
656                 info("Probing for which registers that are "
657                      "read/write for page 0x%x", page);
658                 for (address = 0; address <= 0xff; address++) {
659                         u8 old_value, ctrl_value, test_value = 0xff;
660
661                         m5602_read_sensor(sd, address, &old_value, 1);
662                         m5602_write_sensor(sd, address, &test_value, 1);
663                         m5602_read_sensor(sd, address, &ctrl_value, 1);
664
665                         if (ctrl_value == test_value)
666                                 info("register 0x%x is writeable", address);
667                         else
668                                 info("register 0x%x is read only", address);
669
670                         /* Restore original value */
671                         m5602_write_sensor(sd, address, &old_value, 1);
672                 }
673         }
674         info("Read/write register probing complete");
675         m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
676 }