V4L/DVB (12977): gspca - m5602-ov7660: Create blue gain control
[sfrench/cifs-2.6.git] / drivers / media / video / gspca / m5602 / m5602_ov7660.c
1 /*
2  * Driver for the ov7660 sensor
3  *
4  * Copyright (C) 2009 Erik AndrĂ©n
5  * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
6  * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
7  *
8  * Portions of code to USB interface and ALi driver software,
9  * Copyright (c) 2006 Willem Duinker
10  * v4l2 interface modeled after the V4L2 driver
11  * for SN9C10x PC Camera Controllers
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License as
15  * published by the Free Software Foundation, version 2.
16  *
17  */
18
19 #include "m5602_ov7660.h"
20
21 static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
22 static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val);
23 static int ov7660_get_blue_gain(struct gspca_dev *gspca_dev, __s32 *val);
24 static int ov7660_set_blue_gain(struct gspca_dev *gspca_dev, __s32 val);
25
26 const static struct ctrl ov7660_ctrls[] = {
27 #define GAIN_IDX 1
28         {
29                 {
30                         .id             = V4L2_CID_GAIN,
31                         .type           = V4L2_CTRL_TYPE_INTEGER,
32                         .name           = "gain",
33                         .minimum        = 0x00,
34                         .maximum        = 0xff,
35                         .step           = 0x1,
36                         .default_value  = OV7660_DEFAULT_GAIN,
37                         .flags          = V4L2_CTRL_FLAG_SLIDER
38                 },
39                 .set = ov7660_set_gain,
40                 .get = ov7660_get_gain
41         },
42 #define BLUE_BALANCE_IDX 2
43         {
44                 {
45                         .id             = V4L2_CID_BLUE_BALANCE,
46                         .type           = V4L2_CTRL_TYPE_INTEGER,
47                         .name           = "blue balance",
48                         .minimum        = 0x00,
49                         .maximum        = 0x7f,
50                         .step           = 0x1,
51                         .default_value  = OV7660_DEFAULT_BLUE_GAIN,
52                         .flags          = V4L2_CTRL_FLAG_SLIDER
53                 },
54                 .set = ov7660_set_blue_gain,
55                 .get = ov7660_get_blue_gain
56         },
57
58 };
59
60 static struct v4l2_pix_format ov7660_modes[] = {
61         {
62                 640,
63                 480,
64                 V4L2_PIX_FMT_SBGGR8,
65                 V4L2_FIELD_NONE,
66                 .sizeimage =
67                         640 * 480,
68                 .bytesperline = 640,
69                 .colorspace = V4L2_COLORSPACE_SRGB,
70                 .priv = 0
71         }
72 };
73
74 static void ov7660_dump_registers(struct sd *sd);
75
76 int ov7660_probe(struct sd *sd)
77 {
78         int err = 0, i;
79         u8 prod_id = 0, ver_id = 0;
80
81         s32 *sensor_settings;
82
83         if (force_sensor) {
84                 if (force_sensor == OV7660_SENSOR) {
85                         info("Forcing an %s sensor", ov7660.name);
86                         goto sensor_found;
87                 }
88                 /* If we want to force another sensor,
89                 don't try to probe this one */
90                 return -ENODEV;
91         }
92
93         /* Do the preinit */
94         for (i = 0; i < ARRAY_SIZE(preinit_ov7660) && !err; i++) {
95                 u8 data[2];
96
97                 if (preinit_ov7660[i][0] == BRIDGE) {
98                         err = m5602_write_bridge(sd,
99                                 preinit_ov7660[i][1],
100                                 preinit_ov7660[i][2]);
101                 } else {
102                         data[0] = preinit_ov7660[i][2];
103                         err = m5602_write_sensor(sd,
104                                 preinit_ov7660[i][1], data, 1);
105                 }
106         }
107         if (err < 0)
108                 return err;
109
110         if (m5602_read_sensor(sd, OV7660_PID, &prod_id, 1))
111                 return -ENODEV;
112
113         if (m5602_read_sensor(sd, OV7660_VER, &ver_id, 1))
114                 return -ENODEV;
115
116         info("Sensor reported 0x%x%x", prod_id, ver_id);
117
118         if ((prod_id == 0x76) && (ver_id == 0x60)) {
119                 info("Detected a ov7660 sensor");
120                 goto sensor_found;
121         }
122         return -ENODEV;
123
124 sensor_found:
125         sensor_settings = kmalloc(
126                 ARRAY_SIZE(ov7660_ctrls) * sizeof(s32), GFP_KERNEL);
127         if (!sensor_settings)
128                 return -ENOMEM;
129
130         sd->gspca_dev.cam.cam_mode = ov7660_modes;
131         sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov7660_modes);
132         sd->desc->ctrls = ov7660_ctrls;
133         sd->desc->nctrls = ARRAY_SIZE(ov7660_ctrls);
134
135         for (i = 0; i < ARRAY_SIZE(ov7660_ctrls); i++)
136                 sensor_settings[i] = ov7660_ctrls[i].qctrl.default_value;
137         sd->sensor_priv = sensor_settings;
138
139         return 0;
140 }
141
142 int ov7660_init(struct sd *sd)
143 {
144         int i, err = 0;
145         s32 *sensor_settings = sd->sensor_priv;
146
147         /* Init the sensor */
148         for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) {
149                 u8 data[2];
150
151                 if (init_ov7660[i][0] == BRIDGE) {
152                         err = m5602_write_bridge(sd,
153                                 init_ov7660[i][1],
154                                 init_ov7660[i][2]);
155                 } else {
156                         data[0] = init_ov7660[i][2];
157                         err = m5602_write_sensor(sd,
158                                         init_ov7660[i][1], data, 1);
159                 }
160         }
161
162         if (dump_sensor)
163                 ov7660_dump_registers(sd);
164
165         err = ov7660_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
166         if (err < 0)
167                 return err;
168
169         return err;
170 }
171
172 int ov7660_start(struct sd *sd)
173 {
174         return 0;
175 }
176
177 int ov7660_stop(struct sd *sd)
178 {
179         return 0;
180 }
181
182 void ov7660_disconnect(struct sd *sd)
183 {
184         ov7660_stop(sd);
185
186         sd->sensor = NULL;
187         kfree(sd->sensor_priv);
188 }
189
190 static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
191 {
192         struct sd *sd = (struct sd *) gspca_dev;
193         s32 *sensor_settings = sd->sensor_priv;
194
195         *val = sensor_settings[GAIN_IDX];
196         PDEBUG(D_V4L2, "Read gain %d", *val);
197         return 0;
198 }
199
200 static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val)
201 {
202         int err;
203         u8 i2c_data;
204         struct sd *sd = (struct sd *) gspca_dev;
205         s32 *sensor_settings = sd->sensor_priv;
206
207         PDEBUG(D_V4L2, "Setting gain to %d", val);
208
209         sensor_settings[GAIN_IDX] = val;
210
211         err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1);
212         return err;
213 }
214
215 static int ov7660_get_blue_gain(struct gspca_dev *gspca_dev, __s32 *val)
216 {
217         struct sd *sd = (struct sd *) gspca_dev;
218         s32 *sensor_settings = sd->sensor_priv;
219
220         *val = sensor_settings[BLUE_BALANCE_IDX];
221         PDEBUG(D_V4L2, "Read blue balance %d", *val);
222         return 0;
223 }
224
225 static int ov7660_set_blue_gain(struct gspca_dev *gspca_dev, __s32 val)
226 {
227         int err;
228         u8 i2c_data;
229         struct sd *sd = (struct sd *) gspca_dev;
230         s32 *sensor_settings = sd->sensor_priv;
231
232         PDEBUG(D_V4L2, "Setting blue balance to %d", val);
233
234         sensor_settings[BLUE_BALANCE_IDX] = val;
235
236         err = m5602_write_sensor(sd, OV7660_BLUE_GAIN, &i2c_data, 1);
237         return err;
238 }
239
240 static void ov7660_dump_registers(struct sd *sd)
241 {
242         int address;
243         info("Dumping the ov7660 register state");
244         for (address = 0; address < 0xa9; address++) {
245                 u8 value;
246                 m5602_read_sensor(sd, address, &value, 1);
247                 info("register 0x%x contains 0x%x",
248                      address, value);
249         }
250
251         info("ov7660 register state dump complete");
252
253         info("Probing for which registers that are read/write");
254         for (address = 0; address < 0xff; address++) {
255                 u8 old_value, ctrl_value;
256                 u8 test_value[2] = {0xff, 0xff};
257
258                 m5602_read_sensor(sd, address, &old_value, 1);
259                 m5602_write_sensor(sd, address, test_value, 1);
260                 m5602_read_sensor(sd, address, &ctrl_value, 1);
261
262                 if (ctrl_value == test_value[0])
263                         info("register 0x%x is writeable", address);
264                 else
265                         info("register 0x%x is read only", address);
266
267                 /* Restore original value */
268                 m5602_write_sensor(sd, address, &old_value, 1);
269         }
270 }