Merge branch 'bkl-removal' of git://git.lwn.net/linux-2.6
[linux-2.6] / 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_init(struct sd *sd)
123 {
124         int i, err = 0;
125
126         for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) {
127                 u8 data[2] = {0x00, 0x00};
128
129                 switch (init_s5k4aa[i][0]) {
130                 case BRIDGE:
131                         err = m5602_write_bridge(sd,
132                                 init_s5k4aa[i][1],
133                                 init_s5k4aa[i][2]);
134                         break;
135
136                 case SENSOR:
137                         data[0] = init_s5k4aa[i][2];
138                         err = m5602_write_sensor(sd,
139                                 init_s5k4aa[i][1], data, 1);
140                         break;
141
142                 case SENSOR_LONG:
143                         data[0] = init_s5k4aa[i][2];
144                         data[1] = init_s5k4aa[i][3];
145                         err = m5602_write_sensor(sd,
146                                 init_s5k4aa[i][1], data, 2);
147                         break;
148                 default:
149                         info("Invalid stream command, exiting init");
150                         return -EINVAL;
151                 }
152         }
153
154         if (dump_sensor)
155                 s5k4aa_dump_registers(sd);
156
157         if (!err && dmi_check_system(s5k4aa_vflip_dmi_table)) {
158                 u8 data = 0x02;
159                 info("vertical flip quirk active");
160                 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
161                 m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
162                 data |= S5K4AA_RM_V_FLIP;
163                 data &= ~S5K4AA_RM_H_FLIP;
164                 m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
165
166                 /* Decrement COLSTART to preserve color order (BGGR) */
167                 m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
168                 data--;
169                 m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
170
171                 /* Increment ROWSTART to preserve color order (BGGR) */
172                 m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
173                 data++;
174                 m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
175         }
176
177         return (err < 0) ? err : 0;
178 }
179
180 int s5k4aa_power_down(struct sd *sd)
181 {
182         return 0;
183 }
184
185 int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
186 {
187         struct sd *sd = (struct sd *) gspca_dev;
188         u8 data = S5K4AA_PAGE_MAP_2;
189         int err;
190
191         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
192         if (err < 0)
193                 goto out;
194
195         err = m5602_read_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
196         if (err < 0)
197                 goto out;
198
199         *val = data << 8;
200         err = m5602_read_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
201         *val |= data;
202         PDEBUG(D_V4L2, "Read exposure %d", *val);
203 out:
204         return err;
205 }
206
207 int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
208 {
209         struct sd *sd = (struct sd *) gspca_dev;
210         u8 data = S5K4AA_PAGE_MAP_2;
211         int err;
212
213         PDEBUG(D_V4L2, "Set exposure to %d", val);
214         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
215         if (err < 0)
216                 goto out;
217         data = (val >> 8) & 0xff;
218         err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
219         if (err < 0)
220                 goto out;
221         data = val & 0xff;
222         err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
223 out:
224         return err;
225 }
226
227 int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
228 {
229         struct sd *sd = (struct sd *) gspca_dev;
230         u8 data = S5K4AA_PAGE_MAP_2;
231         int err;
232
233         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
234         if (err < 0)
235                 goto out;
236
237         err = m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
238         *val = (data & S5K4AA_RM_V_FLIP) >> 7;
239         PDEBUG(D_V4L2, "Read vertical flip %d", *val);
240
241 out:
242         return err;
243 }
244
245 int s5k4aa_set_vflip(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         PDEBUG(D_V4L2, "Set vertical flip to %d", val);
252         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
253         if (err < 0)
254                 goto out;
255         err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
256         if (err < 0)
257                 goto out;
258         data = ((data & ~S5K4AA_RM_V_FLIP)
259                         | ((val & 0x01) << 7));
260         err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
261         if (err < 0)
262                 goto out;
263
264         if (val) {
265                 err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
266                 if (err < 0)
267                         goto out;
268
269                 data++;
270                 err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
271         } else {
272                 err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
273                 if (err < 0)
274                         goto out;
275
276                 data--;
277                 err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
278         }
279 out:
280         return err;
281 }
282
283 int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
284 {
285         struct sd *sd = (struct sd *) gspca_dev;
286         u8 data = S5K4AA_PAGE_MAP_2;
287         int err;
288
289         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
290         if (err < 0)
291                 goto out;
292
293         err = m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
294         *val = (data & S5K4AA_RM_H_FLIP) >> 6;
295         PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
296 out:
297         return err;
298 }
299
300 int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
301 {
302         struct sd *sd = (struct sd *) gspca_dev;
303         u8 data = S5K4AA_PAGE_MAP_2;
304         int err;
305
306         PDEBUG(D_V4L2, "Set horizontal flip to %d",
307                val);
308         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
309         if (err < 0)
310                 goto out;
311         err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
312         if (err < 0)
313                 goto out;
314
315         data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
316         err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
317         if (err < 0)
318                 goto out;
319
320         if (val) {
321                 err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
322                 if (err < 0)
323                         goto out;
324                 data++;
325                 err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
326                 if (err < 0)
327                         goto out;
328         } else {
329                 err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
330                 if (err < 0)
331                         goto out;
332                 data--;
333                 err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
334         }
335 out:
336         return err;
337 }
338
339 int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
340 {
341         struct sd *sd = (struct sd *) gspca_dev;
342         u8 data = S5K4AA_PAGE_MAP_2;
343         int err;
344
345         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
346         if (err < 0)
347                 goto out;
348
349         err = m5602_read_sensor(sd, S5K4AA_GAIN_2, &data, 1);
350         *val = data;
351         PDEBUG(D_V4L2, "Read gain %d", *val);
352
353 out:
354         return err;
355 }
356
357 int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
358 {
359         struct sd *sd = (struct sd *) gspca_dev;
360         u8 data = S5K4AA_PAGE_MAP_2;
361         int err;
362
363         PDEBUG(D_V4L2, "Set gain to %d", val);
364         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
365         if (err < 0)
366                 goto out;
367
368         data = val & 0xff;
369         err = m5602_write_sensor(sd, S5K4AA_GAIN_2, &data, 1);
370
371 out:
372         return err;
373 }
374
375 static void s5k4aa_dump_registers(struct sd *sd)
376 {
377         int address;
378         u8 page, old_page;
379         m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
380         for (page = 0; page < 16; page++) {
381                 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
382                 info("Dumping the s5k4aa register state for page 0x%x", page);
383                 for (address = 0; address <= 0xff; address++) {
384                         u8 value = 0;
385                         m5602_read_sensor(sd, address, &value, 1);
386                         info("register 0x%x contains 0x%x",
387                              address, value);
388                 }
389         }
390         info("s5k4aa register state dump complete");
391
392         for (page = 0; page < 16; page++) {
393                 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
394                 info("Probing for which registers that are "
395                      "read/write for page 0x%x", page);
396                 for (address = 0; address <= 0xff; address++) {
397                         u8 old_value, ctrl_value, test_value = 0xff;
398
399                         m5602_read_sensor(sd, address, &old_value, 1);
400                         m5602_write_sensor(sd, address, &test_value, 1);
401                         m5602_read_sensor(sd, address, &ctrl_value, 1);
402
403                         if (ctrl_value == test_value)
404                                 info("register 0x%x is writeable", address);
405                         else
406                                 info("register 0x%x is read only", address);
407
408                         /* Restore original value */
409                         m5602_write_sensor(sd, address, &old_value, 1);
410                 }
411         }
412         info("Read/write register probing complete");
413         m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
414 }