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