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