aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/gspca/m5602
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/gspca/m5602')
-rw-r--r--drivers/media/video/gspca/m5602/Kconfig11
-rw-r--r--drivers/media/video/gspca/m5602/Makefile11
-rw-r--r--drivers/media/video/gspca/m5602/m5602_bridge.h163
-rw-r--r--drivers/media/video/gspca/m5602/m5602_core.c434
-rw-r--r--drivers/media/video/gspca/m5602/m5602_mt9m111.c645
-rw-r--r--drivers/media/video/gspca/m5602/m5602_mt9m111.h271
-rw-r--r--drivers/media/video/gspca/m5602/m5602_ov7660.c487
-rw-r--r--drivers/media/video/gspca/m5602/m5602_ov7660.h260
-rw-r--r--drivers/media/video/gspca/m5602/m5602_ov9650.c880
-rw-r--r--drivers/media/video/gspca/m5602/m5602_ov9650.h307
-rw-r--r--drivers/media/video/gspca/m5602/m5602_po1030.c762
-rw-r--r--drivers/media/video/gspca/m5602/m5602_po1030.h272
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k4aa.c721
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k4aa.h283
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k83a.c601
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k83a.h193
-rw-r--r--drivers/media/video/gspca/m5602/m5602_sensor.h70
17 files changed, 6371 insertions, 0 deletions
diff --git a/drivers/media/video/gspca/m5602/Kconfig b/drivers/media/video/gspca/m5602/Kconfig
new file mode 100644
index 00000000000..5a69016ed75
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/Kconfig
@@ -0,0 +1,11 @@
1config USB_M5602
2 tristate "ALi USB m5602 Camera Driver"
3 depends on VIDEO_V4L2 && USB_GSPCA
4 help
5 Say Y here if you want support for cameras based on the
6 ALi m5602 connected to various image sensors.
7
8 See <file:Documentation/video4linux/m5602.txt> for more info.
9
10 To compile this driver as a module, choose M here: the
11 module will be called gspca_m5602.
diff --git a/drivers/media/video/gspca/m5602/Makefile b/drivers/media/video/gspca/m5602/Makefile
new file mode 100644
index 00000000000..bf7a19a1e6d
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/Makefile
@@ -0,0 +1,11 @@
1obj-$(CONFIG_USB_M5602) += gspca_m5602.o
2
3gspca_m5602-objs := m5602_core.o \
4 m5602_ov9650.o \
5 m5602_ov7660.o \
6 m5602_mt9m111.o \
7 m5602_po1030.o \
8 m5602_s5k83a.o \
9 m5602_s5k4aa.o
10
11EXTRA_CFLAGS += -Idrivers/media/video/gspca
diff --git a/drivers/media/video/gspca/m5602/m5602_bridge.h b/drivers/media/video/gspca/m5602/m5602_bridge.h
new file mode 100644
index 00000000000..51af3ee3ab8
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_bridge.h
@@ -0,0 +1,163 @@
1/*
2 * USB Driver for ALi m5602 based webcams
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#ifndef M5602_BRIDGE_H_
20#define M5602_BRIDGE_H_
21
22#include <linux/slab.h>
23#include "gspca.h"
24
25#define MODULE_NAME "ALi m5602"
26
27/*****************************************************************************/
28
29#define M5602_XB_SENSOR_TYPE 0x00
30#define M5602_XB_SENSOR_CTRL 0x01
31#define M5602_XB_LINE_OF_FRAME_H 0x02
32#define M5602_XB_LINE_OF_FRAME_L 0x03
33#define M5602_XB_PIX_OF_LINE_H 0x04
34#define M5602_XB_PIX_OF_LINE_L 0x05
35#define M5602_XB_VSYNC_PARA 0x06
36#define M5602_XB_HSYNC_PARA 0x07
37#define M5602_XB_TEST_MODE_1 0x08
38#define M5602_XB_TEST_MODE_2 0x09
39#define M5602_XB_SIG_INI 0x0a
40#define M5602_XB_DS_PARA 0x0e
41#define M5602_XB_TRIG_PARA 0x0f
42#define M5602_XB_CLK_PD 0x10
43#define M5602_XB_MCU_CLK_CTRL 0x12
44#define M5602_XB_MCU_CLK_DIV 0x13
45#define M5602_XB_SEN_CLK_CTRL 0x14
46#define M5602_XB_SEN_CLK_DIV 0x15
47#define M5602_XB_AUD_CLK_CTRL 0x16
48#define M5602_XB_AUD_CLK_DIV 0x17
49#define M5602_OB_AC_LINK_STATE 0x22
50#define M5602_OB_PCM_SLOT_INDEX 0x24
51#define M5602_OB_GPIO_SLOT_INDEX 0x25
52#define M5602_OB_ACRX_STATUS_ADDRESS_H 0x28
53#define M5602_OB_ACRX_STATUS_DATA_L 0x29
54#define M5602_OB_ACRX_STATUS_DATA_H 0x2a
55#define M5602_OB_ACTX_COMMAND_ADDRESS 0x31
56#define M5602_OB_ACRX_COMMAND_DATA_L 0x32
57#define M5602_OB_ACTX_COMMAND_DATA_H 0X33
58#define M5602_XB_DEVCTR1 0x41
59#define M5602_XB_EPSETR0 0x42
60#define M5602_XB_EPAFCTR 0x47
61#define M5602_XB_EPBFCTR 0x49
62#define M5602_XB_EPEFCTR 0x4f
63#define M5602_XB_TEST_REG 0x53
64#define M5602_XB_ALT2SIZE 0x54
65#define M5602_XB_ALT3SIZE 0x55
66#define M5602_XB_OBSFRAME 0x56
67#define M5602_XB_PWR_CTL 0x59
68#define M5602_XB_ADC_CTRL 0x60
69#define M5602_XB_ADC_DATA 0x61
70#define M5602_XB_MISC_CTRL 0x62
71#define M5602_XB_SNAPSHOT 0x63
72#define M5602_XB_SCRATCH_1 0x64
73#define M5602_XB_SCRATCH_2 0x65
74#define M5602_XB_SCRATCH_3 0x66
75#define M5602_XB_SCRATCH_4 0x67
76#define M5602_XB_I2C_CTRL 0x68
77#define M5602_XB_I2C_CLK_DIV 0x69
78#define M5602_XB_I2C_DEV_ADDR 0x6a
79#define M5602_XB_I2C_REG_ADDR 0x6b
80#define M5602_XB_I2C_DATA 0x6c
81#define M5602_XB_I2C_STATUS 0x6d
82#define M5602_XB_GPIO_DAT_H 0x70
83#define M5602_XB_GPIO_DAT_L 0x71
84#define M5602_XB_GPIO_DIR_H 0x72
85#define M5602_XB_GPIO_DIR_L 0x73
86#define M5602_XB_GPIO_EN_H 0x74
87#define M5602_XB_GPIO_EN_L 0x75
88#define M5602_XB_GPIO_DAT 0x76
89#define M5602_XB_GPIO_DIR 0x77
90#define M5602_XB_SEN_CLK_CONTROL 0x80
91#define M5602_XB_SEN_CLK_DIVISION 0x81
92#define M5602_XB_CPR_CLK_CONTROL 0x82
93#define M5602_XB_CPR_CLK_DIVISION 0x83
94#define M5602_XB_MCU_CLK_CONTROL 0x84
95#define M5602_XB_MCU_CLK_DIVISION 0x85
96#define M5602_XB_DCT_CLK_CONTROL 0x86
97#define M5602_XB_DCT_CLK_DIVISION 0x87
98#define M5602_XB_EC_CLK_CONTROL 0x88
99#define M5602_XB_EC_CLK_DIVISION 0x89
100#define M5602_XB_LBUF_CLK_CONTROL 0x8a
101#define M5602_XB_LBUF_CLK_DIVISION 0x8b
102
103#define I2C_BUSY 0x80
104
105/*****************************************************************************/
106
107/* Driver info */
108#define DRIVER_AUTHOR "ALi m5602 Linux Driver Project"
109#define DRIVER_DESC "ALi m5602 webcam driver"
110
111#define M5602_ISOC_ENDPOINT_ADDR 0x81
112#define M5602_INTR_ENDPOINT_ADDR 0x82
113
114#define M5602_URB_MSG_TIMEOUT 5000
115
116/*****************************************************************************/
117
118/* A skeleton used for sending messages to the m5602 bridge */
119static const unsigned char bridge_urb_skeleton[] = {
120 0x13, 0x00, 0x81, 0x00
121};
122
123/* A skeleton used for sending messages to the sensor */
124static const unsigned char sensor_urb_skeleton[] = {
125 0x23, M5602_XB_GPIO_EN_H, 0x81, 0x06,
126 0x23, M5602_XB_MISC_CTRL, 0x81, 0x80,
127 0x13, M5602_XB_I2C_DEV_ADDR, 0x81, 0x00,
128 0x13, M5602_XB_I2C_REG_ADDR, 0x81, 0x00,
129 0x13, M5602_XB_I2C_DATA, 0x81, 0x00,
130 0x13, M5602_XB_I2C_CTRL, 0x81, 0x11
131};
132
133struct sd {
134 struct gspca_dev gspca_dev;
135
136 /* A pointer to the currently connected sensor */
137 const struct m5602_sensor *sensor;
138
139 struct sd_desc *desc;
140
141 /* Sensor private data */
142 void *sensor_priv;
143
144 /* The current frame's id, used to detect frame boundaries */
145 u8 frame_id;
146
147 /* The current frame count */
148 u32 frame_count;
149};
150
151int m5602_read_bridge(
152 struct sd *sd, const u8 address, u8 *i2c_data);
153
154int m5602_write_bridge(
155 struct sd *sd, const u8 address, const u8 i2c_data);
156
157int m5602_write_sensor(struct sd *sd, const u8 address,
158 u8 *i2c_data, const u8 len);
159
160int m5602_read_sensor(struct sd *sd, const u8 address,
161 u8 *i2c_data, const u8 len);
162
163#endif
diff --git a/drivers/media/video/gspca/m5602/m5602_core.c b/drivers/media/video/gspca/m5602/m5602_core.c
new file mode 100644
index 00000000000..a7722b1aef9
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_core.c
@@ -0,0 +1,434 @@
1 /*
2 * USB Driver for ALi m5602 based webcams
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_ov9650.h"
20#include "m5602_ov7660.h"
21#include "m5602_mt9m111.h"
22#include "m5602_po1030.h"
23#include "m5602_s5k83a.h"
24#include "m5602_s5k4aa.h"
25
26/* Kernel module parameters */
27int force_sensor;
28static int dump_bridge;
29int dump_sensor;
30
31static const struct usb_device_id m5602_table[] = {
32 {USB_DEVICE(0x0402, 0x5602)},
33 {}
34};
35
36MODULE_DEVICE_TABLE(usb, m5602_table);
37
38/* Reads a byte from the m5602 */
39int m5602_read_bridge(struct sd *sd, const u8 address, u8 *i2c_data)
40{
41 int err;
42 struct usb_device *udev = sd->gspca_dev.dev;
43 __u8 *buf = sd->gspca_dev.usb_buf;
44
45 err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
46 0x04, 0xc0, 0x14,
47 0x8100 + address, buf,
48 1, M5602_URB_MSG_TIMEOUT);
49 *i2c_data = buf[0];
50
51 PDEBUG(D_CONF, "Reading bridge register 0x%x containing 0x%x",
52 address, *i2c_data);
53
54 /* usb_control_msg(...) returns the number of bytes sent upon success,
55 mask that and return zero instead*/
56 return (err < 0) ? err : 0;
57}
58
59/* Writes a byte to the m5602 */
60int m5602_write_bridge(struct sd *sd, const u8 address, const u8 i2c_data)
61{
62 int err;
63 struct usb_device *udev = sd->gspca_dev.dev;
64 __u8 *buf = sd->gspca_dev.usb_buf;
65
66 PDEBUG(D_CONF, "Writing bridge register 0x%x with 0x%x",
67 address, i2c_data);
68
69 memcpy(buf, bridge_urb_skeleton,
70 sizeof(bridge_urb_skeleton));
71 buf[1] = address;
72 buf[3] = i2c_data;
73
74 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
75 0x04, 0x40, 0x19,
76 0x0000, buf,
77 4, M5602_URB_MSG_TIMEOUT);
78
79 /* usb_control_msg(...) returns the number of bytes sent upon success,
80 mask that and return zero instead */
81 return (err < 0) ? err : 0;
82}
83
84static int m5602_wait_for_i2c(struct sd *sd)
85{
86 int err;
87 u8 data;
88
89 do {
90 err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, &data);
91 } while ((data & I2C_BUSY) && !err);
92 return err;
93}
94
95int m5602_read_sensor(struct sd *sd, const u8 address,
96 u8 *i2c_data, const u8 len)
97{
98 int err, i;
99
100 if (!len || len > sd->sensor->i2c_regW)
101 return -EINVAL;
102
103 err = m5602_wait_for_i2c(sd);
104 if (err < 0)
105 return err;
106
107 err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
108 sd->sensor->i2c_slave_id);
109 if (err < 0)
110 return err;
111
112 err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
113 if (err < 0)
114 return err;
115
116 /* Sensors with registers that are of only
117 one byte width are differently read */
118
119 /* FIXME: This works with the ov9650, but has issues with the po1030 */
120 if (sd->sensor->i2c_regW == 1) {
121 err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 1);
122 if (err < 0)
123 return err;
124
125 err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x08);
126 } else {
127 err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x18 + len);
128 }
129
130 for (i = 0; (i < len) && !err; i++) {
131 err = m5602_wait_for_i2c(sd);
132 if (err < 0)
133 return err;
134
135 err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
136
137 PDEBUG(D_CONF, "Reading sensor register "
138 "0x%x containing 0x%x ", address, *i2c_data);
139 }
140 return err;
141}
142
143int m5602_write_sensor(struct sd *sd, const u8 address,
144 u8 *i2c_data, const u8 len)
145{
146 int err, i;
147 u8 *p;
148 struct usb_device *udev = sd->gspca_dev.dev;
149 __u8 *buf = sd->gspca_dev.usb_buf;
150
151 /* No sensor with a data width larger than 16 bits has yet been seen */
152 if (len > sd->sensor->i2c_regW || !len)
153 return -EINVAL;
154
155 memcpy(buf, sensor_urb_skeleton,
156 sizeof(sensor_urb_skeleton));
157
158 buf[11] = sd->sensor->i2c_slave_id;
159 buf[15] = address;
160
161 /* Special case larger sensor writes */
162 p = buf + 16;
163
164 /* Copy a four byte write sequence for each byte to be written to */
165 for (i = 0; i < len; i++) {
166 memcpy(p, sensor_urb_skeleton + 16, 4);
167 p[3] = i2c_data[i];
168 p += 4;
169 PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
170 address, i2c_data[i]);
171 }
172
173 /* Copy the tailer */
174 memcpy(p, sensor_urb_skeleton + 20, 4);
175
176 /* Set the total length */
177 p[3] = 0x10 + len;
178
179 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
180 0x04, 0x40, 0x19,
181 0x0000, buf,
182 20 + len * 4, M5602_URB_MSG_TIMEOUT);
183
184 return (err < 0) ? err : 0;
185}
186
187/* Dump all the registers of the m5602 bridge,
188 unfortunately this breaks the camera until it's power cycled */
189static void m5602_dump_bridge(struct sd *sd)
190{
191 int i;
192 for (i = 0; i < 0x80; i++) {
193 unsigned char val = 0;
194 m5602_read_bridge(sd, i, &val);
195 info("ALi m5602 address 0x%x contains 0x%x", i, val);
196 }
197 info("Warning: The ALi m5602 webcam probably won't work "
198 "until it's power cycled");
199}
200
201static int m5602_probe_sensor(struct sd *sd)
202{
203 /* Try the po1030 */
204 sd->sensor = &po1030;
205 if (!sd->sensor->probe(sd))
206 return 0;
207
208 /* Try the mt9m111 sensor */
209 sd->sensor = &mt9m111;
210 if (!sd->sensor->probe(sd))
211 return 0;
212
213 /* Try the s5k4aa */
214 sd->sensor = &s5k4aa;
215 if (!sd->sensor->probe(sd))
216 return 0;
217
218 /* Try the ov9650 */
219 sd->sensor = &ov9650;
220 if (!sd->sensor->probe(sd))
221 return 0;
222
223 /* Try the ov7660 */
224 sd->sensor = &ov7660;
225 if (!sd->sensor->probe(sd))
226 return 0;
227
228 /* Try the s5k83a */
229 sd->sensor = &s5k83a;
230 if (!sd->sensor->probe(sd))
231 return 0;
232
233 /* More sensor probe function goes here */
234 info("Failed to find a sensor");
235 sd->sensor = NULL;
236 return -ENODEV;
237}
238
239static int m5602_configure(struct gspca_dev *gspca_dev,
240 const struct usb_device_id *id);
241
242static int m5602_init(struct gspca_dev *gspca_dev)
243{
244 struct sd *sd = (struct sd *) gspca_dev;
245 int err;
246
247 PDEBUG(D_CONF, "Initializing ALi m5602 webcam");
248 /* Run the init sequence */
249 err = sd->sensor->init(sd);
250
251 return err;
252}
253
254static int m5602_start_transfer(struct gspca_dev *gspca_dev)
255{
256 struct sd *sd = (struct sd *) gspca_dev;
257 __u8 *buf = sd->gspca_dev.usb_buf;
258 int err;
259
260 /* Send start command to the camera */
261 const u8 buffer[4] = {0x13, 0xf9, 0x0f, 0x01};
262
263 if (sd->sensor->start)
264 sd->sensor->start(sd);
265
266 memcpy(buf, buffer, sizeof(buffer));
267 err = usb_control_msg(gspca_dev->dev,
268 usb_sndctrlpipe(gspca_dev->dev, 0),
269 0x04, 0x40, 0x19, 0x0000, buf,
270 sizeof(buffer), M5602_URB_MSG_TIMEOUT);
271
272 PDEBUG(D_STREAM, "Transfer started");
273 return (err < 0) ? err : 0;
274}
275
276static void m5602_urb_complete(struct gspca_dev *gspca_dev,
277 u8 *data, int len)
278{
279 struct sd *sd = (struct sd *) gspca_dev;
280
281 if (len < 6) {
282 PDEBUG(D_PACK, "Packet is less than 6 bytes");
283 return;
284 }
285
286 /* Frame delimiter: ff xx xx xx ff ff */
287 if (data[0] == 0xff && data[4] == 0xff && data[5] == 0xff &&
288 data[2] != sd->frame_id) {
289 PDEBUG(D_FRAM, "Frame delimiter detected");
290 sd->frame_id = data[2];
291
292 /* Remove the extra fluff appended on each header */
293 data += 6;
294 len -= 6;
295
296 /* Complete the last frame (if any) */
297 gspca_frame_add(gspca_dev, LAST_PACKET,
298 NULL, 0);
299 sd->frame_count++;
300
301 /* Create a new frame */
302 gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
303
304 PDEBUG(D_FRAM, "Starting new frame %d",
305 sd->frame_count);
306
307 } else {
308 int cur_frame_len;
309
310 cur_frame_len = gspca_dev->image_len;
311 /* Remove urb header */
312 data += 4;
313 len -= 4;
314
315 if (cur_frame_len + len <= gspca_dev->frsz) {
316 PDEBUG(D_FRAM, "Continuing frame %d copying %d bytes",
317 sd->frame_count, len);
318
319 gspca_frame_add(gspca_dev, INTER_PACKET,
320 data, len);
321 } else {
322 /* Add the remaining data up to frame size */
323 gspca_frame_add(gspca_dev, INTER_PACKET, data,
324 gspca_dev->frsz - cur_frame_len);
325 }
326 }
327}
328
329static void m5602_stop_transfer(struct gspca_dev *gspca_dev)
330{
331 struct sd *sd = (struct sd *) gspca_dev;
332
333 /* Run the sensor specific end transfer sequence */
334 if (sd->sensor->stop)
335 sd->sensor->stop(sd);
336}
337
338/* sub-driver description, the ctrl and nctrl is filled at probe time */
339static struct sd_desc sd_desc = {
340 .name = MODULE_NAME,
341 .config = m5602_configure,
342 .init = m5602_init,
343 .start = m5602_start_transfer,
344 .stopN = m5602_stop_transfer,
345 .pkt_scan = m5602_urb_complete
346};
347
348/* this function is called at probe time */
349static int m5602_configure(struct gspca_dev *gspca_dev,
350 const struct usb_device_id *id)
351{
352 struct sd *sd = (struct sd *) gspca_dev;
353 struct cam *cam;
354 int err;
355
356 cam = &gspca_dev->cam;
357 sd->desc = &sd_desc;
358
359 if (dump_bridge)
360 m5602_dump_bridge(sd);
361
362 /* Probe sensor */
363 err = m5602_probe_sensor(sd);
364 if (err)
365 goto fail;
366
367 return 0;
368
369fail:
370 PDEBUG(D_ERR, "ALi m5602 webcam failed");
371 cam->cam_mode = NULL;
372 cam->nmodes = 0;
373
374 return err;
375}
376
377static int m5602_probe(struct usb_interface *intf,
378 const struct usb_device_id *id)
379{
380 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
381 THIS_MODULE);
382}
383
384static void m5602_disconnect(struct usb_interface *intf)
385{
386 struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
387 struct sd *sd = (struct sd *) gspca_dev;
388
389 if (sd->sensor->disconnect)
390 sd->sensor->disconnect(sd);
391
392 gspca_disconnect(intf);
393}
394
395static struct usb_driver sd_driver = {
396 .name = MODULE_NAME,
397 .id_table = m5602_table,
398 .probe = m5602_probe,
399#ifdef CONFIG_PM
400 .suspend = gspca_suspend,
401 .resume = gspca_resume,
402#endif
403 .disconnect = m5602_disconnect
404};
405
406/* -- module insert / remove -- */
407static int __init mod_m5602_init(void)
408{
409 return usb_register(&sd_driver);
410}
411
412static void __exit mod_m5602_exit(void)
413{
414 usb_deregister(&sd_driver);
415}
416
417module_init(mod_m5602_init);
418module_exit(mod_m5602_exit);
419
420MODULE_AUTHOR(DRIVER_AUTHOR);
421MODULE_DESCRIPTION(DRIVER_DESC);
422MODULE_LICENSE("GPL");
423module_param(force_sensor, int, S_IRUGO | S_IWUSR);
424MODULE_PARM_DESC(force_sensor,
425 "forces detection of a sensor, "
426 "1 = OV9650, 2 = S5K83A, 3 = S5K4AA, "
427 "4 = MT9M111, 5 = PO1030, 6 = OV7660");
428
429module_param(dump_bridge, bool, S_IRUGO | S_IWUSR);
430MODULE_PARM_DESC(dump_bridge, "Dumps all usb bridge registers at startup");
431
432module_param(dump_sensor, bool, S_IRUGO | S_IWUSR);
433MODULE_PARM_DESC(dump_sensor, "Dumps all usb sensor registers "
434 "at startup providing a sensor is found");
diff --git a/drivers/media/video/gspca/m5602/m5602_mt9m111.c b/drivers/media/video/gspca/m5602/m5602_mt9m111.c
new file mode 100644
index 00000000000..0d605a52b92
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_mt9m111.c
@@ -0,0 +1,645 @@
1/*
2 * Driver for the mt9m111 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_mt9m111.h"
20
21static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
22static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
23static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
24static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
25static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
26static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val);
27static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
28 __s32 val);
29static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev,
30 __s32 *val);
31static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val);
32static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val);
33static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
34static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
35static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
36static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
37
38static struct v4l2_pix_format mt9m111_modes[] = {
39 {
40 640,
41 480,
42 V4L2_PIX_FMT_SBGGR8,
43 V4L2_FIELD_NONE,
44 .sizeimage = 640 * 480,
45 .bytesperline = 640,
46 .colorspace = V4L2_COLORSPACE_SRGB,
47 .priv = 0
48 }
49};
50
51static const struct ctrl mt9m111_ctrls[] = {
52#define VFLIP_IDX 0
53 {
54 {
55 .id = V4L2_CID_VFLIP,
56 .type = V4L2_CTRL_TYPE_BOOLEAN,
57 .name = "vertical flip",
58 .minimum = 0,
59 .maximum = 1,
60 .step = 1,
61 .default_value = 0
62 },
63 .set = mt9m111_set_vflip,
64 .get = mt9m111_get_vflip
65 },
66#define HFLIP_IDX 1
67 {
68 {
69 .id = V4L2_CID_HFLIP,
70 .type = V4L2_CTRL_TYPE_BOOLEAN,
71 .name = "horizontal flip",
72 .minimum = 0,
73 .maximum = 1,
74 .step = 1,
75 .default_value = 0
76 },
77 .set = mt9m111_set_hflip,
78 .get = mt9m111_get_hflip
79 },
80#define GAIN_IDX 2
81 {
82 {
83 .id = V4L2_CID_GAIN,
84 .type = V4L2_CTRL_TYPE_INTEGER,
85 .name = "gain",
86 .minimum = 0,
87 .maximum = (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2,
88 .step = 1,
89 .default_value = MT9M111_DEFAULT_GAIN,
90 .flags = V4L2_CTRL_FLAG_SLIDER
91 },
92 .set = mt9m111_set_gain,
93 .get = mt9m111_get_gain
94 },
95#define AUTO_WHITE_BALANCE_IDX 3
96 {
97 {
98 .id = V4L2_CID_AUTO_WHITE_BALANCE,
99 .type = V4L2_CTRL_TYPE_BOOLEAN,
100 .name = "auto white balance",
101 .minimum = 0,
102 .maximum = 1,
103 .step = 1,
104 .default_value = 0,
105 },
106 .set = mt9m111_set_auto_white_balance,
107 .get = mt9m111_get_auto_white_balance
108 },
109#define GREEN_BALANCE_IDX 4
110 {
111 {
112 .id = M5602_V4L2_CID_GREEN_BALANCE,
113 .type = V4L2_CTRL_TYPE_INTEGER,
114 .name = "green balance",
115 .minimum = 0x00,
116 .maximum = 0x7ff,
117 .step = 0x1,
118 .default_value = MT9M111_GREEN_GAIN_DEFAULT,
119 .flags = V4L2_CTRL_FLAG_SLIDER
120 },
121 .set = mt9m111_set_green_balance,
122 .get = mt9m111_get_green_balance
123 },
124#define BLUE_BALANCE_IDX 5
125 {
126 {
127 .id = V4L2_CID_BLUE_BALANCE,
128 .type = V4L2_CTRL_TYPE_INTEGER,
129 .name = "blue balance",
130 .minimum = 0x00,
131 .maximum = 0x7ff,
132 .step = 0x1,
133 .default_value = MT9M111_BLUE_GAIN_DEFAULT,
134 .flags = V4L2_CTRL_FLAG_SLIDER
135 },
136 .set = mt9m111_set_blue_balance,
137 .get = mt9m111_get_blue_balance
138 },
139#define RED_BALANCE_IDX 5
140 {
141 {
142 .id = V4L2_CID_RED_BALANCE,
143 .type = V4L2_CTRL_TYPE_INTEGER,
144 .name = "red balance",
145 .minimum = 0x00,
146 .maximum = 0x7ff,
147 .step = 0x1,
148 .default_value = MT9M111_RED_GAIN_DEFAULT,
149 .flags = V4L2_CTRL_FLAG_SLIDER
150 },
151 .set = mt9m111_set_red_balance,
152 .get = mt9m111_get_red_balance
153 },
154};
155
156static void mt9m111_dump_registers(struct sd *sd);
157
158int mt9m111_probe(struct sd *sd)
159{
160 u8 data[2] = {0x00, 0x00};
161 int i;
162 s32 *sensor_settings;
163
164 if (force_sensor) {
165 if (force_sensor == MT9M111_SENSOR) {
166 info("Forcing a %s sensor", mt9m111.name);
167 goto sensor_found;
168 }
169 /* If we want to force another sensor, don't try to probe this
170 * one */
171 return -ENODEV;
172 }
173
174 PDEBUG(D_PROBE, "Probing for a mt9m111 sensor");
175
176 /* Do the preinit */
177 for (i = 0; i < ARRAY_SIZE(preinit_mt9m111); i++) {
178 if (preinit_mt9m111[i][0] == BRIDGE) {
179 m5602_write_bridge(sd,
180 preinit_mt9m111[i][1],
181 preinit_mt9m111[i][2]);
182 } else {
183 data[0] = preinit_mt9m111[i][2];
184 data[1] = preinit_mt9m111[i][3];
185 m5602_write_sensor(sd,
186 preinit_mt9m111[i][1], data, 2);
187 }
188 }
189
190 if (m5602_read_sensor(sd, MT9M111_SC_CHIPVER, data, 2))
191 return -ENODEV;
192
193 if ((data[0] == 0x14) && (data[1] == 0x3a)) {
194 info("Detected a mt9m111 sensor");
195 goto sensor_found;
196 }
197
198 return -ENODEV;
199
200sensor_found:
201 sensor_settings = kmalloc(ARRAY_SIZE(mt9m111_ctrls) * sizeof(s32),
202 GFP_KERNEL);
203 if (!sensor_settings)
204 return -ENOMEM;
205
206 sd->gspca_dev.cam.cam_mode = mt9m111_modes;
207 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(mt9m111_modes);
208 sd->desc->ctrls = mt9m111_ctrls;
209 sd->desc->nctrls = ARRAY_SIZE(mt9m111_ctrls);
210
211 for (i = 0; i < ARRAY_SIZE(mt9m111_ctrls); i++)
212 sensor_settings[i] = mt9m111_ctrls[i].qctrl.default_value;
213 sd->sensor_priv = sensor_settings;
214
215 return 0;
216}
217
218int mt9m111_init(struct sd *sd)
219{
220 int i, err = 0;
221 s32 *sensor_settings = sd->sensor_priv;
222
223 /* Init the sensor */
224 for (i = 0; i < ARRAY_SIZE(init_mt9m111) && !err; i++) {
225 u8 data[2];
226
227 if (init_mt9m111[i][0] == BRIDGE) {
228 err = m5602_write_bridge(sd,
229 init_mt9m111[i][1],
230 init_mt9m111[i][2]);
231 } else {
232 data[0] = init_mt9m111[i][2];
233 data[1] = init_mt9m111[i][3];
234 err = m5602_write_sensor(sd,
235 init_mt9m111[i][1], data, 2);
236 }
237 }
238
239 if (dump_sensor)
240 mt9m111_dump_registers(sd);
241
242 err = mt9m111_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
243 if (err < 0)
244 return err;
245
246 err = mt9m111_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
247 if (err < 0)
248 return err;
249
250 err = mt9m111_set_green_balance(&sd->gspca_dev,
251 sensor_settings[GREEN_BALANCE_IDX]);
252 if (err < 0)
253 return err;
254
255 err = mt9m111_set_blue_balance(&sd->gspca_dev,
256 sensor_settings[BLUE_BALANCE_IDX]);
257 if (err < 0)
258 return err;
259
260 err = mt9m111_set_red_balance(&sd->gspca_dev,
261 sensor_settings[RED_BALANCE_IDX]);
262 if (err < 0)
263 return err;
264
265 return mt9m111_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
266}
267
268int mt9m111_start(struct sd *sd)
269{
270 int i, err = 0;
271 u8 data[2];
272 struct cam *cam = &sd->gspca_dev.cam;
273 s32 *sensor_settings = sd->sensor_priv;
274
275 int width = cam->cam_mode[sd->gspca_dev.curr_mode].width - 1;
276 int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
277
278 for (i = 0; i < ARRAY_SIZE(start_mt9m111) && !err; i++) {
279 if (start_mt9m111[i][0] == BRIDGE) {
280 err = m5602_write_bridge(sd,
281 start_mt9m111[i][1],
282 start_mt9m111[i][2]);
283 } else {
284 data[0] = start_mt9m111[i][2];
285 data[1] = start_mt9m111[i][3];
286 err = m5602_write_sensor(sd,
287 start_mt9m111[i][1], data, 2);
288 }
289 }
290 if (err < 0)
291 return err;
292
293 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff);
294 if (err < 0)
295 return err;
296
297 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff));
298 if (err < 0)
299 return err;
300
301 for (i = 0; i < 2 && !err; i++)
302 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
303 if (err < 0)
304 return err;
305
306 err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
307 if (err < 0)
308 return err;
309
310 err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 2);
311 if (err < 0)
312 return err;
313
314 for (i = 0; i < 2 && !err; i++)
315 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 0);
316 if (err < 0)
317 return err;
318
319 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
320 (width >> 8) & 0xff);
321 if (err < 0)
322 return err;
323
324 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, width & 0xff);
325 if (err < 0)
326 return err;
327
328 err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
329 if (err < 0)
330 return err;
331
332 switch (width) {
333 case 640:
334 PDEBUG(D_V4L2, "Configuring camera for VGA mode");
335 data[0] = MT9M111_RMB_OVER_SIZED;
336 data[1] = MT9M111_RMB_ROW_SKIP_2X |
337 MT9M111_RMB_COLUMN_SKIP_2X |
338 (sensor_settings[VFLIP_IDX] << 0) |
339 (sensor_settings[HFLIP_IDX] << 1);
340
341 err = m5602_write_sensor(sd,
342 MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
343 break;
344
345 case 320:
346 PDEBUG(D_V4L2, "Configuring camera for QVGA mode");
347 data[0] = MT9M111_RMB_OVER_SIZED;
348 data[1] = MT9M111_RMB_ROW_SKIP_4X |
349 MT9M111_RMB_COLUMN_SKIP_4X |
350 (sensor_settings[VFLIP_IDX] << 0) |
351 (sensor_settings[HFLIP_IDX] << 1);
352 err = m5602_write_sensor(sd,
353 MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
354 break;
355 }
356 return err;
357}
358
359void mt9m111_disconnect(struct sd *sd)
360{
361 sd->sensor = NULL;
362 kfree(sd->sensor_priv);
363}
364
365static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
366{
367 struct sd *sd = (struct sd *) gspca_dev;
368 s32 *sensor_settings = sd->sensor_priv;
369
370 *val = sensor_settings[VFLIP_IDX];
371 PDEBUG(D_V4L2, "Read vertical flip %d", *val);
372
373 return 0;
374}
375
376static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
377{
378 int err;
379 u8 data[2] = {0x00, 0x00};
380 struct sd *sd = (struct sd *) gspca_dev;
381 s32 *sensor_settings = sd->sensor_priv;
382
383 PDEBUG(D_V4L2, "Set vertical flip to %d", val);
384
385 sensor_settings[VFLIP_IDX] = val;
386
387 /* The mt9m111 is flipped by default */
388 val = !val;
389
390 /* Set the correct page map */
391 err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
392 if (err < 0)
393 return err;
394
395 err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
396 if (err < 0)
397 return err;
398
399 data[1] = (data[1] & 0xfe) | val;
400 err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
401 data, 2);
402 return err;
403}
404
405static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
406{
407 struct sd *sd = (struct sd *) gspca_dev;
408 s32 *sensor_settings = sd->sensor_priv;
409
410 *val = sensor_settings[HFLIP_IDX];
411 PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
412
413 return 0;
414}
415
416static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
417{
418 int err;
419 u8 data[2] = {0x00, 0x00};
420 struct sd *sd = (struct sd *) gspca_dev;
421 s32 *sensor_settings = sd->sensor_priv;
422
423 PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
424
425 sensor_settings[HFLIP_IDX] = val;
426
427 /* The mt9m111 is flipped by default */
428 val = !val;
429
430 /* Set the correct page map */
431 err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
432 if (err < 0)
433 return err;
434
435 err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
436 if (err < 0)
437 return err;
438
439 data[1] = (data[1] & 0xfd) | ((val << 1) & 0x02);
440 err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
441 data, 2);
442 return err;
443}
444
445static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
446{
447 struct sd *sd = (struct sd *) gspca_dev;
448 s32 *sensor_settings = sd->sensor_priv;
449
450 *val = sensor_settings[GAIN_IDX];
451 PDEBUG(D_V4L2, "Read gain %d", *val);
452
453 return 0;
454}
455
456static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
457 __s32 val)
458{
459 struct sd *sd = (struct sd *) gspca_dev;
460 s32 *sensor_settings = sd->sensor_priv;
461 int err;
462 u8 data[2];
463
464 err = m5602_read_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2);
465 if (err < 0)
466 return err;
467
468 sensor_settings[AUTO_WHITE_BALANCE_IDX] = val & 0x01;
469 data[1] = ((data[1] & 0xfd) | ((val & 0x01) << 1));
470
471 err = m5602_write_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2);
472
473 PDEBUG(D_V4L2, "Set auto white balance %d", val);
474 return err;
475}
476
477static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev,
478 __s32 *val) {
479 struct sd *sd = (struct sd *) gspca_dev;
480 s32 *sensor_settings = sd->sensor_priv;
481
482 *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
483 PDEBUG(D_V4L2, "Read auto white balance %d", *val);
484 return 0;
485}
486
487static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
488{
489 int err, tmp;
490 u8 data[2] = {0x00, 0x00};
491 struct sd *sd = (struct sd *) gspca_dev;
492 s32 *sensor_settings = sd->sensor_priv;
493
494 sensor_settings[GAIN_IDX] = val;
495
496 /* Set the correct page map */
497 err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
498 if (err < 0)
499 return err;
500
501 if (val >= INITIAL_MAX_GAIN * 2 * 2 * 2)
502 return -EINVAL;
503
504 if ((val >= INITIAL_MAX_GAIN * 2 * 2) &&
505 (val < (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2))
506 tmp = (1 << 10) | (val << 9) |
507 (val << 8) | (val / 8);
508 else if ((val >= INITIAL_MAX_GAIN * 2) &&
509 (val < INITIAL_MAX_GAIN * 2 * 2))
510 tmp = (1 << 9) | (1 << 8) | (val / 4);
511 else if ((val >= INITIAL_MAX_GAIN) &&
512 (val < INITIAL_MAX_GAIN * 2))
513 tmp = (1 << 8) | (val / 2);
514 else
515 tmp = val;
516
517 data[1] = (tmp & 0xff);
518 data[0] = (tmp & 0xff00) >> 8;
519 PDEBUG(D_V4L2, "tmp=%d, data[1]=%d, data[0]=%d", tmp,
520 data[1], data[0]);
521
522 err = m5602_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN,
523 data, 2);
524
525 return err;
526}
527
528static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
529{
530 int err;
531 u8 data[2];
532 struct sd *sd = (struct sd *) gspca_dev;
533 s32 *sensor_settings = sd->sensor_priv;
534
535 sensor_settings[GREEN_BALANCE_IDX] = val;
536 data[1] = (val & 0xff);
537 data[0] = (val & 0xff00) >> 8;
538
539 PDEBUG(D_V4L2, "Set green balance %d", val);
540 err = m5602_write_sensor(sd, MT9M111_SC_GREEN_1_GAIN,
541 data, 2);
542 if (err < 0)
543 return err;
544
545 return m5602_write_sensor(sd, MT9M111_SC_GREEN_2_GAIN,
546 data, 2);
547}
548
549static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val)
550{
551 struct sd *sd = (struct sd *) gspca_dev;
552 s32 *sensor_settings = sd->sensor_priv;
553
554 *val = sensor_settings[GREEN_BALANCE_IDX];
555 PDEBUG(D_V4L2, "Read green balance %d", *val);
556 return 0;
557}
558
559static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
560{
561 u8 data[2];
562 struct sd *sd = (struct sd *) gspca_dev;
563 s32 *sensor_settings = sd->sensor_priv;
564
565 sensor_settings[BLUE_BALANCE_IDX] = val;
566 data[1] = (val & 0xff);
567 data[0] = (val & 0xff00) >> 8;
568
569 PDEBUG(D_V4L2, "Set blue balance %d", val);
570
571 return m5602_write_sensor(sd, MT9M111_SC_BLUE_GAIN,
572 data, 2);
573}
574
575static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
576{
577 struct sd *sd = (struct sd *) gspca_dev;
578 s32 *sensor_settings = sd->sensor_priv;
579
580 *val = sensor_settings[BLUE_BALANCE_IDX];
581 PDEBUG(D_V4L2, "Read blue balance %d", *val);
582 return 0;
583}
584
585static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
586{
587 u8 data[2];
588 struct sd *sd = (struct sd *) gspca_dev;
589 s32 *sensor_settings = sd->sensor_priv;
590
591 sensor_settings[RED_BALANCE_IDX] = val;
592 data[1] = (val & 0xff);
593 data[0] = (val & 0xff00) >> 8;
594
595 PDEBUG(D_V4L2, "Set red balance %d", val);
596
597 return m5602_write_sensor(sd, MT9M111_SC_RED_GAIN,
598 data, 2);
599}
600
601static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
602{
603 struct sd *sd = (struct sd *) gspca_dev;
604 s32 *sensor_settings = sd->sensor_priv;
605
606 *val = sensor_settings[RED_BALANCE_IDX];
607 PDEBUG(D_V4L2, "Read red balance %d", *val);
608 return 0;
609}
610
611static void mt9m111_dump_registers(struct sd *sd)
612{
613 u8 address, value[2] = {0x00, 0x00};
614
615 info("Dumping the mt9m111 register state");
616
617 info("Dumping the mt9m111 sensor core registers");
618 value[1] = MT9M111_SENSOR_CORE;
619 m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
620 for (address = 0; address < 0xff; address++) {
621 m5602_read_sensor(sd, address, value, 2);
622 info("register 0x%x contains 0x%x%x",
623 address, value[0], value[1]);
624 }
625
626 info("Dumping the mt9m111 color pipeline registers");
627 value[1] = MT9M111_COLORPIPE;
628 m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
629 for (address = 0; address < 0xff; address++) {
630 m5602_read_sensor(sd, address, value, 2);
631 info("register 0x%x contains 0x%x%x",
632 address, value[0], value[1]);
633 }
634
635 info("Dumping the mt9m111 camera control registers");
636 value[1] = MT9M111_CAMERA_CONTROL;
637 m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
638 for (address = 0; address < 0xff; address++) {
639 m5602_read_sensor(sd, address, value, 2);
640 info("register 0x%x contains 0x%x%x",
641 address, value[0], value[1]);
642 }
643
644 info("mt9m111 register state dump complete");
645}
diff --git a/drivers/media/video/gspca/m5602/m5602_mt9m111.h b/drivers/media/video/gspca/m5602/m5602_mt9m111.h
new file mode 100644
index 00000000000..b1f0c492036
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_mt9m111.h
@@ -0,0 +1,271 @@
1/*
2 * Driver for the mt9m111 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 * Some defines taken from the mt9m111 sensor driver
14 * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr>
15 *
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License as
18 * published by the Free Software Foundation, version 2.
19 *
20 */
21
22#ifndef M5602_MT9M111_H_
23#define M5602_MT9M111_H_
24
25#include "m5602_sensor.h"
26
27/*****************************************************************************/
28
29#define MT9M111_SC_CHIPVER 0x00
30#define MT9M111_SC_ROWSTART 0x01
31#define MT9M111_SC_COLSTART 0x02
32#define MT9M111_SC_WINDOW_HEIGHT 0x03
33#define MT9M111_SC_WINDOW_WIDTH 0x04
34#define MT9M111_SC_HBLANK_CONTEXT_B 0x05
35#define MT9M111_SC_VBLANK_CONTEXT_B 0x06
36#define MT9M111_SC_HBLANK_CONTEXT_A 0x07
37#define MT9M111_SC_VBLANK_CONTEXT_A 0x08
38#define MT9M111_SC_SHUTTER_WIDTH 0x09
39#define MT9M111_SC_ROW_SPEED 0x0a
40#define MT9M111_SC_EXTRA_DELAY 0x0b
41#define MT9M111_SC_SHUTTER_DELAY 0x0c
42#define MT9M111_SC_RESET 0x0d
43#define MT9M111_SC_R_MODE_CONTEXT_B 0x20
44#define MT9M111_SC_R_MODE_CONTEXT_A 0x21
45#define MT9M111_SC_FLASH_CONTROL 0x23
46#define MT9M111_SC_GREEN_1_GAIN 0x2b
47#define MT9M111_SC_BLUE_GAIN 0x2c
48#define MT9M111_SC_RED_GAIN 0x2d
49#define MT9M111_SC_GREEN_2_GAIN 0x2e
50#define MT9M111_SC_GLOBAL_GAIN 0x2f
51
52#define MT9M111_CONTEXT_CONTROL 0xc8
53#define MT9M111_PAGE_MAP 0xf0
54#define MT9M111_BYTEWISE_ADDRESS 0xf1
55
56#define MT9M111_CP_OPERATING_MODE_CTL 0x06
57#define MT9M111_CP_LUMA_OFFSET 0x34
58#define MT9M111_CP_LUMA_CLIP 0x35
59#define MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A 0x3a
60#define MT9M111_CP_LENS_CORRECTION_1 0x3b
61#define MT9M111_CP_DEFECT_CORR_CONTEXT_A 0x4c
62#define MT9M111_CP_DEFECT_CORR_CONTEXT_B 0x4d
63#define MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B 0x9b
64#define MT9M111_CP_GLOBAL_CLK_CONTROL 0xb3
65
66#define MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18 0x65
67#define MT9M111_CC_AWB_PARAMETER_7 0x28
68
69#define MT9M111_SENSOR_CORE 0x00
70#define MT9M111_COLORPIPE 0x01
71#define MT9M111_CAMERA_CONTROL 0x02
72
73#define MT9M111_RESET (1 << 0)
74#define MT9M111_RESTART (1 << 1)
75#define MT9M111_ANALOG_STANDBY (1 << 2)
76#define MT9M111_CHIP_ENABLE (1 << 3)
77#define MT9M111_CHIP_DISABLE (0 << 3)
78#define MT9M111_OUTPUT_DISABLE (1 << 4)
79#define MT9M111_SHOW_BAD_FRAMES (1 << 0)
80#define MT9M111_RESTART_BAD_FRAMES (1 << 1)
81#define MT9M111_SYNCHRONIZE_CHANGES (1 << 7)
82
83#define MT9M111_RMB_OVER_SIZED (1 << 0)
84#define MT9M111_RMB_MIRROR_ROWS (1 << 0)
85#define MT9M111_RMB_MIRROR_COLS (1 << 1)
86#define MT9M111_RMB_ROW_SKIP_2X (1 << 2)
87#define MT9M111_RMB_COLUMN_SKIP_2X (1 << 3)
88#define MT9M111_RMB_ROW_SKIP_4X (1 << 4)
89#define MT9M111_RMB_COLUMN_SKIP_4X (1 << 5)
90
91#define MT9M111_COLOR_MATRIX_BYPASS (1 << 4)
92#define MT9M111_SEL_CONTEXT_B (1 << 3)
93
94#define MT9M111_TRISTATE_PIN_IN_STANDBY (1 << 1)
95#define MT9M111_SOC_SOFT_STANDBY (1 << 0)
96
97#define MT9M111_2D_DEFECT_CORRECTION_ENABLE (1 << 0)
98
99#define INITIAL_MAX_GAIN 64
100#define MT9M111_DEFAULT_GAIN 283
101#define MT9M111_GREEN_GAIN_DEFAULT 0x20
102#define MT9M111_BLUE_GAIN_DEFAULT 0x20
103#define MT9M111_RED_GAIN_DEFAULT 0x20
104
105/*****************************************************************************/
106
107/* Kernel module parameters */
108extern int force_sensor;
109extern int dump_sensor;
110
111int mt9m111_probe(struct sd *sd);
112int mt9m111_init(struct sd *sd);
113int mt9m111_start(struct sd *sd);
114void mt9m111_disconnect(struct sd *sd);
115
116static const struct m5602_sensor mt9m111 = {
117 .name = "MT9M111",
118
119 .i2c_slave_id = 0xba,
120 .i2c_regW = 2,
121
122 .probe = mt9m111_probe,
123 .init = mt9m111_init,
124 .disconnect = mt9m111_disconnect,
125 .start = mt9m111_start,
126};
127
128static const unsigned char preinit_mt9m111[][4] = {
129 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
130 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
131 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
132 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
133 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
134 {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
135 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
136 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
137
138 {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
139 {SENSOR, MT9M111_SC_RESET,
140 MT9M111_RESET |
141 MT9M111_RESTART |
142 MT9M111_ANALOG_STANDBY |
143 MT9M111_CHIP_DISABLE,
144 MT9M111_SHOW_BAD_FRAMES |
145 MT9M111_RESTART_BAD_FRAMES |
146 MT9M111_SYNCHRONIZE_CHANGES},
147
148 {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
149 {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
150 {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
151 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
152 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
153 {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
154 {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
155 {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
156
157 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
158 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
159 {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
160 {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
161 {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
162 {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
163
164 {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00}
165};
166
167static const unsigned char init_mt9m111[][4] = {
168 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
169 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
170 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
171 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
172 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
173 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
174
175 {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
176 {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
177 {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
178 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
179 {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
180 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
181 {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
182 {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
183 {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
184 {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00},
185
186 {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
187 {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
188 {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
189 {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
190 {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00,
191 MT9M111_CP_OPERATING_MODE_CTL},
192 {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a},
193 {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00,
194 MT9M111_2D_DEFECT_CORRECTION_ENABLE},
195 {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00,
196 MT9M111_2D_DEFECT_CORRECTION_ENABLE},
197 {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00},
198 {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00},
199 {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00},
200 {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00},
201 {SENSOR, 0xcd, 0x00, 0x0e},
202 {SENSOR, 0xd0, 0x00, 0x40},
203
204 {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02},
205 {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00},
206 {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03},
207
208 {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
209 {SENSOR, 0x33, 0x03, 0x49},
210 {SENSOR, 0x34, 0xc0, 0x19},
211 {SENSOR, 0x3f, 0x20, 0x20},
212 {SENSOR, 0x40, 0x20, 0x20},
213 {SENSOR, 0x5a, 0xc0, 0x0a},
214 {SENSOR, 0x70, 0x7b, 0x0a},
215 {SENSOR, 0x71, 0xff, 0x00},
216 {SENSOR, 0x72, 0x19, 0x0e},
217 {SENSOR, 0x73, 0x18, 0x0f},
218 {SENSOR, 0x74, 0x57, 0x32},
219 {SENSOR, 0x75, 0x56, 0x34},
220 {SENSOR, 0x76, 0x73, 0x35},
221 {SENSOR, 0x77, 0x30, 0x12},
222 {SENSOR, 0x78, 0x79, 0x02},
223 {SENSOR, 0x79, 0x75, 0x06},
224 {SENSOR, 0x7a, 0x77, 0x0a},
225 {SENSOR, 0x7b, 0x78, 0x09},
226 {SENSOR, 0x7c, 0x7d, 0x06},
227 {SENSOR, 0x7d, 0x31, 0x10},
228 {SENSOR, 0x7e, 0x00, 0x7e},
229 {SENSOR, 0x80, 0x59, 0x04},
230 {SENSOR, 0x81, 0x59, 0x04},
231 {SENSOR, 0x82, 0x57, 0x0a},
232 {SENSOR, 0x83, 0x58, 0x0b},
233 {SENSOR, 0x84, 0x47, 0x0c},
234 {SENSOR, 0x85, 0x48, 0x0e},
235 {SENSOR, 0x86, 0x5b, 0x02},
236 {SENSOR, 0x87, 0x00, 0x5c},
237 {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, MT9M111_SEL_CONTEXT_B},
238 {SENSOR, 0x60, 0x00, 0x80},
239 {SENSOR, 0x61, 0x00, 0x00},
240 {SENSOR, 0x62, 0x00, 0x00},
241 {SENSOR, 0x63, 0x00, 0x00},
242 {SENSOR, 0x64, 0x00, 0x00},
243
244 {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d}, /* 13 */
245 {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x12}, /* 18 */
246 {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x00}, /* 1024 */
247 {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x10}, /* 1296 */
248 {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x60}, /* 352 */
249 {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11}, /* 17 */
250 {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x60}, /* 352 */
251 {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11}, /* 17 */
252 {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x0f}, /* 271 */
253 {SENSOR, 0x30, 0x04, 0x00},
254 /* Set number of blank rows chosen to 400 */
255 {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0x90},
256};
257
258static const unsigned char start_mt9m111[][4] = {
259 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
260 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
261 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
262 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
263 {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
264 {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
265 {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
266 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
267 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
268 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
269 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
270};
271#endif
diff --git a/drivers/media/video/gspca/m5602/m5602_ov7660.c b/drivers/media/video/gspca/m5602/m5602_ov7660.c
new file mode 100644
index 00000000000..b12f60464b3
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_ov7660.c
@@ -0,0 +1,487 @@
1/*
2 * Driver for the ov7660 sensor
3 *
4 * Copyright (C) 2009 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_ov7660.h"
20
21static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
22static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val);
23static int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev,
24 __s32 *val);
25static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
26 __s32 val);
27static int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
28static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
29static int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val);
30static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val);
31static int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
32static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
33static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
34static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
35
36static const struct ctrl ov7660_ctrls[] = {
37#define GAIN_IDX 1
38 {
39 {
40 .id = V4L2_CID_GAIN,
41 .type = V4L2_CTRL_TYPE_INTEGER,
42 .name = "gain",
43 .minimum = 0x00,
44 .maximum = 0xff,
45 .step = 0x1,
46 .default_value = OV7660_DEFAULT_GAIN,
47 .flags = V4L2_CTRL_FLAG_SLIDER
48 },
49 .set = ov7660_set_gain,
50 .get = ov7660_get_gain
51 },
52#define BLUE_BALANCE_IDX 2
53#define RED_BALANCE_IDX 3
54#define AUTO_WHITE_BALANCE_IDX 4
55 {
56 {
57 .id = V4L2_CID_AUTO_WHITE_BALANCE,
58 .type = V4L2_CTRL_TYPE_BOOLEAN,
59 .name = "auto white balance",
60 .minimum = 0,
61 .maximum = 1,
62 .step = 1,
63 .default_value = 1
64 },
65 .set = ov7660_set_auto_white_balance,
66 .get = ov7660_get_auto_white_balance
67 },
68#define AUTO_GAIN_CTRL_IDX 5
69 {
70 {
71 .id = V4L2_CID_AUTOGAIN,
72 .type = V4L2_CTRL_TYPE_BOOLEAN,
73 .name = "auto gain control",
74 .minimum = 0,
75 .maximum = 1,
76 .step = 1,
77 .default_value = 1
78 },
79 .set = ov7660_set_auto_gain,
80 .get = ov7660_get_auto_gain
81 },
82#define AUTO_EXPOSURE_IDX 6
83 {
84 {
85 .id = V4L2_CID_EXPOSURE_AUTO,
86 .type = V4L2_CTRL_TYPE_BOOLEAN,
87 .name = "auto exposure",
88 .minimum = 0,
89 .maximum = 1,
90 .step = 1,
91 .default_value = 1
92 },
93 .set = ov7660_set_auto_exposure,
94 .get = ov7660_get_auto_exposure
95 },
96#define HFLIP_IDX 7
97 {
98 {
99 .id = V4L2_CID_HFLIP,
100 .type = V4L2_CTRL_TYPE_BOOLEAN,
101 .name = "horizontal flip",
102 .minimum = 0,
103 .maximum = 1,
104 .step = 1,
105 .default_value = 0
106 },
107 .set = ov7660_set_hflip,
108 .get = ov7660_get_hflip
109 },
110#define VFLIP_IDX 8
111 {
112 {
113 .id = V4L2_CID_VFLIP,
114 .type = V4L2_CTRL_TYPE_BOOLEAN,
115 .name = "vertical flip",
116 .minimum = 0,
117 .maximum = 1,
118 .step = 1,
119 .default_value = 0
120 },
121 .set = ov7660_set_vflip,
122 .get = ov7660_get_vflip
123 },
124
125};
126
127static struct v4l2_pix_format ov7660_modes[] = {
128 {
129 640,
130 480,
131 V4L2_PIX_FMT_SBGGR8,
132 V4L2_FIELD_NONE,
133 .sizeimage =
134 640 * 480,
135 .bytesperline = 640,
136 .colorspace = V4L2_COLORSPACE_SRGB,
137 .priv = 0
138 }
139};
140
141static void ov7660_dump_registers(struct sd *sd);
142
143int ov7660_probe(struct sd *sd)
144{
145 int err = 0, i;
146 u8 prod_id = 0, ver_id = 0;
147
148 s32 *sensor_settings;
149
150 if (force_sensor) {
151 if (force_sensor == OV7660_SENSOR) {
152 info("Forcing an %s sensor", ov7660.name);
153 goto sensor_found;
154 }
155 /* If we want to force another sensor,
156 don't try to probe this one */
157 return -ENODEV;
158 }
159
160 /* Do the preinit */
161 for (i = 0; i < ARRAY_SIZE(preinit_ov7660) && !err; i++) {
162 u8 data[2];
163
164 if (preinit_ov7660[i][0] == BRIDGE) {
165 err = m5602_write_bridge(sd,
166 preinit_ov7660[i][1],
167 preinit_ov7660[i][2]);
168 } else {
169 data[0] = preinit_ov7660[i][2];
170 err = m5602_write_sensor(sd,
171 preinit_ov7660[i][1], data, 1);
172 }
173 }
174 if (err < 0)
175 return err;
176
177 if (m5602_read_sensor(sd, OV7660_PID, &prod_id, 1))
178 return -ENODEV;
179
180 if (m5602_read_sensor(sd, OV7660_VER, &ver_id, 1))
181 return -ENODEV;
182
183 info("Sensor reported 0x%x%x", prod_id, ver_id);
184
185 if ((prod_id == 0x76) && (ver_id == 0x60)) {
186 info("Detected a ov7660 sensor");
187 goto sensor_found;
188 }
189 return -ENODEV;
190
191sensor_found:
192 sensor_settings = kmalloc(
193 ARRAY_SIZE(ov7660_ctrls) * sizeof(s32), GFP_KERNEL);
194 if (!sensor_settings)
195 return -ENOMEM;
196
197 sd->gspca_dev.cam.cam_mode = ov7660_modes;
198 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov7660_modes);
199 sd->desc->ctrls = ov7660_ctrls;
200 sd->desc->nctrls = ARRAY_SIZE(ov7660_ctrls);
201
202 for (i = 0; i < ARRAY_SIZE(ov7660_ctrls); i++)
203 sensor_settings[i] = ov7660_ctrls[i].qctrl.default_value;
204 sd->sensor_priv = sensor_settings;
205
206 return 0;
207}
208
209int ov7660_init(struct sd *sd)
210{
211 int i, err = 0;
212 s32 *sensor_settings = sd->sensor_priv;
213
214 /* Init the sensor */
215 for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) {
216 u8 data[2];
217
218 if (init_ov7660[i][0] == BRIDGE) {
219 err = m5602_write_bridge(sd,
220 init_ov7660[i][1],
221 init_ov7660[i][2]);
222 } else {
223 data[0] = init_ov7660[i][2];
224 err = m5602_write_sensor(sd,
225 init_ov7660[i][1], data, 1);
226 }
227 }
228
229 if (dump_sensor)
230 ov7660_dump_registers(sd);
231
232 err = ov7660_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
233 if (err < 0)
234 return err;
235
236 err = ov7660_set_auto_white_balance(&sd->gspca_dev,
237 sensor_settings[AUTO_WHITE_BALANCE_IDX]);
238 if (err < 0)
239 return err;
240
241 err = ov7660_set_auto_gain(&sd->gspca_dev,
242 sensor_settings[AUTO_GAIN_CTRL_IDX]);
243 if (err < 0)
244 return err;
245
246 err = ov7660_set_auto_exposure(&sd->gspca_dev,
247 sensor_settings[AUTO_EXPOSURE_IDX]);
248 if (err < 0)
249 return err;
250 err = ov7660_set_hflip(&sd->gspca_dev,
251 sensor_settings[HFLIP_IDX]);
252 if (err < 0)
253 return err;
254
255 err = ov7660_set_vflip(&sd->gspca_dev,
256 sensor_settings[VFLIP_IDX]);
257
258 return err;
259}
260
261int ov7660_start(struct sd *sd)
262{
263 return 0;
264}
265
266int ov7660_stop(struct sd *sd)
267{
268 return 0;
269}
270
271void ov7660_disconnect(struct sd *sd)
272{
273 ov7660_stop(sd);
274
275 sd->sensor = NULL;
276 kfree(sd->sensor_priv);
277}
278
279static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
280{
281 struct sd *sd = (struct sd *) gspca_dev;
282 s32 *sensor_settings = sd->sensor_priv;
283
284 *val = sensor_settings[GAIN_IDX];
285 PDEBUG(D_V4L2, "Read gain %d", *val);
286 return 0;
287}
288
289static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val)
290{
291 int err;
292 u8 i2c_data;
293 struct sd *sd = (struct sd *) gspca_dev;
294 s32 *sensor_settings = sd->sensor_priv;
295
296 PDEBUG(D_V4L2, "Setting gain to %d", val);
297
298 sensor_settings[GAIN_IDX] = val;
299
300 err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1);
301 return err;
302}
303
304
305static int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev,
306 __s32 *val)
307{
308 struct sd *sd = (struct sd *) gspca_dev;
309 s32 *sensor_settings = sd->sensor_priv;
310
311 *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
312 return 0;
313}
314
315static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
316 __s32 val)
317{
318 int err;
319 u8 i2c_data;
320 struct sd *sd = (struct sd *) gspca_dev;
321 s32 *sensor_settings = sd->sensor_priv;
322
323 PDEBUG(D_V4L2, "Set auto white balance to %d", val);
324
325 sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
326 err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
327 if (err < 0)
328 return err;
329
330 i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1));
331 err = m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
332
333 return err;
334}
335
336static int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
337{
338 struct sd *sd = (struct sd *) gspca_dev;
339 s32 *sensor_settings = sd->sensor_priv;
340
341 *val = sensor_settings[AUTO_GAIN_CTRL_IDX];
342 PDEBUG(D_V4L2, "Read auto gain control %d", *val);
343 return 0;
344}
345
346static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
347{
348 int err;
349 u8 i2c_data;
350 struct sd *sd = (struct sd *) gspca_dev;
351 s32 *sensor_settings = sd->sensor_priv;
352
353 PDEBUG(D_V4L2, "Set auto gain control to %d", val);
354
355 sensor_settings[AUTO_GAIN_CTRL_IDX] = val;
356 err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
357 if (err < 0)
358 return err;
359
360 i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2));
361
362 return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
363}
364
365static int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val)
366{
367 struct sd *sd = (struct sd *) gspca_dev;
368 s32 *sensor_settings = sd->sensor_priv;
369
370 *val = sensor_settings[AUTO_EXPOSURE_IDX];
371 PDEBUG(D_V4L2, "Read auto exposure control %d", *val);
372 return 0;
373}
374
375static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev,
376 __s32 val)
377{
378 int err;
379 u8 i2c_data;
380 struct sd *sd = (struct sd *) gspca_dev;
381 s32 *sensor_settings = sd->sensor_priv;
382
383 PDEBUG(D_V4L2, "Set auto exposure control to %d", val);
384
385 sensor_settings[AUTO_EXPOSURE_IDX] = val;
386 err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
387 if (err < 0)
388 return err;
389
390 i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0));
391
392 return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
393}
394
395static int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
396{
397 struct sd *sd = (struct sd *) gspca_dev;
398 s32 *sensor_settings = sd->sensor_priv;
399
400 *val = sensor_settings[HFLIP_IDX];
401 PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
402 return 0;
403}
404
405static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
406{
407 int err;
408 u8 i2c_data;
409 struct sd *sd = (struct sd *) gspca_dev;
410 s32 *sensor_settings = sd->sensor_priv;
411
412 PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
413
414 sensor_settings[HFLIP_IDX] = val;
415
416 i2c_data = ((val & 0x01) << 5) |
417 (sensor_settings[VFLIP_IDX] << 4);
418
419 err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1);
420
421 return err;
422}
423
424static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
425{
426 struct sd *sd = (struct sd *) gspca_dev;
427 s32 *sensor_settings = sd->sensor_priv;
428
429 *val = sensor_settings[VFLIP_IDX];
430 PDEBUG(D_V4L2, "Read vertical flip %d", *val);
431
432 return 0;
433}
434
435static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
436{
437 int err;
438 u8 i2c_data;
439 struct sd *sd = (struct sd *) gspca_dev;
440 s32 *sensor_settings = sd->sensor_priv;
441
442 PDEBUG(D_V4L2, "Set vertical flip to %d", val);
443 sensor_settings[VFLIP_IDX] = val;
444
445 i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5);
446 err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1);
447 if (err < 0)
448 return err;
449
450 /* When vflip is toggled we need to readjust the bridge hsync/vsync */
451 if (gspca_dev->streaming)
452 err = ov7660_start(sd);
453
454 return err;
455}
456
457static void ov7660_dump_registers(struct sd *sd)
458{
459 int address;
460 info("Dumping the ov7660 register state");
461 for (address = 0; address < 0xa9; address++) {
462 u8 value;
463 m5602_read_sensor(sd, address, &value, 1);
464 info("register 0x%x contains 0x%x",
465 address, value);
466 }
467
468 info("ov7660 register state dump complete");
469
470 info("Probing for which registers that are read/write");
471 for (address = 0; address < 0xff; address++) {
472 u8 old_value, ctrl_value;
473 u8 test_value[2] = {0xff, 0xff};
474
475 m5602_read_sensor(sd, address, &old_value, 1);
476 m5602_write_sensor(sd, address, test_value, 1);
477 m5602_read_sensor(sd, address, &ctrl_value, 1);
478
479 if (ctrl_value == test_value[0])
480 info("register 0x%x is writeable", address);
481 else
482 info("register 0x%x is read only", address);
483
484 /* Restore original value */
485 m5602_write_sensor(sd, address, &old_value, 1);
486 }
487}
diff --git a/drivers/media/video/gspca/m5602/m5602_ov7660.h b/drivers/media/video/gspca/m5602/m5602_ov7660.h
new file mode 100644
index 00000000000..2efd607987e
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_ov7660.h
@@ -0,0 +1,260 @@
1/*
2 * Driver for the ov7660 sensor
3 *
4 * Copyright (C) 2009 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#ifndef M5602_OV7660_H_
20#define M5602_OV7660_H_
21
22#include "m5602_sensor.h"
23
24#define OV7660_GAIN 0x00
25#define OV7660_BLUE_GAIN 0x01
26#define OV7660_RED_GAIN 0x02
27#define OV7660_VREF 0x03
28#define OV7660_COM1 0x04
29#define OV7660_BAVE 0x05
30#define OV7660_GEAVE 0x06
31#define OV7660_AECHH 0x07
32#define OV7660_RAVE 0x08
33#define OV7660_COM2 0x09
34#define OV7660_PID 0x0a
35#define OV7660_VER 0x0b
36#define OV7660_COM3 0x0c
37#define OV7660_COM4 0x0d
38#define OV7660_COM5 0x0e
39#define OV7660_COM6 0x0f
40#define OV7660_AECH 0x10
41#define OV7660_CLKRC 0x11
42#define OV7660_COM7 0x12
43#define OV7660_COM8 0x13
44#define OV7660_COM9 0x14
45#define OV7660_COM10 0x15
46#define OV7660_RSVD16 0x16
47#define OV7660_HSTART 0x17
48#define OV7660_HSTOP 0x18
49#define OV7660_VSTART 0x19
50#define OV7660_VSTOP 0x1a
51#define OV7660_PSHFT 0x1b
52#define OV7660_MIDH 0x1c
53#define OV7660_MIDL 0x1d
54#define OV7660_MVFP 0x1e
55#define OV7660_LAEC 0x1f
56#define OV7660_BOS 0x20
57#define OV7660_GBOS 0x21
58#define OV7660_GROS 0x22
59#define OV7660_ROS 0x23
60#define OV7660_AEW 0x24
61#define OV7660_AEB 0x25
62#define OV7660_VPT 0x26
63#define OV7660_BBIAS 0x27
64#define OV7660_GbBIAS 0x28
65#define OV7660_RSVD29 0x29
66#define OV7660_RBIAS 0x2c
67#define OV7660_HREF 0x32
68#define OV7660_ADC 0x37
69#define OV7660_OFON 0x39
70#define OV7660_TSLB 0x3a
71#define OV7660_COM12 0x3c
72#define OV7660_COM13 0x3d
73#define OV7660_LCC1 0x62
74#define OV7660_LCC2 0x63
75#define OV7660_LCC3 0x64
76#define OV7660_LCC4 0x65
77#define OV7660_LCC5 0x66
78#define OV7660_HV 0x69
79#define OV7660_RSVDA1 0xa1
80
81#define OV7660_DEFAULT_GAIN 0x0e
82#define OV7660_DEFAULT_RED_GAIN 0x80
83#define OV7660_DEFAULT_BLUE_GAIN 0x80
84#define OV7660_DEFAULT_SATURATION 0x00
85#define OV7660_DEFAULT_EXPOSURE 0x20
86
87/* Kernel module parameters */
88extern int force_sensor;
89extern int dump_sensor;
90
91int ov7660_probe(struct sd *sd);
92int ov7660_init(struct sd *sd);
93int ov7660_start(struct sd *sd);
94int ov7660_stop(struct sd *sd);
95void ov7660_disconnect(struct sd *sd);
96
97static const struct m5602_sensor ov7660 = {
98 .name = "ov7660",
99 .i2c_slave_id = 0x42,
100 .i2c_regW = 1,
101 .probe = ov7660_probe,
102 .init = ov7660_init,
103 .start = ov7660_start,
104 .stop = ov7660_stop,
105 .disconnect = ov7660_disconnect,
106};
107
108static const unsigned char preinit_ov7660[][4] = {
109 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
110 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
111 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
112 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
113 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
114 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d},
115 {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
116 {BRIDGE, M5602_XB_GPIO_DIR, 0x03},
117 {BRIDGE, M5602_XB_GPIO_DIR, 0x03},
118 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
119 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
120
121 {SENSOR, OV7660_OFON, 0x0c},
122 {SENSOR, OV7660_COM2, 0x11},
123 {SENSOR, OV7660_COM7, 0x05},
124
125 {BRIDGE, M5602_XB_GPIO_DIR, 0x01},
126 {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
127 {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
128 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
129 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
130 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08},
131 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
132 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
133 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
134 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
135 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
136 {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
137 {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
138 {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
139 {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}
140};
141
142static const unsigned char init_ov7660[][4] = {
143 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
144 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
145 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
146 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
147 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
148 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d},
149 {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
150 {BRIDGE, M5602_XB_GPIO_DIR, 0x01},
151 {BRIDGE, M5602_XB_GPIO_DIR, 0x01},
152 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
153 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
154 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
155 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
156 {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
157 {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
158 {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
159 {BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
160 {SENSOR, OV7660_COM7, 0x80},
161 {SENSOR, OV7660_CLKRC, 0x80},
162 {SENSOR, OV7660_COM9, 0x4c},
163 {SENSOR, OV7660_OFON, 0x43},
164 {SENSOR, OV7660_COM12, 0x28},
165 {SENSOR, OV7660_COM8, 0x00},
166 {SENSOR, OV7660_COM10, 0x40},
167 {SENSOR, OV7660_HSTART, 0x0c},
168 {SENSOR, OV7660_HSTOP, 0x61},
169 {SENSOR, OV7660_HREF, 0xa4},
170 {SENSOR, OV7660_PSHFT, 0x0b},
171 {SENSOR, OV7660_VSTART, 0x01},
172 {SENSOR, OV7660_VSTOP, 0x7a},
173 {SENSOR, OV7660_VSTOP, 0x00},
174 {SENSOR, OV7660_COM7, 0x05},
175 {SENSOR, OV7660_COM6, 0x42},
176 {SENSOR, OV7660_BBIAS, 0x94},
177 {SENSOR, OV7660_GbBIAS, 0x94},
178 {SENSOR, OV7660_RSVD29, 0x94},
179 {SENSOR, OV7660_RBIAS, 0x94},
180 {SENSOR, OV7660_COM1, 0x00},
181 {SENSOR, OV7660_AECH, 0x00},
182 {SENSOR, OV7660_AECHH, 0x00},
183 {SENSOR, OV7660_ADC, 0x05},
184 {SENSOR, OV7660_COM13, 0x00},
185 {SENSOR, OV7660_RSVDA1, 0x23},
186 {SENSOR, OV7660_TSLB, 0x0d},
187 {SENSOR, OV7660_HV, 0x80},
188 {SENSOR, OV7660_LCC1, 0x00},
189 {SENSOR, OV7660_LCC2, 0x00},
190 {SENSOR, OV7660_LCC3, 0x10},
191 {SENSOR, OV7660_LCC4, 0x40},
192 {SENSOR, OV7660_LCC5, 0x01},
193
194 {SENSOR, OV7660_AECH, 0x20},
195 {SENSOR, OV7660_COM1, 0x00},
196 {SENSOR, OV7660_OFON, 0x0c},
197 {SENSOR, OV7660_COM2, 0x11},
198 {SENSOR, OV7660_COM7, 0x05},
199 {BRIDGE, M5602_XB_GPIO_DIR, 0x01},
200 {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
201 {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
202 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
203 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
204 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08},
205 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
206 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
207 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
208 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
209 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
210 {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
211 {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
212 {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
213 {BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
214 {SENSOR, OV7660_AECH, 0x5f},
215 {SENSOR, OV7660_COM1, 0x03},
216 {SENSOR, OV7660_OFON, 0x0c},
217 {SENSOR, OV7660_COM2, 0x11},
218 {SENSOR, OV7660_COM7, 0x05},
219 {BRIDGE, M5602_XB_GPIO_DIR, 0x01},
220 {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
221 {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
222 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
223 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
224 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08},
225 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
226 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
227 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
228 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
229 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
230 {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
231 {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
232 {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
233 {BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
234
235 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06},
236 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
237 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
238 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
239 {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81},
240 {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82},
241 {BRIDGE, M5602_XB_SIG_INI, 0x01},
242 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
243 {BRIDGE, M5602_XB_VSYNC_PARA, 0x08},
244 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
245 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
246 {BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
247 {BRIDGE, M5602_XB_VSYNC_PARA, 0xec},
248 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
249 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
250 {BRIDGE, M5602_XB_SIG_INI, 0x00},
251 {BRIDGE, M5602_XB_SIG_INI, 0x02},
252 {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
253 {BRIDGE, M5602_XB_HSYNC_PARA, 0x27},
254 {BRIDGE, M5602_XB_HSYNC_PARA, 0x02},
255 {BRIDGE, M5602_XB_HSYNC_PARA, 0xa7},
256 {BRIDGE, M5602_XB_SIG_INI, 0x00},
257 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
258 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
259};
260#endif
diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.c b/drivers/media/video/gspca/m5602/m5602_ov9650.c
new file mode 100644
index 00000000000..703d48670a2
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_ov9650.c
@@ -0,0 +1,880 @@
1/*
2 * Driver for the ov9650 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_ov9650.h"
20
21static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
22static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
23static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
24static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val);
25static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
26static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
27static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
28static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
29static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
30static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
31static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
32static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
33static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev,
34 __s32 *val);
35static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
36 __s32 val);
37static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
38static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
39static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val);
40static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val);
41
42/* Vertically and horizontally flips the image if matched, needed for machines
43 where the sensor is mounted upside down */
44static
45 const
46 struct dmi_system_id ov9650_flip_dmi_table[] = {
47 {
48 .ident = "ASUS A6Ja",
49 .matches = {
50 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
51 DMI_MATCH(DMI_PRODUCT_NAME, "A6J")
52 }
53 },
54 {
55 .ident = "ASUS A6JC",
56 .matches = {
57 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
58 DMI_MATCH(DMI_PRODUCT_NAME, "A6JC")
59 }
60 },
61 {
62 .ident = "ASUS A6K",
63 .matches = {
64 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
65 DMI_MATCH(DMI_PRODUCT_NAME, "A6K")
66 }
67 },
68 {
69 .ident = "ASUS A6Kt",
70 .matches = {
71 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
72 DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt")
73 }
74 },
75 {
76 .ident = "ASUS A6VA",
77 .matches = {
78 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
79 DMI_MATCH(DMI_PRODUCT_NAME, "A6VA")
80 }
81 },
82 {
83
84 .ident = "ASUS A6VC",
85 .matches = {
86 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
87 DMI_MATCH(DMI_PRODUCT_NAME, "A6VC")
88 }
89 },
90 {
91 .ident = "ASUS A6VM",
92 .matches = {
93 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
94 DMI_MATCH(DMI_PRODUCT_NAME, "A6VM")
95 }
96 },
97 {
98 .ident = "ASUS A7V",
99 .matches = {
100 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
101 DMI_MATCH(DMI_PRODUCT_NAME, "A7V")
102 }
103 },
104 {
105 .ident = "Alienware Aurora m9700",
106 .matches = {
107 DMI_MATCH(DMI_SYS_VENDOR, "alienware"),
108 DMI_MATCH(DMI_PRODUCT_NAME, "Aurora m9700")
109 }
110 },
111 {}
112};
113
114static const struct ctrl ov9650_ctrls[] = {
115#define EXPOSURE_IDX 0
116 {
117 {
118 .id = V4L2_CID_EXPOSURE,
119 .type = V4L2_CTRL_TYPE_INTEGER,
120 .name = "exposure",
121 .minimum = 0x00,
122 .maximum = 0x1ff,
123 .step = 0x4,
124 .default_value = EXPOSURE_DEFAULT,
125 .flags = V4L2_CTRL_FLAG_SLIDER
126 },
127 .set = ov9650_set_exposure,
128 .get = ov9650_get_exposure
129 },
130#define GAIN_IDX 1
131 {
132 {
133 .id = V4L2_CID_GAIN,
134 .type = V4L2_CTRL_TYPE_INTEGER,
135 .name = "gain",
136 .minimum = 0x00,
137 .maximum = 0x3ff,
138 .step = 0x1,
139 .default_value = GAIN_DEFAULT,
140 .flags = V4L2_CTRL_FLAG_SLIDER
141 },
142 .set = ov9650_set_gain,
143 .get = ov9650_get_gain
144 },
145#define RED_BALANCE_IDX 2
146 {
147 {
148 .id = V4L2_CID_RED_BALANCE,
149 .type = V4L2_CTRL_TYPE_INTEGER,
150 .name = "red balance",
151 .minimum = 0x00,
152 .maximum = 0xff,
153 .step = 0x1,
154 .default_value = RED_GAIN_DEFAULT,
155 .flags = V4L2_CTRL_FLAG_SLIDER
156 },
157 .set = ov9650_set_red_balance,
158 .get = ov9650_get_red_balance
159 },
160#define BLUE_BALANCE_IDX 3
161 {
162 {
163 .id = V4L2_CID_BLUE_BALANCE,
164 .type = V4L2_CTRL_TYPE_INTEGER,
165 .name = "blue balance",
166 .minimum = 0x00,
167 .maximum = 0xff,
168 .step = 0x1,
169 .default_value = BLUE_GAIN_DEFAULT,
170 .flags = V4L2_CTRL_FLAG_SLIDER
171 },
172 .set = ov9650_set_blue_balance,
173 .get = ov9650_get_blue_balance
174 },
175#define HFLIP_IDX 4
176 {
177 {
178 .id = V4L2_CID_HFLIP,
179 .type = V4L2_CTRL_TYPE_BOOLEAN,
180 .name = "horizontal flip",
181 .minimum = 0,
182 .maximum = 1,
183 .step = 1,
184 .default_value = 0
185 },
186 .set = ov9650_set_hflip,
187 .get = ov9650_get_hflip
188 },
189#define VFLIP_IDX 5
190 {
191 {
192 .id = V4L2_CID_VFLIP,
193 .type = V4L2_CTRL_TYPE_BOOLEAN,
194 .name = "vertical flip",
195 .minimum = 0,
196 .maximum = 1,
197 .step = 1,
198 .default_value = 0
199 },
200 .set = ov9650_set_vflip,
201 .get = ov9650_get_vflip
202 },
203#define AUTO_WHITE_BALANCE_IDX 6
204 {
205 {
206 .id = V4L2_CID_AUTO_WHITE_BALANCE,
207 .type = V4L2_CTRL_TYPE_BOOLEAN,
208 .name = "auto white balance",
209 .minimum = 0,
210 .maximum = 1,
211 .step = 1,
212 .default_value = 1
213 },
214 .set = ov9650_set_auto_white_balance,
215 .get = ov9650_get_auto_white_balance
216 },
217#define AUTO_GAIN_CTRL_IDX 7
218 {
219 {
220 .id = V4L2_CID_AUTOGAIN,
221 .type = V4L2_CTRL_TYPE_BOOLEAN,
222 .name = "auto gain control",
223 .minimum = 0,
224 .maximum = 1,
225 .step = 1,
226 .default_value = 1
227 },
228 .set = ov9650_set_auto_gain,
229 .get = ov9650_get_auto_gain
230 },
231#define AUTO_EXPOSURE_IDX 8
232 {
233 {
234 .id = V4L2_CID_EXPOSURE_AUTO,
235 .type = V4L2_CTRL_TYPE_BOOLEAN,
236 .name = "auto exposure",
237 .minimum = 0,
238 .maximum = 1,
239 .step = 1,
240 .default_value = 1
241 },
242 .set = ov9650_set_auto_exposure,
243 .get = ov9650_get_auto_exposure
244 }
245
246};
247
248static struct v4l2_pix_format ov9650_modes[] = {
249 {
250 176,
251 144,
252 V4L2_PIX_FMT_SBGGR8,
253 V4L2_FIELD_NONE,
254 .sizeimage =
255 176 * 144,
256 .bytesperline = 176,
257 .colorspace = V4L2_COLORSPACE_SRGB,
258 .priv = 9
259 }, {
260 320,
261 240,
262 V4L2_PIX_FMT_SBGGR8,
263 V4L2_FIELD_NONE,
264 .sizeimage =
265 320 * 240,
266 .bytesperline = 320,
267 .colorspace = V4L2_COLORSPACE_SRGB,
268 .priv = 8
269 }, {
270 352,
271 288,
272 V4L2_PIX_FMT_SBGGR8,
273 V4L2_FIELD_NONE,
274 .sizeimage =
275 352 * 288,
276 .bytesperline = 352,
277 .colorspace = V4L2_COLORSPACE_SRGB,
278 .priv = 9
279 }, {
280 640,
281 480,
282 V4L2_PIX_FMT_SBGGR8,
283 V4L2_FIELD_NONE,
284 .sizeimage =
285 640 * 480,
286 .bytesperline = 640,
287 .colorspace = V4L2_COLORSPACE_SRGB,
288 .priv = 9
289 }
290};
291
292static void ov9650_dump_registers(struct sd *sd);
293
294int ov9650_probe(struct sd *sd)
295{
296 int err = 0;
297 u8 prod_id = 0, ver_id = 0, i;
298 s32 *sensor_settings;
299
300 if (force_sensor) {
301 if (force_sensor == OV9650_SENSOR) {
302 info("Forcing an %s sensor", ov9650.name);
303 goto sensor_found;
304 }
305 /* If we want to force another sensor,
306 don't try to probe this one */
307 return -ENODEV;
308 }
309
310 PDEBUG(D_PROBE, "Probing for an ov9650 sensor");
311
312 /* Run the pre-init before probing the sensor */
313 for (i = 0; i < ARRAY_SIZE(preinit_ov9650) && !err; i++) {
314 u8 data = preinit_ov9650[i][2];
315 if (preinit_ov9650[i][0] == SENSOR)
316 err = m5602_write_sensor(sd,
317 preinit_ov9650[i][1], &data, 1);
318 else
319 err = m5602_write_bridge(sd,
320 preinit_ov9650[i][1], data);
321 }
322
323 if (err < 0)
324 return err;
325
326 if (m5602_read_sensor(sd, OV9650_PID, &prod_id, 1))
327 return -ENODEV;
328
329 if (m5602_read_sensor(sd, OV9650_VER, &ver_id, 1))
330 return -ENODEV;
331
332 if ((prod_id == 0x96) && (ver_id == 0x52)) {
333 info("Detected an ov9650 sensor");
334 goto sensor_found;
335 }
336 return -ENODEV;
337
338sensor_found:
339 sensor_settings = kmalloc(
340 ARRAY_SIZE(ov9650_ctrls) * sizeof(s32), GFP_KERNEL);
341 if (!sensor_settings)
342 return -ENOMEM;
343
344 sd->gspca_dev.cam.cam_mode = ov9650_modes;
345 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov9650_modes);
346 sd->desc->ctrls = ov9650_ctrls;
347 sd->desc->nctrls = ARRAY_SIZE(ov9650_ctrls);
348
349 for (i = 0; i < ARRAY_SIZE(ov9650_ctrls); i++)
350 sensor_settings[i] = ov9650_ctrls[i].qctrl.default_value;
351 sd->sensor_priv = sensor_settings;
352 return 0;
353}
354
355int ov9650_init(struct sd *sd)
356{
357 int i, err = 0;
358 u8 data;
359 s32 *sensor_settings = sd->sensor_priv;
360
361 if (dump_sensor)
362 ov9650_dump_registers(sd);
363
364 for (i = 0; i < ARRAY_SIZE(init_ov9650) && !err; i++) {
365 data = init_ov9650[i][2];
366 if (init_ov9650[i][0] == SENSOR)
367 err = m5602_write_sensor(sd, init_ov9650[i][1],
368 &data, 1);
369 else
370 err = m5602_write_bridge(sd, init_ov9650[i][1], data);
371 }
372
373 err = ov9650_set_exposure(&sd->gspca_dev,
374 sensor_settings[EXPOSURE_IDX]);
375 if (err < 0)
376 return err;
377
378 err = ov9650_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
379 if (err < 0)
380 return err;
381
382 err = ov9650_set_red_balance(&sd->gspca_dev,
383 sensor_settings[RED_BALANCE_IDX]);
384 if (err < 0)
385 return err;
386
387 err = ov9650_set_blue_balance(&sd->gspca_dev,
388 sensor_settings[BLUE_BALANCE_IDX]);
389 if (err < 0)
390 return err;
391
392 err = ov9650_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
393 if (err < 0)
394 return err;
395
396 err = ov9650_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
397 if (err < 0)
398 return err;
399
400 err = ov9650_set_auto_exposure(&sd->gspca_dev,
401 sensor_settings[AUTO_EXPOSURE_IDX]);
402 if (err < 0)
403 return err;
404
405 err = ov9650_set_auto_white_balance(&sd->gspca_dev,
406 sensor_settings[AUTO_WHITE_BALANCE_IDX]);
407 if (err < 0)
408 return err;
409
410 err = ov9650_set_auto_gain(&sd->gspca_dev,
411 sensor_settings[AUTO_GAIN_CTRL_IDX]);
412 return err;
413}
414
415int ov9650_start(struct sd *sd)
416{
417 u8 data;
418 int i, err = 0;
419 struct cam *cam = &sd->gspca_dev.cam;
420 s32 *sensor_settings = sd->sensor_priv;
421
422 int width = cam->cam_mode[sd->gspca_dev.curr_mode].width;
423 int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
424 int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
425 int hor_offs = OV9650_LEFT_OFFSET;
426
427 if ((!dmi_check_system(ov9650_flip_dmi_table) &&
428 sensor_settings[VFLIP_IDX]) ||
429 (dmi_check_system(ov9650_flip_dmi_table) &&
430 !sensor_settings[VFLIP_IDX]))
431 ver_offs--;
432
433 if (width <= 320)
434 hor_offs /= 2;
435
436 /* Synthesize the vsync/hsync setup */
437 for (i = 0; i < ARRAY_SIZE(res_init_ov9650) && !err; i++) {
438 if (res_init_ov9650[i][0] == BRIDGE)
439 err = m5602_write_bridge(sd, res_init_ov9650[i][1],
440 res_init_ov9650[i][2]);
441 else if (res_init_ov9650[i][0] == SENSOR) {
442 data = res_init_ov9650[i][2];
443 err = m5602_write_sensor(sd,
444 res_init_ov9650[i][1], &data, 1);
445 }
446 }
447 if (err < 0)
448 return err;
449
450 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA,
451 ((ver_offs >> 8) & 0xff));
452 if (err < 0)
453 return err;
454
455 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (ver_offs & 0xff));
456 if (err < 0)
457 return err;
458
459 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
460 if (err < 0)
461 return err;
462
463 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff);
464 if (err < 0)
465 return err;
466
467 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff));
468 if (err < 0)
469 return err;
470
471 for (i = 0; i < 2 && !err; i++)
472 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
473 if (err < 0)
474 return err;
475
476 err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
477 if (err < 0)
478 return err;
479
480 err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 2);
481 if (err < 0)
482 return err;
483
484 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
485 (hor_offs >> 8) & 0xff);
486 if (err < 0)
487 return err;
488
489 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, hor_offs & 0xff);
490 if (err < 0)
491 return err;
492
493 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
494 ((width + hor_offs) >> 8) & 0xff);
495 if (err < 0)
496 return err;
497
498 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
499 ((width + hor_offs) & 0xff));
500 if (err < 0)
501 return err;
502
503 err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
504 if (err < 0)
505 return err;
506
507 switch (width) {
508 case 640:
509 PDEBUG(D_V4L2, "Configuring camera for VGA mode");
510
511 data = OV9650_VGA_SELECT | OV9650_RGB_SELECT |
512 OV9650_RAW_RGB_SELECT;
513 err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
514 break;
515
516 case 352:
517 PDEBUG(D_V4L2, "Configuring camera for CIF mode");
518
519 data = OV9650_CIF_SELECT | OV9650_RGB_SELECT |
520 OV9650_RAW_RGB_SELECT;
521 err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
522 break;
523
524 case 320:
525 PDEBUG(D_V4L2, "Configuring camera for QVGA mode");
526
527 data = OV9650_QVGA_SELECT | OV9650_RGB_SELECT |
528 OV9650_RAW_RGB_SELECT;
529 err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
530 break;
531
532 case 176:
533 PDEBUG(D_V4L2, "Configuring camera for QCIF mode");
534
535 data = OV9650_QCIF_SELECT | OV9650_RGB_SELECT |
536 OV9650_RAW_RGB_SELECT;
537 err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
538 break;
539 }
540 return err;
541}
542
543int ov9650_stop(struct sd *sd)
544{
545 u8 data = OV9650_SOFT_SLEEP | OV9650_OUTPUT_DRIVE_2X;
546 return m5602_write_sensor(sd, OV9650_COM2, &data, 1);
547}
548
549void ov9650_disconnect(struct sd *sd)
550{
551 ov9650_stop(sd);
552
553 sd->sensor = NULL;
554 kfree(sd->sensor_priv);
555}
556
557static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
558{
559 struct sd *sd = (struct sd *) gspca_dev;
560 s32 *sensor_settings = sd->sensor_priv;
561
562 *val = sensor_settings[EXPOSURE_IDX];
563 PDEBUG(D_V4L2, "Read exposure %d", *val);
564 return 0;
565}
566
567static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
568{
569 struct sd *sd = (struct sd *) gspca_dev;
570 s32 *sensor_settings = sd->sensor_priv;
571 u8 i2c_data;
572 int err;
573
574 PDEBUG(D_V4L2, "Set exposure to %d", val);
575
576 sensor_settings[EXPOSURE_IDX] = val;
577 /* The 6 MSBs */
578 i2c_data = (val >> 10) & 0x3f;
579 err = m5602_write_sensor(sd, OV9650_AECHM,
580 &i2c_data, 1);
581 if (err < 0)
582 return err;
583
584 /* The 8 middle bits */
585 i2c_data = (val >> 2) & 0xff;
586 err = m5602_write_sensor(sd, OV9650_AECH,
587 &i2c_data, 1);
588 if (err < 0)
589 return err;
590
591 /* The 2 LSBs */
592 i2c_data = val & 0x03;
593 err = m5602_write_sensor(sd, OV9650_COM1, &i2c_data, 1);
594 return err;
595}
596
597static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
598{
599 struct sd *sd = (struct sd *) gspca_dev;
600 s32 *sensor_settings = sd->sensor_priv;
601
602 *val = sensor_settings[GAIN_IDX];
603 PDEBUG(D_V4L2, "Read gain %d", *val);
604 return 0;
605}
606
607static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
608{
609 int err;
610 u8 i2c_data;
611 struct sd *sd = (struct sd *) gspca_dev;
612 s32 *sensor_settings = sd->sensor_priv;
613
614 PDEBUG(D_V4L2, "Setting gain to %d", val);
615
616 sensor_settings[GAIN_IDX] = val;
617
618 /* The 2 MSB */
619 /* Read the OV9650_VREF register first to avoid
620 corrupting the VREF high and low bits */
621 err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
622 if (err < 0)
623 return err;
624
625 /* Mask away all uninteresting bits */
626 i2c_data = ((val & 0x0300) >> 2) |
627 (i2c_data & 0x3f);
628 err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1);
629 if (err < 0)
630 return err;
631
632 /* The 8 LSBs */
633 i2c_data = val & 0xff;
634 err = m5602_write_sensor(sd, OV9650_GAIN, &i2c_data, 1);
635 return err;
636}
637
638static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
639{
640 struct sd *sd = (struct sd *) gspca_dev;
641 s32 *sensor_settings = sd->sensor_priv;
642
643 *val = sensor_settings[RED_BALANCE_IDX];
644 PDEBUG(D_V4L2, "Read red gain %d", *val);
645 return 0;
646}
647
648static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
649{
650 int err;
651 u8 i2c_data;
652 struct sd *sd = (struct sd *) gspca_dev;
653 s32 *sensor_settings = sd->sensor_priv;
654
655 PDEBUG(D_V4L2, "Set red gain to %d", val);
656
657 sensor_settings[RED_BALANCE_IDX] = val;
658
659 i2c_data = val & 0xff;
660 err = m5602_write_sensor(sd, OV9650_RED, &i2c_data, 1);
661 return err;
662}
663
664static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
665{
666 struct sd *sd = (struct sd *) gspca_dev;
667 s32 *sensor_settings = sd->sensor_priv;
668
669 *val = sensor_settings[BLUE_BALANCE_IDX];
670 PDEBUG(D_V4L2, "Read blue gain %d", *val);
671
672 return 0;
673}
674
675static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
676{
677 int err;
678 u8 i2c_data;
679 struct sd *sd = (struct sd *) gspca_dev;
680 s32 *sensor_settings = sd->sensor_priv;
681
682 PDEBUG(D_V4L2, "Set blue gain to %d", val);
683
684 sensor_settings[BLUE_BALANCE_IDX] = val;
685
686 i2c_data = val & 0xff;
687 err = m5602_write_sensor(sd, OV9650_BLUE, &i2c_data, 1);
688 return err;
689}
690
691static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
692{
693 struct sd *sd = (struct sd *) gspca_dev;
694 s32 *sensor_settings = sd->sensor_priv;
695
696 *val = sensor_settings[HFLIP_IDX];
697 PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
698 return 0;
699}
700
701static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
702{
703 int err;
704 u8 i2c_data;
705 struct sd *sd = (struct sd *) gspca_dev;
706 s32 *sensor_settings = sd->sensor_priv;
707
708 PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
709
710 sensor_settings[HFLIP_IDX] = val;
711
712 if (!dmi_check_system(ov9650_flip_dmi_table))
713 i2c_data = ((val & 0x01) << 5) |
714 (sensor_settings[VFLIP_IDX] << 4);
715 else
716 i2c_data = ((val & 0x01) << 5) |
717 (!sensor_settings[VFLIP_IDX] << 4);
718
719 err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
720
721 return err;
722}
723
724static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
725{
726 struct sd *sd = (struct sd *) gspca_dev;
727 s32 *sensor_settings = sd->sensor_priv;
728
729 *val = sensor_settings[VFLIP_IDX];
730 PDEBUG(D_V4L2, "Read vertical flip %d", *val);
731
732 return 0;
733}
734
735static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
736{
737 int err;
738 u8 i2c_data;
739 struct sd *sd = (struct sd *) gspca_dev;
740 s32 *sensor_settings = sd->sensor_priv;
741
742 PDEBUG(D_V4L2, "Set vertical flip to %d", val);
743 sensor_settings[VFLIP_IDX] = val;
744
745 if (dmi_check_system(ov9650_flip_dmi_table))
746 val = !val;
747
748 i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5);
749 err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
750 if (err < 0)
751 return err;
752
753 /* When vflip is toggled we need to readjust the bridge hsync/vsync */
754 if (gspca_dev->streaming)
755 err = ov9650_start(sd);
756
757 return err;
758}
759
760static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val)
761{
762 struct sd *sd = (struct sd *) gspca_dev;
763 s32 *sensor_settings = sd->sensor_priv;
764
765 *val = sensor_settings[AUTO_EXPOSURE_IDX];
766 PDEBUG(D_V4L2, "Read auto exposure control %d", *val);
767 return 0;
768}
769
770static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev,
771 __s32 val)
772{
773 int err;
774 u8 i2c_data;
775 struct sd *sd = (struct sd *) gspca_dev;
776 s32 *sensor_settings = sd->sensor_priv;
777
778 PDEBUG(D_V4L2, "Set auto exposure control to %d", val);
779
780 sensor_settings[AUTO_EXPOSURE_IDX] = val;
781 err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
782 if (err < 0)
783 return err;
784
785 i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0));
786
787 return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
788}
789
790static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev,
791 __s32 *val)
792{
793 struct sd *sd = (struct sd *) gspca_dev;
794 s32 *sensor_settings = sd->sensor_priv;
795
796 *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
797 return 0;
798}
799
800static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
801 __s32 val)
802{
803 int err;
804 u8 i2c_data;
805 struct sd *sd = (struct sd *) gspca_dev;
806 s32 *sensor_settings = sd->sensor_priv;
807
808 PDEBUG(D_V4L2, "Set auto white balance to %d", val);
809
810 sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
811 err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
812 if (err < 0)
813 return err;
814
815 i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1));
816 err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
817
818 return err;
819}
820
821static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
822{
823 struct sd *sd = (struct sd *) gspca_dev;
824 s32 *sensor_settings = sd->sensor_priv;
825
826 *val = sensor_settings[AUTO_GAIN_CTRL_IDX];
827 PDEBUG(D_V4L2, "Read auto gain control %d", *val);
828 return 0;
829}
830
831static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
832{
833 int err;
834 u8 i2c_data;
835 struct sd *sd = (struct sd *) gspca_dev;
836 s32 *sensor_settings = sd->sensor_priv;
837
838 PDEBUG(D_V4L2, "Set auto gain control to %d", val);
839
840 sensor_settings[AUTO_GAIN_CTRL_IDX] = val;
841 err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
842 if (err < 0)
843 return err;
844
845 i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2));
846
847 return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
848}
849
850static void ov9650_dump_registers(struct sd *sd)
851{
852 int address;
853 info("Dumping the ov9650 register state");
854 for (address = 0; address < 0xa9; address++) {
855 u8 value;
856 m5602_read_sensor(sd, address, &value, 1);
857 info("register 0x%x contains 0x%x",
858 address, value);
859 }
860
861 info("ov9650 register state dump complete");
862
863 info("Probing for which registers that are read/write");
864 for (address = 0; address < 0xff; address++) {
865 u8 old_value, ctrl_value;
866 u8 test_value[2] = {0xff, 0xff};
867
868 m5602_read_sensor(sd, address, &old_value, 1);
869 m5602_write_sensor(sd, address, test_value, 1);
870 m5602_read_sensor(sd, address, &ctrl_value, 1);
871
872 if (ctrl_value == test_value[0])
873 info("register 0x%x is writeable", address);
874 else
875 info("register 0x%x is read only", address);
876
877 /* Restore original value */
878 m5602_write_sensor(sd, address, &old_value, 1);
879 }
880}
diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.h b/drivers/media/video/gspca/m5602/m5602_ov9650.h
new file mode 100644
index 00000000000..da9a129b739
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_ov9650.h
@@ -0,0 +1,307 @@
1/*
2 * Driver for the ov9650 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#ifndef M5602_OV9650_H_
20#define M5602_OV9650_H_
21
22#include <linux/dmi.h>
23#include "m5602_sensor.h"
24
25/*****************************************************************************/
26
27#define OV9650_GAIN 0x00
28#define OV9650_BLUE 0x01
29#define OV9650_RED 0x02
30#define OV9650_VREF 0x03
31#define OV9650_COM1 0x04
32#define OV9650_BAVE 0x05
33#define OV9650_GEAVE 0x06
34#define OV9650_RSVD7 0x07
35#define OV9650_COM2 0x09
36#define OV9650_PID 0x0a
37#define OV9650_VER 0x0b
38#define OV9650_COM3 0x0c
39#define OV9650_COM4 0x0d
40#define OV9650_COM5 0x0e
41#define OV9650_COM6 0x0f
42#define OV9650_AECH 0x10
43#define OV9650_CLKRC 0x11
44#define OV9650_COM7 0x12
45#define OV9650_COM8 0x13
46#define OV9650_COM9 0x14
47#define OV9650_COM10 0x15
48#define OV9650_RSVD16 0x16
49#define OV9650_HSTART 0x17
50#define OV9650_HSTOP 0x18
51#define OV9650_VSTRT 0x19
52#define OV9650_VSTOP 0x1a
53#define OV9650_PSHFT 0x1b
54#define OV9650_MVFP 0x1e
55#define OV9650_AEW 0x24
56#define OV9650_AEB 0x25
57#define OV9650_VPT 0x26
58#define OV9650_BBIAS 0x27
59#define OV9650_GbBIAS 0x28
60#define OV9650_Gr_COM 0x29
61#define OV9650_RBIAS 0x2c
62#define OV9650_HREF 0x32
63#define OV9650_CHLF 0x33
64#define OV9650_ARBLM 0x34
65#define OV9650_RSVD35 0x35
66#define OV9650_RSVD36 0x36
67#define OV9650_ADC 0x37
68#define OV9650_ACOM38 0x38
69#define OV9650_OFON 0x39
70#define OV9650_TSLB 0x3a
71#define OV9650_COM12 0x3c
72#define OV9650_COM13 0x3d
73#define OV9650_COM15 0x40
74#define OV9650_COM16 0x41
75#define OV9650_LCC1 0x62
76#define OV9650_LCC2 0x63
77#define OV9650_LCC3 0x64
78#define OV9650_LCC4 0x65
79#define OV9650_LCC5 0x66
80#define OV9650_HV 0x69
81#define OV9650_DBLV 0x6b
82#define OV9650_COM21 0x8b
83#define OV9650_COM22 0x8c
84#define OV9650_COM24 0x8e
85#define OV9650_DBLC1 0x8f
86#define OV9650_RSVD94 0x94
87#define OV9650_RSVD95 0x95
88#define OV9650_RSVD96 0x96
89#define OV9650_LCCFB 0x9d
90#define OV9650_LCCFR 0x9e
91#define OV9650_AECHM 0xa1
92#define OV9650_COM26 0xa5
93#define OV9650_ACOMA8 0xa8
94#define OV9650_ACOMA9 0xa9
95
96#define OV9650_REGISTER_RESET (1 << 7)
97#define OV9650_VGA_SELECT (1 << 6)
98#define OV9650_CIF_SELECT (1 << 5)
99#define OV9650_QVGA_SELECT (1 << 4)
100#define OV9650_QCIF_SELECT (1 << 3)
101#define OV9650_RGB_SELECT (1 << 2)
102#define OV9650_RAW_RGB_SELECT (1 << 0)
103
104#define OV9650_FAST_AGC_AEC (1 << 7)
105#define OV9650_AEC_UNLIM_STEP_SIZE (1 << 6)
106#define OV9650_BANDING (1 << 5)
107#define OV9650_AGC_EN (1 << 2)
108#define OV9650_AWB_EN (1 << 1)
109#define OV9650_AEC_EN (1 << 0)
110
111#define OV9650_VARIOPIXEL (1 << 2)
112#define OV9650_SYSTEM_CLK_SEL (1 << 7)
113#define OV9650_SLAM_MODE (1 << 4)
114
115#define OV9650_QVGA_VARIOPIXEL (1 << 7)
116
117#define OV9650_VFLIP (1 << 4)
118#define OV9650_HFLIP (1 << 5)
119
120#define OV9650_SOFT_SLEEP (1 << 4)
121#define OV9650_OUTPUT_DRIVE_2X (1 << 0)
122
123#define OV9650_DENOISE_ENABLE (1 << 5)
124#define OV9650_WHITE_PIXEL_ENABLE (1 << 1)
125#define OV9650_WHITE_PIXEL_OPTION (1 << 0)
126
127#define OV9650_LEFT_OFFSET 0x62
128
129#define GAIN_DEFAULT 0x14
130#define RED_GAIN_DEFAULT 0x70
131#define BLUE_GAIN_DEFAULT 0x20
132#define EXPOSURE_DEFAULT 0x1ff
133
134/*****************************************************************************/
135
136/* Kernel module parameters */
137extern int force_sensor;
138extern int dump_sensor;
139
140int ov9650_probe(struct sd *sd);
141int ov9650_init(struct sd *sd);
142int ov9650_start(struct sd *sd);
143int ov9650_stop(struct sd *sd);
144void ov9650_disconnect(struct sd *sd);
145
146static const struct m5602_sensor ov9650 = {
147 .name = "OV9650",
148 .i2c_slave_id = 0x60,
149 .i2c_regW = 1,
150 .probe = ov9650_probe,
151 .init = ov9650_init,
152 .start = ov9650_start,
153 .stop = ov9650_stop,
154 .disconnect = ov9650_disconnect,
155};
156
157static const unsigned char preinit_ov9650[][3] = {
158 /* [INITCAM] */
159 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
160 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
161 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
162 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
163 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
164 {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
165
166 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08},
167 {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
168 {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
169 {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
170 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
171 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
172 {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
173 {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a},
174 /* Reset chip */
175 {SENSOR, OV9650_COM7, OV9650_REGISTER_RESET},
176 /* Enable double clock */
177 {SENSOR, OV9650_CLKRC, 0x80},
178 /* Do something out of spec with the power */
179 {SENSOR, OV9650_OFON, 0x40}
180};
181
182static const unsigned char init_ov9650[][3] = {
183 /* [INITCAM] */
184 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
185 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
186 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
187 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
188 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
189 {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
190
191 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08},
192 {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
193 {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
194 {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
195 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
196 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
197 {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
198 {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a},
199
200 /* Reset chip */
201 {SENSOR, OV9650_COM7, OV9650_REGISTER_RESET},
202 /* One extra reset is needed in order to make the sensor behave
203 properly when resuming from ram, could be a timing issue */
204 {SENSOR, OV9650_COM7, OV9650_REGISTER_RESET},
205
206 /* Enable double clock */
207 {SENSOR, OV9650_CLKRC, 0x80},
208 /* Do something out of spec with the power */
209 {SENSOR, OV9650_OFON, 0x40},
210
211 /* Set fast AGC/AEC algorithm with unlimited step size */
212 {SENSOR, OV9650_COM8, OV9650_FAST_AGC_AEC |
213 OV9650_AEC_UNLIM_STEP_SIZE},
214
215 {SENSOR, OV9650_CHLF, 0x10},
216 {SENSOR, OV9650_ARBLM, 0xbf},
217 {SENSOR, OV9650_ACOM38, 0x81},
218 /* Turn off color matrix coefficient double option */
219 {SENSOR, OV9650_COM16, 0x00},
220 /* Enable color matrix for RGB/YUV, Delay Y channel,
221 set output Y/UV delay to 1 */
222 {SENSOR, OV9650_COM13, 0x19},
223 /* Enable digital BLC, Set output mode to U Y V Y */
224 {SENSOR, OV9650_TSLB, 0x0c},
225 /* Limit the AGC/AEC stable upper region */
226 {SENSOR, OV9650_COM24, 0x00},
227 /* Enable HREF and some out of spec things */
228 {SENSOR, OV9650_COM12, 0x73},
229 /* Set all DBLC offset signs to positive and
230 do some out of spec stuff */
231 {SENSOR, OV9650_DBLC1, 0xdf},
232 {SENSOR, OV9650_COM21, 0x06},
233 {SENSOR, OV9650_RSVD35, 0x91},
234 /* Necessary, no camera stream without it */
235 {SENSOR, OV9650_RSVD16, 0x06},
236 {SENSOR, OV9650_RSVD94, 0x99},
237 {SENSOR, OV9650_RSVD95, 0x99},
238 {SENSOR, OV9650_RSVD96, 0x04},
239 /* Enable full range output */
240 {SENSOR, OV9650_COM15, 0x0},
241 /* Enable HREF at optical black, enable ADBLC bias,
242 enable ADBLC, reset timings at format change */
243 {SENSOR, OV9650_COM6, 0x4b},
244 /* Subtract 32 from the B channel bias */
245 {SENSOR, OV9650_BBIAS, 0xa0},
246 /* Subtract 32 from the Gb channel bias */
247 {SENSOR, OV9650_GbBIAS, 0xa0},
248 /* Do not bypass the analog BLC and to some out of spec stuff */
249 {SENSOR, OV9650_Gr_COM, 0x00},
250 /* Subtract 32 from the R channel bias */
251 {SENSOR, OV9650_RBIAS, 0xa0},
252 /* Subtract 32 from the R channel bias */
253 {SENSOR, OV9650_RBIAS, 0x0},
254 {SENSOR, OV9650_COM26, 0x80},
255 {SENSOR, OV9650_ACOMA9, 0x98},
256 /* Set the AGC/AEC stable region upper limit */
257 {SENSOR, OV9650_AEW, 0x68},
258 /* Set the AGC/AEC stable region lower limit */
259 {SENSOR, OV9650_AEB, 0x5c},
260 /* Set the high and low limit nibbles to 3 */
261 {SENSOR, OV9650_VPT, 0xc3},
262 /* Set the Automatic Gain Ceiling (AGC) to 128x,
263 drop VSYNC at frame drop,
264 limit exposure timing,
265 drop frame when the AEC step is larger than the exposure gap */
266 {SENSOR, OV9650_COM9, 0x6e},
267 /* Set VSYNC negative, Set RESET to SLHS (slave mode horizontal sync)
268 and set PWDN to SLVS (slave mode vertical sync) */
269 {SENSOR, OV9650_COM10, 0x42},
270 /* Set horizontal column start high to default value */
271 {SENSOR, OV9650_HSTART, 0x1a}, /* 210 */
272 /* Set horizontal column end */
273 {SENSOR, OV9650_HSTOP, 0xbf}, /* 1534 */
274 /* Complementing register to the two writes above */
275 {SENSOR, OV9650_HREF, 0xb2},
276 /* Set vertical row start high bits */
277 {SENSOR, OV9650_VSTRT, 0x02},
278 /* Set vertical row end low bits */
279 {SENSOR, OV9650_VSTOP, 0x7e},
280 /* Set complementing vertical frame control */
281 {SENSOR, OV9650_VREF, 0x10},
282 {SENSOR, OV9650_ADC, 0x04},
283 {SENSOR, OV9650_HV, 0x40},
284
285 /* Enable denoise, and white-pixel erase */
286 {SENSOR, OV9650_COM22, OV9650_DENOISE_ENABLE |
287 OV9650_WHITE_PIXEL_ENABLE |
288 OV9650_WHITE_PIXEL_OPTION},
289
290 /* Enable VARIOPIXEL */
291 {SENSOR, OV9650_COM3, OV9650_VARIOPIXEL},
292 {SENSOR, OV9650_COM4, OV9650_QVGA_VARIOPIXEL},
293
294 /* Put the sensor in soft sleep mode */
295 {SENSOR, OV9650_COM2, OV9650_SOFT_SLEEP | OV9650_OUTPUT_DRIVE_2X},
296};
297
298static const unsigned char res_init_ov9650[][3] = {
299 {SENSOR, OV9650_COM2, OV9650_OUTPUT_DRIVE_2X},
300
301 {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x82},
302 {BRIDGE, M5602_XB_LINE_OF_FRAME_L, 0x00},
303 {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82},
304 {BRIDGE, M5602_XB_PIX_OF_LINE_L, 0x00},
305 {BRIDGE, M5602_XB_SIG_INI, 0x01}
306};
307#endif
diff --git a/drivers/media/video/gspca/m5602/m5602_po1030.c b/drivers/media/video/gspca/m5602/m5602_po1030.c
new file mode 100644
index 00000000000..1febd34c2f0
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_po1030.c
@@ -0,0 +1,762 @@
1/*
2 * Driver for the po1030 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_po1030.h"
20
21static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
22static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
23static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
24static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val);
25static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
26static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
27static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
28static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
29static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val);
30static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val);
31static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
32static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
33static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
34static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
35static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev,
36 __s32 val);
37static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev,
38 __s32 *val);
39static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,
40 __s32 val);
41static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev,
42 __s32 *val);
43
44static struct v4l2_pix_format po1030_modes[] = {
45 {
46 640,
47 480,
48 V4L2_PIX_FMT_SBGGR8,
49 V4L2_FIELD_NONE,
50 .sizeimage = 640 * 480,
51 .bytesperline = 640,
52 .colorspace = V4L2_COLORSPACE_SRGB,
53 .priv = 2
54 }
55};
56
57static const struct ctrl po1030_ctrls[] = {
58#define GAIN_IDX 0
59 {
60 {
61 .id = V4L2_CID_GAIN,
62 .type = V4L2_CTRL_TYPE_INTEGER,
63 .name = "gain",
64 .minimum = 0x00,
65 .maximum = 0x4f,
66 .step = 0x1,
67 .default_value = PO1030_GLOBAL_GAIN_DEFAULT,
68 .flags = V4L2_CTRL_FLAG_SLIDER
69 },
70 .set = po1030_set_gain,
71 .get = po1030_get_gain
72 },
73#define EXPOSURE_IDX 1
74 {
75 {
76 .id = V4L2_CID_EXPOSURE,
77 .type = V4L2_CTRL_TYPE_INTEGER,
78 .name = "exposure",
79 .minimum = 0x00,
80 .maximum = 0x02ff,
81 .step = 0x1,
82 .default_value = PO1030_EXPOSURE_DEFAULT,
83 .flags = V4L2_CTRL_FLAG_SLIDER
84 },
85 .set = po1030_set_exposure,
86 .get = po1030_get_exposure
87 },
88#define RED_BALANCE_IDX 2
89 {
90 {
91 .id = V4L2_CID_RED_BALANCE,
92 .type = V4L2_CTRL_TYPE_INTEGER,
93 .name = "red balance",
94 .minimum = 0x00,
95 .maximum = 0xff,
96 .step = 0x1,
97 .default_value = PO1030_RED_GAIN_DEFAULT,
98 .flags = V4L2_CTRL_FLAG_SLIDER
99 },
100 .set = po1030_set_red_balance,
101 .get = po1030_get_red_balance
102 },
103#define BLUE_BALANCE_IDX 3
104 {
105 {
106 .id = V4L2_CID_BLUE_BALANCE,
107 .type = V4L2_CTRL_TYPE_INTEGER,
108 .name = "blue balance",
109 .minimum = 0x00,
110 .maximum = 0xff,
111 .step = 0x1,
112 .default_value = PO1030_BLUE_GAIN_DEFAULT,
113 .flags = V4L2_CTRL_FLAG_SLIDER
114 },
115 .set = po1030_set_blue_balance,
116 .get = po1030_get_blue_balance
117 },
118#define HFLIP_IDX 4
119 {
120 {
121 .id = V4L2_CID_HFLIP,
122 .type = V4L2_CTRL_TYPE_BOOLEAN,
123 .name = "horizontal flip",
124 .minimum = 0,
125 .maximum = 1,
126 .step = 1,
127 .default_value = 0,
128 },
129 .set = po1030_set_hflip,
130 .get = po1030_get_hflip
131 },
132#define VFLIP_IDX 5
133 {
134 {
135 .id = V4L2_CID_VFLIP,
136 .type = V4L2_CTRL_TYPE_BOOLEAN,
137 .name = "vertical flip",
138 .minimum = 0,
139 .maximum = 1,
140 .step = 1,
141 .default_value = 0,
142 },
143 .set = po1030_set_vflip,
144 .get = po1030_get_vflip
145 },
146#define AUTO_WHITE_BALANCE_IDX 6
147 {
148 {
149 .id = V4L2_CID_AUTO_WHITE_BALANCE,
150 .type = V4L2_CTRL_TYPE_BOOLEAN,
151 .name = "auto white balance",
152 .minimum = 0,
153 .maximum = 1,
154 .step = 1,
155 .default_value = 0,
156 },
157 .set = po1030_set_auto_white_balance,
158 .get = po1030_get_auto_white_balance
159 },
160#define AUTO_EXPOSURE_IDX 7
161 {
162 {
163 .id = V4L2_CID_EXPOSURE_AUTO,
164 .type = V4L2_CTRL_TYPE_BOOLEAN,
165 .name = "auto exposure",
166 .minimum = 0,
167 .maximum = 1,
168 .step = 1,
169 .default_value = 0,
170 },
171 .set = po1030_set_auto_exposure,
172 .get = po1030_get_auto_exposure
173 },
174#define GREEN_BALANCE_IDX 8
175 {
176 {
177 .id = M5602_V4L2_CID_GREEN_BALANCE,
178 .type = V4L2_CTRL_TYPE_INTEGER,
179 .name = "green balance",
180 .minimum = 0x00,
181 .maximum = 0xff,
182 .step = 0x1,
183 .default_value = PO1030_GREEN_GAIN_DEFAULT,
184 .flags = V4L2_CTRL_FLAG_SLIDER
185 },
186 .set = po1030_set_green_balance,
187 .get = po1030_get_green_balance
188 },
189};
190
191static void po1030_dump_registers(struct sd *sd);
192
193int po1030_probe(struct sd *sd)
194{
195 u8 dev_id_h = 0, i;
196 s32 *sensor_settings;
197
198 if (force_sensor) {
199 if (force_sensor == PO1030_SENSOR) {
200 info("Forcing a %s sensor", po1030.name);
201 goto sensor_found;
202 }
203 /* If we want to force another sensor, don't try to probe this
204 * one */
205 return -ENODEV;
206 }
207
208 PDEBUG(D_PROBE, "Probing for a po1030 sensor");
209
210 /* Run the pre-init to actually probe the unit */
211 for (i = 0; i < ARRAY_SIZE(preinit_po1030); i++) {
212 u8 data = preinit_po1030[i][2];
213 if (preinit_po1030[i][0] == SENSOR)
214 m5602_write_sensor(sd,
215 preinit_po1030[i][1], &data, 1);
216 else
217 m5602_write_bridge(sd, preinit_po1030[i][1], data);
218 }
219
220 if (m5602_read_sensor(sd, PO1030_DEVID_H, &dev_id_h, 1))
221 return -ENODEV;
222
223 if (dev_id_h == 0x30) {
224 info("Detected a po1030 sensor");
225 goto sensor_found;
226 }
227 return -ENODEV;
228
229sensor_found:
230 sensor_settings = kmalloc(
231 ARRAY_SIZE(po1030_ctrls) * sizeof(s32), GFP_KERNEL);
232 if (!sensor_settings)
233 return -ENOMEM;
234
235 sd->gspca_dev.cam.cam_mode = po1030_modes;
236 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(po1030_modes);
237 sd->desc->ctrls = po1030_ctrls;
238 sd->desc->nctrls = ARRAY_SIZE(po1030_ctrls);
239
240 for (i = 0; i < ARRAY_SIZE(po1030_ctrls); i++)
241 sensor_settings[i] = po1030_ctrls[i].qctrl.default_value;
242 sd->sensor_priv = sensor_settings;
243
244 return 0;
245}
246
247int po1030_init(struct sd *sd)
248{
249 s32 *sensor_settings = sd->sensor_priv;
250 int i, err = 0;
251
252 /* Init the sensor */
253 for (i = 0; i < ARRAY_SIZE(init_po1030) && !err; i++) {
254 u8 data[2] = {0x00, 0x00};
255
256 switch (init_po1030[i][0]) {
257 case BRIDGE:
258 err = m5602_write_bridge(sd,
259 init_po1030[i][1],
260 init_po1030[i][2]);
261 break;
262
263 case SENSOR:
264 data[0] = init_po1030[i][2];
265 err = m5602_write_sensor(sd,
266 init_po1030[i][1], data, 1);
267 break;
268
269 default:
270 info("Invalid stream command, exiting init");
271 return -EINVAL;
272 }
273 }
274 if (err < 0)
275 return err;
276
277 if (dump_sensor)
278 po1030_dump_registers(sd);
279
280 err = po1030_set_exposure(&sd->gspca_dev,
281 sensor_settings[EXPOSURE_IDX]);
282 if (err < 0)
283 return err;
284
285 err = po1030_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
286 if (err < 0)
287 return err;
288
289 err = po1030_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
290 if (err < 0)
291 return err;
292
293 err = po1030_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
294 if (err < 0)
295 return err;
296
297 err = po1030_set_red_balance(&sd->gspca_dev,
298 sensor_settings[RED_BALANCE_IDX]);
299 if (err < 0)
300 return err;
301
302 err = po1030_set_blue_balance(&sd->gspca_dev,
303 sensor_settings[BLUE_BALANCE_IDX]);
304 if (err < 0)
305 return err;
306
307 err = po1030_set_green_balance(&sd->gspca_dev,
308 sensor_settings[GREEN_BALANCE_IDX]);
309 if (err < 0)
310 return err;
311
312 err = po1030_set_auto_white_balance(&sd->gspca_dev,
313 sensor_settings[AUTO_WHITE_BALANCE_IDX]);
314 if (err < 0)
315 return err;
316
317 err = po1030_set_auto_exposure(&sd->gspca_dev,
318 sensor_settings[AUTO_EXPOSURE_IDX]);
319 return err;
320}
321
322int po1030_start(struct sd *sd)
323{
324 struct cam *cam = &sd->gspca_dev.cam;
325 int i, err = 0;
326 int width = cam->cam_mode[sd->gspca_dev.curr_mode].width;
327 int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
328 int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
329 u8 data;
330
331 switch (width) {
332 case 320:
333 data = PO1030_SUBSAMPLING;
334 err = m5602_write_sensor(sd, PO1030_CONTROL3, &data, 1);
335 if (err < 0)
336 return err;
337
338 data = ((width + 3) >> 8) & 0xff;
339 err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_H, &data, 1);
340 if (err < 0)
341 return err;
342
343 data = (width + 3) & 0xff;
344 err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_L, &data, 1);
345 if (err < 0)
346 return err;
347
348 data = ((height + 1) >> 8) & 0xff;
349 err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_H, &data, 1);
350 if (err < 0)
351 return err;
352
353 data = (height + 1) & 0xff;
354 err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_L, &data, 1);
355
356 height += 6;
357 width -= 1;
358 break;
359
360 case 640:
361 data = 0;
362 err = m5602_write_sensor(sd, PO1030_CONTROL3, &data, 1);
363 if (err < 0)
364 return err;
365
366 data = ((width + 7) >> 8) & 0xff;
367 err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_H, &data, 1);
368 if (err < 0)
369 return err;
370
371 data = (width + 7) & 0xff;
372 err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_L, &data, 1);
373 if (err < 0)
374 return err;
375
376 data = ((height + 3) >> 8) & 0xff;
377 err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_H, &data, 1);
378 if (err < 0)
379 return err;
380
381 data = (height + 3) & 0xff;
382 err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_L, &data, 1);
383
384 height += 12;
385 width -= 2;
386 break;
387 }
388 err = m5602_write_bridge(sd, M5602_XB_SENSOR_TYPE, 0x0c);
389 if (err < 0)
390 return err;
391
392 err = m5602_write_bridge(sd, M5602_XB_LINE_OF_FRAME_H, 0x81);
393 if (err < 0)
394 return err;
395
396 err = m5602_write_bridge(sd, M5602_XB_PIX_OF_LINE_H, 0x82);
397 if (err < 0)
398 return err;
399
400 err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0x01);
401 if (err < 0)
402 return err;
403
404 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA,
405 ((ver_offs >> 8) & 0xff));
406 if (err < 0)
407 return err;
408
409 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (ver_offs & 0xff));
410 if (err < 0)
411 return err;
412
413 for (i = 0; i < 2 && !err; i++)
414 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
415 if (err < 0)
416 return err;
417
418 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff);
419 if (err < 0)
420 return err;
421
422 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff));
423 if (err < 0)
424 return err;
425
426 for (i = 0; i < 2 && !err; i++)
427 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
428
429 for (i = 0; i < 2 && !err; i++)
430 err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
431
432 for (i = 0; i < 2 && !err; i++)
433 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 0);
434 if (err < 0)
435 return err;
436
437 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (width >> 8) & 0xff);
438 if (err < 0)
439 return err;
440
441 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (width & 0xff));
442 if (err < 0)
443 return err;
444
445 err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
446 return err;
447}
448
449static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
450{
451 struct sd *sd = (struct sd *) gspca_dev;
452 s32 *sensor_settings = sd->sensor_priv;
453
454 *val = sensor_settings[EXPOSURE_IDX];
455 PDEBUG(D_V4L2, "Exposure read as %d", *val);
456 return 0;
457}
458
459static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
460{
461 struct sd *sd = (struct sd *) gspca_dev;
462 s32 *sensor_settings = sd->sensor_priv;
463 u8 i2c_data;
464 int err;
465
466 sensor_settings[EXPOSURE_IDX] = val;
467 PDEBUG(D_V4L2, "Set exposure to %d", val & 0xffff);
468
469 i2c_data = ((val & 0xff00) >> 8);
470 PDEBUG(D_V4L2, "Set exposure to high byte to 0x%x",
471 i2c_data);
472
473 err = m5602_write_sensor(sd, PO1030_INTEGLINES_H,
474 &i2c_data, 1);
475 if (err < 0)
476 return err;
477
478 i2c_data = (val & 0xff);
479 PDEBUG(D_V4L2, "Set exposure to low byte to 0x%x",
480 i2c_data);
481 err = m5602_write_sensor(sd, PO1030_INTEGLINES_M,
482 &i2c_data, 1);
483
484 return err;
485}
486
487static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
488{
489 struct sd *sd = (struct sd *) gspca_dev;
490 s32 *sensor_settings = sd->sensor_priv;
491
492 *val = sensor_settings[GAIN_IDX];
493 PDEBUG(D_V4L2, "Read global gain %d", *val);
494 return 0;
495}
496
497static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val)
498{
499 struct sd *sd = (struct sd *) gspca_dev;
500 s32 *sensor_settings = sd->sensor_priv;
501 u8 i2c_data;
502 int err;
503
504 sensor_settings[GAIN_IDX] = val;
505
506 i2c_data = val & 0xff;
507 PDEBUG(D_V4L2, "Set global gain to %d", i2c_data);
508 err = m5602_write_sensor(sd, PO1030_GLOBALGAIN,
509 &i2c_data, 1);
510 return err;
511}
512
513static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
514{
515 struct sd *sd = (struct sd *) gspca_dev;
516 s32 *sensor_settings = sd->sensor_priv;
517
518 *val = sensor_settings[HFLIP_IDX];
519 PDEBUG(D_V4L2, "Read hflip %d", *val);
520
521 return 0;
522}
523
524static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
525{
526 struct sd *sd = (struct sd *) gspca_dev;
527 s32 *sensor_settings = sd->sensor_priv;
528 u8 i2c_data;
529 int err;
530
531 sensor_settings[HFLIP_IDX] = val;
532
533 PDEBUG(D_V4L2, "Set hflip %d", val);
534 err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1);
535 if (err < 0)
536 return err;
537
538 i2c_data = (0x7f & i2c_data) | ((val & 0x01) << 7);
539
540 err = m5602_write_sensor(sd, PO1030_CONTROL2,
541 &i2c_data, 1);
542
543 return err;
544}
545
546static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
547{
548 struct sd *sd = (struct sd *) gspca_dev;
549 s32 *sensor_settings = sd->sensor_priv;
550
551 *val = sensor_settings[VFLIP_IDX];
552 PDEBUG(D_V4L2, "Read vflip %d", *val);
553
554 return 0;
555}
556
557static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
558{
559 struct sd *sd = (struct sd *) gspca_dev;
560 s32 *sensor_settings = sd->sensor_priv;
561 u8 i2c_data;
562 int err;
563
564 sensor_settings[VFLIP_IDX] = val;
565
566 PDEBUG(D_V4L2, "Set vflip %d", val);
567 err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1);
568 if (err < 0)
569 return err;
570
571 i2c_data = (i2c_data & 0xbf) | ((val & 0x01) << 6);
572
573 err = m5602_write_sensor(sd, PO1030_CONTROL2,
574 &i2c_data, 1);
575
576 return err;
577}
578
579static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
580{
581 struct sd *sd = (struct sd *) gspca_dev;
582 s32 *sensor_settings = sd->sensor_priv;
583
584 *val = sensor_settings[RED_BALANCE_IDX];
585 PDEBUG(D_V4L2, "Read red gain %d", *val);
586 return 0;
587}
588
589static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
590{
591 struct sd *sd = (struct sd *) gspca_dev;
592 s32 *sensor_settings = sd->sensor_priv;
593 u8 i2c_data;
594 int err;
595
596 sensor_settings[RED_BALANCE_IDX] = val;
597
598 i2c_data = val & 0xff;
599 PDEBUG(D_V4L2, "Set red gain to %d", i2c_data);
600 err = m5602_write_sensor(sd, PO1030_RED_GAIN,
601 &i2c_data, 1);
602 return err;
603}
604
605static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
606{
607 struct sd *sd = (struct sd *) gspca_dev;
608 s32 *sensor_settings = sd->sensor_priv;
609
610 *val = sensor_settings[BLUE_BALANCE_IDX];
611 PDEBUG(D_V4L2, "Read blue gain %d", *val);
612
613 return 0;
614}
615
616static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
617{
618 struct sd *sd = (struct sd *) gspca_dev;
619 s32 *sensor_settings = sd->sensor_priv;
620 u8 i2c_data;
621 int err;
622
623 sensor_settings[BLUE_BALANCE_IDX] = val;
624
625 i2c_data = val & 0xff;
626 PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data);
627 err = m5602_write_sensor(sd, PO1030_BLUE_GAIN,
628 &i2c_data, 1);
629
630 return err;
631}
632
633static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val)
634{
635 struct sd *sd = (struct sd *) gspca_dev;
636 s32 *sensor_settings = sd->sensor_priv;
637
638 *val = sensor_settings[GREEN_BALANCE_IDX];
639 PDEBUG(D_V4L2, "Read green gain %d", *val);
640
641 return 0;
642}
643
644static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
645{
646 struct sd *sd = (struct sd *) gspca_dev;
647 s32 *sensor_settings = sd->sensor_priv;
648 u8 i2c_data;
649 int err;
650
651 sensor_settings[GREEN_BALANCE_IDX] = val;
652 i2c_data = val & 0xff;
653 PDEBUG(D_V4L2, "Set green gain to %d", i2c_data);
654
655 err = m5602_write_sensor(sd, PO1030_GREEN_1_GAIN,
656 &i2c_data, 1);
657 if (err < 0)
658 return err;
659
660 return m5602_write_sensor(sd, PO1030_GREEN_2_GAIN,
661 &i2c_data, 1);
662}
663
664static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev,
665 __s32 *val)
666{
667 struct sd *sd = (struct sd *) gspca_dev;
668 s32 *sensor_settings = sd->sensor_priv;
669
670 *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
671 PDEBUG(D_V4L2, "Auto white balancing is %d", *val);
672
673 return 0;
674}
675
676static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev,
677 __s32 val)
678{
679 struct sd *sd = (struct sd *) gspca_dev;
680 s32 *sensor_settings = sd->sensor_priv;
681 u8 i2c_data;
682 int err;
683
684 sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
685
686 err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
687 if (err < 0)
688 return err;
689
690 PDEBUG(D_V4L2, "Set auto white balance to %d", val);
691 i2c_data = (i2c_data & 0xfe) | (val & 0x01);
692 err = m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
693 return err;
694}
695
696static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev,
697 __s32 *val)
698{
699 struct sd *sd = (struct sd *) gspca_dev;
700 s32 *sensor_settings = sd->sensor_priv;
701
702 *val = sensor_settings[AUTO_EXPOSURE_IDX];
703 PDEBUG(D_V4L2, "Auto exposure is %d", *val);
704 return 0;
705}
706
707static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,
708 __s32 val)
709{
710 struct sd *sd = (struct sd *) gspca_dev;
711 s32 *sensor_settings = sd->sensor_priv;
712 u8 i2c_data;
713 int err;
714
715 sensor_settings[AUTO_EXPOSURE_IDX] = val;
716 err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
717 if (err < 0)
718 return err;
719
720 PDEBUG(D_V4L2, "Set auto exposure to %d", val);
721 i2c_data = (i2c_data & 0xfd) | ((val & 0x01) << 1);
722 return m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
723}
724
725void po1030_disconnect(struct sd *sd)
726{
727 sd->sensor = NULL;
728 kfree(sd->sensor_priv);
729}
730
731static void po1030_dump_registers(struct sd *sd)
732{
733 int address;
734 u8 value = 0;
735
736 info("Dumping the po1030 sensor core registers");
737 for (address = 0; address < 0x7f; address++) {
738 m5602_read_sensor(sd, address, &value, 1);
739 info("register 0x%x contains 0x%x",
740 address, value);
741 }
742
743 info("po1030 register state dump complete");
744
745 info("Probing for which registers that are read/write");
746 for (address = 0; address < 0xff; address++) {
747 u8 old_value, ctrl_value;
748 u8 test_value[2] = {0xff, 0xff};
749
750 m5602_read_sensor(sd, address, &old_value, 1);
751 m5602_write_sensor(sd, address, test_value, 1);
752 m5602_read_sensor(sd, address, &ctrl_value, 1);
753
754 if (ctrl_value == test_value[0])
755 info("register 0x%x is writeable", address);
756 else
757 info("register 0x%x is read only", address);
758
759 /* Restore original value */
760 m5602_write_sensor(sd, address, &old_value, 1);
761 }
762}
diff --git a/drivers/media/video/gspca/m5602/m5602_po1030.h b/drivers/media/video/gspca/m5602/m5602_po1030.h
new file mode 100644
index 00000000000..33835959639
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_po1030.h
@@ -0,0 +1,272 @@
1/*
2 * Driver for the po1030 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 * Register defines taken from Pascal Stangs Procyon Armlib
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License as
17 * published by the Free Software Foundation, version 2.
18 *
19 */
20
21#ifndef M5602_PO1030_H_
22#define M5602_PO1030_H_
23
24#include "m5602_sensor.h"
25
26/*****************************************************************************/
27
28#define PO1030_DEVID_H 0x00
29#define PO1030_DEVID_L 0x01
30#define PO1030_FRAMEWIDTH_H 0x04
31#define PO1030_FRAMEWIDTH_L 0x05
32#define PO1030_FRAMEHEIGHT_H 0x06
33#define PO1030_FRAMEHEIGHT_L 0x07
34#define PO1030_WINDOWX_H 0x08
35#define PO1030_WINDOWX_L 0x09
36#define PO1030_WINDOWY_H 0x0a
37#define PO1030_WINDOWY_L 0x0b
38#define PO1030_WINDOWWIDTH_H 0x0c
39#define PO1030_WINDOWWIDTH_L 0x0d
40#define PO1030_WINDOWHEIGHT_H 0x0e
41#define PO1030_WINDOWHEIGHT_L 0x0f
42
43#define PO1030_GLOBALIBIAS 0x12
44#define PO1030_PIXELIBIAS 0x13
45
46#define PO1030_GLOBALGAIN 0x15
47#define PO1030_RED_GAIN 0x16
48#define PO1030_GREEN_1_GAIN 0x17
49#define PO1030_BLUE_GAIN 0x18
50#define PO1030_GREEN_2_GAIN 0x19
51
52#define PO1030_INTEGLINES_H 0x1a
53#define PO1030_INTEGLINES_M 0x1b
54#define PO1030_INTEGLINES_L 0x1c
55
56#define PO1030_CONTROL1 0x1d
57#define PO1030_CONTROL2 0x1e
58#define PO1030_CONTROL3 0x1f
59#define PO1030_CONTROL4 0x20
60
61#define PO1030_PERIOD50_H 0x23
62#define PO1030_PERIOD50_L 0x24
63#define PO1030_PERIOD60_H 0x25
64#define PO1030_PERIOD60_L 0x26
65#define PO1030_REGCLK167 0x27
66#define PO1030_FLICKER_DELTA50 0x28
67#define PO1030_FLICKERDELTA60 0x29
68
69#define PO1030_ADCOFFSET 0x2c
70
71/* Gamma Correction Coeffs */
72#define PO1030_GC0 0x2d
73#define PO1030_GC1 0x2e
74#define PO1030_GC2 0x2f
75#define PO1030_GC3 0x30
76#define PO1030_GC4 0x31
77#define PO1030_GC5 0x32
78#define PO1030_GC6 0x33
79#define PO1030_GC7 0x34
80
81/* Color Transform Matrix */
82#define PO1030_CT0 0x35
83#define PO1030_CT1 0x36
84#define PO1030_CT2 0x37
85#define PO1030_CT3 0x38
86#define PO1030_CT4 0x39
87#define PO1030_CT5 0x3a
88#define PO1030_CT6 0x3b
89#define PO1030_CT7 0x3c
90#define PO1030_CT8 0x3d
91
92#define PO1030_AUTOCTRL1 0x3e
93#define PO1030_AUTOCTRL2 0x3f
94
95#define PO1030_YTARGET 0x40
96#define PO1030_GLOBALGAINMIN 0x41
97#define PO1030_GLOBALGAINMAX 0x42
98
99#define PO1030_AWB_RED_TUNING 0x47
100#define PO1030_AWB_BLUE_TUNING 0x48
101
102/* Output format control */
103#define PO1030_OUTFORMCTRL1 0x5a
104#define PO1030_OUTFORMCTRL2 0x5b
105#define PO1030_OUTFORMCTRL3 0x5c
106#define PO1030_OUTFORMCTRL4 0x5d
107#define PO1030_OUTFORMCTRL5 0x5e
108
109#define PO1030_EDGE_ENH_OFF 0x5f
110#define PO1030_EGA 0x60
111
112#define PO1030_Cb_U_GAIN 0x63
113#define PO1030_Cr_V_GAIN 0x64
114
115#define PO1030_YCONTRAST 0x74
116#define PO1030_YSATURATION 0x75
117
118#define PO1030_HFLIP (1 << 7)
119#define PO1030_VFLIP (1 << 6)
120
121#define PO1030_HREF_ENABLE (1 << 6)
122
123#define PO1030_RAW_RGB_BAYER 0x4
124
125#define PO1030_FRAME_EQUAL (1 << 3)
126#define PO1030_AUTO_SUBSAMPLING (1 << 4)
127
128#define PO1030_WEIGHT_WIN_2X (1 << 3)
129
130#define PO1030_SHUTTER_MODE (1 << 6)
131#define PO1030_AUTO_SUBSAMPLING (1 << 4)
132#define PO1030_FRAME_EQUAL (1 << 3)
133
134#define PO1030_SENSOR_RESET (1 << 5)
135
136#define PO1030_SUBSAMPLING (1 << 6)
137
138/*****************************************************************************/
139
140#define PO1030_GLOBAL_GAIN_DEFAULT 0x12
141#define PO1030_EXPOSURE_DEFAULT 0x0085
142#define PO1030_BLUE_GAIN_DEFAULT 0x36
143#define PO1030_RED_GAIN_DEFAULT 0x36
144#define PO1030_GREEN_GAIN_DEFAULT 0x40
145
146/*****************************************************************************/
147
148/* Kernel module parameters */
149extern int force_sensor;
150extern int dump_sensor;
151
152int po1030_probe(struct sd *sd);
153int po1030_init(struct sd *sd);
154int po1030_start(struct sd *sd);
155void po1030_disconnect(struct sd *sd);
156
157static const struct m5602_sensor po1030 = {
158 .name = "PO1030",
159
160 .i2c_slave_id = 0xdc,
161 .i2c_regW = 1,
162
163 .probe = po1030_probe,
164 .init = po1030_init,
165 .start = po1030_start,
166 .disconnect = po1030_disconnect,
167};
168
169static const unsigned char preinit_po1030[][3] = {
170 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
171 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
172 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
173 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
174 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
175 {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
176 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
177 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
178 {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
179 {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
180 {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
181 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
182 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
183
184 {SENSOR, PO1030_AUTOCTRL2, PO1030_SENSOR_RESET | (1 << 2)},
185
186 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
187 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
188 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
189 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
190 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
191 {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
192 {BRIDGE, M5602_XB_GPIO_DAT, 0x00}
193};
194
195static const unsigned char init_po1030[][3] = {
196 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
197 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
198 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
199 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
200 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
201 {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
202 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
203
204 {SENSOR, PO1030_AUTOCTRL2, PO1030_SENSOR_RESET | (1 << 2)},
205
206 {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
207 {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
208 {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
209 {BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
210 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
211 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
212 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
213 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
214 {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
215 {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
216
217 {SENSOR, PO1030_AUTOCTRL2, 0x04},
218
219 {SENSOR, PO1030_OUTFORMCTRL2, PO1030_RAW_RGB_BAYER},
220 {SENSOR, PO1030_AUTOCTRL1, PO1030_WEIGHT_WIN_2X},
221
222 {SENSOR, PO1030_CONTROL2, 0x03},
223 {SENSOR, 0x21, 0x90},
224 {SENSOR, PO1030_YTARGET, 0x60},
225 {SENSOR, 0x59, 0x13},
226 {SENSOR, PO1030_OUTFORMCTRL1, PO1030_HREF_ENABLE},
227 {SENSOR, PO1030_EDGE_ENH_OFF, 0x00},
228 {SENSOR, PO1030_EGA, 0x80},
229 {SENSOR, 0x78, 0x14},
230 {SENSOR, 0x6f, 0x01},
231 {SENSOR, PO1030_GLOBALGAINMAX, 0x14},
232 {SENSOR, PO1030_Cb_U_GAIN, 0x38},
233 {SENSOR, PO1030_Cr_V_GAIN, 0x38},
234 {SENSOR, PO1030_CONTROL1, PO1030_SHUTTER_MODE |
235 PO1030_AUTO_SUBSAMPLING |
236 PO1030_FRAME_EQUAL},
237 {SENSOR, PO1030_GC0, 0x10},
238 {SENSOR, PO1030_GC1, 0x20},
239 {SENSOR, PO1030_GC2, 0x40},
240 {SENSOR, PO1030_GC3, 0x60},
241 {SENSOR, PO1030_GC4, 0x80},
242 {SENSOR, PO1030_GC5, 0xa0},
243 {SENSOR, PO1030_GC6, 0xc0},
244 {SENSOR, PO1030_GC7, 0xff},
245
246 /* Set the width to 751 */
247 {SENSOR, PO1030_FRAMEWIDTH_H, 0x02},
248 {SENSOR, PO1030_FRAMEWIDTH_L, 0xef},
249
250 /* Set the height to 540 */
251 {SENSOR, PO1030_FRAMEHEIGHT_H, 0x02},
252 {SENSOR, PO1030_FRAMEHEIGHT_L, 0x1c},
253
254 /* Set the x window to 1 */
255 {SENSOR, PO1030_WINDOWX_H, 0x00},
256 {SENSOR, PO1030_WINDOWX_L, 0x01},
257
258 /* Set the y window to 1 */
259 {SENSOR, PO1030_WINDOWY_H, 0x00},
260 {SENSOR, PO1030_WINDOWY_L, 0x01},
261
262 /* with a very low lighted environment increase the exposure but
263 * decrease the FPS (Frame Per Second) */
264 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
265 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
266
267 {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
268 {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
269 {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
270 {BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
271};
272#endif
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
new file mode 100644
index 00000000000..d27280be985
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
@@ -0,0 +1,721 @@
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
21static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
22static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
23static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
24static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
25static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
26static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
27static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
28static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val);
29static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val);
30static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val);
31static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
32static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
33
34static
35 const
36 struct dmi_system_id s5k4aa_vflip_dmi_table[] = {
37 {
38 .ident = "BRUNEINIT",
39 .matches = {
40 DMI_MATCH(DMI_SYS_VENDOR, "BRUNENIT"),
41 DMI_MATCH(DMI_PRODUCT_NAME, "BRUNENIT"),
42 DMI_MATCH(DMI_BOARD_VERSION, "00030D0000000001")
43 }
44 }, {
45 .ident = "Fujitsu-Siemens Amilo Xa 2528",
46 .matches = {
47 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
48 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528")
49 }
50 }, {
51 .ident = "Fujitsu-Siemens Amilo Xi 2428",
52 .matches = {
53 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
54 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2428")
55 }
56 }, {
57 .ident = "Fujitsu-Siemens Amilo Xi 2528",
58 .matches = {
59 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
60 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2528")
61 }
62 }, {
63 .ident = "Fujitsu-Siemens Amilo Xi 2550",
64 .matches = {
65 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
66 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550")
67 }
68 }, {
69 .ident = "Fujitsu-Siemens Amilo Pa 2548",
70 .matches = {
71 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
72 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2548")
73 }
74 }, {
75 .ident = "MSI GX700",
76 .matches = {
77 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
78 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
79 DMI_MATCH(DMI_BIOS_DATE, "12/02/2008")
80 }
81 }, {
82 .ident = "MSI GX700",
83 .matches = {
84 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
85 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
86 DMI_MATCH(DMI_BIOS_DATE, "07/26/2007")
87 }
88 }, {
89 .ident = "MSI GX700",
90 .matches = {
91 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
92 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
93 DMI_MATCH(DMI_BIOS_DATE, "07/19/2007")
94 }
95 }, {
96 .ident = "MSI GX700/GX705/EX700",
97 .matches = {
98 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
99 DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700")
100 }
101 }, {
102 .ident = "MSI L735",
103 .matches = {
104 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
105 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1717X")
106 }
107 }, {
108 .ident = "Lenovo Y300",
109 .matches = {
110 DMI_MATCH(DMI_SYS_VENDOR, "L3000 Y300"),
111 DMI_MATCH(DMI_PRODUCT_NAME, "Y300")
112 }
113 },
114 { }
115};
116
117static struct v4l2_pix_format s5k4aa_modes[] = {
118 {
119 640,
120 480,
121 V4L2_PIX_FMT_SBGGR8,
122 V4L2_FIELD_NONE,
123 .sizeimage =
124 640 * 480,
125 .bytesperline = 640,
126 .colorspace = V4L2_COLORSPACE_SRGB,
127 .priv = 0
128 },
129 {
130 1280,
131 1024,
132 V4L2_PIX_FMT_SBGGR8,
133 V4L2_FIELD_NONE,
134 .sizeimage =
135 1280 * 1024,
136 .bytesperline = 1280,
137 .colorspace = V4L2_COLORSPACE_SRGB,
138 .priv = 0
139 }
140};
141
142static const struct ctrl s5k4aa_ctrls[] = {
143#define VFLIP_IDX 0
144 {
145 {
146 .id = V4L2_CID_VFLIP,
147 .type = V4L2_CTRL_TYPE_BOOLEAN,
148 .name = "vertical flip",
149 .minimum = 0,
150 .maximum = 1,
151 .step = 1,
152 .default_value = 0
153 },
154 .set = s5k4aa_set_vflip,
155 .get = s5k4aa_get_vflip
156 },
157#define HFLIP_IDX 1
158 {
159 {
160 .id = V4L2_CID_HFLIP,
161 .type = V4L2_CTRL_TYPE_BOOLEAN,
162 .name = "horizontal flip",
163 .minimum = 0,
164 .maximum = 1,
165 .step = 1,
166 .default_value = 0
167 },
168 .set = s5k4aa_set_hflip,
169 .get = s5k4aa_get_hflip
170 },
171#define GAIN_IDX 2
172 {
173 {
174 .id = V4L2_CID_GAIN,
175 .type = V4L2_CTRL_TYPE_INTEGER,
176 .name = "Gain",
177 .minimum = 0,
178 .maximum = 127,
179 .step = 1,
180 .default_value = S5K4AA_DEFAULT_GAIN,
181 .flags = V4L2_CTRL_FLAG_SLIDER
182 },
183 .set = s5k4aa_set_gain,
184 .get = s5k4aa_get_gain
185 },
186#define EXPOSURE_IDX 3
187 {
188 {
189 .id = V4L2_CID_EXPOSURE,
190 .type = V4L2_CTRL_TYPE_INTEGER,
191 .name = "Exposure",
192 .minimum = 13,
193 .maximum = 0xfff,
194 .step = 1,
195 .default_value = 0x100,
196 .flags = V4L2_CTRL_FLAG_SLIDER
197 },
198 .set = s5k4aa_set_exposure,
199 .get = s5k4aa_get_exposure
200 },
201#define NOISE_SUPP_IDX 4
202 {
203 {
204 .id = V4L2_CID_PRIVATE_BASE,
205 .type = V4L2_CTRL_TYPE_BOOLEAN,
206 .name = "Noise suppression (smoothing)",
207 .minimum = 0,
208 .maximum = 1,
209 .step = 1,
210 .default_value = 1,
211 },
212 .set = s5k4aa_set_noise,
213 .get = s5k4aa_get_noise
214 },
215#define BRIGHTNESS_IDX 5
216 {
217 {
218 .id = V4L2_CID_BRIGHTNESS,
219 .type = V4L2_CTRL_TYPE_INTEGER,
220 .name = "Brightness",
221 .minimum = 0,
222 .maximum = 0x1f,
223 .step = 1,
224 .default_value = S5K4AA_DEFAULT_BRIGHTNESS,
225 },
226 .set = s5k4aa_set_brightness,
227 .get = s5k4aa_get_brightness
228 },
229
230};
231
232static void s5k4aa_dump_registers(struct sd *sd);
233
234int s5k4aa_probe(struct sd *sd)
235{
236 u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
237 const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
238 int i, err = 0;
239 s32 *sensor_settings;
240
241 if (force_sensor) {
242 if (force_sensor == S5K4AA_SENSOR) {
243 info("Forcing a %s sensor", s5k4aa.name);
244 goto sensor_found;
245 }
246 /* If we want to force another sensor, don't try to probe this
247 * one */
248 return -ENODEV;
249 }
250
251 PDEBUG(D_PROBE, "Probing for a s5k4aa sensor");
252
253 /* Preinit the sensor */
254 for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) {
255 u8 data[2] = {0x00, 0x00};
256
257 switch (preinit_s5k4aa[i][0]) {
258 case BRIDGE:
259 err = m5602_write_bridge(sd,
260 preinit_s5k4aa[i][1],
261 preinit_s5k4aa[i][2]);
262 break;
263
264 case SENSOR:
265 data[0] = preinit_s5k4aa[i][2];
266 err = m5602_write_sensor(sd,
267 preinit_s5k4aa[i][1],
268 data, 1);
269 break;
270
271 case SENSOR_LONG:
272 data[0] = preinit_s5k4aa[i][2];
273 data[1] = preinit_s5k4aa[i][3];
274 err = m5602_write_sensor(sd,
275 preinit_s5k4aa[i][1],
276 data, 2);
277 break;
278 default:
279 info("Invalid stream command, exiting init");
280 return -EINVAL;
281 }
282 }
283
284 /* Test some registers, but we don't know their exact meaning yet */
285 if (m5602_read_sensor(sd, 0x00, prod_id, 2))
286 return -ENODEV;
287 if (m5602_read_sensor(sd, 0x02, prod_id+2, 2))
288 return -ENODEV;
289 if (m5602_read_sensor(sd, 0x04, prod_id+4, 2))
290 return -ENODEV;
291
292 if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
293 return -ENODEV;
294 else
295 info("Detected a s5k4aa sensor");
296
297sensor_found:
298 sensor_settings = kmalloc(
299 ARRAY_SIZE(s5k4aa_ctrls) * sizeof(s32), GFP_KERNEL);
300 if (!sensor_settings)
301 return -ENOMEM;
302
303 sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
304 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
305 sd->desc->ctrls = s5k4aa_ctrls;
306 sd->desc->nctrls = ARRAY_SIZE(s5k4aa_ctrls);
307
308 for (i = 0; i < ARRAY_SIZE(s5k4aa_ctrls); i++)
309 sensor_settings[i] = s5k4aa_ctrls[i].qctrl.default_value;
310 sd->sensor_priv = sensor_settings;
311
312 return 0;
313}
314
315int s5k4aa_start(struct sd *sd)
316{
317 int i, err = 0;
318 u8 data[2];
319 struct cam *cam = &sd->gspca_dev.cam;
320 s32 *sensor_settings = sd->sensor_priv;
321
322 switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) {
323 case 1280:
324 PDEBUG(D_V4L2, "Configuring camera for SXGA mode");
325
326 for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) {
327 switch (SXGA_s5k4aa[i][0]) {
328 case BRIDGE:
329 err = m5602_write_bridge(sd,
330 SXGA_s5k4aa[i][1],
331 SXGA_s5k4aa[i][2]);
332 break;
333
334 case SENSOR:
335 data[0] = SXGA_s5k4aa[i][2];
336 err = m5602_write_sensor(sd,
337 SXGA_s5k4aa[i][1],
338 data, 1);
339 break;
340
341 case SENSOR_LONG:
342 data[0] = SXGA_s5k4aa[i][2];
343 data[1] = SXGA_s5k4aa[i][3];
344 err = m5602_write_sensor(sd,
345 SXGA_s5k4aa[i][1],
346 data, 2);
347 break;
348
349 default:
350 err("Invalid stream command, exiting init");
351 return -EINVAL;
352 }
353 }
354 err = s5k4aa_set_noise(&sd->gspca_dev, 0);
355 if (err < 0)
356 return err;
357 break;
358
359 case 640:
360 PDEBUG(D_V4L2, "Configuring camera for VGA mode");
361
362 for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) {
363 switch (VGA_s5k4aa[i][0]) {
364 case BRIDGE:
365 err = m5602_write_bridge(sd,
366 VGA_s5k4aa[i][1],
367 VGA_s5k4aa[i][2]);
368 break;
369
370 case SENSOR:
371 data[0] = VGA_s5k4aa[i][2];
372 err = m5602_write_sensor(sd,
373 VGA_s5k4aa[i][1],
374 data, 1);
375 break;
376
377 case SENSOR_LONG:
378 data[0] = VGA_s5k4aa[i][2];
379 data[1] = VGA_s5k4aa[i][3];
380 err = m5602_write_sensor(sd,
381 VGA_s5k4aa[i][1],
382 data, 2);
383 break;
384
385 default:
386 err("Invalid stream command, exiting init");
387 return -EINVAL;
388 }
389 }
390 err = s5k4aa_set_noise(&sd->gspca_dev, 1);
391 if (err < 0)
392 return err;
393 break;
394 }
395 if (err < 0)
396 return err;
397
398 err = s5k4aa_set_exposure(&sd->gspca_dev,
399 sensor_settings[EXPOSURE_IDX]);
400 if (err < 0)
401 return err;
402
403 err = s5k4aa_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
404 if (err < 0)
405 return err;
406
407 err = s5k4aa_set_brightness(&sd->gspca_dev,
408 sensor_settings[BRIGHTNESS_IDX]);
409 if (err < 0)
410 return err;
411
412 err = s5k4aa_set_noise(&sd->gspca_dev, sensor_settings[NOISE_SUPP_IDX]);
413 if (err < 0)
414 return err;
415
416 err = s5k4aa_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
417 if (err < 0)
418 return err;
419
420 return s5k4aa_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
421}
422
423int s5k4aa_init(struct sd *sd)
424{
425 int i, err = 0;
426
427 for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) {
428 u8 data[2] = {0x00, 0x00};
429
430 switch (init_s5k4aa[i][0]) {
431 case BRIDGE:
432 err = m5602_write_bridge(sd,
433 init_s5k4aa[i][1],
434 init_s5k4aa[i][2]);
435 break;
436
437 case SENSOR:
438 data[0] = init_s5k4aa[i][2];
439 err = m5602_write_sensor(sd,
440 init_s5k4aa[i][1], data, 1);
441 break;
442
443 case SENSOR_LONG:
444 data[0] = init_s5k4aa[i][2];
445 data[1] = init_s5k4aa[i][3];
446 err = m5602_write_sensor(sd,
447 init_s5k4aa[i][1], data, 2);
448 break;
449 default:
450 info("Invalid stream command, exiting init");
451 return -EINVAL;
452 }
453 }
454
455 if (dump_sensor)
456 s5k4aa_dump_registers(sd);
457
458 return err;
459}
460
461static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
462{
463 struct sd *sd = (struct sd *) gspca_dev;
464 s32 *sensor_settings = sd->sensor_priv;
465
466 *val = sensor_settings[EXPOSURE_IDX];
467 PDEBUG(D_V4L2, "Read exposure %d", *val);
468
469 return 0;
470}
471
472static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
473{
474 struct sd *sd = (struct sd *) gspca_dev;
475 s32 *sensor_settings = sd->sensor_priv;
476 u8 data = S5K4AA_PAGE_MAP_2;
477 int err;
478
479 sensor_settings[EXPOSURE_IDX] = val;
480 PDEBUG(D_V4L2, "Set exposure to %d", val);
481 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
482 if (err < 0)
483 return err;
484 data = (val >> 8) & 0xff;
485 err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
486 if (err < 0)
487 return err;
488 data = val & 0xff;
489 err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
490
491 return err;
492}
493
494static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
495{
496 struct sd *sd = (struct sd *) gspca_dev;
497 s32 *sensor_settings = sd->sensor_priv;
498
499 *val = sensor_settings[VFLIP_IDX];
500 PDEBUG(D_V4L2, "Read vertical flip %d", *val);
501
502 return 0;
503}
504
505static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
506{
507 struct sd *sd = (struct sd *) gspca_dev;
508 s32 *sensor_settings = sd->sensor_priv;
509 u8 data = S5K4AA_PAGE_MAP_2;
510 int err;
511
512 sensor_settings[VFLIP_IDX] = val;
513
514 PDEBUG(D_V4L2, "Set vertical flip to %d", val);
515 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
516 if (err < 0)
517 return err;
518
519 err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
520 if (err < 0)
521 return err;
522
523 if (dmi_check_system(s5k4aa_vflip_dmi_table))
524 val = !val;
525
526 data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7));
527 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
528 if (err < 0)
529 return err;
530
531 err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
532 if (err < 0)
533 return err;
534 if (val)
535 data &= 0xfe;
536 else
537 data |= 0x01;
538 err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
539 return err;
540}
541
542static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
543{
544 struct sd *sd = (struct sd *) gspca_dev;
545 s32 *sensor_settings = sd->sensor_priv;
546
547 *val = sensor_settings[HFLIP_IDX];
548 PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
549
550 return 0;
551}
552
553static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
554{
555 struct sd *sd = (struct sd *) gspca_dev;
556 s32 *sensor_settings = sd->sensor_priv;
557 u8 data = S5K4AA_PAGE_MAP_2;
558 int err;
559
560 sensor_settings[HFLIP_IDX] = val;
561
562 PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
563 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
564 if (err < 0)
565 return err;
566
567 err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
568 if (err < 0)
569 return err;
570
571 if (dmi_check_system(s5k4aa_vflip_dmi_table))
572 val = !val;
573
574 data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
575 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
576 if (err < 0)
577 return err;
578
579 err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
580 if (err < 0)
581 return err;
582 if (val)
583 data &= 0xfe;
584 else
585 data |= 0x01;
586 err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
587 return err;
588}
589
590static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
591{
592 struct sd *sd = (struct sd *) gspca_dev;
593 s32 *sensor_settings = sd->sensor_priv;
594
595 *val = sensor_settings[GAIN_IDX];
596 PDEBUG(D_V4L2, "Read gain %d", *val);
597 return 0;
598}
599
600static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
601{
602 struct sd *sd = (struct sd *) gspca_dev;
603 s32 *sensor_settings = sd->sensor_priv;
604 u8 data = S5K4AA_PAGE_MAP_2;
605 int err;
606
607 sensor_settings[GAIN_IDX] = val;
608
609 PDEBUG(D_V4L2, "Set gain to %d", val);
610 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
611 if (err < 0)
612 return err;
613
614 data = val & 0xff;
615 err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1);
616
617 return err;
618}
619
620static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
621{
622 struct sd *sd = (struct sd *) gspca_dev;
623 s32 *sensor_settings = sd->sensor_priv;
624
625 *val = sensor_settings[BRIGHTNESS_IDX];
626 PDEBUG(D_V4L2, "Read brightness %d", *val);
627 return 0;
628}
629
630static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
631{
632 struct sd *sd = (struct sd *) gspca_dev;
633 s32 *sensor_settings = sd->sensor_priv;
634 u8 data = S5K4AA_PAGE_MAP_2;
635 int err;
636
637 sensor_settings[BRIGHTNESS_IDX] = val;
638
639 PDEBUG(D_V4L2, "Set brightness to %d", 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 return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
646}
647
648static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val)
649{
650 struct sd *sd = (struct sd *) gspca_dev;
651 s32 *sensor_settings = sd->sensor_priv;
652
653 *val = sensor_settings[NOISE_SUPP_IDX];
654 PDEBUG(D_V4L2, "Read noise %d", *val);
655 return 0;
656}
657
658static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
659{
660 struct sd *sd = (struct sd *) gspca_dev;
661 s32 *sensor_settings = sd->sensor_priv;
662 u8 data = S5K4AA_PAGE_MAP_2;
663 int err;
664
665 sensor_settings[NOISE_SUPP_IDX] = val;
666
667 PDEBUG(D_V4L2, "Set noise to %d", val);
668 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
669 if (err < 0)
670 return err;
671
672 data = val & 0x01;
673 return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
674}
675
676void s5k4aa_disconnect(struct sd *sd)
677{
678 sd->sensor = NULL;
679 kfree(sd->sensor_priv);
680}
681
682static void s5k4aa_dump_registers(struct sd *sd)
683{
684 int address;
685 u8 page, old_page;
686 m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
687 for (page = 0; page < 16; page++) {
688 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
689 info("Dumping the s5k4aa register state for page 0x%x", page);
690 for (address = 0; address <= 0xff; address++) {
691 u8 value = 0;
692 m5602_read_sensor(sd, address, &value, 1);
693 info("register 0x%x contains 0x%x",
694 address, value);
695 }
696 }
697 info("s5k4aa register state dump complete");
698
699 for (page = 0; page < 16; page++) {
700 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
701 info("Probing for which registers that are "
702 "read/write for page 0x%x", page);
703 for (address = 0; address <= 0xff; address++) {
704 u8 old_value, ctrl_value, test_value = 0xff;
705
706 m5602_read_sensor(sd, address, &old_value, 1);
707 m5602_write_sensor(sd, address, &test_value, 1);
708 m5602_read_sensor(sd, address, &ctrl_value, 1);
709
710 if (ctrl_value == test_value)
711 info("register 0x%x is writeable", address);
712 else
713 info("register 0x%x is read only", address);
714
715 /* Restore original value */
716 m5602_write_sensor(sd, address, &old_value, 1);
717 }
718 }
719 info("Read/write register probing complete");
720 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
721}
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.h b/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
new file mode 100644
index 00000000000..8cc7a3f6da7
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
@@ -0,0 +1,283 @@
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#ifndef M5602_S5K4AA_H_
20#define M5602_S5K4AA_H_
21
22#include <linux/dmi.h>
23
24#include "m5602_sensor.h"
25
26/*****************************************************************************/
27
28#define S5K4AA_PAGE_MAP 0xec
29
30#define S5K4AA_PAGE_MAP_0 0x00
31#define S5K4AA_PAGE_MAP_1 0x01
32#define S5K4AA_PAGE_MAP_2 0x02
33
34/* Sensor register definitions for page 0x02 */
35#define S5K4AA_READ_MODE 0x03
36#define S5K4AA_ROWSTART_HI 0x04
37#define S5K4AA_ROWSTART_LO 0x05
38#define S5K4AA_COLSTART_HI 0x06
39#define S5K4AA_COLSTART_LO 0x07
40#define S5K4AA_WINDOW_HEIGHT_HI 0x08
41#define S5K4AA_WINDOW_HEIGHT_LO 0x09
42#define S5K4AA_WINDOW_WIDTH_HI 0x0a
43#define S5K4AA_WINDOW_WIDTH_LO 0x0b
44#define S5K4AA_GLOBAL_GAIN__ 0x0f
45/* sync lost, if too low, reduces frame rate if too high */
46#define S5K4AA_H_BLANK_HI__ 0x1d
47#define S5K4AA_H_BLANK_LO__ 0x1e
48#define S5K4AA_EXPOSURE_HI 0x17
49#define S5K4AA_EXPOSURE_LO 0x18
50#define S5K4AA_BRIGHTNESS 0x1f /* (digital?) gain : 5 bits */
51#define S5K4AA_GAIN 0x20 /* (analogue?) gain : 7 bits */
52#define S5K4AA_NOISE_SUPP 0x37
53
54#define S5K4AA_RM_ROW_SKIP_4X 0x08
55#define S5K4AA_RM_ROW_SKIP_2X 0x04
56#define S5K4AA_RM_COL_SKIP_4X 0x02
57#define S5K4AA_RM_COL_SKIP_2X 0x01
58#define S5K4AA_RM_H_FLIP 0x40
59#define S5K4AA_RM_V_FLIP 0x80
60
61#define S5K4AA_DEFAULT_GAIN 0x5f
62#define S5K4AA_DEFAULT_BRIGHTNESS 0x10
63
64/*****************************************************************************/
65
66/* Kernel module parameters */
67extern int force_sensor;
68extern int dump_sensor;
69
70int s5k4aa_probe(struct sd *sd);
71int s5k4aa_init(struct sd *sd);
72int s5k4aa_start(struct sd *sd);
73void s5k4aa_disconnect(struct sd *sd);
74
75static const struct m5602_sensor s5k4aa = {
76 .name = "S5K4AA",
77 .i2c_slave_id = 0x5a,
78 .i2c_regW = 2,
79
80 .probe = s5k4aa_probe,
81 .init = s5k4aa_init,
82 .start = s5k4aa_start,
83 .disconnect = s5k4aa_disconnect,
84};
85
86static const unsigned char preinit_s5k4aa[][4] = {
87 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
88 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
89 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
90 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
91 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
92 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
93 {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
94
95 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
96 {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
97 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
98 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
99 {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
100 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
101 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
102 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
103 {BRIDGE, M5602_XB_GPIO_DAT, 0x00, 0x00},
104 {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
105 {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
106 {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
107 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
108 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
109 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
110 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00},
111
112 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
113 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
114 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
115 {BRIDGE, M5602_XB_GPIO_DAT, 0x14, 0x00},
116 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
117 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
118 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
119 {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
120 {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
121 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
122 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
123 {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
124 {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
125
126 {SENSOR, S5K4AA_PAGE_MAP, 0x00, 0x00}
127};
128
129static const unsigned char init_s5k4aa[][4] = {
130 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
131 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
132 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
133 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
134 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
135 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
136 {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
137
138 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
139 {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
140 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
141 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
142 {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
143 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
144 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
145 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
146 {BRIDGE, M5602_XB_GPIO_DAT, 0x00, 0x00},
147 {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
148 {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
149 {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
150 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
151 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
152 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
153 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00},
154
155 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
156 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
157 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
158 {BRIDGE, M5602_XB_GPIO_DAT, 0x14, 0x00},
159 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
160 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
161 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
162 {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
163 {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
164 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
165 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
166 {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
167 {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
168
169 {SENSOR, S5K4AA_PAGE_MAP, 0x07, 0x00},
170 {SENSOR, 0x36, 0x01, 0x00},
171 {SENSOR, S5K4AA_PAGE_MAP, 0x00, 0x00},
172 {SENSOR, 0x7b, 0xff, 0x00},
173 {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
174 {SENSOR, 0x0c, 0x05, 0x00},
175 {SENSOR, 0x02, 0x0e, 0x00},
176 {SENSOR, S5K4AA_READ_MODE, 0xa0, 0x00},
177 {SENSOR, 0x37, 0x00, 0x00},
178};
179
180static const unsigned char VGA_s5k4aa[][4] = {
181 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
182 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
183 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
184 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00},
185 {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
186 {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
187 {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
188 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
189 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
190 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
191 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
192 /* VSYNC_PARA, VSYNC_PARA : img height 480 = 0x01e0 */
193 {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
194 {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0, 0x00},
195 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
196 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
197 {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
198 {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
199 {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
200 {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
201 /* HSYNC_PARA, HSYNC_PARA : img width 640 = 0x0280 */
202 {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
203 {BRIDGE, M5602_XB_HSYNC_PARA, 0x80, 0x00},
204 {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
205 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
206 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, /* 48 MHz */
207
208 {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
209 {SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP | S5K4AA_RM_ROW_SKIP_2X
210 | S5K4AA_RM_COL_SKIP_2X, 0x00},
211 /* 0x37 : Fix image stability when light is too bright and improves
212 * image quality in 640x480, but worsens it in 1280x1024 */
213 {SENSOR, 0x37, 0x01, 0x00},
214 /* ROWSTART_HI, ROWSTART_LO : 10 + (1024-960)/2 = 42 = 0x002a */
215 {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00},
216 {SENSOR, S5K4AA_ROWSTART_LO, 0x29, 0x00},
217 {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00},
218 {SENSOR, S5K4AA_COLSTART_LO, 0x0c, 0x00},
219 /* window_height_hi, window_height_lo : 960 = 0x03c0 */
220 {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x03, 0x00},
221 {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0xc0, 0x00},
222 /* window_width_hi, window_width_lo : 1280 = 0x0500 */
223 {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00},
224 {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x00, 0x00},
225 {SENSOR, S5K4AA_H_BLANK_HI__, 0x00, 0x00},
226 {SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00}, /* helps to sync... */
227 {SENSOR, S5K4AA_EXPOSURE_HI, 0x01, 0x00},
228 {SENSOR, S5K4AA_EXPOSURE_LO, 0x00, 0x00},
229 {SENSOR, 0x11, 0x04, 0x00},
230 {SENSOR, 0x12, 0xc3, 0x00},
231 {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
232 {SENSOR, 0x02, 0x0e, 0x00},
233};
234
235static const unsigned char SXGA_s5k4aa[][4] = {
236 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
237 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
238 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
239 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00},
240 {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
241 {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
242 {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
243 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
244 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
245 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
246 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
247 /* VSYNC_PARA, VSYNC_PARA : img height 1024 = 0x0400 */
248 {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
249 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
250 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
251 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
252 {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
253 {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
254 {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
255 {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
256 /* HSYNC_PARA, HSYNC_PARA : img width 1280 = 0x0500 */
257 {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00},
258 {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
259 {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
260 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
261 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, /* 48 MHz */
262
263 {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
264 {SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP, 0x00},
265 {SENSOR, 0x37, 0x01, 0x00},
266 {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00},
267 {SENSOR, S5K4AA_ROWSTART_LO, 0x09, 0x00},
268 {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00},
269 {SENSOR, S5K4AA_COLSTART_LO, 0x0a, 0x00},
270 {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x04, 0x00},
271 {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0x00, 0x00},
272 {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00},
273 {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x00, 0x00},
274 {SENSOR, S5K4AA_H_BLANK_HI__, 0x01, 0x00},
275 {SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00},
276 {SENSOR, S5K4AA_EXPOSURE_HI, 0x01, 0x00},
277 {SENSOR, S5K4AA_EXPOSURE_LO, 0x00, 0x00},
278 {SENSOR, 0x11, 0x04, 0x00},
279 {SENSOR, 0x12, 0xc3, 0x00},
280 {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
281 {SENSOR, 0x02, 0x0e, 0x00},
282};
283#endif
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.c b/drivers/media/video/gspca/m5602/m5602_s5k83a.c
new file mode 100644
index 00000000000..fbd91545497
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_s5k83a.c
@@ -0,0 +1,601 @@
1/*
2 * Driver for the s5k83a 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 <linux/kthread.h>
20#include "m5602_s5k83a.h"
21
22static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val);
23static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
24static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
25static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
26static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
27static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
28static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
29static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
30static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
31static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
32
33static struct v4l2_pix_format s5k83a_modes[] = {
34 {
35 640,
36 480,
37 V4L2_PIX_FMT_SBGGR8,
38 V4L2_FIELD_NONE,
39 .sizeimage =
40 640 * 480,
41 .bytesperline = 640,
42 .colorspace = V4L2_COLORSPACE_SRGB,
43 .priv = 0
44 }
45};
46
47static const struct ctrl s5k83a_ctrls[] = {
48#define GAIN_IDX 0
49 {
50 {
51 .id = V4L2_CID_GAIN,
52 .type = V4L2_CTRL_TYPE_INTEGER,
53 .name = "gain",
54 .minimum = 0x00,
55 .maximum = 0xff,
56 .step = 0x01,
57 .default_value = S5K83A_DEFAULT_GAIN,
58 .flags = V4L2_CTRL_FLAG_SLIDER
59 },
60 .set = s5k83a_set_gain,
61 .get = s5k83a_get_gain
62
63 },
64#define BRIGHTNESS_IDX 1
65 {
66 {
67 .id = V4L2_CID_BRIGHTNESS,
68 .type = V4L2_CTRL_TYPE_INTEGER,
69 .name = "brightness",
70 .minimum = 0x00,
71 .maximum = 0xff,
72 .step = 0x01,
73 .default_value = S5K83A_DEFAULT_BRIGHTNESS,
74 .flags = V4L2_CTRL_FLAG_SLIDER
75 },
76 .set = s5k83a_set_brightness,
77 .get = s5k83a_get_brightness,
78 },
79#define EXPOSURE_IDX 2
80 {
81 {
82 .id = V4L2_CID_EXPOSURE,
83 .type = V4L2_CTRL_TYPE_INTEGER,
84 .name = "exposure",
85 .minimum = 0x00,
86 .maximum = S5K83A_MAXIMUM_EXPOSURE,
87 .step = 0x01,
88 .default_value = S5K83A_DEFAULT_EXPOSURE,
89 .flags = V4L2_CTRL_FLAG_SLIDER
90 },
91 .set = s5k83a_set_exposure,
92 .get = s5k83a_get_exposure
93 },
94#define HFLIP_IDX 3
95 {
96 {
97 .id = V4L2_CID_HFLIP,
98 .type = V4L2_CTRL_TYPE_BOOLEAN,
99 .name = "horizontal flip",
100 .minimum = 0,
101 .maximum = 1,
102 .step = 1,
103 .default_value = 0
104 },
105 .set = s5k83a_set_hflip,
106 .get = s5k83a_get_hflip
107 },
108#define VFLIP_IDX 4
109 {
110 {
111 .id = V4L2_CID_VFLIP,
112 .type = V4L2_CTRL_TYPE_BOOLEAN,
113 .name = "vertical flip",
114 .minimum = 0,
115 .maximum = 1,
116 .step = 1,
117 .default_value = 0
118 },
119 .set = s5k83a_set_vflip,
120 .get = s5k83a_get_vflip
121 }
122};
123
124static void s5k83a_dump_registers(struct sd *sd);
125static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data);
126static int s5k83a_set_led_indication(struct sd *sd, u8 val);
127static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
128 __s32 vflip, __s32 hflip);
129
130int s5k83a_probe(struct sd *sd)
131{
132 struct s5k83a_priv *sens_priv;
133 u8 prod_id = 0, ver_id = 0;
134 int i, err = 0;
135
136 if (force_sensor) {
137 if (force_sensor == S5K83A_SENSOR) {
138 info("Forcing a %s sensor", s5k83a.name);
139 goto sensor_found;
140 }
141 /* If we want to force another sensor, don't try to probe this
142 * one */
143 return -ENODEV;
144 }
145
146 PDEBUG(D_PROBE, "Probing for a s5k83a sensor");
147
148 /* Preinit the sensor */
149 for (i = 0; i < ARRAY_SIZE(preinit_s5k83a) && !err; i++) {
150 u8 data[2] = {preinit_s5k83a[i][2], preinit_s5k83a[i][3]};
151 if (preinit_s5k83a[i][0] == SENSOR)
152 err = m5602_write_sensor(sd, preinit_s5k83a[i][1],
153 data, 2);
154 else
155 err = m5602_write_bridge(sd, preinit_s5k83a[i][1],
156 data[0]);
157 }
158
159 /* We don't know what register (if any) that contain the product id
160 * Just pick the first addresses that seem to produce the same results
161 * on multiple machines */
162 if (m5602_read_sensor(sd, 0x00, &prod_id, 1))
163 return -ENODEV;
164
165 if (m5602_read_sensor(sd, 0x01, &ver_id, 1))
166 return -ENODEV;
167
168 if ((prod_id == 0xff) || (ver_id == 0xff))
169 return -ENODEV;
170 else
171 info("Detected a s5k83a sensor");
172
173sensor_found:
174 sens_priv = kmalloc(
175 sizeof(struct s5k83a_priv), GFP_KERNEL);
176 if (!sens_priv)
177 return -ENOMEM;
178
179 sens_priv->settings =
180 kmalloc(sizeof(s32)*ARRAY_SIZE(s5k83a_ctrls), GFP_KERNEL);
181 if (!sens_priv->settings) {
182 kfree(sens_priv);
183 return -ENOMEM;
184 }
185
186 sd->gspca_dev.cam.cam_mode = s5k83a_modes;
187 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes);
188 sd->desc->ctrls = s5k83a_ctrls;
189 sd->desc->nctrls = ARRAY_SIZE(s5k83a_ctrls);
190
191 /* null the pointer! thread is't running now */
192 sens_priv->rotation_thread = NULL;
193
194 for (i = 0; i < ARRAY_SIZE(s5k83a_ctrls); i++)
195 sens_priv->settings[i] = s5k83a_ctrls[i].qctrl.default_value;
196
197 sd->sensor_priv = sens_priv;
198 return 0;
199}
200
201int s5k83a_init(struct sd *sd)
202{
203 int i, err = 0;
204 s32 *sensor_settings =
205 ((struct s5k83a_priv *) sd->sensor_priv)->settings;
206
207 for (i = 0; i < ARRAY_SIZE(init_s5k83a) && !err; i++) {
208 u8 data[2] = {0x00, 0x00};
209
210 switch (init_s5k83a[i][0]) {
211 case BRIDGE:
212 err = m5602_write_bridge(sd,
213 init_s5k83a[i][1],
214 init_s5k83a[i][2]);
215 break;
216
217 case SENSOR:
218 data[0] = init_s5k83a[i][2];
219 err = m5602_write_sensor(sd,
220 init_s5k83a[i][1], data, 1);
221 break;
222
223 case SENSOR_LONG:
224 data[0] = init_s5k83a[i][2];
225 data[1] = init_s5k83a[i][3];
226 err = m5602_write_sensor(sd,
227 init_s5k83a[i][1], data, 2);
228 break;
229 default:
230 info("Invalid stream command, exiting init");
231 return -EINVAL;
232 }
233 }
234
235 if (dump_sensor)
236 s5k83a_dump_registers(sd);
237
238 err = s5k83a_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
239 if (err < 0)
240 return err;
241
242 err = s5k83a_set_brightness(&sd->gspca_dev,
243 sensor_settings[BRIGHTNESS_IDX]);
244 if (err < 0)
245 return err;
246
247 err = s5k83a_set_exposure(&sd->gspca_dev,
248 sensor_settings[EXPOSURE_IDX]);
249 if (err < 0)
250 return err;
251
252 err = s5k83a_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
253 if (err < 0)
254 return err;
255
256 err = s5k83a_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
257
258 return err;
259}
260
261static int rotation_thread_function(void *data)
262{
263 struct sd *sd = (struct sd *) data;
264 struct s5k83a_priv *sens_priv = sd->sensor_priv;
265 u8 reg, previous_rotation = 0;
266 __s32 vflip, hflip;
267
268 set_current_state(TASK_INTERRUPTIBLE);
269 while (!schedule_timeout(100)) {
270 if (mutex_lock_interruptible(&sd->gspca_dev.usb_lock))
271 break;
272
273 s5k83a_get_rotation(sd, &reg);
274 if (previous_rotation != reg) {
275 previous_rotation = reg;
276 info("Camera was flipped");
277
278 s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
279 s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
280
281 if (reg) {
282 vflip = !vflip;
283 hflip = !hflip;
284 }
285 s5k83a_set_flip_real((struct gspca_dev *) sd,
286 vflip, hflip);
287 }
288
289 mutex_unlock(&sd->gspca_dev.usb_lock);
290 set_current_state(TASK_INTERRUPTIBLE);
291 }
292
293 /* return to "front" flip */
294 if (previous_rotation) {
295 s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
296 s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
297 s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip);
298 }
299
300 sens_priv->rotation_thread = NULL;
301 return 0;
302}
303
304int s5k83a_start(struct sd *sd)
305{
306 int i, err = 0;
307 struct s5k83a_priv *sens_priv = sd->sensor_priv;
308
309 /* Create another thread, polling the GPIO ports of the camera to check
310 if it got rotated. This is how the windows driver does it so we have
311 to assume that there is no better way of accomplishing this */
312 sens_priv->rotation_thread = kthread_create(rotation_thread_function,
313 sd, "rotation thread");
314 wake_up_process(sens_priv->rotation_thread);
315
316 /* Preinit the sensor */
317 for (i = 0; i < ARRAY_SIZE(start_s5k83a) && !err; i++) {
318 u8 data[2] = {start_s5k83a[i][2], start_s5k83a[i][3]};
319 if (start_s5k83a[i][0] == SENSOR)
320 err = m5602_write_sensor(sd, start_s5k83a[i][1],
321 data, 2);
322 else
323 err = m5602_write_bridge(sd, start_s5k83a[i][1],
324 data[0]);
325 }
326 if (err < 0)
327 return err;
328
329 return s5k83a_set_led_indication(sd, 1);
330}
331
332int s5k83a_stop(struct sd *sd)
333{
334 struct s5k83a_priv *sens_priv = sd->sensor_priv;
335
336 if (sens_priv->rotation_thread)
337 kthread_stop(sens_priv->rotation_thread);
338
339 return s5k83a_set_led_indication(sd, 0);
340}
341
342void s5k83a_disconnect(struct sd *sd)
343{
344 struct s5k83a_priv *sens_priv = sd->sensor_priv;
345
346 s5k83a_stop(sd);
347
348 sd->sensor = NULL;
349 kfree(sens_priv->settings);
350 kfree(sens_priv);
351}
352
353static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
354{
355 struct sd *sd = (struct sd *) gspca_dev;
356 struct s5k83a_priv *sens_priv = sd->sensor_priv;
357
358 *val = sens_priv->settings[GAIN_IDX];
359 return 0;
360}
361
362static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
363{
364 int err;
365 u8 data[2];
366 struct sd *sd = (struct sd *) gspca_dev;
367 struct s5k83a_priv *sens_priv = sd->sensor_priv;
368
369 sens_priv->settings[GAIN_IDX] = val;
370
371 data[0] = 0x00;
372 data[1] = 0x20;
373 err = m5602_write_sensor(sd, 0x14, data, 2);
374 if (err < 0)
375 return err;
376
377 data[0] = 0x01;
378 data[1] = 0x00;
379 err = m5602_write_sensor(sd, 0x0d, data, 2);
380 if (err < 0)
381 return err;
382
383 /* FIXME: This is not sane, we need to figure out the composition
384 of these registers */
385 data[0] = val >> 3; /* gain, high 5 bits */
386 data[1] = val >> 1; /* gain, high 7 bits */
387 err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2);
388
389 return err;
390}
391
392static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
393{
394 struct sd *sd = (struct sd *) gspca_dev;
395 struct s5k83a_priv *sens_priv = sd->sensor_priv;
396
397 *val = sens_priv->settings[BRIGHTNESS_IDX];
398 return 0;
399}
400
401static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
402{
403 int err;
404 u8 data[1];
405 struct sd *sd = (struct sd *) gspca_dev;
406 struct s5k83a_priv *sens_priv = sd->sensor_priv;
407
408 sens_priv->settings[BRIGHTNESS_IDX] = val;
409 data[0] = val;
410 err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1);
411 return err;
412}
413
414static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
415{
416 struct sd *sd = (struct sd *) gspca_dev;
417 struct s5k83a_priv *sens_priv = sd->sensor_priv;
418
419 *val = sens_priv->settings[EXPOSURE_IDX];
420 return 0;
421}
422
423static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
424{
425 int err;
426 u8 data[2];
427 struct sd *sd = (struct sd *) gspca_dev;
428 struct s5k83a_priv *sens_priv = sd->sensor_priv;
429
430 sens_priv->settings[EXPOSURE_IDX] = val;
431 data[0] = 0;
432 data[1] = val;
433 err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2);
434 return err;
435}
436
437static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
438{
439 struct sd *sd = (struct sd *) gspca_dev;
440 struct s5k83a_priv *sens_priv = sd->sensor_priv;
441
442 *val = sens_priv->settings[VFLIP_IDX];
443 return 0;
444}
445
446static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
447 __s32 vflip, __s32 hflip)
448{
449 int err;
450 u8 data[1];
451 struct sd *sd = (struct sd *) gspca_dev;
452
453 data[0] = 0x05;
454 err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
455 if (err < 0)
456 return err;
457
458 /* six bit is vflip, seven is hflip */
459 data[0] = S5K83A_FLIP_MASK;
460 data[0] = (vflip) ? data[0] | 0x40 : data[0];
461 data[0] = (hflip) ? data[0] | 0x80 : data[0];
462
463 err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
464 if (err < 0)
465 return err;
466
467 data[0] = (vflip) ? 0x0b : 0x0a;
468 err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1);
469 if (err < 0)
470 return err;
471
472 data[0] = (hflip) ? 0x0a : 0x0b;
473 err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
474 return err;
475}
476
477static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
478{
479 int err;
480 u8 reg;
481 __s32 hflip;
482 struct sd *sd = (struct sd *) gspca_dev;
483 struct s5k83a_priv *sens_priv = sd->sensor_priv;
484
485 sens_priv->settings[VFLIP_IDX] = val;
486
487 s5k83a_get_hflip(gspca_dev, &hflip);
488
489 err = s5k83a_get_rotation(sd, &reg);
490 if (err < 0)
491 return err;
492 if (reg) {
493 val = !val;
494 hflip = !hflip;
495 }
496
497 err = s5k83a_set_flip_real(gspca_dev, val, hflip);
498 return err;
499}
500
501static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
502{
503 struct sd *sd = (struct sd *) gspca_dev;
504 struct s5k83a_priv *sens_priv = sd->sensor_priv;
505
506 *val = sens_priv->settings[HFLIP_IDX];
507 return 0;
508}
509
510static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
511{
512 int err;
513 u8 reg;
514 __s32 vflip;
515 struct sd *sd = (struct sd *) gspca_dev;
516 struct s5k83a_priv *sens_priv = sd->sensor_priv;
517
518 sens_priv->settings[HFLIP_IDX] = val;
519
520 s5k83a_get_vflip(gspca_dev, &vflip);
521
522 err = s5k83a_get_rotation(sd, &reg);
523 if (err < 0)
524 return err;
525 if (reg) {
526 val = !val;
527 vflip = !vflip;
528 }
529
530 err = s5k83a_set_flip_real(gspca_dev, vflip, val);
531 return err;
532}
533
534static int s5k83a_set_led_indication(struct sd *sd, u8 val)
535{
536 int err = 0;
537 u8 data[1];
538
539 err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, data);
540 if (err < 0)
541 return err;
542
543 if (val)
544 data[0] = data[0] | S5K83A_GPIO_LED_MASK;
545 else
546 data[0] = data[0] & ~S5K83A_GPIO_LED_MASK;
547
548 err = m5602_write_bridge(sd, M5602_XB_GPIO_DAT, data[0]);
549
550 return err;
551}
552
553/* Get camera rotation on Acer notebooks */
554static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data)
555{
556 int err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, reg_data);
557 *reg_data = (*reg_data & S5K83A_GPIO_ROTATION_MASK) ? 0 : 1;
558 return err;
559}
560
561static void s5k83a_dump_registers(struct sd *sd)
562{
563 int address;
564 u8 page, old_page;
565 m5602_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
566
567 for (page = 0; page < 16; page++) {
568 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
569 info("Dumping the s5k83a register state for page 0x%x", page);
570 for (address = 0; address <= 0xff; address++) {
571 u8 val = 0;
572 m5602_read_sensor(sd, address, &val, 1);
573 info("register 0x%x contains 0x%x",
574 address, val);
575 }
576 }
577 info("s5k83a register state dump complete");
578
579 for (page = 0; page < 16; page++) {
580 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
581 info("Probing for which registers that are read/write "
582 "for page 0x%x", page);
583 for (address = 0; address <= 0xff; address++) {
584 u8 old_val, ctrl_val, test_val = 0xff;
585
586 m5602_read_sensor(sd, address, &old_val, 1);
587 m5602_write_sensor(sd, address, &test_val, 1);
588 m5602_read_sensor(sd, address, &ctrl_val, 1);
589
590 if (ctrl_val == test_val)
591 info("register 0x%x is writeable", address);
592 else
593 info("register 0x%x is read only", address);
594
595 /* Restore original val */
596 m5602_write_sensor(sd, address, &old_val, 1);
597 }
598 }
599 info("Read/write register probing complete");
600 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
601}
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.h b/drivers/media/video/gspca/m5602/m5602_s5k83a.h
new file mode 100644
index 00000000000..80a63a236e2
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_s5k83a.h
@@ -0,0 +1,193 @@
1/*
2 * Driver for the s5k83a 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#ifndef M5602_S5K83A_H_
20#define M5602_S5K83A_H_
21
22#include "m5602_sensor.h"
23
24#define S5K83A_FLIP 0x01
25#define S5K83A_HFLIP_TUNE 0x03
26#define S5K83A_VFLIP_TUNE 0x05
27#define S5K83A_BRIGHTNESS 0x0a
28#define S5K83A_EXPOSURE 0x18
29#define S5K83A_GAIN 0x1b
30#define S5K83A_PAGE_MAP 0xec
31
32#define S5K83A_DEFAULT_GAIN 0x71
33#define S5K83A_DEFAULT_BRIGHTNESS 0x7e
34#define S5K83A_DEFAULT_EXPOSURE 0x00
35#define S5K83A_MAXIMUM_EXPOSURE 0x3c
36#define S5K83A_FLIP_MASK 0x10
37#define S5K83A_GPIO_LED_MASK 0x10
38#define S5K83A_GPIO_ROTATION_MASK 0x40
39
40/*****************************************************************************/
41
42/* Kernel module parameters */
43extern int force_sensor;
44extern int dump_sensor;
45
46int s5k83a_probe(struct sd *sd);
47int s5k83a_init(struct sd *sd);
48int s5k83a_start(struct sd *sd);
49int s5k83a_stop(struct sd *sd);
50void s5k83a_disconnect(struct sd *sd);
51
52static const struct m5602_sensor s5k83a = {
53 .name = "S5K83A",
54 .probe = s5k83a_probe,
55 .init = s5k83a_init,
56 .start = s5k83a_start,
57 .stop = s5k83a_stop,
58 .disconnect = s5k83a_disconnect,
59 .i2c_slave_id = 0x5a,
60 .i2c_regW = 2,
61};
62
63struct s5k83a_priv {
64 /* We use another thread periodically
65 probing the orientation of the camera */
66 struct task_struct *rotation_thread;
67 s32 *settings;
68};
69
70static const unsigned char preinit_s5k83a[][4] = {
71 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
72 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
73 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
74 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
75 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
76 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
77 {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
78
79 {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
80 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
81 {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
82 {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
83 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
84 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
85 {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
86 {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
87 {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
88 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
89 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
90 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
91 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
92 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
93 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
94 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
95 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
96 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
97 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
98 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
99 {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
100 {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
101 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
102 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
103 {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
104 {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
105};
106
107/* This could probably be considerably shortened.
108 I don't have the hardware to experiment with it, patches welcome
109*/
110static const unsigned char init_s5k83a[][4] = {
111 /* The following sequence is useless after a clean boot
112 but is necessary after resume from suspend */
113 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
114 {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
115 {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
116 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
117 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
118 {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
119 {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
120 {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
121 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
122 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
123 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
124 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
125 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
126 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
127 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
128 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
129 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
130 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
131 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
132 {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
133 {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
134 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
135 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
136 {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
137 {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
138
139 {SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00},
140 {SENSOR, 0xaf, 0x01, 0x00},
141 {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00},
142 {SENSOR, 0x7b, 0xff, 0x00},
143 {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
144 {SENSOR, 0x01, 0x50, 0x00},
145 {SENSOR, 0x12, 0x20, 0x00},
146 {SENSOR, 0x17, 0x40, 0x00},
147 {SENSOR, 0x1c, 0x00, 0x00},
148 {SENSOR, 0x02, 0x70, 0x00},
149 {SENSOR, 0x03, 0x0b, 0x00},
150 {SENSOR, 0x04, 0xf0, 0x00},
151 {SENSOR, 0x05, 0x0b, 0x00},
152 {SENSOR, 0x06, 0x71, 0x00},
153 {SENSOR, 0x07, 0xe8, 0x00}, /* 488 */
154 {SENSOR, 0x08, 0x02, 0x00},
155 {SENSOR, 0x09, 0x88, 0x00}, /* 648 */
156 {SENSOR, 0x14, 0x00, 0x00},
157 {SENSOR, 0x15, 0x20, 0x00}, /* 32 */
158 {SENSOR, 0x19, 0x00, 0x00},
159 {SENSOR, 0x1a, 0x98, 0x00}, /* 152 */
160 {SENSOR, 0x0f, 0x02, 0x00},
161 {SENSOR, 0x10, 0xe5, 0x00}, /* 741 */
162 /* normal colors
163 (this is value after boot, but after tries can be different) */
164 {SENSOR, 0x00, 0x06, 0x00},
165};
166
167static const unsigned char start_s5k83a[][4] = {
168 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
169 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
170 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
171 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
172 {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
173 {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
174 {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
175 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 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, 0x01, 0x00},
180 {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00}, /* 484 */
181 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
182 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
183 {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
184 {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
185 {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
186 {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
187 {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
188 {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00}, /* 639 */
189 {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
190 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
191 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
192};
193#endif
diff --git a/drivers/media/video/gspca/m5602/m5602_sensor.h b/drivers/media/video/gspca/m5602/m5602_sensor.h
new file mode 100644
index 00000000000..edff4f1f586
--- /dev/null
+++ b/drivers/media/video/gspca/m5602/m5602_sensor.h
@@ -0,0 +1,70 @@
1/*
2 * USB Driver for ALi m5602 based webcams
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#ifndef M5602_SENSOR_H_
20#define M5602_SENSOR_H_
21
22#include "m5602_bridge.h"
23
24#define M5602_V4L2_CID_GREEN_BALANCE (V4L2_CID_PRIVATE_BASE + 0)
25#define M5602_V4L2_CID_NOISE_SUPPRESION (V4L2_CID_PRIVATE_BASE + 1)
26
27/* Enumerates all supported sensors */
28enum sensors {
29 OV9650_SENSOR = 1,
30 S5K83A_SENSOR = 2,
31 S5K4AA_SENSOR = 3,
32 MT9M111_SENSOR = 4,
33 PO1030_SENSOR = 5,
34 OV7660_SENSOR = 6,
35};
36
37/* Enumerates all possible instruction types */
38enum instruction {
39 BRIDGE,
40 SENSOR,
41 SENSOR_LONG
42};
43
44struct m5602_sensor {
45 /* Defines the name of a sensor */
46 char name[32];
47
48 /* What i2c address the sensor is connected to */
49 u8 i2c_slave_id;
50
51 /* Width of each i2c register (in bytes) */
52 u8 i2c_regW;
53
54 /* Probes if the sensor is connected */
55 int (*probe)(struct sd *sd);
56
57 /* Performs a initialization sequence */
58 int (*init)(struct sd *sd);
59
60 /* Executed when the camera starts to send data */
61 int (*start)(struct sd *sd);
62
63 /* Executed when the camera ends to send data */
64 int (*stop)(struct sd *sd);
65
66 /* Executed when the device is disconnected */
67 void (*disconnect)(struct sd *sd);
68};
69
70#endif