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