Merge branches 'sh/pci-express-integration', 'sh/rsk-updates', 'sh/platform-updates...
[linux-2.6] / 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
24 const static struct ctrl ov7660_ctrls[] = {
25 #define GAIN_IDX 1
26         {
27                 {
28                         .id             = V4L2_CID_GAIN,
29                         .type           = V4L2_CTRL_TYPE_INTEGER,
30                         .name           = "gain",
31                         .minimum        = 0x00,
32                         .maximum        = 0xff,
33                         .step           = 0x1,
34                         .default_value  = OV7660_DEFAULT_GAIN,
35                         .flags          = V4L2_CTRL_FLAG_SLIDER
36                 },
37                 .set = ov7660_set_gain,
38                 .get = ov7660_get_gain
39         },
40 };
41
42 static struct v4l2_pix_format ov7660_modes[] = {
43         {
44                 640,
45                 480,
46                 V4L2_PIX_FMT_SBGGR8,
47                 V4L2_FIELD_NONE,
48                 .sizeimage =
49                         640 * 480,
50                 .bytesperline = 640,
51                 .colorspace = V4L2_COLORSPACE_SRGB,
52                 .priv = 0
53         }
54 };
55
56 static void ov7660_dump_registers(struct sd *sd);
57
58 int ov7660_probe(struct sd *sd)
59 {
60         int err = 0, i;
61         u8 prod_id = 0, ver_id = 0;
62
63         s32 *sensor_settings;
64
65         if (force_sensor) {
66                 if (force_sensor == OV7660_SENSOR) {
67                         info("Forcing an %s sensor", ov7660.name);
68                         goto sensor_found;
69                 }
70                 /* If we want to force another sensor,
71                 don't try to probe this one */
72                 return -ENODEV;
73         }
74
75         /* Do the preinit */
76         for (i = 0; i < ARRAY_SIZE(preinit_ov7660) && !err; i++) {
77                 u8 data[2];
78
79                 if (preinit_ov7660[i][0] == BRIDGE) {
80                         err = m5602_write_bridge(sd,
81                                 preinit_ov7660[i][1],
82                                 preinit_ov7660[i][2]);
83                 } else {
84                         data[0] = preinit_ov7660[i][2];
85                         err = m5602_write_sensor(sd,
86                                 preinit_ov7660[i][1], data, 1);
87                 }
88         }
89         if (err < 0)
90                 return err;
91
92         if (m5602_read_sensor(sd, OV7660_PID, &prod_id, 1))
93                 return -ENODEV;
94
95         if (m5602_read_sensor(sd, OV7660_VER, &ver_id, 1))
96                 return -ENODEV;
97
98         info("Sensor reported 0x%x%x", prod_id, ver_id);
99
100         if ((prod_id == 0x76) && (ver_id == 0x60)) {
101                 info("Detected a ov7660 sensor");
102                 goto sensor_found;
103         }
104         return -ENODEV;
105
106 sensor_found:
107         sensor_settings = kmalloc(
108                 ARRAY_SIZE(ov7660_ctrls) * sizeof(s32), GFP_KERNEL);
109         if (!sensor_settings)
110                 return -ENOMEM;
111
112         sd->gspca_dev.cam.cam_mode = ov7660_modes;
113         sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov7660_modes);
114         sd->desc->ctrls = ov7660_ctrls;
115         sd->desc->nctrls = ARRAY_SIZE(ov7660_ctrls);
116
117         for (i = 0; i < ARRAY_SIZE(ov7660_ctrls); i++)
118                 sensor_settings[i] = ov7660_ctrls[i].qctrl.default_value;
119         sd->sensor_priv = sensor_settings;
120
121         return 0;
122 }
123
124 int ov7660_init(struct sd *sd)
125 {
126         int i, err = 0;
127         s32 *sensor_settings = sd->sensor_priv;
128
129         /* Init the sensor */
130         for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) {
131                 u8 data[2];
132
133                 if (init_ov7660[i][0] == BRIDGE) {
134                         err = m5602_write_bridge(sd,
135                                 init_ov7660[i][1],
136                                 init_ov7660[i][2]);
137                 } else {
138                         data[0] = init_ov7660[i][2];
139                         err = m5602_write_sensor(sd,
140                                         init_ov7660[i][1], data, 1);
141                 }
142         }
143
144         if (dump_sensor)
145                 ov7660_dump_registers(sd);
146
147         err = ov7660_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
148         if (err < 0)
149                 return err;
150
151         return err;
152 }
153
154 int ov7660_start(struct sd *sd)
155 {
156         return 0;
157 }
158
159 int ov7660_stop(struct sd *sd)
160 {
161         return 0;
162 }
163
164 void ov7660_disconnect(struct sd *sd)
165 {
166         ov7660_stop(sd);
167
168         sd->sensor = NULL;
169         kfree(sd->sensor_priv);
170 }
171
172 static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
173 {
174         struct sd *sd = (struct sd *) gspca_dev;
175         s32 *sensor_settings = sd->sensor_priv;
176
177         *val = sensor_settings[GAIN_IDX];
178         PDEBUG(D_V4L2, "Read gain %d", *val);
179         return 0;
180 }
181
182 static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val)
183 {
184         int err;
185         u8 i2c_data;
186         struct sd *sd = (struct sd *) gspca_dev;
187         s32 *sensor_settings = sd->sensor_priv;
188
189         PDEBUG(D_V4L2, "Setting gain to %d", val);
190
191         sensor_settings[GAIN_IDX] = val;
192
193         err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1);
194         return err;
195 }
196
197 static void ov7660_dump_registers(struct sd *sd)
198 {
199         int address;
200         info("Dumping the ov7660 register state");
201         for (address = 0; address < 0xa9; address++) {
202                 u8 value;
203                 m5602_read_sensor(sd, address, &value, 1);
204                 info("register 0x%x contains 0x%x",
205                      address, value);
206         }
207
208         info("ov7660 register state dump complete");
209
210         info("Probing for which registers that are read/write");
211         for (address = 0; address < 0xff; address++) {
212                 u8 old_value, ctrl_value;
213                 u8 test_value[2] = {0xff, 0xff};
214
215                 m5602_read_sensor(sd, address, &old_value, 1);
216                 m5602_write_sensor(sd, address, test_value, 1);
217                 m5602_read_sensor(sd, address, &ctrl_value, 1);
218
219                 if (ctrl_value == test_value[0])
220                         info("register 0x%x is writeable", address);
221                 else
222                         info("register 0x%x is read only", address);
223
224                 /* Restore original value */
225                 m5602_write_sensor(sd, address, &old_value, 1);
226         }
227 }