134aa8879SHans Verkuil /* 234aa8879SHans Verkuil * ov2640 Camera Driver 334aa8879SHans Verkuil * 434aa8879SHans Verkuil * Copyright (C) 2010 Alberto Panizzo <maramaopercheseimorto@gmail.com> 534aa8879SHans Verkuil * 634aa8879SHans Verkuil * Based on ov772x, ov9640 drivers and previous non merged implementations. 734aa8879SHans Verkuil * 834aa8879SHans Verkuil * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved. 934aa8879SHans Verkuil * Copyright (C) 2006, OmniVision 1034aa8879SHans Verkuil * 1134aa8879SHans Verkuil * This program is free software; you can redistribute it and/or modify 1234aa8879SHans Verkuil * it under the terms of the GNU General Public License version 2 as 1334aa8879SHans Verkuil * published by the Free Software Foundation. 1434aa8879SHans Verkuil */ 1534aa8879SHans Verkuil 1634aa8879SHans Verkuil #include <linux/init.h> 1734aa8879SHans Verkuil #include <linux/module.h> 1834aa8879SHans Verkuil #include <linux/i2c.h> 1946796cfcSHans Verkuil #include <linux/clk.h> 2034aa8879SHans Verkuil #include <linux/slab.h> 2134aa8879SHans Verkuil #include <linux/delay.h> 2234aa8879SHans Verkuil #include <linux/gpio.h> 2334aa8879SHans Verkuil #include <linux/gpio/consumer.h> 2434aa8879SHans Verkuil #include <linux/of_gpio.h> 2534aa8879SHans Verkuil #include <linux/v4l2-mediabus.h> 2634aa8879SHans Verkuil #include <linux/videodev2.h> 2734aa8879SHans Verkuil 2834aa8879SHans Verkuil #include <media/v4l2-device.h> 2934aa8879SHans Verkuil #include <media/v4l2-subdev.h> 3034aa8879SHans Verkuil #include <media/v4l2-ctrls.h> 3134aa8879SHans Verkuil #include <media/v4l2-image-sizes.h> 3234aa8879SHans Verkuil 3334aa8879SHans Verkuil #define VAL_SET(x, mask, rshift, lshift) \ 3434aa8879SHans Verkuil ((((x) >> rshift) & mask) << lshift) 3534aa8879SHans Verkuil /* 3634aa8879SHans Verkuil * DSP registers 3734aa8879SHans Verkuil * register offset for BANK_SEL == BANK_SEL_DSP 3834aa8879SHans Verkuil */ 3934aa8879SHans Verkuil #define R_BYPASS 0x05 /* Bypass DSP */ 4034aa8879SHans Verkuil #define R_BYPASS_DSP_BYPAS 0x01 /* Bypass DSP, sensor out directly */ 4134aa8879SHans Verkuil #define R_BYPASS_USE_DSP 0x00 /* Use the internal DSP */ 4234aa8879SHans Verkuil #define QS 0x44 /* Quantization Scale Factor */ 4334aa8879SHans Verkuil #define CTRLI 0x50 4434aa8879SHans Verkuil #define CTRLI_LP_DP 0x80 4534aa8879SHans Verkuil #define CTRLI_ROUND 0x40 4634aa8879SHans Verkuil #define CTRLI_V_DIV_SET(x) VAL_SET(x, 0x3, 0, 3) 4734aa8879SHans Verkuil #define CTRLI_H_DIV_SET(x) VAL_SET(x, 0x3, 0, 0) 4834aa8879SHans Verkuil #define HSIZE 0x51 /* H_SIZE[7:0] (real/4) */ 4934aa8879SHans Verkuil #define HSIZE_SET(x) VAL_SET(x, 0xFF, 2, 0) 5034aa8879SHans Verkuil #define VSIZE 0x52 /* V_SIZE[7:0] (real/4) */ 5134aa8879SHans Verkuil #define VSIZE_SET(x) VAL_SET(x, 0xFF, 2, 0) 5234aa8879SHans Verkuil #define XOFFL 0x53 /* OFFSET_X[7:0] */ 5334aa8879SHans Verkuil #define XOFFL_SET(x) VAL_SET(x, 0xFF, 0, 0) 5434aa8879SHans Verkuil #define YOFFL 0x54 /* OFFSET_Y[7:0] */ 5534aa8879SHans Verkuil #define YOFFL_SET(x) VAL_SET(x, 0xFF, 0, 0) 5634aa8879SHans Verkuil #define VHYX 0x55 /* Offset and size completion */ 5734aa8879SHans Verkuil #define VHYX_VSIZE_SET(x) VAL_SET(x, 0x1, (8+2), 7) 5834aa8879SHans Verkuil #define VHYX_HSIZE_SET(x) VAL_SET(x, 0x1, (8+2), 3) 5934aa8879SHans Verkuil #define VHYX_YOFF_SET(x) VAL_SET(x, 0x3, 8, 4) 6034aa8879SHans Verkuil #define VHYX_XOFF_SET(x) VAL_SET(x, 0x3, 8, 0) 6134aa8879SHans Verkuil #define DPRP 0x56 6234aa8879SHans Verkuil #define TEST 0x57 /* Horizontal size completion */ 6334aa8879SHans Verkuil #define TEST_HSIZE_SET(x) VAL_SET(x, 0x1, (9+2), 7) 6434aa8879SHans Verkuil #define ZMOW 0x5A /* Zoom: Out Width OUTW[7:0] (real/4) */ 6534aa8879SHans Verkuil #define ZMOW_OUTW_SET(x) VAL_SET(x, 0xFF, 2, 0) 6634aa8879SHans Verkuil #define ZMOH 0x5B /* Zoom: Out Height OUTH[7:0] (real/4) */ 6734aa8879SHans Verkuil #define ZMOH_OUTH_SET(x) VAL_SET(x, 0xFF, 2, 0) 6834aa8879SHans Verkuil #define ZMHH 0x5C /* Zoom: Speed and H&W completion */ 6934aa8879SHans Verkuil #define ZMHH_ZSPEED_SET(x) VAL_SET(x, 0x0F, 0, 4) 7034aa8879SHans Verkuil #define ZMHH_OUTH_SET(x) VAL_SET(x, 0x1, (8+2), 2) 7134aa8879SHans Verkuil #define ZMHH_OUTW_SET(x) VAL_SET(x, 0x3, (8+2), 0) 7234aa8879SHans Verkuil #define BPADDR 0x7C /* SDE Indirect Register Access: Address */ 7334aa8879SHans Verkuil #define BPDATA 0x7D /* SDE Indirect Register Access: Data */ 7434aa8879SHans Verkuil #define CTRL2 0x86 /* DSP Module enable 2 */ 7534aa8879SHans Verkuil #define CTRL2_DCW_EN 0x20 7634aa8879SHans Verkuil #define CTRL2_SDE_EN 0x10 7734aa8879SHans Verkuil #define CTRL2_UV_ADJ_EN 0x08 7834aa8879SHans Verkuil #define CTRL2_UV_AVG_EN 0x04 7934aa8879SHans Verkuil #define CTRL2_CMX_EN 0x01 8034aa8879SHans Verkuil #define CTRL3 0x87 /* DSP Module enable 3 */ 8134aa8879SHans Verkuil #define CTRL3_BPC_EN 0x80 8234aa8879SHans Verkuil #define CTRL3_WPC_EN 0x40 8334aa8879SHans Verkuil #define SIZEL 0x8C /* Image Size Completion */ 8434aa8879SHans Verkuil #define SIZEL_HSIZE8_11_SET(x) VAL_SET(x, 0x1, 11, 6) 8534aa8879SHans Verkuil #define SIZEL_HSIZE8_SET(x) VAL_SET(x, 0x7, 0, 3) 8634aa8879SHans Verkuil #define SIZEL_VSIZE8_SET(x) VAL_SET(x, 0x7, 0, 0) 8734aa8879SHans Verkuil #define HSIZE8 0xC0 /* Image Horizontal Size HSIZE[10:3] */ 8834aa8879SHans Verkuil #define HSIZE8_SET(x) VAL_SET(x, 0xFF, 3, 0) 8934aa8879SHans Verkuil #define VSIZE8 0xC1 /* Image Vertical Size VSIZE[10:3] */ 9034aa8879SHans Verkuil #define VSIZE8_SET(x) VAL_SET(x, 0xFF, 3, 0) 9134aa8879SHans Verkuil #define CTRL0 0xC2 /* DSP Module enable 0 */ 9234aa8879SHans Verkuil #define CTRL0_AEC_EN 0x80 9334aa8879SHans Verkuil #define CTRL0_AEC_SEL 0x40 9434aa8879SHans Verkuil #define CTRL0_STAT_SEL 0x20 9534aa8879SHans Verkuil #define CTRL0_VFIRST 0x10 9634aa8879SHans Verkuil #define CTRL0_YUV422 0x08 9734aa8879SHans Verkuil #define CTRL0_YUV_EN 0x04 9834aa8879SHans Verkuil #define CTRL0_RGB_EN 0x02 9934aa8879SHans Verkuil #define CTRL0_RAW_EN 0x01 10034aa8879SHans Verkuil #define CTRL1 0xC3 /* DSP Module enable 1 */ 10134aa8879SHans Verkuil #define CTRL1_CIP 0x80 10234aa8879SHans Verkuil #define CTRL1_DMY 0x40 10334aa8879SHans Verkuil #define CTRL1_RAW_GMA 0x20 10434aa8879SHans Verkuil #define CTRL1_DG 0x10 10534aa8879SHans Verkuil #define CTRL1_AWB 0x08 10634aa8879SHans Verkuil #define CTRL1_AWB_GAIN 0x04 10734aa8879SHans Verkuil #define CTRL1_LENC 0x02 10834aa8879SHans Verkuil #define CTRL1_PRE 0x01 10906dd8f77SFrank Schaefer /* REG 0xC7 (unknown name): affects Auto White Balance (AWB) 11006dd8f77SFrank Schaefer * AWB_OFF 0x40 11106dd8f77SFrank Schaefer * AWB_SIMPLE 0x10 11206dd8f77SFrank Schaefer * AWB_ON 0x00 (Advanced AWB ?) */ 11334aa8879SHans Verkuil #define R_DVP_SP 0xD3 /* DVP output speed control */ 11434aa8879SHans Verkuil #define R_DVP_SP_AUTO_MODE 0x80 11534aa8879SHans Verkuil #define R_DVP_SP_DVP_MASK 0x3F /* DVP PCLK = sysclk (48)/[6:0] (YUV0); 11634aa8879SHans Verkuil * = sysclk (48)/(2*[6:0]) (RAW);*/ 11734aa8879SHans Verkuil #define IMAGE_MODE 0xDA /* Image Output Format Select */ 11834aa8879SHans Verkuil #define IMAGE_MODE_Y8_DVP_EN 0x40 11934aa8879SHans Verkuil #define IMAGE_MODE_JPEG_EN 0x10 12034aa8879SHans Verkuil #define IMAGE_MODE_YUV422 0x00 12134aa8879SHans Verkuil #define IMAGE_MODE_RAW10 0x04 /* (DVP) */ 12234aa8879SHans Verkuil #define IMAGE_MODE_RGB565 0x08 12334aa8879SHans Verkuil #define IMAGE_MODE_HREF_VSYNC 0x02 /* HREF timing select in DVP JPEG output 12434aa8879SHans Verkuil * mode (0 for HREF is same as sensor) */ 12534aa8879SHans Verkuil #define IMAGE_MODE_LBYTE_FIRST 0x01 /* Byte swap enable for DVP 12634aa8879SHans Verkuil * 1: Low byte first UYVY (C2[4] =0) 12734aa8879SHans Verkuil * VYUY (C2[4] =1) 12834aa8879SHans Verkuil * 0: High byte first YUYV (C2[4]=0) 12934aa8879SHans Verkuil * YVYU (C2[4] = 1) */ 13034aa8879SHans Verkuil #define RESET 0xE0 /* Reset */ 13134aa8879SHans Verkuil #define RESET_MICROC 0x40 13234aa8879SHans Verkuil #define RESET_SCCB 0x20 13334aa8879SHans Verkuil #define RESET_JPEG 0x10 13434aa8879SHans Verkuil #define RESET_DVP 0x04 13534aa8879SHans Verkuil #define RESET_IPU 0x02 13634aa8879SHans Verkuil #define RESET_CIF 0x01 13734aa8879SHans Verkuil #define REGED 0xED /* Register ED */ 13834aa8879SHans Verkuil #define REGED_CLK_OUT_DIS 0x10 13934aa8879SHans Verkuil #define MS_SP 0xF0 /* SCCB Master Speed */ 14034aa8879SHans Verkuil #define SS_ID 0xF7 /* SCCB Slave ID */ 14134aa8879SHans Verkuil #define SS_CTRL 0xF8 /* SCCB Slave Control */ 14234aa8879SHans Verkuil #define SS_CTRL_ADD_AUTO_INC 0x20 14334aa8879SHans Verkuil #define SS_CTRL_EN 0x08 14434aa8879SHans Verkuil #define SS_CTRL_DELAY_CLK 0x04 14534aa8879SHans Verkuil #define SS_CTRL_ACC_EN 0x02 14634aa8879SHans Verkuil #define SS_CTRL_SEN_PASS_THR 0x01 14734aa8879SHans Verkuil #define MC_BIST 0xF9 /* Microcontroller misc register */ 14834aa8879SHans Verkuil #define MC_BIST_RESET 0x80 /* Microcontroller Reset */ 14934aa8879SHans Verkuil #define MC_BIST_BOOT_ROM_SEL 0x40 15034aa8879SHans Verkuil #define MC_BIST_12KB_SEL 0x20 15134aa8879SHans Verkuil #define MC_BIST_12KB_MASK 0x30 15234aa8879SHans Verkuil #define MC_BIST_512KB_SEL 0x08 15334aa8879SHans Verkuil #define MC_BIST_512KB_MASK 0x0C 15434aa8879SHans Verkuil #define MC_BIST_BUSY_BIT_R 0x02 15534aa8879SHans Verkuil #define MC_BIST_MC_RES_ONE_SH_W 0x02 15634aa8879SHans Verkuil #define MC_BIST_LAUNCH 0x01 15734aa8879SHans Verkuil #define BANK_SEL 0xFF /* Register Bank Select */ 15834aa8879SHans Verkuil #define BANK_SEL_DSP 0x00 15934aa8879SHans Verkuil #define BANK_SEL_SENS 0x01 16034aa8879SHans Verkuil 16134aa8879SHans Verkuil /* 16234aa8879SHans Verkuil * Sensor registers 16334aa8879SHans Verkuil * register offset for BANK_SEL == BANK_SEL_SENS 16434aa8879SHans Verkuil */ 16534aa8879SHans Verkuil #define GAIN 0x00 /* AGC - Gain control gain setting */ 16634aa8879SHans Verkuil #define COM1 0x03 /* Common control 1 */ 16734aa8879SHans Verkuil #define COM1_1_DUMMY_FR 0x40 16834aa8879SHans Verkuil #define COM1_3_DUMMY_FR 0x80 16934aa8879SHans Verkuil #define COM1_7_DUMMY_FR 0xC0 17034aa8879SHans Verkuil #define COM1_VWIN_LSB_UXGA 0x0F 17134aa8879SHans Verkuil #define COM1_VWIN_LSB_SVGA 0x0A 17234aa8879SHans Verkuil #define COM1_VWIN_LSB_CIF 0x06 17334aa8879SHans Verkuil #define REG04 0x04 /* Register 04 */ 17434aa8879SHans Verkuil #define REG04_DEF 0x20 /* Always set */ 17534aa8879SHans Verkuil #define REG04_HFLIP_IMG 0x80 /* Horizontal mirror image ON/OFF */ 17634aa8879SHans Verkuil #define REG04_VFLIP_IMG 0x40 /* Vertical flip image ON/OFF */ 17734aa8879SHans Verkuil #define REG04_VREF_EN 0x10 17834aa8879SHans Verkuil #define REG04_HREF_EN 0x08 17934aa8879SHans Verkuil #define REG04_AEC_SET(x) VAL_SET(x, 0x3, 0, 0) 18034aa8879SHans Verkuil #define REG08 0x08 /* Frame Exposure One-pin Control Pre-charge Row Num */ 18134aa8879SHans Verkuil #define COM2 0x09 /* Common control 2 */ 18234aa8879SHans Verkuil #define COM2_SOFT_SLEEP_MODE 0x10 /* Soft sleep mode */ 18334aa8879SHans Verkuil /* Output drive capability */ 18434aa8879SHans Verkuil #define COM2_OCAP_Nx_SET(N) (((N) - 1) & 0x03) /* N = [1x .. 4x] */ 18534aa8879SHans Verkuil #define PID 0x0A /* Product ID Number MSB */ 18634aa8879SHans Verkuil #define VER 0x0B /* Product ID Number LSB */ 18734aa8879SHans Verkuil #define COM3 0x0C /* Common control 3 */ 18834aa8879SHans Verkuil #define COM3_BAND_50H 0x04 /* 0 For Banding at 60H */ 18934aa8879SHans Verkuil #define COM3_BAND_AUTO 0x02 /* Auto Banding */ 19034aa8879SHans Verkuil #define COM3_SING_FR_SNAPSH 0x01 /* 0 For enable live video output after the 19134aa8879SHans Verkuil * snapshot sequence*/ 19234aa8879SHans Verkuil #define AEC 0x10 /* AEC[9:2] Exposure Value */ 19334aa8879SHans Verkuil #define CLKRC 0x11 /* Internal clock */ 19434aa8879SHans Verkuil #define CLKRC_EN 0x80 19534aa8879SHans Verkuil #define CLKRC_DIV_SET(x) (((x) - 1) & 0x1F) /* CLK = XVCLK/(x) */ 19634aa8879SHans Verkuil #define COM7 0x12 /* Common control 7 */ 19734aa8879SHans Verkuil #define COM7_SRST 0x80 /* Initiates system reset. All registers are 19834aa8879SHans Verkuil * set to factory default values after which 19934aa8879SHans Verkuil * the chip resumes normal operation */ 20034aa8879SHans Verkuil #define COM7_RES_UXGA 0x00 /* Resolution selectors for UXGA */ 20134aa8879SHans Verkuil #define COM7_RES_SVGA 0x40 /* SVGA */ 20234aa8879SHans Verkuil #define COM7_RES_CIF 0x20 /* CIF */ 20334aa8879SHans Verkuil #define COM7_ZOOM_EN 0x04 /* Enable Zoom mode */ 20434aa8879SHans Verkuil #define COM7_COLOR_BAR_TEST 0x02 /* Enable Color Bar Test Pattern */ 20534aa8879SHans Verkuil #define COM8 0x13 /* Common control 8 */ 206534dca98SFrank Schaefer #define COM8_DEF 0xC0 20734aa8879SHans Verkuil #define COM8_BNDF_EN 0x20 /* Banding filter ON/OFF */ 20834aa8879SHans Verkuil #define COM8_AGC_EN 0x04 /* AGC Auto/Manual control selection */ 20934aa8879SHans Verkuil #define COM8_AEC_EN 0x01 /* Auto/Manual Exposure control */ 21034aa8879SHans Verkuil #define COM9 0x14 /* Common control 9 21134aa8879SHans Verkuil * Automatic gain ceiling - maximum AGC value [7:5]*/ 21234aa8879SHans Verkuil #define COM9_AGC_GAIN_2x 0x00 /* 000 : 2x */ 21334aa8879SHans Verkuil #define COM9_AGC_GAIN_4x 0x20 /* 001 : 4x */ 21434aa8879SHans Verkuil #define COM9_AGC_GAIN_8x 0x40 /* 010 : 8x */ 21534aa8879SHans Verkuil #define COM9_AGC_GAIN_16x 0x60 /* 011 : 16x */ 21634aa8879SHans Verkuil #define COM9_AGC_GAIN_32x 0x80 /* 100 : 32x */ 21734aa8879SHans Verkuil #define COM9_AGC_GAIN_64x 0xA0 /* 101 : 64x */ 21834aa8879SHans Verkuil #define COM9_AGC_GAIN_128x 0xC0 /* 110 : 128x */ 21934aa8879SHans Verkuil #define COM10 0x15 /* Common control 10 */ 22034aa8879SHans Verkuil #define COM10_PCLK_HREF 0x20 /* PCLK output qualified by HREF */ 22134aa8879SHans Verkuil #define COM10_PCLK_RISE 0x10 /* Data is updated at the rising edge of 22234aa8879SHans Verkuil * PCLK (user can latch data at the next 22334aa8879SHans Verkuil * falling edge of PCLK). 22434aa8879SHans Verkuil * 0 otherwise. */ 22534aa8879SHans Verkuil #define COM10_HREF_INV 0x08 /* Invert HREF polarity: 22634aa8879SHans Verkuil * HREF negative for valid data*/ 22734aa8879SHans Verkuil #define COM10_VSINC_INV 0x02 /* Invert VSYNC polarity */ 22834aa8879SHans Verkuil #define HSTART 0x17 /* Horizontal Window start MSB 8 bit */ 22934aa8879SHans Verkuil #define HEND 0x18 /* Horizontal Window end MSB 8 bit */ 23034aa8879SHans Verkuil #define VSTART 0x19 /* Vertical Window start MSB 8 bit */ 23134aa8879SHans Verkuil #define VEND 0x1A /* Vertical Window end MSB 8 bit */ 23234aa8879SHans Verkuil #define MIDH 0x1C /* Manufacturer ID byte - high */ 23334aa8879SHans Verkuil #define MIDL 0x1D /* Manufacturer ID byte - low */ 23434aa8879SHans Verkuil #define AEW 0x24 /* AGC/AEC - Stable operating region (upper limit) */ 23534aa8879SHans Verkuil #define AEB 0x25 /* AGC/AEC - Stable operating region (lower limit) */ 23634aa8879SHans Verkuil #define VV 0x26 /* AGC/AEC Fast mode operating region */ 23734aa8879SHans Verkuil #define VV_HIGH_TH_SET(x) VAL_SET(x, 0xF, 0, 4) 23834aa8879SHans Verkuil #define VV_LOW_TH_SET(x) VAL_SET(x, 0xF, 0, 0) 23934aa8879SHans Verkuil #define REG2A 0x2A /* Dummy pixel insert MSB */ 24034aa8879SHans Verkuil #define FRARL 0x2B /* Dummy pixel insert LSB */ 24134aa8879SHans Verkuil #define ADDVFL 0x2D /* LSB of insert dummy lines in Vertical direction */ 24234aa8879SHans Verkuil #define ADDVFH 0x2E /* MSB of insert dummy lines in Vertical direction */ 24334aa8879SHans Verkuil #define YAVG 0x2F /* Y/G Channel Average value */ 24434aa8879SHans Verkuil #define REG32 0x32 /* Common Control 32 */ 24534aa8879SHans Verkuil #define REG32_PCLK_DIV_2 0x80 /* PCLK freq divided by 2 */ 24634aa8879SHans Verkuil #define REG32_PCLK_DIV_4 0xC0 /* PCLK freq divided by 4 */ 24734aa8879SHans Verkuil #define ARCOM2 0x34 /* Zoom: Horizontal start point */ 24834aa8879SHans Verkuil #define REG45 0x45 /* Register 45 */ 24934aa8879SHans Verkuil #define FLL 0x46 /* Frame Length Adjustment LSBs */ 25034aa8879SHans Verkuil #define FLH 0x47 /* Frame Length Adjustment MSBs */ 25134aa8879SHans Verkuil #define COM19 0x48 /* Zoom: Vertical start point */ 25234aa8879SHans Verkuil #define ZOOMS 0x49 /* Zoom: Vertical start point */ 25334aa8879SHans Verkuil #define COM22 0x4B /* Flash light control */ 25434aa8879SHans Verkuil #define COM25 0x4E /* For Banding operations */ 255d81638eaSFrank Schaefer #define COM25_50HZ_BANDING_AEC_MSBS_MASK 0xC0 /* 50Hz Bd. AEC 2 MSBs */ 256d81638eaSFrank Schaefer #define COM25_60HZ_BANDING_AEC_MSBS_MASK 0x30 /* 60Hz Bd. AEC 2 MSBs */ 257d81638eaSFrank Schaefer #define COM25_50HZ_BANDING_AEC_MSBS_SET(x) VAL_SET(x, 0x3, 8, 6) 258d81638eaSFrank Schaefer #define COM25_60HZ_BANDING_AEC_MSBS_SET(x) VAL_SET(x, 0x3, 8, 4) 25934aa8879SHans Verkuil #define BD50 0x4F /* 50Hz Banding AEC 8 LSBs */ 260d81638eaSFrank Schaefer #define BD50_50HZ_BANDING_AEC_LSBS_SET(x) VAL_SET(x, 0xFF, 0, 0) 26134aa8879SHans Verkuil #define BD60 0x50 /* 60Hz Banding AEC 8 LSBs */ 262d81638eaSFrank Schaefer #define BD60_60HZ_BANDING_AEC_LSBS_SET(x) VAL_SET(x, 0xFF, 0, 0) 263d81638eaSFrank Schaefer #define REG5A 0x5A /* 50/60Hz Banding Maximum AEC Step */ 264d81638eaSFrank Schaefer #define BD50_MAX_AEC_STEP_MASK 0xF0 /* 50Hz Banding Max. AEC Step */ 265d81638eaSFrank Schaefer #define BD60_MAX_AEC_STEP_MASK 0x0F /* 60Hz Banding Max. AEC Step */ 266d81638eaSFrank Schaefer #define BD50_MAX_AEC_STEP_SET(x) VAL_SET((x - 1), 0x0F, 0, 4) 267d81638eaSFrank Schaefer #define BD60_MAX_AEC_STEP_SET(x) VAL_SET((x - 1), 0x0F, 0, 0) 26834aa8879SHans Verkuil #define REG5D 0x5D /* AVGsel[7:0], 16-zone average weight option */ 26934aa8879SHans Verkuil #define REG5E 0x5E /* AVGsel[15:8], 16-zone average weight option */ 27034aa8879SHans Verkuil #define REG5F 0x5F /* AVGsel[23:16], 16-zone average weight option */ 27134aa8879SHans Verkuil #define REG60 0x60 /* AVGsel[31:24], 16-zone average weight option */ 27234aa8879SHans Verkuil #define HISTO_LOW 0x61 /* Histogram Algorithm Low Level */ 27334aa8879SHans Verkuil #define HISTO_HIGH 0x62 /* Histogram Algorithm High Level */ 27434aa8879SHans Verkuil 27534aa8879SHans Verkuil /* 27634aa8879SHans Verkuil * ID 27734aa8879SHans Verkuil */ 27834aa8879SHans Verkuil #define MANUFACTURER_ID 0x7FA2 27934aa8879SHans Verkuil #define PID_OV2640 0x2642 28034aa8879SHans Verkuil #define VERSION(pid, ver) ((pid << 8) | (ver & 0xFF)) 28134aa8879SHans Verkuil 28234aa8879SHans Verkuil /* 28334aa8879SHans Verkuil * Struct 28434aa8879SHans Verkuil */ 28534aa8879SHans Verkuil struct regval_list { 28634aa8879SHans Verkuil u8 reg_num; 28734aa8879SHans Verkuil u8 value; 28834aa8879SHans Verkuil }; 28934aa8879SHans Verkuil 29034aa8879SHans Verkuil struct ov2640_win_size { 29134aa8879SHans Verkuil char *name; 29234aa8879SHans Verkuil u32 width; 29334aa8879SHans Verkuil u32 height; 29434aa8879SHans Verkuil const struct regval_list *regs; 29534aa8879SHans Verkuil }; 29634aa8879SHans Verkuil 29734aa8879SHans Verkuil 29834aa8879SHans Verkuil struct ov2640_priv { 29934aa8879SHans Verkuil struct v4l2_subdev subdev; 300ff0e9c1dSHans Verkuil #if defined(CONFIG_MEDIA_CONTROLLER) 301ff0e9c1dSHans Verkuil struct media_pad pad; 302ff0e9c1dSHans Verkuil #endif 30334aa8879SHans Verkuil struct v4l2_ctrl_handler hdl; 30434aa8879SHans Verkuil u32 cfmt_code; 30546796cfcSHans Verkuil struct clk *clk; 30634aa8879SHans Verkuil const struct ov2640_win_size *win; 30734aa8879SHans Verkuil 30834aa8879SHans Verkuil struct gpio_desc *resetb_gpio; 30934aa8879SHans Verkuil struct gpio_desc *pwdn_gpio; 3102aae3939SAkinobu Mita 3112aae3939SAkinobu Mita struct mutex lock; /* lock to protect streaming */ 3122aae3939SAkinobu Mita bool streaming; 31334aa8879SHans Verkuil }; 31434aa8879SHans Verkuil 31534aa8879SHans Verkuil /* 31634aa8879SHans Verkuil * Registers settings 31734aa8879SHans Verkuil */ 31834aa8879SHans Verkuil 31934aa8879SHans Verkuil #define ENDMARKER { 0xff, 0xff } 32034aa8879SHans Verkuil 32134aa8879SHans Verkuil static const struct regval_list ov2640_init_regs[] = { 32234aa8879SHans Verkuil { BANK_SEL, BANK_SEL_DSP }, 32334aa8879SHans Verkuil { 0x2c, 0xff }, 32434aa8879SHans Verkuil { 0x2e, 0xdf }, 32534aa8879SHans Verkuil { BANK_SEL, BANK_SEL_SENS }, 32634aa8879SHans Verkuil { 0x3c, 0x32 }, 32734aa8879SHans Verkuil { CLKRC, CLKRC_DIV_SET(1) }, 32834aa8879SHans Verkuil { COM2, COM2_OCAP_Nx_SET(3) }, 32934aa8879SHans Verkuil { REG04, REG04_DEF | REG04_HREF_EN }, 33034aa8879SHans Verkuil { COM8, COM8_DEF | COM8_BNDF_EN | COM8_AGC_EN | COM8_AEC_EN }, 33134aa8879SHans Verkuil { COM9, COM9_AGC_GAIN_8x | 0x08}, 33234aa8879SHans Verkuil { 0x2c, 0x0c }, 33334aa8879SHans Verkuil { 0x33, 0x78 }, 33434aa8879SHans Verkuil { 0x3a, 0x33 }, 33534aa8879SHans Verkuil { 0x3b, 0xfb }, 33634aa8879SHans Verkuil { 0x3e, 0x00 }, 33734aa8879SHans Verkuil { 0x43, 0x11 }, 33834aa8879SHans Verkuil { 0x16, 0x10 }, 33934aa8879SHans Verkuil { 0x39, 0x02 }, 34034aa8879SHans Verkuil { 0x35, 0x88 }, 34134aa8879SHans Verkuil { 0x22, 0x0a }, 34234aa8879SHans Verkuil { 0x37, 0x40 }, 34334aa8879SHans Verkuil { 0x23, 0x00 }, 34434aa8879SHans Verkuil { ARCOM2, 0xa0 }, 34534aa8879SHans Verkuil { 0x06, 0x02 }, 34634aa8879SHans Verkuil { 0x06, 0x88 }, 34734aa8879SHans Verkuil { 0x07, 0xc0 }, 34834aa8879SHans Verkuil { 0x0d, 0xb7 }, 34934aa8879SHans Verkuil { 0x0e, 0x01 }, 35034aa8879SHans Verkuil { 0x4c, 0x00 }, 35134aa8879SHans Verkuil { 0x4a, 0x81 }, 35234aa8879SHans Verkuil { 0x21, 0x99 }, 35334aa8879SHans Verkuil { AEW, 0x40 }, 35434aa8879SHans Verkuil { AEB, 0x38 }, 35534aa8879SHans Verkuil { VV, VV_HIGH_TH_SET(0x08) | VV_LOW_TH_SET(0x02) }, 35634aa8879SHans Verkuil { 0x5c, 0x00 }, 35734aa8879SHans Verkuil { 0x63, 0x00 }, 35834aa8879SHans Verkuil { FLL, 0x22 }, 35934aa8879SHans Verkuil { COM3, 0x38 | COM3_BAND_AUTO }, 36034aa8879SHans Verkuil { REG5D, 0x55 }, 36134aa8879SHans Verkuil { REG5E, 0x7d }, 36234aa8879SHans Verkuil { REG5F, 0x7d }, 36334aa8879SHans Verkuil { REG60, 0x55 }, 36434aa8879SHans Verkuil { HISTO_LOW, 0x70 }, 36534aa8879SHans Verkuil { HISTO_HIGH, 0x80 }, 36634aa8879SHans Verkuil { 0x7c, 0x05 }, 36734aa8879SHans Verkuil { 0x20, 0x80 }, 36834aa8879SHans Verkuil { 0x28, 0x30 }, 36934aa8879SHans Verkuil { 0x6c, 0x00 }, 37034aa8879SHans Verkuil { 0x6d, 0x80 }, 37134aa8879SHans Verkuil { 0x6e, 0x00 }, 37234aa8879SHans Verkuil { 0x70, 0x02 }, 37334aa8879SHans Verkuil { 0x71, 0x94 }, 37434aa8879SHans Verkuil { 0x73, 0xc1 }, 37534aa8879SHans Verkuil { 0x3d, 0x34 }, 37634aa8879SHans Verkuil { COM7, COM7_RES_UXGA | COM7_ZOOM_EN }, 377d81638eaSFrank Schaefer { REG5A, BD50_MAX_AEC_STEP_SET(6) 378d81638eaSFrank Schaefer | BD60_MAX_AEC_STEP_SET(8) }, /* 0x57 */ 379d81638eaSFrank Schaefer { COM25, COM25_50HZ_BANDING_AEC_MSBS_SET(0x0bb) 380d81638eaSFrank Schaefer | COM25_60HZ_BANDING_AEC_MSBS_SET(0x09c) }, /* 0x00 */ 381d81638eaSFrank Schaefer { BD50, BD50_50HZ_BANDING_AEC_LSBS_SET(0x0bb) }, /* 0xbb */ 382d81638eaSFrank Schaefer { BD60, BD60_60HZ_BANDING_AEC_LSBS_SET(0x09c) }, /* 0x9c */ 38334aa8879SHans Verkuil { BANK_SEL, BANK_SEL_DSP }, 38434aa8879SHans Verkuil { 0xe5, 0x7f }, 38534aa8879SHans Verkuil { MC_BIST, MC_BIST_RESET | MC_BIST_BOOT_ROM_SEL }, 38634aa8879SHans Verkuil { 0x41, 0x24 }, 38734aa8879SHans Verkuil { RESET, RESET_JPEG | RESET_DVP }, 38834aa8879SHans Verkuil { 0x76, 0xff }, 38934aa8879SHans Verkuil { 0x33, 0xa0 }, 39034aa8879SHans Verkuil { 0x42, 0x20 }, 39134aa8879SHans Verkuil { 0x43, 0x18 }, 39234aa8879SHans Verkuil { 0x4c, 0x00 }, 39334aa8879SHans Verkuil { CTRL3, CTRL3_BPC_EN | CTRL3_WPC_EN | 0x10 }, 39434aa8879SHans Verkuil { 0x88, 0x3f }, 39534aa8879SHans Verkuil { 0xd7, 0x03 }, 39634aa8879SHans Verkuil { 0xd9, 0x10 }, 39734aa8879SHans Verkuil { R_DVP_SP, R_DVP_SP_AUTO_MODE | 0x2 }, 39834aa8879SHans Verkuil { 0xc8, 0x08 }, 39934aa8879SHans Verkuil { 0xc9, 0x80 }, 40034aa8879SHans Verkuil { BPADDR, 0x00 }, 40134aa8879SHans Verkuil { BPDATA, 0x00 }, 40234aa8879SHans Verkuil { BPADDR, 0x03 }, 40334aa8879SHans Verkuil { BPDATA, 0x48 }, 40434aa8879SHans Verkuil { BPDATA, 0x48 }, 40534aa8879SHans Verkuil { BPADDR, 0x08 }, 40634aa8879SHans Verkuil { BPDATA, 0x20 }, 40734aa8879SHans Verkuil { BPDATA, 0x10 }, 40834aa8879SHans Verkuil { BPDATA, 0x0e }, 40934aa8879SHans Verkuil { 0x90, 0x00 }, 41034aa8879SHans Verkuil { 0x91, 0x0e }, 41134aa8879SHans Verkuil { 0x91, 0x1a }, 41234aa8879SHans Verkuil { 0x91, 0x31 }, 41334aa8879SHans Verkuil { 0x91, 0x5a }, 41434aa8879SHans Verkuil { 0x91, 0x69 }, 41534aa8879SHans Verkuil { 0x91, 0x75 }, 41634aa8879SHans Verkuil { 0x91, 0x7e }, 41734aa8879SHans Verkuil { 0x91, 0x88 }, 41834aa8879SHans Verkuil { 0x91, 0x8f }, 41934aa8879SHans Verkuil { 0x91, 0x96 }, 42034aa8879SHans Verkuil { 0x91, 0xa3 }, 42134aa8879SHans Verkuil { 0x91, 0xaf }, 42234aa8879SHans Verkuil { 0x91, 0xc4 }, 42334aa8879SHans Verkuil { 0x91, 0xd7 }, 42434aa8879SHans Verkuil { 0x91, 0xe8 }, 42534aa8879SHans Verkuil { 0x91, 0x20 }, 42634aa8879SHans Verkuil { 0x92, 0x00 }, 42734aa8879SHans Verkuil { 0x93, 0x06 }, 42834aa8879SHans Verkuil { 0x93, 0xe3 }, 42934aa8879SHans Verkuil { 0x93, 0x03 }, 43034aa8879SHans Verkuil { 0x93, 0x03 }, 43134aa8879SHans Verkuil { 0x93, 0x00 }, 43234aa8879SHans Verkuil { 0x93, 0x02 }, 43334aa8879SHans Verkuil { 0x93, 0x00 }, 43434aa8879SHans Verkuil { 0x93, 0x00 }, 43534aa8879SHans Verkuil { 0x93, 0x00 }, 43634aa8879SHans Verkuil { 0x93, 0x00 }, 43734aa8879SHans Verkuil { 0x93, 0x00 }, 43834aa8879SHans Verkuil { 0x93, 0x00 }, 43934aa8879SHans Verkuil { 0x93, 0x00 }, 44034aa8879SHans Verkuil { 0x96, 0x00 }, 44134aa8879SHans Verkuil { 0x97, 0x08 }, 44234aa8879SHans Verkuil { 0x97, 0x19 }, 44334aa8879SHans Verkuil { 0x97, 0x02 }, 44434aa8879SHans Verkuil { 0x97, 0x0c }, 44534aa8879SHans Verkuil { 0x97, 0x24 }, 44634aa8879SHans Verkuil { 0x97, 0x30 }, 44734aa8879SHans Verkuil { 0x97, 0x28 }, 44834aa8879SHans Verkuil { 0x97, 0x26 }, 44934aa8879SHans Verkuil { 0x97, 0x02 }, 45034aa8879SHans Verkuil { 0x97, 0x98 }, 45134aa8879SHans Verkuil { 0x97, 0x80 }, 45234aa8879SHans Verkuil { 0x97, 0x00 }, 45334aa8879SHans Verkuil { 0x97, 0x00 }, 45434aa8879SHans Verkuil { 0xa4, 0x00 }, 45534aa8879SHans Verkuil { 0xa8, 0x00 }, 45634aa8879SHans Verkuil { 0xc5, 0x11 }, 45734aa8879SHans Verkuil { 0xc6, 0x51 }, 45834aa8879SHans Verkuil { 0xbf, 0x80 }, 45906dd8f77SFrank Schaefer { 0xc7, 0x10 }, /* simple AWB */ 46034aa8879SHans Verkuil { 0xb6, 0x66 }, 46134aa8879SHans Verkuil { 0xb8, 0xA5 }, 46234aa8879SHans Verkuil { 0xb7, 0x64 }, 46334aa8879SHans Verkuil { 0xb9, 0x7C }, 46434aa8879SHans Verkuil { 0xb3, 0xaf }, 46534aa8879SHans Verkuil { 0xb4, 0x97 }, 46634aa8879SHans Verkuil { 0xb5, 0xFF }, 46734aa8879SHans Verkuil { 0xb0, 0xC5 }, 46834aa8879SHans Verkuil { 0xb1, 0x94 }, 46934aa8879SHans Verkuil { 0xb2, 0x0f }, 47034aa8879SHans Verkuil { 0xc4, 0x5c }, 47134aa8879SHans Verkuil { 0xa6, 0x00 }, 47234aa8879SHans Verkuil { 0xa7, 0x20 }, 47334aa8879SHans Verkuil { 0xa7, 0xd8 }, 47434aa8879SHans Verkuil { 0xa7, 0x1b }, 47534aa8879SHans Verkuil { 0xa7, 0x31 }, 47634aa8879SHans Verkuil { 0xa7, 0x00 }, 47734aa8879SHans Verkuil { 0xa7, 0x18 }, 47834aa8879SHans Verkuil { 0xa7, 0x20 }, 47934aa8879SHans Verkuil { 0xa7, 0xd8 }, 48034aa8879SHans Verkuil { 0xa7, 0x19 }, 48134aa8879SHans Verkuil { 0xa7, 0x31 }, 48234aa8879SHans Verkuil { 0xa7, 0x00 }, 48334aa8879SHans Verkuil { 0xa7, 0x18 }, 48434aa8879SHans Verkuil { 0xa7, 0x20 }, 48534aa8879SHans Verkuil { 0xa7, 0xd8 }, 48634aa8879SHans Verkuil { 0xa7, 0x19 }, 48734aa8879SHans Verkuil { 0xa7, 0x31 }, 48834aa8879SHans Verkuil { 0xa7, 0x00 }, 48934aa8879SHans Verkuil { 0xa7, 0x18 }, 49034aa8879SHans Verkuil { 0x7f, 0x00 }, 49134aa8879SHans Verkuil { 0xe5, 0x1f }, 49234aa8879SHans Verkuil { 0xe1, 0x77 }, 49334aa8879SHans Verkuil { 0xdd, 0x7f }, 49434aa8879SHans Verkuil { CTRL0, CTRL0_YUV422 | CTRL0_YUV_EN | CTRL0_RGB_EN }, 49534aa8879SHans Verkuil ENDMARKER, 49634aa8879SHans Verkuil }; 49734aa8879SHans Verkuil 49834aa8879SHans Verkuil /* 49934aa8879SHans Verkuil * Register settings for window size 50034aa8879SHans Verkuil * The preamble, setup the internal DSP to input an UXGA (1600x1200) image. 50134aa8879SHans Verkuil * Then the different zooming configurations will setup the output image size. 50234aa8879SHans Verkuil */ 50334aa8879SHans Verkuil static const struct regval_list ov2640_size_change_preamble_regs[] = { 50434aa8879SHans Verkuil { BANK_SEL, BANK_SEL_DSP }, 50534aa8879SHans Verkuil { RESET, RESET_DVP }, 5062f7711b2SFrank Schaefer { SIZEL, SIZEL_HSIZE8_11_SET(UXGA_WIDTH) | 5072f7711b2SFrank Schaefer SIZEL_HSIZE8_SET(UXGA_WIDTH) | 5082f7711b2SFrank Schaefer SIZEL_VSIZE8_SET(UXGA_HEIGHT) }, 50934aa8879SHans Verkuil { HSIZE8, HSIZE8_SET(UXGA_WIDTH) }, 51034aa8879SHans Verkuil { VSIZE8, VSIZE8_SET(UXGA_HEIGHT) }, 51134aa8879SHans Verkuil { CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN | 51234aa8879SHans Verkuil CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN }, 51334aa8879SHans Verkuil { HSIZE, HSIZE_SET(UXGA_WIDTH) }, 51434aa8879SHans Verkuil { VSIZE, VSIZE_SET(UXGA_HEIGHT) }, 51534aa8879SHans Verkuil { XOFFL, XOFFL_SET(0) }, 51634aa8879SHans Verkuil { YOFFL, YOFFL_SET(0) }, 51734aa8879SHans Verkuil { VHYX, VHYX_HSIZE_SET(UXGA_WIDTH) | VHYX_VSIZE_SET(UXGA_HEIGHT) | 51834aa8879SHans Verkuil VHYX_XOFF_SET(0) | VHYX_YOFF_SET(0)}, 51934aa8879SHans Verkuil { TEST, TEST_HSIZE_SET(UXGA_WIDTH) }, 52034aa8879SHans Verkuil ENDMARKER, 52134aa8879SHans Verkuil }; 52234aa8879SHans Verkuil 52334aa8879SHans Verkuil #define PER_SIZE_REG_SEQ(x, y, v_div, h_div, pclk_div) \ 52434aa8879SHans Verkuil { CTRLI, CTRLI_LP_DP | CTRLI_V_DIV_SET(v_div) | \ 52534aa8879SHans Verkuil CTRLI_H_DIV_SET(h_div)}, \ 52634aa8879SHans Verkuil { ZMOW, ZMOW_OUTW_SET(x) }, \ 52734aa8879SHans Verkuil { ZMOH, ZMOH_OUTH_SET(y) }, \ 52834aa8879SHans Verkuil { ZMHH, ZMHH_OUTW_SET(x) | ZMHH_OUTH_SET(y) }, \ 52934aa8879SHans Verkuil { R_DVP_SP, pclk_div }, \ 53034aa8879SHans Verkuil { RESET, 0x00} 53134aa8879SHans Verkuil 53234aa8879SHans Verkuil static const struct regval_list ov2640_qcif_regs[] = { 53334aa8879SHans Verkuil PER_SIZE_REG_SEQ(QCIF_WIDTH, QCIF_HEIGHT, 3, 3, 4), 53434aa8879SHans Verkuil ENDMARKER, 53534aa8879SHans Verkuil }; 53634aa8879SHans Verkuil 53734aa8879SHans Verkuil static const struct regval_list ov2640_qvga_regs[] = { 53834aa8879SHans Verkuil PER_SIZE_REG_SEQ(QVGA_WIDTH, QVGA_HEIGHT, 2, 2, 4), 53934aa8879SHans Verkuil ENDMARKER, 54034aa8879SHans Verkuil }; 54134aa8879SHans Verkuil 54234aa8879SHans Verkuil static const struct regval_list ov2640_cif_regs[] = { 54334aa8879SHans Verkuil PER_SIZE_REG_SEQ(CIF_WIDTH, CIF_HEIGHT, 2, 2, 8), 54434aa8879SHans Verkuil ENDMARKER, 54534aa8879SHans Verkuil }; 54634aa8879SHans Verkuil 54734aa8879SHans Verkuil static const struct regval_list ov2640_vga_regs[] = { 54834aa8879SHans Verkuil PER_SIZE_REG_SEQ(VGA_WIDTH, VGA_HEIGHT, 0, 0, 2), 54934aa8879SHans Verkuil ENDMARKER, 55034aa8879SHans Verkuil }; 55134aa8879SHans Verkuil 55234aa8879SHans Verkuil static const struct regval_list ov2640_svga_regs[] = { 55334aa8879SHans Verkuil PER_SIZE_REG_SEQ(SVGA_WIDTH, SVGA_HEIGHT, 1, 1, 2), 55434aa8879SHans Verkuil ENDMARKER, 55534aa8879SHans Verkuil }; 55634aa8879SHans Verkuil 55734aa8879SHans Verkuil static const struct regval_list ov2640_xga_regs[] = { 55834aa8879SHans Verkuil PER_SIZE_REG_SEQ(XGA_WIDTH, XGA_HEIGHT, 0, 0, 2), 55934aa8879SHans Verkuil { CTRLI, 0x00}, 56034aa8879SHans Verkuil ENDMARKER, 56134aa8879SHans Verkuil }; 56234aa8879SHans Verkuil 56334aa8879SHans Verkuil static const struct regval_list ov2640_sxga_regs[] = { 56434aa8879SHans Verkuil PER_SIZE_REG_SEQ(SXGA_WIDTH, SXGA_HEIGHT, 0, 0, 2), 56534aa8879SHans Verkuil { CTRLI, 0x00}, 56634aa8879SHans Verkuil { R_DVP_SP, 2 | R_DVP_SP_AUTO_MODE }, 56734aa8879SHans Verkuil ENDMARKER, 56834aa8879SHans Verkuil }; 56934aa8879SHans Verkuil 57034aa8879SHans Verkuil static const struct regval_list ov2640_uxga_regs[] = { 57134aa8879SHans Verkuil PER_SIZE_REG_SEQ(UXGA_WIDTH, UXGA_HEIGHT, 0, 0, 0), 57234aa8879SHans Verkuil { CTRLI, 0x00}, 57334aa8879SHans Verkuil { R_DVP_SP, 0 | R_DVP_SP_AUTO_MODE }, 57434aa8879SHans Verkuil ENDMARKER, 57534aa8879SHans Verkuil }; 57634aa8879SHans Verkuil 57734aa8879SHans Verkuil #define OV2640_SIZE(n, w, h, r) \ 57834aa8879SHans Verkuil {.name = n, .width = w , .height = h, .regs = r } 57934aa8879SHans Verkuil 58034aa8879SHans Verkuil static const struct ov2640_win_size ov2640_supported_win_sizes[] = { 58134aa8879SHans Verkuil OV2640_SIZE("QCIF", QCIF_WIDTH, QCIF_HEIGHT, ov2640_qcif_regs), 58234aa8879SHans Verkuil OV2640_SIZE("QVGA", QVGA_WIDTH, QVGA_HEIGHT, ov2640_qvga_regs), 58334aa8879SHans Verkuil OV2640_SIZE("CIF", CIF_WIDTH, CIF_HEIGHT, ov2640_cif_regs), 58434aa8879SHans Verkuil OV2640_SIZE("VGA", VGA_WIDTH, VGA_HEIGHT, ov2640_vga_regs), 58534aa8879SHans Verkuil OV2640_SIZE("SVGA", SVGA_WIDTH, SVGA_HEIGHT, ov2640_svga_regs), 58634aa8879SHans Verkuil OV2640_SIZE("XGA", XGA_WIDTH, XGA_HEIGHT, ov2640_xga_regs), 58734aa8879SHans Verkuil OV2640_SIZE("SXGA", SXGA_WIDTH, SXGA_HEIGHT, ov2640_sxga_regs), 58834aa8879SHans Verkuil OV2640_SIZE("UXGA", UXGA_WIDTH, UXGA_HEIGHT, ov2640_uxga_regs), 58934aa8879SHans Verkuil }; 59034aa8879SHans Verkuil 59134aa8879SHans Verkuil /* 59234aa8879SHans Verkuil * Register settings for pixel formats 59334aa8879SHans Verkuil */ 59434aa8879SHans Verkuil static const struct regval_list ov2640_format_change_preamble_regs[] = { 59534aa8879SHans Verkuil { BANK_SEL, BANK_SEL_DSP }, 59634aa8879SHans Verkuil { R_BYPASS, R_BYPASS_USE_DSP }, 59734aa8879SHans Verkuil ENDMARKER, 59834aa8879SHans Verkuil }; 59934aa8879SHans Verkuil 60034aa8879SHans Verkuil static const struct regval_list ov2640_yuyv_regs[] = { 60134aa8879SHans Verkuil { IMAGE_MODE, IMAGE_MODE_YUV422 }, 60234aa8879SHans Verkuil { 0xd7, 0x03 }, 60334aa8879SHans Verkuil { 0x33, 0xa0 }, 60434aa8879SHans Verkuil { 0xe5, 0x1f }, 60534aa8879SHans Verkuil { 0xe1, 0x67 }, 60634aa8879SHans Verkuil { RESET, 0x00 }, 60734aa8879SHans Verkuil { R_BYPASS, R_BYPASS_USE_DSP }, 60834aa8879SHans Verkuil ENDMARKER, 60934aa8879SHans Verkuil }; 61034aa8879SHans Verkuil 61134aa8879SHans Verkuil static const struct regval_list ov2640_uyvy_regs[] = { 61234aa8879SHans Verkuil { IMAGE_MODE, IMAGE_MODE_LBYTE_FIRST | IMAGE_MODE_YUV422 }, 61334aa8879SHans Verkuil { 0xd7, 0x01 }, 61434aa8879SHans Verkuil { 0x33, 0xa0 }, 61534aa8879SHans Verkuil { 0xe1, 0x67 }, 61634aa8879SHans Verkuil { RESET, 0x00 }, 61734aa8879SHans Verkuil { R_BYPASS, R_BYPASS_USE_DSP }, 61834aa8879SHans Verkuil ENDMARKER, 61934aa8879SHans Verkuil }; 62034aa8879SHans Verkuil 62134aa8879SHans Verkuil static const struct regval_list ov2640_rgb565_be_regs[] = { 62234aa8879SHans Verkuil { IMAGE_MODE, IMAGE_MODE_RGB565 }, 62334aa8879SHans Verkuil { 0xd7, 0x03 }, 62434aa8879SHans Verkuil { RESET, 0x00 }, 62534aa8879SHans Verkuil { R_BYPASS, R_BYPASS_USE_DSP }, 62634aa8879SHans Verkuil ENDMARKER, 62734aa8879SHans Verkuil }; 62834aa8879SHans Verkuil 62934aa8879SHans Verkuil static const struct regval_list ov2640_rgb565_le_regs[] = { 63034aa8879SHans Verkuil { IMAGE_MODE, IMAGE_MODE_LBYTE_FIRST | IMAGE_MODE_RGB565 }, 63134aa8879SHans Verkuil { 0xd7, 0x03 }, 63234aa8879SHans Verkuil { RESET, 0x00 }, 63334aa8879SHans Verkuil { R_BYPASS, R_BYPASS_USE_DSP }, 63434aa8879SHans Verkuil ENDMARKER, 63534aa8879SHans Verkuil }; 63634aa8879SHans Verkuil 63734aa8879SHans Verkuil static u32 ov2640_codes[] = { 63834aa8879SHans Verkuil MEDIA_BUS_FMT_YUYV8_2X8, 63934aa8879SHans Verkuil MEDIA_BUS_FMT_UYVY8_2X8, 640d72b196fSFrank Schaefer MEDIA_BUS_FMT_YVYU8_2X8, 641d72b196fSFrank Schaefer MEDIA_BUS_FMT_VYUY8_2X8, 64234aa8879SHans Verkuil MEDIA_BUS_FMT_RGB565_2X8_BE, 64334aa8879SHans Verkuil MEDIA_BUS_FMT_RGB565_2X8_LE, 64434aa8879SHans Verkuil }; 64534aa8879SHans Verkuil 64634aa8879SHans Verkuil /* 64734aa8879SHans Verkuil * General functions 64834aa8879SHans Verkuil */ 64934aa8879SHans Verkuil static struct ov2640_priv *to_ov2640(const struct i2c_client *client) 65034aa8879SHans Verkuil { 65134aa8879SHans Verkuil return container_of(i2c_get_clientdata(client), struct ov2640_priv, 65234aa8879SHans Verkuil subdev); 65334aa8879SHans Verkuil } 65434aa8879SHans Verkuil 65534aa8879SHans Verkuil static int ov2640_write_array(struct i2c_client *client, 65634aa8879SHans Verkuil const struct regval_list *vals) 65734aa8879SHans Verkuil { 65834aa8879SHans Verkuil int ret; 65934aa8879SHans Verkuil 66034aa8879SHans Verkuil while ((vals->reg_num != 0xff) || (vals->value != 0xff)) { 66134aa8879SHans Verkuil ret = i2c_smbus_write_byte_data(client, 66234aa8879SHans Verkuil vals->reg_num, vals->value); 66334aa8879SHans Verkuil dev_vdbg(&client->dev, "array: 0x%02x, 0x%02x", 66434aa8879SHans Verkuil vals->reg_num, vals->value); 66534aa8879SHans Verkuil 66634aa8879SHans Verkuil if (ret < 0) 66734aa8879SHans Verkuil return ret; 66834aa8879SHans Verkuil vals++; 66934aa8879SHans Verkuil } 67034aa8879SHans Verkuil return 0; 67134aa8879SHans Verkuil } 67234aa8879SHans Verkuil 67334aa8879SHans Verkuil static int ov2640_mask_set(struct i2c_client *client, 67434aa8879SHans Verkuil u8 reg, u8 mask, u8 set) 67534aa8879SHans Verkuil { 67634aa8879SHans Verkuil s32 val = i2c_smbus_read_byte_data(client, reg); 67734aa8879SHans Verkuil if (val < 0) 67834aa8879SHans Verkuil return val; 67934aa8879SHans Verkuil 68034aa8879SHans Verkuil val &= ~mask; 68134aa8879SHans Verkuil val |= set & mask; 68234aa8879SHans Verkuil 68334aa8879SHans Verkuil dev_vdbg(&client->dev, "masks: 0x%02x, 0x%02x", reg, val); 68434aa8879SHans Verkuil 68534aa8879SHans Verkuil return i2c_smbus_write_byte_data(client, reg, val); 68634aa8879SHans Verkuil } 68734aa8879SHans Verkuil 68834aa8879SHans Verkuil static int ov2640_reset(struct i2c_client *client) 68934aa8879SHans Verkuil { 69034aa8879SHans Verkuil int ret; 69191c158ddSColin Ian King static const struct regval_list reset_seq[] = { 69234aa8879SHans Verkuil {BANK_SEL, BANK_SEL_SENS}, 69334aa8879SHans Verkuil {COM7, COM7_SRST}, 69434aa8879SHans Verkuil ENDMARKER, 69534aa8879SHans Verkuil }; 69634aa8879SHans Verkuil 69734aa8879SHans Verkuil ret = ov2640_write_array(client, reset_seq); 69834aa8879SHans Verkuil if (ret) 69934aa8879SHans Verkuil goto err; 70034aa8879SHans Verkuil 70134aa8879SHans Verkuil msleep(5); 70234aa8879SHans Verkuil err: 70334aa8879SHans Verkuil dev_dbg(&client->dev, "%s: (ret %d)", __func__, ret); 70434aa8879SHans Verkuil return ret; 70534aa8879SHans Verkuil } 70634aa8879SHans Verkuil 70734aa8879SHans Verkuil /* 70834aa8879SHans Verkuil * functions 70934aa8879SHans Verkuil */ 71034aa8879SHans Verkuil static int ov2640_s_ctrl(struct v4l2_ctrl *ctrl) 71134aa8879SHans Verkuil { 71234aa8879SHans Verkuil struct v4l2_subdev *sd = 71334aa8879SHans Verkuil &container_of(ctrl->handler, struct ov2640_priv, hdl)->subdev; 71434aa8879SHans Verkuil struct i2c_client *client = v4l2_get_subdevdata(sd); 71534aa8879SHans Verkuil u8 val; 71634aa8879SHans Verkuil int ret; 71734aa8879SHans Verkuil 71834aa8879SHans Verkuil ret = i2c_smbus_write_byte_data(client, BANK_SEL, BANK_SEL_SENS); 71934aa8879SHans Verkuil if (ret < 0) 72034aa8879SHans Verkuil return ret; 72134aa8879SHans Verkuil 72234aa8879SHans Verkuil switch (ctrl->id) { 72334aa8879SHans Verkuil case V4L2_CID_VFLIP: 7247f140fc2SFrank Schaefer val = ctrl->val ? REG04_VFLIP_IMG | REG04_VREF_EN : 0x00; 7257f140fc2SFrank Schaefer return ov2640_mask_set(client, REG04, 7267f140fc2SFrank Schaefer REG04_VFLIP_IMG | REG04_VREF_EN, val); 7277f140fc2SFrank Schaefer /* NOTE: REG04_VREF_EN: 1 line shift / even/odd line swap */ 72834aa8879SHans Verkuil case V4L2_CID_HFLIP: 72934aa8879SHans Verkuil val = ctrl->val ? REG04_HFLIP_IMG : 0x00; 73034aa8879SHans Verkuil return ov2640_mask_set(client, REG04, REG04_HFLIP_IMG, val); 73134aa8879SHans Verkuil } 73234aa8879SHans Verkuil 73334aa8879SHans Verkuil return -EINVAL; 73434aa8879SHans Verkuil } 73534aa8879SHans Verkuil 73634aa8879SHans Verkuil #ifdef CONFIG_VIDEO_ADV_DEBUG 73734aa8879SHans Verkuil static int ov2640_g_register(struct v4l2_subdev *sd, 73834aa8879SHans Verkuil struct v4l2_dbg_register *reg) 73934aa8879SHans Verkuil { 74034aa8879SHans Verkuil struct i2c_client *client = v4l2_get_subdevdata(sd); 74134aa8879SHans Verkuil int ret; 74234aa8879SHans Verkuil 74334aa8879SHans Verkuil reg->size = 1; 74434aa8879SHans Verkuil if (reg->reg > 0xff) 74534aa8879SHans Verkuil return -EINVAL; 74634aa8879SHans Verkuil 74734aa8879SHans Verkuil ret = i2c_smbus_read_byte_data(client, reg->reg); 74834aa8879SHans Verkuil if (ret < 0) 74934aa8879SHans Verkuil return ret; 75034aa8879SHans Verkuil 75134aa8879SHans Verkuil reg->val = ret; 75234aa8879SHans Verkuil 75334aa8879SHans Verkuil return 0; 75434aa8879SHans Verkuil } 75534aa8879SHans Verkuil 75634aa8879SHans Verkuil static int ov2640_s_register(struct v4l2_subdev *sd, 75734aa8879SHans Verkuil const struct v4l2_dbg_register *reg) 75834aa8879SHans Verkuil { 75934aa8879SHans Verkuil struct i2c_client *client = v4l2_get_subdevdata(sd); 76034aa8879SHans Verkuil 76134aa8879SHans Verkuil if (reg->reg > 0xff || 76234aa8879SHans Verkuil reg->val > 0xff) 76334aa8879SHans Verkuil return -EINVAL; 76434aa8879SHans Verkuil 76534aa8879SHans Verkuil return i2c_smbus_write_byte_data(client, reg->reg, reg->val); 76634aa8879SHans Verkuil } 76734aa8879SHans Verkuil #endif 76834aa8879SHans Verkuil 76934aa8879SHans Verkuil static int ov2640_s_power(struct v4l2_subdev *sd, int on) 77034aa8879SHans Verkuil { 7713622d3e7SMauro Carvalho Chehab #ifdef CONFIG_GPIOLIB 77234aa8879SHans Verkuil struct i2c_client *client = v4l2_get_subdevdata(sd); 77334aa8879SHans Verkuil struct ov2640_priv *priv = to_ov2640(client); 77434aa8879SHans Verkuil 775a463ea99SMauro Carvalho Chehab if (priv->pwdn_gpio) 77634aa8879SHans Verkuil gpiod_direction_output(priv->pwdn_gpio, !on); 77734aa8879SHans Verkuil if (on && priv->resetb_gpio) { 77834aa8879SHans Verkuil /* Active the resetb pin to perform a reset pulse */ 77934aa8879SHans Verkuil gpiod_direction_output(priv->resetb_gpio, 1); 78034aa8879SHans Verkuil usleep_range(3000, 5000); 7813622d3e7SMauro Carvalho Chehab gpiod_set_value(priv->resetb_gpio, 0); 78234aa8879SHans Verkuil } 783a463ea99SMauro Carvalho Chehab #endif 78434aa8879SHans Verkuil return 0; 78534aa8879SHans Verkuil } 78634aa8879SHans Verkuil 78734aa8879SHans Verkuil /* Select the nearest higher resolution for capture */ 78838eeb491SFrank Schaefer static const struct ov2640_win_size *ov2640_select_win(u32 width, u32 height) 78934aa8879SHans Verkuil { 79034aa8879SHans Verkuil int i, default_size = ARRAY_SIZE(ov2640_supported_win_sizes) - 1; 79134aa8879SHans Verkuil 79234aa8879SHans Verkuil for (i = 0; i < ARRAY_SIZE(ov2640_supported_win_sizes); i++) { 79338eeb491SFrank Schaefer if (ov2640_supported_win_sizes[i].width >= width && 79438eeb491SFrank Schaefer ov2640_supported_win_sizes[i].height >= height) 79534aa8879SHans Verkuil return &ov2640_supported_win_sizes[i]; 79634aa8879SHans Verkuil } 79734aa8879SHans Verkuil 79834aa8879SHans Verkuil return &ov2640_supported_win_sizes[default_size]; 79934aa8879SHans Verkuil } 80034aa8879SHans Verkuil 801aa23c053SHans Verkuil static int ov2640_set_params(struct i2c_client *client, 802aa23c053SHans Verkuil const struct ov2640_win_size *win, u32 code) 80334aa8879SHans Verkuil { 80434aa8879SHans Verkuil const struct regval_list *selected_cfmt_regs; 805d72b196fSFrank Schaefer u8 val; 80634aa8879SHans Verkuil int ret; 80734aa8879SHans Verkuil 8082aae3939SAkinobu Mita if (!win) 8092aae3939SAkinobu Mita return -EINVAL; 81034aa8879SHans Verkuil 81134aa8879SHans Verkuil switch (code) { 81234aa8879SHans Verkuil case MEDIA_BUS_FMT_RGB565_2X8_BE: 81334aa8879SHans Verkuil dev_dbg(&client->dev, "%s: Selected cfmt RGB565 BE", __func__); 81434aa8879SHans Verkuil selected_cfmt_regs = ov2640_rgb565_be_regs; 81534aa8879SHans Verkuil break; 81634aa8879SHans Verkuil case MEDIA_BUS_FMT_RGB565_2X8_LE: 81734aa8879SHans Verkuil dev_dbg(&client->dev, "%s: Selected cfmt RGB565 LE", __func__); 81834aa8879SHans Verkuil selected_cfmt_regs = ov2640_rgb565_le_regs; 81934aa8879SHans Verkuil break; 82034aa8879SHans Verkuil case MEDIA_BUS_FMT_YUYV8_2X8: 82134aa8879SHans Verkuil dev_dbg(&client->dev, "%s: Selected cfmt YUYV (YUV422)", __func__); 82234aa8879SHans Verkuil selected_cfmt_regs = ov2640_yuyv_regs; 82334aa8879SHans Verkuil break; 82434aa8879SHans Verkuil case MEDIA_BUS_FMT_UYVY8_2X8: 82534aa8879SHans Verkuil default: 82634aa8879SHans Verkuil dev_dbg(&client->dev, "%s: Selected cfmt UYVY", __func__); 82734aa8879SHans Verkuil selected_cfmt_regs = ov2640_uyvy_regs; 82834aa8879SHans Verkuil break; 829d72b196fSFrank Schaefer case MEDIA_BUS_FMT_YVYU8_2X8: 830d72b196fSFrank Schaefer dev_dbg(&client->dev, "%s: Selected cfmt YVYU", __func__); 831d72b196fSFrank Schaefer selected_cfmt_regs = ov2640_yuyv_regs; 832d72b196fSFrank Schaefer break; 833d72b196fSFrank Schaefer case MEDIA_BUS_FMT_VYUY8_2X8: 834d72b196fSFrank Schaefer dev_dbg(&client->dev, "%s: Selected cfmt VYUY", __func__); 835d72b196fSFrank Schaefer selected_cfmt_regs = ov2640_uyvy_regs; 836d72b196fSFrank Schaefer break; 83734aa8879SHans Verkuil } 83834aa8879SHans Verkuil 83934aa8879SHans Verkuil /* reset hardware */ 84034aa8879SHans Verkuil ov2640_reset(client); 84134aa8879SHans Verkuil 84234aa8879SHans Verkuil /* initialize the sensor with default data */ 84334aa8879SHans Verkuil dev_dbg(&client->dev, "%s: Init default", __func__); 84434aa8879SHans Verkuil ret = ov2640_write_array(client, ov2640_init_regs); 84534aa8879SHans Verkuil if (ret < 0) 84634aa8879SHans Verkuil goto err; 84734aa8879SHans Verkuil 84834aa8879SHans Verkuil /* select preamble */ 8492aae3939SAkinobu Mita dev_dbg(&client->dev, "%s: Set size to %s", __func__, win->name); 85034aa8879SHans Verkuil ret = ov2640_write_array(client, ov2640_size_change_preamble_regs); 85134aa8879SHans Verkuil if (ret < 0) 85234aa8879SHans Verkuil goto err; 85334aa8879SHans Verkuil 85434aa8879SHans Verkuil /* set size win */ 8552aae3939SAkinobu Mita ret = ov2640_write_array(client, win->regs); 85634aa8879SHans Verkuil if (ret < 0) 85734aa8879SHans Verkuil goto err; 85834aa8879SHans Verkuil 85934aa8879SHans Verkuil /* cfmt preamble */ 86034aa8879SHans Verkuil dev_dbg(&client->dev, "%s: Set cfmt", __func__); 86134aa8879SHans Verkuil ret = ov2640_write_array(client, ov2640_format_change_preamble_regs); 86234aa8879SHans Verkuil if (ret < 0) 86334aa8879SHans Verkuil goto err; 86434aa8879SHans Verkuil 86534aa8879SHans Verkuil /* set cfmt */ 86634aa8879SHans Verkuil ret = ov2640_write_array(client, selected_cfmt_regs); 86734aa8879SHans Verkuil if (ret < 0) 86834aa8879SHans Verkuil goto err; 869d72b196fSFrank Schaefer val = (code == MEDIA_BUS_FMT_YVYU8_2X8) 870d72b196fSFrank Schaefer || (code == MEDIA_BUS_FMT_VYUY8_2X8) ? CTRL0_VFIRST : 0x00; 871d72b196fSFrank Schaefer ret = ov2640_mask_set(client, CTRL0, CTRL0_VFIRST, val); 872d72b196fSFrank Schaefer if (ret < 0) 873d72b196fSFrank Schaefer goto err; 87434aa8879SHans Verkuil 87534aa8879SHans Verkuil return 0; 87634aa8879SHans Verkuil 87734aa8879SHans Verkuil err: 87834aa8879SHans Verkuil dev_err(&client->dev, "%s: Error %d", __func__, ret); 87934aa8879SHans Verkuil ov2640_reset(client); 88034aa8879SHans Verkuil 88134aa8879SHans Verkuil return ret; 88234aa8879SHans Verkuil } 88334aa8879SHans Verkuil 88434aa8879SHans Verkuil static int ov2640_get_fmt(struct v4l2_subdev *sd, 88534aa8879SHans Verkuil struct v4l2_subdev_pad_config *cfg, 88634aa8879SHans Verkuil struct v4l2_subdev_format *format) 88734aa8879SHans Verkuil { 88834aa8879SHans Verkuil struct v4l2_mbus_framefmt *mf = &format->format; 88934aa8879SHans Verkuil struct i2c_client *client = v4l2_get_subdevdata(sd); 89034aa8879SHans Verkuil struct ov2640_priv *priv = to_ov2640(client); 89134aa8879SHans Verkuil 89234aa8879SHans Verkuil if (format->pad) 89334aa8879SHans Verkuil return -EINVAL; 89434aa8879SHans Verkuil 89534aa8879SHans Verkuil if (!priv->win) { 89638eeb491SFrank Schaefer priv->win = ov2640_select_win(SVGA_WIDTH, SVGA_HEIGHT); 89734aa8879SHans Verkuil priv->cfmt_code = MEDIA_BUS_FMT_UYVY8_2X8; 89834aa8879SHans Verkuil } 89934aa8879SHans Verkuil 90034aa8879SHans Verkuil mf->width = priv->win->width; 90134aa8879SHans Verkuil mf->height = priv->win->height; 90234aa8879SHans Verkuil mf->code = priv->cfmt_code; 90334aa8879SHans Verkuil mf->colorspace = V4L2_COLORSPACE_SRGB; 90434aa8879SHans Verkuil mf->field = V4L2_FIELD_NONE; 90534aa8879SHans Verkuil 90634aa8879SHans Verkuil return 0; 90734aa8879SHans Verkuil } 90834aa8879SHans Verkuil 90934aa8879SHans Verkuil static int ov2640_set_fmt(struct v4l2_subdev *sd, 91034aa8879SHans Verkuil struct v4l2_subdev_pad_config *cfg, 91134aa8879SHans Verkuil struct v4l2_subdev_format *format) 91234aa8879SHans Verkuil { 91334aa8879SHans Verkuil struct v4l2_mbus_framefmt *mf = &format->format; 91434aa8879SHans Verkuil struct i2c_client *client = v4l2_get_subdevdata(sd); 9152aae3939SAkinobu Mita struct ov2640_priv *priv = to_ov2640(client); 916aa23c053SHans Verkuil const struct ov2640_win_size *win; 9172aae3939SAkinobu Mita int ret = 0; 91834aa8879SHans Verkuil 91934aa8879SHans Verkuil if (format->pad) 92034aa8879SHans Verkuil return -EINVAL; 92134aa8879SHans Verkuil 9222aae3939SAkinobu Mita mutex_lock(&priv->lock); 9232aae3939SAkinobu Mita 924aa23c053SHans Verkuil /* select suitable win */ 92538eeb491SFrank Schaefer win = ov2640_select_win(mf->width, mf->height); 92638eeb491SFrank Schaefer mf->width = win->width; 92738eeb491SFrank Schaefer mf->height = win->height; 92834aa8879SHans Verkuil 92934aa8879SHans Verkuil mf->field = V4L2_FIELD_NONE; 93034aa8879SHans Verkuil mf->colorspace = V4L2_COLORSPACE_SRGB; 93134aa8879SHans Verkuil 93234aa8879SHans Verkuil switch (mf->code) { 93334aa8879SHans Verkuil case MEDIA_BUS_FMT_RGB565_2X8_BE: 93434aa8879SHans Verkuil case MEDIA_BUS_FMT_RGB565_2X8_LE: 93534aa8879SHans Verkuil case MEDIA_BUS_FMT_YUYV8_2X8: 93634aa8879SHans Verkuil case MEDIA_BUS_FMT_UYVY8_2X8: 937d72b196fSFrank Schaefer case MEDIA_BUS_FMT_YVYU8_2X8: 938d72b196fSFrank Schaefer case MEDIA_BUS_FMT_VYUY8_2X8: 93934aa8879SHans Verkuil break; 94034aa8879SHans Verkuil default: 94134aa8879SHans Verkuil mf->code = MEDIA_BUS_FMT_UYVY8_2X8; 94234aa8879SHans Verkuil break; 94334aa8879SHans Verkuil } 94434aa8879SHans Verkuil 9452aae3939SAkinobu Mita if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { 9462aae3939SAkinobu Mita struct ov2640_priv *priv = to_ov2640(client); 9472aae3939SAkinobu Mita 9482aae3939SAkinobu Mita if (priv->streaming) { 9492aae3939SAkinobu Mita ret = -EBUSY; 9502aae3939SAkinobu Mita goto out; 9512aae3939SAkinobu Mita } 9522aae3939SAkinobu Mita /* select win */ 9532aae3939SAkinobu Mita priv->win = win; 9542aae3939SAkinobu Mita /* select format */ 9552aae3939SAkinobu Mita priv->cfmt_code = mf->code; 9562aae3939SAkinobu Mita } else { 95734aa8879SHans Verkuil cfg->try_fmt = *mf; 9582aae3939SAkinobu Mita } 9592aae3939SAkinobu Mita out: 9602aae3939SAkinobu Mita mutex_unlock(&priv->lock); 9612aae3939SAkinobu Mita 9622aae3939SAkinobu Mita return ret; 96334aa8879SHans Verkuil } 96434aa8879SHans Verkuil 96534aa8879SHans Verkuil static int ov2640_enum_mbus_code(struct v4l2_subdev *sd, 96634aa8879SHans Verkuil struct v4l2_subdev_pad_config *cfg, 96734aa8879SHans Verkuil struct v4l2_subdev_mbus_code_enum *code) 96834aa8879SHans Verkuil { 96934aa8879SHans Verkuil if (code->pad || code->index >= ARRAY_SIZE(ov2640_codes)) 97034aa8879SHans Verkuil return -EINVAL; 97134aa8879SHans Verkuil 97234aa8879SHans Verkuil code->code = ov2640_codes[code->index]; 97334aa8879SHans Verkuil return 0; 97434aa8879SHans Verkuil } 97534aa8879SHans Verkuil 97634aa8879SHans Verkuil static int ov2640_get_selection(struct v4l2_subdev *sd, 97734aa8879SHans Verkuil struct v4l2_subdev_pad_config *cfg, 97834aa8879SHans Verkuil struct v4l2_subdev_selection *sel) 97934aa8879SHans Verkuil { 98034aa8879SHans Verkuil if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) 98134aa8879SHans Verkuil return -EINVAL; 98234aa8879SHans Verkuil 98334aa8879SHans Verkuil switch (sel->target) { 98434aa8879SHans Verkuil case V4L2_SEL_TGT_CROP_BOUNDS: 98534aa8879SHans Verkuil case V4L2_SEL_TGT_CROP_DEFAULT: 98634aa8879SHans Verkuil case V4L2_SEL_TGT_CROP: 98734aa8879SHans Verkuil sel->r.left = 0; 98834aa8879SHans Verkuil sel->r.top = 0; 98934aa8879SHans Verkuil sel->r.width = UXGA_WIDTH; 99034aa8879SHans Verkuil sel->r.height = UXGA_HEIGHT; 99134aa8879SHans Verkuil return 0; 99234aa8879SHans Verkuil default: 99334aa8879SHans Verkuil return -EINVAL; 99434aa8879SHans Verkuil } 99534aa8879SHans Verkuil } 99634aa8879SHans Verkuil 9972aae3939SAkinobu Mita static int ov2640_s_stream(struct v4l2_subdev *sd, int on) 9982aae3939SAkinobu Mita { 9992aae3939SAkinobu Mita struct i2c_client *client = v4l2_get_subdevdata(sd); 10002aae3939SAkinobu Mita struct ov2640_priv *priv = to_ov2640(client); 10012aae3939SAkinobu Mita int ret = 0; 10022aae3939SAkinobu Mita 10032aae3939SAkinobu Mita mutex_lock(&priv->lock); 10042aae3939SAkinobu Mita if (priv->streaming == !on) { 10052aae3939SAkinobu Mita if (on) { 10062aae3939SAkinobu Mita ret = ov2640_set_params(client, priv->win, 10072aae3939SAkinobu Mita priv->cfmt_code); 10082aae3939SAkinobu Mita } 10092aae3939SAkinobu Mita } 10102aae3939SAkinobu Mita if (!ret) 10112aae3939SAkinobu Mita priv->streaming = on; 10122aae3939SAkinobu Mita mutex_unlock(&priv->lock); 10132aae3939SAkinobu Mita 10142aae3939SAkinobu Mita return ret; 10152aae3939SAkinobu Mita } 10162aae3939SAkinobu Mita 101734aa8879SHans Verkuil static int ov2640_video_probe(struct i2c_client *client) 101834aa8879SHans Verkuil { 101934aa8879SHans Verkuil struct ov2640_priv *priv = to_ov2640(client); 102034aa8879SHans Verkuil u8 pid, ver, midh, midl; 102134aa8879SHans Verkuil const char *devname; 102234aa8879SHans Verkuil int ret; 102334aa8879SHans Verkuil 102434aa8879SHans Verkuil ret = ov2640_s_power(&priv->subdev, 1); 102534aa8879SHans Verkuil if (ret < 0) 102634aa8879SHans Verkuil return ret; 102734aa8879SHans Verkuil 102834aa8879SHans Verkuil /* 102934aa8879SHans Verkuil * check and show product ID and manufacturer ID 103034aa8879SHans Verkuil */ 103134aa8879SHans Verkuil i2c_smbus_write_byte_data(client, BANK_SEL, BANK_SEL_SENS); 103234aa8879SHans Verkuil pid = i2c_smbus_read_byte_data(client, PID); 103334aa8879SHans Verkuil ver = i2c_smbus_read_byte_data(client, VER); 103434aa8879SHans Verkuil midh = i2c_smbus_read_byte_data(client, MIDH); 103534aa8879SHans Verkuil midl = i2c_smbus_read_byte_data(client, MIDL); 103634aa8879SHans Verkuil 103734aa8879SHans Verkuil switch (VERSION(pid, ver)) { 103834aa8879SHans Verkuil case PID_OV2640: 103934aa8879SHans Verkuil devname = "ov2640"; 104034aa8879SHans Verkuil break; 104134aa8879SHans Verkuil default: 104234aa8879SHans Verkuil dev_err(&client->dev, 104334aa8879SHans Verkuil "Product ID error %x:%x\n", pid, ver); 104434aa8879SHans Verkuil ret = -ENODEV; 104534aa8879SHans Verkuil goto done; 104634aa8879SHans Verkuil } 104734aa8879SHans Verkuil 104834aa8879SHans Verkuil dev_info(&client->dev, 104934aa8879SHans Verkuil "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", 105034aa8879SHans Verkuil devname, pid, ver, midh, midl); 105134aa8879SHans Verkuil 105234aa8879SHans Verkuil ret = v4l2_ctrl_handler_setup(&priv->hdl); 105334aa8879SHans Verkuil 105434aa8879SHans Verkuil done: 105534aa8879SHans Verkuil ov2640_s_power(&priv->subdev, 0); 105634aa8879SHans Verkuil return ret; 105734aa8879SHans Verkuil } 105834aa8879SHans Verkuil 105934aa8879SHans Verkuil static const struct v4l2_ctrl_ops ov2640_ctrl_ops = { 106034aa8879SHans Verkuil .s_ctrl = ov2640_s_ctrl, 106134aa8879SHans Verkuil }; 106234aa8879SHans Verkuil 106334aa8879SHans Verkuil static const struct v4l2_subdev_core_ops ov2640_subdev_core_ops = { 106434aa8879SHans Verkuil #ifdef CONFIG_VIDEO_ADV_DEBUG 106534aa8879SHans Verkuil .g_register = ov2640_g_register, 106634aa8879SHans Verkuil .s_register = ov2640_s_register, 106734aa8879SHans Verkuil #endif 106834aa8879SHans Verkuil .s_power = ov2640_s_power, 106934aa8879SHans Verkuil }; 107034aa8879SHans Verkuil 107134aa8879SHans Verkuil static const struct v4l2_subdev_pad_ops ov2640_subdev_pad_ops = { 107234aa8879SHans Verkuil .enum_mbus_code = ov2640_enum_mbus_code, 107334aa8879SHans Verkuil .get_selection = ov2640_get_selection, 107434aa8879SHans Verkuil .get_fmt = ov2640_get_fmt, 107534aa8879SHans Verkuil .set_fmt = ov2640_set_fmt, 107634aa8879SHans Verkuil }; 107734aa8879SHans Verkuil 10782aae3939SAkinobu Mita static const struct v4l2_subdev_video_ops ov2640_subdev_video_ops = { 10792aae3939SAkinobu Mita .s_stream = ov2640_s_stream, 10802aae3939SAkinobu Mita }; 10812aae3939SAkinobu Mita 108234aa8879SHans Verkuil static const struct v4l2_subdev_ops ov2640_subdev_ops = { 108334aa8879SHans Verkuil .core = &ov2640_subdev_core_ops, 108434aa8879SHans Verkuil .pad = &ov2640_subdev_pad_ops, 10852aae3939SAkinobu Mita .video = &ov2640_subdev_video_ops, 108634aa8879SHans Verkuil }; 108734aa8879SHans Verkuil 108834aa8879SHans Verkuil static int ov2640_probe_dt(struct i2c_client *client, 108934aa8879SHans Verkuil struct ov2640_priv *priv) 109034aa8879SHans Verkuil { 10913622d3e7SMauro Carvalho Chehab int ret; 10923622d3e7SMauro Carvalho Chehab 109334aa8879SHans Verkuil /* Request the reset GPIO deasserted */ 109434aa8879SHans Verkuil priv->resetb_gpio = devm_gpiod_get_optional(&client->dev, "resetb", 109534aa8879SHans Verkuil GPIOD_OUT_LOW); 10963622d3e7SMauro Carvalho Chehab 109734aa8879SHans Verkuil if (!priv->resetb_gpio) 109834aa8879SHans Verkuil dev_dbg(&client->dev, "resetb gpio is not assigned!\n"); 10993622d3e7SMauro Carvalho Chehab 11003622d3e7SMauro Carvalho Chehab ret = PTR_ERR_OR_ZERO(priv->resetb_gpio); 11013622d3e7SMauro Carvalho Chehab if (ret && ret != -ENOSYS) { 11023622d3e7SMauro Carvalho Chehab dev_dbg(&client->dev, 11033622d3e7SMauro Carvalho Chehab "Error %d while getting resetb gpio\n", ret); 11043622d3e7SMauro Carvalho Chehab return ret; 11053622d3e7SMauro Carvalho Chehab } 110634aa8879SHans Verkuil 110734aa8879SHans Verkuil /* Request the power down GPIO asserted */ 110834aa8879SHans Verkuil priv->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "pwdn", 110934aa8879SHans Verkuil GPIOD_OUT_HIGH); 11103622d3e7SMauro Carvalho Chehab 111134aa8879SHans Verkuil if (!priv->pwdn_gpio) 111234aa8879SHans Verkuil dev_dbg(&client->dev, "pwdn gpio is not assigned!\n"); 11133622d3e7SMauro Carvalho Chehab 11143622d3e7SMauro Carvalho Chehab ret = PTR_ERR_OR_ZERO(priv->pwdn_gpio); 11153622d3e7SMauro Carvalho Chehab if (ret && ret != -ENOSYS) { 11163622d3e7SMauro Carvalho Chehab dev_dbg(&client->dev, 11173622d3e7SMauro Carvalho Chehab "Error %d while getting pwdn gpio\n", ret); 11183622d3e7SMauro Carvalho Chehab return ret; 11193622d3e7SMauro Carvalho Chehab } 112034aa8879SHans Verkuil 112134aa8879SHans Verkuil return 0; 112234aa8879SHans Verkuil } 112334aa8879SHans Verkuil 112434aa8879SHans Verkuil /* 112534aa8879SHans Verkuil * i2c_driver functions 112634aa8879SHans Verkuil */ 112734aa8879SHans Verkuil static int ov2640_probe(struct i2c_client *client, 112834aa8879SHans Verkuil const struct i2c_device_id *did) 112934aa8879SHans Verkuil { 113034aa8879SHans Verkuil struct ov2640_priv *priv; 113134aa8879SHans Verkuil struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); 113234aa8879SHans Verkuil int ret; 113334aa8879SHans Verkuil 113434aa8879SHans Verkuil if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { 113534aa8879SHans Verkuil dev_err(&adapter->dev, 113634aa8879SHans Verkuil "OV2640: I2C-Adapter doesn't support SMBUS\n"); 113734aa8879SHans Verkuil return -EIO; 113834aa8879SHans Verkuil } 113934aa8879SHans Verkuil 114019fab6feSMarkus Elfring priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); 11410fd58435SMarkus Elfring if (!priv) 114234aa8879SHans Verkuil return -ENOMEM; 114334aa8879SHans Verkuil 114446796cfcSHans Verkuil if (client->dev.of_node) { 114546796cfcSHans Verkuil priv->clk = devm_clk_get(&client->dev, "xvclk"); 114634aa8879SHans Verkuil if (IS_ERR(priv->clk)) 1147877f1af1SFabio Estevam return PTR_ERR(priv->clk); 1148c3d14780SFabio Estevam ret = clk_prepare_enable(priv->clk); 1149c3d14780SFabio Estevam if (ret) 1150c3d14780SFabio Estevam return ret; 115134aa8879SHans Verkuil } 115234aa8879SHans Verkuil 115334aa8879SHans Verkuil ret = ov2640_probe_dt(client, priv); 115434aa8879SHans Verkuil if (ret) 115534aa8879SHans Verkuil goto err_clk; 115634aa8879SHans Verkuil 115734aa8879SHans Verkuil v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops); 11586b725eb6SAkinobu Mita priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 11592aae3939SAkinobu Mita mutex_init(&priv->lock); 116034aa8879SHans Verkuil v4l2_ctrl_handler_init(&priv->hdl, 2); 116134aa8879SHans Verkuil v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops, 116234aa8879SHans Verkuil V4L2_CID_VFLIP, 0, 1, 1, 0); 116334aa8879SHans Verkuil v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops, 116434aa8879SHans Verkuil V4L2_CID_HFLIP, 0, 1, 1, 0); 116534aa8879SHans Verkuil priv->subdev.ctrl_handler = &priv->hdl; 116634aa8879SHans Verkuil if (priv->hdl.error) { 116734aa8879SHans Verkuil ret = priv->hdl.error; 116846796cfcSHans Verkuil goto err_hdl; 116934aa8879SHans Verkuil } 1170ff0e9c1dSHans Verkuil #if defined(CONFIG_MEDIA_CONTROLLER) 1171ff0e9c1dSHans Verkuil priv->pad.flags = MEDIA_PAD_FL_SOURCE; 1172ff0e9c1dSHans Verkuil priv->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; 1173ff0e9c1dSHans Verkuil ret = media_entity_pads_init(&priv->subdev.entity, 1, &priv->pad); 1174ff0e9c1dSHans Verkuil if (ret < 0) 1175ff0e9c1dSHans Verkuil goto err_hdl; 1176ff0e9c1dSHans Verkuil #endif 117734aa8879SHans Verkuil 117834aa8879SHans Verkuil ret = ov2640_video_probe(client); 117934aa8879SHans Verkuil if (ret < 0) 1180ff0e9c1dSHans Verkuil goto err_videoprobe; 118134aa8879SHans Verkuil 118234aa8879SHans Verkuil ret = v4l2_async_register_subdev(&priv->subdev); 118334aa8879SHans Verkuil if (ret < 0) 1184ff0e9c1dSHans Verkuil goto err_videoprobe; 118534aa8879SHans Verkuil 118634aa8879SHans Verkuil dev_info(&adapter->dev, "OV2640 Probed\n"); 118734aa8879SHans Verkuil 118834aa8879SHans Verkuil return 0; 118934aa8879SHans Verkuil 1190ff0e9c1dSHans Verkuil err_videoprobe: 1191ff0e9c1dSHans Verkuil media_entity_cleanup(&priv->subdev.entity); 119246796cfcSHans Verkuil err_hdl: 119334aa8879SHans Verkuil v4l2_ctrl_handler_free(&priv->hdl); 11942aae3939SAkinobu Mita mutex_destroy(&priv->lock); 119534aa8879SHans Verkuil err_clk: 119646796cfcSHans Verkuil clk_disable_unprepare(priv->clk); 119734aa8879SHans Verkuil return ret; 119834aa8879SHans Verkuil } 119934aa8879SHans Verkuil 120034aa8879SHans Verkuil static int ov2640_remove(struct i2c_client *client) 120134aa8879SHans Verkuil { 120234aa8879SHans Verkuil struct ov2640_priv *priv = to_ov2640(client); 120334aa8879SHans Verkuil 120434aa8879SHans Verkuil v4l2_async_unregister_subdev(&priv->subdev); 120534aa8879SHans Verkuil v4l2_ctrl_handler_free(&priv->hdl); 12062aae3939SAkinobu Mita mutex_destroy(&priv->lock); 1207ff0e9c1dSHans Verkuil media_entity_cleanup(&priv->subdev.entity); 120846796cfcSHans Verkuil v4l2_device_unregister_subdev(&priv->subdev); 120946796cfcSHans Verkuil clk_disable_unprepare(priv->clk); 121034aa8879SHans Verkuil return 0; 121134aa8879SHans Verkuil } 121234aa8879SHans Verkuil 121334aa8879SHans Verkuil static const struct i2c_device_id ov2640_id[] = { 121434aa8879SHans Verkuil { "ov2640", 0 }, 121534aa8879SHans Verkuil { } 121634aa8879SHans Verkuil }; 121734aa8879SHans Verkuil MODULE_DEVICE_TABLE(i2c, ov2640_id); 121834aa8879SHans Verkuil 121934aa8879SHans Verkuil static const struct of_device_id ov2640_of_match[] = { 122034aa8879SHans Verkuil {.compatible = "ovti,ov2640", }, 122134aa8879SHans Verkuil {}, 122234aa8879SHans Verkuil }; 122334aa8879SHans Verkuil MODULE_DEVICE_TABLE(of, ov2640_of_match); 122434aa8879SHans Verkuil 122534aa8879SHans Verkuil static struct i2c_driver ov2640_i2c_driver = { 122634aa8879SHans Verkuil .driver = { 122734aa8879SHans Verkuil .name = "ov2640", 122834aa8879SHans Verkuil .of_match_table = of_match_ptr(ov2640_of_match), 122934aa8879SHans Verkuil }, 123034aa8879SHans Verkuil .probe = ov2640_probe, 123134aa8879SHans Verkuil .remove = ov2640_remove, 123234aa8879SHans Verkuil .id_table = ov2640_id, 123334aa8879SHans Verkuil }; 123434aa8879SHans Verkuil 123534aa8879SHans Verkuil module_i2c_driver(ov2640_i2c_driver); 123634aa8879SHans Verkuil 123734aa8879SHans Verkuil MODULE_DESCRIPTION("Driver for Omni Vision 2640 sensor"); 123834aa8879SHans Verkuil MODULE_AUTHOR("Alberto Panizzo"); 123934aa8879SHans Verkuil MODULE_LICENSE("GPL v2"); 1240