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