Linux-libre 5.4.47-gnu
[librecmc/linux-libre.git] / drivers / media / usb / gspca / m5602 / m5602_s5k4aa.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Driver for the s5k4aa sensor
4  *
5  * Copyright (C) 2008 Erik AndrĂ©n
6  * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
7  * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
8  *
9  * Portions of code to USB interface and ALi driver software,
10  * Copyright (c) 2006 Willem Duinker
11  * v4l2 interface modeled after the V4L2 driver
12  * for SN9C10x PC Camera Controllers
13  */
14
15 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
16
17 #include "m5602_s5k4aa.h"
18
19 static const unsigned char preinit_s5k4aa[][4] = {
20         {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
21         {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
22         {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
23         {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
24         {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
25         {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
26         {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
27
28         {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
29         {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
30         {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
31         {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
32         {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
33         {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
34         {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
35         {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
36         {BRIDGE, M5602_XB_GPIO_DAT, 0x00, 0x00},
37         {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
38         {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
39         {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
40         {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
41         {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
42         {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
43         {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00},
44
45         {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
46         {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
47         {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
48         {BRIDGE, M5602_XB_GPIO_DAT, 0x14, 0x00},
49         {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
50         {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
51         {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
52         {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
53         {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
54         {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
55         {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
56         {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
57         {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
58
59         {SENSOR, S5K4AA_PAGE_MAP, 0x00, 0x00}
60 };
61
62 static const unsigned char init_s5k4aa[][4] = {
63         {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
64         {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
65         {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
66         {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
67         {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
68         {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
69         {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
70
71         {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
72         {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
73         {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
74         {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
75         {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
76         {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
77         {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
78         {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
79         {BRIDGE, M5602_XB_GPIO_DAT, 0x00, 0x00},
80         {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
81         {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
82         {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
83         {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
84         {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
85         {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
86         {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00},
87
88         {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
89         {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
90         {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
91         {BRIDGE, M5602_XB_GPIO_DAT, 0x14, 0x00},
92         {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
93         {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
94         {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
95         {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
96         {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
97         {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
98         {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
99         {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
100         {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
101
102         {SENSOR, S5K4AA_PAGE_MAP, 0x07, 0x00},
103         {SENSOR, 0x36, 0x01, 0x00},
104         {SENSOR, S5K4AA_PAGE_MAP, 0x00, 0x00},
105         {SENSOR, 0x7b, 0xff, 0x00},
106         {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
107         {SENSOR, 0x0c, 0x05, 0x00},
108         {SENSOR, 0x02, 0x0e, 0x00},
109         {SENSOR, S5K4AA_READ_MODE, 0xa0, 0x00},
110         {SENSOR, 0x37, 0x00, 0x00},
111 };
112
113 static const unsigned char VGA_s5k4aa[][4] = {
114         {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
115         {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
116         {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
117         {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00},
118         {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
119         {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
120         {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
121         {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
122         {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
123         {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
124         {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
125         /* VSYNC_PARA, VSYNC_PARA : img height 480 = 0x01e0 */
126         {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
127         {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0, 0x00},
128         {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
129         {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
130         {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
131         {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
132         {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
133         {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
134         /* HSYNC_PARA, HSYNC_PARA : img width 640 = 0x0280 */
135         {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
136         {BRIDGE, M5602_XB_HSYNC_PARA, 0x80, 0x00},
137         {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
138         {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
139         {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, /* 48 MHz */
140
141         {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
142         {SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP | S5K4AA_RM_ROW_SKIP_2X
143                 | S5K4AA_RM_COL_SKIP_2X, 0x00},
144         /* 0x37 : Fix image stability when light is too bright and improves
145          * image quality in 640x480, but worsens it in 1280x1024 */
146         {SENSOR, 0x37, 0x01, 0x00},
147         /* ROWSTART_HI, ROWSTART_LO : 10 + (1024-960)/2 = 42 = 0x002a */
148         {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00},
149         {SENSOR, S5K4AA_ROWSTART_LO, 0x29, 0x00},
150         {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00},
151         {SENSOR, S5K4AA_COLSTART_LO, 0x0c, 0x00},
152         /* window_height_hi, window_height_lo : 960 = 0x03c0 */
153         {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x03, 0x00},
154         {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0xc0, 0x00},
155         /* window_width_hi, window_width_lo : 1280 = 0x0500 */
156         {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00},
157         {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x00, 0x00},
158         {SENSOR, S5K4AA_H_BLANK_HI__, 0x00, 0x00},
159         {SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00}, /* helps to sync... */
160         {SENSOR, S5K4AA_EXPOSURE_HI, 0x01, 0x00},
161         {SENSOR, S5K4AA_EXPOSURE_LO, 0x00, 0x00},
162         {SENSOR, 0x11, 0x04, 0x00},
163         {SENSOR, 0x12, 0xc3, 0x00},
164         {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
165         {SENSOR, 0x02, 0x0e, 0x00},
166 };
167
168 static const unsigned char SXGA_s5k4aa[][4] = {
169         {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
170         {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
171         {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
172         {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00},
173         {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
174         {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
175         {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
176         {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
177         {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
178         {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
179         {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
180         /* VSYNC_PARA, VSYNC_PARA : img height 1024 = 0x0400 */
181         {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
182         {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
183         {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
184         {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
185         {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
186         {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
187         {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
188         {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
189         /* HSYNC_PARA, HSYNC_PARA : img width 1280 = 0x0500 */
190         {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00},
191         {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
192         {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
193         {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
194         {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, /* 48 MHz */
195
196         {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
197         {SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP, 0x00},
198         {SENSOR, 0x37, 0x01, 0x00},
199         {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00},
200         {SENSOR, S5K4AA_ROWSTART_LO, 0x09, 0x00},
201         {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00},
202         {SENSOR, S5K4AA_COLSTART_LO, 0x0a, 0x00},
203         {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x04, 0x00},
204         {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0x00, 0x00},
205         {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00},
206         {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x00, 0x00},
207         {SENSOR, S5K4AA_H_BLANK_HI__, 0x01, 0x00},
208         {SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00},
209         {SENSOR, S5K4AA_EXPOSURE_HI, 0x01, 0x00},
210         {SENSOR, S5K4AA_EXPOSURE_LO, 0x00, 0x00},
211         {SENSOR, 0x11, 0x04, 0x00},
212         {SENSOR, 0x12, 0xc3, 0x00},
213         {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
214         {SENSOR, 0x02, 0x0e, 0x00},
215 };
216
217
218 static int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl);
219 static void s5k4aa_dump_registers(struct sd *sd);
220
221 static const struct v4l2_ctrl_ops s5k4aa_ctrl_ops = {
222         .s_ctrl = s5k4aa_s_ctrl,
223 };
224
225 static
226     const
227         struct dmi_system_id s5k4aa_vflip_dmi_table[] = {
228         {
229                 .ident = "BRUNEINIT",
230                 .matches = {
231                         DMI_MATCH(DMI_SYS_VENDOR, "BRUNENIT"),
232                         DMI_MATCH(DMI_PRODUCT_NAME, "BRUNENIT"),
233                         DMI_MATCH(DMI_BOARD_VERSION, "00030D0000000001")
234                 }
235         }, {
236                 .ident = "Fujitsu-Siemens Amilo Xa 2528",
237                 .matches = {
238                         DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
239                         DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528")
240                 }
241         }, {
242                 .ident = "Fujitsu-Siemens Amilo Xi 2428",
243                 .matches = {
244                         DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
245                         DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2428")
246                 }
247         }, {
248                 .ident = "Fujitsu-Siemens Amilo Xi 2528",
249                 .matches = {
250                         DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
251                         DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2528")
252                 }
253         }, {
254                 .ident = "Fujitsu-Siemens Amilo Xi 2550",
255                 .matches = {
256                         DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
257                         DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550")
258                 }
259         }, {
260                 .ident = "Fujitsu-Siemens Amilo Pa 2548",
261                 .matches = {
262                         DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
263                         DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2548")
264                 }
265         }, {
266                 .ident = "Fujitsu-Siemens Amilo Pi 2530",
267                 .matches = {
268                         DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
269                         DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 2530")
270                 }
271         }, {
272                 .ident = "MSI GX700",
273                 .matches = {
274                         DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
275                         DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
276                         DMI_MATCH(DMI_BIOS_DATE, "12/02/2008")
277                 }
278         }, {
279                 .ident = "MSI GX700",
280                 .matches = {
281                         DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
282                         DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
283                         DMI_MATCH(DMI_BIOS_DATE, "07/26/2007")
284                 }
285         }, {
286                 .ident = "MSI GX700",
287                 .matches = {
288                         DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
289                         DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
290                         DMI_MATCH(DMI_BIOS_DATE, "07/19/2007")
291                 }
292         }, {
293                 .ident = "MSI GX700/GX705/EX700",
294                 .matches = {
295                         DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
296                         DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700")
297                 }
298         }, {
299                 .ident = "MSI L735",
300                 .matches = {
301                         DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
302                         DMI_MATCH(DMI_PRODUCT_NAME, "MS-1717X")
303                 }
304         }, {
305                 .ident = "Lenovo Y300",
306                 .matches = {
307                         DMI_MATCH(DMI_SYS_VENDOR, "L3000 Y300"),
308                         DMI_MATCH(DMI_PRODUCT_NAME, "Y300")
309                 }
310         },
311         { }
312 };
313
314 static struct v4l2_pix_format s5k4aa_modes[] = {
315         {
316                 640,
317                 480,
318                 V4L2_PIX_FMT_SBGGR8,
319                 V4L2_FIELD_NONE,
320                 .sizeimage =
321                         640 * 480,
322                 .bytesperline = 640,
323                 .colorspace = V4L2_COLORSPACE_SRGB,
324                 .priv = 0
325         },
326         {
327                 1280,
328                 1024,
329                 V4L2_PIX_FMT_SBGGR8,
330                 V4L2_FIELD_NONE,
331                 .sizeimage =
332                         1280 * 1024,
333                 .bytesperline = 1280,
334                 .colorspace = V4L2_COLORSPACE_SRGB,
335                 .priv = 0
336         }
337 };
338
339 int s5k4aa_probe(struct sd *sd)
340 {
341         u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
342         const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
343         struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
344         int i, err = 0;
345
346         if (force_sensor) {
347                 if (force_sensor == S5K4AA_SENSOR) {
348                         pr_info("Forcing a %s sensor\n", s5k4aa.name);
349                         goto sensor_found;
350                 }
351                 /* If we want to force another sensor, don't try to probe this
352                  * one */
353                 return -ENODEV;
354         }
355
356         gspca_dbg(gspca_dev, D_PROBE, "Probing for a s5k4aa sensor\n");
357
358         /* Preinit the sensor */
359         for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) {
360                 u8 data[2] = {0x00, 0x00};
361
362                 switch (preinit_s5k4aa[i][0]) {
363                 case BRIDGE:
364                         err = m5602_write_bridge(sd,
365                                                  preinit_s5k4aa[i][1],
366                                                  preinit_s5k4aa[i][2]);
367                         break;
368
369                 case SENSOR:
370                         data[0] = preinit_s5k4aa[i][2];
371                         err = m5602_write_sensor(sd,
372                                                   preinit_s5k4aa[i][1],
373                                                   data, 1);
374                         break;
375
376                 case SENSOR_LONG:
377                         data[0] = preinit_s5k4aa[i][2];
378                         data[1] = preinit_s5k4aa[i][3];
379                         err = m5602_write_sensor(sd,
380                                                   preinit_s5k4aa[i][1],
381                                                   data, 2);
382                         break;
383                 default:
384                         pr_info("Invalid stream command, exiting init\n");
385                         return -EINVAL;
386                 }
387         }
388
389         /* Test some registers, but we don't know their exact meaning yet */
390         if (m5602_read_sensor(sd, 0x00, prod_id, 2))
391                 return -ENODEV;
392         if (m5602_read_sensor(sd, 0x02, prod_id+2, 2))
393                 return -ENODEV;
394         if (m5602_read_sensor(sd, 0x04, prod_id+4, 2))
395                 return -ENODEV;
396
397         if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
398                 return -ENODEV;
399         else
400                 pr_info("Detected a s5k4aa sensor\n");
401
402 sensor_found:
403         sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
404         sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
405
406         return 0;
407 }
408
409 int s5k4aa_start(struct sd *sd)
410 {
411         int i, err = 0;
412         u8 data[2];
413         struct cam *cam = &sd->gspca_dev.cam;
414         struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
415
416         switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) {
417         case 1280:
418                 gspca_dbg(gspca_dev, D_CONF, "Configuring camera for SXGA mode\n");
419
420                 for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) {
421                         switch (SXGA_s5k4aa[i][0]) {
422                         case BRIDGE:
423                                 err = m5602_write_bridge(sd,
424                                                  SXGA_s5k4aa[i][1],
425                                                  SXGA_s5k4aa[i][2]);
426                         break;
427
428                         case SENSOR:
429                                 data[0] = SXGA_s5k4aa[i][2];
430                                 err = m5602_write_sensor(sd,
431                                                  SXGA_s5k4aa[i][1],
432                                                  data, 1);
433                         break;
434
435                         case SENSOR_LONG:
436                                 data[0] = SXGA_s5k4aa[i][2];
437                                 data[1] = SXGA_s5k4aa[i][3];
438                                 err = m5602_write_sensor(sd,
439                                                   SXGA_s5k4aa[i][1],
440                                                   data, 2);
441                         break;
442
443                         default:
444                                 pr_err("Invalid stream command, exiting init\n");
445                                 return -EINVAL;
446                         }
447                 }
448                 break;
449
450         case 640:
451                 gspca_dbg(gspca_dev, D_CONF, "Configuring camera for VGA mode\n");
452
453                 for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) {
454                         switch (VGA_s5k4aa[i][0]) {
455                         case BRIDGE:
456                                 err = m5602_write_bridge(sd,
457                                                  VGA_s5k4aa[i][1],
458                                                  VGA_s5k4aa[i][2]);
459                         break;
460
461                         case SENSOR:
462                                 data[0] = VGA_s5k4aa[i][2];
463                                 err = m5602_write_sensor(sd,
464                                                  VGA_s5k4aa[i][1],
465                                                  data, 1);
466                         break;
467
468                         case SENSOR_LONG:
469                                 data[0] = VGA_s5k4aa[i][2];
470                                 data[1] = VGA_s5k4aa[i][3];
471                                 err = m5602_write_sensor(sd,
472                                                   VGA_s5k4aa[i][1],
473                                                   data, 2);
474                         break;
475
476                         default:
477                                 pr_err("Invalid stream command, exiting init\n");
478                                 return -EINVAL;
479                         }
480                 }
481                 break;
482         }
483         if (err < 0)
484                 return err;
485
486         return 0;
487 }
488
489 int s5k4aa_init(struct sd *sd)
490 {
491         int i, err = 0;
492
493         for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) {
494                 u8 data[2] = {0x00, 0x00};
495
496                 switch (init_s5k4aa[i][0]) {
497                 case BRIDGE:
498                         err = m5602_write_bridge(sd,
499                                 init_s5k4aa[i][1],
500                                 init_s5k4aa[i][2]);
501                         break;
502
503                 case SENSOR:
504                         data[0] = init_s5k4aa[i][2];
505                         err = m5602_write_sensor(sd,
506                                 init_s5k4aa[i][1], data, 1);
507                         break;
508
509                 case SENSOR_LONG:
510                         data[0] = init_s5k4aa[i][2];
511                         data[1] = init_s5k4aa[i][3];
512                         err = m5602_write_sensor(sd,
513                                 init_s5k4aa[i][1], data, 2);
514                         break;
515                 default:
516                         pr_info("Invalid stream command, exiting init\n");
517                         return -EINVAL;
518                 }
519         }
520
521         if (dump_sensor)
522                 s5k4aa_dump_registers(sd);
523
524         return err;
525 }
526
527 int s5k4aa_init_controls(struct sd *sd)
528 {
529         struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
530
531         sd->gspca_dev.vdev.ctrl_handler = hdl;
532         v4l2_ctrl_handler_init(hdl, 6);
533
534         v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_BRIGHTNESS,
535                           0, 0x1f, 1, S5K4AA_DEFAULT_BRIGHTNESS);
536
537         v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_EXPOSURE,
538                           13, 0xfff, 1, 0x100);
539
540         v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_GAIN,
541                           0, 127, 1, S5K4AA_DEFAULT_GAIN);
542
543         v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_SHARPNESS,
544                           0, 1, 1, 1);
545
546         sd->hflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_HFLIP,
547                                       0, 1, 1, 0);
548         sd->vflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_VFLIP,
549                                       0, 1, 1, 0);
550
551         if (hdl->error) {
552                 pr_err("Could not initialize controls\n");
553                 return hdl->error;
554         }
555
556         v4l2_ctrl_cluster(2, &sd->hflip);
557
558         return 0;
559 }
560
561 static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
562 {
563         struct sd *sd = (struct sd *) gspca_dev;
564         u8 data = S5K4AA_PAGE_MAP_2;
565         int err;
566
567         gspca_dbg(gspca_dev, D_CONF, "Set exposure to %d\n", val);
568         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
569         if (err < 0)
570                 return err;
571         data = (val >> 8) & 0xff;
572         err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
573         if (err < 0)
574                 return err;
575         data = val & 0xff;
576         err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
577
578         return err;
579 }
580
581 static int s5k4aa_set_hvflip(struct gspca_dev *gspca_dev)
582 {
583         struct sd *sd = (struct sd *) gspca_dev;
584         u8 data = S5K4AA_PAGE_MAP_2;
585         int err;
586         int hflip = sd->hflip->val;
587         int vflip = sd->vflip->val;
588
589         gspca_dbg(gspca_dev, D_CONF, "Set hvflip %d %d\n", hflip, vflip);
590         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
591         if (err < 0)
592                 return err;
593
594         err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
595         if (err < 0)
596                 return err;
597
598         if (dmi_check_system(s5k4aa_vflip_dmi_table)) {
599                 hflip = !hflip;
600                 vflip = !vflip;
601         }
602
603         data = (data & 0x7f) | (vflip << 7) | (hflip << 6);
604         err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
605         if (err < 0)
606                 return err;
607
608         err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
609         if (err < 0)
610                 return err;
611         if (hflip)
612                 data &= 0xfe;
613         else
614                 data |= 0x01;
615         err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
616         if (err < 0)
617                 return err;
618
619         err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
620         if (err < 0)
621                 return err;
622         if (vflip)
623                 data &= 0xfe;
624         else
625                 data |= 0x01;
626         err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
627         if (err < 0)
628                 return err;
629
630         return 0;
631 }
632
633 static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
634 {
635         struct sd *sd = (struct sd *) gspca_dev;
636         u8 data = S5K4AA_PAGE_MAP_2;
637         int err;
638
639         gspca_dbg(gspca_dev, D_CONF, "Set gain to %d\n", val);
640         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
641         if (err < 0)
642                 return err;
643
644         data = val & 0xff;
645         err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1);
646
647         return err;
648 }
649
650 static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
651 {
652         struct sd *sd = (struct sd *) gspca_dev;
653         u8 data = S5K4AA_PAGE_MAP_2;
654         int err;
655
656         gspca_dbg(gspca_dev, D_CONF, "Set brightness to %d\n", val);
657         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
658         if (err < 0)
659                 return err;
660
661         data = val & 0xff;
662         return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
663 }
664
665 static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
666 {
667         struct sd *sd = (struct sd *) gspca_dev;
668         u8 data = S5K4AA_PAGE_MAP_2;
669         int err;
670
671         gspca_dbg(gspca_dev, D_CONF, "Set noise to %d\n", val);
672         err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
673         if (err < 0)
674                 return err;
675
676         data = val & 0x01;
677         return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
678 }
679
680 static int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl)
681 {
682         struct gspca_dev *gspca_dev =
683                 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
684         int err;
685
686         if (!gspca_dev->streaming)
687                 return 0;
688
689         switch (ctrl->id) {
690         case V4L2_CID_BRIGHTNESS:
691                 err = s5k4aa_set_brightness(gspca_dev, ctrl->val);
692                 break;
693         case V4L2_CID_EXPOSURE:
694                 err = s5k4aa_set_exposure(gspca_dev, ctrl->val);
695                 break;
696         case V4L2_CID_GAIN:
697                 err = s5k4aa_set_gain(gspca_dev, ctrl->val);
698                 break;
699         case V4L2_CID_SHARPNESS:
700                 err = s5k4aa_set_noise(gspca_dev, ctrl->val);
701                 break;
702         case V4L2_CID_HFLIP:
703                 err = s5k4aa_set_hvflip(gspca_dev);
704                 break;
705         default:
706                 return -EINVAL;
707         }
708
709         return err;
710 }
711
712 void s5k4aa_disconnect(struct sd *sd)
713 {
714         sd->sensor = NULL;
715 }
716
717 static void s5k4aa_dump_registers(struct sd *sd)
718 {
719         int address;
720         u8 page, old_page;
721         m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
722         for (page = 0; page < 16; page++) {
723                 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
724                 pr_info("Dumping the s5k4aa register state for page 0x%x\n",
725                         page);
726                 for (address = 0; address <= 0xff; address++) {
727                         u8 value = 0;
728                         m5602_read_sensor(sd, address, &value, 1);
729                         pr_info("register 0x%x contains 0x%x\n",
730                                 address, value);
731                 }
732         }
733         pr_info("s5k4aa register state dump complete\n");
734
735         for (page = 0; page < 16; page++) {
736                 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
737                 pr_info("Probing for which registers that are read/write for page 0x%x\n",
738                         page);
739                 for (address = 0; address <= 0xff; address++) {
740                         u8 old_value, ctrl_value, test_value = 0xff;
741
742                         m5602_read_sensor(sd, address, &old_value, 1);
743                         m5602_write_sensor(sd, address, &test_value, 1);
744                         m5602_read_sensor(sd, address, &ctrl_value, 1);
745
746                         if (ctrl_value == test_value)
747                                 pr_info("register 0x%x is writeable\n",
748                                         address);
749                         else
750                                 pr_info("register 0x%x is read only\n",
751                                         address);
752
753                         /* Restore original value */
754                         m5602_write_sensor(sd, address, &old_value, 1);
755                 }
756         }
757         pr_info("Read/write register probing complete\n");
758         m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
759 }