ov772x.c (1112babde21483d86ed3fbad1320b0ddf9ab2ece) ov772x.c (762c28121d7cf183db6ef70988d3b47bb60e4869)
1// SPDX-License-Identifier: GPL-2.0
1/*
2 * ov772x Camera Driver
3 *
2/*
3 * ov772x Camera Driver
4 *
5 * Copyright (C) 2017 Jacopo Mondi <jacopo+renesas@jmondi.org>
6 *
4 * Copyright (C) 2008 Renesas Solutions Corp.
5 * Kuninori Morimoto <morimoto.kuninori@renesas.com>
6 *
7 * Based on ov7670 and soc_camera_platform driver,
8 *
9 * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
10 * Copyright (C) 2008 Magnus Damm
11 * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
7 * Copyright (C) 2008 Renesas Solutions Corp.
8 * Kuninori Morimoto <morimoto.kuninori@renesas.com>
9 *
10 * Based on ov7670 and soc_camera_platform driver,
11 *
12 * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
13 * Copyright (C) 2008 Magnus Damm
14 * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License version 2 as
15 * published by the Free Software Foundation.
16 */
17
15 */
16
17#include <linux/clk.h>
18#include <linux/delay.h>
19#include <linux/gpio/consumer.h>
20#include <linux/i2c.h>
18#include <linux/init.h>
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/init.h>
22#include <linux/kernel.h>
23#include <linux/module.h>
21#include <linux/i2c.h>
22#include <linux/slab.h>
24#include <linux/slab.h>
23#include <linux/delay.h>
24#include <linux/v4l2-mediabus.h>
25#include <linux/videodev2.h>
26
27#include <media/i2c/ov772x.h>
25#include <linux/v4l2-mediabus.h>
26#include <linux/videodev2.h>
27
28#include <media/i2c/ov772x.h>
28#include <media/soc_camera.h>
29#include <media/v4l2-clk.h>
29
30#include <media/v4l2-ctrls.h>
30#include <media/v4l2-ctrls.h>
31#include <media/v4l2-subdev.h>
31#include <media/v4l2-device.h>
32#include <media/v4l2-image-sizes.h>
32#include <media/v4l2-image-sizes.h>
33#include <media/v4l2-subdev.h>
33
34/*
35 * register offset
36 */
37#define GAIN 0x00 /* AGC - Gain control gain setting */
38#define BLUE 0x01 /* AWB - Blue channel gain setting */
39#define RED 0x02 /* AWB - Red channel gain setting */
40#define GREEN 0x03 /* AWB - Green channel gain setting */

--- 347 unchanged lines hidden (view full) ---

388 char *name;
389 unsigned char com7_bit;
390 struct v4l2_rect rect;
391};
392
393struct ov772x_priv {
394 struct v4l2_subdev subdev;
395 struct v4l2_ctrl_handler hdl;
34
35/*
36 * register offset
37 */
38#define GAIN 0x00 /* AGC - Gain control gain setting */
39#define BLUE 0x01 /* AWB - Blue channel gain setting */
40#define RED 0x02 /* AWB - Red channel gain setting */
41#define GREEN 0x03 /* AWB - Green channel gain setting */

--- 347 unchanged lines hidden (view full) ---

389 char *name;
390 unsigned char com7_bit;
391 struct v4l2_rect rect;
392};
393
394struct ov772x_priv {
395 struct v4l2_subdev subdev;
396 struct v4l2_ctrl_handler hdl;
396 struct v4l2_clk *clk;
397 struct clk *clk;
397 struct ov772x_camera_info *info;
398 struct ov772x_camera_info *info;
399 struct gpio_desc *pwdn_gpio;
400 struct gpio_desc *rstb_gpio;
398 const struct ov772x_color_format *cfmt;
399 const struct ov772x_win_size *win;
400 unsigned short flag_vflip:1;
401 unsigned short flag_hflip:1;
402 /* band_filter = COM8[5] ? 256 - BDBASE : 0 */
403 unsigned short band_filter;
404};
405
406/*
407 * supported color format list
408 */
409static const struct ov772x_color_format ov772x_cfmts[] = {
410 {
411 .code = MEDIA_BUS_FMT_YUYV8_2X8,
401 const struct ov772x_color_format *cfmt;
402 const struct ov772x_win_size *win;
403 unsigned short flag_vflip:1;
404 unsigned short flag_hflip:1;
405 /* band_filter = COM8[5] ? 256 - BDBASE : 0 */
406 unsigned short band_filter;
407};
408
409/*
410 * supported color format list
411 */
412static const struct ov772x_color_format ov772x_cfmts[] = {
413 {
414 .code = MEDIA_BUS_FMT_YUYV8_2X8,
412 .colorspace = V4L2_COLORSPACE_JPEG,
415 .colorspace = V4L2_COLORSPACE_SRGB,
413 .dsp3 = 0x0,
414 .dsp4 = DSP_OFMT_YUV,
415 .com3 = SWAP_YUV,
416 .com7 = OFMT_YUV,
417 },
418 {
419 .code = MEDIA_BUS_FMT_YVYU8_2X8,
416 .dsp3 = 0x0,
417 .dsp4 = DSP_OFMT_YUV,
418 .com3 = SWAP_YUV,
419 .com7 = OFMT_YUV,
420 },
421 {
422 .code = MEDIA_BUS_FMT_YVYU8_2X8,
420 .colorspace = V4L2_COLORSPACE_JPEG,
423 .colorspace = V4L2_COLORSPACE_SRGB,
421 .dsp3 = UV_ON,
422 .dsp4 = DSP_OFMT_YUV,
423 .com3 = SWAP_YUV,
424 .com7 = OFMT_YUV,
425 },
426 {
427 .code = MEDIA_BUS_FMT_UYVY8_2X8,
424 .dsp3 = UV_ON,
425 .dsp4 = DSP_OFMT_YUV,
426 .com3 = SWAP_YUV,
427 .com7 = OFMT_YUV,
428 },
429 {
430 .code = MEDIA_BUS_FMT_UYVY8_2X8,
428 .colorspace = V4L2_COLORSPACE_JPEG,
431 .colorspace = V4L2_COLORSPACE_SRGB,
429 .dsp3 = 0x0,
430 .dsp4 = DSP_OFMT_YUV,
431 .com3 = 0x0,
432 .com7 = OFMT_YUV,
433 },
434 {
435 .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
436 .colorspace = V4L2_COLORSPACE_SRGB,

--- 108 unchanged lines hidden (view full) ---

545 return ret;
546
547 msleep(1);
548
549 return ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
550}
551
552/*
432 .dsp3 = 0x0,
433 .dsp4 = DSP_OFMT_YUV,
434 .com3 = 0x0,
435 .com7 = OFMT_YUV,
436 },
437 {
438 .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
439 .colorspace = V4L2_COLORSPACE_SRGB,

--- 108 unchanged lines hidden (view full) ---

548 return ret;
549
550 msleep(1);
551
552 return ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
553}
554
555/*
553 * soc_camera_ops function
556 * subdev ops
554 */
555
556static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
557{
558 struct i2c_client *client = v4l2_get_subdevdata(sd);
559 struct ov772x_priv *priv = to_ov772x(sd);
560
561 if (!enable) {

--- 83 unchanged lines hidden (view full) ---

645 if (reg->reg > 0xff ||
646 reg->val > 0xff)
647 return -EINVAL;
648
649 return ov772x_write(client, reg->reg, reg->val);
650}
651#endif
652
557 */
558
559static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
560{
561 struct i2c_client *client = v4l2_get_subdevdata(sd);
562 struct ov772x_priv *priv = to_ov772x(sd);
563
564 if (!enable) {

--- 83 unchanged lines hidden (view full) ---

648 if (reg->reg > 0xff ||
649 reg->val > 0xff)
650 return -EINVAL;
651
652 return ov772x_write(client, reg->reg, reg->val);
653}
654#endif
655
656static int ov772x_power_on(struct ov772x_priv *priv)
657{
658 struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
659 int ret;
660
661 if (priv->clk) {
662 ret = clk_prepare_enable(priv->clk);
663 if (ret)
664 return ret;
665 }
666
667 if (priv->pwdn_gpio) {
668 gpiod_set_value(priv->pwdn_gpio, 1);
669 usleep_range(500, 1000);
670 }
671
672 /*
673 * FIXME: The reset signal is connected to a shared GPIO on some
674 * platforms (namely the SuperH Migo-R). Until a framework becomes
675 * available to handle this cleanly, request the GPIO temporarily
676 * to avoid conflicts.
677 */
678 priv->rstb_gpio = gpiod_get_optional(&client->dev, "rstb",
679 GPIOD_OUT_LOW);
680 if (IS_ERR(priv->rstb_gpio)) {
681 dev_info(&client->dev, "Unable to get GPIO \"rstb\"");
682 return PTR_ERR(priv->rstb_gpio);
683 }
684
685 if (priv->rstb_gpio) {
686 gpiod_set_value(priv->rstb_gpio, 1);
687 usleep_range(500, 1000);
688 gpiod_set_value(priv->rstb_gpio, 0);
689 usleep_range(500, 1000);
690
691 gpiod_put(priv->rstb_gpio);
692 }
693
694 return 0;
695}
696
697static int ov772x_power_off(struct ov772x_priv *priv)
698{
699 clk_disable_unprepare(priv->clk);
700
701 if (priv->pwdn_gpio) {
702 gpiod_set_value(priv->pwdn_gpio, 0);
703 usleep_range(500, 1000);
704 }
705
706 return 0;
707}
708
653static int ov772x_s_power(struct v4l2_subdev *sd, int on)
654{
709static int ov772x_s_power(struct v4l2_subdev *sd, int on)
710{
655 struct i2c_client *client = v4l2_get_subdevdata(sd);
656 struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
657 struct ov772x_priv *priv = to_ov772x(sd);
658
711 struct ov772x_priv *priv = to_ov772x(sd);
712
659 return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
713 return on ? ov772x_power_on(priv) :
714 ov772x_power_off(priv);
660}
661
662static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height)
663{
664 const struct ov772x_win_size *win = &ov772x_win_sizes[0];
665 u32 best_diff = UINT_MAX;
666 unsigned int i;
667

--- 182 unchanged lines hidden (view full) ---

850
851 return ret;
852}
853
854static int ov772x_get_selection(struct v4l2_subdev *sd,
855 struct v4l2_subdev_pad_config *cfg,
856 struct v4l2_subdev_selection *sel)
857{
715}
716
717static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height)
718{
719 const struct ov772x_win_size *win = &ov772x_win_sizes[0];
720 u32 best_diff = UINT_MAX;
721 unsigned int i;
722

--- 182 unchanged lines hidden (view full) ---

905
906 return ret;
907}
908
909static int ov772x_get_selection(struct v4l2_subdev *sd,
910 struct v4l2_subdev_pad_config *cfg,
911 struct v4l2_subdev_selection *sel)
912{
913 struct ov772x_priv *priv = to_ov772x(sd);
914
858 if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
859 return -EINVAL;
860
861 sel->r.left = 0;
862 sel->r.top = 0;
863 switch (sel->target) {
864 case V4L2_SEL_TGT_CROP_BOUNDS:
865 case V4L2_SEL_TGT_CROP_DEFAULT:
915 if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
916 return -EINVAL;
917
918 sel->r.left = 0;
919 sel->r.top = 0;
920 switch (sel->target) {
921 case V4L2_SEL_TGT_CROP_BOUNDS:
922 case V4L2_SEL_TGT_CROP_DEFAULT:
866 sel->r.width = OV772X_MAX_WIDTH;
867 sel->r.height = OV772X_MAX_HEIGHT;
868 return 0;
869 case V4L2_SEL_TGT_CROP:
923 case V4L2_SEL_TGT_CROP:
870 sel->r.width = VGA_WIDTH;
871 sel->r.height = VGA_HEIGHT;
924 sel->r.width = priv->win->rect.width;
925 sel->r.height = priv->win->rect.height;
872 return 0;
873 default:
874 return -EINVAL;
875 }
876}
877
878static int ov772x_get_fmt(struct v4l2_subdev *sd,
879 struct v4l2_subdev_pad_config *cfg,

--- 29 unchanged lines hidden (view full) ---

909
910 ov772x_select_params(mf, &cfmt, &win);
911
912 mf->code = cfmt->code;
913 mf->width = win->rect.width;
914 mf->height = win->rect.height;
915 mf->field = V4L2_FIELD_NONE;
916 mf->colorspace = cfmt->colorspace;
926 return 0;
927 default:
928 return -EINVAL;
929 }
930}
931
932static int ov772x_get_fmt(struct v4l2_subdev *sd,
933 struct v4l2_subdev_pad_config *cfg,

--- 29 unchanged lines hidden (view full) ---

963
964 ov772x_select_params(mf, &cfmt, &win);
965
966 mf->code = cfmt->code;
967 mf->width = win->rect.width;
968 mf->height = win->rect.height;
969 mf->field = V4L2_FIELD_NONE;
970 mf->colorspace = cfmt->colorspace;
971 mf->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
972 mf->quantization = V4L2_QUANTIZATION_DEFAULT;
973 mf->xfer_func = V4L2_XFER_FUNC_DEFAULT;
917
918 if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
919 cfg->try_fmt = *mf;
920 return 0;
921 }
922
923 ret = ov772x_set_params(priv, cfmt, win);
924 if (ret < 0)

--- 67 unchanged lines hidden (view full) ---

992{
993 if (code->pad || code->index >= ARRAY_SIZE(ov772x_cfmts))
994 return -EINVAL;
995
996 code->code = ov772x_cfmts[code->index].code;
997 return 0;
998}
999
974
975 if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
976 cfg->try_fmt = *mf;
977 return 0;
978 }
979
980 ret = ov772x_set_params(priv, cfmt, win);
981 if (ret < 0)

--- 67 unchanged lines hidden (view full) ---

1049{
1050 if (code->pad || code->index >= ARRAY_SIZE(ov772x_cfmts))
1051 return -EINVAL;
1052
1053 code->code = ov772x_cfmts[code->index].code;
1054 return 0;
1055}
1056
1000static int ov772x_g_mbus_config(struct v4l2_subdev *sd,
1001 struct v4l2_mbus_config *cfg)
1002{
1003 struct i2c_client *client = v4l2_get_subdevdata(sd);
1004 struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
1005
1006 cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
1007 V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
1008 V4L2_MBUS_DATA_ACTIVE_HIGH;
1009 cfg->type = V4L2_MBUS_PARALLEL;
1010 cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
1011
1012 return 0;
1013}
1014
1015static const struct v4l2_subdev_video_ops ov772x_subdev_video_ops = {
1016 .s_stream = ov772x_s_stream,
1057static const struct v4l2_subdev_video_ops ov772x_subdev_video_ops = {
1058 .s_stream = ov772x_s_stream,
1017 .g_mbus_config = ov772x_g_mbus_config,
1018};
1019
1020static const struct v4l2_subdev_pad_ops ov772x_subdev_pad_ops = {
1021 .enum_mbus_code = ov772x_enum_mbus_code,
1022 .get_selection = ov772x_get_selection,
1023 .get_fmt = ov772x_get_fmt,
1024 .set_fmt = ov772x_set_fmt,
1025};

--- 7 unchanged lines hidden (view full) ---

1033/*
1034 * i2c_driver function
1035 */
1036
1037static int ov772x_probe(struct i2c_client *client,
1038 const struct i2c_device_id *did)
1039{
1040 struct ov772x_priv *priv;
1059};
1060
1061static const struct v4l2_subdev_pad_ops ov772x_subdev_pad_ops = {
1062 .enum_mbus_code = ov772x_enum_mbus_code,
1063 .get_selection = ov772x_get_selection,
1064 .get_fmt = ov772x_get_fmt,
1065 .set_fmt = ov772x_set_fmt,
1066};

--- 7 unchanged lines hidden (view full) ---

1074/*
1075 * i2c_driver function
1076 */
1077
1078static int ov772x_probe(struct i2c_client *client,
1079 const struct i2c_device_id *did)
1080{
1081 struct ov772x_priv *priv;
1041 struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
1042 struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
1082 struct i2c_adapter *adapter = client->adapter;
1043 int ret;
1044
1083 int ret;
1084
1045 if (!ssdd || !ssdd->drv_priv) {
1046 dev_err(&client->dev, "OV772X: missing platform data!\n");
1085 if (!client->dev.platform_data) {
1086 dev_err(&client->dev, "Missing ov772x platform data\n");
1047 return -EINVAL;
1048 }
1049
1050 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
1051 I2C_FUNC_PROTOCOL_MANGLING)) {
1052 dev_err(&adapter->dev,
1053 "I2C-Adapter doesn't support SMBUS_BYTE_DATA or PROTOCOL_MANGLING\n");
1054 return -EIO;
1055 }
1056 client->flags |= I2C_CLIENT_SCCB;
1057
1058 priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
1059 if (!priv)
1060 return -ENOMEM;
1061
1087 return -EINVAL;
1088 }
1089
1090 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
1091 I2C_FUNC_PROTOCOL_MANGLING)) {
1092 dev_err(&adapter->dev,
1093 "I2C-Adapter doesn't support SMBUS_BYTE_DATA or PROTOCOL_MANGLING\n");
1094 return -EIO;
1095 }
1096 client->flags |= I2C_CLIENT_SCCB;
1097
1098 priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
1099 if (!priv)
1100 return -ENOMEM;
1101
1062 priv->info = ssdd->drv_priv;
1102 priv->info = client->dev.platform_data;
1063
1064 v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops);
1065 v4l2_ctrl_handler_init(&priv->hdl, 3);
1066 v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
1067 V4L2_CID_VFLIP, 0, 1, 1, 0);
1068 v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
1069 V4L2_CID_HFLIP, 0, 1, 1, 0);
1070 v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
1071 V4L2_CID_BAND_STOP_FILTER, 0, 256, 1, 0);
1072 priv->subdev.ctrl_handler = &priv->hdl;
1073 if (priv->hdl.error)
1074 return priv->hdl.error;
1075
1103
1104 v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops);
1105 v4l2_ctrl_handler_init(&priv->hdl, 3);
1106 v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
1107 V4L2_CID_VFLIP, 0, 1, 1, 0);
1108 v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
1109 V4L2_CID_HFLIP, 0, 1, 1, 0);
1110 v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
1111 V4L2_CID_BAND_STOP_FILTER, 0, 256, 1, 0);
1112 priv->subdev.ctrl_handler = &priv->hdl;
1113 if (priv->hdl.error)
1114 return priv->hdl.error;
1115
1076 priv->clk = v4l2_clk_get(&client->dev, "mclk");
1116 priv->clk = clk_get(&client->dev, "xclk");
1077 if (IS_ERR(priv->clk)) {
1117 if (IS_ERR(priv->clk)) {
1118 dev_err(&client->dev, "Unable to get xclk clock\n");
1078 ret = PTR_ERR(priv->clk);
1119 ret = PTR_ERR(priv->clk);
1079 goto eclkget;
1120 goto error_ctrl_free;
1080 }
1081
1121 }
1122
1082 ret = ov772x_video_probe(priv);
1083 if (ret < 0) {
1084 v4l2_clk_put(priv->clk);
1085eclkget:
1086 v4l2_ctrl_handler_free(&priv->hdl);
1087 } else {
1088 priv->cfmt = &ov772x_cfmts[0];
1089 priv->win = &ov772x_win_sizes[0];
1123 priv->pwdn_gpio = gpiod_get_optional(&client->dev, "pwdn",
1124 GPIOD_OUT_LOW);
1125 if (IS_ERR(priv->pwdn_gpio)) {
1126 dev_info(&client->dev, "Unable to get GPIO \"pwdn\"");
1127 ret = PTR_ERR(priv->pwdn_gpio);
1128 goto error_clk_put;
1090 }
1091
1129 }
1130
1131 ret = ov772x_video_probe(priv);
1132 if (ret < 0)
1133 goto error_gpio_put;
1134
1135 priv->cfmt = &ov772x_cfmts[0];
1136 priv->win = &ov772x_win_sizes[0];
1137
1138 ret = v4l2_async_register_subdev(&priv->subdev);
1139 if (ret)
1140 goto error_gpio_put;
1141
1142 return 0;
1143
1144error_gpio_put:
1145 if (priv->pwdn_gpio)
1146 gpiod_put(priv->pwdn_gpio);
1147error_clk_put:
1148 clk_put(priv->clk);
1149error_ctrl_free:
1150 v4l2_ctrl_handler_free(&priv->hdl);
1151
1092 return ret;
1093}
1094
1095static int ov772x_remove(struct i2c_client *client)
1096{
1097 struct ov772x_priv *priv = to_ov772x(i2c_get_clientdata(client));
1098
1152 return ret;
1153}
1154
1155static int ov772x_remove(struct i2c_client *client)
1156{
1157 struct ov772x_priv *priv = to_ov772x(i2c_get_clientdata(client));
1158
1099 v4l2_clk_put(priv->clk);
1159 clk_put(priv->clk);
1160 if (priv->pwdn_gpio)
1161 gpiod_put(priv->pwdn_gpio);
1100 v4l2_device_unregister_subdev(&priv->subdev);
1101 v4l2_ctrl_handler_free(&priv->hdl);
1102 return 0;
1103}
1104
1105static const struct i2c_device_id ov772x_id[] = {
1106 { "ov772x", 0 },
1107 { }

--- 6 unchanged lines hidden (view full) ---

1114 },
1115 .probe = ov772x_probe,
1116 .remove = ov772x_remove,
1117 .id_table = ov772x_id,
1118};
1119
1120module_i2c_driver(ov772x_i2c_driver);
1121
1162 v4l2_device_unregister_subdev(&priv->subdev);
1163 v4l2_ctrl_handler_free(&priv->hdl);
1164 return 0;
1165}
1166
1167static const struct i2c_device_id ov772x_id[] = {
1168 { "ov772x", 0 },
1169 { }

--- 6 unchanged lines hidden (view full) ---

1176 },
1177 .probe = ov772x_probe,
1178 .remove = ov772x_remove,
1179 .id_table = ov772x_id,
1180};
1181
1182module_i2c_driver(ov772x_i2c_driver);
1183
1122MODULE_DESCRIPTION("SoC Camera driver for ov772x");
1184MODULE_DESCRIPTION("V4L2 driver for OV772x image sensor");
1123MODULE_AUTHOR("Kuninori Morimoto");
1124MODULE_LICENSE("GPL v2");
1185MODULE_AUTHOR("Kuninori Morimoto");
1186MODULE_LICENSE("GPL v2");