Commit | Line | Data |
---|---|---|
c109f816 EA |
1 | /* |
2 | * Driver for the po1030 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_po1030.h" | |
20 | ||
658efb63 EA |
21 | static void po1030_dump_registers(struct sd *sd); |
22 | ||
c109f816 EA |
23 | int po1030_probe(struct sd *sd) |
24 | { | |
25 | u8 prod_id = 0, ver_id = 0, i; | |
26 | ||
27 | if (force_sensor) { | |
28 | if (force_sensor == PO1030_SENSOR) { | |
29 | info("Forcing a %s sensor", po1030.name); | |
30 | goto sensor_found; | |
31 | } | |
32 | /* If we want to force another sensor, don't try to probe this | |
33 | * one */ | |
34 | return -ENODEV; | |
35 | } | |
36 | ||
37 | info("Probing for a po1030 sensor"); | |
38 | ||
39 | /* Run the pre-init to actually probe the unit */ | |
40 | for (i = 0; i < ARRAY_SIZE(preinit_po1030); i++) { | |
41 | u8 data = preinit_po1030[i][2]; | |
42 | if (preinit_po1030[i][0] == SENSOR) | |
6dc4cff0 | 43 | m5602_write_sensor(sd, |
c109f816 EA |
44 | preinit_po1030[i][1], &data, 1); |
45 | else | |
46 | m5602_write_bridge(sd, preinit_po1030[i][1], data); | |
47 | } | |
48 | ||
c061c97e | 49 | if (m5602_read_sensor(sd, 0x3, &prod_id, 1)) |
c109f816 EA |
50 | return -ENODEV; |
51 | ||
c061c97e | 52 | if (m5602_read_sensor(sd, 0x4, &ver_id, 1)) |
c109f816 EA |
53 | return -ENODEV; |
54 | ||
55 | if ((prod_id == 0x02) && (ver_id == 0xef)) { | |
56 | info("Detected a po1030 sensor"); | |
57 | goto sensor_found; | |
58 | } | |
59 | return -ENODEV; | |
60 | ||
61 | sensor_found: | |
62 | sd->gspca_dev.cam.cam_mode = po1030.modes; | |
63 | sd->gspca_dev.cam.nmodes = po1030.nmodes; | |
d2d7e9ae EA |
64 | sd->desc->ctrls = po1030.ctrls; |
65 | sd->desc->nctrls = po1030.nctrls; | |
c109f816 EA |
66 | return 0; |
67 | } | |
68 | ||
c109f816 EA |
69 | int po1030_init(struct sd *sd) |
70 | { | |
71 | int i, err = 0; | |
72 | ||
73 | /* Init the sensor */ | |
7b9f2467 | 74 | for (i = 0; i < ARRAY_SIZE(init_po1030) && !err; i++) { |
c109f816 EA |
75 | u8 data[2] = {0x00, 0x00}; |
76 | ||
77 | switch (init_po1030[i][0]) { | |
78 | case BRIDGE: | |
79 | err = m5602_write_bridge(sd, | |
80 | init_po1030[i][1], | |
81 | init_po1030[i][2]); | |
82 | break; | |
83 | ||
84 | case SENSOR: | |
85 | data[0] = init_po1030[i][2]; | |
6dc4cff0 | 86 | err = m5602_write_sensor(sd, |
c109f816 EA |
87 | init_po1030[i][1], data, 1); |
88 | break; | |
89 | ||
90 | case SENSOR_LONG: | |
91 | data[0] = init_po1030[i][2]; | |
92 | data[1] = init_po1030[i][3]; | |
6dc4cff0 | 93 | err = m5602_write_sensor(sd, |
c109f816 EA |
94 | init_po1030[i][1], data, 2); |
95 | break; | |
96 | default: | |
97 | info("Invalid stream command, exiting init"); | |
98 | return -EINVAL; | |
99 | } | |
100 | } | |
101 | ||
102 | if (dump_sensor) | |
103 | po1030_dump_registers(sd); | |
104 | ||
7b9f2467 | 105 | return err; |
c109f816 EA |
106 | } |
107 | ||
108 | int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) | |
109 | { | |
110 | struct sd *sd = (struct sd *) gspca_dev; | |
111 | u8 i2c_data; | |
112 | int err; | |
113 | ||
c061c97e | 114 | err = m5602_read_sensor(sd, PO1030_REG_INTEGLINES_H, |
c109f816 EA |
115 | &i2c_data, 1); |
116 | if (err < 0) | |
117 | goto out; | |
118 | *val = (i2c_data << 8); | |
119 | ||
c061c97e | 120 | err = m5602_read_sensor(sd, PO1030_REG_INTEGLINES_M, |
c109f816 EA |
121 | &i2c_data, 1); |
122 | *val |= i2c_data; | |
123 | ||
17ea88ae | 124 | PDEBUG(D_V4L2, "Exposure read as %d", *val); |
c109f816 | 125 | out: |
7b9f2467 | 126 | return err; |
c109f816 EA |
127 | } |
128 | ||
129 | int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val) | |
130 | { | |
131 | struct sd *sd = (struct sd *) gspca_dev; | |
132 | u8 i2c_data; | |
133 | int err; | |
134 | ||
17ea88ae | 135 | PDEBUG(D_V4L2, "Set exposure to %d", val & 0xffff); |
c109f816 EA |
136 | |
137 | i2c_data = ((val & 0xff00) >> 8); | |
17ea88ae | 138 | PDEBUG(D_V4L2, "Set exposure to high byte to 0x%x", |
c109f816 EA |
139 | i2c_data); |
140 | ||
6dc4cff0 | 141 | err = m5602_write_sensor(sd, PO1030_REG_INTEGLINES_H, |
c109f816 EA |
142 | &i2c_data, 1); |
143 | if (err < 0) | |
144 | goto out; | |
145 | ||
146 | i2c_data = (val & 0xff); | |
17ea88ae | 147 | PDEBUG(D_V4L2, "Set exposure to low byte to 0x%x", |
c109f816 | 148 | i2c_data); |
6dc4cff0 | 149 | err = m5602_write_sensor(sd, PO1030_REG_INTEGLINES_M, |
c109f816 EA |
150 | &i2c_data, 1); |
151 | ||
152 | out: | |
7b9f2467 | 153 | return err; |
c109f816 EA |
154 | } |
155 | ||
156 | int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val) | |
157 | { | |
158 | struct sd *sd = (struct sd *) gspca_dev; | |
159 | u8 i2c_data; | |
160 | int err; | |
161 | ||
c061c97e | 162 | err = m5602_read_sensor(sd, PO1030_REG_GLOBALGAIN, |
c109f816 EA |
163 | &i2c_data, 1); |
164 | *val = i2c_data; | |
17ea88ae | 165 | PDEBUG(D_V4L2, "Read global gain %d", *val); |
c109f816 | 166 | |
7b9f2467 | 167 | return err; |
c109f816 EA |
168 | } |
169 | ||
e2c97491 EA |
170 | int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) |
171 | { | |
172 | struct sd *sd = (struct sd *) gspca_dev; | |
173 | u8 i2c_data; | |
174 | int err; | |
175 | ||
c061c97e | 176 | err = m5602_read_sensor(sd, PO1030_REG_CONTROL2, |
e2c97491 EA |
177 | &i2c_data, 1); |
178 | ||
179 | *val = (i2c_data >> 7) & 0x01 ; | |
180 | ||
181 | PDEBUG(D_V4L2, "Read hflip %d", *val); | |
182 | ||
7b9f2467 | 183 | return err; |
e2c97491 EA |
184 | } |
185 | ||
186 | int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val) | |
187 | { | |
188 | struct sd *sd = (struct sd *) gspca_dev; | |
189 | u8 i2c_data; | |
190 | int err; | |
191 | ||
192 | PDEBUG(D_V4L2, "Set hflip %d", val); | |
193 | ||
194 | i2c_data = (val & 0x01) << 7; | |
195 | ||
6dc4cff0 | 196 | err = m5602_write_sensor(sd, PO1030_REG_CONTROL2, |
e2c97491 EA |
197 | &i2c_data, 1); |
198 | ||
7b9f2467 | 199 | return err; |
e2c97491 EA |
200 | } |
201 | ||
202 | int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) | |
203 | { | |
204 | struct sd *sd = (struct sd *) gspca_dev; | |
205 | u8 i2c_data; | |
206 | int err; | |
207 | ||
c061c97e | 208 | err = m5602_read_sensor(sd, PO1030_REG_GLOBALGAIN, |
e2c97491 EA |
209 | &i2c_data, 1); |
210 | ||
211 | *val = (i2c_data >> 6) & 0x01; | |
212 | ||
213 | PDEBUG(D_V4L2, "Read vflip %d", *val); | |
214 | ||
7b9f2467 | 215 | return err; |
e2c97491 EA |
216 | } |
217 | ||
218 | int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val) | |
219 | { | |
220 | struct sd *sd = (struct sd *) gspca_dev; | |
221 | u8 i2c_data; | |
222 | int err; | |
223 | ||
224 | PDEBUG(D_V4L2, "Set vflip %d", val); | |
225 | ||
226 | i2c_data = (val & 0x01) << 6; | |
227 | ||
6dc4cff0 | 228 | err = m5602_write_sensor(sd, PO1030_REG_CONTROL2, |
e2c97491 EA |
229 | &i2c_data, 1); |
230 | ||
7b9f2467 | 231 | return err; |
e2c97491 EA |
232 | } |
233 | ||
c109f816 EA |
234 | int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val) |
235 | { | |
236 | struct sd *sd = (struct sd *) gspca_dev; | |
237 | u8 i2c_data; | |
238 | int err; | |
239 | ||
240 | i2c_data = val & 0xff; | |
17ea88ae | 241 | PDEBUG(D_V4L2, "Set global gain to %d", i2c_data); |
6dc4cff0 | 242 | err = m5602_write_sensor(sd, PO1030_REG_GLOBALGAIN, |
c109f816 | 243 | &i2c_data, 1); |
7b9f2467 | 244 | return err; |
c109f816 EA |
245 | } |
246 | ||
247 | int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) | |
248 | { | |
249 | struct sd *sd = (struct sd *) gspca_dev; | |
250 | u8 i2c_data; | |
251 | int err; | |
252 | ||
c061c97e | 253 | err = m5602_read_sensor(sd, PO1030_REG_RED_GAIN, |
c109f816 EA |
254 | &i2c_data, 1); |
255 | *val = i2c_data; | |
17ea88ae | 256 | PDEBUG(D_V4L2, "Read red gain %d", *val); |
7b9f2467 | 257 | return err; |
c109f816 EA |
258 | } |
259 | ||
260 | int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) | |
261 | { | |
262 | struct sd *sd = (struct sd *) gspca_dev; | |
263 | u8 i2c_data; | |
264 | int err; | |
265 | ||
266 | i2c_data = val & 0xff; | |
17ea88ae | 267 | PDEBUG(D_V4L2, "Set red gain to %d", i2c_data); |
6dc4cff0 | 268 | err = m5602_write_sensor(sd, PO1030_REG_RED_GAIN, |
c109f816 | 269 | &i2c_data, 1); |
7b9f2467 | 270 | return err; |
c109f816 EA |
271 | } |
272 | ||
273 | int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) | |
274 | { | |
275 | struct sd *sd = (struct sd *) gspca_dev; | |
276 | u8 i2c_data; | |
277 | int err; | |
278 | ||
c061c97e | 279 | err = m5602_read_sensor(sd, PO1030_REG_BLUE_GAIN, |
c109f816 EA |
280 | &i2c_data, 1); |
281 | *val = i2c_data; | |
17ea88ae | 282 | PDEBUG(D_V4L2, "Read blue gain %d", *val); |
c109f816 | 283 | |
7b9f2467 | 284 | return err; |
c109f816 EA |
285 | } |
286 | ||
287 | int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) | |
288 | { | |
289 | struct sd *sd = (struct sd *) gspca_dev; | |
290 | u8 i2c_data; | |
291 | int err; | |
292 | i2c_data = val & 0xff; | |
17ea88ae | 293 | PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data); |
6dc4cff0 | 294 | err = m5602_write_sensor(sd, PO1030_REG_BLUE_GAIN, |
c109f816 EA |
295 | &i2c_data, 1); |
296 | ||
7b9f2467 | 297 | return err; |
c109f816 EA |
298 | } |
299 | ||
300 | int po1030_power_down(struct sd *sd) | |
301 | { | |
302 | return 0; | |
303 | } | |
304 | ||
658efb63 | 305 | static void po1030_dump_registers(struct sd *sd) |
c109f816 EA |
306 | { |
307 | int address; | |
308 | u8 value = 0; | |
309 | ||
310 | info("Dumping the po1030 sensor core registers"); | |
311 | for (address = 0; address < 0x7f; address++) { | |
c061c97e | 312 | m5602_read_sensor(sd, address, &value, 1); |
c109f816 EA |
313 | info("register 0x%x contains 0x%x", |
314 | address, value); | |
315 | } | |
316 | ||
317 | info("po1030 register state dump complete"); | |
318 | ||
319 | info("Probing for which registers that are read/write"); | |
320 | for (address = 0; address < 0xff; address++) { | |
321 | u8 old_value, ctrl_value; | |
322 | u8 test_value[2] = {0xff, 0xff}; | |
323 | ||
c061c97e | 324 | m5602_read_sensor(sd, address, &old_value, 1); |
6dc4cff0 | 325 | m5602_write_sensor(sd, address, test_value, 1); |
c061c97e | 326 | m5602_read_sensor(sd, address, &ctrl_value, 1); |
c109f816 EA |
327 | |
328 | if (ctrl_value == test_value[0]) | |
329 | info("register 0x%x is writeable", address); | |
330 | else | |
331 | info("register 0x%x is read only", address); | |
332 | ||
333 | /* Restore original value */ | |
6dc4cff0 | 334 | m5602_write_sensor(sd, address, &old_value, 1); |
c109f816 EA |
335 | } |
336 | } |