1202ea1f0SScott Jiang /* 2202ea1f0SScott Jiang * adv7183.c Analog Devices ADV7183 video decoder driver 3202ea1f0SScott Jiang * 4202ea1f0SScott Jiang * Copyright (c) 2011 Analog Devices Inc. 5202ea1f0SScott Jiang * 6202ea1f0SScott Jiang * This program is free software; you can redistribute it and/or modify 7202ea1f0SScott Jiang * it under the terms of the GNU General Public License version 2 as 8202ea1f0SScott Jiang * published by the Free Software Foundation. 9202ea1f0SScott Jiang * 10202ea1f0SScott Jiang * This program is distributed in the hope that it will be useful, 11202ea1f0SScott Jiang * but WITHOUT ANY WARRANTY; without even the implied warranty of 12202ea1f0SScott Jiang * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13202ea1f0SScott Jiang * GNU General Public License for more details. 14202ea1f0SScott Jiang * 15202ea1f0SScott Jiang * You should have received a copy of the GNU General Public License 16202ea1f0SScott Jiang * along with this program; if not, write to the Free Software 17202ea1f0SScott Jiang * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18202ea1f0SScott Jiang */ 19202ea1f0SScott Jiang 20202ea1f0SScott Jiang #include <linux/delay.h> 21202ea1f0SScott Jiang #include <linux/errno.h> 22202ea1f0SScott Jiang #include <linux/gpio.h> 23202ea1f0SScott Jiang #include <linux/i2c.h> 24202ea1f0SScott Jiang #include <linux/init.h> 25202ea1f0SScott Jiang #include <linux/module.h> 26202ea1f0SScott Jiang #include <linux/slab.h> 27202ea1f0SScott Jiang #include <linux/types.h> 28202ea1f0SScott Jiang #include <linux/videodev2.h> 29202ea1f0SScott Jiang 30202ea1f0SScott Jiang #include <media/adv7183.h> 31202ea1f0SScott Jiang #include <media/v4l2-ctrls.h> 32202ea1f0SScott Jiang #include <media/v4l2-device.h> 33202ea1f0SScott Jiang 34202ea1f0SScott Jiang #include "adv7183_regs.h" 35202ea1f0SScott Jiang 36202ea1f0SScott Jiang struct adv7183 { 37202ea1f0SScott Jiang struct v4l2_subdev sd; 38202ea1f0SScott Jiang struct v4l2_ctrl_handler hdl; 39202ea1f0SScott Jiang 40202ea1f0SScott Jiang v4l2_std_id std; /* Current set standard */ 41202ea1f0SScott Jiang u32 input; 42202ea1f0SScott Jiang u32 output; 43202ea1f0SScott Jiang unsigned reset_pin; 44202ea1f0SScott Jiang unsigned oe_pin; 45202ea1f0SScott Jiang struct v4l2_mbus_framefmt fmt; 46202ea1f0SScott Jiang }; 47202ea1f0SScott Jiang 48202ea1f0SScott Jiang /* EXAMPLES USING 27 MHz CLOCK 49202ea1f0SScott Jiang * Mode 1 CVBS Input (Composite Video on AIN5) 50202ea1f0SScott Jiang * All standards are supported through autodetect, 8-bit, 4:2:2, ITU-R BT.656 output on P15 to P8. 51202ea1f0SScott Jiang */ 52202ea1f0SScott Jiang static const unsigned char adv7183_init_regs[] = { 53202ea1f0SScott Jiang ADV7183_IN_CTRL, 0x04, /* CVBS input on AIN5 */ 54202ea1f0SScott Jiang ADV7183_DIGI_CLAMP_CTRL_1, 0x00, /* Slow down digital clamps */ 55202ea1f0SScott Jiang ADV7183_SHAP_FILT_CTRL, 0x41, /* Set CSFM to SH1 */ 56202ea1f0SScott Jiang ADV7183_ADC_CTRL, 0x16, /* Power down ADC 1 and ADC 2 */ 57202ea1f0SScott Jiang ADV7183_CTI_DNR_CTRL_4, 0x04, /* Set DNR threshold to 4 for flat response */ 58202ea1f0SScott Jiang /* ADI recommended programming sequence */ 59202ea1f0SScott Jiang ADV7183_ADI_CTRL, 0x80, 60202ea1f0SScott Jiang ADV7183_CTI_DNR_CTRL_4, 0x20, 61202ea1f0SScott Jiang 0x52, 0x18, 62202ea1f0SScott Jiang 0x58, 0xED, 63202ea1f0SScott Jiang 0x77, 0xC5, 64202ea1f0SScott Jiang 0x7C, 0x93, 65202ea1f0SScott Jiang 0x7D, 0x00, 66202ea1f0SScott Jiang 0xD0, 0x48, 67202ea1f0SScott Jiang 0xD5, 0xA0, 68202ea1f0SScott Jiang 0xD7, 0xEA, 69202ea1f0SScott Jiang ADV7183_SD_SATURATION_CR, 0x3E, 70202ea1f0SScott Jiang ADV7183_PAL_V_END, 0x3E, 71202ea1f0SScott Jiang ADV7183_PAL_F_TOGGLE, 0x0F, 72202ea1f0SScott Jiang ADV7183_ADI_CTRL, 0x00, 73202ea1f0SScott Jiang }; 74202ea1f0SScott Jiang 75202ea1f0SScott Jiang static inline struct adv7183 *to_adv7183(struct v4l2_subdev *sd) 76202ea1f0SScott Jiang { 77202ea1f0SScott Jiang return container_of(sd, struct adv7183, sd); 78202ea1f0SScott Jiang } 79202ea1f0SScott Jiang static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) 80202ea1f0SScott Jiang { 81202ea1f0SScott Jiang return &container_of(ctrl->handler, struct adv7183, hdl)->sd; 82202ea1f0SScott Jiang } 83202ea1f0SScott Jiang 84202ea1f0SScott Jiang static inline int adv7183_read(struct v4l2_subdev *sd, unsigned char reg) 85202ea1f0SScott Jiang { 86202ea1f0SScott Jiang struct i2c_client *client = v4l2_get_subdevdata(sd); 87202ea1f0SScott Jiang 88202ea1f0SScott Jiang return i2c_smbus_read_byte_data(client, reg); 89202ea1f0SScott Jiang } 90202ea1f0SScott Jiang 91202ea1f0SScott Jiang static inline int adv7183_write(struct v4l2_subdev *sd, unsigned char reg, 92202ea1f0SScott Jiang unsigned char value) 93202ea1f0SScott Jiang { 94202ea1f0SScott Jiang struct i2c_client *client = v4l2_get_subdevdata(sd); 95202ea1f0SScott Jiang 96202ea1f0SScott Jiang return i2c_smbus_write_byte_data(client, reg, value); 97202ea1f0SScott Jiang } 98202ea1f0SScott Jiang 99202ea1f0SScott Jiang static int adv7183_writeregs(struct v4l2_subdev *sd, 100202ea1f0SScott Jiang const unsigned char *regs, unsigned int num) 101202ea1f0SScott Jiang { 102202ea1f0SScott Jiang unsigned char reg, data; 103202ea1f0SScott Jiang unsigned int cnt = 0; 104202ea1f0SScott Jiang 105202ea1f0SScott Jiang if (num & 0x1) { 106202ea1f0SScott Jiang v4l2_err(sd, "invalid regs array\n"); 107202ea1f0SScott Jiang return -1; 108202ea1f0SScott Jiang } 109202ea1f0SScott Jiang 110202ea1f0SScott Jiang while (cnt < num) { 111202ea1f0SScott Jiang reg = *regs++; 112202ea1f0SScott Jiang data = *regs++; 113202ea1f0SScott Jiang cnt += 2; 114202ea1f0SScott Jiang 115202ea1f0SScott Jiang adv7183_write(sd, reg, data); 116202ea1f0SScott Jiang } 117202ea1f0SScott Jiang return 0; 118202ea1f0SScott Jiang } 119202ea1f0SScott Jiang 120202ea1f0SScott Jiang static int adv7183_log_status(struct v4l2_subdev *sd) 121202ea1f0SScott Jiang { 122202ea1f0SScott Jiang struct adv7183 *decoder = to_adv7183(sd); 123202ea1f0SScott Jiang 124202ea1f0SScott Jiang v4l2_info(sd, "adv7183: Input control = 0x%02x\n", 125202ea1f0SScott Jiang adv7183_read(sd, ADV7183_IN_CTRL)); 126202ea1f0SScott Jiang v4l2_info(sd, "adv7183: Video selection = 0x%02x\n", 127202ea1f0SScott Jiang adv7183_read(sd, ADV7183_VD_SEL)); 128202ea1f0SScott Jiang v4l2_info(sd, "adv7183: Output control = 0x%02x\n", 129202ea1f0SScott Jiang adv7183_read(sd, ADV7183_OUT_CTRL)); 130202ea1f0SScott Jiang v4l2_info(sd, "adv7183: Extended output control = 0x%02x\n", 131202ea1f0SScott Jiang adv7183_read(sd, ADV7183_EXT_OUT_CTRL)); 132202ea1f0SScott Jiang v4l2_info(sd, "adv7183: Autodetect enable = 0x%02x\n", 133202ea1f0SScott Jiang adv7183_read(sd, ADV7183_AUTO_DET_EN)); 134202ea1f0SScott Jiang v4l2_info(sd, "adv7183: Contrast = 0x%02x\n", 135202ea1f0SScott Jiang adv7183_read(sd, ADV7183_CONTRAST)); 136202ea1f0SScott Jiang v4l2_info(sd, "adv7183: Brightness = 0x%02x\n", 137202ea1f0SScott Jiang adv7183_read(sd, ADV7183_BRIGHTNESS)); 138202ea1f0SScott Jiang v4l2_info(sd, "adv7183: Hue = 0x%02x\n", 139202ea1f0SScott Jiang adv7183_read(sd, ADV7183_HUE)); 140202ea1f0SScott Jiang v4l2_info(sd, "adv7183: Default value Y = 0x%02x\n", 141202ea1f0SScott Jiang adv7183_read(sd, ADV7183_DEF_Y)); 142202ea1f0SScott Jiang v4l2_info(sd, "adv7183: Default value C = 0x%02x\n", 143202ea1f0SScott Jiang adv7183_read(sd, ADV7183_DEF_C)); 144202ea1f0SScott Jiang v4l2_info(sd, "adv7183: ADI control = 0x%02x\n", 145202ea1f0SScott Jiang adv7183_read(sd, ADV7183_ADI_CTRL)); 146202ea1f0SScott Jiang v4l2_info(sd, "adv7183: Power Management = 0x%02x\n", 147202ea1f0SScott Jiang adv7183_read(sd, ADV7183_POW_MANAGE)); 148202ea1f0SScott Jiang v4l2_info(sd, "adv7183: Status 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n", 149202ea1f0SScott Jiang adv7183_read(sd, ADV7183_STATUS_1), 150202ea1f0SScott Jiang adv7183_read(sd, ADV7183_STATUS_2), 151202ea1f0SScott Jiang adv7183_read(sd, ADV7183_STATUS_3)); 152202ea1f0SScott Jiang v4l2_info(sd, "adv7183: Ident = 0x%02x\n", 153202ea1f0SScott Jiang adv7183_read(sd, ADV7183_IDENT)); 154202ea1f0SScott Jiang v4l2_info(sd, "adv7183: Analog clamp control = 0x%02x\n", 155202ea1f0SScott Jiang adv7183_read(sd, ADV7183_ANAL_CLAMP_CTRL)); 156202ea1f0SScott Jiang v4l2_info(sd, "adv7183: Digital clamp control 1 = 0x%02x\n", 157202ea1f0SScott Jiang adv7183_read(sd, ADV7183_DIGI_CLAMP_CTRL_1)); 158202ea1f0SScott Jiang v4l2_info(sd, "adv7183: Shaping filter control 1 and 2 = 0x%02x 0x%02x\n", 159202ea1f0SScott Jiang adv7183_read(sd, ADV7183_SHAP_FILT_CTRL), 160202ea1f0SScott Jiang adv7183_read(sd, ADV7183_SHAP_FILT_CTRL_2)); 161202ea1f0SScott Jiang v4l2_info(sd, "adv7183: Comb filter control = 0x%02x\n", 162202ea1f0SScott Jiang adv7183_read(sd, ADV7183_COMB_FILT_CTRL)); 163202ea1f0SScott Jiang v4l2_info(sd, "adv7183: ADI control 2 = 0x%02x\n", 164202ea1f0SScott Jiang adv7183_read(sd, ADV7183_ADI_CTRL_2)); 165202ea1f0SScott Jiang v4l2_info(sd, "adv7183: Pixel delay control = 0x%02x\n", 166202ea1f0SScott Jiang adv7183_read(sd, ADV7183_PIX_DELAY_CTRL)); 167202ea1f0SScott Jiang v4l2_info(sd, "adv7183: Misc gain control = 0x%02x\n", 168202ea1f0SScott Jiang adv7183_read(sd, ADV7183_MISC_GAIN_CTRL)); 169202ea1f0SScott Jiang v4l2_info(sd, "adv7183: AGC mode control = 0x%02x\n", 170202ea1f0SScott Jiang adv7183_read(sd, ADV7183_AGC_MODE_CTRL)); 171202ea1f0SScott Jiang v4l2_info(sd, "adv7183: Chroma gain control 1 and 2 = 0x%02x 0x%02x\n", 172202ea1f0SScott Jiang adv7183_read(sd, ADV7183_CHRO_GAIN_CTRL_1), 173202ea1f0SScott Jiang adv7183_read(sd, ADV7183_CHRO_GAIN_CTRL_2)); 174202ea1f0SScott Jiang v4l2_info(sd, "adv7183: Luma gain control 1 and 2 = 0x%02x 0x%02x\n", 175202ea1f0SScott Jiang adv7183_read(sd, ADV7183_LUMA_GAIN_CTRL_1), 176202ea1f0SScott Jiang adv7183_read(sd, ADV7183_LUMA_GAIN_CTRL_2)); 177202ea1f0SScott Jiang v4l2_info(sd, "adv7183: Vsync field control 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n", 178202ea1f0SScott Jiang adv7183_read(sd, ADV7183_VS_FIELD_CTRL_1), 179202ea1f0SScott Jiang adv7183_read(sd, ADV7183_VS_FIELD_CTRL_2), 180202ea1f0SScott Jiang adv7183_read(sd, ADV7183_VS_FIELD_CTRL_3)); 181*6d3be300SMasanari Iida v4l2_info(sd, "adv7183: Hsync position control 1 2 and 3 = 0x%02x 0x%02x 0x%02x\n", 182202ea1f0SScott Jiang adv7183_read(sd, ADV7183_HS_POS_CTRL_1), 183202ea1f0SScott Jiang adv7183_read(sd, ADV7183_HS_POS_CTRL_2), 184202ea1f0SScott Jiang adv7183_read(sd, ADV7183_HS_POS_CTRL_3)); 185202ea1f0SScott Jiang v4l2_info(sd, "adv7183: Polarity = 0x%02x\n", 186202ea1f0SScott Jiang adv7183_read(sd, ADV7183_POLARITY)); 187202ea1f0SScott Jiang v4l2_info(sd, "adv7183: ADC control = 0x%02x\n", 188202ea1f0SScott Jiang adv7183_read(sd, ADV7183_ADC_CTRL)); 189202ea1f0SScott Jiang v4l2_info(sd, "adv7183: SD offset Cb and Cr = 0x%02x 0x%02x\n", 190202ea1f0SScott Jiang adv7183_read(sd, ADV7183_SD_OFFSET_CB), 191202ea1f0SScott Jiang adv7183_read(sd, ADV7183_SD_OFFSET_CR)); 192202ea1f0SScott Jiang v4l2_info(sd, "adv7183: SD saturation Cb and Cr = 0x%02x 0x%02x\n", 193202ea1f0SScott Jiang adv7183_read(sd, ADV7183_SD_SATURATION_CB), 194202ea1f0SScott Jiang adv7183_read(sd, ADV7183_SD_SATURATION_CR)); 195202ea1f0SScott Jiang v4l2_info(sd, "adv7183: Drive strength = 0x%02x\n", 196202ea1f0SScott Jiang adv7183_read(sd, ADV7183_DRIVE_STR)); 197202ea1f0SScott Jiang v4l2_ctrl_handler_log_status(&decoder->hdl, sd->name); 198202ea1f0SScott Jiang return 0; 199202ea1f0SScott Jiang } 200202ea1f0SScott Jiang 201202ea1f0SScott Jiang static int adv7183_g_std(struct v4l2_subdev *sd, v4l2_std_id *std) 202202ea1f0SScott Jiang { 203202ea1f0SScott Jiang struct adv7183 *decoder = to_adv7183(sd); 204202ea1f0SScott Jiang 205202ea1f0SScott Jiang *std = decoder->std; 206202ea1f0SScott Jiang return 0; 207202ea1f0SScott Jiang } 208202ea1f0SScott Jiang 209202ea1f0SScott Jiang static int adv7183_s_std(struct v4l2_subdev *sd, v4l2_std_id std) 210202ea1f0SScott Jiang { 211202ea1f0SScott Jiang struct adv7183 *decoder = to_adv7183(sd); 212202ea1f0SScott Jiang int reg; 213202ea1f0SScott Jiang 214202ea1f0SScott Jiang reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF; 215202ea1f0SScott Jiang if (std == V4L2_STD_PAL_60) 216202ea1f0SScott Jiang reg |= 0x60; 217202ea1f0SScott Jiang else if (std == V4L2_STD_NTSC_443) 218202ea1f0SScott Jiang reg |= 0x70; 219202ea1f0SScott Jiang else if (std == V4L2_STD_PAL_N) 220202ea1f0SScott Jiang reg |= 0x90; 221202ea1f0SScott Jiang else if (std == V4L2_STD_PAL_M) 222202ea1f0SScott Jiang reg |= 0xA0; 223202ea1f0SScott Jiang else if (std == V4L2_STD_PAL_Nc) 224202ea1f0SScott Jiang reg |= 0xC0; 225202ea1f0SScott Jiang else if (std & V4L2_STD_PAL) 226202ea1f0SScott Jiang reg |= 0x80; 227202ea1f0SScott Jiang else if (std & V4L2_STD_NTSC) 228202ea1f0SScott Jiang reg |= 0x50; 229202ea1f0SScott Jiang else if (std & V4L2_STD_SECAM) 230202ea1f0SScott Jiang reg |= 0xE0; 231202ea1f0SScott Jiang else 232202ea1f0SScott Jiang return -EINVAL; 233202ea1f0SScott Jiang adv7183_write(sd, ADV7183_IN_CTRL, reg); 234202ea1f0SScott Jiang 235202ea1f0SScott Jiang decoder->std = std; 236202ea1f0SScott Jiang 237202ea1f0SScott Jiang return 0; 238202ea1f0SScott Jiang } 239202ea1f0SScott Jiang 240202ea1f0SScott Jiang static int adv7183_reset(struct v4l2_subdev *sd, u32 val) 241202ea1f0SScott Jiang { 242202ea1f0SScott Jiang int reg; 243202ea1f0SScott Jiang 244202ea1f0SScott Jiang reg = adv7183_read(sd, ADV7183_POW_MANAGE) | 0x80; 245202ea1f0SScott Jiang adv7183_write(sd, ADV7183_POW_MANAGE, reg); 246202ea1f0SScott Jiang /* wait 5ms before any further i2c writes are performed */ 247202ea1f0SScott Jiang usleep_range(5000, 10000); 248202ea1f0SScott Jiang return 0; 249202ea1f0SScott Jiang } 250202ea1f0SScott Jiang 251202ea1f0SScott Jiang static int adv7183_s_routing(struct v4l2_subdev *sd, 252202ea1f0SScott Jiang u32 input, u32 output, u32 config) 253202ea1f0SScott Jiang { 254202ea1f0SScott Jiang struct adv7183 *decoder = to_adv7183(sd); 255202ea1f0SScott Jiang int reg; 256202ea1f0SScott Jiang 257202ea1f0SScott Jiang if ((input > ADV7183_COMPONENT1) || (output > ADV7183_16BIT_OUT)) 258202ea1f0SScott Jiang return -EINVAL; 259202ea1f0SScott Jiang 260202ea1f0SScott Jiang if (input != decoder->input) { 261202ea1f0SScott Jiang decoder->input = input; 262202ea1f0SScott Jiang reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF0; 263202ea1f0SScott Jiang switch (input) { 264202ea1f0SScott Jiang case ADV7183_COMPOSITE1: 265202ea1f0SScott Jiang reg |= 0x1; 266202ea1f0SScott Jiang break; 267202ea1f0SScott Jiang case ADV7183_COMPOSITE2: 268202ea1f0SScott Jiang reg |= 0x2; 269202ea1f0SScott Jiang break; 270202ea1f0SScott Jiang case ADV7183_COMPOSITE3: 271202ea1f0SScott Jiang reg |= 0x3; 272202ea1f0SScott Jiang break; 273202ea1f0SScott Jiang case ADV7183_COMPOSITE4: 274202ea1f0SScott Jiang reg |= 0x4; 275202ea1f0SScott Jiang break; 276202ea1f0SScott Jiang case ADV7183_COMPOSITE5: 277202ea1f0SScott Jiang reg |= 0x5; 278202ea1f0SScott Jiang break; 279202ea1f0SScott Jiang case ADV7183_COMPOSITE6: 280202ea1f0SScott Jiang reg |= 0xB; 281202ea1f0SScott Jiang break; 282202ea1f0SScott Jiang case ADV7183_COMPOSITE7: 283202ea1f0SScott Jiang reg |= 0xC; 284202ea1f0SScott Jiang break; 285202ea1f0SScott Jiang case ADV7183_COMPOSITE8: 286202ea1f0SScott Jiang reg |= 0xD; 287202ea1f0SScott Jiang break; 288202ea1f0SScott Jiang case ADV7183_COMPOSITE9: 289202ea1f0SScott Jiang reg |= 0xE; 290202ea1f0SScott Jiang break; 291202ea1f0SScott Jiang case ADV7183_COMPOSITE10: 292202ea1f0SScott Jiang reg |= 0xF; 293202ea1f0SScott Jiang break; 294202ea1f0SScott Jiang case ADV7183_SVIDEO0: 295202ea1f0SScott Jiang reg |= 0x6; 296202ea1f0SScott Jiang break; 297202ea1f0SScott Jiang case ADV7183_SVIDEO1: 298202ea1f0SScott Jiang reg |= 0x7; 299202ea1f0SScott Jiang break; 300202ea1f0SScott Jiang case ADV7183_SVIDEO2: 301202ea1f0SScott Jiang reg |= 0x8; 302202ea1f0SScott Jiang break; 303202ea1f0SScott Jiang case ADV7183_COMPONENT0: 304202ea1f0SScott Jiang reg |= 0x9; 305202ea1f0SScott Jiang break; 306202ea1f0SScott Jiang case ADV7183_COMPONENT1: 307202ea1f0SScott Jiang reg |= 0xA; 308202ea1f0SScott Jiang break; 309202ea1f0SScott Jiang default: 310202ea1f0SScott Jiang break; 311202ea1f0SScott Jiang } 312202ea1f0SScott Jiang adv7183_write(sd, ADV7183_IN_CTRL, reg); 313202ea1f0SScott Jiang } 314202ea1f0SScott Jiang 315202ea1f0SScott Jiang if (output != decoder->output) { 316202ea1f0SScott Jiang decoder->output = output; 317202ea1f0SScott Jiang reg = adv7183_read(sd, ADV7183_OUT_CTRL) & 0xC0; 318202ea1f0SScott Jiang switch (output) { 319202ea1f0SScott Jiang case ADV7183_16BIT_OUT: 320202ea1f0SScott Jiang reg |= 0x9; 321202ea1f0SScott Jiang break; 322202ea1f0SScott Jiang default: 323202ea1f0SScott Jiang reg |= 0xC; 324202ea1f0SScott Jiang break; 325202ea1f0SScott Jiang } 326202ea1f0SScott Jiang adv7183_write(sd, ADV7183_OUT_CTRL, reg); 327202ea1f0SScott Jiang } 328202ea1f0SScott Jiang 329202ea1f0SScott Jiang return 0; 330202ea1f0SScott Jiang } 331202ea1f0SScott Jiang 332202ea1f0SScott Jiang static int adv7183_s_ctrl(struct v4l2_ctrl *ctrl) 333202ea1f0SScott Jiang { 334202ea1f0SScott Jiang struct v4l2_subdev *sd = to_sd(ctrl); 335202ea1f0SScott Jiang int val = ctrl->val; 336202ea1f0SScott Jiang 337202ea1f0SScott Jiang switch (ctrl->id) { 338202ea1f0SScott Jiang case V4L2_CID_BRIGHTNESS: 339202ea1f0SScott Jiang if (val < 0) 340202ea1f0SScott Jiang val = 127 - val; 341202ea1f0SScott Jiang adv7183_write(sd, ADV7183_BRIGHTNESS, val); 342202ea1f0SScott Jiang break; 343202ea1f0SScott Jiang case V4L2_CID_CONTRAST: 344202ea1f0SScott Jiang adv7183_write(sd, ADV7183_CONTRAST, val); 345202ea1f0SScott Jiang break; 346202ea1f0SScott Jiang case V4L2_CID_SATURATION: 347202ea1f0SScott Jiang adv7183_write(sd, ADV7183_SD_SATURATION_CB, val >> 8); 348202ea1f0SScott Jiang adv7183_write(sd, ADV7183_SD_SATURATION_CR, (val & 0xFF)); 349202ea1f0SScott Jiang break; 350202ea1f0SScott Jiang case V4L2_CID_HUE: 351202ea1f0SScott Jiang adv7183_write(sd, ADV7183_SD_OFFSET_CB, val >> 8); 352202ea1f0SScott Jiang adv7183_write(sd, ADV7183_SD_OFFSET_CR, (val & 0xFF)); 353202ea1f0SScott Jiang break; 354202ea1f0SScott Jiang default: 355202ea1f0SScott Jiang return -EINVAL; 356202ea1f0SScott Jiang } 357202ea1f0SScott Jiang 358202ea1f0SScott Jiang return 0; 359202ea1f0SScott Jiang } 360202ea1f0SScott Jiang 361202ea1f0SScott Jiang static int adv7183_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) 362202ea1f0SScott Jiang { 363202ea1f0SScott Jiang struct adv7183 *decoder = to_adv7183(sd); 364202ea1f0SScott Jiang int reg; 365202ea1f0SScott Jiang 366202ea1f0SScott Jiang /* enable autodetection block */ 367202ea1f0SScott Jiang reg = adv7183_read(sd, ADV7183_IN_CTRL) & 0xF; 368202ea1f0SScott Jiang adv7183_write(sd, ADV7183_IN_CTRL, reg); 369202ea1f0SScott Jiang 370202ea1f0SScott Jiang /* wait autodetection switch */ 371202ea1f0SScott Jiang mdelay(10); 372202ea1f0SScott Jiang 373202ea1f0SScott Jiang /* get autodetection result */ 374202ea1f0SScott Jiang reg = adv7183_read(sd, ADV7183_STATUS_1); 375202ea1f0SScott Jiang switch ((reg >> 0x4) & 0x7) { 376202ea1f0SScott Jiang case 0: 3777dd8fbbeSHans Verkuil *std &= V4L2_STD_NTSC; 378202ea1f0SScott Jiang break; 379202ea1f0SScott Jiang case 1: 3807dd8fbbeSHans Verkuil *std &= V4L2_STD_NTSC_443; 381202ea1f0SScott Jiang break; 382202ea1f0SScott Jiang case 2: 3837dd8fbbeSHans Verkuil *std &= V4L2_STD_PAL_M; 384202ea1f0SScott Jiang break; 385202ea1f0SScott Jiang case 3: 3867dd8fbbeSHans Verkuil *std &= V4L2_STD_PAL_60; 387202ea1f0SScott Jiang break; 388202ea1f0SScott Jiang case 4: 3897dd8fbbeSHans Verkuil *std &= V4L2_STD_PAL; 390202ea1f0SScott Jiang break; 391202ea1f0SScott Jiang case 5: 3927dd8fbbeSHans Verkuil *std &= V4L2_STD_SECAM; 393202ea1f0SScott Jiang break; 394202ea1f0SScott Jiang case 6: 3957dd8fbbeSHans Verkuil *std &= V4L2_STD_PAL_Nc; 396202ea1f0SScott Jiang break; 397202ea1f0SScott Jiang case 7: 3987dd8fbbeSHans Verkuil *std &= V4L2_STD_SECAM; 399202ea1f0SScott Jiang break; 400202ea1f0SScott Jiang default: 401202ea1f0SScott Jiang *std = V4L2_STD_UNKNOWN; 402202ea1f0SScott Jiang break; 403202ea1f0SScott Jiang } 404202ea1f0SScott Jiang 405202ea1f0SScott Jiang /* after std detection, write back user set std */ 406202ea1f0SScott Jiang adv7183_s_std(sd, decoder->std); 407202ea1f0SScott Jiang return 0; 408202ea1f0SScott Jiang } 409202ea1f0SScott Jiang 410202ea1f0SScott Jiang static int adv7183_g_input_status(struct v4l2_subdev *sd, u32 *status) 411202ea1f0SScott Jiang { 412202ea1f0SScott Jiang int reg; 413202ea1f0SScott Jiang 414202ea1f0SScott Jiang *status = V4L2_IN_ST_NO_SIGNAL; 415202ea1f0SScott Jiang reg = adv7183_read(sd, ADV7183_STATUS_1); 416202ea1f0SScott Jiang if (reg < 0) 417202ea1f0SScott Jiang return reg; 418202ea1f0SScott Jiang if (reg & 0x1) 419202ea1f0SScott Jiang *status = 0; 420202ea1f0SScott Jiang return 0; 421202ea1f0SScott Jiang } 422202ea1f0SScott Jiang 423202ea1f0SScott Jiang static int adv7183_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, 424202ea1f0SScott Jiang enum v4l2_mbus_pixelcode *code) 425202ea1f0SScott Jiang { 426202ea1f0SScott Jiang if (index > 0) 427202ea1f0SScott Jiang return -EINVAL; 428202ea1f0SScott Jiang 429202ea1f0SScott Jiang *code = V4L2_MBUS_FMT_UYVY8_2X8; 430202ea1f0SScott Jiang return 0; 431202ea1f0SScott Jiang } 432202ea1f0SScott Jiang 433202ea1f0SScott Jiang static int adv7183_try_mbus_fmt(struct v4l2_subdev *sd, 434202ea1f0SScott Jiang struct v4l2_mbus_framefmt *fmt) 435202ea1f0SScott Jiang { 436202ea1f0SScott Jiang struct adv7183 *decoder = to_adv7183(sd); 437202ea1f0SScott Jiang 438202ea1f0SScott Jiang fmt->code = V4L2_MBUS_FMT_UYVY8_2X8; 439202ea1f0SScott Jiang fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; 440202ea1f0SScott Jiang if (decoder->std & V4L2_STD_525_60) { 441202ea1f0SScott Jiang fmt->field = V4L2_FIELD_SEQ_TB; 442202ea1f0SScott Jiang fmt->width = 720; 443202ea1f0SScott Jiang fmt->height = 480; 444202ea1f0SScott Jiang } else { 445202ea1f0SScott Jiang fmt->field = V4L2_FIELD_SEQ_BT; 446202ea1f0SScott Jiang fmt->width = 720; 447202ea1f0SScott Jiang fmt->height = 576; 448202ea1f0SScott Jiang } 449202ea1f0SScott Jiang return 0; 450202ea1f0SScott Jiang } 451202ea1f0SScott Jiang 452202ea1f0SScott Jiang static int adv7183_s_mbus_fmt(struct v4l2_subdev *sd, 453202ea1f0SScott Jiang struct v4l2_mbus_framefmt *fmt) 454202ea1f0SScott Jiang { 455202ea1f0SScott Jiang struct adv7183 *decoder = to_adv7183(sd); 456202ea1f0SScott Jiang 457202ea1f0SScott Jiang adv7183_try_mbus_fmt(sd, fmt); 458202ea1f0SScott Jiang decoder->fmt = *fmt; 459202ea1f0SScott Jiang return 0; 460202ea1f0SScott Jiang } 461202ea1f0SScott Jiang 462202ea1f0SScott Jiang static int adv7183_g_mbus_fmt(struct v4l2_subdev *sd, 463202ea1f0SScott Jiang struct v4l2_mbus_framefmt *fmt) 464202ea1f0SScott Jiang { 465202ea1f0SScott Jiang struct adv7183 *decoder = to_adv7183(sd); 466202ea1f0SScott Jiang 467202ea1f0SScott Jiang *fmt = decoder->fmt; 468202ea1f0SScott Jiang return 0; 469202ea1f0SScott Jiang } 470202ea1f0SScott Jiang 471202ea1f0SScott Jiang static int adv7183_s_stream(struct v4l2_subdev *sd, int enable) 472202ea1f0SScott Jiang { 473202ea1f0SScott Jiang struct adv7183 *decoder = to_adv7183(sd); 474202ea1f0SScott Jiang 475202ea1f0SScott Jiang if (enable) 47695323361SLaurent Pinchart gpio_set_value(decoder->oe_pin, 0); 477202ea1f0SScott Jiang else 47895323361SLaurent Pinchart gpio_set_value(decoder->oe_pin, 1); 479202ea1f0SScott Jiang udelay(1); 480202ea1f0SScott Jiang return 0; 481202ea1f0SScott Jiang } 482202ea1f0SScott Jiang 483202ea1f0SScott Jiang #ifdef CONFIG_VIDEO_ADV_DEBUG 484202ea1f0SScott Jiang static int adv7183_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) 485202ea1f0SScott Jiang { 486202ea1f0SScott Jiang reg->val = adv7183_read(sd, reg->reg & 0xff); 487202ea1f0SScott Jiang reg->size = 1; 488202ea1f0SScott Jiang return 0; 489202ea1f0SScott Jiang } 490202ea1f0SScott Jiang 491977ba3b1SHans Verkuil static int adv7183_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) 492202ea1f0SScott Jiang { 493202ea1f0SScott Jiang adv7183_write(sd, reg->reg & 0xff, reg->val & 0xff); 494202ea1f0SScott Jiang return 0; 495202ea1f0SScott Jiang } 496202ea1f0SScott Jiang #endif 497202ea1f0SScott Jiang 498202ea1f0SScott Jiang static const struct v4l2_ctrl_ops adv7183_ctrl_ops = { 499202ea1f0SScott Jiang .s_ctrl = adv7183_s_ctrl, 500202ea1f0SScott Jiang }; 501202ea1f0SScott Jiang 502202ea1f0SScott Jiang static const struct v4l2_subdev_core_ops adv7183_core_ops = { 503202ea1f0SScott Jiang .log_status = adv7183_log_status, 504202ea1f0SScott Jiang .g_std = adv7183_g_std, 505202ea1f0SScott Jiang .s_std = adv7183_s_std, 506202ea1f0SScott Jiang .reset = adv7183_reset, 507202ea1f0SScott Jiang #ifdef CONFIG_VIDEO_ADV_DEBUG 508202ea1f0SScott Jiang .g_register = adv7183_g_register, 509202ea1f0SScott Jiang .s_register = adv7183_s_register, 510202ea1f0SScott Jiang #endif 511202ea1f0SScott Jiang }; 512202ea1f0SScott Jiang 513202ea1f0SScott Jiang static const struct v4l2_subdev_video_ops adv7183_video_ops = { 514202ea1f0SScott Jiang .s_routing = adv7183_s_routing, 515202ea1f0SScott Jiang .querystd = adv7183_querystd, 516202ea1f0SScott Jiang .g_input_status = adv7183_g_input_status, 517202ea1f0SScott Jiang .enum_mbus_fmt = adv7183_enum_mbus_fmt, 518202ea1f0SScott Jiang .try_mbus_fmt = adv7183_try_mbus_fmt, 519202ea1f0SScott Jiang .s_mbus_fmt = adv7183_s_mbus_fmt, 520202ea1f0SScott Jiang .g_mbus_fmt = adv7183_g_mbus_fmt, 521202ea1f0SScott Jiang .s_stream = adv7183_s_stream, 522202ea1f0SScott Jiang }; 523202ea1f0SScott Jiang 524202ea1f0SScott Jiang static const struct v4l2_subdev_ops adv7183_ops = { 525202ea1f0SScott Jiang .core = &adv7183_core_ops, 526202ea1f0SScott Jiang .video = &adv7183_video_ops, 527202ea1f0SScott Jiang }; 528202ea1f0SScott Jiang 529202ea1f0SScott Jiang static int adv7183_probe(struct i2c_client *client, 530202ea1f0SScott Jiang const struct i2c_device_id *id) 531202ea1f0SScott Jiang { 532202ea1f0SScott Jiang struct adv7183 *decoder; 533202ea1f0SScott Jiang struct v4l2_subdev *sd; 534202ea1f0SScott Jiang struct v4l2_ctrl_handler *hdl; 535202ea1f0SScott Jiang int ret; 536202ea1f0SScott Jiang struct v4l2_mbus_framefmt fmt; 537202ea1f0SScott Jiang const unsigned *pin_array; 538202ea1f0SScott Jiang 539202ea1f0SScott Jiang /* Check if the adapter supports the needed features */ 540202ea1f0SScott Jiang if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 541202ea1f0SScott Jiang return -EIO; 542202ea1f0SScott Jiang 543202ea1f0SScott Jiang v4l_info(client, "chip found @ 0x%02x (%s)\n", 544202ea1f0SScott Jiang client->addr << 1, client->adapter->name); 545202ea1f0SScott Jiang 546202ea1f0SScott Jiang pin_array = client->dev.platform_data; 547202ea1f0SScott Jiang if (pin_array == NULL) 548202ea1f0SScott Jiang return -EINVAL; 549202ea1f0SScott Jiang 550c02b211dSLaurent Pinchart decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL); 551202ea1f0SScott Jiang if (decoder == NULL) 552202ea1f0SScott Jiang return -ENOMEM; 553202ea1f0SScott Jiang 554202ea1f0SScott Jiang decoder->reset_pin = pin_array[0]; 555202ea1f0SScott Jiang decoder->oe_pin = pin_array[1]; 556202ea1f0SScott Jiang 557b015ba29SLaurent Pinchart if (devm_gpio_request_one(&client->dev, decoder->reset_pin, 558b015ba29SLaurent Pinchart GPIOF_OUT_INIT_LOW, "ADV7183 Reset")) { 559202ea1f0SScott Jiang v4l_err(client, "failed to request GPIO %d\n", decoder->reset_pin); 560c02b211dSLaurent Pinchart return -EBUSY; 561202ea1f0SScott Jiang } 562202ea1f0SScott Jiang 563b015ba29SLaurent Pinchart if (devm_gpio_request_one(&client->dev, decoder->oe_pin, 564b015ba29SLaurent Pinchart GPIOF_OUT_INIT_HIGH, 56595323361SLaurent Pinchart "ADV7183 Output Enable")) { 566202ea1f0SScott Jiang v4l_err(client, "failed to request GPIO %d\n", decoder->oe_pin); 567b015ba29SLaurent Pinchart return -EBUSY; 568202ea1f0SScott Jiang } 569202ea1f0SScott Jiang 570202ea1f0SScott Jiang sd = &decoder->sd; 571202ea1f0SScott Jiang v4l2_i2c_subdev_init(sd, client, &adv7183_ops); 572202ea1f0SScott Jiang 573202ea1f0SScott Jiang hdl = &decoder->hdl; 574202ea1f0SScott Jiang v4l2_ctrl_handler_init(hdl, 4); 575202ea1f0SScott Jiang v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops, 576202ea1f0SScott Jiang V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); 577202ea1f0SScott Jiang v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops, 578202ea1f0SScott Jiang V4L2_CID_CONTRAST, 0, 0xFF, 1, 0x80); 579202ea1f0SScott Jiang v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops, 580202ea1f0SScott Jiang V4L2_CID_SATURATION, 0, 0xFFFF, 1, 0x8080); 581202ea1f0SScott Jiang v4l2_ctrl_new_std(hdl, &adv7183_ctrl_ops, 582202ea1f0SScott Jiang V4L2_CID_HUE, 0, 0xFFFF, 1, 0x8080); 583202ea1f0SScott Jiang /* hook the control handler into the driver */ 584202ea1f0SScott Jiang sd->ctrl_handler = hdl; 585202ea1f0SScott Jiang if (hdl->error) { 586202ea1f0SScott Jiang ret = hdl->error; 587202ea1f0SScott Jiang 588202ea1f0SScott Jiang v4l2_ctrl_handler_free(hdl); 589b015ba29SLaurent Pinchart return ret; 590202ea1f0SScott Jiang } 591202ea1f0SScott Jiang 592202ea1f0SScott Jiang /* v4l2 doesn't support an autodetect standard, pick PAL as default */ 593202ea1f0SScott Jiang decoder->std = V4L2_STD_PAL; 594202ea1f0SScott Jiang decoder->input = ADV7183_COMPOSITE4; 595202ea1f0SScott Jiang decoder->output = ADV7183_8BIT_OUT; 596202ea1f0SScott Jiang 597202ea1f0SScott Jiang /* reset chip */ 598202ea1f0SScott Jiang /* reset pulse width at least 5ms */ 599202ea1f0SScott Jiang mdelay(10); 60095323361SLaurent Pinchart gpio_set_value(decoder->reset_pin, 1); 601202ea1f0SScott Jiang /* wait 5ms before any further i2c writes are performed */ 602202ea1f0SScott Jiang mdelay(5); 603202ea1f0SScott Jiang 604202ea1f0SScott Jiang adv7183_writeregs(sd, adv7183_init_regs, ARRAY_SIZE(adv7183_init_regs)); 605202ea1f0SScott Jiang adv7183_s_std(sd, decoder->std); 606202ea1f0SScott Jiang fmt.width = 720; 607202ea1f0SScott Jiang fmt.height = 576; 608202ea1f0SScott Jiang adv7183_s_mbus_fmt(sd, &fmt); 609202ea1f0SScott Jiang 610202ea1f0SScott Jiang /* initialize the hardware to the default control values */ 611202ea1f0SScott Jiang ret = v4l2_ctrl_handler_setup(hdl); 612202ea1f0SScott Jiang if (ret) { 613202ea1f0SScott Jiang v4l2_ctrl_handler_free(hdl); 614b015ba29SLaurent Pinchart return ret; 615202ea1f0SScott Jiang } 616202ea1f0SScott Jiang 617202ea1f0SScott Jiang return 0; 618202ea1f0SScott Jiang } 619202ea1f0SScott Jiang 620202ea1f0SScott Jiang static int adv7183_remove(struct i2c_client *client) 621202ea1f0SScott Jiang { 622202ea1f0SScott Jiang struct v4l2_subdev *sd = i2c_get_clientdata(client); 623202ea1f0SScott Jiang 624202ea1f0SScott Jiang v4l2_device_unregister_subdev(sd); 625202ea1f0SScott Jiang v4l2_ctrl_handler_free(sd->ctrl_handler); 626202ea1f0SScott Jiang return 0; 627202ea1f0SScott Jiang } 628202ea1f0SScott Jiang 629202ea1f0SScott Jiang static const struct i2c_device_id adv7183_id[] = { 630202ea1f0SScott Jiang {"adv7183", 0}, 631202ea1f0SScott Jiang {}, 632202ea1f0SScott Jiang }; 633202ea1f0SScott Jiang 634202ea1f0SScott Jiang MODULE_DEVICE_TABLE(i2c, adv7183_id); 635202ea1f0SScott Jiang 636202ea1f0SScott Jiang static struct i2c_driver adv7183_driver = { 637202ea1f0SScott Jiang .driver = { 638202ea1f0SScott Jiang .owner = THIS_MODULE, 639202ea1f0SScott Jiang .name = "adv7183", 640202ea1f0SScott Jiang }, 641202ea1f0SScott Jiang .probe = adv7183_probe, 6424c62e976SGreg Kroah-Hartman .remove = adv7183_remove, 643202ea1f0SScott Jiang .id_table = adv7183_id, 644202ea1f0SScott Jiang }; 645202ea1f0SScott Jiang 64601aea0bfSWei Yongjun module_i2c_driver(adv7183_driver); 647202ea1f0SScott Jiang 648202ea1f0SScott Jiang MODULE_DESCRIPTION("Analog Devices ADV7183 video decoder driver"); 649202ea1f0SScott Jiang MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>"); 650202ea1f0SScott Jiang MODULE_LICENSE("GPL v2"); 651