GNU Linux-libre 4.14.266-gnu1
[releases.git] / drivers / media / i2c / vs6624.c
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
35 struct 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
43 static 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
61 static 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
69 /*(DEBLOBBED)*/
70
71 static const u16 vs6624_p2[] = {
72         0x806f, 0x01,
73         0x058c, 0x01,
74         0x0000, 0x00,
75 };
76
77 static const u16 vs6624_run_setup[] = {
78         0x1d18, 0x00,                           /* Enableconstrainedwhitebalance */
79         VS6624_PEAK_MIN_OUT_G_MSB, 0x3c,        /* Damper PeakGain Output MSB */
80         VS6624_PEAK_MIN_OUT_G_LSB, 0x66,        /* Damper PeakGain Output LSB */
81         VS6624_CM_LOW_THR_MSB, 0x65,            /* Damper Low MSB */
82         VS6624_CM_LOW_THR_LSB, 0xd1,            /* Damper Low LSB */
83         VS6624_CM_HIGH_THR_MSB, 0x66,           /* Damper High MSB */
84         VS6624_CM_HIGH_THR_LSB, 0x62,           /* Damper High LSB */
85         VS6624_CM_MIN_OUT_MSB, 0x00,            /* Damper Min output MSB */
86         VS6624_CM_MIN_OUT_LSB, 0x00,            /* Damper Min output LSB */
87         VS6624_NORA_DISABLE, 0x00,              /* Nora fDisable */
88         VS6624_NORA_USAGE, 0x04,                /* Nora usage */
89         VS6624_NORA_LOW_THR_MSB, 0x63,          /* Damper Low MSB Changed 0x63 to 0x65 */
90         VS6624_NORA_LOW_THR_LSB, 0xd1,          /* Damper Low LSB */
91         VS6624_NORA_HIGH_THR_MSB, 0x68,         /* Damper High MSB */
92         VS6624_NORA_HIGH_THR_LSB, 0xdd,         /* Damper High LSB */
93         VS6624_NORA_MIN_OUT_MSB, 0x3a,          /* Damper Min output MSB */
94         VS6624_NORA_MIN_OUT_LSB, 0x00,          /* Damper Min output LSB */
95         VS6624_F2B_DISABLE, 0x00,               /* Disable */
96         0x1d8a, 0x30,                           /* MAXWeightHigh */
97         0x1d91, 0x62,                           /* fpDamperLowThresholdHigh MSB */
98         0x1d92, 0x4a,                           /* fpDamperLowThresholdHigh LSB */
99         0x1d95, 0x65,                           /* fpDamperHighThresholdHigh MSB */
100         0x1d96, 0x0e,                           /* fpDamperHighThresholdHigh LSB */
101         0x1da1, 0x3a,                           /* fpMinimumDamperOutputLow MSB */
102         0x1da2, 0xb8,                           /* fpMinimumDamperOutputLow LSB */
103         0x1e08, 0x06,                           /* MAXWeightLow */
104         0x1e0a, 0x0a,                           /* MAXWeightHigh */
105         0x1601, 0x3a,                           /* Red A MSB */
106         0x1602, 0x14,                           /* Red A LSB */
107         0x1605, 0x3b,                           /* Blue A MSB */
108         0x1606, 0x85,                           /* BLue A LSB */
109         0x1609, 0x3b,                           /* RED B MSB */
110         0x160a, 0x85,                           /* RED B LSB */
111         0x160d, 0x3a,                           /* Blue B MSB */
112         0x160e, 0x14,                           /* Blue B LSB */
113         0x1611, 0x30,                           /* Max Distance from Locus MSB */
114         0x1612, 0x8f,                           /* Max Distance from Locus MSB */
115         0x1614, 0x01,                           /* Enable constrainer */
116         0x0000, 0x00,
117 };
118
119 static const u16 vs6624_default[] = {
120         VS6624_CONTRAST0, 0x84,
121         VS6624_SATURATION0, 0x75,
122         VS6624_GAMMA0, 0x11,
123         VS6624_CONTRAST1, 0x84,
124         VS6624_SATURATION1, 0x75,
125         VS6624_GAMMA1, 0x11,
126         VS6624_MAN_RG, 0x80,
127         VS6624_MAN_GG, 0x80,
128         VS6624_MAN_BG, 0x80,
129         VS6624_WB_MODE, 0x1,
130         VS6624_EXPO_COMPENSATION, 0xfe,
131         VS6624_EXPO_METER, 0x0,
132         VS6624_LIGHT_FREQ, 0x64,
133         VS6624_PEAK_GAIN, 0xe,
134         VS6624_PEAK_LOW_THR, 0x28,
135         VS6624_HMIRROR0, 0x0,
136         VS6624_VFLIP0, 0x0,
137         VS6624_ZOOM_HSTEP0_MSB, 0x0,
138         VS6624_ZOOM_HSTEP0_LSB, 0x1,
139         VS6624_ZOOM_VSTEP0_MSB, 0x0,
140         VS6624_ZOOM_VSTEP0_LSB, 0x1,
141         VS6624_PAN_HSTEP0_MSB, 0x0,
142         VS6624_PAN_HSTEP0_LSB, 0xf,
143         VS6624_PAN_VSTEP0_MSB, 0x0,
144         VS6624_PAN_VSTEP0_LSB, 0xf,
145         VS6624_SENSOR_MODE, 0x1,
146         VS6624_SYNC_CODE_SETUP, 0x21,
147         VS6624_DISABLE_FR_DAMPER, 0x0,
148         VS6624_FR_DEN, 0x1,
149         VS6624_FR_NUM_LSB, 0xf,
150         VS6624_INIT_PIPE_SETUP, 0x0,
151         VS6624_IMG_FMT0, 0x0,
152         VS6624_YUV_SETUP, 0x1,
153         VS6624_IMAGE_SIZE0, 0x2,
154         0x0000, 0x00,
155 };
156
157 static inline struct vs6624 *to_vs6624(struct v4l2_subdev *sd)
158 {
159         return container_of(sd, struct vs6624, sd);
160 }
161 static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
162 {
163         return &container_of(ctrl->handler, struct vs6624, hdl)->sd;
164 }
165
166 #ifdef CONFIG_VIDEO_ADV_DEBUG
167 static int vs6624_read(struct v4l2_subdev *sd, u16 index)
168 {
169         struct i2c_client *client = v4l2_get_subdevdata(sd);
170         u8 buf[2];
171
172         buf[0] = index >> 8;
173         buf[1] = index;
174         i2c_master_send(client, buf, 2);
175         i2c_master_recv(client, buf, 1);
176
177         return buf[0];
178 }
179 #endif
180
181 static int vs6624_write(struct v4l2_subdev *sd, u16 index,
182                                 u8 value)
183 {
184         struct i2c_client *client = v4l2_get_subdevdata(sd);
185         u8 buf[3];
186
187         buf[0] = index >> 8;
188         buf[1] = index;
189         buf[2] = value;
190
191         return i2c_master_send(client, buf, 3);
192 }
193
194 static int vs6624_writeregs(struct v4l2_subdev *sd, const u16 *regs)
195 {
196         u16 reg;
197         u8 data;
198
199         while (*regs != 0x00) {
200                 reg = *regs++;
201                 data = *regs++;
202
203                 vs6624_write(sd, reg, data);
204         }
205         return 0;
206 }
207
208 static int vs6624_s_ctrl(struct v4l2_ctrl *ctrl)
209 {
210         struct v4l2_subdev *sd = to_sd(ctrl);
211
212         switch (ctrl->id) {
213         case V4L2_CID_CONTRAST:
214                 vs6624_write(sd, VS6624_CONTRAST0, ctrl->val);
215                 break;
216         case V4L2_CID_SATURATION:
217                 vs6624_write(sd, VS6624_SATURATION0, ctrl->val);
218                 break;
219         case V4L2_CID_HFLIP:
220                 vs6624_write(sd, VS6624_HMIRROR0, ctrl->val);
221                 break;
222         case V4L2_CID_VFLIP:
223                 vs6624_write(sd, VS6624_VFLIP0, ctrl->val);
224                 break;
225         default:
226                 return -EINVAL;
227         }
228
229         return 0;
230 }
231
232 static int vs6624_enum_mbus_code(struct v4l2_subdev *sd,
233                 struct v4l2_subdev_pad_config *cfg,
234                 struct v4l2_subdev_mbus_code_enum *code)
235 {
236         if (code->pad || code->index >= ARRAY_SIZE(vs6624_formats))
237                 return -EINVAL;
238
239         code->code = vs6624_formats[code->index].mbus_code;
240         return 0;
241 }
242
243 static int vs6624_set_fmt(struct v4l2_subdev *sd,
244                 struct v4l2_subdev_pad_config *cfg,
245                 struct v4l2_subdev_format *format)
246 {
247         struct v4l2_mbus_framefmt *fmt = &format->format;
248         struct vs6624 *sensor = to_vs6624(sd);
249         int index;
250
251         if (format->pad)
252                 return -EINVAL;
253
254         for (index = 0; index < ARRAY_SIZE(vs6624_formats); index++)
255                 if (vs6624_formats[index].mbus_code == fmt->code)
256                         break;
257         if (index >= ARRAY_SIZE(vs6624_formats)) {
258                 /* default to first format */
259                 index = 0;
260                 fmt->code = vs6624_formats[0].mbus_code;
261         }
262
263         /* sensor mode is VGA */
264         if (fmt->width > VGA_WIDTH)
265                 fmt->width = VGA_WIDTH;
266         if (fmt->height > VGA_HEIGHT)
267                 fmt->height = VGA_HEIGHT;
268         fmt->width = fmt->width & (~3);
269         fmt->height = fmt->height & (~3);
270         fmt->field = V4L2_FIELD_NONE;
271         fmt->colorspace = vs6624_formats[index].colorspace;
272
273         if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
274                 cfg->try_fmt = *fmt;
275                 return 0;
276         }
277
278         /* set image format */
279         switch (fmt->code) {
280         case MEDIA_BUS_FMT_UYVY8_2X8:
281                 vs6624_write(sd, VS6624_IMG_FMT0, 0x0);
282                 vs6624_write(sd, VS6624_YUV_SETUP, 0x1);
283                 break;
284         case MEDIA_BUS_FMT_YUYV8_2X8:
285                 vs6624_write(sd, VS6624_IMG_FMT0, 0x0);
286                 vs6624_write(sd, VS6624_YUV_SETUP, 0x3);
287                 break;
288         case MEDIA_BUS_FMT_RGB565_2X8_LE:
289                 vs6624_write(sd, VS6624_IMG_FMT0, 0x4);
290                 vs6624_write(sd, VS6624_RGB_SETUP, 0x0);
291                 break;
292         default:
293                 return -EINVAL;
294         }
295
296         /* set image size */
297         if ((fmt->width == VGA_WIDTH) && (fmt->height == VGA_HEIGHT))
298                 vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x2);
299         else if ((fmt->width == QVGA_WIDTH) && (fmt->height == QVGA_HEIGHT))
300                 vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x4);
301         else if ((fmt->width == QQVGA_WIDTH) && (fmt->height == QQVGA_HEIGHT))
302                 vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x6);
303         else if ((fmt->width == CIF_WIDTH) && (fmt->height == CIF_HEIGHT))
304                 vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x3);
305         else if ((fmt->width == QCIF_WIDTH) && (fmt->height == QCIF_HEIGHT))
306                 vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x5);
307         else if ((fmt->width == QQCIF_WIDTH) && (fmt->height == QQCIF_HEIGHT))
308                 vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x7);
309         else {
310                 vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x8);
311                 vs6624_write(sd, VS6624_MAN_HSIZE0_MSB, fmt->width >> 8);
312                 vs6624_write(sd, VS6624_MAN_HSIZE0_LSB, fmt->width & 0xFF);
313                 vs6624_write(sd, VS6624_MAN_VSIZE0_MSB, fmt->height >> 8);
314                 vs6624_write(sd, VS6624_MAN_VSIZE0_LSB, fmt->height & 0xFF);
315                 vs6624_write(sd, VS6624_CROP_CTRL0, 0x1);
316         }
317
318         sensor->fmt = *fmt;
319
320         return 0;
321 }
322
323 static int vs6624_get_fmt(struct v4l2_subdev *sd,
324                 struct v4l2_subdev_pad_config *cfg,
325                 struct v4l2_subdev_format *format)
326 {
327         struct vs6624 *sensor = to_vs6624(sd);
328
329         if (format->pad)
330                 return -EINVAL;
331
332         format->format = sensor->fmt;
333         return 0;
334 }
335
336 static int vs6624_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
337 {
338         struct vs6624 *sensor = to_vs6624(sd);
339         struct v4l2_captureparm *cp = &parms->parm.capture;
340
341         if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
342                 return -EINVAL;
343
344         memset(cp, 0, sizeof(*cp));
345         cp->capability = V4L2_CAP_TIMEPERFRAME;
346         cp->timeperframe.numerator = sensor->frame_rate.denominator;
347         cp->timeperframe.denominator = sensor->frame_rate.numerator;
348         return 0;
349 }
350
351 static int vs6624_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
352 {
353         struct vs6624 *sensor = to_vs6624(sd);
354         struct v4l2_captureparm *cp = &parms->parm.capture;
355         struct v4l2_fract *tpf = &cp->timeperframe;
356
357         if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
358                 return -EINVAL;
359         if (cp->extendedmode != 0)
360                 return -EINVAL;
361
362         if (tpf->numerator == 0 || tpf->denominator == 0
363                 || (tpf->denominator > tpf->numerator * MAX_FRAME_RATE)) {
364                 /* reset to max frame rate */
365                 tpf->numerator = 1;
366                 tpf->denominator = MAX_FRAME_RATE;
367         }
368         sensor->frame_rate.numerator = tpf->denominator;
369         sensor->frame_rate.denominator = tpf->numerator;
370         vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0);
371         vs6624_write(sd, VS6624_FR_NUM_MSB,
372                         sensor->frame_rate.numerator >> 8);
373         vs6624_write(sd, VS6624_FR_NUM_LSB,
374                         sensor->frame_rate.numerator & 0xFF);
375         vs6624_write(sd, VS6624_FR_DEN,
376                         sensor->frame_rate.denominator & 0xFF);
377         return 0;
378 }
379
380 static int vs6624_s_stream(struct v4l2_subdev *sd, int enable)
381 {
382         if (enable)
383                 vs6624_write(sd, VS6624_USER_CMD, 0x2);
384         else
385                 vs6624_write(sd, VS6624_USER_CMD, 0x4);
386         udelay(100);
387         return 0;
388 }
389
390 #ifdef CONFIG_VIDEO_ADV_DEBUG
391 static int vs6624_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
392 {
393         reg->val = vs6624_read(sd, reg->reg & 0xffff);
394         reg->size = 1;
395         return 0;
396 }
397
398 static int vs6624_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
399 {
400         vs6624_write(sd, reg->reg & 0xffff, reg->val & 0xff);
401         return 0;
402 }
403 #endif
404
405 static const struct v4l2_ctrl_ops vs6624_ctrl_ops = {
406         .s_ctrl = vs6624_s_ctrl,
407 };
408
409 static const struct v4l2_subdev_core_ops vs6624_core_ops = {
410 #ifdef CONFIG_VIDEO_ADV_DEBUG
411         .g_register = vs6624_g_register,
412         .s_register = vs6624_s_register,
413 #endif
414 };
415
416 static const struct v4l2_subdev_video_ops vs6624_video_ops = {
417         .s_parm = vs6624_s_parm,
418         .g_parm = vs6624_g_parm,
419         .s_stream = vs6624_s_stream,
420 };
421
422 static const struct v4l2_subdev_pad_ops vs6624_pad_ops = {
423         .enum_mbus_code = vs6624_enum_mbus_code,
424         .get_fmt = vs6624_get_fmt,
425         .set_fmt = vs6624_set_fmt,
426 };
427
428 static const struct v4l2_subdev_ops vs6624_ops = {
429         .core = &vs6624_core_ops,
430         .video = &vs6624_video_ops,
431         .pad = &vs6624_pad_ops,
432 };
433
434 static int vs6624_probe(struct i2c_client *client,
435                         const struct i2c_device_id *id)
436 {
437         struct vs6624 *sensor;
438         struct v4l2_subdev *sd;
439         struct v4l2_ctrl_handler *hdl;
440         const unsigned *ce;
441         int ret;
442
443         /* Check if the adapter supports the needed features */
444         if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
445                 return -EIO;
446
447         ce = client->dev.platform_data;
448         if (ce == NULL)
449                 return -EINVAL;
450
451         ret = devm_gpio_request_one(&client->dev, *ce, GPIOF_OUT_INIT_HIGH,
452                                     "VS6624 Chip Enable");
453         if (ret) {
454                 v4l_err(client, "failed to request GPIO %d\n", *ce);
455                 return ret;
456         }
457         /* wait 100ms before any further i2c writes are performed */
458         mdelay(100);
459
460         sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
461         if (sensor == NULL)
462                 return -ENOMEM;
463
464         sd = &sensor->sd;
465         v4l2_i2c_subdev_init(sd, client, &vs6624_ops);
466
467         /*(DEBLOBBED)*/
468         vs6624_write(sd, VS6624_MICRO_EN, 0x2);
469         vs6624_write(sd, VS6624_DIO_EN, 0x1);
470         mdelay(10);
471         vs6624_writeregs(sd, vs6624_p2);
472
473         vs6624_writeregs(sd, vs6624_default);
474         vs6624_write(sd, VS6624_HSYNC_SETUP, 0xF);
475         vs6624_writeregs(sd, vs6624_run_setup);
476
477         /* set frame rate */
478         sensor->frame_rate.numerator = MAX_FRAME_RATE;
479         sensor->frame_rate.denominator = 1;
480         vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0);
481         vs6624_write(sd, VS6624_FR_NUM_MSB,
482                         sensor->frame_rate.numerator >> 8);
483         vs6624_write(sd, VS6624_FR_NUM_LSB,
484                         sensor->frame_rate.numerator & 0xFF);
485         vs6624_write(sd, VS6624_FR_DEN,
486                         sensor->frame_rate.denominator & 0xFF);
487
488         sensor->fmt = vs6624_default_fmt;
489         sensor->ce_pin = *ce;
490
491         v4l_info(client, "chip found @ 0x%02x (%s)\n",
492                         client->addr << 1, client->adapter->name);
493
494         hdl = &sensor->hdl;
495         v4l2_ctrl_handler_init(hdl, 4);
496         v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
497                         V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x87);
498         v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
499                         V4L2_CID_SATURATION, 0, 0xFF, 1, 0x78);
500         v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
501                         V4L2_CID_HFLIP, 0, 1, 1, 0);
502         v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
503                         V4L2_CID_VFLIP, 0, 1, 1, 0);
504         /* hook the control handler into the driver */
505         sd->ctrl_handler = hdl;
506         if (hdl->error) {
507                 int err = hdl->error;
508
509                 v4l2_ctrl_handler_free(hdl);
510                 return err;
511         }
512
513         /* initialize the hardware to the default control values */
514         ret = v4l2_ctrl_handler_setup(hdl);
515         if (ret)
516                 v4l2_ctrl_handler_free(hdl);
517         return ret;
518 }
519
520 static int vs6624_remove(struct i2c_client *client)
521 {
522         struct v4l2_subdev *sd = i2c_get_clientdata(client);
523
524         v4l2_device_unregister_subdev(sd);
525         v4l2_ctrl_handler_free(sd->ctrl_handler);
526         return 0;
527 }
528
529 static const struct i2c_device_id vs6624_id[] = {
530         {"vs6624", 0},
531         {},
532 };
533
534 MODULE_DEVICE_TABLE(i2c, vs6624_id);
535
536 static struct i2c_driver vs6624_driver = {
537         .driver = {
538                 .name   = "vs6624",
539         },
540         .probe          = vs6624_probe,
541         .remove         = vs6624_remove,
542         .id_table       = vs6624_id,
543 };
544
545 module_i2c_driver(vs6624_driver);
546
547 MODULE_DESCRIPTION("VS6624 sensor driver");
548 MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
549 MODULE_LICENSE("GPL v2");