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"); |