linux/drivers/media/i2c/vs6624.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * vs6624.c ST VS6624 CMOS image sensor driver
   4 *
   5 * Copyright (c) 2011 Analog Devices Inc.
   6 */
   7
   8#include <linux/delay.h>
   9#include <linux/errno.h>
  10#include <linux/gpio.h>
  11#include <linux/i2c.h>
  12#include <linux/init.h>
  13#include <linux/module.h>
  14#include <linux/slab.h>
  15#include <linux/types.h>
  16#include <linux/videodev2.h>
  17
  18#include <media/v4l2-ctrls.h>
  19#include <media/v4l2-device.h>
  20#include <media/v4l2-mediabus.h>
  21#include <media/v4l2-image-sizes.h>
  22
  23#include "vs6624_regs.h"
  24
  25#define MAX_FRAME_RATE  30
  26
  27struct vs6624 {
  28        struct v4l2_subdev sd;
  29        struct v4l2_ctrl_handler hdl;
  30        struct v4l2_fract frame_rate;
  31        struct v4l2_mbus_framefmt fmt;
  32        unsigned ce_pin;
  33};
  34
  35static const struct vs6624_format {
  36        u32 mbus_code;
  37        enum v4l2_colorspace colorspace;
  38} vs6624_formats[] = {
  39        {
  40                .mbus_code      = MEDIA_BUS_FMT_UYVY8_2X8,
  41                .colorspace     = V4L2_COLORSPACE_JPEG,
  42        },
  43        {
  44                .mbus_code      = MEDIA_BUS_FMT_YUYV8_2X8,
  45                .colorspace     = V4L2_COLORSPACE_JPEG,
  46        },
  47        {
  48                .mbus_code      = MEDIA_BUS_FMT_RGB565_2X8_LE,
  49                .colorspace     = V4L2_COLORSPACE_SRGB,
  50        },
  51};
  52
  53static const struct v4l2_mbus_framefmt vs6624_default_fmt = {
  54        .width = VGA_WIDTH,
  55        .height = VGA_HEIGHT,
  56        .code = MEDIA_BUS_FMT_UYVY8_2X8,
  57        .field = V4L2_FIELD_NONE,
  58        .colorspace = V4L2_COLORSPACE_JPEG,
  59};
  60
  61static const u16 vs6624_p1[] = {
  62        0x8104, 0x03,
  63        0x8105, 0x01,
  64        0xc900, 0x03,
  65        0xc904, 0x47,
  66        0xc905, 0x10,
  67        0xc906, 0x80,
  68        0xc907, 0x3a,
  69        0x903a, 0x02,
  70        0x903b, 0x47,
  71        0x903c, 0x15,
  72        0xc908, 0x31,
  73        0xc909, 0xdc,
  74        0xc90a, 0x80,
  75        0xc90b, 0x44,
  76        0x9044, 0x02,
  77        0x9045, 0x31,
  78        0x9046, 0xe2,
  79        0xc90c, 0x07,
  80        0xc90d, 0xe0,
  81        0xc90e, 0x80,
  82        0xc90f, 0x47,
  83        0x9047, 0x90,
  84        0x9048, 0x83,
  85        0x9049, 0x81,
  86        0x904a, 0xe0,
  87        0x904b, 0x60,
  88        0x904c, 0x08,
  89        0x904d, 0x90,
  90        0x904e, 0xc0,
  91        0x904f, 0x43,
  92        0x9050, 0x74,
  93        0x9051, 0x01,
  94        0x9052, 0xf0,
  95        0x9053, 0x80,
  96        0x9054, 0x05,
  97        0x9055, 0xE4,
  98        0x9056, 0x90,
  99        0x9057, 0xc0,
 100        0x9058, 0x43,
 101        0x9059, 0xf0,
 102        0x905a, 0x02,
 103        0x905b, 0x07,
 104        0x905c, 0xec,
 105        0xc910, 0x5d,
 106        0xc911, 0xca,
 107        0xc912, 0x80,
 108        0xc913, 0x5d,
 109        0x905d, 0xa3,
 110        0x905e, 0x04,
 111        0x905f, 0xf0,
 112        0x9060, 0xa3,
 113        0x9061, 0x04,
 114        0x9062, 0xf0,
 115        0x9063, 0x22,
 116        0xc914, 0x72,
 117        0xc915, 0x92,
 118        0xc916, 0x80,
 119        0xc917, 0x64,
 120        0x9064, 0x74,
 121        0x9065, 0x01,
 122        0x9066, 0x02,
 123        0x9067, 0x72,
 124        0x9068, 0x95,
 125        0xc918, 0x47,
 126        0xc919, 0xf2,
 127        0xc91a, 0x81,
 128        0xc91b, 0x69,
 129        0x9169, 0x74,
 130        0x916a, 0x02,
 131        0x916b, 0xf0,
 132        0x916c, 0xec,
 133        0x916d, 0xb4,
 134        0x916e, 0x10,
 135        0x916f, 0x0a,
 136        0x9170, 0x90,
 137        0x9171, 0x80,
 138        0x9172, 0x16,
 139        0x9173, 0xe0,
 140        0x9174, 0x70,
 141        0x9175, 0x04,
 142        0x9176, 0x90,
 143        0x9177, 0xd3,
 144        0x9178, 0xc4,
 145        0x9179, 0xf0,
 146        0x917a, 0x22,
 147        0xc91c, 0x0a,
 148        0xc91d, 0xbe,
 149        0xc91e, 0x80,
 150        0xc91f, 0x73,
 151        0x9073, 0xfc,
 152        0x9074, 0xa3,
 153        0x9075, 0xe0,
 154        0x9076, 0xf5,
 155        0x9077, 0x82,
 156        0x9078, 0x8c,
 157        0x9079, 0x83,
 158        0x907a, 0xa3,
 159        0x907b, 0xa3,
 160        0x907c, 0xe0,
 161        0x907d, 0xfc,
 162        0x907e, 0xa3,
 163        0x907f, 0xe0,
 164        0x9080, 0xc3,
 165        0x9081, 0x9f,
 166        0x9082, 0xff,
 167        0x9083, 0xec,
 168        0x9084, 0x9e,
 169        0x9085, 0xfe,
 170        0x9086, 0x02,
 171        0x9087, 0x0a,
 172        0x9088, 0xea,
 173        0xc920, 0x47,
 174        0xc921, 0x38,
 175        0xc922, 0x80,
 176        0xc923, 0x89,
 177        0x9089, 0xec,
 178        0x908a, 0xd3,
 179        0x908b, 0x94,
 180        0x908c, 0x20,
 181        0x908d, 0x40,
 182        0x908e, 0x01,
 183        0x908f, 0x1c,
 184        0x9090, 0x90,
 185        0x9091, 0xd3,
 186        0x9092, 0xd4,
 187        0x9093, 0xec,
 188        0x9094, 0xf0,
 189        0x9095, 0x02,
 190        0x9096, 0x47,
 191        0x9097, 0x3d,
 192        0xc924, 0x45,
 193        0xc925, 0xca,
 194        0xc926, 0x80,
 195        0xc927, 0x98,
 196        0x9098, 0x12,
 197        0x9099, 0x77,
 198        0x909a, 0xd6,
 199        0x909b, 0x02,
 200        0x909c, 0x45,
 201        0x909d, 0xcd,
 202        0xc928, 0x20,
 203        0xc929, 0xd5,
 204        0xc92a, 0x80,
 205        0xc92b, 0x9e,
 206        0x909e, 0x90,
 207        0x909f, 0x82,
 208        0x90a0, 0x18,
 209        0x90a1, 0xe0,
 210        0x90a2, 0xb4,
 211        0x90a3, 0x03,
 212        0x90a4, 0x0e,
 213        0x90a5, 0x90,
 214        0x90a6, 0x83,
 215        0x90a7, 0xbf,
 216        0x90a8, 0xe0,
 217        0x90a9, 0x60,
 218        0x90aa, 0x08,
 219        0x90ab, 0x90,
 220        0x90ac, 0x81,
 221        0x90ad, 0xfc,
 222        0x90ae, 0xe0,
 223        0x90af, 0xff,
 224        0x90b0, 0xc3,
 225        0x90b1, 0x13,
 226        0x90b2, 0xf0,
 227        0x90b3, 0x90,
 228        0x90b4, 0x81,
 229        0x90b5, 0xfc,
 230        0x90b6, 0xe0,
 231        0x90b7, 0xff,
 232        0x90b8, 0x02,
 233        0x90b9, 0x20,
 234        0x90ba, 0xda,
 235        0xc92c, 0x70,
 236        0xc92d, 0xbc,
 237        0xc92e, 0x80,
 238        0xc92f, 0xbb,
 239        0x90bb, 0x90,
 240        0x90bc, 0x82,
 241        0x90bd, 0x18,
 242        0x90be, 0xe0,
 243        0x90bf, 0xb4,
 244        0x90c0, 0x03,
 245        0x90c1, 0x06,
 246        0x90c2, 0x90,
 247        0x90c3, 0xc1,
 248        0x90c4, 0x06,
 249        0x90c5, 0x74,
 250        0x90c6, 0x05,
 251        0x90c7, 0xf0,
 252        0x90c8, 0x90,
 253        0x90c9, 0xd3,
 254        0x90ca, 0xa0,
 255        0x90cb, 0x02,
 256        0x90cc, 0x70,
 257        0x90cd, 0xbf,
 258        0xc930, 0x72,
 259        0xc931, 0x21,
 260        0xc932, 0x81,
 261        0xc933, 0x3b,
 262        0x913b, 0x7d,
 263        0x913c, 0x02,
 264        0x913d, 0x7f,
 265        0x913e, 0x7b,
 266        0x913f, 0x02,
 267        0x9140, 0x72,
 268        0x9141, 0x25,
 269        0xc934, 0x28,
 270        0xc935, 0xae,
 271        0xc936, 0x80,
 272        0xc937, 0xd2,
 273        0x90d2, 0xf0,
 274        0x90d3, 0x90,
 275        0x90d4, 0xd2,
 276        0x90d5, 0x0a,
 277        0x90d6, 0x02,
 278        0x90d7, 0x28,
 279        0x90d8, 0xb4,
 280        0xc938, 0x28,
 281        0xc939, 0xb1,
 282        0xc93a, 0x80,
 283        0xc93b, 0xd9,
 284        0x90d9, 0x90,
 285        0x90da, 0x83,
 286        0x90db, 0xba,
 287        0x90dc, 0xe0,
 288        0x90dd, 0xff,
 289        0x90de, 0x90,
 290        0x90df, 0xd2,
 291        0x90e0, 0x08,
 292        0x90e1, 0xe0,
 293        0x90e2, 0xe4,
 294        0x90e3, 0xef,
 295        0x90e4, 0xf0,
 296        0x90e5, 0xa3,
 297        0x90e6, 0xe0,
 298        0x90e7, 0x74,
 299        0x90e8, 0xff,
 300        0x90e9, 0xf0,
 301        0x90ea, 0x90,
 302        0x90eb, 0xd2,
 303        0x90ec, 0x0a,
 304        0x90ed, 0x02,
 305        0x90ee, 0x28,
 306        0x90ef, 0xb4,
 307        0xc93c, 0x29,
 308        0xc93d, 0x79,
 309        0xc93e, 0x80,
 310        0xc93f, 0xf0,
 311        0x90f0, 0xf0,
 312        0x90f1, 0x90,
 313        0x90f2, 0xd2,
 314        0x90f3, 0x0e,
 315        0x90f4, 0x02,
 316        0x90f5, 0x29,
 317        0x90f6, 0x7f,
 318        0xc940, 0x29,
 319        0xc941, 0x7c,
 320        0xc942, 0x80,
 321        0xc943, 0xf7,
 322        0x90f7, 0x90,
 323        0x90f8, 0x83,
 324        0x90f9, 0xba,
 325        0x90fa, 0xe0,
 326        0x90fb, 0xff,
 327        0x90fc, 0x90,
 328        0x90fd, 0xd2,
 329        0x90fe, 0x0c,
 330        0x90ff, 0xe0,
 331        0x9100, 0xe4,
 332        0x9101, 0xef,
 333        0x9102, 0xf0,
 334        0x9103, 0xa3,
 335        0x9104, 0xe0,
 336        0x9105, 0x74,
 337        0x9106, 0xff,
 338        0x9107, 0xf0,
 339        0x9108, 0x90,
 340        0x9109, 0xd2,
 341        0x910a, 0x0e,
 342        0x910b, 0x02,
 343        0x910c, 0x29,
 344        0x910d, 0x7f,
 345        0xc944, 0x2a,
 346        0xc945, 0x42,
 347        0xc946, 0x81,
 348        0xc947, 0x0e,
 349        0x910e, 0xf0,
 350        0x910f, 0x90,
 351        0x9110, 0xd2,
 352        0x9111, 0x12,
 353        0x9112, 0x02,
 354        0x9113, 0x2a,
 355        0x9114, 0x48,
 356        0xc948, 0x2a,
 357        0xc949, 0x45,
 358        0xc94a, 0x81,
 359        0xc94b, 0x15,
 360        0x9115, 0x90,
 361        0x9116, 0x83,
 362        0x9117, 0xba,
 363        0x9118, 0xe0,
 364        0x9119, 0xff,
 365        0x911a, 0x90,
 366        0x911b, 0xd2,
 367        0x911c, 0x10,
 368        0x911d, 0xe0,
 369        0x911e, 0xe4,
 370        0x911f, 0xef,
 371        0x9120, 0xf0,
 372        0x9121, 0xa3,
 373        0x9122, 0xe0,
 374        0x9123, 0x74,
 375        0x9124, 0xff,
 376        0x9125, 0xf0,
 377        0x9126, 0x90,
 378        0x9127, 0xd2,
 379        0x9128, 0x12,
 380        0x9129, 0x02,
 381        0x912a, 0x2a,
 382        0x912b, 0x48,
 383        0xc900, 0x01,
 384        0x0000, 0x00,
 385};
 386
 387static const u16 vs6624_p2[] = {
 388        0x806f, 0x01,
 389        0x058c, 0x01,
 390        0x0000, 0x00,
 391};
 392
 393static const u16 vs6624_run_setup[] = {
 394        0x1d18, 0x00,                           /* Enableconstrainedwhitebalance */
 395        VS6624_PEAK_MIN_OUT_G_MSB, 0x3c,        /* Damper PeakGain Output MSB */
 396        VS6624_PEAK_MIN_OUT_G_LSB, 0x66,        /* Damper PeakGain Output LSB */
 397        VS6624_CM_LOW_THR_MSB, 0x65,            /* Damper Low MSB */
 398        VS6624_CM_LOW_THR_LSB, 0xd1,            /* Damper Low LSB */
 399        VS6624_CM_HIGH_THR_MSB, 0x66,           /* Damper High MSB */
 400        VS6624_CM_HIGH_THR_LSB, 0x62,           /* Damper High LSB */
 401        VS6624_CM_MIN_OUT_MSB, 0x00,            /* Damper Min output MSB */
 402        VS6624_CM_MIN_OUT_LSB, 0x00,            /* Damper Min output LSB */
 403        VS6624_NORA_DISABLE, 0x00,              /* Nora fDisable */
 404        VS6624_NORA_USAGE, 0x04,                /* Nora usage */
 405        VS6624_NORA_LOW_THR_MSB, 0x63,          /* Damper Low MSB Changed 0x63 to 0x65 */
 406        VS6624_NORA_LOW_THR_LSB, 0xd1,          /* Damper Low LSB */
 407        VS6624_NORA_HIGH_THR_MSB, 0x68,         /* Damper High MSB */
 408        VS6624_NORA_HIGH_THR_LSB, 0xdd,         /* Damper High LSB */
 409        VS6624_NORA_MIN_OUT_MSB, 0x3a,          /* Damper Min output MSB */
 410        VS6624_NORA_MIN_OUT_LSB, 0x00,          /* Damper Min output LSB */
 411        VS6624_F2B_DISABLE, 0x00,               /* Disable */
 412        0x1d8a, 0x30,                           /* MAXWeightHigh */
 413        0x1d91, 0x62,                           /* fpDamperLowThresholdHigh MSB */
 414        0x1d92, 0x4a,                           /* fpDamperLowThresholdHigh LSB */
 415        0x1d95, 0x65,                           /* fpDamperHighThresholdHigh MSB */
 416        0x1d96, 0x0e,                           /* fpDamperHighThresholdHigh LSB */
 417        0x1da1, 0x3a,                           /* fpMinimumDamperOutputLow MSB */
 418        0x1da2, 0xb8,                           /* fpMinimumDamperOutputLow LSB */
 419        0x1e08, 0x06,                           /* MAXWeightLow */
 420        0x1e0a, 0x0a,                           /* MAXWeightHigh */
 421        0x1601, 0x3a,                           /* Red A MSB */
 422        0x1602, 0x14,                           /* Red A LSB */
 423        0x1605, 0x3b,                           /* Blue A MSB */
 424        0x1606, 0x85,                           /* BLue A LSB */
 425        0x1609, 0x3b,                           /* RED B MSB */
 426        0x160a, 0x85,                           /* RED B LSB */
 427        0x160d, 0x3a,                           /* Blue B MSB */
 428        0x160e, 0x14,                           /* Blue B LSB */
 429        0x1611, 0x30,                           /* Max Distance from Locus MSB */
 430        0x1612, 0x8f,                           /* Max Distance from Locus MSB */
 431        0x1614, 0x01,                           /* Enable constrainer */
 432        0x0000, 0x00,
 433};
 434
 435static const u16 vs6624_default[] = {
 436        VS6624_CONTRAST0, 0x84,
 437        VS6624_SATURATION0, 0x75,
 438        VS6624_GAMMA0, 0x11,
 439        VS6624_CONTRAST1, 0x84,
 440        VS6624_SATURATION1, 0x75,
 441        VS6624_GAMMA1, 0x11,
 442        VS6624_MAN_RG, 0x80,
 443        VS6624_MAN_GG, 0x80,
 444        VS6624_MAN_BG, 0x80,
 445        VS6624_WB_MODE, 0x1,
 446        VS6624_EXPO_COMPENSATION, 0xfe,
 447        VS6624_EXPO_METER, 0x0,
 448        VS6624_LIGHT_FREQ, 0x64,
 449        VS6624_PEAK_GAIN, 0xe,
 450        VS6624_PEAK_LOW_THR, 0x28,
 451        VS6624_HMIRROR0, 0x0,
 452        VS6624_VFLIP0, 0x0,
 453        VS6624_ZOOM_HSTEP0_MSB, 0x0,
 454        VS6624_ZOOM_HSTEP0_LSB, 0x1,
 455        VS6624_ZOOM_VSTEP0_MSB, 0x0,
 456        VS6624_ZOOM_VSTEP0_LSB, 0x1,
 457        VS6624_PAN_HSTEP0_MSB, 0x0,
 458        VS6624_PAN_HSTEP0_LSB, 0xf,
 459        VS6624_PAN_VSTEP0_MSB, 0x0,
 460        VS6624_PAN_VSTEP0_LSB, 0xf,
 461        VS6624_SENSOR_MODE, 0x1,
 462        VS6624_SYNC_CODE_SETUP, 0x21,
 463        VS6624_DISABLE_FR_DAMPER, 0x0,
 464        VS6624_FR_DEN, 0x1,
 465        VS6624_FR_NUM_LSB, 0xf,
 466        VS6624_INIT_PIPE_SETUP, 0x0,
 467        VS6624_IMG_FMT0, 0x0,
 468        VS6624_YUV_SETUP, 0x1,
 469        VS6624_IMAGE_SIZE0, 0x2,
 470        0x0000, 0x00,
 471};
 472
 473static inline struct vs6624 *to_vs6624(struct v4l2_subdev *sd)
 474{
 475        return container_of(sd, struct vs6624, sd);
 476}
 477static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
 478{
 479        return &container_of(ctrl->handler, struct vs6624, hdl)->sd;
 480}
 481
 482#ifdef CONFIG_VIDEO_ADV_DEBUG
 483static int vs6624_read(struct v4l2_subdev *sd, u16 index)
 484{
 485        struct i2c_client *client = v4l2_get_subdevdata(sd);
 486        u8 buf[2];
 487
 488        buf[0] = index >> 8;
 489        buf[1] = index;
 490        i2c_master_send(client, buf, 2);
 491        i2c_master_recv(client, buf, 1);
 492
 493        return buf[0];
 494}
 495#endif
 496
 497static int vs6624_write(struct v4l2_subdev *sd, u16 index,
 498                                u8 value)
 499{
 500        struct i2c_client *client = v4l2_get_subdevdata(sd);
 501        u8 buf[3];
 502
 503        buf[0] = index >> 8;
 504        buf[1] = index;
 505        buf[2] = value;
 506
 507        return i2c_master_send(client, buf, 3);
 508}
 509
 510static int vs6624_writeregs(struct v4l2_subdev *sd, const u16 *regs)
 511{
 512        u16 reg;
 513        u8 data;
 514
 515        while (*regs != 0x00) {
 516                reg = *regs++;
 517                data = *regs++;
 518
 519                vs6624_write(sd, reg, data);
 520        }
 521        return 0;
 522}
 523
 524static int vs6624_s_ctrl(struct v4l2_ctrl *ctrl)
 525{
 526        struct v4l2_subdev *sd = to_sd(ctrl);
 527
 528        switch (ctrl->id) {
 529        case V4L2_CID_CONTRAST:
 530                vs6624_write(sd, VS6624_CONTRAST0, ctrl->val);
 531                break;
 532        case V4L2_CID_SATURATION:
 533                vs6624_write(sd, VS6624_SATURATION0, ctrl->val);
 534                break;
 535        case V4L2_CID_HFLIP:
 536                vs6624_write(sd, VS6624_HMIRROR0, ctrl->val);
 537                break;
 538        case V4L2_CID_VFLIP:
 539                vs6624_write(sd, VS6624_VFLIP0, ctrl->val);
 540                break;
 541        default:
 542                return -EINVAL;
 543        }
 544
 545        return 0;
 546}
 547
 548static int vs6624_enum_mbus_code(struct v4l2_subdev *sd,
 549                struct v4l2_subdev_pad_config *cfg,
 550                struct v4l2_subdev_mbus_code_enum *code)
 551{
 552        if (code->pad || code->index >= ARRAY_SIZE(vs6624_formats))
 553                return -EINVAL;
 554
 555        code->code = vs6624_formats[code->index].mbus_code;
 556        return 0;
 557}
 558
 559static int vs6624_set_fmt(struct v4l2_subdev *sd,
 560                struct v4l2_subdev_pad_config *cfg,
 561                struct v4l2_subdev_format *format)
 562{
 563        struct v4l2_mbus_framefmt *fmt = &format->format;
 564        struct vs6624 *sensor = to_vs6624(sd);
 565        int index;
 566
 567        if (format->pad)
 568                return -EINVAL;
 569
 570        for (index = 0; index < ARRAY_SIZE(vs6624_formats); index++)
 571                if (vs6624_formats[index].mbus_code == fmt->code)
 572                        break;
 573        if (index >= ARRAY_SIZE(vs6624_formats)) {
 574                /* default to first format */
 575                index = 0;
 576                fmt->code = vs6624_formats[0].mbus_code;
 577        }
 578
 579        /* sensor mode is VGA */
 580        if (fmt->width > VGA_WIDTH)
 581                fmt->width = VGA_WIDTH;
 582        if (fmt->height > VGA_HEIGHT)
 583                fmt->height = VGA_HEIGHT;
 584        fmt->width = fmt->width & (~3);
 585        fmt->height = fmt->height & (~3);
 586        fmt->field = V4L2_FIELD_NONE;
 587        fmt->colorspace = vs6624_formats[index].colorspace;
 588
 589        if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
 590                cfg->try_fmt = *fmt;
 591                return 0;
 592        }
 593
 594        /* set image format */
 595        switch (fmt->code) {
 596        case MEDIA_BUS_FMT_UYVY8_2X8:
 597                vs6624_write(sd, VS6624_IMG_FMT0, 0x0);
 598                vs6624_write(sd, VS6624_YUV_SETUP, 0x1);
 599                break;
 600        case MEDIA_BUS_FMT_YUYV8_2X8:
 601                vs6624_write(sd, VS6624_IMG_FMT0, 0x0);
 602                vs6624_write(sd, VS6624_YUV_SETUP, 0x3);
 603                break;
 604        case MEDIA_BUS_FMT_RGB565_2X8_LE:
 605                vs6624_write(sd, VS6624_IMG_FMT0, 0x4);
 606                vs6624_write(sd, VS6624_RGB_SETUP, 0x0);
 607                break;
 608        default:
 609                return -EINVAL;
 610        }
 611
 612        /* set image size */
 613        if ((fmt->width == VGA_WIDTH) && (fmt->height == VGA_HEIGHT))
 614                vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x2);
 615        else if ((fmt->width == QVGA_WIDTH) && (fmt->height == QVGA_HEIGHT))
 616                vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x4);
 617        else if ((fmt->width == QQVGA_WIDTH) && (fmt->height == QQVGA_HEIGHT))
 618                vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x6);
 619        else if ((fmt->width == CIF_WIDTH) && (fmt->height == CIF_HEIGHT))
 620                vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x3);
 621        else if ((fmt->width == QCIF_WIDTH) && (fmt->height == QCIF_HEIGHT))
 622                vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x5);
 623        else if ((fmt->width == QQCIF_WIDTH) && (fmt->height == QQCIF_HEIGHT))
 624                vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x7);
 625        else {
 626                vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x8);
 627                vs6624_write(sd, VS6624_MAN_HSIZE0_MSB, fmt->width >> 8);
 628                vs6624_write(sd, VS6624_MAN_HSIZE0_LSB, fmt->width & 0xFF);
 629                vs6624_write(sd, VS6624_MAN_VSIZE0_MSB, fmt->height >> 8);
 630                vs6624_write(sd, VS6624_MAN_VSIZE0_LSB, fmt->height & 0xFF);
 631                vs6624_write(sd, VS6624_CROP_CTRL0, 0x1);
 632        }
 633
 634        sensor->fmt = *fmt;
 635
 636        return 0;
 637}
 638
 639static int vs6624_get_fmt(struct v4l2_subdev *sd,
 640                struct v4l2_subdev_pad_config *cfg,
 641                struct v4l2_subdev_format *format)
 642{
 643        struct vs6624 *sensor = to_vs6624(sd);
 644
 645        if (format->pad)
 646                return -EINVAL;
 647
 648        format->format = sensor->fmt;
 649        return 0;
 650}
 651
 652static int vs6624_g_frame_interval(struct v4l2_subdev *sd,
 653                                   struct v4l2_subdev_frame_interval *ival)
 654{
 655        struct vs6624 *sensor = to_vs6624(sd);
 656
 657        ival->interval.numerator = sensor->frame_rate.denominator;
 658        ival->interval.denominator = sensor->frame_rate.numerator;
 659        return 0;
 660}
 661
 662static int vs6624_s_frame_interval(struct v4l2_subdev *sd,
 663                                   struct v4l2_subdev_frame_interval *ival)
 664{
 665        struct vs6624 *sensor = to_vs6624(sd);
 666        struct v4l2_fract *tpf = &ival->interval;
 667
 668
 669        if (tpf->numerator == 0 || tpf->denominator == 0
 670                || (tpf->denominator > tpf->numerator * MAX_FRAME_RATE)) {
 671                /* reset to max frame rate */
 672                tpf->numerator = 1;
 673                tpf->denominator = MAX_FRAME_RATE;
 674        }
 675        sensor->frame_rate.numerator = tpf->denominator;
 676        sensor->frame_rate.denominator = tpf->numerator;
 677        vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0);
 678        vs6624_write(sd, VS6624_FR_NUM_MSB,
 679                        sensor->frame_rate.numerator >> 8);
 680        vs6624_write(sd, VS6624_FR_NUM_LSB,
 681                        sensor->frame_rate.numerator & 0xFF);
 682        vs6624_write(sd, VS6624_FR_DEN,
 683                        sensor->frame_rate.denominator & 0xFF);
 684        return 0;
 685}
 686
 687static int vs6624_s_stream(struct v4l2_subdev *sd, int enable)
 688{
 689        if (enable)
 690                vs6624_write(sd, VS6624_USER_CMD, 0x2);
 691        else
 692                vs6624_write(sd, VS6624_USER_CMD, 0x4);
 693        udelay(100);
 694        return 0;
 695}
 696
 697#ifdef CONFIG_VIDEO_ADV_DEBUG
 698static int vs6624_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
 699{
 700        reg->val = vs6624_read(sd, reg->reg & 0xffff);
 701        reg->size = 1;
 702        return 0;
 703}
 704
 705static int vs6624_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
 706{
 707        vs6624_write(sd, reg->reg & 0xffff, reg->val & 0xff);
 708        return 0;
 709}
 710#endif
 711
 712static const struct v4l2_ctrl_ops vs6624_ctrl_ops = {
 713        .s_ctrl = vs6624_s_ctrl,
 714};
 715
 716static const struct v4l2_subdev_core_ops vs6624_core_ops = {
 717#ifdef CONFIG_VIDEO_ADV_DEBUG
 718        .g_register = vs6624_g_register,
 719        .s_register = vs6624_s_register,
 720#endif
 721};
 722
 723static const struct v4l2_subdev_video_ops vs6624_video_ops = {
 724        .s_frame_interval = vs6624_s_frame_interval,
 725        .g_frame_interval = vs6624_g_frame_interval,
 726        .s_stream = vs6624_s_stream,
 727};
 728
 729static const struct v4l2_subdev_pad_ops vs6624_pad_ops = {
 730        .enum_mbus_code = vs6624_enum_mbus_code,
 731        .get_fmt = vs6624_get_fmt,
 732        .set_fmt = vs6624_set_fmt,
 733};
 734
 735static const struct v4l2_subdev_ops vs6624_ops = {
 736        .core = &vs6624_core_ops,
 737        .video = &vs6624_video_ops,
 738        .pad = &vs6624_pad_ops,
 739};
 740
 741static int vs6624_probe(struct i2c_client *client,
 742                        const struct i2c_device_id *id)
 743{
 744        struct vs6624 *sensor;
 745        struct v4l2_subdev *sd;
 746        struct v4l2_ctrl_handler *hdl;
 747        const unsigned *ce;
 748        int ret;
 749
 750        /* Check if the adapter supports the needed features */
 751        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
 752                return -EIO;
 753
 754        ce = client->dev.platform_data;
 755        if (ce == NULL)
 756                return -EINVAL;
 757
 758        ret = devm_gpio_request_one(&client->dev, *ce, GPIOF_OUT_INIT_HIGH,
 759                                    "VS6624 Chip Enable");
 760        if (ret) {
 761                v4l_err(client, "failed to request GPIO %d\n", *ce);
 762                return ret;
 763        }
 764        /* wait 100ms before any further i2c writes are performed */
 765        msleep(100);
 766
 767        sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
 768        if (sensor == NULL)
 769                return -ENOMEM;
 770
 771        sd = &sensor->sd;
 772        v4l2_i2c_subdev_init(sd, client, &vs6624_ops);
 773
 774        vs6624_writeregs(sd, vs6624_p1);
 775        vs6624_write(sd, VS6624_MICRO_EN, 0x2);
 776        vs6624_write(sd, VS6624_DIO_EN, 0x1);
 777        usleep_range(10000, 11000);
 778        vs6624_writeregs(sd, vs6624_p2);
 779
 780        vs6624_writeregs(sd, vs6624_default);
 781        vs6624_write(sd, VS6624_HSYNC_SETUP, 0xF);
 782        vs6624_writeregs(sd, vs6624_run_setup);
 783
 784        /* set frame rate */
 785        sensor->frame_rate.numerator = MAX_FRAME_RATE;
 786        sensor->frame_rate.denominator = 1;
 787        vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0);
 788        vs6624_write(sd, VS6624_FR_NUM_MSB,
 789                        sensor->frame_rate.numerator >> 8);
 790        vs6624_write(sd, VS6624_FR_NUM_LSB,
 791                        sensor->frame_rate.numerator & 0xFF);
 792        vs6624_write(sd, VS6624_FR_DEN,
 793                        sensor->frame_rate.denominator & 0xFF);
 794
 795        sensor->fmt = vs6624_default_fmt;
 796        sensor->ce_pin = *ce;
 797
 798        v4l_info(client, "chip found @ 0x%02x (%s)\n",
 799                        client->addr << 1, client->adapter->name);
 800
 801        hdl = &sensor->hdl;
 802        v4l2_ctrl_handler_init(hdl, 4);
 803        v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
 804                        V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x87);
 805        v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
 806                        V4L2_CID_SATURATION, 0, 0xFF, 1, 0x78);
 807        v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
 808                        V4L2_CID_HFLIP, 0, 1, 1, 0);
 809        v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
 810                        V4L2_CID_VFLIP, 0, 1, 1, 0);
 811        /* hook the control handler into the driver */
 812        sd->ctrl_handler = hdl;
 813        if (hdl->error) {
 814                int err = hdl->error;
 815
 816                v4l2_ctrl_handler_free(hdl);
 817                return err;
 818        }
 819
 820        /* initialize the hardware to the default control values */
 821        ret = v4l2_ctrl_handler_setup(hdl);
 822        if (ret)
 823                v4l2_ctrl_handler_free(hdl);
 824        return ret;
 825}
 826
 827static int vs6624_remove(struct i2c_client *client)
 828{
 829        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 830
 831        v4l2_device_unregister_subdev(sd);
 832        v4l2_ctrl_handler_free(sd->ctrl_handler);
 833        return 0;
 834}
 835
 836static const struct i2c_device_id vs6624_id[] = {
 837        {"vs6624", 0},
 838        {},
 839};
 840
 841MODULE_DEVICE_TABLE(i2c, vs6624_id);
 842
 843static struct i2c_driver vs6624_driver = {
 844        .driver = {
 845                .name   = "vs6624",
 846        },
 847        .probe          = vs6624_probe,
 848        .remove         = vs6624_remove,
 849        .id_table       = vs6624_id,
 850};
 851
 852module_i2c_driver(vs6624_driver);
 853
 854MODULE_DESCRIPTION("VS6624 sensor driver");
 855MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
 856MODULE_LICENSE("GPL v2");
 857