linux/drivers/media/usb/gspca/m5602/m5602_s5k4aa.c
<<
>>
Prefs
   1/*
   2 * Driver for the s5k4aa 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 "m5602_s5k4aa.h"
  22
  23static int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl);
  24static void s5k4aa_dump_registers(struct sd *sd);
  25
  26static const struct v4l2_ctrl_ops s5k4aa_ctrl_ops = {
  27        .s_ctrl = s5k4aa_s_ctrl,
  28};
  29
  30static
  31    const
  32        struct dmi_system_id s5k4aa_vflip_dmi_table[] = {
  33        {
  34                .ident = "BRUNEINIT",
  35                .matches = {
  36                        DMI_MATCH(DMI_SYS_VENDOR, "BRUNENIT"),
  37                        DMI_MATCH(DMI_PRODUCT_NAME, "BRUNENIT"),
  38                        DMI_MATCH(DMI_BOARD_VERSION, "00030D0000000001")
  39                }
  40        }, {
  41                .ident = "Fujitsu-Siemens Amilo Xa 2528",
  42                .matches = {
  43                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
  44                        DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528")
  45                }
  46        }, {
  47                .ident = "Fujitsu-Siemens Amilo Xi 2428",
  48                .matches = {
  49                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
  50                        DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2428")
  51                }
  52        }, {
  53                .ident = "Fujitsu-Siemens Amilo Xi 2528",
  54                .matches = {
  55                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
  56                        DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2528")
  57                }
  58        }, {
  59                .ident = "Fujitsu-Siemens Amilo Xi 2550",
  60                .matches = {
  61                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
  62                        DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2550")
  63                }
  64        }, {
  65                .ident = "Fujitsu-Siemens Amilo Pa 2548",
  66                .matches = {
  67                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
  68                        DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2548")
  69                }
  70        }, {
  71                .ident = "Fujitsu-Siemens Amilo Pi 2530",
  72                .matches = {
  73                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
  74                        DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 2530")
  75                }
  76        }, {
  77                .ident = "MSI GX700",
  78                .matches = {
  79                        DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
  80                        DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
  81                        DMI_MATCH(DMI_BIOS_DATE, "12/02/2008")
  82                }
  83        }, {
  84                .ident = "MSI GX700",
  85                .matches = {
  86                        DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
  87                        DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
  88                        DMI_MATCH(DMI_BIOS_DATE, "07/26/2007")
  89                }
  90        }, {
  91                .ident = "MSI GX700",
  92                .matches = {
  93                        DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
  94                        DMI_MATCH(DMI_PRODUCT_NAME, "GX700"),
  95                        DMI_MATCH(DMI_BIOS_DATE, "07/19/2007")
  96                }
  97        }, {
  98                .ident = "MSI GX700/GX705/EX700",
  99                .matches = {
 100                        DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
 101                        DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700")
 102                }
 103        }, {
 104                .ident = "MSI L735",
 105                .matches = {
 106                        DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
 107                        DMI_MATCH(DMI_PRODUCT_NAME, "MS-1717X")
 108                }
 109        }, {
 110                .ident = "Lenovo Y300",
 111                .matches = {
 112                        DMI_MATCH(DMI_SYS_VENDOR, "L3000 Y300"),
 113                        DMI_MATCH(DMI_PRODUCT_NAME, "Y300")
 114                }
 115        },
 116        { }
 117};
 118
 119static struct v4l2_pix_format s5k4aa_modes[] = {
 120        {
 121                640,
 122                480,
 123                V4L2_PIX_FMT_SBGGR8,
 124                V4L2_FIELD_NONE,
 125                .sizeimage =
 126                        640 * 480,
 127                .bytesperline = 640,
 128                .colorspace = V4L2_COLORSPACE_SRGB,
 129                .priv = 0
 130        },
 131        {
 132                1280,
 133                1024,
 134                V4L2_PIX_FMT_SBGGR8,
 135                V4L2_FIELD_NONE,
 136                .sizeimage =
 137                        1280 * 1024,
 138                .bytesperline = 1280,
 139                .colorspace = V4L2_COLORSPACE_SRGB,
 140                .priv = 0
 141        }
 142};
 143
 144int s5k4aa_probe(struct sd *sd)
 145{
 146        u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
 147        const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
 148        struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
 149        int i, err = 0;
 150
 151        if (force_sensor) {
 152                if (force_sensor == S5K4AA_SENSOR) {
 153                        pr_info("Forcing a %s sensor\n", s5k4aa.name);
 154                        goto sensor_found;
 155                }
 156                /* If we want to force another sensor, don't try to probe this
 157                 * one */
 158                return -ENODEV;
 159        }
 160
 161        PDEBUG(D_PROBE, "Probing for a s5k4aa sensor");
 162
 163        /* Preinit the sensor */
 164        for (i = 0; i < ARRAY_SIZE(preinit_s5k4aa) && !err; i++) {
 165                u8 data[2] = {0x00, 0x00};
 166
 167                switch (preinit_s5k4aa[i][0]) {
 168                case BRIDGE:
 169                        err = m5602_write_bridge(sd,
 170                                                 preinit_s5k4aa[i][1],
 171                                                 preinit_s5k4aa[i][2]);
 172                        break;
 173
 174                case SENSOR:
 175                        data[0] = preinit_s5k4aa[i][2];
 176                        err = m5602_write_sensor(sd,
 177                                                  preinit_s5k4aa[i][1],
 178                                                  data, 1);
 179                        break;
 180
 181                case SENSOR_LONG:
 182                        data[0] = preinit_s5k4aa[i][2];
 183                        data[1] = preinit_s5k4aa[i][3];
 184                        err = m5602_write_sensor(sd,
 185                                                  preinit_s5k4aa[i][1],
 186                                                  data, 2);
 187                        break;
 188                default:
 189                        pr_info("Invalid stream command, exiting init\n");
 190                        return -EINVAL;
 191                }
 192        }
 193
 194        /* Test some registers, but we don't know their exact meaning yet */
 195        if (m5602_read_sensor(sd, 0x00, prod_id, 2))
 196                return -ENODEV;
 197        if (m5602_read_sensor(sd, 0x02, prod_id+2, 2))
 198                return -ENODEV;
 199        if (m5602_read_sensor(sd, 0x04, prod_id+4, 2))
 200                return -ENODEV;
 201
 202        if (memcmp(prod_id, expected_prod_id, sizeof(prod_id)))
 203                return -ENODEV;
 204        else
 205                pr_info("Detected a s5k4aa sensor\n");
 206
 207sensor_found:
 208        sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
 209        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
 210
 211        return 0;
 212}
 213
 214int s5k4aa_start(struct sd *sd)
 215{
 216        int i, err = 0;
 217        u8 data[2];
 218        struct cam *cam = &sd->gspca_dev.cam;
 219        struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
 220
 221        switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) {
 222        case 1280:
 223                PDEBUG(D_CONF, "Configuring camera for SXGA mode");
 224
 225                for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) {
 226                        switch (SXGA_s5k4aa[i][0]) {
 227                        case BRIDGE:
 228                                err = m5602_write_bridge(sd,
 229                                                 SXGA_s5k4aa[i][1],
 230                                                 SXGA_s5k4aa[i][2]);
 231                        break;
 232
 233                        case SENSOR:
 234                                data[0] = SXGA_s5k4aa[i][2];
 235                                err = m5602_write_sensor(sd,
 236                                                 SXGA_s5k4aa[i][1],
 237                                                 data, 1);
 238                        break;
 239
 240                        case SENSOR_LONG:
 241                                data[0] = SXGA_s5k4aa[i][2];
 242                                data[1] = SXGA_s5k4aa[i][3];
 243                                err = m5602_write_sensor(sd,
 244                                                  SXGA_s5k4aa[i][1],
 245                                                  data, 2);
 246                        break;
 247
 248                        default:
 249                                pr_err("Invalid stream command, exiting init\n");
 250                                return -EINVAL;
 251                        }
 252                }
 253                break;
 254
 255        case 640:
 256                PDEBUG(D_CONF, "Configuring camera for VGA mode");
 257
 258                for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) {
 259                        switch (VGA_s5k4aa[i][0]) {
 260                        case BRIDGE:
 261                                err = m5602_write_bridge(sd,
 262                                                 VGA_s5k4aa[i][1],
 263                                                 VGA_s5k4aa[i][2]);
 264                        break;
 265
 266                        case SENSOR:
 267                                data[0] = VGA_s5k4aa[i][2];
 268                                err = m5602_write_sensor(sd,
 269                                                 VGA_s5k4aa[i][1],
 270                                                 data, 1);
 271                        break;
 272
 273                        case SENSOR_LONG:
 274                                data[0] = VGA_s5k4aa[i][2];
 275                                data[1] = VGA_s5k4aa[i][3];
 276                                err = m5602_write_sensor(sd,
 277                                                  VGA_s5k4aa[i][1],
 278                                                  data, 2);
 279                        break;
 280
 281                        default:
 282                                pr_err("Invalid stream command, exiting init\n");
 283                                return -EINVAL;
 284                        }
 285                }
 286                break;
 287        }
 288        if (err < 0)
 289                return err;
 290
 291        return 0;
 292}
 293
 294int s5k4aa_init(struct sd *sd)
 295{
 296        int i, err = 0;
 297
 298        for (i = 0; i < ARRAY_SIZE(init_s5k4aa) && !err; i++) {
 299                u8 data[2] = {0x00, 0x00};
 300
 301                switch (init_s5k4aa[i][0]) {
 302                case BRIDGE:
 303                        err = m5602_write_bridge(sd,
 304                                init_s5k4aa[i][1],
 305                                init_s5k4aa[i][2]);
 306                        break;
 307
 308                case SENSOR:
 309                        data[0] = init_s5k4aa[i][2];
 310                        err = m5602_write_sensor(sd,
 311                                init_s5k4aa[i][1], data, 1);
 312                        break;
 313
 314                case SENSOR_LONG:
 315                        data[0] = init_s5k4aa[i][2];
 316                        data[1] = init_s5k4aa[i][3];
 317                        err = m5602_write_sensor(sd,
 318                                init_s5k4aa[i][1], data, 2);
 319                        break;
 320                default:
 321                        pr_info("Invalid stream command, exiting init\n");
 322                        return -EINVAL;
 323                }
 324        }
 325
 326        if (dump_sensor)
 327                s5k4aa_dump_registers(sd);
 328
 329        return err;
 330}
 331
 332int s5k4aa_init_controls(struct sd *sd)
 333{
 334        struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
 335
 336        sd->gspca_dev.vdev.ctrl_handler = hdl;
 337        v4l2_ctrl_handler_init(hdl, 6);
 338
 339        v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_BRIGHTNESS,
 340                          0, 0x1f, 1, S5K4AA_DEFAULT_BRIGHTNESS);
 341
 342        v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_EXPOSURE,
 343                          13, 0xfff, 1, 0x100);
 344
 345        v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_GAIN,
 346                          0, 127, 1, S5K4AA_DEFAULT_GAIN);
 347
 348        v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_SHARPNESS,
 349                          0, 1, 1, 1);
 350
 351        sd->hflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_HFLIP,
 352                                      0, 1, 1, 0);
 353        sd->vflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_VFLIP,
 354                                      0, 1, 1, 0);
 355
 356        if (hdl->error) {
 357                pr_err("Could not initialize controls\n");
 358                return hdl->error;
 359        }
 360
 361        v4l2_ctrl_cluster(2, &sd->hflip);
 362
 363        return 0;
 364}
 365
 366static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
 367{
 368        struct sd *sd = (struct sd *) gspca_dev;
 369        u8 data = S5K4AA_PAGE_MAP_2;
 370        int err;
 371
 372        PDEBUG(D_CONF, "Set exposure to %d", val);
 373        err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
 374        if (err < 0)
 375                return err;
 376        data = (val >> 8) & 0xff;
 377        err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
 378        if (err < 0)
 379                return err;
 380        data = val & 0xff;
 381        err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
 382
 383        return err;
 384}
 385
 386static int s5k4aa_set_hvflip(struct gspca_dev *gspca_dev)
 387{
 388        struct sd *sd = (struct sd *) gspca_dev;
 389        u8 data = S5K4AA_PAGE_MAP_2;
 390        int err;
 391        int hflip = sd->hflip->val;
 392        int vflip = sd->vflip->val;
 393
 394        PDEBUG(D_CONF, "Set hvflip %d %d", hflip, vflip);
 395        err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
 396        if (err < 0)
 397                return err;
 398
 399        err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
 400        if (err < 0)
 401                return err;
 402
 403        if (dmi_check_system(s5k4aa_vflip_dmi_table)) {
 404                hflip = !hflip;
 405                vflip = !vflip;
 406        }
 407
 408        data = (data & 0x7f) | (vflip << 7) | (hflip << 6);
 409        err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
 410        if (err < 0)
 411                return err;
 412
 413        err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
 414        if (err < 0)
 415                return err;
 416        if (hflip)
 417                data &= 0xfe;
 418        else
 419                data |= 0x01;
 420        err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
 421        if (err < 0)
 422                return err;
 423
 424        err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
 425        if (err < 0)
 426                return err;
 427        if (vflip)
 428                data &= 0xfe;
 429        else
 430                data |= 0x01;
 431        err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
 432        if (err < 0)
 433                return err;
 434
 435        return 0;
 436}
 437
 438static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 439{
 440        struct sd *sd = (struct sd *) gspca_dev;
 441        u8 data = S5K4AA_PAGE_MAP_2;
 442        int err;
 443
 444        PDEBUG(D_CONF, "Set gain to %d", val);
 445        err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
 446        if (err < 0)
 447                return err;
 448
 449        data = val & 0xff;
 450        err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1);
 451
 452        return err;
 453}
 454
 455static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
 456{
 457        struct sd *sd = (struct sd *) gspca_dev;
 458        u8 data = S5K4AA_PAGE_MAP_2;
 459        int err;
 460
 461        PDEBUG(D_CONF, "Set brightness to %d", val);
 462        err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
 463        if (err < 0)
 464                return err;
 465
 466        data = val & 0xff;
 467        return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
 468}
 469
 470static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
 471{
 472        struct sd *sd = (struct sd *) gspca_dev;
 473        u8 data = S5K4AA_PAGE_MAP_2;
 474        int err;
 475
 476        PDEBUG(D_CONF, "Set noise to %d", val);
 477        err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
 478        if (err < 0)
 479                return err;
 480
 481        data = val & 0x01;
 482        return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
 483}
 484
 485static int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl)
 486{
 487        struct gspca_dev *gspca_dev =
 488                container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
 489        int err;
 490
 491        if (!gspca_dev->streaming)
 492                return 0;
 493
 494        switch (ctrl->id) {
 495        case V4L2_CID_BRIGHTNESS:
 496                err = s5k4aa_set_brightness(gspca_dev, ctrl->val);
 497                break;
 498        case V4L2_CID_EXPOSURE:
 499                err = s5k4aa_set_exposure(gspca_dev, ctrl->val);
 500                break;
 501        case V4L2_CID_GAIN:
 502                err = s5k4aa_set_gain(gspca_dev, ctrl->val);
 503                break;
 504        case V4L2_CID_SHARPNESS:
 505                err = s5k4aa_set_noise(gspca_dev, ctrl->val);
 506                break;
 507        case V4L2_CID_HFLIP:
 508                err = s5k4aa_set_hvflip(gspca_dev);
 509                break;
 510        default:
 511                return -EINVAL;
 512        }
 513
 514        return err;
 515}
 516
 517void s5k4aa_disconnect(struct sd *sd)
 518{
 519        sd->sensor = NULL;
 520}
 521
 522static void s5k4aa_dump_registers(struct sd *sd)
 523{
 524        int address;
 525        u8 page, old_page;
 526        m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
 527        for (page = 0; page < 16; page++) {
 528                m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
 529                pr_info("Dumping the s5k4aa register state for page 0x%x\n",
 530                        page);
 531                for (address = 0; address <= 0xff; address++) {
 532                        u8 value = 0;
 533                        m5602_read_sensor(sd, address, &value, 1);
 534                        pr_info("register 0x%x contains 0x%x\n",
 535                                address, value);
 536                }
 537        }
 538        pr_info("s5k4aa register state dump complete\n");
 539
 540        for (page = 0; page < 16; page++) {
 541                m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1);
 542                pr_info("Probing for which registers that are read/write for page 0x%x\n",
 543                        page);
 544                for (address = 0; address <= 0xff; address++) {
 545                        u8 old_value, ctrl_value, test_value = 0xff;
 546
 547                        m5602_read_sensor(sd, address, &old_value, 1);
 548                        m5602_write_sensor(sd, address, &test_value, 1);
 549                        m5602_read_sensor(sd, address, &ctrl_value, 1);
 550
 551                        if (ctrl_value == test_value)
 552                                pr_info("register 0x%x is writeable\n",
 553                                        address);
 554                        else
 555                                pr_info("register 0x%x is read only\n",
 556                                        address);
 557
 558                        /* Restore original value */
 559                        m5602_write_sensor(sd, address, &old_value, 1);
 560                }
 561        }
 562        pr_info("Read/write register probing complete\n");
 563        m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1);
 564}
 565