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