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