linux/drivers/media/usb/sn9c102/sn9c102_pas106b.c
<<
>>
Prefs
   1/***************************************************************************
   2 * Plug-in for PAS106B image sensor connected to the SN9C1xx PC Camera     *
   3 * Controllers                                                             *
   4 *                                                                         *
   5 * Copyright (C) 2004-2007 by Luca Risolia <luca.risolia@studio.unibo.it>  *
   6 *                                                                         *
   7 * This program is free software; you can redistribute it and/or modify    *
   8 * it under the terms of the GNU General Public License as published by    *
   9 * the Free Software Foundation; either version 2 of the License, or       *
  10 * (at your option) any later version.                                     *
  11 *                                                                         *
  12 * This program is distributed in the hope that it will be useful,         *
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
  15 * GNU General Public License for more details.                            *
  16 *                                                                         *
  17 * You should have received a copy of the GNU General Public License       *
  18 * along with this program; if not, write to the Free Software             *
  19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
  20 ***************************************************************************/
  21
  22#include <linux/delay.h>
  23#include "sn9c102_sensor.h"
  24#include "sn9c102_devtable.h"
  25
  26
  27static int pas106b_init(struct sn9c102_device* cam)
  28{
  29        int err = 0;
  30
  31        err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11},
  32                                       {0x00, 0x14}, {0x20, 0x17},
  33                                       {0x20, 0x19}, {0x09, 0x18});
  34
  35        err += sn9c102_i2c_write(cam, 0x02, 0x0c);
  36        err += sn9c102_i2c_write(cam, 0x05, 0x5a);
  37        err += sn9c102_i2c_write(cam, 0x06, 0x88);
  38        err += sn9c102_i2c_write(cam, 0x07, 0x80);
  39        err += sn9c102_i2c_write(cam, 0x10, 0x06);
  40        err += sn9c102_i2c_write(cam, 0x11, 0x06);
  41        err += sn9c102_i2c_write(cam, 0x12, 0x00);
  42        err += sn9c102_i2c_write(cam, 0x14, 0x02);
  43        err += sn9c102_i2c_write(cam, 0x13, 0x01);
  44
  45        msleep(400);
  46
  47        return err;
  48}
  49
  50
  51static int pas106b_get_ctrl(struct sn9c102_device* cam,
  52                            struct v4l2_control* ctrl)
  53{
  54        switch (ctrl->id) {
  55        case V4L2_CID_EXPOSURE:
  56                {
  57                        int r1 = sn9c102_i2c_read(cam, 0x03),
  58                            r2 = sn9c102_i2c_read(cam, 0x04);
  59                        if (r1 < 0 || r2 < 0)
  60                                return -EIO;
  61                        ctrl->value = (r1 << 4) | (r2 & 0x0f);
  62                }
  63                return 0;
  64        case V4L2_CID_RED_BALANCE:
  65                if ((ctrl->value = sn9c102_i2c_read(cam, 0x0c)) < 0)
  66                        return -EIO;
  67                ctrl->value &= 0x1f;
  68                return 0;
  69        case V4L2_CID_BLUE_BALANCE:
  70                if ((ctrl->value = sn9c102_i2c_read(cam, 0x09)) < 0)
  71                        return -EIO;
  72                ctrl->value &= 0x1f;
  73                return 0;
  74        case V4L2_CID_GAIN:
  75                if ((ctrl->value = sn9c102_i2c_read(cam, 0x0e)) < 0)
  76                        return -EIO;
  77                ctrl->value &= 0x1f;
  78                return 0;
  79        case V4L2_CID_CONTRAST:
  80                if ((ctrl->value = sn9c102_i2c_read(cam, 0x0f)) < 0)
  81                        return -EIO;
  82                ctrl->value &= 0x07;
  83                return 0;
  84        case SN9C102_V4L2_CID_GREEN_BALANCE:
  85                if ((ctrl->value = sn9c102_i2c_read(cam, 0x0a)) < 0)
  86                        return -EIO;
  87                ctrl->value = (ctrl->value & 0x1f) << 1;
  88                return 0;
  89        case SN9C102_V4L2_CID_DAC_MAGNITUDE:
  90                if ((ctrl->value = sn9c102_i2c_read(cam, 0x08)) < 0)
  91                        return -EIO;
  92                ctrl->value &= 0xf8;
  93                return 0;
  94        default:
  95                return -EINVAL;
  96        }
  97}
  98
  99
 100static int pas106b_set_ctrl(struct sn9c102_device* cam,
 101                            const struct v4l2_control* ctrl)
 102{
 103        int err = 0;
 104
 105        switch (ctrl->id) {
 106        case V4L2_CID_EXPOSURE:
 107                err += sn9c102_i2c_write(cam, 0x03, ctrl->value >> 4);
 108                err += sn9c102_i2c_write(cam, 0x04, ctrl->value & 0x0f);
 109                break;
 110        case V4L2_CID_RED_BALANCE:
 111                err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
 112                break;
 113        case V4L2_CID_BLUE_BALANCE:
 114                err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
 115                break;
 116        case V4L2_CID_GAIN:
 117                err += sn9c102_i2c_write(cam, 0x0e, ctrl->value);
 118                break;
 119        case V4L2_CID_CONTRAST:
 120                err += sn9c102_i2c_write(cam, 0x0f, ctrl->value);
 121                break;
 122        case SN9C102_V4L2_CID_GREEN_BALANCE:
 123                err += sn9c102_i2c_write(cam, 0x0a, ctrl->value >> 1);
 124                err += sn9c102_i2c_write(cam, 0x0b, ctrl->value >> 1);
 125                break;
 126        case SN9C102_V4L2_CID_DAC_MAGNITUDE:
 127                err += sn9c102_i2c_write(cam, 0x08, ctrl->value << 3);
 128                break;
 129        default:
 130                return -EINVAL;
 131        }
 132        err += sn9c102_i2c_write(cam, 0x13, 0x01);
 133
 134        return err ? -EIO : 0;
 135}
 136
 137
 138static int pas106b_set_crop(struct sn9c102_device* cam,
 139                            const struct v4l2_rect* rect)
 140{
 141        struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
 142        int err = 0;
 143        u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
 144           v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
 145
 146        err += sn9c102_write_reg(cam, h_start, 0x12);
 147        err += sn9c102_write_reg(cam, v_start, 0x13);
 148
 149        return err;
 150}
 151
 152
 153static int pas106b_set_pix_format(struct sn9c102_device* cam,
 154                                  const struct v4l2_pix_format* pix)
 155{
 156        int err = 0;
 157
 158        if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
 159                err += sn9c102_write_reg(cam, 0x2c, 0x17);
 160        else
 161                err += sn9c102_write_reg(cam, 0x20, 0x17);
 162
 163        return err;
 164}
 165
 166
 167static const struct sn9c102_sensor pas106b = {
 168        .name = "PAS106B",
 169        .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
 170        .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102,
 171        .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
 172        .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
 173        .interface = SN9C102_I2C_2WIRES,
 174        .i2c_slave_id = 0x40,
 175        .init = &pas106b_init,
 176        .qctrl = {
 177                {
 178                        .id = V4L2_CID_EXPOSURE,
 179                        .type = V4L2_CTRL_TYPE_INTEGER,
 180                        .name = "exposure",
 181                        .minimum = 0x125,
 182                        .maximum = 0xfff,
 183                        .step = 0x001,
 184                        .default_value = 0x140,
 185                        .flags = 0,
 186                },
 187                {
 188                        .id = V4L2_CID_GAIN,
 189                        .type = V4L2_CTRL_TYPE_INTEGER,
 190                        .name = "global gain",
 191                        .minimum = 0x00,
 192                        .maximum = 0x1f,
 193                        .step = 0x01,
 194                        .default_value = 0x0d,
 195                        .flags = 0,
 196                },
 197                {
 198                        .id = V4L2_CID_CONTRAST,
 199                        .type = V4L2_CTRL_TYPE_INTEGER,
 200                        .name = "contrast",
 201                        .minimum = 0x00,
 202                        .maximum = 0x07,
 203                        .step = 0x01,
 204                        .default_value = 0x00, /* 0x00~0x03 have same effect */
 205                        .flags = 0,
 206                },
 207                {
 208                        .id = V4L2_CID_RED_BALANCE,
 209                        .type = V4L2_CTRL_TYPE_INTEGER,
 210                        .name = "red balance",
 211                        .minimum = 0x00,
 212                        .maximum = 0x1f,
 213                        .step = 0x01,
 214                        .default_value = 0x04,
 215                        .flags = 0,
 216                },
 217                {
 218                        .id = V4L2_CID_BLUE_BALANCE,
 219                        .type = V4L2_CTRL_TYPE_INTEGER,
 220                        .name = "blue balance",
 221                        .minimum = 0x00,
 222                        .maximum = 0x1f,
 223                        .step = 0x01,
 224                        .default_value = 0x06,
 225                        .flags = 0,
 226                },
 227                {
 228                        .id = SN9C102_V4L2_CID_GREEN_BALANCE,
 229                        .type = V4L2_CTRL_TYPE_INTEGER,
 230                        .name = "green balance",
 231                        .minimum = 0x00,
 232                        .maximum = 0x3e,
 233                        .step = 0x02,
 234                        .default_value = 0x02,
 235                        .flags = 0,
 236                },
 237                {
 238                        .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
 239                        .type = V4L2_CTRL_TYPE_INTEGER,
 240                        .name = "DAC magnitude",
 241                        .minimum = 0x00,
 242                        .maximum = 0x1f,
 243                        .step = 0x01,
 244                        .default_value = 0x01,
 245                        .flags = 0,
 246                },
 247        },
 248        .get_ctrl = &pas106b_get_ctrl,
 249        .set_ctrl = &pas106b_set_ctrl,
 250        .cropcap = {
 251                .bounds = {
 252                        .left = 0,
 253                        .top = 0,
 254                        .width = 352,
 255                        .height = 288,
 256                },
 257                .defrect = {
 258                        .left = 0,
 259                        .top = 0,
 260                        .width = 352,
 261                        .height = 288,
 262                },
 263        },
 264        .set_crop = &pas106b_set_crop,
 265        .pix_format = {
 266                .width = 352,
 267                .height = 288,
 268                .pixelformat = V4L2_PIX_FMT_SBGGR8,
 269                .priv = 8, /* we use this field as 'bits per pixel' */
 270        },
 271        .set_pix_format = &pas106b_set_pix_format
 272};
 273
 274
 275int sn9c102_probe_pas106b(struct sn9c102_device* cam)
 276{
 277        int r0 = 0, r1 = 0;
 278        unsigned int pid = 0;
 279
 280        /*
 281           Minimal initialization to enable the I2C communication
 282           NOTE: do NOT change the values!
 283        */
 284        if (sn9c102_write_const_regs(cam,
 285                                     {0x01, 0x01}, /* sensor power down */
 286                                     {0x00, 0x01}, /* sensor power on */
 287                                    {0x28, 0x17})) /* sensor clock at 24 MHz */
 288                return -EIO;
 289
 290        r0 = sn9c102_i2c_try_read(cam, &pas106b, 0x00);
 291        r1 = sn9c102_i2c_try_read(cam, &pas106b, 0x01);
 292        if (r0 < 0 || r1 < 0)
 293                return -EIO;
 294
 295        pid = (r0 << 11) | ((r1 & 0xf0) >> 4);
 296        if (pid != 0x007)
 297                return -ENODEV;
 298
 299        sn9c102_attach_sensor(cam, &pas106b);
 300
 301        return 0;
 302}
 303