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> 28cb7a01acSMauro Carvalho Chehab #include <media/v4l2-ioctl.h> 29cb7a01acSMauro Carvalho Chehab #include <linux/videodev2.h> 30cb7a01acSMauro Carvalho Chehab #include <media/v4l2-device.h> 31cb7a01acSMauro Carvalho Chehab #include <media/v4l2-ctrls.h> 32cb7a01acSMauro Carvalho Chehab #include <linux/mutex.h> 33c18818e9SLars-Peter Clausen #include <linux/delay.h> 34cb7a01acSMauro Carvalho Chehab 35f5dde49bSLars-Peter Clausen #define ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM 0x0 36f5dde49bSLars-Peter Clausen #define ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM_PED 0x1 37f5dde49bSLars-Peter Clausen #define ADV7180_STD_AD_PAL_N_NTSC_J_SECAM 0x2 38f5dde49bSLars-Peter Clausen #define ADV7180_STD_AD_PAL_N_NTSC_M_SECAM 0x3 39f5dde49bSLars-Peter Clausen #define ADV7180_STD_NTSC_J 0x4 40f5dde49bSLars-Peter Clausen #define ADV7180_STD_NTSC_M 0x5 41f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL60 0x6 42f5dde49bSLars-Peter Clausen #define ADV7180_STD_NTSC_443 0x7 43f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_BG 0x8 44f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_N 0x9 45f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_M 0xa 46f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_M_PED 0xb 47f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_COMB_N 0xc 48f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_COMB_N_PED 0xd 49f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_SECAM 0xe 50f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_SECAM_PED 0xf 51f5dde49bSLars-Peter Clausen 523999e5d0SLars-Peter Clausen #define ADV7180_REG_INPUT_CONTROL 0x0000 53cb7a01acSMauro Carvalho Chehab #define ADV7180_INPUT_CONTROL_INSEL_MASK 0x0f 54cb7a01acSMauro Carvalho Chehab 55c5ef8f8cSLars-Peter Clausen #define ADV7182_REG_INPUT_VIDSEL 0x0002 56c5ef8f8cSLars-Peter Clausen 573999e5d0SLars-Peter Clausen #define ADV7180_REG_EXTENDED_OUTPUT_CONTROL 0x0004 58cb7a01acSMauro Carvalho Chehab #define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS 0xC5 59cb7a01acSMauro Carvalho Chehab 60029d6177SLars-Peter Clausen #define ADV7180_REG_AUTODETECT_ENABLE 0x07 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 1013999e5d0SLars-Peter Clausen #define ADV7180_REG_ICONF1 0x0040 102cb7a01acSMauro Carvalho Chehab #define ADV7180_ICONF1_ACTIVE_LOW 0x01 103cb7a01acSMauro Carvalho Chehab #define ADV7180_ICONF1_PSYNC_ONLY 0x10 104cb7a01acSMauro Carvalho Chehab #define ADV7180_ICONF1_ACTIVE_TO_CLR 0xC0 105cb7a01acSMauro Carvalho Chehab /* Saturation */ 1063999e5d0SLars-Peter Clausen #define ADV7180_REG_SD_SAT_CB 0x00e3 /*Unsigned */ 1073999e5d0SLars-Peter Clausen #define ADV7180_REG_SD_SAT_CR 0x00e4 /*Unsigned */ 108cb7a01acSMauro Carvalho Chehab #define ADV7180_SAT_MIN 0 109cb7a01acSMauro Carvalho Chehab #define ADV7180_SAT_DEF 128 110cb7a01acSMauro Carvalho Chehab #define ADV7180_SAT_MAX 255 111cb7a01acSMauro Carvalho Chehab 112cb7a01acSMauro Carvalho Chehab #define ADV7180_IRQ1_LOCK 0x01 113cb7a01acSMauro Carvalho Chehab #define ADV7180_IRQ1_UNLOCK 0x02 1143999e5d0SLars-Peter Clausen #define ADV7180_REG_ISR1 0x0042 1153999e5d0SLars-Peter Clausen #define ADV7180_REG_ICR1 0x0043 1163999e5d0SLars-Peter Clausen #define ADV7180_REG_IMR1 0x0044 1173999e5d0SLars-Peter Clausen #define ADV7180_REG_IMR2 0x0048 118cb7a01acSMauro Carvalho Chehab #define ADV7180_IRQ3_AD_CHANGE 0x08 1193999e5d0SLars-Peter Clausen #define ADV7180_REG_ISR3 0x004A 1203999e5d0SLars-Peter Clausen #define ADV7180_REG_ICR3 0x004B 1213999e5d0SLars-Peter Clausen #define ADV7180_REG_IMR3 0x004C 122029d6177SLars-Peter Clausen #define ADV7180_REG_IMR4 0x50 123cb7a01acSMauro Carvalho Chehab 1243999e5d0SLars-Peter Clausen #define ADV7180_REG_NTSC_V_BIT_END 0x00E6 125cb7a01acSMauro Carvalho Chehab #define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND 0x4F 126cb7a01acSMauro Carvalho Chehab 127851a54efSLars-Peter Clausen #define ADV7180_REG_VPP_SLAVE_ADDR 0xFD 128b37135e3SLars-Peter Clausen #define ADV7180_REG_CSI_SLAVE_ADDR 0xFE 129b37135e3SLars-Peter Clausen 130b37135e3SLars-Peter Clausen #define ADV7180_CSI_REG_PWRDN 0x00 131b37135e3SLars-Peter Clausen #define ADV7180_CSI_PWRDN 0x80 132b37135e3SLars-Peter Clausen 133f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN1 0x00 134f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN2 0x01 135f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN3 0x02 136f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN4 0x03 137f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN5 0x04 138f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN6 0x05 139f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_SVIDEO_AIN1_AIN2 0x06 140f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_SVIDEO_AIN3_AIN4 0x07 141f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_SVIDEO_AIN5_AIN6 0x08 142f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_YPRPB_AIN1_AIN2_AIN3 0x09 143f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0a 144f5dde49bSLars-Peter Clausen 145c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN1 0x00 146c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN2 0x01 147c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN3 0x02 148c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN4 0x03 149c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN5 0x04 150c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN6 0x05 151c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN7 0x06 152c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN8 0x07 153c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_SVIDEO_AIN1_AIN2 0x08 154c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_SVIDEO_AIN3_AIN4 0x09 155c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_SVIDEO_AIN5_AIN6 0x0a 156c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_SVIDEO_AIN7_AIN8 0x0b 157c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3 0x0c 158c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0d 159c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2 0x0e 160c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4 0x0f 161c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6 0x10 162c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8 0x11 163c5ef8f8cSLars-Peter Clausen 164b37135e3SLars-Peter Clausen #define ADV7180_DEFAULT_CSI_I2C_ADDR 0x44 165851a54efSLars-Peter Clausen #define ADV7180_DEFAULT_VPP_I2C_ADDR 0x42 166b37135e3SLars-Peter Clausen 167f5dde49bSLars-Peter Clausen struct adv7180_state; 168f5dde49bSLars-Peter Clausen 169f5dde49bSLars-Peter Clausen #define ADV7180_FLAG_RESET_POWERED BIT(0) 170bf7dcb80SLars-Peter Clausen #define ADV7180_FLAG_V2 BIT(1) 171b37135e3SLars-Peter Clausen #define ADV7180_FLAG_MIPI_CSI2 BIT(2) 172851a54efSLars-Peter Clausen #define ADV7180_FLAG_I2P BIT(3) 173f5dde49bSLars-Peter Clausen 174f5dde49bSLars-Peter Clausen struct adv7180_chip_info { 175f5dde49bSLars-Peter Clausen unsigned int flags; 176f5dde49bSLars-Peter Clausen unsigned int valid_input_mask; 177f5dde49bSLars-Peter Clausen int (*set_std)(struct adv7180_state *st, unsigned int std); 178f5dde49bSLars-Peter Clausen int (*select_input)(struct adv7180_state *st, unsigned int input); 179f5dde49bSLars-Peter Clausen int (*init)(struct adv7180_state *state); 180f5dde49bSLars-Peter Clausen }; 181f5dde49bSLars-Peter Clausen 182cb7a01acSMauro Carvalho Chehab struct adv7180_state { 183cb7a01acSMauro Carvalho Chehab struct v4l2_ctrl_handler ctrl_hdl; 184cb7a01acSMauro Carvalho Chehab struct v4l2_subdev sd; 185d5d51a82SLars-Peter Clausen struct media_pad pad; 186cb7a01acSMauro Carvalho Chehab struct mutex mutex; /* mutual excl. when accessing chip */ 187cb7a01acSMauro Carvalho Chehab int irq; 188cb7a01acSMauro Carvalho Chehab v4l2_std_id curr_norm; 189cb7a01acSMauro Carvalho Chehab bool autodetect; 190e246c333SLars-Peter Clausen bool powered; 191cb7a01acSMauro Carvalho Chehab u8 input; 1923999e5d0SLars-Peter Clausen 1933999e5d0SLars-Peter Clausen struct i2c_client *client; 1943999e5d0SLars-Peter Clausen unsigned int register_page; 195b37135e3SLars-Peter Clausen struct i2c_client *csi_client; 196851a54efSLars-Peter Clausen struct i2c_client *vpp_client; 197f5dde49bSLars-Peter Clausen const struct adv7180_chip_info *chip_info; 198851a54efSLars-Peter Clausen enum v4l2_field field; 199cb7a01acSMauro Carvalho Chehab }; 200cb7a01acSMauro Carvalho Chehab #define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler, \ 201cb7a01acSMauro Carvalho Chehab struct adv7180_state, \ 202cb7a01acSMauro Carvalho Chehab ctrl_hdl)->sd) 203cb7a01acSMauro Carvalho Chehab 2043999e5d0SLars-Peter Clausen static int adv7180_select_page(struct adv7180_state *state, unsigned int page) 2053999e5d0SLars-Peter Clausen { 2063999e5d0SLars-Peter Clausen if (state->register_page != page) { 2073999e5d0SLars-Peter Clausen i2c_smbus_write_byte_data(state->client, ADV7180_REG_CTRL, 2083999e5d0SLars-Peter Clausen page); 2093999e5d0SLars-Peter Clausen state->register_page = page; 2103999e5d0SLars-Peter Clausen } 2113999e5d0SLars-Peter Clausen 2123999e5d0SLars-Peter Clausen return 0; 2133999e5d0SLars-Peter Clausen } 2143999e5d0SLars-Peter Clausen 2153999e5d0SLars-Peter Clausen static int adv7180_write(struct adv7180_state *state, unsigned int reg, 2163999e5d0SLars-Peter Clausen unsigned int value) 2173999e5d0SLars-Peter Clausen { 2183999e5d0SLars-Peter Clausen lockdep_assert_held(&state->mutex); 2193999e5d0SLars-Peter Clausen adv7180_select_page(state, reg >> 8); 2203999e5d0SLars-Peter Clausen return i2c_smbus_write_byte_data(state->client, reg & 0xff, value); 2213999e5d0SLars-Peter Clausen } 2223999e5d0SLars-Peter Clausen 2233999e5d0SLars-Peter Clausen static int adv7180_read(struct adv7180_state *state, unsigned int reg) 2243999e5d0SLars-Peter Clausen { 2253999e5d0SLars-Peter Clausen lockdep_assert_held(&state->mutex); 2263999e5d0SLars-Peter Clausen adv7180_select_page(state, reg >> 8); 2273999e5d0SLars-Peter Clausen return i2c_smbus_read_byte_data(state->client, reg & 0xff); 2283999e5d0SLars-Peter Clausen } 2293999e5d0SLars-Peter Clausen 230b37135e3SLars-Peter Clausen static int adv7180_csi_write(struct adv7180_state *state, unsigned int reg, 231b37135e3SLars-Peter Clausen unsigned int value) 232b37135e3SLars-Peter Clausen { 233b37135e3SLars-Peter Clausen return i2c_smbus_write_byte_data(state->csi_client, reg, value); 234b37135e3SLars-Peter Clausen } 235b37135e3SLars-Peter Clausen 236f5dde49bSLars-Peter Clausen static int adv7180_set_video_standard(struct adv7180_state *state, 237f5dde49bSLars-Peter Clausen unsigned int std) 238f5dde49bSLars-Peter Clausen { 239f5dde49bSLars-Peter Clausen return state->chip_info->set_std(state, std); 240f5dde49bSLars-Peter Clausen } 2413999e5d0SLars-Peter Clausen 242851a54efSLars-Peter Clausen static int adv7180_vpp_write(struct adv7180_state *state, unsigned int reg, 243851a54efSLars-Peter Clausen unsigned int value) 244851a54efSLars-Peter Clausen { 245851a54efSLars-Peter Clausen return i2c_smbus_write_byte_data(state->vpp_client, reg, value); 246851a54efSLars-Peter Clausen } 247851a54efSLars-Peter Clausen 248cb7a01acSMauro Carvalho Chehab static v4l2_std_id adv7180_std_to_v4l2(u8 status1) 249cb7a01acSMauro Carvalho Chehab { 250b294a192SVladimir Barinov /* in case V4L2_IN_ST_NO_SIGNAL */ 251b294a192SVladimir Barinov if (!(status1 & ADV7180_STATUS1_IN_LOCK)) 252b294a192SVladimir Barinov return V4L2_STD_UNKNOWN; 253b294a192SVladimir Barinov 254cb7a01acSMauro Carvalho Chehab switch (status1 & ADV7180_STATUS1_AUTOD_MASK) { 255cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_NTSM_M_J: 256cb7a01acSMauro Carvalho Chehab return V4L2_STD_NTSC; 257cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_NTSC_4_43: 258cb7a01acSMauro Carvalho Chehab return V4L2_STD_NTSC_443; 259cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_PAL_M: 260cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL_M; 261cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_PAL_60: 262cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL_60; 263cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_PAL_B_G: 264cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL; 265cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_SECAM: 266cb7a01acSMauro Carvalho Chehab return V4L2_STD_SECAM; 267cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_PAL_COMB: 268cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL_Nc | V4L2_STD_PAL_N; 269cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_SECAM_525: 270cb7a01acSMauro Carvalho Chehab return V4L2_STD_SECAM; 271cb7a01acSMauro Carvalho Chehab default: 272cb7a01acSMauro Carvalho Chehab return V4L2_STD_UNKNOWN; 273cb7a01acSMauro Carvalho Chehab } 274cb7a01acSMauro Carvalho Chehab } 275cb7a01acSMauro Carvalho Chehab 276cb7a01acSMauro Carvalho Chehab static int v4l2_std_to_adv7180(v4l2_std_id std) 277cb7a01acSMauro Carvalho Chehab { 278cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_PAL_60) 279f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL60; 280cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_NTSC_443) 281f5dde49bSLars-Peter Clausen return ADV7180_STD_NTSC_443; 282cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_PAL_N) 283f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL_N; 284cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_PAL_M) 285f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL_M; 286cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_PAL_Nc) 287f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL_COMB_N; 288cb7a01acSMauro Carvalho Chehab 289cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_PAL) 290f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL_BG; 291cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_NTSC) 292f5dde49bSLars-Peter Clausen return ADV7180_STD_NTSC_M; 293cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_SECAM) 294f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL_SECAM; 295cb7a01acSMauro Carvalho Chehab 296cb7a01acSMauro Carvalho Chehab return -EINVAL; 297cb7a01acSMauro Carvalho Chehab } 298cb7a01acSMauro Carvalho Chehab 299cb7a01acSMauro Carvalho Chehab static u32 adv7180_status_to_v4l2(u8 status1) 300cb7a01acSMauro Carvalho Chehab { 301cb7a01acSMauro Carvalho Chehab if (!(status1 & ADV7180_STATUS1_IN_LOCK)) 302cb7a01acSMauro Carvalho Chehab return V4L2_IN_ST_NO_SIGNAL; 303cb7a01acSMauro Carvalho Chehab 304cb7a01acSMauro Carvalho Chehab return 0; 305cb7a01acSMauro Carvalho Chehab } 306cb7a01acSMauro Carvalho Chehab 3073999e5d0SLars-Peter Clausen static int __adv7180_status(struct adv7180_state *state, u32 *status, 308cb7a01acSMauro Carvalho Chehab v4l2_std_id *std) 309cb7a01acSMauro Carvalho Chehab { 3103999e5d0SLars-Peter Clausen int status1 = adv7180_read(state, ADV7180_REG_STATUS1); 311cb7a01acSMauro Carvalho Chehab 312cb7a01acSMauro Carvalho Chehab if (status1 < 0) 313cb7a01acSMauro Carvalho Chehab return status1; 314cb7a01acSMauro Carvalho Chehab 315cb7a01acSMauro Carvalho Chehab if (status) 316cb7a01acSMauro Carvalho Chehab *status = adv7180_status_to_v4l2(status1); 317cb7a01acSMauro Carvalho Chehab if (std) 318cb7a01acSMauro Carvalho Chehab *std = adv7180_std_to_v4l2(status1); 319cb7a01acSMauro Carvalho Chehab 320cb7a01acSMauro Carvalho Chehab return 0; 321cb7a01acSMauro Carvalho Chehab } 322cb7a01acSMauro Carvalho Chehab 323cb7a01acSMauro Carvalho Chehab static inline struct adv7180_state *to_state(struct v4l2_subdev *sd) 324cb7a01acSMauro Carvalho Chehab { 325cb7a01acSMauro Carvalho Chehab return container_of(sd, struct adv7180_state, sd); 326cb7a01acSMauro Carvalho Chehab } 327cb7a01acSMauro Carvalho Chehab 328cb7a01acSMauro Carvalho Chehab static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) 329cb7a01acSMauro Carvalho Chehab { 330cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 331cb7a01acSMauro Carvalho Chehab int err = mutex_lock_interruptible(&state->mutex); 332cb7a01acSMauro Carvalho Chehab if (err) 333cb7a01acSMauro Carvalho Chehab return err; 334cb7a01acSMauro Carvalho Chehab 335cb7a01acSMauro Carvalho Chehab /* when we are interrupt driven we know the state */ 336cb7a01acSMauro Carvalho Chehab if (!state->autodetect || state->irq > 0) 337cb7a01acSMauro Carvalho Chehab *std = state->curr_norm; 338cb7a01acSMauro Carvalho Chehab else 3393999e5d0SLars-Peter Clausen err = __adv7180_status(state, NULL, std); 340cb7a01acSMauro Carvalho Chehab 341cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex); 342cb7a01acSMauro Carvalho Chehab return err; 343cb7a01acSMauro Carvalho Chehab } 344cb7a01acSMauro Carvalho Chehab 345cb7a01acSMauro Carvalho Chehab static int adv7180_s_routing(struct v4l2_subdev *sd, u32 input, 346cb7a01acSMauro Carvalho Chehab u32 output, u32 config) 347cb7a01acSMauro Carvalho Chehab { 348cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 349cb7a01acSMauro Carvalho Chehab int ret = mutex_lock_interruptible(&state->mutex); 350cb7a01acSMauro Carvalho Chehab 351cb7a01acSMauro Carvalho Chehab if (ret) 352cb7a01acSMauro Carvalho Chehab return ret; 353cb7a01acSMauro Carvalho Chehab 354f5dde49bSLars-Peter Clausen if (input > 31 || !(BIT(input) & state->chip_info->valid_input_mask)) { 355f5dde49bSLars-Peter Clausen ret = -EINVAL; 356cb7a01acSMauro Carvalho Chehab goto out; 357f5dde49bSLars-Peter Clausen } 358cb7a01acSMauro Carvalho Chehab 359f5dde49bSLars-Peter Clausen ret = state->chip_info->select_input(state, input); 360cb7a01acSMauro Carvalho Chehab 361f5dde49bSLars-Peter Clausen if (ret == 0) 362cb7a01acSMauro Carvalho Chehab state->input = input; 363cb7a01acSMauro Carvalho Chehab out: 364cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex); 365cb7a01acSMauro Carvalho Chehab return ret; 366cb7a01acSMauro Carvalho Chehab } 367cb7a01acSMauro Carvalho Chehab 368cb7a01acSMauro Carvalho Chehab static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status) 369cb7a01acSMauro Carvalho Chehab { 370cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 371cb7a01acSMauro Carvalho Chehab int ret = mutex_lock_interruptible(&state->mutex); 372cb7a01acSMauro Carvalho Chehab if (ret) 373cb7a01acSMauro Carvalho Chehab return ret; 374cb7a01acSMauro Carvalho Chehab 3753999e5d0SLars-Peter Clausen ret = __adv7180_status(state, status, NULL); 376cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex); 377cb7a01acSMauro Carvalho Chehab return ret; 378cb7a01acSMauro Carvalho Chehab } 379cb7a01acSMauro Carvalho Chehab 3803e35e33cSLars-Peter Clausen static int adv7180_program_std(struct adv7180_state *state) 3813e35e33cSLars-Peter Clausen { 3823e35e33cSLars-Peter Clausen int ret; 3833e35e33cSLars-Peter Clausen 3843e35e33cSLars-Peter Clausen if (state->autodetect) { 385f5dde49bSLars-Peter Clausen ret = adv7180_set_video_standard(state, 386f5dde49bSLars-Peter Clausen ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM); 3873e35e33cSLars-Peter Clausen if (ret < 0) 3883e35e33cSLars-Peter Clausen return ret; 3893e35e33cSLars-Peter Clausen 3903e35e33cSLars-Peter Clausen __adv7180_status(state, NULL, &state->curr_norm); 3913e35e33cSLars-Peter Clausen } else { 3923e35e33cSLars-Peter Clausen ret = v4l2_std_to_adv7180(state->curr_norm); 3933e35e33cSLars-Peter Clausen if (ret < 0) 3943e35e33cSLars-Peter Clausen return ret; 3953e35e33cSLars-Peter Clausen 396f5dde49bSLars-Peter Clausen ret = adv7180_set_video_standard(state, ret); 3973e35e33cSLars-Peter Clausen if (ret < 0) 3983e35e33cSLars-Peter Clausen return ret; 3993e35e33cSLars-Peter Clausen } 4003e35e33cSLars-Peter Clausen 4013e35e33cSLars-Peter Clausen return 0; 4023e35e33cSLars-Peter Clausen } 4033e35e33cSLars-Peter Clausen 404cb7a01acSMauro Carvalho Chehab static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std) 405cb7a01acSMauro Carvalho Chehab { 406cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 407cb7a01acSMauro Carvalho Chehab int ret = mutex_lock_interruptible(&state->mutex); 4083e35e33cSLars-Peter Clausen 409cb7a01acSMauro Carvalho Chehab if (ret) 410cb7a01acSMauro Carvalho Chehab return ret; 411cb7a01acSMauro Carvalho Chehab 412cb7a01acSMauro Carvalho Chehab /* all standards -> autodetect */ 413cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_ALL) { 414cb7a01acSMauro Carvalho Chehab state->autodetect = true; 415cb7a01acSMauro Carvalho Chehab } else { 4163e35e33cSLars-Peter Clausen /* Make sure we can support this std */ 417cb7a01acSMauro Carvalho Chehab ret = v4l2_std_to_adv7180(std); 418cb7a01acSMauro Carvalho Chehab if (ret < 0) 419cb7a01acSMauro Carvalho Chehab goto out; 420cb7a01acSMauro Carvalho Chehab 421cb7a01acSMauro Carvalho Chehab state->curr_norm = std; 422cb7a01acSMauro Carvalho Chehab state->autodetect = false; 423cb7a01acSMauro Carvalho Chehab } 4243e35e33cSLars-Peter Clausen 4253e35e33cSLars-Peter Clausen ret = adv7180_program_std(state); 426cb7a01acSMauro Carvalho Chehab out: 427cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex); 428cb7a01acSMauro Carvalho Chehab return ret; 429cb7a01acSMauro Carvalho Chehab } 430cb7a01acSMauro Carvalho Chehab 4313999e5d0SLars-Peter Clausen static int adv7180_set_power(struct adv7180_state *state, bool on) 432e246c333SLars-Peter Clausen { 433e246c333SLars-Peter Clausen u8 val; 434b37135e3SLars-Peter Clausen int ret; 435e246c333SLars-Peter Clausen 436e246c333SLars-Peter Clausen if (on) 437e246c333SLars-Peter Clausen val = ADV7180_PWR_MAN_ON; 438e246c333SLars-Peter Clausen else 439e246c333SLars-Peter Clausen val = ADV7180_PWR_MAN_OFF; 440e246c333SLars-Peter Clausen 441b37135e3SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_PWR_MAN, val); 442b37135e3SLars-Peter Clausen if (ret) 443b37135e3SLars-Peter Clausen return ret; 444b37135e3SLars-Peter Clausen 445b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 446b37135e3SLars-Peter Clausen if (on) { 447b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0xDE, 0x02); 448b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0xD2, 0xF7); 449b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0xD8, 0x65); 450b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0xE0, 0x09); 451b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0x2C, 0x00); 452851a54efSLars-Peter Clausen if (state->field == V4L2_FIELD_NONE) 453851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x1D, 0x80); 454b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0x00, 0x00); 455b37135e3SLars-Peter Clausen } else { 456b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0x00, 0x80); 457b37135e3SLars-Peter Clausen } 458b37135e3SLars-Peter Clausen } 459b37135e3SLars-Peter Clausen 460b37135e3SLars-Peter Clausen return 0; 461e246c333SLars-Peter Clausen } 462e246c333SLars-Peter Clausen 463e246c333SLars-Peter Clausen static int adv7180_s_power(struct v4l2_subdev *sd, int on) 464e246c333SLars-Peter Clausen { 465e246c333SLars-Peter Clausen struct adv7180_state *state = to_state(sd); 466e246c333SLars-Peter Clausen int ret; 467e246c333SLars-Peter Clausen 468e246c333SLars-Peter Clausen ret = mutex_lock_interruptible(&state->mutex); 469e246c333SLars-Peter Clausen if (ret) 470e246c333SLars-Peter Clausen return ret; 471e246c333SLars-Peter Clausen 4723999e5d0SLars-Peter Clausen ret = adv7180_set_power(state, on); 473e246c333SLars-Peter Clausen if (ret == 0) 474e246c333SLars-Peter Clausen state->powered = on; 475e246c333SLars-Peter Clausen 476e246c333SLars-Peter Clausen mutex_unlock(&state->mutex); 477e246c333SLars-Peter Clausen return ret; 478e246c333SLars-Peter Clausen } 479e246c333SLars-Peter Clausen 480cb7a01acSMauro Carvalho Chehab static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl) 481cb7a01acSMauro Carvalho Chehab { 482cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = to_adv7180_sd(ctrl); 483cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 484cb7a01acSMauro Carvalho Chehab int ret = mutex_lock_interruptible(&state->mutex); 485cb7a01acSMauro Carvalho Chehab int val; 486cb7a01acSMauro Carvalho Chehab 487cb7a01acSMauro Carvalho Chehab if (ret) 488cb7a01acSMauro Carvalho Chehab return ret; 489cb7a01acSMauro Carvalho Chehab val = ctrl->val; 490cb7a01acSMauro Carvalho Chehab switch (ctrl->id) { 491cb7a01acSMauro Carvalho Chehab case V4L2_CID_BRIGHTNESS: 4923999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_BRI, val); 493cb7a01acSMauro Carvalho Chehab break; 494cb7a01acSMauro Carvalho Chehab case V4L2_CID_HUE: 495cb7a01acSMauro Carvalho Chehab /*Hue is inverted according to HSL chart */ 4963999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_HUE, -val); 497cb7a01acSMauro Carvalho Chehab break; 498cb7a01acSMauro Carvalho Chehab case V4L2_CID_CONTRAST: 4993999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_CON, val); 500cb7a01acSMauro Carvalho Chehab break; 501cb7a01acSMauro Carvalho Chehab case V4L2_CID_SATURATION: 502cb7a01acSMauro Carvalho Chehab /* 503cb7a01acSMauro Carvalho Chehab *This could be V4L2_CID_BLUE_BALANCE/V4L2_CID_RED_BALANCE 504cb7a01acSMauro Carvalho Chehab *Let's not confuse the user, everybody understands saturation 505cb7a01acSMauro Carvalho Chehab */ 5063999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_SD_SAT_CB, val); 507cb7a01acSMauro Carvalho Chehab if (ret < 0) 508cb7a01acSMauro Carvalho Chehab break; 5093999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_SD_SAT_CR, val); 510cb7a01acSMauro Carvalho Chehab break; 511cb7a01acSMauro Carvalho Chehab default: 512cb7a01acSMauro Carvalho Chehab ret = -EINVAL; 513cb7a01acSMauro Carvalho Chehab } 514cb7a01acSMauro Carvalho Chehab 515cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex); 516cb7a01acSMauro Carvalho Chehab return ret; 517cb7a01acSMauro Carvalho Chehab } 518cb7a01acSMauro Carvalho Chehab 519cb7a01acSMauro Carvalho Chehab static const struct v4l2_ctrl_ops adv7180_ctrl_ops = { 520cb7a01acSMauro Carvalho Chehab .s_ctrl = adv7180_s_ctrl, 521cb7a01acSMauro Carvalho Chehab }; 522cb7a01acSMauro Carvalho Chehab 523cb7a01acSMauro Carvalho Chehab static int adv7180_init_controls(struct adv7180_state *state) 524cb7a01acSMauro Carvalho Chehab { 525cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_init(&state->ctrl_hdl, 4); 526cb7a01acSMauro Carvalho Chehab 527cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, 528cb7a01acSMauro Carvalho Chehab V4L2_CID_BRIGHTNESS, ADV7180_BRI_MIN, 529cb7a01acSMauro Carvalho Chehab ADV7180_BRI_MAX, 1, ADV7180_BRI_DEF); 530cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, 531cb7a01acSMauro Carvalho Chehab V4L2_CID_CONTRAST, ADV7180_CON_MIN, 532cb7a01acSMauro Carvalho Chehab ADV7180_CON_MAX, 1, ADV7180_CON_DEF); 533cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, 534cb7a01acSMauro Carvalho Chehab V4L2_CID_SATURATION, ADV7180_SAT_MIN, 535cb7a01acSMauro Carvalho Chehab ADV7180_SAT_MAX, 1, ADV7180_SAT_DEF); 536cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, 537cb7a01acSMauro Carvalho Chehab V4L2_CID_HUE, ADV7180_HUE_MIN, 538cb7a01acSMauro Carvalho Chehab ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF); 539cb7a01acSMauro Carvalho Chehab state->sd.ctrl_handler = &state->ctrl_hdl; 540cb7a01acSMauro Carvalho Chehab if (state->ctrl_hdl.error) { 541cb7a01acSMauro Carvalho Chehab int err = state->ctrl_hdl.error; 542cb7a01acSMauro Carvalho Chehab 543cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_free(&state->ctrl_hdl); 544cb7a01acSMauro Carvalho Chehab return err; 545cb7a01acSMauro Carvalho Chehab } 546cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_setup(&state->ctrl_hdl); 547cb7a01acSMauro Carvalho Chehab 548cb7a01acSMauro Carvalho Chehab return 0; 549cb7a01acSMauro Carvalho Chehab } 550cb7a01acSMauro Carvalho Chehab static void adv7180_exit_controls(struct adv7180_state *state) 551cb7a01acSMauro Carvalho Chehab { 552cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_free(&state->ctrl_hdl); 553cb7a01acSMauro Carvalho Chehab } 554cb7a01acSMauro Carvalho Chehab 555d5d51a82SLars-Peter Clausen static int adv7180_enum_mbus_code(struct v4l2_subdev *sd, 556d5d51a82SLars-Peter Clausen struct v4l2_subdev_fh *fh, 557d5d51a82SLars-Peter Clausen struct v4l2_subdev_mbus_code_enum *code) 558cccb83f7SVladimir Barinov { 559d5d51a82SLars-Peter Clausen if (code->index != 0) 560cccb83f7SVladimir Barinov return -EINVAL; 561cccb83f7SVladimir Barinov 562d5d51a82SLars-Peter Clausen code->code = MEDIA_BUS_FMT_YUYV8_2X8; 563cccb83f7SVladimir Barinov 564cccb83f7SVladimir Barinov return 0; 565cccb83f7SVladimir Barinov } 566cccb83f7SVladimir Barinov 567cccb83f7SVladimir Barinov static int adv7180_mbus_fmt(struct v4l2_subdev *sd, 568cccb83f7SVladimir Barinov struct v4l2_mbus_framefmt *fmt) 569cccb83f7SVladimir Barinov { 570cccb83f7SVladimir Barinov struct adv7180_state *state = to_state(sd); 571cccb83f7SVladimir Barinov 572f5fe58fdSBoris BREZILLON fmt->code = MEDIA_BUS_FMT_YUYV8_2X8; 573cccb83f7SVladimir Barinov fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; 574cccb83f7SVladimir Barinov fmt->width = 720; 575cccb83f7SVladimir Barinov fmt->height = state->curr_norm & V4L2_STD_525_60 ? 480 : 576; 576cccb83f7SVladimir Barinov 577cccb83f7SVladimir Barinov return 0; 578cccb83f7SVladimir Barinov } 579cccb83f7SVladimir Barinov 580851a54efSLars-Peter Clausen static int adv7180_set_field_mode(struct adv7180_state *state) 581851a54efSLars-Peter Clausen { 582851a54efSLars-Peter Clausen if (!(state->chip_info->flags & ADV7180_FLAG_I2P)) 583851a54efSLars-Peter Clausen return 0; 584851a54efSLars-Peter Clausen 585851a54efSLars-Peter Clausen if (state->field == V4L2_FIELD_NONE) { 586851a54efSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 587851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x01, 0x20); 588851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x02, 0x28); 589851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x03, 0x38); 590851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x04, 0x30); 591851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x05, 0x30); 592851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x06, 0x80); 593851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x07, 0x70); 594851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x08, 0x50); 595851a54efSLars-Peter Clausen } 596851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0xa3, 0x00); 597851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0x5b, 0x00); 598851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0x55, 0x80); 599851a54efSLars-Peter Clausen } else { 600851a54efSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 601851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x01, 0x18); 602851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x02, 0x18); 603851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x03, 0x30); 604851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x04, 0x20); 605851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x05, 0x28); 606851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x06, 0x40); 607851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x07, 0x58); 608851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x08, 0x30); 609851a54efSLars-Peter Clausen } 610851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0xa3, 0x70); 611851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0x5b, 0x80); 612851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0x55, 0x00); 613851a54efSLars-Peter Clausen } 614851a54efSLars-Peter Clausen 615851a54efSLars-Peter Clausen return 0; 616851a54efSLars-Peter Clausen } 617851a54efSLars-Peter Clausen 618d5d51a82SLars-Peter Clausen static int adv7180_get_pad_format(struct v4l2_subdev *sd, 619d5d51a82SLars-Peter Clausen struct v4l2_subdev_fh *fh, 620d5d51a82SLars-Peter Clausen struct v4l2_subdev_format *format) 621d5d51a82SLars-Peter Clausen { 622851a54efSLars-Peter Clausen struct adv7180_state *state = to_state(sd); 623851a54efSLars-Peter Clausen 624851a54efSLars-Peter Clausen if (format->which == V4L2_SUBDEV_FORMAT_TRY) { 625851a54efSLars-Peter Clausen format->format = *v4l2_subdev_get_try_format(fh, 0); 626851a54efSLars-Peter Clausen } else { 627851a54efSLars-Peter Clausen adv7180_mbus_fmt(sd, &format->format); 628851a54efSLars-Peter Clausen format->format.field = state->field; 629851a54efSLars-Peter Clausen } 630851a54efSLars-Peter Clausen 631851a54efSLars-Peter Clausen return 0; 632d5d51a82SLars-Peter Clausen } 633d5d51a82SLars-Peter Clausen 634d5d51a82SLars-Peter Clausen static int adv7180_set_pad_format(struct v4l2_subdev *sd, 635d5d51a82SLars-Peter Clausen struct v4l2_subdev_fh *fh, 636d5d51a82SLars-Peter Clausen struct v4l2_subdev_format *format) 637d5d51a82SLars-Peter Clausen { 638851a54efSLars-Peter Clausen struct adv7180_state *state = to_state(sd); 639851a54efSLars-Peter Clausen struct v4l2_mbus_framefmt *framefmt; 640851a54efSLars-Peter Clausen 641851a54efSLars-Peter Clausen switch (format->format.field) { 642851a54efSLars-Peter Clausen case V4L2_FIELD_NONE: 643851a54efSLars-Peter Clausen if (!(state->chip_info->flags & ADV7180_FLAG_I2P)) 644851a54efSLars-Peter Clausen format->format.field = V4L2_FIELD_INTERLACED; 645851a54efSLars-Peter Clausen break; 646851a54efSLars-Peter Clausen default: 647851a54efSLars-Peter Clausen format->format.field = V4L2_FIELD_INTERLACED; 648851a54efSLars-Peter Clausen break; 649851a54efSLars-Peter Clausen } 650851a54efSLars-Peter Clausen 651851a54efSLars-Peter Clausen if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { 652851a54efSLars-Peter Clausen framefmt = &format->format; 653851a54efSLars-Peter Clausen if (state->field != format->format.field) { 654851a54efSLars-Peter Clausen state->field = format->format.field; 655851a54efSLars-Peter Clausen adv7180_set_power(state, false); 656851a54efSLars-Peter Clausen adv7180_set_field_mode(state); 657851a54efSLars-Peter Clausen adv7180_set_power(state, true); 658851a54efSLars-Peter Clausen } 659851a54efSLars-Peter Clausen } else { 660851a54efSLars-Peter Clausen framefmt = v4l2_subdev_get_try_format(fh, 0); 661851a54efSLars-Peter Clausen *framefmt = format->format; 662851a54efSLars-Peter Clausen } 663851a54efSLars-Peter Clausen 664851a54efSLars-Peter Clausen return adv7180_mbus_fmt(sd, framefmt); 665d5d51a82SLars-Peter Clausen } 666d5d51a82SLars-Peter Clausen 667cccb83f7SVladimir Barinov static int adv7180_g_mbus_config(struct v4l2_subdev *sd, 668cccb83f7SVladimir Barinov struct v4l2_mbus_config *cfg) 669cccb83f7SVladimir Barinov { 670b37135e3SLars-Peter Clausen struct adv7180_state *state = to_state(sd); 671b37135e3SLars-Peter Clausen 672b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 673b37135e3SLars-Peter Clausen cfg->type = V4L2_MBUS_CSI2; 674b37135e3SLars-Peter Clausen cfg->flags = V4L2_MBUS_CSI2_1_LANE | 675b37135e3SLars-Peter Clausen V4L2_MBUS_CSI2_CHANNEL_0 | 676b37135e3SLars-Peter Clausen V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; 677b37135e3SLars-Peter Clausen } else { 678cccb83f7SVladimir Barinov /* 679cccb83f7SVladimir Barinov * The ADV7180 sensor supports BT.601/656 output modes. 680cccb83f7SVladimir Barinov * The BT.656 is default and not yet configurable by s/w. 681cccb83f7SVladimir Barinov */ 682cccb83f7SVladimir Barinov cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | 683cccb83f7SVladimir Barinov V4L2_MBUS_DATA_ACTIVE_HIGH; 684cccb83f7SVladimir Barinov cfg->type = V4L2_MBUS_BT656; 685b37135e3SLars-Peter Clausen } 686cccb83f7SVladimir Barinov 687cccb83f7SVladimir Barinov return 0; 688cccb83f7SVladimir Barinov } 689cccb83f7SVladimir Barinov 690cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops adv7180_video_ops = { 6918774bed9SLaurent Pinchart .s_std = adv7180_s_std, 692cb7a01acSMauro Carvalho Chehab .querystd = adv7180_querystd, 693cb7a01acSMauro Carvalho Chehab .g_input_status = adv7180_g_input_status, 694cb7a01acSMauro Carvalho Chehab .s_routing = adv7180_s_routing, 695cccb83f7SVladimir Barinov .g_mbus_config = adv7180_g_mbus_config, 696cb7a01acSMauro Carvalho Chehab }; 697cb7a01acSMauro Carvalho Chehab 698f5dde49bSLars-Peter Clausen 699cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_core_ops adv7180_core_ops = { 700e246c333SLars-Peter Clausen .s_power = adv7180_s_power, 701cb7a01acSMauro Carvalho Chehab }; 702cb7a01acSMauro Carvalho Chehab 703d5d51a82SLars-Peter Clausen static const struct v4l2_subdev_pad_ops adv7180_pad_ops = { 704d5d51a82SLars-Peter Clausen .enum_mbus_code = adv7180_enum_mbus_code, 705d5d51a82SLars-Peter Clausen .set_fmt = adv7180_set_pad_format, 706d5d51a82SLars-Peter Clausen .get_fmt = adv7180_get_pad_format, 707d5d51a82SLars-Peter Clausen }; 708d5d51a82SLars-Peter Clausen 709cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops adv7180_ops = { 710cb7a01acSMauro Carvalho Chehab .core = &adv7180_core_ops, 711cb7a01acSMauro Carvalho Chehab .video = &adv7180_video_ops, 712d5d51a82SLars-Peter Clausen .pad = &adv7180_pad_ops, 713cb7a01acSMauro Carvalho Chehab }; 714cb7a01acSMauro Carvalho Chehab 7150c25534dSLars-Peter Clausen static irqreturn_t adv7180_irq(int irq, void *devid) 716cb7a01acSMauro Carvalho Chehab { 7170c25534dSLars-Peter Clausen struct adv7180_state *state = devid; 718cb7a01acSMauro Carvalho Chehab u8 isr3; 719cb7a01acSMauro Carvalho Chehab 720cb7a01acSMauro Carvalho Chehab mutex_lock(&state->mutex); 7213999e5d0SLars-Peter Clausen isr3 = adv7180_read(state, ADV7180_REG_ISR3); 722cb7a01acSMauro Carvalho Chehab /* clear */ 7233999e5d0SLars-Peter Clausen adv7180_write(state, ADV7180_REG_ICR3, isr3); 724cb7a01acSMauro Carvalho Chehab 725cb7a01acSMauro Carvalho Chehab if (isr3 & ADV7180_IRQ3_AD_CHANGE && state->autodetect) 7263999e5d0SLars-Peter Clausen __adv7180_status(state, NULL, &state->curr_norm); 727cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex); 728cb7a01acSMauro Carvalho Chehab 729cb7a01acSMauro Carvalho Chehab return IRQ_HANDLED; 730cb7a01acSMauro Carvalho Chehab } 731cb7a01acSMauro Carvalho Chehab 732f5dde49bSLars-Peter Clausen static int adv7180_init(struct adv7180_state *state) 733f5dde49bSLars-Peter Clausen { 734f5dde49bSLars-Peter Clausen int ret; 735f5dde49bSLars-Peter Clausen 736f5dde49bSLars-Peter Clausen /* ITU-R BT.656-4 compatible */ 737f5dde49bSLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 738f5dde49bSLars-Peter Clausen ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS); 739f5dde49bSLars-Peter Clausen if (ret < 0) 740f5dde49bSLars-Peter Clausen return ret; 741f5dde49bSLars-Peter Clausen 742f5dde49bSLars-Peter Clausen /* Manually set V bit end position in NTSC mode */ 743f5dde49bSLars-Peter Clausen return adv7180_write(state, ADV7180_REG_NTSC_V_BIT_END, 744f5dde49bSLars-Peter Clausen ADV7180_NTSC_V_BIT_END_MANUAL_NVEND); 745f5dde49bSLars-Peter Clausen } 746f5dde49bSLars-Peter Clausen 747f5dde49bSLars-Peter Clausen static int adv7180_set_std(struct adv7180_state *state, unsigned int std) 748f5dde49bSLars-Peter Clausen { 749f5dde49bSLars-Peter Clausen return adv7180_write(state, ADV7180_REG_INPUT_CONTROL, 750f5dde49bSLars-Peter Clausen (std << 4) | state->input); 751f5dde49bSLars-Peter Clausen } 752f5dde49bSLars-Peter Clausen 753f5dde49bSLars-Peter Clausen static int adv7180_select_input(struct adv7180_state *state, unsigned int input) 754f5dde49bSLars-Peter Clausen { 755f5dde49bSLars-Peter Clausen int ret; 756f5dde49bSLars-Peter Clausen 757f5dde49bSLars-Peter Clausen ret = adv7180_read(state, ADV7180_REG_INPUT_CONTROL); 758f5dde49bSLars-Peter Clausen if (ret < 0) 759f5dde49bSLars-Peter Clausen return ret; 760f5dde49bSLars-Peter Clausen 761f5dde49bSLars-Peter Clausen ret &= ~ADV7180_INPUT_CONTROL_INSEL_MASK; 762f5dde49bSLars-Peter Clausen ret |= input; 763f5dde49bSLars-Peter Clausen return adv7180_write(state, ADV7180_REG_INPUT_CONTROL, ret); 764f5dde49bSLars-Peter Clausen } 765f5dde49bSLars-Peter Clausen 766c5ef8f8cSLars-Peter Clausen static int adv7182_init(struct adv7180_state *state) 767c5ef8f8cSLars-Peter Clausen { 768b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) 769b37135e3SLars-Peter Clausen adv7180_write(state, ADV7180_REG_CSI_SLAVE_ADDR, 770b37135e3SLars-Peter Clausen ADV7180_DEFAULT_CSI_I2C_ADDR << 1); 771b37135e3SLars-Peter Clausen 772851a54efSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_I2P) 773851a54efSLars-Peter Clausen adv7180_write(state, ADV7180_REG_VPP_SLAVE_ADDR, 774851a54efSLars-Peter Clausen ADV7180_DEFAULT_VPP_I2C_ADDR << 1); 775851a54efSLars-Peter Clausen 776bf7dcb80SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_V2) { 777bf7dcb80SLars-Peter Clausen /* ADI recommended writes for improved video quality */ 778bf7dcb80SLars-Peter Clausen adv7180_write(state, 0x0080, 0x51); 779bf7dcb80SLars-Peter Clausen adv7180_write(state, 0x0081, 0x51); 780bf7dcb80SLars-Peter Clausen adv7180_write(state, 0x0082, 0x68); 781bf7dcb80SLars-Peter Clausen } 782bf7dcb80SLars-Peter Clausen 783c5ef8f8cSLars-Peter Clausen /* ADI required writes */ 784b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 785b37135e3SLars-Peter Clausen adv7180_write(state, 0x0003, 0x4e); 786b37135e3SLars-Peter Clausen adv7180_write(state, 0x0004, 0x57); 787b37135e3SLars-Peter Clausen adv7180_write(state, 0x001d, 0xc0); 788b37135e3SLars-Peter Clausen } else { 789b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_V2) 790b37135e3SLars-Peter Clausen adv7180_write(state, 0x0004, 0x17); 791b37135e3SLars-Peter Clausen else 792b37135e3SLars-Peter Clausen adv7180_write(state, 0x0004, 0x07); 793c5ef8f8cSLars-Peter Clausen adv7180_write(state, 0x0003, 0x0c); 794c5ef8f8cSLars-Peter Clausen adv7180_write(state, 0x001d, 0x40); 795b37135e3SLars-Peter Clausen } 796b37135e3SLars-Peter Clausen 797b37135e3SLars-Peter Clausen adv7180_write(state, 0x0013, 0x00); 798c5ef8f8cSLars-Peter Clausen 799c5ef8f8cSLars-Peter Clausen return 0; 800c5ef8f8cSLars-Peter Clausen } 801c5ef8f8cSLars-Peter Clausen 802c5ef8f8cSLars-Peter Clausen static int adv7182_set_std(struct adv7180_state *state, unsigned int std) 803c5ef8f8cSLars-Peter Clausen { 804c5ef8f8cSLars-Peter Clausen return adv7180_write(state, ADV7182_REG_INPUT_VIDSEL, std << 4); 805c5ef8f8cSLars-Peter Clausen } 806c5ef8f8cSLars-Peter Clausen 807c5ef8f8cSLars-Peter Clausen enum adv7182_input_type { 808c5ef8f8cSLars-Peter Clausen ADV7182_INPUT_TYPE_CVBS, 809c5ef8f8cSLars-Peter Clausen ADV7182_INPUT_TYPE_DIFF_CVBS, 810c5ef8f8cSLars-Peter Clausen ADV7182_INPUT_TYPE_SVIDEO, 811c5ef8f8cSLars-Peter Clausen ADV7182_INPUT_TYPE_YPBPR, 812c5ef8f8cSLars-Peter Clausen }; 813c5ef8f8cSLars-Peter Clausen 814c5ef8f8cSLars-Peter Clausen static enum adv7182_input_type adv7182_get_input_type(unsigned int input) 815c5ef8f8cSLars-Peter Clausen { 816c5ef8f8cSLars-Peter Clausen switch (input) { 817c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN1: 818c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN2: 819c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN3: 820c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN4: 821c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN5: 822c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN6: 823c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN7: 824c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN8: 825c5ef8f8cSLars-Peter Clausen return ADV7182_INPUT_TYPE_CVBS; 826c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_SVIDEO_AIN1_AIN2: 827c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_SVIDEO_AIN3_AIN4: 828c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_SVIDEO_AIN5_AIN6: 829c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_SVIDEO_AIN7_AIN8: 830c5ef8f8cSLars-Peter Clausen return ADV7182_INPUT_TYPE_SVIDEO; 831c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3: 832c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6: 833c5ef8f8cSLars-Peter Clausen return ADV7182_INPUT_TYPE_YPBPR; 834c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2: 835c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4: 836c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6: 837c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8: 838c5ef8f8cSLars-Peter Clausen return ADV7182_INPUT_TYPE_DIFF_CVBS; 839c5ef8f8cSLars-Peter Clausen default: /* Will never happen */ 840c5ef8f8cSLars-Peter Clausen return 0; 841c5ef8f8cSLars-Peter Clausen } 842c5ef8f8cSLars-Peter Clausen } 843c5ef8f8cSLars-Peter Clausen 844c5ef8f8cSLars-Peter Clausen /* ADI recommended writes to registers 0x52, 0x53, 0x54 */ 845c5ef8f8cSLars-Peter Clausen static unsigned int adv7182_lbias_settings[][3] = { 846c5ef8f8cSLars-Peter Clausen [ADV7182_INPUT_TYPE_CVBS] = { 0xCB, 0x4E, 0x80 }, 847c5ef8f8cSLars-Peter Clausen [ADV7182_INPUT_TYPE_DIFF_CVBS] = { 0xC0, 0x4E, 0x80 }, 848c5ef8f8cSLars-Peter Clausen [ADV7182_INPUT_TYPE_SVIDEO] = { 0x0B, 0xCE, 0x80 }, 849c5ef8f8cSLars-Peter Clausen [ADV7182_INPUT_TYPE_YPBPR] = { 0x0B, 0x4E, 0xC0 }, 850c5ef8f8cSLars-Peter Clausen }; 851c5ef8f8cSLars-Peter Clausen 852bf7dcb80SLars-Peter Clausen static unsigned int adv7280_lbias_settings[][3] = { 853bf7dcb80SLars-Peter Clausen [ADV7182_INPUT_TYPE_CVBS] = { 0xCD, 0x4E, 0x80 }, 854bf7dcb80SLars-Peter Clausen [ADV7182_INPUT_TYPE_DIFF_CVBS] = { 0xC0, 0x4E, 0x80 }, 855bf7dcb80SLars-Peter Clausen [ADV7182_INPUT_TYPE_SVIDEO] = { 0x0B, 0xCE, 0x80 }, 856bf7dcb80SLars-Peter Clausen [ADV7182_INPUT_TYPE_YPBPR] = { 0x0B, 0x4E, 0xC0 }, 857bf7dcb80SLars-Peter Clausen }; 858bf7dcb80SLars-Peter Clausen 859c5ef8f8cSLars-Peter Clausen static int adv7182_select_input(struct adv7180_state *state, unsigned int input) 860c5ef8f8cSLars-Peter Clausen { 861c5ef8f8cSLars-Peter Clausen enum adv7182_input_type input_type; 862c5ef8f8cSLars-Peter Clausen unsigned int *lbias; 863c5ef8f8cSLars-Peter Clausen unsigned int i; 864c5ef8f8cSLars-Peter Clausen int ret; 865c5ef8f8cSLars-Peter Clausen 866c5ef8f8cSLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL, input); 867c5ef8f8cSLars-Peter Clausen if (ret) 868c5ef8f8cSLars-Peter Clausen return ret; 869c5ef8f8cSLars-Peter Clausen 870c5ef8f8cSLars-Peter Clausen /* Reset clamp circuitry - ADI recommended writes */ 871c5ef8f8cSLars-Peter Clausen adv7180_write(state, 0x809c, 0x00); 872c5ef8f8cSLars-Peter Clausen adv7180_write(state, 0x809c, 0xff); 873c5ef8f8cSLars-Peter Clausen 874c5ef8f8cSLars-Peter Clausen input_type = adv7182_get_input_type(input); 875c5ef8f8cSLars-Peter Clausen 876c5ef8f8cSLars-Peter Clausen switch (input_type) { 877c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_TYPE_CVBS: 878c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_TYPE_DIFF_CVBS: 879c5ef8f8cSLars-Peter Clausen /* ADI recommends to use the SH1 filter */ 880c5ef8f8cSLars-Peter Clausen adv7180_write(state, 0x0017, 0x41); 881c5ef8f8cSLars-Peter Clausen break; 882c5ef8f8cSLars-Peter Clausen default: 883c5ef8f8cSLars-Peter Clausen adv7180_write(state, 0x0017, 0x01); 884c5ef8f8cSLars-Peter Clausen break; 885c5ef8f8cSLars-Peter Clausen } 886c5ef8f8cSLars-Peter Clausen 887bf7dcb80SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_V2) 888bf7dcb80SLars-Peter Clausen lbias = adv7280_lbias_settings[input_type]; 889bf7dcb80SLars-Peter Clausen else 890c5ef8f8cSLars-Peter Clausen lbias = adv7182_lbias_settings[input_type]; 891c5ef8f8cSLars-Peter Clausen 892c5ef8f8cSLars-Peter Clausen for (i = 0; i < ARRAY_SIZE(adv7182_lbias_settings[0]); i++) 893c5ef8f8cSLars-Peter Clausen adv7180_write(state, 0x0052 + i, lbias[i]); 894c5ef8f8cSLars-Peter Clausen 895c5ef8f8cSLars-Peter Clausen if (input_type == ADV7182_INPUT_TYPE_DIFF_CVBS) { 896c5ef8f8cSLars-Peter Clausen /* ADI required writes to make differential CVBS work */ 897c5ef8f8cSLars-Peter Clausen adv7180_write(state, 0x005f, 0xa8); 898c5ef8f8cSLars-Peter Clausen adv7180_write(state, 0x005a, 0x90); 899c5ef8f8cSLars-Peter Clausen adv7180_write(state, 0x0060, 0xb0); 900c5ef8f8cSLars-Peter Clausen adv7180_write(state, 0x80b6, 0x08); 901c5ef8f8cSLars-Peter Clausen adv7180_write(state, 0x80c0, 0xa0); 902c5ef8f8cSLars-Peter Clausen } else { 903c5ef8f8cSLars-Peter Clausen adv7180_write(state, 0x005f, 0xf0); 904c5ef8f8cSLars-Peter Clausen adv7180_write(state, 0x005a, 0xd0); 905c5ef8f8cSLars-Peter Clausen adv7180_write(state, 0x0060, 0x10); 906c5ef8f8cSLars-Peter Clausen adv7180_write(state, 0x80b6, 0x9c); 907c5ef8f8cSLars-Peter Clausen adv7180_write(state, 0x80c0, 0x00); 908c5ef8f8cSLars-Peter Clausen } 909c5ef8f8cSLars-Peter Clausen 910c5ef8f8cSLars-Peter Clausen return 0; 911c5ef8f8cSLars-Peter Clausen } 912c5ef8f8cSLars-Peter Clausen 913f5dde49bSLars-Peter Clausen static const struct adv7180_chip_info adv7180_info = { 914f5dde49bSLars-Peter Clausen .flags = ADV7180_FLAG_RESET_POWERED, 915f5dde49bSLars-Peter Clausen /* We cannot discriminate between LQFP and 40-pin LFCSP, so accept 916f5dde49bSLars-Peter Clausen * all inputs and let the card driver take care of validation 917f5dde49bSLars-Peter Clausen */ 918f5dde49bSLars-Peter Clausen .valid_input_mask = BIT(ADV7180_INPUT_CVBS_AIN1) | 919f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_CVBS_AIN2) | 920f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_CVBS_AIN3) | 921f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_CVBS_AIN4) | 922f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_CVBS_AIN5) | 923f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_CVBS_AIN6) | 924f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_SVIDEO_AIN1_AIN2) | 925f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_SVIDEO_AIN3_AIN4) | 926f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_SVIDEO_AIN5_AIN6) | 927f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_YPRPB_AIN1_AIN2_AIN3) | 928f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_YPRPB_AIN4_AIN5_AIN6), 929f5dde49bSLars-Peter Clausen .init = adv7180_init, 930f5dde49bSLars-Peter Clausen .set_std = adv7180_set_std, 931f5dde49bSLars-Peter Clausen .select_input = adv7180_select_input, 932f5dde49bSLars-Peter Clausen }; 933f5dde49bSLars-Peter Clausen 934c5ef8f8cSLars-Peter Clausen static const struct adv7180_chip_info adv7182_info = { 935c5ef8f8cSLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 936c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 937c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) | 938c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) | 939c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 940c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 941c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | 942c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 943c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4), 944c5ef8f8cSLars-Peter Clausen .init = adv7182_init, 945c5ef8f8cSLars-Peter Clausen .set_std = adv7182_set_std, 946c5ef8f8cSLars-Peter Clausen .select_input = adv7182_select_input, 947c5ef8f8cSLars-Peter Clausen }; 948c5ef8f8cSLars-Peter Clausen 949bf7dcb80SLars-Peter Clausen static const struct adv7180_chip_info adv7280_info = { 950851a54efSLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P, 951bf7dcb80SLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 952bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 953bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) | 954bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) | 955bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 956bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 957bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3), 958bf7dcb80SLars-Peter Clausen .init = adv7182_init, 959bf7dcb80SLars-Peter Clausen .set_std = adv7182_set_std, 960bf7dcb80SLars-Peter Clausen .select_input = adv7182_select_input, 961bf7dcb80SLars-Peter Clausen }; 962bf7dcb80SLars-Peter Clausen 963b37135e3SLars-Peter Clausen static const struct adv7180_chip_info adv7280_m_info = { 964851a54efSLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P, 965b37135e3SLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 966b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 967b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) | 968b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) | 969b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN5) | 970b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN6) | 971b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) | 972b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) | 973b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 974b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 975b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN5_AIN6) | 976b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 977b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | 978b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6), 979b37135e3SLars-Peter Clausen .init = adv7182_init, 980b37135e3SLars-Peter Clausen .set_std = adv7182_set_std, 981b37135e3SLars-Peter Clausen .select_input = adv7182_select_input, 982b37135e3SLars-Peter Clausen }; 983b37135e3SLars-Peter Clausen 984bf7dcb80SLars-Peter Clausen static const struct adv7180_chip_info adv7281_info = { 985b37135e3SLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2, 986bf7dcb80SLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 987bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 988bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) | 989bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) | 990bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 991bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 992bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 993bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), 994bf7dcb80SLars-Peter Clausen .init = adv7182_init, 995bf7dcb80SLars-Peter Clausen .set_std = adv7182_set_std, 996bf7dcb80SLars-Peter Clausen .select_input = adv7182_select_input, 997bf7dcb80SLars-Peter Clausen }; 998bf7dcb80SLars-Peter Clausen 999b37135e3SLars-Peter Clausen static const struct adv7180_chip_info adv7281_m_info = { 1000b37135e3SLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2, 1001b37135e3SLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1002b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1003b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) | 1004b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) | 1005b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) | 1006b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) | 1007b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1008b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 1009b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 1010b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | 1011b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 1012b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) | 1013b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), 1014b37135e3SLars-Peter Clausen .init = adv7182_init, 1015b37135e3SLars-Peter Clausen .set_std = adv7182_set_std, 1016b37135e3SLars-Peter Clausen .select_input = adv7182_select_input, 1017b37135e3SLars-Peter Clausen }; 1018b37135e3SLars-Peter Clausen 1019b37135e3SLars-Peter Clausen static const struct adv7180_chip_info adv7281_ma_info = { 1020b37135e3SLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2, 1021b37135e3SLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1022b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1023b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) | 1024b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) | 1025b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN5) | 1026b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN6) | 1027b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) | 1028b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) | 1029b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1030b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 1031b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN5_AIN6) | 1032b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 1033b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | 1034b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6) | 1035b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 1036b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) | 1037b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6) | 1038b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), 1039b37135e3SLars-Peter Clausen .init = adv7182_init, 1040b37135e3SLars-Peter Clausen .set_std = adv7182_set_std, 1041b37135e3SLars-Peter Clausen .select_input = adv7182_select_input, 1042b37135e3SLars-Peter Clausen }; 1043b37135e3SLars-Peter Clausen 1044851a54efSLars-Peter Clausen static const struct adv7180_chip_info adv7282_info = { 1045851a54efSLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P, 1046851a54efSLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1047851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1048851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) | 1049851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) | 1050851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1051851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 1052851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 1053851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), 1054851a54efSLars-Peter Clausen .init = adv7182_init, 1055851a54efSLars-Peter Clausen .set_std = adv7182_set_std, 1056851a54efSLars-Peter Clausen .select_input = adv7182_select_input, 1057851a54efSLars-Peter Clausen }; 1058851a54efSLars-Peter Clausen 1059851a54efSLars-Peter Clausen static const struct adv7180_chip_info adv7282_m_info = { 1060851a54efSLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P, 1061851a54efSLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1062851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1063851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) | 1064851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) | 1065851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) | 1066851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) | 1067851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1068851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 1069851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 1070851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 1071851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) | 1072851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), 1073851a54efSLars-Peter Clausen .init = adv7182_init, 1074851a54efSLars-Peter Clausen .set_std = adv7182_set_std, 1075851a54efSLars-Peter Clausen .select_input = adv7182_select_input, 1076851a54efSLars-Peter Clausen }; 1077851a54efSLars-Peter Clausen 10783999e5d0SLars-Peter Clausen static int init_device(struct adv7180_state *state) 1079cb7a01acSMauro Carvalho Chehab { 1080cb7a01acSMauro Carvalho Chehab int ret; 1081cb7a01acSMauro Carvalho Chehab 10823999e5d0SLars-Peter Clausen mutex_lock(&state->mutex); 10833999e5d0SLars-Peter Clausen 1084c18818e9SLars-Peter Clausen adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES); 1085c18818e9SLars-Peter Clausen usleep_range(2000, 10000); 1086c18818e9SLars-Peter Clausen 1087f5dde49bSLars-Peter Clausen ret = state->chip_info->init(state); 10883e35e33cSLars-Peter Clausen if (ret) 10893999e5d0SLars-Peter Clausen goto out_unlock; 1090cb7a01acSMauro Carvalho Chehab 1091f5dde49bSLars-Peter Clausen ret = adv7180_program_std(state); 1092f5dde49bSLars-Peter Clausen if (ret) 10933999e5d0SLars-Peter Clausen goto out_unlock; 1094cb7a01acSMauro Carvalho Chehab 1095851a54efSLars-Peter Clausen adv7180_set_field_mode(state); 1096851a54efSLars-Peter Clausen 1097cb7a01acSMauro Carvalho Chehab /* register for interrupts */ 1098cb7a01acSMauro Carvalho Chehab if (state->irq > 0) { 1099cb7a01acSMauro Carvalho Chehab /* config the Interrupt pin to be active low */ 11003999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_ICONF1, 1101cb7a01acSMauro Carvalho Chehab ADV7180_ICONF1_ACTIVE_LOW | 1102cb7a01acSMauro Carvalho Chehab ADV7180_ICONF1_PSYNC_ONLY); 1103cb7a01acSMauro Carvalho Chehab if (ret < 0) 11043999e5d0SLars-Peter Clausen goto out_unlock; 1105cb7a01acSMauro Carvalho Chehab 11063999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_IMR1, 0); 1107cb7a01acSMauro Carvalho Chehab if (ret < 0) 11083999e5d0SLars-Peter Clausen goto out_unlock; 1109cb7a01acSMauro Carvalho Chehab 11103999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_IMR2, 0); 1111cb7a01acSMauro Carvalho Chehab if (ret < 0) 11123999e5d0SLars-Peter Clausen goto out_unlock; 1113cb7a01acSMauro Carvalho Chehab 1114cb7a01acSMauro Carvalho Chehab /* enable AD change interrupts interrupts */ 11153999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_IMR3, 1116cb7a01acSMauro Carvalho Chehab ADV7180_IRQ3_AD_CHANGE); 1117cb7a01acSMauro Carvalho Chehab if (ret < 0) 11183999e5d0SLars-Peter Clausen goto out_unlock; 1119cb7a01acSMauro Carvalho Chehab 11203999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_IMR4, 0); 1121cb7a01acSMauro Carvalho Chehab if (ret < 0) 11223999e5d0SLars-Peter Clausen goto out_unlock; 1123cb7a01acSMauro Carvalho Chehab } 1124cb7a01acSMauro Carvalho Chehab 11253999e5d0SLars-Peter Clausen out_unlock: 11263999e5d0SLars-Peter Clausen mutex_unlock(&state->mutex); 1127df065b37SAlexey Khoroshilov 1128df065b37SAlexey Khoroshilov return ret; 1129cb7a01acSMauro Carvalho Chehab } 1130cb7a01acSMauro Carvalho Chehab 11314c62e976SGreg Kroah-Hartman static int adv7180_probe(struct i2c_client *client, 1132cb7a01acSMauro Carvalho Chehab const struct i2c_device_id *id) 1133cb7a01acSMauro Carvalho Chehab { 1134cb7a01acSMauro Carvalho Chehab struct adv7180_state *state; 1135cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd; 1136cb7a01acSMauro Carvalho Chehab int ret; 1137cb7a01acSMauro Carvalho Chehab 1138cb7a01acSMauro Carvalho Chehab /* Check if the adapter supports the needed features */ 1139cb7a01acSMauro Carvalho Chehab if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 1140cb7a01acSMauro Carvalho Chehab return -EIO; 1141cb7a01acSMauro Carvalho Chehab 1142cb7a01acSMauro Carvalho Chehab v4l_info(client, "chip found @ 0x%02x (%s)\n", 1143cb7a01acSMauro Carvalho Chehab client->addr, client->adapter->name); 1144cb7a01acSMauro Carvalho Chehab 1145c02b211dSLaurent Pinchart state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL); 11467657e064SFabio Estevam if (state == NULL) 11477657e064SFabio Estevam return -ENOMEM; 1148cb7a01acSMauro Carvalho Chehab 11493999e5d0SLars-Peter Clausen state->client = client; 1150851a54efSLars-Peter Clausen state->field = V4L2_FIELD_INTERLACED; 1151f5dde49bSLars-Peter Clausen state->chip_info = (struct adv7180_chip_info *)id->driver_data; 11523999e5d0SLars-Peter Clausen 1153b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 1154b37135e3SLars-Peter Clausen state->csi_client = i2c_new_dummy(client->adapter, 1155b37135e3SLars-Peter Clausen ADV7180_DEFAULT_CSI_I2C_ADDR); 1156b37135e3SLars-Peter Clausen if (!state->csi_client) 1157b37135e3SLars-Peter Clausen return -ENOMEM; 1158b37135e3SLars-Peter Clausen } 1159b37135e3SLars-Peter Clausen 1160851a54efSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_I2P) { 1161851a54efSLars-Peter Clausen state->vpp_client = i2c_new_dummy(client->adapter, 1162851a54efSLars-Peter Clausen ADV7180_DEFAULT_VPP_I2C_ADDR); 1163851a54efSLars-Peter Clausen if (!state->vpp_client) { 1164851a54efSLars-Peter Clausen ret = -ENOMEM; 1165851a54efSLars-Peter Clausen goto err_unregister_csi_client; 1166851a54efSLars-Peter Clausen } 1167851a54efSLars-Peter Clausen } 1168851a54efSLars-Peter Clausen 1169cb7a01acSMauro Carvalho Chehab state->irq = client->irq; 1170cb7a01acSMauro Carvalho Chehab mutex_init(&state->mutex); 1171cb7a01acSMauro Carvalho Chehab state->autodetect = true; 1172f5dde49bSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_RESET_POWERED) 1173e246c333SLars-Peter Clausen state->powered = true; 1174f5dde49bSLars-Peter Clausen else 1175f5dde49bSLars-Peter Clausen state->powered = false; 1176cb7a01acSMauro Carvalho Chehab state->input = 0; 1177cb7a01acSMauro Carvalho Chehab sd = &state->sd; 1178cb7a01acSMauro Carvalho Chehab v4l2_i2c_subdev_init(sd, client, &adv7180_ops); 1179d5d51a82SLars-Peter Clausen sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; 1180cb7a01acSMauro Carvalho Chehab 1181cb7a01acSMauro Carvalho Chehab ret = adv7180_init_controls(state); 1182cb7a01acSMauro Carvalho Chehab if (ret) 1183851a54efSLars-Peter Clausen goto err_unregister_vpp_client; 1184d5d51a82SLars-Peter Clausen 1185d5d51a82SLars-Peter Clausen state->pad.flags = MEDIA_PAD_FL_SOURCE; 1186d5d51a82SLars-Peter Clausen sd->entity.flags |= MEDIA_ENT_T_V4L2_SUBDEV_DECODER; 1187d5d51a82SLars-Peter Clausen ret = media_entity_init(&sd->entity, 1, &state->pad, 0); 1188cb7a01acSMauro Carvalho Chehab if (ret) 1189cb7a01acSMauro Carvalho Chehab goto err_free_ctrl; 1190fa5b7945SLars-Peter Clausen 1191d5d51a82SLars-Peter Clausen ret = init_device(state); 1192d5d51a82SLars-Peter Clausen if (ret) 1193d5d51a82SLars-Peter Clausen goto err_media_entity_cleanup; 1194d5d51a82SLars-Peter Clausen 1195fa5721d1SLars-Peter Clausen if (state->irq) { 1196fa5721d1SLars-Peter Clausen ret = request_threaded_irq(client->irq, NULL, adv7180_irq, 1197f3e991d4SLars-Peter Clausen IRQF_ONESHOT | IRQF_TRIGGER_FALLING, 1198f3e991d4SLars-Peter Clausen KBUILD_MODNAME, state); 1199fa5721d1SLars-Peter Clausen if (ret) 1200d5d51a82SLars-Peter Clausen goto err_media_entity_cleanup; 1201fa5721d1SLars-Peter Clausen } 1202fa5721d1SLars-Peter Clausen 1203fa5b7945SLars-Peter Clausen ret = v4l2_async_register_subdev(sd); 1204fa5b7945SLars-Peter Clausen if (ret) 1205fa5b7945SLars-Peter Clausen goto err_free_irq; 1206fa5b7945SLars-Peter Clausen 1207cb7a01acSMauro Carvalho Chehab return 0; 1208cb7a01acSMauro Carvalho Chehab 1209fa5b7945SLars-Peter Clausen err_free_irq: 1210fa5b7945SLars-Peter Clausen if (state->irq > 0) 1211fa5b7945SLars-Peter Clausen free_irq(client->irq, state); 1212d5d51a82SLars-Peter Clausen err_media_entity_cleanup: 1213d5d51a82SLars-Peter Clausen media_entity_cleanup(&sd->entity); 1214cb7a01acSMauro Carvalho Chehab err_free_ctrl: 1215cb7a01acSMauro Carvalho Chehab adv7180_exit_controls(state); 1216851a54efSLars-Peter Clausen err_unregister_vpp_client: 1217851a54efSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_I2P) 1218851a54efSLars-Peter Clausen i2c_unregister_device(state->vpp_client); 1219b37135e3SLars-Peter Clausen err_unregister_csi_client: 1220b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) 1221b37135e3SLars-Peter Clausen i2c_unregister_device(state->csi_client); 1222297a0ae3SLars-Peter Clausen mutex_destroy(&state->mutex); 1223cb7a01acSMauro Carvalho Chehab return ret; 1224cb7a01acSMauro Carvalho Chehab } 1225cb7a01acSMauro Carvalho Chehab 12264c62e976SGreg Kroah-Hartman static int adv7180_remove(struct i2c_client *client) 1227cb7a01acSMauro Carvalho Chehab { 1228cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = i2c_get_clientdata(client); 1229cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 1230cb7a01acSMauro Carvalho Chehab 1231fa5b7945SLars-Peter Clausen v4l2_async_unregister_subdev(sd); 1232fa5b7945SLars-Peter Clausen 12330c25534dSLars-Peter Clausen if (state->irq > 0) 1234cb7a01acSMauro Carvalho Chehab free_irq(client->irq, state); 1235cb7a01acSMauro Carvalho Chehab 1236d5d51a82SLars-Peter Clausen media_entity_cleanup(&sd->entity); 1237b13f4af2SLars-Peter Clausen adv7180_exit_controls(state); 1238b37135e3SLars-Peter Clausen 1239851a54efSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_I2P) 1240851a54efSLars-Peter Clausen i2c_unregister_device(state->vpp_client); 1241b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) 1242b37135e3SLars-Peter Clausen i2c_unregister_device(state->csi_client); 1243b37135e3SLars-Peter Clausen 1244297a0ae3SLars-Peter Clausen mutex_destroy(&state->mutex); 1245b37135e3SLars-Peter Clausen 1246cb7a01acSMauro Carvalho Chehab return 0; 1247cb7a01acSMauro Carvalho Chehab } 1248cb7a01acSMauro Carvalho Chehab 1249cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id adv7180_id[] = { 1250f5dde49bSLars-Peter Clausen { "adv7180", (kernel_ulong_t)&adv7180_info }, 1251c5ef8f8cSLars-Peter Clausen { "adv7182", (kernel_ulong_t)&adv7182_info }, 1252bf7dcb80SLars-Peter Clausen { "adv7280", (kernel_ulong_t)&adv7280_info }, 1253b37135e3SLars-Peter Clausen { "adv7280-m", (kernel_ulong_t)&adv7280_m_info }, 1254bf7dcb80SLars-Peter Clausen { "adv7281", (kernel_ulong_t)&adv7281_info }, 1255b37135e3SLars-Peter Clausen { "adv7281-m", (kernel_ulong_t)&adv7281_m_info }, 1256b37135e3SLars-Peter Clausen { "adv7281-ma", (kernel_ulong_t)&adv7281_ma_info }, 1257851a54efSLars-Peter Clausen { "adv7282", (kernel_ulong_t)&adv7282_info }, 1258851a54efSLars-Peter Clausen { "adv7282-m", (kernel_ulong_t)&adv7282_m_info }, 1259cb7a01acSMauro Carvalho Chehab {}, 1260cb7a01acSMauro Carvalho Chehab }; 1261f5dde49bSLars-Peter Clausen MODULE_DEVICE_TABLE(i2c, adv7180_id); 1262cb7a01acSMauro Carvalho Chehab 1263cc1088dcSLars-Peter Clausen #ifdef CONFIG_PM_SLEEP 1264cc1088dcSLars-Peter Clausen static int adv7180_suspend(struct device *dev) 1265cb7a01acSMauro Carvalho Chehab { 1266cc1088dcSLars-Peter Clausen struct i2c_client *client = to_i2c_client(dev); 1267e246c333SLars-Peter Clausen struct v4l2_subdev *sd = i2c_get_clientdata(client); 1268e246c333SLars-Peter Clausen struct adv7180_state *state = to_state(sd); 1269cb7a01acSMauro Carvalho Chehab 12703999e5d0SLars-Peter Clausen return adv7180_set_power(state, false); 1271cb7a01acSMauro Carvalho Chehab } 1272cb7a01acSMauro Carvalho Chehab 1273cc1088dcSLars-Peter Clausen static int adv7180_resume(struct device *dev) 1274cb7a01acSMauro Carvalho Chehab { 1275cc1088dcSLars-Peter Clausen struct i2c_client *client = to_i2c_client(dev); 1276cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = i2c_get_clientdata(client); 1277cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 1278cb7a01acSMauro Carvalho Chehab int ret; 1279cb7a01acSMauro Carvalho Chehab 12803999e5d0SLars-Peter Clausen ret = init_device(state); 1281cb7a01acSMauro Carvalho Chehab if (ret < 0) 1282cb7a01acSMauro Carvalho Chehab return ret; 1283c18818e9SLars-Peter Clausen 1284c18818e9SLars-Peter Clausen ret = adv7180_set_power(state, state->powered); 1285c18818e9SLars-Peter Clausen if (ret) 1286c18818e9SLars-Peter Clausen return ret; 1287c18818e9SLars-Peter Clausen 1288cb7a01acSMauro Carvalho Chehab return 0; 1289cb7a01acSMauro Carvalho Chehab } 1290cc1088dcSLars-Peter Clausen 1291cc1088dcSLars-Peter Clausen static SIMPLE_DEV_PM_OPS(adv7180_pm_ops, adv7180_suspend, adv7180_resume); 1292cc1088dcSLars-Peter Clausen #define ADV7180_PM_OPS (&adv7180_pm_ops) 1293cc1088dcSLars-Peter Clausen 1294cc1088dcSLars-Peter Clausen #else 1295cc1088dcSLars-Peter Clausen #define ADV7180_PM_OPS NULL 1296cb7a01acSMauro Carvalho Chehab #endif 1297cb7a01acSMauro Carvalho Chehab 1298cb7a01acSMauro Carvalho Chehab static struct i2c_driver adv7180_driver = { 1299cb7a01acSMauro Carvalho Chehab .driver = { 1300cb7a01acSMauro Carvalho Chehab .owner = THIS_MODULE, 1301cb7a01acSMauro Carvalho Chehab .name = KBUILD_MODNAME, 1302cc1088dcSLars-Peter Clausen .pm = ADV7180_PM_OPS, 1303cb7a01acSMauro Carvalho Chehab }, 1304cb7a01acSMauro Carvalho Chehab .probe = adv7180_probe, 13054c62e976SGreg Kroah-Hartman .remove = adv7180_remove, 1306cb7a01acSMauro Carvalho Chehab .id_table = adv7180_id, 1307cb7a01acSMauro Carvalho Chehab }; 1308cb7a01acSMauro Carvalho Chehab 1309cb7a01acSMauro Carvalho Chehab module_i2c_driver(adv7180_driver); 1310cb7a01acSMauro Carvalho Chehab 1311cb7a01acSMauro Carvalho Chehab MODULE_DESCRIPTION("Analog Devices ADV7180 video decoder driver"); 1312cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Mocean Laboratories"); 1313cb7a01acSMauro Carvalho Chehab MODULE_LICENSE("GPL v2"); 1314