]> git.proxmox.com Git - mirror_ubuntu-kernels.git/blame - drivers/media/video/gspca/m5602/m5602_mt9m111.c
Merge branch 'for-linus' of git://git.kernel.dk/linux-2.6-block
[mirror_ubuntu-kernels.git] / drivers / media / video / gspca / m5602 / m5602_mt9m111.c
CommitLineData
c109f816
EA
1/*
2 * Driver for the mt9m111 sensor
3 *
0c505e68 4 * Copyright (C) 2008 Erik Andrén
c109f816
EA
5 * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
6 * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
7 *
8 * Portions of code to USB interface and ALi driver software,
9 * Copyright (c) 2006 Willem Duinker
10 * v4l2 interface modeled after the V4L2 driver
11 * for SN9C10x PC Camera Controllers
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License as
15 * published by the Free Software Foundation, version 2.
16 *
17 */
18
19#include "m5602_mt9m111.h"
20
74cadfe1
EA
21static struct v4l2_pix_format mt9m111_modes[] = {
22 {
23 640,
24 480,
25 V4L2_PIX_FMT_SBGGR8,
26 V4L2_FIELD_NONE,
27 .sizeimage = 640 * 480,
28 .bytesperline = 640,
29 .colorspace = V4L2_COLORSPACE_SRGB,
30 .priv = 0
31 }
32};
33
e17cc08c
EA
34const static struct ctrl mt9m111_ctrls[] = {
35 {
36 {
37 .id = V4L2_CID_VFLIP,
38 .type = V4L2_CTRL_TYPE_BOOLEAN,
39 .name = "vertical flip",
40 .minimum = 0,
41 .maximum = 1,
42 .step = 1,
43 .default_value = 0
44 },
45 .set = mt9m111_set_vflip,
46 .get = mt9m111_get_vflip
47 }, {
48 {
49 .id = V4L2_CID_HFLIP,
50 .type = V4L2_CTRL_TYPE_BOOLEAN,
51 .name = "horizontal flip",
52 .minimum = 0,
53 .maximum = 1,
54 .step = 1,
55 .default_value = 0
56 },
57 .set = mt9m111_set_hflip,
58 .get = mt9m111_get_hflip
59 }, {
60 {
61 .id = V4L2_CID_GAIN,
62 .type = V4L2_CTRL_TYPE_INTEGER,
63 .name = "gain",
64 .minimum = 0,
65 .maximum = (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2,
66 .step = 1,
67 .default_value = DEFAULT_GAIN,
68 .flags = V4L2_CTRL_FLAG_SLIDER
69 },
70 .set = mt9m111_set_gain,
71 .get = mt9m111_get_gain
72 }
73};
74
75
658efb63
EA
76static void mt9m111_dump_registers(struct sd *sd);
77
c109f816
EA
78int mt9m111_probe(struct sd *sd)
79{
80 u8 data[2] = {0x00, 0x00};
81 int i;
82
83 if (force_sensor) {
84 if (force_sensor == MT9M111_SENSOR) {
85 info("Forcing a %s sensor", mt9m111.name);
86 goto sensor_found;
87 }
88 /* If we want to force another sensor, don't try to probe this
89 * one */
90 return -ENODEV;
91 }
92
93 info("Probing for a mt9m111 sensor");
94
95 /* Do the preinit */
96 for (i = 0; i < ARRAY_SIZE(preinit_mt9m111); i++) {
97 if (preinit_mt9m111[i][0] == BRIDGE) {
98 m5602_write_bridge(sd,
99 preinit_mt9m111[i][1],
100 preinit_mt9m111[i][2]);
101 } else {
102 data[0] = preinit_mt9m111[i][2];
103 data[1] = preinit_mt9m111[i][3];
6dc4cff0 104 m5602_write_sensor(sd,
c109f816
EA
105 preinit_mt9m111[i][1], data, 2);
106 }
107 }
108
4f93c450 109 if (m5602_read_sensor(sd, MT9M111_SC_CHIPVER, data, 2))
c109f816
EA
110 return -ENODEV;
111
112 if ((data[0] == 0x14) && (data[1] == 0x3a)) {
113 info("Detected a mt9m111 sensor");
114 goto sensor_found;
115 }
116
117 return -ENODEV;
118
119sensor_found:
74cadfe1
EA
120 sd->gspca_dev.cam.cam_mode = mt9m111_modes;
121 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(mt9m111_modes);
e17cc08c 122 sd->desc->ctrls = mt9m111_ctrls;
e4cc4fcc 123 sd->desc->nctrls = ARRAY_SIZE(mt9m111_ctrls);
c109f816
EA
124 return 0;
125}
126
127int mt9m111_init(struct sd *sd)
128{
f1918fa2 129 int i, err = 0;
c109f816
EA
130
131 /* Init the sensor */
8bcbc911 132 for (i = 0; i < ARRAY_SIZE(init_mt9m111) && !err; i++) {
c109f816
EA
133 u8 data[2];
134
135 if (init_mt9m111[i][0] == BRIDGE) {
136 err = m5602_write_bridge(sd,
137 init_mt9m111[i][1],
138 init_mt9m111[i][2]);
139 } else {
140 data[0] = init_mt9m111[i][2];
141 data[1] = init_mt9m111[i][3];
6dc4cff0 142 err = m5602_write_sensor(sd,
c109f816
EA
143 init_mt9m111[i][1], data, 2);
144 }
145 }
146
147 if (dump_sensor)
148 mt9m111_dump_registers(sd);
149
150 return (err < 0) ? err : 0;
151}
152
153int mt9m111_power_down(struct sd *sd)
154{
155 return 0;
156}
157
158int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
159{
160 int err;
161 u8 data[2] = {0x00, 0x00};
162 struct sd *sd = (struct sd *) gspca_dev;
163
4f93c450 164 err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
c109f816
EA
165 data, 2);
166 *val = data[0] & MT9M111_RMB_MIRROR_ROWS;
17ea88ae 167 PDEBUG(D_V4L2, "Read vertical flip %d", *val);
c109f816 168
8bcbc911 169 return err;
c109f816
EA
170}
171
172int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
173{
174 int err;
175 u8 data[2] = {0x00, 0x00};
176 struct sd *sd = (struct sd *) gspca_dev;
177
17ea88ae 178 PDEBUG(D_V4L2, "Set vertical flip to %d", val);
c109f816
EA
179
180 /* Set the correct page map */
6dc4cff0 181 err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
c109f816 182 if (err < 0)
051781b3 183 return err;
c109f816 184
4f93c450 185 err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
c109f816 186 if (err < 0)
051781b3 187 return err;
c109f816
EA
188
189 data[0] = (data[0] & 0xfe) | val;
6dc4cff0 190 err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
c109f816 191 data, 2);
8bcbc911 192 return err;
c109f816
EA
193}
194
195int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
196{
197 int err;
198 u8 data[2] = {0x00, 0x00};
199 struct sd *sd = (struct sd *) gspca_dev;
200
4f93c450 201 err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
c109f816
EA
202 data, 2);
203 *val = data[0] & MT9M111_RMB_MIRROR_COLS;
17ea88ae 204 PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
c109f816 205
8bcbc911 206 return err;
c109f816
EA
207}
208
209int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
210{
211 int err;
212 u8 data[2] = {0x00, 0x00};
213 struct sd *sd = (struct sd *) gspca_dev;
214
17ea88ae 215 PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
c109f816
EA
216
217 /* Set the correct page map */
6dc4cff0 218 err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
c109f816 219 if (err < 0)
051781b3 220 return err;
c109f816 221
4f93c450 222 err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
c109f816 223 if (err < 0)
051781b3 224 return err;
c109f816
EA
225
226 data[0] = (data[0] & 0xfd) | ((val << 1) & 0x02);
6dc4cff0 227 err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
c109f816 228 data, 2);
8bcbc911 229 return err;
c109f816
EA
230}
231
232int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
233{
234 int err, tmp;
235 u8 data[2] = {0x00, 0x00};
236 struct sd *sd = (struct sd *) gspca_dev;
237
4f93c450 238 err = m5602_read_sensor(sd, MT9M111_SC_GLOBAL_GAIN, data, 2);
c109f816
EA
239 tmp = ((data[1] << 8) | data[0]);
240
241 *val = ((tmp & (1 << 10)) * 2) |
242 ((tmp & (1 << 9)) * 2) |
243 ((tmp & (1 << 8)) * 2) |
244 (tmp & 0x7f);
245
17ea88ae 246 PDEBUG(D_V4L2, "Read gain %d", *val);
c109f816 247
8bcbc911 248 return err;
c109f816
EA
249}
250
251int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
252{
253 int err, tmp;
254 u8 data[2] = {0x00, 0x00};
255 struct sd *sd = (struct sd *) gspca_dev;
256
257 /* Set the correct page map */
6dc4cff0 258 err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
c109f816 259 if (err < 0)
051781b3 260 return err;
c109f816
EA
261
262 if (val >= INITIAL_MAX_GAIN * 2 * 2 * 2)
263 return -EINVAL;
264
265 if ((val >= INITIAL_MAX_GAIN * 2 * 2) &&
266 (val < (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2))
267 tmp = (1 << 10) | (val << 9) |
268 (val << 8) | (val / 8);
269 else if ((val >= INITIAL_MAX_GAIN * 2) &&
270 (val < INITIAL_MAX_GAIN * 2 * 2))
271 tmp = (1 << 9) | (1 << 8) | (val / 4);
272 else if ((val >= INITIAL_MAX_GAIN) &&
273 (val < INITIAL_MAX_GAIN * 2))
274 tmp = (1 << 8) | (val / 2);
275 else
276 tmp = val;
277
278 data[1] = (tmp & 0xff00) >> 8;
279 data[0] = (tmp & 0xff);
17ea88ae 280 PDEBUG(D_V4L2, "tmp=%d, data[1]=%d, data[0]=%d", tmp,
c109f816
EA
281 data[1], data[0]);
282
6dc4cff0 283 err = m5602_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN,
c109f816 284 data, 2);
051781b3 285
8bcbc911 286 return err;
c109f816
EA
287}
288
658efb63 289static void mt9m111_dump_registers(struct sd *sd)
c109f816
EA
290{
291 u8 address, value[2] = {0x00, 0x00};
292
293 info("Dumping the mt9m111 register state");
294
295 info("Dumping the mt9m111 sensor core registers");
296 value[1] = MT9M111_SENSOR_CORE;
6dc4cff0 297 m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
c109f816 298 for (address = 0; address < 0xff; address++) {
4f93c450 299 m5602_read_sensor(sd, address, value, 2);
c109f816
EA
300 info("register 0x%x contains 0x%x%x",
301 address, value[0], value[1]);
302 }
303
304 info("Dumping the mt9m111 color pipeline registers");
305 value[1] = MT9M111_COLORPIPE;
6dc4cff0 306 m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
c109f816 307 for (address = 0; address < 0xff; address++) {
4f93c450 308 m5602_read_sensor(sd, address, value, 2);
c109f816
EA
309 info("register 0x%x contains 0x%x%x",
310 address, value[0], value[1]);
311 }
312
313 info("Dumping the mt9m111 camera control registers");
314 value[1] = MT9M111_CAMERA_CONTROL;
6dc4cff0 315 m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2);
c109f816 316 for (address = 0; address < 0xff; address++) {
4f93c450 317 m5602_read_sensor(sd, address, value, 2);
c109f816
EA
318 info("register 0x%x contains 0x%x%x",
319 address, value[0], value[1]);
320 }
321
322 info("mt9m111 register state dump complete");
323}