]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/media/video/gspca/m5602/m5602_s5k4aa.c
V4L/DVB (11413): gspca - m5602-mt9m111: Separate mode vectors per sensor.
[linux-2.6-omap-h63xx.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
22     const
23         struct dmi_system_id s5k4aa_vflip_dmi_table[] = {
24         {
25                 .ident = "Fujitsu-Siemens Amilo Xa 2528",
26                 .matches = {
27                         DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
28                         DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528")
29                 }
30         }, {
31                 .ident = "Fujitsu-Siemens Amilo Xi 2550",
32                 .matches = {
33                         DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
34                         DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550")
35                 }
36         }, {
37                 .ident = "MSI GX700",
38                 .matches = {
39                         DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
40                         DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
41                         DMI_MATCH(DMI_BIOS_DATE, "07/26/2007")
42                 }
43         }, {
44                 .ident = "MSI GX700/GX705/EX700",
45                 .matches = {
46                         DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
47                         DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700")
48                 }
49         },
50         { }
51 };
52
53 static struct v4l2_pix_format s5k4aa_modes[] = {
54         {
55                 640,
56                 480,
57                 V4L2_PIX_FMT_SBGGR8,
58                 V4L2_FIELD_NONE,
59                 .sizeimage =
60                         640 * 480,
61                 .bytesperline = 640,
62                 .colorspace = V4L2_COLORSPACE_SRGB,
63                 .priv = 0
64         }
65 };
66
67 static void s5k4aa_dump_registers(struct sd *sd);
68
69 int s5k4aa_probe(struct sd *sd)
70 {
71         u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
72         const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
73         int i, err = 0;
74
75         if (force_sensor) {
76                 if (force_sensor == S5K4AA_SENSOR) {
77                         info("Forcing a %s sensor", s5k4aa.name);
78                         goto sensor_found;
79                 }
80                 /* If we want to force another sensor, don't try to probe this
81                  * one */
82                 return -ENODEV;
83         }
84
85         info("Probing for a s5k4aa sensor");
86
87         /* Preinit the sensor */
88         for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) {
89                 u8 data[2] = {0x00, 0x00};
90
91                 switch (preinit_s5k4aa[i][0]) {
92                 case BRIDGE:
93                         err = m5602_write_bridge(sd,
94                                                  preinit_s5k4aa[i][1],
95                                                  preinit_s5k4aa[i][2]);
96                         break;
97
98                 case SENSOR:
99                         data[0] = preinit_s5k4aa[i][2];
100                         err = m5602_write_sensor(sd,
101                                                   preinit_s5k4aa[i][1],
102                                                   data, 1);
103                         break;
104
105                 case SENSOR_LONG:
106                         data[0] = preinit_s5k4aa[i][2];
107                         data[1] = preinit_s5k4aa[i][3];
108                         err = m5602_write_sensor(sd,
109                                                   preinit_s5k4aa[i][1],
110                                                   data, 2);
111                         break;
112                 default:
113                         info("Invalid stream command, exiting init");
114                         return -EINVAL;
115                 }
116         }
117
118         /* Test some registers, but we don't know their exact meaning yet */
119         if (m5602_read_sensor(sd, 0x00, prod_id, 2))
120                 return -ENODEV;
121         if (m5602_read_sensor(sd, 0x02, prod_id+2, 2))
122                 return -ENODEV;
123         if (m5602_read_sensor(sd, 0x04, prod_id+4, 2))
124                 return -ENODEV;
125
126         if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
127                 return -ENODEV;
128         else
129                 info("Detected a s5k4aa sensor");
130
131 sensor_found:
132         sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
133         sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
134         sd->desc->ctrls = s5k4aa.ctrls;
135         sd->desc->nctrls = ARRAY_SIZE(s5k4aa_ctrls);
136         return 0;
137 }
138
139 int s5k4aa_start(struct sd *sd)
140 {
141         int i, err = 0;
142         u8 data[2];
143         struct cam *cam = &sd->gspca_dev.cam;
144
145         switch (cam->cam_mode[sd->gspca_dev.curr_mode].width)
146         {
147         case 640:
148                 PDEBUG(D_V4L2, "Configuring camera for VGA mode");
149
150                 for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) {
151                         switch (VGA_s5k4aa[i][0]) {
152                         case BRIDGE:
153                                 err = m5602_write_bridge(sd,
154                                                  VGA_s5k4aa[i][1],
155                                                  VGA_s5k4aa[i][2]);
156                         break;
157
158                         case SENSOR:
159                                 data[0] = VGA_s5k4aa[i][2];
160                                 err = m5602_write_sensor(sd,
161                                                  VGA_s5k4aa[i][1],
162                                                  data, 1);
163                         break;
164
165                         case SENSOR_LONG:
166                                 data[0] = VGA_s5k4aa[i][2];
167                                 data[1] = VGA_s5k4aa[i][3];
168                                 err = m5602_write_sensor(sd,
169                                                   VGA_s5k4aa[i][1],
170                                                   data, 2);
171                         break;
172
173                         default:
174                                 err("Invalid stream command, exiting init");
175                                 return -EINVAL;
176                         }
177                 }
178         }
179         return err;
180 }
181
182 int s5k4aa_init(struct sd *sd)
183 {
184         int i, err = 0;
185
186         for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) {
187                 u8 data[2] = {0x00, 0x00};
188
189                 switch (init_s5k4aa[i][0]) {
190                 case BRIDGE:
191                         err = m5602_write_bridge(sd,
192                                 init_s5k4aa[i][1],
193                                 init_s5k4aa[i][2]);
194                         break;
195
196                 case SENSOR:
197                         data[0] = init_s5k4aa[i][2];
198                         err = m5602_write_sensor(sd,
199                                 init_s5k4aa[i][1], data, 1);
200                         break;
201
202                 case SENSOR_LONG:
203                         data[0] = init_s5k4aa[i][2];
204                         data[1] = init_s5k4aa[i][3];
205                         err = m5602_write_sensor(sd,
206                                 init_s5k4aa[i][1], data, 2);
207                         break;
208                 default:
209                         info("Invalid stream command, exiting init");
210                         return -EINVAL;
211                 }
212         }
213
214         if (dump_sensor)
215                 s5k4aa_dump_registers(sd);
216
217         if (!err && dmi_check_system(s5k4aa_vflip_dmi_table)) {
218                 u8 data = 0x02;
219                 info("vertical flip quirk active");
220                 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
221                 m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
222                 data |= S5K4AA_RM_V_FLIP;
223                 data &= ~S5K4AA_RM_H_FLIP;
224                 m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
225
226                 /* Decrement COLSTART to preserve color order (BGGR) */
227                 m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
228                 data--;
229                 m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
230
231                 /* Increment ROWSTART to preserve color order (BGGR) */
232                 m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
233                 data++;
234                 m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
235         }
236
237         return (err < 0) ? err : 0;
238 }
239
240 int s5k4aa_power_down(struct sd *sd)
241 {
242         return 0;
243 }
244
245 int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
246 {
247         struct sd *sd = (struct sd *) gspca_dev;
248         u8 data = S5K4AA_PAGE_MAP_2;
249         int err;
250
251         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
252         if (err < 0)
253                 return err;
254
255         err = m5602_read_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
256         if (err < 0)
257                 return err;
258
259         *val = data << 8;
260         err = m5602_read_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
261         *val |= data;
262         PDEBUG(D_V4L2, "Read exposure %d", *val);
263
264         return err;
265 }
266
267 int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
268 {
269         struct sd *sd = (struct sd *) gspca_dev;
270         u8 data = S5K4AA_PAGE_MAP_2;
271         int err;
272
273         PDEBUG(D_V4L2, "Set exposure to %d", val);
274         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
275         if (err < 0)
276                 return err;
277         data = (val >> 8) & 0xff;
278         err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
279         if (err < 0)
280                 return err;
281         data = val & 0xff;
282         err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
283
284         return err;
285 }
286
287 int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
288 {
289         struct sd *sd = (struct sd *) gspca_dev;
290         u8 data = S5K4AA_PAGE_MAP_2;
291         int err;
292
293         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
294         if (err < 0)
295                 return err;
296
297         err = m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
298         *val = (data & S5K4AA_RM_V_FLIP) >> 7;
299         PDEBUG(D_V4L2, "Read vertical flip %d", *val);
300
301         return err;
302 }
303
304 int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
305 {
306         struct sd *sd = (struct sd *) gspca_dev;
307         u8 data = S5K4AA_PAGE_MAP_2;
308         int err;
309
310         PDEBUG(D_V4L2, "Set vertical flip to %d", val);
311         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
312         if (err < 0)
313                 return err;
314         err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
315         if (err < 0)
316                 return err;
317         data = ((data & ~S5K4AA_RM_V_FLIP)
318                         | ((val & 0x01) << 7));
319         err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
320         if (err < 0)
321                 return err;
322
323         if (val) {
324                 err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
325                 if (err < 0)
326                         return err;
327
328                 data++;
329                 err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
330         } else {
331                 err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
332                 if (err < 0)
333                         return err;
334
335                 data--;
336                 err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
337         }
338
339         return err;
340 }
341
342 int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
343 {
344         struct sd *sd = (struct sd *) gspca_dev;
345         u8 data = S5K4AA_PAGE_MAP_2;
346         int err;
347
348         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
349         if (err < 0)
350                 return err;
351
352         err = m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
353         *val = (data & S5K4AA_RM_H_FLIP) >> 6;
354         PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
355
356         return err;
357 }
358
359 int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
360 {
361         struct sd *sd = (struct sd *) gspca_dev;
362         u8 data = S5K4AA_PAGE_MAP_2;
363         int err;
364
365         PDEBUG(D_V4L2, "Set horizontal flip to %d",
366                val);
367         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
368         if (err < 0)
369                 return err;
370         err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
371         if (err < 0)
372                 return err;
373
374         data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
375         err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
376         if (err < 0)
377                 return err;
378
379         if (val) {
380                 err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
381                 if (err < 0)
382                         return err;
383                 data++;
384                 err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
385                 if (err < 0)
386                         return err;
387         } else {
388                 err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
389                 if (err < 0)
390                         return err;
391                 data--;
392                 err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
393         }
394
395         return err;
396 }
397
398 int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
399 {
400         struct sd *sd = (struct sd *) gspca_dev;
401         u8 data = S5K4AA_PAGE_MAP_2;
402         int err;
403
404         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
405         if (err < 0)
406                 return err;
407
408         err = m5602_read_sensor(sd, S5K4AA_GAIN_2, &data, 1);
409         *val = data;
410         PDEBUG(D_V4L2, "Read gain %d", *val);
411
412         return err;
413 }
414
415 int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
416 {
417         struct sd *sd = (struct sd *) gspca_dev;
418         u8 data = S5K4AA_PAGE_MAP_2;
419         int err;
420
421         PDEBUG(D_V4L2, "Set gain to %d", val);
422         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
423         if (err < 0)
424                 return err;
425
426         data = val & 0xff;
427         err = m5602_write_sensor(sd, S5K4AA_GAIN_2, &data, 1);
428
429         return err;
430 }
431
432 static void s5k4aa_dump_registers(struct sd *sd)
433 {
434         int address;
435         u8 page, old_page;
436         m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
437         for (page = 0; page < 16; page++) {
438                 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
439                 info("Dumping the s5k4aa register state for page 0x%x", page);
440                 for (address = 0; address <= 0xff; address++) {
441                         u8 value = 0;
442                         m5602_read_sensor(sd, address, &value, 1);
443                         info("register 0x%x contains 0x%x",
444                              address, value);
445                 }
446         }
447         info("s5k4aa register state dump complete");
448
449         for (page = 0; page < 16; page++) {
450                 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
451                 info("Probing for which registers that are "
452                      "read/write for page 0x%x", page);
453                 for (address = 0; address <= 0xff; address++) {
454                         u8 old_value, ctrl_value, test_value = 0xff;
455
456                         m5602_read_sensor(sd, address, &old_value, 1);
457                         m5602_write_sensor(sd, address, &test_value, 1);
458                         m5602_read_sensor(sd, address, &ctrl_value, 1);
459
460                         if (ctrl_value == test_value)
461                                 info("register 0x%x is writeable", address);
462                         else
463                                 info("register 0x%x is read only", address);
464
465                         /* Restore original value */
466                         m5602_write_sensor(sd, address, &old_value, 1);
467                 }
468         }
469         info("Read/write register probing complete");
470         m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
471 }