linux/drivers/media/usb/gspca/m5602/m5602_s5k83a.c
<<
>>
Prefs
   1/*
   2 * Driver for the s5k83a 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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  20
  21#include <linux/kthread.h>
  22#include "m5602_s5k83a.h"
  23
  24static int s5k83a_s_ctrl(struct v4l2_ctrl *ctrl);
  25
  26static const struct v4l2_ctrl_ops s5k83a_ctrl_ops = {
  27        .s_ctrl = s5k83a_s_ctrl,
  28};
  29
  30static struct v4l2_pix_format s5k83a_modes[] = {
  31        {
  32                640,
  33                480,
  34                V4L2_PIX_FMT_SBGGR8,
  35                V4L2_FIELD_NONE,
  36                .sizeimage =
  37                        640 * 480,
  38                .bytesperline = 640,
  39                .colorspace = V4L2_COLORSPACE_SRGB,
  40                .priv = 0
  41        }
  42};
  43
  44static const unsigned char preinit_s5k83a[][4] = {
  45        {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
  46        {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
  47        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
  48        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
  49        {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
  50        {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
  51        {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
  52
  53        {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
  54        {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
  55        {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
  56        {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
  57        {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
  58        {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
  59        {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
  60        {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
  61        {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
  62        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
  63        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
  64        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
  65        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
  66        {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
  67        {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
  68        {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
  69        {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
  70        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
  71        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
  72        {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
  73        {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
  74        {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
  75        {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
  76        {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
  77        {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
  78        {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
  79};
  80
  81/* This could probably be considerably shortened.
  82   I don't have the hardware to experiment with it, patches welcome
  83*/
  84static const unsigned char init_s5k83a[][4] = {
  85        /* The following sequence is useless after a clean boot
  86           but is necessary after resume from suspend */
  87        {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
  88        {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
  89        {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
  90        {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
  91        {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
  92        {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
  93        {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
  94        {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
  95        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
  96        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
  97        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
  98        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
  99        {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
 100        {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
 101        {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
 102        {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
 103        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
 104        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
 105        {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
 106        {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
 107        {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
 108        {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
 109        {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
 110        {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
 111        {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
 112
 113        {SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00},
 114        {SENSOR, 0xaf, 0x01, 0x00},
 115        {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00},
 116        {SENSOR, 0x7b, 0xff, 0x00},
 117        {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
 118        {SENSOR, 0x01, 0x50, 0x00},
 119        {SENSOR, 0x12, 0x20, 0x00},
 120        {SENSOR, 0x17, 0x40, 0x00},
 121        {SENSOR, 0x1c, 0x00, 0x00},
 122        {SENSOR, 0x02, 0x70, 0x00},
 123        {SENSOR, 0x03, 0x0b, 0x00},
 124        {SENSOR, 0x04, 0xf0, 0x00},
 125        {SENSOR, 0x05, 0x0b, 0x00},
 126        {SENSOR, 0x06, 0x71, 0x00},
 127        {SENSOR, 0x07, 0xe8, 0x00}, /* 488 */
 128        {SENSOR, 0x08, 0x02, 0x00},
 129        {SENSOR, 0x09, 0x88, 0x00}, /* 648 */
 130        {SENSOR, 0x14, 0x00, 0x00},
 131        {SENSOR, 0x15, 0x20, 0x00}, /* 32 */
 132        {SENSOR, 0x19, 0x00, 0x00},
 133        {SENSOR, 0x1a, 0x98, 0x00}, /* 152 */
 134        {SENSOR, 0x0f, 0x02, 0x00},
 135        {SENSOR, 0x10, 0xe5, 0x00}, /* 741 */
 136        /* normal colors
 137        (this is value after boot, but after tries can be different) */
 138        {SENSOR, 0x00, 0x06, 0x00},
 139};
 140
 141static const unsigned char start_s5k83a[][4] = {
 142        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
 143        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
 144        {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
 145        {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
 146        {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
 147        {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
 148        {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
 149        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
 150        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
 151        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
 152        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
 153        {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
 154        {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00}, /* 484 */
 155        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
 156        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
 157        {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
 158        {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
 159        {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
 160        {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
 161        {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
 162        {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00}, /* 639 */
 163        {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
 164        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
 165        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
 166};
 167
 168static void s5k83a_dump_registers(struct sd *sd);
 169static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data);
 170static int s5k83a_set_led_indication(struct sd *sd, u8 val);
 171static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
 172                                __s32 vflip, __s32 hflip);
 173
 174int s5k83a_probe(struct sd *sd)
 175{
 176        u8 prod_id = 0, ver_id = 0;
 177        int i, err = 0;
 178        struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
 179
 180        if (force_sensor) {
 181                if (force_sensor == S5K83A_SENSOR) {
 182                        pr_info("Forcing a %s sensor\n", s5k83a.name);
 183                        goto sensor_found;
 184                }
 185                /* If we want to force another sensor, don't try to probe this
 186                 * one */
 187                return -ENODEV;
 188        }
 189
 190        gspca_dbg(gspca_dev, D_PROBE, "Probing for a s5k83a sensor\n");
 191
 192        /* Preinit the sensor */
 193        for (i = 0; i < ARRAY_SIZE(preinit_s5k83a) && !err; i++) {
 194                u8 data[2] = {preinit_s5k83a[i][2], preinit_s5k83a[i][3]};
 195                if (preinit_s5k83a[i][0] == SENSOR)
 196                        err = m5602_write_sensor(sd, preinit_s5k83a[i][1],
 197                                data, 2);
 198                else
 199                        err = m5602_write_bridge(sd, preinit_s5k83a[i][1],
 200                                data[0]);
 201        }
 202
 203        /* We don't know what register (if any) that contain the product id
 204         * Just pick the first addresses that seem to produce the same results
 205         * on multiple machines */
 206        if (m5602_read_sensor(sd, 0x00, &prod_id, 1))
 207                return -ENODEV;
 208
 209        if (m5602_read_sensor(sd, 0x01, &ver_id, 1))
 210                return -ENODEV;
 211
 212        if ((prod_id == 0xff) || (ver_id == 0xff))
 213                return -ENODEV;
 214        else
 215                pr_info("Detected a s5k83a sensor\n");
 216
 217sensor_found:
 218        sd->gspca_dev.cam.cam_mode = s5k83a_modes;
 219        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes);
 220
 221        /* null the pointer! thread is't running now */
 222        sd->rotation_thread = NULL;
 223
 224        return 0;
 225}
 226
 227int s5k83a_init(struct sd *sd)
 228{
 229        int i, err = 0;
 230
 231        for (i = 0; i < ARRAY_SIZE(init_s5k83a) && !err; i++) {
 232                u8 data[2] = {0x00, 0x00};
 233
 234                switch (init_s5k83a[i][0]) {
 235                case BRIDGE:
 236                        err = m5602_write_bridge(sd,
 237                                        init_s5k83a[i][1],
 238                                        init_s5k83a[i][2]);
 239                        break;
 240
 241                case SENSOR:
 242                        data[0] = init_s5k83a[i][2];
 243                        err = m5602_write_sensor(sd,
 244                                init_s5k83a[i][1], data, 1);
 245                        break;
 246
 247                case SENSOR_LONG:
 248                        data[0] = init_s5k83a[i][2];
 249                        data[1] = init_s5k83a[i][3];
 250                        err = m5602_write_sensor(sd,
 251                                init_s5k83a[i][1], data, 2);
 252                        break;
 253                default:
 254                        pr_info("Invalid stream command, exiting init\n");
 255                        return -EINVAL;
 256                }
 257        }
 258
 259        if (dump_sensor)
 260                s5k83a_dump_registers(sd);
 261
 262        return err;
 263}
 264
 265int s5k83a_init_controls(struct sd *sd)
 266{
 267        struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
 268
 269        sd->gspca_dev.vdev.ctrl_handler = hdl;
 270        v4l2_ctrl_handler_init(hdl, 6);
 271
 272        v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_BRIGHTNESS,
 273                          0, 255, 1, S5K83A_DEFAULT_BRIGHTNESS);
 274
 275        v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_EXPOSURE,
 276                          0, S5K83A_MAXIMUM_EXPOSURE, 1,
 277                          S5K83A_DEFAULT_EXPOSURE);
 278
 279        v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_GAIN,
 280                          0, 255, 1, S5K83A_DEFAULT_GAIN);
 281
 282        sd->hflip = v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_HFLIP,
 283                                      0, 1, 1, 0);
 284        sd->vflip = v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_VFLIP,
 285                                      0, 1, 1, 0);
 286
 287        if (hdl->error) {
 288                pr_err("Could not initialize controls\n");
 289                return hdl->error;
 290        }
 291
 292        v4l2_ctrl_cluster(2, &sd->hflip);
 293
 294        return 0;
 295}
 296
 297static int rotation_thread_function(void *data)
 298{
 299        struct sd *sd = (struct sd *) data;
 300        u8 reg, previous_rotation = 0;
 301        __s32 vflip, hflip;
 302
 303        set_current_state(TASK_INTERRUPTIBLE);
 304        while (!schedule_timeout(msecs_to_jiffies(100))) {
 305                if (mutex_lock_interruptible(&sd->gspca_dev.usb_lock))
 306                        break;
 307
 308                s5k83a_get_rotation(sd, &reg);
 309                if (previous_rotation != reg) {
 310                        previous_rotation = reg;
 311                        pr_info("Camera was flipped\n");
 312
 313                        hflip = sd->hflip->val;
 314                        vflip = sd->vflip->val;
 315
 316                        if (reg) {
 317                                vflip = !vflip;
 318                                hflip = !hflip;
 319                        }
 320                        s5k83a_set_flip_real((struct gspca_dev *) sd,
 321                                              vflip, hflip);
 322                }
 323
 324                mutex_unlock(&sd->gspca_dev.usb_lock);
 325                set_current_state(TASK_INTERRUPTIBLE);
 326        }
 327
 328        /* return to "front" flip */
 329        if (previous_rotation) {
 330                hflip = sd->hflip->val;
 331                vflip = sd->vflip->val;
 332                s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip);
 333        }
 334
 335        sd->rotation_thread = NULL;
 336        return 0;
 337}
 338
 339int s5k83a_start(struct sd *sd)
 340{
 341        int i, err = 0;
 342
 343        /* Create another thread, polling the GPIO ports of the camera to check
 344           if it got rotated. This is how the windows driver does it so we have
 345           to assume that there is no better way of accomplishing this */
 346        sd->rotation_thread = kthread_create(rotation_thread_function,
 347                                             sd, "rotation thread");
 348        if (IS_ERR(sd->rotation_thread)) {
 349                err = PTR_ERR(sd->rotation_thread);
 350                sd->rotation_thread = NULL;
 351                return err;
 352        }
 353        wake_up_process(sd->rotation_thread);
 354
 355        /* Preinit the sensor */
 356        for (i = 0; i < ARRAY_SIZE(start_s5k83a) && !err; i++) {
 357                u8 data[2] = {start_s5k83a[i][2], start_s5k83a[i][3]};
 358                if (start_s5k83a[i][0] == SENSOR)
 359                        err = m5602_write_sensor(sd, start_s5k83a[i][1],
 360                                data, 2);
 361                else
 362                        err = m5602_write_bridge(sd, start_s5k83a[i][1],
 363                                data[0]);
 364        }
 365        if (err < 0)
 366                return err;
 367
 368        return s5k83a_set_led_indication(sd, 1);
 369}
 370
 371int s5k83a_stop(struct sd *sd)
 372{
 373        if (sd->rotation_thread)
 374                kthread_stop(sd->rotation_thread);
 375
 376        return s5k83a_set_led_indication(sd, 0);
 377}
 378
 379void s5k83a_disconnect(struct sd *sd)
 380{
 381        s5k83a_stop(sd);
 382
 383        sd->sensor = NULL;
 384}
 385
 386static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 387{
 388        int err;
 389        u8 data[2];
 390        struct sd *sd = (struct sd *) gspca_dev;
 391
 392        data[0] = 0x00;
 393        data[1] = 0x20;
 394        err = m5602_write_sensor(sd, 0x14, data, 2);
 395        if (err < 0)
 396                return err;
 397
 398        data[0] = 0x01;
 399        data[1] = 0x00;
 400        err = m5602_write_sensor(sd, 0x0d, data, 2);
 401        if (err < 0)
 402                return err;
 403
 404        /* FIXME: This is not sane, we need to figure out the composition
 405                  of these registers */
 406        data[0] = val >> 3; /* gain, high 5 bits */
 407        data[1] = val >> 1; /* gain, high 7 bits */
 408        err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2);
 409
 410        return err;
 411}
 412
 413static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
 414{
 415        int err;
 416        u8 data[1];
 417        struct sd *sd = (struct sd *) gspca_dev;
 418
 419        data[0] = val;
 420        err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1);
 421        return err;
 422}
 423
 424static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
 425{
 426        int err;
 427        u8 data[2];
 428        struct sd *sd = (struct sd *) gspca_dev;
 429
 430        data[0] = 0;
 431        data[1] = val;
 432        err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2);
 433        return err;
 434}
 435
 436static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
 437                                __s32 vflip, __s32 hflip)
 438{
 439        int err;
 440        u8 data[1];
 441        struct sd *sd = (struct sd *) gspca_dev;
 442
 443        data[0] = 0x05;
 444        err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
 445        if (err < 0)
 446                return err;
 447
 448        /* six bit is vflip, seven is hflip */
 449        data[0] = S5K83A_FLIP_MASK;
 450        data[0] = (vflip) ? data[0] | 0x40 : data[0];
 451        data[0] = (hflip) ? data[0] | 0x80 : data[0];
 452
 453        err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
 454        if (err < 0)
 455                return err;
 456
 457        data[0] = (vflip) ? 0x0b : 0x0a;
 458        err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1);
 459        if (err < 0)
 460                return err;
 461
 462        data[0] = (hflip) ? 0x0a : 0x0b;
 463        err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
 464        return err;
 465}
 466
 467static int s5k83a_set_hvflip(struct gspca_dev *gspca_dev)
 468{
 469        int err;
 470        u8 reg;
 471        struct sd *sd = (struct sd *) gspca_dev;
 472        int hflip = sd->hflip->val;
 473        int vflip = sd->vflip->val;
 474
 475        err = s5k83a_get_rotation(sd, &reg);
 476        if (err < 0)
 477                return err;
 478        if (reg) {
 479                hflip = !hflip;
 480                vflip = !vflip;
 481        }
 482
 483        err = s5k83a_set_flip_real(gspca_dev, vflip, hflip);
 484        return err;
 485}
 486
 487static int s5k83a_s_ctrl(struct v4l2_ctrl *ctrl)
 488{
 489        struct gspca_dev *gspca_dev =
 490                container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
 491        int err;
 492
 493        if (!gspca_dev->streaming)
 494                return 0;
 495
 496        switch (ctrl->id) {
 497        case V4L2_CID_BRIGHTNESS:
 498                err = s5k83a_set_brightness(gspca_dev, ctrl->val);
 499                break;
 500        case V4L2_CID_EXPOSURE:
 501                err = s5k83a_set_exposure(gspca_dev, ctrl->val);
 502                break;
 503        case V4L2_CID_GAIN:
 504                err = s5k83a_set_gain(gspca_dev, ctrl->val);
 505                break;
 506        case V4L2_CID_HFLIP:
 507                err = s5k83a_set_hvflip(gspca_dev);
 508                break;
 509        default:
 510                return -EINVAL;
 511        }
 512
 513        return err;
 514}
 515
 516static int s5k83a_set_led_indication(struct sd *sd, u8 val)
 517{
 518        int err = 0;
 519        u8 data[1];
 520
 521        err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, data);
 522        if (err < 0)
 523                return err;
 524
 525        if (val)
 526                data[0] = data[0] | S5K83A_GPIO_LED_MASK;
 527        else
 528                data[0] = data[0] & ~S5K83A_GPIO_LED_MASK;
 529
 530        err = m5602_write_bridge(sd, M5602_XB_GPIO_DAT, data[0]);
 531
 532        return err;
 533}
 534
 535/* Get camera rotation on Acer notebooks */
 536static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data)
 537{
 538        int err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, reg_data);
 539        *reg_data = (*reg_data & S5K83A_GPIO_ROTATION_MASK) ? 0 : 1;
 540        return err;
 541}
 542
 543static void s5k83a_dump_registers(struct sd *sd)
 544{
 545        int address;
 546        u8 page, old_page;
 547        m5602_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
 548
 549        for (page = 0; page < 16; page++) {
 550                m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
 551                pr_info("Dumping the s5k83a register state for page 0x%x\n",
 552                        page);
 553                for (address = 0; address <= 0xff; address++) {
 554                        u8 val = 0;
 555                        m5602_read_sensor(sd, address, &val, 1);
 556                        pr_info("register 0x%x contains 0x%x\n", address, val);
 557                }
 558        }
 559        pr_info("s5k83a register state dump complete\n");
 560
 561        for (page = 0; page < 16; page++) {
 562                m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
 563                pr_info("Probing for which registers that are read/write for page 0x%x\n",
 564                        page);
 565                for (address = 0; address <= 0xff; address++) {
 566                        u8 old_val, ctrl_val, test_val = 0xff;
 567
 568                        m5602_read_sensor(sd, address, &old_val, 1);
 569                        m5602_write_sensor(sd, address, &test_val, 1);
 570                        m5602_read_sensor(sd, address, &ctrl_val, 1);
 571
 572                        if (ctrl_val == test_val)
 573                                pr_info("register 0x%x is writeable\n",
 574                                        address);
 575                        else
 576                                pr_info("register 0x%x is read only\n",
 577                                        address);
 578
 579                        /* Restore original val */
 580                        m5602_write_sensor(sd, address, &old_val, 1);
 581                }
 582        }
 583        pr_info("Read/write register probing complete\n");
 584        m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
 585}
 586