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
46db9edaafSBenjamin Marty #define ADV7182_REG_INPUT_RESERVED BIT(2)
47c5ef8f8cSLars-Peter Clausen
48ce5d6290SSteve Longerbeam #define ADV7180_REG_OUTPUT_CONTROL 0x0003
493999e5d0SLars-Peter Clausen #define ADV7180_REG_EXTENDED_OUTPUT_CONTROL 0x0004
50cb7a01acSMauro Carvalho Chehab #define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS 0xC5
51cb7a01acSMauro Carvalho Chehab
52ce5d6290SSteve Longerbeam #define ADV7180_REG_AUTODETECT_ENABLE 0x0007
53cb7a01acSMauro Carvalho Chehab #define ADV7180_AUTODETECT_DEFAULT 0x7f
54cb7a01acSMauro Carvalho Chehab /* Contrast */
553999e5d0SLars-Peter Clausen #define ADV7180_REG_CON 0x0008 /*Unsigned */
56cb7a01acSMauro Carvalho Chehab #define ADV7180_CON_MIN 0
57cb7a01acSMauro Carvalho Chehab #define ADV7180_CON_DEF 128
58cb7a01acSMauro Carvalho Chehab #define ADV7180_CON_MAX 255
59cb7a01acSMauro Carvalho Chehab /* Brightness*/
603999e5d0SLars-Peter Clausen #define ADV7180_REG_BRI 0x000a /*Signed */
61cb7a01acSMauro Carvalho Chehab #define ADV7180_BRI_MIN -128
62cb7a01acSMauro Carvalho Chehab #define ADV7180_BRI_DEF 0
63cb7a01acSMauro Carvalho Chehab #define ADV7180_BRI_MAX 127
64cb7a01acSMauro Carvalho Chehab /* Hue */
653999e5d0SLars-Peter Clausen #define ADV7180_REG_HUE 0x000b /*Signed, inverted */
66cb7a01acSMauro Carvalho Chehab #define ADV7180_HUE_MIN -127
67cb7a01acSMauro Carvalho Chehab #define ADV7180_HUE_DEF 0
68cb7a01acSMauro Carvalho Chehab #define ADV7180_HUE_MAX 128
69cb7a01acSMauro Carvalho Chehab
70a76c86f4SFabio Estevam #define ADV7180_REG_DEF_VALUE_Y 0x000c
71a76c86f4SFabio Estevam #define ADV7180_DEF_VAL_EN 0x1
72a76c86f4SFabio Estevam #define ADV7180_DEF_VAL_AUTO_EN 0x2
733999e5d0SLars-Peter Clausen #define ADV7180_REG_CTRL 0x000e
74029d6177SLars-Peter Clausen #define ADV7180_CTRL_IRQ_SPACE 0x20
75cb7a01acSMauro Carvalho Chehab
76029d6177SLars-Peter Clausen #define ADV7180_REG_PWR_MAN 0x0f
77cb7a01acSMauro Carvalho Chehab #define ADV7180_PWR_MAN_ON 0x04
78cb7a01acSMauro Carvalho Chehab #define ADV7180_PWR_MAN_OFF 0x24
79cb7a01acSMauro Carvalho Chehab #define ADV7180_PWR_MAN_RES 0x80
80cb7a01acSMauro Carvalho Chehab
813999e5d0SLars-Peter Clausen #define ADV7180_REG_STATUS1 0x0010
82cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_IN_LOCK 0x01
83cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_MASK 0x70
84cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_NTSM_M_J 0x00
85cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_NTSC_4_43 0x10
86cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_PAL_M 0x20
87cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_PAL_60 0x30
88cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_PAL_B_G 0x40
89cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_SECAM 0x50
90cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_PAL_COMB 0x60
91cb7a01acSMauro Carvalho Chehab #define ADV7180_STATUS1_AUTOD_SECAM_525 0x70
92cb7a01acSMauro Carvalho Chehab
933999e5d0SLars-Peter Clausen #define ADV7180_REG_IDENT 0x0011
94cb7a01acSMauro Carvalho Chehab #define ADV7180_ID_7180 0x18
95cb7a01acSMauro Carvalho Chehab
96ce5d6290SSteve Longerbeam #define ADV7180_REG_STATUS3 0x0013
97ce5d6290SSteve Longerbeam #define ADV7180_REG_ANALOG_CLAMP_CTL 0x0014
98ce5d6290SSteve Longerbeam #define ADV7180_REG_SHAP_FILTER_CTL_1 0x0017
99ce5d6290SSteve Longerbeam #define ADV7180_REG_CTRL_2 0x001d
100ce5d6290SSteve Longerbeam #define ADV7180_REG_VSYNC_FIELD_CTL_1 0x0031
101ed771d75SMatthew Michilot #define ADV7180_VSYNC_FIELD_CTL_1_NEWAV 0x12
102ce5d6290SSteve Longerbeam #define ADV7180_REG_MANUAL_WIN_CTL_1 0x003d
103ce5d6290SSteve Longerbeam #define ADV7180_REG_MANUAL_WIN_CTL_2 0x003e
104ce5d6290SSteve Longerbeam #define ADV7180_REG_MANUAL_WIN_CTL_3 0x003f
105ce5d6290SSteve Longerbeam #define ADV7180_REG_LOCK_CNT 0x0051
106ce5d6290SSteve Longerbeam #define ADV7180_REG_CVBS_TRIM 0x0052
107ce5d6290SSteve Longerbeam #define ADV7180_REG_CLAMP_ADJ 0x005a
108ce5d6290SSteve Longerbeam #define ADV7180_REG_RES_CIR 0x005f
109ce5d6290SSteve Longerbeam #define ADV7180_REG_DIFF_MODE 0x0060
110ce5d6290SSteve Longerbeam
11152e37f0aSSteve Longerbeam #define ADV7180_REG_ICONF1 0x2040
112cb7a01acSMauro Carvalho Chehab #define ADV7180_ICONF1_ACTIVE_LOW 0x01
113cb7a01acSMauro Carvalho Chehab #define ADV7180_ICONF1_PSYNC_ONLY 0x10
114cb7a01acSMauro Carvalho Chehab #define ADV7180_ICONF1_ACTIVE_TO_CLR 0xC0
115cb7a01acSMauro Carvalho Chehab /* Saturation */
1163999e5d0SLars-Peter Clausen #define ADV7180_REG_SD_SAT_CB 0x00e3 /*Unsigned */
1173999e5d0SLars-Peter Clausen #define ADV7180_REG_SD_SAT_CR 0x00e4 /*Unsigned */
118cb7a01acSMauro Carvalho Chehab #define ADV7180_SAT_MIN 0
119cb7a01acSMauro Carvalho Chehab #define ADV7180_SAT_DEF 128
120cb7a01acSMauro Carvalho Chehab #define ADV7180_SAT_MAX 255
121cb7a01acSMauro Carvalho Chehab
122cb7a01acSMauro Carvalho Chehab #define ADV7180_IRQ1_LOCK 0x01
123cb7a01acSMauro Carvalho Chehab #define ADV7180_IRQ1_UNLOCK 0x02
12452e37f0aSSteve Longerbeam #define ADV7180_REG_ISR1 0x2042
12552e37f0aSSteve Longerbeam #define ADV7180_REG_ICR1 0x2043
12652e37f0aSSteve Longerbeam #define ADV7180_REG_IMR1 0x2044
12752e37f0aSSteve Longerbeam #define ADV7180_REG_IMR2 0x2048
128cb7a01acSMauro Carvalho Chehab #define ADV7180_IRQ3_AD_CHANGE 0x08
12952e37f0aSSteve Longerbeam #define ADV7180_REG_ISR3 0x204A
13052e37f0aSSteve Longerbeam #define ADV7180_REG_ICR3 0x204B
13152e37f0aSSteve Longerbeam #define ADV7180_REG_IMR3 0x204C
13252e37f0aSSteve Longerbeam #define ADV7180_REG_IMR4 0x2050
133cb7a01acSMauro Carvalho Chehab
1343999e5d0SLars-Peter Clausen #define ADV7180_REG_NTSC_V_BIT_END 0x00E6
135cb7a01acSMauro Carvalho Chehab #define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND 0x4F
136cb7a01acSMauro Carvalho Chehab
137851a54efSLars-Peter Clausen #define ADV7180_REG_VPP_SLAVE_ADDR 0xFD
138b37135e3SLars-Peter Clausen #define ADV7180_REG_CSI_SLAVE_ADDR 0xFE
139b37135e3SLars-Peter Clausen
140ce5d6290SSteve Longerbeam #define ADV7180_REG_ACE_CTRL1 0x4080
141ce5d6290SSteve Longerbeam #define ADV7180_REG_ACE_CTRL5 0x4084
14208b717c2SLars-Peter Clausen #define ADV7180_REG_FLCONTROL 0x40e0
14308b717c2SLars-Peter Clausen #define ADV7180_FLCONTROL_FL_ENABLE 0x1
14408b717c2SLars-Peter Clausen
145ce5d6290SSteve Longerbeam #define ADV7180_REG_RST_CLAMP 0x809c
146ce5d6290SSteve Longerbeam #define ADV7180_REG_AGC_ADJ1 0x80b6
147ce5d6290SSteve Longerbeam #define ADV7180_REG_AGC_ADJ2 0x80c0
148ce5d6290SSteve Longerbeam
149b37135e3SLars-Peter Clausen #define ADV7180_CSI_REG_PWRDN 0x00
150b37135e3SLars-Peter Clausen #define ADV7180_CSI_PWRDN 0x80
151b37135e3SLars-Peter Clausen
152f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN1 0x00
153f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN2 0x01
154f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN3 0x02
155f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN4 0x03
156f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN5 0x04
157f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_CVBS_AIN6 0x05
158f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_SVIDEO_AIN1_AIN2 0x06
159f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_SVIDEO_AIN3_AIN4 0x07
160f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_SVIDEO_AIN5_AIN6 0x08
161f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_YPRPB_AIN1_AIN2_AIN3 0x09
162f5dde49bSLars-Peter Clausen #define ADV7180_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0a
163f5dde49bSLars-Peter Clausen
164c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN1 0x00
165c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN2 0x01
166c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN3 0x02
167c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN4 0x03
168c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN5 0x04
169c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN6 0x05
170c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN7 0x06
171c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_CVBS_AIN8 0x07
172c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_SVIDEO_AIN1_AIN2 0x08
173c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_SVIDEO_AIN3_AIN4 0x09
174c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_SVIDEO_AIN5_AIN6 0x0a
175c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_SVIDEO_AIN7_AIN8 0x0b
176c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3 0x0c
177c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0d
178c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2 0x0e
179c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4 0x0f
180c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6 0x10
181c5ef8f8cSLars-Peter Clausen #define ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8 0x11
182c5ef8f8cSLars-Peter Clausen
183b37135e3SLars-Peter Clausen #define ADV7180_DEFAULT_CSI_I2C_ADDR 0x44
184851a54efSLars-Peter Clausen #define ADV7180_DEFAULT_VPP_I2C_ADDR 0x42
185b37135e3SLars-Peter Clausen
18608b717c2SLars-Peter Clausen #define V4L2_CID_ADV_FAST_SWITCH (V4L2_CID_USER_ADV7180_BASE + 0x00)
18708b717c2SLars-Peter Clausen
1889483a3f8STim Harvey /* Initial number of frames to skip to avoid possible garbage */
1899483a3f8STim Harvey #define ADV7180_NUM_OF_SKIP_FRAMES 2
1909483a3f8STim Harvey
191f5dde49bSLars-Peter Clausen struct adv7180_state;
192f5dde49bSLars-Peter Clausen
193f5dde49bSLars-Peter Clausen #define ADV7180_FLAG_RESET_POWERED BIT(0)
194bf7dcb80SLars-Peter Clausen #define ADV7180_FLAG_V2 BIT(1)
195b37135e3SLars-Peter Clausen #define ADV7180_FLAG_MIPI_CSI2 BIT(2)
196851a54efSLars-Peter Clausen #define ADV7180_FLAG_I2P BIT(3)
197f5dde49bSLars-Peter Clausen
198f5dde49bSLars-Peter Clausen struct adv7180_chip_info {
199f5dde49bSLars-Peter Clausen unsigned int flags;
200f5dde49bSLars-Peter Clausen unsigned int valid_input_mask;
201f5dde49bSLars-Peter Clausen int (*set_std)(struct adv7180_state *st, unsigned int std);
202f5dde49bSLars-Peter Clausen int (*select_input)(struct adv7180_state *st, unsigned int input);
203f5dde49bSLars-Peter Clausen int (*init)(struct adv7180_state *state);
204f5dde49bSLars-Peter Clausen };
205f5dde49bSLars-Peter Clausen
206cb7a01acSMauro Carvalho Chehab struct adv7180_state {
207cb7a01acSMauro Carvalho Chehab struct v4l2_ctrl_handler ctrl_hdl;
208cb7a01acSMauro Carvalho Chehab struct v4l2_subdev sd;
209d5d51a82SLars-Peter Clausen struct media_pad pad;
210cb7a01acSMauro Carvalho Chehab struct mutex mutex; /* mutual excl. when accessing chip */
211cb7a01acSMauro Carvalho Chehab int irq;
21265d9e14aSSteve Longerbeam struct gpio_desc *pwdn_gpio;
213abb7c7c2SFrieder Schrempf struct gpio_desc *rst_gpio;
214cb7a01acSMauro Carvalho Chehab v4l2_std_id curr_norm;
215e246c333SLars-Peter Clausen bool powered;
216937feeedSHans Verkuil bool streaming;
217cb7a01acSMauro Carvalho Chehab u8 input;
2183999e5d0SLars-Peter Clausen
2193999e5d0SLars-Peter Clausen struct i2c_client *client;
2203999e5d0SLars-Peter Clausen unsigned int register_page;
221b37135e3SLars-Peter Clausen struct i2c_client *csi_client;
222851a54efSLars-Peter Clausen struct i2c_client *vpp_client;
223f5dde49bSLars-Peter Clausen const struct adv7180_chip_info *chip_info;
224851a54efSLars-Peter Clausen enum v4l2_field field;
225ed771d75SMatthew Michilot bool force_bt656_4;
226cb7a01acSMauro Carvalho Chehab };
227cb7a01acSMauro Carvalho Chehab #define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler, \
228cb7a01acSMauro Carvalho Chehab struct adv7180_state, \
229cb7a01acSMauro Carvalho Chehab ctrl_hdl)->sd)
230cb7a01acSMauro Carvalho Chehab
adv7180_select_page(struct adv7180_state * state,unsigned int page)2313999e5d0SLars-Peter Clausen static int adv7180_select_page(struct adv7180_state *state, unsigned int page)
2323999e5d0SLars-Peter Clausen {
2333999e5d0SLars-Peter Clausen if (state->register_page != page) {
2343999e5d0SLars-Peter Clausen i2c_smbus_write_byte_data(state->client, ADV7180_REG_CTRL,
2353999e5d0SLars-Peter Clausen page);
2363999e5d0SLars-Peter Clausen state->register_page = page;
2373999e5d0SLars-Peter Clausen }
2383999e5d0SLars-Peter Clausen
2393999e5d0SLars-Peter Clausen return 0;
2403999e5d0SLars-Peter Clausen }
2413999e5d0SLars-Peter Clausen
adv7180_write(struct adv7180_state * state,unsigned int reg,unsigned int value)2423999e5d0SLars-Peter Clausen static int adv7180_write(struct adv7180_state *state, unsigned int reg,
2433999e5d0SLars-Peter Clausen unsigned int value)
2443999e5d0SLars-Peter Clausen {
2453999e5d0SLars-Peter Clausen lockdep_assert_held(&state->mutex);
2463999e5d0SLars-Peter Clausen adv7180_select_page(state, reg >> 8);
2473999e5d0SLars-Peter Clausen return i2c_smbus_write_byte_data(state->client, reg & 0xff, value);
2483999e5d0SLars-Peter Clausen }
2493999e5d0SLars-Peter Clausen
adv7180_read(struct adv7180_state * state,unsigned int reg)2503999e5d0SLars-Peter Clausen static int adv7180_read(struct adv7180_state *state, unsigned int reg)
2513999e5d0SLars-Peter Clausen {
2523999e5d0SLars-Peter Clausen lockdep_assert_held(&state->mutex);
2533999e5d0SLars-Peter Clausen adv7180_select_page(state, reg >> 8);
2543999e5d0SLars-Peter Clausen return i2c_smbus_read_byte_data(state->client, reg & 0xff);
2553999e5d0SLars-Peter Clausen }
2563999e5d0SLars-Peter Clausen
adv7180_csi_write(struct adv7180_state * state,unsigned int reg,unsigned int value)257b37135e3SLars-Peter Clausen static int adv7180_csi_write(struct adv7180_state *state, unsigned int reg,
258b37135e3SLars-Peter Clausen unsigned int value)
259b37135e3SLars-Peter Clausen {
260b37135e3SLars-Peter Clausen return i2c_smbus_write_byte_data(state->csi_client, reg, value);
261b37135e3SLars-Peter Clausen }
262b37135e3SLars-Peter Clausen
adv7180_set_video_standard(struct adv7180_state * state,unsigned int std)263f5dde49bSLars-Peter Clausen static int adv7180_set_video_standard(struct adv7180_state *state,
264f5dde49bSLars-Peter Clausen unsigned int std)
265f5dde49bSLars-Peter Clausen {
266f5dde49bSLars-Peter Clausen return state->chip_info->set_std(state, std);
267f5dde49bSLars-Peter Clausen }
2683999e5d0SLars-Peter Clausen
adv7180_vpp_write(struct adv7180_state * state,unsigned int reg,unsigned int value)269851a54efSLars-Peter Clausen static int adv7180_vpp_write(struct adv7180_state *state, unsigned int reg,
270851a54efSLars-Peter Clausen unsigned int value)
271851a54efSLars-Peter Clausen {
272851a54efSLars-Peter Clausen return i2c_smbus_write_byte_data(state->vpp_client, reg, value);
273851a54efSLars-Peter Clausen }
274851a54efSLars-Peter Clausen
adv7180_std_to_v4l2(u8 status1)275cb7a01acSMauro Carvalho Chehab static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
276cb7a01acSMauro Carvalho Chehab {
277b294a192SVladimir Barinov /* in case V4L2_IN_ST_NO_SIGNAL */
278b294a192SVladimir Barinov if (!(status1 & ADV7180_STATUS1_IN_LOCK))
279b294a192SVladimir Barinov return V4L2_STD_UNKNOWN;
280b294a192SVladimir Barinov
281cb7a01acSMauro Carvalho Chehab switch (status1 & ADV7180_STATUS1_AUTOD_MASK) {
282cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_NTSM_M_J:
283cb7a01acSMauro Carvalho Chehab return V4L2_STD_NTSC;
284cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_NTSC_4_43:
285cb7a01acSMauro Carvalho Chehab return V4L2_STD_NTSC_443;
286cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_PAL_M:
287cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL_M;
288cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_PAL_60:
289cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL_60;
290cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_PAL_B_G:
291cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL;
292cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_SECAM:
293cb7a01acSMauro Carvalho Chehab return V4L2_STD_SECAM;
294cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_PAL_COMB:
295cb7a01acSMauro Carvalho Chehab return V4L2_STD_PAL_Nc | V4L2_STD_PAL_N;
296cb7a01acSMauro Carvalho Chehab case ADV7180_STATUS1_AUTOD_SECAM_525:
297cb7a01acSMauro Carvalho Chehab return V4L2_STD_SECAM;
298cb7a01acSMauro Carvalho Chehab default:
299cb7a01acSMauro Carvalho Chehab return V4L2_STD_UNKNOWN;
300cb7a01acSMauro Carvalho Chehab }
301cb7a01acSMauro Carvalho Chehab }
302cb7a01acSMauro Carvalho Chehab
v4l2_std_to_adv7180(v4l2_std_id std)303cb7a01acSMauro Carvalho Chehab static int v4l2_std_to_adv7180(v4l2_std_id std)
304cb7a01acSMauro Carvalho Chehab {
305cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_PAL_60)
306f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL60;
307cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_NTSC_443)
308f5dde49bSLars-Peter Clausen return ADV7180_STD_NTSC_443;
309cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_PAL_N)
310f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL_N;
311cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_PAL_M)
312f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL_M;
313cb7a01acSMauro Carvalho Chehab if (std == V4L2_STD_PAL_Nc)
314f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL_COMB_N;
315cb7a01acSMauro Carvalho Chehab
316cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_PAL)
317f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL_BG;
318cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_NTSC)
319f5dde49bSLars-Peter Clausen return ADV7180_STD_NTSC_M;
320cb7a01acSMauro Carvalho Chehab if (std & V4L2_STD_SECAM)
321f5dde49bSLars-Peter Clausen return ADV7180_STD_PAL_SECAM;
322cb7a01acSMauro Carvalho Chehab
323cb7a01acSMauro Carvalho Chehab return -EINVAL;
324cb7a01acSMauro Carvalho Chehab }
325cb7a01acSMauro Carvalho Chehab
adv7180_status_to_v4l2(u8 status1)326cb7a01acSMauro Carvalho Chehab static u32 adv7180_status_to_v4l2(u8 status1)
327cb7a01acSMauro Carvalho Chehab {
328cb7a01acSMauro Carvalho Chehab if (!(status1 & ADV7180_STATUS1_IN_LOCK))
329cb7a01acSMauro Carvalho Chehab return V4L2_IN_ST_NO_SIGNAL;
330cb7a01acSMauro Carvalho Chehab
331cb7a01acSMauro Carvalho Chehab return 0;
332cb7a01acSMauro Carvalho Chehab }
333cb7a01acSMauro Carvalho Chehab
__adv7180_status(struct adv7180_state * state,u32 * status,v4l2_std_id * std)3343999e5d0SLars-Peter Clausen static int __adv7180_status(struct adv7180_state *state, u32 *status,
335cb7a01acSMauro Carvalho Chehab v4l2_std_id *std)
336cb7a01acSMauro Carvalho Chehab {
3373999e5d0SLars-Peter Clausen int status1 = adv7180_read(state, ADV7180_REG_STATUS1);
338cb7a01acSMauro Carvalho Chehab
339cb7a01acSMauro Carvalho Chehab if (status1 < 0)
340cb7a01acSMauro Carvalho Chehab return status1;
341cb7a01acSMauro Carvalho Chehab
342cb7a01acSMauro Carvalho Chehab if (status)
343cb7a01acSMauro Carvalho Chehab *status = adv7180_status_to_v4l2(status1);
344cb7a01acSMauro Carvalho Chehab if (std)
345cb7a01acSMauro Carvalho Chehab *std = adv7180_std_to_v4l2(status1);
346cb7a01acSMauro Carvalho Chehab
347cb7a01acSMauro Carvalho Chehab return 0;
348cb7a01acSMauro Carvalho Chehab }
349cb7a01acSMauro Carvalho Chehab
to_state(struct v4l2_subdev * sd)350cb7a01acSMauro Carvalho Chehab static inline struct adv7180_state *to_state(struct v4l2_subdev *sd)
351cb7a01acSMauro Carvalho Chehab {
352cb7a01acSMauro Carvalho Chehab return container_of(sd, struct adv7180_state, sd);
353cb7a01acSMauro Carvalho Chehab }
354cb7a01acSMauro Carvalho Chehab
adv7180_querystd(struct v4l2_subdev * sd,v4l2_std_id * std)355cb7a01acSMauro Carvalho Chehab static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
356cb7a01acSMauro Carvalho Chehab {
357cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd);
358cb7a01acSMauro Carvalho Chehab int err = mutex_lock_interruptible(&state->mutex);
359cb7a01acSMauro Carvalho Chehab if (err)
360cb7a01acSMauro Carvalho Chehab return err;
361cb7a01acSMauro Carvalho Chehab
362937feeedSHans Verkuil if (state->streaming) {
363937feeedSHans Verkuil err = -EBUSY;
364937feeedSHans Verkuil goto unlock;
365937feeedSHans Verkuil }
366cb7a01acSMauro Carvalho Chehab
367937feeedSHans Verkuil err = adv7180_set_video_standard(state,
368937feeedSHans Verkuil ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM);
369937feeedSHans Verkuil if (err)
370937feeedSHans Verkuil goto unlock;
371937feeedSHans Verkuil
372937feeedSHans Verkuil msleep(100);
373937feeedSHans Verkuil __adv7180_status(state, NULL, std);
374937feeedSHans Verkuil
375937feeedSHans Verkuil err = v4l2_std_to_adv7180(state->curr_norm);
376937feeedSHans Verkuil if (err < 0)
377937feeedSHans Verkuil goto unlock;
378937feeedSHans Verkuil
379937feeedSHans Verkuil err = adv7180_set_video_standard(state, err);
380937feeedSHans Verkuil
381937feeedSHans Verkuil unlock:
382cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex);
383cb7a01acSMauro Carvalho Chehab return err;
384cb7a01acSMauro Carvalho Chehab }
385cb7a01acSMauro Carvalho Chehab
adv7180_s_routing(struct v4l2_subdev * sd,u32 input,u32 output,u32 config)386cb7a01acSMauro Carvalho Chehab static int adv7180_s_routing(struct v4l2_subdev *sd, u32 input,
387cb7a01acSMauro Carvalho Chehab u32 output, u32 config)
388cb7a01acSMauro Carvalho Chehab {
389cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd);
390cb7a01acSMauro Carvalho Chehab int ret = mutex_lock_interruptible(&state->mutex);
391cb7a01acSMauro Carvalho Chehab
392cb7a01acSMauro Carvalho Chehab if (ret)
393cb7a01acSMauro Carvalho Chehab return ret;
394cb7a01acSMauro Carvalho Chehab
395f5dde49bSLars-Peter Clausen if (input > 31 || !(BIT(input) & state->chip_info->valid_input_mask)) {
396f5dde49bSLars-Peter Clausen ret = -EINVAL;
397cb7a01acSMauro Carvalho Chehab goto out;
398f5dde49bSLars-Peter Clausen }
399cb7a01acSMauro Carvalho Chehab
400f5dde49bSLars-Peter Clausen ret = state->chip_info->select_input(state, input);
401cb7a01acSMauro Carvalho Chehab
402f5dde49bSLars-Peter Clausen if (ret == 0)
403cb7a01acSMauro Carvalho Chehab state->input = input;
404cb7a01acSMauro Carvalho Chehab out:
405cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex);
406cb7a01acSMauro Carvalho Chehab return ret;
407cb7a01acSMauro Carvalho Chehab }
408cb7a01acSMauro Carvalho Chehab
adv7180_g_input_status(struct v4l2_subdev * sd,u32 * status)409cb7a01acSMauro Carvalho Chehab static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status)
410cb7a01acSMauro Carvalho Chehab {
411cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd);
412cb7a01acSMauro Carvalho Chehab int ret = mutex_lock_interruptible(&state->mutex);
413cb7a01acSMauro Carvalho Chehab if (ret)
414cb7a01acSMauro Carvalho Chehab return ret;
415cb7a01acSMauro Carvalho Chehab
4163999e5d0SLars-Peter Clausen ret = __adv7180_status(state, status, NULL);
417cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex);
418cb7a01acSMauro Carvalho Chehab return ret;
419cb7a01acSMauro Carvalho Chehab }
420cb7a01acSMauro Carvalho Chehab
adv7180_program_std(struct adv7180_state * state)4213e35e33cSLars-Peter Clausen static int adv7180_program_std(struct adv7180_state *state)
4223e35e33cSLars-Peter Clausen {
4233e35e33cSLars-Peter Clausen int ret;
4243e35e33cSLars-Peter Clausen
4253e35e33cSLars-Peter Clausen ret = v4l2_std_to_adv7180(state->curr_norm);
4263e35e33cSLars-Peter Clausen if (ret < 0)
4273e35e33cSLars-Peter Clausen return ret;
4283e35e33cSLars-Peter Clausen
429f5dde49bSLars-Peter Clausen ret = adv7180_set_video_standard(state, ret);
4303e35e33cSLars-Peter Clausen if (ret < 0)
4313e35e33cSLars-Peter Clausen return ret;
4323e35e33cSLars-Peter Clausen return 0;
4333e35e33cSLars-Peter Clausen }
4343e35e33cSLars-Peter Clausen
adv7180_s_std(struct v4l2_subdev * sd,v4l2_std_id std)435cb7a01acSMauro Carvalho Chehab static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
436cb7a01acSMauro Carvalho Chehab {
437cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd);
438cb7a01acSMauro Carvalho Chehab int ret = mutex_lock_interruptible(&state->mutex);
4393e35e33cSLars-Peter Clausen
440cb7a01acSMauro Carvalho Chehab if (ret)
441cb7a01acSMauro Carvalho Chehab return ret;
442cb7a01acSMauro Carvalho Chehab
4433e35e33cSLars-Peter Clausen /* Make sure we can support this std */
444cb7a01acSMauro Carvalho Chehab ret = v4l2_std_to_adv7180(std);
445cb7a01acSMauro Carvalho Chehab if (ret < 0)
446cb7a01acSMauro Carvalho Chehab goto out;
447cb7a01acSMauro Carvalho Chehab
448cb7a01acSMauro Carvalho Chehab state->curr_norm = std;
4493e35e33cSLars-Peter Clausen
4503e35e33cSLars-Peter Clausen ret = adv7180_program_std(state);
451cb7a01acSMauro Carvalho Chehab out:
452cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex);
453cb7a01acSMauro Carvalho Chehab return ret;
454cb7a01acSMauro Carvalho Chehab }
455cb7a01acSMauro Carvalho Chehab
adv7180_g_std(struct v4l2_subdev * sd,v4l2_std_id * norm)456d0fadc86SNiklas Söderlund static int adv7180_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm)
457d0fadc86SNiklas Söderlund {
458d0fadc86SNiklas Söderlund struct adv7180_state *state = to_state(sd);
459d0fadc86SNiklas Söderlund
460d0fadc86SNiklas Söderlund *norm = state->curr_norm;
461d0fadc86SNiklas Söderlund
462d0fadc86SNiklas Söderlund return 0;
463d0fadc86SNiklas Söderlund }
464d0fadc86SNiklas Söderlund
adv7180_g_frame_interval(struct v4l2_subdev * sd,struct v4l2_subdev_frame_interval * fi)46538566d28SNiklas Söderlund static int adv7180_g_frame_interval(struct v4l2_subdev *sd,
46638566d28SNiklas Söderlund struct v4l2_subdev_frame_interval *fi)
46738566d28SNiklas Söderlund {
46838566d28SNiklas Söderlund struct adv7180_state *state = to_state(sd);
46938566d28SNiklas Söderlund
47038566d28SNiklas Söderlund if (state->curr_norm & V4L2_STD_525_60) {
47138566d28SNiklas Söderlund fi->interval.numerator = 1001;
47238566d28SNiklas Söderlund fi->interval.denominator = 30000;
47338566d28SNiklas Söderlund } else {
47438566d28SNiklas Söderlund fi->interval.numerator = 1;
47538566d28SNiklas Söderlund fi->interval.denominator = 25;
47638566d28SNiklas Söderlund }
47738566d28SNiklas Söderlund
47838566d28SNiklas Söderlund return 0;
47938566d28SNiklas Söderlund }
48038566d28SNiklas Söderlund
adv7180_set_power_pin(struct adv7180_state * state,bool on)48165d9e14aSSteve Longerbeam static void adv7180_set_power_pin(struct adv7180_state *state, bool on)
48265d9e14aSSteve Longerbeam {
48365d9e14aSSteve Longerbeam if (!state->pwdn_gpio)
48465d9e14aSSteve Longerbeam return;
48565d9e14aSSteve Longerbeam
48665d9e14aSSteve Longerbeam if (on) {
48765d9e14aSSteve Longerbeam gpiod_set_value_cansleep(state->pwdn_gpio, 0);
48865d9e14aSSteve Longerbeam usleep_range(5000, 10000);
48965d9e14aSSteve Longerbeam } else {
49065d9e14aSSteve Longerbeam gpiod_set_value_cansleep(state->pwdn_gpio, 1);
49165d9e14aSSteve Longerbeam }
49265d9e14aSSteve Longerbeam }
49365d9e14aSSteve Longerbeam
adv7180_set_reset_pin(struct adv7180_state * state,bool on)494abb7c7c2SFrieder Schrempf static void adv7180_set_reset_pin(struct adv7180_state *state, bool on)
495abb7c7c2SFrieder Schrempf {
496abb7c7c2SFrieder Schrempf if (!state->rst_gpio)
497abb7c7c2SFrieder Schrempf return;
498abb7c7c2SFrieder Schrempf
499abb7c7c2SFrieder Schrempf if (on) {
500abb7c7c2SFrieder Schrempf gpiod_set_value_cansleep(state->rst_gpio, 1);
501abb7c7c2SFrieder Schrempf } else {
502abb7c7c2SFrieder Schrempf gpiod_set_value_cansleep(state->rst_gpio, 0);
503abb7c7c2SFrieder Schrempf usleep_range(5000, 10000);
504abb7c7c2SFrieder Schrempf }
505abb7c7c2SFrieder Schrempf }
506abb7c7c2SFrieder Schrempf
adv7180_set_power(struct adv7180_state * state,bool on)5073999e5d0SLars-Peter Clausen static int adv7180_set_power(struct adv7180_state *state, bool on)
508e246c333SLars-Peter Clausen {
509e246c333SLars-Peter Clausen u8 val;
510b37135e3SLars-Peter Clausen int ret;
511e246c333SLars-Peter Clausen
512e246c333SLars-Peter Clausen if (on)
513e246c333SLars-Peter Clausen val = ADV7180_PWR_MAN_ON;
514e246c333SLars-Peter Clausen else
515e246c333SLars-Peter Clausen val = ADV7180_PWR_MAN_OFF;
516e246c333SLars-Peter Clausen
517b37135e3SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_PWR_MAN, val);
518b37135e3SLars-Peter Clausen if (ret)
519b37135e3SLars-Peter Clausen return ret;
520b37135e3SLars-Peter Clausen
521b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
522b37135e3SLars-Peter Clausen if (on) {
523b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0xDE, 0x02);
524b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0xD2, 0xF7);
525b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0xD8, 0x65);
526b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0xE0, 0x09);
527b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0x2C, 0x00);
528851a54efSLars-Peter Clausen if (state->field == V4L2_FIELD_NONE)
529851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x1D, 0x80);
530b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0x00, 0x00);
531b37135e3SLars-Peter Clausen } else {
532b37135e3SLars-Peter Clausen adv7180_csi_write(state, 0x00, 0x80);
533b37135e3SLars-Peter Clausen }
534b37135e3SLars-Peter Clausen }
535b37135e3SLars-Peter Clausen
536b37135e3SLars-Peter Clausen return 0;
537e246c333SLars-Peter Clausen }
538e246c333SLars-Peter Clausen
adv7180_s_power(struct v4l2_subdev * sd,int on)539e246c333SLars-Peter Clausen static int adv7180_s_power(struct v4l2_subdev *sd, int on)
540e246c333SLars-Peter Clausen {
541e246c333SLars-Peter Clausen struct adv7180_state *state = to_state(sd);
542e246c333SLars-Peter Clausen int ret;
543e246c333SLars-Peter Clausen
544e246c333SLars-Peter Clausen ret = mutex_lock_interruptible(&state->mutex);
545e246c333SLars-Peter Clausen if (ret)
546e246c333SLars-Peter Clausen return ret;
547e246c333SLars-Peter Clausen
5483999e5d0SLars-Peter Clausen ret = adv7180_set_power(state, on);
549e246c333SLars-Peter Clausen if (ret == 0)
550e246c333SLars-Peter Clausen state->powered = on;
551e246c333SLars-Peter Clausen
552e246c333SLars-Peter Clausen mutex_unlock(&state->mutex);
553e246c333SLars-Peter Clausen return ret;
554e246c333SLars-Peter Clausen }
555e246c333SLars-Peter Clausen
556a76c86f4SFabio Estevam static const char * const test_pattern_menu[] = {
557a76c86f4SFabio Estevam "Single color",
558a76c86f4SFabio Estevam "Color bars",
559a76c86f4SFabio Estevam "Luma ramp",
560a76c86f4SFabio Estevam "Boundary box",
561a76c86f4SFabio Estevam "Disable",
562a76c86f4SFabio Estevam };
563a76c86f4SFabio Estevam
adv7180_test_pattern(struct adv7180_state * state,int value)564a76c86f4SFabio Estevam static int adv7180_test_pattern(struct adv7180_state *state, int value)
565a76c86f4SFabio Estevam {
566a76c86f4SFabio Estevam unsigned int reg = 0;
567a76c86f4SFabio Estevam
568a76c86f4SFabio Estevam /* Map menu value into register value */
569a76c86f4SFabio Estevam if (value < 3)
570a76c86f4SFabio Estevam reg = value;
571a76c86f4SFabio Estevam if (value == 3)
572a76c86f4SFabio Estevam reg = 5;
573a76c86f4SFabio Estevam
574a76c86f4SFabio Estevam adv7180_write(state, ADV7180_REG_ANALOG_CLAMP_CTL, reg);
575a76c86f4SFabio Estevam
576a76c86f4SFabio Estevam if (value == ARRAY_SIZE(test_pattern_menu) - 1) {
577a76c86f4SFabio Estevam reg = adv7180_read(state, ADV7180_REG_DEF_VALUE_Y);
578a76c86f4SFabio Estevam reg &= ~ADV7180_DEF_VAL_EN;
579a76c86f4SFabio Estevam adv7180_write(state, ADV7180_REG_DEF_VALUE_Y, reg);
580a76c86f4SFabio Estevam return 0;
581a76c86f4SFabio Estevam }
582a76c86f4SFabio Estevam
583a76c86f4SFabio Estevam reg = adv7180_read(state, ADV7180_REG_DEF_VALUE_Y);
584a76c86f4SFabio Estevam reg |= ADV7180_DEF_VAL_EN | ADV7180_DEF_VAL_AUTO_EN;
585a76c86f4SFabio Estevam adv7180_write(state, ADV7180_REG_DEF_VALUE_Y, reg);
586a76c86f4SFabio Estevam
587a76c86f4SFabio Estevam return 0;
588a76c86f4SFabio Estevam }
589a76c86f4SFabio Estevam
adv7180_s_ctrl(struct v4l2_ctrl * ctrl)590cb7a01acSMauro Carvalho Chehab static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
591cb7a01acSMauro Carvalho Chehab {
592cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = to_adv7180_sd(ctrl);
593cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd);
594cb7a01acSMauro Carvalho Chehab int ret = mutex_lock_interruptible(&state->mutex);
595cb7a01acSMauro Carvalho Chehab int val;
596cb7a01acSMauro Carvalho Chehab
597cb7a01acSMauro Carvalho Chehab if (ret)
598cb7a01acSMauro Carvalho Chehab return ret;
599cb7a01acSMauro Carvalho Chehab val = ctrl->val;
600cb7a01acSMauro Carvalho Chehab switch (ctrl->id) {
601cb7a01acSMauro Carvalho Chehab case V4L2_CID_BRIGHTNESS:
6023999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_BRI, val);
603cb7a01acSMauro Carvalho Chehab break;
604cb7a01acSMauro Carvalho Chehab case V4L2_CID_HUE:
605cb7a01acSMauro Carvalho Chehab /*Hue is inverted according to HSL chart */
6063999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_HUE, -val);
607cb7a01acSMauro Carvalho Chehab break;
608cb7a01acSMauro Carvalho Chehab case V4L2_CID_CONTRAST:
6093999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_CON, val);
610cb7a01acSMauro Carvalho Chehab break;
611cb7a01acSMauro Carvalho Chehab case V4L2_CID_SATURATION:
612cb7a01acSMauro Carvalho Chehab /*
613cb7a01acSMauro Carvalho Chehab *This could be V4L2_CID_BLUE_BALANCE/V4L2_CID_RED_BALANCE
614cb7a01acSMauro Carvalho Chehab *Let's not confuse the user, everybody understands saturation
615cb7a01acSMauro Carvalho Chehab */
6163999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_SD_SAT_CB, val);
617cb7a01acSMauro Carvalho Chehab if (ret < 0)
618cb7a01acSMauro Carvalho Chehab break;
6193999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_SD_SAT_CR, val);
620cb7a01acSMauro Carvalho Chehab break;
62108b717c2SLars-Peter Clausen case V4L2_CID_ADV_FAST_SWITCH:
62208b717c2SLars-Peter Clausen if (ctrl->val) {
62308b717c2SLars-Peter Clausen /* ADI required write */
62408b717c2SLars-Peter Clausen adv7180_write(state, 0x80d9, 0x44);
62508b717c2SLars-Peter Clausen adv7180_write(state, ADV7180_REG_FLCONTROL,
62608b717c2SLars-Peter Clausen ADV7180_FLCONTROL_FL_ENABLE);
62708b717c2SLars-Peter Clausen } else {
62808b717c2SLars-Peter Clausen /* ADI required write */
62908b717c2SLars-Peter Clausen adv7180_write(state, 0x80d9, 0xc4);
63008b717c2SLars-Peter Clausen adv7180_write(state, ADV7180_REG_FLCONTROL, 0x00);
63108b717c2SLars-Peter Clausen }
63208b717c2SLars-Peter Clausen break;
633a76c86f4SFabio Estevam case V4L2_CID_TEST_PATTERN:
634a76c86f4SFabio Estevam ret = adv7180_test_pattern(state, val);
635a76c86f4SFabio Estevam break;
636cb7a01acSMauro Carvalho Chehab default:
637cb7a01acSMauro Carvalho Chehab ret = -EINVAL;
638cb7a01acSMauro Carvalho Chehab }
639cb7a01acSMauro Carvalho Chehab
640cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex);
641cb7a01acSMauro Carvalho Chehab return ret;
642cb7a01acSMauro Carvalho Chehab }
643cb7a01acSMauro Carvalho Chehab
644cb7a01acSMauro Carvalho Chehab static const struct v4l2_ctrl_ops adv7180_ctrl_ops = {
645cb7a01acSMauro Carvalho Chehab .s_ctrl = adv7180_s_ctrl,
646cb7a01acSMauro Carvalho Chehab };
647cb7a01acSMauro Carvalho Chehab
64808b717c2SLars-Peter Clausen static const struct v4l2_ctrl_config adv7180_ctrl_fast_switch = {
64908b717c2SLars-Peter Clausen .ops = &adv7180_ctrl_ops,
65008b717c2SLars-Peter Clausen .id = V4L2_CID_ADV_FAST_SWITCH,
65108b717c2SLars-Peter Clausen .name = "Fast Switching",
65208b717c2SLars-Peter Clausen .type = V4L2_CTRL_TYPE_BOOLEAN,
65308b717c2SLars-Peter Clausen .min = 0,
65408b717c2SLars-Peter Clausen .max = 1,
65508b717c2SLars-Peter Clausen .step = 1,
65608b717c2SLars-Peter Clausen };
65708b717c2SLars-Peter Clausen
adv7180_init_controls(struct adv7180_state * state)658cb7a01acSMauro Carvalho Chehab static int adv7180_init_controls(struct adv7180_state *state)
659cb7a01acSMauro Carvalho Chehab {
660cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_init(&state->ctrl_hdl, 4);
661cb7a01acSMauro Carvalho Chehab
662cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
663cb7a01acSMauro Carvalho Chehab V4L2_CID_BRIGHTNESS, ADV7180_BRI_MIN,
664cb7a01acSMauro Carvalho Chehab ADV7180_BRI_MAX, 1, ADV7180_BRI_DEF);
665cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
666cb7a01acSMauro Carvalho Chehab V4L2_CID_CONTRAST, ADV7180_CON_MIN,
667cb7a01acSMauro Carvalho Chehab ADV7180_CON_MAX, 1, ADV7180_CON_DEF);
668cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
669cb7a01acSMauro Carvalho Chehab V4L2_CID_SATURATION, ADV7180_SAT_MIN,
670cb7a01acSMauro Carvalho Chehab ADV7180_SAT_MAX, 1, ADV7180_SAT_DEF);
671cb7a01acSMauro Carvalho Chehab v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
672cb7a01acSMauro Carvalho Chehab V4L2_CID_HUE, ADV7180_HUE_MIN,
673cb7a01acSMauro Carvalho Chehab ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF);
67408b717c2SLars-Peter Clausen v4l2_ctrl_new_custom(&state->ctrl_hdl, &adv7180_ctrl_fast_switch, NULL);
67508b717c2SLars-Peter Clausen
676a76c86f4SFabio Estevam v4l2_ctrl_new_std_menu_items(&state->ctrl_hdl, &adv7180_ctrl_ops,
677a76c86f4SFabio Estevam V4L2_CID_TEST_PATTERN,
678a76c86f4SFabio Estevam ARRAY_SIZE(test_pattern_menu) - 1,
679a76c86f4SFabio Estevam 0, ARRAY_SIZE(test_pattern_menu) - 1,
680a76c86f4SFabio Estevam test_pattern_menu);
681a76c86f4SFabio Estevam
682cb7a01acSMauro Carvalho Chehab state->sd.ctrl_handler = &state->ctrl_hdl;
683cb7a01acSMauro Carvalho Chehab if (state->ctrl_hdl.error) {
684cb7a01acSMauro Carvalho Chehab int err = state->ctrl_hdl.error;
685cb7a01acSMauro Carvalho Chehab
686cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_free(&state->ctrl_hdl);
687cb7a01acSMauro Carvalho Chehab return err;
688cb7a01acSMauro Carvalho Chehab }
689cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_setup(&state->ctrl_hdl);
690cb7a01acSMauro Carvalho Chehab
691cb7a01acSMauro Carvalho Chehab return 0;
692cb7a01acSMauro Carvalho Chehab }
adv7180_exit_controls(struct adv7180_state * state)693cb7a01acSMauro Carvalho Chehab static void adv7180_exit_controls(struct adv7180_state *state)
694cb7a01acSMauro Carvalho Chehab {
695cb7a01acSMauro Carvalho Chehab v4l2_ctrl_handler_free(&state->ctrl_hdl);
696cb7a01acSMauro Carvalho Chehab }
697cb7a01acSMauro Carvalho Chehab
adv7180_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)698d5d51a82SLars-Peter Clausen static int adv7180_enum_mbus_code(struct v4l2_subdev *sd,
6990d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
700d5d51a82SLars-Peter Clausen struct v4l2_subdev_mbus_code_enum *code)
701cccb83f7SVladimir Barinov {
702d5d51a82SLars-Peter Clausen if (code->index != 0)
703cccb83f7SVladimir Barinov return -EINVAL;
704cccb83f7SVladimir Barinov
7056de690ddSNiklas Söderlund code->code = MEDIA_BUS_FMT_UYVY8_2X8;
706cccb83f7SVladimir Barinov
707cccb83f7SVladimir Barinov return 0;
708cccb83f7SVladimir Barinov }
709cccb83f7SVladimir Barinov
adv7180_mbus_fmt(struct v4l2_subdev * sd,struct v4l2_mbus_framefmt * fmt)710cccb83f7SVladimir Barinov static int adv7180_mbus_fmt(struct v4l2_subdev *sd,
711cccb83f7SVladimir Barinov struct v4l2_mbus_framefmt *fmt)
712cccb83f7SVladimir Barinov {
713cccb83f7SVladimir Barinov struct adv7180_state *state = to_state(sd);
714cccb83f7SVladimir Barinov
7156de690ddSNiklas Söderlund fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
716cccb83f7SVladimir Barinov fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
717cccb83f7SVladimir Barinov fmt->width = 720;
718cccb83f7SVladimir Barinov fmt->height = state->curr_norm & V4L2_STD_525_60 ? 480 : 576;
719cccb83f7SVladimir Barinov
7206457b626SNiklas Söderlund if (state->field == V4L2_FIELD_ALTERNATE)
7216457b626SNiklas Söderlund fmt->height /= 2;
7226457b626SNiklas Söderlund
723cccb83f7SVladimir Barinov return 0;
724cccb83f7SVladimir Barinov }
725cccb83f7SVladimir Barinov
adv7180_set_field_mode(struct adv7180_state * state)726851a54efSLars-Peter Clausen static int adv7180_set_field_mode(struct adv7180_state *state)
727851a54efSLars-Peter Clausen {
728851a54efSLars-Peter Clausen if (!(state->chip_info->flags & ADV7180_FLAG_I2P))
729851a54efSLars-Peter Clausen return 0;
730851a54efSLars-Peter Clausen
731851a54efSLars-Peter Clausen if (state->field == V4L2_FIELD_NONE) {
732851a54efSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
733851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x01, 0x20);
734851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x02, 0x28);
735851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x03, 0x38);
736851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x04, 0x30);
737851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x05, 0x30);
738851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x06, 0x80);
739851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x07, 0x70);
740851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x08, 0x50);
741851a54efSLars-Peter Clausen }
742851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0xa3, 0x00);
743851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0x5b, 0x00);
744851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0x55, 0x80);
745851a54efSLars-Peter Clausen } else {
746851a54efSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
747851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x01, 0x18);
748851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x02, 0x18);
749851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x03, 0x30);
750851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x04, 0x20);
751851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x05, 0x28);
752851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x06, 0x40);
753851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x07, 0x58);
754851a54efSLars-Peter Clausen adv7180_csi_write(state, 0x08, 0x30);
755851a54efSLars-Peter Clausen }
756851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0xa3, 0x70);
757851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0x5b, 0x80);
758851a54efSLars-Peter Clausen adv7180_vpp_write(state, 0x55, 0x00);
759851a54efSLars-Peter Clausen }
760851a54efSLars-Peter Clausen
761851a54efSLars-Peter Clausen return 0;
762851a54efSLars-Peter Clausen }
763851a54efSLars-Peter Clausen
adv7180_get_pad_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)764d5d51a82SLars-Peter Clausen static int adv7180_get_pad_format(struct v4l2_subdev *sd,
7650d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
766d5d51a82SLars-Peter Clausen struct v4l2_subdev_format *format)
767d5d51a82SLars-Peter Clausen {
768851a54efSLars-Peter Clausen struct adv7180_state *state = to_state(sd);
769851a54efSLars-Peter Clausen
770851a54efSLars-Peter Clausen if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
7710d346d2aSTomi Valkeinen format->format = *v4l2_subdev_get_try_format(sd, sd_state, 0);
772851a54efSLars-Peter Clausen } else {
773851a54efSLars-Peter Clausen adv7180_mbus_fmt(sd, &format->format);
774851a54efSLars-Peter Clausen format->format.field = state->field;
775851a54efSLars-Peter Clausen }
776851a54efSLars-Peter Clausen
777851a54efSLars-Peter Clausen return 0;
778d5d51a82SLars-Peter Clausen }
779d5d51a82SLars-Peter Clausen
adv7180_set_pad_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * format)780d5d51a82SLars-Peter Clausen static int adv7180_set_pad_format(struct v4l2_subdev *sd,
7810d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
782d5d51a82SLars-Peter Clausen struct v4l2_subdev_format *format)
783d5d51a82SLars-Peter Clausen {
784851a54efSLars-Peter Clausen struct adv7180_state *state = to_state(sd);
785851a54efSLars-Peter Clausen struct v4l2_mbus_framefmt *framefmt;
786e0ad7a9bSNiklas Söderlund int ret;
787851a54efSLars-Peter Clausen
788851a54efSLars-Peter Clausen switch (format->format.field) {
789851a54efSLars-Peter Clausen case V4L2_FIELD_NONE:
7906457b626SNiklas Söderlund if (state->chip_info->flags & ADV7180_FLAG_I2P)
791851a54efSLars-Peter Clausen break;
7921771e9fbSGustavo A. R. Silva fallthrough;
793851a54efSLars-Peter Clausen default:
7946457b626SNiklas Söderlund format->format.field = V4L2_FIELD_ALTERNATE;
795851a54efSLars-Peter Clausen break;
796851a54efSLars-Peter Clausen }
797851a54efSLars-Peter Clausen
798e0ad7a9bSNiklas Söderlund ret = adv7180_mbus_fmt(sd, &format->format);
799e0ad7a9bSNiklas Söderlund
800851a54efSLars-Peter Clausen if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
801851a54efSLars-Peter Clausen if (state->field != format->format.field) {
802851a54efSLars-Peter Clausen state->field = format->format.field;
803851a54efSLars-Peter Clausen adv7180_set_power(state, false);
804851a54efSLars-Peter Clausen adv7180_set_field_mode(state);
805851a54efSLars-Peter Clausen adv7180_set_power(state, true);
806851a54efSLars-Peter Clausen }
807851a54efSLars-Peter Clausen } else {
8080d346d2aSTomi Valkeinen framefmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
809851a54efSLars-Peter Clausen *framefmt = format->format;
810851a54efSLars-Peter Clausen }
811851a54efSLars-Peter Clausen
812e0ad7a9bSNiklas Söderlund return ret;
813d5d51a82SLars-Peter Clausen }
814d5d51a82SLars-Peter Clausen
adv7180_init_cfg(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state)81523c72dd9SNiklas Söderlund static int adv7180_init_cfg(struct v4l2_subdev *sd,
8160d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state)
81723c72dd9SNiklas Söderlund {
81823c72dd9SNiklas Söderlund struct v4l2_subdev_format fmt = {
8190d346d2aSTomi Valkeinen .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY
82023c72dd9SNiklas Söderlund : V4L2_SUBDEV_FORMAT_ACTIVE,
82123c72dd9SNiklas Söderlund };
82223c72dd9SNiklas Söderlund
8230d346d2aSTomi Valkeinen return adv7180_set_pad_format(sd, sd_state, &fmt);
82423c72dd9SNiklas Söderlund }
82523c72dd9SNiklas Söderlund
adv7180_get_mbus_config(struct v4l2_subdev * sd,unsigned int pad,struct v4l2_mbus_config * cfg)8260c3da525SJacopo Mondi static int adv7180_get_mbus_config(struct v4l2_subdev *sd,
8270c3da525SJacopo Mondi unsigned int pad,
828cccb83f7SVladimir Barinov struct v4l2_mbus_config *cfg)
829cccb83f7SVladimir Barinov {
830b37135e3SLars-Peter Clausen struct adv7180_state *state = to_state(sd);
831b37135e3SLars-Peter Clausen
832b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
8332d95e7edSSakari Ailus cfg->type = V4L2_MBUS_CSI2_DPHY;
8346a7bdd89SLaurent Pinchart cfg->bus.mipi_csi2.num_data_lanes = 1;
835b9f7caa7SLaurent Pinchart cfg->bus.mipi_csi2.flags = 0;
836b37135e3SLars-Peter Clausen } else {
837cccb83f7SVladimir Barinov /*
838cccb83f7SVladimir Barinov * The ADV7180 sensor supports BT.601/656 output modes.
839cccb83f7SVladimir Barinov * The BT.656 is default and not yet configurable by s/w.
840cccb83f7SVladimir Barinov */
8416a7bdd89SLaurent Pinchart cfg->bus.parallel.flags = V4L2_MBUS_MASTER |
8426a7bdd89SLaurent Pinchart V4L2_MBUS_PCLK_SAMPLE_RISING |
843cccb83f7SVladimir Barinov V4L2_MBUS_DATA_ACTIVE_HIGH;
844cccb83f7SVladimir Barinov cfg->type = V4L2_MBUS_BT656;
845b37135e3SLars-Peter Clausen }
846cccb83f7SVladimir Barinov
847cccb83f7SVladimir Barinov return 0;
848cccb83f7SVladimir Barinov }
849cccb83f7SVladimir Barinov
adv7180_get_skip_frames(struct v4l2_subdev * sd,u32 * frames)8509483a3f8STim Harvey static int adv7180_get_skip_frames(struct v4l2_subdev *sd, u32 *frames)
8519483a3f8STim Harvey {
8529483a3f8STim Harvey *frames = ADV7180_NUM_OF_SKIP_FRAMES;
8539483a3f8STim Harvey
8549483a3f8STim Harvey return 0;
8559483a3f8STim Harvey }
8569483a3f8STim Harvey
adv7180_g_pixelaspect(struct v4l2_subdev * sd,struct v4l2_fract * aspect)857ecf37493SHans Verkuil static int adv7180_g_pixelaspect(struct v4l2_subdev *sd, struct v4l2_fract *aspect)
85864b3df92SNiklas Söderlund {
85964b3df92SNiklas Söderlund struct adv7180_state *state = to_state(sd);
86064b3df92SNiklas Söderlund
86164b3df92SNiklas Söderlund if (state->curr_norm & V4L2_STD_525_60) {
862ecf37493SHans Verkuil aspect->numerator = 11;
863ecf37493SHans Verkuil aspect->denominator = 10;
86464b3df92SNiklas Söderlund } else {
865ecf37493SHans Verkuil aspect->numerator = 54;
866ecf37493SHans Verkuil aspect->denominator = 59;
86764b3df92SNiklas Söderlund }
86864b3df92SNiklas Söderlund
86964b3df92SNiklas Söderlund return 0;
87064b3df92SNiklas Söderlund }
87164b3df92SNiklas Söderlund
adv7180_g_tvnorms(struct v4l2_subdev * sd,v4l2_std_id * norm)872bae4c757SNiklas Söderlund static int adv7180_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm)
873bae4c757SNiklas Söderlund {
874bae4c757SNiklas Söderlund *norm = V4L2_STD_ALL;
875bae4c757SNiklas Söderlund return 0;
876bae4c757SNiklas Söderlund }
877bae4c757SNiklas Söderlund
adv7180_s_stream(struct v4l2_subdev * sd,int enable)878937feeedSHans Verkuil static int adv7180_s_stream(struct v4l2_subdev *sd, int enable)
879937feeedSHans Verkuil {
880937feeedSHans Verkuil struct adv7180_state *state = to_state(sd);
881937feeedSHans Verkuil int ret;
882937feeedSHans Verkuil
883937feeedSHans Verkuil /* It's always safe to stop streaming, no need to take the lock */
884937feeedSHans Verkuil if (!enable) {
885937feeedSHans Verkuil state->streaming = enable;
886937feeedSHans Verkuil return 0;
887937feeedSHans Verkuil }
888937feeedSHans Verkuil
889937feeedSHans Verkuil /* Must wait until querystd released the lock */
890937feeedSHans Verkuil ret = mutex_lock_interruptible(&state->mutex);
891937feeedSHans Verkuil if (ret)
892937feeedSHans Verkuil return ret;
893937feeedSHans Verkuil state->streaming = enable;
894937feeedSHans Verkuil mutex_unlock(&state->mutex);
895937feeedSHans Verkuil return 0;
896937feeedSHans Verkuil }
897937feeedSHans Verkuil
adv7180_subscribe_event(struct v4l2_subdev * sd,struct v4l2_fh * fh,struct v4l2_event_subscription * sub)898937feeedSHans Verkuil static int adv7180_subscribe_event(struct v4l2_subdev *sd,
899937feeedSHans Verkuil struct v4l2_fh *fh,
900937feeedSHans Verkuil struct v4l2_event_subscription *sub)
901937feeedSHans Verkuil {
902937feeedSHans Verkuil switch (sub->type) {
903937feeedSHans Verkuil case V4L2_EVENT_SOURCE_CHANGE:
904937feeedSHans Verkuil return v4l2_src_change_event_subdev_subscribe(sd, fh, sub);
905937feeedSHans Verkuil case V4L2_EVENT_CTRL:
906937feeedSHans Verkuil return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub);
907937feeedSHans Verkuil default:
908937feeedSHans Verkuil return -EINVAL;
909937feeedSHans Verkuil }
910937feeedSHans Verkuil }
911937feeedSHans Verkuil
912cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_video_ops adv7180_video_ops = {
9138774bed9SLaurent Pinchart .s_std = adv7180_s_std,
914d0fadc86SNiklas Söderlund .g_std = adv7180_g_std,
91538566d28SNiklas Söderlund .g_frame_interval = adv7180_g_frame_interval,
916cb7a01acSMauro Carvalho Chehab .querystd = adv7180_querystd,
917cb7a01acSMauro Carvalho Chehab .g_input_status = adv7180_g_input_status,
918cb7a01acSMauro Carvalho Chehab .s_routing = adv7180_s_routing,
919ecf37493SHans Verkuil .g_pixelaspect = adv7180_g_pixelaspect,
920bae4c757SNiklas Söderlund .g_tvnorms = adv7180_g_tvnorms,
921937feeedSHans Verkuil .s_stream = adv7180_s_stream,
922cb7a01acSMauro Carvalho Chehab };
923cb7a01acSMauro Carvalho Chehab
924cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_core_ops adv7180_core_ops = {
925e246c333SLars-Peter Clausen .s_power = adv7180_s_power,
926937feeedSHans Verkuil .subscribe_event = adv7180_subscribe_event,
927937feeedSHans Verkuil .unsubscribe_event = v4l2_event_subdev_unsubscribe,
928cb7a01acSMauro Carvalho Chehab };
929cb7a01acSMauro Carvalho Chehab
930d5d51a82SLars-Peter Clausen static const struct v4l2_subdev_pad_ops adv7180_pad_ops = {
93123c72dd9SNiklas Söderlund .init_cfg = adv7180_init_cfg,
932d5d51a82SLars-Peter Clausen .enum_mbus_code = adv7180_enum_mbus_code,
933d5d51a82SLars-Peter Clausen .set_fmt = adv7180_set_pad_format,
934d5d51a82SLars-Peter Clausen .get_fmt = adv7180_get_pad_format,
9350c3da525SJacopo Mondi .get_mbus_config = adv7180_get_mbus_config,
936d5d51a82SLars-Peter Clausen };
937d5d51a82SLars-Peter Clausen
9389483a3f8STim Harvey static const struct v4l2_subdev_sensor_ops adv7180_sensor_ops = {
9399483a3f8STim Harvey .g_skip_frames = adv7180_get_skip_frames,
9409483a3f8STim Harvey };
9419483a3f8STim Harvey
942cb7a01acSMauro Carvalho Chehab static const struct v4l2_subdev_ops adv7180_ops = {
943cb7a01acSMauro Carvalho Chehab .core = &adv7180_core_ops,
944cb7a01acSMauro Carvalho Chehab .video = &adv7180_video_ops,
945d5d51a82SLars-Peter Clausen .pad = &adv7180_pad_ops,
9469483a3f8STim Harvey .sensor = &adv7180_sensor_ops,
947cb7a01acSMauro Carvalho Chehab };
948cb7a01acSMauro Carvalho Chehab
adv7180_irq(int irq,void * devid)9490c25534dSLars-Peter Clausen static irqreturn_t adv7180_irq(int irq, void *devid)
950cb7a01acSMauro Carvalho Chehab {
9510c25534dSLars-Peter Clausen struct adv7180_state *state = devid;
952cb7a01acSMauro Carvalho Chehab u8 isr3;
953cb7a01acSMauro Carvalho Chehab
954cb7a01acSMauro Carvalho Chehab mutex_lock(&state->mutex);
9553999e5d0SLars-Peter Clausen isr3 = adv7180_read(state, ADV7180_REG_ISR3);
956cb7a01acSMauro Carvalho Chehab /* clear */
9573999e5d0SLars-Peter Clausen adv7180_write(state, ADV7180_REG_ICR3, isr3);
958cb7a01acSMauro Carvalho Chehab
959937feeedSHans Verkuil if (isr3 & ADV7180_IRQ3_AD_CHANGE) {
960937feeedSHans Verkuil static const struct v4l2_event src_ch = {
961937feeedSHans Verkuil .type = V4L2_EVENT_SOURCE_CHANGE,
962937feeedSHans Verkuil .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
963937feeedSHans Verkuil };
964937feeedSHans Verkuil
965937feeedSHans Verkuil v4l2_subdev_notify_event(&state->sd, &src_ch);
966937feeedSHans Verkuil }
967cb7a01acSMauro Carvalho Chehab mutex_unlock(&state->mutex);
968cb7a01acSMauro Carvalho Chehab
969cb7a01acSMauro Carvalho Chehab return IRQ_HANDLED;
970cb7a01acSMauro Carvalho Chehab }
971cb7a01acSMauro Carvalho Chehab
adv7180_init(struct adv7180_state * state)972f5dde49bSLars-Peter Clausen static int adv7180_init(struct adv7180_state *state)
973f5dde49bSLars-Peter Clausen {
974f5dde49bSLars-Peter Clausen int ret;
975f5dde49bSLars-Peter Clausen
976f5dde49bSLars-Peter Clausen /* ITU-R BT.656-4 compatible */
977f5dde49bSLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL,
978f5dde49bSLars-Peter Clausen ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS);
979f5dde49bSLars-Peter Clausen if (ret < 0)
980f5dde49bSLars-Peter Clausen return ret;
981f5dde49bSLars-Peter Clausen
982f5dde49bSLars-Peter Clausen /* Manually set V bit end position in NTSC mode */
983f5dde49bSLars-Peter Clausen return adv7180_write(state, ADV7180_REG_NTSC_V_BIT_END,
984f5dde49bSLars-Peter Clausen ADV7180_NTSC_V_BIT_END_MANUAL_NVEND);
985f5dde49bSLars-Peter Clausen }
986f5dde49bSLars-Peter Clausen
adv7180_set_std(struct adv7180_state * state,unsigned int std)987f5dde49bSLars-Peter Clausen static int adv7180_set_std(struct adv7180_state *state, unsigned int std)
988f5dde49bSLars-Peter Clausen {
989f5dde49bSLars-Peter Clausen return adv7180_write(state, ADV7180_REG_INPUT_CONTROL,
990f5dde49bSLars-Peter Clausen (std << 4) | state->input);
991f5dde49bSLars-Peter Clausen }
992f5dde49bSLars-Peter Clausen
adv7180_select_input(struct adv7180_state * state,unsigned int input)993f5dde49bSLars-Peter Clausen static int adv7180_select_input(struct adv7180_state *state, unsigned int input)
994f5dde49bSLars-Peter Clausen {
995f5dde49bSLars-Peter Clausen int ret;
996f5dde49bSLars-Peter Clausen
997f5dde49bSLars-Peter Clausen ret = adv7180_read(state, ADV7180_REG_INPUT_CONTROL);
998f5dde49bSLars-Peter Clausen if (ret < 0)
999f5dde49bSLars-Peter Clausen return ret;
1000f5dde49bSLars-Peter Clausen
1001f5dde49bSLars-Peter Clausen ret &= ~ADV7180_INPUT_CONTROL_INSEL_MASK;
1002f5dde49bSLars-Peter Clausen ret |= input;
1003f5dde49bSLars-Peter Clausen return adv7180_write(state, ADV7180_REG_INPUT_CONTROL, ret);
1004f5dde49bSLars-Peter Clausen }
1005f5dde49bSLars-Peter Clausen
adv7182_init(struct adv7180_state * state)1006c5ef8f8cSLars-Peter Clausen static int adv7182_init(struct adv7180_state *state)
1007c5ef8f8cSLars-Peter Clausen {
1008b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2)
1009b37135e3SLars-Peter Clausen adv7180_write(state, ADV7180_REG_CSI_SLAVE_ADDR,
1010b37135e3SLars-Peter Clausen ADV7180_DEFAULT_CSI_I2C_ADDR << 1);
1011b37135e3SLars-Peter Clausen
1012851a54efSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_I2P)
1013851a54efSLars-Peter Clausen adv7180_write(state, ADV7180_REG_VPP_SLAVE_ADDR,
1014851a54efSLars-Peter Clausen ADV7180_DEFAULT_VPP_I2C_ADDR << 1);
1015851a54efSLars-Peter Clausen
1016bf7dcb80SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_V2) {
1017bf7dcb80SLars-Peter Clausen /* ADI recommended writes for improved video quality */
1018bf7dcb80SLars-Peter Clausen adv7180_write(state, 0x0080, 0x51);
1019bf7dcb80SLars-Peter Clausen adv7180_write(state, 0x0081, 0x51);
1020bf7dcb80SLars-Peter Clausen adv7180_write(state, 0x0082, 0x68);
1021bf7dcb80SLars-Peter Clausen }
1022bf7dcb80SLars-Peter Clausen
1023c5ef8f8cSLars-Peter Clausen /* ADI required writes */
1024b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
1025ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_OUTPUT_CONTROL, 0x4e);
1026ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 0x57);
1027ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_CTRL_2, 0xc0);
1028b37135e3SLars-Peter Clausen } else {
1029ed771d75SMatthew Michilot if (state->chip_info->flags & ADV7180_FLAG_V2) {
1030ed771d75SMatthew Michilot if (state->force_bt656_4) {
1031ed771d75SMatthew Michilot /* ITU-R BT.656-4 compatible */
1032ed771d75SMatthew Michilot adv7180_write(state,
1033ed771d75SMatthew Michilot ADV7180_REG_EXTENDED_OUTPUT_CONTROL,
1034ed771d75SMatthew Michilot ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS);
1035ed771d75SMatthew Michilot /* Manually set NEWAVMODE */
1036ed771d75SMatthew Michilot adv7180_write(state,
1037ed771d75SMatthew Michilot ADV7180_REG_VSYNC_FIELD_CTL_1,
1038ed771d75SMatthew Michilot ADV7180_VSYNC_FIELD_CTL_1_NEWAV);
1039ed771d75SMatthew Michilot /* Manually set V bit end position in NTSC mode */
1040ed771d75SMatthew Michilot adv7180_write(state,
1041ed771d75SMatthew Michilot ADV7180_REG_NTSC_V_BIT_END,
1042ed771d75SMatthew Michilot ADV7180_NTSC_V_BIT_END_MANUAL_NVEND);
1043ed771d75SMatthew Michilot } else {
1044ce5d6290SSteve Longerbeam adv7180_write(state,
1045ce5d6290SSteve Longerbeam ADV7180_REG_EXTENDED_OUTPUT_CONTROL,
1046ce5d6290SSteve Longerbeam 0x17);
1047ed771d75SMatthew Michilot }
1048ed771d75SMatthew Michilot }
1049b37135e3SLars-Peter Clausen else
1050ce5d6290SSteve Longerbeam adv7180_write(state,
1051ce5d6290SSteve Longerbeam ADV7180_REG_EXTENDED_OUTPUT_CONTROL,
1052ce5d6290SSteve Longerbeam 0x07);
1053ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_OUTPUT_CONTROL, 0x0c);
1054ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_CTRL_2, 0x40);
1055b37135e3SLars-Peter Clausen }
1056b37135e3SLars-Peter Clausen
1057b37135e3SLars-Peter Clausen adv7180_write(state, 0x0013, 0x00);
1058c5ef8f8cSLars-Peter Clausen
1059c5ef8f8cSLars-Peter Clausen return 0;
1060c5ef8f8cSLars-Peter Clausen }
1061c5ef8f8cSLars-Peter Clausen
adv7182_set_std(struct adv7180_state * state,unsigned int std)1062c5ef8f8cSLars-Peter Clausen static int adv7182_set_std(struct adv7180_state *state, unsigned int std)
1063c5ef8f8cSLars-Peter Clausen {
1064db9edaafSBenjamin Marty /* Failing to set the reserved bit can result in increased video noise */
1065db9edaafSBenjamin Marty return adv7180_write(state, ADV7182_REG_INPUT_VIDSEL,
1066db9edaafSBenjamin Marty (std << 4) | ADV7182_REG_INPUT_RESERVED);
1067c5ef8f8cSLars-Peter Clausen }
1068c5ef8f8cSLars-Peter Clausen
1069c5ef8f8cSLars-Peter Clausen enum adv7182_input_type {
1070c5ef8f8cSLars-Peter Clausen ADV7182_INPUT_TYPE_CVBS,
1071c5ef8f8cSLars-Peter Clausen ADV7182_INPUT_TYPE_DIFF_CVBS,
1072c5ef8f8cSLars-Peter Clausen ADV7182_INPUT_TYPE_SVIDEO,
1073c5ef8f8cSLars-Peter Clausen ADV7182_INPUT_TYPE_YPBPR,
1074c5ef8f8cSLars-Peter Clausen };
1075c5ef8f8cSLars-Peter Clausen
adv7182_get_input_type(unsigned int input)1076c5ef8f8cSLars-Peter Clausen static enum adv7182_input_type adv7182_get_input_type(unsigned int input)
1077c5ef8f8cSLars-Peter Clausen {
1078c5ef8f8cSLars-Peter Clausen switch (input) {
1079c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN1:
1080c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN2:
1081c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN3:
1082c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN4:
1083c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN5:
1084c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN6:
1085c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN7:
1086c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_CVBS_AIN8:
1087c5ef8f8cSLars-Peter Clausen return ADV7182_INPUT_TYPE_CVBS;
1088c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_SVIDEO_AIN1_AIN2:
1089c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_SVIDEO_AIN3_AIN4:
1090c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_SVIDEO_AIN5_AIN6:
1091c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_SVIDEO_AIN7_AIN8:
1092c5ef8f8cSLars-Peter Clausen return ADV7182_INPUT_TYPE_SVIDEO;
1093c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3:
1094c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6:
1095c5ef8f8cSLars-Peter Clausen return ADV7182_INPUT_TYPE_YPBPR;
1096c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2:
1097c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4:
1098c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6:
1099c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8:
1100c5ef8f8cSLars-Peter Clausen return ADV7182_INPUT_TYPE_DIFF_CVBS;
1101c5ef8f8cSLars-Peter Clausen default: /* Will never happen */
1102c5ef8f8cSLars-Peter Clausen return 0;
1103c5ef8f8cSLars-Peter Clausen }
1104c5ef8f8cSLars-Peter Clausen }
1105c5ef8f8cSLars-Peter Clausen
1106c5ef8f8cSLars-Peter Clausen /* ADI recommended writes to registers 0x52, 0x53, 0x54 */
1107c5ef8f8cSLars-Peter Clausen static unsigned int adv7182_lbias_settings[][3] = {
1108c5ef8f8cSLars-Peter Clausen [ADV7182_INPUT_TYPE_CVBS] = { 0xCB, 0x4E, 0x80 },
1109c5ef8f8cSLars-Peter Clausen [ADV7182_INPUT_TYPE_DIFF_CVBS] = { 0xC0, 0x4E, 0x80 },
1110c5ef8f8cSLars-Peter Clausen [ADV7182_INPUT_TYPE_SVIDEO] = { 0x0B, 0xCE, 0x80 },
1111c5ef8f8cSLars-Peter Clausen [ADV7182_INPUT_TYPE_YPBPR] = { 0x0B, 0x4E, 0xC0 },
1112c5ef8f8cSLars-Peter Clausen };
1113c5ef8f8cSLars-Peter Clausen
1114bf7dcb80SLars-Peter Clausen static unsigned int adv7280_lbias_settings[][3] = {
1115bf7dcb80SLars-Peter Clausen [ADV7182_INPUT_TYPE_CVBS] = { 0xCD, 0x4E, 0x80 },
1116bf7dcb80SLars-Peter Clausen [ADV7182_INPUT_TYPE_DIFF_CVBS] = { 0xC0, 0x4E, 0x80 },
1117bf7dcb80SLars-Peter Clausen [ADV7182_INPUT_TYPE_SVIDEO] = { 0x0B, 0xCE, 0x80 },
1118bf7dcb80SLars-Peter Clausen [ADV7182_INPUT_TYPE_YPBPR] = { 0x0B, 0x4E, 0xC0 },
1119bf7dcb80SLars-Peter Clausen };
1120bf7dcb80SLars-Peter Clausen
adv7182_select_input(struct adv7180_state * state,unsigned int input)1121c5ef8f8cSLars-Peter Clausen static int adv7182_select_input(struct adv7180_state *state, unsigned int input)
1122c5ef8f8cSLars-Peter Clausen {
1123c5ef8f8cSLars-Peter Clausen enum adv7182_input_type input_type;
1124c5ef8f8cSLars-Peter Clausen unsigned int *lbias;
1125c5ef8f8cSLars-Peter Clausen unsigned int i;
1126c5ef8f8cSLars-Peter Clausen int ret;
1127c5ef8f8cSLars-Peter Clausen
1128c5ef8f8cSLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL, input);
1129c5ef8f8cSLars-Peter Clausen if (ret)
1130c5ef8f8cSLars-Peter Clausen return ret;
1131c5ef8f8cSLars-Peter Clausen
1132c5ef8f8cSLars-Peter Clausen /* Reset clamp circuitry - ADI recommended writes */
1133ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_RST_CLAMP, 0x00);
1134ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_RST_CLAMP, 0xff);
1135c5ef8f8cSLars-Peter Clausen
1136c5ef8f8cSLars-Peter Clausen input_type = adv7182_get_input_type(input);
1137c5ef8f8cSLars-Peter Clausen
1138c5ef8f8cSLars-Peter Clausen switch (input_type) {
1139c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_TYPE_CVBS:
1140c5ef8f8cSLars-Peter Clausen case ADV7182_INPUT_TYPE_DIFF_CVBS:
1141c5ef8f8cSLars-Peter Clausen /* ADI recommends to use the SH1 filter */
1142ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_SHAP_FILTER_CTL_1, 0x41);
1143c5ef8f8cSLars-Peter Clausen break;
1144c5ef8f8cSLars-Peter Clausen default:
1145ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_SHAP_FILTER_CTL_1, 0x01);
1146c5ef8f8cSLars-Peter Clausen break;
1147c5ef8f8cSLars-Peter Clausen }
1148c5ef8f8cSLars-Peter Clausen
1149bf7dcb80SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_V2)
1150bf7dcb80SLars-Peter Clausen lbias = adv7280_lbias_settings[input_type];
1151bf7dcb80SLars-Peter Clausen else
1152c5ef8f8cSLars-Peter Clausen lbias = adv7182_lbias_settings[input_type];
1153c5ef8f8cSLars-Peter Clausen
1154c5ef8f8cSLars-Peter Clausen for (i = 0; i < ARRAY_SIZE(adv7182_lbias_settings[0]); i++)
1155ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_CVBS_TRIM + i, lbias[i]);
1156c5ef8f8cSLars-Peter Clausen
1157c5ef8f8cSLars-Peter Clausen if (input_type == ADV7182_INPUT_TYPE_DIFF_CVBS) {
1158c5ef8f8cSLars-Peter Clausen /* ADI required writes to make differential CVBS work */
1159ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_RES_CIR, 0xa8);
1160ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_CLAMP_ADJ, 0x90);
1161ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_DIFF_MODE, 0xb0);
1162ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_AGC_ADJ1, 0x08);
1163ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_AGC_ADJ2, 0xa0);
1164c5ef8f8cSLars-Peter Clausen } else {
1165ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_RES_CIR, 0xf0);
1166ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_CLAMP_ADJ, 0xd0);
1167ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_DIFF_MODE, 0x10);
1168ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_AGC_ADJ1, 0x9c);
1169ce5d6290SSteve Longerbeam adv7180_write(state, ADV7180_REG_AGC_ADJ2, 0x00);
1170c5ef8f8cSLars-Peter Clausen }
1171c5ef8f8cSLars-Peter Clausen
1172c5ef8f8cSLars-Peter Clausen return 0;
1173c5ef8f8cSLars-Peter Clausen }
1174c5ef8f8cSLars-Peter Clausen
1175f5dde49bSLars-Peter Clausen static const struct adv7180_chip_info adv7180_info = {
1176f5dde49bSLars-Peter Clausen .flags = ADV7180_FLAG_RESET_POWERED,
1177f5dde49bSLars-Peter Clausen /* We cannot discriminate between LQFP and 40-pin LFCSP, so accept
1178f5dde49bSLars-Peter Clausen * all inputs and let the card driver take care of validation
1179f5dde49bSLars-Peter Clausen */
1180f5dde49bSLars-Peter Clausen .valid_input_mask = BIT(ADV7180_INPUT_CVBS_AIN1) |
1181f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_CVBS_AIN2) |
1182f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_CVBS_AIN3) |
1183f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_CVBS_AIN4) |
1184f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_CVBS_AIN5) |
1185f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_CVBS_AIN6) |
1186f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_SVIDEO_AIN1_AIN2) |
1187f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_SVIDEO_AIN3_AIN4) |
1188f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_SVIDEO_AIN5_AIN6) |
1189f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_YPRPB_AIN1_AIN2_AIN3) |
1190f5dde49bSLars-Peter Clausen BIT(ADV7180_INPUT_YPRPB_AIN4_AIN5_AIN6),
1191f5dde49bSLars-Peter Clausen .init = adv7180_init,
1192f5dde49bSLars-Peter Clausen .set_std = adv7180_set_std,
1193f5dde49bSLars-Peter Clausen .select_input = adv7180_select_input,
1194f5dde49bSLars-Peter Clausen };
1195f5dde49bSLars-Peter Clausen
1196c5ef8f8cSLars-Peter Clausen static const struct adv7180_chip_info adv7182_info = {
1197c5ef8f8cSLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
1198c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) |
1199c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) |
1200c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) |
1201c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
1202c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
1203c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) |
1204c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
1205c5ef8f8cSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4),
1206c5ef8f8cSLars-Peter Clausen .init = adv7182_init,
1207c5ef8f8cSLars-Peter Clausen .set_std = adv7182_set_std,
1208c5ef8f8cSLars-Peter Clausen .select_input = adv7182_select_input,
1209c5ef8f8cSLars-Peter Clausen };
1210c5ef8f8cSLars-Peter Clausen
1211bf7dcb80SLars-Peter Clausen static const struct adv7180_chip_info adv7280_info = {
1212851a54efSLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P,
1213bf7dcb80SLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
1214bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) |
1215bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) |
1216bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) |
1217bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
1218bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
1219bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3),
1220bf7dcb80SLars-Peter Clausen .init = adv7182_init,
1221bf7dcb80SLars-Peter Clausen .set_std = adv7182_set_std,
1222bf7dcb80SLars-Peter Clausen .select_input = adv7182_select_input,
1223bf7dcb80SLars-Peter Clausen };
1224bf7dcb80SLars-Peter Clausen
1225b37135e3SLars-Peter Clausen static const struct adv7180_chip_info adv7280_m_info = {
1226851a54efSLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P,
1227b37135e3SLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
1228b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) |
1229b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) |
1230b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) |
1231b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN5) |
1232b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN6) |
1233b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) |
1234b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) |
1235b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
1236b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
1237b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN5_AIN6) |
1238b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
1239b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) |
1240b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6),
1241b37135e3SLars-Peter Clausen .init = adv7182_init,
1242b37135e3SLars-Peter Clausen .set_std = adv7182_set_std,
1243b37135e3SLars-Peter Clausen .select_input = adv7182_select_input,
1244b37135e3SLars-Peter Clausen };
1245b37135e3SLars-Peter Clausen
1246bf7dcb80SLars-Peter Clausen static const struct adv7180_chip_info adv7281_info = {
1247b37135e3SLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2,
1248bf7dcb80SLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
1249bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) |
1250bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) |
1251bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) |
1252bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
1253bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
1254bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
1255bf7dcb80SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8),
1256bf7dcb80SLars-Peter Clausen .init = adv7182_init,
1257bf7dcb80SLars-Peter Clausen .set_std = adv7182_set_std,
1258bf7dcb80SLars-Peter Clausen .select_input = adv7182_select_input,
1259bf7dcb80SLars-Peter Clausen };
1260bf7dcb80SLars-Peter Clausen
1261b37135e3SLars-Peter Clausen static const struct adv7180_chip_info adv7281_m_info = {
1262b37135e3SLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2,
1263b37135e3SLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
1264b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) |
1265b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) |
1266b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) |
1267b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) |
1268b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) |
1269b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
1270b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
1271b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
1272b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) |
1273b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
1274b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) |
1275b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8),
1276b37135e3SLars-Peter Clausen .init = adv7182_init,
1277b37135e3SLars-Peter Clausen .set_std = adv7182_set_std,
1278b37135e3SLars-Peter Clausen .select_input = adv7182_select_input,
1279b37135e3SLars-Peter Clausen };
1280b37135e3SLars-Peter Clausen
1281b37135e3SLars-Peter Clausen static const struct adv7180_chip_info adv7281_ma_info = {
1282b37135e3SLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2,
1283b37135e3SLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
1284b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) |
1285b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) |
1286b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) |
1287b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN5) |
1288b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN6) |
1289b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) |
1290b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) |
1291b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
1292b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
1293b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN5_AIN6) |
1294b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
1295b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) |
1296b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6) |
1297b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
1298b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) |
1299b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6) |
1300b37135e3SLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8),
1301b37135e3SLars-Peter Clausen .init = adv7182_init,
1302b37135e3SLars-Peter Clausen .set_std = adv7182_set_std,
1303b37135e3SLars-Peter Clausen .select_input = adv7182_select_input,
1304b37135e3SLars-Peter Clausen };
1305b37135e3SLars-Peter Clausen
1306851a54efSLars-Peter Clausen static const struct adv7180_chip_info adv7282_info = {
1307851a54efSLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P,
1308851a54efSLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
1309851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) |
1310851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) |
1311851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) |
1312851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
1313851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
1314851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
1315851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8),
1316851a54efSLars-Peter Clausen .init = adv7182_init,
1317851a54efSLars-Peter Clausen .set_std = adv7182_set_std,
1318851a54efSLars-Peter Clausen .select_input = adv7182_select_input,
1319851a54efSLars-Peter Clausen };
1320851a54efSLars-Peter Clausen
1321851a54efSLars-Peter Clausen static const struct adv7180_chip_info adv7282_m_info = {
1322851a54efSLars-Peter Clausen .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P,
1323851a54efSLars-Peter Clausen .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
1324851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN2) |
1325851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN3) |
1326851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN4) |
1327851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN7) |
1328851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_CVBS_AIN8) |
1329851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
1330851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
1331851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
1332851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
1333851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) |
1334851a54efSLars-Peter Clausen BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8),
1335851a54efSLars-Peter Clausen .init = adv7182_init,
1336851a54efSLars-Peter Clausen .set_std = adv7182_set_std,
1337851a54efSLars-Peter Clausen .select_input = adv7182_select_input,
1338851a54efSLars-Peter Clausen };
1339851a54efSLars-Peter Clausen
init_device(struct adv7180_state * state)13403999e5d0SLars-Peter Clausen static int init_device(struct adv7180_state *state)
1341cb7a01acSMauro Carvalho Chehab {
1342cb7a01acSMauro Carvalho Chehab int ret;
1343cb7a01acSMauro Carvalho Chehab
13443999e5d0SLars-Peter Clausen mutex_lock(&state->mutex);
13453999e5d0SLars-Peter Clausen
134665d9e14aSSteve Longerbeam adv7180_set_power_pin(state, true);
1347abb7c7c2SFrieder Schrempf adv7180_set_reset_pin(state, false);
134865d9e14aSSteve Longerbeam
1349c18818e9SLars-Peter Clausen adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES);
135016dfe72fSUlrich Hecht usleep_range(5000, 10000);
1351c18818e9SLars-Peter Clausen
1352f5dde49bSLars-Peter Clausen ret = state->chip_info->init(state);
13533e35e33cSLars-Peter Clausen if (ret)
13543999e5d0SLars-Peter Clausen goto out_unlock;
1355cb7a01acSMauro Carvalho Chehab
1356f5dde49bSLars-Peter Clausen ret = adv7180_program_std(state);
1357f5dde49bSLars-Peter Clausen if (ret)
13583999e5d0SLars-Peter Clausen goto out_unlock;
1359cb7a01acSMauro Carvalho Chehab
1360851a54efSLars-Peter Clausen adv7180_set_field_mode(state);
1361851a54efSLars-Peter Clausen
1362cb7a01acSMauro Carvalho Chehab /* register for interrupts */
1363cb7a01acSMauro Carvalho Chehab if (state->irq > 0) {
1364cb7a01acSMauro Carvalho Chehab /* config the Interrupt pin to be active low */
13653999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_ICONF1,
1366cb7a01acSMauro Carvalho Chehab ADV7180_ICONF1_ACTIVE_LOW |
1367cb7a01acSMauro Carvalho Chehab ADV7180_ICONF1_PSYNC_ONLY);
1368cb7a01acSMauro Carvalho Chehab if (ret < 0)
13693999e5d0SLars-Peter Clausen goto out_unlock;
1370cb7a01acSMauro Carvalho Chehab
13713999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_IMR1, 0);
1372cb7a01acSMauro Carvalho Chehab if (ret < 0)
13733999e5d0SLars-Peter Clausen goto out_unlock;
1374cb7a01acSMauro Carvalho Chehab
13753999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_IMR2, 0);
1376cb7a01acSMauro Carvalho Chehab if (ret < 0)
13773999e5d0SLars-Peter Clausen goto out_unlock;
1378cb7a01acSMauro Carvalho Chehab
1379cb7a01acSMauro Carvalho Chehab /* enable AD change interrupts interrupts */
13803999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_IMR3,
1381cb7a01acSMauro Carvalho Chehab ADV7180_IRQ3_AD_CHANGE);
1382cb7a01acSMauro Carvalho Chehab if (ret < 0)
13833999e5d0SLars-Peter Clausen goto out_unlock;
1384cb7a01acSMauro Carvalho Chehab
13853999e5d0SLars-Peter Clausen ret = adv7180_write(state, ADV7180_REG_IMR4, 0);
1386cb7a01acSMauro Carvalho Chehab if (ret < 0)
13873999e5d0SLars-Peter Clausen goto out_unlock;
1388cb7a01acSMauro Carvalho Chehab }
1389cb7a01acSMauro Carvalho Chehab
13903999e5d0SLars-Peter Clausen out_unlock:
13913999e5d0SLars-Peter Clausen mutex_unlock(&state->mutex);
1392df065b37SAlexey Khoroshilov
1393df065b37SAlexey Khoroshilov return ret;
1394cb7a01acSMauro Carvalho Chehab }
1395cb7a01acSMauro Carvalho Chehab
adv7180_probe(struct i2c_client * client)1396f2478d6eSUwe Kleine-König static int adv7180_probe(struct i2c_client *client)
1397cb7a01acSMauro Carvalho Chehab {
1398f2478d6eSUwe Kleine-König const struct i2c_device_id *id = i2c_client_get_device_id(client);
1399ed771d75SMatthew Michilot struct device_node *np = client->dev.of_node;
1400cb7a01acSMauro Carvalho Chehab struct adv7180_state *state;
1401cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd;
1402cb7a01acSMauro Carvalho Chehab int ret;
1403cb7a01acSMauro Carvalho Chehab
1404cb7a01acSMauro Carvalho Chehab /* Check if the adapter supports the needed features */
1405cb7a01acSMauro Carvalho Chehab if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
1406cb7a01acSMauro Carvalho Chehab return -EIO;
1407cb7a01acSMauro Carvalho Chehab
1408c02b211dSLaurent Pinchart state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
14097657e064SFabio Estevam if (state == NULL)
14107657e064SFabio Estevam return -ENOMEM;
1411cb7a01acSMauro Carvalho Chehab
14123999e5d0SLars-Peter Clausen state->client = client;
14136457b626SNiklas Söderlund state->field = V4L2_FIELD_ALTERNATE;
1414f5dde49bSLars-Peter Clausen state->chip_info = (struct adv7180_chip_info *)id->driver_data;
14153999e5d0SLars-Peter Clausen
141665d9e14aSSteve Longerbeam state->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown",
141765d9e14aSSteve Longerbeam GPIOD_OUT_HIGH);
141865d9e14aSSteve Longerbeam if (IS_ERR(state->pwdn_gpio)) {
141965d9e14aSSteve Longerbeam ret = PTR_ERR(state->pwdn_gpio);
142065d9e14aSSteve Longerbeam v4l_err(client, "request for power pin failed: %d\n", ret);
142165d9e14aSSteve Longerbeam return ret;
142265d9e14aSSteve Longerbeam }
142365d9e14aSSteve Longerbeam
1424abb7c7c2SFrieder Schrempf state->rst_gpio = devm_gpiod_get_optional(&client->dev, "reset",
1425abb7c7c2SFrieder Schrempf GPIOD_OUT_HIGH);
1426abb7c7c2SFrieder Schrempf if (IS_ERR(state->rst_gpio)) {
1427abb7c7c2SFrieder Schrempf ret = PTR_ERR(state->rst_gpio);
1428abb7c7c2SFrieder Schrempf v4l_err(client, "request for reset pin failed: %d\n", ret);
1429abb7c7c2SFrieder Schrempf return ret;
1430abb7c7c2SFrieder Schrempf }
1431abb7c7c2SFrieder Schrempf
1432ed771d75SMatthew Michilot if (of_property_read_bool(np, "adv,force-bt656-4"))
1433ed771d75SMatthew Michilot state->force_bt656_4 = true;
1434ed771d75SMatthew Michilot
1435b37135e3SLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
143631b9754cSWolfram Sang state->csi_client = i2c_new_dummy_device(client->adapter,
1437b37135e3SLars-Peter Clausen ADV7180_DEFAULT_CSI_I2C_ADDR);
143831b9754cSWolfram Sang if (IS_ERR(state->csi_client))
143931b9754cSWolfram Sang return PTR_ERR(state->csi_client);
1440b37135e3SLars-Peter Clausen }
1441b37135e3SLars-Peter Clausen
1442851a54efSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_I2P) {
144331b9754cSWolfram Sang state->vpp_client = i2c_new_dummy_device(client->adapter,
1444851a54efSLars-Peter Clausen ADV7180_DEFAULT_VPP_I2C_ADDR);
144531b9754cSWolfram Sang if (IS_ERR(state->vpp_client)) {
144631b9754cSWolfram Sang ret = PTR_ERR(state->vpp_client);
1447851a54efSLars-Peter Clausen goto err_unregister_csi_client;
1448851a54efSLars-Peter Clausen }
1449851a54efSLars-Peter Clausen }
1450851a54efSLars-Peter Clausen
1451cb7a01acSMauro Carvalho Chehab state->irq = client->irq;
1452cb7a01acSMauro Carvalho Chehab mutex_init(&state->mutex);
1453937feeedSHans Verkuil state->curr_norm = V4L2_STD_NTSC;
1454f5dde49bSLars-Peter Clausen if (state->chip_info->flags & ADV7180_FLAG_RESET_POWERED)
1455e246c333SLars-Peter Clausen state->powered = true;
1456f5dde49bSLars-Peter Clausen else
1457f5dde49bSLars-Peter Clausen state->powered = false;
1458cb7a01acSMauro Carvalho Chehab state->input = 0;
1459cb7a01acSMauro Carvalho Chehab sd = &state->sd;
1460cb7a01acSMauro Carvalho Chehab v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
14615cc72c47SAkinobu Mita sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
1462cb7a01acSMauro Carvalho Chehab
1463cb7a01acSMauro Carvalho Chehab ret = adv7180_init_controls(state);
1464cb7a01acSMauro Carvalho Chehab if (ret)
1465851a54efSLars-Peter Clausen goto err_unregister_vpp_client;
1466d5d51a82SLars-Peter Clausen
1467d5d51a82SLars-Peter Clausen state->pad.flags = MEDIA_PAD_FL_SOURCE;
1468ca0fa5f0SHans Verkuil sd->entity.function = MEDIA_ENT_F_ATV_DECODER;
1469ab22e77cSMauro Carvalho Chehab ret = media_entity_pads_init(&sd->entity, 1, &state->pad);
1470cb7a01acSMauro Carvalho Chehab if (ret)
1471cb7a01acSMauro Carvalho Chehab goto err_free_ctrl;
1472fa5b7945SLars-Peter Clausen
1473d5d51a82SLars-Peter Clausen ret = init_device(state);
1474d5d51a82SLars-Peter Clausen if (ret)
1475d5d51a82SLars-Peter Clausen goto err_media_entity_cleanup;
1476d5d51a82SLars-Peter Clausen
1477fa5721d1SLars-Peter Clausen if (state->irq) {
1478fa5721d1SLars-Peter Clausen ret = request_threaded_irq(client->irq, NULL, adv7180_irq,
1479f3e991d4SLars-Peter Clausen IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
1480f3e991d4SLars-Peter Clausen KBUILD_MODNAME, state);
1481fa5721d1SLars-Peter Clausen if (ret)
1482d5d51a82SLars-Peter Clausen goto err_media_entity_cleanup;
1483fa5721d1SLars-Peter Clausen }
1484fa5721d1SLars-Peter Clausen
1485fa5b7945SLars-Peter Clausen ret = v4l2_async_register_subdev(sd);
1486fa5b7945SLars-Peter Clausen if (ret)
1487fa5b7945SLars-Peter Clausen goto err_free_irq;
1488fa5b7945SLars-Peter Clausen
1489f7b96a9fSFabio Estevam mutex_lock(&state->mutex);
1490f7b96a9fSFabio Estevam ret = adv7180_read(state, ADV7180_REG_IDENT);
1491f7b96a9fSFabio Estevam mutex_unlock(&state->mutex);
1492f7b96a9fSFabio Estevam if (ret < 0)
1493f7b96a9fSFabio Estevam goto err_v4l2_async_unregister;
1494f7b96a9fSFabio Estevam
1495f7b96a9fSFabio Estevam v4l_info(client, "chip id 0x%x found @ 0x%02x (%s)\n",
1496f7b96a9fSFabio Estevam ret, client->addr, client->adapter->name);
1497b19c25f4SFabio Estevam
1498cb7a01acSMauro Carvalho Chehab return 0;
1499cb7a01acSMauro Carvalho Chehab
1500f7b96a9fSFabio Estevam err_v4l2_async_unregister:
1501f7b96a9fSFabio Estevam v4l2_async_unregister_subdev(sd);
1502fa5b7945SLars-Peter Clausen err_free_irq:
1503fa5b7945SLars-Peter Clausen if (state->irq > 0)
1504fa5b7945SLars-Peter Clausen free_irq(client->irq, state);
1505d5d51a82SLars-Peter Clausen err_media_entity_cleanup:
1506d5d51a82SLars-Peter Clausen media_entity_cleanup(&sd->entity);
1507cb7a01acSMauro Carvalho Chehab err_free_ctrl:
1508cb7a01acSMauro Carvalho Chehab adv7180_exit_controls(state);
1509851a54efSLars-Peter Clausen err_unregister_vpp_client:
1510851a54efSLars-Peter Clausen i2c_unregister_device(state->vpp_client);
1511b37135e3SLars-Peter Clausen err_unregister_csi_client:
1512b37135e3SLars-Peter Clausen i2c_unregister_device(state->csi_client);
1513297a0ae3SLars-Peter Clausen mutex_destroy(&state->mutex);
1514cb7a01acSMauro Carvalho Chehab return ret;
1515cb7a01acSMauro Carvalho Chehab }
1516cb7a01acSMauro Carvalho Chehab
adv7180_remove(struct i2c_client * client)1517ed5c2f5fSUwe Kleine-König static void adv7180_remove(struct i2c_client *client)
1518cb7a01acSMauro Carvalho Chehab {
1519cb7a01acSMauro Carvalho Chehab struct v4l2_subdev *sd = i2c_get_clientdata(client);
1520cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd);
1521cb7a01acSMauro Carvalho Chehab
1522fa5b7945SLars-Peter Clausen v4l2_async_unregister_subdev(sd);
1523fa5b7945SLars-Peter Clausen
15240c25534dSLars-Peter Clausen if (state->irq > 0)
1525cb7a01acSMauro Carvalho Chehab free_irq(client->irq, state);
1526cb7a01acSMauro Carvalho Chehab
1527d5d51a82SLars-Peter Clausen media_entity_cleanup(&sd->entity);
1528b13f4af2SLars-Peter Clausen adv7180_exit_controls(state);
1529b37135e3SLars-Peter Clausen
1530851a54efSLars-Peter Clausen i2c_unregister_device(state->vpp_client);
1531b37135e3SLars-Peter Clausen i2c_unregister_device(state->csi_client);
1532b37135e3SLars-Peter Clausen
1533abb7c7c2SFrieder Schrempf adv7180_set_reset_pin(state, true);
153465d9e14aSSteve Longerbeam adv7180_set_power_pin(state, false);
153565d9e14aSSteve Longerbeam
1536297a0ae3SLars-Peter Clausen mutex_destroy(&state->mutex);
1537cb7a01acSMauro Carvalho Chehab }
1538cb7a01acSMauro Carvalho Chehab
1539cb7a01acSMauro Carvalho Chehab static const struct i2c_device_id adv7180_id[] = {
1540f5dde49bSLars-Peter Clausen { "adv7180", (kernel_ulong_t)&adv7180_info },
1541281ddc3cSUlrich Hecht { "adv7180cp", (kernel_ulong_t)&adv7180_info },
1542281ddc3cSUlrich Hecht { "adv7180st", (kernel_ulong_t)&adv7180_info },
1543c5ef8f8cSLars-Peter Clausen { "adv7182", (kernel_ulong_t)&adv7182_info },
1544bf7dcb80SLars-Peter Clausen { "adv7280", (kernel_ulong_t)&adv7280_info },
1545b37135e3SLars-Peter Clausen { "adv7280-m", (kernel_ulong_t)&adv7280_m_info },
1546bf7dcb80SLars-Peter Clausen { "adv7281", (kernel_ulong_t)&adv7281_info },
1547b37135e3SLars-Peter Clausen { "adv7281-m", (kernel_ulong_t)&adv7281_m_info },
1548b37135e3SLars-Peter Clausen { "adv7281-ma", (kernel_ulong_t)&adv7281_ma_info },
1549851a54efSLars-Peter Clausen { "adv7282", (kernel_ulong_t)&adv7282_info },
1550851a54efSLars-Peter Clausen { "adv7282-m", (kernel_ulong_t)&adv7282_m_info },
1551cb7a01acSMauro Carvalho Chehab {},
1552cb7a01acSMauro Carvalho Chehab };
1553f5dde49bSLars-Peter Clausen MODULE_DEVICE_TABLE(i2c, adv7180_id);
1554cb7a01acSMauro Carvalho Chehab
1555cc1088dcSLars-Peter Clausen #ifdef CONFIG_PM_SLEEP
adv7180_suspend(struct device * dev)1556cc1088dcSLars-Peter Clausen static int adv7180_suspend(struct device *dev)
1557cb7a01acSMauro Carvalho Chehab {
155817ed3c90SKrzysztof Kozlowski struct v4l2_subdev *sd = dev_get_drvdata(dev);
1559e246c333SLars-Peter Clausen struct adv7180_state *state = to_state(sd);
1560cb7a01acSMauro Carvalho Chehab
15613999e5d0SLars-Peter Clausen return adv7180_set_power(state, false);
1562cb7a01acSMauro Carvalho Chehab }
1563cb7a01acSMauro Carvalho Chehab
adv7180_resume(struct device * dev)1564cc1088dcSLars-Peter Clausen static int adv7180_resume(struct device *dev)
1565cb7a01acSMauro Carvalho Chehab {
156617ed3c90SKrzysztof Kozlowski struct v4l2_subdev *sd = dev_get_drvdata(dev);
1567cb7a01acSMauro Carvalho Chehab struct adv7180_state *state = to_state(sd);
1568cb7a01acSMauro Carvalho Chehab int ret;
1569cb7a01acSMauro Carvalho Chehab
15703999e5d0SLars-Peter Clausen ret = init_device(state);
1571cb7a01acSMauro Carvalho Chehab if (ret < 0)
1572cb7a01acSMauro Carvalho Chehab return ret;
1573c18818e9SLars-Peter Clausen
1574c18818e9SLars-Peter Clausen ret = adv7180_set_power(state, state->powered);
1575c18818e9SLars-Peter Clausen if (ret)
1576c18818e9SLars-Peter Clausen return ret;
1577c18818e9SLars-Peter Clausen
1578cb7a01acSMauro Carvalho Chehab return 0;
1579cb7a01acSMauro Carvalho Chehab }
1580cc1088dcSLars-Peter Clausen
1581cc1088dcSLars-Peter Clausen static SIMPLE_DEV_PM_OPS(adv7180_pm_ops, adv7180_suspend, adv7180_resume);
1582cc1088dcSLars-Peter Clausen #define ADV7180_PM_OPS (&adv7180_pm_ops)
1583cc1088dcSLars-Peter Clausen
1584cc1088dcSLars-Peter Clausen #else
1585cc1088dcSLars-Peter Clausen #define ADV7180_PM_OPS NULL
1586cb7a01acSMauro Carvalho Chehab #endif
1587cb7a01acSMauro Carvalho Chehab
1588250121d3SBen Dooks #ifdef CONFIG_OF
1589250121d3SBen Dooks static const struct of_device_id adv7180_of_id[] = {
1590250121d3SBen Dooks { .compatible = "adi,adv7180", },
1591ce1ec5c0SUlrich Hecht { .compatible = "adi,adv7180cp", },
1592ce1ec5c0SUlrich Hecht { .compatible = "adi,adv7180st", },
1593bf14e74cSJulian Scheel { .compatible = "adi,adv7182", },
1594bf14e74cSJulian Scheel { .compatible = "adi,adv7280", },
1595bf14e74cSJulian Scheel { .compatible = "adi,adv7280-m", },
1596bf14e74cSJulian Scheel { .compatible = "adi,adv7281", },
1597bf14e74cSJulian Scheel { .compatible = "adi,adv7281-m", },
1598bf14e74cSJulian Scheel { .compatible = "adi,adv7281-ma", },
1599bf14e74cSJulian Scheel { .compatible = "adi,adv7282", },
1600bf14e74cSJulian Scheel { .compatible = "adi,adv7282-m", },
1601250121d3SBen Dooks { },
1602250121d3SBen Dooks };
1603250121d3SBen Dooks
1604250121d3SBen Dooks MODULE_DEVICE_TABLE(of, adv7180_of_id);
1605250121d3SBen Dooks #endif
1606250121d3SBen Dooks
1607cb7a01acSMauro Carvalho Chehab static struct i2c_driver adv7180_driver = {
1608cb7a01acSMauro Carvalho Chehab .driver = {
1609cb7a01acSMauro Carvalho Chehab .name = KBUILD_MODNAME,
1610cc1088dcSLars-Peter Clausen .pm = ADV7180_PM_OPS,
1611250121d3SBen Dooks .of_match_table = of_match_ptr(adv7180_of_id),
1612cb7a01acSMauro Carvalho Chehab },
1613*aaeb31c0SUwe Kleine-König .probe = adv7180_probe,
16144c62e976SGreg Kroah-Hartman .remove = adv7180_remove,
1615cb7a01acSMauro Carvalho Chehab .id_table = adv7180_id,
1616cb7a01acSMauro Carvalho Chehab };
1617cb7a01acSMauro Carvalho Chehab
1618cb7a01acSMauro Carvalho Chehab module_i2c_driver(adv7180_driver);
1619cb7a01acSMauro Carvalho Chehab
1620cb7a01acSMauro Carvalho Chehab MODULE_DESCRIPTION("Analog Devices ADV7180 video decoder driver");
1621cb7a01acSMauro Carvalho Chehab MODULE_AUTHOR("Mocean Laboratories");
1622cb7a01acSMauro Carvalho Chehab MODULE_LICENSE("GPL v2");
1623