linux/drivers/media/video/sn9c102/sn9c102_mi0360.c
<<
>>
Prefs
   1/***************************************************************************
   2 * Plug-in for MI-0360 image sensor connected to the SN9C1xx PC Camera     *
   3 * Controllers                                                             *
   4 *                                                                         *
   5 * Copyright (C) 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 "sn9c102_sensor.h"
  23#include "sn9c102_devtable.h"
  24
  25
  26static int mi0360_init(struct sn9c102_device* cam)
  27{
  28        struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
  29        int err = 0;
  30
  31        switch (sn9c102_get_bridge(cam)) {
  32        case BRIDGE_SN9C103:
  33                err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11},
  34                                               {0x0a, 0x14}, {0x40, 0x01},
  35                                               {0x20, 0x17}, {0x07, 0x18},
  36                                               {0xa0, 0x19}, {0x02, 0x1c},
  37                                               {0x03, 0x1d}, {0x0f, 0x1e},
  38                                               {0x0c, 0x1f}, {0x00, 0x20},
  39                                               {0x10, 0x21}, {0x20, 0x22},
  40                                               {0x30, 0x23}, {0x40, 0x24},
  41                                               {0x50, 0x25}, {0x60, 0x26},
  42                                               {0x70, 0x27}, {0x80, 0x28},
  43                                               {0x90, 0x29}, {0xa0, 0x2a},
  44                                               {0xb0, 0x2b}, {0xc0, 0x2c},
  45                                               {0xd0, 0x2d}, {0xe0, 0x2e},
  46                                               {0xf0, 0x2f}, {0xff, 0x30});
  47                break;
  48        case BRIDGE_SN9C105:
  49        case BRIDGE_SN9C120:
  50                err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02},
  51                                               {0x00, 0x03}, {0x1a, 0x04},
  52                                               {0x50, 0x05}, {0x20, 0x06},
  53                                               {0x10, 0x07}, {0x03, 0x10},
  54                                               {0x08, 0x14}, {0xa2, 0x17},
  55                                               {0x47, 0x18}, {0x00, 0x19},
  56                                               {0x1d, 0x1a}, {0x10, 0x1b},
  57                                               {0x02, 0x1c}, {0x03, 0x1d},
  58                                               {0x0f, 0x1e}, {0x0c, 0x1f},
  59                                               {0x00, 0x20}, {0x29, 0x21},
  60                                               {0x40, 0x22}, {0x54, 0x23},
  61                                               {0x66, 0x24}, {0x76, 0x25},
  62                                               {0x85, 0x26}, {0x94, 0x27},
  63                                               {0xa1, 0x28}, {0xae, 0x29},
  64                                               {0xbb, 0x2a}, {0xc7, 0x2b},
  65                                               {0xd3, 0x2c}, {0xde, 0x2d},
  66                                               {0xea, 0x2e}, {0xf4, 0x2f},
  67                                               {0xff, 0x30}, {0x00, 0x3F},
  68                                               {0xC7, 0x40}, {0x01, 0x41},
  69                                               {0x44, 0x42}, {0x00, 0x43},
  70                                               {0x44, 0x44}, {0x00, 0x45},
  71                                               {0x44, 0x46}, {0x00, 0x47},
  72                                               {0xC7, 0x48}, {0x01, 0x49},
  73                                               {0xC7, 0x4A}, {0x01, 0x4B},
  74                                               {0xC7, 0x4C}, {0x01, 0x4D},
  75                                               {0x44, 0x4E}, {0x00, 0x4F},
  76                                               {0x44, 0x50}, {0x00, 0x51},
  77                                               {0x44, 0x52}, {0x00, 0x53},
  78                                               {0xC7, 0x54}, {0x01, 0x55},
  79                                               {0xC7, 0x56}, {0x01, 0x57},
  80                                               {0xC7, 0x58}, {0x01, 0x59},
  81                                               {0x44, 0x5A}, {0x00, 0x5B},
  82                                               {0x44, 0x5C}, {0x00, 0x5D},
  83                                               {0x44, 0x5E}, {0x00, 0x5F},
  84                                               {0xC7, 0x60}, {0x01, 0x61},
  85                                               {0xC7, 0x62}, {0x01, 0x63},
  86                                               {0xC7, 0x64}, {0x01, 0x65},
  87                                               {0x44, 0x66}, {0x00, 0x67},
  88                                               {0x44, 0x68}, {0x00, 0x69},
  89                                               {0x44, 0x6A}, {0x00, 0x6B},
  90                                               {0xC7, 0x6C}, {0x01, 0x6D},
  91                                               {0xC7, 0x6E}, {0x01, 0x6F},
  92                                               {0xC7, 0x70}, {0x01, 0x71},
  93                                               {0x44, 0x72}, {0x00, 0x73},
  94                                               {0x44, 0x74}, {0x00, 0x75},
  95                                               {0x44, 0x76}, {0x00, 0x77},
  96                                               {0xC7, 0x78}, {0x01, 0x79},
  97                                               {0xC7, 0x7A}, {0x01, 0x7B},
  98                                               {0xC7, 0x7C}, {0x01, 0x7D},
  99                                               {0x44, 0x7E}, {0x00, 0x7F},
 100                                               {0x14, 0x84}, {0x00, 0x85},
 101                                               {0x27, 0x86}, {0x00, 0x87},
 102                                               {0x07, 0x88}, {0x00, 0x89},
 103                                               {0xEC, 0x8A}, {0x0f, 0x8B},
 104                                               {0xD8, 0x8C}, {0x0f, 0x8D},
 105                                               {0x3D, 0x8E}, {0x00, 0x8F},
 106                                               {0x3D, 0x90}, {0x00, 0x91},
 107                                               {0xCD, 0x92}, {0x0f, 0x93},
 108                                               {0xf7, 0x94}, {0x0f, 0x95},
 109                                               {0x0C, 0x96}, {0x00, 0x97},
 110                                               {0x00, 0x98}, {0x66, 0x99},
 111                                               {0x05, 0x9A}, {0x00, 0x9B},
 112                                               {0x04, 0x9C}, {0x00, 0x9D},
 113                                               {0x08, 0x9E}, {0x00, 0x9F},
 114                                               {0x2D, 0xC0}, {0x2D, 0xC1},
 115                                               {0x3A, 0xC2}, {0x05, 0xC3},
 116                                               {0x04, 0xC4}, {0x3F, 0xC5},
 117                                               {0x00, 0xC6}, {0x00, 0xC7},
 118                                               {0x50, 0xC8}, {0x3C, 0xC9},
 119                                               {0x28, 0xCA}, {0xD8, 0xCB},
 120                                               {0x14, 0xCC}, {0xEC, 0xCD},
 121                                               {0x32, 0xCE}, {0xDD, 0xCF},
 122                                               {0x32, 0xD0}, {0xDD, 0xD1},
 123                                               {0x6A, 0xD2}, {0x50, 0xD3},
 124                                               {0x00, 0xD4}, {0x00, 0xD5},
 125                                               {0x00, 0xD6});
 126                break;
 127        default:
 128                break;
 129        }
 130
 131        err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
 132                                         0x00, 0x01, 0, 0);
 133        err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d,
 134                                         0x00, 0x00, 0, 0);
 135        err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03,
 136                                         0x01, 0xe1, 0, 0);
 137        err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04,
 138                                         0x02, 0x81, 0, 0);
 139        err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05,
 140                                         0x00, 0x17, 0, 0);
 141        err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06,
 142                                         0x00, 0x11, 0, 0);
 143        err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x62,
 144                                         0x04, 0x9a, 0, 0);
 145
 146        return err;
 147}
 148
 149
 150static int mi0360_get_ctrl(struct sn9c102_device* cam,
 151                           struct v4l2_control* ctrl)
 152{
 153        struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
 154        u8 data[2];
 155
 156        switch (ctrl->id) {
 157        case V4L2_CID_EXPOSURE:
 158                if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x09, 2,
 159                                             data) < 0)
 160                        return -EIO;
 161                ctrl->value = data[0];
 162                return 0;
 163        case V4L2_CID_GAIN:
 164                if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x35, 2,
 165                                             data) < 0)
 166                        return -EIO;
 167                ctrl->value = data[1];
 168                return 0;
 169        case V4L2_CID_RED_BALANCE:
 170                if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2c, 2,
 171                                             data) < 0)
 172                        return -EIO;
 173                ctrl->value = data[1];
 174                return 0;
 175        case V4L2_CID_BLUE_BALANCE:
 176                if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2d, 2,
 177                                             data) < 0)
 178                        return -EIO;
 179                ctrl->value = data[1];
 180                return 0;
 181        case SN9C102_V4L2_CID_GREEN_BALANCE:
 182                if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x2e, 2,
 183                                             data) < 0)
 184                        return -EIO;
 185                ctrl->value = data[1];
 186                return 0;
 187        case V4L2_CID_HFLIP:
 188                if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2,
 189                                             data) < 0)
 190                        return -EIO;
 191                ctrl->value = data[1] & 0x20 ? 1 : 0;
 192                return 0;
 193        case V4L2_CID_VFLIP:
 194                if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2,
 195                                             data) < 0)
 196                        return -EIO;
 197                ctrl->value = data[1] & 0x80 ? 1 : 0;
 198                return 0;
 199        default:
 200                return -EINVAL;
 201        }
 202
 203        return 0;
 204}
 205
 206
 207static int mi0360_set_ctrl(struct sn9c102_device* cam,
 208                           const struct v4l2_control* ctrl)
 209{
 210        struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
 211        int err = 0;
 212
 213        switch (ctrl->id) {
 214        case V4L2_CID_EXPOSURE:
 215                err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
 216                                                 0x09, ctrl->value, 0x00,
 217                                                 0, 0);
 218                break;
 219        case V4L2_CID_GAIN:
 220                err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
 221                                                 0x35, 0x03, ctrl->value,
 222                                                 0, 0);
 223                break;
 224        case V4L2_CID_RED_BALANCE:
 225                err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
 226                                                 0x2c, 0x03, ctrl->value,
 227                                                 0, 0);
 228                break;
 229        case V4L2_CID_BLUE_BALANCE:
 230                err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
 231                                                 0x2d, 0x03, ctrl->value,
 232                                                 0, 0);
 233                break;
 234        case SN9C102_V4L2_CID_GREEN_BALANCE:
 235                err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
 236                                                 0x2b, 0x03, ctrl->value,
 237                                                 0, 0);
 238                err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
 239                                                 0x2e, 0x03, ctrl->value,
 240                                                 0, 0);
 241                break;
 242        case V4L2_CID_HFLIP:
 243                err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
 244                                                 0x20, ctrl->value ? 0x40:0x00,
 245                                                 ctrl->value ? 0x20:0x00,
 246                                                 0, 0);
 247                break;
 248        case V4L2_CID_VFLIP:
 249                err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
 250                                                 0x20, ctrl->value ? 0x80:0x00,
 251                                                 ctrl->value ? 0x80:0x00,
 252                                                 0, 0);
 253                break;
 254        default:
 255                return -EINVAL;
 256        }
 257
 258        return err ? -EIO : 0;
 259}
 260
 261
 262static int mi0360_set_crop(struct sn9c102_device* cam,
 263                            const struct v4l2_rect* rect)
 264{
 265        struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
 266        int err = 0;
 267        u8 h_start = 0, v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
 268
 269        switch (sn9c102_get_bridge(cam)) {
 270        case BRIDGE_SN9C103:
 271                h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0;
 272                break;
 273        case BRIDGE_SN9C105:
 274        case BRIDGE_SN9C120:
 275                h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1;
 276                break;
 277        default:
 278                break;
 279        }
 280
 281        err += sn9c102_write_reg(cam, h_start, 0x12);
 282        err += sn9c102_write_reg(cam, v_start, 0x13);
 283
 284        return err;
 285}
 286
 287
 288static int mi0360_set_pix_format(struct sn9c102_device* cam,
 289                                 const struct v4l2_pix_format* pix)
 290{
 291        struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
 292        int err = 0;
 293
 294        if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
 295                err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
 296                                                 0x0a, 0x00, 0x05, 0, 0);
 297                err += sn9c102_write_reg(cam, 0x60, 0x19);
 298                if (sn9c102_get_bridge(cam) == BRIDGE_SN9C105 ||
 299                    sn9c102_get_bridge(cam) == BRIDGE_SN9C120)
 300                        err += sn9c102_write_reg(cam, 0xa6, 0x17);
 301        } else {
 302                err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id,
 303                                                 0x0a, 0x00, 0x02, 0, 0);
 304                err += sn9c102_write_reg(cam, 0x20, 0x19);
 305                if (sn9c102_get_bridge(cam) == BRIDGE_SN9C105 ||
 306                    sn9c102_get_bridge(cam) == BRIDGE_SN9C120)
 307                        err += sn9c102_write_reg(cam, 0xa2, 0x17);
 308        }
 309
 310        return err;
 311}
 312
 313
 314static const struct sn9c102_sensor mi0360 = {
 315        .name = "MI-0360",
 316        .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
 317        .supported_bridge = BRIDGE_SN9C103 | BRIDGE_SN9C105 | BRIDGE_SN9C120,
 318        .frequency = SN9C102_I2C_100KHZ,
 319        .interface = SN9C102_I2C_2WIRES,
 320        .i2c_slave_id = 0x5d,
 321        .init = &mi0360_init,
 322        .qctrl = {
 323                {
 324                        .id = V4L2_CID_EXPOSURE,
 325                        .type = V4L2_CTRL_TYPE_INTEGER,
 326                        .name = "exposure",
 327                        .minimum = 0x00,
 328                        .maximum = 0x0f,
 329                        .step = 0x01,
 330                        .default_value = 0x05,
 331                        .flags = 0,
 332                },
 333                {
 334                        .id = V4L2_CID_GAIN,
 335                        .type = V4L2_CTRL_TYPE_INTEGER,
 336                        .name = "global gain",
 337                        .minimum = 0x00,
 338                        .maximum = 0x7f,
 339                        .step = 0x01,
 340                        .default_value = 0x25,
 341                        .flags = 0,
 342                },
 343                {
 344                        .id = V4L2_CID_HFLIP,
 345                        .type = V4L2_CTRL_TYPE_BOOLEAN,
 346                        .name = "horizontal mirror",
 347                        .minimum = 0,
 348                        .maximum = 1,
 349                        .step = 1,
 350                        .default_value = 0,
 351                        .flags = 0,
 352                },
 353                {
 354                        .id = V4L2_CID_VFLIP,
 355                        .type = V4L2_CTRL_TYPE_BOOLEAN,
 356                        .name = "vertical mirror",
 357                        .minimum = 0,
 358                        .maximum = 1,
 359                        .step = 1,
 360                        .default_value = 0,
 361                        .flags = 0,
 362                },
 363                {
 364                        .id = V4L2_CID_BLUE_BALANCE,
 365                        .type = V4L2_CTRL_TYPE_INTEGER,
 366                        .name = "blue balance",
 367                        .minimum = 0x00,
 368                        .maximum = 0x7f,
 369                        .step = 0x01,
 370                        .default_value = 0x0f,
 371                        .flags = 0,
 372                },
 373                {
 374                        .id = V4L2_CID_RED_BALANCE,
 375                        .type = V4L2_CTRL_TYPE_INTEGER,
 376                        .name = "red balance",
 377                        .minimum = 0x00,
 378                        .maximum = 0x7f,
 379                        .step = 0x01,
 380                        .default_value = 0x32,
 381                        .flags = 0,
 382                },
 383                {
 384                        .id = SN9C102_V4L2_CID_GREEN_BALANCE,
 385                        .type = V4L2_CTRL_TYPE_INTEGER,
 386                        .name = "green balance",
 387                        .minimum = 0x00,
 388                        .maximum = 0x7f,
 389                        .step = 0x01,
 390                        .default_value = 0x25,
 391                        .flags = 0,
 392                },
 393        },
 394        .get_ctrl = &mi0360_get_ctrl,
 395        .set_ctrl = &mi0360_set_ctrl,
 396        .cropcap = {
 397                .bounds = {
 398                        .left = 0,
 399                        .top = 0,
 400                        .width = 640,
 401                        .height = 480,
 402                },
 403                .defrect = {
 404                        .left = 0,
 405                        .top = 0,
 406                        .width = 640,
 407                        .height = 480,
 408                },
 409        },
 410        .set_crop = &mi0360_set_crop,
 411        .pix_format = {
 412                .width = 640,
 413                .height = 480,
 414                .pixelformat = V4L2_PIX_FMT_SBGGR8,
 415                .priv = 8,
 416        },
 417        .set_pix_format = &mi0360_set_pix_format
 418};
 419
 420
 421int sn9c102_probe_mi0360(struct sn9c102_device* cam)
 422{
 423
 424        u8 data[2];
 425
 426        switch (sn9c102_get_bridge(cam)) {
 427        case BRIDGE_SN9C103:
 428                if (sn9c102_write_const_regs(cam, {0x01, 0x01}, {0x00, 0x01},
 429                                             {0x28, 0x17}))
 430                        return -EIO;
 431                break;
 432        case BRIDGE_SN9C105:
 433        case BRIDGE_SN9C120:
 434                if (sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1},
 435                                             {0x01, 0x01}, {0x00, 0x01},
 436                                             {0x28, 0x17}))
 437                        return -EIO;
 438                break;
 439        default:
 440                break;
 441        }
 442
 443        if (sn9c102_i2c_try_raw_read(cam, &mi0360, mi0360.i2c_slave_id, 0x00,
 444                                     2, data) < 0)
 445                return -EIO;
 446
 447        if (data[0] != 0x82 || data[1] != 0x43)
 448                return -ENODEV;
 449
 450        sn9c102_attach_sensor(cam, &mi0360);
 451
 452        return 0;
 453}
 454