1300 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * ov2640 Camera Driver4 *5 * Copyright (C) 2010 Alberto Panizzo <maramaopercheseimorto@gmail.com>6 *7 * Based on ov772x, ov9640 drivers and previous non merged implementations.8 *9 * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved.10 * Copyright (C) 2006, OmniVision11 */12 13#include <linux/init.h>14#include <linux/module.h>15#include <linux/i2c.h>16#include <linux/clk.h>17#include <linux/slab.h>18#include <linux/delay.h>19#include <linux/gpio/consumer.h>20#include <linux/v4l2-mediabus.h>21#include <linux/videodev2.h>22 23#include <media/v4l2-device.h>24#include <media/v4l2-event.h>25#include <media/v4l2-subdev.h>26#include <media/v4l2-ctrls.h>27#include <media/v4l2-image-sizes.h>28 29#define VAL_SET(x, mask, rshift, lshift) \30 ((((x) >> rshift) & mask) << lshift)31/*32 * DSP registers33 * register offset for BANK_SEL == BANK_SEL_DSP34 */35#define R_BYPASS 0x05 /* Bypass DSP */36#define R_BYPASS_DSP_BYPAS 0x01 /* Bypass DSP, sensor out directly */37#define R_BYPASS_USE_DSP 0x00 /* Use the internal DSP */38#define QS 0x44 /* Quantization Scale Factor */39#define CTRLI 0x5040#define CTRLI_LP_DP 0x8041#define CTRLI_ROUND 0x4042#define CTRLI_V_DIV_SET(x) VAL_SET(x, 0x3, 0, 3)43#define CTRLI_H_DIV_SET(x) VAL_SET(x, 0x3, 0, 0)44#define HSIZE 0x51 /* H_SIZE[7:0] (real/4) */45#define HSIZE_SET(x) VAL_SET(x, 0xFF, 2, 0)46#define VSIZE 0x52 /* V_SIZE[7:0] (real/4) */47#define VSIZE_SET(x) VAL_SET(x, 0xFF, 2, 0)48#define XOFFL 0x53 /* OFFSET_X[7:0] */49#define XOFFL_SET(x) VAL_SET(x, 0xFF, 0, 0)50#define YOFFL 0x54 /* OFFSET_Y[7:0] */51#define YOFFL_SET(x) VAL_SET(x, 0xFF, 0, 0)52#define VHYX 0x55 /* Offset and size completion */53#define VHYX_VSIZE_SET(x) VAL_SET(x, 0x1, (8+2), 7)54#define VHYX_HSIZE_SET(x) VAL_SET(x, 0x1, (8+2), 3)55#define VHYX_YOFF_SET(x) VAL_SET(x, 0x3, 8, 4)56#define VHYX_XOFF_SET(x) VAL_SET(x, 0x3, 8, 0)57#define DPRP 0x5658#define TEST 0x57 /* Horizontal size completion */59#define TEST_HSIZE_SET(x) VAL_SET(x, 0x1, (9+2), 7)60#define ZMOW 0x5A /* Zoom: Out Width OUTW[7:0] (real/4) */61#define ZMOW_OUTW_SET(x) VAL_SET(x, 0xFF, 2, 0)62#define ZMOH 0x5B /* Zoom: Out Height OUTH[7:0] (real/4) */63#define ZMOH_OUTH_SET(x) VAL_SET(x, 0xFF, 2, 0)64#define ZMHH 0x5C /* Zoom: Speed and H&W completion */65#define ZMHH_ZSPEED_SET(x) VAL_SET(x, 0x0F, 0, 4)66#define ZMHH_OUTH_SET(x) VAL_SET(x, 0x1, (8+2), 2)67#define ZMHH_OUTW_SET(x) VAL_SET(x, 0x3, (8+2), 0)68#define BPADDR 0x7C /* SDE Indirect Register Access: Address */69#define BPDATA 0x7D /* SDE Indirect Register Access: Data */70#define CTRL2 0x86 /* DSP Module enable 2 */71#define CTRL2_DCW_EN 0x2072#define CTRL2_SDE_EN 0x1073#define CTRL2_UV_ADJ_EN 0x0874#define CTRL2_UV_AVG_EN 0x0475#define CTRL2_CMX_EN 0x0176#define CTRL3 0x87 /* DSP Module enable 3 */77#define CTRL3_BPC_EN 0x8078#define CTRL3_WPC_EN 0x4079#define SIZEL 0x8C /* Image Size Completion */80#define SIZEL_HSIZE8_11_SET(x) VAL_SET(x, 0x1, 11, 6)81#define SIZEL_HSIZE8_SET(x) VAL_SET(x, 0x7, 0, 3)82#define SIZEL_VSIZE8_SET(x) VAL_SET(x, 0x7, 0, 0)83#define HSIZE8 0xC0 /* Image Horizontal Size HSIZE[10:3] */84#define HSIZE8_SET(x) VAL_SET(x, 0xFF, 3, 0)85#define VSIZE8 0xC1 /* Image Vertical Size VSIZE[10:3] */86#define VSIZE8_SET(x) VAL_SET(x, 0xFF, 3, 0)87#define CTRL0 0xC2 /* DSP Module enable 0 */88#define CTRL0_AEC_EN 0x8089#define CTRL0_AEC_SEL 0x4090#define CTRL0_STAT_SEL 0x2091#define CTRL0_VFIRST 0x1092#define CTRL0_YUV422 0x0893#define CTRL0_YUV_EN 0x0494#define CTRL0_RGB_EN 0x0295#define CTRL0_RAW_EN 0x0196#define CTRL1 0xC3 /* DSP Module enable 1 */97#define CTRL1_CIP 0x8098#define CTRL1_DMY 0x4099#define CTRL1_RAW_GMA 0x20100#define CTRL1_DG 0x10101#define CTRL1_AWB 0x08102#define CTRL1_AWB_GAIN 0x04103#define CTRL1_LENC 0x02104#define CTRL1_PRE 0x01105/* REG 0xC7 (unknown name): affects Auto White Balance (AWB)106 * AWB_OFF 0x40107 * AWB_SIMPLE 0x10108 * AWB_ON 0x00 (Advanced AWB ?) */109#define R_DVP_SP 0xD3 /* DVP output speed control */110#define R_DVP_SP_AUTO_MODE 0x80111#define R_DVP_SP_DVP_MASK 0x3F /* DVP PCLK = sysclk (48)/[6:0] (YUV0);112 * = sysclk (48)/(2*[6:0]) (RAW);*/113#define IMAGE_MODE 0xDA /* Image Output Format Select */114#define IMAGE_MODE_Y8_DVP_EN 0x40115#define IMAGE_MODE_JPEG_EN 0x10116#define IMAGE_MODE_YUV422 0x00117#define IMAGE_MODE_RAW10 0x04 /* (DVP) */118#define IMAGE_MODE_RGB565 0x08119#define IMAGE_MODE_HREF_VSYNC 0x02 /* HREF timing select in DVP JPEG output120 * mode (0 for HREF is same as sensor) */121#define IMAGE_MODE_LBYTE_FIRST 0x01 /* Byte swap enable for DVP122 * 1: Low byte first UYVY (C2[4] =0)123 * VYUY (C2[4] =1)124 * 0: High byte first YUYV (C2[4]=0)125 * YVYU (C2[4] = 1) */126#define RESET 0xE0 /* Reset */127#define RESET_MICROC 0x40128#define RESET_SCCB 0x20129#define RESET_JPEG 0x10130#define RESET_DVP 0x04131#define RESET_IPU 0x02132#define RESET_CIF 0x01133#define REGED 0xED /* Register ED */134#define REGED_CLK_OUT_DIS 0x10135#define MS_SP 0xF0 /* SCCB Master Speed */136#define SS_ID 0xF7 /* SCCB Slave ID */137#define SS_CTRL 0xF8 /* SCCB Slave Control */138#define SS_CTRL_ADD_AUTO_INC 0x20139#define SS_CTRL_EN 0x08140#define SS_CTRL_DELAY_CLK 0x04141#define SS_CTRL_ACC_EN 0x02142#define SS_CTRL_SEN_PASS_THR 0x01143#define MC_BIST 0xF9 /* Microcontroller misc register */144#define MC_BIST_RESET 0x80 /* Microcontroller Reset */145#define MC_BIST_BOOT_ROM_SEL 0x40146#define MC_BIST_12KB_SEL 0x20147#define MC_BIST_12KB_MASK 0x30148#define MC_BIST_512KB_SEL 0x08149#define MC_BIST_512KB_MASK 0x0C150#define MC_BIST_BUSY_BIT_R 0x02151#define MC_BIST_MC_RES_ONE_SH_W 0x02152#define MC_BIST_LAUNCH 0x01153#define BANK_SEL 0xFF /* Register Bank Select */154#define BANK_SEL_DSP 0x00155#define BANK_SEL_SENS 0x01156 157/*158 * Sensor registers159 * register offset for BANK_SEL == BANK_SEL_SENS160 */161#define GAIN 0x00 /* AGC - Gain control gain setting */162#define COM1 0x03 /* Common control 1 */163#define COM1_1_DUMMY_FR 0x40164#define COM1_3_DUMMY_FR 0x80165#define COM1_7_DUMMY_FR 0xC0166#define COM1_VWIN_LSB_UXGA 0x0F167#define COM1_VWIN_LSB_SVGA 0x0A168#define COM1_VWIN_LSB_CIF 0x06169#define REG04 0x04 /* Register 04 */170#define REG04_DEF 0x20 /* Always set */171#define REG04_HFLIP_IMG 0x80 /* Horizontal mirror image ON/OFF */172#define REG04_VFLIP_IMG 0x40 /* Vertical flip image ON/OFF */173#define REG04_VREF_EN 0x10174#define REG04_HREF_EN 0x08175#define REG04_AEC_SET(x) VAL_SET(x, 0x3, 0, 0)176#define REG08 0x08 /* Frame Exposure One-pin Control Pre-charge Row Num */177#define COM2 0x09 /* Common control 2 */178#define COM2_SOFT_SLEEP_MODE 0x10 /* Soft sleep mode */179 /* Output drive capability */180#define COM2_OCAP_Nx_SET(N) (((N) - 1) & 0x03) /* N = [1x .. 4x] */181#define PID 0x0A /* Product ID Number MSB */182#define VER 0x0B /* Product ID Number LSB */183#define COM3 0x0C /* Common control 3 */184#define COM3_BAND_50H 0x04 /* 0 For Banding at 60H */185#define COM3_BAND_AUTO 0x02 /* Auto Banding */186#define COM3_SING_FR_SNAPSH 0x01 /* 0 For enable live video output after the187 * snapshot sequence*/188#define AEC 0x10 /* AEC[9:2] Exposure Value */189#define CLKRC 0x11 /* Internal clock */190#define CLKRC_EN 0x80191#define CLKRC_DIV_SET(x) (((x) - 1) & 0x1F) /* CLK = XVCLK/(x) */192#define COM7 0x12 /* Common control 7 */193#define COM7_SRST 0x80 /* Initiates system reset. All registers are194 * set to factory default values after which195 * the chip resumes normal operation */196#define COM7_RES_UXGA 0x00 /* Resolution selectors for UXGA */197#define COM7_RES_SVGA 0x40 /* SVGA */198#define COM7_RES_CIF 0x20 /* CIF */199#define COM7_ZOOM_EN 0x04 /* Enable Zoom mode */200#define COM7_COLOR_BAR_TEST 0x02 /* Enable Color Bar Test Pattern */201#define COM8 0x13 /* Common control 8 */202#define COM8_DEF 0xC0203#define COM8_BNDF_EN 0x20 /* Banding filter ON/OFF */204#define COM8_AGC_EN 0x04 /* AGC Auto/Manual control selection */205#define COM8_AEC_EN 0x01 /* Auto/Manual Exposure control */206#define COM9 0x14 /* Common control 9207 * Automatic gain ceiling - maximum AGC value [7:5]*/208#define COM9_AGC_GAIN_2x 0x00 /* 000 : 2x */209#define COM9_AGC_GAIN_4x 0x20 /* 001 : 4x */210#define COM9_AGC_GAIN_8x 0x40 /* 010 : 8x */211#define COM9_AGC_GAIN_16x 0x60 /* 011 : 16x */212#define COM9_AGC_GAIN_32x 0x80 /* 100 : 32x */213#define COM9_AGC_GAIN_64x 0xA0 /* 101 : 64x */214#define COM9_AGC_GAIN_128x 0xC0 /* 110 : 128x */215#define COM10 0x15 /* Common control 10 */216#define COM10_PCLK_HREF 0x20 /* PCLK output qualified by HREF */217#define COM10_PCLK_RISE 0x10 /* Data is updated at the rising edge of218 * PCLK (user can latch data at the next219 * falling edge of PCLK).220 * 0 otherwise. */221#define COM10_HREF_INV 0x08 /* Invert HREF polarity:222 * HREF negative for valid data*/223#define COM10_VSINC_INV 0x02 /* Invert VSYNC polarity */224#define HSTART 0x17 /* Horizontal Window start MSB 8 bit */225#define HEND 0x18 /* Horizontal Window end MSB 8 bit */226#define VSTART 0x19 /* Vertical Window start MSB 8 bit */227#define VEND 0x1A /* Vertical Window end MSB 8 bit */228#define MIDH 0x1C /* Manufacturer ID byte - high */229#define MIDL 0x1D /* Manufacturer ID byte - low */230#define AEW 0x24 /* AGC/AEC - Stable operating region (upper limit) */231#define AEB 0x25 /* AGC/AEC - Stable operating region (lower limit) */232#define VV 0x26 /* AGC/AEC Fast mode operating region */233#define VV_HIGH_TH_SET(x) VAL_SET(x, 0xF, 0, 4)234#define VV_LOW_TH_SET(x) VAL_SET(x, 0xF, 0, 0)235#define REG2A 0x2A /* Dummy pixel insert MSB */236#define FRARL 0x2B /* Dummy pixel insert LSB */237#define ADDVFL 0x2D /* LSB of insert dummy lines in Vertical direction */238#define ADDVFH 0x2E /* MSB of insert dummy lines in Vertical direction */239#define YAVG 0x2F /* Y/G Channel Average value */240#define REG32 0x32 /* Common Control 32 */241#define REG32_PCLK_DIV_2 0x80 /* PCLK freq divided by 2 */242#define REG32_PCLK_DIV_4 0xC0 /* PCLK freq divided by 4 */243#define ARCOM2 0x34 /* Zoom: Horizontal start point */244#define REG45 0x45 /* Register 45 */245#define FLL 0x46 /* Frame Length Adjustment LSBs */246#define FLH 0x47 /* Frame Length Adjustment MSBs */247#define COM19 0x48 /* Zoom: Vertical start point */248#define ZOOMS 0x49 /* Zoom: Vertical start point */249#define COM22 0x4B /* Flash light control */250#define COM25 0x4E /* For Banding operations */251#define COM25_50HZ_BANDING_AEC_MSBS_MASK 0xC0 /* 50Hz Bd. AEC 2 MSBs */252#define COM25_60HZ_BANDING_AEC_MSBS_MASK 0x30 /* 60Hz Bd. AEC 2 MSBs */253#define COM25_50HZ_BANDING_AEC_MSBS_SET(x) VAL_SET(x, 0x3, 8, 6)254#define COM25_60HZ_BANDING_AEC_MSBS_SET(x) VAL_SET(x, 0x3, 8, 4)255#define BD50 0x4F /* 50Hz Banding AEC 8 LSBs */256#define BD50_50HZ_BANDING_AEC_LSBS_SET(x) VAL_SET(x, 0xFF, 0, 0)257#define BD60 0x50 /* 60Hz Banding AEC 8 LSBs */258#define BD60_60HZ_BANDING_AEC_LSBS_SET(x) VAL_SET(x, 0xFF, 0, 0)259#define REG5A 0x5A /* 50/60Hz Banding Maximum AEC Step */260#define BD50_MAX_AEC_STEP_MASK 0xF0 /* 50Hz Banding Max. AEC Step */261#define BD60_MAX_AEC_STEP_MASK 0x0F /* 60Hz Banding Max. AEC Step */262#define BD50_MAX_AEC_STEP_SET(x) VAL_SET((x - 1), 0x0F, 0, 4)263#define BD60_MAX_AEC_STEP_SET(x) VAL_SET((x - 1), 0x0F, 0, 0)264#define REG5D 0x5D /* AVGsel[7:0], 16-zone average weight option */265#define REG5E 0x5E /* AVGsel[15:8], 16-zone average weight option */266#define REG5F 0x5F /* AVGsel[23:16], 16-zone average weight option */267#define REG60 0x60 /* AVGsel[31:24], 16-zone average weight option */268#define HISTO_LOW 0x61 /* Histogram Algorithm Low Level */269#define HISTO_HIGH 0x62 /* Histogram Algorithm High Level */270 271/*272 * ID273 */274#define MANUFACTURER_ID 0x7FA2275#define PID_OV2640 0x2642276#define VERSION(pid, ver) ((pid << 8) | (ver & 0xFF))277 278/*279 * Struct280 */281struct regval_list {282 u8 reg_num;283 u8 value;284};285 286struct ov2640_win_size {287 char *name;288 u32 width;289 u32 height;290 const struct regval_list *regs;291};292 293 294struct ov2640_priv {295 struct v4l2_subdev subdev;296 struct media_pad pad;297 struct v4l2_ctrl_handler hdl;298 u32 cfmt_code;299 struct clk *clk;300 const struct ov2640_win_size *win;301 302 struct gpio_desc *resetb_gpio;303 struct gpio_desc *pwdn_gpio;304 305 struct mutex lock; /* lock to protect streaming and power_count */306 bool streaming;307 int power_count;308};309 310/*311 * Registers settings312 */313 314#define ENDMARKER { 0xff, 0xff }315 316static 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 { REG5A, BD50_MAX_AEC_STEP_SET(6)373 | BD60_MAX_AEC_STEP_SET(8) }, /* 0x57 */374 { COM25, COM25_50HZ_BANDING_AEC_MSBS_SET(0x0bb)375 | COM25_60HZ_BANDING_AEC_MSBS_SET(0x09c) }, /* 0x00 */376 { BD50, BD50_50HZ_BANDING_AEC_LSBS_SET(0x0bb) }, /* 0xbb */377 { BD60, BD60_60HZ_BANDING_AEC_LSBS_SET(0x09c) }, /* 0x9c */378 { BANK_SEL, BANK_SEL_DSP },379 { 0xe5, 0x7f },380 { MC_BIST, MC_BIST_RESET | MC_BIST_BOOT_ROM_SEL },381 { 0x41, 0x24 },382 { RESET, RESET_JPEG | RESET_DVP },383 { 0x76, 0xff },384 { 0x33, 0xa0 },385 { 0x42, 0x20 },386 { 0x43, 0x18 },387 { 0x4c, 0x00 },388 { CTRL3, CTRL3_BPC_EN | CTRL3_WPC_EN | 0x10 },389 { 0x88, 0x3f },390 { 0xd7, 0x03 },391 { 0xd9, 0x10 },392 { R_DVP_SP, R_DVP_SP_AUTO_MODE | 0x2 },393 { 0xc8, 0x08 },394 { 0xc9, 0x80 },395 { BPADDR, 0x00 },396 { BPDATA, 0x00 },397 { BPADDR, 0x03 },398 { BPDATA, 0x48 },399 { BPDATA, 0x48 },400 { BPADDR, 0x08 },401 { BPDATA, 0x20 },402 { BPDATA, 0x10 },403 { BPDATA, 0x0e },404 { 0x90, 0x00 },405 { 0x91, 0x0e },406 { 0x91, 0x1a },407 { 0x91, 0x31 },408 { 0x91, 0x5a },409 { 0x91, 0x69 },410 { 0x91, 0x75 },411 { 0x91, 0x7e },412 { 0x91, 0x88 },413 { 0x91, 0x8f },414 { 0x91, 0x96 },415 { 0x91, 0xa3 },416 { 0x91, 0xaf },417 { 0x91, 0xc4 },418 { 0x91, 0xd7 },419 { 0x91, 0xe8 },420 { 0x91, 0x20 },421 { 0x92, 0x00 },422 { 0x93, 0x06 },423 { 0x93, 0xe3 },424 { 0x93, 0x03 },425 { 0x93, 0x03 },426 { 0x93, 0x00 },427 { 0x93, 0x02 },428 { 0x93, 0x00 },429 { 0x93, 0x00 },430 { 0x93, 0x00 },431 { 0x93, 0x00 },432 { 0x93, 0x00 },433 { 0x93, 0x00 },434 { 0x93, 0x00 },435 { 0x96, 0x00 },436 { 0x97, 0x08 },437 { 0x97, 0x19 },438 { 0x97, 0x02 },439 { 0x97, 0x0c },440 { 0x97, 0x24 },441 { 0x97, 0x30 },442 { 0x97, 0x28 },443 { 0x97, 0x26 },444 { 0x97, 0x02 },445 { 0x97, 0x98 },446 { 0x97, 0x80 },447 { 0x97, 0x00 },448 { 0x97, 0x00 },449 { 0xa4, 0x00 },450 { 0xa8, 0x00 },451 { 0xc5, 0x11 },452 { 0xc6, 0x51 },453 { 0xbf, 0x80 },454 { 0xc7, 0x10 }, /* simple AWB */455 { 0xb6, 0x66 },456 { 0xb8, 0xA5 },457 { 0xb7, 0x64 },458 { 0xb9, 0x7C },459 { 0xb3, 0xaf },460 { 0xb4, 0x97 },461 { 0xb5, 0xFF },462 { 0xb0, 0xC5 },463 { 0xb1, 0x94 },464 { 0xb2, 0x0f },465 { 0xc4, 0x5c },466 { 0xa6, 0x00 },467 { 0xa7, 0x20 },468 { 0xa7, 0xd8 },469 { 0xa7, 0x1b },470 { 0xa7, 0x31 },471 { 0xa7, 0x00 },472 { 0xa7, 0x18 },473 { 0xa7, 0x20 },474 { 0xa7, 0xd8 },475 { 0xa7, 0x19 },476 { 0xa7, 0x31 },477 { 0xa7, 0x00 },478 { 0xa7, 0x18 },479 { 0xa7, 0x20 },480 { 0xa7, 0xd8 },481 { 0xa7, 0x19 },482 { 0xa7, 0x31 },483 { 0xa7, 0x00 },484 { 0xa7, 0x18 },485 { 0x7f, 0x00 },486 { 0xe5, 0x1f },487 { 0xe1, 0x77 },488 { 0xdd, 0x7f },489 { CTRL0, CTRL0_YUV422 | CTRL0_YUV_EN | CTRL0_RGB_EN },490 ENDMARKER,491};492 493/*494 * Register settings for window size495 * The preamble, setup the internal DSP to input an UXGA (1600x1200) image.496 * Then the different zooming configurations will setup the output image size.497 */498static const struct regval_list ov2640_size_change_preamble_regs[] = {499 { BANK_SEL, BANK_SEL_DSP },500 { RESET, RESET_DVP },501 { SIZEL, SIZEL_HSIZE8_11_SET(UXGA_WIDTH) |502 SIZEL_HSIZE8_SET(UXGA_WIDTH) |503 SIZEL_VSIZE8_SET(UXGA_HEIGHT) },504 { HSIZE8, HSIZE8_SET(UXGA_WIDTH) },505 { VSIZE8, VSIZE8_SET(UXGA_HEIGHT) },506 { CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN |507 CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN },508 { HSIZE, HSIZE_SET(UXGA_WIDTH) },509 { VSIZE, VSIZE_SET(UXGA_HEIGHT) },510 { XOFFL, XOFFL_SET(0) },511 { YOFFL, YOFFL_SET(0) },512 { VHYX, VHYX_HSIZE_SET(UXGA_WIDTH) | VHYX_VSIZE_SET(UXGA_HEIGHT) |513 VHYX_XOFF_SET(0) | VHYX_YOFF_SET(0)},514 { TEST, TEST_HSIZE_SET(UXGA_WIDTH) },515 ENDMARKER,516};517 518#define PER_SIZE_REG_SEQ(x, y, v_div, h_div, pclk_div) \519 { CTRLI, CTRLI_LP_DP | CTRLI_V_DIV_SET(v_div) | \520 CTRLI_H_DIV_SET(h_div)}, \521 { ZMOW, ZMOW_OUTW_SET(x) }, \522 { ZMOH, ZMOH_OUTH_SET(y) }, \523 { ZMHH, ZMHH_OUTW_SET(x) | ZMHH_OUTH_SET(y) }, \524 { R_DVP_SP, pclk_div }, \525 { RESET, 0x00}526 527static const struct regval_list ov2640_qcif_regs[] = {528 PER_SIZE_REG_SEQ(QCIF_WIDTH, QCIF_HEIGHT, 3, 3, 4),529 ENDMARKER,530};531 532static const struct regval_list ov2640_qvga_regs[] = {533 PER_SIZE_REG_SEQ(QVGA_WIDTH, QVGA_HEIGHT, 2, 2, 4),534 ENDMARKER,535};536 537static const struct regval_list ov2640_cif_regs[] = {538 PER_SIZE_REG_SEQ(CIF_WIDTH, CIF_HEIGHT, 2, 2, 8),539 ENDMARKER,540};541 542static const struct regval_list ov2640_vga_regs[] = {543 PER_SIZE_REG_SEQ(VGA_WIDTH, VGA_HEIGHT, 0, 0, 2),544 ENDMARKER,545};546 547static const struct regval_list ov2640_svga_regs[] = {548 PER_SIZE_REG_SEQ(SVGA_WIDTH, SVGA_HEIGHT, 1, 1, 2),549 ENDMARKER,550};551 552static const struct regval_list ov2640_xga_regs[] = {553 PER_SIZE_REG_SEQ(XGA_WIDTH, XGA_HEIGHT, 0, 0, 2),554 { CTRLI, 0x00},555 ENDMARKER,556};557 558static const struct regval_list ov2640_sxga_regs[] = {559 PER_SIZE_REG_SEQ(SXGA_WIDTH, SXGA_HEIGHT, 0, 0, 2),560 { CTRLI, 0x00},561 { R_DVP_SP, 2 | R_DVP_SP_AUTO_MODE },562 ENDMARKER,563};564 565static const struct regval_list ov2640_uxga_regs[] = {566 PER_SIZE_REG_SEQ(UXGA_WIDTH, UXGA_HEIGHT, 0, 0, 0),567 { CTRLI, 0x00},568 { R_DVP_SP, 0 | R_DVP_SP_AUTO_MODE },569 ENDMARKER,570};571 572#define OV2640_SIZE(n, w, h, r) \573 {.name = n, .width = w , .height = h, .regs = r }574 575static const struct ov2640_win_size ov2640_supported_win_sizes[] = {576 OV2640_SIZE("QCIF", QCIF_WIDTH, QCIF_HEIGHT, ov2640_qcif_regs),577 OV2640_SIZE("QVGA", QVGA_WIDTH, QVGA_HEIGHT, ov2640_qvga_regs),578 OV2640_SIZE("CIF", CIF_WIDTH, CIF_HEIGHT, ov2640_cif_regs),579 OV2640_SIZE("VGA", VGA_WIDTH, VGA_HEIGHT, ov2640_vga_regs),580 OV2640_SIZE("SVGA", SVGA_WIDTH, SVGA_HEIGHT, ov2640_svga_regs),581 OV2640_SIZE("XGA", XGA_WIDTH, XGA_HEIGHT, ov2640_xga_regs),582 OV2640_SIZE("SXGA", SXGA_WIDTH, SXGA_HEIGHT, ov2640_sxga_regs),583 OV2640_SIZE("UXGA", UXGA_WIDTH, UXGA_HEIGHT, ov2640_uxga_regs),584};585 586/*587 * Register settings for pixel formats588 */589static const struct regval_list ov2640_format_change_preamble_regs[] = {590 { BANK_SEL, BANK_SEL_DSP },591 { R_BYPASS, R_BYPASS_USE_DSP },592 ENDMARKER,593};594 595static const struct regval_list ov2640_yuyv_regs[] = {596 { IMAGE_MODE, IMAGE_MODE_YUV422 },597 { 0xd7, 0x03 },598 { 0x33, 0xa0 },599 { 0xe5, 0x1f },600 { 0xe1, 0x67 },601 { RESET, 0x00 },602 { R_BYPASS, R_BYPASS_USE_DSP },603 ENDMARKER,604};605 606static const struct regval_list ov2640_uyvy_regs[] = {607 { IMAGE_MODE, IMAGE_MODE_LBYTE_FIRST | IMAGE_MODE_YUV422 },608 { 0xd7, 0x01 },609 { 0x33, 0xa0 },610 { 0xe1, 0x67 },611 { RESET, 0x00 },612 { R_BYPASS, R_BYPASS_USE_DSP },613 ENDMARKER,614};615 616static const struct regval_list ov2640_rgb565_be_regs[] = {617 { IMAGE_MODE, IMAGE_MODE_RGB565 },618 { 0xd7, 0x03 },619 { RESET, 0x00 },620 { R_BYPASS, R_BYPASS_USE_DSP },621 ENDMARKER,622};623 624static const struct regval_list ov2640_rgb565_le_regs[] = {625 { IMAGE_MODE, IMAGE_MODE_LBYTE_FIRST | IMAGE_MODE_RGB565 },626 { 0xd7, 0x03 },627 { RESET, 0x00 },628 { R_BYPASS, R_BYPASS_USE_DSP },629 ENDMARKER,630};631 632static u32 ov2640_codes[] = {633 MEDIA_BUS_FMT_YUYV8_2X8,634 MEDIA_BUS_FMT_UYVY8_2X8,635 MEDIA_BUS_FMT_YVYU8_2X8,636 MEDIA_BUS_FMT_VYUY8_2X8,637 MEDIA_BUS_FMT_RGB565_2X8_BE,638 MEDIA_BUS_FMT_RGB565_2X8_LE,639};640 641/*642 * General functions643 */644static struct ov2640_priv *to_ov2640(const struct i2c_client *client)645{646 return container_of(i2c_get_clientdata(client), struct ov2640_priv,647 subdev);648}649 650static int ov2640_write_array(struct i2c_client *client,651 const struct regval_list *vals)652{653 int ret;654 655 while ((vals->reg_num != 0xff) || (vals->value != 0xff)) {656 ret = i2c_smbus_write_byte_data(client,657 vals->reg_num, vals->value);658 dev_vdbg(&client->dev, "array: 0x%02x, 0x%02x",659 vals->reg_num, vals->value);660 661 if (ret < 0)662 return ret;663 vals++;664 }665 return 0;666}667 668static int ov2640_mask_set(struct i2c_client *client,669 u8 reg, u8 mask, u8 set)670{671 s32 val = i2c_smbus_read_byte_data(client, reg);672 if (val < 0)673 return val;674 675 val &= ~mask;676 val |= set & mask;677 678 dev_vdbg(&client->dev, "masks: 0x%02x, 0x%02x", reg, val);679 680 return i2c_smbus_write_byte_data(client, reg, val);681}682 683static int ov2640_reset(struct i2c_client *client)684{685 int ret;686 static const struct regval_list reset_seq[] = {687 {BANK_SEL, BANK_SEL_SENS},688 {COM7, COM7_SRST},689 ENDMARKER,690 };691 692 ret = ov2640_write_array(client, reset_seq);693 if (ret)694 goto err;695 696 msleep(5);697err:698 dev_dbg(&client->dev, "%s: (ret %d)", __func__, ret);699 return ret;700}701 702static const char * const ov2640_test_pattern_menu[] = {703 "Disabled",704 "Eight Vertical Colour Bars",705};706 707/*708 * functions709 */710static int ov2640_s_ctrl(struct v4l2_ctrl *ctrl)711{712 struct v4l2_subdev *sd =713 &container_of(ctrl->handler, struct ov2640_priv, hdl)->subdev;714 struct i2c_client *client = v4l2_get_subdevdata(sd);715 struct ov2640_priv *priv = to_ov2640(client);716 u8 val;717 int ret;718 719 /* v4l2_ctrl_lock() locks our own mutex */720 721 /*722 * If the device is not powered up by the host driver, do not apply any723 * controls to H/W at this time. Instead the controls will be restored724 * when the streaming is started.725 */726 if (!priv->power_count)727 return 0;728 729 ret = i2c_smbus_write_byte_data(client, BANK_SEL, BANK_SEL_SENS);730 if (ret < 0)731 return ret;732 733 switch (ctrl->id) {734 case V4L2_CID_VFLIP:735 val = ctrl->val ? REG04_VFLIP_IMG | REG04_VREF_EN : 0x00;736 return ov2640_mask_set(client, REG04,737 REG04_VFLIP_IMG | REG04_VREF_EN, val);738 /* NOTE: REG04_VREF_EN: 1 line shift / even/odd line swap */739 case V4L2_CID_HFLIP:740 val = ctrl->val ? REG04_HFLIP_IMG : 0x00;741 return ov2640_mask_set(client, REG04, REG04_HFLIP_IMG, val);742 case V4L2_CID_TEST_PATTERN:743 val = ctrl->val ? COM7_COLOR_BAR_TEST : 0x00;744 return ov2640_mask_set(client, COM7, COM7_COLOR_BAR_TEST, val);745 }746 747 return -EINVAL;748}749 750#ifdef CONFIG_VIDEO_ADV_DEBUG751static int ov2640_g_register(struct v4l2_subdev *sd,752 struct v4l2_dbg_register *reg)753{754 struct i2c_client *client = v4l2_get_subdevdata(sd);755 int ret;756 757 reg->size = 1;758 if (reg->reg > 0xff)759 return -EINVAL;760 761 ret = i2c_smbus_read_byte_data(client, reg->reg);762 if (ret < 0)763 return ret;764 765 reg->val = ret;766 767 return 0;768}769 770static int ov2640_s_register(struct v4l2_subdev *sd,771 const struct v4l2_dbg_register *reg)772{773 struct i2c_client *client = v4l2_get_subdevdata(sd);774 775 if (reg->reg > 0xff ||776 reg->val > 0xff)777 return -EINVAL;778 779 return i2c_smbus_write_byte_data(client, reg->reg, reg->val);780}781#endif782 783static void ov2640_set_power(struct ov2640_priv *priv, int on)784{785#ifdef CONFIG_GPIOLIB786 if (priv->pwdn_gpio)787 gpiod_direction_output(priv->pwdn_gpio, !on);788 if (on && priv->resetb_gpio) {789 /* Active the resetb pin to perform a reset pulse */790 gpiod_direction_output(priv->resetb_gpio, 1);791 usleep_range(3000, 5000);792 gpiod_set_value(priv->resetb_gpio, 0);793 }794#endif795}796 797static int ov2640_s_power(struct v4l2_subdev *sd, int on)798{799 struct i2c_client *client = v4l2_get_subdevdata(sd);800 struct ov2640_priv *priv = to_ov2640(client);801 802 mutex_lock(&priv->lock);803 804 /*805 * If the power count is modified from 0 to != 0 or from != 0 to 0,806 * update the power state.807 */808 if (priv->power_count == !on)809 ov2640_set_power(priv, on);810 priv->power_count += on ? 1 : -1;811 WARN_ON(priv->power_count < 0);812 mutex_unlock(&priv->lock);813 814 return 0;815}816 817/* Select the nearest higher resolution for capture */818static const struct ov2640_win_size *ov2640_select_win(u32 width, u32 height)819{820 int i, default_size = ARRAY_SIZE(ov2640_supported_win_sizes) - 1;821 822 for (i = 0; i < ARRAY_SIZE(ov2640_supported_win_sizes); i++) {823 if (ov2640_supported_win_sizes[i].width >= width &&824 ov2640_supported_win_sizes[i].height >= height)825 return &ov2640_supported_win_sizes[i];826 }827 828 return &ov2640_supported_win_sizes[default_size];829}830 831static int ov2640_set_params(struct i2c_client *client,832 const struct ov2640_win_size *win, u32 code)833{834 const struct regval_list *selected_cfmt_regs;835 u8 val;836 int ret;837 838 switch (code) {839 case MEDIA_BUS_FMT_RGB565_2X8_BE:840 dev_dbg(&client->dev, "%s: Selected cfmt RGB565 BE", __func__);841 selected_cfmt_regs = ov2640_rgb565_be_regs;842 break;843 case MEDIA_BUS_FMT_RGB565_2X8_LE:844 dev_dbg(&client->dev, "%s: Selected cfmt RGB565 LE", __func__);845 selected_cfmt_regs = ov2640_rgb565_le_regs;846 break;847 case MEDIA_BUS_FMT_YUYV8_2X8:848 dev_dbg(&client->dev, "%s: Selected cfmt YUYV (YUV422)", __func__);849 selected_cfmt_regs = ov2640_yuyv_regs;850 break;851 case MEDIA_BUS_FMT_UYVY8_2X8:852 default:853 dev_dbg(&client->dev, "%s: Selected cfmt UYVY", __func__);854 selected_cfmt_regs = ov2640_uyvy_regs;855 break;856 case MEDIA_BUS_FMT_YVYU8_2X8:857 dev_dbg(&client->dev, "%s: Selected cfmt YVYU", __func__);858 selected_cfmt_regs = ov2640_yuyv_regs;859 break;860 case MEDIA_BUS_FMT_VYUY8_2X8:861 dev_dbg(&client->dev, "%s: Selected cfmt VYUY", __func__);862 selected_cfmt_regs = ov2640_uyvy_regs;863 break;864 }865 866 /* reset hardware */867 ov2640_reset(client);868 869 /* initialize the sensor with default data */870 dev_dbg(&client->dev, "%s: Init default", __func__);871 ret = ov2640_write_array(client, ov2640_init_regs);872 if (ret < 0)873 goto err;874 875 /* select preamble */876 dev_dbg(&client->dev, "%s: Set size to %s", __func__, win->name);877 ret = ov2640_write_array(client, ov2640_size_change_preamble_regs);878 if (ret < 0)879 goto err;880 881 /* set size win */882 ret = ov2640_write_array(client, win->regs);883 if (ret < 0)884 goto err;885 886 /* cfmt preamble */887 dev_dbg(&client->dev, "%s: Set cfmt", __func__);888 ret = ov2640_write_array(client, ov2640_format_change_preamble_regs);889 if (ret < 0)890 goto err;891 892 /* set cfmt */893 ret = ov2640_write_array(client, selected_cfmt_regs);894 if (ret < 0)895 goto err;896 val = (code == MEDIA_BUS_FMT_YVYU8_2X8)897 || (code == MEDIA_BUS_FMT_VYUY8_2X8) ? CTRL0_VFIRST : 0x00;898 ret = ov2640_mask_set(client, CTRL0, CTRL0_VFIRST, val);899 if (ret < 0)900 goto err;901 902 return 0;903 904err:905 dev_err(&client->dev, "%s: Error %d", __func__, ret);906 ov2640_reset(client);907 908 return ret;909}910 911static int ov2640_get_fmt(struct v4l2_subdev *sd,912 struct v4l2_subdev_state *sd_state,913 struct v4l2_subdev_format *format)914{915 struct v4l2_mbus_framefmt *mf = &format->format;916 struct i2c_client *client = v4l2_get_subdevdata(sd);917 struct ov2640_priv *priv = to_ov2640(client);918 919 if (format->pad)920 return -EINVAL;921 922 if (format->which == V4L2_SUBDEV_FORMAT_TRY) {923 mf = v4l2_subdev_state_get_format(sd_state, 0);924 format->format = *mf;925 return 0;926 }927 928 mf->width = priv->win->width;929 mf->height = priv->win->height;930 mf->code = priv->cfmt_code;931 mf->colorspace = V4L2_COLORSPACE_SRGB;932 mf->field = V4L2_FIELD_NONE;933 mf->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;934 mf->quantization = V4L2_QUANTIZATION_DEFAULT;935 mf->xfer_func = V4L2_XFER_FUNC_DEFAULT;936 937 return 0;938}939 940static int ov2640_set_fmt(struct v4l2_subdev *sd,941 struct v4l2_subdev_state *sd_state,942 struct v4l2_subdev_format *format)943{944 struct v4l2_mbus_framefmt *mf = &format->format;945 struct i2c_client *client = v4l2_get_subdevdata(sd);946 struct ov2640_priv *priv = to_ov2640(client);947 const struct ov2640_win_size *win;948 int ret = 0;949 950 if (format->pad)951 return -EINVAL;952 953 mutex_lock(&priv->lock);954 955 /* select suitable win */956 win = ov2640_select_win(mf->width, mf->height);957 mf->width = win->width;958 mf->height = win->height;959 960 mf->field = V4L2_FIELD_NONE;961 mf->colorspace = V4L2_COLORSPACE_SRGB;962 mf->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;963 mf->quantization = V4L2_QUANTIZATION_DEFAULT;964 mf->xfer_func = V4L2_XFER_FUNC_DEFAULT;965 966 switch (mf->code) {967 case MEDIA_BUS_FMT_RGB565_2X8_BE:968 case MEDIA_BUS_FMT_RGB565_2X8_LE:969 case MEDIA_BUS_FMT_YUYV8_2X8:970 case MEDIA_BUS_FMT_UYVY8_2X8:971 case MEDIA_BUS_FMT_YVYU8_2X8:972 case MEDIA_BUS_FMT_VYUY8_2X8:973 break;974 default:975 mf->code = MEDIA_BUS_FMT_UYVY8_2X8;976 break;977 }978 979 if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {980 struct ov2640_priv *priv = to_ov2640(client);981 982 if (priv->streaming) {983 ret = -EBUSY;984 goto out;985 }986 /* select win */987 priv->win = win;988 /* select format */989 priv->cfmt_code = mf->code;990 } else {991 *v4l2_subdev_state_get_format(sd_state, 0) = *mf;992 }993out:994 mutex_unlock(&priv->lock);995 996 return ret;997}998 999static int ov2640_init_state(struct v4l2_subdev *sd,1000 struct v4l2_subdev_state *sd_state)1001{1002 struct v4l2_mbus_framefmt *try_fmt =1003 v4l2_subdev_state_get_format(sd_state, 0);1004 const struct ov2640_win_size *win =1005 ov2640_select_win(SVGA_WIDTH, SVGA_HEIGHT);1006 1007 try_fmt->width = win->width;1008 try_fmt->height = win->height;1009 try_fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;1010 try_fmt->colorspace = V4L2_COLORSPACE_SRGB;1011 try_fmt->field = V4L2_FIELD_NONE;1012 try_fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;1013 try_fmt->quantization = V4L2_QUANTIZATION_DEFAULT;1014 try_fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;1015 1016 return 0;1017}1018 1019static int ov2640_enum_mbus_code(struct v4l2_subdev *sd,1020 struct v4l2_subdev_state *sd_state,1021 struct v4l2_subdev_mbus_code_enum *code)1022{1023 if (code->pad || code->index >= ARRAY_SIZE(ov2640_codes))1024 return -EINVAL;1025 1026 code->code = ov2640_codes[code->index];1027 return 0;1028}1029 1030static int ov2640_get_selection(struct v4l2_subdev *sd,1031 struct v4l2_subdev_state *sd_state,1032 struct v4l2_subdev_selection *sel)1033{1034 if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)1035 return -EINVAL;1036 1037 switch (sel->target) {1038 case V4L2_SEL_TGT_CROP_BOUNDS:1039 case V4L2_SEL_TGT_CROP:1040 sel->r.left = 0;1041 sel->r.top = 0;1042 sel->r.width = UXGA_WIDTH;1043 sel->r.height = UXGA_HEIGHT;1044 return 0;1045 default:1046 return -EINVAL;1047 }1048}1049 1050static int ov2640_s_stream(struct v4l2_subdev *sd, int on)1051{1052 struct i2c_client *client = v4l2_get_subdevdata(sd);1053 struct ov2640_priv *priv = to_ov2640(client);1054 int ret = 0;1055 1056 mutex_lock(&priv->lock);1057 if (priv->streaming == !on) {1058 if (on) {1059 ret = ov2640_set_params(client, priv->win,1060 priv->cfmt_code);1061 if (!ret)1062 ret = __v4l2_ctrl_handler_setup(&priv->hdl);1063 }1064 }1065 if (!ret)1066 priv->streaming = on;1067 mutex_unlock(&priv->lock);1068 1069 return ret;1070}1071 1072static int ov2640_video_probe(struct i2c_client *client)1073{1074 struct ov2640_priv *priv = to_ov2640(client);1075 u8 pid, ver, midh, midl;1076 const char *devname;1077 int ret;1078 1079 ret = ov2640_s_power(&priv->subdev, 1);1080 if (ret < 0)1081 return ret;1082 1083 /*1084 * check and show product ID and manufacturer ID1085 */1086 i2c_smbus_write_byte_data(client, BANK_SEL, BANK_SEL_SENS);1087 pid = i2c_smbus_read_byte_data(client, PID);1088 ver = i2c_smbus_read_byte_data(client, VER);1089 midh = i2c_smbus_read_byte_data(client, MIDH);1090 midl = i2c_smbus_read_byte_data(client, MIDL);1091 1092 switch (VERSION(pid, ver)) {1093 case PID_OV2640:1094 devname = "ov2640";1095 break;1096 default:1097 dev_err(&client->dev,1098 "Product ID error %x:%x\n", pid, ver);1099 ret = -ENODEV;1100 goto done;1101 }1102 1103 dev_info(&client->dev,1104 "%s Product ID %0x:%0x Manufacturer ID %x:%x\n",1105 devname, pid, ver, midh, midl);1106 1107done:1108 ov2640_s_power(&priv->subdev, 0);1109 return ret;1110}1111 1112static const struct v4l2_ctrl_ops ov2640_ctrl_ops = {1113 .s_ctrl = ov2640_s_ctrl,1114};1115 1116static const struct v4l2_subdev_core_ops ov2640_subdev_core_ops = {1117 .log_status = v4l2_ctrl_subdev_log_status,1118 .subscribe_event = v4l2_ctrl_subdev_subscribe_event,1119 .unsubscribe_event = v4l2_event_subdev_unsubscribe,1120#ifdef CONFIG_VIDEO_ADV_DEBUG1121 .g_register = ov2640_g_register,1122 .s_register = ov2640_s_register,1123#endif1124 .s_power = ov2640_s_power,1125};1126 1127static const struct v4l2_subdev_pad_ops ov2640_subdev_pad_ops = {1128 .enum_mbus_code = ov2640_enum_mbus_code,1129 .get_selection = ov2640_get_selection,1130 .get_fmt = ov2640_get_fmt,1131 .set_fmt = ov2640_set_fmt,1132};1133 1134static const struct v4l2_subdev_video_ops ov2640_subdev_video_ops = {1135 .s_stream = ov2640_s_stream,1136};1137 1138static const struct v4l2_subdev_ops ov2640_subdev_ops = {1139 .core = &ov2640_subdev_core_ops,1140 .pad = &ov2640_subdev_pad_ops,1141 .video = &ov2640_subdev_video_ops,1142};1143 1144static const struct v4l2_subdev_internal_ops ov2640_internal_ops = {1145 .init_state = ov2640_init_state,1146};1147 1148static int ov2640_probe_dt(struct i2c_client *client,1149 struct ov2640_priv *priv)1150{1151 int ret;1152 1153 /* Request the reset GPIO deasserted */1154 priv->resetb_gpio = devm_gpiod_get_optional(&client->dev, "resetb",1155 GPIOD_OUT_LOW);1156 1157 if (!priv->resetb_gpio)1158 dev_dbg(&client->dev, "resetb gpio is not assigned!\n");1159 1160 ret = PTR_ERR_OR_ZERO(priv->resetb_gpio);1161 if (ret && ret != -ENOSYS) {1162 dev_dbg(&client->dev,1163 "Error %d while getting resetb gpio\n", ret);1164 return ret;1165 }1166 1167 /* Request the power down GPIO asserted */1168 priv->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "pwdn",1169 GPIOD_OUT_HIGH);1170 1171 if (!priv->pwdn_gpio)1172 dev_dbg(&client->dev, "pwdn gpio is not assigned!\n");1173 1174 ret = PTR_ERR_OR_ZERO(priv->pwdn_gpio);1175 if (ret && ret != -ENOSYS) {1176 dev_dbg(&client->dev,1177 "Error %d while getting pwdn gpio\n", ret);1178 return ret;1179 }1180 1181 return 0;1182}1183 1184/*1185 * i2c_driver functions1186 */1187static int ov2640_probe(struct i2c_client *client)1188{1189 struct ov2640_priv *priv;1190 struct i2c_adapter *adapter = client->adapter;1191 int ret;1192 1193 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {1194 dev_err(&adapter->dev,1195 "OV2640: I2C-Adapter doesn't support SMBUS\n");1196 return -EIO;1197 }1198 1199 priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);1200 if (!priv)1201 return -ENOMEM;1202 1203 if (client->dev.of_node) {1204 priv->clk = devm_clk_get_enabled(&client->dev, "xvclk");1205 if (IS_ERR(priv->clk))1206 return PTR_ERR(priv->clk);1207 }1208 1209 ret = ov2640_probe_dt(client, priv);1210 if (ret)1211 return ret;1212 1213 priv->win = ov2640_select_win(SVGA_WIDTH, SVGA_HEIGHT);1214 priv->cfmt_code = MEDIA_BUS_FMT_UYVY8_2X8;1215 1216 v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops);1217 priv->subdev.internal_ops = &ov2640_internal_ops;1218 priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |1219 V4L2_SUBDEV_FL_HAS_EVENTS;1220 mutex_init(&priv->lock);1221 v4l2_ctrl_handler_init(&priv->hdl, 3);1222 priv->hdl.lock = &priv->lock;1223 v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops,1224 V4L2_CID_VFLIP, 0, 1, 1, 0);1225 v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops,1226 V4L2_CID_HFLIP, 0, 1, 1, 0);1227 v4l2_ctrl_new_std_menu_items(&priv->hdl, &ov2640_ctrl_ops,1228 V4L2_CID_TEST_PATTERN,1229 ARRAY_SIZE(ov2640_test_pattern_menu) - 1, 0, 0,1230 ov2640_test_pattern_menu);1231 priv->subdev.ctrl_handler = &priv->hdl;1232 if (priv->hdl.error) {1233 ret = priv->hdl.error;1234 goto err_hdl;1235 }1236 priv->pad.flags = MEDIA_PAD_FL_SOURCE;1237 priv->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR;1238 ret = media_entity_pads_init(&priv->subdev.entity, 1, &priv->pad);1239 if (ret < 0)1240 goto err_hdl;1241 1242 ret = ov2640_video_probe(client);1243 if (ret < 0)1244 goto err_videoprobe;1245 1246 ret = v4l2_async_register_subdev(&priv->subdev);1247 if (ret < 0)1248 goto err_videoprobe;1249 1250 dev_info(&adapter->dev, "OV2640 Probed\n");1251 1252 return 0;1253 1254err_videoprobe:1255 media_entity_cleanup(&priv->subdev.entity);1256err_hdl:1257 v4l2_ctrl_handler_free(&priv->hdl);1258 mutex_destroy(&priv->lock);1259 return ret;1260}1261 1262static void ov2640_remove(struct i2c_client *client)1263{1264 struct ov2640_priv *priv = to_ov2640(client);1265 1266 v4l2_async_unregister_subdev(&priv->subdev);1267 v4l2_ctrl_handler_free(&priv->hdl);1268 mutex_destroy(&priv->lock);1269 media_entity_cleanup(&priv->subdev.entity);1270 v4l2_device_unregister_subdev(&priv->subdev);1271}1272 1273static const struct i2c_device_id ov2640_id[] = {1274 { "ov2640" },1275 { }1276};1277MODULE_DEVICE_TABLE(i2c, ov2640_id);1278 1279static const struct of_device_id ov2640_of_match[] = {1280 {.compatible = "ovti,ov2640", },1281 {},1282};1283MODULE_DEVICE_TABLE(of, ov2640_of_match);1284 1285static struct i2c_driver ov2640_i2c_driver = {1286 .driver = {1287 .name = "ov2640",1288 .of_match_table = ov2640_of_match,1289 },1290 .probe = ov2640_probe,1291 .remove = ov2640_remove,1292 .id_table = ov2640_id,1293};1294 1295module_i2c_driver(ov2640_i2c_driver);1296 1297MODULE_DESCRIPTION("Driver for Omni Vision 2640 sensor");1298MODULE_AUTHOR("Alberto Panizzo");1299MODULE_LICENSE("GPL v2");1300