aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/usb/gspca/m5602
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2012-08-13 23:13:22 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-08-15 15:25:07 -0400
commit0c0d06cac63ee327ceaab4b5ffe2206574ab86bd (patch)
treee759f0dc3185d97f2a0c6b5cd5e32ea6faa74d40 /drivers/media/usb/gspca/m5602
parent84cfe9e79bd5ac11c963f4841158454fefa872f6 (diff)
[media] rename most media/video usb drivers to media/usb
Rename all USB drivers with their own directory under drivers/media/video into drivers/media/usb and update the building system. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/usb/gspca/m5602')
-rw-r--r--drivers/media/usb/gspca/m5602/Kconfig11
-rw-r--r--drivers/media/usb/gspca/m5602/Makefile11
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_bridge.h163
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_core.c424
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_mt9m111.c647
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_mt9m111.h271
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_ov7660.c488
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_ov7660.h260
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_ov9650.c881
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_ov9650.h307
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_po1030.c763
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_po1030.h272
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_s5k4aa.c726
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_s5k4aa.h283
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_s5k83a.c605
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_s5k83a.h193
-rw-r--r--drivers/media/usb/gspca/m5602/m5602_sensor.h70
17 files changed, 6375 insertions, 0 deletions
diff --git a/drivers/media/usb/gspca/m5602/Kconfig b/drivers/media/usb/gspca/m5602/Kconfig
new file mode 100644
index 000000000000..5a69016ed75f
--- /dev/null
+++ b/drivers/media/usb/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/usb/gspca/m5602/Makefile b/drivers/media/usb/gspca/m5602/Makefile
new file mode 100644
index 000000000000..8e1fb5a1d2a1
--- /dev/null
+++ b/drivers/media/usb/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
11ccflags-y += -I$(srctree)/drivers/media/usb/gspca
diff --git a/drivers/media/usb/gspca/m5602/m5602_bridge.h b/drivers/media/usb/gspca/m5602/m5602_bridge.h
new file mode 100644
index 000000000000..51af3ee3ab85
--- /dev/null
+++ b/drivers/media/usb/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/usb/gspca/m5602/m5602_core.c b/drivers/media/usb/gspca/m5602/m5602_core.c
new file mode 100644
index 000000000000..ed22638978ce
--- /dev/null
+++ b/drivers/media/usb/gspca/m5602/m5602_core.c
@@ -0,0 +1,424 @@
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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20
21#include "m5602_ov9650.h"
22#include "m5602_ov7660.h"
23#include "m5602_mt9m111.h"
24#include "m5602_po1030.h"
25#include "m5602_s5k83a.h"
26#include "m5602_s5k4aa.h"
27
28/* Kernel module parameters */
29int force_sensor;
30static bool dump_bridge;
31bool dump_sensor;
32
33static const struct usb_device_id m5602_table[] = {
34 {USB_DEVICE(0x0402, 0x5602)},
35 {}
36};
37
38MODULE_DEVICE_TABLE(usb, m5602_table);
39
40/* Reads a byte from the m5602 */
41int m5602_read_bridge(struct sd *sd, const u8 address, u8 *i2c_data)
42{
43 int err;
44 struct usb_device *udev = sd->gspca_dev.dev;
45 __u8 *buf = sd->gspca_dev.usb_buf;
46
47 err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
48 0x04, 0xc0, 0x14,
49 0x8100 + address, buf,
50 1, M5602_URB_MSG_TIMEOUT);
51 *i2c_data = buf[0];
52
53 PDEBUG(D_CONF, "Reading bridge register 0x%x containing 0x%x",
54 address, *i2c_data);
55
56 /* usb_control_msg(...) returns the number of bytes sent upon success,
57 mask that and return zero instead*/
58 return (err < 0) ? err : 0;
59}
60
61/* Writes a byte to the m5602 */
62int m5602_write_bridge(struct sd *sd, const u8 address, const u8 i2c_data)
63{
64 int err;
65 struct usb_device *udev = sd->gspca_dev.dev;
66 __u8 *buf = sd->gspca_dev.usb_buf;
67
68 PDEBUG(D_CONF, "Writing bridge register 0x%x with 0x%x",
69 address, i2c_data);
70
71 memcpy(buf, bridge_urb_skeleton,
72 sizeof(bridge_urb_skeleton));
73 buf[1] = address;
74 buf[3] = i2c_data;
75
76 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
77 0x04, 0x40, 0x19,
78 0x0000, buf,
79 4, M5602_URB_MSG_TIMEOUT);
80
81 /* usb_control_msg(...) returns the number of bytes sent upon success,
82 mask that and return zero instead */
83 return (err < 0) ? err : 0;
84}
85
86static int m5602_wait_for_i2c(struct sd *sd)
87{
88 int err;
89 u8 data;
90
91 do {
92 err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, &data);
93 } while ((data & I2C_BUSY) && !err);
94 return err;
95}
96
97int m5602_read_sensor(struct sd *sd, const u8 address,
98 u8 *i2c_data, const u8 len)
99{
100 int err, i;
101
102 if (!len || len > sd->sensor->i2c_regW)
103 return -EINVAL;
104
105 err = m5602_wait_for_i2c(sd);
106 if (err < 0)
107 return err;
108
109 err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
110 sd->sensor->i2c_slave_id);
111 if (err < 0)
112 return err;
113
114 err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
115 if (err < 0)
116 return err;
117
118 /* Sensors with registers that are of only
119 one byte width are differently read */
120
121 /* FIXME: This works with the ov9650, but has issues with the po1030 */
122 if (sd->sensor->i2c_regW == 1) {
123 err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 1);
124 if (err < 0)
125 return err;
126
127 err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x08);
128 } else {
129 err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x18 + len);
130 }
131
132 for (i = 0; (i < len) && !err; i++) {
133 err = m5602_wait_for_i2c(sd);
134 if (err < 0)
135 return err;
136
137 err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
138
139 PDEBUG(D_CONF, "Reading sensor register "
140 "0x%x containing 0x%x ", address, *i2c_data);
141 }
142 return err;
143}
144
145int m5602_write_sensor(struct sd *sd, const u8 address,
146 u8 *i2c_data, const u8 len)
147{
148 int err, i;
149 u8 *p;
150 struct usb_device *udev = sd->gspca_dev.dev;
151 __u8 *buf = sd->gspca_dev.usb_buf;
152
153 /* No sensor with a data width larger than 16 bits has yet been seen */
154 if (len > sd->sensor->i2c_regW || !len)
155 return -EINVAL;
156
157 memcpy(buf, sensor_urb_skeleton,
158 sizeof(sensor_urb_skeleton));
159
160 buf[11] = sd->sensor->i2c_slave_id;
161 buf[15] = address;
162
163 /* Special case larger sensor writes */
164 p = buf + 16;
165
166 /* Copy a four byte write sequence for each byte to be written to */
167 for (i = 0; i < len; i++) {
168 memcpy(p, sensor_urb_skeleton + 16, 4);
169 p[3] = i2c_data[i];
170 p += 4;
171 PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x",
172 address, i2c_data[i]);
173 }
174
175 /* Copy the tailer */
176 memcpy(p, sensor_urb_skeleton + 20, 4);
177
178 /* Set the total length */
179 p[3] = 0x10 + len;
180
181 err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
182 0x04, 0x40, 0x19,
183 0x0000, buf,
184 20 + len * 4, M5602_URB_MSG_TIMEOUT);
185
186 return (err < 0) ? err : 0;
187}
188
189/* Dump all the registers of the m5602 bridge,
190 unfortunately this breaks the camera until it's power cycled */
191static void m5602_dump_bridge(struct sd *sd)
192{
193 int i;
194 for (i = 0; i < 0x80; i++) {
195 unsigned char val = 0;
196 m5602_read_bridge(sd, i, &val);
197 pr_info("ALi m5602 address 0x%x contains 0x%x\n", i, val);
198 }
199 pr_info("Warning: The ALi m5602 webcam probably won't work until it's power cycled\n");
200}
201
202static int m5602_probe_sensor(struct sd *sd)
203{
204 /* Try the po1030 */
205 sd->sensor = &po1030;
206 if (!sd->sensor->probe(sd))
207 return 0;
208
209 /* Try the mt9m111 sensor */
210 sd->sensor = &mt9m111;
211 if (!sd->sensor->probe(sd))
212 return 0;
213
214 /* Try the s5k4aa */
215 sd->sensor = &s5k4aa;
216 if (!sd->sensor->probe(sd))
217 return 0;
218
219 /* Try the ov9650 */
220 sd->sensor = &ov9650;
221 if (!sd->sensor->probe(sd))
222 return 0;
223
224 /* Try the ov7660 */
225 sd->sensor = &ov7660;
226 if (!sd->sensor->probe(sd))
227 return 0;
228
229 /* Try the s5k83a */
230 sd->sensor = &s5k83a;
231 if (!sd->sensor->probe(sd))
232 return 0;
233
234 /* More sensor probe function goes here */
235 pr_info("Failed to find a sensor\n");
236 sd->sensor = NULL;
237 return -ENODEV;
238}
239
240static int m5602_configure(struct gspca_dev *gspca_dev,
241 const struct usb_device_id *id);
242
243static int m5602_init(struct gspca_dev *gspca_dev)
244{
245 struct sd *sd = (struct sd *) gspca_dev;
246 int err;
247
248 PDEBUG(D_CONF, "Initializing ALi m5602 webcam");
249 /* Run the init sequence */
250 err = sd->sensor->init(sd);
251
252 return err;
253}
254
255static int m5602_start_transfer(struct gspca_dev *gspca_dev)
256{
257 struct sd *sd = (struct sd *) gspca_dev;
258 __u8 *buf = sd->gspca_dev.usb_buf;
259 int err;
260
261 /* Send start command to the camera */
262 const u8 buffer[4] = {0x13, 0xf9, 0x0f, 0x01};
263
264 if (sd->sensor->start)
265 sd->sensor->start(sd);
266
267 memcpy(buf, buffer, sizeof(buffer));
268 err = usb_control_msg(gspca_dev->dev,
269 usb_sndctrlpipe(gspca_dev->dev, 0),
270 0x04, 0x40, 0x19, 0x0000, buf,
271 sizeof(buffer), M5602_URB_MSG_TIMEOUT);
272
273 PDEBUG(D_STREAM, "Transfer started");
274 return (err < 0) ? err : 0;
275}
276
277static void m5602_urb_complete(struct gspca_dev *gspca_dev,
278 u8 *data, int len)
279{
280 struct sd *sd = (struct sd *) gspca_dev;
281
282 if (len < 6) {
283 PDEBUG(D_PACK, "Packet is less than 6 bytes");
284 return;
285 }
286
287 /* Frame delimiter: ff xx xx xx ff ff */
288 if (data[0] == 0xff && data[4] == 0xff && data[5] == 0xff &&
289 data[2] != sd->frame_id) {
290 PDEBUG(D_FRAM, "Frame delimiter detected");
291 sd->frame_id = data[2];
292
293 /* Remove the extra fluff appended on each header */
294 data += 6;
295 len -= 6;
296
297 /* Complete the last frame (if any) */
298 gspca_frame_add(gspca_dev, LAST_PACKET,
299 NULL, 0);
300 sd->frame_count++;
301
302 /* Create a new frame */
303 gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
304
305 PDEBUG(D_FRAM, "Starting new frame %d",
306 sd->frame_count);
307
308 } else {
309 int cur_frame_len;
310
311 cur_frame_len = gspca_dev->image_len;
312 /* Remove urb header */
313 data += 4;
314 len -= 4;
315
316 if (cur_frame_len + len <= gspca_dev->frsz) {
317 PDEBUG(D_FRAM, "Continuing frame %d copying %d bytes",
318 sd->frame_count, len);
319
320 gspca_frame_add(gspca_dev, INTER_PACKET,
321 data, len);
322 } else {
323 /* Add the remaining data up to frame size */
324 gspca_frame_add(gspca_dev, INTER_PACKET, data,
325 gspca_dev->frsz - cur_frame_len);
326 }
327 }
328}
329
330static void m5602_stop_transfer(struct gspca_dev *gspca_dev)
331{
332 struct sd *sd = (struct sd *) gspca_dev;
333
334 /* Run the sensor specific end transfer sequence */
335 if (sd->sensor->stop)
336 sd->sensor->stop(sd);
337}
338
339/* sub-driver description, the ctrl and nctrl is filled at probe time */
340static struct sd_desc sd_desc = {
341 .name = MODULE_NAME,
342 .config = m5602_configure,
343 .init = m5602_init,
344 .start = m5602_start_transfer,
345 .stopN = m5602_stop_transfer,
346 .pkt_scan = m5602_urb_complete
347};
348
349/* this function is called at probe time */
350static int m5602_configure(struct gspca_dev *gspca_dev,
351 const struct usb_device_id *id)
352{
353 struct sd *sd = (struct sd *) gspca_dev;
354 struct cam *cam;
355 int err;
356
357 cam = &gspca_dev->cam;
358 sd->desc = &sd_desc;
359
360 if (dump_bridge)
361 m5602_dump_bridge(sd);
362
363 /* Probe sensor */
364 err = m5602_probe_sensor(sd);
365 if (err)
366 goto fail;
367
368 return 0;
369
370fail:
371 PDEBUG(D_ERR, "ALi m5602 webcam failed");
372 cam->cam_mode = NULL;
373 cam->nmodes = 0;
374
375 return err;
376}
377
378static int m5602_probe(struct usb_interface *intf,
379 const struct usb_device_id *id)
380{
381 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
382 THIS_MODULE);
383}
384
385static void m5602_disconnect(struct usb_interface *intf)
386{
387 struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
388 struct sd *sd = (struct sd *) gspca_dev;
389
390 if (sd->sensor->disconnect)
391 sd->sensor->disconnect(sd);
392
393 gspca_disconnect(intf);
394}
395
396static struct usb_driver sd_driver = {
397 .name = MODULE_NAME,
398 .id_table = m5602_table,
399 .probe = m5602_probe,
400#ifdef CONFIG_PM
401 .suspend = gspca_suspend,
402 .resume = gspca_resume,
403 .reset_resume = gspca_resume,
404#endif
405 .disconnect = m5602_disconnect
406};
407
408module_usb_driver(sd_driver);
409
410MODULE_AUTHOR(DRIVER_AUTHOR);
411MODULE_DESCRIPTION(DRIVER_DESC);
412MODULE_LICENSE("GPL");
413module_param(force_sensor, int, S_IRUGO | S_IWUSR);
414MODULE_PARM_DESC(force_sensor,
415 "forces detection of a sensor, "
416 "1 = OV9650, 2 = S5K83A, 3 = S5K4AA, "
417 "4 = MT9M111, 5 = PO1030, 6 = OV7660");
418
419module_param(dump_bridge, bool, S_IRUGO | S_IWUSR);
420MODULE_PARM_DESC(dump_bridge, "Dumps all usb bridge registers at startup");
421
422module_param(dump_sensor, bool, S_IRUGO | S_IWUSR);
423MODULE_PARM_DESC(dump_sensor, "Dumps all usb sensor registers "
424 "at startup providing a sensor is found");
diff --git a/drivers/media/usb/gspca/m5602/m5602_mt9m111.c b/drivers/media/usb/gspca/m5602/m5602_mt9m111.c
new file mode 100644
index 000000000000..6268aa24ec5d
--- /dev/null
+++ b/drivers/media/usb/gspca/m5602/m5602_mt9m111.c
@@ -0,0 +1,647 @@
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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20
21#include "m5602_mt9m111.h"
22
23static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
24static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
25static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
26static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
27static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
28static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val);
29static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
30 __s32 val);
31static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev,
32 __s32 *val);
33static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val);
34static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val);
35static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
36static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
37static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
38static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
39
40static struct v4l2_pix_format mt9m111_modes[] = {
41 {
42 640,
43 480,
44 V4L2_PIX_FMT_SBGGR8,
45 V4L2_FIELD_NONE,
46 .sizeimage = 640 * 480,
47 .bytesperline = 640,
48 .colorspace = V4L2_COLORSPACE_SRGB,
49 .priv = 0
50 }
51};
52
53static const struct ctrl mt9m111_ctrls[] = {
54#define VFLIP_IDX 0
55 {
56 {
57 .id = V4L2_CID_VFLIP,
58 .type = V4L2_CTRL_TYPE_BOOLEAN,
59 .name = "vertical flip",
60 .minimum = 0,
61 .maximum = 1,
62 .step = 1,
63 .default_value = 0
64 },
65 .set = mt9m111_set_vflip,
66 .get = mt9m111_get_vflip
67 },
68#define HFLIP_IDX 1
69 {
70 {
71 .id = V4L2_CID_HFLIP,
72 .type = V4L2_CTRL_TYPE_BOOLEAN,
73 .name = "horizontal flip",
74 .minimum = 0,
75 .maximum = 1,
76 .step = 1,
77 .default_value = 0
78 },
79 .set = mt9m111_set_hflip,
80 .get = mt9m111_get_hflip
81 },
82#define GAIN_IDX 2
83 {
84 {
85 .id = V4L2_CID_GAIN,
86 .type = V4L2_CTRL_TYPE_INTEGER,
87 .name = "gain",
88 .minimum = 0,
89 .maximum = (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2,
90 .step = 1,
91 .default_value = MT9M111_DEFAULT_GAIN,
92 .flags = V4L2_CTRL_FLAG_SLIDER
93 },
94 .set = mt9m111_set_gain,
95 .get = mt9m111_get_gain
96 },
97#define AUTO_WHITE_BALANCE_IDX 3
98 {
99 {
100 .id = V4L2_CID_AUTO_WHITE_BALANCE,
101 .type = V4L2_CTRL_TYPE_BOOLEAN,
102 .name = "auto white balance",
103 .minimum = 0,
104 .maximum = 1,
105 .step = 1,
106 .default_value = 0,
107 },
108 .set = mt9m111_set_auto_white_balance,
109 .get = mt9m111_get_auto_white_balance
110 },
111#define GREEN_BALANCE_IDX 4
112 {
113 {
114 .id = M5602_V4L2_CID_GREEN_BALANCE,
115 .type = V4L2_CTRL_TYPE_INTEGER,
116 .name = "green balance",
117 .minimum = 0x00,
118 .maximum = 0x7ff,
119 .step = 0x1,
120 .default_value = MT9M111_GREEN_GAIN_DEFAULT,
121 .flags = V4L2_CTRL_FLAG_SLIDER
122 },
123 .set = mt9m111_set_green_balance,
124 .get = mt9m111_get_green_balance
125 },
126#define BLUE_BALANCE_IDX 5
127 {
128 {
129 .id = V4L2_CID_BLUE_BALANCE,
130 .type = V4L2_CTRL_TYPE_INTEGER,
131 .name = "blue balance",
132 .minimum = 0x00,
133 .maximum = 0x7ff,
134 .step = 0x1,
135 .default_value = MT9M111_BLUE_GAIN_DEFAULT,
136 .flags = V4L2_CTRL_FLAG_SLIDER
137 },
138 .set = mt9m111_set_blue_balance,
139 .get = mt9m111_get_blue_balance
140 },
141#define RED_BALANCE_IDX 5
142 {
143 {
144 .id = V4L2_CID_RED_BALANCE,
145 .type = V4L2_CTRL_TYPE_INTEGER,
146 .name = "red balance",
147 .minimum = 0x00,
148 .maximum = 0x7ff,
149 .step = 0x1,
150 .default_value = MT9M111_RED_GAIN_DEFAULT,
151 .flags = V4L2_CTRL_FLAG_SLIDER
152 },
153 .set = mt9m111_set_red_balance,
154 .get = mt9m111_get_red_balance
155 },
156};
157
158static void mt9m111_dump_registers(struct sd *sd);
159
160int mt9m111_probe(struct sd *sd)
161{
162 u8 data[2] = {0x00, 0x00};
163 int i;
164 s32 *sensor_settings;
165
166 if (force_sensor) {
167 if (force_sensor == MT9M111_SENSOR) {
168 pr_info("Forcing a %s sensor\n", mt9m111.name);
169 goto sensor_found;
170 }
171 /* If we want to force another sensor, don't try to probe this
172 * one */
173 return -ENODEV;
174 }
175
176 PDEBUG(D_PROBE, "Probing for a mt9m111 sensor");
177
178 /* Do the preinit */
179 for (i = 0; i < ARRAY_SIZE(preinit_mt9m111); i++) {
180 if (preinit_mt9m111[i][0] == BRIDGE) {
181 m5602_write_bridge(sd,
182 preinit_mt9m111[i][1],
183 preinit_mt9m111[i][2]);
184 } else {
185 data[0] = preinit_mt9m111[i][2];
186 data[1] = preinit_mt9m111[i][3];
187 m5602_write_sensor(sd,
188 preinit_mt9m111[i][1], data, 2);
189 }
190 }
191
192 if (m5602_read_sensor(sd, MT9M111_SC_CHIPVER, data, 2))
193 return -ENODEV;
194
195 if ((data[0] == 0x14) && (data[1] == 0x3a)) {
196 pr_info("Detected a mt9m111 sensor\n");
197 goto sensor_found;
198 }
199
200 return -ENODEV;
201
202sensor_found:
203 sensor_settings = kmalloc(ARRAY_SIZE(mt9m111_ctrls) * sizeof(s32),
204 GFP_KERNEL);
205 if (!sensor_settings)
206 return -ENOMEM;
207
208 sd->gspca_dev.cam.cam_mode = mt9m111_modes;
209 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(mt9m111_modes);
210 sd->desc->ctrls = mt9m111_ctrls;
211 sd->desc->nctrls = ARRAY_SIZE(mt9m111_ctrls);
212
213 for (i = 0; i < ARRAY_SIZE(mt9m111_ctrls); i++)
214 sensor_settings[i] = mt9m111_ctrls[i].qctrl.default_value;
215 sd->sensor_priv = sensor_settings;
216
217 return 0;
218}
219
220int mt9m111_init(struct sd *sd)
221{
222 int i, err = 0;
223 s32 *sensor_settings = sd->sensor_priv;
224
225 /* Init the sensor */
226 for (i = 0; i < ARRAY_SIZE(init_mt9m111) && !err; i++) {
227 u8 data[2];
228
229 if (init_mt9m111[i][0] == BRIDGE) {
230 err = m5602_write_bridge(sd,
231 init_mt9m111[i][1],
232 init_mt9m111[i][2]);
233 } else {
234 data[0] = init_mt9m111[i][2];
235 data[1] = init_mt9m111[i][3];
236 err = m5602_write_sensor(sd,
237 init_mt9m111[i][1], data, 2);
238 }
239 }
240
241 if (dump_sensor)
242 mt9m111_dump_registers(sd);
243
244 err = mt9m111_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
245 if (err < 0)
246 return err;
247
248 err = mt9m111_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
249 if (err < 0)
250 return err;
251
252 err = mt9m111_set_green_balance(&sd->gspca_dev,
253 sensor_settings[GREEN_BALANCE_IDX]);
254 if (err < 0)
255 return err;
256
257 err = mt9m111_set_blue_balance(&sd->gspca_dev,
258 sensor_settings[BLUE_BALANCE_IDX]);
259 if (err < 0)
260 return err;
261
262 err = mt9m111_set_red_balance(&sd->gspca_dev,
263 sensor_settings[RED_BALANCE_IDX]);
264 if (err < 0)
265 return err;
266
267 return mt9m111_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
268}
269
270int mt9m111_start(struct sd *sd)
271{
272 int i, err = 0;
273 u8 data[2];
274 struct cam *cam = &sd->gspca_dev.cam;
275 s32 *sensor_settings = sd->sensor_priv;
276
277 int width = cam->cam_mode[sd->gspca_dev.curr_mode].width - 1;
278 int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
279
280 for (i = 0; i < ARRAY_SIZE(start_mt9m111) && !err; i++) {
281 if (start_mt9m111[i][0] == BRIDGE) {
282 err = m5602_write_bridge(sd,
283 start_mt9m111[i][1],
284 start_mt9m111[i][2]);
285 } else {
286 data[0] = start_mt9m111[i][2];
287 data[1] = start_mt9m111[i][3];
288 err = m5602_write_sensor(sd,
289 start_mt9m111[i][1], data, 2);
290 }
291 }
292 if (err < 0)
293 return err;
294
295 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff);
296 if (err < 0)
297 return err;
298
299 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff));
300 if (err < 0)
301 return err;
302
303 for (i = 0; i < 2 && !err; i++)
304 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
305 if (err < 0)
306 return err;
307
308 err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
309 if (err < 0)
310 return err;
311
312 err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 2);
313 if (err < 0)
314 return err;
315
316 for (i = 0; i < 2 && !err; i++)
317 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 0);
318 if (err < 0)
319 return err;
320
321 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
322 (width >> 8) & 0xff);
323 if (err < 0)
324 return err;
325
326 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, width & 0xff);
327 if (err < 0)
328 return err;
329
330 err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
331 if (err < 0)
332 return err;
333
334 switch (width) {
335 case 640:
336 PDEBUG(D_V4L2, "Configuring camera for VGA mode");
337 data[0] = MT9M111_RMB_OVER_SIZED;
338 data[1] = MT9M111_RMB_ROW_SKIP_2X |
339 MT9M111_RMB_COLUMN_SKIP_2X |
340 (sensor_settings[VFLIP_IDX] << 0) |
341 (sensor_settings[HFLIP_IDX] << 1);
342
343 err = m5602_write_sensor(sd,
344 MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
345 break;
346
347 case 320:
348 PDEBUG(D_V4L2, "Configuring camera for QVGA mode");
349 data[0] = MT9M111_RMB_OVER_SIZED;
350 data[1] = MT9M111_RMB_ROW_SKIP_4X |
351 MT9M111_RMB_COLUMN_SKIP_4X |
352 (sensor_settings[VFLIP_IDX] << 0) |
353 (sensor_settings[HFLIP_IDX] << 1);
354 err = m5602_write_sensor(sd,
355 MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
356 break;
357 }
358 return err;
359}
360
361void mt9m111_disconnect(struct sd *sd)
362{
363 sd->sensor = NULL;
364 kfree(sd->sensor_priv);
365}
366
367static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
368{
369 struct sd *sd = (struct sd *) gspca_dev;
370 s32 *sensor_settings = sd->sensor_priv;
371
372 *val = sensor_settings[VFLIP_IDX];
373 PDEBUG(D_V4L2, "Read vertical flip %d", *val);
374
375 return 0;
376}
377
378static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
379{
380 int err;
381 u8 data[2] = {0x00, 0x00};
382 struct sd *sd = (struct sd *) gspca_dev;
383 s32 *sensor_settings = sd->sensor_priv;
384
385 PDEBUG(D_V4L2, "Set vertical flip to %d", val);
386
387 sensor_settings[VFLIP_IDX] = val;
388
389 /* The mt9m111 is flipped by default */
390 val = !val;
391
392 /* Set the correct page map */
393 err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
394 if (err < 0)
395 return err;
396
397 err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
398 if (err < 0)
399 return err;
400
401 data[1] = (data[1] & 0xfe) | val;
402 err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
403 data, 2);
404 return err;
405}
406
407static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
408{
409 struct sd *sd = (struct sd *) gspca_dev;
410 s32 *sensor_settings = sd->sensor_priv;
411
412 *val = sensor_settings[HFLIP_IDX];
413 PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
414
415 return 0;
416}
417
418static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
419{
420 int err;
421 u8 data[2] = {0x00, 0x00};
422 struct sd *sd = (struct sd *) gspca_dev;
423 s32 *sensor_settings = sd->sensor_priv;
424
425 PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
426
427 sensor_settings[HFLIP_IDX] = val;
428
429 /* The mt9m111 is flipped by default */
430 val = !val;
431
432 /* Set the correct page map */
433 err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
434 if (err < 0)
435 return err;
436
437 err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
438 if (err < 0)
439 return err;
440
441 data[1] = (data[1] & 0xfd) | ((val << 1) & 0x02);
442 err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
443 data, 2);
444 return err;
445}
446
447static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
448{
449 struct sd *sd = (struct sd *) gspca_dev;
450 s32 *sensor_settings = sd->sensor_priv;
451
452 *val = sensor_settings[GAIN_IDX];
453 PDEBUG(D_V4L2, "Read gain %d", *val);
454
455 return 0;
456}
457
458static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
459 __s32 val)
460{
461 struct sd *sd = (struct sd *) gspca_dev;
462 s32 *sensor_settings = sd->sensor_priv;
463 int err;
464 u8 data[2];
465
466 err = m5602_read_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2);
467 if (err < 0)
468 return err;
469
470 sensor_settings[AUTO_WHITE_BALANCE_IDX] = val & 0x01;
471 data[1] = ((data[1] & 0xfd) | ((val & 0x01) << 1));
472
473 err = m5602_write_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2);
474
475 PDEBUG(D_V4L2, "Set auto white balance %d", val);
476 return err;
477}
478
479static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev,
480 __s32 *val) {
481 struct sd *sd = (struct sd *) gspca_dev;
482 s32 *sensor_settings = sd->sensor_priv;
483
484 *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
485 PDEBUG(D_V4L2, "Read auto white balance %d", *val);
486 return 0;
487}
488
489static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
490{
491 int err, tmp;
492 u8 data[2] = {0x00, 0x00};
493 struct sd *sd = (struct sd *) gspca_dev;
494 s32 *sensor_settings = sd->sensor_priv;
495
496 sensor_settings[GAIN_IDX] = val;
497
498 /* Set the correct page map */
499 err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
500 if (err < 0)
501 return err;
502
503 if (val >= INITIAL_MAX_GAIN * 2 * 2 * 2)
504 return -EINVAL;
505
506 if ((val >= INITIAL_MAX_GAIN * 2 * 2) &&
507 (val < (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2))
508 tmp = (1 << 10) | (val << 9) |
509 (val << 8) | (val / 8);
510 else if ((val >= INITIAL_MAX_GAIN * 2) &&
511 (val < INITIAL_MAX_GAIN * 2 * 2))
512 tmp = (1 << 9) | (1 << 8) | (val / 4);
513 else if ((val >= INITIAL_MAX_GAIN) &&
514 (val < INITIAL_MAX_GAIN * 2))
515 tmp = (1 << 8) | (val / 2);
516 else
517 tmp = val;
518
519 data[1] = (tmp & 0xff);
520 data[0] = (tmp & 0xff00) >> 8;
521 PDEBUG(D_V4L2, "tmp=%d, data[1]=%d, data[0]=%d", tmp,
522 data[1], data[0]);
523
524 err = m5602_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN,
525 data, 2);
526
527 return err;
528}
529
530static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
531{
532 int err;
533 u8 data[2];
534 struct sd *sd = (struct sd *) gspca_dev;
535 s32 *sensor_settings = sd->sensor_priv;
536
537 sensor_settings[GREEN_BALANCE_IDX] = val;
538 data[1] = (val & 0xff);
539 data[0] = (val & 0xff00) >> 8;
540
541 PDEBUG(D_V4L2, "Set green balance %d", val);
542 err = m5602_write_sensor(sd, MT9M111_SC_GREEN_1_GAIN,
543 data, 2);
544 if (err < 0)
545 return err;
546
547 return m5602_write_sensor(sd, MT9M111_SC_GREEN_2_GAIN,
548 data, 2);
549}
550
551static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val)
552{
553 struct sd *sd = (struct sd *) gspca_dev;
554 s32 *sensor_settings = sd->sensor_priv;
555
556 *val = sensor_settings[GREEN_BALANCE_IDX];
557 PDEBUG(D_V4L2, "Read green balance %d", *val);
558 return 0;
559}
560
561static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
562{
563 u8 data[2];
564 struct sd *sd = (struct sd *) gspca_dev;
565 s32 *sensor_settings = sd->sensor_priv;
566
567 sensor_settings[BLUE_BALANCE_IDX] = val;
568 data[1] = (val & 0xff);
569 data[0] = (val & 0xff00) >> 8;
570
571 PDEBUG(D_V4L2, "Set blue balance %d", val);
572
573 return m5602_write_sensor(sd, MT9M111_SC_BLUE_GAIN,
574 data, 2);
575}
576
577static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
578{
579 struct sd *sd = (struct sd *) gspca_dev;
580 s32 *sensor_settings = sd->sensor_priv;
581
582 *val = sensor_settings[BLUE_BALANCE_IDX];
583 PDEBUG(D_V4L2, "Read blue balance %d", *val);
584 return 0;
585}
586
587static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
588{
589 u8 data[2];
590 struct sd *sd = (struct sd *) gspca_dev;
591 s32 *sensor_settings = sd->sensor_priv;
592
593 sensor_settings[RED_BALANCE_IDX] = val;
594 data[1] = (val & 0xff);
595 data[0] = (val & 0xff00) >> 8;
596
597 PDEBUG(D_V4L2, "Set red balance %d", val);
598
599 return m5602_write_sensor(sd, MT9M111_SC_RED_GAIN,
600 data, 2);
601}
602
603static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
604{
605 struct sd *sd = (struct sd *) gspca_dev;
606 s32 *sensor_settings = sd->sensor_priv;
607
608 *val = sensor_settings[RED_BALANCE_IDX];
609 PDEBUG(D_V4L2, "Read red balance %d", *val);
610 return 0;
611}
612
613static void mt9m111_dump_registers(struct sd *sd)
614{
615 u8 address, value[2] = {0x00, 0x00};
616
617 pr_info("Dumping the mt9m111 register state\n");
618
619 pr_info("Dumping the mt9m111 sensor core registers\n");
620 value[1] = MT9M111_SENSOR_CORE;
621 m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
622 for (address = 0; address < 0xff; address++) {
623 m5602_read_sensor(sd, address, value, 2);
624 pr_info("register 0x%x contains 0x%x%x\n",
625 address, value[0], value[1]);
626 }
627
628 pr_info("Dumping the mt9m111 color pipeline registers\n");
629 value[1] = MT9M111_COLORPIPE;
630 m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
631 for (address = 0; address < 0xff; address++) {
632 m5602_read_sensor(sd, address, value, 2);
633 pr_info("register 0x%x contains 0x%x%x\n",
634 address, value[0], value[1]);
635 }
636
637 pr_info("Dumping the mt9m111 camera control registers\n");
638 value[1] = MT9M111_CAMERA_CONTROL;
639 m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
640 for (address = 0; address < 0xff; address++) {
641 m5602_read_sensor(sd, address, value, 2);
642 pr_info("register 0x%x contains 0x%x%x\n",
643 address, value[0], value[1]);
644 }
645
646 pr_info("mt9m111 register state dump complete\n");
647}
diff --git a/drivers/media/usb/gspca/m5602/m5602_mt9m111.h b/drivers/media/usb/gspca/m5602/m5602_mt9m111.h
new file mode 100644
index 000000000000..8c672b5c8c6a
--- /dev/null
+++ b/drivers/media/usb/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 bool 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/usb/gspca/m5602/m5602_ov7660.c b/drivers/media/usb/gspca/m5602/m5602_ov7660.c
new file mode 100644
index 000000000000..9a14835c128f
--- /dev/null
+++ b/drivers/media/usb/gspca/m5602/m5602_ov7660.c
@@ -0,0 +1,488 @@
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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20
21#include "m5602_ov7660.h"
22
23static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
24static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val);
25static int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev,
26 __s32 *val);
27static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
28 __s32 val);
29static int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
30static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
31static int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val);
32static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val);
33static int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
34static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
35static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
36static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
37
38static const struct ctrl ov7660_ctrls[] = {
39#define GAIN_IDX 1
40 {
41 {
42 .id = V4L2_CID_GAIN,
43 .type = V4L2_CTRL_TYPE_INTEGER,
44 .name = "gain",
45 .minimum = 0x00,
46 .maximum = 0xff,
47 .step = 0x1,
48 .default_value = OV7660_DEFAULT_GAIN,
49 .flags = V4L2_CTRL_FLAG_SLIDER
50 },
51 .set = ov7660_set_gain,
52 .get = ov7660_get_gain
53 },
54#define BLUE_BALANCE_IDX 2
55#define RED_BALANCE_IDX 3
56#define AUTO_WHITE_BALANCE_IDX 4
57 {
58 {
59 .id = V4L2_CID_AUTO_WHITE_BALANCE,
60 .type = V4L2_CTRL_TYPE_BOOLEAN,
61 .name = "auto white balance",
62 .minimum = 0,
63 .maximum = 1,
64 .step = 1,
65 .default_value = 1
66 },
67 .set = ov7660_set_auto_white_balance,
68 .get = ov7660_get_auto_white_balance
69 },
70#define AUTO_GAIN_CTRL_IDX 5
71 {
72 {
73 .id = V4L2_CID_AUTOGAIN,
74 .type = V4L2_CTRL_TYPE_BOOLEAN,
75 .name = "auto gain control",
76 .minimum = 0,
77 .maximum = 1,
78 .step = 1,
79 .default_value = 1
80 },
81 .set = ov7660_set_auto_gain,
82 .get = ov7660_get_auto_gain
83 },
84#define AUTO_EXPOSURE_IDX 6
85 {
86 {
87 .id = V4L2_CID_EXPOSURE_AUTO,
88 .type = V4L2_CTRL_TYPE_BOOLEAN,
89 .name = "auto exposure",
90 .minimum = 0,
91 .maximum = 1,
92 .step = 1,
93 .default_value = 1
94 },
95 .set = ov7660_set_auto_exposure,
96 .get = ov7660_get_auto_exposure
97 },
98#define HFLIP_IDX 7
99 {
100 {
101 .id = V4L2_CID_HFLIP,
102 .type = V4L2_CTRL_TYPE_BOOLEAN,
103 .name = "horizontal flip",
104 .minimum = 0,
105 .maximum = 1,
106 .step = 1,
107 .default_value = 0
108 },
109 .set = ov7660_set_hflip,
110 .get = ov7660_get_hflip
111 },
112#define VFLIP_IDX 8
113 {
114 {
115 .id = V4L2_CID_VFLIP,
116 .type = V4L2_CTRL_TYPE_BOOLEAN,
117 .name = "vertical flip",
118 .minimum = 0,
119 .maximum = 1,
120 .step = 1,
121 .default_value = 0
122 },
123 .set = ov7660_set_vflip,
124 .get = ov7660_get_vflip
125 },
126
127};
128
129static struct v4l2_pix_format ov7660_modes[] = {
130 {
131 640,
132 480,
133 V4L2_PIX_FMT_SBGGR8,
134 V4L2_FIELD_NONE,
135 .sizeimage =
136 640 * 480,
137 .bytesperline = 640,
138 .colorspace = V4L2_COLORSPACE_SRGB,
139 .priv = 0
140 }
141};
142
143static void ov7660_dump_registers(struct sd *sd);
144
145int ov7660_probe(struct sd *sd)
146{
147 int err = 0, i;
148 u8 prod_id = 0, ver_id = 0;
149
150 s32 *sensor_settings;
151
152 if (force_sensor) {
153 if (force_sensor == OV7660_SENSOR) {
154 pr_info("Forcing an %s sensor\n", ov7660.name);
155 goto sensor_found;
156 }
157 /* If we want to force another sensor,
158 don't try to probe this one */
159 return -ENODEV;
160 }
161
162 /* Do the preinit */
163 for (i = 0; i < ARRAY_SIZE(preinit_ov7660) && !err; i++) {
164 u8 data[2];
165
166 if (preinit_ov7660[i][0] == BRIDGE) {
167 err = m5602_write_bridge(sd,
168 preinit_ov7660[i][1],
169 preinit_ov7660[i][2]);
170 } else {
171 data[0] = preinit_ov7660[i][2];
172 err = m5602_write_sensor(sd,
173 preinit_ov7660[i][1], data, 1);
174 }
175 }
176 if (err < 0)
177 return err;
178
179 if (m5602_read_sensor(sd, OV7660_PID, &prod_id, 1))
180 return -ENODEV;
181
182 if (m5602_read_sensor(sd, OV7660_VER, &ver_id, 1))
183 return -ENODEV;
184
185 pr_info("Sensor reported 0x%x%x\n", prod_id, ver_id);
186
187 if ((prod_id == 0x76) && (ver_id == 0x60)) {
188 pr_info("Detected a ov7660 sensor\n");
189 goto sensor_found;
190 }
191 return -ENODEV;
192
193sensor_found:
194 sensor_settings = kmalloc(
195 ARRAY_SIZE(ov7660_ctrls) * sizeof(s32), GFP_KERNEL);
196 if (!sensor_settings)
197 return -ENOMEM;
198
199 sd->gspca_dev.cam.cam_mode = ov7660_modes;
200 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov7660_modes);
201 sd->desc->ctrls = ov7660_ctrls;
202 sd->desc->nctrls = ARRAY_SIZE(ov7660_ctrls);
203
204 for (i = 0; i < ARRAY_SIZE(ov7660_ctrls); i++)
205 sensor_settings[i] = ov7660_ctrls[i].qctrl.default_value;
206 sd->sensor_priv = sensor_settings;
207
208 return 0;
209}
210
211int ov7660_init(struct sd *sd)
212{
213 int i, err = 0;
214 s32 *sensor_settings = sd->sensor_priv;
215
216 /* Init the sensor */
217 for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) {
218 u8 data[2];
219
220 if (init_ov7660[i][0] == BRIDGE) {
221 err = m5602_write_bridge(sd,
222 init_ov7660[i][1],
223 init_ov7660[i][2]);
224 } else {
225 data[0] = init_ov7660[i][2];
226 err = m5602_write_sensor(sd,
227 init_ov7660[i][1], data, 1);
228 }
229 }
230
231 if (dump_sensor)
232 ov7660_dump_registers(sd);
233
234 err = ov7660_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
235 if (err < 0)
236 return err;
237
238 err = ov7660_set_auto_white_balance(&sd->gspca_dev,
239 sensor_settings[AUTO_WHITE_BALANCE_IDX]);
240 if (err < 0)
241 return err;
242
243 err = ov7660_set_auto_gain(&sd->gspca_dev,
244 sensor_settings[AUTO_GAIN_CTRL_IDX]);
245 if (err < 0)
246 return err;
247
248 err = ov7660_set_auto_exposure(&sd->gspca_dev,
249 sensor_settings[AUTO_EXPOSURE_IDX]);
250 if (err < 0)
251 return err;
252 err = ov7660_set_hflip(&sd->gspca_dev,
253 sensor_settings[HFLIP_IDX]);
254 if (err < 0)
255 return err;
256
257 err = ov7660_set_vflip(&sd->gspca_dev,
258 sensor_settings[VFLIP_IDX]);
259
260 return err;
261}
262
263int ov7660_start(struct sd *sd)
264{
265 return 0;
266}
267
268int ov7660_stop(struct sd *sd)
269{
270 return 0;
271}
272
273void ov7660_disconnect(struct sd *sd)
274{
275 ov7660_stop(sd);
276
277 sd->sensor = NULL;
278 kfree(sd->sensor_priv);
279}
280
281static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
282{
283 struct sd *sd = (struct sd *) gspca_dev;
284 s32 *sensor_settings = sd->sensor_priv;
285
286 *val = sensor_settings[GAIN_IDX];
287 PDEBUG(D_V4L2, "Read gain %d", *val);
288 return 0;
289}
290
291static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val)
292{
293 int err;
294 u8 i2c_data;
295 struct sd *sd = (struct sd *) gspca_dev;
296 s32 *sensor_settings = sd->sensor_priv;
297
298 PDEBUG(D_V4L2, "Setting gain to %d", val);
299
300 sensor_settings[GAIN_IDX] = val;
301
302 err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1);
303 return err;
304}
305
306
307static int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev,
308 __s32 *val)
309{
310 struct sd *sd = (struct sd *) gspca_dev;
311 s32 *sensor_settings = sd->sensor_priv;
312
313 *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
314 return 0;
315}
316
317static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
318 __s32 val)
319{
320 int err;
321 u8 i2c_data;
322 struct sd *sd = (struct sd *) gspca_dev;
323 s32 *sensor_settings = sd->sensor_priv;
324
325 PDEBUG(D_V4L2, "Set auto white balance to %d", val);
326
327 sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
328 err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
329 if (err < 0)
330 return err;
331
332 i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1));
333 err = m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
334
335 return err;
336}
337
338static int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
339{
340 struct sd *sd = (struct sd *) gspca_dev;
341 s32 *sensor_settings = sd->sensor_priv;
342
343 *val = sensor_settings[AUTO_GAIN_CTRL_IDX];
344 PDEBUG(D_V4L2, "Read auto gain control %d", *val);
345 return 0;
346}
347
348static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
349{
350 int err;
351 u8 i2c_data;
352 struct sd *sd = (struct sd *) gspca_dev;
353 s32 *sensor_settings = sd->sensor_priv;
354
355 PDEBUG(D_V4L2, "Set auto gain control to %d", val);
356
357 sensor_settings[AUTO_GAIN_CTRL_IDX] = val;
358 err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
359 if (err < 0)
360 return err;
361
362 i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2));
363
364 return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
365}
366
367static int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val)
368{
369 struct sd *sd = (struct sd *) gspca_dev;
370 s32 *sensor_settings = sd->sensor_priv;
371
372 *val = sensor_settings[AUTO_EXPOSURE_IDX];
373 PDEBUG(D_V4L2, "Read auto exposure control %d", *val);
374 return 0;
375}
376
377static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev,
378 __s32 val)
379{
380 int err;
381 u8 i2c_data;
382 struct sd *sd = (struct sd *) gspca_dev;
383 s32 *sensor_settings = sd->sensor_priv;
384
385 PDEBUG(D_V4L2, "Set auto exposure control to %d", val);
386
387 sensor_settings[AUTO_EXPOSURE_IDX] = val;
388 err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
389 if (err < 0)
390 return err;
391
392 i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0));
393
394 return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
395}
396
397static int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
398{
399 struct sd *sd = (struct sd *) gspca_dev;
400 s32 *sensor_settings = sd->sensor_priv;
401
402 *val = sensor_settings[HFLIP_IDX];
403 PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
404 return 0;
405}
406
407static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
408{
409 int err;
410 u8 i2c_data;
411 struct sd *sd = (struct sd *) gspca_dev;
412 s32 *sensor_settings = sd->sensor_priv;
413
414 PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
415
416 sensor_settings[HFLIP_IDX] = val;
417
418 i2c_data = ((val & 0x01) << 5) |
419 (sensor_settings[VFLIP_IDX] << 4);
420
421 err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1);
422
423 return err;
424}
425
426static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
427{
428 struct sd *sd = (struct sd *) gspca_dev;
429 s32 *sensor_settings = sd->sensor_priv;
430
431 *val = sensor_settings[VFLIP_IDX];
432 PDEBUG(D_V4L2, "Read vertical flip %d", *val);
433
434 return 0;
435}
436
437static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
438{
439 int err;
440 u8 i2c_data;
441 struct sd *sd = (struct sd *) gspca_dev;
442 s32 *sensor_settings = sd->sensor_priv;
443
444 PDEBUG(D_V4L2, "Set vertical flip to %d", val);
445 sensor_settings[VFLIP_IDX] = val;
446
447 i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5);
448 err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1);
449 if (err < 0)
450 return err;
451
452 /* When vflip is toggled we need to readjust the bridge hsync/vsync */
453 if (gspca_dev->streaming)
454 err = ov7660_start(sd);
455
456 return err;
457}
458
459static void ov7660_dump_registers(struct sd *sd)
460{
461 int address;
462 pr_info("Dumping the ov7660 register state\n");
463 for (address = 0; address < 0xa9; address++) {
464 u8 value;
465 m5602_read_sensor(sd, address, &value, 1);
466 pr_info("register 0x%x contains 0x%x\n", address, value);
467 }
468
469 pr_info("ov7660 register state dump complete\n");
470
471 pr_info("Probing for which registers that are read/write\n");
472 for (address = 0; address < 0xff; address++) {
473 u8 old_value, ctrl_value;
474 u8 test_value[2] = {0xff, 0xff};
475
476 m5602_read_sensor(sd, address, &old_value, 1);
477 m5602_write_sensor(sd, address, test_value, 1);
478 m5602_read_sensor(sd, address, &ctrl_value, 1);
479
480 if (ctrl_value == test_value[0])
481 pr_info("register 0x%x is writeable\n", address);
482 else
483 pr_info("register 0x%x is read only\n", address);
484
485 /* Restore original value */
486 m5602_write_sensor(sd, address, &old_value, 1);
487 }
488}
diff --git a/drivers/media/usb/gspca/m5602/m5602_ov7660.h b/drivers/media/usb/gspca/m5602/m5602_ov7660.h
new file mode 100644
index 000000000000..2b6a13b508f7
--- /dev/null
+++ b/drivers/media/usb/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 bool 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/usb/gspca/m5602/m5602_ov9650.c b/drivers/media/usb/gspca/m5602/m5602_ov9650.c
new file mode 100644
index 000000000000..2114a8b90ec9
--- /dev/null
+++ b/drivers/media/usb/gspca/m5602/m5602_ov9650.c
@@ -0,0 +1,881 @@
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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20
21#include "m5602_ov9650.h"
22
23static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
24static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
25static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
26static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val);
27static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
28static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
29static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
30static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
31static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
32static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
33static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
34static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
35static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev,
36 __s32 *val);
37static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
38 __s32 val);
39static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
40static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
41static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val);
42static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val);
43
44/* Vertically and horizontally flips the image if matched, needed for machines
45 where the sensor is mounted upside down */
46static
47 const
48 struct dmi_system_id ov9650_flip_dmi_table[] = {
49 {
50 .ident = "ASUS A6Ja",
51 .matches = {
52 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
53 DMI_MATCH(DMI_PRODUCT_NAME, "A6J")
54 }
55 },
56 {
57 .ident = "ASUS A6JC",
58 .matches = {
59 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
60 DMI_MATCH(DMI_PRODUCT_NAME, "A6JC")
61 }
62 },
63 {
64 .ident = "ASUS A6K",
65 .matches = {
66 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
67 DMI_MATCH(DMI_PRODUCT_NAME, "A6K")
68 }
69 },
70 {
71 .ident = "ASUS A6Kt",
72 .matches = {
73 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
74 DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt")
75 }
76 },
77 {
78 .ident = "ASUS A6VA",
79 .matches = {
80 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
81 DMI_MATCH(DMI_PRODUCT_NAME, "A6VA")
82 }
83 },
84 {
85
86 .ident = "ASUS A6VC",
87 .matches = {
88 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
89 DMI_MATCH(DMI_PRODUCT_NAME, "A6VC")
90 }
91 },
92 {
93 .ident = "ASUS A6VM",
94 .matches = {
95 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
96 DMI_MATCH(DMI_PRODUCT_NAME, "A6VM")
97 }
98 },
99 {
100 .ident = "ASUS A7V",
101 .matches = {
102 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
103 DMI_MATCH(DMI_PRODUCT_NAME, "A7V")
104 }
105 },
106 {
107 .ident = "Alienware Aurora m9700",
108 .matches = {
109 DMI_MATCH(DMI_SYS_VENDOR, "alienware"),
110 DMI_MATCH(DMI_PRODUCT_NAME, "Aurora m9700")
111 }
112 },
113 {}
114};
115
116static const struct ctrl ov9650_ctrls[] = {
117#define EXPOSURE_IDX 0
118 {
119 {
120 .id = V4L2_CID_EXPOSURE,
121 .type = V4L2_CTRL_TYPE_INTEGER,
122 .name = "exposure",
123 .minimum = 0x00,
124 .maximum = 0x1ff,
125 .step = 0x4,
126 .default_value = EXPOSURE_DEFAULT,
127 .flags = V4L2_CTRL_FLAG_SLIDER
128 },
129 .set = ov9650_set_exposure,
130 .get = ov9650_get_exposure
131 },
132#define GAIN_IDX 1
133 {
134 {
135 .id = V4L2_CID_GAIN,
136 .type = V4L2_CTRL_TYPE_INTEGER,
137 .name = "gain",
138 .minimum = 0x00,
139 .maximum = 0x3ff,
140 .step = 0x1,
141 .default_value = GAIN_DEFAULT,
142 .flags = V4L2_CTRL_FLAG_SLIDER
143 },
144 .set = ov9650_set_gain,
145 .get = ov9650_get_gain
146 },
147#define RED_BALANCE_IDX 2
148 {
149 {
150 .id = V4L2_CID_RED_BALANCE,
151 .type = V4L2_CTRL_TYPE_INTEGER,
152 .name = "red balance",
153 .minimum = 0x00,
154 .maximum = 0xff,
155 .step = 0x1,
156 .default_value = RED_GAIN_DEFAULT,
157 .flags = V4L2_CTRL_FLAG_SLIDER
158 },
159 .set = ov9650_set_red_balance,
160 .get = ov9650_get_red_balance
161 },
162#define BLUE_BALANCE_IDX 3
163 {
164 {
165 .id = V4L2_CID_BLUE_BALANCE,
166 .type = V4L2_CTRL_TYPE_INTEGER,
167 .name = "blue balance",
168 .minimum = 0x00,
169 .maximum = 0xff,
170 .step = 0x1,
171 .default_value = BLUE_GAIN_DEFAULT,
172 .flags = V4L2_CTRL_FLAG_SLIDER
173 },
174 .set = ov9650_set_blue_balance,
175 .get = ov9650_get_blue_balance
176 },
177#define HFLIP_IDX 4
178 {
179 {
180 .id = V4L2_CID_HFLIP,
181 .type = V4L2_CTRL_TYPE_BOOLEAN,
182 .name = "horizontal flip",
183 .minimum = 0,
184 .maximum = 1,
185 .step = 1,
186 .default_value = 0
187 },
188 .set = ov9650_set_hflip,
189 .get = ov9650_get_hflip
190 },
191#define VFLIP_IDX 5
192 {
193 {
194 .id = V4L2_CID_VFLIP,
195 .type = V4L2_CTRL_TYPE_BOOLEAN,
196 .name = "vertical flip",
197 .minimum = 0,
198 .maximum = 1,
199 .step = 1,
200 .default_value = 0
201 },
202 .set = ov9650_set_vflip,
203 .get = ov9650_get_vflip
204 },
205#define AUTO_WHITE_BALANCE_IDX 6
206 {
207 {
208 .id = V4L2_CID_AUTO_WHITE_BALANCE,
209 .type = V4L2_CTRL_TYPE_BOOLEAN,
210 .name = "auto white balance",
211 .minimum = 0,
212 .maximum = 1,
213 .step = 1,
214 .default_value = 1
215 },
216 .set = ov9650_set_auto_white_balance,
217 .get = ov9650_get_auto_white_balance
218 },
219#define AUTO_GAIN_CTRL_IDX 7
220 {
221 {
222 .id = V4L2_CID_AUTOGAIN,
223 .type = V4L2_CTRL_TYPE_BOOLEAN,
224 .name = "auto gain control",
225 .minimum = 0,
226 .maximum = 1,
227 .step = 1,
228 .default_value = 1
229 },
230 .set = ov9650_set_auto_gain,
231 .get = ov9650_get_auto_gain
232 },
233#define AUTO_EXPOSURE_IDX 8
234 {
235 {
236 .id = V4L2_CID_EXPOSURE_AUTO,
237 .type = V4L2_CTRL_TYPE_BOOLEAN,
238 .name = "auto exposure",
239 .minimum = 0,
240 .maximum = 1,
241 .step = 1,
242 .default_value = 1
243 },
244 .set = ov9650_set_auto_exposure,
245 .get = ov9650_get_auto_exposure
246 }
247
248};
249
250static struct v4l2_pix_format ov9650_modes[] = {
251 {
252 176,
253 144,
254 V4L2_PIX_FMT_SBGGR8,
255 V4L2_FIELD_NONE,
256 .sizeimage =
257 176 * 144,
258 .bytesperline = 176,
259 .colorspace = V4L2_COLORSPACE_SRGB,
260 .priv = 9
261 }, {
262 320,
263 240,
264 V4L2_PIX_FMT_SBGGR8,
265 V4L2_FIELD_NONE,
266 .sizeimage =
267 320 * 240,
268 .bytesperline = 320,
269 .colorspace = V4L2_COLORSPACE_SRGB,
270 .priv = 8
271 }, {
272 352,
273 288,
274 V4L2_PIX_FMT_SBGGR8,
275 V4L2_FIELD_NONE,
276 .sizeimage =
277 352 * 288,
278 .bytesperline = 352,
279 .colorspace = V4L2_COLORSPACE_SRGB,
280 .priv = 9
281 }, {
282 640,
283 480,
284 V4L2_PIX_FMT_SBGGR8,
285 V4L2_FIELD_NONE,
286 .sizeimage =
287 640 * 480,
288 .bytesperline = 640,
289 .colorspace = V4L2_COLORSPACE_SRGB,
290 .priv = 9
291 }
292};
293
294static void ov9650_dump_registers(struct sd *sd);
295
296int ov9650_probe(struct sd *sd)
297{
298 int err = 0;
299 u8 prod_id = 0, ver_id = 0, i;
300 s32 *sensor_settings;
301
302 if (force_sensor) {
303 if (force_sensor == OV9650_SENSOR) {
304 pr_info("Forcing an %s sensor\n", ov9650.name);
305 goto sensor_found;
306 }
307 /* If we want to force another sensor,
308 don't try to probe this one */
309 return -ENODEV;
310 }
311
312 PDEBUG(D_PROBE, "Probing for an ov9650 sensor");
313
314 /* Run the pre-init before probing the sensor */
315 for (i = 0; i < ARRAY_SIZE(preinit_ov9650) && !err; i++) {
316 u8 data = preinit_ov9650[i][2];
317 if (preinit_ov9650[i][0] == SENSOR)
318 err = m5602_write_sensor(sd,
319 preinit_ov9650[i][1], &data, 1);
320 else
321 err = m5602_write_bridge(sd,
322 preinit_ov9650[i][1], data);
323 }
324
325 if (err < 0)
326 return err;
327
328 if (m5602_read_sensor(sd, OV9650_PID, &prod_id, 1))
329 return -ENODEV;
330
331 if (m5602_read_sensor(sd, OV9650_VER, &ver_id, 1))
332 return -ENODEV;
333
334 if ((prod_id == 0x96) && (ver_id == 0x52)) {
335 pr_info("Detected an ov9650 sensor\n");
336 goto sensor_found;
337 }
338 return -ENODEV;
339
340sensor_found:
341 sensor_settings = kmalloc(
342 ARRAY_SIZE(ov9650_ctrls) * sizeof(s32), GFP_KERNEL);
343 if (!sensor_settings)
344 return -ENOMEM;
345
346 sd->gspca_dev.cam.cam_mode = ov9650_modes;
347 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov9650_modes);
348 sd->desc->ctrls = ov9650_ctrls;
349 sd->desc->nctrls = ARRAY_SIZE(ov9650_ctrls);
350
351 for (i = 0; i < ARRAY_SIZE(ov9650_ctrls); i++)
352 sensor_settings[i] = ov9650_ctrls[i].qctrl.default_value;
353 sd->sensor_priv = sensor_settings;
354 return 0;
355}
356
357int ov9650_init(struct sd *sd)
358{
359 int i, err = 0;
360 u8 data;
361 s32 *sensor_settings = sd->sensor_priv;
362
363 if (dump_sensor)
364 ov9650_dump_registers(sd);
365
366 for (i = 0; i < ARRAY_SIZE(init_ov9650) && !err; i++) {
367 data = init_ov9650[i][2];
368 if (init_ov9650[i][0] == SENSOR)
369 err = m5602_write_sensor(sd, init_ov9650[i][1],
370 &data, 1);
371 else
372 err = m5602_write_bridge(sd, init_ov9650[i][1], data);
373 }
374
375 err = ov9650_set_exposure(&sd->gspca_dev,
376 sensor_settings[EXPOSURE_IDX]);
377 if (err < 0)
378 return err;
379
380 err = ov9650_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
381 if (err < 0)
382 return err;
383
384 err = ov9650_set_red_balance(&sd->gspca_dev,
385 sensor_settings[RED_BALANCE_IDX]);
386 if (err < 0)
387 return err;
388
389 err = ov9650_set_blue_balance(&sd->gspca_dev,
390 sensor_settings[BLUE_BALANCE_IDX]);
391 if (err < 0)
392 return err;
393
394 err = ov9650_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
395 if (err < 0)
396 return err;
397
398 err = ov9650_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
399 if (err < 0)
400 return err;
401
402 err = ov9650_set_auto_exposure(&sd->gspca_dev,
403 sensor_settings[AUTO_EXPOSURE_IDX]);
404 if (err < 0)
405 return err;
406
407 err = ov9650_set_auto_white_balance(&sd->gspca_dev,
408 sensor_settings[AUTO_WHITE_BALANCE_IDX]);
409 if (err < 0)
410 return err;
411
412 err = ov9650_set_auto_gain(&sd->gspca_dev,
413 sensor_settings[AUTO_GAIN_CTRL_IDX]);
414 return err;
415}
416
417int ov9650_start(struct sd *sd)
418{
419 u8 data;
420 int i, err = 0;
421 struct cam *cam = &sd->gspca_dev.cam;
422 s32 *sensor_settings = sd->sensor_priv;
423
424 int width = cam->cam_mode[sd->gspca_dev.curr_mode].width;
425 int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
426 int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
427 int hor_offs = OV9650_LEFT_OFFSET;
428
429 if ((!dmi_check_system(ov9650_flip_dmi_table) &&
430 sensor_settings[VFLIP_IDX]) ||
431 (dmi_check_system(ov9650_flip_dmi_table) &&
432 !sensor_settings[VFLIP_IDX]))
433 ver_offs--;
434
435 if (width <= 320)
436 hor_offs /= 2;
437
438 /* Synthesize the vsync/hsync setup */
439 for (i = 0; i < ARRAY_SIZE(res_init_ov9650) && !err; i++) {
440 if (res_init_ov9650[i][0] == BRIDGE)
441 err = m5602_write_bridge(sd, res_init_ov9650[i][1],
442 res_init_ov9650[i][2]);
443 else if (res_init_ov9650[i][0] == SENSOR) {
444 data = res_init_ov9650[i][2];
445 err = m5602_write_sensor(sd,
446 res_init_ov9650[i][1], &data, 1);
447 }
448 }
449 if (err < 0)
450 return err;
451
452 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA,
453 ((ver_offs >> 8) & 0xff));
454 if (err < 0)
455 return err;
456
457 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (ver_offs & 0xff));
458 if (err < 0)
459 return err;
460
461 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
462 if (err < 0)
463 return err;
464
465 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff);
466 if (err < 0)
467 return err;
468
469 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff));
470 if (err < 0)
471 return err;
472
473 for (i = 0; i < 2 && !err; i++)
474 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
475 if (err < 0)
476 return err;
477
478 err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
479 if (err < 0)
480 return err;
481
482 err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 2);
483 if (err < 0)
484 return err;
485
486 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
487 (hor_offs >> 8) & 0xff);
488 if (err < 0)
489 return err;
490
491 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, hor_offs & 0xff);
492 if (err < 0)
493 return err;
494
495 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
496 ((width + hor_offs) >> 8) & 0xff);
497 if (err < 0)
498 return err;
499
500 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
501 ((width + hor_offs) & 0xff));
502 if (err < 0)
503 return err;
504
505 err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
506 if (err < 0)
507 return err;
508
509 switch (width) {
510 case 640:
511 PDEBUG(D_V4L2, "Configuring camera for VGA mode");
512
513 data = OV9650_VGA_SELECT | OV9650_RGB_SELECT |
514 OV9650_RAW_RGB_SELECT;
515 err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
516 break;
517
518 case 352:
519 PDEBUG(D_V4L2, "Configuring camera for CIF mode");
520
521 data = OV9650_CIF_SELECT | OV9650_RGB_SELECT |
522 OV9650_RAW_RGB_SELECT;
523 err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
524 break;
525
526 case 320:
527 PDEBUG(D_V4L2, "Configuring camera for QVGA mode");
528
529 data = OV9650_QVGA_SELECT | OV9650_RGB_SELECT |
530 OV9650_RAW_RGB_SELECT;
531 err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
532 break;
533
534 case 176:
535 PDEBUG(D_V4L2, "Configuring camera for QCIF mode");
536
537 data = OV9650_QCIF_SELECT | OV9650_RGB_SELECT |
538 OV9650_RAW_RGB_SELECT;
539 err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
540 break;
541 }
542 return err;
543}
544
545int ov9650_stop(struct sd *sd)
546{
547 u8 data = OV9650_SOFT_SLEEP | OV9650_OUTPUT_DRIVE_2X;
548 return m5602_write_sensor(sd, OV9650_COM2, &data, 1);
549}
550
551void ov9650_disconnect(struct sd *sd)
552{
553 ov9650_stop(sd);
554
555 sd->sensor = NULL;
556 kfree(sd->sensor_priv);
557}
558
559static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
560{
561 struct sd *sd = (struct sd *) gspca_dev;
562 s32 *sensor_settings = sd->sensor_priv;
563
564 *val = sensor_settings[EXPOSURE_IDX];
565 PDEBUG(D_V4L2, "Read exposure %d", *val);
566 return 0;
567}
568
569static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
570{
571 struct sd *sd = (struct sd *) gspca_dev;
572 s32 *sensor_settings = sd->sensor_priv;
573 u8 i2c_data;
574 int err;
575
576 PDEBUG(D_V4L2, "Set exposure to %d", val);
577
578 sensor_settings[EXPOSURE_IDX] = val;
579 /* The 6 MSBs */
580 i2c_data = (val >> 10) & 0x3f;
581 err = m5602_write_sensor(sd, OV9650_AECHM,
582 &i2c_data, 1);
583 if (err < 0)
584 return err;
585
586 /* The 8 middle bits */
587 i2c_data = (val >> 2) & 0xff;
588 err = m5602_write_sensor(sd, OV9650_AECH,
589 &i2c_data, 1);
590 if (err < 0)
591 return err;
592
593 /* The 2 LSBs */
594 i2c_data = val & 0x03;
595 err = m5602_write_sensor(sd, OV9650_COM1, &i2c_data, 1);
596 return err;
597}
598
599static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
600{
601 struct sd *sd = (struct sd *) gspca_dev;
602 s32 *sensor_settings = sd->sensor_priv;
603
604 *val = sensor_settings[GAIN_IDX];
605 PDEBUG(D_V4L2, "Read gain %d", *val);
606 return 0;
607}
608
609static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
610{
611 int err;
612 u8 i2c_data;
613 struct sd *sd = (struct sd *) gspca_dev;
614 s32 *sensor_settings = sd->sensor_priv;
615
616 PDEBUG(D_V4L2, "Setting gain to %d", val);
617
618 sensor_settings[GAIN_IDX] = val;
619
620 /* The 2 MSB */
621 /* Read the OV9650_VREF register first to avoid
622 corrupting the VREF high and low bits */
623 err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
624 if (err < 0)
625 return err;
626
627 /* Mask away all uninteresting bits */
628 i2c_data = ((val & 0x0300) >> 2) |
629 (i2c_data & 0x3f);
630 err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1);
631 if (err < 0)
632 return err;
633
634 /* The 8 LSBs */
635 i2c_data = val & 0xff;
636 err = m5602_write_sensor(sd, OV9650_GAIN, &i2c_data, 1);
637 return err;
638}
639
640static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
641{
642 struct sd *sd = (struct sd *) gspca_dev;
643 s32 *sensor_settings = sd->sensor_priv;
644
645 *val = sensor_settings[RED_BALANCE_IDX];
646 PDEBUG(D_V4L2, "Read red gain %d", *val);
647 return 0;
648}
649
650static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
651{
652 int err;
653 u8 i2c_data;
654 struct sd *sd = (struct sd *) gspca_dev;
655 s32 *sensor_settings = sd->sensor_priv;
656
657 PDEBUG(D_V4L2, "Set red gain to %d", val);
658
659 sensor_settings[RED_BALANCE_IDX] = val;
660
661 i2c_data = val & 0xff;
662 err = m5602_write_sensor(sd, OV9650_RED, &i2c_data, 1);
663 return err;
664}
665
666static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
667{
668 struct sd *sd = (struct sd *) gspca_dev;
669 s32 *sensor_settings = sd->sensor_priv;
670
671 *val = sensor_settings[BLUE_BALANCE_IDX];
672 PDEBUG(D_V4L2, "Read blue gain %d", *val);
673
674 return 0;
675}
676
677static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
678{
679 int err;
680 u8 i2c_data;
681 struct sd *sd = (struct sd *) gspca_dev;
682 s32 *sensor_settings = sd->sensor_priv;
683
684 PDEBUG(D_V4L2, "Set blue gain to %d", val);
685
686 sensor_settings[BLUE_BALANCE_IDX] = val;
687
688 i2c_data = val & 0xff;
689 err = m5602_write_sensor(sd, OV9650_BLUE, &i2c_data, 1);
690 return err;
691}
692
693static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
694{
695 struct sd *sd = (struct sd *) gspca_dev;
696 s32 *sensor_settings = sd->sensor_priv;
697
698 *val = sensor_settings[HFLIP_IDX];
699 PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
700 return 0;
701}
702
703static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
704{
705 int err;
706 u8 i2c_data;
707 struct sd *sd = (struct sd *) gspca_dev;
708 s32 *sensor_settings = sd->sensor_priv;
709
710 PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
711
712 sensor_settings[HFLIP_IDX] = val;
713
714 if (!dmi_check_system(ov9650_flip_dmi_table))
715 i2c_data = ((val & 0x01) << 5) |
716 (sensor_settings[VFLIP_IDX] << 4);
717 else
718 i2c_data = ((val & 0x01) << 5) |
719 (!sensor_settings[VFLIP_IDX] << 4);
720
721 err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
722
723 return err;
724}
725
726static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
727{
728 struct sd *sd = (struct sd *) gspca_dev;
729 s32 *sensor_settings = sd->sensor_priv;
730
731 *val = sensor_settings[VFLIP_IDX];
732 PDEBUG(D_V4L2, "Read vertical flip %d", *val);
733
734 return 0;
735}
736
737static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
738{
739 int err;
740 u8 i2c_data;
741 struct sd *sd = (struct sd *) gspca_dev;
742 s32 *sensor_settings = sd->sensor_priv;
743
744 PDEBUG(D_V4L2, "Set vertical flip to %d", val);
745 sensor_settings[VFLIP_IDX] = val;
746
747 if (dmi_check_system(ov9650_flip_dmi_table))
748 val = !val;
749
750 i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5);
751 err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
752 if (err < 0)
753 return err;
754
755 /* When vflip is toggled we need to readjust the bridge hsync/vsync */
756 if (gspca_dev->streaming)
757 err = ov9650_start(sd);
758
759 return err;
760}
761
762static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val)
763{
764 struct sd *sd = (struct sd *) gspca_dev;
765 s32 *sensor_settings = sd->sensor_priv;
766
767 *val = sensor_settings[AUTO_EXPOSURE_IDX];
768 PDEBUG(D_V4L2, "Read auto exposure control %d", *val);
769 return 0;
770}
771
772static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev,
773 __s32 val)
774{
775 int err;
776 u8 i2c_data;
777 struct sd *sd = (struct sd *) gspca_dev;
778 s32 *sensor_settings = sd->sensor_priv;
779
780 PDEBUG(D_V4L2, "Set auto exposure control to %d", val);
781
782 sensor_settings[AUTO_EXPOSURE_IDX] = val;
783 err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
784 if (err < 0)
785 return err;
786
787 i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0));
788
789 return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
790}
791
792static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev,
793 __s32 *val)
794{
795 struct sd *sd = (struct sd *) gspca_dev;
796 s32 *sensor_settings = sd->sensor_priv;
797
798 *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
799 return 0;
800}
801
802static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
803 __s32 val)
804{
805 int err;
806 u8 i2c_data;
807 struct sd *sd = (struct sd *) gspca_dev;
808 s32 *sensor_settings = sd->sensor_priv;
809
810 PDEBUG(D_V4L2, "Set auto white balance to %d", val);
811
812 sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
813 err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
814 if (err < 0)
815 return err;
816
817 i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1));
818 err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
819
820 return err;
821}
822
823static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
824{
825 struct sd *sd = (struct sd *) gspca_dev;
826 s32 *sensor_settings = sd->sensor_priv;
827
828 *val = sensor_settings[AUTO_GAIN_CTRL_IDX];
829 PDEBUG(D_V4L2, "Read auto gain control %d", *val);
830 return 0;
831}
832
833static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
834{
835 int err;
836 u8 i2c_data;
837 struct sd *sd = (struct sd *) gspca_dev;
838 s32 *sensor_settings = sd->sensor_priv;
839
840 PDEBUG(D_V4L2, "Set auto gain control to %d", val);
841
842 sensor_settings[AUTO_GAIN_CTRL_IDX] = val;
843 err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
844 if (err < 0)
845 return err;
846
847 i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2));
848
849 return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
850}
851
852static void ov9650_dump_registers(struct sd *sd)
853{
854 int address;
855 pr_info("Dumping the ov9650 register state\n");
856 for (address = 0; address < 0xa9; address++) {
857 u8 value;
858 m5602_read_sensor(sd, address, &value, 1);
859 pr_info("register 0x%x contains 0x%x\n", address, value);
860 }
861
862 pr_info("ov9650 register state dump complete\n");
863
864 pr_info("Probing for which registers that are read/write\n");
865 for (address = 0; address < 0xff; address++) {
866 u8 old_value, ctrl_value;
867 u8 test_value[2] = {0xff, 0xff};
868
869 m5602_read_sensor(sd, address, &old_value, 1);
870 m5602_write_sensor(sd, address, test_value, 1);
871 m5602_read_sensor(sd, address, &ctrl_value, 1);
872
873 if (ctrl_value == test_value[0])
874 pr_info("register 0x%x is writeable\n", address);
875 else
876 pr_info("register 0x%x is read only\n", address);
877
878 /* Restore original value */
879 m5602_write_sensor(sd, address, &old_value, 1);
880 }
881}
diff --git a/drivers/media/usb/gspca/m5602/m5602_ov9650.h b/drivers/media/usb/gspca/m5602/m5602_ov9650.h
new file mode 100644
index 000000000000..f7aa5bf68983
--- /dev/null
+++ b/drivers/media/usb/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 bool 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/usb/gspca/m5602/m5602_po1030.c b/drivers/media/usb/gspca/m5602/m5602_po1030.c
new file mode 100644
index 000000000000..b8771698cbcb
--- /dev/null
+++ b/drivers/media/usb/gspca/m5602/m5602_po1030.c
@@ -0,0 +1,763 @@
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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20
21#include "m5602_po1030.h"
22
23static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
24static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
25static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
26static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val);
27static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
28static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
29static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
30static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
31static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val);
32static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val);
33static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
34static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
35static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
36static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
37static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev,
38 __s32 val);
39static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev,
40 __s32 *val);
41static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,
42 __s32 val);
43static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev,
44 __s32 *val);
45
46static struct v4l2_pix_format po1030_modes[] = {
47 {
48 640,
49 480,
50 V4L2_PIX_FMT_SBGGR8,
51 V4L2_FIELD_NONE,
52 .sizeimage = 640 * 480,
53 .bytesperline = 640,
54 .colorspace = V4L2_COLORSPACE_SRGB,
55 .priv = 2
56 }
57};
58
59static const struct ctrl po1030_ctrls[] = {
60#define GAIN_IDX 0
61 {
62 {
63 .id = V4L2_CID_GAIN,
64 .type = V4L2_CTRL_TYPE_INTEGER,
65 .name = "gain",
66 .minimum = 0x00,
67 .maximum = 0x4f,
68 .step = 0x1,
69 .default_value = PO1030_GLOBAL_GAIN_DEFAULT,
70 .flags = V4L2_CTRL_FLAG_SLIDER
71 },
72 .set = po1030_set_gain,
73 .get = po1030_get_gain
74 },
75#define EXPOSURE_IDX 1
76 {
77 {
78 .id = V4L2_CID_EXPOSURE,
79 .type = V4L2_CTRL_TYPE_INTEGER,
80 .name = "exposure",
81 .minimum = 0x00,
82 .maximum = 0x02ff,
83 .step = 0x1,
84 .default_value = PO1030_EXPOSURE_DEFAULT,
85 .flags = V4L2_CTRL_FLAG_SLIDER
86 },
87 .set = po1030_set_exposure,
88 .get = po1030_get_exposure
89 },
90#define RED_BALANCE_IDX 2
91 {
92 {
93 .id = V4L2_CID_RED_BALANCE,
94 .type = V4L2_CTRL_TYPE_INTEGER,
95 .name = "red balance",
96 .minimum = 0x00,
97 .maximum = 0xff,
98 .step = 0x1,
99 .default_value = PO1030_RED_GAIN_DEFAULT,
100 .flags = V4L2_CTRL_FLAG_SLIDER
101 },
102 .set = po1030_set_red_balance,
103 .get = po1030_get_red_balance
104 },
105#define BLUE_BALANCE_IDX 3
106 {
107 {
108 .id = V4L2_CID_BLUE_BALANCE,
109 .type = V4L2_CTRL_TYPE_INTEGER,
110 .name = "blue balance",
111 .minimum = 0x00,
112 .maximum = 0xff,
113 .step = 0x1,
114 .default_value = PO1030_BLUE_GAIN_DEFAULT,
115 .flags = V4L2_CTRL_FLAG_SLIDER
116 },
117 .set = po1030_set_blue_balance,
118 .get = po1030_get_blue_balance
119 },
120#define HFLIP_IDX 4
121 {
122 {
123 .id = V4L2_CID_HFLIP,
124 .type = V4L2_CTRL_TYPE_BOOLEAN,
125 .name = "horizontal flip",
126 .minimum = 0,
127 .maximum = 1,
128 .step = 1,
129 .default_value = 0,
130 },
131 .set = po1030_set_hflip,
132 .get = po1030_get_hflip
133 },
134#define VFLIP_IDX 5
135 {
136 {
137 .id = V4L2_CID_VFLIP,
138 .type = V4L2_CTRL_TYPE_BOOLEAN,
139 .name = "vertical flip",
140 .minimum = 0,
141 .maximum = 1,
142 .step = 1,
143 .default_value = 0,
144 },
145 .set = po1030_set_vflip,
146 .get = po1030_get_vflip
147 },
148#define AUTO_WHITE_BALANCE_IDX 6
149 {
150 {
151 .id = V4L2_CID_AUTO_WHITE_BALANCE,
152 .type = V4L2_CTRL_TYPE_BOOLEAN,
153 .name = "auto white balance",
154 .minimum = 0,
155 .maximum = 1,
156 .step = 1,
157 .default_value = 0,
158 },
159 .set = po1030_set_auto_white_balance,
160 .get = po1030_get_auto_white_balance
161 },
162#define AUTO_EXPOSURE_IDX 7
163 {
164 {
165 .id = V4L2_CID_EXPOSURE_AUTO,
166 .type = V4L2_CTRL_TYPE_BOOLEAN,
167 .name = "auto exposure",
168 .minimum = 0,
169 .maximum = 1,
170 .step = 1,
171 .default_value = 0,
172 },
173 .set = po1030_set_auto_exposure,
174 .get = po1030_get_auto_exposure
175 },
176#define GREEN_BALANCE_IDX 8
177 {
178 {
179 .id = M5602_V4L2_CID_GREEN_BALANCE,
180 .type = V4L2_CTRL_TYPE_INTEGER,
181 .name = "green balance",
182 .minimum = 0x00,
183 .maximum = 0xff,
184 .step = 0x1,
185 .default_value = PO1030_GREEN_GAIN_DEFAULT,
186 .flags = V4L2_CTRL_FLAG_SLIDER
187 },
188 .set = po1030_set_green_balance,
189 .get = po1030_get_green_balance
190 },
191};
192
193static void po1030_dump_registers(struct sd *sd);
194
195int po1030_probe(struct sd *sd)
196{
197 u8 dev_id_h = 0, i;
198 s32 *sensor_settings;
199
200 if (force_sensor) {
201 if (force_sensor == PO1030_SENSOR) {
202 pr_info("Forcing a %s sensor\n", po1030.name);
203 goto sensor_found;
204 }
205 /* If we want to force another sensor, don't try to probe this
206 * one */
207 return -ENODEV;
208 }
209
210 PDEBUG(D_PROBE, "Probing for a po1030 sensor");
211
212 /* Run the pre-init to actually probe the unit */
213 for (i = 0; i < ARRAY_SIZE(preinit_po1030); i++) {
214 u8 data = preinit_po1030[i][2];
215 if (preinit_po1030[i][0] == SENSOR)
216 m5602_write_sensor(sd,
217 preinit_po1030[i][1], &data, 1);
218 else
219 m5602_write_bridge(sd, preinit_po1030[i][1], data);
220 }
221
222 if (m5602_read_sensor(sd, PO1030_DEVID_H, &dev_id_h, 1))
223 return -ENODEV;
224
225 if (dev_id_h == 0x30) {
226 pr_info("Detected a po1030 sensor\n");
227 goto sensor_found;
228 }
229 return -ENODEV;
230
231sensor_found:
232 sensor_settings = kmalloc(
233 ARRAY_SIZE(po1030_ctrls) * sizeof(s32), GFP_KERNEL);
234 if (!sensor_settings)
235 return -ENOMEM;
236
237 sd->gspca_dev.cam.cam_mode = po1030_modes;
238 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(po1030_modes);
239 sd->desc->ctrls = po1030_ctrls;
240 sd->desc->nctrls = ARRAY_SIZE(po1030_ctrls);
241
242 for (i = 0; i < ARRAY_SIZE(po1030_ctrls); i++)
243 sensor_settings[i] = po1030_ctrls[i].qctrl.default_value;
244 sd->sensor_priv = sensor_settings;
245
246 return 0;
247}
248
249int po1030_init(struct sd *sd)
250{
251 s32 *sensor_settings = sd->sensor_priv;
252 int i, err = 0;
253
254 /* Init the sensor */
255 for (i = 0; i < ARRAY_SIZE(init_po1030) && !err; i++) {
256 u8 data[2] = {0x00, 0x00};
257
258 switch (init_po1030[i][0]) {
259 case BRIDGE:
260 err = m5602_write_bridge(sd,
261 init_po1030[i][1],
262 init_po1030[i][2]);
263 break;
264
265 case SENSOR:
266 data[0] = init_po1030[i][2];
267 err = m5602_write_sensor(sd,
268 init_po1030[i][1], data, 1);
269 break;
270
271 default:
272 pr_info("Invalid stream command, exiting init\n");
273 return -EINVAL;
274 }
275 }
276 if (err < 0)
277 return err;
278
279 if (dump_sensor)
280 po1030_dump_registers(sd);
281
282 err = po1030_set_exposure(&sd->gspca_dev,
283 sensor_settings[EXPOSURE_IDX]);
284 if (err < 0)
285 return err;
286
287 err = po1030_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
288 if (err < 0)
289 return err;
290
291 err = po1030_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
292 if (err < 0)
293 return err;
294
295 err = po1030_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
296 if (err < 0)
297 return err;
298
299 err = po1030_set_red_balance(&sd->gspca_dev,
300 sensor_settings[RED_BALANCE_IDX]);
301 if (err < 0)
302 return err;
303
304 err = po1030_set_blue_balance(&sd->gspca_dev,
305 sensor_settings[BLUE_BALANCE_IDX]);
306 if (err < 0)
307 return err;
308
309 err = po1030_set_green_balance(&sd->gspca_dev,
310 sensor_settings[GREEN_BALANCE_IDX]);
311 if (err < 0)
312 return err;
313
314 err = po1030_set_auto_white_balance(&sd->gspca_dev,
315 sensor_settings[AUTO_WHITE_BALANCE_IDX]);
316 if (err < 0)
317 return err;
318
319 err = po1030_set_auto_exposure(&sd->gspca_dev,
320 sensor_settings[AUTO_EXPOSURE_IDX]);
321 return err;
322}
323
324int po1030_start(struct sd *sd)
325{
326 struct cam *cam = &sd->gspca_dev.cam;
327 int i, err = 0;
328 int width = cam->cam_mode[sd->gspca_dev.curr_mode].width;
329 int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
330 int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
331 u8 data;
332
333 switch (width) {
334 case 320:
335 data = PO1030_SUBSAMPLING;
336 err = m5602_write_sensor(sd, PO1030_CONTROL3, &data, 1);
337 if (err < 0)
338 return err;
339
340 data = ((width + 3) >> 8) & 0xff;
341 err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_H, &data, 1);
342 if (err < 0)
343 return err;
344
345 data = (width + 3) & 0xff;
346 err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_L, &data, 1);
347 if (err < 0)
348 return err;
349
350 data = ((height + 1) >> 8) & 0xff;
351 err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_H, &data, 1);
352 if (err < 0)
353 return err;
354
355 data = (height + 1) & 0xff;
356 err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_L, &data, 1);
357
358 height += 6;
359 width -= 1;
360 break;
361
362 case 640:
363 data = 0;
364 err = m5602_write_sensor(sd, PO1030_CONTROL3, &data, 1);
365 if (err < 0)
366 return err;
367
368 data = ((width + 7) >> 8) & 0xff;
369 err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_H, &data, 1);
370 if (err < 0)
371 return err;
372
373 data = (width + 7) & 0xff;
374 err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_L, &data, 1);
375 if (err < 0)
376 return err;
377
378 data = ((height + 3) >> 8) & 0xff;
379 err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_H, &data, 1);
380 if (err < 0)
381 return err;
382
383 data = (height + 3) & 0xff;
384 err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_L, &data, 1);
385
386 height += 12;
387 width -= 2;
388 break;
389 }
390 err = m5602_write_bridge(sd, M5602_XB_SENSOR_TYPE, 0x0c);
391 if (err < 0)
392 return err;
393
394 err = m5602_write_bridge(sd, M5602_XB_LINE_OF_FRAME_H, 0x81);
395 if (err < 0)
396 return err;
397
398 err = m5602_write_bridge(sd, M5602_XB_PIX_OF_LINE_H, 0x82);
399 if (err < 0)
400 return err;
401
402 err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0x01);
403 if (err < 0)
404 return err;
405
406 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA,
407 ((ver_offs >> 8) & 0xff));
408 if (err < 0)
409 return err;
410
411 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (ver_offs & 0xff));
412 if (err < 0)
413 return err;
414
415 for (i = 0; i < 2 && !err; i++)
416 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
417 if (err < 0)
418 return err;
419
420 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff);
421 if (err < 0)
422 return err;
423
424 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff));
425 if (err < 0)
426 return err;
427
428 for (i = 0; i < 2 && !err; i++)
429 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
430
431 for (i = 0; i < 2 && !err; i++)
432 err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
433
434 for (i = 0; i < 2 && !err; i++)
435 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 0);
436 if (err < 0)
437 return err;
438
439 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (width >> 8) & 0xff);
440 if (err < 0)
441 return err;
442
443 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (width & 0xff));
444 if (err < 0)
445 return err;
446
447 err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
448 return err;
449}
450
451static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
452{
453 struct sd *sd = (struct sd *) gspca_dev;
454 s32 *sensor_settings = sd->sensor_priv;
455
456 *val = sensor_settings[EXPOSURE_IDX];
457 PDEBUG(D_V4L2, "Exposure read as %d", *val);
458 return 0;
459}
460
461static int po1030_set_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 u8 i2c_data;
466 int err;
467
468 sensor_settings[EXPOSURE_IDX] = val;
469 PDEBUG(D_V4L2, "Set exposure to %d", val & 0xffff);
470
471 i2c_data = ((val & 0xff00) >> 8);
472 PDEBUG(D_V4L2, "Set exposure to high byte to 0x%x",
473 i2c_data);
474
475 err = m5602_write_sensor(sd, PO1030_INTEGLINES_H,
476 &i2c_data, 1);
477 if (err < 0)
478 return err;
479
480 i2c_data = (val & 0xff);
481 PDEBUG(D_V4L2, "Set exposure to low byte to 0x%x",
482 i2c_data);
483 err = m5602_write_sensor(sd, PO1030_INTEGLINES_M,
484 &i2c_data, 1);
485
486 return err;
487}
488
489static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
490{
491 struct sd *sd = (struct sd *) gspca_dev;
492 s32 *sensor_settings = sd->sensor_priv;
493
494 *val = sensor_settings[GAIN_IDX];
495 PDEBUG(D_V4L2, "Read global gain %d", *val);
496 return 0;
497}
498
499static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val)
500{
501 struct sd *sd = (struct sd *) gspca_dev;
502 s32 *sensor_settings = sd->sensor_priv;
503 u8 i2c_data;
504 int err;
505
506 sensor_settings[GAIN_IDX] = val;
507
508 i2c_data = val & 0xff;
509 PDEBUG(D_V4L2, "Set global gain to %d", i2c_data);
510 err = m5602_write_sensor(sd, PO1030_GLOBALGAIN,
511 &i2c_data, 1);
512 return err;
513}
514
515static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
516{
517 struct sd *sd = (struct sd *) gspca_dev;
518 s32 *sensor_settings = sd->sensor_priv;
519
520 *val = sensor_settings[HFLIP_IDX];
521 PDEBUG(D_V4L2, "Read hflip %d", *val);
522
523 return 0;
524}
525
526static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
527{
528 struct sd *sd = (struct sd *) gspca_dev;
529 s32 *sensor_settings = sd->sensor_priv;
530 u8 i2c_data;
531 int err;
532
533 sensor_settings[HFLIP_IDX] = val;
534
535 PDEBUG(D_V4L2, "Set hflip %d", val);
536 err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1);
537 if (err < 0)
538 return err;
539
540 i2c_data = (0x7f & i2c_data) | ((val & 0x01) << 7);
541
542 err = m5602_write_sensor(sd, PO1030_CONTROL2,
543 &i2c_data, 1);
544
545 return err;
546}
547
548static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
549{
550 struct sd *sd = (struct sd *) gspca_dev;
551 s32 *sensor_settings = sd->sensor_priv;
552
553 *val = sensor_settings[VFLIP_IDX];
554 PDEBUG(D_V4L2, "Read vflip %d", *val);
555
556 return 0;
557}
558
559static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
560{
561 struct sd *sd = (struct sd *) gspca_dev;
562 s32 *sensor_settings = sd->sensor_priv;
563 u8 i2c_data;
564 int err;
565
566 sensor_settings[VFLIP_IDX] = val;
567
568 PDEBUG(D_V4L2, "Set vflip %d", val);
569 err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1);
570 if (err < 0)
571 return err;
572
573 i2c_data = (i2c_data & 0xbf) | ((val & 0x01) << 6);
574
575 err = m5602_write_sensor(sd, PO1030_CONTROL2,
576 &i2c_data, 1);
577
578 return err;
579}
580
581static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
582{
583 struct sd *sd = (struct sd *) gspca_dev;
584 s32 *sensor_settings = sd->sensor_priv;
585
586 *val = sensor_settings[RED_BALANCE_IDX];
587 PDEBUG(D_V4L2, "Read red gain %d", *val);
588 return 0;
589}
590
591static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
592{
593 struct sd *sd = (struct sd *) gspca_dev;
594 s32 *sensor_settings = sd->sensor_priv;
595 u8 i2c_data;
596 int err;
597
598 sensor_settings[RED_BALANCE_IDX] = val;
599
600 i2c_data = val & 0xff;
601 PDEBUG(D_V4L2, "Set red gain to %d", i2c_data);
602 err = m5602_write_sensor(sd, PO1030_RED_GAIN,
603 &i2c_data, 1);
604 return err;
605}
606
607static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
608{
609 struct sd *sd = (struct sd *) gspca_dev;
610 s32 *sensor_settings = sd->sensor_priv;
611
612 *val = sensor_settings[BLUE_BALANCE_IDX];
613 PDEBUG(D_V4L2, "Read blue gain %d", *val);
614
615 return 0;
616}
617
618static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
619{
620 struct sd *sd = (struct sd *) gspca_dev;
621 s32 *sensor_settings = sd->sensor_priv;
622 u8 i2c_data;
623 int err;
624
625 sensor_settings[BLUE_BALANCE_IDX] = val;
626
627 i2c_data = val & 0xff;
628 PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data);
629 err = m5602_write_sensor(sd, PO1030_BLUE_GAIN,
630 &i2c_data, 1);
631
632 return err;
633}
634
635static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val)
636{
637 struct sd *sd = (struct sd *) gspca_dev;
638 s32 *sensor_settings = sd->sensor_priv;
639
640 *val = sensor_settings[GREEN_BALANCE_IDX];
641 PDEBUG(D_V4L2, "Read green gain %d", *val);
642
643 return 0;
644}
645
646static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
647{
648 struct sd *sd = (struct sd *) gspca_dev;
649 s32 *sensor_settings = sd->sensor_priv;
650 u8 i2c_data;
651 int err;
652
653 sensor_settings[GREEN_BALANCE_IDX] = val;
654 i2c_data = val & 0xff;
655 PDEBUG(D_V4L2, "Set green gain to %d", i2c_data);
656
657 err = m5602_write_sensor(sd, PO1030_GREEN_1_GAIN,
658 &i2c_data, 1);
659 if (err < 0)
660 return err;
661
662 return m5602_write_sensor(sd, PO1030_GREEN_2_GAIN,
663 &i2c_data, 1);
664}
665
666static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev,
667 __s32 *val)
668{
669 struct sd *sd = (struct sd *) gspca_dev;
670 s32 *sensor_settings = sd->sensor_priv;
671
672 *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
673 PDEBUG(D_V4L2, "Auto white balancing is %d", *val);
674
675 return 0;
676}
677
678static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev,
679 __s32 val)
680{
681 struct sd *sd = (struct sd *) gspca_dev;
682 s32 *sensor_settings = sd->sensor_priv;
683 u8 i2c_data;
684 int err;
685
686 sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
687
688 err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
689 if (err < 0)
690 return err;
691
692 PDEBUG(D_V4L2, "Set auto white balance to %d", val);
693 i2c_data = (i2c_data & 0xfe) | (val & 0x01);
694 err = m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
695 return err;
696}
697
698static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev,
699 __s32 *val)
700{
701 struct sd *sd = (struct sd *) gspca_dev;
702 s32 *sensor_settings = sd->sensor_priv;
703
704 *val = sensor_settings[AUTO_EXPOSURE_IDX];
705 PDEBUG(D_V4L2, "Auto exposure is %d", *val);
706 return 0;
707}
708
709static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,
710 __s32 val)
711{
712 struct sd *sd = (struct sd *) gspca_dev;
713 s32 *sensor_settings = sd->sensor_priv;
714 u8 i2c_data;
715 int err;
716
717 sensor_settings[AUTO_EXPOSURE_IDX] = val;
718 err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
719 if (err < 0)
720 return err;
721
722 PDEBUG(D_V4L2, "Set auto exposure to %d", val);
723 i2c_data = (i2c_data & 0xfd) | ((val & 0x01) << 1);
724 return m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
725}
726
727void po1030_disconnect(struct sd *sd)
728{
729 sd->sensor = NULL;
730 kfree(sd->sensor_priv);
731}
732
733static void po1030_dump_registers(struct sd *sd)
734{
735 int address;
736 u8 value = 0;
737
738 pr_info("Dumping the po1030 sensor core registers\n");
739 for (address = 0; address < 0x7f; address++) {
740 m5602_read_sensor(sd, address, &value, 1);
741 pr_info("register 0x%x contains 0x%x\n", address, value);
742 }
743
744 pr_info("po1030 register state dump complete\n");
745
746 pr_info("Probing for which registers that are read/write\n");
747 for (address = 0; address < 0xff; address++) {
748 u8 old_value, ctrl_value;
749 u8 test_value[2] = {0xff, 0xff};
750
751 m5602_read_sensor(sd, address, &old_value, 1);
752 m5602_write_sensor(sd, address, test_value, 1);
753 m5602_read_sensor(sd, address, &ctrl_value, 1);
754
755 if (ctrl_value == test_value[0])
756 pr_info("register 0x%x is writeable\n", address);
757 else
758 pr_info("register 0x%x is read only\n", address);
759
760 /* Restore original value */
761 m5602_write_sensor(sd, address, &old_value, 1);
762 }
763}
diff --git a/drivers/media/usb/gspca/m5602/m5602_po1030.h b/drivers/media/usb/gspca/m5602/m5602_po1030.h
new file mode 100644
index 000000000000..81a2bcb88fe3
--- /dev/null
+++ b/drivers/media/usb/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 bool 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/usb/gspca/m5602/m5602_s5k4aa.c b/drivers/media/usb/gspca/m5602/m5602_s5k4aa.c
new file mode 100644
index 000000000000..cc8ec3f7e8dc
--- /dev/null
+++ b/drivers/media/usb/gspca/m5602/m5602_s5k4aa.c
@@ -0,0 +1,726 @@
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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20
21#include "m5602_s5k4aa.h"
22
23static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
24static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
25static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
26static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
27static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
28static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
29static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
30static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val);
31static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val);
32static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val);
33static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
34static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
35
36static
37 const
38 struct dmi_system_id s5k4aa_vflip_dmi_table[] = {
39 {
40 .ident = "BRUNEINIT",
41 .matches = {
42 DMI_MATCH(DMI_SYS_VENDOR, "BRUNENIT"),
43 DMI_MATCH(DMI_PRODUCT_NAME, "BRUNENIT"),
44 DMI_MATCH(DMI_BOARD_VERSION, "00030D0000000001")
45 }
46 }, {
47 .ident = "Fujitsu-Siemens Amilo Xa 2528",
48 .matches = {
49 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
50 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528")
51 }
52 }, {
53 .ident = "Fujitsu-Siemens Amilo Xi 2428",
54 .matches = {
55 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
56 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2428")
57 }
58 }, {
59 .ident = "Fujitsu-Siemens Amilo Xi 2528",
60 .matches = {
61 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
62 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2528")
63 }
64 }, {
65 .ident = "Fujitsu-Siemens Amilo Xi 2550",
66 .matches = {
67 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
68 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550")
69 }
70 }, {
71 .ident = "Fujitsu-Siemens Amilo Pa 2548",
72 .matches = {
73 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
74 DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2548")
75 }
76 }, {
77 .ident = "MSI GX700",
78 .matches = {
79 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
80 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
81 DMI_MATCH(DMI_BIOS_DATE, "12/02/2008")
82 }
83 }, {
84 .ident = "MSI GX700",
85 .matches = {
86 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
87 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
88 DMI_MATCH(DMI_BIOS_DATE, "07/26/2007")
89 }
90 }, {
91 .ident = "MSI GX700",
92 .matches = {
93 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
94 DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
95 DMI_MATCH(DMI_BIOS_DATE, "07/19/2007")
96 }
97 }, {
98 .ident = "MSI GX700/GX705/EX700",
99 .matches = {
100 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
101 DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700")
102 }
103 }, {
104 .ident = "MSI L735",
105 .matches = {
106 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
107 DMI_MATCH(DMI_PRODUCT_NAME, "MS-1717X")
108 }
109 }, {
110 .ident = "Lenovo Y300",
111 .matches = {
112 DMI_MATCH(DMI_SYS_VENDOR, "L3000 Y300"),
113 DMI_MATCH(DMI_PRODUCT_NAME, "Y300")
114 }
115 },
116 { }
117};
118
119static struct v4l2_pix_format s5k4aa_modes[] = {
120 {
121 640,
122 480,
123 V4L2_PIX_FMT_SBGGR8,
124 V4L2_FIELD_NONE,
125 .sizeimage =
126 640 * 480,
127 .bytesperline = 640,
128 .colorspace = V4L2_COLORSPACE_SRGB,
129 .priv = 0
130 },
131 {
132 1280,
133 1024,
134 V4L2_PIX_FMT_SBGGR8,
135 V4L2_FIELD_NONE,
136 .sizeimage =
137 1280 * 1024,
138 .bytesperline = 1280,
139 .colorspace = V4L2_COLORSPACE_SRGB,
140 .priv = 0
141 }
142};
143
144static const struct ctrl s5k4aa_ctrls[] = {
145#define VFLIP_IDX 0
146 {
147 {
148 .id = V4L2_CID_VFLIP,
149 .type = V4L2_CTRL_TYPE_BOOLEAN,
150 .name = "vertical flip",
151 .minimum = 0,
152 .maximum = 1,
153 .step = 1,
154 .default_value = 0
155 },
156 .set = s5k4aa_set_vflip,
157 .get = s5k4aa_get_vflip
158 },
159#define HFLIP_IDX 1
160 {
161 {
162 .id = V4L2_CID_HFLIP,
163 .type = V4L2_CTRL_TYPE_BOOLEAN,
164 .name = "horizontal flip",
165 .minimum = 0,
166 .maximum = 1,
167 .step = 1,
168 .default_value = 0
169 },
170 .set = s5k4aa_set_hflip,
171 .get = s5k4aa_get_hflip
172 },
173#define GAIN_IDX 2
174 {
175 {
176 .id = V4L2_CID_GAIN,
177 .type = V4L2_CTRL_TYPE_INTEGER,
178 .name = "Gain",
179 .minimum = 0,
180 .maximum = 127,
181 .step = 1,
182 .default_value = S5K4AA_DEFAULT_GAIN,
183 .flags = V4L2_CTRL_FLAG_SLIDER
184 },
185 .set = s5k4aa_set_gain,
186 .get = s5k4aa_get_gain
187 },
188#define EXPOSURE_IDX 3
189 {
190 {
191 .id = V4L2_CID_EXPOSURE,
192 .type = V4L2_CTRL_TYPE_INTEGER,
193 .name = "Exposure",
194 .minimum = 13,
195 .maximum = 0xfff,
196 .step = 1,
197 .default_value = 0x100,
198 .flags = V4L2_CTRL_FLAG_SLIDER
199 },
200 .set = s5k4aa_set_exposure,
201 .get = s5k4aa_get_exposure
202 },
203#define NOISE_SUPP_IDX 4
204 {
205 {
206 .id = V4L2_CID_PRIVATE_BASE,
207 .type = V4L2_CTRL_TYPE_BOOLEAN,
208 .name = "Noise suppression (smoothing)",
209 .minimum = 0,
210 .maximum = 1,
211 .step = 1,
212 .default_value = 1,
213 },
214 .set = s5k4aa_set_noise,
215 .get = s5k4aa_get_noise
216 },
217#define BRIGHTNESS_IDX 5
218 {
219 {
220 .id = V4L2_CID_BRIGHTNESS,
221 .type = V4L2_CTRL_TYPE_INTEGER,
222 .name = "Brightness",
223 .minimum = 0,
224 .maximum = 0x1f,
225 .step = 1,
226 .default_value = S5K4AA_DEFAULT_BRIGHTNESS,
227 },
228 .set = s5k4aa_set_brightness,
229 .get = s5k4aa_get_brightness
230 },
231
232};
233
234static void s5k4aa_dump_registers(struct sd *sd);
235
236int s5k4aa_probe(struct sd *sd)
237{
238 u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
239 const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
240 int i, err = 0;
241 s32 *sensor_settings;
242
243 if (force_sensor) {
244 if (force_sensor == S5K4AA_SENSOR) {
245 pr_info("Forcing a %s sensor\n", s5k4aa.name);
246 goto sensor_found;
247 }
248 /* If we want to force another sensor, don't try to probe this
249 * one */
250 return -ENODEV;
251 }
252
253 PDEBUG(D_PROBE, "Probing for a s5k4aa sensor");
254
255 /* Preinit the sensor */
256 for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) {
257 u8 data[2] = {0x00, 0x00};
258
259 switch (preinit_s5k4aa[i][0]) {
260 case BRIDGE:
261 err = m5602_write_bridge(sd,
262 preinit_s5k4aa[i][1],
263 preinit_s5k4aa[i][2]);
264 break;
265
266 case SENSOR:
267 data[0] = preinit_s5k4aa[i][2];
268 err = m5602_write_sensor(sd,
269 preinit_s5k4aa[i][1],
270 data, 1);
271 break;
272
273 case SENSOR_LONG:
274 data[0] = preinit_s5k4aa[i][2];
275 data[1] = preinit_s5k4aa[i][3];
276 err = m5602_write_sensor(sd,
277 preinit_s5k4aa[i][1],
278 data, 2);
279 break;
280 default:
281 pr_info("Invalid stream command, exiting init\n");
282 return -EINVAL;
283 }
284 }
285
286 /* Test some registers, but we don't know their exact meaning yet */
287 if (m5602_read_sensor(sd, 0x00, prod_id, 2))
288 return -ENODEV;
289 if (m5602_read_sensor(sd, 0x02, prod_id+2, 2))
290 return -ENODEV;
291 if (m5602_read_sensor(sd, 0x04, prod_id+4, 2))
292 return -ENODEV;
293
294 if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
295 return -ENODEV;
296 else
297 pr_info("Detected a s5k4aa sensor\n");
298
299sensor_found:
300 sensor_settings = kmalloc(
301 ARRAY_SIZE(s5k4aa_ctrls) * sizeof(s32), GFP_KERNEL);
302 if (!sensor_settings)
303 return -ENOMEM;
304
305 sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
306 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
307 sd->desc->ctrls = s5k4aa_ctrls;
308 sd->desc->nctrls = ARRAY_SIZE(s5k4aa_ctrls);
309
310 for (i = 0; i < ARRAY_SIZE(s5k4aa_ctrls); i++)
311 sensor_settings[i] = s5k4aa_ctrls[i].qctrl.default_value;
312 sd->sensor_priv = sensor_settings;
313
314 return 0;
315}
316
317int s5k4aa_start(struct sd *sd)
318{
319 int i, err = 0;
320 u8 data[2];
321 struct cam *cam = &sd->gspca_dev.cam;
322 s32 *sensor_settings = sd->sensor_priv;
323
324 switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) {
325 case 1280:
326 PDEBUG(D_V4L2, "Configuring camera for SXGA mode");
327
328 for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) {
329 switch (SXGA_s5k4aa[i][0]) {
330 case BRIDGE:
331 err = m5602_write_bridge(sd,
332 SXGA_s5k4aa[i][1],
333 SXGA_s5k4aa[i][2]);
334 break;
335
336 case SENSOR:
337 data[0] = SXGA_s5k4aa[i][2];
338 err = m5602_write_sensor(sd,
339 SXGA_s5k4aa[i][1],
340 data, 1);
341 break;
342
343 case SENSOR_LONG:
344 data[0] = SXGA_s5k4aa[i][2];
345 data[1] = SXGA_s5k4aa[i][3];
346 err = m5602_write_sensor(sd,
347 SXGA_s5k4aa[i][1],
348 data, 2);
349 break;
350
351 default:
352 pr_err("Invalid stream command, exiting init\n");
353 return -EINVAL;
354 }
355 }
356 err = s5k4aa_set_noise(&sd->gspca_dev, 0);
357 if (err < 0)
358 return err;
359 break;
360
361 case 640:
362 PDEBUG(D_V4L2, "Configuring camera for VGA mode");
363
364 for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) {
365 switch (VGA_s5k4aa[i][0]) {
366 case BRIDGE:
367 err = m5602_write_bridge(sd,
368 VGA_s5k4aa[i][1],
369 VGA_s5k4aa[i][2]);
370 break;
371
372 case SENSOR:
373 data[0] = VGA_s5k4aa[i][2];
374 err = m5602_write_sensor(sd,
375 VGA_s5k4aa[i][1],
376 data, 1);
377 break;
378
379 case SENSOR_LONG:
380 data[0] = VGA_s5k4aa[i][2];
381 data[1] = VGA_s5k4aa[i][3];
382 err = m5602_write_sensor(sd,
383 VGA_s5k4aa[i][1],
384 data, 2);
385 break;
386
387 default:
388 pr_err("Invalid stream command, exiting init\n");
389 return -EINVAL;
390 }
391 }
392 err = s5k4aa_set_noise(&sd->gspca_dev, 1);
393 if (err < 0)
394 return err;
395 break;
396 }
397 if (err < 0)
398 return err;
399
400 err = s5k4aa_set_exposure(&sd->gspca_dev,
401 sensor_settings[EXPOSURE_IDX]);
402 if (err < 0)
403 return err;
404
405 err = s5k4aa_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
406 if (err < 0)
407 return err;
408
409 err = s5k4aa_set_brightness(&sd->gspca_dev,
410 sensor_settings[BRIGHTNESS_IDX]);
411 if (err < 0)
412 return err;
413
414 err = s5k4aa_set_noise(&sd->gspca_dev, sensor_settings[NOISE_SUPP_IDX]);
415 if (err < 0)
416 return err;
417
418 err = s5k4aa_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
419 if (err < 0)
420 return err;
421
422 return s5k4aa_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
423}
424
425int s5k4aa_init(struct sd *sd)
426{
427 int i, err = 0;
428
429 for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) {
430 u8 data[2] = {0x00, 0x00};
431
432 switch (init_s5k4aa[i][0]) {
433 case BRIDGE:
434 err = m5602_write_bridge(sd,
435 init_s5k4aa[i][1],
436 init_s5k4aa[i][2]);
437 break;
438
439 case SENSOR:
440 data[0] = init_s5k4aa[i][2];
441 err = m5602_write_sensor(sd,
442 init_s5k4aa[i][1], data, 1);
443 break;
444
445 case SENSOR_LONG:
446 data[0] = init_s5k4aa[i][2];
447 data[1] = init_s5k4aa[i][3];
448 err = m5602_write_sensor(sd,
449 init_s5k4aa[i][1], data, 2);
450 break;
451 default:
452 pr_info("Invalid stream command, exiting init\n");
453 return -EINVAL;
454 }
455 }
456
457 if (dump_sensor)
458 s5k4aa_dump_registers(sd);
459
460 return err;
461}
462
463static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
464{
465 struct sd *sd = (struct sd *) gspca_dev;
466 s32 *sensor_settings = sd->sensor_priv;
467
468 *val = sensor_settings[EXPOSURE_IDX];
469 PDEBUG(D_V4L2, "Read exposure %d", *val);
470
471 return 0;
472}
473
474static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
475{
476 struct sd *sd = (struct sd *) gspca_dev;
477 s32 *sensor_settings = sd->sensor_priv;
478 u8 data = S5K4AA_PAGE_MAP_2;
479 int err;
480
481 sensor_settings[EXPOSURE_IDX] = val;
482 PDEBUG(D_V4L2, "Set exposure to %d", val);
483 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
484 if (err < 0)
485 return err;
486 data = (val >> 8) & 0xff;
487 err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
488 if (err < 0)
489 return err;
490 data = val & 0xff;
491 err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
492
493 return err;
494}
495
496static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
497{
498 struct sd *sd = (struct sd *) gspca_dev;
499 s32 *sensor_settings = sd->sensor_priv;
500
501 *val = sensor_settings[VFLIP_IDX];
502 PDEBUG(D_V4L2, "Read vertical flip %d", *val);
503
504 return 0;
505}
506
507static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
508{
509 struct sd *sd = (struct sd *) gspca_dev;
510 s32 *sensor_settings = sd->sensor_priv;
511 u8 data = S5K4AA_PAGE_MAP_2;
512 int err;
513
514 sensor_settings[VFLIP_IDX] = val;
515
516 PDEBUG(D_V4L2, "Set vertical flip to %d", val);
517 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
518 if (err < 0)
519 return err;
520
521 err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
522 if (err < 0)
523 return err;
524
525 if (dmi_check_system(s5k4aa_vflip_dmi_table))
526 val = !val;
527
528 data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7));
529 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
530 if (err < 0)
531 return err;
532
533 err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
534 if (err < 0)
535 return err;
536 if (val)
537 data &= 0xfe;
538 else
539 data |= 0x01;
540 err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
541 return err;
542}
543
544static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
545{
546 struct sd *sd = (struct sd *) gspca_dev;
547 s32 *sensor_settings = sd->sensor_priv;
548
549 *val = sensor_settings[HFLIP_IDX];
550 PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
551
552 return 0;
553}
554
555static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
556{
557 struct sd *sd = (struct sd *) gspca_dev;
558 s32 *sensor_settings = sd->sensor_priv;
559 u8 data = S5K4AA_PAGE_MAP_2;
560 int err;
561
562 sensor_settings[HFLIP_IDX] = val;
563
564 PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
565 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
566 if (err < 0)
567 return err;
568
569 err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
570 if (err < 0)
571 return err;
572
573 if (dmi_check_system(s5k4aa_vflip_dmi_table))
574 val = !val;
575
576 data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
577 err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
578 if (err < 0)
579 return err;
580
581 err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
582 if (err < 0)
583 return err;
584 if (val)
585 data &= 0xfe;
586 else
587 data |= 0x01;
588 err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
589 return err;
590}
591
592static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
593{
594 struct sd *sd = (struct sd *) gspca_dev;
595 s32 *sensor_settings = sd->sensor_priv;
596
597 *val = sensor_settings[GAIN_IDX];
598 PDEBUG(D_V4L2, "Read gain %d", *val);
599 return 0;
600}
601
602static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
603{
604 struct sd *sd = (struct sd *) gspca_dev;
605 s32 *sensor_settings = sd->sensor_priv;
606 u8 data = S5K4AA_PAGE_MAP_2;
607 int err;
608
609 sensor_settings[GAIN_IDX] = val;
610
611 PDEBUG(D_V4L2, "Set gain to %d", val);
612 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
613 if (err < 0)
614 return err;
615
616 data = val & 0xff;
617 err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1);
618
619 return err;
620}
621
622static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
623{
624 struct sd *sd = (struct sd *) gspca_dev;
625 s32 *sensor_settings = sd->sensor_priv;
626
627 *val = sensor_settings[BRIGHTNESS_IDX];
628 PDEBUG(D_V4L2, "Read brightness %d", *val);
629 return 0;
630}
631
632static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
633{
634 struct sd *sd = (struct sd *) gspca_dev;
635 s32 *sensor_settings = sd->sensor_priv;
636 u8 data = S5K4AA_PAGE_MAP_2;
637 int err;
638
639 sensor_settings[BRIGHTNESS_IDX] = val;
640
641 PDEBUG(D_V4L2, "Set brightness to %d", val);
642 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
643 if (err < 0)
644 return err;
645
646 data = val & 0xff;
647 return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
648}
649
650static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val)
651{
652 struct sd *sd = (struct sd *) gspca_dev;
653 s32 *sensor_settings = sd->sensor_priv;
654
655 *val = sensor_settings[NOISE_SUPP_IDX];
656 PDEBUG(D_V4L2, "Read noise %d", *val);
657 return 0;
658}
659
660static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
661{
662 struct sd *sd = (struct sd *) gspca_dev;
663 s32 *sensor_settings = sd->sensor_priv;
664 u8 data = S5K4AA_PAGE_MAP_2;
665 int err;
666
667 sensor_settings[NOISE_SUPP_IDX] = val;
668
669 PDEBUG(D_V4L2, "Set noise to %d", val);
670 err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
671 if (err < 0)
672 return err;
673
674 data = val & 0x01;
675 return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
676}
677
678void s5k4aa_disconnect(struct sd *sd)
679{
680 sd->sensor = NULL;
681 kfree(sd->sensor_priv);
682}
683
684static void s5k4aa_dump_registers(struct sd *sd)
685{
686 int address;
687 u8 page, old_page;
688 m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
689 for (page = 0; page < 16; page++) {
690 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
691 pr_info("Dumping the s5k4aa register state for page 0x%x\n",
692 page);
693 for (address = 0; address <= 0xff; address++) {
694 u8 value = 0;
695 m5602_read_sensor(sd, address, &value, 1);
696 pr_info("register 0x%x contains 0x%x\n",
697 address, value);
698 }
699 }
700 pr_info("s5k4aa register state dump complete\n");
701
702 for (page = 0; page < 16; page++) {
703 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
704 pr_info("Probing for which registers that are read/write for page 0x%x\n",
705 page);
706 for (address = 0; address <= 0xff; address++) {
707 u8 old_value, ctrl_value, test_value = 0xff;
708
709 m5602_read_sensor(sd, address, &old_value, 1);
710 m5602_write_sensor(sd, address, &test_value, 1);
711 m5602_read_sensor(sd, address, &ctrl_value, 1);
712
713 if (ctrl_value == test_value)
714 pr_info("register 0x%x is writeable\n",
715 address);
716 else
717 pr_info("register 0x%x is read only\n",
718 address);
719
720 /* Restore original value */
721 m5602_write_sensor(sd, address, &old_value, 1);
722 }
723 }
724 pr_info("Read/write register probing complete\n");
725 m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
726}
diff --git a/drivers/media/usb/gspca/m5602/m5602_s5k4aa.h b/drivers/media/usb/gspca/m5602/m5602_s5k4aa.h
new file mode 100644
index 000000000000..8e0035e731c7
--- /dev/null
+++ b/drivers/media/usb/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 bool 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/usb/gspca/m5602/m5602_s5k83a.c b/drivers/media/usb/gspca/m5602/m5602_s5k83a.c
new file mode 100644
index 000000000000..1de743a02b02
--- /dev/null
+++ b/drivers/media/usb/gspca/m5602/m5602_s5k83a.c
@@ -0,0 +1,605 @@
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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20
21#include <linux/kthread.h>
22#include "m5602_s5k83a.h"
23
24static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val);
25static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
26static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
27static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
28static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
29static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
30static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
31static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
32static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
33static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
34
35static struct v4l2_pix_format s5k83a_modes[] = {
36 {
37 640,
38 480,
39 V4L2_PIX_FMT_SBGGR8,
40 V4L2_FIELD_NONE,
41 .sizeimage =
42 640 * 480,
43 .bytesperline = 640,
44 .colorspace = V4L2_COLORSPACE_SRGB,
45 .priv = 0
46 }
47};
48
49static const struct ctrl s5k83a_ctrls[] = {
50#define GAIN_IDX 0
51 {
52 {
53 .id = V4L2_CID_GAIN,
54 .type = V4L2_CTRL_TYPE_INTEGER,
55 .name = "gain",
56 .minimum = 0x00,
57 .maximum = 0xff,
58 .step = 0x01,
59 .default_value = S5K83A_DEFAULT_GAIN,
60 .flags = V4L2_CTRL_FLAG_SLIDER
61 },
62 .set = s5k83a_set_gain,
63 .get = s5k83a_get_gain
64
65 },
66#define BRIGHTNESS_IDX 1
67 {
68 {
69 .id = V4L2_CID_BRIGHTNESS,
70 .type = V4L2_CTRL_TYPE_INTEGER,
71 .name = "brightness",
72 .minimum = 0x00,
73 .maximum = 0xff,
74 .step = 0x01,
75 .default_value = S5K83A_DEFAULT_BRIGHTNESS,
76 .flags = V4L2_CTRL_FLAG_SLIDER
77 },
78 .set = s5k83a_set_brightness,
79 .get = s5k83a_get_brightness,
80 },
81#define EXPOSURE_IDX 2
82 {
83 {
84 .id = V4L2_CID_EXPOSURE,
85 .type = V4L2_CTRL_TYPE_INTEGER,
86 .name = "exposure",
87 .minimum = 0x00,
88 .maximum = S5K83A_MAXIMUM_EXPOSURE,
89 .step = 0x01,
90 .default_value = S5K83A_DEFAULT_EXPOSURE,
91 .flags = V4L2_CTRL_FLAG_SLIDER
92 },
93 .set = s5k83a_set_exposure,
94 .get = s5k83a_get_exposure
95 },
96#define HFLIP_IDX 3
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 = s5k83a_set_hflip,
108 .get = s5k83a_get_hflip
109 },
110#define VFLIP_IDX 4
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 = s5k83a_set_vflip,
122 .get = s5k83a_get_vflip
123 }
124};
125
126static void s5k83a_dump_registers(struct sd *sd);
127static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data);
128static int s5k83a_set_led_indication(struct sd *sd, u8 val);
129static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
130 __s32 vflip, __s32 hflip);
131
132int s5k83a_probe(struct sd *sd)
133{
134 struct s5k83a_priv *sens_priv;
135 u8 prod_id = 0, ver_id = 0;
136 int i, err = 0;
137
138 if (force_sensor) {
139 if (force_sensor == S5K83A_SENSOR) {
140 pr_info("Forcing a %s sensor\n", s5k83a.name);
141 goto sensor_found;
142 }
143 /* If we want to force another sensor, don't try to probe this
144 * one */
145 return -ENODEV;
146 }
147
148 PDEBUG(D_PROBE, "Probing for a s5k83a sensor");
149
150 /* Preinit the sensor */
151 for (i = 0; i < ARRAY_SIZE(preinit_s5k83a) && !err; i++) {
152 u8 data[2] = {preinit_s5k83a[i][2], preinit_s5k83a[i][3]};
153 if (preinit_s5k83a[i][0] == SENSOR)
154 err = m5602_write_sensor(sd, preinit_s5k83a[i][1],
155 data, 2);
156 else
157 err = m5602_write_bridge(sd, preinit_s5k83a[i][1],
158 data[0]);
159 }
160
161 /* We don't know what register (if any) that contain the product id
162 * Just pick the first addresses that seem to produce the same results
163 * on multiple machines */
164 if (m5602_read_sensor(sd, 0x00, &prod_id, 1))
165 return -ENODEV;
166
167 if (m5602_read_sensor(sd, 0x01, &ver_id, 1))
168 return -ENODEV;
169
170 if ((prod_id == 0xff) || (ver_id == 0xff))
171 return -ENODEV;
172 else
173 pr_info("Detected a s5k83a sensor\n");
174
175sensor_found:
176 sens_priv = kmalloc(
177 sizeof(struct s5k83a_priv), GFP_KERNEL);
178 if (!sens_priv)
179 return -ENOMEM;
180
181 sens_priv->settings =
182 kmalloc(sizeof(s32)*ARRAY_SIZE(s5k83a_ctrls), GFP_KERNEL);
183 if (!sens_priv->settings) {
184 kfree(sens_priv);
185 return -ENOMEM;
186 }
187
188 sd->gspca_dev.cam.cam_mode = s5k83a_modes;
189 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes);
190 sd->desc->ctrls = s5k83a_ctrls;
191 sd->desc->nctrls = ARRAY_SIZE(s5k83a_ctrls);
192
193 /* null the pointer! thread is't running now */
194 sens_priv->rotation_thread = NULL;
195
196 for (i = 0; i < ARRAY_SIZE(s5k83a_ctrls); i++)
197 sens_priv->settings[i] = s5k83a_ctrls[i].qctrl.default_value;
198
199 sd->sensor_priv = sens_priv;
200 return 0;
201}
202
203int s5k83a_init(struct sd *sd)
204{
205 int i, err = 0;
206 s32 *sensor_settings =
207 ((struct s5k83a_priv *) sd->sensor_priv)->settings;
208
209 for (i = 0; i < ARRAY_SIZE(init_s5k83a) && !err; i++) {
210 u8 data[2] = {0x00, 0x00};
211
212 switch (init_s5k83a[i][0]) {
213 case BRIDGE:
214 err = m5602_write_bridge(sd,
215 init_s5k83a[i][1],
216 init_s5k83a[i][2]);
217 break;
218
219 case SENSOR:
220 data[0] = init_s5k83a[i][2];
221 err = m5602_write_sensor(sd,
222 init_s5k83a[i][1], data, 1);
223 break;
224
225 case SENSOR_LONG:
226 data[0] = init_s5k83a[i][2];
227 data[1] = init_s5k83a[i][3];
228 err = m5602_write_sensor(sd,
229 init_s5k83a[i][1], data, 2);
230 break;
231 default:
232 pr_info("Invalid stream command, exiting init\n");
233 return -EINVAL;
234 }
235 }
236
237 if (dump_sensor)
238 s5k83a_dump_registers(sd);
239
240 err = s5k83a_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
241 if (err < 0)
242 return err;
243
244 err = s5k83a_set_brightness(&sd->gspca_dev,
245 sensor_settings[BRIGHTNESS_IDX]);
246 if (err < 0)
247 return err;
248
249 err = s5k83a_set_exposure(&sd->gspca_dev,
250 sensor_settings[EXPOSURE_IDX]);
251 if (err < 0)
252 return err;
253
254 err = s5k83a_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
255 if (err < 0)
256 return err;
257
258 err = s5k83a_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
259
260 return err;
261}
262
263static int rotation_thread_function(void *data)
264{
265 struct sd *sd = (struct sd *) data;
266 struct s5k83a_priv *sens_priv = sd->sensor_priv;
267 u8 reg, previous_rotation = 0;
268 __s32 vflip, hflip;
269
270 set_current_state(TASK_INTERRUPTIBLE);
271 while (!schedule_timeout(100)) {
272 if (mutex_lock_interruptible(&sd->gspca_dev.usb_lock))
273 break;
274
275 s5k83a_get_rotation(sd, &reg);
276 if (previous_rotation != reg) {
277 previous_rotation = reg;
278 pr_info("Camera was flipped\n");
279
280 s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
281 s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
282
283 if (reg) {
284 vflip = !vflip;
285 hflip = !hflip;
286 }
287 s5k83a_set_flip_real((struct gspca_dev *) sd,
288 vflip, hflip);
289 }
290
291 mutex_unlock(&sd->gspca_dev.usb_lock);
292 set_current_state(TASK_INTERRUPTIBLE);
293 }
294
295 /* return to "front" flip */
296 if (previous_rotation) {
297 s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
298 s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
299 s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip);
300 }
301
302 sens_priv->rotation_thread = NULL;
303 return 0;
304}
305
306int s5k83a_start(struct sd *sd)
307{
308 int i, err = 0;
309 struct s5k83a_priv *sens_priv = sd->sensor_priv;
310
311 /* Create another thread, polling the GPIO ports of the camera to check
312 if it got rotated. This is how the windows driver does it so we have
313 to assume that there is no better way of accomplishing this */
314 sens_priv->rotation_thread = kthread_create(rotation_thread_function,
315 sd, "rotation thread");
316 wake_up_process(sens_priv->rotation_thread);
317
318 /* Preinit the sensor */
319 for (i = 0; i < ARRAY_SIZE(start_s5k83a) && !err; i++) {
320 u8 data[2] = {start_s5k83a[i][2], start_s5k83a[i][3]};
321 if (start_s5k83a[i][0] == SENSOR)
322 err = m5602_write_sensor(sd, start_s5k83a[i][1],
323 data, 2);
324 else
325 err = m5602_write_bridge(sd, start_s5k83a[i][1],
326 data[0]);
327 }
328 if (err < 0)
329 return err;
330
331 return s5k83a_set_led_indication(sd, 1);
332}
333
334int s5k83a_stop(struct sd *sd)
335{
336 struct s5k83a_priv *sens_priv = sd->sensor_priv;
337
338 if (sens_priv->rotation_thread)
339 kthread_stop(sens_priv->rotation_thread);
340
341 return s5k83a_set_led_indication(sd, 0);
342}
343
344void s5k83a_disconnect(struct sd *sd)
345{
346 struct s5k83a_priv *sens_priv = sd->sensor_priv;
347
348 s5k83a_stop(sd);
349
350 sd->sensor = NULL;
351 kfree(sens_priv->settings);
352 kfree(sens_priv);
353}
354
355static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
356{
357 struct sd *sd = (struct sd *) gspca_dev;
358 struct s5k83a_priv *sens_priv = sd->sensor_priv;
359
360 *val = sens_priv->settings[GAIN_IDX];
361 return 0;
362}
363
364static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
365{
366 int err;
367 u8 data[2];
368 struct sd *sd = (struct sd *) gspca_dev;
369 struct s5k83a_priv *sens_priv = sd->sensor_priv;
370
371 sens_priv->settings[GAIN_IDX] = val;
372
373 data[0] = 0x00;
374 data[1] = 0x20;
375 err = m5602_write_sensor(sd, 0x14, data, 2);
376 if (err < 0)
377 return err;
378
379 data[0] = 0x01;
380 data[1] = 0x00;
381 err = m5602_write_sensor(sd, 0x0d, data, 2);
382 if (err < 0)
383 return err;
384
385 /* FIXME: This is not sane, we need to figure out the composition
386 of these registers */
387 data[0] = val >> 3; /* gain, high 5 bits */
388 data[1] = val >> 1; /* gain, high 7 bits */
389 err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2);
390
391 return err;
392}
393
394static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
395{
396 struct sd *sd = (struct sd *) gspca_dev;
397 struct s5k83a_priv *sens_priv = sd->sensor_priv;
398
399 *val = sens_priv->settings[BRIGHTNESS_IDX];
400 return 0;
401}
402
403static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
404{
405 int err;
406 u8 data[1];
407 struct sd *sd = (struct sd *) gspca_dev;
408 struct s5k83a_priv *sens_priv = sd->sensor_priv;
409
410 sens_priv->settings[BRIGHTNESS_IDX] = val;
411 data[0] = val;
412 err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1);
413 return err;
414}
415
416static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
417{
418 struct sd *sd = (struct sd *) gspca_dev;
419 struct s5k83a_priv *sens_priv = sd->sensor_priv;
420
421 *val = sens_priv->settings[EXPOSURE_IDX];
422 return 0;
423}
424
425static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
426{
427 int err;
428 u8 data[2];
429 struct sd *sd = (struct sd *) gspca_dev;
430 struct s5k83a_priv *sens_priv = sd->sensor_priv;
431
432 sens_priv->settings[EXPOSURE_IDX] = val;
433 data[0] = 0;
434 data[1] = val;
435 err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2);
436 return err;
437}
438
439static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
440{
441 struct sd *sd = (struct sd *) gspca_dev;
442 struct s5k83a_priv *sens_priv = sd->sensor_priv;
443
444 *val = sens_priv->settings[VFLIP_IDX];
445 return 0;
446}
447
448static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
449 __s32 vflip, __s32 hflip)
450{
451 int err;
452 u8 data[1];
453 struct sd *sd = (struct sd *) gspca_dev;
454
455 data[0] = 0x05;
456 err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
457 if (err < 0)
458 return err;
459
460 /* six bit is vflip, seven is hflip */
461 data[0] = S5K83A_FLIP_MASK;
462 data[0] = (vflip) ? data[0] | 0x40 : data[0];
463 data[0] = (hflip) ? data[0] | 0x80 : data[0];
464
465 err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
466 if (err < 0)
467 return err;
468
469 data[0] = (vflip) ? 0x0b : 0x0a;
470 err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1);
471 if (err < 0)
472 return err;
473
474 data[0] = (hflip) ? 0x0a : 0x0b;
475 err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
476 return err;
477}
478
479static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
480{
481 int err;
482 u8 reg;
483 __s32 hflip;
484 struct sd *sd = (struct sd *) gspca_dev;
485 struct s5k83a_priv *sens_priv = sd->sensor_priv;
486
487 sens_priv->settings[VFLIP_IDX] = val;
488
489 s5k83a_get_hflip(gspca_dev, &hflip);
490
491 err = s5k83a_get_rotation(sd, &reg);
492 if (err < 0)
493 return err;
494 if (reg) {
495 val = !val;
496 hflip = !hflip;
497 }
498
499 err = s5k83a_set_flip_real(gspca_dev, val, hflip);
500 return err;
501}
502
503static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
504{
505 struct sd *sd = (struct sd *) gspca_dev;
506 struct s5k83a_priv *sens_priv = sd->sensor_priv;
507
508 *val = sens_priv->settings[HFLIP_IDX];
509 return 0;
510}
511
512static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
513{
514 int err;
515 u8 reg;
516 __s32 vflip;
517 struct sd *sd = (struct sd *) gspca_dev;
518 struct s5k83a_priv *sens_priv = sd->sensor_priv;
519
520 sens_priv->settings[HFLIP_IDX] = val;
521
522 s5k83a_get_vflip(gspca_dev, &vflip);
523
524 err = s5k83a_get_rotation(sd, &reg);
525 if (err < 0)
526 return err;
527 if (reg) {
528 val = !val;
529 vflip = !vflip;
530 }
531
532 err = s5k83a_set_flip_real(gspca_dev, vflip, val);
533 return err;
534}
535
536static int s5k83a_set_led_indication(struct sd *sd, u8 val)
537{
538 int err = 0;
539 u8 data[1];
540
541 err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, data);
542 if (err < 0)
543 return err;
544
545 if (val)
546 data[0] = data[0] | S5K83A_GPIO_LED_MASK;
547 else
548 data[0] = data[0] & ~S5K83A_GPIO_LED_MASK;
549
550 err = m5602_write_bridge(sd, M5602_XB_GPIO_DAT, data[0]);
551
552 return err;
553}
554
555/* Get camera rotation on Acer notebooks */
556static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data)
557{
558 int err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, reg_data);
559 *reg_data = (*reg_data & S5K83A_GPIO_ROTATION_MASK) ? 0 : 1;
560 return err;
561}
562
563static void s5k83a_dump_registers(struct sd *sd)
564{
565 int address;
566 u8 page, old_page;
567 m5602_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
568
569 for (page = 0; page < 16; page++) {
570 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
571 pr_info("Dumping the s5k83a register state for page 0x%x\n",
572 page);
573 for (address = 0; address <= 0xff; address++) {
574 u8 val = 0;
575 m5602_read_sensor(sd, address, &val, 1);
576 pr_info("register 0x%x contains 0x%x\n", address, val);
577 }
578 }
579 pr_info("s5k83a register state dump complete\n");
580
581 for (page = 0; page < 16; page++) {
582 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
583 pr_info("Probing for which registers that are read/write for page 0x%x\n",
584 page);
585 for (address = 0; address <= 0xff; address++) {
586 u8 old_val, ctrl_val, test_val = 0xff;
587
588 m5602_read_sensor(sd, address, &old_val, 1);
589 m5602_write_sensor(sd, address, &test_val, 1);
590 m5602_read_sensor(sd, address, &ctrl_val, 1);
591
592 if (ctrl_val == test_val)
593 pr_info("register 0x%x is writeable\n",
594 address);
595 else
596 pr_info("register 0x%x is read only\n",
597 address);
598
599 /* Restore original val */
600 m5602_write_sensor(sd, address, &old_val, 1);
601 }
602 }
603 pr_info("Read/write register probing complete\n");
604 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
605}
diff --git a/drivers/media/usb/gspca/m5602/m5602_s5k83a.h b/drivers/media/usb/gspca/m5602/m5602_s5k83a.h
new file mode 100644
index 000000000000..79952247b534
--- /dev/null
+++ b/drivers/media/usb/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 bool 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/usb/gspca/m5602/m5602_sensor.h b/drivers/media/usb/gspca/m5602/m5602_sensor.h
new file mode 100644
index 000000000000..edff4f1f586f
--- /dev/null
+++ b/drivers/media/usb/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