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 * You should have received a copy of the GNU General Public License 17cb7a01acSMauro Carvalho Chehab * along with this program; if not, write to the Free Software 18cb7a01acSMauro Carvalho Chehab * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19cb7a01acSMauro Carvalho Chehab */ 20cb7a01acSMauro Carvalho Chehab 21cb7a01acSMauro Carvalho Chehab #include <linux/module.h> 22cb7a01acSMauro Carvalho Chehab #include <linux/init.h> 23cb7a01acSMauro Carvalho Chehab #include <linux/errno.h> 24cb7a01acSMauro Carvalho Chehab #include <linux/kernel.h> 25cb7a01acSMauro Carvalho Chehab #include <linux/interrupt.h> 26cb7a01acSMauro Carvalho Chehab #include <linux/i2c.h> 27cb7a01acSMauro Carvalho Chehab #include <linux/slab.h> 28250121d3SBen Dooks #include <linux/of.h> 2965d9e14aSSteve Longerbeam #include <linux/gpio/consumer.h> 30cb7a01acSMauro Carvalho Chehab #include <linux/videodev2.h> 31937feeedSHans Verkuil #include <media/v4l2-ioctl.h> 32937feeedSHans Verkuil #include <media/v4l2-event.h> 33cb7a01acSMauro Carvalho Chehab #include <media/v4l2-device.h> 34cb7a01acSMauro Carvalho Chehab #include <media/v4l2-ctrls.h> 35cb7a01acSMauro Carvalho Chehab #include <linux/mutex.h> 36c18818e9SLars-Peter Clausen #include <linux/delay.h> 37cb7a01acSMauro Carvalho Chehab 38f5dde49bSLars-Peter Clausen #define ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM 0x0 39f5dde49bSLars-Peter Clausen #define ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM_PED 0x1 40f5dde49bSLars-Peter Clausen #define ADV7180_STD_AD_PAL_N_NTSC_J_SECAM 0x2 41f5dde49bSLars-Peter Clausen #define ADV7180_STD_AD_PAL_N_NTSC_M_SECAM 0x3 42f5dde49bSLars-Peter Clausen #define ADV7180_STD_NTSC_J 0x4 43f5dde49bSLars-Peter Clausen #define ADV7180_STD_NTSC_M 0x5 44f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL60 0x6 45f5dde49bSLars-Peter Clausen #define ADV7180_STD_NTSC_443 0x7 46f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_BG 0x8 47f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_N 0x9 48f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_M 0xa 49f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_M_PED 0xb 50f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_COMB_N 0xc 51f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_COMB_N_PED 0xd 52f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_SECAM 0xe 53f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_SECAM_PED 0xf 54f5dde49bSLars-Peter Clausen 553999e5d0SLars-Peter Clausen #define ADV7180_REG_INPUT_CONTROL 0x0000 56cb7a01acSMauro Carvalho Chehab #define ADV7180_INPUT_CONTROL_INSEL_MASK 0x0f 57cb7a01acSMauro Carvalho Chehab 58c5ef8f8cSLars-Peter Clausen #define ADV7182_REG_INPUT_VIDSEL 0x0002 59c5ef8f8cSLars-Peter Clausen 60ce5d6290SSteve Longerbeam #define ADV7180_REG_OUTPUT_CONTROL 0x0003 613999e5d0SLars-Peter Clausen #define ADV7180_REG_EXTENDED_OUTPUT_CONTROL 0x0004 62cb7a01acSMauro Carvalho Chehab #define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS 0xC5 63cb7a01acSMauro Carvalho Chehab 64ce5d6290SSteve Longerbeam #define ADV7180_REG_AUTODETECT_ENABLE 0x0007 65cb7a01acSMauro Carvalho Chehab #define ADV7180_AUTODETECT_DEFAULT 0x7f 66cb7a01acSMauro Carvalho Chehab /* Contrast */ 673999e5d0SLars-Peter Clausen #define ADV7180_REG_CON 0x0008 /*Unsigned */ 68cb7a01acSMauro Carvalho Chehab #define ADV7180_CON_MIN 0 69cb7a01acSMauro Carvalho Chehab #define ADV7180_CON_DEF 128 70cb7a01acSMauro Carvalho Chehab #define ADV7180_CON_MAX 255 71cb7a01acSMauro Carvalho Chehab /* Brightness*/ 723999e5d0SLars-Peter Clausen #define ADV7180_REG_BRI 0x000a /*Signed */ 73cb7a01acSMauro Carvalho Chehab #define ADV7180_BRI_MIN -128 74cb7a01acSMauro Carvalho Chehab #define ADV7180_BRI_DEF 0 75cb7a01acSMauro Carvalho Chehab #define ADV7180_BRI_MAX 127 76cb7a01acSMauro Carvalho Chehab /* Hue */ 773999e5d0SLars-Peter Clausen #define ADV7180_REG_HUE 0x000b /*Signed, inverted */ 78cb7a01acSMauro Carvalho Chehab #define ADV7180_HUE_MIN -127 79cb7a01acSMauro Carvalho Chehab #define ADV7180_HUE_DEF 0 80cb7a01acSMauro Carvalho Chehab #define ADV7180_HUE_MAX 128 81cb7a01acSMauro Carvalho Chehab 823999e5d0SLars-Peter Clausen #define ADV7180_REG_CTRL 0x000e 83029d6177SLars-Peter Clausen #define ADV7180_CTRL_IRQ_SPACE 0x20 84cb7a01acSMauro Carvalho Chehab 85029d6177SLars-Peter Clausen #define ADV7180_REG_PWR_MAN 0x0f 86cb7a01acSMauro Carvalho Chehab #define ADV7180_PWR_MAN_ON 0x04 87cb7a01acSMauro Carvalho Chehab #define ADV7180_PWR_MAN_OFF 0x24 88cb7a01acSMauro Carvalho Chehab #define ADV7180_PWR_MAN_RES 0x80 89cb7a01acSMauro Carvalho Chehab 903999e5d0SLars-Peter Clausen #define ADV7180_REG_STATUS1 0x0010 91cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_IN_LOCK 0x01 92cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_MASK 0x70 93cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_NTSM_M_J 0x00 94cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_NTSC_4_43 0x10 95cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_PAL_M 0x20 96cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_PAL_60 0x30 97cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_PAL_B_G 0x40 98cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_SECAM 0x50 99cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_PAL_COMB 0x60 100cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_SECAM_525 0x70 101cb7a01acSMauro Carvalho Chehab 1023999e5d0SLars-Peter Clausen #define ADV7180_REG_IDENT 0x0011 103cb7a01acSMauro Carvalho Chehab #define ADV7180_ID_7180 0x18 104cb7a01acSMauro Carvalho Chehab 105ce5d6290SSteve Longerbeam #define ADV7180_REG_STATUS3 0x0013 106ce5d6290SSteve Longerbeam #define ADV7180_REG_ANALOG_CLAMP_CTL 0x0014 107ce5d6290SSteve Longerbeam #define ADV7180_REG_SHAP_FILTER_CTL_1 0x0017 108ce5d6290SSteve Longerbeam #define ADV7180_REG_CTRL_2 0x001d 109ce5d6290SSteve Longerbeam #define ADV7180_REG_VSYNC_FIELD_CTL_1 0x0031 110ce5d6290SSteve Longerbeam #define ADV7180_REG_MANUAL_WIN_CTL_1 0x003d 111ce5d6290SSteve Longerbeam #define ADV7180_REG_MANUAL_WIN_CTL_2 0x003e 112ce5d6290SSteve Longerbeam #define ADV7180_REG_MANUAL_WIN_CTL_3 0x003f 113ce5d6290SSteve Longerbeam #define ADV7180_REG_LOCK_CNT 0x0051 114ce5d6290SSteve Longerbeam #define ADV7180_REG_CVBS_TRIM 0x0052 115ce5d6290SSteve Longerbeam #define ADV7180_REG_CLAMP_ADJ 0x005a 116ce5d6290SSteve Longerbeam #define ADV7180_REG_RES_CIR 0x005f 117ce5d6290SSteve Longerbeam #define ADV7180_REG_DIFF_MODE 0x0060 118ce5d6290SSteve Longerbeam 11952e37f0aSSteve Longerbeam #define ADV7180_REG_ICONF1 0x2040 120cb7a01acSMauro Carvalho Chehab #define ADV7180_ICONF1_ACTIVE_LOW 0x01 121cb7a01acSMauro Carvalho Chehab #define ADV7180_ICONF1_PSYNC_ONLY 0x10 122cb7a01acSMauro Carvalho Chehab #define ADV7180_ICONF1_ACTIVE_TO_CLR 0xC0 123cb7a01acSMauro Carvalho Chehab /* Saturation */ 1243999e5d0SLars-Peter Clausen #define ADV7180_REG_SD_SAT_CB 0x00e3 /*Unsigned */ 1253999e5d0SLars-Peter Clausen #define ADV7180_REG_SD_SAT_CR 0x00e4 /*Unsigned */ 126cb7a01acSMauro Carvalho Chehab #define ADV7180_SAT_MIN 0 127cb7a01acSMauro Carvalho Chehab #define ADV7180_SAT_DEF 128 128cb7a01acSMauro Carvalho Chehab #define ADV7180_SAT_MAX 255 129cb7a01acSMauro Carvalho Chehab 130cb7a01acSMauro Carvalho Chehab #define ADV7180_IRQ1_LOCK 0x01 131cb7a01acSMauro Carvalho Chehab #define ADV7180_IRQ1_UNLOCK 0x02 13252e37f0aSSteve Longerbeam #define ADV7180_REG_ISR1 0x2042 13352e37f0aSSteve Longerbeam #define ADV7180_REG_ICR1 0x2043 13452e37f0aSSteve Longerbeam #define ADV7180_REG_IMR1 0x2044 13552e37f0aSSteve Longerbeam #define ADV7180_REG_IMR2 0x2048 136cb7a01acSMauro Carvalho Chehab #define ADV7180_IRQ3_AD_CHANGE 0x08 13752e37f0aSSteve Longerbeam #define ADV7180_REG_ISR3 0x204A 13852e37f0aSSteve Longerbeam #define ADV7180_REG_ICR3 0x204B 13952e37f0aSSteve Longerbeam #define ADV7180_REG_IMR3 0x204C 14052e37f0aSSteve Longerbeam #define ADV7180_REG_IMR4 0x2050 141cb7a01acSMauro Carvalho Chehab 1423999e5d0SLars-Peter Clausen #define ADV7180_REG_NTSC_V_BIT_END 0x00E6 143cb7a01acSMauro Carvalho Chehab #define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND 0x4F 144cb7a01acSMauro Carvalho Chehab 145851a54efSLars-Peter Clausen #define ADV7180_REG_VPP_SLAVE_ADDR 0xFD 146b37135e3SLars-Peter Clausen #define ADV7180_REG_CSI_SLAVE_ADDR 0xFE 147b37135e3SLars-Peter Clausen 148ce5d6290SSteve Longerbeam #define ADV7180_REG_ACE_CTRL1 0x4080 149ce5d6290SSteve Longerbeam #define ADV7180_REG_ACE_CTRL5 0x4084 15008b717c2SLars-Peter Clausen #define ADV7180_REG_FLCONTROL 0x40e0 15108b717c2SLars-Peter Clausen #define ADV7180_FLCONTROL_FL_ENABLE 0x1 15208b717c2SLars-Peter Clausen 153ce5d6290SSteve Longerbeam #define ADV7180_REG_RST_CLAMP 0x809c 154ce5d6290SSteve Longerbeam #define ADV7180_REG_AGC_ADJ1 0x80b6 155ce5d6290SSteve Longerbeam #define ADV7180_REG_AGC_ADJ2 0x80c0 156ce5d6290SSteve Longerbeam 157b37135e3SLars-Peter Clausen #define ADV7180_CSI_REG_PWRDN 0x00 158b37135e3SLars-Peter Clausen #define ADV7180_CSI_PWRDN 0x80 159b37135e3SLars-Peter Clausen 160f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN1 0x00 161f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN2 0x01 162f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN3 0x02 163f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN4 0x03 164f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN5 0x04 165f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN6 0x05 166f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_SVIDEO_AIN1_AIN2 0x06 167f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_SVIDEO_AIN3_AIN4 0x07 168f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_SVIDEO_AIN5_AIN6 0x08 169f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_YPRPB_AIN1_AIN2_AIN3 0x09 170f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0a 171f5dde49bSLars-Peter Clausen 172c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN1 0x00 173c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN2 0x01 174c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN3 0x02 175c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN4 0x03 176c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN5 0x04 177c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN6 0x05 178c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN7 0x06 179c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN8 0x07 180c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_SVIDEO_AIN1_AIN2 0x08 181c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_SVIDEO_AIN3_AIN4 0x09 182c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_SVIDEO_AIN5_AIN6 0x0a 183c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_SVIDEO_AIN7_AIN8 0x0b 184c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3 0x0c 185c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0d 186c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2 0x0e 187c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4 0x0f 188c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6 0x10 189c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8 0x11 190c5ef8f8cSLars-Peter Clausen 191b37135e3SLars-Peter Clausen #define ADV7180_DEFAULT_CSI_I2C_ADDR 0x44 192851a54efSLars-Peter Clausen #define ADV7180_DEFAULT_VPP_I2C_ADDR 0x42 193b37135e3SLars-Peter Clausen 19408b717c2SLars-Peter Clausen #define V4L2_CID_ADV_FAST_SWITCH (V4L2_CID_USER_ADV7180_BASE + 0x00) 19508b717c2SLars-Peter Clausen 196f5dde49bSLars-Peter Clausen struct adv7180_state; 197f5dde49bSLars-Peter Clausen 198f5dde49bSLars-Peter Clausen #define ADV7180_FLAG_RESET_POWERED BIT(0) 199bf7dcb80SLars-Peter Clausen #define ADV7180_FLAG_V2 BIT(1) 200b37135e3SLars-Peter Clausen #define ADV7180_FLAG_MIPI_CSI2 BIT(2) 201851a54efSLars-Peter Clausen #define ADV7180_FLAG_I2P BIT(3) 202f5dde49bSLars-Peter Clausen 203f5dde49bSLars-Peter Clausen struct adv7180_chip_info { 204f5dde49bSLars-Peter Clausen unsigned int flags; 205f5dde49bSLars-Peter Clausen unsigned int valid_input_mask; 206f5dde49bSLars-Peter Clausen int (*set_std)(struct adv7180_state *st, unsigned int std); 207f5dde49bSLars-Peter Clausen int (*select_input)(struct adv7180_state *st, unsigned int input); 208f5dde49bSLars-Peter Clausen int (*init)(struct adv7180_state *state); 209f5dde49bSLars-Peter Clausen }; 210f5dde49bSLars-Peter Clausen 211cb7a01acSMauro Carvalho Chehab struct adv7180_state { 212cb7a01acSMauro Carvalho Chehab struct v4l2_ctrl_handler ctrl_hdl; 213cb7a01acSMauro Carvalho Chehab struct v4l2_subdev sd; 214d5d51a82SLars-Peter Clausen struct media_pad pad; 215cb7a01acSMauro Carvalho Chehab struct mutex mutex; /* mutual excl. when accessing chip */ 216cb7a01acSMauro Carvalho Chehab int irq; 21765d9e14aSSteve Longerbeam struct gpio_desc *pwdn_gpio; 218cb7a01acSMauro Carvalho Chehab v4l2_std_id curr_norm; 219e246c333SLars-Peter Clausen bool powered; 220937feeedSHans Verkuil bool streaming; 221cb7a01acSMauro Carvalho Chehab u8 input; 2223999e5d0SLars-Peter Clausen 2233999e5d0SLars-Peter Clausen struct i2c_client *client; 2243999e5d0SLars-Peter Clausen unsigned int register_page; 225b37135e3SLars-Peter Clausen struct i2c_client *csi_client; 226851a54efSLars-Peter Clausen struct i2c_client *vpp_client; 227f5dde49bSLars-Peter Clausen const struct adv7180_chip_info *chip_info; 228851a54efSLars-Peter Clausen enum v4l2_field field; 229cb7a01acSMauro Carvalho Chehab }; 230cb7a01acSMauro Carvalho Chehab #define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler, \ 231cb7a01acSMauro Carvalho Chehab struct adv7180_state, \ 232cb7a01acSMauro Carvalho Chehab ctrl_hdl)->sd) 233cb7a01acSMauro Carvalho Chehab 2343999e5d0SLars-Peter Clausen static int adv7180_select_page(struct adv7180_state *state, unsigned int page) 2353999e5d0SLars-Peter Clausen { 2363999e5d0SLars-Peter Clausen if (state->register_page != page) { 2373999e5d0SLars-Peter Clausen i2c_smbus_write_byte_data(state->client, ADV7180_REG_CTRL, 2383999e5d0SLars-Peter Clausen page); 2393999e5d0SLars-Peter Clausen state->register_page = page; 2403999e5d0SLars-Peter Clausen } 2413999e5d0SLars-Peter Clausen 2423999e5d0SLars-Peter Clausen return 0; 2433999e5d0SLars-Peter Clausen } 2443999e5d0SLars-Peter Clausen 2453999e5d0SLars-Peter Clausen static int adv7180_write(struct adv7180_state *state, unsigned int reg, 2463999e5d0SLars-Peter Clausen unsigned int value) 2473999e5d0SLars-Peter Clausen { 2483999e5d0SLars-Peter Clausen lockdep_assert_held(&state->mutex); 2493999e5d0SLars-Peter Clausen adv7180_select_page(state, reg >> 8); 2503999e5d0SLars-Peter Clausen return i2c_smbus_write_byte_data(state->client, reg & 0xff, value); 2513999e5d0SLars-Peter Clausen } 2523999e5d0SLars-Peter Clausen 2533999e5d0SLars-Peter Clausen static int adv7180_read(struct adv7180_state *state, unsigned int reg) 2543999e5d0SLars-Peter Clausen { 2553999e5d0SLars-Peter Clausen lockdep_assert_held(&state->mutex); 2563999e5d0SLars-Peter Clausen adv7180_select_page(state, reg >> 8); 2573999e5d0SLars-Peter Clausen return i2c_smbus_read_byte_data(state->client, reg & 0xff); 2583999e5d0SLars-Peter Clausen } 2593999e5d0SLars-Peter Clausen 260b37135e3SLars-Peter Clausen static int adv7180_csi_write(struct adv7180_state *state, unsigned int reg, 261b37135e3SLars-Peter Clausen unsigned int value) 262b37135e3SLars-Peter Clausen { 263b37135e3SLars-Peter Clausen return i2c_smbus_write_byte_data(state->csi_client, reg, value); 264b37135e3SLars-Peter Clausen } 265b37135e3SLars-Peter Clausen 266f5dde49bSLars-Peter Clausen static int adv7180_set_video_standard(struct adv7180_state *state, 267f5dde49bSLars-Peter Clausen unsigned int std) 268f5dde49bSLars-Peter Clausen { 269f5dde49bSLars-Peter Clausen return state->chip_info->set_std(state, std); 270f5dde49bSLars-Peter Clausen } 2713999e5d0SLars-Peter Clausen 272851a54efSLars-Peter Clausen static int adv7180_vpp_write(struct adv7180_state *state, unsigned int reg, 273851a54efSLars-Peter Clausen unsigned int value) 274851a54efSLars-Peter Clausen { 275851a54efSLars-Peter Clausen return i2c_smbus_write_byte_data(state->vpp_client, reg, value); 276851a54efSLars-Peter Clausen } 277851a54efSLars-Peter Clausen 278cb7a01acSMauro Carvalho Chehab static v4l2_std_id adv7180_std_to_v4l2(u8 status1) 279cb7a01acSMauro Carvalho Chehab { 280b294a192SVladimir Barinov /* in case V4L2_IN_ST_NO_SIGNAL */ 281b294a192SVladimir Barinov if (!(status1 & ADV7180_STATUS1_IN_LOCK)) 282b294a192SVladimir Barinov return V4L2_STD_UNKNOWN; 283b294a192SVladimir Barinov 284cb7a01acSMauro Carvalho Chehab switch (status1 & ADV7180_STATUS1_AUTOD_MASK) { 285cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_NTSM_M_J: 286cb7a01acSMauro Carvalho Chehab return V4L2_STD_NTSC; 287cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_NTSC_4_43: 288cb7a01acSMauro Carvalho Chehab return V4L2_STD_NTSC_443; 289cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_PAL_M: 290cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL_M; 291cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_PAL_60: 292cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL_60; 293cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_PAL_B_G: 294cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL; 295cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_SECAM: 296cb7a01acSMauro Carvalho Chehab return V4L2_STD_SECAM; 297cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_PAL_COMB: 298cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL_Nc | V4L2_STD_PAL_N; 299cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_SECAM_525: 300cb7a01acSMauro Carvalho Chehab return V4L2_STD_SECAM; 301cb7a01acSMauro Carvalho Chehab default: 302cb7a01acSMauro Carvalho Chehab return V4L2_STD_UNKNOWN; 303cb7a01acSMauro Carvalho Chehab } 304cb7a01acSMauro Carvalho Chehab } 305cb7a01acSMauro Carvalho Chehab 306cb7a01acSMauro Carvalho Chehab static int v4l2_std_to_adv7180(v4l2_std_id std) 307cb7a01acSMauro Carvalho Chehab { 308cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_PAL_60) 309f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL60; 310cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_NTSC_443) 311f5dde49bSLars-Peter Clausen return ADV7180_STD_NTSC_443; 312cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_PAL_N) 313f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL_N; 314cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_PAL_M) 315f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL_M; 316cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_PAL_Nc) 317f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL_COMB_N; 318cb7a01acSMauro Carvalho Chehab 319cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_PAL) 320f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL_BG; 321cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_NTSC) 322f5dde49bSLars-Peter Clausen return ADV7180_STD_NTSC_M; 323cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_SECAM) 324f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL_SECAM; 325cb7a01acSMauro Carvalho Chehab 326cb7a01acSMauro Carvalho Chehab return -EINVAL; 327cb7a01acSMauro Carvalho Chehab } 328cb7a01acSMauro Carvalho Chehab 329cb7a01acSMauro Carvalho Chehab static u32 adv7180_status_to_v4l2(u8 status1) 330cb7a01acSMauro Carvalho Chehab { 331cb7a01acSMauro Carvalho Chehab if (!(status1 & ADV7180_STATUS1_IN_LOCK)) 332cb7a01acSMauro Carvalho Chehab return V4L2_IN_ST_NO_SIGNAL; 333cb7a01acSMauro Carvalho Chehab 334cb7a01acSMauro Carvalho Chehab return 0; 335cb7a01acSMauro Carvalho Chehab } 336cb7a01acSMauro Carvalho Chehab 3373999e5d0SLars-Peter Clausen static int __adv7180_status(struct adv7180_state *state, u32 *status, 338cb7a01acSMauro Carvalho Chehab v4l2_std_id *std) 339cb7a01acSMauro Carvalho Chehab { 3403999e5d0SLars-Peter Clausen int status1 = adv7180_read(state, ADV7180_REG_STATUS1); 341cb7a01acSMauro Carvalho Chehab 342cb7a01acSMauro Carvalho Chehab if (status1 < 0) 343cb7a01acSMauro Carvalho Chehab return status1; 344cb7a01acSMauro Carvalho Chehab 345cb7a01acSMauro Carvalho Chehab if (status) 346cb7a01acSMauro Carvalho Chehab *status = adv7180_status_to_v4l2(status1); 347cb7a01acSMauro Carvalho Chehab if (std) 348cb7a01acSMauro Carvalho Chehab *std = adv7180_std_to_v4l2(status1); 349cb7a01acSMauro Carvalho Chehab 350cb7a01acSMauro Carvalho Chehab return 0; 351cb7a01acSMauro Carvalho Chehab } 352cb7a01acSMauro Carvalho Chehab 353cb7a01acSMauro Carvalho Chehab static inline struct adv7180_state *to_state(struct v4l2_subdev *sd) 354cb7a01acSMauro Carvalho Chehab { 355cb7a01acSMauro Carvalho Chehab return container_of(sd, struct adv7180_state, sd); 356cb7a01acSMauro Carvalho Chehab } 357cb7a01acSMauro Carvalho Chehab 358cb7a01acSMauro Carvalho Chehab static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) 359cb7a01acSMauro Carvalho Chehab { 360cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 361cb7a01acSMauro Carvalho Chehab int err = mutex_lock_interruptible(&state->mutex); 362cb7a01acSMauro Carvalho Chehab if (err) 363cb7a01acSMauro Carvalho Chehab return err; 364cb7a01acSMauro Carvalho Chehab 365937feeedSHans Verkuil if (state->streaming) { 366937feeedSHans Verkuil err = -EBUSY; 367937feeedSHans Verkuil goto unlock; 368937feeedSHans Verkuil } 369cb7a01acSMauro Carvalho Chehab 370937feeedSHans Verkuil err = adv7180_set_video_standard(state, 371937feeedSHans Verkuil ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM); 372937feeedSHans Verkuil if (err) 373937feeedSHans Verkuil goto unlock; 374937feeedSHans Verkuil 375937feeedSHans Verkuil msleep(100); 376937feeedSHans Verkuil __adv7180_status(state, NULL, std); 377937feeedSHans Verkuil 378937feeedSHans Verkuil err = v4l2_std_to_adv7180(state->curr_norm); 379937feeedSHans Verkuil if (err < 0) 380937feeedSHans Verkuil goto unlock; 381937feeedSHans Verkuil 382937feeedSHans Verkuil err = adv7180_set_video_standard(state, err); 383937feeedSHans Verkuil 384937feeedSHans Verkuil unlock: 385cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex); 386cb7a01acSMauro Carvalho Chehab return err; 387cb7a01acSMauro Carvalho Chehab } 388cb7a01acSMauro Carvalho Chehab 389cb7a01acSMauro Carvalho Chehab static int adv7180_s_routing(struct v4l2_subdev *sd, u32 input, 390cb7a01acSMauro Carvalho Chehab u32 output, u32 config) 391cb7a01acSMauro Carvalho Chehab { 392cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 393cb7a01acSMauro Carvalho Chehab int ret = mutex_lock_interruptible(&state->mutex); 394cb7a01acSMauro Carvalho Chehab 395cb7a01acSMauro Carvalho Chehab if (ret) 396cb7a01acSMauro Carvalho Chehab return ret; 397cb7a01acSMauro Carvalho Chehab 398f5dde49bSLars-Peter Clausen if (input > 31 || !(BIT(input) & state->chip_info->valid_input_mask)) { 399f5dde49bSLars-Peter Clausen ret = -EINVAL; 400cb7a01acSMauro Carvalho Chehab goto out; 401f5dde49bSLars-Peter Clausen } 402cb7a01acSMauro Carvalho Chehab 403f5dde49bSLars-Peter Clausen ret = state->chip_info->select_input(state, input); 404cb7a01acSMauro Carvalho Chehab 405f5dde49bSLars-Peter Clausen if (ret == 0) 406cb7a01acSMauro Carvalho Chehab state->input = input; 407cb7a01acSMauro Carvalho Chehab out: 408cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex); 409cb7a01acSMauro Carvalho Chehab return ret; 410cb7a01acSMauro Carvalho Chehab } 411cb7a01acSMauro Carvalho Chehab 412cb7a01acSMauro Carvalho Chehab static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status) 413cb7a01acSMauro Carvalho Chehab { 414cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 415cb7a01acSMauro Carvalho Chehab int ret = mutex_lock_interruptible(&state->mutex); 416cb7a01acSMauro Carvalho Chehab if (ret) 417cb7a01acSMauro Carvalho Chehab return ret; 418cb7a01acSMauro Carvalho Chehab 4193999e5d0SLars-Peter Clausen ret = __adv7180_status(state, status, NULL); 420cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex); 421cb7a01acSMauro Carvalho Chehab return ret; 422cb7a01acSMauro Carvalho Chehab } 423cb7a01acSMauro Carvalho Chehab 4243e35e33cSLars-Peter Clausen static int adv7180_program_std(struct adv7180_state *state) 4253e35e33cSLars-Peter Clausen { 4263e35e33cSLars-Peter Clausen int ret; 4273e35e33cSLars-Peter Clausen 4283e35e33cSLars-Peter Clausen ret = v4l2_std_to_adv7180(state->curr_norm); 4293e35e33cSLars-Peter Clausen if (ret < 0) 4303e35e33cSLars-Peter Clausen return ret; 4313e35e33cSLars-Peter Clausen 432f5dde49bSLars-Peter Clausen ret = adv7180_set_video_standard(state, ret); 4333e35e33cSLars-Peter Clausen if (ret < 0) 4343e35e33cSLars-Peter Clausen return ret; 4353e35e33cSLars-Peter Clausen return 0; 4363e35e33cSLars-Peter Clausen } 4373e35e33cSLars-Peter Clausen 438cb7a01acSMauro Carvalho Chehab static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std) 439cb7a01acSMauro Carvalho Chehab { 440cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 441cb7a01acSMauro Carvalho Chehab int ret = mutex_lock_interruptible(&state->mutex); 4423e35e33cSLars-Peter Clausen 443cb7a01acSMauro Carvalho Chehab if (ret) 444cb7a01acSMauro Carvalho Chehab return ret; 445cb7a01acSMauro Carvalho Chehab 4463e35e33cSLars-Peter Clausen /* Make sure we can support this std */ 447cb7a01acSMauro Carvalho Chehab ret = v4l2_std_to_adv7180(std); 448cb7a01acSMauro Carvalho Chehab if (ret < 0) 449cb7a01acSMauro Carvalho Chehab goto out; 450cb7a01acSMauro Carvalho Chehab 451cb7a01acSMauro Carvalho Chehab state->curr_norm = std; 4523e35e33cSLars-Peter Clausen 4533e35e33cSLars-Peter Clausen ret = adv7180_program_std(state); 454cb7a01acSMauro Carvalho Chehab out: 455cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex); 456cb7a01acSMauro Carvalho Chehab return ret; 457cb7a01acSMauro Carvalho Chehab } 458cb7a01acSMauro Carvalho Chehab 459d0fadc86SNiklas Söderlund static int adv7180_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm) 460d0fadc86SNiklas Söderlund { 461d0fadc86SNiklas Söderlund struct adv7180_state *state = to_state(sd); 462d0fadc86SNiklas Söderlund 463d0fadc86SNiklas Söderlund *norm = state->curr_norm; 464d0fadc86SNiklas Söderlund 465d0fadc86SNiklas Söderlund return 0; 466d0fadc86SNiklas Söderlund } 467d0fadc86SNiklas Söderlund 46865d9e14aSSteve Longerbeam static void adv7180_set_power_pin(struct adv7180_state *state, bool on) 46965d9e14aSSteve Longerbeam { 47065d9e14aSSteve Longerbeam if (!state->pwdn_gpio) 47165d9e14aSSteve Longerbeam return; 47265d9e14aSSteve Longerbeam 47365d9e14aSSteve Longerbeam if (on) { 47465d9e14aSSteve Longerbeam gpiod_set_value_cansleep(state->pwdn_gpio, 0); 47565d9e14aSSteve Longerbeam usleep_range(5000, 10000); 47665d9e14aSSteve Longerbeam } else { 47765d9e14aSSteve Longerbeam gpiod_set_value_cansleep(state->pwdn_gpio, 1); 47865d9e14aSSteve Longerbeam } 47965d9e14aSSteve Longerbeam } 48065d9e14aSSteve Longerbeam 4813999e5d0SLars-Peter Clausen static int adv7180_set_power(struct adv7180_state *state, bool on) 482e246c333SLars-Peter Clausen { 483e246c333SLars-Peter Clausen u8 val; 484b37135e3SLars-Peter Clausen int ret; 485e246c333SLars-Peter Clausen 486e246c333SLars-Peter Clausen if (on) 487e246c333SLars-Peter Clausen val = ADV7180_PWR_MAN_ON; 488e246c333SLars-Peter Clausen else 489e246c333SLars-Peter Clausen val = ADV7180_PWR_MAN_OFF; 490e246c333SLars-Peter Clausen 491b37135e3SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_PWR_MAN, val); 492b37135e3SLars-Peter Clausen if (ret) 493b37135e3SLars-Peter Clausen return ret; 494b37135e3SLars-Peter Clausen 495b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 496b37135e3SLars-Peter Clausen if (on) { 497b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0xDE, 0x02); 498b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0xD2, 0xF7); 499b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0xD8, 0x65); 500b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0xE0, 0x09); 501b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0x2C, 0x00); 502851a54efSLars-Peter Clausen if (state->field == V4L2_FIELD_NONE) 503851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x1D, 0x80); 504b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0x00, 0x00); 505b37135e3SLars-Peter Clausen } else { 506b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0x00, 0x80); 507b37135e3SLars-Peter Clausen } 508b37135e3SLars-Peter Clausen } 509b37135e3SLars-Peter Clausen 510b37135e3SLars-Peter Clausen return 0; 511e246c333SLars-Peter Clausen } 512e246c333SLars-Peter Clausen 513e246c333SLars-Peter Clausen static int adv7180_s_power(struct v4l2_subdev *sd, int on) 514e246c333SLars-Peter Clausen { 515e246c333SLars-Peter Clausen struct adv7180_state *state = to_state(sd); 516e246c333SLars-Peter Clausen int ret; 517e246c333SLars-Peter Clausen 518e246c333SLars-Peter Clausen ret = mutex_lock_interruptible(&state->mutex); 519e246c333SLars-Peter Clausen if (ret) 520e246c333SLars-Peter Clausen return ret; 521e246c333SLars-Peter Clausen 5223999e5d0SLars-Peter Clausen ret = adv7180_set_power(state, on); 523e246c333SLars-Peter Clausen if (ret == 0) 524e246c333SLars-Peter Clausen state->powered = on; 525e246c333SLars-Peter Clausen 526e246c333SLars-Peter Clausen mutex_unlock(&state->mutex); 527e246c333SLars-Peter Clausen return ret; 528e246c333SLars-Peter Clausen } 529e246c333SLars-Peter Clausen 530cb7a01acSMauro Carvalho Chehab static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl) 531cb7a01acSMauro Carvalho Chehab { 532cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = to_adv7180_sd(ctrl); 533cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 534cb7a01acSMauro Carvalho Chehab int ret = mutex_lock_interruptible(&state->mutex); 535cb7a01acSMauro Carvalho Chehab int val; 536cb7a01acSMauro Carvalho Chehab 537cb7a01acSMauro Carvalho Chehab if (ret) 538cb7a01acSMauro Carvalho Chehab return ret; 539cb7a01acSMauro Carvalho Chehab val = ctrl->val; 540cb7a01acSMauro Carvalho Chehab switch (ctrl->id) { 541cb7a01acSMauro Carvalho Chehab case V4L2_CID_BRIGHTNESS: 5423999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_BRI, val); 543cb7a01acSMauro Carvalho Chehab break; 544cb7a01acSMauro Carvalho Chehab case V4L2_CID_HUE: 545cb7a01acSMauro Carvalho Chehab /*Hue is inverted according to HSL chart */ 5463999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_HUE, -val); 547cb7a01acSMauro Carvalho Chehab break; 548cb7a01acSMauro Carvalho Chehab case V4L2_CID_CONTRAST: 5493999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_CON, val); 550cb7a01acSMauro Carvalho Chehab break; 551cb7a01acSMauro Carvalho Chehab case V4L2_CID_SATURATION: 552cb7a01acSMauro Carvalho Chehab /* 553cb7a01acSMauro Carvalho Chehab *This could be V4L2_CID_BLUE_BALANCE/V4L2_CID_RED_BALANCE 554cb7a01acSMauro Carvalho Chehab *Let's not confuse the user, everybody understands saturation 555cb7a01acSMauro Carvalho Chehab */ 5563999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_SD_SAT_CB, val); 557cb7a01acSMauro Carvalho Chehab if (ret < 0) 558cb7a01acSMauro Carvalho Chehab break; 5593999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_SD_SAT_CR, val); 560cb7a01acSMauro Carvalho Chehab break; 56108b717c2SLars-Peter Clausen case V4L2_CID_ADV_FAST_SWITCH: 56208b717c2SLars-Peter Clausen if (ctrl->val) { 56308b717c2SLars-Peter Clausen /* ADI required write */ 56408b717c2SLars-Peter Clausen adv7180_write(state, 0x80d9, 0x44); 56508b717c2SLars-Peter Clausen adv7180_write(state, ADV7180_REG_FLCONTROL, 56608b717c2SLars-Peter Clausen ADV7180_FLCONTROL_FL_ENABLE); 56708b717c2SLars-Peter Clausen } else { 56808b717c2SLars-Peter Clausen /* ADI required write */ 56908b717c2SLars-Peter Clausen adv7180_write(state, 0x80d9, 0xc4); 57008b717c2SLars-Peter Clausen adv7180_write(state, ADV7180_REG_FLCONTROL, 0x00); 57108b717c2SLars-Peter Clausen } 57208b717c2SLars-Peter Clausen break; 573cb7a01acSMauro Carvalho Chehab default: 574cb7a01acSMauro Carvalho Chehab ret = -EINVAL; 575cb7a01acSMauro Carvalho Chehab } 576cb7a01acSMauro Carvalho Chehab 577cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex); 578cb7a01acSMauro Carvalho Chehab return ret; 579cb7a01acSMauro Carvalho Chehab } 580cb7a01acSMauro Carvalho Chehab 581cb7a01acSMauro Carvalho Chehab static const struct v4l2_ctrl_ops adv7180_ctrl_ops = { 582cb7a01acSMauro Carvalho Chehab .s_ctrl = adv7180_s_ctrl, 583cb7a01acSMauro Carvalho Chehab }; 584cb7a01acSMauro Carvalho Chehab 58508b717c2SLars-Peter Clausen static const struct v4l2_ctrl_config adv7180_ctrl_fast_switch = { 58608b717c2SLars-Peter Clausen .ops = &adv7180_ctrl_ops, 58708b717c2SLars-Peter Clausen .id = V4L2_CID_ADV_FAST_SWITCH, 58808b717c2SLars-Peter Clausen .name = "Fast Switching", 58908b717c2SLars-Peter Clausen .type = V4L2_CTRL_TYPE_BOOLEAN, 59008b717c2SLars-Peter Clausen .min = 0, 59108b717c2SLars-Peter Clausen .max = 1, 59208b717c2SLars-Peter Clausen .step = 1, 59308b717c2SLars-Peter Clausen }; 59408b717c2SLars-Peter Clausen 595cb7a01acSMauro Carvalho Chehab static int adv7180_init_controls(struct adv7180_state *state) 596cb7a01acSMauro Carvalho Chehab { 597cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_init(&state->ctrl_hdl, 4); 598cb7a01acSMauro Carvalho Chehab 599cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, 600cb7a01acSMauro Carvalho Chehab V4L2_CID_BRIGHTNESS, ADV7180_BRI_MIN, 601cb7a01acSMauro Carvalho Chehab ADV7180_BRI_MAX, 1, ADV7180_BRI_DEF); 602cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, 603cb7a01acSMauro Carvalho Chehab V4L2_CID_CONTRAST, ADV7180_CON_MIN, 604cb7a01acSMauro Carvalho Chehab ADV7180_CON_MAX, 1, ADV7180_CON_DEF); 605cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, 606cb7a01acSMauro Carvalho Chehab V4L2_CID_SATURATION, ADV7180_SAT_MIN, 607cb7a01acSMauro Carvalho Chehab ADV7180_SAT_MAX, 1, ADV7180_SAT_DEF); 608cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, 609cb7a01acSMauro Carvalho Chehab V4L2_CID_HUE, ADV7180_HUE_MIN, 610cb7a01acSMauro Carvalho Chehab ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF); 61108b717c2SLars-Peter Clausen v4l2_ctrl_new_custom(&state->ctrl_hdl, &adv7180_ctrl_fast_switch, NULL); 61208b717c2SLars-Peter Clausen 613cb7a01acSMauro Carvalho Chehab state->sd.ctrl_handler = &state->ctrl_hdl; 614cb7a01acSMauro Carvalho Chehab if (state->ctrl_hdl.error) { 615cb7a01acSMauro Carvalho Chehab int err = state->ctrl_hdl.error; 616cb7a01acSMauro Carvalho Chehab 617cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_free(&state->ctrl_hdl); 618cb7a01acSMauro Carvalho Chehab return err; 619cb7a01acSMauro Carvalho Chehab } 620cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_setup(&state->ctrl_hdl); 621cb7a01acSMauro Carvalho Chehab 622cb7a01acSMauro Carvalho Chehab return 0; 623cb7a01acSMauro Carvalho Chehab } 624cb7a01acSMauro Carvalho Chehab static void adv7180_exit_controls(struct adv7180_state *state) 625cb7a01acSMauro Carvalho Chehab { 626cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_free(&state->ctrl_hdl); 627cb7a01acSMauro Carvalho Chehab } 628cb7a01acSMauro Carvalho Chehab 629d5d51a82SLars-Peter Clausen static int adv7180_enum_mbus_code(struct v4l2_subdev *sd, 630f7234138SHans Verkuil struct v4l2_subdev_pad_config *cfg, 631d5d51a82SLars-Peter Clausen struct v4l2_subdev_mbus_code_enum *code) 632cccb83f7SVladimir Barinov { 633d5d51a82SLars-Peter Clausen if (code->index != 0) 634cccb83f7SVladimir Barinov return -EINVAL; 635cccb83f7SVladimir Barinov 6366de690ddSNiklas Söderlund code->code = MEDIA_BUS_FMT_UYVY8_2X8; 637cccb83f7SVladimir Barinov 638cccb83f7SVladimir Barinov return 0; 639cccb83f7SVladimir Barinov } 640cccb83f7SVladimir Barinov 641cccb83f7SVladimir Barinov static int adv7180_mbus_fmt(struct v4l2_subdev *sd, 642cccb83f7SVladimir Barinov struct v4l2_mbus_framefmt *fmt) 643cccb83f7SVladimir Barinov { 644cccb83f7SVladimir Barinov struct adv7180_state *state = to_state(sd); 645cccb83f7SVladimir Barinov 6466de690ddSNiklas Söderlund fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; 647cccb83f7SVladimir Barinov fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; 648cccb83f7SVladimir Barinov fmt->width = 720; 649cccb83f7SVladimir Barinov fmt->height = state->curr_norm & V4L2_STD_525_60 ? 480 : 576; 650cccb83f7SVladimir Barinov 651cccb83f7SVladimir Barinov return 0; 652cccb83f7SVladimir Barinov } 653cccb83f7SVladimir Barinov 654851a54efSLars-Peter Clausen static int adv7180_set_field_mode(struct adv7180_state *state) 655851a54efSLars-Peter Clausen { 656851a54efSLars-Peter Clausen if (!(state->chip_info->flags & ADV7180_FLAG_I2P)) 657851a54efSLars-Peter Clausen return 0; 658851a54efSLars-Peter Clausen 659851a54efSLars-Peter Clausen if (state->field == V4L2_FIELD_NONE) { 660851a54efSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 661851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x01, 0x20); 662851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x02, 0x28); 663851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x03, 0x38); 664851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x04, 0x30); 665851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x05, 0x30); 666851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x06, 0x80); 667851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x07, 0x70); 668851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x08, 0x50); 669851a54efSLars-Peter Clausen } 670851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0xa3, 0x00); 671851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0x5b, 0x00); 672851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0x55, 0x80); 673851a54efSLars-Peter Clausen } else { 674851a54efSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 675851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x01, 0x18); 676851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x02, 0x18); 677851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x03, 0x30); 678851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x04, 0x20); 679851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x05, 0x28); 680851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x06, 0x40); 681851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x07, 0x58); 682851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x08, 0x30); 683851a54efSLars-Peter Clausen } 684851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0xa3, 0x70); 685851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0x5b, 0x80); 686851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0x55, 0x00); 687851a54efSLars-Peter Clausen } 688851a54efSLars-Peter Clausen 689851a54efSLars-Peter Clausen return 0; 690851a54efSLars-Peter Clausen } 691851a54efSLars-Peter Clausen 692d5d51a82SLars-Peter Clausen static int adv7180_get_pad_format(struct v4l2_subdev *sd, 693f7234138SHans Verkuil struct v4l2_subdev_pad_config *cfg, 694d5d51a82SLars-Peter Clausen struct v4l2_subdev_format *format) 695d5d51a82SLars-Peter Clausen { 696851a54efSLars-Peter Clausen struct adv7180_state *state = to_state(sd); 697851a54efSLars-Peter Clausen 698851a54efSLars-Peter Clausen if (format->which == V4L2_SUBDEV_FORMAT_TRY) { 699f7234138SHans Verkuil format->format = *v4l2_subdev_get_try_format(sd, cfg, 0); 700851a54efSLars-Peter Clausen } else { 701851a54efSLars-Peter Clausen adv7180_mbus_fmt(sd, &format->format); 702851a54efSLars-Peter Clausen format->format.field = state->field; 703851a54efSLars-Peter Clausen } 704851a54efSLars-Peter Clausen 705851a54efSLars-Peter Clausen return 0; 706d5d51a82SLars-Peter Clausen } 707d5d51a82SLars-Peter Clausen 708d5d51a82SLars-Peter Clausen static int adv7180_set_pad_format(struct v4l2_subdev *sd, 709f7234138SHans Verkuil struct v4l2_subdev_pad_config *cfg, 710d5d51a82SLars-Peter Clausen struct v4l2_subdev_format *format) 711d5d51a82SLars-Peter Clausen { 712851a54efSLars-Peter Clausen struct adv7180_state *state = to_state(sd); 713851a54efSLars-Peter Clausen struct v4l2_mbus_framefmt *framefmt; 714851a54efSLars-Peter Clausen 715851a54efSLars-Peter Clausen switch (format->format.field) { 716851a54efSLars-Peter Clausen case V4L2_FIELD_NONE: 717851a54efSLars-Peter Clausen if (!(state->chip_info->flags & ADV7180_FLAG_I2P)) 718851a54efSLars-Peter Clausen format->format.field = V4L2_FIELD_INTERLACED; 719851a54efSLars-Peter Clausen break; 720851a54efSLars-Peter Clausen default: 721851a54efSLars-Peter Clausen format->format.field = V4L2_FIELD_INTERLACED; 722851a54efSLars-Peter Clausen break; 723851a54efSLars-Peter Clausen } 724851a54efSLars-Peter Clausen 725851a54efSLars-Peter Clausen if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { 726851a54efSLars-Peter Clausen framefmt = &format->format; 727851a54efSLars-Peter Clausen if (state->field != format->format.field) { 728851a54efSLars-Peter Clausen state->field = format->format.field; 729851a54efSLars-Peter Clausen adv7180_set_power(state, false); 730851a54efSLars-Peter Clausen adv7180_set_field_mode(state); 731851a54efSLars-Peter Clausen adv7180_set_power(state, true); 732851a54efSLars-Peter Clausen } 733851a54efSLars-Peter Clausen } else { 734f7234138SHans Verkuil framefmt = v4l2_subdev_get_try_format(sd, cfg, 0); 735851a54efSLars-Peter Clausen *framefmt = format->format; 736851a54efSLars-Peter Clausen } 737851a54efSLars-Peter Clausen 738851a54efSLars-Peter Clausen return adv7180_mbus_fmt(sd, framefmt); 739d5d51a82SLars-Peter Clausen } 740d5d51a82SLars-Peter Clausen 741cccb83f7SVladimir Barinov static int adv7180_g_mbus_config(struct v4l2_subdev *sd, 742cccb83f7SVladimir Barinov struct v4l2_mbus_config *cfg) 743cccb83f7SVladimir Barinov { 744b37135e3SLars-Peter Clausen struct adv7180_state *state = to_state(sd); 745b37135e3SLars-Peter Clausen 746b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 747b37135e3SLars-Peter Clausen cfg->type = V4L2_MBUS_CSI2; 748b37135e3SLars-Peter Clausen cfg->flags = V4L2_MBUS_CSI2_1_LANE | 749b37135e3SLars-Peter Clausen V4L2_MBUS_CSI2_CHANNEL_0 | 750b37135e3SLars-Peter Clausen V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; 751b37135e3SLars-Peter Clausen } else { 752cccb83f7SVladimir Barinov /* 753cccb83f7SVladimir Barinov * The ADV7180 sensor supports BT.601/656 output modes. 754cccb83f7SVladimir Barinov * The BT.656 is default and not yet configurable by s/w. 755cccb83f7SVladimir Barinov */ 756cccb83f7SVladimir Barinov cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | 757cccb83f7SVladimir Barinov V4L2_MBUS_DATA_ACTIVE_HIGH; 758cccb83f7SVladimir Barinov cfg->type = V4L2_MBUS_BT656; 759b37135e3SLars-Peter Clausen } 760cccb83f7SVladimir Barinov 761cccb83f7SVladimir Barinov return 0; 762cccb83f7SVladimir Barinov } 763cccb83f7SVladimir Barinov 764ecf37493SHans Verkuil static int adv7180_g_pixelaspect(struct v4l2_subdev *sd, struct v4l2_fract *aspect) 76564b3df92SNiklas Söderlund { 76664b3df92SNiklas Söderlund struct adv7180_state *state = to_state(sd); 76764b3df92SNiklas Söderlund 76864b3df92SNiklas Söderlund if (state->curr_norm & V4L2_STD_525_60) { 769ecf37493SHans Verkuil aspect->numerator = 11; 770ecf37493SHans Verkuil aspect->denominator = 10; 77164b3df92SNiklas Söderlund } else { 772ecf37493SHans Verkuil aspect->numerator = 54; 773ecf37493SHans Verkuil aspect->denominator = 59; 77464b3df92SNiklas Söderlund } 77564b3df92SNiklas Söderlund 77664b3df92SNiklas Söderlund return 0; 77764b3df92SNiklas Söderlund } 77864b3df92SNiklas Söderlund 779bae4c757SNiklas Söderlund static int adv7180_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm) 780bae4c757SNiklas Söderlund { 781bae4c757SNiklas Söderlund *norm = V4L2_STD_ALL; 782bae4c757SNiklas Söderlund return 0; 783bae4c757SNiklas Söderlund } 784bae4c757SNiklas Söderlund 785937feeedSHans Verkuil static int adv7180_s_stream(struct v4l2_subdev *sd, int enable) 786937feeedSHans Verkuil { 787937feeedSHans Verkuil struct adv7180_state *state = to_state(sd); 788937feeedSHans Verkuil int ret; 789937feeedSHans Verkuil 790937feeedSHans Verkuil /* It's always safe to stop streaming, no need to take the lock */ 791937feeedSHans Verkuil if (!enable) { 792937feeedSHans Verkuil state->streaming = enable; 793937feeedSHans Verkuil return 0; 794937feeedSHans Verkuil } 795937feeedSHans Verkuil 796937feeedSHans Verkuil /* Must wait until querystd released the lock */ 797937feeedSHans Verkuil ret = mutex_lock_interruptible(&state->mutex); 798937feeedSHans Verkuil if (ret) 799937feeedSHans Verkuil return ret; 800937feeedSHans Verkuil state->streaming = enable; 801937feeedSHans Verkuil mutex_unlock(&state->mutex); 802937feeedSHans Verkuil return 0; 803937feeedSHans Verkuil } 804937feeedSHans Verkuil 805937feeedSHans Verkuil static int adv7180_subscribe_event(struct v4l2_subdev *sd, 806937feeedSHans Verkuil struct v4l2_fh *fh, 807937feeedSHans Verkuil struct v4l2_event_subscription *sub) 808937feeedSHans Verkuil { 809937feeedSHans Verkuil switch (sub->type) { 810937feeedSHans Verkuil case V4L2_EVENT_SOURCE_CHANGE: 811937feeedSHans Verkuil return v4l2_src_change_event_subdev_subscribe(sd, fh, sub); 812937feeedSHans Verkuil case V4L2_EVENT_CTRL: 813937feeedSHans Verkuil return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub); 814937feeedSHans Verkuil default: 815937feeedSHans Verkuil return -EINVAL; 816937feeedSHans Verkuil } 817937feeedSHans Verkuil } 818937feeedSHans Verkuil 819cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops adv7180_video_ops = { 8208774bed9SLaurent Pinchart .s_std = adv7180_s_std, 821d0fadc86SNiklas Söderlund .g_std = adv7180_g_std, 822cb7a01acSMauro Carvalho Chehab .querystd = adv7180_querystd, 823cb7a01acSMauro Carvalho Chehab .g_input_status = adv7180_g_input_status, 824cb7a01acSMauro Carvalho Chehab .s_routing = adv7180_s_routing, 825cccb83f7SVladimir Barinov .g_mbus_config = adv7180_g_mbus_config, 826ecf37493SHans Verkuil .g_pixelaspect = adv7180_g_pixelaspect, 827bae4c757SNiklas Söderlund .g_tvnorms = adv7180_g_tvnorms, 828937feeedSHans Verkuil .s_stream = adv7180_s_stream, 829cb7a01acSMauro Carvalho Chehab }; 830cb7a01acSMauro Carvalho Chehab 831cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_core_ops adv7180_core_ops = { 832e246c333SLars-Peter Clausen .s_power = adv7180_s_power, 833937feeedSHans Verkuil .subscribe_event = adv7180_subscribe_event, 834937feeedSHans Verkuil .unsubscribe_event = v4l2_event_subdev_unsubscribe, 835cb7a01acSMauro Carvalho Chehab }; 836cb7a01acSMauro Carvalho Chehab 837d5d51a82SLars-Peter Clausen static const struct v4l2_subdev_pad_ops adv7180_pad_ops = { 838d5d51a82SLars-Peter Clausen .enum_mbus_code = adv7180_enum_mbus_code, 839d5d51a82SLars-Peter Clausen .set_fmt = adv7180_set_pad_format, 840d5d51a82SLars-Peter Clausen .get_fmt = adv7180_get_pad_format, 841d5d51a82SLars-Peter Clausen }; 842d5d51a82SLars-Peter Clausen 843cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops adv7180_ops = { 844cb7a01acSMauro Carvalho Chehab .core = &adv7180_core_ops, 845cb7a01acSMauro Carvalho Chehab .video = &adv7180_video_ops, 846d5d51a82SLars-Peter Clausen .pad = &adv7180_pad_ops, 847cb7a01acSMauro Carvalho Chehab }; 848cb7a01acSMauro Carvalho Chehab 8490c25534dSLars-Peter Clausen static irqreturn_t adv7180_irq(int irq, void *devid) 850cb7a01acSMauro Carvalho Chehab { 8510c25534dSLars-Peter Clausen struct adv7180_state *state = devid; 852cb7a01acSMauro Carvalho Chehab u8 isr3; 853cb7a01acSMauro Carvalho Chehab 854cb7a01acSMauro Carvalho Chehab mutex_lock(&state->mutex); 8553999e5d0SLars-Peter Clausen isr3 = adv7180_read(state, ADV7180_REG_ISR3); 856cb7a01acSMauro Carvalho Chehab /* clear */ 8573999e5d0SLars-Peter Clausen adv7180_write(state, ADV7180_REG_ICR3, isr3); 858cb7a01acSMauro Carvalho Chehab 859937feeedSHans Verkuil if (isr3 & ADV7180_IRQ3_AD_CHANGE) { 860937feeedSHans Verkuil static const struct v4l2_event src_ch = { 861937feeedSHans Verkuil .type = V4L2_EVENT_SOURCE_CHANGE, 862937feeedSHans Verkuil .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, 863937feeedSHans Verkuil }; 864937feeedSHans Verkuil 865937feeedSHans Verkuil v4l2_subdev_notify_event(&state->sd, &src_ch); 866937feeedSHans Verkuil } 867cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex); 868cb7a01acSMauro Carvalho Chehab 869cb7a01acSMauro Carvalho Chehab return IRQ_HANDLED; 870cb7a01acSMauro Carvalho Chehab } 871cb7a01acSMauro Carvalho Chehab 872f5dde49bSLars-Peter Clausen static int adv7180_init(struct adv7180_state *state) 873f5dde49bSLars-Peter Clausen { 874f5dde49bSLars-Peter Clausen int ret; 875f5dde49bSLars-Peter Clausen 876f5dde49bSLars-Peter Clausen /* ITU-R BT.656-4 compatible */ 877f5dde49bSLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 878f5dde49bSLars-Peter Clausen ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS); 879f5dde49bSLars-Peter Clausen if (ret < 0) 880f5dde49bSLars-Peter Clausen return ret; 881f5dde49bSLars-Peter Clausen 882f5dde49bSLars-Peter Clausen /* Manually set V bit end position in NTSC mode */ 883f5dde49bSLars-Peter Clausen return adv7180_write(state, ADV7180_REG_NTSC_V_BIT_END, 884f5dde49bSLars-Peter Clausen ADV7180_NTSC_V_BIT_END_MANUAL_NVEND); 885f5dde49bSLars-Peter Clausen } 886f5dde49bSLars-Peter Clausen 887f5dde49bSLars-Peter Clausen static int adv7180_set_std(struct adv7180_state *state, unsigned int std) 888f5dde49bSLars-Peter Clausen { 889f5dde49bSLars-Peter Clausen return adv7180_write(state, ADV7180_REG_INPUT_CONTROL, 890f5dde49bSLars-Peter Clausen (std << 4) | state->input); 891f5dde49bSLars-Peter Clausen } 892f5dde49bSLars-Peter Clausen 893f5dde49bSLars-Peter Clausen static int adv7180_select_input(struct adv7180_state *state, unsigned int input) 894f5dde49bSLars-Peter Clausen { 895f5dde49bSLars-Peter Clausen int ret; 896f5dde49bSLars-Peter Clausen 897f5dde49bSLars-Peter Clausen ret = adv7180_read(state, ADV7180_REG_INPUT_CONTROL); 898f5dde49bSLars-Peter Clausen if (ret < 0) 899f5dde49bSLars-Peter Clausen return ret; 900f5dde49bSLars-Peter Clausen 901f5dde49bSLars-Peter Clausen ret &= ~ADV7180_INPUT_CONTROL_INSEL_MASK; 902f5dde49bSLars-Peter Clausen ret |= input; 903f5dde49bSLars-Peter Clausen return adv7180_write(state, ADV7180_REG_INPUT_CONTROL, ret); 904f5dde49bSLars-Peter Clausen } 905f5dde49bSLars-Peter Clausen 906c5ef8f8cSLars-Peter Clausen static int adv7182_init(struct adv7180_state *state) 907c5ef8f8cSLars-Peter Clausen { 908b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) 909b37135e3SLars-Peter Clausen adv7180_write(state, ADV7180_REG_CSI_SLAVE_ADDR, 910b37135e3SLars-Peter Clausen ADV7180_DEFAULT_CSI_I2C_ADDR << 1); 911b37135e3SLars-Peter Clausen 912851a54efSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_I2P) 913851a54efSLars-Peter Clausen adv7180_write(state, ADV7180_REG_VPP_SLAVE_ADDR, 914851a54efSLars-Peter Clausen ADV7180_DEFAULT_VPP_I2C_ADDR << 1); 915851a54efSLars-Peter Clausen 916bf7dcb80SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_V2) { 917bf7dcb80SLars-Peter Clausen /* ADI recommended writes for improved video quality */ 918bf7dcb80SLars-Peter Clausen adv7180_write(state, 0x0080, 0x51); 919bf7dcb80SLars-Peter Clausen adv7180_write(state, 0x0081, 0x51); 920bf7dcb80SLars-Peter Clausen adv7180_write(state, 0x0082, 0x68); 921bf7dcb80SLars-Peter Clausen } 922bf7dcb80SLars-Peter Clausen 923c5ef8f8cSLars-Peter Clausen /* ADI required writes */ 924b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 925ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_OUTPUT_CONTROL, 0x4e); 926ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 0x57); 927ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_CTRL_2, 0xc0); 928b37135e3SLars-Peter Clausen } else { 929b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_V2) 930ce5d6290SSteve Longerbeam adv7180_write(state, 931ce5d6290SSteve Longerbeam ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 932ce5d6290SSteve Longerbeam 0x17); 933b37135e3SLars-Peter Clausen else 934ce5d6290SSteve Longerbeam adv7180_write(state, 935ce5d6290SSteve Longerbeam ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 936ce5d6290SSteve Longerbeam 0x07); 937ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_OUTPUT_CONTROL, 0x0c); 938ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_CTRL_2, 0x40); 939b37135e3SLars-Peter Clausen } 940b37135e3SLars-Peter Clausen 941b37135e3SLars-Peter Clausen adv7180_write(state, 0x0013, 0x00); 942c5ef8f8cSLars-Peter Clausen 943c5ef8f8cSLars-Peter Clausen return 0; 944c5ef8f8cSLars-Peter Clausen } 945c5ef8f8cSLars-Peter Clausen 946c5ef8f8cSLars-Peter Clausen static int adv7182_set_std(struct adv7180_state *state, unsigned int std) 947c5ef8f8cSLars-Peter Clausen { 948c5ef8f8cSLars-Peter Clausen return adv7180_write(state, ADV7182_REG_INPUT_VIDSEL, std << 4); 949c5ef8f8cSLars-Peter Clausen } 950c5ef8f8cSLars-Peter Clausen 951c5ef8f8cSLars-Peter Clausen enum adv7182_input_type { 952c5ef8f8cSLars-Peter Clausen ADV7182_INPUT_TYPE_CVBS, 953c5ef8f8cSLars-Peter Clausen ADV7182_INPUT_TYPE_DIFF_CVBS, 954c5ef8f8cSLars-Peter Clausen ADV7182_INPUT_TYPE_SVIDEO, 955c5ef8f8cSLars-Peter Clausen ADV7182_INPUT_TYPE_YPBPR, 956c5ef8f8cSLars-Peter Clausen }; 957c5ef8f8cSLars-Peter Clausen 958c5ef8f8cSLars-Peter Clausen static enum adv7182_input_type adv7182_get_input_type(unsigned int input) 959c5ef8f8cSLars-Peter Clausen { 960c5ef8f8cSLars-Peter Clausen switch (input) { 961c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN1: 962c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN2: 963c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN3: 964c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN4: 965c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN5: 966c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN6: 967c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN7: 968c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN8: 969c5ef8f8cSLars-Peter Clausen return ADV7182_INPUT_TYPE_CVBS; 970c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_SVIDEO_AIN1_AIN2: 971c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_SVIDEO_AIN3_AIN4: 972c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_SVIDEO_AIN5_AIN6: 973c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_SVIDEO_AIN7_AIN8: 974c5ef8f8cSLars-Peter Clausen return ADV7182_INPUT_TYPE_SVIDEO; 975c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3: 976c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6: 977c5ef8f8cSLars-Peter Clausen return ADV7182_INPUT_TYPE_YPBPR; 978c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2: 979c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4: 980c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6: 981c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8: 982c5ef8f8cSLars-Peter Clausen return ADV7182_INPUT_TYPE_DIFF_CVBS; 983c5ef8f8cSLars-Peter Clausen default: /* Will never happen */ 984c5ef8f8cSLars-Peter Clausen return 0; 985c5ef8f8cSLars-Peter Clausen } 986c5ef8f8cSLars-Peter Clausen } 987c5ef8f8cSLars-Peter Clausen 988c5ef8f8cSLars-Peter Clausen /* ADI recommended writes to registers 0x52, 0x53, 0x54 */ 989c5ef8f8cSLars-Peter Clausen static unsigned int adv7182_lbias_settings[][3] = { 990c5ef8f8cSLars-Peter Clausen [ADV7182_INPUT_TYPE_CVBS] = { 0xCB, 0x4E, 0x80 }, 991c5ef8f8cSLars-Peter Clausen [ADV7182_INPUT_TYPE_DIFF_CVBS] = { 0xC0, 0x4E, 0x80 }, 992c5ef8f8cSLars-Peter Clausen [ADV7182_INPUT_TYPE_SVIDEO] = { 0x0B, 0xCE, 0x80 }, 993c5ef8f8cSLars-Peter Clausen [ADV7182_INPUT_TYPE_YPBPR] = { 0x0B, 0x4E, 0xC0 }, 994c5ef8f8cSLars-Peter Clausen }; 995c5ef8f8cSLars-Peter Clausen 996bf7dcb80SLars-Peter Clausen static unsigned int adv7280_lbias_settings[][3] = { 997bf7dcb80SLars-Peter Clausen [ADV7182_INPUT_TYPE_CVBS] = { 0xCD, 0x4E, 0x80 }, 998bf7dcb80SLars-Peter Clausen [ADV7182_INPUT_TYPE_DIFF_CVBS] = { 0xC0, 0x4E, 0x80 }, 999bf7dcb80SLars-Peter Clausen [ADV7182_INPUT_TYPE_SVIDEO] = { 0x0B, 0xCE, 0x80 }, 1000bf7dcb80SLars-Peter Clausen [ADV7182_INPUT_TYPE_YPBPR] = { 0x0B, 0x4E, 0xC0 }, 1001bf7dcb80SLars-Peter Clausen }; 1002bf7dcb80SLars-Peter Clausen 1003c5ef8f8cSLars-Peter Clausen static int adv7182_select_input(struct adv7180_state *state, unsigned int input) 1004c5ef8f8cSLars-Peter Clausen { 1005c5ef8f8cSLars-Peter Clausen enum adv7182_input_type input_type; 1006c5ef8f8cSLars-Peter Clausen unsigned int *lbias; 1007c5ef8f8cSLars-Peter Clausen unsigned int i; 1008c5ef8f8cSLars-Peter Clausen int ret; 1009c5ef8f8cSLars-Peter Clausen 1010c5ef8f8cSLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL, input); 1011c5ef8f8cSLars-Peter Clausen if (ret) 1012c5ef8f8cSLars-Peter Clausen return ret; 1013c5ef8f8cSLars-Peter Clausen 1014c5ef8f8cSLars-Peter Clausen /* Reset clamp circuitry - ADI recommended writes */ 1015ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_RST_CLAMP, 0x00); 1016ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_RST_CLAMP, 0xff); 1017c5ef8f8cSLars-Peter Clausen 1018c5ef8f8cSLars-Peter Clausen input_type = adv7182_get_input_type(input); 1019c5ef8f8cSLars-Peter Clausen 1020c5ef8f8cSLars-Peter Clausen switch (input_type) { 1021c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_TYPE_CVBS: 1022c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_TYPE_DIFF_CVBS: 1023c5ef8f8cSLars-Peter Clausen /* ADI recommends to use the SH1 filter */ 1024ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_SHAP_FILTER_CTL_1, 0x41); 1025c5ef8f8cSLars-Peter Clausen break; 1026c5ef8f8cSLars-Peter Clausen default: 1027ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_SHAP_FILTER_CTL_1, 0x01); 1028c5ef8f8cSLars-Peter Clausen break; 1029c5ef8f8cSLars-Peter Clausen } 1030c5ef8f8cSLars-Peter Clausen 1031bf7dcb80SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_V2) 1032bf7dcb80SLars-Peter Clausen lbias = adv7280_lbias_settings[input_type]; 1033bf7dcb80SLars-Peter Clausen else 1034c5ef8f8cSLars-Peter Clausen lbias = adv7182_lbias_settings[input_type]; 1035c5ef8f8cSLars-Peter Clausen 1036c5ef8f8cSLars-Peter Clausen for (i = 0; i < ARRAY_SIZE(adv7182_lbias_settings[0]); i++) 1037ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_CVBS_TRIM + i, lbias[i]); 1038c5ef8f8cSLars-Peter Clausen 1039c5ef8f8cSLars-Peter Clausen if (input_type == ADV7182_INPUT_TYPE_DIFF_CVBS) { 1040c5ef8f8cSLars-Peter Clausen /* ADI required writes to make differential CVBS work */ 1041ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_RES_CIR, 0xa8); 1042ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_CLAMP_ADJ, 0x90); 1043ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_DIFF_MODE, 0xb0); 1044ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_AGC_ADJ1, 0x08); 1045ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_AGC_ADJ2, 0xa0); 1046c5ef8f8cSLars-Peter Clausen } else { 1047ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_RES_CIR, 0xf0); 1048ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_CLAMP_ADJ, 0xd0); 1049ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_DIFF_MODE, 0x10); 1050ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_AGC_ADJ1, 0x9c); 1051ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_AGC_ADJ2, 0x00); 1052c5ef8f8cSLars-Peter Clausen } 1053c5ef8f8cSLars-Peter Clausen 1054c5ef8f8cSLars-Peter Clausen return 0; 1055c5ef8f8cSLars-Peter Clausen } 1056c5ef8f8cSLars-Peter Clausen 1057f5dde49bSLars-Peter Clausen static const struct adv7180_chip_info adv7180_info = { 1058f5dde49bSLars-Peter Clausen .flags = ADV7180_FLAG_RESET_POWERED, 1059f5dde49bSLars-Peter Clausen /* We cannot discriminate between LQFP and 40-pin LFCSP, so accept 1060f5dde49bSLars-Peter Clausen * all inputs and let the card driver take care of validation 1061f5dde49bSLars-Peter Clausen */ 1062f5dde49bSLars-Peter Clausen .valid_input_mask = BIT(ADV7180_INPUT_CVBS_AIN1) | 1063f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_CVBS_AIN2) | 1064f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_CVBS_AIN3) | 1065f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_CVBS_AIN4) | 1066f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_CVBS_AIN5) | 1067f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_CVBS_AIN6) | 1068f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_SVIDEO_AIN1_AIN2) | 1069f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_SVIDEO_AIN3_AIN4) | 1070f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_SVIDEO_AIN5_AIN6) | 1071f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_YPRPB_AIN1_AIN2_AIN3) | 1072f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_YPRPB_AIN4_AIN5_AIN6), 1073f5dde49bSLars-Peter Clausen .init = adv7180_init, 1074f5dde49bSLars-Peter Clausen .set_std = adv7180_set_std, 1075f5dde49bSLars-Peter Clausen .select_input = adv7180_select_input, 1076f5dde49bSLars-Peter Clausen }; 1077f5dde49bSLars-Peter Clausen 1078c5ef8f8cSLars-Peter Clausen static const struct adv7180_chip_info adv7182_info = { 1079c5ef8f8cSLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1080c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1081c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) | 1082c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) | 1083c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1084c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 1085c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | 1086c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 1087c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4), 1088c5ef8f8cSLars-Peter Clausen .init = adv7182_init, 1089c5ef8f8cSLars-Peter Clausen .set_std = adv7182_set_std, 1090c5ef8f8cSLars-Peter Clausen .select_input = adv7182_select_input, 1091c5ef8f8cSLars-Peter Clausen }; 1092c5ef8f8cSLars-Peter Clausen 1093bf7dcb80SLars-Peter Clausen static const struct adv7180_chip_info adv7280_info = { 1094851a54efSLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P, 1095bf7dcb80SLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1096bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1097bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) | 1098bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) | 1099bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1100bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 1101bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3), 1102bf7dcb80SLars-Peter Clausen .init = adv7182_init, 1103bf7dcb80SLars-Peter Clausen .set_std = adv7182_set_std, 1104bf7dcb80SLars-Peter Clausen .select_input = adv7182_select_input, 1105bf7dcb80SLars-Peter Clausen }; 1106bf7dcb80SLars-Peter Clausen 1107b37135e3SLars-Peter Clausen static const struct adv7180_chip_info adv7280_m_info = { 1108851a54efSLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P, 1109b37135e3SLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1110b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1111b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) | 1112b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) | 1113b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN5) | 1114b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN6) | 1115b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) | 1116b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) | 1117b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1118b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 1119b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN5_AIN6) | 1120b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 1121b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | 1122b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6), 1123b37135e3SLars-Peter Clausen .init = adv7182_init, 1124b37135e3SLars-Peter Clausen .set_std = adv7182_set_std, 1125b37135e3SLars-Peter Clausen .select_input = adv7182_select_input, 1126b37135e3SLars-Peter Clausen }; 1127b37135e3SLars-Peter Clausen 1128bf7dcb80SLars-Peter Clausen static const struct adv7180_chip_info adv7281_info = { 1129b37135e3SLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2, 1130bf7dcb80SLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1131bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1132bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) | 1133bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) | 1134bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1135bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 1136bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 1137bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), 1138bf7dcb80SLars-Peter Clausen .init = adv7182_init, 1139bf7dcb80SLars-Peter Clausen .set_std = adv7182_set_std, 1140bf7dcb80SLars-Peter Clausen .select_input = adv7182_select_input, 1141bf7dcb80SLars-Peter Clausen }; 1142bf7dcb80SLars-Peter Clausen 1143b37135e3SLars-Peter Clausen static const struct adv7180_chip_info adv7281_m_info = { 1144b37135e3SLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2, 1145b37135e3SLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1146b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1147b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) | 1148b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) | 1149b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) | 1150b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) | 1151b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1152b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 1153b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 1154b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | 1155b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 1156b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) | 1157b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), 1158b37135e3SLars-Peter Clausen .init = adv7182_init, 1159b37135e3SLars-Peter Clausen .set_std = adv7182_set_std, 1160b37135e3SLars-Peter Clausen .select_input = adv7182_select_input, 1161b37135e3SLars-Peter Clausen }; 1162b37135e3SLars-Peter Clausen 1163b37135e3SLars-Peter Clausen static const struct adv7180_chip_info adv7281_ma_info = { 1164b37135e3SLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2, 1165b37135e3SLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1166b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1167b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) | 1168b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) | 1169b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN5) | 1170b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN6) | 1171b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) | 1172b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) | 1173b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1174b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 1175b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN5_AIN6) | 1176b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 1177b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | 1178b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6) | 1179b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 1180b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) | 1181b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6) | 1182b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), 1183b37135e3SLars-Peter Clausen .init = adv7182_init, 1184b37135e3SLars-Peter Clausen .set_std = adv7182_set_std, 1185b37135e3SLars-Peter Clausen .select_input = adv7182_select_input, 1186b37135e3SLars-Peter Clausen }; 1187b37135e3SLars-Peter Clausen 1188851a54efSLars-Peter Clausen static const struct adv7180_chip_info adv7282_info = { 1189851a54efSLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P, 1190851a54efSLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1191851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1192851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) | 1193851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) | 1194851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1195851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 1196851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 1197851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), 1198851a54efSLars-Peter Clausen .init = adv7182_init, 1199851a54efSLars-Peter Clausen .set_std = adv7182_set_std, 1200851a54efSLars-Peter Clausen .select_input = adv7182_select_input, 1201851a54efSLars-Peter Clausen }; 1202851a54efSLars-Peter Clausen 1203851a54efSLars-Peter Clausen static const struct adv7180_chip_info adv7282_m_info = { 1204851a54efSLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P, 1205851a54efSLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1206851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1207851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) | 1208851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) | 1209851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) | 1210851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) | 1211851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1212851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 1213851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 1214851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 1215851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) | 1216851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), 1217851a54efSLars-Peter Clausen .init = adv7182_init, 1218851a54efSLars-Peter Clausen .set_std = adv7182_set_std, 1219851a54efSLars-Peter Clausen .select_input = adv7182_select_input, 1220851a54efSLars-Peter Clausen }; 1221851a54efSLars-Peter Clausen 12223999e5d0SLars-Peter Clausen static int init_device(struct adv7180_state *state) 1223cb7a01acSMauro Carvalho Chehab { 1224cb7a01acSMauro Carvalho Chehab int ret; 1225cb7a01acSMauro Carvalho Chehab 12263999e5d0SLars-Peter Clausen mutex_lock(&state->mutex); 12273999e5d0SLars-Peter Clausen 122865d9e14aSSteve Longerbeam adv7180_set_power_pin(state, true); 122965d9e14aSSteve Longerbeam 1230c18818e9SLars-Peter Clausen adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES); 123116dfe72fSUlrich Hecht usleep_range(5000, 10000); 1232c18818e9SLars-Peter Clausen 1233f5dde49bSLars-Peter Clausen ret = state->chip_info->init(state); 12343e35e33cSLars-Peter Clausen if (ret) 12353999e5d0SLars-Peter Clausen goto out_unlock; 1236cb7a01acSMauro Carvalho Chehab 1237f5dde49bSLars-Peter Clausen ret = adv7180_program_std(state); 1238f5dde49bSLars-Peter Clausen if (ret) 12393999e5d0SLars-Peter Clausen goto out_unlock; 1240cb7a01acSMauro Carvalho Chehab 1241851a54efSLars-Peter Clausen adv7180_set_field_mode(state); 1242851a54efSLars-Peter Clausen 1243cb7a01acSMauro Carvalho Chehab /* register for interrupts */ 1244cb7a01acSMauro Carvalho Chehab if (state->irq > 0) { 1245cb7a01acSMauro Carvalho Chehab /* config the Interrupt pin to be active low */ 12463999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_ICONF1, 1247cb7a01acSMauro Carvalho Chehab ADV7180_ICONF1_ACTIVE_LOW | 1248cb7a01acSMauro Carvalho Chehab ADV7180_ICONF1_PSYNC_ONLY); 1249cb7a01acSMauro Carvalho Chehab if (ret < 0) 12503999e5d0SLars-Peter Clausen goto out_unlock; 1251cb7a01acSMauro Carvalho Chehab 12523999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_IMR1, 0); 1253cb7a01acSMauro Carvalho Chehab if (ret < 0) 12543999e5d0SLars-Peter Clausen goto out_unlock; 1255cb7a01acSMauro Carvalho Chehab 12563999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_IMR2, 0); 1257cb7a01acSMauro Carvalho Chehab if (ret < 0) 12583999e5d0SLars-Peter Clausen goto out_unlock; 1259cb7a01acSMauro Carvalho Chehab 1260cb7a01acSMauro Carvalho Chehab /* enable AD change interrupts interrupts */ 12613999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_IMR3, 1262cb7a01acSMauro Carvalho Chehab ADV7180_IRQ3_AD_CHANGE); 1263cb7a01acSMauro Carvalho Chehab if (ret < 0) 12643999e5d0SLars-Peter Clausen goto out_unlock; 1265cb7a01acSMauro Carvalho Chehab 12663999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_IMR4, 0); 1267cb7a01acSMauro Carvalho Chehab if (ret < 0) 12683999e5d0SLars-Peter Clausen goto out_unlock; 1269cb7a01acSMauro Carvalho Chehab } 1270cb7a01acSMauro Carvalho Chehab 12713999e5d0SLars-Peter Clausen out_unlock: 12723999e5d0SLars-Peter Clausen mutex_unlock(&state->mutex); 1273df065b37SAlexey Khoroshilov 1274df065b37SAlexey Khoroshilov return ret; 1275cb7a01acSMauro Carvalho Chehab } 1276cb7a01acSMauro Carvalho Chehab 12774c62e976SGreg Kroah-Hartman static int adv7180_probe(struct i2c_client *client, 1278cb7a01acSMauro Carvalho Chehab const struct i2c_device_id *id) 1279cb7a01acSMauro Carvalho Chehab { 1280cb7a01acSMauro Carvalho Chehab struct adv7180_state *state; 1281cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd; 1282cb7a01acSMauro Carvalho Chehab int ret; 1283cb7a01acSMauro Carvalho Chehab 1284cb7a01acSMauro Carvalho Chehab /* Check if the adapter supports the needed features */ 1285cb7a01acSMauro Carvalho Chehab if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 1286cb7a01acSMauro Carvalho Chehab return -EIO; 1287cb7a01acSMauro Carvalho Chehab 1288cb7a01acSMauro Carvalho Chehab v4l_info(client, "chip found @ 0x%02x (%s)\n", 1289cb7a01acSMauro Carvalho Chehab client->addr, client->adapter->name); 1290cb7a01acSMauro Carvalho Chehab 1291c02b211dSLaurent Pinchart state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL); 12927657e064SFabio Estevam if (state == NULL) 12937657e064SFabio Estevam return -ENOMEM; 1294cb7a01acSMauro Carvalho Chehab 12953999e5d0SLars-Peter Clausen state->client = client; 1296851a54efSLars-Peter Clausen state->field = V4L2_FIELD_INTERLACED; 1297f5dde49bSLars-Peter Clausen state->chip_info = (struct adv7180_chip_info *)id->driver_data; 12983999e5d0SLars-Peter Clausen 129965d9e14aSSteve Longerbeam state->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown", 130065d9e14aSSteve Longerbeam GPIOD_OUT_HIGH); 130165d9e14aSSteve Longerbeam if (IS_ERR(state->pwdn_gpio)) { 130265d9e14aSSteve Longerbeam ret = PTR_ERR(state->pwdn_gpio); 130365d9e14aSSteve Longerbeam v4l_err(client, "request for power pin failed: %d\n", ret); 130465d9e14aSSteve Longerbeam return ret; 130565d9e14aSSteve Longerbeam } 130665d9e14aSSteve Longerbeam 1307b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 1308b37135e3SLars-Peter Clausen state->csi_client = i2c_new_dummy(client->adapter, 1309b37135e3SLars-Peter Clausen ADV7180_DEFAULT_CSI_I2C_ADDR); 1310b37135e3SLars-Peter Clausen if (!state->csi_client) 1311b37135e3SLars-Peter Clausen return -ENOMEM; 1312b37135e3SLars-Peter Clausen } 1313b37135e3SLars-Peter Clausen 1314851a54efSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_I2P) { 1315851a54efSLars-Peter Clausen state->vpp_client = i2c_new_dummy(client->adapter, 1316851a54efSLars-Peter Clausen ADV7180_DEFAULT_VPP_I2C_ADDR); 1317851a54efSLars-Peter Clausen if (!state->vpp_client) { 1318851a54efSLars-Peter Clausen ret = -ENOMEM; 1319851a54efSLars-Peter Clausen goto err_unregister_csi_client; 1320851a54efSLars-Peter Clausen } 1321851a54efSLars-Peter Clausen } 1322851a54efSLars-Peter Clausen 1323cb7a01acSMauro Carvalho Chehab state->irq = client->irq; 1324cb7a01acSMauro Carvalho Chehab mutex_init(&state->mutex); 1325937feeedSHans Verkuil state->curr_norm = V4L2_STD_NTSC; 1326f5dde49bSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_RESET_POWERED) 1327e246c333SLars-Peter Clausen state->powered = true; 1328f5dde49bSLars-Peter Clausen else 1329f5dde49bSLars-Peter Clausen state->powered = false; 1330cb7a01acSMauro Carvalho Chehab state->input = 0; 1331cb7a01acSMauro Carvalho Chehab sd = &state->sd; 1332cb7a01acSMauro Carvalho Chehab v4l2_i2c_subdev_init(sd, client, &adv7180_ops); 1333937feeedSHans Verkuil sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; 1334cb7a01acSMauro Carvalho Chehab 1335cb7a01acSMauro Carvalho Chehab ret = adv7180_init_controls(state); 1336cb7a01acSMauro Carvalho Chehab if (ret) 1337851a54efSLars-Peter Clausen goto err_unregister_vpp_client; 1338d5d51a82SLars-Peter Clausen 1339d5d51a82SLars-Peter Clausen state->pad.flags = MEDIA_PAD_FL_SOURCE; 13404ca72efaSMauro Carvalho Chehab sd->entity.flags |= MEDIA_ENT_F_ATV_DECODER; 1341ab22e77cSMauro Carvalho Chehab ret = media_entity_pads_init(&sd->entity, 1, &state->pad); 1342cb7a01acSMauro Carvalho Chehab if (ret) 1343cb7a01acSMauro Carvalho Chehab goto err_free_ctrl; 1344fa5b7945SLars-Peter Clausen 1345d5d51a82SLars-Peter Clausen ret = init_device(state); 1346d5d51a82SLars-Peter Clausen if (ret) 1347d5d51a82SLars-Peter Clausen goto err_media_entity_cleanup; 1348d5d51a82SLars-Peter Clausen 1349fa5721d1SLars-Peter Clausen if (state->irq) { 1350fa5721d1SLars-Peter Clausen ret = request_threaded_irq(client->irq, NULL, adv7180_irq, 1351f3e991d4SLars-Peter Clausen IRQF_ONESHOT | IRQF_TRIGGER_FALLING, 1352f3e991d4SLars-Peter Clausen KBUILD_MODNAME, state); 1353fa5721d1SLars-Peter Clausen if (ret) 1354d5d51a82SLars-Peter Clausen goto err_media_entity_cleanup; 1355fa5721d1SLars-Peter Clausen } 1356fa5721d1SLars-Peter Clausen 1357fa5b7945SLars-Peter Clausen ret = v4l2_async_register_subdev(sd); 1358fa5b7945SLars-Peter Clausen if (ret) 1359fa5b7945SLars-Peter Clausen goto err_free_irq; 1360fa5b7945SLars-Peter Clausen 1361cb7a01acSMauro Carvalho Chehab return 0; 1362cb7a01acSMauro Carvalho Chehab 1363fa5b7945SLars-Peter Clausen err_free_irq: 1364fa5b7945SLars-Peter Clausen if (state->irq > 0) 1365fa5b7945SLars-Peter Clausen free_irq(client->irq, state); 1366d5d51a82SLars-Peter Clausen err_media_entity_cleanup: 1367d5d51a82SLars-Peter Clausen media_entity_cleanup(&sd->entity); 1368cb7a01acSMauro Carvalho Chehab err_free_ctrl: 1369cb7a01acSMauro Carvalho Chehab adv7180_exit_controls(state); 1370851a54efSLars-Peter Clausen err_unregister_vpp_client: 1371851a54efSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_I2P) 1372851a54efSLars-Peter Clausen i2c_unregister_device(state->vpp_client); 1373b37135e3SLars-Peter Clausen err_unregister_csi_client: 1374b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) 1375b37135e3SLars-Peter Clausen i2c_unregister_device(state->csi_client); 1376297a0ae3SLars-Peter Clausen mutex_destroy(&state->mutex); 1377cb7a01acSMauro Carvalho Chehab return ret; 1378cb7a01acSMauro Carvalho Chehab } 1379cb7a01acSMauro Carvalho Chehab 13804c62e976SGreg Kroah-Hartman static int adv7180_remove(struct i2c_client *client) 1381cb7a01acSMauro Carvalho Chehab { 1382cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = i2c_get_clientdata(client); 1383cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 1384cb7a01acSMauro Carvalho Chehab 1385fa5b7945SLars-Peter Clausen v4l2_async_unregister_subdev(sd); 1386fa5b7945SLars-Peter Clausen 13870c25534dSLars-Peter Clausen if (state->irq > 0) 1388cb7a01acSMauro Carvalho Chehab free_irq(client->irq, state); 1389cb7a01acSMauro Carvalho Chehab 1390d5d51a82SLars-Peter Clausen media_entity_cleanup(&sd->entity); 1391b13f4af2SLars-Peter Clausen adv7180_exit_controls(state); 1392b37135e3SLars-Peter Clausen 1393851a54efSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_I2P) 1394851a54efSLars-Peter Clausen i2c_unregister_device(state->vpp_client); 1395b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) 1396b37135e3SLars-Peter Clausen i2c_unregister_device(state->csi_client); 1397b37135e3SLars-Peter Clausen 139865d9e14aSSteve Longerbeam adv7180_set_power_pin(state, false); 139965d9e14aSSteve Longerbeam 1400297a0ae3SLars-Peter Clausen mutex_destroy(&state->mutex); 1401b37135e3SLars-Peter Clausen 1402cb7a01acSMauro Carvalho Chehab return 0; 1403cb7a01acSMauro Carvalho Chehab } 1404cb7a01acSMauro Carvalho Chehab 1405cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id adv7180_id[] = { 1406f5dde49bSLars-Peter Clausen { "adv7180", (kernel_ulong_t)&adv7180_info }, 1407c5ef8f8cSLars-Peter Clausen { "adv7182", (kernel_ulong_t)&adv7182_info }, 1408bf7dcb80SLars-Peter Clausen { "adv7280", (kernel_ulong_t)&adv7280_info }, 1409b37135e3SLars-Peter Clausen { "adv7280-m", (kernel_ulong_t)&adv7280_m_info }, 1410bf7dcb80SLars-Peter Clausen { "adv7281", (kernel_ulong_t)&adv7281_info }, 1411b37135e3SLars-Peter Clausen { "adv7281-m", (kernel_ulong_t)&adv7281_m_info }, 1412b37135e3SLars-Peter Clausen { "adv7281-ma", (kernel_ulong_t)&adv7281_ma_info }, 1413851a54efSLars-Peter Clausen { "adv7282", (kernel_ulong_t)&adv7282_info }, 1414851a54efSLars-Peter Clausen { "adv7282-m", (kernel_ulong_t)&adv7282_m_info }, 1415cb7a01acSMauro Carvalho Chehab {}, 1416cb7a01acSMauro Carvalho Chehab }; 1417f5dde49bSLars-Peter Clausen MODULE_DEVICE_TABLE(i2c, adv7180_id); 1418cb7a01acSMauro Carvalho Chehab 1419cc1088dcSLars-Peter Clausen #ifdef CONFIG_PM_SLEEP 1420cc1088dcSLars-Peter Clausen static int adv7180_suspend(struct device *dev) 1421cb7a01acSMauro Carvalho Chehab { 1422cc1088dcSLars-Peter Clausen struct i2c_client *client = to_i2c_client(dev); 1423e246c333SLars-Peter Clausen struct v4l2_subdev *sd = i2c_get_clientdata(client); 1424e246c333SLars-Peter Clausen struct adv7180_state *state = to_state(sd); 1425cb7a01acSMauro Carvalho Chehab 14263999e5d0SLars-Peter Clausen return adv7180_set_power(state, false); 1427cb7a01acSMauro Carvalho Chehab } 1428cb7a01acSMauro Carvalho Chehab 1429cc1088dcSLars-Peter Clausen static int adv7180_resume(struct device *dev) 1430cb7a01acSMauro Carvalho Chehab { 1431cc1088dcSLars-Peter Clausen struct i2c_client *client = to_i2c_client(dev); 1432cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = i2c_get_clientdata(client); 1433cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 1434cb7a01acSMauro Carvalho Chehab int ret; 1435cb7a01acSMauro Carvalho Chehab 14363999e5d0SLars-Peter Clausen ret = init_device(state); 1437cb7a01acSMauro Carvalho Chehab if (ret < 0) 1438cb7a01acSMauro Carvalho Chehab return ret; 1439c18818e9SLars-Peter Clausen 1440c18818e9SLars-Peter Clausen ret = adv7180_set_power(state, state->powered); 1441c18818e9SLars-Peter Clausen if (ret) 1442c18818e9SLars-Peter Clausen return ret; 1443c18818e9SLars-Peter Clausen 1444cb7a01acSMauro Carvalho Chehab return 0; 1445cb7a01acSMauro Carvalho Chehab } 1446cc1088dcSLars-Peter Clausen 1447cc1088dcSLars-Peter Clausen static SIMPLE_DEV_PM_OPS(adv7180_pm_ops, adv7180_suspend, adv7180_resume); 1448cc1088dcSLars-Peter Clausen #define ADV7180_PM_OPS (&adv7180_pm_ops) 1449cc1088dcSLars-Peter Clausen 1450cc1088dcSLars-Peter Clausen #else 1451cc1088dcSLars-Peter Clausen #define ADV7180_PM_OPS NULL 1452cb7a01acSMauro Carvalho Chehab #endif 1453cb7a01acSMauro Carvalho Chehab 1454250121d3SBen Dooks #ifdef CONFIG_OF 1455250121d3SBen Dooks static const struct of_device_id adv7180_of_id[] = { 1456250121d3SBen Dooks { .compatible = "adi,adv7180", }, 1457bf14e74cSJulian Scheel { .compatible = "adi,adv7182", }, 1458bf14e74cSJulian Scheel { .compatible = "adi,adv7280", }, 1459bf14e74cSJulian Scheel { .compatible = "adi,adv7280-m", }, 1460bf14e74cSJulian Scheel { .compatible = "adi,adv7281", }, 1461bf14e74cSJulian Scheel { .compatible = "adi,adv7281-m", }, 1462bf14e74cSJulian Scheel { .compatible = "adi,adv7281-ma", }, 1463bf14e74cSJulian Scheel { .compatible = "adi,adv7282", }, 1464bf14e74cSJulian Scheel { .compatible = "adi,adv7282-m", }, 1465250121d3SBen Dooks { }, 1466250121d3SBen Dooks }; 1467250121d3SBen Dooks 1468250121d3SBen Dooks MODULE_DEVICE_TABLE(of, adv7180_of_id); 1469250121d3SBen Dooks #endif 1470250121d3SBen Dooks 1471cb7a01acSMauro Carvalho Chehab static struct i2c_driver adv7180_driver = { 1472cb7a01acSMauro Carvalho Chehab .driver = { 1473cb7a01acSMauro Carvalho Chehab .name = KBUILD_MODNAME, 1474cc1088dcSLars-Peter Clausen .pm = ADV7180_PM_OPS, 1475250121d3SBen Dooks .of_match_table = of_match_ptr(adv7180_of_id), 1476cb7a01acSMauro Carvalho Chehab }, 1477cb7a01acSMauro Carvalho Chehab .probe = adv7180_probe, 14784c62e976SGreg Kroah-Hartman .remove = adv7180_remove, 1479cb7a01acSMauro Carvalho Chehab .id_table = adv7180_id, 1480cb7a01acSMauro Carvalho Chehab }; 1481cb7a01acSMauro Carvalho Chehab 1482cb7a01acSMauro Carvalho Chehab module_i2c_driver(adv7180_driver); 1483cb7a01acSMauro Carvalho Chehab 1484cb7a01acSMauro Carvalho Chehab MODULE_DESCRIPTION("Analog Devices ADV7180 video decoder driver"); 1485cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Mocean Laboratories"); 1486cb7a01acSMauro Carvalho Chehab MODULE_LICENSE("GPL v2"); 1487