Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] V4L2: Add a v4l2-subdev (soc-camera) driver for OmniVision OV2640 sensor

Signed-off-by: Alberto Panizzo <maramaopercheseimorto@gmail.com>
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

authored by

Alberto Panizzo and committed by
Mauro Carvalho Chehab
3153ac9c b6a633c1

+1213
+6
drivers/media/video/Kconfig
··· 794 794 help 795 795 This is a generic SoC camera platform driver, useful for testing 796 796 797 + config SOC_CAMERA_OV2640 798 + tristate "ov2640 camera support" 799 + depends on SOC_CAMERA && I2C 800 + help 801 + This is a ov2640 camera driver 802 + 797 803 config SOC_CAMERA_OV6650 798 804 tristate "ov6650 sensor support" 799 805 depends on SOC_CAMERA && I2C
+1
drivers/media/video/Makefile
··· 75 75 obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o 76 76 obj-$(CONFIG_SOC_CAMERA_MT9T112) += mt9t112.o 77 77 obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o 78 + obj-$(CONFIG_SOC_CAMERA_OV2640) += ov2640.o 78 79 obj-$(CONFIG_SOC_CAMERA_OV6650) += ov6650.o 79 80 obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o 80 81 obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o
+1205
drivers/media/video/ov2640.c
··· 1 + /* 2 + * ov2640 Camera Driver 3 + * 4 + * Copyright (C) 2010 Alberto Panizzo <maramaopercheseimorto@gmail.com> 5 + * 6 + * Based on ov772x, ov9640 drivers and previous non merged implementations. 7 + * 8 + * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. 9 + * Copyright (C) 2006, OmniVision 10 + * 11 + * This program is free software; you can redistribute it and/or modify 12 + * it under the terms of the GNU General Public License version 2 as 13 + * published by the Free Software Foundation. 14 + */ 15 + 16 + #include <linux/init.h> 17 + #include <linux/module.h> 18 + #include <linux/i2c.h> 19 + #include <linux/slab.h> 20 + #include <linux/delay.h> 21 + #include <linux/videodev2.h> 22 + #include <media/v4l2-chip-ident.h> 23 + #include <media/v4l2-subdev.h> 24 + #include <media/soc_camera.h> 25 + #include <media/soc_mediabus.h> 26 + 27 + #define VAL_SET(x, mask, rshift, lshift) \ 28 + ((((x) >> rshift) & mask) << lshift) 29 + /* 30 + * DSP registers 31 + * register offset for BANK_SEL == BANK_SEL_DSP 32 + */ 33 + #define R_BYPASS 0x05 /* Bypass DSP */ 34 + #define R_BYPASS_DSP_BYPAS 0x01 /* Bypass DSP, sensor out directly */ 35 + #define R_BYPASS_USE_DSP 0x00 /* Use the internal DSP */ 36 + #define QS 0x44 /* Quantization Scale Factor */ 37 + #define CTRLI 0x50 38 + #define CTRLI_LP_DP 0x80 39 + #define CTRLI_ROUND 0x40 40 + #define CTRLI_V_DIV_SET(x) VAL_SET(x, 0x3, 0, 3) 41 + #define CTRLI_H_DIV_SET(x) VAL_SET(x, 0x3, 0, 0) 42 + #define HSIZE 0x51 /* H_SIZE[7:0] (real/4) */ 43 + #define HSIZE_SET(x) VAL_SET(x, 0xFF, 2, 0) 44 + #define VSIZE 0x52 /* V_SIZE[7:0] (real/4) */ 45 + #define VSIZE_SET(x) VAL_SET(x, 0xFF, 2, 0) 46 + #define XOFFL 0x53 /* OFFSET_X[7:0] */ 47 + #define XOFFL_SET(x) VAL_SET(x, 0xFF, 0, 0) 48 + #define YOFFL 0x54 /* OFFSET_Y[7:0] */ 49 + #define YOFFL_SET(x) VAL_SET(x, 0xFF, 0, 0) 50 + #define VHYX 0x55 /* Offset and size completion */ 51 + #define VHYX_VSIZE_SET(x) VAL_SET(x, 0x1, (8+2), 7) 52 + #define VHYX_HSIZE_SET(x) VAL_SET(x, 0x1, (8+2), 3) 53 + #define VHYX_YOFF_SET(x) VAL_SET(x, 0x3, 8, 4) 54 + #define VHYX_XOFF_SET(x) VAL_SET(x, 0x3, 8, 0) 55 + #define DPRP 0x56 56 + #define TEST 0x57 /* Horizontal size completion */ 57 + #define TEST_HSIZE_SET(x) VAL_SET(x, 0x1, (9+2), 7) 58 + #define ZMOW 0x5A /* Zoom: Out Width OUTW[7:0] (real/4) */ 59 + #define ZMOW_OUTW_SET(x) VAL_SET(x, 0xFF, 2, 0) 60 + #define ZMOH 0x5B /* Zoom: Out Height OUTH[7:0] (real/4) */ 61 + #define ZMOH_OUTH_SET(x) VAL_SET(x, 0xFF, 2, 0) 62 + #define ZMHH 0x5C /* Zoom: Speed and H&W completion */ 63 + #define ZMHH_ZSPEED_SET(x) VAL_SET(x, 0x0F, 0, 4) 64 + #define ZMHH_OUTH_SET(x) VAL_SET(x, 0x1, (8+2), 2) 65 + #define ZMHH_OUTW_SET(x) VAL_SET(x, 0x3, (8+2), 0) 66 + #define BPADDR 0x7C /* SDE Indirect Register Access: Address */ 67 + #define BPDATA 0x7D /* SDE Indirect Register Access: Data */ 68 + #define CTRL2 0x86 /* DSP Module enable 2 */ 69 + #define CTRL2_DCW_EN 0x20 70 + #define CTRL2_SDE_EN 0x10 71 + #define CTRL2_UV_ADJ_EN 0x08 72 + #define CTRL2_UV_AVG_EN 0x04 73 + #define CTRL2_CMX_EN 0x01 74 + #define CTRL3 0x87 /* DSP Module enable 3 */ 75 + #define CTRL3_BPC_EN 0x80 76 + #define CTRL3_WPC_EN 0x40 77 + #define SIZEL 0x8C /* Image Size Completion */ 78 + #define SIZEL_HSIZE8_11_SET(x) VAL_SET(x, 0x1, 11, 6) 79 + #define SIZEL_HSIZE8_SET(x) VAL_SET(x, 0x7, 0, 3) 80 + #define SIZEL_VSIZE8_SET(x) VAL_SET(x, 0x7, 0, 0) 81 + #define HSIZE8 0xC0 /* Image Horizontal Size HSIZE[10:3] */ 82 + #define HSIZE8_SET(x) VAL_SET(x, 0xFF, 3, 0) 83 + #define VSIZE8 0xC1 /* Image Vertical Size VSIZE[10:3] */ 84 + #define VSIZE8_SET(x) VAL_SET(x, 0xFF, 3, 0) 85 + #define CTRL0 0xC2 /* DSP Module enable 0 */ 86 + #define CTRL0_AEC_EN 0x80 87 + #define CTRL0_AEC_SEL 0x40 88 + #define CTRL0_STAT_SEL 0x20 89 + #define CTRL0_VFIRST 0x10 90 + #define CTRL0_YUV422 0x08 91 + #define CTRL0_YUV_EN 0x04 92 + #define CTRL0_RGB_EN 0x02 93 + #define CTRL0_RAW_EN 0x01 94 + #define CTRL1 0xC3 /* DSP Module enable 1 */ 95 + #define CTRL1_CIP 0x80 96 + #define CTRL1_DMY 0x40 97 + #define CTRL1_RAW_GMA 0x20 98 + #define CTRL1_DG 0x10 99 + #define CTRL1_AWB 0x08 100 + #define CTRL1_AWB_GAIN 0x04 101 + #define CTRL1_LENC 0x02 102 + #define CTRL1_PRE 0x01 103 + #define R_DVP_SP 0xD3 /* DVP output speed control */ 104 + #define R_DVP_SP_AUTO_MODE 0x80 105 + #define R_DVP_SP_DVP_MASK 0x3F /* DVP PCLK = sysclk (48)/[6:0] (YUV0); 106 + * = sysclk (48)/(2*[6:0]) (RAW);*/ 107 + #define IMAGE_MODE 0xDA /* Image Output Format Select */ 108 + #define IMAGE_MODE_Y8_DVP_EN 0x40 109 + #define IMAGE_MODE_JPEG_EN 0x10 110 + #define IMAGE_MODE_YUV422 0x00 111 + #define IMAGE_MODE_RAW10 0x04 /* (DVP) */ 112 + #define IMAGE_MODE_RGB565 0x08 113 + #define IMAGE_MODE_HREF_VSYNC 0x02 /* HREF timing select in DVP JPEG output 114 + * mode (0 for HREF is same as sensor) */ 115 + #define IMAGE_MODE_LBYTE_FIRST 0x01 /* Byte swap enable for DVP 116 + * 1: Low byte first UYVY (C2[4] =0) 117 + * VYUY (C2[4] =1) 118 + * 0: High byte first YUYV (C2[4]=0) 119 + * YVYU (C2[4] = 1) */ 120 + #define RESET 0xE0 /* Reset */ 121 + #define RESET_MICROC 0x40 122 + #define RESET_SCCB 0x20 123 + #define RESET_JPEG 0x10 124 + #define RESET_DVP 0x04 125 + #define RESET_IPU 0x02 126 + #define RESET_CIF 0x01 127 + #define REGED 0xED /* Register ED */ 128 + #define REGED_CLK_OUT_DIS 0x10 129 + #define MS_SP 0xF0 /* SCCB Master Speed */ 130 + #define SS_ID 0xF7 /* SCCB Slave ID */ 131 + #define SS_CTRL 0xF8 /* SCCB Slave Control */ 132 + #define SS_CTRL_ADD_AUTO_INC 0x20 133 + #define SS_CTRL_EN 0x08 134 + #define SS_CTRL_DELAY_CLK 0x04 135 + #define SS_CTRL_ACC_EN 0x02 136 + #define SS_CTRL_SEN_PASS_THR 0x01 137 + #define MC_BIST 0xF9 /* Microcontroller misc register */ 138 + #define MC_BIST_RESET 0x80 /* Microcontroller Reset */ 139 + #define MC_BIST_BOOT_ROM_SEL 0x40 140 + #define MC_BIST_12KB_SEL 0x20 141 + #define MC_BIST_12KB_MASK 0x30 142 + #define MC_BIST_512KB_SEL 0x08 143 + #define MC_BIST_512KB_MASK 0x0C 144 + #define MC_BIST_BUSY_BIT_R 0x02 145 + #define MC_BIST_MC_RES_ONE_SH_W 0x02 146 + #define MC_BIST_LAUNCH 0x01 147 + #define BANK_SEL 0xFF /* Register Bank Select */ 148 + #define BANK_SEL_DSP 0x00 149 + #define BANK_SEL_SENS 0x01 150 + 151 + /* 152 + * Sensor registers 153 + * register offset for BANK_SEL == BANK_SEL_SENS 154 + */ 155 + #define GAIN 0x00 /* AGC - Gain control gain setting */ 156 + #define COM1 0x03 /* Common control 1 */ 157 + #define COM1_1_DUMMY_FR 0x40 158 + #define COM1_3_DUMMY_FR 0x80 159 + #define COM1_7_DUMMY_FR 0xC0 160 + #define COM1_VWIN_LSB_UXGA 0x0F 161 + #define COM1_VWIN_LSB_SVGA 0x0A 162 + #define COM1_VWIN_LSB_CIF 0x06 163 + #define REG04 0x04 /* Register 04 */ 164 + #define REG04_DEF 0x20 /* Always set */ 165 + #define REG04_HFLIP_IMG 0x80 /* Horizontal mirror image ON/OFF */ 166 + #define REG04_VFLIP_IMG 0x40 /* Vertical flip image ON/OFF */ 167 + #define REG04_VREF_EN 0x10 168 + #define REG04_HREF_EN 0x08 169 + #define REG04_AEC_SET(x) VAL_SET(x, 0x3, 0, 0) 170 + #define REG08 0x08 /* Frame Exposure One-pin Control Pre-charge Row Num */ 171 + #define COM2 0x09 /* Common control 2 */ 172 + #define COM2_SOFT_SLEEP_MODE 0x10 /* Soft sleep mode */ 173 + /* Output drive capability */ 174 + #define COM2_OCAP_Nx_SET(N) (((N) - 1) & 0x03) /* N = [1x .. 4x] */ 175 + #define PID 0x0A /* Product ID Number MSB */ 176 + #define VER 0x0B /* Product ID Number LSB */ 177 + #define COM3 0x0C /* Common control 3 */ 178 + #define COM3_BAND_50H 0x04 /* 0 For Banding at 60H */ 179 + #define COM3_BAND_AUTO 0x02 /* Auto Banding */ 180 + #define COM3_SING_FR_SNAPSH 0x01 /* 0 For enable live video output after the 181 + * snapshot sequence*/ 182 + #define AEC 0x10 /* AEC[9:2] Exposure Value */ 183 + #define CLKRC 0x11 /* Internal clock */ 184 + #define CLKRC_EN 0x80 185 + #define CLKRC_DIV_SET(x) (((x) - 1) & 0x1F) /* CLK = XVCLK/(x) */ 186 + #define COM7 0x12 /* Common control 7 */ 187 + #define COM7_SRST 0x80 /* Initiates system reset. All registers are 188 + * set to factory default values after which 189 + * the chip resumes normal operation */ 190 + #define COM7_RES_UXGA 0x00 /* Resolution selectors for UXGA */ 191 + #define COM7_RES_SVGA 0x40 /* SVGA */ 192 + #define COM7_RES_CIF 0x20 /* CIF */ 193 + #define COM7_ZOOM_EN 0x04 /* Enable Zoom mode */ 194 + #define COM7_COLOR_BAR_TEST 0x02 /* Enable Color Bar Test Pattern */ 195 + #define COM8 0x13 /* Common control 8 */ 196 + #define COM8_DEF 0xC0 /* Banding filter ON/OFF */ 197 + #define COM8_BNDF_EN 0x20 /* Banding filter ON/OFF */ 198 + #define COM8_AGC_EN 0x04 /* AGC Auto/Manual control selection */ 199 + #define COM8_AEC_EN 0x01 /* Auto/Manual Exposure control */ 200 + #define COM9 0x14 /* Common control 9 201 + * Automatic gain ceiling - maximum AGC value [7:5]*/ 202 + #define COM9_AGC_GAIN_2x 0x00 /* 000 : 2x */ 203 + #define COM9_AGC_GAIN_4x 0x20 /* 001 : 4x */ 204 + #define COM9_AGC_GAIN_8x 0x40 /* 010 : 8x */ 205 + #define COM9_AGC_GAIN_16x 0x60 /* 011 : 16x */ 206 + #define COM9_AGC_GAIN_32x 0x80 /* 100 : 32x */ 207 + #define COM9_AGC_GAIN_64x 0xA0 /* 101 : 64x */ 208 + #define COM9_AGC_GAIN_128x 0xC0 /* 110 : 128x */ 209 + #define COM10 0x15 /* Common control 10 */ 210 + #define COM10_PCLK_HREF 0x20 /* PCLK output qualified by HREF */ 211 + #define COM10_PCLK_RISE 0x10 /* Data is updated at the rising edge of 212 + * PCLK (user can latch data at the next 213 + * falling edge of PCLK). 214 + * 0 otherwise. */ 215 + #define COM10_HREF_INV 0x08 /* Invert HREF polarity: 216 + * HREF negative for valid data*/ 217 + #define COM10_VSINC_INV 0x02 /* Invert VSYNC polarity */ 218 + #define HSTART 0x17 /* Horizontal Window start MSB 8 bit */ 219 + #define HEND 0x18 /* Horizontal Window end MSB 8 bit */ 220 + #define VSTART 0x19 /* Vertical Window start MSB 8 bit */ 221 + #define VEND 0x1A /* Vertical Window end MSB 8 bit */ 222 + #define MIDH 0x1C /* Manufacturer ID byte - high */ 223 + #define MIDL 0x1D /* Manufacturer ID byte - low */ 224 + #define AEW 0x24 /* AGC/AEC - Stable operating region (upper limit) */ 225 + #define AEB 0x25 /* AGC/AEC - Stable operating region (lower limit) */ 226 + #define VV 0x26 /* AGC/AEC Fast mode operating region */ 227 + #define VV_HIGH_TH_SET(x) VAL_SET(x, 0xF, 0, 4) 228 + #define VV_LOW_TH_SET(x) VAL_SET(x, 0xF, 0, 0) 229 + #define REG2A 0x2A /* Dummy pixel insert MSB */ 230 + #define FRARL 0x2B /* Dummy pixel insert LSB */ 231 + #define ADDVFL 0x2D /* LSB of insert dummy lines in Vertical direction */ 232 + #define ADDVFH 0x2E /* MSB of insert dummy lines in Vertical direction */ 233 + #define YAVG 0x2F /* Y/G Channel Average value */ 234 + #define REG32 0x32 /* Common Control 32 */ 235 + #define REG32_PCLK_DIV_2 0x80 /* PCLK freq divided by 2 */ 236 + #define REG32_PCLK_DIV_4 0xC0 /* PCLK freq divided by 4 */ 237 + #define ARCOM2 0x34 /* Zoom: Horizontal start point */ 238 + #define REG45 0x45 /* Register 45 */ 239 + #define FLL 0x46 /* Frame Length Adjustment LSBs */ 240 + #define FLH 0x47 /* Frame Length Adjustment MSBs */ 241 + #define COM19 0x48 /* Zoom: Vertical start point */ 242 + #define ZOOMS 0x49 /* Zoom: Vertical start point */ 243 + #define COM22 0x4B /* Flash light control */ 244 + #define COM25 0x4E /* For Banding operations */ 245 + #define BD50 0x4F /* 50Hz Banding AEC 8 LSBs */ 246 + #define BD60 0x50 /* 60Hz Banding AEC 8 LSBs */ 247 + #define REG5D 0x5D /* AVGsel[7:0], 16-zone average weight option */ 248 + #define REG5E 0x5E /* AVGsel[15:8], 16-zone average weight option */ 249 + #define REG5F 0x5F /* AVGsel[23:16], 16-zone average weight option */ 250 + #define REG60 0x60 /* AVGsel[31:24], 16-zone average weight option */ 251 + #define HISTO_LOW 0x61 /* Histogram Algorithm Low Level */ 252 + #define HISTO_HIGH 0x62 /* Histogram Algorithm High Level */ 253 + 254 + /* 255 + * ID 256 + */ 257 + #define MANUFACTURER_ID 0x7FA2 258 + #define PID_OV2640 0x2642 259 + #define VERSION(pid, ver) ((pid << 8) | (ver & 0xFF)) 260 + 261 + /* 262 + * Struct 263 + */ 264 + struct regval_list { 265 + u8 reg_num; 266 + u8 value; 267 + }; 268 + 269 + /* Supported resolutions */ 270 + enum ov2640_width { 271 + W_QCIF = 176, 272 + W_QVGA = 320, 273 + W_CIF = 352, 274 + W_VGA = 640, 275 + W_SVGA = 800, 276 + W_XGA = 1024, 277 + W_SXGA = 1280, 278 + W_UXGA = 1600, 279 + }; 280 + 281 + enum ov2640_height { 282 + H_QCIF = 144, 283 + H_QVGA = 240, 284 + H_CIF = 288, 285 + H_VGA = 480, 286 + H_SVGA = 600, 287 + H_XGA = 768, 288 + H_SXGA = 1024, 289 + H_UXGA = 1200, 290 + }; 291 + 292 + struct ov2640_win_size { 293 + char *name; 294 + enum ov2640_width width; 295 + enum ov2640_height height; 296 + const struct regval_list *regs; 297 + }; 298 + 299 + 300 + struct ov2640_priv { 301 + struct v4l2_subdev subdev; 302 + struct ov2640_camera_info *info; 303 + enum v4l2_mbus_pixelcode cfmt_code; 304 + const struct ov2640_win_size *win; 305 + int model; 306 + u16 flag_vflip:1; 307 + u16 flag_hflip:1; 308 + }; 309 + 310 + /* 311 + * Registers settings 312 + */ 313 + 314 + #define ENDMARKER { 0xff, 0xff } 315 + 316 + static const struct regval_list ov2640_init_regs[] = { 317 + { BANK_SEL, BANK_SEL_DSP }, 318 + { 0x2c, 0xff }, 319 + { 0x2e, 0xdf }, 320 + { BANK_SEL, BANK_SEL_SENS }, 321 + { 0x3c, 0x32 }, 322 + { CLKRC, CLKRC_DIV_SET(1) }, 323 + { COM2, COM2_OCAP_Nx_SET(3) }, 324 + { REG04, REG04_DEF | REG04_HREF_EN }, 325 + { COM8, COM8_DEF | COM8_BNDF_EN | COM8_AGC_EN | COM8_AEC_EN }, 326 + { COM9, COM9_AGC_GAIN_8x | 0x08}, 327 + { 0x2c, 0x0c }, 328 + { 0x33, 0x78 }, 329 + { 0x3a, 0x33 }, 330 + { 0x3b, 0xfb }, 331 + { 0x3e, 0x00 }, 332 + { 0x43, 0x11 }, 333 + { 0x16, 0x10 }, 334 + { 0x39, 0x02 }, 335 + { 0x35, 0x88 }, 336 + { 0x22, 0x0a }, 337 + { 0x37, 0x40 }, 338 + { 0x23, 0x00 }, 339 + { ARCOM2, 0xa0 }, 340 + { 0x06, 0x02 }, 341 + { 0x06, 0x88 }, 342 + { 0x07, 0xc0 }, 343 + { 0x0d, 0xb7 }, 344 + { 0x0e, 0x01 }, 345 + { 0x4c, 0x00 }, 346 + { 0x4a, 0x81 }, 347 + { 0x21, 0x99 }, 348 + { AEW, 0x40 }, 349 + { AEB, 0x38 }, 350 + { VV, VV_HIGH_TH_SET(0x08) | VV_LOW_TH_SET(0x02) }, 351 + { 0x5c, 0x00 }, 352 + { 0x63, 0x00 }, 353 + { FLL, 0x22 }, 354 + { COM3, 0x38 | COM3_BAND_AUTO }, 355 + { REG5D, 0x55 }, 356 + { REG5E, 0x7d }, 357 + { REG5F, 0x7d }, 358 + { REG60, 0x55 }, 359 + { HISTO_LOW, 0x70 }, 360 + { HISTO_HIGH, 0x80 }, 361 + { 0x7c, 0x05 }, 362 + { 0x20, 0x80 }, 363 + { 0x28, 0x30 }, 364 + { 0x6c, 0x00 }, 365 + { 0x6d, 0x80 }, 366 + { 0x6e, 0x00 }, 367 + { 0x70, 0x02 }, 368 + { 0x71, 0x94 }, 369 + { 0x73, 0xc1 }, 370 + { 0x3d, 0x34 }, 371 + { COM7, COM7_RES_UXGA | COM7_ZOOM_EN }, 372 + { 0x5a, 0x57 }, 373 + { BD50, 0xbb }, 374 + { BD60, 0x9c }, 375 + { BANK_SEL, BANK_SEL_DSP }, 376 + { 0xe5, 0x7f }, 377 + { MC_BIST, MC_BIST_RESET | MC_BIST_BOOT_ROM_SEL }, 378 + { 0x41, 0x24 }, 379 + { RESET, RESET_JPEG | RESET_DVP }, 380 + { 0x76, 0xff }, 381 + { 0x33, 0xa0 }, 382 + { 0x42, 0x20 }, 383 + { 0x43, 0x18 }, 384 + { 0x4c, 0x00 }, 385 + { CTRL3, CTRL3_BPC_EN | CTRL3_WPC_EN | 0x10 }, 386 + { 0x88, 0x3f }, 387 + { 0xd7, 0x03 }, 388 + { 0xd9, 0x10 }, 389 + { R_DVP_SP , R_DVP_SP_AUTO_MODE | 0x2 }, 390 + { 0xc8, 0x08 }, 391 + { 0xc9, 0x80 }, 392 + { BPADDR, 0x00 }, 393 + { BPDATA, 0x00 }, 394 + { BPADDR, 0x03 }, 395 + { BPDATA, 0x48 }, 396 + { BPDATA, 0x48 }, 397 + { BPADDR, 0x08 }, 398 + { BPDATA, 0x20 }, 399 + { BPDATA, 0x10 }, 400 + { BPDATA, 0x0e }, 401 + { 0x90, 0x00 }, 402 + { 0x91, 0x0e }, 403 + { 0x91, 0x1a }, 404 + { 0x91, 0x31 }, 405 + { 0x91, 0x5a }, 406 + { 0x91, 0x69 }, 407 + { 0x91, 0x75 }, 408 + { 0x91, 0x7e }, 409 + { 0x91, 0x88 }, 410 + { 0x91, 0x8f }, 411 + { 0x91, 0x96 }, 412 + { 0x91, 0xa3 }, 413 + { 0x91, 0xaf }, 414 + { 0x91, 0xc4 }, 415 + { 0x91, 0xd7 }, 416 + { 0x91, 0xe8 }, 417 + { 0x91, 0x20 }, 418 + { 0x92, 0x00 }, 419 + { 0x93, 0x06 }, 420 + { 0x93, 0xe3 }, 421 + { 0x93, 0x03 }, 422 + { 0x93, 0x03 }, 423 + { 0x93, 0x00 }, 424 + { 0x93, 0x02 }, 425 + { 0x93, 0x00 }, 426 + { 0x93, 0x00 }, 427 + { 0x93, 0x00 }, 428 + { 0x93, 0x00 }, 429 + { 0x93, 0x00 }, 430 + { 0x93, 0x00 }, 431 + { 0x93, 0x00 }, 432 + { 0x96, 0x00 }, 433 + { 0x97, 0x08 }, 434 + { 0x97, 0x19 }, 435 + { 0x97, 0x02 }, 436 + { 0x97, 0x0c }, 437 + { 0x97, 0x24 }, 438 + { 0x97, 0x30 }, 439 + { 0x97, 0x28 }, 440 + { 0x97, 0x26 }, 441 + { 0x97, 0x02 }, 442 + { 0x97, 0x98 }, 443 + { 0x97, 0x80 }, 444 + { 0x97, 0x00 }, 445 + { 0x97, 0x00 }, 446 + { 0xa4, 0x00 }, 447 + { 0xa8, 0x00 }, 448 + { 0xc5, 0x11 }, 449 + { 0xc6, 0x51 }, 450 + { 0xbf, 0x80 }, 451 + { 0xc7, 0x10 }, 452 + { 0xb6, 0x66 }, 453 + { 0xb8, 0xA5 }, 454 + { 0xb7, 0x64 }, 455 + { 0xb9, 0x7C }, 456 + { 0xb3, 0xaf }, 457 + { 0xb4, 0x97 }, 458 + { 0xb5, 0xFF }, 459 + { 0xb0, 0xC5 }, 460 + { 0xb1, 0x94 }, 461 + { 0xb2, 0x0f }, 462 + { 0xc4, 0x5c }, 463 + { 0xa6, 0x00 }, 464 + { 0xa7, 0x20 }, 465 + { 0xa7, 0xd8 }, 466 + { 0xa7, 0x1b }, 467 + { 0xa7, 0x31 }, 468 + { 0xa7, 0x00 }, 469 + { 0xa7, 0x18 }, 470 + { 0xa7, 0x20 }, 471 + { 0xa7, 0xd8 }, 472 + { 0xa7, 0x19 }, 473 + { 0xa7, 0x31 }, 474 + { 0xa7, 0x00 }, 475 + { 0xa7, 0x18 }, 476 + { 0xa7, 0x20 }, 477 + { 0xa7, 0xd8 }, 478 + { 0xa7, 0x19 }, 479 + { 0xa7, 0x31 }, 480 + { 0xa7, 0x00 }, 481 + { 0xa7, 0x18 }, 482 + { 0x7f, 0x00 }, 483 + { 0xe5, 0x1f }, 484 + { 0xe1, 0x77 }, 485 + { 0xdd, 0x7f }, 486 + { CTRL0, CTRL0_YUV422 | CTRL0_YUV_EN | CTRL0_RGB_EN }, 487 + ENDMARKER, 488 + }; 489 + 490 + /* 491 + * Register settings for window size 492 + * The preamble, setup the internal DSP to input an UXGA (1600x1200) image. 493 + * Then the different zooming configurations will setup the output image size. 494 + */ 495 + static const struct regval_list ov2640_size_change_preamble_regs[] = { 496 + { BANK_SEL, BANK_SEL_DSP }, 497 + { RESET, RESET_DVP }, 498 + { HSIZE8, HSIZE8_SET(W_UXGA) }, 499 + { VSIZE8, VSIZE8_SET(H_UXGA) }, 500 + { CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN | 501 + CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN }, 502 + { HSIZE, HSIZE_SET(W_UXGA) }, 503 + { VSIZE, VSIZE_SET(H_UXGA) }, 504 + { XOFFL, XOFFL_SET(0) }, 505 + { YOFFL, YOFFL_SET(0) }, 506 + { VHYX, VHYX_HSIZE_SET(W_UXGA) | VHYX_VSIZE_SET(H_UXGA) | 507 + VHYX_XOFF_SET(0) | VHYX_YOFF_SET(0)}, 508 + { TEST, TEST_HSIZE_SET(W_UXGA) }, 509 + ENDMARKER, 510 + }; 511 + 512 + #define PER_SIZE_REG_SEQ(x, y, v_div, h_div, pclk_div) \ 513 + { CTRLI, CTRLI_LP_DP | CTRLI_V_DIV_SET(v_div) | \ 514 + CTRLI_H_DIV_SET(h_div)}, \ 515 + { ZMOW, ZMOW_OUTW_SET(x) }, \ 516 + { ZMOH, ZMOH_OUTH_SET(y) }, \ 517 + { ZMHH, ZMHH_OUTW_SET(x) | ZMHH_OUTH_SET(y) }, \ 518 + { R_DVP_SP, pclk_div }, \ 519 + { RESET, 0x00} 520 + 521 + static const struct regval_list ov2640_qcif_regs[] = { 522 + PER_SIZE_REG_SEQ(W_QCIF, H_QCIF, 3, 3, 4), 523 + ENDMARKER, 524 + }; 525 + 526 + static const struct regval_list ov2640_qvga_regs[] = { 527 + PER_SIZE_REG_SEQ(W_QVGA, H_QVGA, 2, 2, 4), 528 + ENDMARKER, 529 + }; 530 + 531 + static const struct regval_list ov2640_cif_regs[] = { 532 + PER_SIZE_REG_SEQ(W_CIF, H_CIF, 2, 2, 8), 533 + ENDMARKER, 534 + }; 535 + 536 + static const struct regval_list ov2640_vga_regs[] = { 537 + PER_SIZE_REG_SEQ(W_VGA, H_VGA, 0, 0, 2), 538 + ENDMARKER, 539 + }; 540 + 541 + static const struct regval_list ov2640_svga_regs[] = { 542 + PER_SIZE_REG_SEQ(W_SVGA, H_SVGA, 1, 1, 2), 543 + ENDMARKER, 544 + }; 545 + 546 + static const struct regval_list ov2640_xga_regs[] = { 547 + PER_SIZE_REG_SEQ(W_XGA, H_XGA, 0, 0, 2), 548 + { CTRLI, 0x00}, 549 + ENDMARKER, 550 + }; 551 + 552 + static const struct regval_list ov2640_sxga_regs[] = { 553 + PER_SIZE_REG_SEQ(W_SXGA, H_SXGA, 0, 0, 2), 554 + { CTRLI, 0x00}, 555 + { R_DVP_SP, 2 | R_DVP_SP_AUTO_MODE }, 556 + ENDMARKER, 557 + }; 558 + 559 + static const struct regval_list ov2640_uxga_regs[] = { 560 + PER_SIZE_REG_SEQ(W_UXGA, H_UXGA, 0, 0, 0), 561 + { CTRLI, 0x00}, 562 + { R_DVP_SP, 0 | R_DVP_SP_AUTO_MODE }, 563 + ENDMARKER, 564 + }; 565 + 566 + #define OV2640_SIZE(n, w, h, r) \ 567 + {.name = n, .width = w , .height = h, .regs = r } 568 + 569 + static const struct ov2640_win_size ov2640_supported_win_sizes[] = { 570 + OV2640_SIZE("QCIF", W_QCIF, H_QCIF, ov2640_qcif_regs), 571 + OV2640_SIZE("QVGA", W_QVGA, H_QVGA, ov2640_qvga_regs), 572 + OV2640_SIZE("CIF", W_CIF, H_CIF, ov2640_cif_regs), 573 + OV2640_SIZE("VGA", W_VGA, H_VGA, ov2640_vga_regs), 574 + OV2640_SIZE("SVGA", W_SVGA, H_SVGA, ov2640_svga_regs), 575 + OV2640_SIZE("XGA", W_XGA, H_XGA, ov2640_xga_regs), 576 + OV2640_SIZE("SXGA", W_SXGA, H_SXGA, ov2640_sxga_regs), 577 + OV2640_SIZE("UXGA", W_UXGA, H_UXGA, ov2640_uxga_regs), 578 + }; 579 + 580 + /* 581 + * Register settings for pixel formats 582 + */ 583 + static const struct regval_list ov2640_format_change_preamble_regs[] = { 584 + { BANK_SEL, BANK_SEL_DSP }, 585 + { R_BYPASS, R_BYPASS_USE_DSP }, 586 + ENDMARKER, 587 + }; 588 + 589 + static const struct regval_list ov2640_yuv422_regs[] = { 590 + { IMAGE_MODE, IMAGE_MODE_LBYTE_FIRST | IMAGE_MODE_YUV422 }, 591 + { 0xD7, 0x01 }, 592 + { 0x33, 0xa0 }, 593 + { 0xe1, 0x67 }, 594 + { RESET, 0x00 }, 595 + { R_BYPASS, R_BYPASS_USE_DSP }, 596 + ENDMARKER, 597 + }; 598 + 599 + static const struct regval_list ov2640_rgb565_regs[] = { 600 + { IMAGE_MODE, IMAGE_MODE_LBYTE_FIRST | IMAGE_MODE_RGB565 }, 601 + { 0xd7, 0x03 }, 602 + { RESET, 0x00 }, 603 + { R_BYPASS, R_BYPASS_USE_DSP }, 604 + ENDMARKER, 605 + }; 606 + 607 + static enum v4l2_mbus_pixelcode ov2640_codes[] = { 608 + V4L2_MBUS_FMT_UYVY8_2X8, 609 + V4L2_MBUS_FMT_RGB565_2X8_LE, 610 + }; 611 + 612 + /* 613 + * Supported controls 614 + */ 615 + static const struct v4l2_queryctrl ov2640_controls[] = { 616 + { 617 + .id = V4L2_CID_VFLIP, 618 + .type = V4L2_CTRL_TYPE_BOOLEAN, 619 + .name = "Flip Vertically", 620 + .minimum = 0, 621 + .maximum = 1, 622 + .step = 1, 623 + .default_value = 0, 624 + }, { 625 + .id = V4L2_CID_HFLIP, 626 + .type = V4L2_CTRL_TYPE_BOOLEAN, 627 + .name = "Flip Horizontally", 628 + .minimum = 0, 629 + .maximum = 1, 630 + .step = 1, 631 + .default_value = 0, 632 + }, 633 + }; 634 + 635 + /* 636 + * General functions 637 + */ 638 + static struct ov2640_priv *to_ov2640(const struct i2c_client *client) 639 + { 640 + return container_of(i2c_get_clientdata(client), struct ov2640_priv, 641 + subdev); 642 + } 643 + 644 + static int ov2640_write_array(struct i2c_client *client, 645 + const struct regval_list *vals) 646 + { 647 + int ret; 648 + 649 + while ((vals->reg_num != 0xff) || (vals->value != 0xff)) { 650 + ret = i2c_smbus_write_byte_data(client, 651 + vals->reg_num, vals->value); 652 + dev_vdbg(&client->dev, "array: 0x%02x, 0x%02x", 653 + vals->reg_num, vals->value); 654 + 655 + if (ret < 0) 656 + return ret; 657 + vals++; 658 + } 659 + return 0; 660 + } 661 + 662 + static int ov2640_mask_set(struct i2c_client *client, 663 + u8 reg, u8 mask, u8 set) 664 + { 665 + s32 val = i2c_smbus_read_byte_data(client, reg); 666 + if (val < 0) 667 + return val; 668 + 669 + val &= ~mask; 670 + val |= set & mask; 671 + 672 + dev_vdbg(&client->dev, "masks: 0x%02x, 0x%02x", reg, val); 673 + 674 + return i2c_smbus_write_byte_data(client, reg, val); 675 + } 676 + 677 + static int ov2640_reset(struct i2c_client *client) 678 + { 679 + int ret; 680 + const struct regval_list reset_seq[] = { 681 + {BANK_SEL, BANK_SEL_SENS}, 682 + {COM7, COM7_SRST}, 683 + ENDMARKER, 684 + }; 685 + 686 + ret = ov2640_write_array(client, reset_seq); 687 + if (ret) 688 + goto err; 689 + 690 + msleep(5); 691 + err: 692 + dev_dbg(&client->dev, "%s: (ret %d)", __func__, ret); 693 + return ret; 694 + } 695 + 696 + /* 697 + * soc_camera_ops functions 698 + */ 699 + static int ov2640_s_stream(struct v4l2_subdev *sd, int enable) 700 + { 701 + return 0; 702 + } 703 + 704 + static int ov2640_set_bus_param(struct soc_camera_device *icd, 705 + unsigned long flags) 706 + { 707 + struct soc_camera_link *icl = to_soc_camera_link(icd); 708 + unsigned long width_flag = flags & SOCAM_DATAWIDTH_MASK; 709 + 710 + /* Only one width bit may be set */ 711 + if (!is_power_of_2(width_flag)) 712 + return -EINVAL; 713 + 714 + if (icl->set_bus_param) 715 + return icl->set_bus_param(icl, width_flag); 716 + 717 + /* 718 + * Without board specific bus width settings we support only the 719 + * sensors native bus width witch are tested working 720 + */ 721 + if (width_flag & (SOCAM_DATAWIDTH_10 | SOCAM_DATAWIDTH_8)) 722 + return 0; 723 + 724 + return 0; 725 + } 726 + 727 + static unsigned long ov2640_query_bus_param(struct soc_camera_device *icd) 728 + { 729 + struct soc_camera_link *icl = to_soc_camera_link(icd); 730 + unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | 731 + SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | 732 + SOCAM_DATA_ACTIVE_HIGH; 733 + 734 + if (icl->query_bus_param) 735 + flags |= icl->query_bus_param(icl) & SOCAM_DATAWIDTH_MASK; 736 + else 737 + flags |= SOCAM_DATAWIDTH_10; 738 + 739 + return soc_camera_apply_sensor_flags(icl, flags); 740 + } 741 + 742 + static int ov2640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) 743 + { 744 + struct i2c_client *client = v4l2_get_subdevdata(sd); 745 + struct ov2640_priv *priv = to_ov2640(client); 746 + 747 + switch (ctrl->id) { 748 + case V4L2_CID_VFLIP: 749 + ctrl->value = priv->flag_vflip; 750 + break; 751 + case V4L2_CID_HFLIP: 752 + ctrl->value = priv->flag_hflip; 753 + break; 754 + } 755 + return 0; 756 + } 757 + 758 + static int ov2640_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) 759 + { 760 + struct i2c_client *client = v4l2_get_subdevdata(sd); 761 + struct ov2640_priv *priv = to_ov2640(client); 762 + int ret = 0; 763 + u8 val; 764 + 765 + switch (ctrl->id) { 766 + case V4L2_CID_VFLIP: 767 + val = ctrl->value ? REG04_VFLIP_IMG : 0x00; 768 + priv->flag_vflip = ctrl->value ? 1 : 0; 769 + ret = ov2640_mask_set(client, REG04, REG04_VFLIP_IMG, val); 770 + break; 771 + case V4L2_CID_HFLIP: 772 + val = ctrl->value ? REG04_HFLIP_IMG : 0x00; 773 + priv->flag_hflip = ctrl->value ? 1 : 0; 774 + ret = ov2640_mask_set(client, REG04, REG04_HFLIP_IMG, val); 775 + break; 776 + } 777 + 778 + return ret; 779 + } 780 + 781 + static int ov2640_g_chip_ident(struct v4l2_subdev *sd, 782 + struct v4l2_dbg_chip_ident *id) 783 + { 784 + struct i2c_client *client = v4l2_get_subdevdata(sd); 785 + struct ov2640_priv *priv = to_ov2640(client); 786 + 787 + id->ident = priv->model; 788 + id->revision = 0; 789 + 790 + return 0; 791 + } 792 + 793 + #ifdef CONFIG_VIDEO_ADV_DEBUG 794 + static int ov2640_g_register(struct v4l2_subdev *sd, 795 + struct v4l2_dbg_register *reg) 796 + { 797 + struct i2c_client *client = v4l2_get_subdevdata(sd); 798 + int ret; 799 + 800 + reg->size = 1; 801 + if (reg->reg > 0xff) 802 + return -EINVAL; 803 + 804 + ret = i2c_smbus_read_byte_data(client, reg->reg); 805 + if (ret < 0) 806 + return ret; 807 + 808 + reg->val = ret; 809 + 810 + return 0; 811 + } 812 + 813 + static int ov2640_s_register(struct v4l2_subdev *sd, 814 + struct v4l2_dbg_register *reg) 815 + { 816 + struct i2c_client *client = v4l2_get_subdevdata(sd); 817 + 818 + if (reg->reg > 0xff || 819 + reg->val > 0xff) 820 + return -EINVAL; 821 + 822 + return i2c_smbus_write_byte_data(client, reg->reg, reg->val); 823 + } 824 + #endif 825 + 826 + /* Select the nearest higher resolution for capture */ 827 + static const struct ov2640_win_size *ov2640_select_win(u32 *width, u32 *height) 828 + { 829 + int i, default_size = ARRAY_SIZE(ov2640_supported_win_sizes) - 1; 830 + 831 + for (i = 0; i < ARRAY_SIZE(ov2640_supported_win_sizes); i++) { 832 + if (ov2640_supported_win_sizes[i].width >= *width && 833 + ov2640_supported_win_sizes[i].height >= *height) { 834 + *width = ov2640_supported_win_sizes[i].width; 835 + *height = ov2640_supported_win_sizes[i].height; 836 + return &ov2640_supported_win_sizes[i]; 837 + } 838 + } 839 + 840 + *width = ov2640_supported_win_sizes[default_size].width; 841 + *height = ov2640_supported_win_sizes[default_size].height; 842 + return &ov2640_supported_win_sizes[default_size]; 843 + } 844 + 845 + static int ov2640_set_params(struct i2c_client *client, u32 *width, u32 *height, 846 + enum v4l2_mbus_pixelcode code) 847 + { 848 + struct ov2640_priv *priv = to_ov2640(client); 849 + const struct regval_list *selected_cfmt_regs; 850 + int ret; 851 + 852 + /* select win */ 853 + priv->win = ov2640_select_win(width, height); 854 + 855 + /* select format */ 856 + priv->cfmt_code = 0; 857 + switch (code) { 858 + case V4L2_MBUS_FMT_RGB565_2X8_LE: 859 + dev_dbg(&client->dev, "%s: Selected cfmt RGB565", __func__); 860 + selected_cfmt_regs = ov2640_rgb565_regs; 861 + break; 862 + default: 863 + case V4L2_MBUS_FMT_UYVY8_2X8: 864 + dev_dbg(&client->dev, "%s: Selected cfmt YUV422", __func__); 865 + selected_cfmt_regs = ov2640_yuv422_regs; 866 + } 867 + 868 + /* reset hardware */ 869 + ov2640_reset(client); 870 + 871 + /* initialize the sensor with default data */ 872 + dev_dbg(&client->dev, "%s: Init default", __func__); 873 + ret = ov2640_write_array(client, ov2640_init_regs); 874 + if (ret < 0) 875 + goto err; 876 + 877 + /* select preamble */ 878 + dev_dbg(&client->dev, "%s: Set size to %s", __func__, priv->win->name); 879 + ret = ov2640_write_array(client, ov2640_size_change_preamble_regs); 880 + if (ret < 0) 881 + goto err; 882 + 883 + /* set size win */ 884 + ret = ov2640_write_array(client, priv->win->regs); 885 + if (ret < 0) 886 + goto err; 887 + 888 + /* cfmt preamble */ 889 + dev_dbg(&client->dev, "%s: Set cfmt", __func__); 890 + ret = ov2640_write_array(client, ov2640_format_change_preamble_regs); 891 + if (ret < 0) 892 + goto err; 893 + 894 + /* set cfmt */ 895 + ret = ov2640_write_array(client, selected_cfmt_regs); 896 + if (ret < 0) 897 + goto err; 898 + 899 + priv->cfmt_code = code; 900 + *width = priv->win->width; 901 + *height = priv->win->height; 902 + 903 + return 0; 904 + 905 + err: 906 + dev_err(&client->dev, "%s: Error %d", __func__, ret); 907 + ov2640_reset(client); 908 + priv->win = NULL; 909 + 910 + return ret; 911 + } 912 + 913 + static int ov2640_g_fmt(struct v4l2_subdev *sd, 914 + struct v4l2_mbus_framefmt *mf) 915 + { 916 + struct i2c_client *client = v4l2_get_subdevdata(sd); 917 + struct ov2640_priv *priv = to_ov2640(client); 918 + 919 + if (!priv->win) { 920 + u32 width = W_SVGA, height = H_SVGA; 921 + int ret = ov2640_set_params(client, &width, &height, 922 + V4L2_MBUS_FMT_UYVY8_2X8); 923 + if (ret < 0) 924 + return ret; 925 + } 926 + 927 + mf->width = priv->win->width; 928 + mf->height = priv->win->height; 929 + mf->code = priv->cfmt_code; 930 + 931 + switch (mf->code) { 932 + case V4L2_MBUS_FMT_RGB565_2X8_LE: 933 + mf->colorspace = V4L2_COLORSPACE_SRGB; 934 + break; 935 + default: 936 + case V4L2_MBUS_FMT_UYVY8_2X8: 937 + mf->colorspace = V4L2_COLORSPACE_JPEG; 938 + } 939 + mf->field = V4L2_FIELD_NONE; 940 + 941 + return 0; 942 + } 943 + 944 + static int ov2640_s_fmt(struct v4l2_subdev *sd, 945 + struct v4l2_mbus_framefmt *mf) 946 + { 947 + struct i2c_client *client = v4l2_get_subdevdata(sd); 948 + int ret; 949 + 950 + 951 + switch (mf->code) { 952 + case V4L2_MBUS_FMT_RGB565_2X8_LE: 953 + mf->colorspace = V4L2_COLORSPACE_SRGB; 954 + break; 955 + default: 956 + mf->code = V4L2_MBUS_FMT_UYVY8_2X8; 957 + case V4L2_MBUS_FMT_UYVY8_2X8: 958 + mf->colorspace = V4L2_COLORSPACE_JPEG; 959 + } 960 + 961 + ret = ov2640_set_params(client, &mf->width, &mf->height, mf->code); 962 + 963 + return ret; 964 + } 965 + 966 + static int ov2640_try_fmt(struct v4l2_subdev *sd, 967 + struct v4l2_mbus_framefmt *mf) 968 + { 969 + const struct ov2640_win_size *win; 970 + 971 + /* 972 + * select suitable win 973 + */ 974 + win = ov2640_select_win(&mf->width, &mf->height); 975 + 976 + mf->field = V4L2_FIELD_NONE; 977 + 978 + switch (mf->code) { 979 + case V4L2_MBUS_FMT_RGB565_2X8_LE: 980 + mf->colorspace = V4L2_COLORSPACE_SRGB; 981 + break; 982 + default: 983 + mf->code = V4L2_MBUS_FMT_UYVY8_2X8; 984 + case V4L2_MBUS_FMT_UYVY8_2X8: 985 + mf->colorspace = V4L2_COLORSPACE_JPEG; 986 + } 987 + 988 + return 0; 989 + } 990 + 991 + static int ov2640_enum_fmt(struct v4l2_subdev *sd, unsigned int index, 992 + enum v4l2_mbus_pixelcode *code) 993 + { 994 + if (index >= ARRAY_SIZE(ov2640_codes)) 995 + return -EINVAL; 996 + 997 + *code = ov2640_codes[index]; 998 + return 0; 999 + } 1000 + 1001 + static int ov2640_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) 1002 + { 1003 + a->c.left = 0; 1004 + a->c.top = 0; 1005 + a->c.width = W_UXGA; 1006 + a->c.height = H_UXGA; 1007 + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 1008 + 1009 + return 0; 1010 + } 1011 + 1012 + static int ov2640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) 1013 + { 1014 + a->bounds.left = 0; 1015 + a->bounds.top = 0; 1016 + a->bounds.width = W_UXGA; 1017 + a->bounds.height = H_UXGA; 1018 + a->defrect = a->bounds; 1019 + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 1020 + a->pixelaspect.numerator = 1; 1021 + a->pixelaspect.denominator = 1; 1022 + 1023 + return 0; 1024 + } 1025 + 1026 + static int ov2640_video_probe(struct soc_camera_device *icd, 1027 + struct i2c_client *client) 1028 + { 1029 + struct ov2640_priv *priv = to_ov2640(client); 1030 + u8 pid, ver, midh, midl; 1031 + const char *devname; 1032 + int ret; 1033 + 1034 + /* 1035 + * we must have a parent by now. And it cannot be a wrong one. 1036 + * So this entire test is completely redundant. 1037 + */ 1038 + if (!icd->dev.parent || 1039 + to_soc_camera_host(icd->dev.parent)->nr != icd->iface) { 1040 + dev_err(&client->dev, "Parent missing or invalid!\n"); 1041 + ret = -ENODEV; 1042 + goto err; 1043 + } 1044 + 1045 + /* 1046 + * check and show product ID and manufacturer ID 1047 + */ 1048 + i2c_smbus_write_byte_data(client, BANK_SEL, BANK_SEL_SENS); 1049 + pid = i2c_smbus_read_byte_data(client, PID); 1050 + ver = i2c_smbus_read_byte_data(client, VER); 1051 + midh = i2c_smbus_read_byte_data(client, MIDH); 1052 + midl = i2c_smbus_read_byte_data(client, MIDL); 1053 + 1054 + switch (VERSION(pid, ver)) { 1055 + case PID_OV2640: 1056 + devname = "ov2640"; 1057 + priv->model = V4L2_IDENT_OV2640; 1058 + break; 1059 + default: 1060 + dev_err(&client->dev, 1061 + "Product ID error %x:%x\n", pid, ver); 1062 + ret = -ENODEV; 1063 + goto err; 1064 + } 1065 + 1066 + dev_info(&client->dev, 1067 + "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", 1068 + devname, pid, ver, midh, midl); 1069 + 1070 + return 0; 1071 + 1072 + err: 1073 + return ret; 1074 + } 1075 + 1076 + static struct soc_camera_ops ov2640_ops = { 1077 + .set_bus_param = ov2640_set_bus_param, 1078 + .query_bus_param = ov2640_query_bus_param, 1079 + .controls = ov2640_controls, 1080 + .num_controls = ARRAY_SIZE(ov2640_controls), 1081 + }; 1082 + 1083 + static struct v4l2_subdev_core_ops ov2640_subdev_core_ops = { 1084 + .g_ctrl = ov2640_g_ctrl, 1085 + .s_ctrl = ov2640_s_ctrl, 1086 + .g_chip_ident = ov2640_g_chip_ident, 1087 + #ifdef CONFIG_VIDEO_ADV_DEBUG 1088 + .g_register = ov2640_g_register, 1089 + .s_register = ov2640_s_register, 1090 + #endif 1091 + }; 1092 + 1093 + static struct v4l2_subdev_video_ops ov2640_subdev_video_ops = { 1094 + .s_stream = ov2640_s_stream, 1095 + .g_mbus_fmt = ov2640_g_fmt, 1096 + .s_mbus_fmt = ov2640_s_fmt, 1097 + .try_mbus_fmt = ov2640_try_fmt, 1098 + .cropcap = ov2640_cropcap, 1099 + .g_crop = ov2640_g_crop, 1100 + .enum_mbus_fmt = ov2640_enum_fmt, 1101 + }; 1102 + 1103 + static struct v4l2_subdev_ops ov2640_subdev_ops = { 1104 + .core = &ov2640_subdev_core_ops, 1105 + .video = &ov2640_subdev_video_ops, 1106 + }; 1107 + 1108 + /* 1109 + * i2c_driver functions 1110 + */ 1111 + static int ov2640_probe(struct i2c_client *client, 1112 + const struct i2c_device_id *did) 1113 + { 1114 + struct ov2640_priv *priv; 1115 + struct soc_camera_device *icd = client->dev.platform_data; 1116 + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); 1117 + struct soc_camera_link *icl; 1118 + int ret; 1119 + 1120 + if (!icd) { 1121 + dev_err(&adapter->dev, "OV2640: missing soc-camera data!\n"); 1122 + return -EINVAL; 1123 + } 1124 + 1125 + icl = to_soc_camera_link(icd); 1126 + if (!icl) { 1127 + dev_err(&adapter->dev, 1128 + "OV2640: Missing platform_data for driver\n"); 1129 + return -EINVAL; 1130 + } 1131 + 1132 + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { 1133 + dev_err(&adapter->dev, 1134 + "OV2640: I2C-Adapter doesn't support SMBUS\n"); 1135 + return -EIO; 1136 + } 1137 + 1138 + priv = kzalloc(sizeof(struct ov2640_priv), GFP_KERNEL); 1139 + if (!priv) { 1140 + dev_err(&adapter->dev, 1141 + "Failed to allocate memory for private data!\n"); 1142 + return -ENOMEM; 1143 + } 1144 + 1145 + priv->info = icl->priv; 1146 + 1147 + v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops); 1148 + 1149 + icd->ops = &ov2640_ops; 1150 + 1151 + ret = ov2640_video_probe(icd, client); 1152 + if (ret) { 1153 + icd->ops = NULL; 1154 + kfree(priv); 1155 + } else { 1156 + dev_info(&adapter->dev, "OV2640 Probed\n"); 1157 + } 1158 + 1159 + return ret; 1160 + } 1161 + 1162 + static int ov2640_remove(struct i2c_client *client) 1163 + { 1164 + struct ov2640_priv *priv = to_ov2640(client); 1165 + struct soc_camera_device *icd = client->dev.platform_data; 1166 + 1167 + icd->ops = NULL; 1168 + kfree(priv); 1169 + return 0; 1170 + } 1171 + 1172 + static const struct i2c_device_id ov2640_id[] = { 1173 + { "ov2640", 0 }, 1174 + { } 1175 + }; 1176 + MODULE_DEVICE_TABLE(i2c, ov2640_id); 1177 + 1178 + static struct i2c_driver ov2640_i2c_driver = { 1179 + .driver = { 1180 + .name = "ov2640", 1181 + }, 1182 + .probe = ov2640_probe, 1183 + .remove = ov2640_remove, 1184 + .id_table = ov2640_id, 1185 + }; 1186 + 1187 + /* 1188 + * Module functions 1189 + */ 1190 + static int __init ov2640_module_init(void) 1191 + { 1192 + return i2c_add_driver(&ov2640_i2c_driver); 1193 + } 1194 + 1195 + static void __exit ov2640_module_exit(void) 1196 + { 1197 + i2c_del_driver(&ov2640_i2c_driver); 1198 + } 1199 + 1200 + module_init(ov2640_module_init); 1201 + module_exit(ov2640_module_exit); 1202 + 1203 + MODULE_DESCRIPTION("SoC Camera driver for Omni Vision 2640 sensor"); 1204 + MODULE_AUTHOR("Alberto Panizzo"); 1205 + MODULE_LICENSE("GPL v2");
+1
include/media/v4l2-chip-ident.h
··· 74 74 V4L2_IDENT_SOI968 = 256, 75 75 V4L2_IDENT_OV9640 = 257, 76 76 V4L2_IDENT_OV6650 = 258, 77 + V4L2_IDENT_OV2640 = 259, 77 78 78 79 /* module saa7146: reserved range 300-309 */ 79 80 V4L2_IDENT_SAA7146 = 300,