12f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik/* 22f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * V4L2 SoC Camera driver for OmniVision OV6650 Camera Sensor 32f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * 42f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * Copyright (C) 2010 Janusz Krzysztofik <jkrzyszt@tis.icnet.pl> 52f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * 62f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * Based on OmniVision OV96xx Camera Driver 72f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * Copyright (C) 2009 Marek Vasut <marek.vasut@gmail.com> 82f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * 92f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * Based on ov772x camera driver: 102f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * Copyright (C) 2008 Renesas Solutions Corp. 112f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * Kuninori Morimoto <morimoto.kuninori@renesas.com> 122f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * 132f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * Based on ov7670 and soc_camera_platform driver, 142f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net> 152f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * Copyright (C) 2008 Magnus Damm 162f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> 172f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * 182f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * Hardware specific bits initialy based on former work by Matt Callow 192f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * drivers/media/video/omap/sensor_ov6650.c 202f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * Copyright (C) 2006 Matt Callow 212f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * 222f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * This program is free software; you can redistribute it and/or modify 232f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * it under the terms of the GNU General Public License version 2 as 242f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * published by the Free Software Foundation. 252f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik */ 262f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 272f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#include <linux/bitops.h> 282f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#include <linux/delay.h> 292f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#include <linux/i2c.h> 302f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#include <linux/slab.h> 3195d20109ad6478ecea5e93ba191270fb645d52c7Guennadi Liakhovetski#include <linux/v4l2-mediabus.h> 327a707b89202f905bd9f9fbde326933c59a81214cPaul Gortmaker#include <linux/module.h> 332f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 342f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#include <media/soc_camera.h> 352f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#include <media/v4l2-chip-ident.h> 36afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil#include <media/v4l2-ctrls.h> 372f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 382f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik/* Register definitions */ 392f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_GAIN 0x00 /* range 00 - 3F */ 402f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_BLUE 0x01 412f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_RED 0x02 422f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_SAT 0x03 /* [7:4] saturation [0:3] reserved */ 432f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_HUE 0x04 /* [7:6] rsrvd [5] hue en [4:0] hue */ 442f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 452f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_BRT 0x06 462f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 472f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_PIDH 0x0a 482f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_PIDL 0x0b 492f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 502f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_AECH 0x10 512f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_CLKRC 0x11 /* Data Format and Internal Clock */ 522f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik /* [7:6] Input system clock (MHz)*/ 532f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik /* 00=8, 01=12, 10=16, 11=24 */ 542f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik /* [5:0]: Internal Clock Pre-Scaler */ 552f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_COMA 0x12 /* [7] Reset */ 562f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_COMB 0x13 572f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_COMC 0x14 582f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_COMD 0x15 592f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_COML 0x16 602f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_HSTRT 0x17 612f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_HSTOP 0x18 622f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_VSTRT 0x19 632f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_VSTOP 0x1a 642f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_PSHFT 0x1b 652f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_MIDH 0x1c 662f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_MIDL 0x1d 672f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_HSYNS 0x1e 682f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_HSYNE 0x1f 692f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_COME 0x20 702f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_YOFF 0x21 712f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_UOFF 0x22 722f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_VOFF 0x23 732f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_AEW 0x24 742f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_AEB 0x25 752f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_COMF 0x26 762f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_COMG 0x27 772f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_COMH 0x28 782f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_COMI 0x29 792f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 802f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_FRARL 0x2b 812f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_COMJ 0x2c 822f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_COMK 0x2d 832f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_AVGY 0x2e 842f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_REF0 0x2f 852f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_REF1 0x30 862f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_REF2 0x31 872f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_FRAJH 0x32 882f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_FRAJL 0x33 892f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_FACT 0x34 902f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_L1AEC 0x35 912f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_AVGU 0x36 922f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_AVGV 0x37 932f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 942f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_SPCB 0x60 952f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_SPCC 0x61 962f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_GAM1 0x62 972f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_GAM2 0x63 982f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_GAM3 0x64 992f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_SPCD 0x65 1002f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 1012f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_SPCE 0x68 1022f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_ADCL 0x69 1032f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 1042f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_RMCO 0x6c 1052f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_GMCO 0x6d 1062f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define REG_BMCO 0x6e 1072f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 1082f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 1092f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik/* Register bits, values, etc. */ 1102f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define OV6650_PIDH 0x66 /* high byte of product ID number */ 1112f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define OV6650_PIDL 0x50 /* low byte of product ID number */ 1122f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define OV6650_MIDH 0x7F /* high byte of mfg ID */ 1132f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define OV6650_MIDL 0xA2 /* low byte of mfg ID */ 1142f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 1152f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define DEF_GAIN 0x00 1162f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define DEF_BLUE 0x80 1172f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define DEF_RED 0x80 1182f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 1192f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define SAT_SHIFT 4 1202f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define SAT_MASK (0xf << SAT_SHIFT) 1212f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define SET_SAT(x) (((x) << SAT_SHIFT) & SAT_MASK) 1222f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 1232f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define HUE_EN BIT(5) 1242f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define HUE_MASK 0x1f 1252f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define DEF_HUE 0x10 1262f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define SET_HUE(x) (HUE_EN | ((x) & HUE_MASK)) 1272f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 1282f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define DEF_AECH 0x4D 1292f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 1302f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define CLKRC_6MHz 0x00 1312f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define CLKRC_12MHz 0x40 1322f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define CLKRC_16MHz 0x80 1332f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define CLKRC_24MHz 0xc0 1342f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define CLKRC_DIV_MASK 0x3f 1352f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define GET_CLKRC_DIV(x) (((x) & CLKRC_DIV_MASK) + 1) 1362f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 1372f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define COMA_RESET BIT(7) 1382f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define COMA_QCIF BIT(5) 1392f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define COMA_RAW_RGB BIT(4) 1402f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define COMA_RGB BIT(3) 1412f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define COMA_BW BIT(2) 1422f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define COMA_WORD_SWAP BIT(1) 1432f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define COMA_BYTE_SWAP BIT(0) 1442f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define DEF_COMA 0x00 1452f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 1462f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define COMB_FLIP_V BIT(7) 1472f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define COMB_FLIP_H BIT(5) 1482f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define COMB_BAND_FILTER BIT(4) 1492f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define COMB_AWB BIT(2) 1502f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define COMB_AGC BIT(1) 1512f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define COMB_AEC BIT(0) 1522f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define DEF_COMB 0x5f 1532f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 1542f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define COML_ONE_CHANNEL BIT(7) 1552f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 1562f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define DEF_HSTRT 0x24 1572f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define DEF_HSTOP 0xd4 1582f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define DEF_VSTRT 0x04 1592f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define DEF_VSTOP 0x94 1602f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 1612f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define COMF_HREF_LOW BIT(4) 1622f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 1632f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define COMJ_PCLK_RISING BIT(4) 1642f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define COMJ_VSYNC_HIGH BIT(0) 1652f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 1662f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik/* supported resolutions */ 1672f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define W_QCIF (DEF_HSTOP - DEF_HSTRT) 1682f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define W_CIF (W_QCIF << 1) 1692f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define H_QCIF (DEF_VSTOP - DEF_VSTRT) 1702f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define H_CIF (H_QCIF << 1) 1712f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 1722f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#define FRAME_RATE_MAX 30 1732f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 1742f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 1752f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstruct ov6650_reg { 1762f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik u8 reg; 1772f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik u8 val; 1782f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik}; 1792f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 1802f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstruct ov6650 { 1812f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct v4l2_subdev subdev; 182afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil struct v4l2_ctrl_handler hdl; 183afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil struct { 184afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil /* exposure/autoexposure cluster */ 185afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil struct v4l2_ctrl *autoexposure; 186afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil struct v4l2_ctrl *exposure; 187afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil }; 188afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil struct { 189afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil /* gain/autogain cluster */ 190afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil struct v4l2_ctrl *autogain; 191afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil struct v4l2_ctrl *gain; 192afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil }; 193afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil struct { 194afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil /* blue/red/autowhitebalance cluster */ 195afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil struct v4l2_ctrl *autowb; 196afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil struct v4l2_ctrl *blue; 197afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil struct v4l2_ctrl *red; 198afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil }; 1992f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik bool half_scale; /* scale down output by 2 */ 2002f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct v4l2_rect rect; /* sensor cropping window */ 2012f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik unsigned long pclk_limit; /* from host */ 2022f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik unsigned long pclk_max; /* from resolution and format */ 2032f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct v4l2_fract tpf; /* as requested with s_parm */ 2042f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik enum v4l2_mbus_pixelcode code; 2052f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik enum v4l2_colorspace colorspace; 2062f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik}; 2072f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 2082f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 2092f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic enum v4l2_mbus_pixelcode ov6650_codes[] = { 2102f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik V4L2_MBUS_FMT_YUYV8_2X8, 2112f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik V4L2_MBUS_FMT_UYVY8_2X8, 2122f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik V4L2_MBUS_FMT_YVYU8_2X8, 2132f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik V4L2_MBUS_FMT_VYUY8_2X8, 2142f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik V4L2_MBUS_FMT_SBGGR8_1X8, 215076704332ca6da550cbc279918ef8b88b4ac1e45Laurent Pinchart V4L2_MBUS_FMT_Y8_1X8, 2162f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik}; 2172f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 2182f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik/* read a register */ 2192f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic int ov6650_reg_read(struct i2c_client *client, u8 reg, u8 *val) 2202f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik{ 2212f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik int ret; 2222f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik u8 data = reg; 2232f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct i2c_msg msg = { 2242f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .addr = client->addr, 2252f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .flags = 0, 2262f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .len = 1, 2272f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .buf = &data, 2282f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik }; 2292f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 2302f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik ret = i2c_transfer(client->adapter, &msg, 1); 2312f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (ret < 0) 2322f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik goto err; 2332f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 2342f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik msg.flags = I2C_M_RD; 2352f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik ret = i2c_transfer(client->adapter, &msg, 1); 2362f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (ret < 0) 2372f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik goto err; 2382f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 2392f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik *val = data; 2402f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return 0; 2412f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 2422f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikerr: 2432f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_err(&client->dev, "Failed reading register 0x%02x!\n", reg); 2442f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return ret; 2452f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik} 2462f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 2472f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik/* write a register */ 2482f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic int ov6650_reg_write(struct i2c_client *client, u8 reg, u8 val) 2492f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik{ 2502f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik int ret; 2512f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik unsigned char data[2] = { reg, val }; 2522f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct i2c_msg msg = { 2532f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .addr = client->addr, 2542f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .flags = 0, 2552f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .len = 2, 2562f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .buf = data, 2572f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik }; 2582f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 2592f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik ret = i2c_transfer(client->adapter, &msg, 1); 2602f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik udelay(100); 2612f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 2622f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (ret < 0) { 2632f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_err(&client->dev, "Failed writing register 0x%02x!\n", reg); 2642f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return ret; 2652f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } 2662f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return 0; 2672f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik} 2682f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 2692f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 2702f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik/* Read a register, alter its bits, write it back */ 2712f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic int ov6650_reg_rmw(struct i2c_client *client, u8 reg, u8 set, u8 mask) 2722f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik{ 2732f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik u8 val; 2742f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik int ret; 2752f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 2762f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik ret = ov6650_reg_read(client, reg, &val); 2772f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (ret) { 2782f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_err(&client->dev, 2792f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik "[Read]-Modify-Write of register 0x%02x failed!\n", 2802f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik reg); 2812f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return ret; 2822f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } 2832f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 2842f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik val &= ~mask; 2852f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik val |= set; 2862f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 2872f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik ret = ov6650_reg_write(client, reg, val); 2882f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (ret) 2892f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_err(&client->dev, 2902f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik "Read-Modify-[Write] of register 0x%02x failed!\n", 2912f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik reg); 2922f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 2932f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return ret; 2942f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik} 2952f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 2962f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic struct ov6650 *to_ov6650(const struct i2c_client *client) 2972f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik{ 2982f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return container_of(i2c_get_clientdata(client), struct ov6650, subdev); 2992f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik} 3002f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 3012f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik/* Start/Stop streaming from the device */ 3022f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic int ov6650_s_stream(struct v4l2_subdev *sd, int enable) 3032f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik{ 3042f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return 0; 3052f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik} 3062f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 3072f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik/* Get status of additional camera capabilities */ 308afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuilstatic int ov6550_g_volatile_ctrl(struct v4l2_ctrl *ctrl) 3092f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik{ 310afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil struct ov6650 *priv = container_of(ctrl->handler, struct ov6650, hdl); 311afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil struct v4l2_subdev *sd = &priv->subdev; 3122f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct i2c_client *client = v4l2_get_subdevdata(sd); 313afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil uint8_t reg, reg2; 3142e56d933fd967a72d5ee4250e1cb6f9de29d936fJanusz Krzysztofik int ret; 3152f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 3162f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik switch (ctrl->id) { 3172f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik case V4L2_CID_AUTOGAIN: 318afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil ret = ov6650_reg_read(client, REG_GAIN, ®); 319afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil if (!ret) 320afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil priv->gain->val = reg; 321afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil return ret; 3222f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik case V4L2_CID_AUTO_WHITE_BALANCE: 323afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil ret = ov6650_reg_read(client, REG_BLUE, ®); 324afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil if (!ret) 325afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil ret = ov6650_reg_read(client, REG_RED, ®2); 326afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil if (!ret) { 327afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil priv->blue->val = reg; 328afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil priv->red->val = reg2; 3292f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } 330afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil return ret; 3312f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik case V4L2_CID_EXPOSURE_AUTO: 332afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil ret = ov6650_reg_read(client, REG_AECH, ®); 333afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil if (!ret) 334afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil priv->exposure->val = reg; 335afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil return ret; 3362f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } 337afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil return -EINVAL; 3382f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik} 3392f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 3402f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik/* Set status of additional camera capabilities */ 341afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuilstatic int ov6550_s_ctrl(struct v4l2_ctrl *ctrl) 3422f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik{ 343afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil struct ov6650 *priv = container_of(ctrl->handler, struct ov6650, hdl); 344afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil struct v4l2_subdev *sd = &priv->subdev; 3452f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct i2c_client *client = v4l2_get_subdevdata(sd); 3462e56d933fd967a72d5ee4250e1cb6f9de29d936fJanusz Krzysztofik int ret; 3472f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 3482f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik switch (ctrl->id) { 3492f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik case V4L2_CID_AUTOGAIN: 3502f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik ret = ov6650_reg_rmw(client, REG_COMB, 351afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil ctrl->val ? COMB_AGC : 0, COMB_AGC); 352afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil if (!ret && !ctrl->val) 353afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil ret = ov6650_reg_write(client, REG_GAIN, priv->gain->val); 354afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil return ret; 3552f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik case V4L2_CID_AUTO_WHITE_BALANCE: 3562f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik ret = ov6650_reg_rmw(client, REG_COMB, 357afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil ctrl->val ? COMB_AWB : 0, COMB_AWB); 358afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil if (!ret && !ctrl->val) { 359afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil ret = ov6650_reg_write(client, REG_BLUE, priv->blue->val); 360afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil if (!ret) 361afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil ret = ov6650_reg_write(client, REG_RED, 362afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil priv->red->val); 363afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil } 364afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil return ret; 3652f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik case V4L2_CID_SATURATION: 366afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil return ov6650_reg_rmw(client, REG_SAT, SET_SAT(ctrl->val), 3672f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik SAT_MASK); 3682f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik case V4L2_CID_HUE: 369afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil return ov6650_reg_rmw(client, REG_HUE, SET_HUE(ctrl->val), 3702f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik HUE_MASK); 3712f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik case V4L2_CID_BRIGHTNESS: 372afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil return ov6650_reg_write(client, REG_BRT, ctrl->val); 3732f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik case V4L2_CID_EXPOSURE_AUTO: 3742e56d933fd967a72d5ee4250e1cb6f9de29d936fJanusz Krzysztofik ret = ov6650_reg_rmw(client, REG_COMB, ctrl->val == 3752e56d933fd967a72d5ee4250e1cb6f9de29d936fJanusz Krzysztofik V4L2_EXPOSURE_AUTO ? COMB_AEC : 0, COMB_AEC); 376afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL) 377afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil ret = ov6650_reg_write(client, REG_AECH, 378afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil priv->exposure->val); 379afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil return ret; 3802f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik case V4L2_CID_GAMMA: 381afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil return ov6650_reg_write(client, REG_GAM1, ctrl->val); 3822f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik case V4L2_CID_VFLIP: 383afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil return ov6650_reg_rmw(client, REG_COMB, 384afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil ctrl->val ? COMB_FLIP_V : 0, COMB_FLIP_V); 3852f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik case V4L2_CID_HFLIP: 386afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil return ov6650_reg_rmw(client, REG_COMB, 387afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil ctrl->val ? COMB_FLIP_H : 0, COMB_FLIP_H); 3882f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } 3892f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 390afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil return -EINVAL; 3912f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik} 3922f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 3932f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik/* Get chip identification */ 3942f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic int ov6650_g_chip_ident(struct v4l2_subdev *sd, 3952f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct v4l2_dbg_chip_ident *id) 3962f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik{ 3972f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik id->ident = V4L2_IDENT_OV6650; 3982f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik id->revision = 0; 3992f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 4002f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return 0; 4012f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik} 4022f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 4032f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#ifdef CONFIG_VIDEO_ADV_DEBUG 4042f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic int ov6650_get_register(struct v4l2_subdev *sd, 4052f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct v4l2_dbg_register *reg) 4062f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik{ 4072f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct i2c_client *client = v4l2_get_subdevdata(sd); 4082f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik int ret; 4092f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik u8 val; 4102f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 4112f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (reg->reg & ~0xff) 4122f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return -EINVAL; 4132f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 4142f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik reg->size = 1; 4152f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 4162f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik ret = ov6650_reg_read(client, reg->reg, &val); 4172f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (!ret) 4182f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik reg->val = (__u64)val; 4192f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 4202f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return ret; 4212f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik} 4222f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 4232f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic int ov6650_set_register(struct v4l2_subdev *sd, 4242f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct v4l2_dbg_register *reg) 4252f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik{ 4262f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct i2c_client *client = v4l2_get_subdevdata(sd); 4272f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 4282f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (reg->reg & ~0xff || reg->val & ~0xff) 4292f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return -EINVAL; 4302f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 4312f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return ov6650_reg_write(client, reg->reg, reg->val); 4322f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik} 4332f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#endif 4342f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 4352f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic int ov6650_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) 4362f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik{ 4372f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct i2c_client *client = v4l2_get_subdevdata(sd); 4382f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct ov6650 *priv = to_ov6650(client); 4392f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 4402f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 4412f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik a->c = priv->rect; 4422f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 4432f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return 0; 4442f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik} 4452f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 4462f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic int ov6650_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) 4472f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik{ 4482f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct i2c_client *client = v4l2_get_subdevdata(sd); 4492f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct ov6650 *priv = to_ov6650(client); 4502f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct v4l2_rect *rect = &a->c; 4512f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik int ret; 4522f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 4532f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 4542f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return -EINVAL; 4552f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 4562f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik rect->left = ALIGN(rect->left, 2); 4572f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik rect->width = ALIGN(rect->width, 2); 4582f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik rect->top = ALIGN(rect->top, 2); 4592f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik rect->height = ALIGN(rect->height, 2); 4602f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik soc_camera_limit_side(&rect->left, &rect->width, 4612f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik DEF_HSTRT << 1, 2, W_CIF); 4622f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik soc_camera_limit_side(&rect->top, &rect->height, 4632f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik DEF_VSTRT << 1, 2, H_CIF); 4642f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 4652f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik ret = ov6650_reg_write(client, REG_HSTRT, rect->left >> 1); 4662f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (!ret) { 4672f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik priv->rect.left = rect->left; 4682f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik ret = ov6650_reg_write(client, REG_HSTOP, 4692f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik (rect->left + rect->width) >> 1); 4702f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } 4712f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (!ret) { 4722f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik priv->rect.width = rect->width; 4732f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik ret = ov6650_reg_write(client, REG_VSTRT, rect->top >> 1); 4742f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } 4752f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (!ret) { 4762f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik priv->rect.top = rect->top; 4772f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik ret = ov6650_reg_write(client, REG_VSTOP, 4782f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik (rect->top + rect->height) >> 1); 4792f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } 4802f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (!ret) 4812f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik priv->rect.height = rect->height; 4822f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 4832f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return ret; 4842f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik} 4852f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 4862f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic int ov6650_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) 4872f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik{ 4882f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 4892f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return -EINVAL; 4902f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 4912f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik a->bounds.left = DEF_HSTRT << 1; 4922f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik a->bounds.top = DEF_VSTRT << 1; 4932f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik a->bounds.width = W_CIF; 4942f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik a->bounds.height = H_CIF; 4952f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik a->defrect = a->bounds; 4962f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik a->pixelaspect.numerator = 1; 4972f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik a->pixelaspect.denominator = 1; 4982f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 4992f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return 0; 5002f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik} 5012f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 5022f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic int ov6650_g_fmt(struct v4l2_subdev *sd, 5032f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct v4l2_mbus_framefmt *mf) 5042f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik{ 5052f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct i2c_client *client = v4l2_get_subdevdata(sd); 5062f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct ov6650 *priv = to_ov6650(client); 5072f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 5082f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik mf->width = priv->rect.width >> priv->half_scale; 5092f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik mf->height = priv->rect.height >> priv->half_scale; 5102f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik mf->code = priv->code; 5112f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik mf->colorspace = priv->colorspace; 5122f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik mf->field = V4L2_FIELD_NONE; 5132f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 5142f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return 0; 5152f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik} 5162f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 5172f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic bool is_unscaled_ok(int width, int height, struct v4l2_rect *rect) 5182f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik{ 519d889eb1e0e371c15c24bd5c46dd2b18d5e3694e5Janusz Krzysztofik return width > rect->width >> 1 || height > rect->height >> 1; 5202f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik} 5212f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 5222f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic u8 to_clkrc(struct v4l2_fract *timeperframe, 5232f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik unsigned long pclk_limit, unsigned long pclk_max) 5242f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik{ 5252f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik unsigned long pclk; 5262f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 5272f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (timeperframe->numerator && timeperframe->denominator) 5282f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik pclk = pclk_max * timeperframe->denominator / 5292f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik (FRAME_RATE_MAX * timeperframe->numerator); 5302f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik else 5312f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik pclk = pclk_max; 5322f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 5332f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (pclk_limit && pclk_limit < pclk) 5342f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik pclk = pclk_limit; 5352f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 5362f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return (pclk_max - 1) / pclk; 5372f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik} 5382f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 5392f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik/* set the format we will capture in */ 5402f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) 5412f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik{ 5422f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct i2c_client *client = v4l2_get_subdevdata(sd); 5434c0b036db808054f10f79e9a3d7928cf90aeb186Guennadi Liakhovetski struct soc_camera_device *icd = v4l2_get_subdev_hostdata(sd); 5442f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct soc_camera_sense *sense = icd->sense; 5452f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct ov6650 *priv = to_ov6650(client); 5462f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik bool half_scale = !is_unscaled_ok(mf->width, mf->height, &priv->rect); 5472f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct v4l2_crop a = { 5482f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, 5492f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .c = { 5502f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .left = priv->rect.left + (priv->rect.width >> 1) - 5512f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik (mf->width >> (1 - half_scale)), 5522f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .top = priv->rect.top + (priv->rect.height >> 1) - 5532f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik (mf->height >> (1 - half_scale)), 5542f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .width = mf->width << half_scale, 5552f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .height = mf->height << half_scale, 5562f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik }, 5572f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik }; 5582f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik enum v4l2_mbus_pixelcode code = mf->code; 5592f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik unsigned long mclk, pclk; 5602f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik u8 coma_set = 0, coma_mask = 0, coml_set, coml_mask, clkrc; 5612f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik int ret; 5622f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 5632f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik /* select color matrix configuration for given color encoding */ 5642f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik switch (code) { 565076704332ca6da550cbc279918ef8b88b4ac1e45Laurent Pinchart case V4L2_MBUS_FMT_Y8_1X8: 5662f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_dbg(&client->dev, "pixel format GREY8_1X8\n"); 5672f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik coma_mask |= COMA_RGB | COMA_WORD_SWAP | COMA_BYTE_SWAP; 5682f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik coma_set |= COMA_BW; 5692f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik break; 5702f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik case V4L2_MBUS_FMT_YUYV8_2X8: 5712f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_dbg(&client->dev, "pixel format YUYV8_2X8_LE\n"); 5722f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik coma_mask |= COMA_RGB | COMA_BW | COMA_BYTE_SWAP; 5732f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik coma_set |= COMA_WORD_SWAP; 5742f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik break; 5752f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik case V4L2_MBUS_FMT_YVYU8_2X8: 5762f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_dbg(&client->dev, "pixel format YVYU8_2X8_LE (untested)\n"); 5772f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP | 5782f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik COMA_BYTE_SWAP; 5792f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik break; 5802f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik case V4L2_MBUS_FMT_UYVY8_2X8: 5812f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_dbg(&client->dev, "pixel format YUYV8_2X8_BE\n"); 5822f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (half_scale) { 5832f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP; 5842f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik coma_set |= COMA_BYTE_SWAP; 5852f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } else { 5862f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik coma_mask |= COMA_RGB | COMA_BW; 5872f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik coma_set |= COMA_BYTE_SWAP | COMA_WORD_SWAP; 5882f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } 5892f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik break; 5902f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik case V4L2_MBUS_FMT_VYUY8_2X8: 5912f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_dbg(&client->dev, "pixel format YVYU8_2X8_BE (untested)\n"); 5922f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (half_scale) { 5932f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik coma_mask |= COMA_RGB | COMA_BW; 5942f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik coma_set |= COMA_BYTE_SWAP | COMA_WORD_SWAP; 5952f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } else { 5962f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP; 5972f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik coma_set |= COMA_BYTE_SWAP; 5982f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } 5992f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik break; 6002f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik case V4L2_MBUS_FMT_SBGGR8_1X8: 6012f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_dbg(&client->dev, "pixel format SBGGR8_1X8 (untested)\n"); 6022f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik coma_mask |= COMA_BW | COMA_BYTE_SWAP | COMA_WORD_SWAP; 6032f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik coma_set |= COMA_RAW_RGB | COMA_RGB; 6042f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik break; 6052f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik default: 6062f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_err(&client->dev, "Pixel format not handled: 0x%x\n", code); 6072f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return -EINVAL; 6082f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } 6092f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik priv->code = code; 6102f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 611076704332ca6da550cbc279918ef8b88b4ac1e45Laurent Pinchart if (code == V4L2_MBUS_FMT_Y8_1X8 || 6122f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik code == V4L2_MBUS_FMT_SBGGR8_1X8) { 6132f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik coml_mask = COML_ONE_CHANNEL; 6142f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik coml_set = 0; 6152f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik priv->pclk_max = 4000000; 6162f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } else { 6172f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik coml_mask = 0; 6182f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik coml_set = COML_ONE_CHANNEL; 6192f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik priv->pclk_max = 8000000; 6202f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } 6212f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 6222f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (code == V4L2_MBUS_FMT_SBGGR8_1X8) 6232f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik priv->colorspace = V4L2_COLORSPACE_SRGB; 6242f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik else if (code != 0) 6252f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik priv->colorspace = V4L2_COLORSPACE_JPEG; 6262f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 6272f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (half_scale) { 6282f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_dbg(&client->dev, "max resolution: QCIF\n"); 6292f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik coma_set |= COMA_QCIF; 6302f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik priv->pclk_max /= 2; 6312f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } else { 6322f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_dbg(&client->dev, "max resolution: CIF\n"); 6332f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik coma_mask |= COMA_QCIF; 6342f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } 6352f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik priv->half_scale = half_scale; 6362f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 6372f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (sense) { 6382f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (sense->master_clock == 8000000) { 6392f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_dbg(&client->dev, "8MHz input clock\n"); 6402f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik clkrc = CLKRC_6MHz; 6412f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } else if (sense->master_clock == 12000000) { 6422f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_dbg(&client->dev, "12MHz input clock\n"); 6432f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik clkrc = CLKRC_12MHz; 6442f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } else if (sense->master_clock == 16000000) { 6452f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_dbg(&client->dev, "16MHz input clock\n"); 6462f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik clkrc = CLKRC_16MHz; 6472f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } else if (sense->master_clock == 24000000) { 6482f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_dbg(&client->dev, "24MHz input clock\n"); 6492f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik clkrc = CLKRC_24MHz; 6502f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } else { 6512f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_err(&client->dev, 6526d73d072fce26567a0e3da5eb86499de9142ffc1Masanari Iida "unsupported input clock, check platform data\n"); 6532f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return -EINVAL; 6542f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } 6552f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik mclk = sense->master_clock; 6562f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik priv->pclk_limit = sense->pixel_clock_max; 6572f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } else { 6582f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik clkrc = CLKRC_24MHz; 6592f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik mclk = 24000000; 6602f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik priv->pclk_limit = 0; 6612f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_dbg(&client->dev, "using default 24MHz input clock\n"); 6622f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } 6632f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 6642f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik clkrc |= to_clkrc(&priv->tpf, priv->pclk_limit, priv->pclk_max); 6652f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 6662f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik pclk = priv->pclk_max / GET_CLKRC_DIV(clkrc); 6672f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_dbg(&client->dev, "pixel clock divider: %ld.%ld\n", 6682f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik mclk / pclk, 10 * mclk % pclk / pclk); 6692f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 6702f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik ret = ov6650_s_crop(sd, &a); 6712f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (!ret) 6722f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik ret = ov6650_reg_rmw(client, REG_COMA, coma_set, coma_mask); 6732f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (!ret) 6742f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik ret = ov6650_reg_write(client, REG_CLKRC, clkrc); 6752f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (!ret) 6762f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik ret = ov6650_reg_rmw(client, REG_COML, coml_set, coml_mask); 6772f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 6782f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (!ret) { 6792f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik mf->colorspace = priv->colorspace; 6802f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik mf->width = priv->rect.width >> half_scale; 6812f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik mf->height = priv->rect.height >> half_scale; 6822f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } 6832f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 6842f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return ret; 6852f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik} 6862f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 6872f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic int ov6650_try_fmt(struct v4l2_subdev *sd, 6882f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct v4l2_mbus_framefmt *mf) 6892f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik{ 6902f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct i2c_client *client = v4l2_get_subdevdata(sd); 6912f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct ov6650 *priv = to_ov6650(client); 6922f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 6932f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (is_unscaled_ok(mf->width, mf->height, &priv->rect)) 6942f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik v4l_bound_align_image(&mf->width, 2, W_CIF, 1, 6952f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik &mf->height, 2, H_CIF, 1, 0); 6962f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 6972f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik mf->field = V4L2_FIELD_NONE; 6982f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 6992f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik switch (mf->code) { 7002f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik case V4L2_MBUS_FMT_Y10_1X10: 701076704332ca6da550cbc279918ef8b88b4ac1e45Laurent Pinchart mf->code = V4L2_MBUS_FMT_Y8_1X8; 702076704332ca6da550cbc279918ef8b88b4ac1e45Laurent Pinchart case V4L2_MBUS_FMT_Y8_1X8: 7032f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik case V4L2_MBUS_FMT_YVYU8_2X8: 7042f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik case V4L2_MBUS_FMT_YUYV8_2X8: 7052f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik case V4L2_MBUS_FMT_VYUY8_2X8: 7062f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik case V4L2_MBUS_FMT_UYVY8_2X8: 7072f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik mf->colorspace = V4L2_COLORSPACE_JPEG; 7082f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik break; 7092f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik default: 7102f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik mf->code = V4L2_MBUS_FMT_SBGGR8_1X8; 7112f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik case V4L2_MBUS_FMT_SBGGR8_1X8: 7122f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik mf->colorspace = V4L2_COLORSPACE_SRGB; 7132f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik break; 7142f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } 7152f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 7162f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return 0; 7172f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik} 7182f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 7192f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic int ov6650_enum_fmt(struct v4l2_subdev *sd, unsigned int index, 7202f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik enum v4l2_mbus_pixelcode *code) 7212f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik{ 7222f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (index >= ARRAY_SIZE(ov6650_codes)) 7232f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return -EINVAL; 7242f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 7252f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik *code = ov6650_codes[index]; 7262f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return 0; 7272f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik} 7282f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 7292f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic int ov6650_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) 7302f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik{ 7312f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct i2c_client *client = v4l2_get_subdevdata(sd); 7322f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct ov6650 *priv = to_ov6650(client); 7332f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct v4l2_captureparm *cp = &parms->parm.capture; 7342f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 7352f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 7362f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return -EINVAL; 7372f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 7382f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik memset(cp, 0, sizeof(*cp)); 7392f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik cp->capability = V4L2_CAP_TIMEPERFRAME; 7402f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik cp->timeperframe.numerator = GET_CLKRC_DIV(to_clkrc(&priv->tpf, 7412f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik priv->pclk_limit, priv->pclk_max)); 7422f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik cp->timeperframe.denominator = FRAME_RATE_MAX; 7432f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 7442f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_dbg(&client->dev, "Frame interval: %u/%u s\n", 7452f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik cp->timeperframe.numerator, cp->timeperframe.denominator); 7462f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 7472f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return 0; 7482f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik} 7492f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 7502f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic int ov6650_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) 7512f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik{ 7522f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct i2c_client *client = v4l2_get_subdevdata(sd); 7532f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct ov6650 *priv = to_ov6650(client); 7542f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct v4l2_captureparm *cp = &parms->parm.capture; 7552f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct v4l2_fract *tpf = &cp->timeperframe; 7562f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik int div, ret; 7572f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik u8 clkrc; 7582f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 7592f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 7602f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return -EINVAL; 7612f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 7622f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (cp->extendedmode != 0) 7632f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return -EINVAL; 7642f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 7652f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (tpf->numerator == 0 || tpf->denominator == 0) 7662f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik div = 1; /* Reset to full rate */ 7672f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik else 7682f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik div = (tpf->numerator * FRAME_RATE_MAX) / tpf->denominator; 7692f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 7702f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (div == 0) 7712f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik div = 1; 7722f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik else if (div > GET_CLKRC_DIV(CLKRC_DIV_MASK)) 7732f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik div = GET_CLKRC_DIV(CLKRC_DIV_MASK); 7742f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 7752f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik /* 7762f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * Keep result to be used as tpf limit 7772f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * for subseqent clock divider calculations 7782f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik */ 7792f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik priv->tpf.numerator = div; 7802f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik priv->tpf.denominator = FRAME_RATE_MAX; 7812f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 7822f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik clkrc = to_clkrc(&priv->tpf, priv->pclk_limit, priv->pclk_max); 7832f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 7842f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik ret = ov6650_reg_rmw(client, REG_CLKRC, clkrc, CLKRC_DIV_MASK); 7852f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (!ret) { 7862f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik tpf->numerator = GET_CLKRC_DIV(clkrc); 7872f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik tpf->denominator = FRAME_RATE_MAX; 7882f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } 7892f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 7902f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return ret; 7912f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik} 7922f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 7932f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik/* Soft reset the camera. This has nothing to do with the RESET pin! */ 7942f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic int ov6650_reset(struct i2c_client *client) 7952f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik{ 7962f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik int ret; 7972f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 7982f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_dbg(&client->dev, "reset\n"); 7992f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 8002f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik ret = ov6650_reg_rmw(client, REG_COMA, COMA_RESET, 0); 8012f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (ret) 8022f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_err(&client->dev, 80325985edcedea6396277003854657b5f3cb31a628Lucas De Marchi "An error occurred while entering soft reset!\n"); 8042f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 8052f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return ret; 8062f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik} 8072f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 8082f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik/* program default register values */ 8092f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic int ov6650_prog_dflt(struct i2c_client *client) 8102f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik{ 8112f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik int ret; 8122f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 8132f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_dbg(&client->dev, "initializing\n"); 8142f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 8152f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik ret = ov6650_reg_write(client, REG_COMA, 0); /* ~COMA_RESET */ 8162f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (!ret) 8172f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_BAND_FILTER); 8182f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 8192f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return ret; 8202f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik} 8212f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 82214178aa57ce6ac4f05b4df8ea9e010486ce83a76Guennadi Liakhovetskistatic int ov6650_video_probe(struct i2c_client *client) 8232f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik{ 8242f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik u8 pidh, pidl, midh, midl; 8252f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik int ret = 0; 8262f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 8272f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik /* 8282f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * check and show product ID and manufacturer ID 8292f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik */ 8302f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik ret = ov6650_reg_read(client, REG_PIDH, &pidh); 8312f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (!ret) 8322f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik ret = ov6650_reg_read(client, REG_PIDL, &pidl); 8332f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (!ret) 8342f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik ret = ov6650_reg_read(client, REG_MIDH, &midh); 8352f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (!ret) 8362f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik ret = ov6650_reg_read(client, REG_MIDL, &midl); 8372f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 8382f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (ret) 8392f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return ret; 8402f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 8412f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if ((pidh != OV6650_PIDH) || (pidl != OV6650_PIDL)) { 8422f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_err(&client->dev, "Product ID error 0x%02x:0x%02x\n", 8432f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik pidh, pidl); 8442f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return -ENODEV; 8452f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } 8462f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 8472f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_info(&client->dev, 8482f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik "ov6650 Product ID 0x%02x:0x%02x Manufacturer ID 0x%02x:0x%02x\n", 8492f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik pidh, pidl, midh, midl); 8502f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 8512f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik ret = ov6650_reset(client); 8522f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (!ret) 8532f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik ret = ov6650_prog_dflt(client); 8542f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 8552f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return ret; 8562f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik} 8572f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 858afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuilstatic const struct v4l2_ctrl_ops ov6550_ctrl_ops = { 859afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil .g_volatile_ctrl = ov6550_g_volatile_ctrl, 860afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil .s_ctrl = ov6550_s_ctrl, 8612f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik}; 8622f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 8632f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic struct v4l2_subdev_core_ops ov6650_core_ops = { 8642f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .g_chip_ident = ov6650_g_chip_ident, 8652f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#ifdef CONFIG_VIDEO_ADV_DEBUG 8662f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .g_register = ov6650_get_register, 8672f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .s_register = ov6650_set_register, 8682f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik#endif 8692f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik}; 8702f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 871db669e79ed27b7842d1d3495836238fb46e29769Guennadi Liakhovetski/* Request bus settings on camera side */ 87259ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetskistatic int ov6650_g_mbus_config(struct v4l2_subdev *sd, 87359ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski struct v4l2_mbus_config *cfg) 87459ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski{ 87559ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski struct i2c_client *client = v4l2_get_subdevdata(sd); 87614178aa57ce6ac4f05b4df8ea9e010486ce83a76Guennadi Liakhovetski struct soc_camera_link *icl = soc_camera_i2c_to_link(client); 87759ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski 87859ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski cfg->flags = V4L2_MBUS_MASTER | 87959ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | 88059ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW | 88159ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | 88259ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski V4L2_MBUS_DATA_ACTIVE_HIGH; 88359ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski cfg->type = V4L2_MBUS_PARALLEL; 88459ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski cfg->flags = soc_camera_apply_board_flags(icl, cfg); 88559ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski 88659ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski return 0; 88759ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski} 88859ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski 889db669e79ed27b7842d1d3495836238fb46e29769Guennadi Liakhovetski/* Alter bus settings on camera side */ 89059ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetskistatic int ov6650_s_mbus_config(struct v4l2_subdev *sd, 89159ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski const struct v4l2_mbus_config *cfg) 89259ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski{ 89359ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski struct i2c_client *client = v4l2_get_subdevdata(sd); 89414178aa57ce6ac4f05b4df8ea9e010486ce83a76Guennadi Liakhovetski struct soc_camera_link *icl = soc_camera_i2c_to_link(client); 89559ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski unsigned long flags = soc_camera_apply_board_flags(icl, cfg); 89659ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski int ret; 89759ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski 89859ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) 89959ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_PCLK_RISING, 0); 90059ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski else 90159ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_PCLK_RISING); 90259ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski if (ret) 90359ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski return ret; 90459ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski 90559ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) 90659ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski ret = ov6650_reg_rmw(client, REG_COMF, COMF_HREF_LOW, 0); 90759ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski else 90859ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski ret = ov6650_reg_rmw(client, REG_COMF, 0, COMF_HREF_LOW); 90959ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski if (ret) 91059ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski return ret; 91159ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski 91259ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski if (flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) 91359ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_VSYNC_HIGH, 0); 91459ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski else 91559ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_VSYNC_HIGH); 91659ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski 91759ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski return ret; 91859ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski} 91959ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski 9202f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic struct v4l2_subdev_video_ops ov6650_video_ops = { 9212f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .s_stream = ov6650_s_stream, 9222f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .g_mbus_fmt = ov6650_g_fmt, 9232f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .s_mbus_fmt = ov6650_s_fmt, 9242f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .try_mbus_fmt = ov6650_try_fmt, 9252f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .enum_mbus_fmt = ov6650_enum_fmt, 9262f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .cropcap = ov6650_cropcap, 9272f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .g_crop = ov6650_g_crop, 9282f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .s_crop = ov6650_s_crop, 9292f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .g_parm = ov6650_g_parm, 9302f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .s_parm = ov6650_s_parm, 93159ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski .g_mbus_config = ov6650_g_mbus_config, 93259ca25b7eb8f6675be94ec18beb8eb66293f550dGuennadi Liakhovetski .s_mbus_config = ov6650_s_mbus_config, 9332f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik}; 9342f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 9352f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic struct v4l2_subdev_ops ov6650_subdev_ops = { 9362f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .core = &ov6650_core_ops, 9372f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .video = &ov6650_video_ops, 9382f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik}; 9392f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 9402f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik/* 9412f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik * i2c_driver function 9422f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik */ 9432f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic int ov6650_probe(struct i2c_client *client, 9442f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik const struct i2c_device_id *did) 9452f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik{ 9462f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct ov6650 *priv; 94714178aa57ce6ac4f05b4df8ea9e010486ce83a76Guennadi Liakhovetski struct soc_camera_link *icl = soc_camera_i2c_to_link(client); 9482f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik int ret; 9492f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 9502f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (!icl) { 9512f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_err(&client->dev, "Missing platform_data for driver\n"); 9522f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return -EINVAL; 9532f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } 9542f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 9552f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik priv = kzalloc(sizeof(*priv), GFP_KERNEL); 9562f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (!priv) { 9572f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik dev_err(&client->dev, 9582f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik "Failed to allocate memory for private data!\n"); 9592f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return -ENOMEM; 9602f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } 9612f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 9622f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik v4l2_i2c_subdev_init(&priv->subdev, client, &ov6650_subdev_ops); 963afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil v4l2_ctrl_handler_init(&priv->hdl, 13); 964afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, 965afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil V4L2_CID_VFLIP, 0, 1, 1, 0); 966afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, 967afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil V4L2_CID_HFLIP, 0, 1, 1, 0); 968afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil priv->autogain = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, 969afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil V4L2_CID_AUTOGAIN, 0, 1, 1, 1); 970afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil priv->gain = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, 971afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil V4L2_CID_GAIN, 0, 0x3f, 1, DEF_GAIN); 972afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil priv->autowb = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, 973afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); 974afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil priv->blue = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, 975afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil V4L2_CID_BLUE_BALANCE, 0, 0xff, 1, DEF_BLUE); 976afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil priv->red = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, 977afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil V4L2_CID_RED_BALANCE, 0, 0xff, 1, DEF_RED); 978afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, 979afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil V4L2_CID_SATURATION, 0, 0xf, 1, 0x8); 980afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, 981afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil V4L2_CID_HUE, 0, HUE_MASK, 1, DEF_HUE); 982afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, 983afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil V4L2_CID_BRIGHTNESS, 0, 0xff, 1, 0x80); 984afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil priv->autoexposure = v4l2_ctrl_new_std_menu(&priv->hdl, 9852e56d933fd967a72d5ee4250e1cb6f9de29d936fJanusz Krzysztofik &ov6550_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 9862e56d933fd967a72d5ee4250e1cb6f9de29d936fJanusz Krzysztofik V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO); 987afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil priv->exposure = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, 988afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil V4L2_CID_EXPOSURE, 0, 0xff, 1, DEF_AECH); 989afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, 990afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil V4L2_CID_GAMMA, 0, 0xff, 1, 0x12); 991afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil 992afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil priv->subdev.ctrl_handler = &priv->hdl; 993afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil if (priv->hdl.error) { 994afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil int err = priv->hdl.error; 9952f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 996afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil kfree(priv); 997afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil return err; 998afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil } 999afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil v4l2_ctrl_auto_cluster(2, &priv->autogain, 0, true); 1000afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil v4l2_ctrl_auto_cluster(3, &priv->autowb, 0, true); 1001afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil v4l2_ctrl_auto_cluster(2, &priv->autoexposure, 1002afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil V4L2_EXPOSURE_MANUAL, true); 10032f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 10042f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik priv->rect.left = DEF_HSTRT << 1; 10052f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik priv->rect.top = DEF_VSTRT << 1; 10062f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik priv->rect.width = W_CIF; 10072f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik priv->rect.height = H_CIF; 10082f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik priv->half_scale = false; 10092f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik priv->code = V4L2_MBUS_FMT_YUYV8_2X8; 10102f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik priv->colorspace = V4L2_COLORSPACE_JPEG; 10112f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 101214178aa57ce6ac4f05b4df8ea9e010486ce83a76Guennadi Liakhovetski ret = ov6650_video_probe(client); 1013afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil if (!ret) 1014afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil ret = v4l2_ctrl_handler_setup(&priv->hdl); 10152f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 10162f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik if (ret) { 1017afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil v4l2_ctrl_handler_free(&priv->hdl); 10182f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik kfree(priv); 10192f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik } 10202f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 10212f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return ret; 10222f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik} 10232f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 10242f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic int ov6650_remove(struct i2c_client *client) 10252f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik{ 10262f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik struct ov6650 *priv = to_ov6650(client); 10272f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 1028afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil v4l2_device_unregister_subdev(&priv->subdev); 1029afd9690c72c3acf77b7f8731b2fcafafd3b7e29eHans Verkuil v4l2_ctrl_handler_free(&priv->hdl); 10302f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik kfree(priv); 10312f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik return 0; 10322f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik} 10332f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 10342f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic const struct i2c_device_id ov6650_id[] = { 10352f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik { "ov6650", 0 }, 10362f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik { } 10372f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik}; 10382f6e2404799ad610317157b73169c109788da0b0Janusz KrzysztofikMODULE_DEVICE_TABLE(i2c, ov6650_id); 10392f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 10402f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofikstatic struct i2c_driver ov6650_i2c_driver = { 10412f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .driver = { 10422f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .name = "ov6650", 10432f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik }, 10442f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .probe = ov6650_probe, 10452f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .remove = ov6650_remove, 10462f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik .id_table = ov6650_id, 10472f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik}; 10482f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 1049c6e8d86fffd8edf1bfccbd441b1812ee919fe3d5Axel Linmodule_i2c_driver(ov6650_i2c_driver); 10502f6e2404799ad610317157b73169c109788da0b0Janusz Krzysztofik 10512f6e2404799ad610317157b73169c109788da0b0Janusz KrzysztofikMODULE_DESCRIPTION("SoC Camera driver for OmniVision OV6650"); 10522f6e2404799ad610317157b73169c109788da0b0Janusz KrzysztofikMODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>"); 10532f6e2404799ad610317157b73169c109788da0b0Janusz KrzysztofikMODULE_LICENSE("GPL v2"); 1054