]> Pileus Git - ~andy/linux/blob - drivers/media/usb/gspca/m5602/m5602_s5k4aa.c
[media] gscpa_m5602: Convert to the control framework
[~andy/linux] / drivers / media / usb / 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 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20
21 #include "m5602_s5k4aa.h"
22
23 static int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl);
24 static void s5k4aa_dump_registers(struct sd *sd);
25
26 static const struct v4l2_ctrl_ops s5k4aa_ctrl_ops = {
27         .s_ctrl = s5k4aa_s_ctrl,
28 };
29
30 static
31     const
32         struct dmi_system_id s5k4aa_vflip_dmi_table[] = {
33         {
34                 .ident = "BRUNEINIT",
35                 .matches = {
36                         DMI_MATCH(DMI_SYS_VENDOR, "BRUNENIT"),
37                         DMI_MATCH(DMI_PRODUCT_NAME, "BRUNENIT"),
38                         DMI_MATCH(DMI_BOARD_VERSION, "00030D0000000001")
39                 }
40         }, {
41                 .ident = "Fujitsu-Siemens Amilo Xa 2528",
42                 .matches = {
43                         DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
44                         DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528")
45                 }
46         }, {
47                 .ident = "Fujitsu-Siemens Amilo Xi 2428",
48                 .matches = {
49                         DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
50                         DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2428")
51                 }
52         }, {
53                 .ident = "Fujitsu-Siemens Amilo Xi 2528",
54                 .matches = {
55                         DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
56                         DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2528")
57                 }
58         }, {
59                 .ident = "Fujitsu-Siemens Amilo Xi 2550",
60                 .matches = {
61                         DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
62                         DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550")
63                 }
64         }, {
65                 .ident = "Fujitsu-Siemens Amilo Pa 2548",
66                 .matches = {
67                         DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
68                         DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2548")
69                 }
70         }, {
71                 .ident = "Fujitsu-Siemens Amilo Pi 2530",
72                 .matches = {
73                         DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
74                         DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 2530")
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,
123                 V4L2_PIX_FMT_SBGGR8,
124                 V4L2_FIELD_NONE,
125                 .sizeimage =
126                         640 * 480,
127                 .bytesperline = 640,
128                 .colorspace = V4L2_COLORSPACE_SRGB,
129                 .priv = 0
130         },
131         {
132                 1280,
133                 1024,
134                 V4L2_PIX_FMT_SBGGR8,
135                 V4L2_FIELD_NONE,
136                 .sizeimage =
137                         1280 * 1024,
138                 .bytesperline = 1280,
139                 .colorspace = V4L2_COLORSPACE_SRGB,
140                 .priv = 0
141         }
142 };
143
144 int s5k4aa_probe(struct sd *sd)
145 {
146         u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
147         const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
148         int i, err = 0;
149
150         if (force_sensor) {
151                 if (force_sensor == S5K4AA_SENSOR) {
152                         pr_info("Forcing a %s sensor\n", s5k4aa.name);
153                         goto sensor_found;
154                 }
155                 /* If we want to force another sensor, don't try to probe this
156                  * one */
157                 return -ENODEV;
158         }
159
160         PDEBUG(D_PROBE, "Probing for a s5k4aa sensor");
161
162         /* Preinit the sensor */
163         for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) {
164                 u8 data[2] = {0x00, 0x00};
165
166                 switch (preinit_s5k4aa[i][0]) {
167                 case BRIDGE:
168                         err = m5602_write_bridge(sd,
169                                                  preinit_s5k4aa[i][1],
170                                                  preinit_s5k4aa[i][2]);
171                         break;
172
173                 case SENSOR:
174                         data[0] = preinit_s5k4aa[i][2];
175                         err = m5602_write_sensor(sd,
176                                                   preinit_s5k4aa[i][1],
177                                                   data, 1);
178                         break;
179
180                 case SENSOR_LONG:
181                         data[0] = preinit_s5k4aa[i][2];
182                         data[1] = preinit_s5k4aa[i][3];
183                         err = m5602_write_sensor(sd,
184                                                   preinit_s5k4aa[i][1],
185                                                   data, 2);
186                         break;
187                 default:
188                         pr_info("Invalid stream command, exiting init\n");
189                         return -EINVAL;
190                 }
191         }
192
193         /* Test some registers, but we don't know their exact meaning yet */
194         if (m5602_read_sensor(sd, 0x00, prod_id, 2))
195                 return -ENODEV;
196         if (m5602_read_sensor(sd, 0x02, prod_id+2, 2))
197                 return -ENODEV;
198         if (m5602_read_sensor(sd, 0x04, prod_id+4, 2))
199                 return -ENODEV;
200
201         if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
202                 return -ENODEV;
203         else
204                 pr_info("Detected a s5k4aa sensor\n");
205
206 sensor_found:
207         sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
208         sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
209
210         return 0;
211 }
212
213 int s5k4aa_start(struct sd *sd)
214 {
215         int i, err = 0;
216         u8 data[2];
217         struct cam *cam = &sd->gspca_dev.cam;
218
219         switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) {
220         case 1280:
221                 PDEBUG(D_V4L2, "Configuring camera for SXGA mode");
222
223                 for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) {
224                         switch (SXGA_s5k4aa[i][0]) {
225                         case BRIDGE:
226                                 err = m5602_write_bridge(sd,
227                                                  SXGA_s5k4aa[i][1],
228                                                  SXGA_s5k4aa[i][2]);
229                         break;
230
231                         case SENSOR:
232                                 data[0] = SXGA_s5k4aa[i][2];
233                                 err = m5602_write_sensor(sd,
234                                                  SXGA_s5k4aa[i][1],
235                                                  data, 1);
236                         break;
237
238                         case SENSOR_LONG:
239                                 data[0] = SXGA_s5k4aa[i][2];
240                                 data[1] = SXGA_s5k4aa[i][3];
241                                 err = m5602_write_sensor(sd,
242                                                   SXGA_s5k4aa[i][1],
243                                                   data, 2);
244                         break;
245
246                         default:
247                                 pr_err("Invalid stream command, exiting init\n");
248                                 return -EINVAL;
249                         }
250                 }
251                 break;
252
253         case 640:
254                 PDEBUG(D_V4L2, "Configuring camera for VGA mode");
255
256                 for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) {
257                         switch (VGA_s5k4aa[i][0]) {
258                         case BRIDGE:
259                                 err = m5602_write_bridge(sd,
260                                                  VGA_s5k4aa[i][1],
261                                                  VGA_s5k4aa[i][2]);
262                         break;
263
264                         case SENSOR:
265                                 data[0] = VGA_s5k4aa[i][2];
266                                 err = m5602_write_sensor(sd,
267                                                  VGA_s5k4aa[i][1],
268                                                  data, 1);
269                         break;
270
271                         case SENSOR_LONG:
272                                 data[0] = VGA_s5k4aa[i][2];
273                                 data[1] = VGA_s5k4aa[i][3];
274                                 err = m5602_write_sensor(sd,
275                                                   VGA_s5k4aa[i][1],
276                                                   data, 2);
277                         break;
278
279                         default:
280                                 pr_err("Invalid stream command, exiting init\n");
281                                 return -EINVAL;
282                         }
283                 }
284                 break;
285         }
286         if (err < 0)
287                 return err;
288
289         return 0;
290 }
291
292 int s5k4aa_init(struct sd *sd)
293 {
294         int i, err = 0;
295
296         for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) {
297                 u8 data[2] = {0x00, 0x00};
298
299                 switch (init_s5k4aa[i][0]) {
300                 case BRIDGE:
301                         err = m5602_write_bridge(sd,
302                                 init_s5k4aa[i][1],
303                                 init_s5k4aa[i][2]);
304                         break;
305
306                 case SENSOR:
307                         data[0] = init_s5k4aa[i][2];
308                         err = m5602_write_sensor(sd,
309                                 init_s5k4aa[i][1], data, 1);
310                         break;
311
312                 case SENSOR_LONG:
313                         data[0] = init_s5k4aa[i][2];
314                         data[1] = init_s5k4aa[i][3];
315                         err = m5602_write_sensor(sd,
316                                 init_s5k4aa[i][1], data, 2);
317                         break;
318                 default:
319                         pr_info("Invalid stream command, exiting init\n");
320                         return -EINVAL;
321                 }
322         }
323
324         if (dump_sensor)
325                 s5k4aa_dump_registers(sd);
326
327         return err;
328 }
329
330 int s5k4aa_init_controls(struct sd *sd)
331 {
332         struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
333
334         sd->gspca_dev.vdev.ctrl_handler = hdl;
335         v4l2_ctrl_handler_init(hdl, 6);
336
337         v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_BRIGHTNESS,
338                           0, 0x1f, 1, S5K4AA_DEFAULT_BRIGHTNESS);
339
340         v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_EXPOSURE,
341                           13, 0xfff, 1, 0x100);
342
343         v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_GAIN,
344                           0, 127, 1, S5K4AA_DEFAULT_GAIN);
345
346         v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_SHARPNESS,
347                           0, 1, 1, 1);
348
349         sd->hflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_HFLIP,
350                                       0, 1, 1, 0);
351         sd->vflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_VFLIP,
352                                       0, 1, 1, 0);
353
354         if (hdl->error) {
355                 pr_err("Could not initialize controls\n");
356                 return hdl->error;
357         }
358
359         v4l2_ctrl_cluster(2, &sd->hflip);
360
361         return 0;
362 }
363
364 static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
365 {
366         struct sd *sd = (struct sd *) gspca_dev;
367         u8 data = S5K4AA_PAGE_MAP_2;
368         int err;
369
370         PDEBUG(D_V4L2, "Set exposure to %d", val);
371         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
372         if (err < 0)
373                 return err;
374         data = (val >> 8) & 0xff;
375         err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
376         if (err < 0)
377                 return err;
378         data = val & 0xff;
379         err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
380
381         return err;
382 }
383
384 static int s5k4aa_set_hvflip(struct gspca_dev *gspca_dev)
385 {
386         struct sd *sd = (struct sd *) gspca_dev;
387         u8 data = S5K4AA_PAGE_MAP_2;
388         int err;
389         int hflip = sd->hflip->val;
390         int vflip = sd->vflip->val;
391
392         PDEBUG(D_V4L2, "Set hvflip %d %d", hflip, vflip);
393         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
394         if (err < 0)
395                 return err;
396
397         err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
398         if (err < 0)
399                 return err;
400
401         if (dmi_check_system(s5k4aa_vflip_dmi_table)) {
402                 hflip = !hflip;
403                 vflip = !vflip;
404         }
405
406         data = (data & 0x7f) | (vflip << 7) | (hflip << 6);
407         err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
408         if (err < 0)
409                 return err;
410
411         err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
412         if (err < 0)
413                 return err;
414         if (hflip)
415                 data &= 0xfe;
416         else
417                 data |= 0x01;
418         err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
419         if (err < 0)
420                 return err;
421
422         err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
423         if (err < 0)
424                 return err;
425         if (vflip)
426                 data &= 0xfe;
427         else
428                 data |= 0x01;
429         err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
430         if (err < 0)
431                 return err;
432
433         return 0;
434 }
435
436 static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
437 {
438         struct sd *sd = (struct sd *) gspca_dev;
439         u8 data = S5K4AA_PAGE_MAP_2;
440         int err;
441
442         PDEBUG(D_V4L2, "Set gain to %d", val);
443         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
444         if (err < 0)
445                 return err;
446
447         data = val & 0xff;
448         err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1);
449
450         return err;
451 }
452
453 static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
454 {
455         struct sd *sd = (struct sd *) gspca_dev;
456         u8 data = S5K4AA_PAGE_MAP_2;
457         int err;
458
459         PDEBUG(D_V4L2, "Set brightness to %d", val);
460         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
461         if (err < 0)
462                 return err;
463
464         data = val & 0xff;
465         return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
466 }
467
468 static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
469 {
470         struct sd *sd = (struct sd *) gspca_dev;
471         u8 data = S5K4AA_PAGE_MAP_2;
472         int err;
473
474         PDEBUG(D_V4L2, "Set noise to %d", val);
475         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
476         if (err < 0)
477                 return err;
478
479         data = val & 0x01;
480         return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
481 }
482
483 static int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl)
484 {
485         struct gspca_dev *gspca_dev =
486                 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
487         int err;
488
489         if (!gspca_dev->streaming)
490                 return 0;
491
492         switch (ctrl->id) {
493         case V4L2_CID_BRIGHTNESS:
494                 err = s5k4aa_set_brightness(gspca_dev, ctrl->val);
495                 break;
496         case V4L2_CID_EXPOSURE:
497                 err = s5k4aa_set_exposure(gspca_dev, ctrl->val);
498                 break;
499         case V4L2_CID_GAIN:
500                 err = s5k4aa_set_gain(gspca_dev, ctrl->val);
501                 break;
502         case V4L2_CID_SHARPNESS:
503                 err = s5k4aa_set_noise(gspca_dev, ctrl->val);
504                 break;
505         case V4L2_CID_HFLIP:
506                 err = s5k4aa_set_hvflip(gspca_dev);
507                 break;
508         default:
509                 return -EINVAL;
510         }
511
512         return err;
513 }
514
515 void s5k4aa_disconnect(struct sd *sd)
516 {
517         sd->sensor = NULL;
518 }
519
520 static void s5k4aa_dump_registers(struct sd *sd)
521 {
522         int address;
523         u8 page, old_page;
524         m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
525         for (page = 0; page < 16; page++) {
526                 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
527                 pr_info("Dumping the s5k4aa register state for page 0x%x\n",
528                         page);
529                 for (address = 0; address <= 0xff; address++) {
530                         u8 value = 0;
531                         m5602_read_sensor(sd, address, &value, 1);
532                         pr_info("register 0x%x contains 0x%x\n",
533                                 address, value);
534                 }
535         }
536         pr_info("s5k4aa register state dump complete\n");
537
538         for (page = 0; page < 16; page++) {
539                 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
540                 pr_info("Probing for which registers that are read/write for page 0x%x\n",
541                         page);
542                 for (address = 0; address <= 0xff; address++) {
543                         u8 old_value, ctrl_value, test_value = 0xff;
544
545                         m5602_read_sensor(sd, address, &old_value, 1);
546                         m5602_write_sensor(sd, address, &test_value, 1);
547                         m5602_read_sensor(sd, address, &ctrl_value, 1);
548
549                         if (ctrl_value == test_value)
550                                 pr_info("register 0x%x is writeable\n",
551                                         address);
552                         else
553                                 pr_info("register 0x%x is read only\n",
554                                         address);
555
556                         /* Restore original value */
557                         m5602_write_sensor(sd, address, &old_value, 1);
558                 }
559         }
560         pr_info("Read/write register probing complete\n");
561         m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
562 }