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