aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLuk?? Karas <lukas.karas@centrum.cz>2009-04-03 01:45:56 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-06-16 17:20:23 -0400
commitac3d5bfecc362a91f38ad864f5d34c639f894214 (patch)
tree52f900200e2d5397a96c6f7baabb3d54f710e4d4 /drivers
parent04f15655f6cd99ba7d7c9ef8f969a71061a1fbac (diff)
V4L/DVB (11451): gspca - m5602-s5k83a: Add rotation, ctrl cache. Rename some ctrls.
s5k83a sensor mounted on many acer laptops have a swiwel allowing it to be rotated. When the camera is in its rotated state, the image needs to be flipped. The only way to check for if the camera has been flipped is to continously poll a register in the m5602. This patch creates a kernel thread which does this. This patch renames some v4l2 ctrls and finally implements a cache in order to prevent unnecessary sensor reads. Signed-off-by: Luk?? Karas <lukas.karas@centrum.cz> Signed-off-by: Erik Andr?n <erik.andren@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/video/gspca/m5602/m5602_core.c18
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k83a.c389
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k83a.h67
3 files changed, 294 insertions, 180 deletions
diff --git a/drivers/media/video/gspca/m5602/m5602_core.c b/drivers/media/video/gspca/m5602/m5602_core.c
index 1aac2985fee6..93302f31aa6f 100644
--- a/drivers/media/video/gspca/m5602/m5602_core.c
+++ b/drivers/media/video/gspca/m5602/m5602_core.c
@@ -80,6 +80,16 @@ int m5602_write_bridge(struct sd *sd, u8 address, u8 i2c_data)
80 return (err < 0) ? err : 0; 80 return (err < 0) ? err : 0;
81} 81}
82 82
83int m5602_wait_for_i2c(struct sd *sd)
84{
85 int err;
86 u8 data;
87 do {
88 err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, &data);
89 } while ((data & I2C_BUSY) && !err);
90 return (err < 0) ? err : 0;
91}
92
83int m5602_read_sensor(struct sd *sd, const u8 address, 93int m5602_read_sensor(struct sd *sd, const u8 address,
84 u8 *i2c_data, const u8 len) 94 u8 *i2c_data, const u8 len)
85{ 95{
@@ -88,9 +98,7 @@ int m5602_read_sensor(struct sd *sd, const u8 address,
88 if (!len || len > sd->sensor->i2c_regW) 98 if (!len || len > sd->sensor->i2c_regW)
89 return -EINVAL; 99 return -EINVAL;
90 100
91 do { 101 err = m5602_wait_for_i2c(sd);
92 err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
93 } while ((*i2c_data & I2C_BUSY) && !err);
94 if (err < 0) 102 if (err < 0)
95 return err; 103 return err;
96 104
@@ -118,6 +126,10 @@ int m5602_read_sensor(struct sd *sd, const u8 address,
118 } 126 }
119 127
120 for (i = 0; (i < len) && !err; i++) { 128 for (i = 0; (i < len) && !err; i++) {
129 err = m5602_wait_for_i2c(sd);
130 if (err < 0)
131 return err;
132
121 err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i])); 133 err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
122 134
123 PDEBUG(D_CONF, "Reading sensor register " 135 PDEBUG(D_CONF, "Reading sensor register "
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.c b/drivers/media/video/gspca/m5602/m5602_s5k83a.c
index 42c86aa4dc8d..c77afcab179e 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k83a.c
+++ b/drivers/media/video/gspca/m5602/m5602_s5k83a.c
@@ -16,6 +16,7 @@
16 * 16 *
17 */ 17 */
18 18
19#include <linux/kthread.h>
19#include "m5602_s5k83a.h" 20#include "m5602_s5k83a.h"
20 21
21static struct v4l2_pix_format s5k83a_modes[] = { 22static struct v4l2_pix_format s5k83a_modes[] = {
@@ -33,47 +34,54 @@ static struct v4l2_pix_format s5k83a_modes[] = {
33}; 34};
34 35
35const static struct ctrl s5k83a_ctrls[] = { 36const static struct ctrl s5k83a_ctrls[] = {
37#define GAIN_IDX 0
36 { 38 {
37 { 39 {
38 .id = V4L2_CID_BRIGHTNESS, 40 .id = V4L2_CID_GAIN,
39 .type = V4L2_CTRL_TYPE_INTEGER, 41 .type = V4L2_CTRL_TYPE_INTEGER,
40 .name = "brightness", 42 .name = "gain",
41 .minimum = 0x00, 43 .minimum = 0x00,
42 .maximum = 0xff, 44 .maximum = 0xff,
43 .step = 0x01, 45 .step = 0x01,
44 .default_value = S5K83A_DEFAULT_BRIGHTNESS, 46 .default_value = S5K83A_DEFAULT_GAIN,
45 .flags = V4L2_CTRL_FLAG_SLIDER 47 .flags = V4L2_CTRL_FLAG_SLIDER
46 }, 48 },
47 .set = s5k83a_set_brightness, 49 .set = s5k83a_set_gain,
48 .get = s5k83a_get_brightness 50 .get = s5k83a_get_gain
49 51
50 }, { 52 },
53#define BRIGHTNESS_IDX 1
54 {
51 { 55 {
52 .id = V4L2_CID_WHITENESS, 56 .id = V4L2_CID_BRIGHTNESS,
53 .type = V4L2_CTRL_TYPE_INTEGER, 57 .type = V4L2_CTRL_TYPE_INTEGER,
54 .name = "whiteness", 58 .name = "brightness",
55 .minimum = 0x00, 59 .minimum = 0x00,
56 .maximum = 0xff, 60 .maximum = 0xff,
57 .step = 0x01, 61 .step = 0x01,
58 .default_value = S5K83A_DEFAULT_WHITENESS, 62 .default_value = S5K83A_DEFAULT_BRIGHTNESS,
59 .flags = V4L2_CTRL_FLAG_SLIDER 63 .flags = V4L2_CTRL_FLAG_SLIDER
60 }, 64 },
61 .set = s5k83a_set_whiteness, 65 .set = s5k83a_set_brightness,
62 .get = s5k83a_get_whiteness, 66 .get = s5k83a_get_brightness,
63 }, { 67 },
68#define EXPOSURE_IDX 2
69 {
64 { 70 {
65 .id = V4L2_CID_GAIN, 71 .id = V4L2_CID_EXPOSURE,
66 .type = V4L2_CTRL_TYPE_INTEGER, 72 .type = V4L2_CTRL_TYPE_INTEGER,
67 .name = "gain", 73 .name = "exposure",
68 .minimum = 0x00, 74 .minimum = 0x00,
69 .maximum = S5K83A_MAXIMUM_GAIN, 75 .maximum = S5K83A_MAXIMUM_EXPOSURE,
70 .step = 0x01, 76 .step = 0x01,
71 .default_value = S5K83A_DEFAULT_GAIN, 77 .default_value = S5K83A_DEFAULT_EXPOSURE,
72 .flags = V4L2_CTRL_FLAG_SLIDER 78 .flags = V4L2_CTRL_FLAG_SLIDER
73 }, 79 },
74 .set = s5k83a_set_gain, 80 .set = s5k83a_set_exposure,
75 .get = s5k83a_get_gain 81 .get = s5k83a_get_exposure
76 }, { 82 },
83#define HFLIP_IDX 3
84 {
77 { 85 {
78 .id = V4L2_CID_HFLIP, 86 .id = V4L2_CID_HFLIP,
79 .type = V4L2_CTRL_TYPE_BOOLEAN, 87 .type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -85,7 +93,9 @@ const static struct ctrl s5k83a_ctrls[] = {
85 }, 93 },
86 .set = s5k83a_set_hflip, 94 .set = s5k83a_set_hflip,
87 .get = s5k83a_get_hflip 95 .get = s5k83a_get_hflip
88 }, { 96 },
97#define VFLIP_IDX 4
98 {
89 { 99 {
90 .id = V4L2_CID_VFLIP, 100 .id = V4L2_CID_VFLIP,
91 .type = V4L2_CTRL_TYPE_BOOLEAN, 101 .type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -101,9 +111,13 @@ const static struct ctrl s5k83a_ctrls[] = {
101}; 111};
102 112
103static void s5k83a_dump_registers(struct sd *sd); 113static void s5k83a_dump_registers(struct sd *sd);
114static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data);
115static int s5k83a_set_led_indication(struct sd *sd, u8 val);
116int s5k83a_set_flip_real(struct gspca_dev *gspca_dev, __s32 vflip, __s32 hflip);
104 117
105int s5k83a_probe(struct sd *sd) 118int s5k83a_probe(struct sd *sd)
106{ 119{
120 struct s5k83a_priv *sens_priv;
107 u8 prod_id = 0, ver_id = 0; 121 u8 prod_id = 0, ver_id = 0;
108 int i, err = 0; 122 int i, err = 0;
109 123
@@ -145,10 +159,28 @@ int s5k83a_probe(struct sd *sd)
145 info("Detected a s5k83a sensor"); 159 info("Detected a s5k83a sensor");
146 160
147sensor_found: 161sensor_found:
162 sens_priv = kmalloc(
163 sizeof(struct s5k83a_priv), GFP_KERNEL);
164 if (!sens_priv)
165 return -ENOMEM;
166
167 sens_priv->settings =
168 kmalloc(sizeof(s32)*ARRAY_SIZE(s5k83a_ctrls), GFP_KERNEL);
169 if (!sens_priv->settings)
170 return -ENOMEM;
171
148 sd->gspca_dev.cam.cam_mode = s5k83a_modes; 172 sd->gspca_dev.cam.cam_mode = s5k83a_modes;
149 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes); 173 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes);
150 sd->desc->ctrls = s5k83a_ctrls; 174 sd->desc->ctrls = s5k83a_ctrls;
151 sd->desc->nctrls = ARRAY_SIZE(s5k83a_ctrls); 175 sd->desc->nctrls = ARRAY_SIZE(s5k83a_ctrls);
176
177 /* null the pointer! thread is't running now */
178 sens_priv->rotation_thread = NULL;
179
180 for (i = 0; i < ARRAY_SIZE(s5k83a_ctrls); i++)
181 sens_priv->settings[i] = s5k83a_ctrls[i].qctrl.default_value;
182
183 sd->sensor_priv = sens_priv;
152 return 0; 184 return 0;
153} 185}
154 186
@@ -190,84 +222,104 @@ int s5k83a_init(struct sd *sd)
190 return (err < 0) ? err : 0; 222 return (err < 0) ? err : 0;
191} 223}
192 224
225static int rotation_thread_function(void *data)
226{
227 struct sd *sd = (struct sd *) data;
228 struct s5k83a_priv *sens_priv = sd->sensor_priv;
229 u8 reg, previous_rotation = 0;
230 __s32 vflip, hflip;
231
232 set_current_state(TASK_INTERRUPTIBLE);
233 while (!schedule_timeout(100)) {
234 if (mutex_lock_interruptible(&sd->gspca_dev.usb_lock))
235 break;
236
237 s5k83a_get_rotation(sd, &reg);
238 if (previous_rotation != reg) {
239 previous_rotation = reg;
240 info("Camera was flipped");
241
242 s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
243 s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
244
245 if (reg) {
246 vflip = !vflip;
247 hflip = !hflip;
248 }
249 s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip);
250 }
251
252 mutex_unlock(&sd->gspca_dev.usb_lock);
253 set_current_state(TASK_INTERRUPTIBLE);
254 }
255
256 /* return to "front" flip */
257 if (previous_rotation) {
258 s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
259 s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
260 s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip);
261 }
262
263 sens_priv->rotation_thread = NULL;
264 return 0;
265}
266
193int s5k83a_start(struct sd *sd) 267int s5k83a_start(struct sd *sd)
194{ 268{
269 struct s5k83a_priv *sens_priv = sd->sensor_priv;
270
271 /* Create another thread, polling the GPIO ports of the camera to check
272 if it got rotated. This is how the windows driver does it so we have
273 to assume that there is no better way of accomplishing this */
274 sens_priv->rotation_thread = kthread_create(rotation_thread_function, sd, "rotation thread");
275 wake_up_process(sens_priv->rotation_thread);
276
195 return s5k83a_set_led_indication(sd, 1); 277 return s5k83a_set_led_indication(sd, 1);
196} 278}
197 279
198int s5k83a_stop(struct sd *sd) 280int s5k83a_stop(struct sd *sd)
199{ 281{
282 struct s5k83a_priv *sens_priv = sd->sensor_priv;
283
284 if (sens_priv->rotation_thread)
285 kthread_stop(sens_priv->rotation_thread);
286
200 return s5k83a_set_led_indication(sd, 0); 287 return s5k83a_set_led_indication(sd, 0);
201} 288}
202 289
203int s5k83a_power_down(struct sd *sd) 290void s5k83a_disconnect(struct sd *sd)
204{ 291{
205 return 0; 292 struct s5k83a_priv *sens_priv = sd->sensor_priv;
206}
207 293
208static void s5k83a_dump_registers(struct sd *sd) 294 s5k83a_stop(sd);
209{
210 int address;
211 u8 page, old_page;
212 m5602_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
213 295
214 for (page = 0; page < 16; page++) { 296 sd->sensor = NULL;
215 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1); 297 kfree(sens_priv->settings);
216 info("Dumping the s5k83a register state for page 0x%x", page); 298 kfree(sens_priv);
217 for (address = 0; address <= 0xff; address++) { 299}
218 u8 val = 0;
219 m5602_read_sensor(sd, address, &val, 1);
220 info("register 0x%x contains 0x%x",
221 address, val);
222 }
223 }
224 info("s5k83a register state dump complete");
225
226 for (page = 0; page < 16; page++) {
227 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
228 info("Probing for which registers that are read/write "
229 "for page 0x%x", page);
230 for (address = 0; address <= 0xff; address++) {
231 u8 old_val, ctrl_val, test_val = 0xff;
232
233 m5602_read_sensor(sd, address, &old_val, 1);
234 m5602_write_sensor(sd, address, &test_val, 1);
235 m5602_read_sensor(sd, address, &ctrl_val, 1);
236
237 if (ctrl_val == test_val)
238 info("register 0x%x is writeable", address);
239 else
240 info("register 0x%x is read only", address);
241 300
242 /* Restore original val */ 301int s5k83a_power_down(struct sd *sd)
243 m5602_write_sensor(sd, address, &old_val, 1); 302{
244 } 303 return 0;
245 }
246 info("Read/write register probing complete");
247 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
248} 304}
249 305
250int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val) 306int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
251{ 307{
252 int err;
253 u8 data[2];
254 struct sd *sd = (struct sd *) gspca_dev; 308 struct sd *sd = (struct sd *) gspca_dev;
309 struct s5k83a_priv *sens_priv = sd->sensor_priv;
255 310
256 err = m5602_read_sensor(sd, S5K83A_BRIGHTNESS, data, 2); 311 *val = sens_priv->settings[GAIN_IDX];
257 if (err < 0) 312 return 0;
258 return err;
259
260 data[1] = data[1] << 1;
261 *val = data[1];
262
263 return err;
264} 313}
265 314
266int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val) 315int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
267{ 316{
268 int err; 317 int err;
269 u8 data[2]; 318 u8 data[2];
270 struct sd *sd = (struct sd *) gspca_dev; 319 struct sd *sd = (struct sd *) gspca_dev;
320 struct s5k83a_priv *sens_priv = sd->sensor_priv;
321
322 sens_priv->settings[GAIN_IDX] = val;
271 323
272 data[0] = 0x00; 324 data[0] = 0x00;
273 data[1] = 0x20; 325 data[1] = 0x20;
@@ -283,89 +335,68 @@ int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
283 335
284 /* FIXME: This is not sane, we need to figure out the composition 336 /* FIXME: This is not sane, we need to figure out the composition
285 of these registers */ 337 of these registers */
286 data[0] = val >> 3; /* brightness, high 5 bits */ 338 data[0] = val >> 3; /* gain, high 5 bits */
287 data[1] = val >> 1; /* brightness, high 7 bits */ 339 data[1] = val >> 1; /* gain, high 7 bits */
288 err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 2); 340 err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2);
289 341
290 return err; 342 return err;
291} 343}
292 344
293int s5k83a_get_whiteness(struct gspca_dev *gspca_dev, __s32 *val) 345int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
294{ 346{
295 int err;
296 u8 data;
297 struct sd *sd = (struct sd *) gspca_dev; 347 struct sd *sd = (struct sd *) gspca_dev;
348 struct s5k83a_priv *sens_priv = sd->sensor_priv;
298 349
299 err = m5602_read_sensor(sd, S5K83A_WHITENESS, &data, 1); 350 *val = sens_priv->settings[BRIGHTNESS_IDX];
300 if (err < 0) 351 return 0;
301 return err;
302
303 *val = data;
304
305 return err;
306} 352}
307 353
308int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val) 354int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
309{ 355{
310 int err; 356 int err;
311 u8 data[1]; 357 u8 data[1];
312 struct sd *sd = (struct sd *) gspca_dev; 358 struct sd *sd = (struct sd *) gspca_dev;
359 struct s5k83a_priv *sens_priv = sd->sensor_priv;
313 360
361 sens_priv->settings[BRIGHTNESS_IDX] = val;
314 data[0] = val; 362 data[0] = val;
315 err = m5602_write_sensor(sd, S5K83A_WHITENESS, data, 1); 363 err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1);
316
317 return err; 364 return err;
318} 365}
319 366
320int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val) 367int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
321{ 368{
322 int err;
323 u8 data[2];
324 struct sd *sd = (struct sd *) gspca_dev; 369 struct sd *sd = (struct sd *) gspca_dev;
370 struct s5k83a_priv *sens_priv = sd->sensor_priv;
325 371
326 err = m5602_read_sensor(sd, S5K83A_GAIN, data, 2); 372 *val = sens_priv->settings[EXPOSURE_IDX];
327 if (err < 0) 373 return 0;
328 return err;
329
330 data[1] = data[1] & 0x3f;
331 if (data[1] > S5K83A_MAXIMUM_GAIN)
332 data[1] = S5K83A_MAXIMUM_GAIN;
333
334 *val = data[1];
335
336 return err;
337} 374}
338 375
339int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val) 376int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
340{ 377{
341 int err; 378 int err;
342 u8 data[2]; 379 u8 data[2];
343 struct sd *sd = (struct sd *) gspca_dev; 380 struct sd *sd = (struct sd *) gspca_dev;
381 struct s5k83a_priv *sens_priv = sd->sensor_priv;
344 382
383 sens_priv->settings[EXPOSURE_IDX] = val;
345 data[0] = 0; 384 data[0] = 0;
346 data[1] = val; 385 data[1] = val;
347 err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2); 386 err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2);
348 return err; 387 return err;
349} 388}
350 389
351int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) 390int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
352{ 391{
353 int err;
354 u8 data[1];
355 struct sd *sd = (struct sd *) gspca_dev; 392 struct sd *sd = (struct sd *) gspca_dev;
393 struct s5k83a_priv *sens_priv = sd->sensor_priv;
356 394
357 data[0] = 0x05; 395 *val = sens_priv->settings[VFLIP_IDX];
358 err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1); 396 return 0;
359 if (err < 0)
360 return err;
361
362 err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
363 *val = (data[0] | 0x40) ? 1 : 0;
364
365 return err;
366} 397}
367 398
368int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val) 399int s5k83a_set_flip_real(struct gspca_dev *gspca_dev, __s32 vflip, __s32 hflip)
369{ 400{
370 int err; 401 int err;
371 u8 data[1]; 402 u8 data[1];
@@ -376,69 +407,83 @@ int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
376 if (err < 0) 407 if (err < 0)
377 return err; 408 return err;
378 409
379 err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1); 410 /* six bit is vflip, seven is hflip */
380 if (err < 0) 411 data[0] = S5K83A_FLIP_MASK;
381 return err; 412 data[0] = (vflip) ? data[0] | 0x40 : data[0];
413 data[0] = (hflip) ? data[0] | 0x80 : data[0];
382 414
383 /* set or zero six bit, seven is hflip */
384 data[0] = (val) ? (data[0] & 0x80) | 0x40 | S5K83A_FLIP_MASK
385 : (data[0] & 0x80) | S5K83A_FLIP_MASK;
386 err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1); 415 err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
387 if (err < 0) 416 if (err < 0)
388 return err; 417 return err;
389 418
390 data[0] = (val) ? 0x0b : 0x0a; 419 data[0] = (vflip) ? 0x0b : 0x0a;
391 err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1); 420 err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1);
421 if (err < 0)
422 return err;
392 423
424 data[0] = (hflip) ? 0x0a : 0x0b;
425 err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
393 return err; 426 return err;
394} 427}
395 428
396int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) 429int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
397{ 430{
398 int err; 431 int err;
399 u8 data[1]; 432 u8 reg;
433 __s32 hflip;
400 struct sd *sd = (struct sd *) gspca_dev; 434 struct sd *sd = (struct sd *) gspca_dev;
435 struct s5k83a_priv *sens_priv = sd->sensor_priv;
401 436
402 data[0] = 0x05; 437 sens_priv->settings[VFLIP_IDX] = val;
403 err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1); 438
439 s5k83a_get_hflip(gspca_dev, &hflip);
440
441 err = s5k83a_get_rotation(sd, &reg);
404 if (err < 0) 442 if (err < 0)
405 return err; 443 return err;
444 if (reg) {
445 val = !val;
446 hflip = !hflip;
447 }
406 448
407 err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1); 449 err = s5k83a_set_flip_real(gspca_dev, val, hflip);
408 *val = (data[0] | 0x80) ? 1 : 0;
409
410 return err; 450 return err;
411} 451}
412 452
453int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
454{
455 struct sd *sd = (struct sd *) gspca_dev;
456 struct s5k83a_priv *sens_priv = sd->sensor_priv;
457
458 *val = sens_priv->settings[HFLIP_IDX];
459 return 0;
460}
461
413int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val) 462int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
414{ 463{
415 int err; 464 int err;
416 u8 data[1]; 465 u8 reg;
466 __s32 vflip;
417 struct sd *sd = (struct sd *) gspca_dev; 467 struct sd *sd = (struct sd *) gspca_dev;
468 struct s5k83a_priv *sens_priv = sd->sensor_priv;
418 469
419 data[0] = 0x05; 470 sens_priv->settings[HFLIP_IDX] = val;
420 err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
421 if (err < 0)
422 return err;
423 471
424 err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1); 472 s5k83a_get_vflip(gspca_dev, &vflip);
425 if (err < 0)
426 return err;
427 473
428 /* set or zero seven bit, six is vflip */ 474 err = s5k83a_get_rotation(sd, &reg);
429 data[0] = (val) ? (data[0] & 0x40) | 0x80 | S5K83A_FLIP_MASK
430 : (data[0] & 0x40) | S5K83A_FLIP_MASK;
431 err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
432 if (err < 0) 475 if (err < 0)
433 return err; 476 return err;
477 if (reg) {
478 val = !val;
479 vflip = !vflip;
480 }
434 481
435 data[0] = (val) ? 0x0a : 0x0b; 482 err = s5k83a_set_flip_real(gspca_dev, vflip, val);
436 err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
437
438 return err; 483 return err;
439} 484}
440 485
441int s5k83a_set_led_indication(struct sd *sd, u8 val) 486static int s5k83a_set_led_indication(struct sd *sd, u8 val)
442{ 487{
443 int err = 0; 488 int err = 0;
444 u8 data[1]; 489 u8 data[1];
@@ -456,3 +501,53 @@ int s5k83a_set_led_indication(struct sd *sd, u8 val)
456 501
457 return (err < 0) ? err : 0; 502 return (err < 0) ? err : 0;
458} 503}
504
505/* Get camera rotation on Acer notebooks */
506static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data)
507{
508 int err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, reg_data);
509 *reg_data = (*reg_data & S5K83A_GPIO_ROTATION_MASK) ? 0 : 1;
510 return err;
511}
512
513static void s5k83a_dump_registers(struct sd *sd)
514{
515 int address;
516 u8 page, old_page;
517 m5602_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
518
519 for (page = 0; page < 16; page++) {
520 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
521 info("Dumping the s5k83a register state for page 0x%x", page);
522 for (address = 0; address <= 0xff; address++) {
523 u8 val = 0;
524 m5602_read_sensor(sd, address, &val, 1);
525 info("register 0x%x contains 0x%x",
526 address, val);
527 }
528 }
529 info("s5k83a register state dump complete");
530
531 for (page = 0; page < 16; page++) {
532 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
533 info("Probing for which registers that are read/write "
534 "for page 0x%x", page);
535 for (address = 0; address <= 0xff; address++) {
536 u8 old_val, ctrl_val, test_val = 0xff;
537
538 m5602_read_sensor(sd, address, &old_val, 1);
539 m5602_write_sensor(sd, address, &test_val, 1);
540 m5602_read_sensor(sd, address, &ctrl_val, 1);
541
542 if (ctrl_val == test_val)
543 info("register 0x%x is writeable", address);
544 else
545 info("register 0x%x is read only", address);
546
547 /* Restore original val */
548 m5602_write_sensor(sd, address, &old_val, 1);
549 }
550 }
551 info("Read/write register probing complete");
552 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
553}
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.h b/drivers/media/video/gspca/m5602/m5602_s5k83a.h
index 819ab25272be..9ca3ca311c88 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k83a.h
+++ b/drivers/media/video/gspca/m5602/m5602_s5k83a.h
@@ -21,20 +21,21 @@
21 21
22#include "m5602_sensor.h" 22#include "m5602_sensor.h"
23 23
24#define S5K83A_FLIP 0x01 24#define S5K83A_FLIP 0x01
25#define S5K83A_HFLIP_TUNE 0x03 25#define S5K83A_HFLIP_TUNE 0x03
26#define S5K83A_VFLIP_TUNE 0x05 26#define S5K83A_VFLIP_TUNE 0x05
27#define S5K83A_WHITENESS 0x0a 27#define S5K83A_BRIGHTNESS 0x0a
28#define S5K83A_GAIN 0x18 28#define S5K83A_EXPOSURE 0x18
29#define S5K83A_BRIGHTNESS 0x1b 29#define S5K83A_GAIN 0x1b
30#define S5K83A_PAGE_MAP 0xec 30#define S5K83A_PAGE_MAP 0xec
31 31
32#define S5K83A_DEFAULT_BRIGHTNESS 0x71 32#define S5K83A_DEFAULT_GAIN 0x71
33#define S5K83A_DEFAULT_WHITENESS 0x7e 33#define S5K83A_DEFAULT_BRIGHTNESS 0x7e
34#define S5K83A_DEFAULT_GAIN 0x00 34#define S5K83A_DEFAULT_EXPOSURE 0x00
35#define S5K83A_MAXIMUM_GAIN 0x3c 35#define S5K83A_MAXIMUM_EXPOSURE 0x3c
36#define S5K83A_FLIP_MASK 0x10 36#define S5K83A_FLIP_MASK 0x10
37#define S5K83A_GPIO_LED_MASK 0x10 37#define S5K83A_GPIO_LED_MASK 0x10
38#define S5K83A_GPIO_ROTATION_MASK 0x40
38 39
39/*****************************************************************************/ 40/*****************************************************************************/
40 41
@@ -47,15 +48,14 @@ int s5k83a_init(struct sd *sd);
47int s5k83a_start(struct sd *sd); 48int s5k83a_start(struct sd *sd);
48int s5k83a_stop(struct sd *sd); 49int s5k83a_stop(struct sd *sd);
49int s5k83a_power_down(struct sd *sd); 50int s5k83a_power_down(struct sd *sd);
51void s5k83a_disconnect(struct sd *sd);
50 52
51int s5k83a_set_led_indication(struct sd *sd, u8 val);
52
53int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
54int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
55int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val);
56int s5k83a_get_whiteness(struct gspca_dev *gspca_dev, __s32 *val);
57int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val); 53int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val);
58int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val); 54int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
55int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
56int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
57int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
58int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
59int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); 59int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
60int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val); 60int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
61int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); 61int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
@@ -68,10 +68,18 @@ static const struct m5602_sensor s5k83a = {
68 .start = s5k83a_start, 68 .start = s5k83a_start,
69 .stop = s5k83a_stop, 69 .stop = s5k83a_stop,
70 .power_down = s5k83a_power_down, 70 .power_down = s5k83a_power_down,
71 .disconnect = s5k83a_disconnect,
71 .i2c_slave_id = 0x5a, 72 .i2c_slave_id = 0x5a,
72 .i2c_regW = 2, 73 .i2c_regW = 2,
73}; 74};
74 75
76struct s5k83a_priv {
77 /* We use another thread periodically
78 probing the orientation of the camera */
79 struct task_struct *rotation_thread;
80 s32 *settings;
81};
82
75static const unsigned char preinit_s5k83a[][4] = 83static const unsigned char preinit_s5k83a[][4] =
76{ 84{
77 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, 85 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
@@ -125,7 +133,7 @@ static const unsigned char init_s5k83a[][4] =
125 {SENSOR, 0x01, 0x50, 0x00}, 133 {SENSOR, 0x01, 0x50, 0x00},
126 {SENSOR, 0x12, 0x20, 0x00}, 134 {SENSOR, 0x12, 0x20, 0x00},
127 {SENSOR, 0x17, 0x40, 0x00}, 135 {SENSOR, 0x17, 0x40, 0x00},
128 {SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00}, 136 {SENSOR, S5K83A_GAIN, 0x0f, 0x00},
129 {SENSOR, 0x1c, 0x00, 0x00}, 137 {SENSOR, 0x1c, 0x00, 0x00},
130 {SENSOR, 0x02, 0x70, 0x00}, 138 {SENSOR, 0x02, 0x70, 0x00},
131 {SENSOR, 0x03, 0x0b, 0x00}, 139 {SENSOR, 0x03, 0x0b, 0x00},
@@ -232,7 +240,7 @@ static const unsigned char init_s5k83a[][4] =
232 {SENSOR, 0x01, 0x50, 0x00}, 240 {SENSOR, 0x01, 0x50, 0x00},
233 {SENSOR, 0x12, 0x20, 0x00}, 241 {SENSOR, 0x12, 0x20, 0x00},
234 {SENSOR, 0x17, 0x40, 0x00}, 242 {SENSOR, 0x17, 0x40, 0x00},
235 {SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00}, 243 {SENSOR, S5K83A_GAIN, 0x0f, 0x00},
236 {SENSOR, 0x1c, 0x00, 0x00}, 244 {SENSOR, 0x1c, 0x00, 0x00},
237 {SENSOR, 0x02, 0x70, 0x00}, 245 {SENSOR, 0x02, 0x70, 0x00},
238 /* some values like 0x10 give a blue-purple image */ 246 /* some values like 0x10 give a blue-purple image */
@@ -320,7 +328,7 @@ static const unsigned char init_s5k83a[][4] =
320 {SENSOR, 0x01, 0x50, 0x00}, 328 {SENSOR, 0x01, 0x50, 0x00},
321 {SENSOR, 0x12, 0x20, 0x00}, 329 {SENSOR, 0x12, 0x20, 0x00},
322 {SENSOR, 0x17, 0x40, 0x00}, 330 {SENSOR, 0x17, 0x40, 0x00},
323 {SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00}, 331 {SENSOR, S5K83A_GAIN, 0x0f, 0x00},
324 {SENSOR, 0x1c, 0x00, 0x00}, 332 {SENSOR, 0x1c, 0x00, 0x00},
325 {SENSOR, 0x02, 0x70, 0x00}, 333 {SENSOR, 0x02, 0x70, 0x00},
326 {SENSOR, 0x03, 0x0b, 0x00}, 334 {SENSOR, 0x03, 0x0b, 0x00},
@@ -374,24 +382,23 @@ static const unsigned char init_s5k83a[][4] =
374 (this is value after boot, but after tries can be different) */ 382 (this is value after boot, but after tries can be different) */
375 {SENSOR, 0x00, 0x06, 0x00}, 383 {SENSOR, 0x00, 0x06, 0x00},
376 384
377 /* set default brightness */ 385 /* set default gain */
378 {SENSOR_LONG, 0x14, 0x00, 0x20}, 386 {SENSOR_LONG, 0x14, 0x00, 0x20},
379 {SENSOR_LONG, 0x0d, 0x01, 0x00}, 387 {SENSOR_LONG, 0x0d, 0x01, 0x00},
380 {SENSOR_LONG, 0x1b, S5K83A_DEFAULT_BRIGHTNESS >> 3, 388 {SENSOR_LONG, 0x1b, S5K83A_DEFAULT_GAIN >> 3,
381 S5K83A_DEFAULT_BRIGHTNESS >> 1}, 389 S5K83A_DEFAULT_GAIN >> 1},
382 390
383 /* set default whiteness */ 391 /* set default brightness */
384 {SENSOR, S5K83A_WHITENESS, S5K83A_DEFAULT_WHITENESS, 0x00}, 392 {SENSOR, S5K83A_BRIGHTNESS, S5K83A_DEFAULT_BRIGHTNESS, 0x00},
385 393
386 /* set default gain */ 394 /* set default exposure */
387 {SENSOR_LONG, 0x18, 0x00, S5K83A_DEFAULT_GAIN}, 395 {SENSOR_LONG, 0x18, 0x00, S5K83A_DEFAULT_EXPOSURE},
388 396
389 /* set default flip */ 397 /* set default flip */
390 {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, 398 {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
391 {SENSOR, S5K83A_FLIP, 0x00 | S5K83A_FLIP_MASK, 0x00}, 399 {SENSOR, S5K83A_FLIP, 0x00 | S5K83A_FLIP_MASK, 0x00},
392 {SENSOR, S5K83A_HFLIP_TUNE, 0x0b, 0x00}, 400 {SENSOR, S5K83A_HFLIP_TUNE, 0x0b, 0x00},
393 {SENSOR, S5K83A_VFLIP_TUNE, 0x0a, 0x00} 401 {SENSOR, S5K83A_VFLIP_TUNE, 0x0a, 0x00}
394
395}; 402};
396 403
397#endif 404#endif