1 // SPDX-License-Identifier: GPL-2.0-only
3 * vs6624.c ST VS6624 CMOS image sensor driver
5 * Copyright (c) 2011 Analog Devices Inc.
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>
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>
23 #include "vs6624_regs.h"
25 #define MAX_FRAME_RATE 30
28 struct v4l2_subdev sd;
29 struct v4l2_ctrl_handler hdl;
30 struct v4l2_fract frame_rate;
31 struct v4l2_mbus_framefmt fmt;
35 static const struct vs6624_format {
37 enum v4l2_colorspace colorspace;
38 } vs6624_formats[] = {
40 .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
41 .colorspace = V4L2_COLORSPACE_JPEG,
44 .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
45 .colorspace = V4L2_COLORSPACE_JPEG,
48 .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
49 .colorspace = V4L2_COLORSPACE_SRGB,
53 static const struct v4l2_mbus_framefmt vs6624_default_fmt = {
56 .code = MEDIA_BUS_FMT_UYVY8_2X8,
57 .field = V4L2_FIELD_NONE,
58 .colorspace = V4L2_COLORSPACE_JPEG,
61 static const u16 vs6624_p1[] = {
387 static const u16 vs6624_p2[] = {
393 static const u16 vs6624_run_setup[] = {
394 0x1d18, 0x00, /* Enableconstrainedwhitebalance */
395 VS6624_PEAK_MIN_OUT_G_MSB, 0x3c, /* Damper PeakGain Output MSB */
396 VS6624_PEAK_MIN_OUT_G_LSB, 0x66, /* Damper PeakGain Output LSB */
397 VS6624_CM_LOW_THR_MSB, 0x65, /* Damper Low MSB */
398 VS6624_CM_LOW_THR_LSB, 0xd1, /* Damper Low LSB */
399 VS6624_CM_HIGH_THR_MSB, 0x66, /* Damper High MSB */
400 VS6624_CM_HIGH_THR_LSB, 0x62, /* Damper High LSB */
401 VS6624_CM_MIN_OUT_MSB, 0x00, /* Damper Min output MSB */
402 VS6624_CM_MIN_OUT_LSB, 0x00, /* Damper Min output LSB */
403 VS6624_NORA_DISABLE, 0x00, /* Nora fDisable */
404 VS6624_NORA_USAGE, 0x04, /* Nora usage */
405 VS6624_NORA_LOW_THR_MSB, 0x63, /* Damper Low MSB Changed 0x63 to 0x65 */
406 VS6624_NORA_LOW_THR_LSB, 0xd1, /* Damper Low LSB */
407 VS6624_NORA_HIGH_THR_MSB, 0x68, /* Damper High MSB */
408 VS6624_NORA_HIGH_THR_LSB, 0xdd, /* Damper High LSB */
409 VS6624_NORA_MIN_OUT_MSB, 0x3a, /* Damper Min output MSB */
410 VS6624_NORA_MIN_OUT_LSB, 0x00, /* Damper Min output LSB */
411 VS6624_F2B_DISABLE, 0x00, /* Disable */
412 0x1d8a, 0x30, /* MAXWeightHigh */
413 0x1d91, 0x62, /* fpDamperLowThresholdHigh MSB */
414 0x1d92, 0x4a, /* fpDamperLowThresholdHigh LSB */
415 0x1d95, 0x65, /* fpDamperHighThresholdHigh MSB */
416 0x1d96, 0x0e, /* fpDamperHighThresholdHigh LSB */
417 0x1da1, 0x3a, /* fpMinimumDamperOutputLow MSB */
418 0x1da2, 0xb8, /* fpMinimumDamperOutputLow LSB */
419 0x1e08, 0x06, /* MAXWeightLow */
420 0x1e0a, 0x0a, /* MAXWeightHigh */
421 0x1601, 0x3a, /* Red A MSB */
422 0x1602, 0x14, /* Red A LSB */
423 0x1605, 0x3b, /* Blue A MSB */
424 0x1606, 0x85, /* BLue A LSB */
425 0x1609, 0x3b, /* RED B MSB */
426 0x160a, 0x85, /* RED B LSB */
427 0x160d, 0x3a, /* Blue B MSB */
428 0x160e, 0x14, /* Blue B LSB */
429 0x1611, 0x30, /* Max Distance from Locus MSB */
430 0x1612, 0x8f, /* Max Distance from Locus MSB */
431 0x1614, 0x01, /* Enable constrainer */
435 static const u16 vs6624_default[] = {
436 VS6624_CONTRAST0, 0x84,
437 VS6624_SATURATION0, 0x75,
439 VS6624_CONTRAST1, 0x84,
440 VS6624_SATURATION1, 0x75,
446 VS6624_EXPO_COMPENSATION, 0xfe,
447 VS6624_EXPO_METER, 0x0,
448 VS6624_LIGHT_FREQ, 0x64,
449 VS6624_PEAK_GAIN, 0xe,
450 VS6624_PEAK_LOW_THR, 0x28,
451 VS6624_HMIRROR0, 0x0,
453 VS6624_ZOOM_HSTEP0_MSB, 0x0,
454 VS6624_ZOOM_HSTEP0_LSB, 0x1,
455 VS6624_ZOOM_VSTEP0_MSB, 0x0,
456 VS6624_ZOOM_VSTEP0_LSB, 0x1,
457 VS6624_PAN_HSTEP0_MSB, 0x0,
458 VS6624_PAN_HSTEP0_LSB, 0xf,
459 VS6624_PAN_VSTEP0_MSB, 0x0,
460 VS6624_PAN_VSTEP0_LSB, 0xf,
461 VS6624_SENSOR_MODE, 0x1,
462 VS6624_SYNC_CODE_SETUP, 0x21,
463 VS6624_DISABLE_FR_DAMPER, 0x0,
465 VS6624_FR_NUM_LSB, 0xf,
466 VS6624_INIT_PIPE_SETUP, 0x0,
467 VS6624_IMG_FMT0, 0x0,
468 VS6624_YUV_SETUP, 0x1,
469 VS6624_IMAGE_SIZE0, 0x2,
473 static inline struct vs6624 *to_vs6624(struct v4l2_subdev *sd)
475 return container_of(sd, struct vs6624, sd);
477 static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
479 return &container_of(ctrl->handler, struct vs6624, hdl)->sd;
482 #ifdef CONFIG_VIDEO_ADV_DEBUG
483 static int vs6624_read(struct v4l2_subdev *sd, u16 index)
485 struct i2c_client *client = v4l2_get_subdevdata(sd);
490 i2c_master_send(client, buf, 2);
491 i2c_master_recv(client, buf, 1);
497 static int vs6624_write(struct v4l2_subdev *sd, u16 index,
500 struct i2c_client *client = v4l2_get_subdevdata(sd);
507 return i2c_master_send(client, buf, 3);
510 static int vs6624_writeregs(struct v4l2_subdev *sd, const u16 *regs)
515 while (*regs != 0x00) {
519 vs6624_write(sd, reg, data);
524 static int vs6624_s_ctrl(struct v4l2_ctrl *ctrl)
526 struct v4l2_subdev *sd = to_sd(ctrl);
529 case V4L2_CID_CONTRAST:
530 vs6624_write(sd, VS6624_CONTRAST0, ctrl->val);
532 case V4L2_CID_SATURATION:
533 vs6624_write(sd, VS6624_SATURATION0, ctrl->val);
536 vs6624_write(sd, VS6624_HMIRROR0, ctrl->val);
539 vs6624_write(sd, VS6624_VFLIP0, ctrl->val);
548 static int vs6624_enum_mbus_code(struct v4l2_subdev *sd,
549 struct v4l2_subdev_state *sd_state,
550 struct v4l2_subdev_mbus_code_enum *code)
552 if (code->pad || code->index >= ARRAY_SIZE(vs6624_formats))
555 code->code = vs6624_formats[code->index].mbus_code;
559 static int vs6624_set_fmt(struct v4l2_subdev *sd,
560 struct v4l2_subdev_state *sd_state,
561 struct v4l2_subdev_format *format)
563 struct v4l2_mbus_framefmt *fmt = &format->format;
564 struct vs6624 *sensor = to_vs6624(sd);
570 for (index = 0; index < ARRAY_SIZE(vs6624_formats); index++)
571 if (vs6624_formats[index].mbus_code == fmt->code)
573 if (index >= ARRAY_SIZE(vs6624_formats)) {
574 /* default to first format */
576 fmt->code = vs6624_formats[0].mbus_code;
579 /* sensor mode is VGA */
580 if (fmt->width > VGA_WIDTH)
581 fmt->width = VGA_WIDTH;
582 if (fmt->height > VGA_HEIGHT)
583 fmt->height = VGA_HEIGHT;
584 fmt->width = fmt->width & (~3);
585 fmt->height = fmt->height & (~3);
586 fmt->field = V4L2_FIELD_NONE;
587 fmt->colorspace = vs6624_formats[index].colorspace;
589 if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
590 sd_state->pads->try_fmt = *fmt;
594 /* set image format */
596 case MEDIA_BUS_FMT_UYVY8_2X8:
597 vs6624_write(sd, VS6624_IMG_FMT0, 0x0);
598 vs6624_write(sd, VS6624_YUV_SETUP, 0x1);
600 case MEDIA_BUS_FMT_YUYV8_2X8:
601 vs6624_write(sd, VS6624_IMG_FMT0, 0x0);
602 vs6624_write(sd, VS6624_YUV_SETUP, 0x3);
604 case MEDIA_BUS_FMT_RGB565_2X8_LE:
605 vs6624_write(sd, VS6624_IMG_FMT0, 0x4);
606 vs6624_write(sd, VS6624_RGB_SETUP, 0x0);
613 if ((fmt->width == VGA_WIDTH) && (fmt->height == VGA_HEIGHT))
614 vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x2);
615 else if ((fmt->width == QVGA_WIDTH) && (fmt->height == QVGA_HEIGHT))
616 vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x4);
617 else if ((fmt->width == QQVGA_WIDTH) && (fmt->height == QQVGA_HEIGHT))
618 vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x6);
619 else if ((fmt->width == CIF_WIDTH) && (fmt->height == CIF_HEIGHT))
620 vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x3);
621 else if ((fmt->width == QCIF_WIDTH) && (fmt->height == QCIF_HEIGHT))
622 vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x5);
623 else if ((fmt->width == QQCIF_WIDTH) && (fmt->height == QQCIF_HEIGHT))
624 vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x7);
626 vs6624_write(sd, VS6624_IMAGE_SIZE0, 0x8);
627 vs6624_write(sd, VS6624_MAN_HSIZE0_MSB, fmt->width >> 8);
628 vs6624_write(sd, VS6624_MAN_HSIZE0_LSB, fmt->width & 0xFF);
629 vs6624_write(sd, VS6624_MAN_VSIZE0_MSB, fmt->height >> 8);
630 vs6624_write(sd, VS6624_MAN_VSIZE0_LSB, fmt->height & 0xFF);
631 vs6624_write(sd, VS6624_CROP_CTRL0, 0x1);
639 static int vs6624_get_fmt(struct v4l2_subdev *sd,
640 struct v4l2_subdev_state *sd_state,
641 struct v4l2_subdev_format *format)
643 struct vs6624 *sensor = to_vs6624(sd);
648 format->format = sensor->fmt;
652 static int vs6624_g_frame_interval(struct v4l2_subdev *sd,
653 struct v4l2_subdev_frame_interval *ival)
655 struct vs6624 *sensor = to_vs6624(sd);
657 ival->interval.numerator = sensor->frame_rate.denominator;
658 ival->interval.denominator = sensor->frame_rate.numerator;
662 static int vs6624_s_frame_interval(struct v4l2_subdev *sd,
663 struct v4l2_subdev_frame_interval *ival)
665 struct vs6624 *sensor = to_vs6624(sd);
666 struct v4l2_fract *tpf = &ival->interval;
669 if (tpf->numerator == 0 || tpf->denominator == 0
670 || (tpf->denominator > tpf->numerator * MAX_FRAME_RATE)) {
671 /* reset to max frame rate */
673 tpf->denominator = MAX_FRAME_RATE;
675 sensor->frame_rate.numerator = tpf->denominator;
676 sensor->frame_rate.denominator = tpf->numerator;
677 vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0);
678 vs6624_write(sd, VS6624_FR_NUM_MSB,
679 sensor->frame_rate.numerator >> 8);
680 vs6624_write(sd, VS6624_FR_NUM_LSB,
681 sensor->frame_rate.numerator & 0xFF);
682 vs6624_write(sd, VS6624_FR_DEN,
683 sensor->frame_rate.denominator & 0xFF);
687 static int vs6624_s_stream(struct v4l2_subdev *sd, int enable)
690 vs6624_write(sd, VS6624_USER_CMD, 0x2);
692 vs6624_write(sd, VS6624_USER_CMD, 0x4);
697 #ifdef CONFIG_VIDEO_ADV_DEBUG
698 static int vs6624_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
700 reg->val = vs6624_read(sd, reg->reg & 0xffff);
705 static int vs6624_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
707 vs6624_write(sd, reg->reg & 0xffff, reg->val & 0xff);
712 static const struct v4l2_ctrl_ops vs6624_ctrl_ops = {
713 .s_ctrl = vs6624_s_ctrl,
716 static const struct v4l2_subdev_core_ops vs6624_core_ops = {
717 #ifdef CONFIG_VIDEO_ADV_DEBUG
718 .g_register = vs6624_g_register,
719 .s_register = vs6624_s_register,
723 static const struct v4l2_subdev_video_ops vs6624_video_ops = {
724 .s_frame_interval = vs6624_s_frame_interval,
725 .g_frame_interval = vs6624_g_frame_interval,
726 .s_stream = vs6624_s_stream,
729 static const struct v4l2_subdev_pad_ops vs6624_pad_ops = {
730 .enum_mbus_code = vs6624_enum_mbus_code,
731 .get_fmt = vs6624_get_fmt,
732 .set_fmt = vs6624_set_fmt,
735 static const struct v4l2_subdev_ops vs6624_ops = {
736 .core = &vs6624_core_ops,
737 .video = &vs6624_video_ops,
738 .pad = &vs6624_pad_ops,
741 static int vs6624_probe(struct i2c_client *client,
742 const struct i2c_device_id *id)
744 struct vs6624 *sensor;
745 struct v4l2_subdev *sd;
746 struct v4l2_ctrl_handler *hdl;
750 /* Check if the adapter supports the needed features */
751 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
754 ce = client->dev.platform_data;
758 ret = devm_gpio_request_one(&client->dev, *ce, GPIOF_OUT_INIT_HIGH,
759 "VS6624 Chip Enable");
761 v4l_err(client, "failed to request GPIO %d\n", *ce);
764 /* wait 100ms before any further i2c writes are performed */
767 sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
772 v4l2_i2c_subdev_init(sd, client, &vs6624_ops);
774 vs6624_writeregs(sd, vs6624_p1);
775 vs6624_write(sd, VS6624_MICRO_EN, 0x2);
776 vs6624_write(sd, VS6624_DIO_EN, 0x1);
777 usleep_range(10000, 11000);
778 vs6624_writeregs(sd, vs6624_p2);
780 vs6624_writeregs(sd, vs6624_default);
781 vs6624_write(sd, VS6624_HSYNC_SETUP, 0xF);
782 vs6624_writeregs(sd, vs6624_run_setup);
785 sensor->frame_rate.numerator = MAX_FRAME_RATE;
786 sensor->frame_rate.denominator = 1;
787 vs6624_write(sd, VS6624_DISABLE_FR_DAMPER, 0x0);
788 vs6624_write(sd, VS6624_FR_NUM_MSB,
789 sensor->frame_rate.numerator >> 8);
790 vs6624_write(sd, VS6624_FR_NUM_LSB,
791 sensor->frame_rate.numerator & 0xFF);
792 vs6624_write(sd, VS6624_FR_DEN,
793 sensor->frame_rate.denominator & 0xFF);
795 sensor->fmt = vs6624_default_fmt;
796 sensor->ce_pin = *ce;
798 v4l_info(client, "chip found @ 0x%02x (%s)\n",
799 client->addr << 1, client->adapter->name);
802 v4l2_ctrl_handler_init(hdl, 4);
803 v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
804 V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x87);
805 v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
806 V4L2_CID_SATURATION, 0, 0xFF, 1, 0x78);
807 v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
808 V4L2_CID_HFLIP, 0, 1, 1, 0);
809 v4l2_ctrl_new_std(hdl, &vs6624_ctrl_ops,
810 V4L2_CID_VFLIP, 0, 1, 1, 0);
811 /* hook the control handler into the driver */
812 sd->ctrl_handler = hdl;
814 int err = hdl->error;
816 v4l2_ctrl_handler_free(hdl);
820 /* initialize the hardware to the default control values */
821 ret = v4l2_ctrl_handler_setup(hdl);
823 v4l2_ctrl_handler_free(hdl);
827 static int vs6624_remove(struct i2c_client *client)
829 struct v4l2_subdev *sd = i2c_get_clientdata(client);
831 v4l2_device_unregister_subdev(sd);
832 v4l2_ctrl_handler_free(sd->ctrl_handler);
836 static const struct i2c_device_id vs6624_id[] = {
841 MODULE_DEVICE_TABLE(i2c, vs6624_id);
843 static struct i2c_driver vs6624_driver = {
847 .probe = vs6624_probe,
848 .remove = vs6624_remove,
849 .id_table = vs6624_id,
852 module_i2c_driver(vs6624_driver);
854 MODULE_DESCRIPTION("VS6624 sensor driver");
855 MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
856 MODULE_LICENSE("GPL v2");