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