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