1661521a8SKuninori Morimoto // SPDX-License-Identifier: GPL-2.0 2cb7a01acSMauro Carvalho Chehab /* 3cb7a01acSMauro Carvalho Chehab * adv7180.c Analog Devices ADV7180 video decoder driver 4cb7a01acSMauro Carvalho Chehab * Copyright (c) 2009 Intel Corporation 5cccb83f7SVladimir Barinov * Copyright (C) 2013 Cogent Embedded, Inc. 6cccb83f7SVladimir Barinov * Copyright (C) 2013 Renesas Solutions Corp. 7cb7a01acSMauro Carvalho Chehab */ 8cb7a01acSMauro Carvalho Chehab #include <linux/module.h> 9cb7a01acSMauro Carvalho Chehab #include <linux/init.h> 10cb7a01acSMauro Carvalho Chehab #include <linux/errno.h> 11cb7a01acSMauro Carvalho Chehab #include <linux/kernel.h> 12cb7a01acSMauro Carvalho Chehab #include <linux/interrupt.h> 13cb7a01acSMauro Carvalho Chehab #include <linux/i2c.h> 14cb7a01acSMauro Carvalho Chehab #include <linux/slab.h> 15250121d3SBen Dooks #include <linux/of.h> 1665d9e14aSSteve Longerbeam #include <linux/gpio/consumer.h> 17cb7a01acSMauro Carvalho Chehab #include <linux/videodev2.h> 18937feeedSHans Verkuil #include <media/v4l2-ioctl.h> 19937feeedSHans Verkuil #include <media/v4l2-event.h> 20cb7a01acSMauro Carvalho Chehab #include <media/v4l2-device.h> 21cb7a01acSMauro Carvalho Chehab #include <media/v4l2-ctrls.h> 22cb7a01acSMauro Carvalho Chehab #include <linux/mutex.h> 23c18818e9SLars-Peter Clausen #include <linux/delay.h> 24cb7a01acSMauro Carvalho Chehab 25f5dde49bSLars-Peter Clausen #define ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM 0x0 26f5dde49bSLars-Peter Clausen #define ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM_PED 0x1 27f5dde49bSLars-Peter Clausen #define ADV7180_STD_AD_PAL_N_NTSC_J_SECAM 0x2 28f5dde49bSLars-Peter Clausen #define ADV7180_STD_AD_PAL_N_NTSC_M_SECAM 0x3 29f5dde49bSLars-Peter Clausen #define ADV7180_STD_NTSC_J 0x4 30f5dde49bSLars-Peter Clausen #define ADV7180_STD_NTSC_M 0x5 31f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL60 0x6 32f5dde49bSLars-Peter Clausen #define ADV7180_STD_NTSC_443 0x7 33f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_BG 0x8 34f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_N 0x9 35f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_M 0xa 36f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_M_PED 0xb 37f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_COMB_N 0xc 38f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_COMB_N_PED 0xd 39f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_SECAM 0xe 40f5dde49bSLars-Peter Clausen #define ADV7180_STD_PAL_SECAM_PED 0xf 41f5dde49bSLars-Peter Clausen 423999e5d0SLars-Peter Clausen #define ADV7180_REG_INPUT_CONTROL 0x0000 43cb7a01acSMauro Carvalho Chehab #define ADV7180_INPUT_CONTROL_INSEL_MASK 0x0f 44cb7a01acSMauro Carvalho Chehab 45c5ef8f8cSLars-Peter Clausen #define ADV7182_REG_INPUT_VIDSEL 0x0002 46c5ef8f8cSLars-Peter Clausen 47ce5d6290SSteve Longerbeam #define ADV7180_REG_OUTPUT_CONTROL 0x0003 483999e5d0SLars-Peter Clausen #define ADV7180_REG_EXTENDED_OUTPUT_CONTROL 0x0004 49cb7a01acSMauro Carvalho Chehab #define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS 0xC5 50cb7a01acSMauro Carvalho Chehab 51ce5d6290SSteve Longerbeam #define ADV7180_REG_AUTODETECT_ENABLE 0x0007 52cb7a01acSMauro Carvalho Chehab #define ADV7180_AUTODETECT_DEFAULT 0x7f 53cb7a01acSMauro Carvalho Chehab /* Contrast */ 543999e5d0SLars-Peter Clausen #define ADV7180_REG_CON 0x0008 /*Unsigned */ 55cb7a01acSMauro Carvalho Chehab #define ADV7180_CON_MIN 0 56cb7a01acSMauro Carvalho Chehab #define ADV7180_CON_DEF 128 57cb7a01acSMauro Carvalho Chehab #define ADV7180_CON_MAX 255 58cb7a01acSMauro Carvalho Chehab /* Brightness*/ 593999e5d0SLars-Peter Clausen #define ADV7180_REG_BRI 0x000a /*Signed */ 60cb7a01acSMauro Carvalho Chehab #define ADV7180_BRI_MIN -128 61cb7a01acSMauro Carvalho Chehab #define ADV7180_BRI_DEF 0 62cb7a01acSMauro Carvalho Chehab #define ADV7180_BRI_MAX 127 63cb7a01acSMauro Carvalho Chehab /* Hue */ 643999e5d0SLars-Peter Clausen #define ADV7180_REG_HUE 0x000b /*Signed, inverted */ 65cb7a01acSMauro Carvalho Chehab #define ADV7180_HUE_MIN -127 66cb7a01acSMauro Carvalho Chehab #define ADV7180_HUE_DEF 0 67cb7a01acSMauro Carvalho Chehab #define ADV7180_HUE_MAX 128 68cb7a01acSMauro Carvalho Chehab 693999e5d0SLars-Peter Clausen #define ADV7180_REG_CTRL 0x000e 70029d6177SLars-Peter Clausen #define ADV7180_CTRL_IRQ_SPACE 0x20 71cb7a01acSMauro Carvalho Chehab 72029d6177SLars-Peter Clausen #define ADV7180_REG_PWR_MAN 0x0f 73cb7a01acSMauro Carvalho Chehab #define ADV7180_PWR_MAN_ON 0x04 74cb7a01acSMauro Carvalho Chehab #define ADV7180_PWR_MAN_OFF 0x24 75cb7a01acSMauro Carvalho Chehab #define ADV7180_PWR_MAN_RES 0x80 76cb7a01acSMauro Carvalho Chehab 773999e5d0SLars-Peter Clausen #define ADV7180_REG_STATUS1 0x0010 78cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_IN_LOCK 0x01 79cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_MASK 0x70 80cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_NTSM_M_J 0x00 81cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_NTSC_4_43 0x10 82cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_PAL_M 0x20 83cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_PAL_60 0x30 84cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_PAL_B_G 0x40 85cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_SECAM 0x50 86cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_PAL_COMB 0x60 87cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_SECAM_525 0x70 88cb7a01acSMauro Carvalho Chehab 893999e5d0SLars-Peter Clausen #define ADV7180_REG_IDENT 0x0011 90cb7a01acSMauro Carvalho Chehab #define ADV7180_ID_7180 0x18 91cb7a01acSMauro Carvalho Chehab 92ce5d6290SSteve Longerbeam #define ADV7180_REG_STATUS3 0x0013 93ce5d6290SSteve Longerbeam #define ADV7180_REG_ANALOG_CLAMP_CTL 0x0014 94ce5d6290SSteve Longerbeam #define ADV7180_REG_SHAP_FILTER_CTL_1 0x0017 95ce5d6290SSteve Longerbeam #define ADV7180_REG_CTRL_2 0x001d 96ce5d6290SSteve Longerbeam #define ADV7180_REG_VSYNC_FIELD_CTL_1 0x0031 97ce5d6290SSteve Longerbeam #define ADV7180_REG_MANUAL_WIN_CTL_1 0x003d 98ce5d6290SSteve Longerbeam #define ADV7180_REG_MANUAL_WIN_CTL_2 0x003e 99ce5d6290SSteve Longerbeam #define ADV7180_REG_MANUAL_WIN_CTL_3 0x003f 100ce5d6290SSteve Longerbeam #define ADV7180_REG_LOCK_CNT 0x0051 101ce5d6290SSteve Longerbeam #define ADV7180_REG_CVBS_TRIM 0x0052 102ce5d6290SSteve Longerbeam #define ADV7180_REG_CLAMP_ADJ 0x005a 103ce5d6290SSteve Longerbeam #define ADV7180_REG_RES_CIR 0x005f 104ce5d6290SSteve Longerbeam #define ADV7180_REG_DIFF_MODE 0x0060 105ce5d6290SSteve Longerbeam 10652e37f0aSSteve Longerbeam #define ADV7180_REG_ICONF1 0x2040 107cb7a01acSMauro Carvalho Chehab #define ADV7180_ICONF1_ACTIVE_LOW 0x01 108cb7a01acSMauro Carvalho Chehab #define ADV7180_ICONF1_PSYNC_ONLY 0x10 109cb7a01acSMauro Carvalho Chehab #define ADV7180_ICONF1_ACTIVE_TO_CLR 0xC0 110cb7a01acSMauro Carvalho Chehab /* Saturation */ 1113999e5d0SLars-Peter Clausen #define ADV7180_REG_SD_SAT_CB 0x00e3 /*Unsigned */ 1123999e5d0SLars-Peter Clausen #define ADV7180_REG_SD_SAT_CR 0x00e4 /*Unsigned */ 113cb7a01acSMauro Carvalho Chehab #define ADV7180_SAT_MIN 0 114cb7a01acSMauro Carvalho Chehab #define ADV7180_SAT_DEF 128 115cb7a01acSMauro Carvalho Chehab #define ADV7180_SAT_MAX 255 116cb7a01acSMauro Carvalho Chehab 117cb7a01acSMauro Carvalho Chehab #define ADV7180_IRQ1_LOCK 0x01 118cb7a01acSMauro Carvalho Chehab #define ADV7180_IRQ1_UNLOCK 0x02 11952e37f0aSSteve Longerbeam #define ADV7180_REG_ISR1 0x2042 12052e37f0aSSteve Longerbeam #define ADV7180_REG_ICR1 0x2043 12152e37f0aSSteve Longerbeam #define ADV7180_REG_IMR1 0x2044 12252e37f0aSSteve Longerbeam #define ADV7180_REG_IMR2 0x2048 123cb7a01acSMauro Carvalho Chehab #define ADV7180_IRQ3_AD_CHANGE 0x08 12452e37f0aSSteve Longerbeam #define ADV7180_REG_ISR3 0x204A 12552e37f0aSSteve Longerbeam #define ADV7180_REG_ICR3 0x204B 12652e37f0aSSteve Longerbeam #define ADV7180_REG_IMR3 0x204C 12752e37f0aSSteve Longerbeam #define ADV7180_REG_IMR4 0x2050 128cb7a01acSMauro Carvalho Chehab 1293999e5d0SLars-Peter Clausen #define ADV7180_REG_NTSC_V_BIT_END 0x00E6 130cb7a01acSMauro Carvalho Chehab #define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND 0x4F 131cb7a01acSMauro Carvalho Chehab 132851a54efSLars-Peter Clausen #define ADV7180_REG_VPP_SLAVE_ADDR 0xFD 133b37135e3SLars-Peter Clausen #define ADV7180_REG_CSI_SLAVE_ADDR 0xFE 134b37135e3SLars-Peter Clausen 135ce5d6290SSteve Longerbeam #define ADV7180_REG_ACE_CTRL1 0x4080 136ce5d6290SSteve Longerbeam #define ADV7180_REG_ACE_CTRL5 0x4084 13708b717c2SLars-Peter Clausen #define ADV7180_REG_FLCONTROL 0x40e0 13808b717c2SLars-Peter Clausen #define ADV7180_FLCONTROL_FL_ENABLE 0x1 13908b717c2SLars-Peter Clausen 140ce5d6290SSteve Longerbeam #define ADV7180_REG_RST_CLAMP 0x809c 141ce5d6290SSteve Longerbeam #define ADV7180_REG_AGC_ADJ1 0x80b6 142ce5d6290SSteve Longerbeam #define ADV7180_REG_AGC_ADJ2 0x80c0 143ce5d6290SSteve Longerbeam 144b37135e3SLars-Peter Clausen #define ADV7180_CSI_REG_PWRDN 0x00 145b37135e3SLars-Peter Clausen #define ADV7180_CSI_PWRDN 0x80 146b37135e3SLars-Peter Clausen 147f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN1 0x00 148f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN2 0x01 149f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN3 0x02 150f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN4 0x03 151f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN5 0x04 152f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN6 0x05 153f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_SVIDEO_AIN1_AIN2 0x06 154f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_SVIDEO_AIN3_AIN4 0x07 155f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_SVIDEO_AIN5_AIN6 0x08 156f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_YPRPB_AIN1_AIN2_AIN3 0x09 157f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0a 158f5dde49bSLars-Peter Clausen 159c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN1 0x00 160c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN2 0x01 161c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN3 0x02 162c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN4 0x03 163c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN5 0x04 164c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN6 0x05 165c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN7 0x06 166c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN8 0x07 167c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_SVIDEO_AIN1_AIN2 0x08 168c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_SVIDEO_AIN3_AIN4 0x09 169c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_SVIDEO_AIN5_AIN6 0x0a 170c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_SVIDEO_AIN7_AIN8 0x0b 171c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3 0x0c 172c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0d 173c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2 0x0e 174c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4 0x0f 175c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6 0x10 176c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8 0x11 177c5ef8f8cSLars-Peter Clausen 178b37135e3SLars-Peter Clausen #define ADV7180_DEFAULT_CSI_I2C_ADDR 0x44 179851a54efSLars-Peter Clausen #define ADV7180_DEFAULT_VPP_I2C_ADDR 0x42 180b37135e3SLars-Peter Clausen 18108b717c2SLars-Peter Clausen #define V4L2_CID_ADV_FAST_SWITCH (V4L2_CID_USER_ADV7180_BASE + 0x00) 18208b717c2SLars-Peter Clausen 1839483a3f8STim Harvey /* Initial number of frames to skip to avoid possible garbage */ 1849483a3f8STim Harvey #define ADV7180_NUM_OF_SKIP_FRAMES 2 1859483a3f8STim Harvey 186f5dde49bSLars-Peter Clausen struct adv7180_state; 187f5dde49bSLars-Peter Clausen 188f5dde49bSLars-Peter Clausen #define ADV7180_FLAG_RESET_POWERED BIT(0) 189bf7dcb80SLars-Peter Clausen #define ADV7180_FLAG_V2 BIT(1) 190b37135e3SLars-Peter Clausen #define ADV7180_FLAG_MIPI_CSI2 BIT(2) 191851a54efSLars-Peter Clausen #define ADV7180_FLAG_I2P BIT(3) 192f5dde49bSLars-Peter Clausen 193f5dde49bSLars-Peter Clausen struct adv7180_chip_info { 194f5dde49bSLars-Peter Clausen unsigned int flags; 195f5dde49bSLars-Peter Clausen unsigned int valid_input_mask; 196f5dde49bSLars-Peter Clausen int (*set_std)(struct adv7180_state *st, unsigned int std); 197f5dde49bSLars-Peter Clausen int (*select_input)(struct adv7180_state *st, unsigned int input); 198f5dde49bSLars-Peter Clausen int (*init)(struct adv7180_state *state); 199f5dde49bSLars-Peter Clausen }; 200f5dde49bSLars-Peter Clausen 201cb7a01acSMauro Carvalho Chehab struct adv7180_state { 202cb7a01acSMauro Carvalho Chehab struct v4l2_ctrl_handler ctrl_hdl; 203cb7a01acSMauro Carvalho Chehab struct v4l2_subdev sd; 204d5d51a82SLars-Peter Clausen struct media_pad pad; 205cb7a01acSMauro Carvalho Chehab struct mutex mutex; /* mutual excl. when accessing chip */ 206cb7a01acSMauro Carvalho Chehab int irq; 20765d9e14aSSteve Longerbeam struct gpio_desc *pwdn_gpio; 208*abb7c7c2SFrieder Schrempf struct gpio_desc *rst_gpio; 209cb7a01acSMauro Carvalho Chehab v4l2_std_id curr_norm; 210e246c333SLars-Peter Clausen bool powered; 211937feeedSHans Verkuil bool streaming; 212cb7a01acSMauro Carvalho Chehab u8 input; 2133999e5d0SLars-Peter Clausen 2143999e5d0SLars-Peter Clausen struct i2c_client *client; 2153999e5d0SLars-Peter Clausen unsigned int register_page; 216b37135e3SLars-Peter Clausen struct i2c_client *csi_client; 217851a54efSLars-Peter Clausen struct i2c_client *vpp_client; 218f5dde49bSLars-Peter Clausen const struct adv7180_chip_info *chip_info; 219851a54efSLars-Peter Clausen enum v4l2_field field; 220cb7a01acSMauro Carvalho Chehab }; 221cb7a01acSMauro Carvalho Chehab #define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler, \ 222cb7a01acSMauro Carvalho Chehab struct adv7180_state, \ 223cb7a01acSMauro Carvalho Chehab ctrl_hdl)->sd) 224cb7a01acSMauro Carvalho Chehab 2253999e5d0SLars-Peter Clausen static int adv7180_select_page(struct adv7180_state *state, unsigned int page) 2263999e5d0SLars-Peter Clausen { 2273999e5d0SLars-Peter Clausen if (state->register_page != page) { 2283999e5d0SLars-Peter Clausen i2c_smbus_write_byte_data(state->client, ADV7180_REG_CTRL, 2293999e5d0SLars-Peter Clausen page); 2303999e5d0SLars-Peter Clausen state->register_page = page; 2313999e5d0SLars-Peter Clausen } 2323999e5d0SLars-Peter Clausen 2333999e5d0SLars-Peter Clausen return 0; 2343999e5d0SLars-Peter Clausen } 2353999e5d0SLars-Peter Clausen 2363999e5d0SLars-Peter Clausen static int adv7180_write(struct adv7180_state *state, unsigned int reg, 2373999e5d0SLars-Peter Clausen unsigned int value) 2383999e5d0SLars-Peter Clausen { 2393999e5d0SLars-Peter Clausen lockdep_assert_held(&state->mutex); 2403999e5d0SLars-Peter Clausen adv7180_select_page(state, reg >> 8); 2413999e5d0SLars-Peter Clausen return i2c_smbus_write_byte_data(state->client, reg & 0xff, value); 2423999e5d0SLars-Peter Clausen } 2433999e5d0SLars-Peter Clausen 2443999e5d0SLars-Peter Clausen static int adv7180_read(struct adv7180_state *state, unsigned int reg) 2453999e5d0SLars-Peter Clausen { 2463999e5d0SLars-Peter Clausen lockdep_assert_held(&state->mutex); 2473999e5d0SLars-Peter Clausen adv7180_select_page(state, reg >> 8); 2483999e5d0SLars-Peter Clausen return i2c_smbus_read_byte_data(state->client, reg & 0xff); 2493999e5d0SLars-Peter Clausen } 2503999e5d0SLars-Peter Clausen 251b37135e3SLars-Peter Clausen static int adv7180_csi_write(struct adv7180_state *state, unsigned int reg, 252b37135e3SLars-Peter Clausen unsigned int value) 253b37135e3SLars-Peter Clausen { 254b37135e3SLars-Peter Clausen return i2c_smbus_write_byte_data(state->csi_client, reg, value); 255b37135e3SLars-Peter Clausen } 256b37135e3SLars-Peter Clausen 257f5dde49bSLars-Peter Clausen static int adv7180_set_video_standard(struct adv7180_state *state, 258f5dde49bSLars-Peter Clausen unsigned int std) 259f5dde49bSLars-Peter Clausen { 260f5dde49bSLars-Peter Clausen return state->chip_info->set_std(state, std); 261f5dde49bSLars-Peter Clausen } 2623999e5d0SLars-Peter Clausen 263851a54efSLars-Peter Clausen static int adv7180_vpp_write(struct adv7180_state *state, unsigned int reg, 264851a54efSLars-Peter Clausen unsigned int value) 265851a54efSLars-Peter Clausen { 266851a54efSLars-Peter Clausen return i2c_smbus_write_byte_data(state->vpp_client, reg, value); 267851a54efSLars-Peter Clausen } 268851a54efSLars-Peter Clausen 269cb7a01acSMauro Carvalho Chehab static v4l2_std_id adv7180_std_to_v4l2(u8 status1) 270cb7a01acSMauro Carvalho Chehab { 271b294a192SVladimir Barinov /* in case V4L2_IN_ST_NO_SIGNAL */ 272b294a192SVladimir Barinov if (!(status1 & ADV7180_STATUS1_IN_LOCK)) 273b294a192SVladimir Barinov return V4L2_STD_UNKNOWN; 274b294a192SVladimir Barinov 275cb7a01acSMauro Carvalho Chehab switch (status1 & ADV7180_STATUS1_AUTOD_MASK) { 276cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_NTSM_M_J: 277cb7a01acSMauro Carvalho Chehab return V4L2_STD_NTSC; 278cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_NTSC_4_43: 279cb7a01acSMauro Carvalho Chehab return V4L2_STD_NTSC_443; 280cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_PAL_M: 281cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL_M; 282cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_PAL_60: 283cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL_60; 284cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_PAL_B_G: 285cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL; 286cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_SECAM: 287cb7a01acSMauro Carvalho Chehab return V4L2_STD_SECAM; 288cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_PAL_COMB: 289cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL_Nc | V4L2_STD_PAL_N; 290cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_SECAM_525: 291cb7a01acSMauro Carvalho Chehab return V4L2_STD_SECAM; 292cb7a01acSMauro Carvalho Chehab default: 293cb7a01acSMauro Carvalho Chehab return V4L2_STD_UNKNOWN; 294cb7a01acSMauro Carvalho Chehab } 295cb7a01acSMauro Carvalho Chehab } 296cb7a01acSMauro Carvalho Chehab 297cb7a01acSMauro Carvalho Chehab static int v4l2_std_to_adv7180(v4l2_std_id std) 298cb7a01acSMauro Carvalho Chehab { 299cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_PAL_60) 300f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL60; 301cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_NTSC_443) 302f5dde49bSLars-Peter Clausen return ADV7180_STD_NTSC_443; 303cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_PAL_N) 304f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL_N; 305cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_PAL_M) 306f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL_M; 307cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_PAL_Nc) 308f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL_COMB_N; 309cb7a01acSMauro Carvalho Chehab 310cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_PAL) 311f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL_BG; 312cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_NTSC) 313f5dde49bSLars-Peter Clausen return ADV7180_STD_NTSC_M; 314cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_SECAM) 315f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL_SECAM; 316cb7a01acSMauro Carvalho Chehab 317cb7a01acSMauro Carvalho Chehab return -EINVAL; 318cb7a01acSMauro Carvalho Chehab } 319cb7a01acSMauro Carvalho Chehab 320cb7a01acSMauro Carvalho Chehab static u32 adv7180_status_to_v4l2(u8 status1) 321cb7a01acSMauro Carvalho Chehab { 322cb7a01acSMauro Carvalho Chehab if (!(status1 & ADV7180_STATUS1_IN_LOCK)) 323cb7a01acSMauro Carvalho Chehab return V4L2_IN_ST_NO_SIGNAL; 324cb7a01acSMauro Carvalho Chehab 325cb7a01acSMauro Carvalho Chehab return 0; 326cb7a01acSMauro Carvalho Chehab } 327cb7a01acSMauro Carvalho Chehab 3283999e5d0SLars-Peter Clausen static int __adv7180_status(struct adv7180_state *state, u32 *status, 329cb7a01acSMauro Carvalho Chehab v4l2_std_id *std) 330cb7a01acSMauro Carvalho Chehab { 3313999e5d0SLars-Peter Clausen int status1 = adv7180_read(state, ADV7180_REG_STATUS1); 332cb7a01acSMauro Carvalho Chehab 333cb7a01acSMauro Carvalho Chehab if (status1 < 0) 334cb7a01acSMauro Carvalho Chehab return status1; 335cb7a01acSMauro Carvalho Chehab 336cb7a01acSMauro Carvalho Chehab if (status) 337cb7a01acSMauro Carvalho Chehab *status = adv7180_status_to_v4l2(status1); 338cb7a01acSMauro Carvalho Chehab if (std) 339cb7a01acSMauro Carvalho Chehab *std = adv7180_std_to_v4l2(status1); 340cb7a01acSMauro Carvalho Chehab 341cb7a01acSMauro Carvalho Chehab return 0; 342cb7a01acSMauro Carvalho Chehab } 343cb7a01acSMauro Carvalho Chehab 344cb7a01acSMauro Carvalho Chehab static inline struct adv7180_state *to_state(struct v4l2_subdev *sd) 345cb7a01acSMauro Carvalho Chehab { 346cb7a01acSMauro Carvalho Chehab return container_of(sd, struct adv7180_state, sd); 347cb7a01acSMauro Carvalho Chehab } 348cb7a01acSMauro Carvalho Chehab 349cb7a01acSMauro Carvalho Chehab static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) 350cb7a01acSMauro Carvalho Chehab { 351cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 352cb7a01acSMauro Carvalho Chehab int err = mutex_lock_interruptible(&state->mutex); 353cb7a01acSMauro Carvalho Chehab if (err) 354cb7a01acSMauro Carvalho Chehab return err; 355cb7a01acSMauro Carvalho Chehab 356937feeedSHans Verkuil if (state->streaming) { 357937feeedSHans Verkuil err = -EBUSY; 358937feeedSHans Verkuil goto unlock; 359937feeedSHans Verkuil } 360cb7a01acSMauro Carvalho Chehab 361937feeedSHans Verkuil err = adv7180_set_video_standard(state, 362937feeedSHans Verkuil ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM); 363937feeedSHans Verkuil if (err) 364937feeedSHans Verkuil goto unlock; 365937feeedSHans Verkuil 366937feeedSHans Verkuil msleep(100); 367937feeedSHans Verkuil __adv7180_status(state, NULL, std); 368937feeedSHans Verkuil 369937feeedSHans Verkuil err = v4l2_std_to_adv7180(state->curr_norm); 370937feeedSHans Verkuil if (err < 0) 371937feeedSHans Verkuil goto unlock; 372937feeedSHans Verkuil 373937feeedSHans Verkuil err = adv7180_set_video_standard(state, err); 374937feeedSHans Verkuil 375937feeedSHans Verkuil unlock: 376cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex); 377cb7a01acSMauro Carvalho Chehab return err; 378cb7a01acSMauro Carvalho Chehab } 379cb7a01acSMauro Carvalho Chehab 380cb7a01acSMauro Carvalho Chehab static int adv7180_s_routing(struct v4l2_subdev *sd, u32 input, 381cb7a01acSMauro Carvalho Chehab u32 output, u32 config) 382cb7a01acSMauro Carvalho Chehab { 383cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 384cb7a01acSMauro Carvalho Chehab int ret = mutex_lock_interruptible(&state->mutex); 385cb7a01acSMauro Carvalho Chehab 386cb7a01acSMauro Carvalho Chehab if (ret) 387cb7a01acSMauro Carvalho Chehab return ret; 388cb7a01acSMauro Carvalho Chehab 389f5dde49bSLars-Peter Clausen if (input > 31 || !(BIT(input) & state->chip_info->valid_input_mask)) { 390f5dde49bSLars-Peter Clausen ret = -EINVAL; 391cb7a01acSMauro Carvalho Chehab goto out; 392f5dde49bSLars-Peter Clausen } 393cb7a01acSMauro Carvalho Chehab 394f5dde49bSLars-Peter Clausen ret = state->chip_info->select_input(state, input); 395cb7a01acSMauro Carvalho Chehab 396f5dde49bSLars-Peter Clausen if (ret == 0) 397cb7a01acSMauro Carvalho Chehab state->input = input; 398cb7a01acSMauro Carvalho Chehab out: 399cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex); 400cb7a01acSMauro Carvalho Chehab return ret; 401cb7a01acSMauro Carvalho Chehab } 402cb7a01acSMauro Carvalho Chehab 403cb7a01acSMauro Carvalho Chehab static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status) 404cb7a01acSMauro Carvalho Chehab { 405cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 406cb7a01acSMauro Carvalho Chehab int ret = mutex_lock_interruptible(&state->mutex); 407cb7a01acSMauro Carvalho Chehab if (ret) 408cb7a01acSMauro Carvalho Chehab return ret; 409cb7a01acSMauro Carvalho Chehab 4103999e5d0SLars-Peter Clausen ret = __adv7180_status(state, status, NULL); 411cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex); 412cb7a01acSMauro Carvalho Chehab return ret; 413cb7a01acSMauro Carvalho Chehab } 414cb7a01acSMauro Carvalho Chehab 4153e35e33cSLars-Peter Clausen static int adv7180_program_std(struct adv7180_state *state) 4163e35e33cSLars-Peter Clausen { 4173e35e33cSLars-Peter Clausen int ret; 4183e35e33cSLars-Peter Clausen 4193e35e33cSLars-Peter Clausen ret = v4l2_std_to_adv7180(state->curr_norm); 4203e35e33cSLars-Peter Clausen if (ret < 0) 4213e35e33cSLars-Peter Clausen return ret; 4223e35e33cSLars-Peter Clausen 423f5dde49bSLars-Peter Clausen ret = adv7180_set_video_standard(state, ret); 4243e35e33cSLars-Peter Clausen if (ret < 0) 4253e35e33cSLars-Peter Clausen return ret; 4263e35e33cSLars-Peter Clausen return 0; 4273e35e33cSLars-Peter Clausen } 4283e35e33cSLars-Peter Clausen 429cb7a01acSMauro Carvalho Chehab static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std) 430cb7a01acSMauro Carvalho Chehab { 431cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 432cb7a01acSMauro Carvalho Chehab int ret = mutex_lock_interruptible(&state->mutex); 4333e35e33cSLars-Peter Clausen 434cb7a01acSMauro Carvalho Chehab if (ret) 435cb7a01acSMauro Carvalho Chehab return ret; 436cb7a01acSMauro Carvalho Chehab 4373e35e33cSLars-Peter Clausen /* Make sure we can support this std */ 438cb7a01acSMauro Carvalho Chehab ret = v4l2_std_to_adv7180(std); 439cb7a01acSMauro Carvalho Chehab if (ret < 0) 440cb7a01acSMauro Carvalho Chehab goto out; 441cb7a01acSMauro Carvalho Chehab 442cb7a01acSMauro Carvalho Chehab state->curr_norm = std; 4433e35e33cSLars-Peter Clausen 4443e35e33cSLars-Peter Clausen ret = adv7180_program_std(state); 445cb7a01acSMauro Carvalho Chehab out: 446cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex); 447cb7a01acSMauro Carvalho Chehab return ret; 448cb7a01acSMauro Carvalho Chehab } 449cb7a01acSMauro Carvalho Chehab 450d0fadc86SNiklas Söderlund static int adv7180_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm) 451d0fadc86SNiklas Söderlund { 452d0fadc86SNiklas Söderlund struct adv7180_state *state = to_state(sd); 453d0fadc86SNiklas Söderlund 454d0fadc86SNiklas Söderlund *norm = state->curr_norm; 455d0fadc86SNiklas Söderlund 456d0fadc86SNiklas Söderlund return 0; 457d0fadc86SNiklas Söderlund } 458d0fadc86SNiklas Söderlund 45938566d28SNiklas Söderlund static int adv7180_g_frame_interval(struct v4l2_subdev *sd, 46038566d28SNiklas Söderlund struct v4l2_subdev_frame_interval *fi) 46138566d28SNiklas Söderlund { 46238566d28SNiklas Söderlund struct adv7180_state *state = to_state(sd); 46338566d28SNiklas Söderlund 46438566d28SNiklas Söderlund if (state->curr_norm & V4L2_STD_525_60) { 46538566d28SNiklas Söderlund fi->interval.numerator = 1001; 46638566d28SNiklas Söderlund fi->interval.denominator = 30000; 46738566d28SNiklas Söderlund } else { 46838566d28SNiklas Söderlund fi->interval.numerator = 1; 46938566d28SNiklas Söderlund fi->interval.denominator = 25; 47038566d28SNiklas Söderlund } 47138566d28SNiklas Söderlund 47238566d28SNiklas Söderlund return 0; 47338566d28SNiklas Söderlund } 47438566d28SNiklas Söderlund 47565d9e14aSSteve Longerbeam static void adv7180_set_power_pin(struct adv7180_state *state, bool on) 47665d9e14aSSteve Longerbeam { 47765d9e14aSSteve Longerbeam if (!state->pwdn_gpio) 47865d9e14aSSteve Longerbeam return; 47965d9e14aSSteve Longerbeam 48065d9e14aSSteve Longerbeam if (on) { 48165d9e14aSSteve Longerbeam gpiod_set_value_cansleep(state->pwdn_gpio, 0); 48265d9e14aSSteve Longerbeam usleep_range(5000, 10000); 48365d9e14aSSteve Longerbeam } else { 48465d9e14aSSteve Longerbeam gpiod_set_value_cansleep(state->pwdn_gpio, 1); 48565d9e14aSSteve Longerbeam } 48665d9e14aSSteve Longerbeam } 48765d9e14aSSteve Longerbeam 488*abb7c7c2SFrieder Schrempf static void adv7180_set_reset_pin(struct adv7180_state *state, bool on) 489*abb7c7c2SFrieder Schrempf { 490*abb7c7c2SFrieder Schrempf if (!state->rst_gpio) 491*abb7c7c2SFrieder Schrempf return; 492*abb7c7c2SFrieder Schrempf 493*abb7c7c2SFrieder Schrempf if (on) { 494*abb7c7c2SFrieder Schrempf gpiod_set_value_cansleep(state->rst_gpio, 1); 495*abb7c7c2SFrieder Schrempf } else { 496*abb7c7c2SFrieder Schrempf gpiod_set_value_cansleep(state->rst_gpio, 0); 497*abb7c7c2SFrieder Schrempf usleep_range(5000, 10000); 498*abb7c7c2SFrieder Schrempf } 499*abb7c7c2SFrieder Schrempf } 500*abb7c7c2SFrieder Schrempf 5013999e5d0SLars-Peter Clausen static int adv7180_set_power(struct adv7180_state *state, bool on) 502e246c333SLars-Peter Clausen { 503e246c333SLars-Peter Clausen u8 val; 504b37135e3SLars-Peter Clausen int ret; 505e246c333SLars-Peter Clausen 506e246c333SLars-Peter Clausen if (on) 507e246c333SLars-Peter Clausen val = ADV7180_PWR_MAN_ON; 508e246c333SLars-Peter Clausen else 509e246c333SLars-Peter Clausen val = ADV7180_PWR_MAN_OFF; 510e246c333SLars-Peter Clausen 511b37135e3SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_PWR_MAN, val); 512b37135e3SLars-Peter Clausen if (ret) 513b37135e3SLars-Peter Clausen return ret; 514b37135e3SLars-Peter Clausen 515b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 516b37135e3SLars-Peter Clausen if (on) { 517b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0xDE, 0x02); 518b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0xD2, 0xF7); 519b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0xD8, 0x65); 520b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0xE0, 0x09); 521b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0x2C, 0x00); 522851a54efSLars-Peter Clausen if (state->field == V4L2_FIELD_NONE) 523851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x1D, 0x80); 524b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0x00, 0x00); 525b37135e3SLars-Peter Clausen } else { 526b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0x00, 0x80); 527b37135e3SLars-Peter Clausen } 528b37135e3SLars-Peter Clausen } 529b37135e3SLars-Peter Clausen 530b37135e3SLars-Peter Clausen return 0; 531e246c333SLars-Peter Clausen } 532e246c333SLars-Peter Clausen 533e246c333SLars-Peter Clausen static int adv7180_s_power(struct v4l2_subdev *sd, int on) 534e246c333SLars-Peter Clausen { 535e246c333SLars-Peter Clausen struct adv7180_state *state = to_state(sd); 536e246c333SLars-Peter Clausen int ret; 537e246c333SLars-Peter Clausen 538e246c333SLars-Peter Clausen ret = mutex_lock_interruptible(&state->mutex); 539e246c333SLars-Peter Clausen if (ret) 540e246c333SLars-Peter Clausen return ret; 541e246c333SLars-Peter Clausen 5423999e5d0SLars-Peter Clausen ret = adv7180_set_power(state, on); 543e246c333SLars-Peter Clausen if (ret == 0) 544e246c333SLars-Peter Clausen state->powered = on; 545e246c333SLars-Peter Clausen 546e246c333SLars-Peter Clausen mutex_unlock(&state->mutex); 547e246c333SLars-Peter Clausen return ret; 548e246c333SLars-Peter Clausen } 549e246c333SLars-Peter Clausen 550cb7a01acSMauro Carvalho Chehab static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl) 551cb7a01acSMauro Carvalho Chehab { 552cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = to_adv7180_sd(ctrl); 553cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 554cb7a01acSMauro Carvalho Chehab int ret = mutex_lock_interruptible(&state->mutex); 555cb7a01acSMauro Carvalho Chehab int val; 556cb7a01acSMauro Carvalho Chehab 557cb7a01acSMauro Carvalho Chehab if (ret) 558cb7a01acSMauro Carvalho Chehab return ret; 559cb7a01acSMauro Carvalho Chehab val = ctrl->val; 560cb7a01acSMauro Carvalho Chehab switch (ctrl->id) { 561cb7a01acSMauro Carvalho Chehab case V4L2_CID_BRIGHTNESS: 5623999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_BRI, val); 563cb7a01acSMauro Carvalho Chehab break; 564cb7a01acSMauro Carvalho Chehab case V4L2_CID_HUE: 565cb7a01acSMauro Carvalho Chehab /*Hue is inverted according to HSL chart */ 5663999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_HUE, -val); 567cb7a01acSMauro Carvalho Chehab break; 568cb7a01acSMauro Carvalho Chehab case V4L2_CID_CONTRAST: 5693999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_CON, val); 570cb7a01acSMauro Carvalho Chehab break; 571cb7a01acSMauro Carvalho Chehab case V4L2_CID_SATURATION: 572cb7a01acSMauro Carvalho Chehab /* 573cb7a01acSMauro Carvalho Chehab *This could be V4L2_CID_BLUE_BALANCE/V4L2_CID_RED_BALANCE 574cb7a01acSMauro Carvalho Chehab *Let's not confuse the user, everybody understands saturation 575cb7a01acSMauro Carvalho Chehab */ 5763999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_SD_SAT_CB, val); 577cb7a01acSMauro Carvalho Chehab if (ret < 0) 578cb7a01acSMauro Carvalho Chehab break; 5793999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_SD_SAT_CR, val); 580cb7a01acSMauro Carvalho Chehab break; 58108b717c2SLars-Peter Clausen case V4L2_CID_ADV_FAST_SWITCH: 58208b717c2SLars-Peter Clausen if (ctrl->val) { 58308b717c2SLars-Peter Clausen /* ADI required write */ 58408b717c2SLars-Peter Clausen adv7180_write(state, 0x80d9, 0x44); 58508b717c2SLars-Peter Clausen adv7180_write(state, ADV7180_REG_FLCONTROL, 58608b717c2SLars-Peter Clausen ADV7180_FLCONTROL_FL_ENABLE); 58708b717c2SLars-Peter Clausen } else { 58808b717c2SLars-Peter Clausen /* ADI required write */ 58908b717c2SLars-Peter Clausen adv7180_write(state, 0x80d9, 0xc4); 59008b717c2SLars-Peter Clausen adv7180_write(state, ADV7180_REG_FLCONTROL, 0x00); 59108b717c2SLars-Peter Clausen } 59208b717c2SLars-Peter Clausen break; 593cb7a01acSMauro Carvalho Chehab default: 594cb7a01acSMauro Carvalho Chehab ret = -EINVAL; 595cb7a01acSMauro Carvalho Chehab } 596cb7a01acSMauro Carvalho Chehab 597cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex); 598cb7a01acSMauro Carvalho Chehab return ret; 599cb7a01acSMauro Carvalho Chehab } 600cb7a01acSMauro Carvalho Chehab 601cb7a01acSMauro Carvalho Chehab static const struct v4l2_ctrl_ops adv7180_ctrl_ops = { 602cb7a01acSMauro Carvalho Chehab .s_ctrl = adv7180_s_ctrl, 603cb7a01acSMauro Carvalho Chehab }; 604cb7a01acSMauro Carvalho Chehab 60508b717c2SLars-Peter Clausen static const struct v4l2_ctrl_config adv7180_ctrl_fast_switch = { 60608b717c2SLars-Peter Clausen .ops = &adv7180_ctrl_ops, 60708b717c2SLars-Peter Clausen .id = V4L2_CID_ADV_FAST_SWITCH, 60808b717c2SLars-Peter Clausen .name = "Fast Switching", 60908b717c2SLars-Peter Clausen .type = V4L2_CTRL_TYPE_BOOLEAN, 61008b717c2SLars-Peter Clausen .min = 0, 61108b717c2SLars-Peter Clausen .max = 1, 61208b717c2SLars-Peter Clausen .step = 1, 61308b717c2SLars-Peter Clausen }; 61408b717c2SLars-Peter Clausen 615cb7a01acSMauro Carvalho Chehab static int adv7180_init_controls(struct adv7180_state *state) 616cb7a01acSMauro Carvalho Chehab { 617cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_init(&state->ctrl_hdl, 4); 618cb7a01acSMauro Carvalho Chehab 619cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, 620cb7a01acSMauro Carvalho Chehab V4L2_CID_BRIGHTNESS, ADV7180_BRI_MIN, 621cb7a01acSMauro Carvalho Chehab ADV7180_BRI_MAX, 1, ADV7180_BRI_DEF); 622cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, 623cb7a01acSMauro Carvalho Chehab V4L2_CID_CONTRAST, ADV7180_CON_MIN, 624cb7a01acSMauro Carvalho Chehab ADV7180_CON_MAX, 1, ADV7180_CON_DEF); 625cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, 626cb7a01acSMauro Carvalho Chehab V4L2_CID_SATURATION, ADV7180_SAT_MIN, 627cb7a01acSMauro Carvalho Chehab ADV7180_SAT_MAX, 1, ADV7180_SAT_DEF); 628cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, 629cb7a01acSMauro Carvalho Chehab V4L2_CID_HUE, ADV7180_HUE_MIN, 630cb7a01acSMauro Carvalho Chehab ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF); 63108b717c2SLars-Peter Clausen v4l2_ctrl_new_custom(&state->ctrl_hdl, &adv7180_ctrl_fast_switch, NULL); 63208b717c2SLars-Peter Clausen 633cb7a01acSMauro Carvalho Chehab state->sd.ctrl_handler = &state->ctrl_hdl; 634cb7a01acSMauro Carvalho Chehab if (state->ctrl_hdl.error) { 635cb7a01acSMauro Carvalho Chehab int err = state->ctrl_hdl.error; 636cb7a01acSMauro Carvalho Chehab 637cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_free(&state->ctrl_hdl); 638cb7a01acSMauro Carvalho Chehab return err; 639cb7a01acSMauro Carvalho Chehab } 640cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_setup(&state->ctrl_hdl); 641cb7a01acSMauro Carvalho Chehab 642cb7a01acSMauro Carvalho Chehab return 0; 643cb7a01acSMauro Carvalho Chehab } 644cb7a01acSMauro Carvalho Chehab static void adv7180_exit_controls(struct adv7180_state *state) 645cb7a01acSMauro Carvalho Chehab { 646cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_free(&state->ctrl_hdl); 647cb7a01acSMauro Carvalho Chehab } 648cb7a01acSMauro Carvalho Chehab 649d5d51a82SLars-Peter Clausen static int adv7180_enum_mbus_code(struct v4l2_subdev *sd, 6500d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 651d5d51a82SLars-Peter Clausen struct v4l2_subdev_mbus_code_enum *code) 652cccb83f7SVladimir Barinov { 653d5d51a82SLars-Peter Clausen if (code->index != 0) 654cccb83f7SVladimir Barinov return -EINVAL; 655cccb83f7SVladimir Barinov 6566de690ddSNiklas Söderlund code->code = MEDIA_BUS_FMT_UYVY8_2X8; 657cccb83f7SVladimir Barinov 658cccb83f7SVladimir Barinov return 0; 659cccb83f7SVladimir Barinov } 660cccb83f7SVladimir Barinov 661cccb83f7SVladimir Barinov static int adv7180_mbus_fmt(struct v4l2_subdev *sd, 662cccb83f7SVladimir Barinov struct v4l2_mbus_framefmt *fmt) 663cccb83f7SVladimir Barinov { 664cccb83f7SVladimir Barinov struct adv7180_state *state = to_state(sd); 665cccb83f7SVladimir Barinov 6666de690ddSNiklas Söderlund fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; 667cccb83f7SVladimir Barinov fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; 668cccb83f7SVladimir Barinov fmt->width = 720; 669cccb83f7SVladimir Barinov fmt->height = state->curr_norm & V4L2_STD_525_60 ? 480 : 576; 670cccb83f7SVladimir Barinov 6716457b626SNiklas Söderlund if (state->field == V4L2_FIELD_ALTERNATE) 6726457b626SNiklas Söderlund fmt->height /= 2; 6736457b626SNiklas Söderlund 674cccb83f7SVladimir Barinov return 0; 675cccb83f7SVladimir Barinov } 676cccb83f7SVladimir Barinov 677851a54efSLars-Peter Clausen static int adv7180_set_field_mode(struct adv7180_state *state) 678851a54efSLars-Peter Clausen { 679851a54efSLars-Peter Clausen if (!(state->chip_info->flags & ADV7180_FLAG_I2P)) 680851a54efSLars-Peter Clausen return 0; 681851a54efSLars-Peter Clausen 682851a54efSLars-Peter Clausen if (state->field == V4L2_FIELD_NONE) { 683851a54efSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 684851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x01, 0x20); 685851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x02, 0x28); 686851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x03, 0x38); 687851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x04, 0x30); 688851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x05, 0x30); 689851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x06, 0x80); 690851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x07, 0x70); 691851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x08, 0x50); 692851a54efSLars-Peter Clausen } 693851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0xa3, 0x00); 694851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0x5b, 0x00); 695851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0x55, 0x80); 696851a54efSLars-Peter Clausen } else { 697851a54efSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 698851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x01, 0x18); 699851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x02, 0x18); 700851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x03, 0x30); 701851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x04, 0x20); 702851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x05, 0x28); 703851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x06, 0x40); 704851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x07, 0x58); 705851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x08, 0x30); 706851a54efSLars-Peter Clausen } 707851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0xa3, 0x70); 708851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0x5b, 0x80); 709851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0x55, 0x00); 710851a54efSLars-Peter Clausen } 711851a54efSLars-Peter Clausen 712851a54efSLars-Peter Clausen return 0; 713851a54efSLars-Peter Clausen } 714851a54efSLars-Peter Clausen 715d5d51a82SLars-Peter Clausen static int adv7180_get_pad_format(struct v4l2_subdev *sd, 7160d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 717d5d51a82SLars-Peter Clausen struct v4l2_subdev_format *format) 718d5d51a82SLars-Peter Clausen { 719851a54efSLars-Peter Clausen struct adv7180_state *state = to_state(sd); 720851a54efSLars-Peter Clausen 721851a54efSLars-Peter Clausen if (format->which == V4L2_SUBDEV_FORMAT_TRY) { 7220d346d2aSTomi Valkeinen format->format = *v4l2_subdev_get_try_format(sd, sd_state, 0); 723851a54efSLars-Peter Clausen } else { 724851a54efSLars-Peter Clausen adv7180_mbus_fmt(sd, &format->format); 725851a54efSLars-Peter Clausen format->format.field = state->field; 726851a54efSLars-Peter Clausen } 727851a54efSLars-Peter Clausen 728851a54efSLars-Peter Clausen return 0; 729d5d51a82SLars-Peter Clausen } 730d5d51a82SLars-Peter Clausen 731d5d51a82SLars-Peter Clausen static int adv7180_set_pad_format(struct v4l2_subdev *sd, 7320d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 733d5d51a82SLars-Peter Clausen struct v4l2_subdev_format *format) 734d5d51a82SLars-Peter Clausen { 735851a54efSLars-Peter Clausen struct adv7180_state *state = to_state(sd); 736851a54efSLars-Peter Clausen struct v4l2_mbus_framefmt *framefmt; 737e0ad7a9bSNiklas Söderlund int ret; 738851a54efSLars-Peter Clausen 739851a54efSLars-Peter Clausen switch (format->format.field) { 740851a54efSLars-Peter Clausen case V4L2_FIELD_NONE: 7416457b626SNiklas Söderlund if (state->chip_info->flags & ADV7180_FLAG_I2P) 742851a54efSLars-Peter Clausen break; 7431771e9fbSGustavo A. R. Silva fallthrough; 744851a54efSLars-Peter Clausen default: 7456457b626SNiklas Söderlund format->format.field = V4L2_FIELD_ALTERNATE; 746851a54efSLars-Peter Clausen break; 747851a54efSLars-Peter Clausen } 748851a54efSLars-Peter Clausen 749e0ad7a9bSNiklas Söderlund ret = adv7180_mbus_fmt(sd, &format->format); 750e0ad7a9bSNiklas Söderlund 751851a54efSLars-Peter Clausen if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { 752851a54efSLars-Peter Clausen if (state->field != format->format.field) { 753851a54efSLars-Peter Clausen state->field = format->format.field; 754851a54efSLars-Peter Clausen adv7180_set_power(state, false); 755851a54efSLars-Peter Clausen adv7180_set_field_mode(state); 756851a54efSLars-Peter Clausen adv7180_set_power(state, true); 757851a54efSLars-Peter Clausen } 758851a54efSLars-Peter Clausen } else { 7590d346d2aSTomi Valkeinen framefmt = v4l2_subdev_get_try_format(sd, sd_state, 0); 760851a54efSLars-Peter Clausen *framefmt = format->format; 761851a54efSLars-Peter Clausen } 762851a54efSLars-Peter Clausen 763e0ad7a9bSNiklas Söderlund return ret; 764d5d51a82SLars-Peter Clausen } 765d5d51a82SLars-Peter Clausen 76623c72dd9SNiklas Söderlund static int adv7180_init_cfg(struct v4l2_subdev *sd, 7670d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state) 76823c72dd9SNiklas Söderlund { 76923c72dd9SNiklas Söderlund struct v4l2_subdev_format fmt = { 7700d346d2aSTomi Valkeinen .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY 77123c72dd9SNiklas Söderlund : V4L2_SUBDEV_FORMAT_ACTIVE, 77223c72dd9SNiklas Söderlund }; 77323c72dd9SNiklas Söderlund 7740d346d2aSTomi Valkeinen return adv7180_set_pad_format(sd, sd_state, &fmt); 77523c72dd9SNiklas Söderlund } 77623c72dd9SNiklas Söderlund 7770c3da525SJacopo Mondi static int adv7180_get_mbus_config(struct v4l2_subdev *sd, 7780c3da525SJacopo Mondi unsigned int pad, 779cccb83f7SVladimir Barinov struct v4l2_mbus_config *cfg) 780cccb83f7SVladimir Barinov { 781b37135e3SLars-Peter Clausen struct adv7180_state *state = to_state(sd); 782b37135e3SLars-Peter Clausen 783b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 7842d95e7edSSakari Ailus cfg->type = V4L2_MBUS_CSI2_DPHY; 785b37135e3SLars-Peter Clausen cfg->flags = V4L2_MBUS_CSI2_1_LANE | 786b37135e3SLars-Peter Clausen V4L2_MBUS_CSI2_CHANNEL_0 | 787b37135e3SLars-Peter Clausen V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; 788b37135e3SLars-Peter Clausen } else { 789cccb83f7SVladimir Barinov /* 790cccb83f7SVladimir Barinov * The ADV7180 sensor supports BT.601/656 output modes. 791cccb83f7SVladimir Barinov * The BT.656 is default and not yet configurable by s/w. 792cccb83f7SVladimir Barinov */ 793cccb83f7SVladimir Barinov cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | 794cccb83f7SVladimir Barinov V4L2_MBUS_DATA_ACTIVE_HIGH; 795cccb83f7SVladimir Barinov cfg->type = V4L2_MBUS_BT656; 796b37135e3SLars-Peter Clausen } 797cccb83f7SVladimir Barinov 798cccb83f7SVladimir Barinov return 0; 799cccb83f7SVladimir Barinov } 800cccb83f7SVladimir Barinov 8019483a3f8STim Harvey static int adv7180_get_skip_frames(struct v4l2_subdev *sd, u32 *frames) 8029483a3f8STim Harvey { 8039483a3f8STim Harvey *frames = ADV7180_NUM_OF_SKIP_FRAMES; 8049483a3f8STim Harvey 8059483a3f8STim Harvey return 0; 8069483a3f8STim Harvey } 8079483a3f8STim Harvey 808ecf37493SHans Verkuil static int adv7180_g_pixelaspect(struct v4l2_subdev *sd, struct v4l2_fract *aspect) 80964b3df92SNiklas Söderlund { 81064b3df92SNiklas Söderlund struct adv7180_state *state = to_state(sd); 81164b3df92SNiklas Söderlund 81264b3df92SNiklas Söderlund if (state->curr_norm & V4L2_STD_525_60) { 813ecf37493SHans Verkuil aspect->numerator = 11; 814ecf37493SHans Verkuil aspect->denominator = 10; 81564b3df92SNiklas Söderlund } else { 816ecf37493SHans Verkuil aspect->numerator = 54; 817ecf37493SHans Verkuil aspect->denominator = 59; 81864b3df92SNiklas Söderlund } 81964b3df92SNiklas Söderlund 82064b3df92SNiklas Söderlund return 0; 82164b3df92SNiklas Söderlund } 82264b3df92SNiklas Söderlund 823bae4c757SNiklas Söderlund static int adv7180_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm) 824bae4c757SNiklas Söderlund { 825bae4c757SNiklas Söderlund *norm = V4L2_STD_ALL; 826bae4c757SNiklas Söderlund return 0; 827bae4c757SNiklas Söderlund } 828bae4c757SNiklas Söderlund 829937feeedSHans Verkuil static int adv7180_s_stream(struct v4l2_subdev *sd, int enable) 830937feeedSHans Verkuil { 831937feeedSHans Verkuil struct adv7180_state *state = to_state(sd); 832937feeedSHans Verkuil int ret; 833937feeedSHans Verkuil 834937feeedSHans Verkuil /* It's always safe to stop streaming, no need to take the lock */ 835937feeedSHans Verkuil if (!enable) { 836937feeedSHans Verkuil state->streaming = enable; 837937feeedSHans Verkuil return 0; 838937feeedSHans Verkuil } 839937feeedSHans Verkuil 840937feeedSHans Verkuil /* Must wait until querystd released the lock */ 841937feeedSHans Verkuil ret = mutex_lock_interruptible(&state->mutex); 842937feeedSHans Verkuil if (ret) 843937feeedSHans Verkuil return ret; 844937feeedSHans Verkuil state->streaming = enable; 845937feeedSHans Verkuil mutex_unlock(&state->mutex); 846937feeedSHans Verkuil return 0; 847937feeedSHans Verkuil } 848937feeedSHans Verkuil 849937feeedSHans Verkuil static int adv7180_subscribe_event(struct v4l2_subdev *sd, 850937feeedSHans Verkuil struct v4l2_fh *fh, 851937feeedSHans Verkuil struct v4l2_event_subscription *sub) 852937feeedSHans Verkuil { 853937feeedSHans Verkuil switch (sub->type) { 854937feeedSHans Verkuil case V4L2_EVENT_SOURCE_CHANGE: 855937feeedSHans Verkuil return v4l2_src_change_event_subdev_subscribe(sd, fh, sub); 856937feeedSHans Verkuil case V4L2_EVENT_CTRL: 857937feeedSHans Verkuil return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub); 858937feeedSHans Verkuil default: 859937feeedSHans Verkuil return -EINVAL; 860937feeedSHans Verkuil } 861937feeedSHans Verkuil } 862937feeedSHans Verkuil 863cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops adv7180_video_ops = { 8648774bed9SLaurent Pinchart .s_std = adv7180_s_std, 865d0fadc86SNiklas Söderlund .g_std = adv7180_g_std, 86638566d28SNiklas Söderlund .g_frame_interval = adv7180_g_frame_interval, 867cb7a01acSMauro Carvalho Chehab .querystd = adv7180_querystd, 868cb7a01acSMauro Carvalho Chehab .g_input_status = adv7180_g_input_status, 869cb7a01acSMauro Carvalho Chehab .s_routing = adv7180_s_routing, 870ecf37493SHans Verkuil .g_pixelaspect = adv7180_g_pixelaspect, 871bae4c757SNiklas Söderlund .g_tvnorms = adv7180_g_tvnorms, 872937feeedSHans Verkuil .s_stream = adv7180_s_stream, 873cb7a01acSMauro Carvalho Chehab }; 874cb7a01acSMauro Carvalho Chehab 875cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_core_ops adv7180_core_ops = { 876e246c333SLars-Peter Clausen .s_power = adv7180_s_power, 877937feeedSHans Verkuil .subscribe_event = adv7180_subscribe_event, 878937feeedSHans Verkuil .unsubscribe_event = v4l2_event_subdev_unsubscribe, 879cb7a01acSMauro Carvalho Chehab }; 880cb7a01acSMauro Carvalho Chehab 881d5d51a82SLars-Peter Clausen static const struct v4l2_subdev_pad_ops adv7180_pad_ops = { 88223c72dd9SNiklas Söderlund .init_cfg = adv7180_init_cfg, 883d5d51a82SLars-Peter Clausen .enum_mbus_code = adv7180_enum_mbus_code, 884d5d51a82SLars-Peter Clausen .set_fmt = adv7180_set_pad_format, 885d5d51a82SLars-Peter Clausen .get_fmt = adv7180_get_pad_format, 8860c3da525SJacopo Mondi .get_mbus_config = adv7180_get_mbus_config, 887d5d51a82SLars-Peter Clausen }; 888d5d51a82SLars-Peter Clausen 8899483a3f8STim Harvey static const struct v4l2_subdev_sensor_ops adv7180_sensor_ops = { 8909483a3f8STim Harvey .g_skip_frames = adv7180_get_skip_frames, 8919483a3f8STim Harvey }; 8929483a3f8STim Harvey 893cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops adv7180_ops = { 894cb7a01acSMauro Carvalho Chehab .core = &adv7180_core_ops, 895cb7a01acSMauro Carvalho Chehab .video = &adv7180_video_ops, 896d5d51a82SLars-Peter Clausen .pad = &adv7180_pad_ops, 8979483a3f8STim Harvey .sensor = &adv7180_sensor_ops, 898cb7a01acSMauro Carvalho Chehab }; 899cb7a01acSMauro Carvalho Chehab 9000c25534dSLars-Peter Clausen static irqreturn_t adv7180_irq(int irq, void *devid) 901cb7a01acSMauro Carvalho Chehab { 9020c25534dSLars-Peter Clausen struct adv7180_state *state = devid; 903cb7a01acSMauro Carvalho Chehab u8 isr3; 904cb7a01acSMauro Carvalho Chehab 905cb7a01acSMauro Carvalho Chehab mutex_lock(&state->mutex); 9063999e5d0SLars-Peter Clausen isr3 = adv7180_read(state, ADV7180_REG_ISR3); 907cb7a01acSMauro Carvalho Chehab /* clear */ 9083999e5d0SLars-Peter Clausen adv7180_write(state, ADV7180_REG_ICR3, isr3); 909cb7a01acSMauro Carvalho Chehab 910937feeedSHans Verkuil if (isr3 & ADV7180_IRQ3_AD_CHANGE) { 911937feeedSHans Verkuil static const struct v4l2_event src_ch = { 912937feeedSHans Verkuil .type = V4L2_EVENT_SOURCE_CHANGE, 913937feeedSHans Verkuil .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, 914937feeedSHans Verkuil }; 915937feeedSHans Verkuil 916937feeedSHans Verkuil v4l2_subdev_notify_event(&state->sd, &src_ch); 917937feeedSHans Verkuil } 918cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex); 919cb7a01acSMauro Carvalho Chehab 920cb7a01acSMauro Carvalho Chehab return IRQ_HANDLED; 921cb7a01acSMauro Carvalho Chehab } 922cb7a01acSMauro Carvalho Chehab 923f5dde49bSLars-Peter Clausen static int adv7180_init(struct adv7180_state *state) 924f5dde49bSLars-Peter Clausen { 925f5dde49bSLars-Peter Clausen int ret; 926f5dde49bSLars-Peter Clausen 927f5dde49bSLars-Peter Clausen /* ITU-R BT.656-4 compatible */ 928f5dde49bSLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 929f5dde49bSLars-Peter Clausen ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS); 930f5dde49bSLars-Peter Clausen if (ret < 0) 931f5dde49bSLars-Peter Clausen return ret; 932f5dde49bSLars-Peter Clausen 933f5dde49bSLars-Peter Clausen /* Manually set V bit end position in NTSC mode */ 934f5dde49bSLars-Peter Clausen return adv7180_write(state, ADV7180_REG_NTSC_V_BIT_END, 935f5dde49bSLars-Peter Clausen ADV7180_NTSC_V_BIT_END_MANUAL_NVEND); 936f5dde49bSLars-Peter Clausen } 937f5dde49bSLars-Peter Clausen 938f5dde49bSLars-Peter Clausen static int adv7180_set_std(struct adv7180_state *state, unsigned int std) 939f5dde49bSLars-Peter Clausen { 940f5dde49bSLars-Peter Clausen return adv7180_write(state, ADV7180_REG_INPUT_CONTROL, 941f5dde49bSLars-Peter Clausen (std << 4) | state->input); 942f5dde49bSLars-Peter Clausen } 943f5dde49bSLars-Peter Clausen 944f5dde49bSLars-Peter Clausen static int adv7180_select_input(struct adv7180_state *state, unsigned int input) 945f5dde49bSLars-Peter Clausen { 946f5dde49bSLars-Peter Clausen int ret; 947f5dde49bSLars-Peter Clausen 948f5dde49bSLars-Peter Clausen ret = adv7180_read(state, ADV7180_REG_INPUT_CONTROL); 949f5dde49bSLars-Peter Clausen if (ret < 0) 950f5dde49bSLars-Peter Clausen return ret; 951f5dde49bSLars-Peter Clausen 952f5dde49bSLars-Peter Clausen ret &= ~ADV7180_INPUT_CONTROL_INSEL_MASK; 953f5dde49bSLars-Peter Clausen ret |= input; 954f5dde49bSLars-Peter Clausen return adv7180_write(state, ADV7180_REG_INPUT_CONTROL, ret); 955f5dde49bSLars-Peter Clausen } 956f5dde49bSLars-Peter Clausen 957c5ef8f8cSLars-Peter Clausen static int adv7182_init(struct adv7180_state *state) 958c5ef8f8cSLars-Peter Clausen { 959b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) 960b37135e3SLars-Peter Clausen adv7180_write(state, ADV7180_REG_CSI_SLAVE_ADDR, 961b37135e3SLars-Peter Clausen ADV7180_DEFAULT_CSI_I2C_ADDR << 1); 962b37135e3SLars-Peter Clausen 963851a54efSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_I2P) 964851a54efSLars-Peter Clausen adv7180_write(state, ADV7180_REG_VPP_SLAVE_ADDR, 965851a54efSLars-Peter Clausen ADV7180_DEFAULT_VPP_I2C_ADDR << 1); 966851a54efSLars-Peter Clausen 967bf7dcb80SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_V2) { 968bf7dcb80SLars-Peter Clausen /* ADI recommended writes for improved video quality */ 969bf7dcb80SLars-Peter Clausen adv7180_write(state, 0x0080, 0x51); 970bf7dcb80SLars-Peter Clausen adv7180_write(state, 0x0081, 0x51); 971bf7dcb80SLars-Peter Clausen adv7180_write(state, 0x0082, 0x68); 972bf7dcb80SLars-Peter Clausen } 973bf7dcb80SLars-Peter Clausen 974c5ef8f8cSLars-Peter Clausen /* ADI required writes */ 975b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 976ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_OUTPUT_CONTROL, 0x4e); 977ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 0x57); 978ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_CTRL_2, 0xc0); 979b37135e3SLars-Peter Clausen } else { 980b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_V2) 981ce5d6290SSteve Longerbeam adv7180_write(state, 982ce5d6290SSteve Longerbeam ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 983ce5d6290SSteve Longerbeam 0x17); 984b37135e3SLars-Peter Clausen else 985ce5d6290SSteve Longerbeam adv7180_write(state, 986ce5d6290SSteve Longerbeam ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 987ce5d6290SSteve Longerbeam 0x07); 988ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_OUTPUT_CONTROL, 0x0c); 989ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_CTRL_2, 0x40); 990b37135e3SLars-Peter Clausen } 991b37135e3SLars-Peter Clausen 992b37135e3SLars-Peter Clausen adv7180_write(state, 0x0013, 0x00); 993c5ef8f8cSLars-Peter Clausen 994c5ef8f8cSLars-Peter Clausen return 0; 995c5ef8f8cSLars-Peter Clausen } 996c5ef8f8cSLars-Peter Clausen 997c5ef8f8cSLars-Peter Clausen static int adv7182_set_std(struct adv7180_state *state, unsigned int std) 998c5ef8f8cSLars-Peter Clausen { 999c5ef8f8cSLars-Peter Clausen return adv7180_write(state, ADV7182_REG_INPUT_VIDSEL, std << 4); 1000c5ef8f8cSLars-Peter Clausen } 1001c5ef8f8cSLars-Peter Clausen 1002c5ef8f8cSLars-Peter Clausen enum adv7182_input_type { 1003c5ef8f8cSLars-Peter Clausen ADV7182_INPUT_TYPE_CVBS, 1004c5ef8f8cSLars-Peter Clausen ADV7182_INPUT_TYPE_DIFF_CVBS, 1005c5ef8f8cSLars-Peter Clausen ADV7182_INPUT_TYPE_SVIDEO, 1006c5ef8f8cSLars-Peter Clausen ADV7182_INPUT_TYPE_YPBPR, 1007c5ef8f8cSLars-Peter Clausen }; 1008c5ef8f8cSLars-Peter Clausen 1009c5ef8f8cSLars-Peter Clausen static enum adv7182_input_type adv7182_get_input_type(unsigned int input) 1010c5ef8f8cSLars-Peter Clausen { 1011c5ef8f8cSLars-Peter Clausen switch (input) { 1012c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN1: 1013c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN2: 1014c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN3: 1015c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN4: 1016c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN5: 1017c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN6: 1018c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN7: 1019c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN8: 1020c5ef8f8cSLars-Peter Clausen return ADV7182_INPUT_TYPE_CVBS; 1021c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_SVIDEO_AIN1_AIN2: 1022c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_SVIDEO_AIN3_AIN4: 1023c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_SVIDEO_AIN5_AIN6: 1024c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_SVIDEO_AIN7_AIN8: 1025c5ef8f8cSLars-Peter Clausen return ADV7182_INPUT_TYPE_SVIDEO; 1026c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3: 1027c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6: 1028c5ef8f8cSLars-Peter Clausen return ADV7182_INPUT_TYPE_YPBPR; 1029c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2: 1030c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4: 1031c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6: 1032c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8: 1033c5ef8f8cSLars-Peter Clausen return ADV7182_INPUT_TYPE_DIFF_CVBS; 1034c5ef8f8cSLars-Peter Clausen default: /* Will never happen */ 1035c5ef8f8cSLars-Peter Clausen return 0; 1036c5ef8f8cSLars-Peter Clausen } 1037c5ef8f8cSLars-Peter Clausen } 1038c5ef8f8cSLars-Peter Clausen 1039c5ef8f8cSLars-Peter Clausen /* ADI recommended writes to registers 0x52, 0x53, 0x54 */ 1040c5ef8f8cSLars-Peter Clausen static unsigned int adv7182_lbias_settings[][3] = { 1041c5ef8f8cSLars-Peter Clausen [ADV7182_INPUT_TYPE_CVBS] = { 0xCB, 0x4E, 0x80 }, 1042c5ef8f8cSLars-Peter Clausen [ADV7182_INPUT_TYPE_DIFF_CVBS] = { 0xC0, 0x4E, 0x80 }, 1043c5ef8f8cSLars-Peter Clausen [ADV7182_INPUT_TYPE_SVIDEO] = { 0x0B, 0xCE, 0x80 }, 1044c5ef8f8cSLars-Peter Clausen [ADV7182_INPUT_TYPE_YPBPR] = { 0x0B, 0x4E, 0xC0 }, 1045c5ef8f8cSLars-Peter Clausen }; 1046c5ef8f8cSLars-Peter Clausen 1047bf7dcb80SLars-Peter Clausen static unsigned int adv7280_lbias_settings[][3] = { 1048bf7dcb80SLars-Peter Clausen [ADV7182_INPUT_TYPE_CVBS] = { 0xCD, 0x4E, 0x80 }, 1049bf7dcb80SLars-Peter Clausen [ADV7182_INPUT_TYPE_DIFF_CVBS] = { 0xC0, 0x4E, 0x80 }, 1050bf7dcb80SLars-Peter Clausen [ADV7182_INPUT_TYPE_SVIDEO] = { 0x0B, 0xCE, 0x80 }, 1051bf7dcb80SLars-Peter Clausen [ADV7182_INPUT_TYPE_YPBPR] = { 0x0B, 0x4E, 0xC0 }, 1052bf7dcb80SLars-Peter Clausen }; 1053bf7dcb80SLars-Peter Clausen 1054c5ef8f8cSLars-Peter Clausen static int adv7182_select_input(struct adv7180_state *state, unsigned int input) 1055c5ef8f8cSLars-Peter Clausen { 1056c5ef8f8cSLars-Peter Clausen enum adv7182_input_type input_type; 1057c5ef8f8cSLars-Peter Clausen unsigned int *lbias; 1058c5ef8f8cSLars-Peter Clausen unsigned int i; 1059c5ef8f8cSLars-Peter Clausen int ret; 1060c5ef8f8cSLars-Peter Clausen 1061c5ef8f8cSLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL, input); 1062c5ef8f8cSLars-Peter Clausen if (ret) 1063c5ef8f8cSLars-Peter Clausen return ret; 1064c5ef8f8cSLars-Peter Clausen 1065c5ef8f8cSLars-Peter Clausen /* Reset clamp circuitry - ADI recommended writes */ 1066ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_RST_CLAMP, 0x00); 1067ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_RST_CLAMP, 0xff); 1068c5ef8f8cSLars-Peter Clausen 1069c5ef8f8cSLars-Peter Clausen input_type = adv7182_get_input_type(input); 1070c5ef8f8cSLars-Peter Clausen 1071c5ef8f8cSLars-Peter Clausen switch (input_type) { 1072c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_TYPE_CVBS: 1073c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_TYPE_DIFF_CVBS: 1074c5ef8f8cSLars-Peter Clausen /* ADI recommends to use the SH1 filter */ 1075ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_SHAP_FILTER_CTL_1, 0x41); 1076c5ef8f8cSLars-Peter Clausen break; 1077c5ef8f8cSLars-Peter Clausen default: 1078ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_SHAP_FILTER_CTL_1, 0x01); 1079c5ef8f8cSLars-Peter Clausen break; 1080c5ef8f8cSLars-Peter Clausen } 1081c5ef8f8cSLars-Peter Clausen 1082bf7dcb80SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_V2) 1083bf7dcb80SLars-Peter Clausen lbias = adv7280_lbias_settings[input_type]; 1084bf7dcb80SLars-Peter Clausen else 1085c5ef8f8cSLars-Peter Clausen lbias = adv7182_lbias_settings[input_type]; 1086c5ef8f8cSLars-Peter Clausen 1087c5ef8f8cSLars-Peter Clausen for (i = 0; i < ARRAY_SIZE(adv7182_lbias_settings[0]); i++) 1088ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_CVBS_TRIM + i, lbias[i]); 1089c5ef8f8cSLars-Peter Clausen 1090c5ef8f8cSLars-Peter Clausen if (input_type == ADV7182_INPUT_TYPE_DIFF_CVBS) { 1091c5ef8f8cSLars-Peter Clausen /* ADI required writes to make differential CVBS work */ 1092ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_RES_CIR, 0xa8); 1093ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_CLAMP_ADJ, 0x90); 1094ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_DIFF_MODE, 0xb0); 1095ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_AGC_ADJ1, 0x08); 1096ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_AGC_ADJ2, 0xa0); 1097c5ef8f8cSLars-Peter Clausen } else { 1098ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_RES_CIR, 0xf0); 1099ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_CLAMP_ADJ, 0xd0); 1100ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_DIFF_MODE, 0x10); 1101ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_AGC_ADJ1, 0x9c); 1102ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_AGC_ADJ2, 0x00); 1103c5ef8f8cSLars-Peter Clausen } 1104c5ef8f8cSLars-Peter Clausen 1105c5ef8f8cSLars-Peter Clausen return 0; 1106c5ef8f8cSLars-Peter Clausen } 1107c5ef8f8cSLars-Peter Clausen 1108f5dde49bSLars-Peter Clausen static const struct adv7180_chip_info adv7180_info = { 1109f5dde49bSLars-Peter Clausen .flags = ADV7180_FLAG_RESET_POWERED, 1110f5dde49bSLars-Peter Clausen /* We cannot discriminate between LQFP and 40-pin LFCSP, so accept 1111f5dde49bSLars-Peter Clausen * all inputs and let the card driver take care of validation 1112f5dde49bSLars-Peter Clausen */ 1113f5dde49bSLars-Peter Clausen .valid_input_mask = BIT(ADV7180_INPUT_CVBS_AIN1) | 1114f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_CVBS_AIN2) | 1115f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_CVBS_AIN3) | 1116f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_CVBS_AIN4) | 1117f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_CVBS_AIN5) | 1118f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_CVBS_AIN6) | 1119f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_SVIDEO_AIN1_AIN2) | 1120f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_SVIDEO_AIN3_AIN4) | 1121f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_SVIDEO_AIN5_AIN6) | 1122f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_YPRPB_AIN1_AIN2_AIN3) | 1123f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_YPRPB_AIN4_AIN5_AIN6), 1124f5dde49bSLars-Peter Clausen .init = adv7180_init, 1125f5dde49bSLars-Peter Clausen .set_std = adv7180_set_std, 1126f5dde49bSLars-Peter Clausen .select_input = adv7180_select_input, 1127f5dde49bSLars-Peter Clausen }; 1128f5dde49bSLars-Peter Clausen 1129c5ef8f8cSLars-Peter Clausen static const struct adv7180_chip_info adv7182_info = { 1130c5ef8f8cSLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1131c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1132c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) | 1133c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) | 1134c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1135c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 1136c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | 1137c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 1138c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4), 1139c5ef8f8cSLars-Peter Clausen .init = adv7182_init, 1140c5ef8f8cSLars-Peter Clausen .set_std = adv7182_set_std, 1141c5ef8f8cSLars-Peter Clausen .select_input = adv7182_select_input, 1142c5ef8f8cSLars-Peter Clausen }; 1143c5ef8f8cSLars-Peter Clausen 1144bf7dcb80SLars-Peter Clausen static const struct adv7180_chip_info adv7280_info = { 1145851a54efSLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P, 1146bf7dcb80SLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1147bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1148bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) | 1149bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) | 1150bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1151bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 1152bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3), 1153bf7dcb80SLars-Peter Clausen .init = adv7182_init, 1154bf7dcb80SLars-Peter Clausen .set_std = adv7182_set_std, 1155bf7dcb80SLars-Peter Clausen .select_input = adv7182_select_input, 1156bf7dcb80SLars-Peter Clausen }; 1157bf7dcb80SLars-Peter Clausen 1158b37135e3SLars-Peter Clausen static const struct adv7180_chip_info adv7280_m_info = { 1159851a54efSLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P, 1160b37135e3SLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1161b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1162b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) | 1163b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) | 1164b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN5) | 1165b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN6) | 1166b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) | 1167b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) | 1168b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1169b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 1170b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN5_AIN6) | 1171b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 1172b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | 1173b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6), 1174b37135e3SLars-Peter Clausen .init = adv7182_init, 1175b37135e3SLars-Peter Clausen .set_std = adv7182_set_std, 1176b37135e3SLars-Peter Clausen .select_input = adv7182_select_input, 1177b37135e3SLars-Peter Clausen }; 1178b37135e3SLars-Peter Clausen 1179bf7dcb80SLars-Peter Clausen static const struct adv7180_chip_info adv7281_info = { 1180b37135e3SLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2, 1181bf7dcb80SLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1182bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1183bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) | 1184bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) | 1185bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1186bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 1187bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 1188bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), 1189bf7dcb80SLars-Peter Clausen .init = adv7182_init, 1190bf7dcb80SLars-Peter Clausen .set_std = adv7182_set_std, 1191bf7dcb80SLars-Peter Clausen .select_input = adv7182_select_input, 1192bf7dcb80SLars-Peter Clausen }; 1193bf7dcb80SLars-Peter Clausen 1194b37135e3SLars-Peter Clausen static const struct adv7180_chip_info adv7281_m_info = { 1195b37135e3SLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2, 1196b37135e3SLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1197b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1198b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) | 1199b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) | 1200b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) | 1201b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) | 1202b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1203b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 1204b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 1205b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | 1206b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 1207b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) | 1208b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), 1209b37135e3SLars-Peter Clausen .init = adv7182_init, 1210b37135e3SLars-Peter Clausen .set_std = adv7182_set_std, 1211b37135e3SLars-Peter Clausen .select_input = adv7182_select_input, 1212b37135e3SLars-Peter Clausen }; 1213b37135e3SLars-Peter Clausen 1214b37135e3SLars-Peter Clausen static const struct adv7180_chip_info adv7281_ma_info = { 1215b37135e3SLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2, 1216b37135e3SLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1217b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1218b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) | 1219b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) | 1220b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN5) | 1221b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN6) | 1222b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) | 1223b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) | 1224b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1225b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 1226b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN5_AIN6) | 1227b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 1228b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) | 1229b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6) | 1230b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 1231b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) | 1232b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6) | 1233b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), 1234b37135e3SLars-Peter Clausen .init = adv7182_init, 1235b37135e3SLars-Peter Clausen .set_std = adv7182_set_std, 1236b37135e3SLars-Peter Clausen .select_input = adv7182_select_input, 1237b37135e3SLars-Peter Clausen }; 1238b37135e3SLars-Peter Clausen 1239851a54efSLars-Peter Clausen static const struct adv7180_chip_info adv7282_info = { 1240851a54efSLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P, 1241851a54efSLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1242851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1243851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) | 1244851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) | 1245851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1246851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 1247851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 1248851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), 1249851a54efSLars-Peter Clausen .init = adv7182_init, 1250851a54efSLars-Peter Clausen .set_std = adv7182_set_std, 1251851a54efSLars-Peter Clausen .select_input = adv7182_select_input, 1252851a54efSLars-Peter Clausen }; 1253851a54efSLars-Peter Clausen 1254851a54efSLars-Peter Clausen static const struct adv7180_chip_info adv7282_m_info = { 1255851a54efSLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P, 1256851a54efSLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) | 1257851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) | 1258851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) | 1259851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) | 1260851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) | 1261851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) | 1262851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) | 1263851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) | 1264851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) | 1265851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) | 1266851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) | 1267851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8), 1268851a54efSLars-Peter Clausen .init = adv7182_init, 1269851a54efSLars-Peter Clausen .set_std = adv7182_set_std, 1270851a54efSLars-Peter Clausen .select_input = adv7182_select_input, 1271851a54efSLars-Peter Clausen }; 1272851a54efSLars-Peter Clausen 12733999e5d0SLars-Peter Clausen static int init_device(struct adv7180_state *state) 1274cb7a01acSMauro Carvalho Chehab { 1275cb7a01acSMauro Carvalho Chehab int ret; 1276cb7a01acSMauro Carvalho Chehab 12773999e5d0SLars-Peter Clausen mutex_lock(&state->mutex); 12783999e5d0SLars-Peter Clausen 127965d9e14aSSteve Longerbeam adv7180_set_power_pin(state, true); 1280*abb7c7c2SFrieder Schrempf adv7180_set_reset_pin(state, false); 128165d9e14aSSteve Longerbeam 1282c18818e9SLars-Peter Clausen adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES); 128316dfe72fSUlrich Hecht usleep_range(5000, 10000); 1284c18818e9SLars-Peter Clausen 1285f5dde49bSLars-Peter Clausen ret = state->chip_info->init(state); 12863e35e33cSLars-Peter Clausen if (ret) 12873999e5d0SLars-Peter Clausen goto out_unlock; 1288cb7a01acSMauro Carvalho Chehab 1289f5dde49bSLars-Peter Clausen ret = adv7180_program_std(state); 1290f5dde49bSLars-Peter Clausen if (ret) 12913999e5d0SLars-Peter Clausen goto out_unlock; 1292cb7a01acSMauro Carvalho Chehab 1293851a54efSLars-Peter Clausen adv7180_set_field_mode(state); 1294851a54efSLars-Peter Clausen 1295cb7a01acSMauro Carvalho Chehab /* register for interrupts */ 1296cb7a01acSMauro Carvalho Chehab if (state->irq > 0) { 1297cb7a01acSMauro Carvalho Chehab /* config the Interrupt pin to be active low */ 12983999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_ICONF1, 1299cb7a01acSMauro Carvalho Chehab ADV7180_ICONF1_ACTIVE_LOW | 1300cb7a01acSMauro Carvalho Chehab ADV7180_ICONF1_PSYNC_ONLY); 1301cb7a01acSMauro Carvalho Chehab if (ret < 0) 13023999e5d0SLars-Peter Clausen goto out_unlock; 1303cb7a01acSMauro Carvalho Chehab 13043999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_IMR1, 0); 1305cb7a01acSMauro Carvalho Chehab if (ret < 0) 13063999e5d0SLars-Peter Clausen goto out_unlock; 1307cb7a01acSMauro Carvalho Chehab 13083999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_IMR2, 0); 1309cb7a01acSMauro Carvalho Chehab if (ret < 0) 13103999e5d0SLars-Peter Clausen goto out_unlock; 1311cb7a01acSMauro Carvalho Chehab 1312cb7a01acSMauro Carvalho Chehab /* enable AD change interrupts interrupts */ 13133999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_IMR3, 1314cb7a01acSMauro Carvalho Chehab ADV7180_IRQ3_AD_CHANGE); 1315cb7a01acSMauro Carvalho Chehab if (ret < 0) 13163999e5d0SLars-Peter Clausen goto out_unlock; 1317cb7a01acSMauro Carvalho Chehab 13183999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_IMR4, 0); 1319cb7a01acSMauro Carvalho Chehab if (ret < 0) 13203999e5d0SLars-Peter Clausen goto out_unlock; 1321cb7a01acSMauro Carvalho Chehab } 1322cb7a01acSMauro Carvalho Chehab 13233999e5d0SLars-Peter Clausen out_unlock: 13243999e5d0SLars-Peter Clausen mutex_unlock(&state->mutex); 1325df065b37SAlexey Khoroshilov 1326df065b37SAlexey Khoroshilov return ret; 1327cb7a01acSMauro Carvalho Chehab } 1328cb7a01acSMauro Carvalho Chehab 13294c62e976SGreg Kroah-Hartman static int adv7180_probe(struct i2c_client *client, 1330cb7a01acSMauro Carvalho Chehab const struct i2c_device_id *id) 1331cb7a01acSMauro Carvalho Chehab { 1332cb7a01acSMauro Carvalho Chehab struct adv7180_state *state; 1333cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd; 1334cb7a01acSMauro Carvalho Chehab int ret; 1335cb7a01acSMauro Carvalho Chehab 1336cb7a01acSMauro Carvalho Chehab /* Check if the adapter supports the needed features */ 1337cb7a01acSMauro Carvalho Chehab if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 1338cb7a01acSMauro Carvalho Chehab return -EIO; 1339cb7a01acSMauro Carvalho Chehab 1340c02b211dSLaurent Pinchart state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL); 13417657e064SFabio Estevam if (state == NULL) 13427657e064SFabio Estevam return -ENOMEM; 1343cb7a01acSMauro Carvalho Chehab 13443999e5d0SLars-Peter Clausen state->client = client; 13456457b626SNiklas Söderlund state->field = V4L2_FIELD_ALTERNATE; 1346f5dde49bSLars-Peter Clausen state->chip_info = (struct adv7180_chip_info *)id->driver_data; 13473999e5d0SLars-Peter Clausen 134865d9e14aSSteve Longerbeam state->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown", 134965d9e14aSSteve Longerbeam GPIOD_OUT_HIGH); 135065d9e14aSSteve Longerbeam if (IS_ERR(state->pwdn_gpio)) { 135165d9e14aSSteve Longerbeam ret = PTR_ERR(state->pwdn_gpio); 135265d9e14aSSteve Longerbeam v4l_err(client, "request for power pin failed: %d\n", ret); 135365d9e14aSSteve Longerbeam return ret; 135465d9e14aSSteve Longerbeam } 135565d9e14aSSteve Longerbeam 1356*abb7c7c2SFrieder Schrempf state->rst_gpio = devm_gpiod_get_optional(&client->dev, "reset", 1357*abb7c7c2SFrieder Schrempf GPIOD_OUT_HIGH); 1358*abb7c7c2SFrieder Schrempf if (IS_ERR(state->rst_gpio)) { 1359*abb7c7c2SFrieder Schrempf ret = PTR_ERR(state->rst_gpio); 1360*abb7c7c2SFrieder Schrempf v4l_err(client, "request for reset pin failed: %d\n", ret); 1361*abb7c7c2SFrieder Schrempf return ret; 1362*abb7c7c2SFrieder Schrempf } 1363*abb7c7c2SFrieder Schrempf 1364b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { 136531b9754cSWolfram Sang state->csi_client = i2c_new_dummy_device(client->adapter, 1366b37135e3SLars-Peter Clausen ADV7180_DEFAULT_CSI_I2C_ADDR); 136731b9754cSWolfram Sang if (IS_ERR(state->csi_client)) 136831b9754cSWolfram Sang return PTR_ERR(state->csi_client); 1369b37135e3SLars-Peter Clausen } 1370b37135e3SLars-Peter Clausen 1371851a54efSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_I2P) { 137231b9754cSWolfram Sang state->vpp_client = i2c_new_dummy_device(client->adapter, 1373851a54efSLars-Peter Clausen ADV7180_DEFAULT_VPP_I2C_ADDR); 137431b9754cSWolfram Sang if (IS_ERR(state->vpp_client)) { 137531b9754cSWolfram Sang ret = PTR_ERR(state->vpp_client); 1376851a54efSLars-Peter Clausen goto err_unregister_csi_client; 1377851a54efSLars-Peter Clausen } 1378851a54efSLars-Peter Clausen } 1379851a54efSLars-Peter Clausen 1380cb7a01acSMauro Carvalho Chehab state->irq = client->irq; 1381cb7a01acSMauro Carvalho Chehab mutex_init(&state->mutex); 1382937feeedSHans Verkuil state->curr_norm = V4L2_STD_NTSC; 1383f5dde49bSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_RESET_POWERED) 1384e246c333SLars-Peter Clausen state->powered = true; 1385f5dde49bSLars-Peter Clausen else 1386f5dde49bSLars-Peter Clausen state->powered = false; 1387cb7a01acSMauro Carvalho Chehab state->input = 0; 1388cb7a01acSMauro Carvalho Chehab sd = &state->sd; 1389cb7a01acSMauro Carvalho Chehab v4l2_i2c_subdev_init(sd, client, &adv7180_ops); 13905cc72c47SAkinobu Mita sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; 1391cb7a01acSMauro Carvalho Chehab 1392cb7a01acSMauro Carvalho Chehab ret = adv7180_init_controls(state); 1393cb7a01acSMauro Carvalho Chehab if (ret) 1394851a54efSLars-Peter Clausen goto err_unregister_vpp_client; 1395d5d51a82SLars-Peter Clausen 1396d5d51a82SLars-Peter Clausen state->pad.flags = MEDIA_PAD_FL_SOURCE; 1397ca0fa5f0SHans Verkuil sd->entity.function = MEDIA_ENT_F_ATV_DECODER; 1398ab22e77cSMauro Carvalho Chehab ret = media_entity_pads_init(&sd->entity, 1, &state->pad); 1399cb7a01acSMauro Carvalho Chehab if (ret) 1400cb7a01acSMauro Carvalho Chehab goto err_free_ctrl; 1401fa5b7945SLars-Peter Clausen 1402d5d51a82SLars-Peter Clausen ret = init_device(state); 1403d5d51a82SLars-Peter Clausen if (ret) 1404d5d51a82SLars-Peter Clausen goto err_media_entity_cleanup; 1405d5d51a82SLars-Peter Clausen 1406fa5721d1SLars-Peter Clausen if (state->irq) { 1407fa5721d1SLars-Peter Clausen ret = request_threaded_irq(client->irq, NULL, adv7180_irq, 1408f3e991d4SLars-Peter Clausen IRQF_ONESHOT | IRQF_TRIGGER_FALLING, 1409f3e991d4SLars-Peter Clausen KBUILD_MODNAME, state); 1410fa5721d1SLars-Peter Clausen if (ret) 1411d5d51a82SLars-Peter Clausen goto err_media_entity_cleanup; 1412fa5721d1SLars-Peter Clausen } 1413fa5721d1SLars-Peter Clausen 1414fa5b7945SLars-Peter Clausen ret = v4l2_async_register_subdev(sd); 1415fa5b7945SLars-Peter Clausen if (ret) 1416fa5b7945SLars-Peter Clausen goto err_free_irq; 1417fa5b7945SLars-Peter Clausen 1418b19c25f4SFabio Estevam v4l_info(client, "chip found @ 0x%02x (%s)\n", 1419b19c25f4SFabio Estevam client->addr, client->adapter->name); 1420b19c25f4SFabio Estevam 1421cb7a01acSMauro Carvalho Chehab return 0; 1422cb7a01acSMauro Carvalho Chehab 1423fa5b7945SLars-Peter Clausen err_free_irq: 1424fa5b7945SLars-Peter Clausen if (state->irq > 0) 1425fa5b7945SLars-Peter Clausen free_irq(client->irq, state); 1426d5d51a82SLars-Peter Clausen err_media_entity_cleanup: 1427d5d51a82SLars-Peter Clausen media_entity_cleanup(&sd->entity); 1428cb7a01acSMauro Carvalho Chehab err_free_ctrl: 1429cb7a01acSMauro Carvalho Chehab adv7180_exit_controls(state); 1430851a54efSLars-Peter Clausen err_unregister_vpp_client: 1431851a54efSLars-Peter Clausen i2c_unregister_device(state->vpp_client); 1432b37135e3SLars-Peter Clausen err_unregister_csi_client: 1433b37135e3SLars-Peter Clausen i2c_unregister_device(state->csi_client); 1434297a0ae3SLars-Peter Clausen mutex_destroy(&state->mutex); 1435cb7a01acSMauro Carvalho Chehab return ret; 1436cb7a01acSMauro Carvalho Chehab } 1437cb7a01acSMauro Carvalho Chehab 14384c62e976SGreg Kroah-Hartman static int adv7180_remove(struct i2c_client *client) 1439cb7a01acSMauro Carvalho Chehab { 1440cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = i2c_get_clientdata(client); 1441cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 1442cb7a01acSMauro Carvalho Chehab 1443fa5b7945SLars-Peter Clausen v4l2_async_unregister_subdev(sd); 1444fa5b7945SLars-Peter Clausen 14450c25534dSLars-Peter Clausen if (state->irq > 0) 1446cb7a01acSMauro Carvalho Chehab free_irq(client->irq, state); 1447cb7a01acSMauro Carvalho Chehab 1448d5d51a82SLars-Peter Clausen media_entity_cleanup(&sd->entity); 1449b13f4af2SLars-Peter Clausen adv7180_exit_controls(state); 1450b37135e3SLars-Peter Clausen 1451851a54efSLars-Peter Clausen i2c_unregister_device(state->vpp_client); 1452b37135e3SLars-Peter Clausen i2c_unregister_device(state->csi_client); 1453b37135e3SLars-Peter Clausen 1454*abb7c7c2SFrieder Schrempf adv7180_set_reset_pin(state, true); 145565d9e14aSSteve Longerbeam adv7180_set_power_pin(state, false); 145665d9e14aSSteve Longerbeam 1457297a0ae3SLars-Peter Clausen mutex_destroy(&state->mutex); 1458b37135e3SLars-Peter Clausen 1459cb7a01acSMauro Carvalho Chehab return 0; 1460cb7a01acSMauro Carvalho Chehab } 1461cb7a01acSMauro Carvalho Chehab 1462cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id adv7180_id[] = { 1463f5dde49bSLars-Peter Clausen { "adv7180", (kernel_ulong_t)&adv7180_info }, 1464281ddc3cSUlrich Hecht { "adv7180cp", (kernel_ulong_t)&adv7180_info }, 1465281ddc3cSUlrich Hecht { "adv7180st", (kernel_ulong_t)&adv7180_info }, 1466c5ef8f8cSLars-Peter Clausen { "adv7182", (kernel_ulong_t)&adv7182_info }, 1467bf7dcb80SLars-Peter Clausen { "adv7280", (kernel_ulong_t)&adv7280_info }, 1468b37135e3SLars-Peter Clausen { "adv7280-m", (kernel_ulong_t)&adv7280_m_info }, 1469bf7dcb80SLars-Peter Clausen { "adv7281", (kernel_ulong_t)&adv7281_info }, 1470b37135e3SLars-Peter Clausen { "adv7281-m", (kernel_ulong_t)&adv7281_m_info }, 1471b37135e3SLars-Peter Clausen { "adv7281-ma", (kernel_ulong_t)&adv7281_ma_info }, 1472851a54efSLars-Peter Clausen { "adv7282", (kernel_ulong_t)&adv7282_info }, 1473851a54efSLars-Peter Clausen { "adv7282-m", (kernel_ulong_t)&adv7282_m_info }, 1474cb7a01acSMauro Carvalho Chehab {}, 1475cb7a01acSMauro Carvalho Chehab }; 1476f5dde49bSLars-Peter Clausen MODULE_DEVICE_TABLE(i2c, adv7180_id); 1477cb7a01acSMauro Carvalho Chehab 1478cc1088dcSLars-Peter Clausen #ifdef CONFIG_PM_SLEEP 1479cc1088dcSLars-Peter Clausen static int adv7180_suspend(struct device *dev) 1480cb7a01acSMauro Carvalho Chehab { 148117ed3c90SKrzysztof Kozlowski struct v4l2_subdev *sd = dev_get_drvdata(dev); 1482e246c333SLars-Peter Clausen struct adv7180_state *state = to_state(sd); 1483cb7a01acSMauro Carvalho Chehab 14843999e5d0SLars-Peter Clausen return adv7180_set_power(state, false); 1485cb7a01acSMauro Carvalho Chehab } 1486cb7a01acSMauro Carvalho Chehab 1487cc1088dcSLars-Peter Clausen static int adv7180_resume(struct device *dev) 1488cb7a01acSMauro Carvalho Chehab { 148917ed3c90SKrzysztof Kozlowski struct v4l2_subdev *sd = dev_get_drvdata(dev); 1490cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd); 1491cb7a01acSMauro Carvalho Chehab int ret; 1492cb7a01acSMauro Carvalho Chehab 14933999e5d0SLars-Peter Clausen ret = init_device(state); 1494cb7a01acSMauro Carvalho Chehab if (ret < 0) 1495cb7a01acSMauro Carvalho Chehab return ret; 1496c18818e9SLars-Peter Clausen 1497c18818e9SLars-Peter Clausen ret = adv7180_set_power(state, state->powered); 1498c18818e9SLars-Peter Clausen if (ret) 1499c18818e9SLars-Peter Clausen return ret; 1500c18818e9SLars-Peter Clausen 1501cb7a01acSMauro Carvalho Chehab return 0; 1502cb7a01acSMauro Carvalho Chehab } 1503cc1088dcSLars-Peter Clausen 1504cc1088dcSLars-Peter Clausen static SIMPLE_DEV_PM_OPS(adv7180_pm_ops, adv7180_suspend, adv7180_resume); 1505cc1088dcSLars-Peter Clausen #define ADV7180_PM_OPS (&adv7180_pm_ops) 1506cc1088dcSLars-Peter Clausen 1507cc1088dcSLars-Peter Clausen #else 1508cc1088dcSLars-Peter Clausen #define ADV7180_PM_OPS NULL 1509cb7a01acSMauro Carvalho Chehab #endif 1510cb7a01acSMauro Carvalho Chehab 1511250121d3SBen Dooks #ifdef CONFIG_OF 1512250121d3SBen Dooks static const struct of_device_id adv7180_of_id[] = { 1513250121d3SBen Dooks { .compatible = "adi,adv7180", }, 1514ce1ec5c0SUlrich Hecht { .compatible = "adi,adv7180cp", }, 1515ce1ec5c0SUlrich Hecht { .compatible = "adi,adv7180st", }, 1516bf14e74cSJulian Scheel { .compatible = "adi,adv7182", }, 1517bf14e74cSJulian Scheel { .compatible = "adi,adv7280", }, 1518bf14e74cSJulian Scheel { .compatible = "adi,adv7280-m", }, 1519bf14e74cSJulian Scheel { .compatible = "adi,adv7281", }, 1520bf14e74cSJulian Scheel { .compatible = "adi,adv7281-m", }, 1521bf14e74cSJulian Scheel { .compatible = "adi,adv7281-ma", }, 1522bf14e74cSJulian Scheel { .compatible = "adi,adv7282", }, 1523bf14e74cSJulian Scheel { .compatible = "adi,adv7282-m", }, 1524250121d3SBen Dooks { }, 1525250121d3SBen Dooks }; 1526250121d3SBen Dooks 1527250121d3SBen Dooks MODULE_DEVICE_TABLE(of, adv7180_of_id); 1528250121d3SBen Dooks #endif 1529250121d3SBen Dooks 1530cb7a01acSMauro Carvalho Chehab static struct i2c_driver adv7180_driver = { 1531cb7a01acSMauro Carvalho Chehab .driver = { 1532cb7a01acSMauro Carvalho Chehab .name = KBUILD_MODNAME, 1533cc1088dcSLars-Peter Clausen .pm = ADV7180_PM_OPS, 1534250121d3SBen Dooks .of_match_table = of_match_ptr(adv7180_of_id), 1535cb7a01acSMauro Carvalho Chehab }, 1536cb7a01acSMauro Carvalho Chehab .probe = adv7180_probe, 15374c62e976SGreg Kroah-Hartman .remove = adv7180_remove, 1538cb7a01acSMauro Carvalho Chehab .id_table = adv7180_id, 1539cb7a01acSMauro Carvalho Chehab }; 1540cb7a01acSMauro Carvalho Chehab 1541cb7a01acSMauro Carvalho Chehab module_i2c_driver(adv7180_driver); 1542cb7a01acSMauro Carvalho Chehab 1543cb7a01acSMauro Carvalho Chehab MODULE_DESCRIPTION("Analog Devices ADV7180 video decoder driver"); 1544cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Mocean Laboratories"); 1545cb7a01acSMauro Carvalho Chehab MODULE_LICENSE("GPL v2"); 1546