e5fed5b89ff43573e5387bd6727028c1a07b35f3
[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         { }
70 };
71
72 static struct v4l2_pix_format s5k4aa_modes[] = {
73         {
74                 640,
75                 480,
76                 V4L2_PIX_FMT_SBGGR8,
77                 V4L2_FIELD_NONE,
78                 .sizeimage =
79                         640 * 480,
80                 .bytesperline = 640,
81                 .colorspace = V4L2_COLORSPACE_SRGB,
82                 .priv = 0
83         },
84         {
85                 1280,
86                 1024,
87                 V4L2_PIX_FMT_SBGGR8,
88                 V4L2_FIELD_NONE,
89                 .sizeimage =
90                         1280 * 1024,
91                 .bytesperline = 1280,
92                 .colorspace = V4L2_COLORSPACE_SRGB,
93                 .priv = 0
94         }
95 };
96
97 static const struct ctrl s5k4aa_ctrls[] = {
98 #define VFLIP_IDX 0
99         {
100                 {
101                         .id             = V4L2_CID_VFLIP,
102                         .type           = V4L2_CTRL_TYPE_BOOLEAN,
103                         .name           = "vertical flip",
104                         .minimum        = 0,
105                         .maximum        = 1,
106                         .step           = 1,
107                         .default_value  = 0
108                 },
109                 .set = s5k4aa_set_vflip,
110                 .get = s5k4aa_get_vflip
111         },
112 #define HFLIP_IDX 1
113         {
114                 {
115                         .id             = V4L2_CID_HFLIP,
116                         .type           = V4L2_CTRL_TYPE_BOOLEAN,
117                         .name           = "horizontal flip",
118                         .minimum        = 0,
119                         .maximum        = 1,
120                         .step           = 1,
121                         .default_value  = 0
122                 },
123                 .set = s5k4aa_set_hflip,
124                 .get = s5k4aa_get_hflip
125         },
126 #define GAIN_IDX 2
127         {
128                 {
129                         .id             = V4L2_CID_GAIN,
130                         .type           = V4L2_CTRL_TYPE_INTEGER,
131                         .name           = "Gain",
132                         .minimum        = 0,
133                         .maximum        = 127,
134                         .step           = 1,
135                         .default_value  = S5K4AA_DEFAULT_GAIN,
136                         .flags          = V4L2_CTRL_FLAG_SLIDER
137                 },
138                 .set = s5k4aa_set_gain,
139                 .get = s5k4aa_get_gain
140         },
141 #define EXPOSURE_IDX 3
142         {
143                 {
144                         .id             = V4L2_CID_EXPOSURE,
145                         .type           = V4L2_CTRL_TYPE_INTEGER,
146                         .name           = "Exposure",
147                         .minimum        = 13,
148                         .maximum        = 0xfff,
149                         .step           = 1,
150                         .default_value  = 0x100,
151                         .flags          = V4L2_CTRL_FLAG_SLIDER
152                 },
153                 .set = s5k4aa_set_exposure,
154                 .get = s5k4aa_get_exposure
155         },
156 #define NOISE_SUPP_IDX 4
157         {
158                 {
159                         .id             = V4L2_CID_PRIVATE_BASE,
160                         .type           = V4L2_CTRL_TYPE_BOOLEAN,
161                         .name           = "Noise suppression (smoothing)",
162                         .minimum        = 0,
163                         .maximum        = 1,
164                         .step           = 1,
165                         .default_value  = 1,
166                 },
167                         .set = s5k4aa_set_noise,
168                         .get = s5k4aa_get_noise
169         },
170 #define BRIGHTNESS_IDX 5
171         {
172                 {
173                         .id             = V4L2_CID_BRIGHTNESS,
174                         .type           = V4L2_CTRL_TYPE_INTEGER,
175                         .name           = "Brightness",
176                         .minimum        = 0,
177                         .maximum        = 0x1f,
178                         .step           = 1,
179                         .default_value  = S5K4AA_DEFAULT_BRIGHTNESS,
180                 },
181                         .set = s5k4aa_set_brightness,
182                         .get = s5k4aa_get_brightness
183         },
184
185 };
186
187 static void s5k4aa_dump_registers(struct sd *sd);
188
189 int s5k4aa_probe(struct sd *sd)
190 {
191         u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
192         const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
193         int i, err = 0;
194         s32 *sensor_settings;
195
196         if (force_sensor) {
197                 if (force_sensor == S5K4AA_SENSOR) {
198                         info("Forcing a %s sensor", s5k4aa.name);
199                         goto sensor_found;
200                 }
201                 /* If we want to force another sensor, don't try to probe this
202                  * one */
203                 return -ENODEV;
204         }
205
206         info("Probing for a s5k4aa sensor");
207
208         /* Preinit the sensor */
209         for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) {
210                 u8 data[2] = {0x00, 0x00};
211
212                 switch (preinit_s5k4aa[i][0]) {
213                 case BRIDGE:
214                         err = m5602_write_bridge(sd,
215                                                  preinit_s5k4aa[i][1],
216                                                  preinit_s5k4aa[i][2]);
217                         break;
218
219                 case SENSOR:
220                         data[0] = preinit_s5k4aa[i][2];
221                         err = m5602_write_sensor(sd,
222                                                   preinit_s5k4aa[i][1],
223                                                   data, 1);
224                         break;
225
226                 case SENSOR_LONG:
227                         data[0] = preinit_s5k4aa[i][2];
228                         data[1] = preinit_s5k4aa[i][3];
229                         err = m5602_write_sensor(sd,
230                                                   preinit_s5k4aa[i][1],
231                                                   data, 2);
232                         break;
233                 default:
234                         info("Invalid stream command, exiting init");
235                         return -EINVAL;
236                 }
237         }
238
239         /* Test some registers, but we don't know their exact meaning yet */
240         if (m5602_read_sensor(sd, 0x00, prod_id, 2))
241                 return -ENODEV;
242         if (m5602_read_sensor(sd, 0x02, prod_id+2, 2))
243                 return -ENODEV;
244         if (m5602_read_sensor(sd, 0x04, prod_id+4, 2))
245                 return -ENODEV;
246
247         if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
248                 return -ENODEV;
249         else
250                 info("Detected a s5k4aa sensor");
251
252 sensor_found:
253         sensor_settings = kmalloc(
254                 ARRAY_SIZE(s5k4aa_ctrls) * sizeof(s32), GFP_KERNEL);
255         if (!sensor_settings)
256                 return -ENOMEM;
257
258         sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
259         sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
260         sd->desc->ctrls = s5k4aa_ctrls;
261         sd->desc->nctrls = ARRAY_SIZE(s5k4aa_ctrls);
262
263         for (i = 0; i < ARRAY_SIZE(s5k4aa_ctrls); i++)
264                 sensor_settings[i] = s5k4aa_ctrls[i].qctrl.default_value;
265         sd->sensor_priv = sensor_settings;
266
267         return 0;
268 }
269
270 int s5k4aa_start(struct sd *sd)
271 {
272         int i, err = 0;
273         u8 data[2];
274         struct cam *cam = &sd->gspca_dev.cam;
275         s32 *sensor_settings = sd->sensor_priv;
276
277         switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) {
278         case 1280:
279                 PDEBUG(D_V4L2, "Configuring camera for SXGA mode");
280
281                 for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) {
282                         switch (SXGA_s5k4aa[i][0]) {
283                         case BRIDGE:
284                                 err = m5602_write_bridge(sd,
285                                                  SXGA_s5k4aa[i][1],
286                                                  SXGA_s5k4aa[i][2]);
287                         break;
288
289                         case SENSOR:
290                                 data[0] = SXGA_s5k4aa[i][2];
291                                 err = m5602_write_sensor(sd,
292                                                  SXGA_s5k4aa[i][1],
293                                                  data, 1);
294                         break;
295
296                         case SENSOR_LONG:
297                                 data[0] = SXGA_s5k4aa[i][2];
298                                 data[1] = SXGA_s5k4aa[i][3];
299                                 err = m5602_write_sensor(sd,
300                                                   SXGA_s5k4aa[i][1],
301                                                   data, 2);
302                         break;
303
304                         default:
305                                 err("Invalid stream command, exiting init");
306                                 return -EINVAL;
307                         }
308                 }
309                 err = s5k4aa_set_noise(&sd->gspca_dev, 0);
310                 if (err < 0)
311                         return err;
312                 break;
313
314         case 640:
315                 PDEBUG(D_V4L2, "Configuring camera for VGA mode");
316
317                 for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) {
318                         switch (VGA_s5k4aa[i][0]) {
319                         case BRIDGE:
320                                 err = m5602_write_bridge(sd,
321                                                  VGA_s5k4aa[i][1],
322                                                  VGA_s5k4aa[i][2]);
323                         break;
324
325                         case SENSOR:
326                                 data[0] = VGA_s5k4aa[i][2];
327                                 err = m5602_write_sensor(sd,
328                                                  VGA_s5k4aa[i][1],
329                                                  data, 1);
330                         break;
331
332                         case SENSOR_LONG:
333                                 data[0] = VGA_s5k4aa[i][2];
334                                 data[1] = VGA_s5k4aa[i][3];
335                                 err = m5602_write_sensor(sd,
336                                                   VGA_s5k4aa[i][1],
337                                                   data, 2);
338                         break;
339
340                         default:
341                                 err("Invalid stream command, exiting init");
342                                 return -EINVAL;
343                         }
344                 }
345                 err = s5k4aa_set_noise(&sd->gspca_dev, 1);
346                 if (err < 0)
347                         return err;
348                 break;
349         }
350         if (err < 0)
351                 return err;
352
353         err = s5k4aa_set_exposure(&sd->gspca_dev,
354                                    sensor_settings[EXPOSURE_IDX]);
355         if (err < 0)
356                 return err;
357
358         err = s5k4aa_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
359         if (err < 0)
360                 return err;
361
362         err = s5k4aa_set_brightness(&sd->gspca_dev,
363                                      sensor_settings[BRIGHTNESS_IDX]);
364         if (err < 0)
365                 return err;
366
367         err = s5k4aa_set_noise(&sd->gspca_dev, sensor_settings[NOISE_SUPP_IDX]);
368         if (err < 0)
369                 return err;
370
371         err = s5k4aa_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
372         if (err < 0)
373                 return err;
374
375         return s5k4aa_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
376 }
377
378 int s5k4aa_init(struct sd *sd)
379 {
380         int i, err = 0;
381
382         for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) {
383                 u8 data[2] = {0x00, 0x00};
384
385                 switch (init_s5k4aa[i][0]) {
386                 case BRIDGE:
387                         err = m5602_write_bridge(sd,
388                                 init_s5k4aa[i][1],
389                                 init_s5k4aa[i][2]);
390                         break;
391
392                 case SENSOR:
393                         data[0] = init_s5k4aa[i][2];
394                         err = m5602_write_sensor(sd,
395                                 init_s5k4aa[i][1], data, 1);
396                         break;
397
398                 case SENSOR_LONG:
399                         data[0] = init_s5k4aa[i][2];
400                         data[1] = init_s5k4aa[i][3];
401                         err = m5602_write_sensor(sd,
402                                 init_s5k4aa[i][1], data, 2);
403                         break;
404                 default:
405                         info("Invalid stream command, exiting init");
406                         return -EINVAL;
407                 }
408         }
409
410         if (dump_sensor)
411                 s5k4aa_dump_registers(sd);
412
413         return err;
414 }
415
416 static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
417 {
418         struct sd *sd = (struct sd *) gspca_dev;
419         s32 *sensor_settings = sd->sensor_priv;
420
421         *val = sensor_settings[EXPOSURE_IDX];
422         PDEBUG(D_V4L2, "Read exposure %d", *val);
423
424         return 0;
425 }
426
427 static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
428 {
429         struct sd *sd = (struct sd *) gspca_dev;
430         s32 *sensor_settings = sd->sensor_priv;
431         u8 data = S5K4AA_PAGE_MAP_2;
432         int err;
433
434         sensor_settings[EXPOSURE_IDX] = val;
435         PDEBUG(D_V4L2, "Set exposure to %d", val);
436         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
437         if (err < 0)
438                 return err;
439         data = (val >> 8) & 0xff;
440         err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
441         if (err < 0)
442                 return err;
443         data = val & 0xff;
444         err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
445
446         return err;
447 }
448
449 static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
450 {
451         struct sd *sd = (struct sd *) gspca_dev;
452         s32 *sensor_settings = sd->sensor_priv;
453
454         *val = sensor_settings[VFLIP_IDX];
455         PDEBUG(D_V4L2, "Read vertical flip %d", *val);
456
457         return 0;
458 }
459
460 static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
461 {
462         struct sd *sd = (struct sd *) gspca_dev;
463         s32 *sensor_settings = sd->sensor_priv;
464         u8 data = S5K4AA_PAGE_MAP_2;
465         int err;
466
467         sensor_settings[VFLIP_IDX] = val;
468
469         PDEBUG(D_V4L2, "Set vertical flip to %d", val);
470         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
471         if (err < 0)
472                 return err;
473         err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
474         if (err < 0)
475                 return err;
476
477         err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
478         if (err < 0)
479                 return err;
480
481         if (dmi_check_system(s5k4aa_vflip_dmi_table))
482                 val = !val;
483
484         data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7));
485         err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
486         if (err < 0)
487                 return err;
488
489         err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
490         if (err < 0)
491                 return err;
492         data = (data & 0xfe) | !val;
493         err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
494         return err;
495 }
496
497 static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
498 {
499         struct sd *sd = (struct sd *) gspca_dev;
500         s32 *sensor_settings = sd->sensor_priv;
501
502         *val = sensor_settings[HFLIP_IDX];
503         PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
504
505         return 0;
506 }
507
508 static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
509 {
510         struct sd *sd = (struct sd *) gspca_dev;
511         s32 *sensor_settings = sd->sensor_priv;
512         u8 data = S5K4AA_PAGE_MAP_2;
513         int err;
514
515         sensor_settings[HFLIP_IDX] = val;
516
517         PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
518         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
519         if (err < 0)
520                 return err;
521         err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
522         if (err < 0)
523                 return err;
524
525         err = m5602_read_sensor(sd, S5K4AA_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 }