xref: /openbmc/linux/drivers/media/i2c/adv7604.c (revision bb88f325)
154450f59SHans Verkuil /*
254450f59SHans Verkuil  * adv7604 - Analog Devices ADV7604 video decoder driver
354450f59SHans Verkuil  *
454450f59SHans Verkuil  * Copyright 2012 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
554450f59SHans Verkuil  *
654450f59SHans Verkuil  * This program is free software; you may redistribute it and/or modify
754450f59SHans Verkuil  * it under the terms of the GNU General Public License as published by
854450f59SHans Verkuil  * the Free Software Foundation; version 2 of the License.
954450f59SHans Verkuil  *
1054450f59SHans Verkuil  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1154450f59SHans Verkuil  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1254450f59SHans Verkuil  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1354450f59SHans Verkuil  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
1454450f59SHans Verkuil  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
1554450f59SHans Verkuil  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1654450f59SHans Verkuil  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1754450f59SHans Verkuil  * SOFTWARE.
1854450f59SHans Verkuil  *
1954450f59SHans Verkuil  */
2054450f59SHans Verkuil 
2154450f59SHans Verkuil /*
2254450f59SHans Verkuil  * References (c = chapter, p = page):
2354450f59SHans Verkuil  * REF_01 - Analog devices, ADV7604, Register Settings Recommendations,
2454450f59SHans Verkuil  *		Revision 2.5, June 2010
2554450f59SHans Verkuil  * REF_02 - Analog devices, Register map documentation, Documentation of
2654450f59SHans Verkuil  *		the register maps, Software manual, Rev. F, June 2010
2754450f59SHans Verkuil  * REF_03 - Analog devices, ADV7604, Hardware Manual, Rev. F, August 2010
2854450f59SHans Verkuil  */
2954450f59SHans Verkuil 
3054450f59SHans Verkuil 
3154450f59SHans Verkuil #include <linux/kernel.h>
3254450f59SHans Verkuil #include <linux/module.h>
3354450f59SHans Verkuil #include <linux/slab.h>
3454450f59SHans Verkuil #include <linux/i2c.h>
3554450f59SHans Verkuil #include <linux/delay.h>
3654450f59SHans Verkuil #include <linux/videodev2.h>
3754450f59SHans Verkuil #include <linux/workqueue.h>
3854450f59SHans Verkuil #include <linux/v4l2-dv-timings.h>
3954450f59SHans Verkuil #include <media/v4l2-device.h>
4054450f59SHans Verkuil #include <media/v4l2-ctrls.h>
4125764158SHans Verkuil #include <media/v4l2-dv-timings.h>
4254450f59SHans Verkuil #include <media/adv7604.h>
4354450f59SHans Verkuil 
4454450f59SHans Verkuil static int debug;
4554450f59SHans Verkuil module_param(debug, int, 0644);
4654450f59SHans Verkuil MODULE_PARM_DESC(debug, "debug level (0-2)");
4754450f59SHans Verkuil 
4854450f59SHans Verkuil MODULE_DESCRIPTION("Analog Devices ADV7604 video decoder driver");
4954450f59SHans Verkuil MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>");
5054450f59SHans Verkuil MODULE_AUTHOR("Mats Randgaard <mats.randgaard@cisco.com>");
5154450f59SHans Verkuil MODULE_LICENSE("GPL");
5254450f59SHans Verkuil 
5354450f59SHans Verkuil /* ADV7604 system clock frequency */
5454450f59SHans Verkuil #define ADV7604_fsc (28636360)
5554450f59SHans Verkuil 
566b0d5d34SHans Verkuil #define DIGITAL_INPUT (state->mode == ADV7604_MODE_HDMI)
5754450f59SHans Verkuil 
5854450f59SHans Verkuil /*
5954450f59SHans Verkuil  **********************************************************************
6054450f59SHans Verkuil  *
6154450f59SHans Verkuil  *  Arrays with configuration parameters for the ADV7604
6254450f59SHans Verkuil  *
6354450f59SHans Verkuil  **********************************************************************
6454450f59SHans Verkuil  */
6554450f59SHans Verkuil struct adv7604_state {
6654450f59SHans Verkuil 	struct adv7604_platform_data pdata;
6754450f59SHans Verkuil 	struct v4l2_subdev sd;
6854450f59SHans Verkuil 	struct media_pad pad;
6954450f59SHans Verkuil 	struct v4l2_ctrl_handler hdl;
706b0d5d34SHans Verkuil 	enum adv7604_mode mode;
7154450f59SHans Verkuil 	struct v4l2_dv_timings timings;
7254450f59SHans Verkuil 	u8 edid[256];
7354450f59SHans Verkuil 	unsigned edid_blocks;
7454450f59SHans Verkuil 	struct v4l2_fract aspect_ratio;
7554450f59SHans Verkuil 	u32 rgb_quantization_range;
7654450f59SHans Verkuil 	struct workqueue_struct *work_queues;
7754450f59SHans Verkuil 	struct delayed_work delayed_work_enable_hotplug;
7854450f59SHans Verkuil 	bool connector_hdmi;
79cf9afb1dSHans Verkuil 	bool restart_stdi_once;
8025a64ac9SMats Randgaard 	u32 prev_input_status;
8154450f59SHans Verkuil 
8254450f59SHans Verkuil 	/* i2c clients */
8354450f59SHans Verkuil 	struct i2c_client *i2c_avlink;
8454450f59SHans Verkuil 	struct i2c_client *i2c_cec;
8554450f59SHans Verkuil 	struct i2c_client *i2c_infoframe;
8654450f59SHans Verkuil 	struct i2c_client *i2c_esdp;
8754450f59SHans Verkuil 	struct i2c_client *i2c_dpp;
8854450f59SHans Verkuil 	struct i2c_client *i2c_afe;
8954450f59SHans Verkuil 	struct i2c_client *i2c_repeater;
9054450f59SHans Verkuil 	struct i2c_client *i2c_edid;
9154450f59SHans Verkuil 	struct i2c_client *i2c_hdmi;
9254450f59SHans Verkuil 	struct i2c_client *i2c_test;
9354450f59SHans Verkuil 	struct i2c_client *i2c_cp;
9454450f59SHans Verkuil 	struct i2c_client *i2c_vdp;
9554450f59SHans Verkuil 
9654450f59SHans Verkuil 	/* controls */
9754450f59SHans Verkuil 	struct v4l2_ctrl *detect_tx_5v_ctrl;
9854450f59SHans Verkuil 	struct v4l2_ctrl *analog_sampling_phase_ctrl;
9954450f59SHans Verkuil 	struct v4l2_ctrl *free_run_color_manual_ctrl;
10054450f59SHans Verkuil 	struct v4l2_ctrl *free_run_color_ctrl;
10154450f59SHans Verkuil 	struct v4l2_ctrl *rgb_quantization_range_ctrl;
10254450f59SHans Verkuil };
10354450f59SHans Verkuil 
10454450f59SHans Verkuil /* Supported CEA and DMT timings */
10554450f59SHans Verkuil static const struct v4l2_dv_timings adv7604_timings[] = {
10654450f59SHans Verkuil 	V4L2_DV_BT_CEA_720X480P59_94,
10754450f59SHans Verkuil 	V4L2_DV_BT_CEA_720X576P50,
10854450f59SHans Verkuil 	V4L2_DV_BT_CEA_1280X720P24,
10954450f59SHans Verkuil 	V4L2_DV_BT_CEA_1280X720P25,
11054450f59SHans Verkuil 	V4L2_DV_BT_CEA_1280X720P50,
11154450f59SHans Verkuil 	V4L2_DV_BT_CEA_1280X720P60,
11254450f59SHans Verkuil 	V4L2_DV_BT_CEA_1920X1080P24,
11354450f59SHans Verkuil 	V4L2_DV_BT_CEA_1920X1080P25,
11454450f59SHans Verkuil 	V4L2_DV_BT_CEA_1920X1080P30,
11554450f59SHans Verkuil 	V4L2_DV_BT_CEA_1920X1080P50,
11654450f59SHans Verkuil 	V4L2_DV_BT_CEA_1920X1080P60,
11754450f59SHans Verkuil 
118ccbd5bc4SHans Verkuil 	/* sorted by DMT ID */
11954450f59SHans Verkuil 	V4L2_DV_BT_DMT_640X350P85,
12054450f59SHans Verkuil 	V4L2_DV_BT_DMT_640X400P85,
12154450f59SHans Verkuil 	V4L2_DV_BT_DMT_720X400P85,
12254450f59SHans Verkuil 	V4L2_DV_BT_DMT_640X480P60,
12354450f59SHans Verkuil 	V4L2_DV_BT_DMT_640X480P72,
12454450f59SHans Verkuil 	V4L2_DV_BT_DMT_640X480P75,
12554450f59SHans Verkuil 	V4L2_DV_BT_DMT_640X480P85,
12654450f59SHans Verkuil 	V4L2_DV_BT_DMT_800X600P56,
12754450f59SHans Verkuil 	V4L2_DV_BT_DMT_800X600P60,
12854450f59SHans Verkuil 	V4L2_DV_BT_DMT_800X600P72,
12954450f59SHans Verkuil 	V4L2_DV_BT_DMT_800X600P75,
13054450f59SHans Verkuil 	V4L2_DV_BT_DMT_800X600P85,
13154450f59SHans Verkuil 	V4L2_DV_BT_DMT_848X480P60,
13254450f59SHans Verkuil 	V4L2_DV_BT_DMT_1024X768P60,
13354450f59SHans Verkuil 	V4L2_DV_BT_DMT_1024X768P70,
13454450f59SHans Verkuil 	V4L2_DV_BT_DMT_1024X768P75,
13554450f59SHans Verkuil 	V4L2_DV_BT_DMT_1024X768P85,
13654450f59SHans Verkuil 	V4L2_DV_BT_DMT_1152X864P75,
13754450f59SHans Verkuil 	V4L2_DV_BT_DMT_1280X768P60_RB,
13854450f59SHans Verkuil 	V4L2_DV_BT_DMT_1280X768P60,
13954450f59SHans Verkuil 	V4L2_DV_BT_DMT_1280X768P75,
14054450f59SHans Verkuil 	V4L2_DV_BT_DMT_1280X768P85,
14154450f59SHans Verkuil 	V4L2_DV_BT_DMT_1280X800P60_RB,
14254450f59SHans Verkuil 	V4L2_DV_BT_DMT_1280X800P60,
14354450f59SHans Verkuil 	V4L2_DV_BT_DMT_1280X800P75,
14454450f59SHans Verkuil 	V4L2_DV_BT_DMT_1280X800P85,
14554450f59SHans Verkuil 	V4L2_DV_BT_DMT_1280X960P60,
14654450f59SHans Verkuil 	V4L2_DV_BT_DMT_1280X960P85,
14754450f59SHans Verkuil 	V4L2_DV_BT_DMT_1280X1024P60,
14854450f59SHans Verkuil 	V4L2_DV_BT_DMT_1280X1024P75,
14954450f59SHans Verkuil 	V4L2_DV_BT_DMT_1280X1024P85,
15054450f59SHans Verkuil 	V4L2_DV_BT_DMT_1360X768P60,
15154450f59SHans Verkuil 	V4L2_DV_BT_DMT_1400X1050P60_RB,
15254450f59SHans Verkuil 	V4L2_DV_BT_DMT_1400X1050P60,
15354450f59SHans Verkuil 	V4L2_DV_BT_DMT_1400X1050P75,
15454450f59SHans Verkuil 	V4L2_DV_BT_DMT_1400X1050P85,
15554450f59SHans Verkuil 	V4L2_DV_BT_DMT_1440X900P60_RB,
15654450f59SHans Verkuil 	V4L2_DV_BT_DMT_1440X900P60,
15754450f59SHans Verkuil 	V4L2_DV_BT_DMT_1600X1200P60,
15854450f59SHans Verkuil 	V4L2_DV_BT_DMT_1680X1050P60_RB,
15954450f59SHans Verkuil 	V4L2_DV_BT_DMT_1680X1050P60,
16054450f59SHans Verkuil 	V4L2_DV_BT_DMT_1792X1344P60,
16154450f59SHans Verkuil 	V4L2_DV_BT_DMT_1856X1392P60,
16254450f59SHans Verkuil 	V4L2_DV_BT_DMT_1920X1200P60_RB,
16354450f59SHans Verkuil 	V4L2_DV_BT_DMT_1366X768P60,
16454450f59SHans Verkuil 	V4L2_DV_BT_DMT_1920X1080P60,
16554450f59SHans Verkuil 	{ },
16654450f59SHans Verkuil };
16754450f59SHans Verkuil 
168ccbd5bc4SHans Verkuil struct adv7604_video_standards {
169ccbd5bc4SHans Verkuil 	struct v4l2_dv_timings timings;
170ccbd5bc4SHans Verkuil 	u8 vid_std;
171ccbd5bc4SHans Verkuil 	u8 v_freq;
172ccbd5bc4SHans Verkuil };
173ccbd5bc4SHans Verkuil 
174ccbd5bc4SHans Verkuil /* sorted by number of lines */
175ccbd5bc4SHans Verkuil static const struct adv7604_video_standards adv7604_prim_mode_comp[] = {
176ccbd5bc4SHans Verkuil 	/* { V4L2_DV_BT_CEA_720X480P59_94, 0x0a, 0x00 }, TODO flickering */
177ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_CEA_720X576P50, 0x0b, 0x00 },
178ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_CEA_1280X720P50, 0x19, 0x01 },
179ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_CEA_1280X720P60, 0x19, 0x00 },
180ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_CEA_1920X1080P24, 0x1e, 0x04 },
181ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_CEA_1920X1080P25, 0x1e, 0x03 },
182ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_CEA_1920X1080P30, 0x1e, 0x02 },
183ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_CEA_1920X1080P50, 0x1e, 0x01 },
184ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_CEA_1920X1080P60, 0x1e, 0x00 },
185ccbd5bc4SHans Verkuil 	/* TODO add 1920x1080P60_RB (CVT timing) */
186ccbd5bc4SHans Verkuil 	{ },
187ccbd5bc4SHans Verkuil };
188ccbd5bc4SHans Verkuil 
189ccbd5bc4SHans Verkuil /* sorted by number of lines */
190ccbd5bc4SHans Verkuil static const struct adv7604_video_standards adv7604_prim_mode_gr[] = {
191ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_640X480P60, 0x08, 0x00 },
192ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_640X480P72, 0x09, 0x00 },
193ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_640X480P75, 0x0a, 0x00 },
194ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_640X480P85, 0x0b, 0x00 },
195ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_800X600P56, 0x00, 0x00 },
196ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_800X600P60, 0x01, 0x00 },
197ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_800X600P72, 0x02, 0x00 },
198ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_800X600P75, 0x03, 0x00 },
199ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_800X600P85, 0x04, 0x00 },
200ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_1024X768P60, 0x0c, 0x00 },
201ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_1024X768P70, 0x0d, 0x00 },
202ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_1024X768P75, 0x0e, 0x00 },
203ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_1024X768P85, 0x0f, 0x00 },
204ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_1280X1024P60, 0x05, 0x00 },
205ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_1280X1024P75, 0x06, 0x00 },
206ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_1360X768P60, 0x12, 0x00 },
207ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_1366X768P60, 0x13, 0x00 },
208ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_1400X1050P60, 0x14, 0x00 },
209ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_1400X1050P75, 0x15, 0x00 },
210ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_1600X1200P60, 0x16, 0x00 }, /* TODO not tested */
211ccbd5bc4SHans Verkuil 	/* TODO add 1600X1200P60_RB (not a DMT timing) */
212ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_1680X1050P60, 0x18, 0x00 },
213ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_1920X1200P60_RB, 0x19, 0x00 }, /* TODO not tested */
214ccbd5bc4SHans Verkuil 	{ },
215ccbd5bc4SHans Verkuil };
216ccbd5bc4SHans Verkuil 
217ccbd5bc4SHans Verkuil /* sorted by number of lines */
218ccbd5bc4SHans Verkuil static const struct adv7604_video_standards adv7604_prim_mode_hdmi_comp[] = {
219ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_CEA_720X480P59_94, 0x0a, 0x00 },
220ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_CEA_720X576P50, 0x0b, 0x00 },
221ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_CEA_1280X720P50, 0x13, 0x01 },
222ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_CEA_1280X720P60, 0x13, 0x00 },
223ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_CEA_1920X1080P24, 0x1e, 0x04 },
224ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_CEA_1920X1080P25, 0x1e, 0x03 },
225ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_CEA_1920X1080P30, 0x1e, 0x02 },
226ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_CEA_1920X1080P50, 0x1e, 0x01 },
227ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_CEA_1920X1080P60, 0x1e, 0x00 },
228ccbd5bc4SHans Verkuil 	{ },
229ccbd5bc4SHans Verkuil };
230ccbd5bc4SHans Verkuil 
231ccbd5bc4SHans Verkuil /* sorted by number of lines */
232ccbd5bc4SHans Verkuil static const struct adv7604_video_standards adv7604_prim_mode_hdmi_gr[] = {
233ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_640X480P60, 0x08, 0x00 },
234ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_640X480P72, 0x09, 0x00 },
235ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_640X480P75, 0x0a, 0x00 },
236ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_640X480P85, 0x0b, 0x00 },
237ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_800X600P56, 0x00, 0x00 },
238ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_800X600P60, 0x01, 0x00 },
239ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_800X600P72, 0x02, 0x00 },
240ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_800X600P75, 0x03, 0x00 },
241ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_800X600P85, 0x04, 0x00 },
242ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_1024X768P60, 0x0c, 0x00 },
243ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_1024X768P70, 0x0d, 0x00 },
244ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_1024X768P75, 0x0e, 0x00 },
245ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_1024X768P85, 0x0f, 0x00 },
246ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_1280X1024P60, 0x05, 0x00 },
247ccbd5bc4SHans Verkuil 	{ V4L2_DV_BT_DMT_1280X1024P75, 0x06, 0x00 },
248ccbd5bc4SHans Verkuil 	{ },
249ccbd5bc4SHans Verkuil };
250ccbd5bc4SHans Verkuil 
25154450f59SHans Verkuil /* ----------------------------------------------------------------------- */
25254450f59SHans Verkuil 
25354450f59SHans Verkuil static inline struct adv7604_state *to_state(struct v4l2_subdev *sd)
25454450f59SHans Verkuil {
25554450f59SHans Verkuil 	return container_of(sd, struct adv7604_state, sd);
25654450f59SHans Verkuil }
25754450f59SHans Verkuil 
25854450f59SHans Verkuil static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
25954450f59SHans Verkuil {
26054450f59SHans Verkuil 	return &container_of(ctrl->handler, struct adv7604_state, hdl)->sd;
26154450f59SHans Verkuil }
26254450f59SHans Verkuil 
26354450f59SHans Verkuil static inline unsigned hblanking(const struct v4l2_bt_timings *t)
26454450f59SHans Verkuil {
265eacf8f9aSHans Verkuil 	return V4L2_DV_BT_BLANKING_WIDTH(t);
26654450f59SHans Verkuil }
26754450f59SHans Verkuil 
26854450f59SHans Verkuil static inline unsigned htotal(const struct v4l2_bt_timings *t)
26954450f59SHans Verkuil {
270eacf8f9aSHans Verkuil 	return V4L2_DV_BT_FRAME_WIDTH(t);
27154450f59SHans Verkuil }
27254450f59SHans Verkuil 
27354450f59SHans Verkuil static inline unsigned vblanking(const struct v4l2_bt_timings *t)
27454450f59SHans Verkuil {
275eacf8f9aSHans Verkuil 	return V4L2_DV_BT_BLANKING_HEIGHT(t);
27654450f59SHans Verkuil }
27754450f59SHans Verkuil 
27854450f59SHans Verkuil static inline unsigned vtotal(const struct v4l2_bt_timings *t)
27954450f59SHans Verkuil {
280eacf8f9aSHans Verkuil 	return V4L2_DV_BT_FRAME_HEIGHT(t);
28154450f59SHans Verkuil }
28254450f59SHans Verkuil 
28354450f59SHans Verkuil /* ----------------------------------------------------------------------- */
28454450f59SHans Verkuil 
28554450f59SHans Verkuil static s32 adv_smbus_read_byte_data_check(struct i2c_client *client,
28654450f59SHans Verkuil 		u8 command, bool check)
28754450f59SHans Verkuil {
28854450f59SHans Verkuil 	union i2c_smbus_data data;
28954450f59SHans Verkuil 
29054450f59SHans Verkuil 	if (!i2c_smbus_xfer(client->adapter, client->addr, client->flags,
29154450f59SHans Verkuil 			I2C_SMBUS_READ, command,
29254450f59SHans Verkuil 			I2C_SMBUS_BYTE_DATA, &data))
29354450f59SHans Verkuil 		return data.byte;
29454450f59SHans Verkuil 	if (check)
29554450f59SHans Verkuil 		v4l_err(client, "error reading %02x, %02x\n",
29654450f59SHans Verkuil 				client->addr, command);
29754450f59SHans Verkuil 	return -EIO;
29854450f59SHans Verkuil }
29954450f59SHans Verkuil 
30054450f59SHans Verkuil static s32 adv_smbus_read_byte_data(struct i2c_client *client, u8 command)
30154450f59SHans Verkuil {
30254450f59SHans Verkuil 	return adv_smbus_read_byte_data_check(client, command, true);
30354450f59SHans Verkuil }
30454450f59SHans Verkuil 
30554450f59SHans Verkuil static s32 adv_smbus_write_byte_data(struct i2c_client *client,
30654450f59SHans Verkuil 					u8 command, u8 value)
30754450f59SHans Verkuil {
30854450f59SHans Verkuil 	union i2c_smbus_data data;
30954450f59SHans Verkuil 	int err;
31054450f59SHans Verkuil 	int i;
31154450f59SHans Verkuil 
31254450f59SHans Verkuil 	data.byte = value;
31354450f59SHans Verkuil 	for (i = 0; i < 3; i++) {
31454450f59SHans Verkuil 		err = i2c_smbus_xfer(client->adapter, client->addr,
31554450f59SHans Verkuil 				client->flags,
31654450f59SHans Verkuil 				I2C_SMBUS_WRITE, command,
31754450f59SHans Verkuil 				I2C_SMBUS_BYTE_DATA, &data);
31854450f59SHans Verkuil 		if (!err)
31954450f59SHans Verkuil 			break;
32054450f59SHans Verkuil 	}
32154450f59SHans Verkuil 	if (err < 0)
32254450f59SHans Verkuil 		v4l_err(client, "error writing %02x, %02x, %02x\n",
32354450f59SHans Verkuil 				client->addr, command, value);
32454450f59SHans Verkuil 	return err;
32554450f59SHans Verkuil }
32654450f59SHans Verkuil 
32754450f59SHans Verkuil static s32 adv_smbus_write_i2c_block_data(struct i2c_client *client,
32854450f59SHans Verkuil 	       u8 command, unsigned length, const u8 *values)
32954450f59SHans Verkuil {
33054450f59SHans Verkuil 	union i2c_smbus_data data;
33154450f59SHans Verkuil 
33254450f59SHans Verkuil 	if (length > I2C_SMBUS_BLOCK_MAX)
33354450f59SHans Verkuil 		length = I2C_SMBUS_BLOCK_MAX;
33454450f59SHans Verkuil 	data.block[0] = length;
33554450f59SHans Verkuil 	memcpy(data.block + 1, values, length);
33654450f59SHans Verkuil 	return i2c_smbus_xfer(client->adapter, client->addr, client->flags,
33754450f59SHans Verkuil 			      I2C_SMBUS_WRITE, command,
33854450f59SHans Verkuil 			      I2C_SMBUS_I2C_BLOCK_DATA, &data);
33954450f59SHans Verkuil }
34054450f59SHans Verkuil 
34154450f59SHans Verkuil /* ----------------------------------------------------------------------- */
34254450f59SHans Verkuil 
34354450f59SHans Verkuil static inline int io_read(struct v4l2_subdev *sd, u8 reg)
34454450f59SHans Verkuil {
34554450f59SHans Verkuil 	struct i2c_client *client = v4l2_get_subdevdata(sd);
34654450f59SHans Verkuil 
34754450f59SHans Verkuil 	return adv_smbus_read_byte_data(client, reg);
34854450f59SHans Verkuil }
34954450f59SHans Verkuil 
35054450f59SHans Verkuil static inline int io_write(struct v4l2_subdev *sd, u8 reg, u8 val)
35154450f59SHans Verkuil {
35254450f59SHans Verkuil 	struct i2c_client *client = v4l2_get_subdevdata(sd);
35354450f59SHans Verkuil 
35454450f59SHans Verkuil 	return adv_smbus_write_byte_data(client, reg, val);
35554450f59SHans Verkuil }
35654450f59SHans Verkuil 
35754450f59SHans Verkuil static inline int io_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
35854450f59SHans Verkuil {
35954450f59SHans Verkuil 	return io_write(sd, reg, (io_read(sd, reg) & mask) | val);
36054450f59SHans Verkuil }
36154450f59SHans Verkuil 
36254450f59SHans Verkuil static inline int avlink_read(struct v4l2_subdev *sd, u8 reg)
36354450f59SHans Verkuil {
36454450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
36554450f59SHans Verkuil 
36654450f59SHans Verkuil 	return adv_smbus_read_byte_data(state->i2c_avlink, reg);
36754450f59SHans Verkuil }
36854450f59SHans Verkuil 
36954450f59SHans Verkuil static inline int avlink_write(struct v4l2_subdev *sd, u8 reg, u8 val)
37054450f59SHans Verkuil {
37154450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
37254450f59SHans Verkuil 
37354450f59SHans Verkuil 	return adv_smbus_write_byte_data(state->i2c_avlink, reg, val);
37454450f59SHans Verkuil }
37554450f59SHans Verkuil 
37654450f59SHans Verkuil static inline int cec_read(struct v4l2_subdev *sd, u8 reg)
37754450f59SHans Verkuil {
37854450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
37954450f59SHans Verkuil 
38054450f59SHans Verkuil 	return adv_smbus_read_byte_data(state->i2c_cec, reg);
38154450f59SHans Verkuil }
38254450f59SHans Verkuil 
38354450f59SHans Verkuil static inline int cec_write(struct v4l2_subdev *sd, u8 reg, u8 val)
38454450f59SHans Verkuil {
38554450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
38654450f59SHans Verkuil 
38754450f59SHans Verkuil 	return adv_smbus_write_byte_data(state->i2c_cec, reg, val);
38854450f59SHans Verkuil }
38954450f59SHans Verkuil 
39054450f59SHans Verkuil static inline int cec_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
39154450f59SHans Verkuil {
39254450f59SHans Verkuil 	return cec_write(sd, reg, (cec_read(sd, reg) & mask) | val);
39354450f59SHans Verkuil }
39454450f59SHans Verkuil 
39554450f59SHans Verkuil static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg)
39654450f59SHans Verkuil {
39754450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
39854450f59SHans Verkuil 
39954450f59SHans Verkuil 	return adv_smbus_read_byte_data(state->i2c_infoframe, reg);
40054450f59SHans Verkuil }
40154450f59SHans Verkuil 
40254450f59SHans Verkuil static inline int infoframe_write(struct v4l2_subdev *sd, u8 reg, u8 val)
40354450f59SHans Verkuil {
40454450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
40554450f59SHans Verkuil 
40654450f59SHans Verkuil 	return adv_smbus_write_byte_data(state->i2c_infoframe, reg, val);
40754450f59SHans Verkuil }
40854450f59SHans Verkuil 
40954450f59SHans Verkuil static inline int esdp_read(struct v4l2_subdev *sd, u8 reg)
41054450f59SHans Verkuil {
41154450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
41254450f59SHans Verkuil 
41354450f59SHans Verkuil 	return adv_smbus_read_byte_data(state->i2c_esdp, reg);
41454450f59SHans Verkuil }
41554450f59SHans Verkuil 
41654450f59SHans Verkuil static inline int esdp_write(struct v4l2_subdev *sd, u8 reg, u8 val)
41754450f59SHans Verkuil {
41854450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
41954450f59SHans Verkuil 
42054450f59SHans Verkuil 	return adv_smbus_write_byte_data(state->i2c_esdp, reg, val);
42154450f59SHans Verkuil }
42254450f59SHans Verkuil 
42354450f59SHans Verkuil static inline int dpp_read(struct v4l2_subdev *sd, u8 reg)
42454450f59SHans Verkuil {
42554450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
42654450f59SHans Verkuil 
42754450f59SHans Verkuil 	return adv_smbus_read_byte_data(state->i2c_dpp, reg);
42854450f59SHans Verkuil }
42954450f59SHans Verkuil 
43054450f59SHans Verkuil static inline int dpp_write(struct v4l2_subdev *sd, u8 reg, u8 val)
43154450f59SHans Verkuil {
43254450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
43354450f59SHans Verkuil 
43454450f59SHans Verkuil 	return adv_smbus_write_byte_data(state->i2c_dpp, reg, val);
43554450f59SHans Verkuil }
43654450f59SHans Verkuil 
43754450f59SHans Verkuil static inline int afe_read(struct v4l2_subdev *sd, u8 reg)
43854450f59SHans Verkuil {
43954450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
44054450f59SHans Verkuil 
44154450f59SHans Verkuil 	return adv_smbus_read_byte_data(state->i2c_afe, reg);
44254450f59SHans Verkuil }
44354450f59SHans Verkuil 
44454450f59SHans Verkuil static inline int afe_write(struct v4l2_subdev *sd, u8 reg, u8 val)
44554450f59SHans Verkuil {
44654450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
44754450f59SHans Verkuil 
44854450f59SHans Verkuil 	return adv_smbus_write_byte_data(state->i2c_afe, reg, val);
44954450f59SHans Verkuil }
45054450f59SHans Verkuil 
45154450f59SHans Verkuil static inline int rep_read(struct v4l2_subdev *sd, u8 reg)
45254450f59SHans Verkuil {
45354450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
45454450f59SHans Verkuil 
45554450f59SHans Verkuil 	return adv_smbus_read_byte_data(state->i2c_repeater, reg);
45654450f59SHans Verkuil }
45754450f59SHans Verkuil 
45854450f59SHans Verkuil static inline int rep_write(struct v4l2_subdev *sd, u8 reg, u8 val)
45954450f59SHans Verkuil {
46054450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
46154450f59SHans Verkuil 
46254450f59SHans Verkuil 	return adv_smbus_write_byte_data(state->i2c_repeater, reg, val);
46354450f59SHans Verkuil }
46454450f59SHans Verkuil 
46554450f59SHans Verkuil static inline int rep_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
46654450f59SHans Verkuil {
46754450f59SHans Verkuil 	return rep_write(sd, reg, (rep_read(sd, reg) & mask) | val);
46854450f59SHans Verkuil }
46954450f59SHans Verkuil 
47054450f59SHans Verkuil static inline int edid_read(struct v4l2_subdev *sd, u8 reg)
47154450f59SHans Verkuil {
47254450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
47354450f59SHans Verkuil 
47454450f59SHans Verkuil 	return adv_smbus_read_byte_data(state->i2c_edid, reg);
47554450f59SHans Verkuil }
47654450f59SHans Verkuil 
47754450f59SHans Verkuil static inline int edid_write(struct v4l2_subdev *sd, u8 reg, u8 val)
47854450f59SHans Verkuil {
47954450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
48054450f59SHans Verkuil 
48154450f59SHans Verkuil 	return adv_smbus_write_byte_data(state->i2c_edid, reg, val);
48254450f59SHans Verkuil }
48354450f59SHans Verkuil 
48454450f59SHans Verkuil static inline int edid_read_block(struct v4l2_subdev *sd, unsigned len, u8 *val)
48554450f59SHans Verkuil {
48654450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
48754450f59SHans Verkuil 	struct i2c_client *client = state->i2c_edid;
48854450f59SHans Verkuil 	u8 msgbuf0[1] = { 0 };
48954450f59SHans Verkuil 	u8 msgbuf1[256];
49009f29673SShubhrajyoti D 	struct i2c_msg msg[2] = {
49109f29673SShubhrajyoti D 		{
49209f29673SShubhrajyoti D 			.addr = client->addr,
49309f29673SShubhrajyoti D 			.len = 1,
49409f29673SShubhrajyoti D 			.buf = msgbuf0
49509f29673SShubhrajyoti D 		},
49609f29673SShubhrajyoti D 		{
49709f29673SShubhrajyoti D 			.addr = client->addr,
49809f29673SShubhrajyoti D 			.flags = I2C_M_RD,
49909f29673SShubhrajyoti D 			.len = len,
50009f29673SShubhrajyoti D 			.buf = msgbuf1
50109f29673SShubhrajyoti D 		},
50254450f59SHans Verkuil 	};
50354450f59SHans Verkuil 
50454450f59SHans Verkuil 	if (i2c_transfer(client->adapter, msg, 2) < 0)
50554450f59SHans Verkuil 		return -EIO;
50654450f59SHans Verkuil 	memcpy(val, msgbuf1, len);
50754450f59SHans Verkuil 	return 0;
50854450f59SHans Verkuil }
50954450f59SHans Verkuil 
51054450f59SHans Verkuil static void adv7604_delayed_work_enable_hotplug(struct work_struct *work)
51154450f59SHans Verkuil {
51254450f59SHans Verkuil 	struct delayed_work *dwork = to_delayed_work(work);
51354450f59SHans Verkuil 	struct adv7604_state *state = container_of(dwork, struct adv7604_state,
51454450f59SHans Verkuil 						delayed_work_enable_hotplug);
51554450f59SHans Verkuil 	struct v4l2_subdev *sd = &state->sd;
51654450f59SHans Verkuil 
51754450f59SHans Verkuil 	v4l2_dbg(2, debug, sd, "%s: enable hotplug\n", __func__);
51854450f59SHans Verkuil 
51954450f59SHans Verkuil 	v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)1);
52054450f59SHans Verkuil }
52154450f59SHans Verkuil 
52254450f59SHans Verkuil static inline int edid_write_block(struct v4l2_subdev *sd,
52354450f59SHans Verkuil 					unsigned len, const u8 *val)
52454450f59SHans Verkuil {
52554450f59SHans Verkuil 	struct i2c_client *client = v4l2_get_subdevdata(sd);
52654450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
52754450f59SHans Verkuil 	int err = 0;
52854450f59SHans Verkuil 	int i;
52954450f59SHans Verkuil 
53054450f59SHans Verkuil 	v4l2_dbg(2, debug, sd, "%s: write EDID block (%d byte)\n", __func__, len);
53154450f59SHans Verkuil 
53254450f59SHans Verkuil 	v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)0);
53354450f59SHans Verkuil 
53454450f59SHans Verkuil 	/* Disables I2C access to internal EDID ram from DDC port */
53554450f59SHans Verkuil 	rep_write_and_or(sd, 0x77, 0xf0, 0x0);
53654450f59SHans Verkuil 
53754450f59SHans Verkuil 	for (i = 0; !err && i < len; i += I2C_SMBUS_BLOCK_MAX)
53854450f59SHans Verkuil 		err = adv_smbus_write_i2c_block_data(state->i2c_edid, i,
53954450f59SHans Verkuil 				I2C_SMBUS_BLOCK_MAX, val + i);
54054450f59SHans Verkuil 	if (err)
54154450f59SHans Verkuil 		return err;
54254450f59SHans Verkuil 
54354450f59SHans Verkuil 	/* adv7604 calculates the checksums and enables I2C access to internal
54454450f59SHans Verkuil 	   EDID ram from DDC port. */
54554450f59SHans Verkuil 	rep_write_and_or(sd, 0x77, 0xf0, 0x1);
54654450f59SHans Verkuil 
54754450f59SHans Verkuil 	for (i = 0; i < 1000; i++) {
54854450f59SHans Verkuil 		if (rep_read(sd, 0x7d) & 1)
54954450f59SHans Verkuil 			break;
55054450f59SHans Verkuil 		mdelay(1);
55154450f59SHans Verkuil 	}
55254450f59SHans Verkuil 	if (i == 1000) {
55354450f59SHans Verkuil 		v4l_err(client, "error enabling edid\n");
55454450f59SHans Verkuil 		return -EIO;
55554450f59SHans Verkuil 	}
55654450f59SHans Verkuil 
55754450f59SHans Verkuil 	/* enable hotplug after 100 ms */
55854450f59SHans Verkuil 	queue_delayed_work(state->work_queues,
55954450f59SHans Verkuil 			&state->delayed_work_enable_hotplug, HZ / 10);
56054450f59SHans Verkuil 	return 0;
56154450f59SHans Verkuil }
56254450f59SHans Verkuil 
56354450f59SHans Verkuil static inline int hdmi_read(struct v4l2_subdev *sd, u8 reg)
56454450f59SHans Verkuil {
56554450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
56654450f59SHans Verkuil 
56754450f59SHans Verkuil 	return adv_smbus_read_byte_data(state->i2c_hdmi, reg);
56854450f59SHans Verkuil }
56954450f59SHans Verkuil 
57054450f59SHans Verkuil static inline int hdmi_write(struct v4l2_subdev *sd, u8 reg, u8 val)
57154450f59SHans Verkuil {
57254450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
57354450f59SHans Verkuil 
57454450f59SHans Verkuil 	return adv_smbus_write_byte_data(state->i2c_hdmi, reg, val);
57554450f59SHans Verkuil }
57654450f59SHans Verkuil 
57754450f59SHans Verkuil static inline int test_read(struct v4l2_subdev *sd, u8 reg)
57854450f59SHans Verkuil {
57954450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
58054450f59SHans Verkuil 
58154450f59SHans Verkuil 	return adv_smbus_read_byte_data(state->i2c_test, reg);
58254450f59SHans Verkuil }
58354450f59SHans Verkuil 
58454450f59SHans Verkuil static inline int test_write(struct v4l2_subdev *sd, u8 reg, u8 val)
58554450f59SHans Verkuil {
58654450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
58754450f59SHans Verkuil 
58854450f59SHans Verkuil 	return adv_smbus_write_byte_data(state->i2c_test, reg, val);
58954450f59SHans Verkuil }
59054450f59SHans Verkuil 
59154450f59SHans Verkuil static inline int cp_read(struct v4l2_subdev *sd, u8 reg)
59254450f59SHans Verkuil {
59354450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
59454450f59SHans Verkuil 
59554450f59SHans Verkuil 	return adv_smbus_read_byte_data(state->i2c_cp, reg);
59654450f59SHans Verkuil }
59754450f59SHans Verkuil 
59854450f59SHans Verkuil static inline int cp_write(struct v4l2_subdev *sd, u8 reg, u8 val)
59954450f59SHans Verkuil {
60054450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
60154450f59SHans Verkuil 
60254450f59SHans Verkuil 	return adv_smbus_write_byte_data(state->i2c_cp, reg, val);
60354450f59SHans Verkuil }
60454450f59SHans Verkuil 
60554450f59SHans Verkuil static inline int cp_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
60654450f59SHans Verkuil {
60754450f59SHans Verkuil 	return cp_write(sd, reg, (cp_read(sd, reg) & mask) | val);
60854450f59SHans Verkuil }
60954450f59SHans Verkuil 
61054450f59SHans Verkuil static inline int vdp_read(struct v4l2_subdev *sd, u8 reg)
61154450f59SHans Verkuil {
61254450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
61354450f59SHans Verkuil 
61454450f59SHans Verkuil 	return adv_smbus_read_byte_data(state->i2c_vdp, reg);
61554450f59SHans Verkuil }
61654450f59SHans Verkuil 
61754450f59SHans Verkuil static inline int vdp_write(struct v4l2_subdev *sd, u8 reg, u8 val)
61854450f59SHans Verkuil {
61954450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
62054450f59SHans Verkuil 
62154450f59SHans Verkuil 	return adv_smbus_write_byte_data(state->i2c_vdp, reg, val);
62254450f59SHans Verkuil }
62354450f59SHans Verkuil 
62454450f59SHans Verkuil /* ----------------------------------------------------------------------- */
62554450f59SHans Verkuil 
62654450f59SHans Verkuil #ifdef CONFIG_VIDEO_ADV_DEBUG
62754450f59SHans Verkuil static void adv7604_inv_register(struct v4l2_subdev *sd)
62854450f59SHans Verkuil {
62954450f59SHans Verkuil 	v4l2_info(sd, "0x000-0x0ff: IO Map\n");
63054450f59SHans Verkuil 	v4l2_info(sd, "0x100-0x1ff: AVLink Map\n");
63154450f59SHans Verkuil 	v4l2_info(sd, "0x200-0x2ff: CEC Map\n");
63254450f59SHans Verkuil 	v4l2_info(sd, "0x300-0x3ff: InfoFrame Map\n");
63354450f59SHans Verkuil 	v4l2_info(sd, "0x400-0x4ff: ESDP Map\n");
63454450f59SHans Verkuil 	v4l2_info(sd, "0x500-0x5ff: DPP Map\n");
63554450f59SHans Verkuil 	v4l2_info(sd, "0x600-0x6ff: AFE Map\n");
63654450f59SHans Verkuil 	v4l2_info(sd, "0x700-0x7ff: Repeater Map\n");
63754450f59SHans Verkuil 	v4l2_info(sd, "0x800-0x8ff: EDID Map\n");
63854450f59SHans Verkuil 	v4l2_info(sd, "0x900-0x9ff: HDMI Map\n");
63954450f59SHans Verkuil 	v4l2_info(sd, "0xa00-0xaff: Test Map\n");
64054450f59SHans Verkuil 	v4l2_info(sd, "0xb00-0xbff: CP Map\n");
64154450f59SHans Verkuil 	v4l2_info(sd, "0xc00-0xcff: VDP Map\n");
64254450f59SHans Verkuil }
64354450f59SHans Verkuil 
64454450f59SHans Verkuil static int adv7604_g_register(struct v4l2_subdev *sd,
64554450f59SHans Verkuil 					struct v4l2_dbg_register *reg)
64654450f59SHans Verkuil {
64754450f59SHans Verkuil 	reg->size = 1;
64854450f59SHans Verkuil 	switch (reg->reg >> 8) {
64954450f59SHans Verkuil 	case 0:
65054450f59SHans Verkuil 		reg->val = io_read(sd, reg->reg & 0xff);
65154450f59SHans Verkuil 		break;
65254450f59SHans Verkuil 	case 1:
65354450f59SHans Verkuil 		reg->val = avlink_read(sd, reg->reg & 0xff);
65454450f59SHans Verkuil 		break;
65554450f59SHans Verkuil 	case 2:
65654450f59SHans Verkuil 		reg->val = cec_read(sd, reg->reg & 0xff);
65754450f59SHans Verkuil 		break;
65854450f59SHans Verkuil 	case 3:
65954450f59SHans Verkuil 		reg->val = infoframe_read(sd, reg->reg & 0xff);
66054450f59SHans Verkuil 		break;
66154450f59SHans Verkuil 	case 4:
66254450f59SHans Verkuil 		reg->val = esdp_read(sd, reg->reg & 0xff);
66354450f59SHans Verkuil 		break;
66454450f59SHans Verkuil 	case 5:
66554450f59SHans Verkuil 		reg->val = dpp_read(sd, reg->reg & 0xff);
66654450f59SHans Verkuil 		break;
66754450f59SHans Verkuil 	case 6:
66854450f59SHans Verkuil 		reg->val = afe_read(sd, reg->reg & 0xff);
66954450f59SHans Verkuil 		break;
67054450f59SHans Verkuil 	case 7:
67154450f59SHans Verkuil 		reg->val = rep_read(sd, reg->reg & 0xff);
67254450f59SHans Verkuil 		break;
67354450f59SHans Verkuil 	case 8:
67454450f59SHans Verkuil 		reg->val = edid_read(sd, reg->reg & 0xff);
67554450f59SHans Verkuil 		break;
67654450f59SHans Verkuil 	case 9:
67754450f59SHans Verkuil 		reg->val = hdmi_read(sd, reg->reg & 0xff);
67854450f59SHans Verkuil 		break;
67954450f59SHans Verkuil 	case 0xa:
68054450f59SHans Verkuil 		reg->val = test_read(sd, reg->reg & 0xff);
68154450f59SHans Verkuil 		break;
68254450f59SHans Verkuil 	case 0xb:
68354450f59SHans Verkuil 		reg->val = cp_read(sd, reg->reg & 0xff);
68454450f59SHans Verkuil 		break;
68554450f59SHans Verkuil 	case 0xc:
68654450f59SHans Verkuil 		reg->val = vdp_read(sd, reg->reg & 0xff);
68754450f59SHans Verkuil 		break;
68854450f59SHans Verkuil 	default:
68954450f59SHans Verkuil 		v4l2_info(sd, "Register %03llx not supported\n", reg->reg);
69054450f59SHans Verkuil 		adv7604_inv_register(sd);
69154450f59SHans Verkuil 		break;
69254450f59SHans Verkuil 	}
69354450f59SHans Verkuil 	return 0;
69454450f59SHans Verkuil }
69554450f59SHans Verkuil 
69654450f59SHans Verkuil static int adv7604_s_register(struct v4l2_subdev *sd,
697977ba3b1SHans Verkuil 					const struct v4l2_dbg_register *reg)
69854450f59SHans Verkuil {
69954450f59SHans Verkuil 	switch (reg->reg >> 8) {
70054450f59SHans Verkuil 	case 0:
70154450f59SHans Verkuil 		io_write(sd, reg->reg & 0xff, reg->val & 0xff);
70254450f59SHans Verkuil 		break;
70354450f59SHans Verkuil 	case 1:
70454450f59SHans Verkuil 		avlink_write(sd, reg->reg & 0xff, reg->val & 0xff);
70554450f59SHans Verkuil 		break;
70654450f59SHans Verkuil 	case 2:
70754450f59SHans Verkuil 		cec_write(sd, reg->reg & 0xff, reg->val & 0xff);
70854450f59SHans Verkuil 		break;
70954450f59SHans Verkuil 	case 3:
71054450f59SHans Verkuil 		infoframe_write(sd, reg->reg & 0xff, reg->val & 0xff);
71154450f59SHans Verkuil 		break;
71254450f59SHans Verkuil 	case 4:
71354450f59SHans Verkuil 		esdp_write(sd, reg->reg & 0xff, reg->val & 0xff);
71454450f59SHans Verkuil 		break;
71554450f59SHans Verkuil 	case 5:
71654450f59SHans Verkuil 		dpp_write(sd, reg->reg & 0xff, reg->val & 0xff);
71754450f59SHans Verkuil 		break;
71854450f59SHans Verkuil 	case 6:
71954450f59SHans Verkuil 		afe_write(sd, reg->reg & 0xff, reg->val & 0xff);
72054450f59SHans Verkuil 		break;
72154450f59SHans Verkuil 	case 7:
72254450f59SHans Verkuil 		rep_write(sd, reg->reg & 0xff, reg->val & 0xff);
72354450f59SHans Verkuil 		break;
72454450f59SHans Verkuil 	case 8:
72554450f59SHans Verkuil 		edid_write(sd, reg->reg & 0xff, reg->val & 0xff);
72654450f59SHans Verkuil 		break;
72754450f59SHans Verkuil 	case 9:
72854450f59SHans Verkuil 		hdmi_write(sd, reg->reg & 0xff, reg->val & 0xff);
72954450f59SHans Verkuil 		break;
73054450f59SHans Verkuil 	case 0xa:
73154450f59SHans Verkuil 		test_write(sd, reg->reg & 0xff, reg->val & 0xff);
73254450f59SHans Verkuil 		break;
73354450f59SHans Verkuil 	case 0xb:
73454450f59SHans Verkuil 		cp_write(sd, reg->reg & 0xff, reg->val & 0xff);
73554450f59SHans Verkuil 		break;
73654450f59SHans Verkuil 	case 0xc:
73754450f59SHans Verkuil 		vdp_write(sd, reg->reg & 0xff, reg->val & 0xff);
73854450f59SHans Verkuil 		break;
73954450f59SHans Verkuil 	default:
74054450f59SHans Verkuil 		v4l2_info(sd, "Register %03llx not supported\n", reg->reg);
74154450f59SHans Verkuil 		adv7604_inv_register(sd);
74254450f59SHans Verkuil 		break;
74354450f59SHans Verkuil 	}
74454450f59SHans Verkuil 	return 0;
74554450f59SHans Verkuil }
74654450f59SHans Verkuil #endif
74754450f59SHans Verkuil 
74854450f59SHans Verkuil static int adv7604_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd)
74954450f59SHans Verkuil {
75054450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
75154450f59SHans Verkuil 
75254450f59SHans Verkuil 	/* port A only */
75354450f59SHans Verkuil 	return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl,
75454450f59SHans Verkuil 				((io_read(sd, 0x6f) & 0x10) >> 4));
75554450f59SHans Verkuil }
75654450f59SHans Verkuil 
757ccbd5bc4SHans Verkuil static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd,
758ccbd5bc4SHans Verkuil 		u8 prim_mode,
759ccbd5bc4SHans Verkuil 		const struct adv7604_video_standards *predef_vid_timings,
760ccbd5bc4SHans Verkuil 		const struct v4l2_dv_timings *timings)
76154450f59SHans Verkuil {
762ccbd5bc4SHans Verkuil 	struct adv7604_state *state = to_state(sd);
763ccbd5bc4SHans Verkuil 	int i;
76454450f59SHans Verkuil 
765ccbd5bc4SHans Verkuil 	for (i = 0; predef_vid_timings[i].timings.bt.width; i++) {
766ccbd5bc4SHans Verkuil 		if (!v4l_match_dv_timings(timings, &predef_vid_timings[i].timings,
767ccbd5bc4SHans Verkuil 					DIGITAL_INPUT ? 250000 : 1000000))
768ccbd5bc4SHans Verkuil 			continue;
769ccbd5bc4SHans Verkuil 		io_write(sd, 0x00, predef_vid_timings[i].vid_std); /* video std */
770ccbd5bc4SHans Verkuil 		io_write(sd, 0x01, (predef_vid_timings[i].v_freq << 4) +
771ccbd5bc4SHans Verkuil 				prim_mode); /* v_freq and prim mode */
772ccbd5bc4SHans Verkuil 		return 0;
77354450f59SHans Verkuil 	}
77454450f59SHans Verkuil 
775ccbd5bc4SHans Verkuil 	return -1;
776ccbd5bc4SHans Verkuil }
77754450f59SHans Verkuil 
778ccbd5bc4SHans Verkuil static int configure_predefined_video_timings(struct v4l2_subdev *sd,
779ccbd5bc4SHans Verkuil 		struct v4l2_dv_timings *timings)
780ccbd5bc4SHans Verkuil {
781ccbd5bc4SHans Verkuil 	struct adv7604_state *state = to_state(sd);
782ccbd5bc4SHans Verkuil 	int err;
783ccbd5bc4SHans Verkuil 
784ccbd5bc4SHans Verkuil 	v4l2_dbg(1, debug, sd, "%s", __func__);
785ccbd5bc4SHans Verkuil 
78654450f59SHans Verkuil 	/* reset to default values */
78754450f59SHans Verkuil 	io_write(sd, 0x16, 0x43);
78854450f59SHans Verkuil 	io_write(sd, 0x17, 0x5a);
789ccbd5bc4SHans Verkuil 	/* disable embedded syncs for auto graphics mode */
790ccbd5bc4SHans Verkuil 	cp_write_and_or(sd, 0x81, 0xef, 0x00);
791ccbd5bc4SHans Verkuil 	cp_write(sd, 0x8f, 0x00);
792ccbd5bc4SHans Verkuil 	cp_write(sd, 0x90, 0x00);
79354450f59SHans Verkuil 	cp_write(sd, 0xa2, 0x00);
79454450f59SHans Verkuil 	cp_write(sd, 0xa3, 0x00);
79554450f59SHans Verkuil 	cp_write(sd, 0xa4, 0x00);
79654450f59SHans Verkuil 	cp_write(sd, 0xa5, 0x00);
79754450f59SHans Verkuil 	cp_write(sd, 0xa6, 0x00);
79854450f59SHans Verkuil 	cp_write(sd, 0xa7, 0x00);
799ccbd5bc4SHans Verkuil 	cp_write(sd, 0xab, 0x00);
800ccbd5bc4SHans Verkuil 	cp_write(sd, 0xac, 0x00);
801ccbd5bc4SHans Verkuil 
802ccbd5bc4SHans Verkuil 	switch (state->mode) {
803ccbd5bc4SHans Verkuil 	case ADV7604_MODE_COMP:
804ccbd5bc4SHans Verkuil 	case ADV7604_MODE_GR:
805ccbd5bc4SHans Verkuil 		err = find_and_set_predefined_video_timings(sd,
806ccbd5bc4SHans Verkuil 				0x01, adv7604_prim_mode_comp, timings);
807ccbd5bc4SHans Verkuil 		if (err)
808ccbd5bc4SHans Verkuil 			err = find_and_set_predefined_video_timings(sd,
809ccbd5bc4SHans Verkuil 					0x02, adv7604_prim_mode_gr, timings);
810ccbd5bc4SHans Verkuil 		break;
811ccbd5bc4SHans Verkuil 	case ADV7604_MODE_HDMI:
812ccbd5bc4SHans Verkuil 		err = find_and_set_predefined_video_timings(sd,
813ccbd5bc4SHans Verkuil 				0x05, adv7604_prim_mode_hdmi_comp, timings);
814ccbd5bc4SHans Verkuil 		if (err)
815ccbd5bc4SHans Verkuil 			err = find_and_set_predefined_video_timings(sd,
816ccbd5bc4SHans Verkuil 					0x06, adv7604_prim_mode_hdmi_gr, timings);
817ccbd5bc4SHans Verkuil 		break;
818ccbd5bc4SHans Verkuil 	default:
819ccbd5bc4SHans Verkuil 		v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n",
820ccbd5bc4SHans Verkuil 				__func__, state->mode);
821ccbd5bc4SHans Verkuil 		err = -1;
822ccbd5bc4SHans Verkuil 		break;
82354450f59SHans Verkuil 	}
82454450f59SHans Verkuil 
82554450f59SHans Verkuil 
826ccbd5bc4SHans Verkuil 	return err;
827ccbd5bc4SHans Verkuil }
828ccbd5bc4SHans Verkuil 
829ccbd5bc4SHans Verkuil static void configure_custom_video_timings(struct v4l2_subdev *sd,
830ccbd5bc4SHans Verkuil 		const struct v4l2_bt_timings *bt)
831ccbd5bc4SHans Verkuil {
832ccbd5bc4SHans Verkuil 	struct adv7604_state *state = to_state(sd);
833ccbd5bc4SHans Verkuil 	struct i2c_client *client = v4l2_get_subdevdata(sd);
834ccbd5bc4SHans Verkuil 	u32 width = htotal(bt);
835ccbd5bc4SHans Verkuil 	u32 height = vtotal(bt);
836ccbd5bc4SHans Verkuil 	u16 cp_start_sav = bt->hsync + bt->hbackporch - 4;
837ccbd5bc4SHans Verkuil 	u16 cp_start_eav = width - bt->hfrontporch;
838ccbd5bc4SHans Verkuil 	u16 cp_start_vbi = height - bt->vfrontporch;
839ccbd5bc4SHans Verkuil 	u16 cp_end_vbi = bt->vsync + bt->vbackporch;
840ccbd5bc4SHans Verkuil 	u16 ch1_fr_ll = (((u32)bt->pixelclock / 100) > 0) ?
841ccbd5bc4SHans Verkuil 		((width * (ADV7604_fsc / 100)) / ((u32)bt->pixelclock / 100)) : 0;
842ccbd5bc4SHans Verkuil 	const u8 pll[2] = {
843ccbd5bc4SHans Verkuil 		0xc0 | ((width >> 8) & 0x1f),
844ccbd5bc4SHans Verkuil 		width & 0xff
845ccbd5bc4SHans Verkuil 	};
846ccbd5bc4SHans Verkuil 
847ccbd5bc4SHans Verkuil 	v4l2_dbg(2, debug, sd, "%s\n", __func__);
848ccbd5bc4SHans Verkuil 
849ccbd5bc4SHans Verkuil 	switch (state->mode) {
850ccbd5bc4SHans Verkuil 	case ADV7604_MODE_COMP:
851ccbd5bc4SHans Verkuil 	case ADV7604_MODE_GR:
852ccbd5bc4SHans Verkuil 		/* auto graphics */
853ccbd5bc4SHans Verkuil 		io_write(sd, 0x00, 0x07); /* video std */
854ccbd5bc4SHans Verkuil 		io_write(sd, 0x01, 0x02); /* prim mode */
855ccbd5bc4SHans Verkuil 		/* enable embedded syncs for auto graphics mode */
856ccbd5bc4SHans Verkuil 		cp_write_and_or(sd, 0x81, 0xef, 0x10);
857ccbd5bc4SHans Verkuil 
858ccbd5bc4SHans Verkuil 		/* Should only be set in auto-graphics mode [REF_02, p. 91-92] */
859ccbd5bc4SHans Verkuil 		/* setup PLL_DIV_MAN_EN and PLL_DIV_RATIO */
860ccbd5bc4SHans Verkuil 		/* IO-map reg. 0x16 and 0x17 should be written in sequence */
861ccbd5bc4SHans Verkuil 		if (adv_smbus_write_i2c_block_data(client, 0x16, 2, pll)) {
862ccbd5bc4SHans Verkuil 			v4l2_err(sd, "writing to reg 0x16 and 0x17 failed\n");
863ccbd5bc4SHans Verkuil 			break;
864ccbd5bc4SHans Verkuil 		}
865ccbd5bc4SHans Verkuil 
866ccbd5bc4SHans Verkuil 		/* active video - horizontal timing */
867ccbd5bc4SHans Verkuil 		cp_write(sd, 0xa2, (cp_start_sav >> 4) & 0xff);
868ccbd5bc4SHans Verkuil 		cp_write(sd, 0xa3, ((cp_start_sav & 0x0f) << 4) |
869ccbd5bc4SHans Verkuil 					((cp_start_eav >> 8) & 0x0f));
870ccbd5bc4SHans Verkuil 		cp_write(sd, 0xa4, cp_start_eav & 0xff);
871ccbd5bc4SHans Verkuil 
872ccbd5bc4SHans Verkuil 		/* active video - vertical timing */
873ccbd5bc4SHans Verkuil 		cp_write(sd, 0xa5, (cp_start_vbi >> 4) & 0xff);
874ccbd5bc4SHans Verkuil 		cp_write(sd, 0xa6, ((cp_start_vbi & 0xf) << 4) |
875ccbd5bc4SHans Verkuil 					((cp_end_vbi >> 8) & 0xf));
876ccbd5bc4SHans Verkuil 		cp_write(sd, 0xa7, cp_end_vbi & 0xff);
877ccbd5bc4SHans Verkuil 		break;
878ccbd5bc4SHans Verkuil 	case ADV7604_MODE_HDMI:
879ccbd5bc4SHans Verkuil 		/* set default prim_mode/vid_std for HDMI
880ccbd5bc4SHans Verkuil 		   accoring to [REF_03, c. 4.2] */
881ccbd5bc4SHans Verkuil 		io_write(sd, 0x00, 0x02); /* video std */
882ccbd5bc4SHans Verkuil 		io_write(sd, 0x01, 0x06); /* prim mode */
883ccbd5bc4SHans Verkuil 		break;
884ccbd5bc4SHans Verkuil 	default:
885ccbd5bc4SHans Verkuil 		v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n",
886ccbd5bc4SHans Verkuil 				__func__, state->mode);
887ccbd5bc4SHans Verkuil 		break;
888ccbd5bc4SHans Verkuil 	}
889ccbd5bc4SHans Verkuil 
890ccbd5bc4SHans Verkuil 	cp_write(sd, 0x8f, (ch1_fr_ll >> 8) & 0x7);
891ccbd5bc4SHans Verkuil 	cp_write(sd, 0x90, ch1_fr_ll & 0xff);
892ccbd5bc4SHans Verkuil 	cp_write(sd, 0xab, (height >> 4) & 0xff);
893ccbd5bc4SHans Verkuil 	cp_write(sd, 0xac, (height & 0x0f) << 4);
894ccbd5bc4SHans Verkuil }
895ccbd5bc4SHans Verkuil 
89654450f59SHans Verkuil static void set_rgb_quantization_range(struct v4l2_subdev *sd)
89754450f59SHans Verkuil {
89854450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
89954450f59SHans Verkuil 
90054450f59SHans Verkuil 	switch (state->rgb_quantization_range) {
90154450f59SHans Verkuil 	case V4L2_DV_RGB_RANGE_AUTO:
90254450f59SHans Verkuil 		/* automatic */
9036b0d5d34SHans Verkuil 		if (DIGITAL_INPUT && !(hdmi_read(sd, 0x05) & 0x80)) {
90454450f59SHans Verkuil 			/* receiving DVI-D signal */
90554450f59SHans Verkuil 
90654450f59SHans Verkuil 			/* ADV7604 selects RGB limited range regardless of
90754450f59SHans Verkuil 			   input format (CE/IT) in automatic mode */
90854450f59SHans Verkuil 			if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) {
90954450f59SHans Verkuil 				/* RGB limited range (16-235) */
91054450f59SHans Verkuil 				io_write_and_or(sd, 0x02, 0x0f, 0x00);
91154450f59SHans Verkuil 
91254450f59SHans Verkuil 			} else {
91354450f59SHans Verkuil 				/* RGB full range (0-255) */
91454450f59SHans Verkuil 				io_write_and_or(sd, 0x02, 0x0f, 0x10);
91554450f59SHans Verkuil 			}
9166b0d5d34SHans Verkuil 		} else {
9176b0d5d34SHans Verkuil 			/* receiving HDMI or analog signal, set automode */
9186b0d5d34SHans Verkuil 			io_write_and_or(sd, 0x02, 0x0f, 0xf0);
91954450f59SHans Verkuil 		}
92054450f59SHans Verkuil 		break;
92154450f59SHans Verkuil 	case V4L2_DV_RGB_RANGE_LIMITED:
92254450f59SHans Verkuil 		/* RGB limited range (16-235) */
92354450f59SHans Verkuil 		io_write_and_or(sd, 0x02, 0x0f, 0x00);
92454450f59SHans Verkuil 		break;
92554450f59SHans Verkuil 	case V4L2_DV_RGB_RANGE_FULL:
92654450f59SHans Verkuil 		/* RGB full range (0-255) */
92754450f59SHans Verkuil 		io_write_and_or(sd, 0x02, 0x0f, 0x10);
92854450f59SHans Verkuil 		break;
92954450f59SHans Verkuil 	}
93054450f59SHans Verkuil }
93154450f59SHans Verkuil 
93254450f59SHans Verkuil 
93354450f59SHans Verkuil static int adv7604_s_ctrl(struct v4l2_ctrl *ctrl)
93454450f59SHans Verkuil {
93554450f59SHans Verkuil 	struct v4l2_subdev *sd = to_sd(ctrl);
93654450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
93754450f59SHans Verkuil 
93854450f59SHans Verkuil 	switch (ctrl->id) {
93954450f59SHans Verkuil 	case V4L2_CID_BRIGHTNESS:
94054450f59SHans Verkuil 		cp_write(sd, 0x3c, ctrl->val);
94154450f59SHans Verkuil 		return 0;
94254450f59SHans Verkuil 	case V4L2_CID_CONTRAST:
94354450f59SHans Verkuil 		cp_write(sd, 0x3a, ctrl->val);
94454450f59SHans Verkuil 		return 0;
94554450f59SHans Verkuil 	case V4L2_CID_SATURATION:
94654450f59SHans Verkuil 		cp_write(sd, 0x3b, ctrl->val);
94754450f59SHans Verkuil 		return 0;
94854450f59SHans Verkuil 	case V4L2_CID_HUE:
94954450f59SHans Verkuil 		cp_write(sd, 0x3d, ctrl->val);
95054450f59SHans Verkuil 		return 0;
95154450f59SHans Verkuil 	case  V4L2_CID_DV_RX_RGB_RANGE:
95254450f59SHans Verkuil 		state->rgb_quantization_range = ctrl->val;
95354450f59SHans Verkuil 		set_rgb_quantization_range(sd);
95454450f59SHans Verkuil 		return 0;
95554450f59SHans Verkuil 	case V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE:
95654450f59SHans Verkuil 		/* Set the analog sampling phase. This is needed to find the
95754450f59SHans Verkuil 		   best sampling phase for analog video: an application or
95854450f59SHans Verkuil 		   driver has to try a number of phases and analyze the picture
95954450f59SHans Verkuil 		   quality before settling on the best performing phase. */
96054450f59SHans Verkuil 		afe_write(sd, 0xc8, ctrl->val);
96154450f59SHans Verkuil 		return 0;
96254450f59SHans Verkuil 	case V4L2_CID_ADV_RX_FREE_RUN_COLOR_MANUAL:
96354450f59SHans Verkuil 		/* Use the default blue color for free running mode,
96454450f59SHans Verkuil 		   or supply your own. */
96554450f59SHans Verkuil 		cp_write_and_or(sd, 0xbf, ~0x04, (ctrl->val << 2));
96654450f59SHans Verkuil 		return 0;
96754450f59SHans Verkuil 	case V4L2_CID_ADV_RX_FREE_RUN_COLOR:
96854450f59SHans Verkuil 		cp_write(sd, 0xc0, (ctrl->val & 0xff0000) >> 16);
96954450f59SHans Verkuil 		cp_write(sd, 0xc1, (ctrl->val & 0x00ff00) >> 8);
97054450f59SHans Verkuil 		cp_write(sd, 0xc2, (u8)(ctrl->val & 0x0000ff));
97154450f59SHans Verkuil 		return 0;
97254450f59SHans Verkuil 	}
97354450f59SHans Verkuil 	return -EINVAL;
97454450f59SHans Verkuil }
97554450f59SHans Verkuil 
97654450f59SHans Verkuil /* ----------------------------------------------------------------------- */
97754450f59SHans Verkuil 
97854450f59SHans Verkuil static inline bool no_power(struct v4l2_subdev *sd)
97954450f59SHans Verkuil {
98054450f59SHans Verkuil 	/* Entire chip or CP powered off */
98154450f59SHans Verkuil 	return io_read(sd, 0x0c) & 0x24;
98254450f59SHans Verkuil }
98354450f59SHans Verkuil 
98454450f59SHans Verkuil static inline bool no_signal_tmds(struct v4l2_subdev *sd)
98554450f59SHans Verkuil {
98654450f59SHans Verkuil 	/* TODO port B, C and D */
98754450f59SHans Verkuil 	return !(io_read(sd, 0x6a) & 0x10);
98854450f59SHans Verkuil }
98954450f59SHans Verkuil 
99054450f59SHans Verkuil static inline bool no_lock_tmds(struct v4l2_subdev *sd)
99154450f59SHans Verkuil {
99254450f59SHans Verkuil 	return (io_read(sd, 0x6a) & 0xe0) != 0xe0;
99354450f59SHans Verkuil }
99454450f59SHans Verkuil 
995bb88f325SMartin Bugge static inline bool is_hdmi(struct v4l2_subdev *sd)
996bb88f325SMartin Bugge {
997bb88f325SMartin Bugge 	return hdmi_read(sd, 0x05) & 0x80;
998bb88f325SMartin Bugge }
999bb88f325SMartin Bugge 
100054450f59SHans Verkuil static inline bool no_lock_sspd(struct v4l2_subdev *sd)
100154450f59SHans Verkuil {
100254450f59SHans Verkuil 	/* TODO channel 2 */
100354450f59SHans Verkuil 	return ((cp_read(sd, 0xb5) & 0xd0) != 0xd0);
100454450f59SHans Verkuil }
100554450f59SHans Verkuil 
100654450f59SHans Verkuil static inline bool no_lock_stdi(struct v4l2_subdev *sd)
100754450f59SHans Verkuil {
100854450f59SHans Verkuil 	/* TODO channel 2 */
100954450f59SHans Verkuil 	return !(cp_read(sd, 0xb1) & 0x80);
101054450f59SHans Verkuil }
101154450f59SHans Verkuil 
101254450f59SHans Verkuil static inline bool no_signal(struct v4l2_subdev *sd)
101354450f59SHans Verkuil {
101454450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
101554450f59SHans Verkuil 	bool ret;
101654450f59SHans Verkuil 
101754450f59SHans Verkuil 	ret = no_power(sd);
101854450f59SHans Verkuil 
101954450f59SHans Verkuil 	ret |= no_lock_stdi(sd);
102054450f59SHans Verkuil 	ret |= no_lock_sspd(sd);
102154450f59SHans Verkuil 
102254450f59SHans Verkuil 	if (DIGITAL_INPUT) {
102354450f59SHans Verkuil 		ret |= no_lock_tmds(sd);
102454450f59SHans Verkuil 		ret |= no_signal_tmds(sd);
102554450f59SHans Verkuil 	}
102654450f59SHans Verkuil 
102754450f59SHans Verkuil 	return ret;
102854450f59SHans Verkuil }
102954450f59SHans Verkuil 
103054450f59SHans Verkuil static inline bool no_lock_cp(struct v4l2_subdev *sd)
103154450f59SHans Verkuil {
103254450f59SHans Verkuil 	/* CP has detected a non standard number of lines on the incoming
103354450f59SHans Verkuil 	   video compared to what it is configured to receive by s_dv_timings */
103454450f59SHans Verkuil 	return io_read(sd, 0x12) & 0x01;
103554450f59SHans Verkuil }
103654450f59SHans Verkuil 
103754450f59SHans Verkuil static int adv7604_g_input_status(struct v4l2_subdev *sd, u32 *status)
103854450f59SHans Verkuil {
103954450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
104054450f59SHans Verkuil 
104154450f59SHans Verkuil 	*status = 0;
104254450f59SHans Verkuil 	*status |= no_power(sd) ? V4L2_IN_ST_NO_POWER : 0;
104354450f59SHans Verkuil 	*status |= no_signal(sd) ? V4L2_IN_ST_NO_SIGNAL : 0;
104454450f59SHans Verkuil 	if (no_lock_cp(sd))
104554450f59SHans Verkuil 		*status |= DIGITAL_INPUT ? V4L2_IN_ST_NO_SYNC : V4L2_IN_ST_NO_H_LOCK;
104654450f59SHans Verkuil 
104754450f59SHans Verkuil 	v4l2_dbg(1, debug, sd, "%s: status = 0x%x\n", __func__, *status);
104854450f59SHans Verkuil 
104954450f59SHans Verkuil 	return 0;
105054450f59SHans Verkuil }
105154450f59SHans Verkuil 
105254450f59SHans Verkuil /* ----------------------------------------------------------------------- */
105354450f59SHans Verkuil 
105454450f59SHans Verkuil static void adv7604_print_timings(struct v4l2_subdev *sd,
105554450f59SHans Verkuil 	struct v4l2_dv_timings *timings, const char *txt, bool detailed)
105654450f59SHans Verkuil {
105754450f59SHans Verkuil 	struct v4l2_bt_timings *bt = &timings->bt;
105854450f59SHans Verkuil 	u32 htot, vtot;
105954450f59SHans Verkuil 
106054450f59SHans Verkuil 	if (timings->type != V4L2_DV_BT_656_1120)
106154450f59SHans Verkuil 		return;
106254450f59SHans Verkuil 
106354450f59SHans Verkuil 	htot = htotal(bt);
106454450f59SHans Verkuil 	vtot = vtotal(bt);
106554450f59SHans Verkuil 
106654450f59SHans Verkuil 	v4l2_info(sd, "%s %dx%d%s%d (%dx%d)",
106754450f59SHans Verkuil 			txt, bt->width, bt->height, bt->interlaced ? "i" : "p",
106854450f59SHans Verkuil 			(htot * vtot) > 0 ? ((u32)bt->pixelclock /
106954450f59SHans Verkuil 				(htot * vtot)) : 0,
107054450f59SHans Verkuil 			htot, vtot);
107154450f59SHans Verkuil 
107254450f59SHans Verkuil 	if (detailed) {
107354450f59SHans Verkuil 		v4l2_info(sd, "    horizontal: fp = %d, %ssync = %d, bp = %d\n",
107454450f59SHans Verkuil 				bt->hfrontporch,
107554450f59SHans Verkuil 				(bt->polarities & V4L2_DV_HSYNC_POS_POL) ? "+" : "-",
107654450f59SHans Verkuil 				bt->hsync, bt->hbackporch);
107754450f59SHans Verkuil 		v4l2_info(sd, "    vertical: fp = %d, %ssync = %d, bp = %d\n",
107854450f59SHans Verkuil 				bt->vfrontporch,
107954450f59SHans Verkuil 				(bt->polarities & V4L2_DV_VSYNC_POS_POL) ? "+" : "-",
108054450f59SHans Verkuil 				bt->vsync, bt->vbackporch);
108154450f59SHans Verkuil 		v4l2_info(sd, "    pixelclock: %lld, flags: 0x%x, standards: 0x%x\n",
108254450f59SHans Verkuil 				bt->pixelclock, bt->flags, bt->standards);
108354450f59SHans Verkuil 	}
108454450f59SHans Verkuil }
108554450f59SHans Verkuil 
108654450f59SHans Verkuil struct stdi_readback {
108754450f59SHans Verkuil 	u16 bl, lcf, lcvs;
108854450f59SHans Verkuil 	u8 hs_pol, vs_pol;
108954450f59SHans Verkuil 	bool interlaced;
109054450f59SHans Verkuil };
109154450f59SHans Verkuil 
109254450f59SHans Verkuil static int stdi2dv_timings(struct v4l2_subdev *sd,
109354450f59SHans Verkuil 		struct stdi_readback *stdi,
109454450f59SHans Verkuil 		struct v4l2_dv_timings *timings)
109554450f59SHans Verkuil {
109654450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
109754450f59SHans Verkuil 	u32 hfreq = (ADV7604_fsc * 8) / stdi->bl;
109854450f59SHans Verkuil 	u32 pix_clk;
109954450f59SHans Verkuil 	int i;
110054450f59SHans Verkuil 
110154450f59SHans Verkuil 	for (i = 0; adv7604_timings[i].bt.height; i++) {
110254450f59SHans Verkuil 		if (vtotal(&adv7604_timings[i].bt) != stdi->lcf + 1)
110354450f59SHans Verkuil 			continue;
110454450f59SHans Verkuil 		if (adv7604_timings[i].bt.vsync != stdi->lcvs)
110554450f59SHans Verkuil 			continue;
110654450f59SHans Verkuil 
110754450f59SHans Verkuil 		pix_clk = hfreq * htotal(&adv7604_timings[i].bt);
110854450f59SHans Verkuil 
110954450f59SHans Verkuil 		if ((pix_clk < adv7604_timings[i].bt.pixelclock + 1000000) &&
111054450f59SHans Verkuil 		    (pix_clk > adv7604_timings[i].bt.pixelclock - 1000000)) {
111154450f59SHans Verkuil 			*timings = adv7604_timings[i];
111254450f59SHans Verkuil 			return 0;
111354450f59SHans Verkuil 		}
111454450f59SHans Verkuil 	}
111554450f59SHans Verkuil 
111654450f59SHans Verkuil 	if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs,
111754450f59SHans Verkuil 			(stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) |
111854450f59SHans Verkuil 			(stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0),
111954450f59SHans Verkuil 			timings))
112054450f59SHans Verkuil 		return 0;
112154450f59SHans Verkuil 	if (v4l2_detect_gtf(stdi->lcf + 1, hfreq, stdi->lcvs,
112254450f59SHans Verkuil 			(stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) |
112354450f59SHans Verkuil 			(stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0),
112454450f59SHans Verkuil 			state->aspect_ratio, timings))
112554450f59SHans Verkuil 		return 0;
112654450f59SHans Verkuil 
1127ccbd5bc4SHans Verkuil 	v4l2_dbg(2, debug, sd,
1128ccbd5bc4SHans Verkuil 		"%s: No format candidate found for lcvs = %d, lcf=%d, bl = %d, %chsync, %cvsync\n",
1129ccbd5bc4SHans Verkuil 		__func__, stdi->lcvs, stdi->lcf, stdi->bl,
1130ccbd5bc4SHans Verkuil 		stdi->hs_pol, stdi->vs_pol);
113154450f59SHans Verkuil 	return -1;
113254450f59SHans Verkuil }
113354450f59SHans Verkuil 
113454450f59SHans Verkuil static int read_stdi(struct v4l2_subdev *sd, struct stdi_readback *stdi)
113554450f59SHans Verkuil {
113654450f59SHans Verkuil 	if (no_lock_stdi(sd) || no_lock_sspd(sd)) {
113754450f59SHans Verkuil 		v4l2_dbg(2, debug, sd, "%s: STDI and/or SSPD not locked\n", __func__);
113854450f59SHans Verkuil 		return -1;
113954450f59SHans Verkuil 	}
114054450f59SHans Verkuil 
114154450f59SHans Verkuil 	/* read STDI */
114254450f59SHans Verkuil 	stdi->bl = ((cp_read(sd, 0xb1) & 0x3f) << 8) | cp_read(sd, 0xb2);
114354450f59SHans Verkuil 	stdi->lcf = ((cp_read(sd, 0xb3) & 0x7) << 8) | cp_read(sd, 0xb4);
114454450f59SHans Verkuil 	stdi->lcvs = cp_read(sd, 0xb3) >> 3;
114554450f59SHans Verkuil 	stdi->interlaced = io_read(sd, 0x12) & 0x10;
114654450f59SHans Verkuil 
114754450f59SHans Verkuil 	/* read SSPD */
114854450f59SHans Verkuil 	if ((cp_read(sd, 0xb5) & 0x03) == 0x01) {
114954450f59SHans Verkuil 		stdi->hs_pol = ((cp_read(sd, 0xb5) & 0x10) ?
115054450f59SHans Verkuil 				((cp_read(sd, 0xb5) & 0x08) ? '+' : '-') : 'x');
115154450f59SHans Verkuil 		stdi->vs_pol = ((cp_read(sd, 0xb5) & 0x40) ?
115254450f59SHans Verkuil 				((cp_read(sd, 0xb5) & 0x20) ? '+' : '-') : 'x');
115354450f59SHans Verkuil 	} else {
115454450f59SHans Verkuil 		stdi->hs_pol = 'x';
115554450f59SHans Verkuil 		stdi->vs_pol = 'x';
115654450f59SHans Verkuil 	}
115754450f59SHans Verkuil 
115854450f59SHans Verkuil 	if (no_lock_stdi(sd) || no_lock_sspd(sd)) {
115954450f59SHans Verkuil 		v4l2_dbg(2, debug, sd,
116054450f59SHans Verkuil 			"%s: signal lost during readout of STDI/SSPD\n", __func__);
116154450f59SHans Verkuil 		return -1;
116254450f59SHans Verkuil 	}
116354450f59SHans Verkuil 
116454450f59SHans Verkuil 	if (stdi->lcf < 239 || stdi->bl < 8 || stdi->bl == 0x3fff) {
116554450f59SHans Verkuil 		v4l2_dbg(2, debug, sd, "%s: invalid signal\n", __func__);
116654450f59SHans Verkuil 		memset(stdi, 0, sizeof(struct stdi_readback));
116754450f59SHans Verkuil 		return -1;
116854450f59SHans Verkuil 	}
116954450f59SHans Verkuil 
117054450f59SHans Verkuil 	v4l2_dbg(2, debug, sd,
117154450f59SHans Verkuil 		"%s: lcf (frame height - 1) = %d, bl = %d, lcvs (vsync) = %d, %chsync, %cvsync, %s\n",
117254450f59SHans Verkuil 		__func__, stdi->lcf, stdi->bl, stdi->lcvs,
117354450f59SHans Verkuil 		stdi->hs_pol, stdi->vs_pol,
117454450f59SHans Verkuil 		stdi->interlaced ? "interlaced" : "progressive");
117554450f59SHans Verkuil 
117654450f59SHans Verkuil 	return 0;
117754450f59SHans Verkuil }
117854450f59SHans Verkuil 
117954450f59SHans Verkuil static int adv7604_enum_dv_timings(struct v4l2_subdev *sd,
118054450f59SHans Verkuil 			struct v4l2_enum_dv_timings *timings)
118154450f59SHans Verkuil {
118254450f59SHans Verkuil 	if (timings->index >= ARRAY_SIZE(adv7604_timings) - 1)
118354450f59SHans Verkuil 		return -EINVAL;
118454450f59SHans Verkuil 	memset(timings->reserved, 0, sizeof(timings->reserved));
118554450f59SHans Verkuil 	timings->timings = adv7604_timings[timings->index];
118654450f59SHans Verkuil 	return 0;
118754450f59SHans Verkuil }
118854450f59SHans Verkuil 
118954450f59SHans Verkuil static int adv7604_dv_timings_cap(struct v4l2_subdev *sd,
119054450f59SHans Verkuil 			struct v4l2_dv_timings_cap *cap)
119154450f59SHans Verkuil {
119254450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
119354450f59SHans Verkuil 
119454450f59SHans Verkuil 	cap->type = V4L2_DV_BT_656_1120;
119554450f59SHans Verkuil 	cap->bt.max_width = 1920;
119654450f59SHans Verkuil 	cap->bt.max_height = 1200;
119754450f59SHans Verkuil 	cap->bt.min_pixelclock = 27000000;
119854450f59SHans Verkuil 	if (DIGITAL_INPUT)
119954450f59SHans Verkuil 		cap->bt.max_pixelclock = 225000000;
120054450f59SHans Verkuil 	else
120154450f59SHans Verkuil 		cap->bt.max_pixelclock = 170000000;
120254450f59SHans Verkuil 	cap->bt.standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
120354450f59SHans Verkuil 			 V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT;
120454450f59SHans Verkuil 	cap->bt.capabilities = V4L2_DV_BT_CAP_PROGRESSIVE |
120554450f59SHans Verkuil 		V4L2_DV_BT_CAP_REDUCED_BLANKING | V4L2_DV_BT_CAP_CUSTOM;
120654450f59SHans Verkuil 	return 0;
120754450f59SHans Verkuil }
120854450f59SHans Verkuil 
120954450f59SHans Verkuil /* Fill the optional fields .standards and .flags in struct v4l2_dv_timings
121054450f59SHans Verkuil    if the format is listed in adv7604_timings[] */
121154450f59SHans Verkuil static void adv7604_fill_optional_dv_timings_fields(struct v4l2_subdev *sd,
121254450f59SHans Verkuil 		struct v4l2_dv_timings *timings)
121354450f59SHans Verkuil {
121454450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
121554450f59SHans Verkuil 	int i;
121654450f59SHans Verkuil 
121754450f59SHans Verkuil 	for (i = 0; adv7604_timings[i].bt.width; i++) {
121854450f59SHans Verkuil 		if (v4l_match_dv_timings(timings, &adv7604_timings[i],
121954450f59SHans Verkuil 					DIGITAL_INPUT ? 250000 : 1000000)) {
122054450f59SHans Verkuil 			*timings = adv7604_timings[i];
122154450f59SHans Verkuil 			break;
122254450f59SHans Verkuil 		}
122354450f59SHans Verkuil 	}
122454450f59SHans Verkuil }
122554450f59SHans Verkuil 
122654450f59SHans Verkuil static int adv7604_query_dv_timings(struct v4l2_subdev *sd,
122754450f59SHans Verkuil 			struct v4l2_dv_timings *timings)
122854450f59SHans Verkuil {
122954450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
123054450f59SHans Verkuil 	struct v4l2_bt_timings *bt = &timings->bt;
123154450f59SHans Verkuil 	struct stdi_readback stdi;
123254450f59SHans Verkuil 
123354450f59SHans Verkuil 	if (!timings)
123454450f59SHans Verkuil 		return -EINVAL;
123554450f59SHans Verkuil 
123654450f59SHans Verkuil 	memset(timings, 0, sizeof(struct v4l2_dv_timings));
123754450f59SHans Verkuil 
123854450f59SHans Verkuil 	if (no_signal(sd)) {
123954450f59SHans Verkuil 		v4l2_dbg(1, debug, sd, "%s: no valid signal\n", __func__);
124054450f59SHans Verkuil 		return -ENOLINK;
124154450f59SHans Verkuil 	}
124254450f59SHans Verkuil 
124354450f59SHans Verkuil 	/* read STDI */
124454450f59SHans Verkuil 	if (read_stdi(sd, &stdi)) {
124554450f59SHans Verkuil 		v4l2_dbg(1, debug, sd, "%s: STDI/SSPD not locked\n", __func__);
124654450f59SHans Verkuil 		return -ENOLINK;
124754450f59SHans Verkuil 	}
124854450f59SHans Verkuil 	bt->interlaced = stdi.interlaced ?
124954450f59SHans Verkuil 		V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE;
125054450f59SHans Verkuil 
125154450f59SHans Verkuil 	if (DIGITAL_INPUT) {
1252bb88f325SMartin Bugge 		uint32_t freq;
1253bb88f325SMartin Bugge 
125454450f59SHans Verkuil 		timings->type = V4L2_DV_BT_656_1120;
125554450f59SHans Verkuil 
125654450f59SHans Verkuil 		bt->width = (hdmi_read(sd, 0x07) & 0x0f) * 256 + hdmi_read(sd, 0x08);
125754450f59SHans Verkuil 		bt->height = (hdmi_read(sd, 0x09) & 0x0f) * 256 + hdmi_read(sd, 0x0a);
1258bb88f325SMartin Bugge 		freq = (hdmi_read(sd, 0x06) * 1000000) +
125954450f59SHans Verkuil 			((hdmi_read(sd, 0x3b) & 0x30) >> 4) * 250000;
1260bb88f325SMartin Bugge 		if (is_hdmi(sd)) {
1261bb88f325SMartin Bugge 			/* adjust for deep color mode */
1262bb88f325SMartin Bugge 			unsigned bits_per_channel = ((hdmi_read(sd, 0x0b) & 0x60) >> 4) + 8;
1263bb88f325SMartin Bugge 
1264bb88f325SMartin Bugge 			freq = freq * 8 / bits_per_channel;
1265bb88f325SMartin Bugge 		}
1266bb88f325SMartin Bugge 		bt->pixelclock = freq;
126754450f59SHans Verkuil 		bt->hfrontporch = (hdmi_read(sd, 0x20) & 0x03) * 256 +
126854450f59SHans Verkuil 			hdmi_read(sd, 0x21);
126954450f59SHans Verkuil 		bt->hsync = (hdmi_read(sd, 0x22) & 0x03) * 256 +
127054450f59SHans Verkuil 			hdmi_read(sd, 0x23);
127154450f59SHans Verkuil 		bt->hbackporch = (hdmi_read(sd, 0x24) & 0x03) * 256 +
127254450f59SHans Verkuil 			hdmi_read(sd, 0x25);
127354450f59SHans Verkuil 		bt->vfrontporch = ((hdmi_read(sd, 0x2a) & 0x1f) * 256 +
127454450f59SHans Verkuil 			hdmi_read(sd, 0x2b)) / 2;
127554450f59SHans Verkuil 		bt->vsync = ((hdmi_read(sd, 0x2e) & 0x1f) * 256 +
127654450f59SHans Verkuil 			hdmi_read(sd, 0x2f)) / 2;
127754450f59SHans Verkuil 		bt->vbackporch = ((hdmi_read(sd, 0x32) & 0x1f) * 256 +
127854450f59SHans Verkuil 			hdmi_read(sd, 0x33)) / 2;
127954450f59SHans Verkuil 		bt->polarities = ((hdmi_read(sd, 0x05) & 0x10) ? V4L2_DV_VSYNC_POS_POL : 0) |
128054450f59SHans Verkuil 			((hdmi_read(sd, 0x05) & 0x20) ? V4L2_DV_HSYNC_POS_POL : 0);
128154450f59SHans Verkuil 		if (bt->interlaced == V4L2_DV_INTERLACED) {
128254450f59SHans Verkuil 			bt->height += (hdmi_read(sd, 0x0b) & 0x0f) * 256 +
128354450f59SHans Verkuil 					hdmi_read(sd, 0x0c);
128454450f59SHans Verkuil 			bt->il_vfrontporch = ((hdmi_read(sd, 0x2c) & 0x1f) * 256 +
128554450f59SHans Verkuil 					hdmi_read(sd, 0x2d)) / 2;
128654450f59SHans Verkuil 			bt->il_vsync = ((hdmi_read(sd, 0x30) & 0x1f) * 256 +
128754450f59SHans Verkuil 					hdmi_read(sd, 0x31)) / 2;
128854450f59SHans Verkuil 			bt->vbackporch = ((hdmi_read(sd, 0x34) & 0x1f) * 256 +
128954450f59SHans Verkuil 					hdmi_read(sd, 0x35)) / 2;
129054450f59SHans Verkuil 		}
129154450f59SHans Verkuil 		adv7604_fill_optional_dv_timings_fields(sd, timings);
129254450f59SHans Verkuil 	} else {
129354450f59SHans Verkuil 		/* find format
129480939647SHans Verkuil 		 * Since LCVS values are inaccurate [REF_03, p. 275-276],
129554450f59SHans Verkuil 		 * stdi2dv_timings() is called with lcvs +-1 if the first attempt fails.
129654450f59SHans Verkuil 		 */
129754450f59SHans Verkuil 		if (!stdi2dv_timings(sd, &stdi, timings))
129854450f59SHans Verkuil 			goto found;
129954450f59SHans Verkuil 		stdi.lcvs += 1;
130054450f59SHans Verkuil 		v4l2_dbg(1, debug, sd, "%s: lcvs + 1 = %d\n", __func__, stdi.lcvs);
130154450f59SHans Verkuil 		if (!stdi2dv_timings(sd, &stdi, timings))
130254450f59SHans Verkuil 			goto found;
130354450f59SHans Verkuil 		stdi.lcvs -= 2;
130454450f59SHans Verkuil 		v4l2_dbg(1, debug, sd, "%s: lcvs - 1 = %d\n", __func__, stdi.lcvs);
130554450f59SHans Verkuil 		if (stdi2dv_timings(sd, &stdi, timings)) {
1306cf9afb1dSHans Verkuil 			/*
1307cf9afb1dSHans Verkuil 			 * The STDI block may measure wrong values, especially
1308cf9afb1dSHans Verkuil 			 * for lcvs and lcf. If the driver can not find any
1309cf9afb1dSHans Verkuil 			 * valid timing, the STDI block is restarted to measure
1310cf9afb1dSHans Verkuil 			 * the video timings again. The function will return an
1311cf9afb1dSHans Verkuil 			 * error, but the restart of STDI will generate a new
1312cf9afb1dSHans Verkuil 			 * STDI interrupt and the format detection process will
1313cf9afb1dSHans Verkuil 			 * restart.
1314cf9afb1dSHans Verkuil 			 */
1315cf9afb1dSHans Verkuil 			if (state->restart_stdi_once) {
1316cf9afb1dSHans Verkuil 				v4l2_dbg(1, debug, sd, "%s: restart STDI\n", __func__);
1317cf9afb1dSHans Verkuil 				/* TODO restart STDI for Sync Channel 2 */
1318cf9afb1dSHans Verkuil 				/* enter one-shot mode */
1319cf9afb1dSHans Verkuil 				cp_write_and_or(sd, 0x86, 0xf9, 0x00);
1320cf9afb1dSHans Verkuil 				/* trigger STDI restart */
1321cf9afb1dSHans Verkuil 				cp_write_and_or(sd, 0x86, 0xf9, 0x04);
1322cf9afb1dSHans Verkuil 				/* reset to continuous mode */
1323cf9afb1dSHans Verkuil 				cp_write_and_or(sd, 0x86, 0xf9, 0x02);
1324cf9afb1dSHans Verkuil 				state->restart_stdi_once = false;
1325cf9afb1dSHans Verkuil 				return -ENOLINK;
1326cf9afb1dSHans Verkuil 			}
132754450f59SHans Verkuil 			v4l2_dbg(1, debug, sd, "%s: format not supported\n", __func__);
132854450f59SHans Verkuil 			return -ERANGE;
132954450f59SHans Verkuil 		}
1330cf9afb1dSHans Verkuil 		state->restart_stdi_once = true;
133154450f59SHans Verkuil 	}
133254450f59SHans Verkuil found:
133354450f59SHans Verkuil 
133454450f59SHans Verkuil 	if (no_signal(sd)) {
133554450f59SHans Verkuil 		v4l2_dbg(1, debug, sd, "%s: signal lost during readout\n", __func__);
133654450f59SHans Verkuil 		memset(timings, 0, sizeof(struct v4l2_dv_timings));
133754450f59SHans Verkuil 		return -ENOLINK;
133854450f59SHans Verkuil 	}
133954450f59SHans Verkuil 
134054450f59SHans Verkuil 	if ((!DIGITAL_INPUT && bt->pixelclock > 170000000) ||
134154450f59SHans Verkuil 			(DIGITAL_INPUT && bt->pixelclock > 225000000)) {
134254450f59SHans Verkuil 		v4l2_dbg(1, debug, sd, "%s: pixelclock out of range %d\n",
134354450f59SHans Verkuil 				__func__, (u32)bt->pixelclock);
134454450f59SHans Verkuil 		return -ERANGE;
134554450f59SHans Verkuil 	}
134654450f59SHans Verkuil 
134754450f59SHans Verkuil 	if (debug > 1)
134854450f59SHans Verkuil 		adv7604_print_timings(sd, timings,
134954450f59SHans Verkuil 				"adv7604_query_dv_timings:", true);
135054450f59SHans Verkuil 
135154450f59SHans Verkuil 	return 0;
135254450f59SHans Verkuil }
135354450f59SHans Verkuil 
135454450f59SHans Verkuil static int adv7604_s_dv_timings(struct v4l2_subdev *sd,
135554450f59SHans Verkuil 		struct v4l2_dv_timings *timings)
135654450f59SHans Verkuil {
135754450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
135854450f59SHans Verkuil 	struct v4l2_bt_timings *bt;
1359ccbd5bc4SHans Verkuil 	int err;
136054450f59SHans Verkuil 
136154450f59SHans Verkuil 	if (!timings)
136254450f59SHans Verkuil 		return -EINVAL;
136354450f59SHans Verkuil 
136454450f59SHans Verkuil 	bt = &timings->bt;
136554450f59SHans Verkuil 
136654450f59SHans Verkuil 	if ((!DIGITAL_INPUT && bt->pixelclock > 170000000) ||
136754450f59SHans Verkuil 			(DIGITAL_INPUT && bt->pixelclock > 225000000)) {
136854450f59SHans Verkuil 		v4l2_dbg(1, debug, sd, "%s: pixelclock out of range %d\n",
136954450f59SHans Verkuil 				__func__, (u32)bt->pixelclock);
137054450f59SHans Verkuil 		return -ERANGE;
137154450f59SHans Verkuil 	}
1372ccbd5bc4SHans Verkuil 
137354450f59SHans Verkuil 	adv7604_fill_optional_dv_timings_fields(sd, timings);
137454450f59SHans Verkuil 
137554450f59SHans Verkuil 	state->timings = *timings;
137654450f59SHans Verkuil 
1377ccbd5bc4SHans Verkuil 	cp_write(sd, 0x91, bt->interlaced ? 0x50 : 0x10);
1378ccbd5bc4SHans Verkuil 
1379ccbd5bc4SHans Verkuil 	/* Use prim_mode and vid_std when available */
1380ccbd5bc4SHans Verkuil 	err = configure_predefined_video_timings(sd, timings);
1381ccbd5bc4SHans Verkuil 	if (err) {
1382ccbd5bc4SHans Verkuil 		/* custom settings when the video format
1383ccbd5bc4SHans Verkuil 		 does not have prim_mode/vid_std */
1384ccbd5bc4SHans Verkuil 		configure_custom_video_timings(sd, bt);
1385ccbd5bc4SHans Verkuil 	}
138654450f59SHans Verkuil 
138754450f59SHans Verkuil 	set_rgb_quantization_range(sd);
138854450f59SHans Verkuil 
138954450f59SHans Verkuil 
139054450f59SHans Verkuil 	if (debug > 1)
139154450f59SHans Verkuil 		adv7604_print_timings(sd, timings,
139254450f59SHans Verkuil 				"adv7604_s_dv_timings:", true);
139354450f59SHans Verkuil 	return 0;
139454450f59SHans Verkuil }
139554450f59SHans Verkuil 
139654450f59SHans Verkuil static int adv7604_g_dv_timings(struct v4l2_subdev *sd,
139754450f59SHans Verkuil 		struct v4l2_dv_timings *timings)
139854450f59SHans Verkuil {
139954450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
140054450f59SHans Verkuil 
140154450f59SHans Verkuil 	*timings = state->timings;
140254450f59SHans Verkuil 	return 0;
140354450f59SHans Verkuil }
140454450f59SHans Verkuil 
14056b0d5d34SHans Verkuil static void enable_input(struct v4l2_subdev *sd)
140654450f59SHans Verkuil {
14076b0d5d34SHans Verkuil 	struct adv7604_state *state = to_state(sd);
14086b0d5d34SHans Verkuil 
14096b0d5d34SHans Verkuil 	switch (state->mode) {
14106b0d5d34SHans Verkuil 	case ADV7604_MODE_COMP:
14116b0d5d34SHans Verkuil 	case ADV7604_MODE_GR:
141254450f59SHans Verkuil 		/* enable */
141354450f59SHans Verkuil 		io_write(sd, 0x15, 0xb0);   /* Disable Tristate of Pins (no audio) */
141454450f59SHans Verkuil 		break;
14156b0d5d34SHans Verkuil 	case ADV7604_MODE_HDMI:
141654450f59SHans Verkuil 		/* enable */
141754450f59SHans Verkuil 		hdmi_write(sd, 0x1a, 0x0a); /* Unmute audio */
141854450f59SHans Verkuil 		hdmi_write(sd, 0x01, 0x00); /* Enable HDMI clock terminators */
141954450f59SHans Verkuil 		io_write(sd, 0x15, 0xa0);   /* Disable Tristate of Pins */
142054450f59SHans Verkuil 		break;
142154450f59SHans Verkuil 	default:
14226b0d5d34SHans Verkuil 		v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n",
14236b0d5d34SHans Verkuil 				__func__, state->mode);
142454450f59SHans Verkuil 		break;
142554450f59SHans Verkuil 	}
142654450f59SHans Verkuil }
142754450f59SHans Verkuil 
142854450f59SHans Verkuil static void disable_input(struct v4l2_subdev *sd)
142954450f59SHans Verkuil {
143054450f59SHans Verkuil 	/* disable */
143154450f59SHans Verkuil 	io_write(sd, 0x15, 0xbe);   /* Tristate all outputs from video core */
143254450f59SHans Verkuil 	hdmi_write(sd, 0x1a, 0x1a); /* Mute audio */
143354450f59SHans Verkuil 	hdmi_write(sd, 0x01, 0x78); /* Disable HDMI clock terminators */
143454450f59SHans Verkuil }
143554450f59SHans Verkuil 
14366b0d5d34SHans Verkuil static void select_input(struct v4l2_subdev *sd)
143754450f59SHans Verkuil {
14386b0d5d34SHans Verkuil 	struct adv7604_state *state = to_state(sd);
143954450f59SHans Verkuil 
14406b0d5d34SHans Verkuil 	switch (state->mode) {
14416b0d5d34SHans Verkuil 	case ADV7604_MODE_COMP:
14426b0d5d34SHans Verkuil 	case ADV7604_MODE_GR:
144354450f59SHans Verkuil 		/* reset ADI recommended settings for HDMI: */
144454450f59SHans Verkuil 		/* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */
144554450f59SHans Verkuil 		hdmi_write(sd, 0x0d, 0x04); /* HDMI filter optimization */
144654450f59SHans Verkuil 		hdmi_write(sd, 0x3d, 0x00); /* DDC bus active pull-up control */
144754450f59SHans Verkuil 		hdmi_write(sd, 0x3e, 0x74); /* TMDS PLL optimization */
144854450f59SHans Verkuil 		hdmi_write(sd, 0x4e, 0x3b); /* TMDS PLL optimization */
144954450f59SHans Verkuil 		hdmi_write(sd, 0x57, 0x74); /* TMDS PLL optimization */
145054450f59SHans Verkuil 		hdmi_write(sd, 0x58, 0x63); /* TMDS PLL optimization */
145154450f59SHans Verkuil 		hdmi_write(sd, 0x8d, 0x18); /* equaliser */
145254450f59SHans Verkuil 		hdmi_write(sd, 0x8e, 0x34); /* equaliser */
145354450f59SHans Verkuil 		hdmi_write(sd, 0x93, 0x88); /* equaliser */
145454450f59SHans Verkuil 		hdmi_write(sd, 0x94, 0x2e); /* equaliser */
145554450f59SHans Verkuil 		hdmi_write(sd, 0x96, 0x00); /* enable automatic EQ changing */
145654450f59SHans Verkuil 
145754450f59SHans Verkuil 		afe_write(sd, 0x00, 0x08); /* power up ADC */
145854450f59SHans Verkuil 		afe_write(sd, 0x01, 0x06); /* power up Analog Front End */
145954450f59SHans Verkuil 		afe_write(sd, 0xc8, 0x00); /* phase control */
146054450f59SHans Verkuil 
146154450f59SHans Verkuil 		/* set ADI recommended settings for digitizer */
146254450f59SHans Verkuil 		/* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 17. */
146354450f59SHans Verkuil 		afe_write(sd, 0x12, 0x7b); /* ADC noise shaping filter controls */
146454450f59SHans Verkuil 		afe_write(sd, 0x0c, 0x1f); /* CP core gain controls */
146554450f59SHans Verkuil 		cp_write(sd, 0x3e, 0x04); /* CP core pre-gain control */
146654450f59SHans Verkuil 		cp_write(sd, 0xc3, 0x39); /* CP coast control. Graphics mode */
146754450f59SHans Verkuil 		cp_write(sd, 0x40, 0x5c); /* CP core pre-gain control. Graphics mode */
146854450f59SHans Verkuil 		break;
146954450f59SHans Verkuil 
14706b0d5d34SHans Verkuil 	case ADV7604_MODE_HDMI:
147154450f59SHans Verkuil 		/* set ADI recommended settings for HDMI: */
147254450f59SHans Verkuil 		/* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */
147354450f59SHans Verkuil 		hdmi_write(sd, 0x0d, 0x84); /* HDMI filter optimization */
147454450f59SHans Verkuil 		hdmi_write(sd, 0x3d, 0x10); /* DDC bus active pull-up control */
147554450f59SHans Verkuil 		hdmi_write(sd, 0x3e, 0x39); /* TMDS PLL optimization */
147654450f59SHans Verkuil 		hdmi_write(sd, 0x4e, 0x3b); /* TMDS PLL optimization */
147754450f59SHans Verkuil 		hdmi_write(sd, 0x57, 0xb6); /* TMDS PLL optimization */
147854450f59SHans Verkuil 		hdmi_write(sd, 0x58, 0x03); /* TMDS PLL optimization */
147954450f59SHans Verkuil 		hdmi_write(sd, 0x8d, 0x18); /* equaliser */
148054450f59SHans Verkuil 		hdmi_write(sd, 0x8e, 0x34); /* equaliser */
148154450f59SHans Verkuil 		hdmi_write(sd, 0x93, 0x8b); /* equaliser */
148254450f59SHans Verkuil 		hdmi_write(sd, 0x94, 0x2d); /* equaliser */
148354450f59SHans Verkuil 		hdmi_write(sd, 0x96, 0x01); /* enable automatic EQ changing */
148454450f59SHans Verkuil 
148554450f59SHans Verkuil 		afe_write(sd, 0x00, 0xff); /* power down ADC */
148654450f59SHans Verkuil 		afe_write(sd, 0x01, 0xfe); /* power down Analog Front End */
148754450f59SHans Verkuil 		afe_write(sd, 0xc8, 0x40); /* phase control */
148854450f59SHans Verkuil 
148954450f59SHans Verkuil 		/* reset ADI recommended settings for digitizer */
149054450f59SHans Verkuil 		/* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 17. */
149154450f59SHans Verkuil 		afe_write(sd, 0x12, 0xfb); /* ADC noise shaping filter controls */
149254450f59SHans Verkuil 		afe_write(sd, 0x0c, 0x0d); /* CP core gain controls */
149354450f59SHans Verkuil 		cp_write(sd, 0x3e, 0x00); /* CP core pre-gain control */
149454450f59SHans Verkuil 		cp_write(sd, 0xc3, 0x39); /* CP coast control. Graphics mode */
149554450f59SHans Verkuil 		cp_write(sd, 0x40, 0x80); /* CP core pre-gain control. Graphics mode */
149654450f59SHans Verkuil 
149754450f59SHans Verkuil 		break;
149854450f59SHans Verkuil 	default:
14996b0d5d34SHans Verkuil 		v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n",
15006b0d5d34SHans Verkuil 				__func__, state->mode);
150154450f59SHans Verkuil 		break;
150254450f59SHans Verkuil 	}
150354450f59SHans Verkuil }
150454450f59SHans Verkuil 
150554450f59SHans Verkuil static int adv7604_s_routing(struct v4l2_subdev *sd,
150654450f59SHans Verkuil 		u32 input, u32 output, u32 config)
150754450f59SHans Verkuil {
150854450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
150954450f59SHans Verkuil 
151054450f59SHans Verkuil 	v4l2_dbg(2, debug, sd, "%s: input %d", __func__, input);
151154450f59SHans Verkuil 
15126b0d5d34SHans Verkuil 	state->mode = input;
151354450f59SHans Verkuil 
151454450f59SHans Verkuil 	disable_input(sd);
151554450f59SHans Verkuil 
15166b0d5d34SHans Verkuil 	select_input(sd);
151754450f59SHans Verkuil 
15186b0d5d34SHans Verkuil 	enable_input(sd);
151954450f59SHans Verkuil 
152054450f59SHans Verkuil 	return 0;
152154450f59SHans Verkuil }
152254450f59SHans Verkuil 
152354450f59SHans Verkuil static int adv7604_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
152454450f59SHans Verkuil 			     enum v4l2_mbus_pixelcode *code)
152554450f59SHans Verkuil {
152654450f59SHans Verkuil 	if (index)
152754450f59SHans Verkuil 		return -EINVAL;
152854450f59SHans Verkuil 	/* Good enough for now */
152954450f59SHans Verkuil 	*code = V4L2_MBUS_FMT_FIXED;
153054450f59SHans Verkuil 	return 0;
153154450f59SHans Verkuil }
153254450f59SHans Verkuil 
153354450f59SHans Verkuil static int adv7604_g_mbus_fmt(struct v4l2_subdev *sd,
153454450f59SHans Verkuil 		struct v4l2_mbus_framefmt *fmt)
153554450f59SHans Verkuil {
153654450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
153754450f59SHans Verkuil 
153854450f59SHans Verkuil 	fmt->width = state->timings.bt.width;
153954450f59SHans Verkuil 	fmt->height = state->timings.bt.height;
154054450f59SHans Verkuil 	fmt->code = V4L2_MBUS_FMT_FIXED;
154154450f59SHans Verkuil 	fmt->field = V4L2_FIELD_NONE;
154254450f59SHans Verkuil 	if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) {
154354450f59SHans Verkuil 		fmt->colorspace = (state->timings.bt.height <= 576) ?
154454450f59SHans Verkuil 			V4L2_COLORSPACE_SMPTE170M : V4L2_COLORSPACE_REC709;
154554450f59SHans Verkuil 	}
154654450f59SHans Verkuil 	return 0;
154754450f59SHans Verkuil }
154854450f59SHans Verkuil 
154954450f59SHans Verkuil static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
155054450f59SHans Verkuil {
155154450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
155254450f59SHans Verkuil 	u8 fmt_change, fmt_change_digital, tx_5v;
155325a64ac9SMats Randgaard 	u32 input_status;
155454450f59SHans Verkuil 
155554450f59SHans Verkuil 	/* format change */
155654450f59SHans Verkuil 	fmt_change = io_read(sd, 0x43) & 0x98;
155754450f59SHans Verkuil 	if (fmt_change)
155854450f59SHans Verkuil 		io_write(sd, 0x44, fmt_change);
155954450f59SHans Verkuil 	fmt_change_digital = DIGITAL_INPUT ? (io_read(sd, 0x6b) & 0xc0) : 0;
156054450f59SHans Verkuil 	if (fmt_change_digital)
156154450f59SHans Verkuil 		io_write(sd, 0x6c, fmt_change_digital);
156254450f59SHans Verkuil 	if (fmt_change || fmt_change_digital) {
156354450f59SHans Verkuil 		v4l2_dbg(1, debug, sd,
156425a64ac9SMats Randgaard 			"%s: fmt_change = 0x%x, fmt_change_digital = 0x%x\n",
156554450f59SHans Verkuil 			__func__, fmt_change, fmt_change_digital);
156625a64ac9SMats Randgaard 
156725a64ac9SMats Randgaard 		adv7604_g_input_status(sd, &input_status);
156825a64ac9SMats Randgaard 		if (input_status != state->prev_input_status) {
156925a64ac9SMats Randgaard 			v4l2_dbg(1, debug, sd,
157025a64ac9SMats Randgaard 				"%s: input_status = 0x%x, prev_input_status = 0x%x\n",
157125a64ac9SMats Randgaard 				__func__, input_status, state->prev_input_status);
157225a64ac9SMats Randgaard 			state->prev_input_status = input_status;
157354450f59SHans Verkuil 			v4l2_subdev_notify(sd, ADV7604_FMT_CHANGE, NULL);
157425a64ac9SMats Randgaard 		}
157525a64ac9SMats Randgaard 
157654450f59SHans Verkuil 		if (handled)
157754450f59SHans Verkuil 			*handled = true;
157854450f59SHans Verkuil 	}
157954450f59SHans Verkuil 	/* tx 5v detect */
158054450f59SHans Verkuil 	tx_5v = io_read(sd, 0x70) & 0x10;
158154450f59SHans Verkuil 	if (tx_5v) {
158254450f59SHans Verkuil 		v4l2_dbg(1, debug, sd, "%s: tx_5v: 0x%x\n", __func__, tx_5v);
158354450f59SHans Verkuil 		io_write(sd, 0x71, tx_5v);
158454450f59SHans Verkuil 		adv7604_s_detect_tx_5v_ctrl(sd);
158554450f59SHans Verkuil 		if (handled)
158654450f59SHans Verkuil 			*handled = true;
158754450f59SHans Verkuil 	}
158854450f59SHans Verkuil 	return 0;
158954450f59SHans Verkuil }
159054450f59SHans Verkuil 
159154450f59SHans Verkuil static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
159254450f59SHans Verkuil {
159354450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
159454450f59SHans Verkuil 
159554450f59SHans Verkuil 	if (edid->pad != 0)
159654450f59SHans Verkuil 		return -EINVAL;
159754450f59SHans Verkuil 	if (edid->blocks == 0)
159854450f59SHans Verkuil 		return -EINVAL;
159954450f59SHans Verkuil 	if (edid->start_block >= state->edid_blocks)
160054450f59SHans Verkuil 		return -EINVAL;
160154450f59SHans Verkuil 	if (edid->start_block + edid->blocks > state->edid_blocks)
160254450f59SHans Verkuil 		edid->blocks = state->edid_blocks - edid->start_block;
160354450f59SHans Verkuil 	if (!edid->edid)
160454450f59SHans Verkuil 		return -EINVAL;
160554450f59SHans Verkuil 	memcpy(edid->edid + edid->start_block * 128,
160654450f59SHans Verkuil 	       state->edid + edid->start_block * 128,
160754450f59SHans Verkuil 	       edid->blocks * 128);
160854450f59SHans Verkuil 	return 0;
160954450f59SHans Verkuil }
161054450f59SHans Verkuil 
161154450f59SHans Verkuil static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
161254450f59SHans Verkuil {
161354450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
161454450f59SHans Verkuil 	int err;
161554450f59SHans Verkuil 
161654450f59SHans Verkuil 	if (edid->pad != 0)
161754450f59SHans Verkuil 		return -EINVAL;
161854450f59SHans Verkuil 	if (edid->start_block != 0)
161954450f59SHans Verkuil 		return -EINVAL;
162054450f59SHans Verkuil 	if (edid->blocks == 0) {
162154450f59SHans Verkuil 		/* Pull down the hotplug pin */
162254450f59SHans Verkuil 		v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)0);
162354450f59SHans Verkuil 		/* Disables I2C access to internal EDID ram from DDC port */
162454450f59SHans Verkuil 		rep_write_and_or(sd, 0x77, 0xf0, 0x0);
162554450f59SHans Verkuil 		state->edid_blocks = 0;
162654450f59SHans Verkuil 		/* Fall back to a 16:9 aspect ratio */
162754450f59SHans Verkuil 		state->aspect_ratio.numerator = 16;
162854450f59SHans Verkuil 		state->aspect_ratio.denominator = 9;
162954450f59SHans Verkuil 		return 0;
163054450f59SHans Verkuil 	}
163154450f59SHans Verkuil 	if (edid->blocks > 2)
163254450f59SHans Verkuil 		return -E2BIG;
163354450f59SHans Verkuil 	if (!edid->edid)
163454450f59SHans Verkuil 		return -EINVAL;
163554450f59SHans Verkuil 	memcpy(state->edid, edid->edid, 128 * edid->blocks);
163654450f59SHans Verkuil 	state->edid_blocks = edid->blocks;
163754450f59SHans Verkuil 	state->aspect_ratio = v4l2_calc_aspect_ratio(edid->edid[0x15],
163854450f59SHans Verkuil 			edid->edid[0x16]);
163954450f59SHans Verkuil 	err = edid_write_block(sd, 128 * edid->blocks, state->edid);
164054450f59SHans Verkuil 	if (err < 0)
164154450f59SHans Verkuil 		v4l2_err(sd, "error %d writing edid\n", err);
164254450f59SHans Verkuil 	return err;
164354450f59SHans Verkuil }
164454450f59SHans Verkuil 
164554450f59SHans Verkuil /*********** avi info frame CEA-861-E **************/
164654450f59SHans Verkuil 
164754450f59SHans Verkuil static void print_avi_infoframe(struct v4l2_subdev *sd)
164854450f59SHans Verkuil {
164954450f59SHans Verkuil 	int i;
165054450f59SHans Verkuil 	u8 buf[14];
165154450f59SHans Verkuil 	u8 avi_len;
165254450f59SHans Verkuil 	u8 avi_ver;
165354450f59SHans Verkuil 
1654bb88f325SMartin Bugge 	if (!is_hdmi(sd)) {
165554450f59SHans Verkuil 		v4l2_info(sd, "receive DVI-D signal (AVI infoframe not supported)\n");
165654450f59SHans Verkuil 		return;
165754450f59SHans Verkuil 	}
165854450f59SHans Verkuil 	if (!(io_read(sd, 0x60) & 0x01)) {
165954450f59SHans Verkuil 		v4l2_info(sd, "AVI infoframe not received\n");
166054450f59SHans Verkuil 		return;
166154450f59SHans Verkuil 	}
166254450f59SHans Verkuil 
166354450f59SHans Verkuil 	if (io_read(sd, 0x83) & 0x01) {
166454450f59SHans Verkuil 		v4l2_info(sd, "AVI infoframe checksum error has occurred earlier\n");
166554450f59SHans Verkuil 		io_write(sd, 0x85, 0x01); /* clear AVI_INF_CKS_ERR_RAW */
166654450f59SHans Verkuil 		if (io_read(sd, 0x83) & 0x01) {
166754450f59SHans Verkuil 			v4l2_info(sd, "AVI infoframe checksum error still present\n");
166854450f59SHans Verkuil 			io_write(sd, 0x85, 0x01); /* clear AVI_INF_CKS_ERR_RAW */
166954450f59SHans Verkuil 		}
167054450f59SHans Verkuil 	}
167154450f59SHans Verkuil 
167254450f59SHans Verkuil 	avi_len = infoframe_read(sd, 0xe2);
167354450f59SHans Verkuil 	avi_ver = infoframe_read(sd, 0xe1);
167454450f59SHans Verkuil 	v4l2_info(sd, "AVI infoframe version %d (%d byte)\n",
167554450f59SHans Verkuil 			avi_ver, avi_len);
167654450f59SHans Verkuil 
167754450f59SHans Verkuil 	if (avi_ver != 0x02)
167854450f59SHans Verkuil 		return;
167954450f59SHans Verkuil 
168054450f59SHans Verkuil 	for (i = 0; i < 14; i++)
168154450f59SHans Verkuil 		buf[i] = infoframe_read(sd, i);
168254450f59SHans Verkuil 
168354450f59SHans Verkuil 	v4l2_info(sd,
168454450f59SHans Verkuil 		"\t%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
168554450f59SHans Verkuil 		buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7],
168654450f59SHans Verkuil 		buf[8], buf[9], buf[10], buf[11], buf[12], buf[13]);
168754450f59SHans Verkuil }
168854450f59SHans Verkuil 
168954450f59SHans Verkuil static int adv7604_log_status(struct v4l2_subdev *sd)
169054450f59SHans Verkuil {
169154450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
169254450f59SHans Verkuil 	struct v4l2_dv_timings timings;
169354450f59SHans Verkuil 	struct stdi_readback stdi;
169454450f59SHans Verkuil 	u8 reg_io_0x02 = io_read(sd, 0x02);
169554450f59SHans Verkuil 
169654450f59SHans Verkuil 	char *csc_coeff_sel_rb[16] = {
169754450f59SHans Verkuil 		"bypassed", "YPbPr601 -> RGB", "reserved", "YPbPr709 -> RGB",
169854450f59SHans Verkuil 		"reserved", "RGB -> YPbPr601", "reserved", "RGB -> YPbPr709",
169954450f59SHans Verkuil 		"reserved", "YPbPr709 -> YPbPr601", "YPbPr601 -> YPbPr709",
170054450f59SHans Verkuil 		"reserved", "reserved", "reserved", "reserved", "manual"
170154450f59SHans Verkuil 	};
170254450f59SHans Verkuil 	char *input_color_space_txt[16] = {
170354450f59SHans Verkuil 		"RGB limited range (16-235)", "RGB full range (0-255)",
170454450f59SHans Verkuil 		"YCbCr Bt.601 (16-235)", "YCbCr Bt.709 (16-235)",
170554450f59SHans Verkuil 		"XvYCC Bt.601", "XvYCC Bt.709",
170654450f59SHans Verkuil 		"YCbCr Bt.601 (0-255)", "YCbCr Bt.709 (0-255)",
170754450f59SHans Verkuil 		"invalid", "invalid", "invalid", "invalid", "invalid",
170854450f59SHans Verkuil 		"invalid", "invalid", "automatic"
170954450f59SHans Verkuil 	};
171054450f59SHans Verkuil 	char *rgb_quantization_range_txt[] = {
171154450f59SHans Verkuil 		"Automatic",
171254450f59SHans Verkuil 		"RGB limited range (16-235)",
171354450f59SHans Verkuil 		"RGB full range (0-255)",
171454450f59SHans Verkuil 	};
1715bb88f325SMartin Bugge 	char *deep_color_mode_txt[4] = {
1716bb88f325SMartin Bugge 		"8-bits per channel",
1717bb88f325SMartin Bugge 		"10-bits per channel",
1718bb88f325SMartin Bugge 		"12-bits per channel",
1719bb88f325SMartin Bugge 		"16-bits per channel (not supported)"
1720bb88f325SMartin Bugge 	};
172154450f59SHans Verkuil 
172254450f59SHans Verkuil 	v4l2_info(sd, "-----Chip status-----\n");
172354450f59SHans Verkuil 	v4l2_info(sd, "Chip power: %s\n", no_power(sd) ? "off" : "on");
172454450f59SHans Verkuil 	v4l2_info(sd, "Connector type: %s\n", state->connector_hdmi ?
172554450f59SHans Verkuil 			"HDMI" : (DIGITAL_INPUT ? "DVI-D" : "DVI-A"));
172654450f59SHans Verkuil 	v4l2_info(sd, "EDID: %s\n", ((rep_read(sd, 0x7d) & 0x01) &&
172754450f59SHans Verkuil 			(rep_read(sd, 0x77) & 0x01)) ? "enabled" : "disabled ");
172854450f59SHans Verkuil 	v4l2_info(sd, "CEC: %s\n", !!(cec_read(sd, 0x2a) & 0x01) ?
172954450f59SHans Verkuil 			"enabled" : "disabled");
173054450f59SHans Verkuil 
173154450f59SHans Verkuil 	v4l2_info(sd, "-----Signal status-----\n");
173254450f59SHans Verkuil 	v4l2_info(sd, "Cable detected (+5V power): %s\n",
173354450f59SHans Verkuil 			(io_read(sd, 0x6f) & 0x10) ? "true" : "false");
173454450f59SHans Verkuil 	v4l2_info(sd, "TMDS signal detected: %s\n",
173554450f59SHans Verkuil 			no_signal_tmds(sd) ? "false" : "true");
173654450f59SHans Verkuil 	v4l2_info(sd, "TMDS signal locked: %s\n",
173754450f59SHans Verkuil 			no_lock_tmds(sd) ? "false" : "true");
173854450f59SHans Verkuil 	v4l2_info(sd, "SSPD locked: %s\n", no_lock_sspd(sd) ? "false" : "true");
173954450f59SHans Verkuil 	v4l2_info(sd, "STDI locked: %s\n", no_lock_stdi(sd) ? "false" : "true");
174054450f59SHans Verkuil 	v4l2_info(sd, "CP locked: %s\n", no_lock_cp(sd) ? "false" : "true");
174154450f59SHans Verkuil 	v4l2_info(sd, "CP free run: %s\n",
174254450f59SHans Verkuil 			(!!(cp_read(sd, 0xff) & 0x10) ? "on" : "off"));
1743ccbd5bc4SHans Verkuil 	v4l2_info(sd, "Prim-mode = 0x%x, video std = 0x%x, v_freq = 0x%x\n",
1744ccbd5bc4SHans Verkuil 			io_read(sd, 0x01) & 0x0f, io_read(sd, 0x00) & 0x3f,
1745ccbd5bc4SHans Verkuil 			(io_read(sd, 0x01) & 0x70) >> 4);
174654450f59SHans Verkuil 
174754450f59SHans Verkuil 	v4l2_info(sd, "-----Video Timings-----\n");
174854450f59SHans Verkuil 	if (read_stdi(sd, &stdi))
174954450f59SHans Verkuil 		v4l2_info(sd, "STDI: not locked\n");
175054450f59SHans Verkuil 	else
175154450f59SHans Verkuil 		v4l2_info(sd, "STDI: lcf (frame height - 1) = %d, bl = %d, lcvs (vsync) = %d, %s, %chsync, %cvsync\n",
175254450f59SHans Verkuil 				stdi.lcf, stdi.bl, stdi.lcvs,
175354450f59SHans Verkuil 				stdi.interlaced ? "interlaced" : "progressive",
175454450f59SHans Verkuil 				stdi.hs_pol, stdi.vs_pol);
175554450f59SHans Verkuil 	if (adv7604_query_dv_timings(sd, &timings))
175654450f59SHans Verkuil 		v4l2_info(sd, "No video detected\n");
175754450f59SHans Verkuil 	else
175854450f59SHans Verkuil 		adv7604_print_timings(sd, &timings, "Detected format:", true);
175954450f59SHans Verkuil 	adv7604_print_timings(sd, &state->timings, "Configured format:", true);
176054450f59SHans Verkuil 
176154450f59SHans Verkuil 	v4l2_info(sd, "-----Color space-----\n");
176254450f59SHans Verkuil 	v4l2_info(sd, "RGB quantization range ctrl: %s\n",
176354450f59SHans Verkuil 			rgb_quantization_range_txt[state->rgb_quantization_range]);
176454450f59SHans Verkuil 	v4l2_info(sd, "Input color space: %s\n",
176554450f59SHans Verkuil 			input_color_space_txt[reg_io_0x02 >> 4]);
176654450f59SHans Verkuil 	v4l2_info(sd, "Output color space: %s %s, saturator %s\n",
176754450f59SHans Verkuil 			(reg_io_0x02 & 0x02) ? "RGB" : "YCbCr",
176854450f59SHans Verkuil 			(reg_io_0x02 & 0x04) ? "(16-235)" : "(0-255)",
176954450f59SHans Verkuil 			((reg_io_0x02 & 0x04) ^ (reg_io_0x02 & 0x01)) ?
177054450f59SHans Verkuil 					"enabled" : "disabled");
177154450f59SHans Verkuil 	v4l2_info(sd, "Color space conversion: %s\n",
177254450f59SHans Verkuil 			csc_coeff_sel_rb[cp_read(sd, 0xfc) >> 4]);
177354450f59SHans Verkuil 
177454450f59SHans Verkuil 	/* Digital video */
177554450f59SHans Verkuil 	if (DIGITAL_INPUT) {
177654450f59SHans Verkuil 		v4l2_info(sd, "-----HDMI status-----\n");
177754450f59SHans Verkuil 		v4l2_info(sd, "HDCP encrypted content: %s\n",
177854450f59SHans Verkuil 				hdmi_read(sd, 0x05) & 0x40 ? "true" : "false");
1779bb88f325SMartin Bugge 		if (is_hdmi(sd))
1780bb88f325SMartin Bugge 			v4l2_info(sd, "deep color mode: %s\n",
1781bb88f325SMartin Bugge 					deep_color_mode_txt[(hdmi_read(sd, 0x0b) >> 5) & 0x3]);
178254450f59SHans Verkuil 		print_avi_infoframe(sd);
178354450f59SHans Verkuil 	}
178454450f59SHans Verkuil 
178554450f59SHans Verkuil 	return 0;
178654450f59SHans Verkuil }
178754450f59SHans Verkuil 
178854450f59SHans Verkuil /* ----------------------------------------------------------------------- */
178954450f59SHans Verkuil 
179054450f59SHans Verkuil static const struct v4l2_ctrl_ops adv7604_ctrl_ops = {
179154450f59SHans Verkuil 	.s_ctrl = adv7604_s_ctrl,
179254450f59SHans Verkuil };
179354450f59SHans Verkuil 
179454450f59SHans Verkuil static const struct v4l2_subdev_core_ops adv7604_core_ops = {
179554450f59SHans Verkuil 	.log_status = adv7604_log_status,
179654450f59SHans Verkuil 	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
179754450f59SHans Verkuil 	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
179854450f59SHans Verkuil 	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
179954450f59SHans Verkuil 	.g_ctrl = v4l2_subdev_g_ctrl,
180054450f59SHans Verkuil 	.s_ctrl = v4l2_subdev_s_ctrl,
180154450f59SHans Verkuil 	.queryctrl = v4l2_subdev_queryctrl,
180254450f59SHans Verkuil 	.querymenu = v4l2_subdev_querymenu,
180354450f59SHans Verkuil 	.interrupt_service_routine = adv7604_isr,
180454450f59SHans Verkuil #ifdef CONFIG_VIDEO_ADV_DEBUG
180554450f59SHans Verkuil 	.g_register = adv7604_g_register,
180654450f59SHans Verkuil 	.s_register = adv7604_s_register,
180754450f59SHans Verkuil #endif
180854450f59SHans Verkuil };
180954450f59SHans Verkuil 
181054450f59SHans Verkuil static const struct v4l2_subdev_video_ops adv7604_video_ops = {
181154450f59SHans Verkuil 	.s_routing = adv7604_s_routing,
181254450f59SHans Verkuil 	.g_input_status = adv7604_g_input_status,
181354450f59SHans Verkuil 	.s_dv_timings = adv7604_s_dv_timings,
181454450f59SHans Verkuil 	.g_dv_timings = adv7604_g_dv_timings,
181554450f59SHans Verkuil 	.query_dv_timings = adv7604_query_dv_timings,
181654450f59SHans Verkuil 	.enum_dv_timings = adv7604_enum_dv_timings,
181754450f59SHans Verkuil 	.dv_timings_cap = adv7604_dv_timings_cap,
181854450f59SHans Verkuil 	.enum_mbus_fmt = adv7604_enum_mbus_fmt,
181954450f59SHans Verkuil 	.g_mbus_fmt = adv7604_g_mbus_fmt,
182054450f59SHans Verkuil 	.try_mbus_fmt = adv7604_g_mbus_fmt,
182154450f59SHans Verkuil 	.s_mbus_fmt = adv7604_g_mbus_fmt,
182254450f59SHans Verkuil };
182354450f59SHans Verkuil 
182454450f59SHans Verkuil static const struct v4l2_subdev_pad_ops adv7604_pad_ops = {
182554450f59SHans Verkuil 	.get_edid = adv7604_get_edid,
182654450f59SHans Verkuil 	.set_edid = adv7604_set_edid,
182754450f59SHans Verkuil };
182854450f59SHans Verkuil 
182954450f59SHans Verkuil static const struct v4l2_subdev_ops adv7604_ops = {
183054450f59SHans Verkuil 	.core = &adv7604_core_ops,
183154450f59SHans Verkuil 	.video = &adv7604_video_ops,
183254450f59SHans Verkuil 	.pad = &adv7604_pad_ops,
183354450f59SHans Verkuil };
183454450f59SHans Verkuil 
183554450f59SHans Verkuil /* -------------------------- custom ctrls ---------------------------------- */
183654450f59SHans Verkuil 
183754450f59SHans Verkuil static const struct v4l2_ctrl_config adv7604_ctrl_analog_sampling_phase = {
183854450f59SHans Verkuil 	.ops = &adv7604_ctrl_ops,
183954450f59SHans Verkuil 	.id = V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE,
184054450f59SHans Verkuil 	.name = "Analog Sampling Phase",
184154450f59SHans Verkuil 	.type = V4L2_CTRL_TYPE_INTEGER,
184254450f59SHans Verkuil 	.min = 0,
184354450f59SHans Verkuil 	.max = 0x1f,
184454450f59SHans Verkuil 	.step = 1,
184554450f59SHans Verkuil 	.def = 0,
184654450f59SHans Verkuil };
184754450f59SHans Verkuil 
184854450f59SHans Verkuil static const struct v4l2_ctrl_config adv7604_ctrl_free_run_color_manual = {
184954450f59SHans Verkuil 	.ops = &adv7604_ctrl_ops,
185054450f59SHans Verkuil 	.id = V4L2_CID_ADV_RX_FREE_RUN_COLOR_MANUAL,
185154450f59SHans Verkuil 	.name = "Free Running Color, Manual",
185254450f59SHans Verkuil 	.type = V4L2_CTRL_TYPE_BOOLEAN,
185354450f59SHans Verkuil 	.min = false,
185454450f59SHans Verkuil 	.max = true,
185554450f59SHans Verkuil 	.step = 1,
185654450f59SHans Verkuil 	.def = false,
185754450f59SHans Verkuil };
185854450f59SHans Verkuil 
185954450f59SHans Verkuil static const struct v4l2_ctrl_config adv7604_ctrl_free_run_color = {
186054450f59SHans Verkuil 	.ops = &adv7604_ctrl_ops,
186154450f59SHans Verkuil 	.id = V4L2_CID_ADV_RX_FREE_RUN_COLOR,
186254450f59SHans Verkuil 	.name = "Free Running Color",
186354450f59SHans Verkuil 	.type = V4L2_CTRL_TYPE_INTEGER,
186454450f59SHans Verkuil 	.min = 0x0,
186554450f59SHans Verkuil 	.max = 0xffffff,
186654450f59SHans Verkuil 	.step = 0x1,
186754450f59SHans Verkuil 	.def = 0x0,
186854450f59SHans Verkuil };
186954450f59SHans Verkuil 
187054450f59SHans Verkuil /* ----------------------------------------------------------------------- */
187154450f59SHans Verkuil 
187254450f59SHans Verkuil static int adv7604_core_init(struct v4l2_subdev *sd)
187354450f59SHans Verkuil {
187454450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
187554450f59SHans Verkuil 	struct adv7604_platform_data *pdata = &state->pdata;
187654450f59SHans Verkuil 
187754450f59SHans Verkuil 	hdmi_write(sd, 0x48,
187854450f59SHans Verkuil 		(pdata->disable_pwrdnb ? 0x80 : 0) |
187954450f59SHans Verkuil 		(pdata->disable_cable_det_rst ? 0x40 : 0));
188054450f59SHans Verkuil 
188154450f59SHans Verkuil 	disable_input(sd);
188254450f59SHans Verkuil 
188354450f59SHans Verkuil 	/* power */
188454450f59SHans Verkuil 	io_write(sd, 0x0c, 0x42);   /* Power up part and power down VDP */
188554450f59SHans Verkuil 	io_write(sd, 0x0b, 0x44);   /* Power down ESDP block */
188654450f59SHans Verkuil 	cp_write(sd, 0xcf, 0x01);   /* Power down macrovision */
188754450f59SHans Verkuil 
188854450f59SHans Verkuil 	/* video format */
188954450f59SHans Verkuil 	io_write_and_or(sd, 0x02, 0xf0,
189054450f59SHans Verkuil 			pdata->alt_gamma << 3 |
189154450f59SHans Verkuil 			pdata->op_656_range << 2 |
189254450f59SHans Verkuil 			pdata->rgb_out << 1 |
189354450f59SHans Verkuil 			pdata->alt_data_sat << 0);
189454450f59SHans Verkuil 	io_write(sd, 0x03, pdata->op_format_sel);
189554450f59SHans Verkuil 	io_write_and_or(sd, 0x04, 0x1f, pdata->op_ch_sel << 5);
189654450f59SHans Verkuil 	io_write_and_or(sd, 0x05, 0xf0, pdata->blank_data << 3 |
189754450f59SHans Verkuil 					pdata->insert_av_codes << 2 |
189854450f59SHans Verkuil 					pdata->replicate_av_codes << 1 |
189954450f59SHans Verkuil 					pdata->invert_cbcr << 0);
190054450f59SHans Verkuil 
190154450f59SHans Verkuil 	/* TODO from platform data */
190254450f59SHans Verkuil 	cp_write(sd, 0x69, 0x30);   /* Enable CP CSC */
190354450f59SHans Verkuil 	io_write(sd, 0x06, 0xa6);   /* positive VS and HS */
190454450f59SHans Verkuil 	io_write(sd, 0x14, 0x7f);   /* Drive strength adjusted to max */
190554450f59SHans Verkuil 	cp_write(sd, 0xba, (pdata->hdmi_free_run_mode << 1) | 0x01); /* HDMI free run */
190654450f59SHans Verkuil 	cp_write(sd, 0xf3, 0xdc); /* Low threshold to enter/exit free run mode */
190754450f59SHans Verkuil 	cp_write(sd, 0xf9, 0x23); /*  STDI ch. 1 - LCVS change threshold -
190880939647SHans Verkuil 				      ADI recommended setting [REF_01, c. 2.3.3] */
190954450f59SHans Verkuil 	cp_write(sd, 0x45, 0x23); /*  STDI ch. 2 - LCVS change threshold -
191080939647SHans Verkuil 				      ADI recommended setting [REF_01, c. 2.3.3] */
191154450f59SHans Verkuil 	cp_write(sd, 0xc9, 0x2d); /* use prim_mode and vid_std as free run resolution
191254450f59SHans Verkuil 				     for digital formats */
191354450f59SHans Verkuil 
191454450f59SHans Verkuil 	/* TODO from platform data */
191554450f59SHans Verkuil 	afe_write(sd, 0xb5, 0x01);  /* Setting MCLK to 256Fs */
191654450f59SHans Verkuil 
191754450f59SHans Verkuil 	afe_write(sd, 0x02, pdata->ain_sel); /* Select analog input muxing mode */
191854450f59SHans Verkuil 	io_write_and_or(sd, 0x30, ~(1 << 4), pdata->output_bus_lsb_to_msb << 4);
191954450f59SHans Verkuil 
192054450f59SHans Verkuil 	/* interrupts */
192154450f59SHans Verkuil 	io_write(sd, 0x40, 0xc2); /* Configure INT1 */
192254450f59SHans Verkuil 	io_write(sd, 0x41, 0xd7); /* STDI irq for any change, disable INT2 */
192354450f59SHans Verkuil 	io_write(sd, 0x46, 0x98); /* Enable SSPD, STDI and CP unlocked interrupts */
192454450f59SHans Verkuil 	io_write(sd, 0x6e, 0xc0); /* Enable V_LOCKED and DE_REGEN_LCK interrupts */
192554450f59SHans Verkuil 	io_write(sd, 0x73, 0x10); /* Enable CABLE_DET_A_ST (+5v) interrupt */
192654450f59SHans Verkuil 
192754450f59SHans Verkuil 	return v4l2_ctrl_handler_setup(sd->ctrl_handler);
192854450f59SHans Verkuil }
192954450f59SHans Verkuil 
193054450f59SHans Verkuil static void adv7604_unregister_clients(struct adv7604_state *state)
193154450f59SHans Verkuil {
193254450f59SHans Verkuil 	if (state->i2c_avlink)
193354450f59SHans Verkuil 		i2c_unregister_device(state->i2c_avlink);
193454450f59SHans Verkuil 	if (state->i2c_cec)
193554450f59SHans Verkuil 		i2c_unregister_device(state->i2c_cec);
193654450f59SHans Verkuil 	if (state->i2c_infoframe)
193754450f59SHans Verkuil 		i2c_unregister_device(state->i2c_infoframe);
193854450f59SHans Verkuil 	if (state->i2c_esdp)
193954450f59SHans Verkuil 		i2c_unregister_device(state->i2c_esdp);
194054450f59SHans Verkuil 	if (state->i2c_dpp)
194154450f59SHans Verkuil 		i2c_unregister_device(state->i2c_dpp);
194254450f59SHans Verkuil 	if (state->i2c_afe)
194354450f59SHans Verkuil 		i2c_unregister_device(state->i2c_afe);
194454450f59SHans Verkuil 	if (state->i2c_repeater)
194554450f59SHans Verkuil 		i2c_unregister_device(state->i2c_repeater);
194654450f59SHans Verkuil 	if (state->i2c_edid)
194754450f59SHans Verkuil 		i2c_unregister_device(state->i2c_edid);
194854450f59SHans Verkuil 	if (state->i2c_hdmi)
194954450f59SHans Verkuil 		i2c_unregister_device(state->i2c_hdmi);
195054450f59SHans Verkuil 	if (state->i2c_test)
195154450f59SHans Verkuil 		i2c_unregister_device(state->i2c_test);
195254450f59SHans Verkuil 	if (state->i2c_cp)
195354450f59SHans Verkuil 		i2c_unregister_device(state->i2c_cp);
195454450f59SHans Verkuil 	if (state->i2c_vdp)
195554450f59SHans Verkuil 		i2c_unregister_device(state->i2c_vdp);
195654450f59SHans Verkuil }
195754450f59SHans Verkuil 
195854450f59SHans Verkuil static struct i2c_client *adv7604_dummy_client(struct v4l2_subdev *sd,
195954450f59SHans Verkuil 							u8 addr, u8 io_reg)
196054450f59SHans Verkuil {
196154450f59SHans Verkuil 	struct i2c_client *client = v4l2_get_subdevdata(sd);
196254450f59SHans Verkuil 
196354450f59SHans Verkuil 	if (addr)
196454450f59SHans Verkuil 		io_write(sd, io_reg, addr << 1);
196554450f59SHans Verkuil 	return i2c_new_dummy(client->adapter, io_read(sd, io_reg) >> 1);
196654450f59SHans Verkuil }
196754450f59SHans Verkuil 
196854450f59SHans Verkuil static int adv7604_probe(struct i2c_client *client,
196954450f59SHans Verkuil 			 const struct i2c_device_id *id)
197054450f59SHans Verkuil {
197154450f59SHans Verkuil 	struct adv7604_state *state;
197254450f59SHans Verkuil 	struct adv7604_platform_data *pdata = client->dev.platform_data;
197354450f59SHans Verkuil 	struct v4l2_ctrl_handler *hdl;
197454450f59SHans Verkuil 	struct v4l2_subdev *sd;
197554450f59SHans Verkuil 	int err;
197654450f59SHans Verkuil 
197754450f59SHans Verkuil 	/* Check if the adapter supports the needed features */
197854450f59SHans Verkuil 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
197954450f59SHans Verkuil 		return -EIO;
198054450f59SHans Verkuil 	v4l_dbg(1, debug, client, "detecting adv7604 client on address 0x%x\n",
198154450f59SHans Verkuil 			client->addr << 1);
198254450f59SHans Verkuil 
1983c02b211dSLaurent Pinchart 	state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
198454450f59SHans Verkuil 	if (!state) {
198554450f59SHans Verkuil 		v4l_err(client, "Could not allocate adv7604_state memory!\n");
198654450f59SHans Verkuil 		return -ENOMEM;
198754450f59SHans Verkuil 	}
198854450f59SHans Verkuil 
198925a64ac9SMats Randgaard 	/* initialize variables */
199025a64ac9SMats Randgaard 	state->restart_stdi_once = true;
199125a64ac9SMats Randgaard 	state->prev_input_status = ~0;
199225a64ac9SMats Randgaard 
199354450f59SHans Verkuil 	/* platform data */
199454450f59SHans Verkuil 	if (!pdata) {
199554450f59SHans Verkuil 		v4l_err(client, "No platform data!\n");
1996c02b211dSLaurent Pinchart 		return -ENODEV;
199754450f59SHans Verkuil 	}
199854450f59SHans Verkuil 	memcpy(&state->pdata, pdata, sizeof(state->pdata));
199954450f59SHans Verkuil 
200054450f59SHans Verkuil 	sd = &state->sd;
200154450f59SHans Verkuil 	v4l2_i2c_subdev_init(sd, client, &adv7604_ops);
200254450f59SHans Verkuil 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
200354450f59SHans Verkuil 	state->connector_hdmi = pdata->connector_hdmi;
200454450f59SHans Verkuil 
200554450f59SHans Verkuil 	/* i2c access to adv7604? */
200654450f59SHans Verkuil 	if (adv_smbus_read_byte_data_check(client, 0xfb, false) != 0x68) {
200754450f59SHans Verkuil 		v4l2_info(sd, "not an adv7604 on address 0x%x\n",
200854450f59SHans Verkuil 				client->addr << 1);
2009c02b211dSLaurent Pinchart 		return -ENODEV;
201054450f59SHans Verkuil 	}
201154450f59SHans Verkuil 
201254450f59SHans Verkuil 	/* control handlers */
201354450f59SHans Verkuil 	hdl = &state->hdl;
201454450f59SHans Verkuil 	v4l2_ctrl_handler_init(hdl, 9);
201554450f59SHans Verkuil 
201654450f59SHans Verkuil 	v4l2_ctrl_new_std(hdl, &adv7604_ctrl_ops,
201754450f59SHans Verkuil 			V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
201854450f59SHans Verkuil 	v4l2_ctrl_new_std(hdl, &adv7604_ctrl_ops,
201954450f59SHans Verkuil 			V4L2_CID_CONTRAST, 0, 255, 1, 128);
202054450f59SHans Verkuil 	v4l2_ctrl_new_std(hdl, &adv7604_ctrl_ops,
202154450f59SHans Verkuil 			V4L2_CID_SATURATION, 0, 255, 1, 128);
202254450f59SHans Verkuil 	v4l2_ctrl_new_std(hdl, &adv7604_ctrl_ops,
202354450f59SHans Verkuil 			V4L2_CID_HUE, 0, 128, 1, 0);
202454450f59SHans Verkuil 
202554450f59SHans Verkuil 	/* private controls */
202654450f59SHans Verkuil 	state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL,
202754450f59SHans Verkuil 			V4L2_CID_DV_RX_POWER_PRESENT, 0, 1, 0, 0);
202854450f59SHans Verkuil 	state->detect_tx_5v_ctrl->is_private = true;
202954450f59SHans Verkuil 	state->rgb_quantization_range_ctrl =
203054450f59SHans Verkuil 		v4l2_ctrl_new_std_menu(hdl, &adv7604_ctrl_ops,
203154450f59SHans Verkuil 			V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL,
203254450f59SHans Verkuil 			0, V4L2_DV_RGB_RANGE_AUTO);
203354450f59SHans Verkuil 	state->rgb_quantization_range_ctrl->is_private = true;
203454450f59SHans Verkuil 
203554450f59SHans Verkuil 	/* custom controls */
203654450f59SHans Verkuil 	state->analog_sampling_phase_ctrl =
203754450f59SHans Verkuil 		v4l2_ctrl_new_custom(hdl, &adv7604_ctrl_analog_sampling_phase, NULL);
203854450f59SHans Verkuil 	state->analog_sampling_phase_ctrl->is_private = true;
203954450f59SHans Verkuil 	state->free_run_color_manual_ctrl =
204054450f59SHans Verkuil 		v4l2_ctrl_new_custom(hdl, &adv7604_ctrl_free_run_color_manual, NULL);
204154450f59SHans Verkuil 	state->free_run_color_manual_ctrl->is_private = true;
204254450f59SHans Verkuil 	state->free_run_color_ctrl =
204354450f59SHans Verkuil 		v4l2_ctrl_new_custom(hdl, &adv7604_ctrl_free_run_color, NULL);
204454450f59SHans Verkuil 	state->free_run_color_ctrl->is_private = true;
204554450f59SHans Verkuil 
204654450f59SHans Verkuil 	sd->ctrl_handler = hdl;
204754450f59SHans Verkuil 	if (hdl->error) {
204854450f59SHans Verkuil 		err = hdl->error;
204954450f59SHans Verkuil 		goto err_hdl;
205054450f59SHans Verkuil 	}
205154450f59SHans Verkuil 	if (adv7604_s_detect_tx_5v_ctrl(sd)) {
205254450f59SHans Verkuil 		err = -ENODEV;
205354450f59SHans Verkuil 		goto err_hdl;
205454450f59SHans Verkuil 	}
205554450f59SHans Verkuil 
205654450f59SHans Verkuil 	state->i2c_avlink = adv7604_dummy_client(sd, pdata->i2c_avlink, 0xf3);
205754450f59SHans Verkuil 	state->i2c_cec = adv7604_dummy_client(sd, pdata->i2c_cec, 0xf4);
205854450f59SHans Verkuil 	state->i2c_infoframe = adv7604_dummy_client(sd, pdata->i2c_infoframe, 0xf5);
205954450f59SHans Verkuil 	state->i2c_esdp = adv7604_dummy_client(sd, pdata->i2c_esdp, 0xf6);
206054450f59SHans Verkuil 	state->i2c_dpp = adv7604_dummy_client(sd, pdata->i2c_dpp, 0xf7);
206154450f59SHans Verkuil 	state->i2c_afe = adv7604_dummy_client(sd, pdata->i2c_afe, 0xf8);
206254450f59SHans Verkuil 	state->i2c_repeater = adv7604_dummy_client(sd, pdata->i2c_repeater, 0xf9);
206354450f59SHans Verkuil 	state->i2c_edid = adv7604_dummy_client(sd, pdata->i2c_edid, 0xfa);
206454450f59SHans Verkuil 	state->i2c_hdmi = adv7604_dummy_client(sd, pdata->i2c_hdmi, 0xfb);
206554450f59SHans Verkuil 	state->i2c_test = adv7604_dummy_client(sd, pdata->i2c_test, 0xfc);
206654450f59SHans Verkuil 	state->i2c_cp = adv7604_dummy_client(sd, pdata->i2c_cp, 0xfd);
206754450f59SHans Verkuil 	state->i2c_vdp = adv7604_dummy_client(sd, pdata->i2c_vdp, 0xfe);
206854450f59SHans Verkuil 	if (!state->i2c_avlink || !state->i2c_cec || !state->i2c_infoframe ||
206954450f59SHans Verkuil 	    !state->i2c_esdp || !state->i2c_dpp || !state->i2c_afe ||
207054450f59SHans Verkuil 	    !state->i2c_repeater || !state->i2c_edid || !state->i2c_hdmi ||
207154450f59SHans Verkuil 	    !state->i2c_test || !state->i2c_cp || !state->i2c_vdp) {
207254450f59SHans Verkuil 		err = -ENOMEM;
207354450f59SHans Verkuil 		v4l2_err(sd, "failed to create all i2c clients\n");
207454450f59SHans Verkuil 		goto err_i2c;
207554450f59SHans Verkuil 	}
207654450f59SHans Verkuil 
207754450f59SHans Verkuil 	/* work queues */
207854450f59SHans Verkuil 	state->work_queues = create_singlethread_workqueue(client->name);
207954450f59SHans Verkuil 	if (!state->work_queues) {
208054450f59SHans Verkuil 		v4l2_err(sd, "Could not create work queue\n");
208154450f59SHans Verkuil 		err = -ENOMEM;
208254450f59SHans Verkuil 		goto err_i2c;
208354450f59SHans Verkuil 	}
208454450f59SHans Verkuil 
208554450f59SHans Verkuil 	INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug,
208654450f59SHans Verkuil 			adv7604_delayed_work_enable_hotplug);
208754450f59SHans Verkuil 
208854450f59SHans Verkuil 	state->pad.flags = MEDIA_PAD_FL_SOURCE;
208954450f59SHans Verkuil 	err = media_entity_init(&sd->entity, 1, &state->pad, 0);
209054450f59SHans Verkuil 	if (err)
209154450f59SHans Verkuil 		goto err_work_queues;
209254450f59SHans Verkuil 
209354450f59SHans Verkuil 	err = adv7604_core_init(sd);
209454450f59SHans Verkuil 	if (err)
209554450f59SHans Verkuil 		goto err_entity;
209654450f59SHans Verkuil 	v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
209754450f59SHans Verkuil 			client->addr << 1, client->adapter->name);
209854450f59SHans Verkuil 	return 0;
209954450f59SHans Verkuil 
210054450f59SHans Verkuil err_entity:
210154450f59SHans Verkuil 	media_entity_cleanup(&sd->entity);
210254450f59SHans Verkuil err_work_queues:
210354450f59SHans Verkuil 	cancel_delayed_work(&state->delayed_work_enable_hotplug);
210454450f59SHans Verkuil 	destroy_workqueue(state->work_queues);
210554450f59SHans Verkuil err_i2c:
210654450f59SHans Verkuil 	adv7604_unregister_clients(state);
210754450f59SHans Verkuil err_hdl:
210854450f59SHans Verkuil 	v4l2_ctrl_handler_free(hdl);
210954450f59SHans Verkuil 	return err;
211054450f59SHans Verkuil }
211154450f59SHans Verkuil 
211254450f59SHans Verkuil /* ----------------------------------------------------------------------- */
211354450f59SHans Verkuil 
211454450f59SHans Verkuil static int adv7604_remove(struct i2c_client *client)
211554450f59SHans Verkuil {
211654450f59SHans Verkuil 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
211754450f59SHans Verkuil 	struct adv7604_state *state = to_state(sd);
211854450f59SHans Verkuil 
211954450f59SHans Verkuil 	cancel_delayed_work(&state->delayed_work_enable_hotplug);
212054450f59SHans Verkuil 	destroy_workqueue(state->work_queues);
212154450f59SHans Verkuil 	v4l2_device_unregister_subdev(sd);
212254450f59SHans Verkuil 	media_entity_cleanup(&sd->entity);
212354450f59SHans Verkuil 	adv7604_unregister_clients(to_state(sd));
212454450f59SHans Verkuil 	v4l2_ctrl_handler_free(sd->ctrl_handler);
212554450f59SHans Verkuil 	return 0;
212654450f59SHans Verkuil }
212754450f59SHans Verkuil 
212854450f59SHans Verkuil /* ----------------------------------------------------------------------- */
212954450f59SHans Verkuil 
213054450f59SHans Verkuil static struct i2c_device_id adv7604_id[] = {
213154450f59SHans Verkuil 	{ "adv7604", 0 },
213254450f59SHans Verkuil 	{ }
213354450f59SHans Verkuil };
213454450f59SHans Verkuil MODULE_DEVICE_TABLE(i2c, adv7604_id);
213554450f59SHans Verkuil 
213654450f59SHans Verkuil static struct i2c_driver adv7604_driver = {
213754450f59SHans Verkuil 	.driver = {
213854450f59SHans Verkuil 		.owner = THIS_MODULE,
213954450f59SHans Verkuil 		.name = "adv7604",
214054450f59SHans Verkuil 	},
214154450f59SHans Verkuil 	.probe = adv7604_probe,
214254450f59SHans Verkuil 	.remove = adv7604_remove,
214354450f59SHans Verkuil 	.id_table = adv7604_id,
214454450f59SHans Verkuil };
214554450f59SHans Verkuil 
214654450f59SHans Verkuil module_i2c_driver(adv7604_driver);
2147