1cb7a01acSMauro Carvalho Chehab /* 2cb7a01acSMauro Carvalho Chehab * adv7180.c Analog Devices ADV7180 video decoder driver 3cb7a01acSMauro Carvalho Chehab * Copyright (c) 2009 Intel Corporation 4cccb83f7SVladimir Barinov * Copyright (C) 2013 Cogent Embedded, Inc. 5cccb83f7SVladimir Barinov * Copyright (C) 2013 Renesas Solutions Corp. 6cb7a01acSMauro Carvalho Chehab * 7cb7a01acSMauro Carvalho Chehab * This program is free software; you can redistribute it and/or modify 8cb7a01acSMauro Carvalho Chehab * it under the terms of the GNU General Public License version 2 as 9cb7a01acSMauro Carvalho Chehab * published by the Free Software Foundation. 10cb7a01acSMauro Carvalho Chehab * 11cb7a01acSMauro Carvalho Chehab * This program is distributed in the hope that it will be useful, 12cb7a01acSMauro Carvalho Chehab * but WITHOUT ANY WARRANTY; without even the implied warranty of 13cb7a01acSMauro Carvalho Chehab * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14cb7a01acSMauro Carvalho Chehab * GNU General Public License for more details. 15cb7a01acSMauro Carvalho Chehab */ 16cb7a01acSMauro Carvalho Chehab 17cb7a01acSMauro Carvalho Chehab #include <linux/module.h> 18cb7a01acSMauro Carvalho Chehab #include <linux/init.h> 19cb7a01acSMauro Carvalho Chehab #include <linux/errno.h> 20cb7a01acSMauro Carvalho Chehab #include <linux/kernel.h> 21cb7a01acSMauro Carvalho Chehab #include <linux/interrupt.h> 22cb7a01acSMauro Carvalho Chehab #include <linux/i2c.h> 23cb7a01acSMauro Carvalho Chehab #include <linux/slab.h> 24250121d3SBen Dooks #include <linux/of.h> 2565d9e14aSSteve Longerbeam #include <linux/gpio/consumer.h> 26cb7a01acSMauro Carvalho Chehab #include <linux/videodev2.h> 27937feeedSHans Verkuil #include <media/v4l2-ioctl.h> 28937feeedSHans Verkuil #include <media/v4l2-event.h> 29cb7a01acSMauro Carvalho Chehab #include <media/v4l2-device.h> 30cb7a01acSMauro Carvalho Chehab #include <media/v4l2-ctrls.h> 31cb7a01acSMauro Carvalho Chehab #include <linux/mutex.h> 32c18818e9SLars-Peter Clausen #include <linux/delay.h> 33cb7a01acSMauro Carvalho Chehab 34f5dde49bSLars-Peter Clausen #define ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM 0x0 35f5dde49bSLars-Peter Clausen #define ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM_PED 0x1 36f5dde49bSLars-Peter Clausen #define ADV7180_STD_AD_PAL_N_NTSC_J_SECAM 0x2 37f5dde49bSLars-Peter Clausen #define ADV7180_STD_AD_PAL_N_NTSC_M_SECAM 0x3 38f5dde49bSLars-Peter Clausen #define ADV7180_STD_NTSC_J 0x4 39f5dde49bSLars-Peter Clausen #define ADV7180_STD_NTSC_M 0x5 40f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL60 0x6 41f5dde49bSLars-Peter Clausen #define ADV7180_STD_NTSC_443 0x7 42f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_BG 0x8 43f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_N 0x9 44f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_M 0xa 45f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_M_PED 0xb 46f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_COMB_N 0xc 47f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_COMB_N_PED 0xd 48f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_SECAM 0xe 49f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_SECAM_PED 0xf 50f5dde49bSLars-Peter Clausen 513999e5d0SLars-Peter Clausen #define ADV7180_REG_INPUT_CONTROL 0x0000 52cb7a01acSMauro Carvalho Chehab #define ADV7180_INPUT_CONTROL_INSEL_MASK 0x0f 53cb7a01acSMauro Carvalho Chehab 54c5ef8f8cSLars-Peter Clausen #define ADV7182_REG_INPUT_VIDSEL 0x0002 55c5ef8f8cSLars-Peter Clausen 56ce5d6290SSteve Longerbeam #define ADV7180_REG_OUTPUT_CONTROL 0x0003 573999e5d0SLars-Peter Clausen #define ADV7180_REG_EXTENDED_OUTPUT_CONTROL 0x0004 58cb7a01acSMauro Carvalho Chehab #define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS 0xC5 59cb7a01acSMauro Carvalho Chehab 60ce5d6290SSteve Longerbeam #define ADV7180_REG_AUTODETECT_ENABLE 0x0007 61cb7a01acSMauro Carvalho Chehab #define ADV7180_AUTODETECT_DEFAULT 0x7f 62cb7a01acSMauro Carvalho Chehab /* Contrast */ 633999e5d0SLars-Peter Clausen #define ADV7180_REG_CON 0x0008 /*Unsigned */ 64cb7a01acSMauro Carvalho Chehab #define ADV7180_CON_MIN 0 65cb7a01acSMauro Carvalho Chehab #define ADV7180_CON_DEF 128 66cb7a01acSMauro Carvalho Chehab #define ADV7180_CON_MAX 255 67cb7a01acSMauro Carvalho Chehab /* Brightness*/ 683999e5d0SLars-Peter Clausen #define ADV7180_REG_BRI 0x000a /*Signed */ 69cb7a01acSMauro Carvalho Chehab #define ADV7180_BRI_MIN -128 70cb7a01acSMauro Carvalho Chehab #define ADV7180_BRI_DEF 0 71cb7a01acSMauro Carvalho Chehab #define ADV7180_BRI_MAX 127 72cb7a01acSMauro Carvalho Chehab /* Hue */ 733999e5d0SLars-Peter Clausen #define ADV7180_REG_HUE 0x000b /*Signed, inverted */ 74cb7a01acSMauro Carvalho Chehab #define ADV7180_HUE_MIN -127 75cb7a01acSMauro Carvalho Chehab #define ADV7180_HUE_DEF 0 76cb7a01acSMauro Carvalho Chehab #define ADV7180_HUE_MAX 128 77cb7a01acSMauro Carvalho Chehab 783999e5d0SLars-Peter Clausen #define ADV7180_REG_CTRL 0x000e 79029d6177SLars-Peter Clausen #define ADV7180_CTRL_IRQ_SPACE 0x20 80cb7a01acSMauro Carvalho Chehab 81029d6177SLars-Peter Clausen #define ADV7180_REG_PWR_MAN 0x0f 82cb7a01acSMauro Carvalho Chehab #define ADV7180_PWR_MAN_ON 0x04 83cb7a01acSMauro Carvalho Chehab #define ADV7180_PWR_MAN_OFF 0x24 84cb7a01acSMauro Carvalho Chehab #define ADV7180_PWR_MAN_RES 0x80 85cb7a01acSMauro Carvalho Chehab 863999e5d0SLars-Peter Clausen #define ADV7180_REG_STATUS1 0x0010 87cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_IN_LOCK 0x01 88cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_MASK 0x70 89cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_NTSM_M_J 0x00 90cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_NTSC_4_43 0x10 91cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_PAL_M 0x20 92cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_PAL_60 0x30 93cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_PAL_B_G 0x40 94cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_SECAM 0x50 95cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_PAL_COMB 0x60 96cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_SECAM_525 0x70 97cb7a01acSMauro Carvalho Chehab 983999e5d0SLars-Peter Clausen #define ADV7180_REG_IDENT 0x0011 99cb7a01acSMauro Carvalho Chehab #define ADV7180_ID_7180 0x18 100cb7a01acSMauro Carvalho Chehab 101ce5d6290SSteve Longerbeam #define ADV7180_REG_STATUS3 0x0013 102ce5d6290SSteve Longerbeam #define ADV7180_REG_ANALOG_CLAMP_CTL 0x0014 103ce5d6290SSteve Longerbeam #define ADV7180_REG_SHAP_FILTER_CTL_1 0x0017 104ce5d6290SSteve Longerbeam #define ADV7180_REG_CTRL_2 0x001d 105ce5d6290SSteve Longerbeam #define ADV7180_REG_VSYNC_FIELD_CTL_1 0x0031 106ce5d6290SSteve Longerbeam #define ADV7180_REG_MANUAL_WIN_CTL_1 0x003d 107ce5d6290SSteve Longerbeam #define ADV7180_REG_MANUAL_WIN_CTL_2 0x003e 108ce5d6290SSteve Longerbeam #define ADV7180_REG_MANUAL_WIN_CTL_3 0x003f 109ce5d6290SSteve Longerbeam #define ADV7180_REG_LOCK_CNT 0x0051 110ce5d6290SSteve Longerbeam #define ADV7180_REG_CVBS_TRIM 0x0052 111ce5d6290SSteve Longerbeam #define ADV7180_REG_CLAMP_ADJ 0x005a 112ce5d6290SSteve Longerbeam #define ADV7180_REG_RES_CIR 0x005f 113ce5d6290SSteve Longerbeam #define ADV7180_REG_DIFF_MODE 0x0060 114ce5d6290SSteve Longerbeam 11552e37f0aSSteve Longerbeam #define ADV7180_REG_ICONF1 0x2040 116cb7a01acSMauro Carvalho Chehab #define ADV7180_ICONF1_ACTIVE_LOW 0x01 117cb7a01acSMauro Carvalho Chehab #define ADV7180_ICONF1_PSYNC_ONLY 0x10 118cb7a01acSMauro Carvalho Chehab #define ADV7180_ICONF1_ACTIVE_TO_CLR 0xC0 119cb7a01acSMauro Carvalho Chehab /* Saturation */ 1203999e5d0SLars-Peter Clausen #define ADV7180_REG_SD_SAT_CB 0x00e3 /*Unsigned */ 1213999e5d0SLars-Peter Clausen #define ADV7180_REG_SD_SAT_CR 0x00e4 /*Unsigned */ 122cb7a01acSMauro Carvalho Chehab #define ADV7180_SAT_MIN 0 123cb7a01acSMauro Carvalho Chehab #define ADV7180_SAT_DEF 128 124cb7a01acSMauro Carvalho Chehab #define ADV7180_SAT_MAX 255 125cb7a01acSMauro Carvalho Chehab 126cb7a01acSMauro Carvalho Chehab #define ADV7180_IRQ1_LOCK 0x01 127cb7a01acSMauro Carvalho Chehab #define ADV7180_IRQ1_UNLOCK 0x02 12852e37f0aSSteve Longerbeam #define ADV7180_REG_ISR1 0x2042 12952e37f0aSSteve Longerbeam #define ADV7180_REG_ICR1 0x2043 13052e37f0aSSteve Longerbeam #define ADV7180_REG_IMR1 0x2044 13152e37f0aSSteve Longerbeam #define ADV7180_REG_IMR2 0x2048 132cb7a01acSMauro Carvalho Chehab #define ADV7180_IRQ3_AD_CHANGE 0x08 13352e37f0aSSteve Longerbeam #define ADV7180_REG_ISR3 0x204A 13452e37f0aSSteve Longerbeam #define ADV7180_REG_ICR3 0x204B 13552e37f0aSSteve Longerbeam #define ADV7180_REG_IMR3 0x204C 13652e37f0aSSteve Longerbeam #define ADV7180_REG_IMR4 0x2050 137cb7a01acSMauro Carvalho Chehab 1383999e5d0SLars-Peter Clausen #define ADV7180_REG_NTSC_V_BIT_END 0x00E6 139cb7a01acSMauro Carvalho Chehab #define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND 0x4F 140cb7a01acSMauro Carvalho Chehab 141851a54efSLars-Peter Clausen #define ADV7180_REG_VPP_SLAVE_ADDR 0xFD 142b37135e3SLars-Peter Clausen #define ADV7180_REG_CSI_SLAVE_ADDR 0xFE 143b37135e3SLars-Peter Clausen 144ce5d6290SSteve Longerbeam #define ADV7180_REG_ACE_CTRL1 0x4080 145ce5d6290SSteve Longerbeam #define ADV7180_REG_ACE_CTRL5 0x4084 14608b717c2SLars-Peter Clausen #define ADV7180_REG_FLCONTROL 0x40e0 14708b717c2SLars-Peter Clausen #define ADV7180_FLCONTROL_FL_ENABLE 0x1 14808b717c2SLars-Peter Clausen 149ce5d6290SSteve Longerbeam #define ADV7180_REG_RST_CLAMP 0x809c 150ce5d6290SSteve Longerbeam #define ADV7180_REG_AGC_ADJ1 0x80b6 151ce5d6290SSteve Longerbeam #define ADV7180_REG_AGC_ADJ2 0x80c0 152ce5d6290SSteve Longerbeam 153b37135e3SLars-Peter Clausen #define ADV7180_CSI_REG_PWRDN 0x00 154b37135e3SLars-Peter Clausen #define ADV7180_CSI_PWRDN 0x80 155b37135e3SLars-Peter Clausen 156f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN1 0x00 157f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN2 0x01 158f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN3 0x02 159f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN4 0x03 160f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN5 0x04 161f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN6 0x05 162f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_SVIDEO_AIN1_AIN2 0x06 163f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_SVIDEO_AIN3_AIN4 0x07 164f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_SVIDEO_AIN5_AIN6 0x08 165f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_YPRPB_AIN1_AIN2_AIN3 0x09 166f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0a 167f5dde49bSLars-Peter Clausen 168c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN1 0x00 169c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN2 0x01 170c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN3 0x02 171c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN4 0x03 172c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN5 0x04 173c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN6 0x05 174c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN7 0x06 175c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN8 0x07 176c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_SVIDEO_AIN1_AIN2 0x08 177c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_SVIDEO_AIN3_AIN4 0x09 178c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_SVIDEO_AIN5_AIN6 0x0a 179c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_SVIDEO_AIN7_AIN8 0x0b 180c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3 0x0c 181c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0d 182c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2 0x0e 183c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4 0x0f 184c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6 0x10 185c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8 0x11 186c5ef8f8cSLars-Peter Clausen 187b37135e3SLars-Peter Clausen #define ADV7180_DEFAULT_CSI_I2C_ADDR 0x44 188851a54efSLars-Peter Clausen #define ADV7180_DEFAULT_VPP_I2C_ADDR 0x42 189b37135e3SLars-Peter Clausen 19008b717c2SLars-Peter Clausen #define V4L2_CID_ADV_FAST_SWITCH (V4L2_CID_USER_ADV7180_BASE + 0x00) 19108b717c2SLars-Peter Clausen 192f5dde49bSLars-Peter Clausen struct adv7180_state; 193f5dde49bSLars-Peter Clausen 194f5dde49bSLars-Peter Clausen #define ADV7180_FLAG_RESET_POWERED BIT(0) 195bf7dcb80SLars-Peter Clausen #define ADV7180_FLAG_V2 BIT(1) 196b37135e3SLars-Peter Clausen #define ADV7180_FLAG_MIPI_CSI2 BIT(2) 197851a54efSLars-Peter Clausen #define ADV7180_FLAG_I2P BIT(3) 198f5dde49bSLars-Peter Clausen 199f5dde49bSLars-Peter Clausen struct adv7180_chip_info { 200f5dde49bSLars-Peter Clausen unsigned int flags; 201f5dde49bSLars-Peter Clausen unsigned int valid_input_mask; 202f5dde49bSLars-Peter Clausen int (*set_std)(struct adv7180_state *st, unsigned int std); 203f5dde49bSLars-Peter Clausen int (*select_input)(struct adv7180_state *st, unsigned int input); 204f5dde49bSLars-Peter Clausen int (*init)(struct adv7180_state *state); 205f5dde49bSLars-Peter Clausen }; 206f5dde49bSLars-Peter Clausen 207cb7a01acSMauro Carvalho Chehab struct adv7180_state { 208cb7a01acSMauro Carvalho Chehab struct v4l2_ctrl_handler ctrl_hdl; 209cb7a01acSMauro Carvalho Chehab struct v4l2_subdev sd; 210d5d51a82SLars-Peter Clausen struct media_pad pad; 211cb7a01acSMauro Carvalho Chehab struct mutex mutex; /* mutual excl. when accessing chip */ 212cb7a01acSMauro Carvalho Chehab int irq; 21365d9e14aSSteve Longerbeam struct gpio_desc *pwdn_gpio; 214cb7a01acSMauro Carvalho Chehab v4l2_std_id curr_norm; 215e246c333SLars-Peter Clausen bool powered; 216937feeedSHans Verkuil bool streaming; 217cb7a01acSMauro Carvalho Chehab u8 input; 2183999e5d0SLars-Peter Clausen 2193999e5d0SLars-Peter Clausen struct i2c_client *client; 2203999e5d0SLars-Peter Clausen unsigned int register_page; 221b37135e3SLars-Peter Clausen struct i2c_client *csi_client; 222851a54efSLars-Peter Clausen struct i2c_client *vpp_client; 223f5dde49bSLars-Peter Clausen const struct adv7180_chip_info *chip_info; 224851a54efSLars-Peter Clausen enum v4l2_field field; 225cb7a01acSMauro Carvalho Chehab }; 226cb7a01acSMauro Carvalho Chehab #define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler, \ 227cb7a01acSMauro Carvalho Chehab struct adv7180_state, \ 228cb7a01acSMauro Carvalho Chehab ctrl_hdl)->sd) 229cb7a01acSMauro Carvalho Chehab 2303999e5d0SLars-Peter Clausen static int adv7180_select_page(struct adv7180_state *state, unsigned int page) 2313999e5d0SLars-Peter Clausen { 2323999e5d0SLars-Peter Clausen if (state->register_page != page) { 2333999e5d0SLars-Peter Clausen i2c_smbus_write_byte_data(state->client, ADV7180_REG_CTRL, 2343999e5d0SLars-Peter Clausen page); 2353999e5d0SLars-Peter Clausen state->register_page = page; 2363999e5d0SLars-Peter Clausen } 2373999e5d0SLars-Peter Clausen 2383999e5d0SLars-Peter Clausen return 0; 2393999e5d0SLars-Peter Clausen } 2403999e5d0SLars-Peter Clausen 2413999e5d0SLars-Peter Clausen static int adv7180_write(struct adv7180_state *state, unsigned int reg, 2423999e5d0SLars-Peter Clausen unsigned int value) 2433999e5d0SLars-Peter Clausen { 2443999e5d0SLars-Peter Clausen lockdep_assert_held(&state->mutex); 2453999e5d0SLars-Peter Clausen adv7180_select_page(state, reg >> 8); 2463999e5d0SLars-Peter Clausen return i2c_smbus_write_byte_data(state->client, reg & 0xff, value); 2473999e5d0SLars-Peter Clausen } 2483999e5d0SLars-Peter Clausen 2493999e5d0SLars-Peter Clausen static int adv7180_read(struct adv7180_state *state, unsigned int reg) 2503999e5d0SLars-Peter Clausen { 2513999e5d0SLars-Peter Clausen lockdep_assert_held(&state->mutex); 2523999e5d0SLars-Peter Clausen adv7180_select_page(state, reg >> 8); 2533999e5d0SLars-Peter Clausen return i2c_smbus_read_byte_data(state->client, reg & 0xff); 2543999e5d0SLars-Peter Clausen } 2553999e5d0SLars-Peter Clausen 256b37135e3SLars-Peter Clausen static int adv7180_csi_write(struct adv7180_state *state, unsigned int reg, 257b37135e3SLars-Peter Clausen unsigned int value) 258b37135e3SLars-Peter Clausen { 259b37135e3SLars-Peter Clausen return i2c_smbus_write_byte_data(state->csi_client, reg, value); 260b37135e3SLars-Peter Clausen } 261b37135e3SLars-Peter Clausen 262f5dde49bSLars-Peter Clausen static int adv7180_set_video_standard(struct adv7180_state *state, 263f5dde49bSLars-Peter Clausen unsigned int std) 264f5dde49bSLars-Peter Clausen { 265f5dde49bSLars-Peter Clausen return state->chip_info->set_std(state, std); 266f5dde49bSLars-Peter Clausen } 2673999e5d0SLars-Peter Clausen 268851a54efSLars-Peter Clausen static int adv7180_vpp_write(struct adv7180_state *state, unsigned int reg, 269851a54efSLars-Peter Clausen unsigned int value) 270851a54efSLars-Peter Clausen { 271851a54efSLars-Peter Clausen return i2c_smbus_write_byte_data(state->vpp_client, reg, value); 272851a54efSLars-Peter Clausen } 273851a54efSLars-Peter Clausen 274cb7a01acSMauro Carvalho Chehab static v4l2_std_id adv7180_std_to_v4l2(u8 status1) 275cb7a01acSMauro Carvalho Chehab { 276b294a192SVladimir Barinov /* in case V4L2_IN_ST_NO_SIGNAL */ 277b294a192SVladimir Barinov if (!(status1 & ADV7180_STATUS1_IN_LOCK)) 278b294a192SVladimir Barinov return V4L2_STD_UNKNOWN; 279b294a192SVladimir Barinov 280cb7a01acSMauro Carvalho Chehab switch (status1 & ADV7180_STATUS1_AUTOD_MASK) { 281cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_NTSM_M_J: 282cb7a01acSMauro Carvalho Chehab return V4L2_STD_NTSC; 283cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_NTSC_4_43: 284cb7a01acSMauro Carvalho Chehab return V4L2_STD_NTSC_443; 285cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_PAL_M: 286cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL_M; 287cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_PAL_60: 288cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL_60; 289cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_PAL_B_G: 290cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL; 291cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_SECAM: 292cb7a01acSMauro Carvalho Chehab return V4L2_STD_SECAM; 293cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_PAL_COMB: 294cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL_Nc | V4L2_STD_PAL_N; 295cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_SECAM_525: 296cb7a01acSMauro Carvalho Chehab return V4L2_STD_SECAM; 297cb7a01acSMauro Carvalho Chehab default: 298cb7a01acSMauro Carvalho Chehab return V4L2_STD_UNKNOWN; 299cb7a01acSMauro Carvalho Chehab } 300cb7a01acSMauro Carvalho Chehab } 301cb7a01acSMauro Carvalho Chehab 302cb7a01acSMauro Carvalho Chehab static int v4l2_std_to_adv7180(v4l2_std_id std) 303cb7a01acSMauro Carvalho Chehab { 304cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_PAL_60) 305f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL60; 306cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_NTSC_443) 307f5dde49bSLars-Peter Clausen return ADV7180_STD_NTSC_443; 308cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_PAL_N) 309f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL_N; 310cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_PAL_M) 311f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL_M; 312cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_PAL_Nc) 313f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL_COMB_N; 314cb7a01acSMauro Carvalho Chehab 315cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_PAL) 316f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL_BG; 317cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_NTSC) 318f5dde49bSLars-Peter Clausen return ADV7180_STD_NTSC_M; 319cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_SECAM) 320f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL_SECAM; 321cb7a01acSMauro Carvalho Chehab 322cb7a01acSMauro Carvalho Chehab return -EINVAL; 323cb7a01acSMauro Carvalho Chehab } 324cb7a01acSMauro Carvalho Chehab 325cb7a01acSMauro Carvalho Chehab static u32 adv7180_status_to_v4l2(u8 status1) 326cb7a01acSMauro Carvalho Chehab { 327cb7a01acSMauro Carvalho Chehab if (!(status1 & ADV7180_STATUS1_IN_LOCK)) 328cb7a01acSMauro Carvalho Chehab return V4L2_IN_ST_NO_SIGNAL; 329cb7a01acSMauro Carvalho Chehab 330cb7a01acSMauro Carvalho Chehab return 0; 331cb7a01acSMauro Carvalho Chehab } 332cb7a01acSMauro Carvalho Chehab 3333999e5d0SLars-Peter Clausen static int __adv7180_status(struct adv7180_state *state, u32 *status, 334cb7a01acSMauro Carvalho Chehab v4l2_std_id *std) 335cb7a01acSMauro Carvalho Chehab { 3363999e5d0SLars-Peter Clausen int status1 = adv7180_read(state, ADV7180_REG_STATUS1); 337cb7a01acSMauro Carvalho Chehab 338cb7a01acSMauro Carvalho Chehab if (status1 < 0) 339cb7a01acSMauro Carvalho Chehab return status1; 340cb7a01acSMauro Carvalho Chehab 341cb7a01acSMauro Carvalho Chehab if (status) 342cb7a01acSMauro Carvalho Chehab *status = adv7180_status_to_v4l2(status1); 343cb7a01acSMauro Carvalho Chehab if (std) 344cb7a01acSMauro Carvalho Chehab *std = adv7180_std_to_v4l2(status1); 345cb7a01acSMauro Carvalho Chehab 346cb7a01acSMauro Carvalho Chehab return 0; 347cb7a01acSMauro Carvalho Chehab } 348cb7a01acSMauro Carvalho Chehab 349cb7a01acSMauro Carvalho Chehab static inline struct adv7180_state *to_state(struct v4l2_subdev *sd) 350cb7a01acSMauro Carvalho Chehab { 351cb7a01acSMauro Carvalho Chehab return container_of(sd, struct adv7180_state, sd); 352cb7a01acSMauro Carvalho Chehab } 353cb7a01acSMauro Carvalho Chehab 354cb7a01acSMauro Carvalho Chehab static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) 355cb7a01acSMauro Carvalho Chehab { 356cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 357cb7a01acSMauro Carvalho Chehab int err = mutex_lock_interruptible(&state->mutex); 358cb7a01acSMauro Carvalho Chehab if (err) 359cb7a01acSMauro Carvalho Chehab return err; 360cb7a01acSMauro Carvalho Chehab 361937feeedSHans Verkuil if (state->streaming) { 362937feeedSHans Verkuil err = -EBUSY; 363937feeedSHans Verkuil goto unlock; 364937feeedSHans Verkuil } 365cb7a01acSMauro Carvalho Chehab 366937feeedSHans Verkuil err = adv7180_set_video_standard(state, 367937feeedSHans Verkuil ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM); 368937feeedSHans Verkuil if (err) 369937feeedSHans Verkuil goto unlock; 370937feeedSHans Verkuil 371937feeedSHans Verkuil msleep(100); 372937feeedSHans Verkuil __adv7180_status(state, NULL, std); 373937feeedSHans Verkuil 374937feeedSHans Verkuil err = v4l2_std_to_adv7180(state->curr_norm); 375937feeedSHans Verkuil if (err < 0) 376937feeedSHans Verkuil goto unlock; 377937feeedSHans Verkuil 378937feeedSHans Verkuil err = adv7180_set_video_standard(state, err); 379937feeedSHans Verkuil 380937feeedSHans Verkuil unlock: 381cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex); 382cb7a01acSMauro Carvalho Chehab return err; 383cb7a01acSMauro Carvalho Chehab } 384cb7a01acSMauro Carvalho Chehab 385cb7a01acSMauro Carvalho Chehab static int adv7180_s_routing(struct v4l2_subdev *sd, u32 input, 386cb7a01acSMauro Carvalho Chehab u32 output, u32 config) 387cb7a01acSMauro Carvalho Chehab { 388cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 389cb7a01acSMauro Carvalho Chehab int ret = mutex_lock_interruptible(&state->mutex); 390cb7a01acSMauro Carvalho Chehab 391cb7a01acSMauro Carvalho Chehab if (ret) 392cb7a01acSMauro Carvalho Chehab return ret; 393cb7a01acSMauro Carvalho Chehab 394f5dde49bSLars-Peter Clausen if (input > 31 || !(BIT(input) & state->chip_info->valid_input_mask)) { 395f5dde49bSLars-Peter Clausen ret = -EINVAL; 396cb7a01acSMauro Carvalho Chehab goto out; 397f5dde49bSLars-Peter Clausen } 398cb7a01acSMauro Carvalho Chehab 399f5dde49bSLars-Peter Clausen ret = state->chip_info->select_input(state, input); 400cb7a01acSMauro Carvalho Chehab 401f5dde49bSLars-Peter Clausen if (ret == 0) 402cb7a01acSMauro Carvalho Chehab state->input = input; 403cb7a01acSMauro Carvalho Chehab out: 404cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex); 405cb7a01acSMauro Carvalho Chehab return ret; 406cb7a01acSMauro Carvalho Chehab } 407cb7a01acSMauro Carvalho Chehab 408cb7a01acSMauro Carvalho Chehab static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status) 409cb7a01acSMauro Carvalho Chehab { 410cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 411cb7a01acSMauro Carvalho Chehab int ret = mutex_lock_interruptible(&state->mutex); 412cb7a01acSMauro Carvalho Chehab if (ret) 413cb7a01acSMauro Carvalho Chehab return ret; 414cb7a01acSMauro Carvalho Chehab 4153999e5d0SLars-Peter Clausen ret = __adv7180_status(state, status, NULL); 416cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex); 417cb7a01acSMauro Carvalho Chehab return ret; 418cb7a01acSMauro Carvalho Chehab } 419cb7a01acSMauro Carvalho Chehab 4203e35e33cSLars-Peter Clausen static int adv7180_program_std(struct adv7180_state *state) 4213e35e33cSLars-Peter Clausen { 4223e35e33cSLars-Peter Clausen int ret; 4233e35e33cSLars-Peter Clausen 4243e35e33cSLars-Peter Clausen ret = v4l2_std_to_adv7180(state->curr_norm); 4253e35e33cSLars-Peter Clausen if (ret < 0) 4263e35e33cSLars-Peter Clausen return ret; 4273e35e33cSLars-Peter Clausen 428f5dde49bSLars-Peter Clausen ret = adv7180_set_video_standard(state, ret); 4293e35e33cSLars-Peter Clausen if (ret < 0) 4303e35e33cSLars-Peter Clausen return ret; 4313e35e33cSLars-Peter Clausen return 0; 4323e35e33cSLars-Peter Clausen } 4333e35e33cSLars-Peter Clausen 434cb7a01acSMauro Carvalho Chehab static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std) 435cb7a01acSMauro Carvalho Chehab { 436cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 437cb7a01acSMauro Carvalho Chehab int ret = mutex_lock_interruptible(&state->mutex); 4383e35e33cSLars-Peter Clausen 439cb7a01acSMauro Carvalho Chehab if (ret) 440cb7a01acSMauro Carvalho Chehab return ret; 441cb7a01acSMauro Carvalho Chehab 4423e35e33cSLars-Peter Clausen /* Make sure we can support this std */ 443cb7a01acSMauro Carvalho Chehab ret = v4l2_std_to_adv7180(std); 444cb7a01acSMauro Carvalho Chehab if (ret < 0) 445cb7a01acSMauro Carvalho Chehab goto out; 446cb7a01acSMauro Carvalho Chehab 447cb7a01acSMauro Carvalho Chehab state->curr_norm = std; 4483e35e33cSLars-Peter Clausen 4493e35e33cSLars-Peter Clausen ret = adv7180_program_std(state); 450cb7a01acSMauro Carvalho Chehab out: 451cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex); 452cb7a01acSMauro Carvalho Chehab return ret; 453cb7a01acSMauro Carvalho Chehab } 454cb7a01acSMauro Carvalho Chehab 455d0fadc86SNiklas Söderlund static int adv7180_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm) 456d0fadc86SNiklas Söderlund { 457d0fadc86SNiklas Söderlund struct adv7180_state *state = to_state(sd); 458d0fadc86SNiklas Söderlund 459d0fadc86SNiklas Söderlund *norm = state->curr_norm; 460d0fadc86SNiklas Söderlund 461d0fadc86SNiklas Söderlund return 0; 462d0fadc86SNiklas Söderlund } 463d0fadc86SNiklas Söderlund 46465d9e14aSSteve Longerbeam static void adv7180_set_power_pin(struct adv7180_state *state, bool on) 46565d9e14aSSteve Longerbeam { 46665d9e14aSSteve Longerbeam if (!state->pwdn_gpio) 46765d9e14aSSteve Longerbeam return; 46865d9e14aSSteve Longerbeam 46965d9e14aSSteve Longerbeam if (on) { 47065d9e14aSSteve Longerbeam gpiod_set_value_cansleep(state->pwdn_gpio, 0); 47165d9e14aSSteve Longerbeam usleep_range(5000, 10000); 47265d9e14aSSteve Longerbeam } else { 47365d9e14aSSteve Longerbeam gpiod_set_value_cansleep(state->pwdn_gpio, 1); 47465d9e14aSSteve Longerbeam } 47565d9e14aSSteve Longerbeam } 47665d9e14aSSteve Longerbeam 4773999e5d0SLars-Peter Clausen static int adv7180_set_power(struct adv7180_state *state, bool on) 478e246c333SLars-Peter Clausen { 479e246c333SLars-Peter Clausen u8 val; 480b37135e3SLars-Peter Clausen int ret; 481e246c333SLars-Peter Clausen 482e246c333SLars-Peter Clausen if (on) 483e246c333SLars-Peter Clausen val = ADV7180_PWR_MAN_ON; 484e246c333SLars-Peter Clausen else 485e246c333SLars-Peter Clausen val = ADV7180_PWR_MAN_OFF; 486e246c333SLars-Peter Clausen 487b37135e3SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_PWR_MAN, val); 488b37135e3SLars-Peter Clausen if (ret) 489b37135e3SLars-Peter Clausen return ret; 490b37135e3SLars-Peter Clausen 491b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 492b37135e3SLars-Peter Clausen if (on) { 493b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0xDE, 0x02); 494b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0xD2, 0xF7); 495b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0xD8, 0x65); 496b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0xE0, 0x09); 497b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0x2C, 0x00); 498851a54efSLars-Peter Clausen if (state->field == V4L2_FIELD_NONE) 499851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x1D, 0x80); 500b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0x00, 0x00); 501b37135e3SLars-Peter Clausen } else { 502b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0x00, 0x80); 503b37135e3SLars-Peter Clausen } 504b37135e3SLars-Peter Clausen } 505b37135e3SLars-Peter Clausen 506b37135e3SLars-Peter Clausen return 0; 507e246c333SLars-Peter Clausen } 508e246c333SLars-Peter Clausen 509e246c333SLars-Peter Clausen static int adv7180_s_power(struct v4l2_subdev *sd, int on) 510e246c333SLars-Peter Clausen { 511e246c333SLars-Peter Clausen struct adv7180_state *state = to_state(sd); 512e246c333SLars-Peter Clausen int ret; 513e246c333SLars-Peter Clausen 514e246c333SLars-Peter Clausen ret = mutex_lock_interruptible(&state->mutex); 515e246c333SLars-Peter Clausen if (ret) 516e246c333SLars-Peter Clausen return ret; 517e246c333SLars-Peter Clausen 5183999e5d0SLars-Peter Clausen ret = adv7180_set_power(state, on); 519e246c333SLars-Peter Clausen if (ret == 0) 520e246c333SLars-Peter Clausen state->powered = on; 521e246c333SLars-Peter Clausen 522e246c333SLars-Peter Clausen mutex_unlock(&state->mutex); 523e246c333SLars-Peter Clausen return ret; 524e246c333SLars-Peter Clausen } 525e246c333SLars-Peter Clausen 526cb7a01acSMauro Carvalho Chehab static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl) 527cb7a01acSMauro Carvalho Chehab { 528cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = to_adv7180_sd(ctrl); 529cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 530cb7a01acSMauro Carvalho Chehab int ret = mutex_lock_interruptible(&state->mutex); 531cb7a01acSMauro Carvalho Chehab int val; 532cb7a01acSMauro Carvalho Chehab 533cb7a01acSMauro Carvalho Chehab if (ret) 534cb7a01acSMauro Carvalho Chehab return ret; 535cb7a01acSMauro Carvalho Chehab val = ctrl->val; 536cb7a01acSMauro Carvalho Chehab switch (ctrl->id) { 537cb7a01acSMauro Carvalho Chehab case V4L2_CID_BRIGHTNESS: 5383999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_BRI, val); 539cb7a01acSMauro Carvalho Chehab break; 540cb7a01acSMauro Carvalho Chehab case V4L2_CID_HUE: 541cb7a01acSMauro Carvalho Chehab /*Hue is inverted according to HSL chart */ 5423999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_HUE, -val); 543cb7a01acSMauro Carvalho Chehab break; 544cb7a01acSMauro Carvalho Chehab case V4L2_CID_CONTRAST: 5453999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_CON, val); 546cb7a01acSMauro Carvalho Chehab break; 547cb7a01acSMauro Carvalho Chehab case V4L2_CID_SATURATION: 548cb7a01acSMauro Carvalho Chehab /* 549cb7a01acSMauro Carvalho Chehab *This could be V4L2_CID_BLUE_BALANCE/V4L2_CID_RED_BALANCE 550cb7a01acSMauro Carvalho Chehab *Let's not confuse the user, everybody understands saturation 551cb7a01acSMauro Carvalho Chehab */ 5523999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_SD_SAT_CB, val); 553cb7a01acSMauro Carvalho Chehab if (ret < 0) 554cb7a01acSMauro Carvalho Chehab break; 5553999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_SD_SAT_CR, val); 556cb7a01acSMauro Carvalho Chehab break; 55708b717c2SLars-Peter Clausen case V4L2_CID_ADV_FAST_SWITCH: 55808b717c2SLars-Peter Clausen if (ctrl->val) { 55908b717c2SLars-Peter Clausen /* ADI required write */ 56008b717c2SLars-Peter Clausen adv7180_write(state, 0x80d9, 0x44); 56108b717c2SLars-Peter Clausen adv7180_write(state, ADV7180_REG_FLCONTROL, 56208b717c2SLars-Peter Clausen ADV7180_FLCONTROL_FL_ENABLE); 56308b717c2SLars-Peter Clausen } else { 56408b717c2SLars-Peter Clausen /* ADI required write */ 56508b717c2SLars-Peter Clausen adv7180_write(state, 0x80d9, 0xc4); 56608b717c2SLars-Peter Clausen adv7180_write(state, ADV7180_REG_FLCONTROL, 0x00); 56708b717c2SLars-Peter Clausen } 56808b717c2SLars-Peter Clausen break; 569cb7a01acSMauro Carvalho Chehab default: 570cb7a01acSMauro Carvalho Chehab ret = -EINVAL; 571cb7a01acSMauro Carvalho Chehab } 572cb7a01acSMauro Carvalho Chehab 573cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex); 574cb7a01acSMauro Carvalho Chehab return ret; 575cb7a01acSMauro Carvalho Chehab } 576cb7a01acSMauro Carvalho Chehab 577cb7a01acSMauro Carvalho Chehab static const struct v4l2_ctrl_ops adv7180_ctrl_ops = { 578cb7a01acSMauro Carvalho Chehab .s_ctrl = adv7180_s_ctrl, 579cb7a01acSMauro Carvalho Chehab }; 580cb7a01acSMauro Carvalho Chehab 58108b717c2SLars-Peter Clausen static const struct v4l2_ctrl_config adv7180_ctrl_fast_switch = { 58208b717c2SLars-Peter Clausen .ops = &adv7180_ctrl_ops, 58308b717c2SLars-Peter Clausen .id = V4L2_CID_ADV_FAST_SWITCH, 58408b717c2SLars-Peter Clausen .name = "Fast Switching", 58508b717c2SLars-Peter Clausen .type = V4L2_CTRL_TYPE_BOOLEAN, 58608b717c2SLars-Peter Clausen .min = 0, 58708b717c2SLars-Peter Clausen .max = 1, 58808b717c2SLars-Peter Clausen .step = 1, 58908b717c2SLars-Peter Clausen }; 59008b717c2SLars-Peter Clausen 591cb7a01acSMauro Carvalho Chehab static int adv7180_init_controls(struct adv7180_state *state) 592cb7a01acSMauro Carvalho Chehab { 593cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_init(&state->ctrl_hdl, 4); 594cb7a01acSMauro Carvalho Chehab 595cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, 596cb7a01acSMauro Carvalho Chehab V4L2_CID_BRIGHTNESS, ADV7180_BRI_MIN, 597cb7a01acSMauro Carvalho Chehab ADV7180_BRI_MAX, 1, ADV7180_BRI_DEF); 598cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, 599cb7a01acSMauro Carvalho Chehab V4L2_CID_CONTRAST, ADV7180_CON_MIN, 600cb7a01acSMauro Carvalho Chehab ADV7180_CON_MAX, 1, ADV7180_CON_DEF); 601cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, 602cb7a01acSMauro Carvalho Chehab V4L2_CID_SATURATION, ADV7180_SAT_MIN, 603cb7a01acSMauro Carvalho Chehab ADV7180_SAT_MAX, 1, ADV7180_SAT_DEF); 604cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, 605cb7a01acSMauro Carvalho Chehab V4L2_CID_HUE, ADV7180_HUE_MIN, 606cb7a01acSMauro Carvalho Chehab ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF); 60708b717c2SLars-Peter Clausen v4l2_ctrl_new_custom(&state->ctrl_hdl, &adv7180_ctrl_fast_switch, NULL); 60808b717c2SLars-Peter Clausen 609cb7a01acSMauro Carvalho Chehab state->sd.ctrl_handler = &state->ctrl_hdl; 610cb7a01acSMauro Carvalho Chehab if (state->ctrl_hdl.error) { 611cb7a01acSMauro Carvalho Chehab int err = state->ctrl_hdl.error; 612cb7a01acSMauro Carvalho Chehab 613cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_free(&state->ctrl_hdl); 614cb7a01acSMauro Carvalho Chehab return err; 615cb7a01acSMauro Carvalho Chehab } 616cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_setup(&state->ctrl_hdl); 617cb7a01acSMauro Carvalho Chehab 618cb7a01acSMauro Carvalho Chehab return 0; 619cb7a01acSMauro Carvalho Chehab } 620cb7a01acSMauro Carvalho Chehab static void adv7180_exit_controls(struct adv7180_state *state) 621cb7a01acSMauro Carvalho Chehab { 622cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_free(&state->ctrl_hdl); 623cb7a01acSMauro Carvalho Chehab } 624cb7a01acSMauro Carvalho Chehab 625d5d51a82SLars-Peter Clausen static int adv7180_enum_mbus_code(struct v4l2_subdev *sd, 626f7234138SHans Verkuil struct v4l2_subdev_pad_config *cfg, 627d5d51a82SLars-Peter Clausen struct v4l2_subdev_mbus_code_enum *code) 628cccb83f7SVladimir Barinov { 629d5d51a82SLars-Peter Clausen if (code->index != 0) 630cccb83f7SVladimir Barinov return -EINVAL; 631cccb83f7SVladimir Barinov 6326de690ddSNiklas Söderlund code->code = MEDIA_BUS_FMT_UYVY8_2X8; 633cccb83f7SVladimir Barinov 634cccb83f7SVladimir Barinov return 0; 635cccb83f7SVladimir Barinov } 636cccb83f7SVladimir Barinov 637cccb83f7SVladimir Barinov static int adv7180_mbus_fmt(struct v4l2_subdev *sd, 638cccb83f7SVladimir Barinov struct v4l2_mbus_framefmt *fmt) 639cccb83f7SVladimir Barinov { 640cccb83f7SVladimir Barinov struct adv7180_state *state = to_state(sd); 641cccb83f7SVladimir Barinov 6426de690ddSNiklas Söderlund fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; 643cccb83f7SVladimir Barinov fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; 644cccb83f7SVladimir Barinov fmt->width = 720; 645cccb83f7SVladimir Barinov fmt->height = state->curr_norm & V4L2_STD_525_60 ? 480 : 576; 646cccb83f7SVladimir Barinov 647cccb83f7SVladimir Barinov return 0; 648cccb83f7SVladimir Barinov } 649cccb83f7SVladimir Barinov 650851a54efSLars-Peter Clausen static int adv7180_set_field_mode(struct adv7180_state *state) 651851a54efSLars-Peter Clausen { 652851a54efSLars-Peter Clausen if (!(state->chip_info->flags & ADV7180_FLAG_I2P)) 653851a54efSLars-Peter Clausen return 0; 654851a54efSLars-Peter Clausen 655851a54efSLars-Peter Clausen if (state->field == V4L2_FIELD_NONE) { 656851a54efSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 657851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x01, 0x20); 658851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x02, 0x28); 659851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x03, 0x38); 660851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x04, 0x30); 661851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x05, 0x30); 662851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x06, 0x80); 663851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x07, 0x70); 664851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x08, 0x50); 665851a54efSLars-Peter Clausen } 666851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0xa3, 0x00); 667851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0x5b, 0x00); 668851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0x55, 0x80); 669851a54efSLars-Peter Clausen } else { 670851a54efSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 671851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x01, 0x18); 672851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x02, 0x18); 673851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x03, 0x30); 674851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x04, 0x20); 675851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x05, 0x28); 676851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x06, 0x40); 677851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x07, 0x58); 678851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x08, 0x30); 679851a54efSLars-Peter Clausen } 680851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0xa3, 0x70); 681851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0x5b, 0x80); 682851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0x55, 0x00); 683851a54efSLars-Peter Clausen } 684851a54efSLars-Peter Clausen 685851a54efSLars-Peter Clausen return 0; 686851a54efSLars-Peter Clausen } 687851a54efSLars-Peter Clausen 688d5d51a82SLars-Peter Clausen static int adv7180_get_pad_format(struct v4l2_subdev *sd, 689f7234138SHans Verkuil struct v4l2_subdev_pad_config *cfg, 690d5d51a82SLars-Peter Clausen struct v4l2_subdev_format *format) 691d5d51a82SLars-Peter Clausen { 692851a54efSLars-Peter Clausen struct adv7180_state *state = to_state(sd); 693851a54efSLars-Peter Clausen 694851a54efSLars-Peter Clausen if (format->which == V4L2_SUBDEV_FORMAT_TRY) { 695f7234138SHans Verkuil format->format = *v4l2_subdev_get_try_format(sd, cfg, 0); 696851a54efSLars-Peter Clausen } else { 697851a54efSLars-Peter Clausen adv7180_mbus_fmt(sd, &format->format); 698851a54efSLars-Peter Clausen format->format.field = state->field; 699851a54efSLars-Peter Clausen } 700851a54efSLars-Peter Clausen 701851a54efSLars-Peter Clausen return 0; 702d5d51a82SLars-Peter Clausen } 703d5d51a82SLars-Peter Clausen 704d5d51a82SLars-Peter Clausen static int adv7180_set_pad_format(struct v4l2_subdev *sd, 705f7234138SHans Verkuil struct v4l2_subdev_pad_config *cfg, 706d5d51a82SLars-Peter Clausen struct v4l2_subdev_format *format) 707d5d51a82SLars-Peter Clausen { 708851a54efSLars-Peter Clausen struct adv7180_state *state = to_state(sd); 709851a54efSLars-Peter Clausen struct v4l2_mbus_framefmt *framefmt; 710e0ad7a9bSNiklas Söderlund int ret; 711851a54efSLars-Peter Clausen 712851a54efSLars-Peter Clausen switch (format->format.field) { 713851a54efSLars-Peter Clausen case V4L2_FIELD_NONE: 714851a54efSLars-Peter Clausen if (!(state->chip_info->flags & ADV7180_FLAG_I2P)) 715851a54efSLars-Peter Clausen format->format.field = V4L2_FIELD_INTERLACED; 716851a54efSLars-Peter Clausen break; 717851a54efSLars-Peter Clausen default: 718851a54efSLars-Peter Clausen format->format.field = V4L2_FIELD_INTERLACED; 719851a54efSLars-Peter Clausen break; 720851a54efSLars-Peter Clausen } 721851a54efSLars-Peter Clausen 722e0ad7a9bSNiklas Söderlund ret = adv7180_mbus_fmt(sd, &format->format); 723e0ad7a9bSNiklas Söderlund 724851a54efSLars-Peter Clausen if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { 725851a54efSLars-Peter Clausen if (state->field != format->format.field) { 726851a54efSLars-Peter Clausen state->field = format->format.field; 727851a54efSLars-Peter Clausen adv7180_set_power(state, false); 728851a54efSLars-Peter Clausen adv7180_set_field_mode(state); 729851a54efSLars-Peter Clausen adv7180_set_power(state, true); 730851a54efSLars-Peter Clausen } 731851a54efSLars-Peter Clausen } else { 732f7234138SHans Verkuil framefmt = v4l2_subdev_get_try_format(sd, cfg, 0); 733851a54efSLars-Peter Clausen *framefmt = format->format; 734851a54efSLars-Peter Clausen } 735851a54efSLars-Peter Clausen 736e0ad7a9bSNiklas Söderlund return ret; 737d5d51a82SLars-Peter Clausen } 738d5d51a82SLars-Peter Clausen 739cccb83f7SVladimir Barinov static int adv7180_g_mbus_config(struct v4l2_subdev *sd, 740cccb83f7SVladimir Barinov struct v4l2_mbus_config *cfg) 741cccb83f7SVladimir Barinov { 742b37135e3SLars-Peter Clausen struct adv7180_state *state = to_state(sd); 743b37135e3SLars-Peter Clausen 744b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 745b37135e3SLars-Peter Clausen cfg->type = V4L2_MBUS_CSI2; 746b37135e3SLars-Peter Clausen cfg->flags = V4L2_MBUS_CSI2_1_LANE | 747b37135e3SLars-Peter Clausen V4L2_MBUS_CSI2_CHANNEL_0 | 748b37135e3SLars-Peter Clausen V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; 749b37135e3SLars-Peter Clausen } else { 750cccb83f7SVladimir Barinov /* 751cccb83f7SVladimir Barinov * The ADV7180 sensor supports BT.601/656 output modes. 752cccb83f7SVladimir Barinov * The BT.656 is default and not yet configurable by s/w. 753cccb83f7SVladimir Barinov */ 754cccb83f7SVladimir Barinov cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | 755cccb83f7SVladimir Barinov V4L2_MBUS_DATA_ACTIVE_HIGH; 756cccb83f7SVladimir Barinov cfg->type = V4L2_MBUS_BT656; 757b37135e3SLars-Peter Clausen } 758cccb83f7SVladimir Barinov 759cccb83f7SVladimir Barinov return 0; 760cccb83f7SVladimir Barinov } 761cccb83f7SVladimir Barinov 762ecf37493SHans Verkuil static int adv7180_g_pixelaspect(struct v4l2_subdev *sd, struct v4l2_fract *aspect) 76364b3df92SNiklas Söderlund { 76464b3df92SNiklas Söderlund struct adv7180_state *state = to_state(sd); 76564b3df92SNiklas Söderlund 76664b3df92SNiklas Söderlund if (state->curr_norm & V4L2_STD_525_60) { 767ecf37493SHans Verkuil aspect->numerator = 11; 768ecf37493SHans Verkuil aspect->denominator = 10; 76964b3df92SNiklas Söderlund } else { 770ecf37493SHans Verkuil aspect->numerator = 54; 771ecf37493SHans Verkuil aspect->denominator = 59; 77264b3df92SNiklas Söderlund } 77364b3df92SNiklas Söderlund 77464b3df92SNiklas Söderlund return 0; 77564b3df92SNiklas Söderlund } 77664b3df92SNiklas Söderlund 777bae4c757SNiklas Söderlund static int adv7180_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm) 778bae4c757SNiklas Söderlund { 779bae4c757SNiklas Söderlund *norm = V4L2_STD_ALL; 780bae4c757SNiklas Söderlund return 0; 781bae4c757SNiklas Söderlund } 782bae4c757SNiklas Söderlund 783937feeedSHans Verkuil static int adv7180_s_stream(struct v4l2_subdev *sd, int enable) 784937feeedSHans Verkuil { 785937feeedSHans Verkuil struct adv7180_state *state = to_state(sd); 786937feeedSHans Verkuil int ret; 787937feeedSHans Verkuil 788937feeedSHans Verkuil /* It's always safe to stop streaming, no need to take the lock */ 789937feeedSHans Verkuil if (!enable) { 790937feeedSHans Verkuil state->streaming = enable; 791937feeedSHans Verkuil return 0; 792937feeedSHans Verkuil } 793937feeedSHans Verkuil 794937feeedSHans Verkuil /* Must wait until querystd released the lock */ 795937feeedSHans Verkuil ret = mutex_lock_interruptible(&state->mutex); 796937feeedSHans Verkuil if (ret) 797937feeedSHans Verkuil return ret; 798937feeedSHans Verkuil state->streaming = enable; 799937feeedSHans Verkuil mutex_unlock(&state->mutex); 800937feeedSHans Verkuil return 0; 801937feeedSHans Verkuil } 802937feeedSHans Verkuil 803937feeedSHans Verkuil static int adv7180_subscribe_event(struct v4l2_subdev *sd, 804937feeedSHans Verkuil struct v4l2_fh *fh, 805937feeedSHans Verkuil struct v4l2_event_subscription *sub) 806937feeedSHans Verkuil { 807937feeedSHans Verkuil switch (sub->type) { 808937feeedSHans Verkuil case V4L2_EVENT_SOURCE_CHANGE: 809937feeedSHans Verkuil return v4l2_src_change_event_subdev_subscribe(sd, fh, sub); 810937feeedSHans Verkuil case V4L2_EVENT_CTRL: 811937feeedSHans Verkuil return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub); 812937feeedSHans Verkuil default: 813937feeedSHans Verkuil return -EINVAL; 814937feeedSHans Verkuil } 815937feeedSHans Verkuil } 816937feeedSHans Verkuil 817cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops adv7180_video_ops = { 8188774bed9SLaurent Pinchart .s_std = adv7180_s_std, 819d0fadc86SNiklas Söderlund .g_std = adv7180_g_std, 820cb7a01acSMauro Carvalho Chehab .querystd = adv7180_querystd, 821cb7a01acSMauro Carvalho Chehab .g_input_status = adv7180_g_input_status, 822cb7a01acSMauro Carvalho Chehab .s_routing = adv7180_s_routing, 823cccb83f7SVladimir Barinov .g_mbus_config = adv7180_g_mbus_config, 824ecf37493SHans Verkuil .g_pixelaspect = adv7180_g_pixelaspect, 825bae4c757SNiklas Söderlund .g_tvnorms = adv7180_g_tvnorms, 826937feeedSHans Verkuil .s_stream = adv7180_s_stream, 827cb7a01acSMauro Carvalho Chehab }; 828cb7a01acSMauro Carvalho Chehab 829cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_core_ops adv7180_core_ops = { 830e246c333SLars-Peter Clausen .s_power = adv7180_s_power, 831937feeedSHans Verkuil .subscribe_event = adv7180_subscribe_event, 832937feeedSHans Verkuil .unsubscribe_event = v4l2_event_subdev_unsubscribe, 833cb7a01acSMauro Carvalho Chehab }; 834cb7a01acSMauro Carvalho Chehab 835d5d51a82SLars-Peter Clausen static const struct v4l2_subdev_pad_ops adv7180_pad_ops = { 836d5d51a82SLars-Peter Clausen .enum_mbus_code = adv7180_enum_mbus_code, 837d5d51a82SLars-Peter Clausen .set_fmt = adv7180_set_pad_format, 838d5d51a82SLars-Peter Clausen .get_fmt = adv7180_get_pad_format, 839d5d51a82SLars-Peter Clausen }; 840d5d51a82SLars-Peter Clausen 841cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops adv7180_ops = { 842cb7a01acSMauro Carvalho Chehab .core = &adv7180_core_ops, 843cb7a01acSMauro Carvalho Chehab .video = &adv7180_video_ops, 844d5d51a82SLars-Peter Clausen .pad = &adv7180_pad_ops, 845cb7a01acSMauro Carvalho Chehab }; 846cb7a01acSMauro Carvalho Chehab 8470c25534dSLars-Peter Clausen static irqreturn_t adv7180_irq(int irq, void *devid) 848cb7a01acSMauro Carvalho Chehab { 8490c25534dSLars-Peter Clausen struct adv7180_state *state = devid; 850cb7a01acSMauro Carvalho Chehab u8 isr3; 851cb7a01acSMauro Carvalho Chehab 852cb7a01acSMauro Carvalho Chehab mutex_lock(&state->mutex); 8533999e5d0SLars-Peter Clausen isr3 = adv7180_read(state, ADV7180_REG_ISR3); 854cb7a01acSMauro Carvalho Chehab /* clear */ 8553999e5d0SLars-Peter Clausen adv7180_write(state, ADV7180_REG_ICR3, isr3); 856cb7a01acSMauro Carvalho Chehab 857937feeedSHans Verkuil if (isr3 & ADV7180_IRQ3_AD_CHANGE) { 858937feeedSHans Verkuil static const struct v4l2_event src_ch = { 859937feeedSHans Verkuil .type = V4L2_EVENT_SOURCE_CHANGE, 860937feeedSHans Verkuil .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, 861937feeedSHans Verkuil }; 862937feeedSHans Verkuil 863937feeedSHans Verkuil v4l2_subdev_notify_event(&state->sd, &src_ch); 864937feeedSHans Verkuil } 865cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex); 866cb7a01acSMauro Carvalho Chehab 867cb7a01acSMauro Carvalho Chehab return IRQ_HANDLED; 868cb7a01acSMauro Carvalho Chehab } 869cb7a01acSMauro Carvalho Chehab 870f5dde49bSLars-Peter Clausen static int adv7180_init(struct adv7180_state *state) 871f5dde49bSLars-Peter Clausen { 872f5dde49bSLars-Peter Clausen int ret; 873f5dde49bSLars-Peter Clausen 874f5dde49bSLars-Peter Clausen /* ITU-R BT.656-4 compatible */ 875f5dde49bSLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 876f5dde49bSLars-Peter Clausen ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS); 877f5dde49bSLars-Peter Clausen if (ret < 0) 878f5dde49bSLars-Peter Clausen return ret; 879f5dde49bSLars-Peter Clausen 880f5dde49bSLars-Peter Clausen /* Manually set V bit end position in NTSC mode */ 881f5dde49bSLars-Peter Clausen return adv7180_write(state, ADV7180_REG_NTSC_V_BIT_END, 882f5dde49bSLars-Peter Clausen ADV7180_NTSC_V_BIT_END_MANUAL_NVEND); 883f5dde49bSLars-Peter Clausen } 884f5dde49bSLars-Peter Clausen 885f5dde49bSLars-Peter Clausen static int adv7180_set_std(struct adv7180_state *state, unsigned int std) 886f5dde49bSLars-Peter Clausen { 887f5dde49bSLars-Peter Clausen return adv7180_write(state, ADV7180_REG_INPUT_CONTROL, 888f5dde49bSLars-Peter Clausen (std << 4) | state->input); 889f5dde49bSLars-Peter Clausen } 890f5dde49bSLars-Peter Clausen 891f5dde49bSLars-Peter Clausen static int adv7180_select_input(struct adv7180_state *state, unsigned int input) 892f5dde49bSLars-Peter Clausen { 893f5dde49bSLars-Peter Clausen int ret; 894f5dde49bSLars-Peter Clausen 895f5dde49bSLars-Peter Clausen ret = adv7180_read(state, ADV7180_REG_INPUT_CONTROL); 896f5dde49bSLars-Peter Clausen if (ret < 0) 897f5dde49bSLars-Peter Clausen return ret; 898f5dde49bSLars-Peter Clausen 899f5dde49bSLars-Peter Clausen ret &= ~ADV7180_INPUT_CONTROL_INSEL_MASK; 900f5dde49bSLars-Peter Clausen ret |= input; 901f5dde49bSLars-Peter Clausen return adv7180_write(state, ADV7180_REG_INPUT_CONTROL, ret); 902f5dde49bSLars-Peter Clausen } 903f5dde49bSLars-Peter Clausen 904c5ef8f8cSLars-Peter Clausen static int adv7182_init(struct adv7180_state *state) 905c5ef8f8cSLars-Peter Clausen { 906b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) 907b37135e3SLars-Peter Clausen adv7180_write(state, ADV7180_REG_CSI_SLAVE_ADDR, 908b37135e3SLars-Peter Clausen ADV7180_DEFAULT_CSI_I2C_ADDR << 1); 909b37135e3SLars-Peter Clausen 910851a54efSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_I2P) 911851a54efSLars-Peter Clausen adv7180_write(state, ADV7180_REG_VPP_SLAVE_ADDR, 912851a54efSLars-Peter Clausen ADV7180_DEFAULT_VPP_I2C_ADDR << 1); 913851a54efSLars-Peter Clausen 914bf7dcb80SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_V2) { 915bf7dcb80SLars-Peter Clausen /* ADI recommended writes for improved video quality */ 916bf7dcb80SLars-Peter Clausen adv7180_write(state, 0x0080, 0x51); 917bf7dcb80SLars-Peter Clausen adv7180_write(state, 0x0081, 0x51); 918bf7dcb80SLars-Peter Clausen adv7180_write(state, 0x0082, 0x68); 919bf7dcb80SLars-Peter Clausen } 920bf7dcb80SLars-Peter Clausen 921c5ef8f8cSLars-Peter Clausen /* ADI required writes */ 922b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 923ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_OUTPUT_CONTROL, 0x4e); 924ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 0x57); 925ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_CTRL_2, 0xc0); 926b37135e3SLars-Peter Clausen } else { 927b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_V2) 928ce5d6290SSteve Longerbeam adv7180_write(state, 929ce5d6290SSteve Longerbeam ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 930ce5d6290SSteve Longerbeam 0x17); 931b37135e3SLars-Peter Clausen else 932ce5d6290SSteve Longerbeam adv7180_write(state, 933ce5d6290SSteve Longerbeam ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 934ce5d6290SSteve Longerbeam 0x07); 935ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_OUTPUT_CONTROL, 0x0c); 936ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_CTRL_2, 0x40); 937b37135e3SLars-Peter Clausen } 938b37135e3SLars-Peter Clausen 939b37135e3SLars-Peter Clausen adv7180_write(state, 0x0013, 0x00); 940c5ef8f8cSLars-Peter Clausen 941c5ef8f8cSLars-Peter Clausen return 0; 942c5ef8f8cSLars-Peter Clausen } 943c5ef8f8cSLars-Peter Clausen 944c5ef8f8cSLars-Peter Clausen static int adv7182_set_std(struct adv7180_state *state, unsigned int std) 945c5ef8f8cSLars-Peter Clausen { 946c5ef8f8cSLars-Peter Clausen return adv7180_write(state, ADV7182_REG_INPUT_VIDSEL, std << 4); 947c5ef8f8cSLars-Peter Clausen } 948c5ef8f8cSLars-Peter Clausen 949c5ef8f8cSLars-Peter Clausen enum adv7182_input_type { 950c5ef8f8cSLars-Peter Clausen ADV7182_INPUT_TYPE_CVBS, 951c5ef8f8cSLars-Peter Clausen ADV7182_INPUT_TYPE_DIFF_CVBS, 952c5ef8f8cSLars-Peter Clausen ADV7182_INPUT_TYPE_SVIDEO, 953c5ef8f8cSLars-Peter Clausen ADV7182_INPUT_TYPE_YPBPR, 954c5ef8f8cSLars-Peter Clausen }; 955c5ef8f8cSLars-Peter Clausen 956c5ef8f8cSLars-Peter Clausen static enum adv7182_input_type adv7182_get_input_type(unsigned int input) 957c5ef8f8cSLars-Peter Clausen { 958c5ef8f8cSLars-Peter Clausen switch (input) { 959c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN1: 960c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN2: 961c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN3: 962c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN4: 963c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN5: 964c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN6: 965c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN7: 966c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN8: 967c5ef8f8cSLars-Peter Clausen return ADV7182_INPUT_TYPE_CVBS; 968c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_SVIDEO_AIN1_AIN2: 969c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_SVIDEO_AIN3_AIN4: 970c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_SVIDEO_AIN5_AIN6: 971c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_SVIDEO_AIN7_AIN8: 972c5ef8f8cSLars-Peter Clausen return ADV7182_INPUT_TYPE_SVIDEO; 973c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3: 974c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6: 975c5ef8f8cSLars-Peter Clausen return ADV7182_INPUT_TYPE_YPBPR; 976c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2: 977c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4: 978c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6: 979c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8: 980c5ef8f8cSLars-Peter Clausen return ADV7182_INPUT_TYPE_DIFF_CVBS; 981c5ef8f8cSLars-Peter Clausen default: /* Will never happen */ 982c5ef8f8cSLars-Peter Clausen return 0; 983c5ef8f8cSLars-Peter Clausen } 984c5ef8f8cSLars-Peter Clausen } 985c5ef8f8cSLars-Peter Clausen 986c5ef8f8cSLars-Peter Clausen /* ADI recommended writes to registers 0x52, 0x53, 0x54 */ 987c5ef8f8cSLars-Peter Clausen static unsigned int adv7182_lbias_settings[][3] = { 988c5ef8f8cSLars-Peter Clausen [ADV7182_INPUT_TYPE_CVBS] = { 0xCB, 0x4E, 0x80 }, 989c5ef8f8cSLars-Peter Clausen [ADV7182_INPUT_TYPE_DIFF_CVBS] = { 0xC0, 0x4E, 0x80 }, 990c5ef8f8cSLars-Peter Clausen [ADV7182_INPUT_TYPE_SVIDEO] = { 0x0B, 0xCE, 0x80 }, 991c5ef8f8cSLars-Peter Clausen [ADV7182_INPUT_TYPE_YPBPR] = { 0x0B, 0x4E, 0xC0 }, 992c5ef8f8cSLars-Peter Clausen }; 993c5ef8f8cSLars-Peter Clausen 994bf7dcb80SLars-Peter Clausen static unsigned int adv7280_lbias_settings[][3] = { 995bf7dcb80SLars-Peter Clausen [ADV7182_INPUT_TYPE_CVBS] = { 0xCD, 0x4E, 0x80 }, 996bf7dcb80SLars-Peter Clausen [ADV7182_INPUT_TYPE_DIFF_CVBS] = { 0xC0, 0x4E, 0x80 }, 997bf7dcb80SLars-Peter Clausen [ADV7182_INPUT_TYPE_SVIDEO] = { 0x0B, 0xCE, 0x80 }, 998bf7dcb80SLars-Peter Clausen [ADV7182_INPUT_TYPE_YPBPR] = { 0x0B, 0x4E, 0xC0 }, 999bf7dcb80SLars-Peter Clausen }; 1000bf7dcb80SLars-Peter Clausen 1001c5ef8f8cSLars-Peter Clausen static int adv7182_select_input(struct adv7180_state *state, unsigned int input) 1002c5ef8f8cSLars-Peter Clausen { 1003c5ef8f8cSLars-Peter Clausen enum adv7182_input_type input_type; 1004c5ef8f8cSLars-Peter Clausen unsigned int *lbias; 1005c5ef8f8cSLars-Peter Clausen unsigned int i; 1006c5ef8f8cSLars-Peter Clausen int ret; 1007c5ef8f8cSLars-Peter Clausen 1008c5ef8f8cSLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL, input); 1009c5ef8f8cSLars-Peter Clausen if (ret) 1010c5ef8f8cSLars-Peter Clausen return ret; 1011c5ef8f8cSLars-Peter Clausen 1012c5ef8f8cSLars-Peter Clausen /* Reset clamp circuitry - ADI recommended writes */ 1013ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_RST_CLAMP, 0x00); 1014ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_RST_CLAMP, 0xff); 1015c5ef8f8cSLars-Peter Clausen 1016c5ef8f8cSLars-Peter Clausen input_type = adv7182_get_input_type(input); 1017c5ef8f8cSLars-Peter Clausen 1018c5ef8f8cSLars-Peter Clausen switch (input_type) { 1019c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_TYPE_CVBS: 1020c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_TYPE_DIFF_CVBS: 1021c5ef8f8cSLars-Peter Clausen /* ADI recommends to use the SH1 filter */ 1022ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_SHAP_FILTER_CTL_1, 0x41); 1023c5ef8f8cSLars-Peter Clausen break; 1024c5ef8f8cSLars-Peter Clausen default: 1025ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_SHAP_FILTER_CTL_1, 0x01); 1026c5ef8f8cSLars-Peter Clausen break; 1027c5ef8f8cSLars-Peter Clausen } 1028c5ef8f8cSLars-Peter Clausen 1029bf7dcb80SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_V2) 1030bf7dcb80SLars-Peter Clausen lbias = adv7280_lbias_settings[input_type]; 1031bf7dcb80SLars-Peter Clausen else 1032c5ef8f8cSLars-Peter Clausen lbias = adv7182_lbias_settings[input_type]; 1033c5ef8f8cSLars-Peter Clausen 1034c5ef8f8cSLars-Peter Clausen for (i = 0; i < ARRAY_SIZE(adv7182_lbias_settings[0]); i++) 1035ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_CVBS_TRIM + i, lbias[i]); 1036c5ef8f8cSLars-Peter Clausen 1037c5ef8f8cSLars-Peter Clausen if (input_type == ADV7182_INPUT_TYPE_DIFF_CVBS) { 1038c5ef8f8cSLars-Peter Clausen /* ADI required writes to make differential CVBS work */ 1039ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_RES_CIR, 0xa8); 1040ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_CLAMP_ADJ, 0x90); 1041ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_DIFF_MODE, 0xb0); 1042ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_AGC_ADJ1, 0x08); 1043ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_AGC_ADJ2, 0xa0); 1044c5ef8f8cSLars-Peter Clausen } else { 1045ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_RES_CIR, 0xf0); 1046ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_CLAMP_ADJ, 0xd0); 1047ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_DIFF_MODE, 0x10); 1048ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_AGC_ADJ1, 0x9c); 1049ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_AGC_ADJ2, 0x00); 1050c5ef8f8cSLars-Peter Clausen } 1051c5ef8f8cSLars-Peter Clausen 1052c5ef8f8cSLars-Peter Clausen return 0; 1053c5ef8f8cSLars-Peter Clausen } 1054c5ef8f8cSLars-Peter Clausen 1055f5dde49bSLars-Peter Clausen static const struct adv7180_chip_info adv7180_info = { 1056f5dde49bSLars-Peter Clausen .flags = ADV7180_FLAG_RESET_POWERED, 1057f5dde49bSLars-Peter Clausen /* We cannot discriminate between LQFP and 40-pin LFCSP, so accept 1058f5dde49bSLars-Peter Clausen * all inputs and let the card driver take care of validation 1059f5dde49bSLars-Peter Clausen */ 1060f5dde49bSLars-Peter Clausen .valid_input_mask = BIT(ADV7180_INPUT_CVBS_AIN1) | 1061f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_CVBS_AIN2) | 1062f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_CVBS_AIN3) | 1063f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_CVBS_AIN4) | 1064f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_CVBS_AIN5) | 1065f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_CVBS_AIN6) | 1066f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_SVIDEO_AIN1_AIN2) | 1067f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_SVIDEO_AIN3_AIN4) | 1068f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_SVIDEO_AIN5_AIN6) | 1069f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_YPRPB_AIN1_AIN2_AIN3) | 1070f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_YPRPB_AIN4_AIN5_AIN6), 1071f5dde49bSLars-Peter Clausen .init = adv7180_init, 1072f5dde49bSLars-Peter Clausen .set_std = adv7180_set_std, 1073f5dde49bSLars-Peter Clausen .select_input = adv7180_select_input, 1074f5dde49bSLars-Peter Clausen }; 1075f5dde49bSLars-Peter Clausen 1076c5ef8f8cSLars-Peter Clausen static const struct adv7180_chip_info adv7182_info = { 1077c5ef8f8cSLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1078c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1079c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) | 1080c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) | 1081c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1082c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 1083c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | 1084c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 1085c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4), 1086c5ef8f8cSLars-Peter Clausen .init = adv7182_init, 1087c5ef8f8cSLars-Peter Clausen .set_std = adv7182_set_std, 1088c5ef8f8cSLars-Peter Clausen .select_input = adv7182_select_input, 1089c5ef8f8cSLars-Peter Clausen }; 1090c5ef8f8cSLars-Peter Clausen 1091bf7dcb80SLars-Peter Clausen static const struct adv7180_chip_info adv7280_info = { 1092851a54efSLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P, 1093bf7dcb80SLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1094bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1095bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) | 1096bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) | 1097bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1098bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 1099bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3), 1100bf7dcb80SLars-Peter Clausen .init = adv7182_init, 1101bf7dcb80SLars-Peter Clausen .set_std = adv7182_set_std, 1102bf7dcb80SLars-Peter Clausen .select_input = adv7182_select_input, 1103bf7dcb80SLars-Peter Clausen }; 1104bf7dcb80SLars-Peter Clausen 1105b37135e3SLars-Peter Clausen static const struct adv7180_chip_info adv7280_m_info = { 1106851a54efSLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P, 1107b37135e3SLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1108b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1109b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) | 1110b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) | 1111b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN5) | 1112b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN6) | 1113b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) | 1114b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) | 1115b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1116b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 1117b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN5_AIN6) | 1118b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 1119b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | 1120b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6), 1121b37135e3SLars-Peter Clausen .init = adv7182_init, 1122b37135e3SLars-Peter Clausen .set_std = adv7182_set_std, 1123b37135e3SLars-Peter Clausen .select_input = adv7182_select_input, 1124b37135e3SLars-Peter Clausen }; 1125b37135e3SLars-Peter Clausen 1126bf7dcb80SLars-Peter Clausen static const struct adv7180_chip_info adv7281_info = { 1127b37135e3SLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2, 1128bf7dcb80SLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1129bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1130bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) | 1131bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) | 1132bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1133bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 1134bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 1135bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), 1136bf7dcb80SLars-Peter Clausen .init = adv7182_init, 1137bf7dcb80SLars-Peter Clausen .set_std = adv7182_set_std, 1138bf7dcb80SLars-Peter Clausen .select_input = adv7182_select_input, 1139bf7dcb80SLars-Peter Clausen }; 1140bf7dcb80SLars-Peter Clausen 1141b37135e3SLars-Peter Clausen static const struct adv7180_chip_info adv7281_m_info = { 1142b37135e3SLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2, 1143b37135e3SLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1144b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1145b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) | 1146b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) | 1147b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) | 1148b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) | 1149b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1150b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 1151b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 1152b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | 1153b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 1154b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) | 1155b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), 1156b37135e3SLars-Peter Clausen .init = adv7182_init, 1157b37135e3SLars-Peter Clausen .set_std = adv7182_set_std, 1158b37135e3SLars-Peter Clausen .select_input = adv7182_select_input, 1159b37135e3SLars-Peter Clausen }; 1160b37135e3SLars-Peter Clausen 1161b37135e3SLars-Peter Clausen static const struct adv7180_chip_info adv7281_ma_info = { 1162b37135e3SLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2, 1163b37135e3SLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1164b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1165b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) | 1166b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) | 1167b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN5) | 1168b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN6) | 1169b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) | 1170b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) | 1171b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1172b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 1173b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN5_AIN6) | 1174b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 1175b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | 1176b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6) | 1177b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 1178b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) | 1179b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6) | 1180b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), 1181b37135e3SLars-Peter Clausen .init = adv7182_init, 1182b37135e3SLars-Peter Clausen .set_std = adv7182_set_std, 1183b37135e3SLars-Peter Clausen .select_input = adv7182_select_input, 1184b37135e3SLars-Peter Clausen }; 1185b37135e3SLars-Peter Clausen 1186851a54efSLars-Peter Clausen static const struct adv7180_chip_info adv7282_info = { 1187851a54efSLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P, 1188851a54efSLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1189851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1190851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) | 1191851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) | 1192851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1193851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 1194851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 1195851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), 1196851a54efSLars-Peter Clausen .init = adv7182_init, 1197851a54efSLars-Peter Clausen .set_std = adv7182_set_std, 1198851a54efSLars-Peter Clausen .select_input = adv7182_select_input, 1199851a54efSLars-Peter Clausen }; 1200851a54efSLars-Peter Clausen 1201851a54efSLars-Peter Clausen static const struct adv7180_chip_info adv7282_m_info = { 1202851a54efSLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P, 1203851a54efSLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1204851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1205851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) | 1206851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) | 1207851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) | 1208851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) | 1209851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1210851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 1211851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 1212851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 1213851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) | 1214851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), 1215851a54efSLars-Peter Clausen .init = adv7182_init, 1216851a54efSLars-Peter Clausen .set_std = adv7182_set_std, 1217851a54efSLars-Peter Clausen .select_input = adv7182_select_input, 1218851a54efSLars-Peter Clausen }; 1219851a54efSLars-Peter Clausen 12203999e5d0SLars-Peter Clausen static int init_device(struct adv7180_state *state) 1221cb7a01acSMauro Carvalho Chehab { 1222cb7a01acSMauro Carvalho Chehab int ret; 1223cb7a01acSMauro Carvalho Chehab 12243999e5d0SLars-Peter Clausen mutex_lock(&state->mutex); 12253999e5d0SLars-Peter Clausen 122665d9e14aSSteve Longerbeam adv7180_set_power_pin(state, true); 122765d9e14aSSteve Longerbeam 1228c18818e9SLars-Peter Clausen adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES); 122916dfe72fSUlrich Hecht usleep_range(5000, 10000); 1230c18818e9SLars-Peter Clausen 1231f5dde49bSLars-Peter Clausen ret = state->chip_info->init(state); 12323e35e33cSLars-Peter Clausen if (ret) 12333999e5d0SLars-Peter Clausen goto out_unlock; 1234cb7a01acSMauro Carvalho Chehab 1235f5dde49bSLars-Peter Clausen ret = adv7180_program_std(state); 1236f5dde49bSLars-Peter Clausen if (ret) 12373999e5d0SLars-Peter Clausen goto out_unlock; 1238cb7a01acSMauro Carvalho Chehab 1239851a54efSLars-Peter Clausen adv7180_set_field_mode(state); 1240851a54efSLars-Peter Clausen 1241cb7a01acSMauro Carvalho Chehab /* register for interrupts */ 1242cb7a01acSMauro Carvalho Chehab if (state->irq > 0) { 1243cb7a01acSMauro Carvalho Chehab /* config the Interrupt pin to be active low */ 12443999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_ICONF1, 1245cb7a01acSMauro Carvalho Chehab ADV7180_ICONF1_ACTIVE_LOW | 1246cb7a01acSMauro Carvalho Chehab ADV7180_ICONF1_PSYNC_ONLY); 1247cb7a01acSMauro Carvalho Chehab if (ret < 0) 12483999e5d0SLars-Peter Clausen goto out_unlock; 1249cb7a01acSMauro Carvalho Chehab 12503999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_IMR1, 0); 1251cb7a01acSMauro Carvalho Chehab if (ret < 0) 12523999e5d0SLars-Peter Clausen goto out_unlock; 1253cb7a01acSMauro Carvalho Chehab 12543999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_IMR2, 0); 1255cb7a01acSMauro Carvalho Chehab if (ret < 0) 12563999e5d0SLars-Peter Clausen goto out_unlock; 1257cb7a01acSMauro Carvalho Chehab 1258cb7a01acSMauro Carvalho Chehab /* enable AD change interrupts interrupts */ 12593999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_IMR3, 1260cb7a01acSMauro Carvalho Chehab ADV7180_IRQ3_AD_CHANGE); 1261cb7a01acSMauro Carvalho Chehab if (ret < 0) 12623999e5d0SLars-Peter Clausen goto out_unlock; 1263cb7a01acSMauro Carvalho Chehab 12643999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_IMR4, 0); 1265cb7a01acSMauro Carvalho Chehab if (ret < 0) 12663999e5d0SLars-Peter Clausen goto out_unlock; 1267cb7a01acSMauro Carvalho Chehab } 1268cb7a01acSMauro Carvalho Chehab 12693999e5d0SLars-Peter Clausen out_unlock: 12703999e5d0SLars-Peter Clausen mutex_unlock(&state->mutex); 1271df065b37SAlexey Khoroshilov 1272df065b37SAlexey Khoroshilov return ret; 1273cb7a01acSMauro Carvalho Chehab } 1274cb7a01acSMauro Carvalho Chehab 12754c62e976SGreg Kroah-Hartman static int adv7180_probe(struct i2c_client *client, 1276cb7a01acSMauro Carvalho Chehab const struct i2c_device_id *id) 1277cb7a01acSMauro Carvalho Chehab { 1278cb7a01acSMauro Carvalho Chehab struct adv7180_state *state; 1279cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd; 1280cb7a01acSMauro Carvalho Chehab int ret; 1281cb7a01acSMauro Carvalho Chehab 1282cb7a01acSMauro Carvalho Chehab /* Check if the adapter supports the needed features */ 1283cb7a01acSMauro Carvalho Chehab if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 1284cb7a01acSMauro Carvalho Chehab return -EIO; 1285cb7a01acSMauro Carvalho Chehab 1286cb7a01acSMauro Carvalho Chehab v4l_info(client, "chip found @ 0x%02x (%s)\n", 1287cb7a01acSMauro Carvalho Chehab client->addr, client->adapter->name); 1288cb7a01acSMauro Carvalho Chehab 1289c02b211dSLaurent Pinchart state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL); 12907657e064SFabio Estevam if (state == NULL) 12917657e064SFabio Estevam return -ENOMEM; 1292cb7a01acSMauro Carvalho Chehab 12933999e5d0SLars-Peter Clausen state->client = client; 1294851a54efSLars-Peter Clausen state->field = V4L2_FIELD_INTERLACED; 1295f5dde49bSLars-Peter Clausen state->chip_info = (struct adv7180_chip_info *)id->driver_data; 12963999e5d0SLars-Peter Clausen 129765d9e14aSSteve Longerbeam state->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown", 129865d9e14aSSteve Longerbeam GPIOD_OUT_HIGH); 129965d9e14aSSteve Longerbeam if (IS_ERR(state->pwdn_gpio)) { 130065d9e14aSSteve Longerbeam ret = PTR_ERR(state->pwdn_gpio); 130165d9e14aSSteve Longerbeam v4l_err(client, "request for power pin failed: %d\n", ret); 130265d9e14aSSteve Longerbeam return ret; 130365d9e14aSSteve Longerbeam } 130465d9e14aSSteve Longerbeam 1305b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 1306b37135e3SLars-Peter Clausen state->csi_client = i2c_new_dummy(client->adapter, 1307b37135e3SLars-Peter Clausen ADV7180_DEFAULT_CSI_I2C_ADDR); 1308b37135e3SLars-Peter Clausen if (!state->csi_client) 1309b37135e3SLars-Peter Clausen return -ENOMEM; 1310b37135e3SLars-Peter Clausen } 1311b37135e3SLars-Peter Clausen 1312851a54efSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_I2P) { 1313851a54efSLars-Peter Clausen state->vpp_client = i2c_new_dummy(client->adapter, 1314851a54efSLars-Peter Clausen ADV7180_DEFAULT_VPP_I2C_ADDR); 1315851a54efSLars-Peter Clausen if (!state->vpp_client) { 1316851a54efSLars-Peter Clausen ret = -ENOMEM; 1317851a54efSLars-Peter Clausen goto err_unregister_csi_client; 1318851a54efSLars-Peter Clausen } 1319851a54efSLars-Peter Clausen } 1320851a54efSLars-Peter Clausen 1321cb7a01acSMauro Carvalho Chehab state->irq = client->irq; 1322cb7a01acSMauro Carvalho Chehab mutex_init(&state->mutex); 1323937feeedSHans Verkuil state->curr_norm = V4L2_STD_NTSC; 1324f5dde49bSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_RESET_POWERED) 1325e246c333SLars-Peter Clausen state->powered = true; 1326f5dde49bSLars-Peter Clausen else 1327f5dde49bSLars-Peter Clausen state->powered = false; 1328cb7a01acSMauro Carvalho Chehab state->input = 0; 1329cb7a01acSMauro Carvalho Chehab sd = &state->sd; 1330cb7a01acSMauro Carvalho Chehab v4l2_i2c_subdev_init(sd, client, &adv7180_ops); 13315cc72c47SAkinobu Mita sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; 1332cb7a01acSMauro Carvalho Chehab 1333cb7a01acSMauro Carvalho Chehab ret = adv7180_init_controls(state); 1334cb7a01acSMauro Carvalho Chehab if (ret) 1335851a54efSLars-Peter Clausen goto err_unregister_vpp_client; 1336d5d51a82SLars-Peter Clausen 1337d5d51a82SLars-Peter Clausen state->pad.flags = MEDIA_PAD_FL_SOURCE; 1338ca0fa5f0SHans Verkuil sd->entity.function = MEDIA_ENT_F_ATV_DECODER; 1339ab22e77cSMauro Carvalho Chehab ret = media_entity_pads_init(&sd->entity, 1, &state->pad); 1340cb7a01acSMauro Carvalho Chehab if (ret) 1341cb7a01acSMauro Carvalho Chehab goto err_free_ctrl; 1342fa5b7945SLars-Peter Clausen 1343d5d51a82SLars-Peter Clausen ret = init_device(state); 1344d5d51a82SLars-Peter Clausen if (ret) 1345d5d51a82SLars-Peter Clausen goto err_media_entity_cleanup; 1346d5d51a82SLars-Peter Clausen 1347fa5721d1SLars-Peter Clausen if (state->irq) { 1348fa5721d1SLars-Peter Clausen ret = request_threaded_irq(client->irq, NULL, adv7180_irq, 1349f3e991d4SLars-Peter Clausen IRQF_ONESHOT | IRQF_TRIGGER_FALLING, 1350f3e991d4SLars-Peter Clausen KBUILD_MODNAME, state); 1351fa5721d1SLars-Peter Clausen if (ret) 1352d5d51a82SLars-Peter Clausen goto err_media_entity_cleanup; 1353fa5721d1SLars-Peter Clausen } 1354fa5721d1SLars-Peter Clausen 1355fa5b7945SLars-Peter Clausen ret = v4l2_async_register_subdev(sd); 1356fa5b7945SLars-Peter Clausen if (ret) 1357fa5b7945SLars-Peter Clausen goto err_free_irq; 1358fa5b7945SLars-Peter Clausen 1359cb7a01acSMauro Carvalho Chehab return 0; 1360cb7a01acSMauro Carvalho Chehab 1361fa5b7945SLars-Peter Clausen err_free_irq: 1362fa5b7945SLars-Peter Clausen if (state->irq > 0) 1363fa5b7945SLars-Peter Clausen free_irq(client->irq, state); 1364d5d51a82SLars-Peter Clausen err_media_entity_cleanup: 1365d5d51a82SLars-Peter Clausen media_entity_cleanup(&sd->entity); 1366cb7a01acSMauro Carvalho Chehab err_free_ctrl: 1367cb7a01acSMauro Carvalho Chehab adv7180_exit_controls(state); 1368851a54efSLars-Peter Clausen err_unregister_vpp_client: 1369851a54efSLars-Peter Clausen i2c_unregister_device(state->vpp_client); 1370b37135e3SLars-Peter Clausen err_unregister_csi_client: 1371b37135e3SLars-Peter Clausen i2c_unregister_device(state->csi_client); 1372297a0ae3SLars-Peter Clausen mutex_destroy(&state->mutex); 1373cb7a01acSMauro Carvalho Chehab return ret; 1374cb7a01acSMauro Carvalho Chehab } 1375cb7a01acSMauro Carvalho Chehab 13764c62e976SGreg Kroah-Hartman static int adv7180_remove(struct i2c_client *client) 1377cb7a01acSMauro Carvalho Chehab { 1378cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = i2c_get_clientdata(client); 1379cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 1380cb7a01acSMauro Carvalho Chehab 1381fa5b7945SLars-Peter Clausen v4l2_async_unregister_subdev(sd); 1382fa5b7945SLars-Peter Clausen 13830c25534dSLars-Peter Clausen if (state->irq > 0) 1384cb7a01acSMauro Carvalho Chehab free_irq(client->irq, state); 1385cb7a01acSMauro Carvalho Chehab 1386d5d51a82SLars-Peter Clausen media_entity_cleanup(&sd->entity); 1387b13f4af2SLars-Peter Clausen adv7180_exit_controls(state); 1388b37135e3SLars-Peter Clausen 1389851a54efSLars-Peter Clausen i2c_unregister_device(state->vpp_client); 1390b37135e3SLars-Peter Clausen i2c_unregister_device(state->csi_client); 1391b37135e3SLars-Peter Clausen 139265d9e14aSSteve Longerbeam adv7180_set_power_pin(state, false); 139365d9e14aSSteve Longerbeam 1394297a0ae3SLars-Peter Clausen mutex_destroy(&state->mutex); 1395b37135e3SLars-Peter Clausen 1396cb7a01acSMauro Carvalho Chehab return 0; 1397cb7a01acSMauro Carvalho Chehab } 1398cb7a01acSMauro Carvalho Chehab 1399cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id adv7180_id[] = { 1400f5dde49bSLars-Peter Clausen { "adv7180", (kernel_ulong_t)&adv7180_info }, 1401281ddc3cSUlrich Hecht { "adv7180cp", (kernel_ulong_t)&adv7180_info }, 1402281ddc3cSUlrich Hecht { "adv7180st", (kernel_ulong_t)&adv7180_info }, 1403c5ef8f8cSLars-Peter Clausen { "adv7182", (kernel_ulong_t)&adv7182_info }, 1404bf7dcb80SLars-Peter Clausen { "adv7280", (kernel_ulong_t)&adv7280_info }, 1405b37135e3SLars-Peter Clausen { "adv7280-m", (kernel_ulong_t)&adv7280_m_info }, 1406bf7dcb80SLars-Peter Clausen { "adv7281", (kernel_ulong_t)&adv7281_info }, 1407b37135e3SLars-Peter Clausen { "adv7281-m", (kernel_ulong_t)&adv7281_m_info }, 1408b37135e3SLars-Peter Clausen { "adv7281-ma", (kernel_ulong_t)&adv7281_ma_info }, 1409851a54efSLars-Peter Clausen { "adv7282", (kernel_ulong_t)&adv7282_info }, 1410851a54efSLars-Peter Clausen { "adv7282-m", (kernel_ulong_t)&adv7282_m_info }, 1411cb7a01acSMauro Carvalho Chehab {}, 1412cb7a01acSMauro Carvalho Chehab }; 1413f5dde49bSLars-Peter Clausen MODULE_DEVICE_TABLE(i2c, adv7180_id); 1414cb7a01acSMauro Carvalho Chehab 1415cc1088dcSLars-Peter Clausen #ifdef CONFIG_PM_SLEEP 1416cc1088dcSLars-Peter Clausen static int adv7180_suspend(struct device *dev) 1417cb7a01acSMauro Carvalho Chehab { 1418cc1088dcSLars-Peter Clausen struct i2c_client *client = to_i2c_client(dev); 1419e246c333SLars-Peter Clausen struct v4l2_subdev *sd = i2c_get_clientdata(client); 1420e246c333SLars-Peter Clausen struct adv7180_state *state = to_state(sd); 1421cb7a01acSMauro Carvalho Chehab 14223999e5d0SLars-Peter Clausen return adv7180_set_power(state, false); 1423cb7a01acSMauro Carvalho Chehab } 1424cb7a01acSMauro Carvalho Chehab 1425cc1088dcSLars-Peter Clausen static int adv7180_resume(struct device *dev) 1426cb7a01acSMauro Carvalho Chehab { 1427cc1088dcSLars-Peter Clausen struct i2c_client *client = to_i2c_client(dev); 1428cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = i2c_get_clientdata(client); 1429cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 1430cb7a01acSMauro Carvalho Chehab int ret; 1431cb7a01acSMauro Carvalho Chehab 14323999e5d0SLars-Peter Clausen ret = init_device(state); 1433cb7a01acSMauro Carvalho Chehab if (ret < 0) 1434cb7a01acSMauro Carvalho Chehab return ret; 1435c18818e9SLars-Peter Clausen 1436c18818e9SLars-Peter Clausen ret = adv7180_set_power(state, state->powered); 1437c18818e9SLars-Peter Clausen if (ret) 1438c18818e9SLars-Peter Clausen return ret; 1439c18818e9SLars-Peter Clausen 1440cb7a01acSMauro Carvalho Chehab return 0; 1441cb7a01acSMauro Carvalho Chehab } 1442cc1088dcSLars-Peter Clausen 1443cc1088dcSLars-Peter Clausen static SIMPLE_DEV_PM_OPS(adv7180_pm_ops, adv7180_suspend, adv7180_resume); 1444cc1088dcSLars-Peter Clausen #define ADV7180_PM_OPS (&adv7180_pm_ops) 1445cc1088dcSLars-Peter Clausen 1446cc1088dcSLars-Peter Clausen #else 1447cc1088dcSLars-Peter Clausen #define ADV7180_PM_OPS NULL 1448cb7a01acSMauro Carvalho Chehab #endif 1449cb7a01acSMauro Carvalho Chehab 1450250121d3SBen Dooks #ifdef CONFIG_OF 1451250121d3SBen Dooks static const struct of_device_id adv7180_of_id[] = { 1452250121d3SBen Dooks { .compatible = "adi,adv7180", }, 1453ce1ec5c0SUlrich Hecht { .compatible = "adi,adv7180cp", }, 1454ce1ec5c0SUlrich Hecht { .compatible = "adi,adv7180st", }, 1455bf14e74cSJulian Scheel { .compatible = "adi,adv7182", }, 1456bf14e74cSJulian Scheel { .compatible = "adi,adv7280", }, 1457bf14e74cSJulian Scheel { .compatible = "adi,adv7280-m", }, 1458bf14e74cSJulian Scheel { .compatible = "adi,adv7281", }, 1459bf14e74cSJulian Scheel { .compatible = "adi,adv7281-m", }, 1460bf14e74cSJulian Scheel { .compatible = "adi,adv7281-ma", }, 1461bf14e74cSJulian Scheel { .compatible = "adi,adv7282", }, 1462bf14e74cSJulian Scheel { .compatible = "adi,adv7282-m", }, 1463250121d3SBen Dooks { }, 1464250121d3SBen Dooks }; 1465250121d3SBen Dooks 1466250121d3SBen Dooks MODULE_DEVICE_TABLE(of, adv7180_of_id); 1467250121d3SBen Dooks #endif 1468250121d3SBen Dooks 1469cb7a01acSMauro Carvalho Chehab static struct i2c_driver adv7180_driver = { 1470cb7a01acSMauro Carvalho Chehab .driver = { 1471cb7a01acSMauro Carvalho Chehab .name = KBUILD_MODNAME, 1472cc1088dcSLars-Peter Clausen .pm = ADV7180_PM_OPS, 1473250121d3SBen Dooks .of_match_table = of_match_ptr(adv7180_of_id), 1474cb7a01acSMauro Carvalho Chehab }, 1475cb7a01acSMauro Carvalho Chehab .probe = adv7180_probe, 14764c62e976SGreg Kroah-Hartman .remove = adv7180_remove, 1477cb7a01acSMauro Carvalho Chehab .id_table = adv7180_id, 1478cb7a01acSMauro Carvalho Chehab }; 1479cb7a01acSMauro Carvalho Chehab 1480cb7a01acSMauro Carvalho Chehab module_i2c_driver(adv7180_driver); 1481cb7a01acSMauro Carvalho Chehab 1482cb7a01acSMauro Carvalho Chehab MODULE_DESCRIPTION("Analog Devices ADV7180 video decoder driver"); 1483cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Mocean Laboratories"); 1484cb7a01acSMauro Carvalho Chehab MODULE_LICENSE("GPL v2"); 1485