Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * vs6624.c ST VS6624 CMOS image sensor driver
0004  *
0005  * Copyright (c) 2011 Analog Devices Inc.
0006  */
0007 
0008 #include <linux/delay.h>
0009 #include <linux/errno.h>
0010 #include <linux/gpio.h>
0011 #include <linux/i2c.h>
0012 #include <linux/init.h>
0013 #include <linux/module.h>
0014 #include <linux/slab.h>
0015 #include <linux/types.h>
0016 #include <linux/videodev2.h>
0017 
0018 #include <media/v4l2-ctrls.h>
0019 #include <media/v4l2-device.h>
0020 #include <media/v4l2-mediabus.h>
0021 #include <media/v4l2-image-sizes.h>
0022 
0023 #include "vs6624_regs.h"
0024 
0025 #define MAX_FRAME_RATE  30
0026 
0027 struct vs6624 {
0028     struct v4l2_subdev sd;
0029     struct v4l2_ctrl_handler hdl;
0030     struct v4l2_fract frame_rate;
0031     struct v4l2_mbus_framefmt fmt;
0032     unsigned ce_pin;
0033 };
0034 
0035 static const struct vs6624_format {
0036     u32 mbus_code;
0037     enum v4l2_colorspace colorspace;
0038 } vs6624_formats[] = {
0039     {
0040         .mbus_code      = MEDIA_BUS_FMT_UYVY8_2X8,
0041         .colorspace     = V4L2_COLORSPACE_JPEG,
0042     },
0043     {
0044         .mbus_code      = MEDIA_BUS_FMT_YUYV8_2X8,
0045         .colorspace     = V4L2_COLORSPACE_JPEG,
0046     },
0047     {
0048         .mbus_code      = MEDIA_BUS_FMT_RGB565_2X8_LE,
0049         .colorspace     = V4L2_COLORSPACE_SRGB,
0050     },
0051 };
0052 
0053 static const struct v4l2_mbus_framefmt vs6624_default_fmt = {
0054     .width = VGA_WIDTH,
0055     .height = VGA_HEIGHT,
0056     .code = MEDIA_BUS_FMT_UYVY8_2X8,
0057     .field = V4L2_FIELD_NONE,
0058     .colorspace = V4L2_COLORSPACE_JPEG,
0059 };
0060 
0061 static const u16 vs6624_p1[] = {
0062     0x8104, 0x03,
0063     0x8105, 0x01,
0064     0xc900, 0x03,
0065     0xc904, 0x47,
0066     0xc905, 0x10,
0067     0xc906, 0x80,
0068     0xc907, 0x3a,
0069     0x903a, 0x02,
0070     0x903b, 0x47,
0071     0x903c, 0x15,
0072     0xc908, 0x31,
0073     0xc909, 0xdc,
0074     0xc90a, 0x80,
0075     0xc90b, 0x44,
0076     0x9044, 0x02,
0077     0x9045, 0x31,
0078     0x9046, 0xe2,
0079     0xc90c, 0x07,
0080     0xc90d, 0xe0,
0081     0xc90e, 0x80,
0082     0xc90f, 0x47,
0083     0x9047, 0x90,
0084     0x9048, 0x83,
0085     0x9049, 0x81,
0086     0x904a, 0xe0,
0087     0x904b, 0x60,
0088     0x904c, 0x08,
0089     0x904d, 0x90,
0090     0x904e, 0xc0,
0091     0x904f, 0x43,
0092     0x9050, 0x74,
0093     0x9051, 0x01,
0094     0x9052, 0xf0,
0095     0x9053, 0x80,
0096     0x9054, 0x05,
0097     0x9055, 0xE4,
0098     0x9056, 0x90,
0099     0x9057, 0xc0,
0100     0x9058, 0x43,
0101     0x9059, 0xf0,
0102     0x905a, 0x02,
0103     0x905b, 0x07,
0104     0x905c, 0xec,
0105     0xc910, 0x5d,
0106     0xc911, 0xca,
0107     0xc912, 0x80,
0108     0xc913, 0x5d,
0109     0x905d, 0xa3,
0110     0x905e, 0x04,
0111     0x905f, 0xf0,
0112     0x9060, 0xa3,
0113     0x9061, 0x04,
0114     0x9062, 0xf0,
0115     0x9063, 0x22,
0116     0xc914, 0x72,
0117     0xc915, 0x92,
0118     0xc916, 0x80,
0119     0xc917, 0x64,
0120     0x9064, 0x74,
0121     0x9065, 0x01,
0122     0x9066, 0x02,
0123     0x9067, 0x72,
0124     0x9068, 0x95,
0125     0xc918, 0x47,
0126     0xc919, 0xf2,
0127     0xc91a, 0x81,
0128     0xc91b, 0x69,
0129     0x9169, 0x74,
0130     0x916a, 0x02,
0131     0x916b, 0xf0,
0132     0x916c, 0xec,
0133     0x916d, 0xb4,
0134     0x916e, 0x10,
0135     0x916f, 0x0a,
0136     0x9170, 0x90,
0137     0x9171, 0x80,
0138     0x9172, 0x16,
0139     0x9173, 0xe0,
0140     0x9174, 0x70,
0141     0x9175, 0x04,
0142     0x9176, 0x90,
0143     0x9177, 0xd3,
0144     0x9178, 0xc4,
0145     0x9179, 0xf0,
0146     0x917a, 0x22,
0147     0xc91c, 0x0a,
0148     0xc91d, 0xbe,
0149     0xc91e, 0x80,
0150     0xc91f, 0x73,
0151     0x9073, 0xfc,
0152     0x9074, 0xa3,
0153     0x9075, 0xe0,
0154     0x9076, 0xf5,
0155     0x9077, 0x82,
0156     0x9078, 0x8c,
0157     0x9079, 0x83,
0158     0x907a, 0xa3,
0159     0x907b, 0xa3,
0160     0x907c, 0xe0,
0161     0x907d, 0xfc,
0162     0x907e, 0xa3,
0163     0x907f, 0xe0,
0164     0x9080, 0xc3,
0165     0x9081, 0x9f,
0166     0x9082, 0xff,
0167     0x9083, 0xec,
0168     0x9084, 0x9e,
0169     0x9085, 0xfe,
0170     0x9086, 0x02,
0171     0x9087, 0x0a,
0172     0x9088, 0xea,
0173     0xc920, 0x47,
0174     0xc921, 0x38,
0175     0xc922, 0x80,
0176     0xc923, 0x89,
0177     0x9089, 0xec,
0178     0x908a, 0xd3,
0179     0x908b, 0x94,
0180     0x908c, 0x20,
0181     0x908d, 0x40,
0182     0x908e, 0x01,
0183     0x908f, 0x1c,
0184     0x9090, 0x90,
0185     0x9091, 0xd3,
0186     0x9092, 0xd4,
0187     0x9093, 0xec,
0188     0x9094, 0xf0,
0189     0x9095, 0x02,
0190     0x9096, 0x47,
0191     0x9097, 0x3d,
0192     0xc924, 0x45,
0193     0xc925, 0xca,
0194     0xc926, 0x80,
0195     0xc927, 0x98,
0196     0x9098, 0x12,
0197     0x9099, 0x77,
0198     0x909a, 0xd6,
0199     0x909b, 0x02,
0200     0x909c, 0x45,
0201     0x909d, 0xcd,
0202     0xc928, 0x20,
0203     0xc929, 0xd5,
0204     0xc92a, 0x80,
0205     0xc92b, 0x9e,
0206     0x909e, 0x90,
0207     0x909f, 0x82,
0208     0x90a0, 0x18,
0209     0x90a1, 0xe0,
0210     0x90a2, 0xb4,
0211     0x90a3, 0x03,
0212     0x90a4, 0x0e,
0213     0x90a5, 0x90,
0214     0x90a6, 0x83,
0215     0x90a7, 0xbf,
0216     0x90a8, 0xe0,
0217     0x90a9, 0x60,
0218     0x90aa, 0x08,
0219     0x90ab, 0x90,
0220     0x90ac, 0x81,
0221     0x90ad, 0xfc,
0222     0x90ae, 0xe0,
0223     0x90af, 0xff,
0224     0x90b0, 0xc3,
0225     0x90b1, 0x13,
0226     0x90b2, 0xf0,
0227     0x90b3, 0x90,
0228     0x90b4, 0x81,
0229     0x90b5, 0xfc,
0230     0x90b6, 0xe0,
0231     0x90b7, 0xff,
0232     0x90b8, 0x02,
0233     0x90b9, 0x20,
0234     0x90ba, 0xda,
0235     0xc92c, 0x70,
0236     0xc92d, 0xbc,
0237     0xc92e, 0x80,
0238     0xc92f, 0xbb,
0239     0x90bb, 0x90,
0240     0x90bc, 0x82,
0241     0x90bd, 0x18,
0242     0x90be, 0xe0,
0243     0x90bf, 0xb4,
0244     0x90c0, 0x03,
0245     0x90c1, 0x06,
0246     0x90c2, 0x90,
0247     0x90c3, 0xc1,
0248     0x90c4, 0x06,
0249     0x90c5, 0x74,
0250     0x90c6, 0x05,
0251     0x90c7, 0xf0,
0252     0x90c8, 0x90,
0253     0x90c9, 0xd3,
0254     0x90ca, 0xa0,
0255     0x90cb, 0x02,
0256     0x90cc, 0x70,
0257     0x90cd, 0xbf,
0258     0xc930, 0x72,
0259     0xc931, 0x21,
0260     0xc932, 0x81,
0261     0xc933, 0x3b,
0262     0x913b, 0x7d,
0263     0x913c, 0x02,
0264     0x913d, 0x7f,
0265     0x913e, 0x7b,
0266     0x913f, 0x02,
0267     0x9140, 0x72,
0268     0x9141, 0x25,
0269     0xc934, 0x28,
0270     0xc935, 0xae,
0271     0xc936, 0x80,
0272     0xc937, 0xd2,
0273     0x90d2, 0xf0,
0274     0x90d3, 0x90,
0275     0x90d4, 0xd2,
0276     0x90d5, 0x0a,
0277     0x90d6, 0x02,
0278     0x90d7, 0x28,
0279     0x90d8, 0xb4,
0280     0xc938, 0x28,
0281     0xc939, 0xb1,
0282     0xc93a, 0x80,
0283     0xc93b, 0xd9,
0284     0x90d9, 0x90,
0285     0x90da, 0x83,
0286     0x90db, 0xba,
0287     0x90dc, 0xe0,
0288     0x90dd, 0xff,
0289     0x90de, 0x90,
0290     0x90df, 0xd2,
0291     0x90e0, 0x08,
0292     0x90e1, 0xe0,
0293     0x90e2, 0xe4,
0294     0x90e3, 0xef,
0295     0x90e4, 0xf0,
0296     0x90e5, 0xa3,
0297     0x90e6, 0xe0,
0298     0x90e7, 0x74,
0299     0x90e8, 0xff,
0300     0x90e9, 0xf0,
0301     0x90ea, 0x90,
0302     0x90eb, 0xd2,
0303     0x90ec, 0x0a,
0304     0x90ed, 0x02,
0305     0x90ee, 0x28,
0306     0x90ef, 0xb4,
0307     0xc93c, 0x29,
0308     0xc93d, 0x79,
0309     0xc93e, 0x80,
0310     0xc93f, 0xf0,
0311     0x90f0, 0xf0,
0312     0x90f1, 0x90,
0313     0x90f2, 0xd2,
0314     0x90f3, 0x0e,
0315     0x90f4, 0x02,
0316     0x90f5, 0x29,
0317     0x90f6, 0x7f,
0318     0xc940, 0x29,
0319     0xc941, 0x7c,
0320     0xc942, 0x80,
0321     0xc943, 0xf7,
0322     0x90f7, 0x90,
0323     0x90f8, 0x83,
0324     0x90f9, 0xba,
0325     0x90fa, 0xe0,
0326     0x90fb, 0xff,
0327     0x90fc, 0x90,
0328     0x90fd, 0xd2,
0329     0x90fe, 0x0c,
0330     0x90ff, 0xe0,
0331     0x9100, 0xe4,
0332     0x9101, 0xef,
0333     0x9102, 0xf0,
0334     0x9103, 0xa3,
0335     0x9104, 0xe0,
0336     0x9105, 0x74,
0337     0x9106, 0xff,
0338     0x9107, 0xf0,
0339     0x9108, 0x90,
0340     0x9109, 0xd2,
0341     0x910a, 0x0e,
0342     0x910b, 0x02,
0343     0x910c, 0x29,
0344     0x910d, 0x7f,
0345     0xc944, 0x2a,
0346     0xc945, 0x42,
0347     0xc946, 0x81,
0348     0xc947, 0x0e,
0349     0x910e, 0xf0,
0350     0x910f, 0x90,
0351     0x9110, 0xd2,
0352     0x9111, 0x12,
0353     0x9112, 0x02,
0354     0x9113, 0x2a,
0355     0x9114, 0x48,
0356     0xc948, 0x2a,
0357     0xc949, 0x45,
0358     0xc94a, 0x81,
0359     0xc94b, 0x15,
0360     0x9115, 0x90,
0361     0x9116, 0x83,
0362     0x9117, 0xba,
0363     0x9118, 0xe0,
0364     0x9119, 0xff,
0365     0x911a, 0x90,
0366     0x911b, 0xd2,
0367     0x911c, 0x10,
0368     0x911d, 0xe0,
0369     0x911e, 0xe4,
0370     0x911f, 0xef,
0371     0x9120, 0xf0,
0372     0x9121, 0xa3,
0373     0x9122, 0xe0,
0374     0x9123, 0x74,
0375     0x9124, 0xff,
0376     0x9125, 0xf0,
0377     0x9126, 0x90,
0378     0x9127, 0xd2,
0379     0x9128, 0x12,
0380     0x9129, 0x02,
0381     0x912a, 0x2a,
0382     0x912b, 0x48,
0383     0xc900, 0x01,
0384     0x0000, 0x00,
0385 };
0386 
0387 static const u16 vs6624_p2[] = {
0388     0x806f, 0x01,
0389     0x058c, 0x01,
0390     0x0000, 0x00,
0391 };
0392 
0393 static const u16 vs6624_run_setup[] = {
0394     0x1d18, 0x00,               /* Enableconstrainedwhitebalance */
0395     VS6624_PEAK_MIN_OUT_G_MSB, 0x3c,    /* Damper PeakGain Output MSB */
0396     VS6624_PEAK_MIN_OUT_G_LSB, 0x66,    /* Damper PeakGain Output LSB */
0397     VS6624_CM_LOW_THR_MSB, 0x65,        /* Damper Low MSB */
0398     VS6624_CM_LOW_THR_LSB, 0xd1,        /* Damper Low LSB */
0399     VS6624_CM_HIGH_THR_MSB, 0x66,       /* Damper High MSB */
0400     VS6624_CM_HIGH_THR_LSB, 0x62,       /* Damper High LSB */
0401     VS6624_CM_MIN_OUT_MSB, 0x00,        /* Damper Min output MSB */
0402     VS6624_CM_MIN_OUT_LSB, 0x00,        /* Damper Min output LSB */
0403     VS6624_NORA_DISABLE, 0x00,      /* Nora fDisable */
0404     VS6624_NORA_USAGE, 0x04,        /* Nora usage */
0405     VS6624_NORA_LOW_THR_MSB, 0x63,      /* Damper Low MSB Changed 0x63 to 0x65 */
0406     VS6624_NORA_LOW_THR_LSB, 0xd1,      /* Damper Low LSB */
0407     VS6624_NORA_HIGH_THR_MSB, 0x68,     /* Damper High MSB */
0408     VS6624_NORA_HIGH_THR_LSB, 0xdd,     /* Damper High LSB */
0409     VS6624_NORA_MIN_OUT_MSB, 0x3a,      /* Damper Min output MSB */
0410     VS6624_NORA_MIN_OUT_LSB, 0x00,      /* Damper Min output LSB */
0411     VS6624_F2B_DISABLE, 0x00,       /* Disable */
0412     0x1d8a, 0x30,               /* MAXWeightHigh */
0413     0x1d91, 0x62,               /* fpDamperLowThresholdHigh MSB */
0414     0x1d92, 0x4a,               /* fpDamperLowThresholdHigh LSB */
0415     0x1d95, 0x65,               /* fpDamperHighThresholdHigh MSB */
0416     0x1d96, 0x0e,               /* fpDamperHighThresholdHigh LSB */
0417     0x1da1, 0x3a,               /* fpMinimumDamperOutputLow MSB */
0418     0x1da2, 0xb8,               /* fpMinimumDamperOutputLow LSB */
0419     0x1e08, 0x06,               /* MAXWeightLow */
0420     0x1e0a, 0x0a,               /* MAXWeightHigh */
0421     0x1601, 0x3a,               /* Red A MSB */
0422     0x1602, 0x14,               /* Red A LSB */
0423     0x1605, 0x3b,               /* Blue A MSB */
0424     0x1606, 0x85,               /* BLue A LSB */
0425     0x1609, 0x3b,               /* RED B MSB */
0426     0x160a, 0x85,               /* RED B LSB */
0427     0x160d, 0x3a,               /* Blue B MSB */
0428     0x160e, 0x14,               /* Blue B LSB */
0429     0x1611, 0x30,               /* Max Distance from Locus MSB */
0430     0x1612, 0x8f,               /* Max Distance from Locus MSB */
0431     0x1614, 0x01,               /* Enable constrainer */
0432     0x0000, 0x00,
0433 };
0434 
0435 static const u16 vs6624_default[] = {
0436     VS6624_CONTRAST0, 0x84,
0437     VS6624_SATURATION0, 0x75,
0438     VS6624_GAMMA0, 0x11,
0439     VS6624_CONTRAST1, 0x84,
0440     VS6624_SATURATION1, 0x75,
0441     VS6624_GAMMA1, 0x11,
0442     VS6624_MAN_RG, 0x80,
0443     VS6624_MAN_GG, 0x80,
0444     VS6624_MAN_BG, 0x80,
0445     VS6624_WB_MODE, 0x1,
0446     VS6624_EXPO_COMPENSATION, 0xfe,
0447     VS6624_EXPO_METER, 0x0,
0448     VS6624_LIGHT_FREQ, 0x64,
0449     VS6624_PEAK_GAIN, 0xe,
0450     VS6624_PEAK_LOW_THR, 0x28,
0451     VS6624_HMIRROR0, 0x0,
0452     VS6624_VFLIP0, 0x0,
0453     VS6624_ZOOM_HSTEP0_MSB, 0x0,
0454     VS6624_ZOOM_HSTEP0_LSB, 0x1,
0455     VS6624_ZOOM_VSTEP0_MSB, 0x0,
0456     VS6624_ZOOM_VSTEP0_LSB, 0x1,
0457     VS6624_PAN_HSTEP0_MSB, 0x0,
0458     VS6624_PAN_HSTEP0_LSB, 0xf,
0459     VS6624_PAN_VSTEP0_MSB, 0x0,
0460     VS6624_PAN_VSTEP0_LSB, 0xf,
0461     VS6624_SENSOR_MODE, 0x1,
0462     VS6624_SYNC_CODE_SETUP, 0x21,
0463     VS6624_DISABLE_FR_DAMPER, 0x0,
0464     VS6624_FR_DEN, 0x1,
0465     VS6624_FR_NUM_LSB, 0xf,
0466     VS6624_INIT_PIPE_SETUP, 0x0,
0467     VS6624_IMG_FMT0, 0x0,
0468     VS6624_YUV_SETUP, 0x1,
0469     VS6624_IMAGE_SIZE0, 0x2,
0470     0x0000, 0x00,
0471 };
0472 
0473 static inline struct vs6624 *to_vs6624(struct v4l2_subdev *sd)
0474 {
0475     return container_of(sd, struct vs6624, sd);
0476 }
0477 static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
0478 {
0479     return &container_of(ctrl->handler, struct vs6624, hdl)->sd;
0480 }
0481 
0482 #ifdef CONFIG_VIDEO_ADV_DEBUG
0483 static int vs6624_read(struct v4l2_subdev *sd, u16 index)
0484 {
0485     struct i2c_client *client = v4l2_get_subdevdata(sd);
0486     u8 buf[2];
0487 
0488     buf[0] = index >> 8;
0489     buf[1] = index;
0490     i2c_master_send(client, buf, 2);
0491     i2c_master_recv(client, buf, 1);
0492 
0493     return buf[0];
0494 }
0495 #endif
0496 
0497 static int vs6624_write(struct v4l2_subdev *sd, u16 index,
0498                 u8 value)
0499 {
0500     struct i2c_client *client = v4l2_get_subdevdata(sd);
0501     u8 buf[3];
0502 
0503     buf[0] = index >> 8;
0504     buf[1] = index;
0505     buf[2] = value;
0506 
0507     return i2c_master_send(client, buf, 3);
0508 }
0509 
0510 static int vs6624_writeregs(struct v4l2_subdev *sd, const u16 *regs)
0511 {
0512     u16 reg;
0513     u8 data;
0514 
0515     while (*regs != 0x00) {
0516         reg = *regs++;
0517         data = *regs++;
0518 
0519         vs6624_write(sd, reg, data);
0520     }
0521     return 0;
0522 }
0523 
0524 static int vs6624_s_ctrl(struct v4l2_ctrl *ctrl)
0525 {
0526     struct v4l2_subdev *sd = to_sd(ctrl);
0527 
0528     switch (ctrl->id) {
0529     case V4L2_CID_CONTRAST:
0530         vs6624_write(sd, VS6624_CONTRAST0, ctrl->val);
0531         break;
0532     case V4L2_CID_SATURATION:
0533         vs6624_write(sd, VS6624_SATURATION0, ctrl->val);
0534         break;
0535     case V4L2_CID_HFLIP:
0536         vs6624_write(sd, VS6624_HMIRROR0, ctrl->val);
0537         break;
0538     case V4L2_CID_VFLIP:
0539         vs6624_write(sd, VS6624_VFLIP0, ctrl->val);
0540         break;
0541     default:
0542         return -EINVAL;
0543     }
0544 
0545     return 0;
0546 }
0547 
0548 static int vs6624_enum_mbus_code(struct v4l2_subdev *sd,
0549         struct v4l2_subdev_state *sd_state,
0550         struct v4l2_subdev_mbus_code_enum *code)
0551 {
0552     if (code->pad || code->index >= ARRAY_SIZE(vs6624_formats))
0553         return -EINVAL;
0554 
0555     code->code = vs6624_formats[code->index].mbus_code;
0556     return 0;
0557 }
0558 
0559 static int vs6624_set_fmt(struct v4l2_subdev *sd,
0560         struct v4l2_subdev_state *sd_state,
0561         struct v4l2_subdev_format *format)
0562 {
0563     struct v4l2_mbus_framefmt *fmt = &format->format;
0564     struct vs6624 *sensor = to_vs6624(sd);
0565     int index;
0566 
0567     if (format->pad)
0568         return -EINVAL;
0569 
0570     for (index = 0; index < ARRAY_SIZE(vs6624_formats); index++)
0571         if (vs6624_formats[index].mbus_code == fmt->code)
0572             break;
0573     if (index >= ARRAY_SIZE(vs6624_formats)) {
0574         /* default to first format */
0575         index = 0;
0576         fmt->code = vs6624_formats[0].mbus_code;
0577     }
0578 
0579     /* sensor mode is VGA */
0580     if (fmt->width > VGA_WIDTH)
0581         fmt->width = VGA_WIDTH;
0582     if (fmt->height > VGA_HEIGHT)
0583         fmt->height = VGA_HEIGHT;
0584     fmt->width = fmt->width & (~3);
0585     fmt->height = fmt->height & (~3);
0586     fmt->field = V4L2_FIELD_NONE;
0587     fmt->colorspace = vs6624_formats[index].colorspace;
0588 
0589     if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
0590         sd_state->pads->try_fmt = *fmt;
0591         return 0;
0592     }
0593 
0594     /* set image format */
0595     switch (fmt->code) {
0596     case MEDIA_BUS_FMT_UYVY8_2X8:
0597         vs6624_write(sd, VS6624_IMG_FMT0, 0x0);
0598         vs6624_write(sd, VS6624_YUV_SETUP, 0x1);
0599         break;
0600     case MEDIA_BUS_FMT_YUYV8_2X8:
0601         vs6624_write(sd, VS6624_IMG_FMT0, 0x0);
0602         vs6624_write(sd, VS6624_YUV_SETUP, 0x3);
0603         break;
0604     case MEDIA_BUS_FMT_RGB565_2X8_LE:
0605         vs6624_write(sd, VS6624_IMG_FMT0, 0x4);
0606         vs6624_write(sd, VS6624_RGB_SETUP, 0x0);
0607         break;
0608     default:
0609         return -EINVAL;
0610     }
0611 
0612     /* set image size */
0613     if ((fmt->width == VGA_WIDTH) && (fmt->height == VGA_HEIGHT))
0614         vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x2);
0615     else if ((fmt->width == QVGA_WIDTH) && (fmt->height == QVGA_HEIGHT))
0616         vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x4);
0617     else if ((fmt->width == QQVGA_WIDTH) && (fmt->height == QQVGA_HEIGHT))
0618         vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x6);
0619     else if ((fmt->width == CIF_WIDTH) && (fmt->height == CIF_HEIGHT))
0620         vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x3);
0621     else if ((fmt->width == QCIF_WIDTH) && (fmt->height == QCIF_HEIGHT))
0622         vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x5);
0623     else if ((fmt->width == QQCIF_WIDTH) && (fmt->height == QQCIF_HEIGHT))
0624         vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x7);
0625     else {
0626         vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x8);
0627         vs6624_write(sd, VS6624_MAN_HSIZE0_MSB, fmt->width >> 8);
0628         vs6624_write(sd, VS6624_MAN_HSIZE0_LSB, fmt->width & 0xFF);
0629         vs6624_write(sd, VS6624_MAN_VSIZE0_MSB, fmt->height >> 8);
0630         vs6624_write(sd, VS6624_MAN_VSIZE0_LSB, fmt->height & 0xFF);
0631         vs6624_write(sd, VS6624_CROP_CTRL0, 0x1);
0632     }
0633 
0634     sensor->fmt = *fmt;
0635 
0636     return 0;
0637 }
0638 
0639 static int vs6624_get_fmt(struct v4l2_subdev *sd,
0640         struct v4l2_subdev_state *sd_state,
0641         struct v4l2_subdev_format *format)
0642 {
0643     struct vs6624 *sensor = to_vs6624(sd);
0644 
0645     if (format->pad)
0646         return -EINVAL;
0647 
0648     format->format = sensor->fmt;
0649     return 0;
0650 }
0651 
0652 static int vs6624_g_frame_interval(struct v4l2_subdev *sd,
0653                    struct v4l2_subdev_frame_interval *ival)
0654 {
0655     struct vs6624 *sensor = to_vs6624(sd);
0656 
0657     ival->interval.numerator = sensor->frame_rate.denominator;
0658     ival->interval.denominator = sensor->frame_rate.numerator;
0659     return 0;
0660 }
0661 
0662 static int vs6624_s_frame_interval(struct v4l2_subdev *sd,
0663                    struct v4l2_subdev_frame_interval *ival)
0664 {
0665     struct vs6624 *sensor = to_vs6624(sd);
0666     struct v4l2_fract *tpf = &ival->interval;
0667 
0668 
0669     if (tpf->numerator == 0 || tpf->denominator == 0
0670         || (tpf->denominator > tpf->numerator * MAX_FRAME_RATE)) {
0671         /* reset to max frame rate */
0672         tpf->numerator = 1;
0673         tpf->denominator = MAX_FRAME_RATE;
0674     }
0675     sensor->frame_rate.numerator = tpf->denominator;
0676     sensor->frame_rate.denominator = tpf->numerator;
0677     vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0);
0678     vs6624_write(sd, VS6624_FR_NUM_MSB,
0679             sensor->frame_rate.numerator >> 8);
0680     vs6624_write(sd, VS6624_FR_NUM_LSB,
0681             sensor->frame_rate.numerator & 0xFF);
0682     vs6624_write(sd, VS6624_FR_DEN,
0683             sensor->frame_rate.denominator & 0xFF);
0684     return 0;
0685 }
0686 
0687 static int vs6624_s_stream(struct v4l2_subdev *sd, int enable)
0688 {
0689     if (enable)
0690         vs6624_write(sd, VS6624_USER_CMD, 0x2);
0691     else
0692         vs6624_write(sd, VS6624_USER_CMD, 0x4);
0693     udelay(100);
0694     return 0;
0695 }
0696 
0697 #ifdef CONFIG_VIDEO_ADV_DEBUG
0698 static int vs6624_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
0699 {
0700     reg->val = vs6624_read(sd, reg->reg & 0xffff);
0701     reg->size = 1;
0702     return 0;
0703 }
0704 
0705 static int vs6624_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
0706 {
0707     vs6624_write(sd, reg->reg & 0xffff, reg->val & 0xff);
0708     return 0;
0709 }
0710 #endif
0711 
0712 static const struct v4l2_ctrl_ops vs6624_ctrl_ops = {
0713     .s_ctrl = vs6624_s_ctrl,
0714 };
0715 
0716 static const struct v4l2_subdev_core_ops vs6624_core_ops = {
0717 #ifdef CONFIG_VIDEO_ADV_DEBUG
0718     .g_register = vs6624_g_register,
0719     .s_register = vs6624_s_register,
0720 #endif
0721 };
0722 
0723 static const struct v4l2_subdev_video_ops vs6624_video_ops = {
0724     .s_frame_interval = vs6624_s_frame_interval,
0725     .g_frame_interval = vs6624_g_frame_interval,
0726     .s_stream = vs6624_s_stream,
0727 };
0728 
0729 static const struct v4l2_subdev_pad_ops vs6624_pad_ops = {
0730     .enum_mbus_code = vs6624_enum_mbus_code,
0731     .get_fmt = vs6624_get_fmt,
0732     .set_fmt = vs6624_set_fmt,
0733 };
0734 
0735 static const struct v4l2_subdev_ops vs6624_ops = {
0736     .core = &vs6624_core_ops,
0737     .video = &vs6624_video_ops,
0738     .pad = &vs6624_pad_ops,
0739 };
0740 
0741 static int vs6624_probe(struct i2c_client *client,
0742             const struct i2c_device_id *id)
0743 {
0744     struct vs6624 *sensor;
0745     struct v4l2_subdev *sd;
0746     struct v4l2_ctrl_handler *hdl;
0747     const unsigned *ce;
0748     int ret;
0749 
0750     /* Check if the adapter supports the needed features */
0751     if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
0752         return -EIO;
0753 
0754     ce = client->dev.platform_data;
0755     if (ce == NULL)
0756         return -EINVAL;
0757 
0758     ret = devm_gpio_request_one(&client->dev, *ce, GPIOF_OUT_INIT_HIGH,
0759                     "VS6624 Chip Enable");
0760     if (ret) {
0761         v4l_err(client, "failed to request GPIO %d\n", *ce);
0762         return ret;
0763     }
0764     /* wait 100ms before any further i2c writes are performed */
0765     msleep(100);
0766 
0767     sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
0768     if (sensor == NULL)
0769         return -ENOMEM;
0770 
0771     sd = &sensor->sd;
0772     v4l2_i2c_subdev_init(sd, client, &vs6624_ops);
0773 
0774     vs6624_writeregs(sd, vs6624_p1);
0775     vs6624_write(sd, VS6624_MICRO_EN, 0x2);
0776     vs6624_write(sd, VS6624_DIO_EN, 0x1);
0777     usleep_range(10000, 11000);
0778     vs6624_writeregs(sd, vs6624_p2);
0779 
0780     vs6624_writeregs(sd, vs6624_default);
0781     vs6624_write(sd, VS6624_HSYNC_SETUP, 0xF);
0782     vs6624_writeregs(sd, vs6624_run_setup);
0783 
0784     /* set frame rate */
0785     sensor->frame_rate.numerator = MAX_FRAME_RATE;
0786     sensor->frame_rate.denominator = 1;
0787     vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0);
0788     vs6624_write(sd, VS6624_FR_NUM_MSB,
0789             sensor->frame_rate.numerator >> 8);
0790     vs6624_write(sd, VS6624_FR_NUM_LSB,
0791             sensor->frame_rate.numerator & 0xFF);
0792     vs6624_write(sd, VS6624_FR_DEN,
0793             sensor->frame_rate.denominator & 0xFF);
0794 
0795     sensor->fmt = vs6624_default_fmt;
0796     sensor->ce_pin = *ce;
0797 
0798     v4l_info(client, "chip found @ 0x%02x (%s)\n",
0799             client->addr << 1, client->adapter->name);
0800 
0801     hdl = &sensor->hdl;
0802     v4l2_ctrl_handler_init(hdl, 4);
0803     v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
0804             V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x87);
0805     v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
0806             V4L2_CID_SATURATION, 0, 0xFF, 1, 0x78);
0807     v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
0808             V4L2_CID_HFLIP, 0, 1, 1, 0);
0809     v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
0810             V4L2_CID_VFLIP, 0, 1, 1, 0);
0811     /* hook the control handler into the driver */
0812     sd->ctrl_handler = hdl;
0813     if (hdl->error) {
0814         int err = hdl->error;
0815 
0816         v4l2_ctrl_handler_free(hdl);
0817         return err;
0818     }
0819 
0820     /* initialize the hardware to the default control values */
0821     ret = v4l2_ctrl_handler_setup(hdl);
0822     if (ret)
0823         v4l2_ctrl_handler_free(hdl);
0824     return ret;
0825 }
0826 
0827 static int vs6624_remove(struct i2c_client *client)
0828 {
0829     struct v4l2_subdev *sd = i2c_get_clientdata(client);
0830 
0831     v4l2_device_unregister_subdev(sd);
0832     v4l2_ctrl_handler_free(sd->ctrl_handler);
0833     return 0;
0834 }
0835 
0836 static const struct i2c_device_id vs6624_id[] = {
0837     {"vs6624", 0},
0838     {},
0839 };
0840 
0841 MODULE_DEVICE_TABLE(i2c, vs6624_id);
0842 
0843 static struct i2c_driver vs6624_driver = {
0844     .driver = {
0845         .name   = "vs6624",
0846     },
0847     .probe          = vs6624_probe,
0848     .remove         = vs6624_remove,
0849     .id_table       = vs6624_id,
0850 };
0851 
0852 module_i2c_driver(vs6624_driver);
0853 
0854 MODULE_DESCRIPTION("VS6624 sensor driver");
0855 MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
0856 MODULE_LICENSE("GPL v2");