]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/media/video/gspca/m5602/m5602_s5k4aa.c
V4L/DVB (9703): Move the s5k4aa vflip quirk table to the main sensor file in order...
[karo-tx-linux.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
54 int s5k4aa_probe(struct sd *sd)
55 {
56         u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
57         const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
58         int i, err = 0;
59
60         if (force_sensor) {
61                 if (force_sensor == S5K4AA_SENSOR) {
62                         info("Forcing a %s sensor", s5k4aa.name);
63                         goto sensor_found;
64                 }
65                 /* If we want to force another sensor, don't try to probe this
66                  * one */
67                 return -ENODEV;
68         }
69
70         info("Probing for a s5k4aa sensor");
71
72         /* Preinit the sensor */
73         for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) {
74                 u8 data[2] = {0x00, 0x00};
75
76                 switch (preinit_s5k4aa[i][0]) {
77                 case BRIDGE:
78                         err = m5602_write_bridge(sd,
79                                                  preinit_s5k4aa[i][1],
80                                                  preinit_s5k4aa[i][2]);
81                         break;
82
83                 case SENSOR:
84                         data[0] = preinit_s5k4aa[i][2];
85                         err = s5k4aa_write_sensor(sd,
86                                                   preinit_s5k4aa[i][1],
87                                                   data, 1);
88                         break;
89
90                 case SENSOR_LONG:
91                         data[0] = preinit_s5k4aa[i][2];
92                         data[1] = preinit_s5k4aa[i][3];
93                         err = s5k4aa_write_sensor(sd,
94                                                   preinit_s5k4aa[i][1],
95                                                   data, 2);
96                         break;
97                 default:
98                         info("Invalid stream command, exiting init");
99                         return -EINVAL;
100                 }
101         }
102
103         /* Test some registers, but we don't know their exact meaning yet */
104         if (s5k4aa_read_sensor(sd, 0x00, prod_id, sizeof(prod_id)))
105                 return -ENODEV;
106
107         if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
108                 return -ENODEV;
109         else
110                 info("Detected a s5k4aa sensor");
111 sensor_found:
112         sd->gspca_dev.cam.cam_mode = s5k4aa.modes;
113         sd->gspca_dev.cam.nmodes = s5k4aa.nmodes;
114         sd->desc->ctrls = s5k4aa.ctrls;
115         sd->desc->nctrls = s5k4aa.nctrls;
116
117         return 0;
118 }
119
120 int s5k4aa_read_sensor(struct sd *sd, const u8 address,
121                        u8 *i2c_data, const u8 len)
122 {
123         int err, i;
124
125         do {
126                 err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
127         } while ((*i2c_data & I2C_BUSY) && !err);
128         if (err < 0)
129                 goto out;
130
131         err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
132                                  sd->sensor->i2c_slave_id);
133         if (err < 0)
134                 goto out;
135
136         err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
137         if (err < 0)
138                 goto out;
139
140         err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x18 + len);
141         if (err < 0)
142                 goto out;
143
144         do {
145                 err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
146         } while ((*i2c_data & I2C_BUSY) && !err);
147         if (err < 0)
148                 goto out;
149
150         for (i = 0; (i < len) & !err; i++) {
151                 err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
152
153                 PDEBUG(D_CONF, "Reading sensor register "
154                                   "0x%x containing 0x%x ", address, *i2c_data);
155         }
156 out:
157         return (err < 0) ? err : 0;
158 }
159
160 int s5k4aa_write_sensor(struct sd *sd, const u8 address,
161                         u8 *i2c_data, const u8 len)
162 {
163         int err, i;
164         u8 *p;
165         struct usb_device *udev = sd->gspca_dev.dev;
166         __u8 *buf = sd->gspca_dev.usb_buf;
167
168         /* No sensor with a data width larger than 16 bits has yet been seen */
169         if (len > 2 || !len)
170                 return -EINVAL;
171
172         memcpy(buf, sensor_urb_skeleton,
173                sizeof(sensor_urb_skeleton));
174
175         buf[11] = sd->sensor->i2c_slave_id;
176         buf[15] = address;
177
178         /* Special case larger sensor writes */
179         p = buf + 16;
180
181         /* Copy a four byte write sequence for each byte to be written to */
182         for (i = 0; i < len; i++) {
183                 memcpy(p, sensor_urb_skeleton + 16, 4);
184                 p[3] = i2c_data[i];
185                 p += 4;
186                 PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
187                        address, i2c_data[i]);
188         }
189
190         /* Copy the tailer */
191         memcpy(p, sensor_urb_skeleton + 20, 4);
192
193         /* Set the total length */
194         p[3] = 0x10 + len;
195
196         err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
197                               0x04, 0x40, 0x19,
198                               0x0000, buf,
199                               20 + len * 4, M5602_URB_MSG_TIMEOUT);
200
201         return (err < 0) ? err : 0;
202 }
203
204 int s5k4aa_init(struct sd *sd)
205 {
206         int i, err = 0;
207
208         for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) {
209                 u8 data[2] = {0x00, 0x00};
210
211                 switch (init_s5k4aa[i][0]) {
212                 case BRIDGE:
213                         err = m5602_write_bridge(sd,
214                                 init_s5k4aa[i][1],
215                                 init_s5k4aa[i][2]);
216                         break;
217
218                 case SENSOR:
219                         data[0] = init_s5k4aa[i][2];
220                         err = s5k4aa_write_sensor(sd,
221                                 init_s5k4aa[i][1], data, 1);
222                         break;
223
224                 case SENSOR_LONG:
225                         data[0] = init_s5k4aa[i][2];
226                         data[1] = init_s5k4aa[i][3];
227                         err = s5k4aa_write_sensor(sd,
228                                 init_s5k4aa[i][1], data, 2);
229                         break;
230                 default:
231                         info("Invalid stream command, exiting init");
232                         return -EINVAL;
233                 }
234         }
235
236         if (dump_sensor)
237                 s5k4aa_dump_registers(sd);
238
239         if (!err && dmi_check_system(s5k4aa_vflip_dmi_table)) {
240                 u8 data = 0x02;
241                 info("vertical flip quirk active");
242                 s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
243                 s5k4aa_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
244                 data |= S5K4AA_RM_V_FLIP;
245                 data &= ~S5K4AA_RM_H_FLIP;
246                 s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
247
248                 /* Decrement COLSTART to preserve color order (BGGR) */
249                 s5k4aa_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
250                 data--;
251                 s5k4aa_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
252
253                 /* Increment ROWSTART to preserve color order (BGGR) */
254                 s5k4aa_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
255                 data++;
256                 s5k4aa_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
257         }
258
259         return (err < 0) ? err : 0;
260 }
261
262 int s5k4aa_power_down(struct sd *sd)
263 {
264         return 0;
265 }
266
267 int s5k4aa_get_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         err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
274         if (err < 0)
275                 goto out;
276
277         err = s5k4aa_read_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
278         if (err < 0)
279                 goto out;
280
281         *val = data << 8;
282         err = s5k4aa_read_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
283         *val |= data;
284         PDEBUG(D_V4L2, "Read exposure %d", *val);
285 out:
286         return (err < 0) ? err : 0;
287 }
288
289 int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
290 {
291         struct sd *sd = (struct sd *) gspca_dev;
292         u8 data = S5K4AA_PAGE_MAP_2;
293         int err;
294
295         PDEBUG(D_V4L2, "Set exposure to %d", val);
296         err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
297         if (err < 0)
298                 goto out;
299         data = (val >> 8) & 0xff;
300         err = s5k4aa_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
301         if (err < 0)
302                 goto out;
303         data = val & 0xff;
304         err = s5k4aa_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
305 out:
306         return (err < 0) ? err : 0;
307 }
308
309 int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
310 {
311         struct sd *sd = (struct sd *) gspca_dev;
312         u8 data = S5K4AA_PAGE_MAP_2;
313         int err;
314
315         err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
316         if (err < 0)
317                 goto out;
318
319         err = s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
320         *val = (data & S5K4AA_RM_V_FLIP) >> 7;
321         PDEBUG(D_V4L2, "Read vertical flip %d", *val);
322
323 out:
324         return (err < 0) ? err : 0;
325 }
326
327 int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
328 {
329         struct sd *sd = (struct sd *) gspca_dev;
330         u8 data = S5K4AA_PAGE_MAP_2;
331         int err;
332
333         PDEBUG(D_V4L2, "Set vertical flip to %d", val);
334         err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
335         if (err < 0)
336                 goto out;
337         err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
338         if (err < 0)
339                 goto out;
340         data = ((data & ~S5K4AA_RM_V_FLIP)
341                         | ((val & 0x01) << 7));
342         err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
343         if (err < 0)
344                 goto out;
345
346         if (val) {
347                 err = s5k4aa_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
348                 if (err < 0)
349                         goto out;
350
351                 data++;
352                 err = s5k4aa_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
353         } else {
354                 err = s5k4aa_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
355                 if (err < 0)
356                         goto out;
357
358                 data--;
359                 err = s5k4aa_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
360         }
361 out:
362         return (err < 0) ? err : 0;
363 }
364
365 int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
366 {
367         struct sd *sd = (struct sd *) gspca_dev;
368         u8 data = S5K4AA_PAGE_MAP_2;
369         int err;
370
371         err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
372         if (err < 0)
373                 goto out;
374
375         err = s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
376         *val = (data & S5K4AA_RM_H_FLIP) >> 6;
377         PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
378 out:
379         return (err < 0) ? err : 0;
380 }
381
382 int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
383 {
384         struct sd *sd = (struct sd *) gspca_dev;
385         u8 data = S5K4AA_PAGE_MAP_2;
386         int err;
387
388         PDEBUG(D_V4L2, "Set horizontal flip to %d",
389                val);
390         err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
391         if (err < 0)
392                 goto out;
393         err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
394         if (err < 0)
395                 goto out;
396
397         data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
398         err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
399         if (err < 0)
400                 goto out;
401
402         if (val) {
403                 err = s5k4aa_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
404                 if (err < 0)
405                         goto out;
406                 data++;
407                 err = s5k4aa_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
408                 if (err < 0)
409                         goto out;
410         } else {
411                 err = s5k4aa_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
412                 if (err < 0)
413                         goto out;
414                 data--;
415                 err = s5k4aa_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
416         }
417 out:
418         return (err < 0) ? err : 0;
419 }
420
421 int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
422 {
423         struct sd *sd = (struct sd *) gspca_dev;
424         u8 data = S5K4AA_PAGE_MAP_2;
425         int err;
426
427         err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
428         if (err < 0)
429                 goto out;
430
431         err = s5k4aa_read_sensor(sd, S5K4AA_GAIN_2, &data, 1);
432         *val = data;
433         PDEBUG(D_V4L2, "Read gain %d", *val);
434
435 out:
436         return (err < 0) ? err : 0;
437 }
438
439 int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
440 {
441         struct sd *sd = (struct sd *) gspca_dev;
442         u8 data = S5K4AA_PAGE_MAP_2;
443         int err;
444
445         PDEBUG(D_V4L2, "Set gain to %d", val);
446         err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
447         if (err < 0)
448                 goto out;
449
450         data = val & 0xff;
451         err = s5k4aa_write_sensor(sd, S5K4AA_GAIN_2, &data, 1);
452
453 out:
454         return (err < 0) ? err : 0;
455 }
456
457 void s5k4aa_dump_registers(struct sd *sd)
458 {
459         int address;
460         u8 page, old_page;
461         s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
462         for (page = 0; page < 16; page++) {
463                 s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
464                 info("Dumping the s5k4aa register state for page 0x%x", page);
465                 for (address = 0; address <= 0xff; address++) {
466                         u8 value = 0;
467                         s5k4aa_read_sensor(sd, address, &value, 1);
468                         info("register 0x%x contains 0x%x",
469                              address, value);
470                 }
471         }
472         info("s5k4aa register state dump complete");
473
474         for (page = 0; page < 16; page++) {
475                 s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
476                 info("Probing for which registers that are "
477                      "read/write for page 0x%x", page);
478                 for (address = 0; address <= 0xff; address++) {
479                         u8 old_value, ctrl_value, test_value = 0xff;
480
481                         s5k4aa_read_sensor(sd, address, &old_value, 1);
482                         s5k4aa_write_sensor(sd, address, &test_value, 1);
483                         s5k4aa_read_sensor(sd, address, &ctrl_value, 1);
484
485                         if (ctrl_value == test_value)
486                                 info("register 0x%x is writeable", address);
487                         else
488                                 info("register 0x%x is read only", address);
489
490                         /* Restore original value */
491                         s5k4aa_write_sensor(sd, address, &old_value, 1);
492                 }
493         }
494         info("Read/write register probing complete");
495         s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
496 }