155e5927eSHans Verkuil // SPDX-License-Identifier: GPL-2.0-only 2a89bcd4cSHans Verkuil /* 3a89bcd4cSHans Verkuil * adv7842 - Analog Devices ADV7842 video decoder driver 4a89bcd4cSHans Verkuil * 5a89bcd4cSHans Verkuil * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved. 6a89bcd4cSHans Verkuil */ 7a89bcd4cSHans Verkuil 8a89bcd4cSHans Verkuil /* 9a89bcd4cSHans Verkuil * References (c = chapter, p = page): 105b64b205SMats Randgaard * REF_01 - Analog devices, ADV7842, 115b64b205SMats Randgaard * Register Settings Recommendations, Rev. 1.9, April 2011 127de6fab1SMats Randgaard * REF_02 - Analog devices, Software User Guide, UG-206, 137de6fab1SMats Randgaard * ADV7842 I2C Register Maps, Rev. 0, November 2010 145b64b205SMats Randgaard * REF_03 - Analog devices, Hardware User Guide, UG-214, 155b64b205SMats Randgaard * ADV7842 Fast Switching 2:1 HDMI 1.4 Receiver with 3D-Comb 165b64b205SMats Randgaard * Decoder and Digitizer , Rev. 0, January 2011 17a89bcd4cSHans Verkuil */ 18a89bcd4cSHans Verkuil 19a89bcd4cSHans Verkuil 20a89bcd4cSHans Verkuil #include <linux/kernel.h> 21a89bcd4cSHans Verkuil #include <linux/module.h> 22a89bcd4cSHans Verkuil #include <linux/slab.h> 23a89bcd4cSHans Verkuil #include <linux/i2c.h> 24a89bcd4cSHans Verkuil #include <linux/delay.h> 25a89bcd4cSHans Verkuil #include <linux/videodev2.h> 26a89bcd4cSHans Verkuil #include <linux/workqueue.h> 27a89bcd4cSHans Verkuil #include <linux/v4l2-dv-timings.h> 2809f90c53SMartin Bugge #include <linux/hdmi.h> 2925c84fb1SHans Verkuil #include <media/cec.h> 30a89bcd4cSHans Verkuil #include <media/v4l2-device.h> 31aef5159fSLars-Peter Clausen #include <media/v4l2-event.h> 32a89bcd4cSHans Verkuil #include <media/v4l2-ctrls.h> 33a89bcd4cSHans Verkuil #include <media/v4l2-dv-timings.h> 34b5dcee22SMauro Carvalho Chehab #include <media/i2c/adv7842.h> 35a89bcd4cSHans Verkuil 36a89bcd4cSHans Verkuil static int debug; 37a89bcd4cSHans Verkuil module_param(debug, int, 0644); 38a89bcd4cSHans Verkuil MODULE_PARM_DESC(debug, "debug level (0-2)"); 39a89bcd4cSHans Verkuil 40a89bcd4cSHans Verkuil MODULE_DESCRIPTION("Analog Devices ADV7842 video decoder driver"); 41a89bcd4cSHans Verkuil MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>"); 42a89bcd4cSHans Verkuil MODULE_AUTHOR("Martin Bugge <marbugge@cisco.com>"); 43a89bcd4cSHans Verkuil MODULE_LICENSE("GPL"); 44a89bcd4cSHans Verkuil 45a89bcd4cSHans Verkuil /* ADV7842 system clock frequency */ 46a89bcd4cSHans Verkuil #define ADV7842_fsc (28636360) 47a89bcd4cSHans Verkuil 48f888ae7eSHans Verkuil #define ADV7842_RGB_OUT (1 << 1) 49f888ae7eSHans Verkuil 50f888ae7eSHans Verkuil #define ADV7842_OP_FORMAT_SEL_8BIT (0 << 0) 51f888ae7eSHans Verkuil #define ADV7842_OP_FORMAT_SEL_10BIT (1 << 0) 52f888ae7eSHans Verkuil #define ADV7842_OP_FORMAT_SEL_12BIT (2 << 0) 53f888ae7eSHans Verkuil 54f888ae7eSHans Verkuil #define ADV7842_OP_MODE_SEL_SDR_422 (0 << 5) 55f888ae7eSHans Verkuil #define ADV7842_OP_MODE_SEL_DDR_422 (1 << 5) 56f888ae7eSHans Verkuil #define ADV7842_OP_MODE_SEL_SDR_444 (2 << 5) 57f888ae7eSHans Verkuil #define ADV7842_OP_MODE_SEL_DDR_444 (3 << 5) 58f888ae7eSHans Verkuil #define ADV7842_OP_MODE_SEL_SDR_422_2X (4 << 5) 59f888ae7eSHans Verkuil #define ADV7842_OP_MODE_SEL_ADI_CM (5 << 5) 60f888ae7eSHans Verkuil 61f888ae7eSHans Verkuil #define ADV7842_OP_CH_SEL_GBR (0 << 5) 62f888ae7eSHans Verkuil #define ADV7842_OP_CH_SEL_GRB (1 << 5) 63f888ae7eSHans Verkuil #define ADV7842_OP_CH_SEL_BGR (2 << 5) 64f888ae7eSHans Verkuil #define ADV7842_OP_CH_SEL_RGB (3 << 5) 65f888ae7eSHans Verkuil #define ADV7842_OP_CH_SEL_BRG (4 << 5) 66f888ae7eSHans Verkuil #define ADV7842_OP_CH_SEL_RBG (5 << 5) 67f888ae7eSHans Verkuil 68f888ae7eSHans Verkuil #define ADV7842_OP_SWAP_CB_CR (1 << 0) 69f888ae7eSHans Verkuil 7025c84fb1SHans Verkuil #define ADV7842_MAX_ADDRS (3) 7125c84fb1SHans Verkuil 72a89bcd4cSHans Verkuil /* 73a89bcd4cSHans Verkuil ********************************************************************** 74a89bcd4cSHans Verkuil * 75a89bcd4cSHans Verkuil * Arrays with configuration parameters for the ADV7842 76a89bcd4cSHans Verkuil * 77a89bcd4cSHans Verkuil ********************************************************************** 78a89bcd4cSHans Verkuil */ 79a89bcd4cSHans Verkuil 80f888ae7eSHans Verkuil struct adv7842_format_info { 81f888ae7eSHans Verkuil u32 code; 82f888ae7eSHans Verkuil u8 op_ch_sel; 83f888ae7eSHans Verkuil bool rgb_out; 84f888ae7eSHans Verkuil bool swap_cb_cr; 85f888ae7eSHans Verkuil u8 op_format_sel; 86f888ae7eSHans Verkuil }; 87f888ae7eSHans Verkuil 88a89bcd4cSHans Verkuil struct adv7842_state { 897de5be44SMartin Bugge struct adv7842_platform_data pdata; 90a89bcd4cSHans Verkuil struct v4l2_subdev sd; 91a89bcd4cSHans Verkuil struct media_pad pad; 92a89bcd4cSHans Verkuil struct v4l2_ctrl_handler hdl; 93a89bcd4cSHans Verkuil enum adv7842_mode mode; 94a89bcd4cSHans Verkuil struct v4l2_dv_timings timings; 95a89bcd4cSHans Verkuil enum adv7842_vid_std_select vid_std_select; 96f888ae7eSHans Verkuil 97f888ae7eSHans Verkuil const struct adv7842_format_info *format; 98f888ae7eSHans Verkuil 99a89bcd4cSHans Verkuil v4l2_std_id norm; 100a89bcd4cSHans Verkuil struct { 101a89bcd4cSHans Verkuil u8 edid[256]; 102a89bcd4cSHans Verkuil u32 present; 103a89bcd4cSHans Verkuil } hdmi_edid; 104a89bcd4cSHans Verkuil struct { 105a89bcd4cSHans Verkuil u8 edid[256]; 106a89bcd4cSHans Verkuil u32 present; 107a89bcd4cSHans Verkuil } vga_edid; 108a89bcd4cSHans Verkuil struct v4l2_fract aspect_ratio; 109a89bcd4cSHans Verkuil u32 rgb_quantization_range; 110a89bcd4cSHans Verkuil bool is_cea_format; 111a89bcd4cSHans Verkuil struct delayed_work delayed_work_enable_hotplug; 1126e9071f2SMartin Bugge bool restart_stdi_once; 113a89bcd4cSHans Verkuil bool hdmi_port_a; 114a89bcd4cSHans Verkuil 115a89bcd4cSHans Verkuil /* i2c clients */ 116a89bcd4cSHans Verkuil struct i2c_client *i2c_sdp_io; 117a89bcd4cSHans Verkuil struct i2c_client *i2c_sdp; 118a89bcd4cSHans Verkuil struct i2c_client *i2c_cp; 119a89bcd4cSHans Verkuil struct i2c_client *i2c_vdp; 120a89bcd4cSHans Verkuil struct i2c_client *i2c_afe; 121a89bcd4cSHans Verkuil struct i2c_client *i2c_hdmi; 122a89bcd4cSHans Verkuil struct i2c_client *i2c_repeater; 123a89bcd4cSHans Verkuil struct i2c_client *i2c_edid; 124a89bcd4cSHans Verkuil struct i2c_client *i2c_infoframe; 125a89bcd4cSHans Verkuil struct i2c_client *i2c_cec; 126a89bcd4cSHans Verkuil struct i2c_client *i2c_avlink; 127a89bcd4cSHans Verkuil 128a89bcd4cSHans Verkuil /* controls */ 129a89bcd4cSHans Verkuil struct v4l2_ctrl *detect_tx_5v_ctrl; 130a89bcd4cSHans Verkuil struct v4l2_ctrl *analog_sampling_phase_ctrl; 131a89bcd4cSHans Verkuil struct v4l2_ctrl *free_run_color_ctrl_manual; 132a89bcd4cSHans Verkuil struct v4l2_ctrl *free_run_color_ctrl; 133a89bcd4cSHans Verkuil struct v4l2_ctrl *rgb_quantization_range_ctrl; 13425c84fb1SHans Verkuil 13525c84fb1SHans Verkuil struct cec_adapter *cec_adap; 13625c84fb1SHans Verkuil u8 cec_addr[ADV7842_MAX_ADDRS]; 13725c84fb1SHans Verkuil u8 cec_valid_addrs; 13825c84fb1SHans Verkuil bool cec_enabled_adap; 139a89bcd4cSHans Verkuil }; 140a89bcd4cSHans Verkuil 141a89bcd4cSHans Verkuil /* Unsupported timings. This device cannot support 720p30. */ 142a89bcd4cSHans Verkuil static const struct v4l2_dv_timings adv7842_timings_exceptions[] = { 143a89bcd4cSHans Verkuil V4L2_DV_BT_CEA_1280X720P30, 144a89bcd4cSHans Verkuil { } 145a89bcd4cSHans Verkuil }; 146a89bcd4cSHans Verkuil 147a89bcd4cSHans Verkuil static bool adv7842_check_dv_timings(const struct v4l2_dv_timings *t, void *hdl) 148a89bcd4cSHans Verkuil { 149a89bcd4cSHans Verkuil int i; 150a89bcd4cSHans Verkuil 151a89bcd4cSHans Verkuil for (i = 0; adv7842_timings_exceptions[i].bt.width; i++) 15285f9e06cSHans Verkuil if (v4l2_match_dv_timings(t, adv7842_timings_exceptions + i, 0, false)) 153a89bcd4cSHans Verkuil return false; 154a89bcd4cSHans Verkuil return true; 155a89bcd4cSHans Verkuil } 156a89bcd4cSHans Verkuil 157a89bcd4cSHans Verkuil struct adv7842_video_standards { 158a89bcd4cSHans Verkuil struct v4l2_dv_timings timings; 159a89bcd4cSHans Verkuil u8 vid_std; 160a89bcd4cSHans Verkuil u8 v_freq; 161a89bcd4cSHans Verkuil }; 162a89bcd4cSHans Verkuil 163a89bcd4cSHans Verkuil /* sorted by number of lines */ 164a89bcd4cSHans Verkuil static const struct adv7842_video_standards adv7842_prim_mode_comp[] = { 165a89bcd4cSHans Verkuil /* { V4L2_DV_BT_CEA_720X480P59_94, 0x0a, 0x00 }, TODO flickering */ 166a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_720X576P50, 0x0b, 0x00 }, 167a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1280X720P50, 0x19, 0x01 }, 168a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1280X720P60, 0x19, 0x00 }, 169a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1920X1080P24, 0x1e, 0x04 }, 170a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1920X1080P25, 0x1e, 0x03 }, 171a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1920X1080P30, 0x1e, 0x02 }, 172a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1920X1080P50, 0x1e, 0x01 }, 173a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1920X1080P60, 0x1e, 0x00 }, 174a89bcd4cSHans Verkuil /* TODO add 1920x1080P60_RB (CVT timing) */ 175a89bcd4cSHans Verkuil { }, 176a89bcd4cSHans Verkuil }; 177a89bcd4cSHans Verkuil 178a89bcd4cSHans Verkuil /* sorted by number of lines */ 179a89bcd4cSHans Verkuil static const struct adv7842_video_standards adv7842_prim_mode_gr[] = { 180a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_640X480P60, 0x08, 0x00 }, 181a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_640X480P72, 0x09, 0x00 }, 182a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_640X480P75, 0x0a, 0x00 }, 183a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_640X480P85, 0x0b, 0x00 }, 184a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_800X600P56, 0x00, 0x00 }, 185a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_800X600P60, 0x01, 0x00 }, 186a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_800X600P72, 0x02, 0x00 }, 187a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_800X600P75, 0x03, 0x00 }, 188a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_800X600P85, 0x04, 0x00 }, 189a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1024X768P60, 0x0c, 0x00 }, 190a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1024X768P70, 0x0d, 0x00 }, 191a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1024X768P75, 0x0e, 0x00 }, 192a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1024X768P85, 0x0f, 0x00 }, 193a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1280X1024P60, 0x05, 0x00 }, 194a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1280X1024P75, 0x06, 0x00 }, 195a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1360X768P60, 0x12, 0x00 }, 196a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1366X768P60, 0x13, 0x00 }, 197a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1400X1050P60, 0x14, 0x00 }, 198a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1400X1050P75, 0x15, 0x00 }, 199a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1600X1200P60, 0x16, 0x00 }, /* TODO not tested */ 200a89bcd4cSHans Verkuil /* TODO add 1600X1200P60_RB (not a DMT timing) */ 201a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1680X1050P60, 0x18, 0x00 }, 202a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1920X1200P60_RB, 0x19, 0x00 }, /* TODO not tested */ 203a89bcd4cSHans Verkuil { }, 204a89bcd4cSHans Verkuil }; 205a89bcd4cSHans Verkuil 206a89bcd4cSHans Verkuil /* sorted by number of lines */ 207a89bcd4cSHans Verkuil static const struct adv7842_video_standards adv7842_prim_mode_hdmi_comp[] = { 208a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_720X480P59_94, 0x0a, 0x00 }, 209a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_720X576P50, 0x0b, 0x00 }, 210a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1280X720P50, 0x13, 0x01 }, 211a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1280X720P60, 0x13, 0x00 }, 212a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1920X1080P24, 0x1e, 0x04 }, 213a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1920X1080P25, 0x1e, 0x03 }, 214a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1920X1080P30, 0x1e, 0x02 }, 215a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1920X1080P50, 0x1e, 0x01 }, 216a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1920X1080P60, 0x1e, 0x00 }, 217a89bcd4cSHans Verkuil { }, 218a89bcd4cSHans Verkuil }; 219a89bcd4cSHans Verkuil 220a89bcd4cSHans Verkuil /* sorted by number of lines */ 221a89bcd4cSHans Verkuil static const struct adv7842_video_standards adv7842_prim_mode_hdmi_gr[] = { 222a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_640X480P60, 0x08, 0x00 }, 223a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_640X480P72, 0x09, 0x00 }, 224a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_640X480P75, 0x0a, 0x00 }, 225a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_640X480P85, 0x0b, 0x00 }, 226a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_800X600P56, 0x00, 0x00 }, 227a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_800X600P60, 0x01, 0x00 }, 228a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_800X600P72, 0x02, 0x00 }, 229a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_800X600P75, 0x03, 0x00 }, 230a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_800X600P85, 0x04, 0x00 }, 231a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1024X768P60, 0x0c, 0x00 }, 232a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1024X768P70, 0x0d, 0x00 }, 233a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1024X768P75, 0x0e, 0x00 }, 234a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1024X768P85, 0x0f, 0x00 }, 235a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1280X1024P60, 0x05, 0x00 }, 236a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1280X1024P75, 0x06, 0x00 }, 237a89bcd4cSHans Verkuil { }, 238a89bcd4cSHans Verkuil }; 239a89bcd4cSHans Verkuil 24048519838SHans Verkuil static const struct v4l2_event adv7842_ev_fmt = { 24148519838SHans Verkuil .type = V4L2_EVENT_SOURCE_CHANGE, 24248519838SHans Verkuil .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, 24348519838SHans Verkuil }; 24448519838SHans Verkuil 245a89bcd4cSHans Verkuil /* ----------------------------------------------------------------------- */ 246a89bcd4cSHans Verkuil 247a89bcd4cSHans Verkuil static inline struct adv7842_state *to_state(struct v4l2_subdev *sd) 248a89bcd4cSHans Verkuil { 249a89bcd4cSHans Verkuil return container_of(sd, struct adv7842_state, sd); 250a89bcd4cSHans Verkuil } 251a89bcd4cSHans Verkuil 252a89bcd4cSHans Verkuil static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) 253a89bcd4cSHans Verkuil { 254a89bcd4cSHans Verkuil return &container_of(ctrl->handler, struct adv7842_state, hdl)->sd; 255a89bcd4cSHans Verkuil } 256a89bcd4cSHans Verkuil 257f888ae7eSHans Verkuil static inline unsigned hblanking(const struct v4l2_bt_timings *t) 258f888ae7eSHans Verkuil { 259f888ae7eSHans Verkuil return V4L2_DV_BT_BLANKING_WIDTH(t); 260f888ae7eSHans Verkuil } 261f888ae7eSHans Verkuil 262a89bcd4cSHans Verkuil static inline unsigned htotal(const struct v4l2_bt_timings *t) 263a89bcd4cSHans Verkuil { 264a89bcd4cSHans Verkuil return V4L2_DV_BT_FRAME_WIDTH(t); 265a89bcd4cSHans Verkuil } 266a89bcd4cSHans Verkuil 267f888ae7eSHans Verkuil static inline unsigned vblanking(const struct v4l2_bt_timings *t) 268f888ae7eSHans Verkuil { 269f888ae7eSHans Verkuil return V4L2_DV_BT_BLANKING_HEIGHT(t); 270f888ae7eSHans Verkuil } 271f888ae7eSHans Verkuil 272a89bcd4cSHans Verkuil static inline unsigned vtotal(const struct v4l2_bt_timings *t) 273a89bcd4cSHans Verkuil { 274a89bcd4cSHans Verkuil return V4L2_DV_BT_FRAME_HEIGHT(t); 275a89bcd4cSHans Verkuil } 276a89bcd4cSHans Verkuil 277a89bcd4cSHans Verkuil 278a89bcd4cSHans Verkuil /* ----------------------------------------------------------------------- */ 279a89bcd4cSHans Verkuil 280a89bcd4cSHans Verkuil static s32 adv_smbus_read_byte_data_check(struct i2c_client *client, 281a89bcd4cSHans Verkuil u8 command, bool check) 282a89bcd4cSHans Verkuil { 283a89bcd4cSHans Verkuil union i2c_smbus_data data; 284a89bcd4cSHans Verkuil 285a89bcd4cSHans Verkuil if (!i2c_smbus_xfer(client->adapter, client->addr, client->flags, 286a89bcd4cSHans Verkuil I2C_SMBUS_READ, command, 287a89bcd4cSHans Verkuil I2C_SMBUS_BYTE_DATA, &data)) 288a89bcd4cSHans Verkuil return data.byte; 289a89bcd4cSHans Verkuil if (check) 290a89bcd4cSHans Verkuil v4l_err(client, "error reading %02x, %02x\n", 291a89bcd4cSHans Verkuil client->addr, command); 292a89bcd4cSHans Verkuil return -EIO; 293a89bcd4cSHans Verkuil } 294a89bcd4cSHans Verkuil 295a89bcd4cSHans Verkuil static s32 adv_smbus_read_byte_data(struct i2c_client *client, u8 command) 296a89bcd4cSHans Verkuil { 297a89bcd4cSHans Verkuil int i; 298a89bcd4cSHans Verkuil 299a89bcd4cSHans Verkuil for (i = 0; i < 3; i++) { 300a89bcd4cSHans Verkuil int ret = adv_smbus_read_byte_data_check(client, command, true); 301a89bcd4cSHans Verkuil 302a89bcd4cSHans Verkuil if (ret >= 0) { 303a89bcd4cSHans Verkuil if (i) 304a89bcd4cSHans Verkuil v4l_err(client, "read ok after %d retries\n", i); 305a89bcd4cSHans Verkuil return ret; 306a89bcd4cSHans Verkuil } 307a89bcd4cSHans Verkuil } 308a89bcd4cSHans Verkuil v4l_err(client, "read failed\n"); 309a89bcd4cSHans Verkuil return -EIO; 310a89bcd4cSHans Verkuil } 311a89bcd4cSHans Verkuil 312a89bcd4cSHans Verkuil static s32 adv_smbus_write_byte_data(struct i2c_client *client, 313a89bcd4cSHans Verkuil u8 command, u8 value) 314a89bcd4cSHans Verkuil { 315a89bcd4cSHans Verkuil union i2c_smbus_data data; 316a89bcd4cSHans Verkuil int err; 317a89bcd4cSHans Verkuil int i; 318a89bcd4cSHans Verkuil 319a89bcd4cSHans Verkuil data.byte = value; 320a89bcd4cSHans Verkuil for (i = 0; i < 3; i++) { 321a89bcd4cSHans Verkuil err = i2c_smbus_xfer(client->adapter, client->addr, 322a89bcd4cSHans Verkuil client->flags, 323a89bcd4cSHans Verkuil I2C_SMBUS_WRITE, command, 324a89bcd4cSHans Verkuil I2C_SMBUS_BYTE_DATA, &data); 325a89bcd4cSHans Verkuil if (!err) 326a89bcd4cSHans Verkuil break; 327a89bcd4cSHans Verkuil } 328a89bcd4cSHans Verkuil if (err < 0) 329a89bcd4cSHans Verkuil v4l_err(client, "error writing %02x, %02x, %02x\n", 330a89bcd4cSHans Verkuil client->addr, command, value); 331a89bcd4cSHans Verkuil return err; 332a89bcd4cSHans Verkuil } 333a89bcd4cSHans Verkuil 334a89bcd4cSHans Verkuil static void adv_smbus_write_byte_no_check(struct i2c_client *client, 335a89bcd4cSHans Verkuil u8 command, u8 value) 336a89bcd4cSHans Verkuil { 337a89bcd4cSHans Verkuil union i2c_smbus_data data; 338a89bcd4cSHans Verkuil data.byte = value; 339a89bcd4cSHans Verkuil 340a89bcd4cSHans Verkuil i2c_smbus_xfer(client->adapter, client->addr, 341a89bcd4cSHans Verkuil client->flags, 342a89bcd4cSHans Verkuil I2C_SMBUS_WRITE, command, 343a89bcd4cSHans Verkuil I2C_SMBUS_BYTE_DATA, &data); 344a89bcd4cSHans Verkuil } 345a89bcd4cSHans Verkuil 346a89bcd4cSHans Verkuil static s32 adv_smbus_write_i2c_block_data(struct i2c_client *client, 347a89bcd4cSHans Verkuil u8 command, unsigned length, const u8 *values) 348a89bcd4cSHans Verkuil { 349a89bcd4cSHans Verkuil union i2c_smbus_data data; 350a89bcd4cSHans Verkuil 351a89bcd4cSHans Verkuil if (length > I2C_SMBUS_BLOCK_MAX) 352a89bcd4cSHans Verkuil length = I2C_SMBUS_BLOCK_MAX; 353a89bcd4cSHans Verkuil data.block[0] = length; 354a89bcd4cSHans Verkuil memcpy(data.block + 1, values, length); 355a89bcd4cSHans Verkuil return i2c_smbus_xfer(client->adapter, client->addr, client->flags, 356a89bcd4cSHans Verkuil I2C_SMBUS_WRITE, command, 357a89bcd4cSHans Verkuil I2C_SMBUS_I2C_BLOCK_DATA, &data); 358a89bcd4cSHans Verkuil } 359a89bcd4cSHans Verkuil 360a89bcd4cSHans Verkuil /* ----------------------------------------------------------------------- */ 361a89bcd4cSHans Verkuil 362a89bcd4cSHans Verkuil static inline int io_read(struct v4l2_subdev *sd, u8 reg) 363a89bcd4cSHans Verkuil { 364a89bcd4cSHans Verkuil struct i2c_client *client = v4l2_get_subdevdata(sd); 365a89bcd4cSHans Verkuil 366a89bcd4cSHans Verkuil return adv_smbus_read_byte_data(client, reg); 367a89bcd4cSHans Verkuil } 368a89bcd4cSHans Verkuil 369a89bcd4cSHans Verkuil static inline int io_write(struct v4l2_subdev *sd, u8 reg, u8 val) 370a89bcd4cSHans Verkuil { 371a89bcd4cSHans Verkuil struct i2c_client *client = v4l2_get_subdevdata(sd); 372a89bcd4cSHans Verkuil 373a89bcd4cSHans Verkuil return adv_smbus_write_byte_data(client, reg, val); 374a89bcd4cSHans Verkuil } 375a89bcd4cSHans Verkuil 376a89bcd4cSHans Verkuil static inline int io_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) 377a89bcd4cSHans Verkuil { 378a89bcd4cSHans Verkuil return io_write(sd, reg, (io_read(sd, reg) & mask) | val); 379a89bcd4cSHans Verkuil } 380a89bcd4cSHans Verkuil 381f888ae7eSHans Verkuil static inline int io_write_clr_set(struct v4l2_subdev *sd, 382f888ae7eSHans Verkuil u8 reg, u8 mask, u8 val) 383f888ae7eSHans Verkuil { 384f888ae7eSHans Verkuil return io_write(sd, reg, (io_read(sd, reg) & ~mask) | val); 385f888ae7eSHans Verkuil } 386f888ae7eSHans Verkuil 387a89bcd4cSHans Verkuil static inline int avlink_read(struct v4l2_subdev *sd, u8 reg) 388a89bcd4cSHans Verkuil { 389a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 390a89bcd4cSHans Verkuil 391a89bcd4cSHans Verkuil return adv_smbus_read_byte_data(state->i2c_avlink, reg); 392a89bcd4cSHans Verkuil } 393a89bcd4cSHans Verkuil 394a89bcd4cSHans Verkuil static inline int avlink_write(struct v4l2_subdev *sd, u8 reg, u8 val) 395a89bcd4cSHans Verkuil { 396a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 397a89bcd4cSHans Verkuil 398a89bcd4cSHans Verkuil return adv_smbus_write_byte_data(state->i2c_avlink, reg, val); 399a89bcd4cSHans Verkuil } 400a89bcd4cSHans Verkuil 401a89bcd4cSHans Verkuil static inline int cec_read(struct v4l2_subdev *sd, u8 reg) 402a89bcd4cSHans Verkuil { 403a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 404a89bcd4cSHans Verkuil 405a89bcd4cSHans Verkuil return adv_smbus_read_byte_data(state->i2c_cec, reg); 406a89bcd4cSHans Verkuil } 407a89bcd4cSHans Verkuil 408a89bcd4cSHans Verkuil static inline int cec_write(struct v4l2_subdev *sd, u8 reg, u8 val) 409a89bcd4cSHans Verkuil { 410a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 411a89bcd4cSHans Verkuil 412a89bcd4cSHans Verkuil return adv_smbus_write_byte_data(state->i2c_cec, reg, val); 413a89bcd4cSHans Verkuil } 414a89bcd4cSHans Verkuil 41525c84fb1SHans Verkuil static inline int cec_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) 416a89bcd4cSHans Verkuil { 41725c84fb1SHans Verkuil return cec_write(sd, reg, (cec_read(sd, reg) & ~mask) | val); 418a89bcd4cSHans Verkuil } 419a89bcd4cSHans Verkuil 420a89bcd4cSHans Verkuil static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg) 421a89bcd4cSHans Verkuil { 422a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 423a89bcd4cSHans Verkuil 424a89bcd4cSHans Verkuil return adv_smbus_read_byte_data(state->i2c_infoframe, reg); 425a89bcd4cSHans Verkuil } 426a89bcd4cSHans Verkuil 427a89bcd4cSHans Verkuil static inline int infoframe_write(struct v4l2_subdev *sd, u8 reg, u8 val) 428a89bcd4cSHans Verkuil { 429a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 430a89bcd4cSHans Verkuil 431a89bcd4cSHans Verkuil return adv_smbus_write_byte_data(state->i2c_infoframe, reg, val); 432a89bcd4cSHans Verkuil } 433a89bcd4cSHans Verkuil 434a89bcd4cSHans Verkuil static inline int sdp_io_read(struct v4l2_subdev *sd, u8 reg) 435a89bcd4cSHans Verkuil { 436a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 437a89bcd4cSHans Verkuil 438a89bcd4cSHans Verkuil return adv_smbus_read_byte_data(state->i2c_sdp_io, reg); 439a89bcd4cSHans Verkuil } 440a89bcd4cSHans Verkuil 441a89bcd4cSHans Verkuil static inline int sdp_io_write(struct v4l2_subdev *sd, u8 reg, u8 val) 442a89bcd4cSHans Verkuil { 443a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 444a89bcd4cSHans Verkuil 445a89bcd4cSHans Verkuil return adv_smbus_write_byte_data(state->i2c_sdp_io, reg, val); 446a89bcd4cSHans Verkuil } 447a89bcd4cSHans Verkuil 448a89bcd4cSHans Verkuil static inline int sdp_io_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) 449a89bcd4cSHans Verkuil { 450a89bcd4cSHans Verkuil return sdp_io_write(sd, reg, (sdp_io_read(sd, reg) & mask) | val); 451a89bcd4cSHans Verkuil } 452a89bcd4cSHans Verkuil 453a89bcd4cSHans Verkuil static inline int sdp_read(struct v4l2_subdev *sd, u8 reg) 454a89bcd4cSHans Verkuil { 455a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 456a89bcd4cSHans Verkuil 457a89bcd4cSHans Verkuil return adv_smbus_read_byte_data(state->i2c_sdp, reg); 458a89bcd4cSHans Verkuil } 459a89bcd4cSHans Verkuil 460a89bcd4cSHans Verkuil static inline int sdp_write(struct v4l2_subdev *sd, u8 reg, u8 val) 461a89bcd4cSHans Verkuil { 462a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 463a89bcd4cSHans Verkuil 464a89bcd4cSHans Verkuil return adv_smbus_write_byte_data(state->i2c_sdp, reg, val); 465a89bcd4cSHans Verkuil } 466a89bcd4cSHans Verkuil 467a89bcd4cSHans Verkuil static inline int sdp_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) 468a89bcd4cSHans Verkuil { 469a89bcd4cSHans Verkuil return sdp_write(sd, reg, (sdp_read(sd, reg) & mask) | val); 470a89bcd4cSHans Verkuil } 471a89bcd4cSHans Verkuil 472a89bcd4cSHans Verkuil static inline int afe_read(struct v4l2_subdev *sd, u8 reg) 473a89bcd4cSHans Verkuil { 474a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 475a89bcd4cSHans Verkuil 476a89bcd4cSHans Verkuil return adv_smbus_read_byte_data(state->i2c_afe, reg); 477a89bcd4cSHans Verkuil } 478a89bcd4cSHans Verkuil 479a89bcd4cSHans Verkuil static inline int afe_write(struct v4l2_subdev *sd, u8 reg, u8 val) 480a89bcd4cSHans Verkuil { 481a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 482a89bcd4cSHans Verkuil 483a89bcd4cSHans Verkuil return adv_smbus_write_byte_data(state->i2c_afe, reg, val); 484a89bcd4cSHans Verkuil } 485a89bcd4cSHans Verkuil 486a89bcd4cSHans Verkuil static inline int afe_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) 487a89bcd4cSHans Verkuil { 488a89bcd4cSHans Verkuil return afe_write(sd, reg, (afe_read(sd, reg) & mask) | val); 489a89bcd4cSHans Verkuil } 490a89bcd4cSHans Verkuil 491a89bcd4cSHans Verkuil static inline int rep_read(struct v4l2_subdev *sd, u8 reg) 492a89bcd4cSHans Verkuil { 493a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 494a89bcd4cSHans Verkuil 495a89bcd4cSHans Verkuil return adv_smbus_read_byte_data(state->i2c_repeater, reg); 496a89bcd4cSHans Verkuil } 497a89bcd4cSHans Verkuil 498a89bcd4cSHans Verkuil static inline int rep_write(struct v4l2_subdev *sd, u8 reg, u8 val) 499a89bcd4cSHans Verkuil { 500a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 501a89bcd4cSHans Verkuil 502a89bcd4cSHans Verkuil return adv_smbus_write_byte_data(state->i2c_repeater, reg, val); 503a89bcd4cSHans Verkuil } 504a89bcd4cSHans Verkuil 505a89bcd4cSHans Verkuil static inline int rep_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) 506a89bcd4cSHans Verkuil { 507a89bcd4cSHans Verkuil return rep_write(sd, reg, (rep_read(sd, reg) & mask) | val); 508a89bcd4cSHans Verkuil } 509a89bcd4cSHans Verkuil 510a89bcd4cSHans Verkuil static inline int edid_read(struct v4l2_subdev *sd, u8 reg) 511a89bcd4cSHans Verkuil { 512a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 513a89bcd4cSHans Verkuil 514a89bcd4cSHans Verkuil return adv_smbus_read_byte_data(state->i2c_edid, reg); 515a89bcd4cSHans Verkuil } 516a89bcd4cSHans Verkuil 517a89bcd4cSHans Verkuil static inline int edid_write(struct v4l2_subdev *sd, u8 reg, u8 val) 518a89bcd4cSHans Verkuil { 519a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 520a89bcd4cSHans Verkuil 521a89bcd4cSHans Verkuil return adv_smbus_write_byte_data(state->i2c_edid, reg, val); 522a89bcd4cSHans Verkuil } 523a89bcd4cSHans Verkuil 524a89bcd4cSHans Verkuil static inline int hdmi_read(struct v4l2_subdev *sd, u8 reg) 525a89bcd4cSHans Verkuil { 526a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 527a89bcd4cSHans Verkuil 528a89bcd4cSHans Verkuil return adv_smbus_read_byte_data(state->i2c_hdmi, reg); 529a89bcd4cSHans Verkuil } 530a89bcd4cSHans Verkuil 531a89bcd4cSHans Verkuil static inline int hdmi_write(struct v4l2_subdev *sd, u8 reg, u8 val) 532a89bcd4cSHans Verkuil { 533a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 534a89bcd4cSHans Verkuil 535a89bcd4cSHans Verkuil return adv_smbus_write_byte_data(state->i2c_hdmi, reg, val); 536a89bcd4cSHans Verkuil } 537a89bcd4cSHans Verkuil 5385b64b205SMats Randgaard static inline int hdmi_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) 5395b64b205SMats Randgaard { 5405b64b205SMats Randgaard return hdmi_write(sd, reg, (hdmi_read(sd, reg) & mask) | val); 5415b64b205SMats Randgaard } 5425b64b205SMats Randgaard 543a89bcd4cSHans Verkuil static inline int cp_read(struct v4l2_subdev *sd, u8 reg) 544a89bcd4cSHans Verkuil { 545a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 546a89bcd4cSHans Verkuil 547a89bcd4cSHans Verkuil return adv_smbus_read_byte_data(state->i2c_cp, reg); 548a89bcd4cSHans Verkuil } 549a89bcd4cSHans Verkuil 550a89bcd4cSHans Verkuil static inline int cp_write(struct v4l2_subdev *sd, u8 reg, u8 val) 551a89bcd4cSHans Verkuil { 552a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 553a89bcd4cSHans Verkuil 554a89bcd4cSHans Verkuil return adv_smbus_write_byte_data(state->i2c_cp, reg, val); 555a89bcd4cSHans Verkuil } 556a89bcd4cSHans Verkuil 557a89bcd4cSHans Verkuil static inline int cp_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) 558a89bcd4cSHans Verkuil { 559a89bcd4cSHans Verkuil return cp_write(sd, reg, (cp_read(sd, reg) & mask) | val); 560a89bcd4cSHans Verkuil } 561a89bcd4cSHans Verkuil 562a89bcd4cSHans Verkuil static inline int vdp_read(struct v4l2_subdev *sd, u8 reg) 563a89bcd4cSHans Verkuil { 564a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 565a89bcd4cSHans Verkuil 566a89bcd4cSHans Verkuil return adv_smbus_read_byte_data(state->i2c_vdp, reg); 567a89bcd4cSHans Verkuil } 568a89bcd4cSHans Verkuil 569a89bcd4cSHans Verkuil static inline int vdp_write(struct v4l2_subdev *sd, u8 reg, u8 val) 570a89bcd4cSHans Verkuil { 571a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 572a89bcd4cSHans Verkuil 573a89bcd4cSHans Verkuil return adv_smbus_write_byte_data(state->i2c_vdp, reg, val); 574a89bcd4cSHans Verkuil } 575a89bcd4cSHans Verkuil 576a89bcd4cSHans Verkuil static void main_reset(struct v4l2_subdev *sd) 577a89bcd4cSHans Verkuil { 578a89bcd4cSHans Verkuil struct i2c_client *client = v4l2_get_subdevdata(sd); 579a89bcd4cSHans Verkuil 580a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, "%s:\n", __func__); 581a89bcd4cSHans Verkuil 582a89bcd4cSHans Verkuil adv_smbus_write_byte_no_check(client, 0xff, 0x80); 583a89bcd4cSHans Verkuil 58484aeed53SMartin Bugge mdelay(5); 585a89bcd4cSHans Verkuil } 586a89bcd4cSHans Verkuil 587f888ae7eSHans Verkuil /* ----------------------------------------------------------------------------- 588f888ae7eSHans Verkuil * Format helpers 589f888ae7eSHans Verkuil */ 590f888ae7eSHans Verkuil 591f888ae7eSHans Verkuil static const struct adv7842_format_info adv7842_formats[] = { 592f888ae7eSHans Verkuil { MEDIA_BUS_FMT_RGB888_1X24, ADV7842_OP_CH_SEL_RGB, true, false, 593f888ae7eSHans Verkuil ADV7842_OP_MODE_SEL_SDR_444 | ADV7842_OP_FORMAT_SEL_8BIT }, 594f888ae7eSHans Verkuil { MEDIA_BUS_FMT_YUYV8_2X8, ADV7842_OP_CH_SEL_RGB, false, false, 595f888ae7eSHans Verkuil ADV7842_OP_MODE_SEL_SDR_422 | ADV7842_OP_FORMAT_SEL_8BIT }, 596f888ae7eSHans Verkuil { MEDIA_BUS_FMT_YVYU8_2X8, ADV7842_OP_CH_SEL_RGB, false, true, 597f888ae7eSHans Verkuil ADV7842_OP_MODE_SEL_SDR_422 | ADV7842_OP_FORMAT_SEL_8BIT }, 598f888ae7eSHans Verkuil { MEDIA_BUS_FMT_YUYV10_2X10, ADV7842_OP_CH_SEL_RGB, false, false, 599f888ae7eSHans Verkuil ADV7842_OP_MODE_SEL_SDR_422 | ADV7842_OP_FORMAT_SEL_10BIT }, 600f888ae7eSHans Verkuil { MEDIA_BUS_FMT_YVYU10_2X10, ADV7842_OP_CH_SEL_RGB, false, true, 601f888ae7eSHans Verkuil ADV7842_OP_MODE_SEL_SDR_422 | ADV7842_OP_FORMAT_SEL_10BIT }, 602f888ae7eSHans Verkuil { MEDIA_BUS_FMT_YUYV12_2X12, ADV7842_OP_CH_SEL_RGB, false, false, 603f888ae7eSHans Verkuil ADV7842_OP_MODE_SEL_SDR_422 | ADV7842_OP_FORMAT_SEL_12BIT }, 604f888ae7eSHans Verkuil { MEDIA_BUS_FMT_YVYU12_2X12, ADV7842_OP_CH_SEL_RGB, false, true, 605f888ae7eSHans Verkuil ADV7842_OP_MODE_SEL_SDR_422 | ADV7842_OP_FORMAT_SEL_12BIT }, 606f888ae7eSHans Verkuil { MEDIA_BUS_FMT_UYVY8_1X16, ADV7842_OP_CH_SEL_RBG, false, false, 607f888ae7eSHans Verkuil ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_8BIT }, 608f888ae7eSHans Verkuil { MEDIA_BUS_FMT_VYUY8_1X16, ADV7842_OP_CH_SEL_RBG, false, true, 609f888ae7eSHans Verkuil ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_8BIT }, 610f888ae7eSHans Verkuil { MEDIA_BUS_FMT_YUYV8_1X16, ADV7842_OP_CH_SEL_RGB, false, false, 611f888ae7eSHans Verkuil ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_8BIT }, 612f888ae7eSHans Verkuil { MEDIA_BUS_FMT_YVYU8_1X16, ADV7842_OP_CH_SEL_RGB, false, true, 613f888ae7eSHans Verkuil ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_8BIT }, 614f888ae7eSHans Verkuil { MEDIA_BUS_FMT_UYVY10_1X20, ADV7842_OP_CH_SEL_RBG, false, false, 615f888ae7eSHans Verkuil ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_10BIT }, 616f888ae7eSHans Verkuil { MEDIA_BUS_FMT_VYUY10_1X20, ADV7842_OP_CH_SEL_RBG, false, true, 617f888ae7eSHans Verkuil ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_10BIT }, 618f888ae7eSHans Verkuil { MEDIA_BUS_FMT_YUYV10_1X20, ADV7842_OP_CH_SEL_RGB, false, false, 619f888ae7eSHans Verkuil ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_10BIT }, 620f888ae7eSHans Verkuil { MEDIA_BUS_FMT_YVYU10_1X20, ADV7842_OP_CH_SEL_RGB, false, true, 621f888ae7eSHans Verkuil ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_10BIT }, 622f888ae7eSHans Verkuil { MEDIA_BUS_FMT_UYVY12_1X24, ADV7842_OP_CH_SEL_RBG, false, false, 623f888ae7eSHans Verkuil ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_12BIT }, 624f888ae7eSHans Verkuil { MEDIA_BUS_FMT_VYUY12_1X24, ADV7842_OP_CH_SEL_RBG, false, true, 625f888ae7eSHans Verkuil ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_12BIT }, 626f888ae7eSHans Verkuil { MEDIA_BUS_FMT_YUYV12_1X24, ADV7842_OP_CH_SEL_RGB, false, false, 627f888ae7eSHans Verkuil ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_12BIT }, 628f888ae7eSHans Verkuil { MEDIA_BUS_FMT_YVYU12_1X24, ADV7842_OP_CH_SEL_RGB, false, true, 629f888ae7eSHans Verkuil ADV7842_OP_MODE_SEL_SDR_422_2X | ADV7842_OP_FORMAT_SEL_12BIT }, 630f888ae7eSHans Verkuil }; 631f888ae7eSHans Verkuil 632f888ae7eSHans Verkuil static const struct adv7842_format_info * 633f888ae7eSHans Verkuil adv7842_format_info(struct adv7842_state *state, u32 code) 634f888ae7eSHans Verkuil { 635f888ae7eSHans Verkuil unsigned int i; 636f888ae7eSHans Verkuil 637f888ae7eSHans Verkuil for (i = 0; i < ARRAY_SIZE(adv7842_formats); ++i) { 638f888ae7eSHans Verkuil if (adv7842_formats[i].code == code) 639f888ae7eSHans Verkuil return &adv7842_formats[i]; 640f888ae7eSHans Verkuil } 641f888ae7eSHans Verkuil 642f888ae7eSHans Verkuil return NULL; 643f888ae7eSHans Verkuil } 644f888ae7eSHans Verkuil 645a89bcd4cSHans Verkuil /* ----------------------------------------------------------------------- */ 646a89bcd4cSHans Verkuil 647933913daSMartin Bugge static inline bool is_analog_input(struct v4l2_subdev *sd) 648933913daSMartin Bugge { 649933913daSMartin Bugge struct adv7842_state *state = to_state(sd); 650933913daSMartin Bugge 651933913daSMartin Bugge return ((state->mode == ADV7842_MODE_RGB) || 652933913daSMartin Bugge (state->mode == ADV7842_MODE_COMP)); 653933913daSMartin Bugge } 654933913daSMartin Bugge 655a89bcd4cSHans Verkuil static inline bool is_digital_input(struct v4l2_subdev *sd) 656a89bcd4cSHans Verkuil { 657a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 658a89bcd4cSHans Verkuil 659a89bcd4cSHans Verkuil return state->mode == ADV7842_MODE_HDMI; 660a89bcd4cSHans Verkuil } 661a89bcd4cSHans Verkuil 662a89bcd4cSHans Verkuil static const struct v4l2_dv_timings_cap adv7842_timings_cap_analog = { 663a89bcd4cSHans Verkuil .type = V4L2_DV_BT_656_1120, 6649b51f175SGianluca Gennari /* keep this initialization for compatibility with GCC < 4.4.6 */ 6659b51f175SGianluca Gennari .reserved = { 0 }, 6662912289aSHans Verkuil V4L2_INIT_BT_TIMINGS(640, 1920, 350, 1200, 25000000, 170000000, 6679b51f175SGianluca Gennari V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | 668a89bcd4cSHans Verkuil V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT, 6699b51f175SGianluca Gennari V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING | 6709b51f175SGianluca Gennari V4L2_DV_BT_CAP_CUSTOM) 671a89bcd4cSHans Verkuil }; 672a89bcd4cSHans Verkuil 673a89bcd4cSHans Verkuil static const struct v4l2_dv_timings_cap adv7842_timings_cap_digital = { 674a89bcd4cSHans Verkuil .type = V4L2_DV_BT_656_1120, 6759b51f175SGianluca Gennari /* keep this initialization for compatibility with GCC < 4.4.6 */ 6769b51f175SGianluca Gennari .reserved = { 0 }, 6772912289aSHans Verkuil V4L2_INIT_BT_TIMINGS(640, 1920, 350, 1200, 25000000, 225000000, 6789b51f175SGianluca Gennari V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | 679a89bcd4cSHans Verkuil V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT, 6809b51f175SGianluca Gennari V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING | 6819b51f175SGianluca Gennari V4L2_DV_BT_CAP_CUSTOM) 682a89bcd4cSHans Verkuil }; 683a89bcd4cSHans Verkuil 684a89bcd4cSHans Verkuil static inline const struct v4l2_dv_timings_cap * 685a89bcd4cSHans Verkuil adv7842_get_dv_timings_cap(struct v4l2_subdev *sd) 686a89bcd4cSHans Verkuil { 687a89bcd4cSHans Verkuil return is_digital_input(sd) ? &adv7842_timings_cap_digital : 688a89bcd4cSHans Verkuil &adv7842_timings_cap_analog; 689a89bcd4cSHans Verkuil } 690a89bcd4cSHans Verkuil 691a89bcd4cSHans Verkuil /* ----------------------------------------------------------------------- */ 692a89bcd4cSHans Verkuil 69325c84fb1SHans Verkuil static u16 adv7842_read_cable_det(struct v4l2_subdev *sd) 69425c84fb1SHans Verkuil { 69525c84fb1SHans Verkuil u8 reg = io_read(sd, 0x6f); 69625c84fb1SHans Verkuil u16 val = 0; 69725c84fb1SHans Verkuil 69825c84fb1SHans Verkuil if (reg & 0x02) 69925c84fb1SHans Verkuil val |= 1; /* port A */ 70025c84fb1SHans Verkuil if (reg & 0x01) 70125c84fb1SHans Verkuil val |= 2; /* port B */ 70225c84fb1SHans Verkuil return val; 70325c84fb1SHans Verkuil } 70425c84fb1SHans Verkuil 705a89bcd4cSHans Verkuil static void adv7842_delayed_work_enable_hotplug(struct work_struct *work) 706a89bcd4cSHans Verkuil { 707a89bcd4cSHans Verkuil struct delayed_work *dwork = to_delayed_work(work); 708a89bcd4cSHans Verkuil struct adv7842_state *state = container_of(dwork, 709a89bcd4cSHans Verkuil struct adv7842_state, delayed_work_enable_hotplug); 710a89bcd4cSHans Verkuil struct v4l2_subdev *sd = &state->sd; 711a89bcd4cSHans Verkuil int present = state->hdmi_edid.present; 712a89bcd4cSHans Verkuil u8 mask = 0; 713a89bcd4cSHans Verkuil 714a89bcd4cSHans Verkuil v4l2_dbg(2, debug, sd, "%s: enable hotplug on ports: 0x%x\n", 715a89bcd4cSHans Verkuil __func__, present); 716a89bcd4cSHans Verkuil 7177de6fab1SMats Randgaard if (present & (0x04 << ADV7842_EDID_PORT_A)) 7187de6fab1SMats Randgaard mask |= 0x20; 7197de6fab1SMats Randgaard if (present & (0x04 << ADV7842_EDID_PORT_B)) 7207de6fab1SMats Randgaard mask |= 0x10; 721a89bcd4cSHans Verkuil io_write_and_or(sd, 0x20, 0xcf, mask); 722a89bcd4cSHans Verkuil } 723a89bcd4cSHans Verkuil 724a89bcd4cSHans Verkuil static int edid_write_vga_segment(struct v4l2_subdev *sd) 725a89bcd4cSHans Verkuil { 726a89bcd4cSHans Verkuil struct i2c_client *client = v4l2_get_subdevdata(sd); 727a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 728a89bcd4cSHans Verkuil const u8 *val = state->vga_edid.edid; 729a89bcd4cSHans Verkuil int err = 0; 730a89bcd4cSHans Verkuil int i; 731a89bcd4cSHans Verkuil 732a89bcd4cSHans Verkuil v4l2_dbg(2, debug, sd, "%s: write EDID on VGA port\n", __func__); 733a89bcd4cSHans Verkuil 734a89bcd4cSHans Verkuil /* HPA disable on port A and B */ 735a89bcd4cSHans Verkuil io_write_and_or(sd, 0x20, 0xcf, 0x00); 736a89bcd4cSHans Verkuil 737a89bcd4cSHans Verkuil /* Disable I2C access to internal EDID ram from VGA DDC port */ 738a89bcd4cSHans Verkuil rep_write_and_or(sd, 0x7f, 0x7f, 0x00); 739a89bcd4cSHans Verkuil 740a89bcd4cSHans Verkuil /* edid segment pointer '1' for VGA port */ 741a89bcd4cSHans Verkuil rep_write_and_or(sd, 0x77, 0xef, 0x10); 742a89bcd4cSHans Verkuil 743a89bcd4cSHans Verkuil for (i = 0; !err && i < 256; i += I2C_SMBUS_BLOCK_MAX) 744a89bcd4cSHans Verkuil err = adv_smbus_write_i2c_block_data(state->i2c_edid, i, 745a89bcd4cSHans Verkuil I2C_SMBUS_BLOCK_MAX, val + i); 746a89bcd4cSHans Verkuil if (err) 747a89bcd4cSHans Verkuil return err; 748a89bcd4cSHans Verkuil 749a89bcd4cSHans Verkuil /* Calculates the checksums and enables I2C access 750a89bcd4cSHans Verkuil * to internal EDID ram from VGA DDC port. 751a89bcd4cSHans Verkuil */ 752a89bcd4cSHans Verkuil rep_write_and_or(sd, 0x7f, 0x7f, 0x80); 753a89bcd4cSHans Verkuil 754a89bcd4cSHans Verkuil for (i = 0; i < 1000; i++) { 755a89bcd4cSHans Verkuil if (rep_read(sd, 0x79) & 0x20) 756a89bcd4cSHans Verkuil break; 757a89bcd4cSHans Verkuil mdelay(1); 758a89bcd4cSHans Verkuil } 759a89bcd4cSHans Verkuil if (i == 1000) { 760a89bcd4cSHans Verkuil v4l_err(client, "error enabling edid on VGA port\n"); 761a89bcd4cSHans Verkuil return -EIO; 762a89bcd4cSHans Verkuil } 763a89bcd4cSHans Verkuil 764a89bcd4cSHans Verkuil /* enable hotplug after 200 ms */ 7651d3e1543SBhaktipriya Shridhar schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 5); 766a89bcd4cSHans Verkuil 767a89bcd4cSHans Verkuil return 0; 768a89bcd4cSHans Verkuil } 769a89bcd4cSHans Verkuil 770a89bcd4cSHans Verkuil static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port) 771a89bcd4cSHans Verkuil { 772a89bcd4cSHans Verkuil struct i2c_client *client = v4l2_get_subdevdata(sd); 773a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 77425c84fb1SHans Verkuil const u8 *edid = state->hdmi_edid.edid; 77525c84fb1SHans Verkuil int spa_loc; 77625c84fb1SHans Verkuil u16 pa; 777a89bcd4cSHans Verkuil int err = 0; 778a89bcd4cSHans Verkuil int i; 779a89bcd4cSHans Verkuil 78025c84fb1SHans Verkuil v4l2_dbg(2, debug, sd, "%s: write EDID on port %c\n", 78125c84fb1SHans Verkuil __func__, (port == ADV7842_EDID_PORT_A) ? 'A' : 'B'); 782a89bcd4cSHans Verkuil 783a89bcd4cSHans Verkuil /* HPA disable on port A and B */ 784a89bcd4cSHans Verkuil io_write_and_or(sd, 0x20, 0xcf, 0x00); 785a89bcd4cSHans Verkuil 786a89bcd4cSHans Verkuil /* Disable I2C access to internal EDID ram from HDMI DDC ports */ 787a89bcd4cSHans Verkuil rep_write_and_or(sd, 0x77, 0xf3, 0x00); 788a89bcd4cSHans Verkuil 789ab83203eSHans Verkuil if (!state->hdmi_edid.present) { 790ab83203eSHans Verkuil cec_phys_addr_invalidate(state->cec_adap); 791fc2e991eSMartin Bugge return 0; 792ab83203eSHans Verkuil } 793fc2e991eSMartin Bugge 7949cfd2753SHans Verkuil pa = v4l2_get_edid_phys_addr(edid, 256, &spa_loc); 7959cfd2753SHans Verkuil err = v4l2_phys_addr_validate(pa, &pa, NULL); 79625c84fb1SHans Verkuil if (err) 79725c84fb1SHans Verkuil return err; 79825c84fb1SHans Verkuil 79925c84fb1SHans Verkuil /* 80025c84fb1SHans Verkuil * Return an error if no location of the source physical address 80125c84fb1SHans Verkuil * was found. 80225c84fb1SHans Verkuil */ 80325c84fb1SHans Verkuil if (spa_loc == 0) 80425c84fb1SHans Verkuil return -EINVAL; 80525c84fb1SHans Verkuil 806a89bcd4cSHans Verkuil /* edid segment pointer '0' for HDMI ports */ 807a89bcd4cSHans Verkuil rep_write_and_or(sd, 0x77, 0xef, 0x00); 808a89bcd4cSHans Verkuil 809a89bcd4cSHans Verkuil for (i = 0; !err && i < 256; i += I2C_SMBUS_BLOCK_MAX) 810a89bcd4cSHans Verkuil err = adv_smbus_write_i2c_block_data(state->i2c_edid, i, 81125c84fb1SHans Verkuil I2C_SMBUS_BLOCK_MAX, edid + i); 812a89bcd4cSHans Verkuil if (err) 813a89bcd4cSHans Verkuil return err; 814a89bcd4cSHans Verkuil 8157de6fab1SMats Randgaard if (port == ADV7842_EDID_PORT_A) { 81625c84fb1SHans Verkuil rep_write(sd, 0x72, edid[spa_loc]); 81725c84fb1SHans Verkuil rep_write(sd, 0x73, edid[spa_loc + 1]); 818a89bcd4cSHans Verkuil } else { 81925c84fb1SHans Verkuil rep_write(sd, 0x74, edid[spa_loc]); 82025c84fb1SHans Verkuil rep_write(sd, 0x75, edid[spa_loc + 1]); 821a89bcd4cSHans Verkuil } 8227de6fab1SMats Randgaard rep_write(sd, 0x76, spa_loc & 0xff); 8237de6fab1SMats Randgaard rep_write_and_or(sd, 0x77, 0xbf, (spa_loc >> 2) & 0x40); 824a89bcd4cSHans Verkuil 825a89bcd4cSHans Verkuil /* Calculates the checksums and enables I2C access to internal 826a89bcd4cSHans Verkuil * EDID ram from HDMI DDC ports 827a89bcd4cSHans Verkuil */ 8287de6fab1SMats Randgaard rep_write_and_or(sd, 0x77, 0xf3, state->hdmi_edid.present); 829a89bcd4cSHans Verkuil 830a89bcd4cSHans Verkuil for (i = 0; i < 1000; i++) { 8317de6fab1SMats Randgaard if (rep_read(sd, 0x7d) & state->hdmi_edid.present) 832a89bcd4cSHans Verkuil break; 833a89bcd4cSHans Verkuil mdelay(1); 834a89bcd4cSHans Verkuil } 835a89bcd4cSHans Verkuil if (i == 1000) { 8367de6fab1SMats Randgaard v4l_err(client, "error enabling edid on port %c\n", 8377de6fab1SMats Randgaard (port == ADV7842_EDID_PORT_A) ? 'A' : 'B'); 838a89bcd4cSHans Verkuil return -EIO; 839a89bcd4cSHans Verkuil } 84025c84fb1SHans Verkuil cec_s_phys_addr(state->cec_adap, pa, false); 841a89bcd4cSHans Verkuil 842a89bcd4cSHans Verkuil /* enable hotplug after 200 ms */ 8431d3e1543SBhaktipriya Shridhar schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 5); 844a89bcd4cSHans Verkuil 845a89bcd4cSHans Verkuil return 0; 846a89bcd4cSHans Verkuil } 847a89bcd4cSHans Verkuil 848a89bcd4cSHans Verkuil /* ----------------------------------------------------------------------- */ 849a89bcd4cSHans Verkuil 850a89bcd4cSHans Verkuil #ifdef CONFIG_VIDEO_ADV_DEBUG 851a89bcd4cSHans Verkuil static void adv7842_inv_register(struct v4l2_subdev *sd) 852a89bcd4cSHans Verkuil { 853a89bcd4cSHans Verkuil v4l2_info(sd, "0x000-0x0ff: IO Map\n"); 854a89bcd4cSHans Verkuil v4l2_info(sd, "0x100-0x1ff: AVLink Map\n"); 855a89bcd4cSHans Verkuil v4l2_info(sd, "0x200-0x2ff: CEC Map\n"); 856a89bcd4cSHans Verkuil v4l2_info(sd, "0x300-0x3ff: InfoFrame Map\n"); 857a89bcd4cSHans Verkuil v4l2_info(sd, "0x400-0x4ff: SDP_IO Map\n"); 858a89bcd4cSHans Verkuil v4l2_info(sd, "0x500-0x5ff: SDP Map\n"); 859a89bcd4cSHans Verkuil v4l2_info(sd, "0x600-0x6ff: AFE Map\n"); 860a89bcd4cSHans Verkuil v4l2_info(sd, "0x700-0x7ff: Repeater Map\n"); 861a89bcd4cSHans Verkuil v4l2_info(sd, "0x800-0x8ff: EDID Map\n"); 862a89bcd4cSHans Verkuil v4l2_info(sd, "0x900-0x9ff: HDMI Map\n"); 863a89bcd4cSHans Verkuil v4l2_info(sd, "0xa00-0xaff: CP Map\n"); 864a89bcd4cSHans Verkuil v4l2_info(sd, "0xb00-0xbff: VDP Map\n"); 865a89bcd4cSHans Verkuil } 866a89bcd4cSHans Verkuil 867a89bcd4cSHans Verkuil static int adv7842_g_register(struct v4l2_subdev *sd, 868a89bcd4cSHans Verkuil struct v4l2_dbg_register *reg) 869a89bcd4cSHans Verkuil { 870a89bcd4cSHans Verkuil reg->size = 1; 871a89bcd4cSHans Verkuil switch (reg->reg >> 8) { 872a89bcd4cSHans Verkuil case 0: 873a89bcd4cSHans Verkuil reg->val = io_read(sd, reg->reg & 0xff); 874a89bcd4cSHans Verkuil break; 875a89bcd4cSHans Verkuil case 1: 876a89bcd4cSHans Verkuil reg->val = avlink_read(sd, reg->reg & 0xff); 877a89bcd4cSHans Verkuil break; 878a89bcd4cSHans Verkuil case 2: 879a89bcd4cSHans Verkuil reg->val = cec_read(sd, reg->reg & 0xff); 880a89bcd4cSHans Verkuil break; 881a89bcd4cSHans Verkuil case 3: 882a89bcd4cSHans Verkuil reg->val = infoframe_read(sd, reg->reg & 0xff); 883a89bcd4cSHans Verkuil break; 884a89bcd4cSHans Verkuil case 4: 885a89bcd4cSHans Verkuil reg->val = sdp_io_read(sd, reg->reg & 0xff); 886a89bcd4cSHans Verkuil break; 887a89bcd4cSHans Verkuil case 5: 888a89bcd4cSHans Verkuil reg->val = sdp_read(sd, reg->reg & 0xff); 889a89bcd4cSHans Verkuil break; 890a89bcd4cSHans Verkuil case 6: 891a89bcd4cSHans Verkuil reg->val = afe_read(sd, reg->reg & 0xff); 892a89bcd4cSHans Verkuil break; 893a89bcd4cSHans Verkuil case 7: 894a89bcd4cSHans Verkuil reg->val = rep_read(sd, reg->reg & 0xff); 895a89bcd4cSHans Verkuil break; 896a89bcd4cSHans Verkuil case 8: 897a89bcd4cSHans Verkuil reg->val = edid_read(sd, reg->reg & 0xff); 898a89bcd4cSHans Verkuil break; 899a89bcd4cSHans Verkuil case 9: 900a89bcd4cSHans Verkuil reg->val = hdmi_read(sd, reg->reg & 0xff); 901a89bcd4cSHans Verkuil break; 902a89bcd4cSHans Verkuil case 0xa: 903a89bcd4cSHans Verkuil reg->val = cp_read(sd, reg->reg & 0xff); 904a89bcd4cSHans Verkuil break; 905a89bcd4cSHans Verkuil case 0xb: 906a89bcd4cSHans Verkuil reg->val = vdp_read(sd, reg->reg & 0xff); 907a89bcd4cSHans Verkuil break; 908a89bcd4cSHans Verkuil default: 909a89bcd4cSHans Verkuil v4l2_info(sd, "Register %03llx not supported\n", reg->reg); 910a89bcd4cSHans Verkuil adv7842_inv_register(sd); 911a89bcd4cSHans Verkuil break; 912a89bcd4cSHans Verkuil } 913a89bcd4cSHans Verkuil return 0; 914a89bcd4cSHans Verkuil } 915a89bcd4cSHans Verkuil 916a89bcd4cSHans Verkuil static int adv7842_s_register(struct v4l2_subdev *sd, 917a89bcd4cSHans Verkuil const struct v4l2_dbg_register *reg) 918a89bcd4cSHans Verkuil { 919a89bcd4cSHans Verkuil u8 val = reg->val & 0xff; 920a89bcd4cSHans Verkuil 921a89bcd4cSHans Verkuil switch (reg->reg >> 8) { 922a89bcd4cSHans Verkuil case 0: 923a89bcd4cSHans Verkuil io_write(sd, reg->reg & 0xff, val); 924a89bcd4cSHans Verkuil break; 925a89bcd4cSHans Verkuil case 1: 926a89bcd4cSHans Verkuil avlink_write(sd, reg->reg & 0xff, val); 927a89bcd4cSHans Verkuil break; 928a89bcd4cSHans Verkuil case 2: 929a89bcd4cSHans Verkuil cec_write(sd, reg->reg & 0xff, val); 930a89bcd4cSHans Verkuil break; 931a89bcd4cSHans Verkuil case 3: 932a89bcd4cSHans Verkuil infoframe_write(sd, reg->reg & 0xff, val); 933a89bcd4cSHans Verkuil break; 934a89bcd4cSHans Verkuil case 4: 935a89bcd4cSHans Verkuil sdp_io_write(sd, reg->reg & 0xff, val); 936a89bcd4cSHans Verkuil break; 937a89bcd4cSHans Verkuil case 5: 938a89bcd4cSHans Verkuil sdp_write(sd, reg->reg & 0xff, val); 939a89bcd4cSHans Verkuil break; 940a89bcd4cSHans Verkuil case 6: 941a89bcd4cSHans Verkuil afe_write(sd, reg->reg & 0xff, val); 942a89bcd4cSHans Verkuil break; 943a89bcd4cSHans Verkuil case 7: 944a89bcd4cSHans Verkuil rep_write(sd, reg->reg & 0xff, val); 945a89bcd4cSHans Verkuil break; 946a89bcd4cSHans Verkuil case 8: 947a89bcd4cSHans Verkuil edid_write(sd, reg->reg & 0xff, val); 948a89bcd4cSHans Verkuil break; 949a89bcd4cSHans Verkuil case 9: 950a89bcd4cSHans Verkuil hdmi_write(sd, reg->reg & 0xff, val); 951a89bcd4cSHans Verkuil break; 952a89bcd4cSHans Verkuil case 0xa: 953a89bcd4cSHans Verkuil cp_write(sd, reg->reg & 0xff, val); 954a89bcd4cSHans Verkuil break; 955a89bcd4cSHans Verkuil case 0xb: 956a89bcd4cSHans Verkuil vdp_write(sd, reg->reg & 0xff, val); 957a89bcd4cSHans Verkuil break; 958a89bcd4cSHans Verkuil default: 959a89bcd4cSHans Verkuil v4l2_info(sd, "Register %03llx not supported\n", reg->reg); 960a89bcd4cSHans Verkuil adv7842_inv_register(sd); 961a89bcd4cSHans Verkuil break; 962a89bcd4cSHans Verkuil } 963a89bcd4cSHans Verkuil return 0; 964a89bcd4cSHans Verkuil } 965a89bcd4cSHans Verkuil #endif 966a89bcd4cSHans Verkuil 967a89bcd4cSHans Verkuil static int adv7842_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd) 968a89bcd4cSHans Verkuil { 969a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 97025c84fb1SHans Verkuil u16 cable_det = adv7842_read_cable_det(sd); 971a89bcd4cSHans Verkuil 97225c84fb1SHans Verkuil v4l2_dbg(1, debug, sd, "%s: 0x%x\n", __func__, cable_det); 973a89bcd4cSHans Verkuil 97425c84fb1SHans Verkuil return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, cable_det); 975a89bcd4cSHans Verkuil } 976a89bcd4cSHans Verkuil 977a89bcd4cSHans Verkuil static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd, 978a89bcd4cSHans Verkuil u8 prim_mode, 979a89bcd4cSHans Verkuil const struct adv7842_video_standards *predef_vid_timings, 980a89bcd4cSHans Verkuil const struct v4l2_dv_timings *timings) 981a89bcd4cSHans Verkuil { 982a89bcd4cSHans Verkuil int i; 983a89bcd4cSHans Verkuil 984a89bcd4cSHans Verkuil for (i = 0; predef_vid_timings[i].timings.bt.width; i++) { 985a89bcd4cSHans Verkuil if (!v4l2_match_dv_timings(timings, &predef_vid_timings[i].timings, 98685f9e06cSHans Verkuil is_digital_input(sd) ? 250000 : 1000000, false)) 987a89bcd4cSHans Verkuil continue; 988a89bcd4cSHans Verkuil /* video std */ 989a89bcd4cSHans Verkuil io_write(sd, 0x00, predef_vid_timings[i].vid_std); 990a89bcd4cSHans Verkuil /* v_freq and prim mode */ 991a89bcd4cSHans Verkuil io_write(sd, 0x01, (predef_vid_timings[i].v_freq << 4) + prim_mode); 992a89bcd4cSHans Verkuil return 0; 993a89bcd4cSHans Verkuil } 994a89bcd4cSHans Verkuil 995a89bcd4cSHans Verkuil return -1; 996a89bcd4cSHans Verkuil } 997a89bcd4cSHans Verkuil 998a89bcd4cSHans Verkuil static int configure_predefined_video_timings(struct v4l2_subdev *sd, 999a89bcd4cSHans Verkuil struct v4l2_dv_timings *timings) 1000a89bcd4cSHans Verkuil { 1001a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 1002a89bcd4cSHans Verkuil int err; 1003a89bcd4cSHans Verkuil 1004a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, "%s\n", __func__); 1005a89bcd4cSHans Verkuil 1006a89bcd4cSHans Verkuil /* reset to default values */ 1007a89bcd4cSHans Verkuil io_write(sd, 0x16, 0x43); 1008a89bcd4cSHans Verkuil io_write(sd, 0x17, 0x5a); 1009a89bcd4cSHans Verkuil /* disable embedded syncs for auto graphics mode */ 1010a89bcd4cSHans Verkuil cp_write_and_or(sd, 0x81, 0xef, 0x00); 1011a89bcd4cSHans Verkuil cp_write(sd, 0x26, 0x00); 1012a89bcd4cSHans Verkuil cp_write(sd, 0x27, 0x00); 1013a89bcd4cSHans Verkuil cp_write(sd, 0x28, 0x00); 1014a89bcd4cSHans Verkuil cp_write(sd, 0x29, 0x00); 10156251e65fSMartin Bugge cp_write(sd, 0x8f, 0x40); 1016a89bcd4cSHans Verkuil cp_write(sd, 0x90, 0x00); 1017a89bcd4cSHans Verkuil cp_write(sd, 0xa5, 0x00); 1018a89bcd4cSHans Verkuil cp_write(sd, 0xa6, 0x00); 1019a89bcd4cSHans Verkuil cp_write(sd, 0xa7, 0x00); 1020a89bcd4cSHans Verkuil cp_write(sd, 0xab, 0x00); 1021a89bcd4cSHans Verkuil cp_write(sd, 0xac, 0x00); 1022a89bcd4cSHans Verkuil 1023a89bcd4cSHans Verkuil switch (state->mode) { 1024a89bcd4cSHans Verkuil case ADV7842_MODE_COMP: 1025a89bcd4cSHans Verkuil case ADV7842_MODE_RGB: 1026a89bcd4cSHans Verkuil err = find_and_set_predefined_video_timings(sd, 1027a89bcd4cSHans Verkuil 0x01, adv7842_prim_mode_comp, timings); 1028a89bcd4cSHans Verkuil if (err) 1029a89bcd4cSHans Verkuil err = find_and_set_predefined_video_timings(sd, 1030a89bcd4cSHans Verkuil 0x02, adv7842_prim_mode_gr, timings); 1031a89bcd4cSHans Verkuil break; 1032a89bcd4cSHans Verkuil case ADV7842_MODE_HDMI: 1033a89bcd4cSHans Verkuil err = find_and_set_predefined_video_timings(sd, 1034a89bcd4cSHans Verkuil 0x05, adv7842_prim_mode_hdmi_comp, timings); 1035a89bcd4cSHans Verkuil if (err) 1036a89bcd4cSHans Verkuil err = find_and_set_predefined_video_timings(sd, 1037a89bcd4cSHans Verkuil 0x06, adv7842_prim_mode_hdmi_gr, timings); 1038a89bcd4cSHans Verkuil break; 1039a89bcd4cSHans Verkuil default: 1040a89bcd4cSHans Verkuil v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", 1041a89bcd4cSHans Verkuil __func__, state->mode); 1042a89bcd4cSHans Verkuil err = -1; 1043a89bcd4cSHans Verkuil break; 1044a89bcd4cSHans Verkuil } 1045a89bcd4cSHans Verkuil 1046a89bcd4cSHans Verkuil 1047a89bcd4cSHans Verkuil return err; 1048a89bcd4cSHans Verkuil } 1049a89bcd4cSHans Verkuil 1050a89bcd4cSHans Verkuil static void configure_custom_video_timings(struct v4l2_subdev *sd, 1051a89bcd4cSHans Verkuil const struct v4l2_bt_timings *bt) 1052a89bcd4cSHans Verkuil { 1053a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 1054a89bcd4cSHans Verkuil struct i2c_client *client = v4l2_get_subdevdata(sd); 1055a89bcd4cSHans Verkuil u32 width = htotal(bt); 1056a89bcd4cSHans Verkuil u32 height = vtotal(bt); 1057a89bcd4cSHans Verkuil u16 cp_start_sav = bt->hsync + bt->hbackporch - 4; 1058a89bcd4cSHans Verkuil u16 cp_start_eav = width - bt->hfrontporch; 1059a89bcd4cSHans Verkuil u16 cp_start_vbi = height - bt->vfrontporch + 1; 1060a89bcd4cSHans Verkuil u16 cp_end_vbi = bt->vsync + bt->vbackporch + 1; 1061a89bcd4cSHans Verkuil u16 ch1_fr_ll = (((u32)bt->pixelclock / 100) > 0) ? 1062a89bcd4cSHans Verkuil ((width * (ADV7842_fsc / 100)) / ((u32)bt->pixelclock / 100)) : 0; 1063a89bcd4cSHans Verkuil const u8 pll[2] = { 1064a89bcd4cSHans Verkuil 0xc0 | ((width >> 8) & 0x1f), 1065a89bcd4cSHans Verkuil width & 0xff 1066a89bcd4cSHans Verkuil }; 1067a89bcd4cSHans Verkuil 1068a89bcd4cSHans Verkuil v4l2_dbg(2, debug, sd, "%s\n", __func__); 1069a89bcd4cSHans Verkuil 1070a89bcd4cSHans Verkuil switch (state->mode) { 1071a89bcd4cSHans Verkuil case ADV7842_MODE_COMP: 1072a89bcd4cSHans Verkuil case ADV7842_MODE_RGB: 1073a89bcd4cSHans Verkuil /* auto graphics */ 1074a89bcd4cSHans Verkuil io_write(sd, 0x00, 0x07); /* video std */ 1075a89bcd4cSHans Verkuil io_write(sd, 0x01, 0x02); /* prim mode */ 1076a89bcd4cSHans Verkuil /* enable embedded syncs for auto graphics mode */ 1077a89bcd4cSHans Verkuil cp_write_and_or(sd, 0x81, 0xef, 0x10); 1078a89bcd4cSHans Verkuil 1079a89bcd4cSHans Verkuil /* Should only be set in auto-graphics mode [REF_02, p. 91-92] */ 1080a89bcd4cSHans Verkuil /* setup PLL_DIV_MAN_EN and PLL_DIV_RATIO */ 1081a89bcd4cSHans Verkuil /* IO-map reg. 0x16 and 0x17 should be written in sequence */ 1082a89bcd4cSHans Verkuil if (adv_smbus_write_i2c_block_data(client, 0x16, 2, pll)) { 1083a89bcd4cSHans Verkuil v4l2_err(sd, "writing to reg 0x16 and 0x17 failed\n"); 1084a89bcd4cSHans Verkuil break; 1085a89bcd4cSHans Verkuil } 1086a89bcd4cSHans Verkuil 1087a89bcd4cSHans Verkuil /* active video - horizontal timing */ 1088a89bcd4cSHans Verkuil cp_write(sd, 0x26, (cp_start_sav >> 8) & 0xf); 1089a89bcd4cSHans Verkuil cp_write(sd, 0x27, (cp_start_sav & 0xff)); 1090a89bcd4cSHans Verkuil cp_write(sd, 0x28, (cp_start_eav >> 8) & 0xf); 1091a89bcd4cSHans Verkuil cp_write(sd, 0x29, (cp_start_eav & 0xff)); 1092a89bcd4cSHans Verkuil 1093a89bcd4cSHans Verkuil /* active video - vertical timing */ 1094a89bcd4cSHans Verkuil cp_write(sd, 0xa5, (cp_start_vbi >> 4) & 0xff); 1095a89bcd4cSHans Verkuil cp_write(sd, 0xa6, ((cp_start_vbi & 0xf) << 4) | 1096a89bcd4cSHans Verkuil ((cp_end_vbi >> 8) & 0xf)); 1097a89bcd4cSHans Verkuil cp_write(sd, 0xa7, cp_end_vbi & 0xff); 1098a89bcd4cSHans Verkuil break; 1099a89bcd4cSHans Verkuil case ADV7842_MODE_HDMI: 1100a89bcd4cSHans Verkuil /* set default prim_mode/vid_std for HDMI 110139c1cb2bSJonathan McCrohan according to [REF_03, c. 4.2] */ 1102a89bcd4cSHans Verkuil io_write(sd, 0x00, 0x02); /* video std */ 1103a89bcd4cSHans Verkuil io_write(sd, 0x01, 0x06); /* prim mode */ 1104a89bcd4cSHans Verkuil break; 1105a89bcd4cSHans Verkuil default: 1106a89bcd4cSHans Verkuil v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", 1107a89bcd4cSHans Verkuil __func__, state->mode); 1108a89bcd4cSHans Verkuil break; 1109a89bcd4cSHans Verkuil } 1110a89bcd4cSHans Verkuil 1111a89bcd4cSHans Verkuil cp_write(sd, 0x8f, (ch1_fr_ll >> 8) & 0x7); 1112a89bcd4cSHans Verkuil cp_write(sd, 0x90, ch1_fr_ll & 0xff); 1113a89bcd4cSHans Verkuil cp_write(sd, 0xab, (height >> 4) & 0xff); 1114a89bcd4cSHans Verkuil cp_write(sd, 0xac, (height & 0x0f) << 4); 1115a89bcd4cSHans Verkuil } 1116a89bcd4cSHans Verkuil 1117933913daSMartin Bugge static void adv7842_set_offset(struct v4l2_subdev *sd, bool auto_offset, u16 offset_a, u16 offset_b, u16 offset_c) 1118933913daSMartin Bugge { 1119933913daSMartin Bugge struct adv7842_state *state = to_state(sd); 1120933913daSMartin Bugge u8 offset_buf[4]; 1121933913daSMartin Bugge 1122933913daSMartin Bugge if (auto_offset) { 1123933913daSMartin Bugge offset_a = 0x3ff; 1124933913daSMartin Bugge offset_b = 0x3ff; 1125933913daSMartin Bugge offset_c = 0x3ff; 1126933913daSMartin Bugge } 1127933913daSMartin Bugge 1128933913daSMartin Bugge v4l2_dbg(2, debug, sd, "%s: %s offset: a = 0x%x, b = 0x%x, c = 0x%x\n", 1129933913daSMartin Bugge __func__, auto_offset ? "Auto" : "Manual", 1130933913daSMartin Bugge offset_a, offset_b, offset_c); 1131933913daSMartin Bugge 1132933913daSMartin Bugge offset_buf[0]= (cp_read(sd, 0x77) & 0xc0) | ((offset_a & 0x3f0) >> 4); 1133933913daSMartin Bugge offset_buf[1] = ((offset_a & 0x00f) << 4) | ((offset_b & 0x3c0) >> 6); 1134933913daSMartin Bugge offset_buf[2] = ((offset_b & 0x03f) << 2) | ((offset_c & 0x300) >> 8); 1135933913daSMartin Bugge offset_buf[3] = offset_c & 0x0ff; 1136933913daSMartin Bugge 1137933913daSMartin Bugge /* Registers must be written in this order with no i2c access in between */ 1138933913daSMartin Bugge if (adv_smbus_write_i2c_block_data(state->i2c_cp, 0x77, 4, offset_buf)) 1139933913daSMartin Bugge v4l2_err(sd, "%s: i2c error writing to CP reg 0x77, 0x78, 0x79, 0x7a\n", __func__); 1140933913daSMartin Bugge } 1141933913daSMartin Bugge 1142933913daSMartin Bugge static void adv7842_set_gain(struct v4l2_subdev *sd, bool auto_gain, u16 gain_a, u16 gain_b, u16 gain_c) 1143933913daSMartin Bugge { 1144933913daSMartin Bugge struct adv7842_state *state = to_state(sd); 1145933913daSMartin Bugge u8 gain_buf[4]; 1146933913daSMartin Bugge u8 gain_man = 1; 1147933913daSMartin Bugge u8 agc_mode_man = 1; 1148933913daSMartin Bugge 1149933913daSMartin Bugge if (auto_gain) { 1150933913daSMartin Bugge gain_man = 0; 1151933913daSMartin Bugge agc_mode_man = 0; 1152933913daSMartin Bugge gain_a = 0x100; 1153933913daSMartin Bugge gain_b = 0x100; 1154933913daSMartin Bugge gain_c = 0x100; 1155933913daSMartin Bugge } 1156933913daSMartin Bugge 1157933913daSMartin Bugge v4l2_dbg(2, debug, sd, "%s: %s gain: a = 0x%x, b = 0x%x, c = 0x%x\n", 1158933913daSMartin Bugge __func__, auto_gain ? "Auto" : "Manual", 1159933913daSMartin Bugge gain_a, gain_b, gain_c); 1160933913daSMartin Bugge 1161933913daSMartin Bugge gain_buf[0] = ((gain_man << 7) | (agc_mode_man << 6) | ((gain_a & 0x3f0) >> 4)); 1162933913daSMartin Bugge gain_buf[1] = (((gain_a & 0x00f) << 4) | ((gain_b & 0x3c0) >> 6)); 1163933913daSMartin Bugge gain_buf[2] = (((gain_b & 0x03f) << 2) | ((gain_c & 0x300) >> 8)); 1164933913daSMartin Bugge gain_buf[3] = ((gain_c & 0x0ff)); 1165933913daSMartin Bugge 1166933913daSMartin Bugge /* Registers must be written in this order with no i2c access in between */ 1167933913daSMartin Bugge if (adv_smbus_write_i2c_block_data(state->i2c_cp, 0x73, 4, gain_buf)) 1168933913daSMartin Bugge v4l2_err(sd, "%s: i2c error writing to CP reg 0x73, 0x74, 0x75, 0x76\n", __func__); 1169933913daSMartin Bugge } 1170933913daSMartin Bugge 1171a89bcd4cSHans Verkuil static void set_rgb_quantization_range(struct v4l2_subdev *sd) 1172a89bcd4cSHans Verkuil { 1173a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 1174933913daSMartin Bugge bool rgb_output = io_read(sd, 0x02) & 0x02; 1175933913daSMartin Bugge bool hdmi_signal = hdmi_read(sd, 0x05) & 0x80; 1176fd74246dSHans Verkuil u8 y = HDMI_COLORSPACE_RGB; 1177fd74246dSHans Verkuil 1178fd74246dSHans Verkuil if (hdmi_signal && (io_read(sd, 0x60) & 1)) 1179fd74246dSHans Verkuil y = infoframe_read(sd, 0x01) >> 5; 1180a89bcd4cSHans Verkuil 1181933913daSMartin Bugge v4l2_dbg(2, debug, sd, "%s: RGB quantization range: %d, RGB out: %d, HDMI: %d\n", 1182933913daSMartin Bugge __func__, state->rgb_quantization_range, 1183933913daSMartin Bugge rgb_output, hdmi_signal); 1184933913daSMartin Bugge 1185933913daSMartin Bugge adv7842_set_gain(sd, true, 0x0, 0x0, 0x0); 1186933913daSMartin Bugge adv7842_set_offset(sd, true, 0x0, 0x0, 0x0); 1187fd74246dSHans Verkuil io_write_clr_set(sd, 0x02, 0x04, rgb_output ? 0 : 4); 118869e9ba6fSHans Verkuil 1189a89bcd4cSHans Verkuil switch (state->rgb_quantization_range) { 1190a89bcd4cSHans Verkuil case V4L2_DV_RGB_RANGE_AUTO: 119169e9ba6fSHans Verkuil if (state->mode == ADV7842_MODE_RGB) { 119269e9ba6fSHans Verkuil /* Receiving analog RGB signal 119369e9ba6fSHans Verkuil * Set RGB full range (0-255) */ 119469e9ba6fSHans Verkuil io_write_and_or(sd, 0x02, 0x0f, 0x10); 119569e9ba6fSHans Verkuil break; 119669e9ba6fSHans Verkuil } 1197a89bcd4cSHans Verkuil 119869e9ba6fSHans Verkuil if (state->mode == ADV7842_MODE_COMP) { 119969e9ba6fSHans Verkuil /* Receiving analog YPbPr signal 120069e9ba6fSHans Verkuil * Set automode */ 120169e9ba6fSHans Verkuil io_write_and_or(sd, 0x02, 0x0f, 0xf0); 120269e9ba6fSHans Verkuil break; 120369e9ba6fSHans Verkuil } 120469e9ba6fSHans Verkuil 1205933913daSMartin Bugge if (hdmi_signal) { 120669e9ba6fSHans Verkuil /* Receiving HDMI signal 120769e9ba6fSHans Verkuil * Set automode */ 120869e9ba6fSHans Verkuil io_write_and_or(sd, 0x02, 0x0f, 0xf0); 120969e9ba6fSHans Verkuil break; 121069e9ba6fSHans Verkuil } 121169e9ba6fSHans Verkuil 121269e9ba6fSHans Verkuil /* Receiving DVI-D signal 121369e9ba6fSHans Verkuil * ADV7842 selects RGB limited range regardless of 121469e9ba6fSHans Verkuil * input format (CE/IT) in automatic mode */ 1215680fee04SHans Verkuil if (state->timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) { 1216a89bcd4cSHans Verkuil /* RGB limited range (16-235) */ 1217a89bcd4cSHans Verkuil io_write_and_or(sd, 0x02, 0x0f, 0x00); 1218a89bcd4cSHans Verkuil } else { 1219a89bcd4cSHans Verkuil /* RGB full range (0-255) */ 1220a89bcd4cSHans Verkuil io_write_and_or(sd, 0x02, 0x0f, 0x10); 1221933913daSMartin Bugge 1222933913daSMartin Bugge if (is_digital_input(sd) && rgb_output) { 1223933913daSMartin Bugge adv7842_set_offset(sd, false, 0x40, 0x40, 0x40); 1224933913daSMartin Bugge } else { 1225933913daSMartin Bugge adv7842_set_gain(sd, false, 0xe0, 0xe0, 0xe0); 1226933913daSMartin Bugge adv7842_set_offset(sd, false, 0x70, 0x70, 0x70); 1227933913daSMartin Bugge } 1228a89bcd4cSHans Verkuil } 1229a89bcd4cSHans Verkuil break; 1230a89bcd4cSHans Verkuil case V4L2_DV_RGB_RANGE_LIMITED: 123169e9ba6fSHans Verkuil if (state->mode == ADV7842_MODE_COMP) { 123269e9ba6fSHans Verkuil /* YCrCb limited range (16-235) */ 123369e9ba6fSHans Verkuil io_write_and_or(sd, 0x02, 0x0f, 0x20); 1234933913daSMartin Bugge break; 1235933913daSMartin Bugge } 1236933913daSMartin Bugge 1237fd74246dSHans Verkuil if (y != HDMI_COLORSPACE_RGB) 1238fd74246dSHans Verkuil break; 1239fd74246dSHans Verkuil 1240a89bcd4cSHans Verkuil /* RGB limited range (16-235) */ 1241a89bcd4cSHans Verkuil io_write_and_or(sd, 0x02, 0x0f, 0x00); 1242933913daSMartin Bugge 1243a89bcd4cSHans Verkuil break; 1244a89bcd4cSHans Verkuil case V4L2_DV_RGB_RANGE_FULL: 124569e9ba6fSHans Verkuil if (state->mode == ADV7842_MODE_COMP) { 124669e9ba6fSHans Verkuil /* YCrCb full range (0-255) */ 124769e9ba6fSHans Verkuil io_write_and_or(sd, 0x02, 0x0f, 0x60); 1248933913daSMartin Bugge break; 1249933913daSMartin Bugge } 1250933913daSMartin Bugge 1251fd74246dSHans Verkuil if (y != HDMI_COLORSPACE_RGB) 1252fd74246dSHans Verkuil break; 1253fd74246dSHans Verkuil 1254a89bcd4cSHans Verkuil /* RGB full range (0-255) */ 1255a89bcd4cSHans Verkuil io_write_and_or(sd, 0x02, 0x0f, 0x10); 1256933913daSMartin Bugge 1257933913daSMartin Bugge if (is_analog_input(sd) || hdmi_signal) 1258933913daSMartin Bugge break; 1259933913daSMartin Bugge 1260933913daSMartin Bugge /* Adjust gain/offset for DVI-D signals only */ 1261933913daSMartin Bugge if (rgb_output) { 1262933913daSMartin Bugge adv7842_set_offset(sd, false, 0x40, 0x40, 0x40); 1263933913daSMartin Bugge } else { 1264933913daSMartin Bugge adv7842_set_gain(sd, false, 0xe0, 0xe0, 0xe0); 1265933913daSMartin Bugge adv7842_set_offset(sd, false, 0x70, 0x70, 0x70); 126669e9ba6fSHans Verkuil } 1267a89bcd4cSHans Verkuil break; 1268a89bcd4cSHans Verkuil } 1269a89bcd4cSHans Verkuil } 1270a89bcd4cSHans Verkuil 1271a89bcd4cSHans Verkuil static int adv7842_s_ctrl(struct v4l2_ctrl *ctrl) 1272a89bcd4cSHans Verkuil { 1273a89bcd4cSHans Verkuil struct v4l2_subdev *sd = to_sd(ctrl); 1274a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 1275a89bcd4cSHans Verkuil 1276a89bcd4cSHans Verkuil /* TODO SDP ctrls 1277a89bcd4cSHans Verkuil contrast/brightness/hue/free run is acting a bit strange, 1278a89bcd4cSHans Verkuil not sure if sdp csc is correct. 1279a89bcd4cSHans Verkuil */ 1280a89bcd4cSHans Verkuil switch (ctrl->id) { 1281a89bcd4cSHans Verkuil /* standard ctrls */ 1282a89bcd4cSHans Verkuil case V4L2_CID_BRIGHTNESS: 1283a89bcd4cSHans Verkuil cp_write(sd, 0x3c, ctrl->val); 1284a89bcd4cSHans Verkuil sdp_write(sd, 0x14, ctrl->val); 1285a89bcd4cSHans Verkuil /* ignore lsb sdp 0x17[3:2] */ 1286a89bcd4cSHans Verkuil return 0; 1287a89bcd4cSHans Verkuil case V4L2_CID_CONTRAST: 1288a89bcd4cSHans Verkuil cp_write(sd, 0x3a, ctrl->val); 1289a89bcd4cSHans Verkuil sdp_write(sd, 0x13, ctrl->val); 1290a89bcd4cSHans Verkuil /* ignore lsb sdp 0x17[1:0] */ 1291a89bcd4cSHans Verkuil return 0; 1292a89bcd4cSHans Verkuil case V4L2_CID_SATURATION: 1293a89bcd4cSHans Verkuil cp_write(sd, 0x3b, ctrl->val); 1294a89bcd4cSHans Verkuil sdp_write(sd, 0x15, ctrl->val); 1295a89bcd4cSHans Verkuil /* ignore lsb sdp 0x17[5:4] */ 1296a89bcd4cSHans Verkuil return 0; 1297a89bcd4cSHans Verkuil case V4L2_CID_HUE: 1298a89bcd4cSHans Verkuil cp_write(sd, 0x3d, ctrl->val); 1299a89bcd4cSHans Verkuil sdp_write(sd, 0x16, ctrl->val); 1300a89bcd4cSHans Verkuil /* ignore lsb sdp 0x17[7:6] */ 1301a89bcd4cSHans Verkuil return 0; 1302a89bcd4cSHans Verkuil /* custom ctrls */ 1303a89bcd4cSHans Verkuil case V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE: 1304a89bcd4cSHans Verkuil afe_write(sd, 0xc8, ctrl->val); 1305a89bcd4cSHans Verkuil return 0; 1306a89bcd4cSHans Verkuil case V4L2_CID_ADV_RX_FREE_RUN_COLOR_MANUAL: 1307a89bcd4cSHans Verkuil cp_write_and_or(sd, 0xbf, ~0x04, (ctrl->val << 2)); 1308a89bcd4cSHans Verkuil sdp_write_and_or(sd, 0xdd, ~0x04, (ctrl->val << 2)); 1309a89bcd4cSHans Verkuil return 0; 1310a89bcd4cSHans Verkuil case V4L2_CID_ADV_RX_FREE_RUN_COLOR: { 1311a89bcd4cSHans Verkuil u8 R = (ctrl->val & 0xff0000) >> 16; 1312a89bcd4cSHans Verkuil u8 G = (ctrl->val & 0x00ff00) >> 8; 1313a89bcd4cSHans Verkuil u8 B = (ctrl->val & 0x0000ff); 1314a89bcd4cSHans Verkuil /* RGB -> YUV, numerical approximation */ 1315a89bcd4cSHans Verkuil int Y = 66 * R + 129 * G + 25 * B; 1316a89bcd4cSHans Verkuil int U = -38 * R - 74 * G + 112 * B; 1317a89bcd4cSHans Verkuil int V = 112 * R - 94 * G - 18 * B; 1318a89bcd4cSHans Verkuil 1319a89bcd4cSHans Verkuil /* Scale down to 8 bits with rounding */ 1320a89bcd4cSHans Verkuil Y = (Y + 128) >> 8; 1321a89bcd4cSHans Verkuil U = (U + 128) >> 8; 1322a89bcd4cSHans Verkuil V = (V + 128) >> 8; 1323a89bcd4cSHans Verkuil /* make U,V positive */ 1324a89bcd4cSHans Verkuil Y += 16; 1325a89bcd4cSHans Verkuil U += 128; 1326a89bcd4cSHans Verkuil V += 128; 1327a89bcd4cSHans Verkuil 1328a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, "R %x, G %x, B %x\n", R, G, B); 1329a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, "Y %x, U %x, V %x\n", Y, U, V); 1330a89bcd4cSHans Verkuil 1331a89bcd4cSHans Verkuil /* CP */ 1332a89bcd4cSHans Verkuil cp_write(sd, 0xc1, R); 1333a89bcd4cSHans Verkuil cp_write(sd, 0xc0, G); 1334a89bcd4cSHans Verkuil cp_write(sd, 0xc2, B); 1335a89bcd4cSHans Verkuil /* SDP */ 1336a89bcd4cSHans Verkuil sdp_write(sd, 0xde, Y); 1337a89bcd4cSHans Verkuil sdp_write(sd, 0xdf, (V & 0xf0) | ((U >> 4) & 0x0f)); 1338a89bcd4cSHans Verkuil return 0; 1339a89bcd4cSHans Verkuil } 1340a89bcd4cSHans Verkuil case V4L2_CID_DV_RX_RGB_RANGE: 1341a89bcd4cSHans Verkuil state->rgb_quantization_range = ctrl->val; 1342a89bcd4cSHans Verkuil set_rgb_quantization_range(sd); 1343a89bcd4cSHans Verkuil return 0; 1344a89bcd4cSHans Verkuil } 1345a89bcd4cSHans Verkuil return -EINVAL; 1346a89bcd4cSHans Verkuil } 1347a89bcd4cSHans Verkuil 1348e8979274SHans Verkuil static int adv7842_g_volatile_ctrl(struct v4l2_ctrl *ctrl) 1349e8979274SHans Verkuil { 1350e8979274SHans Verkuil struct v4l2_subdev *sd = to_sd(ctrl); 1351e8979274SHans Verkuil 1352e8979274SHans Verkuil if (ctrl->id == V4L2_CID_DV_RX_IT_CONTENT_TYPE) { 1353e8979274SHans Verkuil ctrl->val = V4L2_DV_IT_CONTENT_TYPE_NO_ITC; 1354e8979274SHans Verkuil if ((io_read(sd, 0x60) & 1) && (infoframe_read(sd, 0x03) & 0x80)) 1355e8979274SHans Verkuil ctrl->val = (infoframe_read(sd, 0x05) >> 4) & 3; 1356e8979274SHans Verkuil return 0; 1357e8979274SHans Verkuil } 1358e8979274SHans Verkuil return -EINVAL; 1359e8979274SHans Verkuil } 1360e8979274SHans Verkuil 1361a89bcd4cSHans Verkuil static inline bool no_power(struct v4l2_subdev *sd) 1362a89bcd4cSHans Verkuil { 1363a89bcd4cSHans Verkuil return io_read(sd, 0x0c) & 0x24; 1364a89bcd4cSHans Verkuil } 1365a89bcd4cSHans Verkuil 1366a89bcd4cSHans Verkuil static inline bool no_cp_signal(struct v4l2_subdev *sd) 1367a89bcd4cSHans Verkuil { 1368a89bcd4cSHans Verkuil return ((cp_read(sd, 0xb5) & 0xd0) != 0xd0) || !(cp_read(sd, 0xb1) & 0x80); 1369a89bcd4cSHans Verkuil } 1370a89bcd4cSHans Verkuil 1371a89bcd4cSHans Verkuil static inline bool is_hdmi(struct v4l2_subdev *sd) 1372a89bcd4cSHans Verkuil { 1373a89bcd4cSHans Verkuil return hdmi_read(sd, 0x05) & 0x80; 1374a89bcd4cSHans Verkuil } 1375a89bcd4cSHans Verkuil 1376a89bcd4cSHans Verkuil static int adv7842_g_input_status(struct v4l2_subdev *sd, u32 *status) 1377a89bcd4cSHans Verkuil { 1378a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 1379a89bcd4cSHans Verkuil 1380a89bcd4cSHans Verkuil *status = 0; 1381a89bcd4cSHans Verkuil 1382a89bcd4cSHans Verkuil if (io_read(sd, 0x0c) & 0x24) 1383a89bcd4cSHans Verkuil *status |= V4L2_IN_ST_NO_POWER; 1384a89bcd4cSHans Verkuil 1385a89bcd4cSHans Verkuil if (state->mode == ADV7842_MODE_SDP) { 1386a89bcd4cSHans Verkuil /* status from SDP block */ 1387a89bcd4cSHans Verkuil if (!(sdp_read(sd, 0x5A) & 0x01)) 1388a89bcd4cSHans Verkuil *status |= V4L2_IN_ST_NO_SIGNAL; 1389a89bcd4cSHans Verkuil 1390a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, "%s: SDP status = 0x%x\n", 1391a89bcd4cSHans Verkuil __func__, *status); 1392a89bcd4cSHans Verkuil return 0; 1393a89bcd4cSHans Verkuil } 1394a89bcd4cSHans Verkuil /* status from CP block */ 1395a89bcd4cSHans Verkuil if ((cp_read(sd, 0xb5) & 0xd0) != 0xd0 || 1396a89bcd4cSHans Verkuil !(cp_read(sd, 0xb1) & 0x80)) 1397a89bcd4cSHans Verkuil /* TODO channel 2 */ 1398a89bcd4cSHans Verkuil *status |= V4L2_IN_ST_NO_SIGNAL; 1399a89bcd4cSHans Verkuil 1400a89bcd4cSHans Verkuil if (is_digital_input(sd) && ((io_read(sd, 0x74) & 0x03) != 0x03)) 1401a89bcd4cSHans Verkuil *status |= V4L2_IN_ST_NO_SIGNAL; 1402a89bcd4cSHans Verkuil 1403a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, "%s: CP status = 0x%x\n", 1404a89bcd4cSHans Verkuil __func__, *status); 1405a89bcd4cSHans Verkuil 1406a89bcd4cSHans Verkuil return 0; 1407a89bcd4cSHans Verkuil } 1408a89bcd4cSHans Verkuil 1409a89bcd4cSHans Verkuil struct stdi_readback { 1410a89bcd4cSHans Verkuil u16 bl, lcf, lcvs; 1411a89bcd4cSHans Verkuil u8 hs_pol, vs_pol; 1412a89bcd4cSHans Verkuil bool interlaced; 1413a89bcd4cSHans Verkuil }; 1414a89bcd4cSHans Verkuil 1415a89bcd4cSHans Verkuil static int stdi2dv_timings(struct v4l2_subdev *sd, 1416a89bcd4cSHans Verkuil struct stdi_readback *stdi, 1417a89bcd4cSHans Verkuil struct v4l2_dv_timings *timings) 1418a89bcd4cSHans Verkuil { 1419a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 1420a89bcd4cSHans Verkuil u32 hfreq = (ADV7842_fsc * 8) / stdi->bl; 1421a89bcd4cSHans Verkuil u32 pix_clk; 1422a89bcd4cSHans Verkuil int i; 1423a89bcd4cSHans Verkuil 1424a89bcd4cSHans Verkuil for (i = 0; v4l2_dv_timings_presets[i].bt.width; i++) { 1425a89bcd4cSHans Verkuil const struct v4l2_bt_timings *bt = &v4l2_dv_timings_presets[i].bt; 1426a89bcd4cSHans Verkuil 1427a89bcd4cSHans Verkuil if (!v4l2_valid_dv_timings(&v4l2_dv_timings_presets[i], 1428a89bcd4cSHans Verkuil adv7842_get_dv_timings_cap(sd), 1429a89bcd4cSHans Verkuil adv7842_check_dv_timings, NULL)) 1430a89bcd4cSHans Verkuil continue; 1431a89bcd4cSHans Verkuil if (vtotal(bt) != stdi->lcf + 1) 1432a89bcd4cSHans Verkuil continue; 1433a89bcd4cSHans Verkuil if (bt->vsync != stdi->lcvs) 1434a89bcd4cSHans Verkuil continue; 1435a89bcd4cSHans Verkuil 1436a89bcd4cSHans Verkuil pix_clk = hfreq * htotal(bt); 1437a89bcd4cSHans Verkuil 1438a89bcd4cSHans Verkuil if ((pix_clk < bt->pixelclock + 1000000) && 1439a89bcd4cSHans Verkuil (pix_clk > bt->pixelclock - 1000000)) { 1440a89bcd4cSHans Verkuil *timings = v4l2_dv_timings_presets[i]; 1441a89bcd4cSHans Verkuil return 0; 1442a89bcd4cSHans Verkuil } 1443a89bcd4cSHans Verkuil } 1444a89bcd4cSHans Verkuil 14455fea1bb7SPrashant Laddha if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs, 0, 1446a89bcd4cSHans Verkuil (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) | 1447a89bcd4cSHans Verkuil (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0), 1448061ddda6SPrashant Laddha false, timings)) 1449a89bcd4cSHans Verkuil return 0; 1450a89bcd4cSHans Verkuil if (v4l2_detect_gtf(stdi->lcf + 1, hfreq, stdi->lcvs, 1451a89bcd4cSHans Verkuil (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) | 1452a89bcd4cSHans Verkuil (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0), 1453061ddda6SPrashant Laddha false, state->aspect_ratio, timings)) 1454a89bcd4cSHans Verkuil return 0; 1455a89bcd4cSHans Verkuil 1456a89bcd4cSHans Verkuil v4l2_dbg(2, debug, sd, 1457a89bcd4cSHans Verkuil "%s: No format candidate found for lcvs = %d, lcf=%d, bl = %d, %chsync, %cvsync\n", 1458a89bcd4cSHans Verkuil __func__, stdi->lcvs, stdi->lcf, stdi->bl, 1459a89bcd4cSHans Verkuil stdi->hs_pol, stdi->vs_pol); 1460a89bcd4cSHans Verkuil return -1; 1461a89bcd4cSHans Verkuil } 1462a89bcd4cSHans Verkuil 1463a89bcd4cSHans Verkuil static int read_stdi(struct v4l2_subdev *sd, struct stdi_readback *stdi) 1464a89bcd4cSHans Verkuil { 1465a89bcd4cSHans Verkuil u32 status; 1466a89bcd4cSHans Verkuil 1467a89bcd4cSHans Verkuil adv7842_g_input_status(sd, &status); 1468a89bcd4cSHans Verkuil if (status & V4L2_IN_ST_NO_SIGNAL) { 1469a89bcd4cSHans Verkuil v4l2_dbg(2, debug, sd, "%s: no signal\n", __func__); 1470a89bcd4cSHans Verkuil return -ENOLINK; 1471a89bcd4cSHans Verkuil } 1472a89bcd4cSHans Verkuil 1473a89bcd4cSHans Verkuil stdi->bl = ((cp_read(sd, 0xb1) & 0x3f) << 8) | cp_read(sd, 0xb2); 1474a89bcd4cSHans Verkuil stdi->lcf = ((cp_read(sd, 0xb3) & 0x7) << 8) | cp_read(sd, 0xb4); 1475a89bcd4cSHans Verkuil stdi->lcvs = cp_read(sd, 0xb3) >> 3; 1476a89bcd4cSHans Verkuil 1477a89bcd4cSHans Verkuil if ((cp_read(sd, 0xb5) & 0x80) && ((cp_read(sd, 0xb5) & 0x03) == 0x01)) { 1478a89bcd4cSHans Verkuil stdi->hs_pol = ((cp_read(sd, 0xb5) & 0x10) ? 1479a89bcd4cSHans Verkuil ((cp_read(sd, 0xb5) & 0x08) ? '+' : '-') : 'x'); 1480a89bcd4cSHans Verkuil stdi->vs_pol = ((cp_read(sd, 0xb5) & 0x40) ? 1481a89bcd4cSHans Verkuil ((cp_read(sd, 0xb5) & 0x20) ? '+' : '-') : 'x'); 1482a89bcd4cSHans Verkuil } else { 1483a89bcd4cSHans Verkuil stdi->hs_pol = 'x'; 1484a89bcd4cSHans Verkuil stdi->vs_pol = 'x'; 1485a89bcd4cSHans Verkuil } 1486a89bcd4cSHans Verkuil stdi->interlaced = (cp_read(sd, 0xb1) & 0x40) ? true : false; 1487a89bcd4cSHans Verkuil 1488a89bcd4cSHans Verkuil if (stdi->lcf < 239 || stdi->bl < 8 || stdi->bl == 0x3fff) { 1489a89bcd4cSHans Verkuil v4l2_dbg(2, debug, sd, "%s: invalid signal\n", __func__); 1490a89bcd4cSHans Verkuil return -ENOLINK; 1491a89bcd4cSHans Verkuil } 1492a89bcd4cSHans Verkuil 1493a89bcd4cSHans Verkuil v4l2_dbg(2, debug, sd, 1494a89bcd4cSHans Verkuil "%s: lcf (frame height - 1) = %d, bl = %d, lcvs (vsync) = %d, %chsync, %cvsync, %s\n", 1495a89bcd4cSHans Verkuil __func__, stdi->lcf, stdi->bl, stdi->lcvs, 1496a89bcd4cSHans Verkuil stdi->hs_pol, stdi->vs_pol, 1497a89bcd4cSHans Verkuil stdi->interlaced ? "interlaced" : "progressive"); 1498a89bcd4cSHans Verkuil 1499a89bcd4cSHans Verkuil return 0; 1500a89bcd4cSHans Verkuil } 1501a89bcd4cSHans Verkuil 1502a89bcd4cSHans Verkuil static int adv7842_enum_dv_timings(struct v4l2_subdev *sd, 1503a89bcd4cSHans Verkuil struct v4l2_enum_dv_timings *timings) 1504a89bcd4cSHans Verkuil { 1505c916194cSLaurent Pinchart if (timings->pad != 0) 1506c916194cSLaurent Pinchart return -EINVAL; 1507c916194cSLaurent Pinchart 1508a89bcd4cSHans Verkuil return v4l2_enum_dv_timings_cap(timings, 1509a89bcd4cSHans Verkuil adv7842_get_dv_timings_cap(sd), adv7842_check_dv_timings, NULL); 1510a89bcd4cSHans Verkuil } 1511a89bcd4cSHans Verkuil 1512a89bcd4cSHans Verkuil static int adv7842_dv_timings_cap(struct v4l2_subdev *sd, 1513a89bcd4cSHans Verkuil struct v4l2_dv_timings_cap *cap) 1514a89bcd4cSHans Verkuil { 1515c916194cSLaurent Pinchart if (cap->pad != 0) 1516c916194cSLaurent Pinchart return -EINVAL; 1517c916194cSLaurent Pinchart 1518a89bcd4cSHans Verkuil *cap = *adv7842_get_dv_timings_cap(sd); 1519a89bcd4cSHans Verkuil return 0; 1520a89bcd4cSHans Verkuil } 1521a89bcd4cSHans Verkuil 1522a89bcd4cSHans Verkuil /* Fill the optional fields .standards and .flags in struct v4l2_dv_timings 152369e9ba6fSHans Verkuil if the format is listed in adv7842_timings[] */ 1524a89bcd4cSHans Verkuil static void adv7842_fill_optional_dv_timings_fields(struct v4l2_subdev *sd, 1525a89bcd4cSHans Verkuil struct v4l2_dv_timings *timings) 1526a89bcd4cSHans Verkuil { 1527a89bcd4cSHans Verkuil v4l2_find_dv_timings_cap(timings, adv7842_get_dv_timings_cap(sd), 1528a89bcd4cSHans Verkuil is_digital_input(sd) ? 250000 : 1000000, 1529a89bcd4cSHans Verkuil adv7842_check_dv_timings, NULL); 1530d842a7cfSHans Verkuil timings->bt.flags |= V4L2_DV_FL_CAN_DETECT_REDUCED_FPS; 1531a89bcd4cSHans Verkuil } 1532a89bcd4cSHans Verkuil 1533a89bcd4cSHans Verkuil static int adv7842_query_dv_timings(struct v4l2_subdev *sd, 1534a89bcd4cSHans Verkuil struct v4l2_dv_timings *timings) 1535a89bcd4cSHans Verkuil { 1536a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 1537a89bcd4cSHans Verkuil struct v4l2_bt_timings *bt = &timings->bt; 1538a89bcd4cSHans Verkuil struct stdi_readback stdi = { 0 }; 1539a89bcd4cSHans Verkuil 1540e78d834aSMartin Bugge v4l2_dbg(1, debug, sd, "%s:\n", __func__); 1541e78d834aSMartin Bugge 1542f8789e6dSHans Verkuil memset(timings, 0, sizeof(struct v4l2_dv_timings)); 1543f8789e6dSHans Verkuil 1544a89bcd4cSHans Verkuil /* SDP block */ 1545a89bcd4cSHans Verkuil if (state->mode == ADV7842_MODE_SDP) 1546a89bcd4cSHans Verkuil return -ENODATA; 1547a89bcd4cSHans Verkuil 1548a89bcd4cSHans Verkuil /* read STDI */ 1549a89bcd4cSHans Verkuil if (read_stdi(sd, &stdi)) { 15506e9071f2SMartin Bugge state->restart_stdi_once = true; 1551a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, "%s: no valid signal\n", __func__); 1552a89bcd4cSHans Verkuil return -ENOLINK; 1553a89bcd4cSHans Verkuil } 1554a89bcd4cSHans Verkuil bt->interlaced = stdi.interlaced ? 1555a89bcd4cSHans Verkuil V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE; 1556f888ae7eSHans Verkuil bt->standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | 1557f888ae7eSHans Verkuil V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT; 1558a89bcd4cSHans Verkuil 1559a89bcd4cSHans Verkuil if (is_digital_input(sd)) { 156028a769f1SHans Verkuil u32 freq; 1561e78d834aSMartin Bugge 1562e78d834aSMartin Bugge timings->type = V4L2_DV_BT_656_1120; 15636e9071f2SMartin Bugge 1564e78d834aSMartin Bugge bt->width = (hdmi_read(sd, 0x07) & 0x0f) * 256 + hdmi_read(sd, 0x08); 1565e78d834aSMartin Bugge bt->height = (hdmi_read(sd, 0x09) & 0x0f) * 256 + hdmi_read(sd, 0x0a); 156681ba0a4eSMartin Bugge freq = ((hdmi_read(sd, 0x51) << 1) + (hdmi_read(sd, 0x52) >> 7)) * 1000000; 156781ba0a4eSMartin Bugge freq += ((hdmi_read(sd, 0x52) & 0x7f) * 7813); 1568a89bcd4cSHans Verkuil if (is_hdmi(sd)) { 1569a89bcd4cSHans Verkuil /* adjust for deep color mode */ 157081ba0a4eSMartin Bugge freq = freq * 8 / (((hdmi_read(sd, 0x0b) & 0xc0) >> 6) * 2 + 8); 1571a89bcd4cSHans Verkuil } 1572e78d834aSMartin Bugge bt->pixelclock = freq; 1573e78d834aSMartin Bugge bt->hfrontporch = (hdmi_read(sd, 0x20) & 0x03) * 256 + 1574a89bcd4cSHans Verkuil hdmi_read(sd, 0x21); 1575e78d834aSMartin Bugge bt->hsync = (hdmi_read(sd, 0x22) & 0x03) * 256 + 1576a89bcd4cSHans Verkuil hdmi_read(sd, 0x23); 1577e78d834aSMartin Bugge bt->hbackporch = (hdmi_read(sd, 0x24) & 0x03) * 256 + 1578a89bcd4cSHans Verkuil hdmi_read(sd, 0x25); 1579e78d834aSMartin Bugge bt->vfrontporch = ((hdmi_read(sd, 0x2a) & 0x1f) * 256 + 1580a89bcd4cSHans Verkuil hdmi_read(sd, 0x2b)) / 2; 1581e78d834aSMartin Bugge bt->vsync = ((hdmi_read(sd, 0x2e) & 0x1f) * 256 + 1582a89bcd4cSHans Verkuil hdmi_read(sd, 0x2f)) / 2; 1583e78d834aSMartin Bugge bt->vbackporch = ((hdmi_read(sd, 0x32) & 0x1f) * 256 + 1584a89bcd4cSHans Verkuil hdmi_read(sd, 0x33)) / 2; 1585e78d834aSMartin Bugge bt->polarities = ((hdmi_read(sd, 0x05) & 0x10) ? V4L2_DV_VSYNC_POS_POL : 0) | 1586e78d834aSMartin Bugge ((hdmi_read(sd, 0x05) & 0x20) ? V4L2_DV_HSYNC_POS_POL : 0); 1587e78d834aSMartin Bugge if (bt->interlaced == V4L2_DV_INTERLACED) { 1588e78d834aSMartin Bugge bt->height += (hdmi_read(sd, 0x0b) & 0x0f) * 256 + 1589e78d834aSMartin Bugge hdmi_read(sd, 0x0c); 1590e78d834aSMartin Bugge bt->il_vfrontporch = ((hdmi_read(sd, 0x2c) & 0x1f) * 256 + 1591e78d834aSMartin Bugge hdmi_read(sd, 0x2d)) / 2; 1592e78d834aSMartin Bugge bt->il_vsync = ((hdmi_read(sd, 0x30) & 0x1f) * 256 + 1593e78d834aSMartin Bugge hdmi_read(sd, 0x31)) / 2; 1594f8789e6dSHans Verkuil bt->il_vbackporch = ((hdmi_read(sd, 0x34) & 0x1f) * 256 + 1595a89bcd4cSHans Verkuil hdmi_read(sd, 0x35)) / 2; 1596f888ae7eSHans Verkuil } else { 1597f888ae7eSHans Verkuil bt->il_vfrontporch = 0; 1598f888ae7eSHans Verkuil bt->il_vsync = 0; 1599f888ae7eSHans Verkuil bt->il_vbackporch = 0; 1600e78d834aSMartin Bugge } 1601e78d834aSMartin Bugge adv7842_fill_optional_dv_timings_fields(sd, timings); 1602d842a7cfSHans Verkuil if ((timings->bt.flags & V4L2_DV_FL_CAN_REDUCE_FPS) && 1603d842a7cfSHans Verkuil freq < bt->pixelclock) { 1604d842a7cfSHans Verkuil u32 reduced_freq = ((u32)bt->pixelclock / 1001) * 1000; 1605d842a7cfSHans Verkuil u32 delta_freq = abs(freq - reduced_freq); 1606d842a7cfSHans Verkuil 1607d842a7cfSHans Verkuil if (delta_freq < ((u32)bt->pixelclock - reduced_freq) / 2) 1608d842a7cfSHans Verkuil timings->bt.flags |= V4L2_DV_FL_REDUCED_FPS; 1609d842a7cfSHans Verkuil } 1610a89bcd4cSHans Verkuil } else { 16116e9071f2SMartin Bugge /* find format 16126e9071f2SMartin Bugge * Since LCVS values are inaccurate [REF_03, p. 339-340], 16136e9071f2SMartin Bugge * stdi2dv_timings() is called with lcvs +-1 if the first attempt fails. 16146e9071f2SMartin Bugge */ 16156e9071f2SMartin Bugge if (!stdi2dv_timings(sd, &stdi, timings)) 16166e9071f2SMartin Bugge goto found; 16176e9071f2SMartin Bugge stdi.lcvs += 1; 16186e9071f2SMartin Bugge v4l2_dbg(1, debug, sd, "%s: lcvs + 1 = %d\n", __func__, stdi.lcvs); 16196e9071f2SMartin Bugge if (!stdi2dv_timings(sd, &stdi, timings)) 16206e9071f2SMartin Bugge goto found; 16216e9071f2SMartin Bugge stdi.lcvs -= 2; 16226e9071f2SMartin Bugge v4l2_dbg(1, debug, sd, "%s: lcvs - 1 = %d\n", __func__, stdi.lcvs); 1623a89bcd4cSHans Verkuil if (stdi2dv_timings(sd, &stdi, timings)) { 16246e9071f2SMartin Bugge /* 16256e9071f2SMartin Bugge * The STDI block may measure wrong values, especially 16266e9071f2SMartin Bugge * for lcvs and lcf. If the driver can not find any 16276e9071f2SMartin Bugge * valid timing, the STDI block is restarted to measure 16286e9071f2SMartin Bugge * the video timings again. The function will return an 16296e9071f2SMartin Bugge * error, but the restart of STDI will generate a new 16306e9071f2SMartin Bugge * STDI interrupt and the format detection process will 16316e9071f2SMartin Bugge * restart. 16326e9071f2SMartin Bugge */ 16336e9071f2SMartin Bugge if (state->restart_stdi_once) { 16346e9071f2SMartin Bugge v4l2_dbg(1, debug, sd, "%s: restart STDI\n", __func__); 16356e9071f2SMartin Bugge /* TODO restart STDI for Sync Channel 2 */ 16366e9071f2SMartin Bugge /* enter one-shot mode */ 16376e9071f2SMartin Bugge cp_write_and_or(sd, 0x86, 0xf9, 0x00); 16386e9071f2SMartin Bugge /* trigger STDI restart */ 16396e9071f2SMartin Bugge cp_write_and_or(sd, 0x86, 0xf9, 0x04); 16406e9071f2SMartin Bugge /* reset to continuous mode */ 16416e9071f2SMartin Bugge cp_write_and_or(sd, 0x86, 0xf9, 0x02); 16426e9071f2SMartin Bugge state->restart_stdi_once = false; 16436e9071f2SMartin Bugge return -ENOLINK; 16446e9071f2SMartin Bugge } 1645a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, "%s: format not supported\n", __func__); 1646a89bcd4cSHans Verkuil return -ERANGE; 1647a89bcd4cSHans Verkuil } 16486e9071f2SMartin Bugge state->restart_stdi_once = true; 1649a89bcd4cSHans Verkuil } 16506e9071f2SMartin Bugge found: 1651a89bcd4cSHans Verkuil 1652a89bcd4cSHans Verkuil if (debug > 1) 1653a89bcd4cSHans Verkuil v4l2_print_dv_timings(sd->name, "adv7842_query_dv_timings:", 1654a89bcd4cSHans Verkuil timings, true); 1655a89bcd4cSHans Verkuil return 0; 1656a89bcd4cSHans Verkuil } 1657a89bcd4cSHans Verkuil 1658a89bcd4cSHans Verkuil static int adv7842_s_dv_timings(struct v4l2_subdev *sd, 1659a89bcd4cSHans Verkuil struct v4l2_dv_timings *timings) 1660a89bcd4cSHans Verkuil { 1661a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 1662a89bcd4cSHans Verkuil struct v4l2_bt_timings *bt; 1663a89bcd4cSHans Verkuil int err; 1664a89bcd4cSHans Verkuil 1665e78d834aSMartin Bugge v4l2_dbg(1, debug, sd, "%s:\n", __func__); 1666e78d834aSMartin Bugge 1667a89bcd4cSHans Verkuil if (state->mode == ADV7842_MODE_SDP) 1668a89bcd4cSHans Verkuil return -ENODATA; 1669a89bcd4cSHans Verkuil 167085f9e06cSHans Verkuil if (v4l2_match_dv_timings(&state->timings, timings, 0, false)) { 1671834a8be1SMartin Bugge v4l2_dbg(1, debug, sd, "%s: no change\n", __func__); 1672834a8be1SMartin Bugge return 0; 1673834a8be1SMartin Bugge } 1674834a8be1SMartin Bugge 1675a89bcd4cSHans Verkuil bt = &timings->bt; 1676a89bcd4cSHans Verkuil 1677a89bcd4cSHans Verkuil if (!v4l2_valid_dv_timings(timings, adv7842_get_dv_timings_cap(sd), 1678a89bcd4cSHans Verkuil adv7842_check_dv_timings, NULL)) 1679a89bcd4cSHans Verkuil return -ERANGE; 1680a89bcd4cSHans Verkuil 1681a89bcd4cSHans Verkuil adv7842_fill_optional_dv_timings_fields(sd, timings); 1682a89bcd4cSHans Verkuil 1683a89bcd4cSHans Verkuil state->timings = *timings; 1684a89bcd4cSHans Verkuil 16856251e65fSMartin Bugge cp_write(sd, 0x91, bt->interlaced ? 0x40 : 0x00); 1686a89bcd4cSHans Verkuil 1687a89bcd4cSHans Verkuil /* Use prim_mode and vid_std when available */ 1688a89bcd4cSHans Verkuil err = configure_predefined_video_timings(sd, timings); 1689a89bcd4cSHans Verkuil if (err) { 1690a89bcd4cSHans Verkuil /* custom settings when the video format 1691a89bcd4cSHans Verkuil does not have prim_mode/vid_std */ 1692a89bcd4cSHans Verkuil configure_custom_video_timings(sd, bt); 1693a89bcd4cSHans Verkuil } 1694a89bcd4cSHans Verkuil 1695a89bcd4cSHans Verkuil set_rgb_quantization_range(sd); 1696a89bcd4cSHans Verkuil 1697a89bcd4cSHans Verkuil 1698a89bcd4cSHans Verkuil if (debug > 1) 1699a89bcd4cSHans Verkuil v4l2_print_dv_timings(sd->name, "adv7842_s_dv_timings: ", 1700a89bcd4cSHans Verkuil timings, true); 1701a89bcd4cSHans Verkuil return 0; 1702a89bcd4cSHans Verkuil } 1703a89bcd4cSHans Verkuil 1704a89bcd4cSHans Verkuil static int adv7842_g_dv_timings(struct v4l2_subdev *sd, 1705a89bcd4cSHans Verkuil struct v4l2_dv_timings *timings) 1706a89bcd4cSHans Verkuil { 1707a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 1708a89bcd4cSHans Verkuil 1709a89bcd4cSHans Verkuil if (state->mode == ADV7842_MODE_SDP) 1710a89bcd4cSHans Verkuil return -ENODATA; 1711a89bcd4cSHans Verkuil *timings = state->timings; 1712a89bcd4cSHans Verkuil return 0; 1713a89bcd4cSHans Verkuil } 1714a89bcd4cSHans Verkuil 1715a89bcd4cSHans Verkuil static void enable_input(struct v4l2_subdev *sd) 1716a89bcd4cSHans Verkuil { 1717a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 171869e9ba6fSHans Verkuil 171969e9ba6fSHans Verkuil set_rgb_quantization_range(sd); 1720a89bcd4cSHans Verkuil switch (state->mode) { 1721a89bcd4cSHans Verkuil case ADV7842_MODE_SDP: 1722a89bcd4cSHans Verkuil case ADV7842_MODE_COMP: 1723a89bcd4cSHans Verkuil case ADV7842_MODE_RGB: 1724a89bcd4cSHans Verkuil io_write(sd, 0x15, 0xb0); /* Disable Tristate of Pins (no audio) */ 1725a89bcd4cSHans Verkuil break; 1726a89bcd4cSHans Verkuil case ADV7842_MODE_HDMI: 1727a89bcd4cSHans Verkuil hdmi_write(sd, 0x01, 0x00); /* Enable HDMI clock terminators */ 1728a89bcd4cSHans Verkuil io_write(sd, 0x15, 0xa0); /* Disable Tristate of Pins */ 17295b64b205SMats Randgaard hdmi_write_and_or(sd, 0x1a, 0xef, 0x00); /* Unmute audio */ 1730a89bcd4cSHans Verkuil break; 1731a89bcd4cSHans Verkuil default: 1732a89bcd4cSHans Verkuil v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", 1733a89bcd4cSHans Verkuil __func__, state->mode); 1734a89bcd4cSHans Verkuil break; 1735a89bcd4cSHans Verkuil } 1736a89bcd4cSHans Verkuil } 1737a89bcd4cSHans Verkuil 1738a89bcd4cSHans Verkuil static void disable_input(struct v4l2_subdev *sd) 1739a89bcd4cSHans Verkuil { 17405b64b205SMats Randgaard hdmi_write_and_or(sd, 0x1a, 0xef, 0x10); /* Mute audio [REF_01, c. 2.2.2] */ 17415b64b205SMats Randgaard msleep(16); /* 512 samples with >= 32 kHz sample rate [REF_03, c. 8.29] */ 1742a89bcd4cSHans Verkuil io_write(sd, 0x15, 0xbe); /* Tristate all outputs from video core */ 1743a89bcd4cSHans Verkuil hdmi_write(sd, 0x01, 0x78); /* Disable HDMI clock terminators */ 1744a89bcd4cSHans Verkuil } 1745a89bcd4cSHans Verkuil 1746a89bcd4cSHans Verkuil static void sdp_csc_coeff(struct v4l2_subdev *sd, 1747a89bcd4cSHans Verkuil const struct adv7842_sdp_csc_coeff *c) 1748a89bcd4cSHans Verkuil { 1749a89bcd4cSHans Verkuil /* csc auto/manual */ 1750a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xe0, 0xbf, c->manual ? 0x00 : 0x40); 1751a89bcd4cSHans Verkuil 1752a89bcd4cSHans Verkuil if (!c->manual) 1753a89bcd4cSHans Verkuil return; 1754a89bcd4cSHans Verkuil 1755a89bcd4cSHans Verkuil /* csc scaling */ 1756a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xe0, 0x7f, c->scaling == 2 ? 0x80 : 0x00); 1757a89bcd4cSHans Verkuil 1758a89bcd4cSHans Verkuil /* A coeff */ 1759a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xe0, 0xe0, c->A1 >> 8); 1760a89bcd4cSHans Verkuil sdp_io_write(sd, 0xe1, c->A1); 1761a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xe2, 0xe0, c->A2 >> 8); 1762a89bcd4cSHans Verkuil sdp_io_write(sd, 0xe3, c->A2); 1763a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xe4, 0xe0, c->A3 >> 8); 1764a89bcd4cSHans Verkuil sdp_io_write(sd, 0xe5, c->A3); 1765a89bcd4cSHans Verkuil 1766a89bcd4cSHans Verkuil /* A scale */ 1767a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xe6, 0x80, c->A4 >> 8); 1768a89bcd4cSHans Verkuil sdp_io_write(sd, 0xe7, c->A4); 1769a89bcd4cSHans Verkuil 1770a89bcd4cSHans Verkuil /* B coeff */ 1771a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xe8, 0xe0, c->B1 >> 8); 1772a89bcd4cSHans Verkuil sdp_io_write(sd, 0xe9, c->B1); 1773a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xea, 0xe0, c->B2 >> 8); 1774a89bcd4cSHans Verkuil sdp_io_write(sd, 0xeb, c->B2); 1775a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xec, 0xe0, c->B3 >> 8); 1776a89bcd4cSHans Verkuil sdp_io_write(sd, 0xed, c->B3); 1777a89bcd4cSHans Verkuil 1778a89bcd4cSHans Verkuil /* B scale */ 1779a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xee, 0x80, c->B4 >> 8); 1780a89bcd4cSHans Verkuil sdp_io_write(sd, 0xef, c->B4); 1781a89bcd4cSHans Verkuil 1782a89bcd4cSHans Verkuil /* C coeff */ 1783a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xf0, 0xe0, c->C1 >> 8); 1784a89bcd4cSHans Verkuil sdp_io_write(sd, 0xf1, c->C1); 1785a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xf2, 0xe0, c->C2 >> 8); 1786a89bcd4cSHans Verkuil sdp_io_write(sd, 0xf3, c->C2); 1787a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xf4, 0xe0, c->C3 >> 8); 1788a89bcd4cSHans Verkuil sdp_io_write(sd, 0xf5, c->C3); 1789a89bcd4cSHans Verkuil 1790a89bcd4cSHans Verkuil /* C scale */ 1791a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xf6, 0x80, c->C4 >> 8); 1792a89bcd4cSHans Verkuil sdp_io_write(sd, 0xf7, c->C4); 1793a89bcd4cSHans Verkuil } 1794a89bcd4cSHans Verkuil 1795a89bcd4cSHans Verkuil static void select_input(struct v4l2_subdev *sd, 1796a89bcd4cSHans Verkuil enum adv7842_vid_std_select vid_std_select) 1797a89bcd4cSHans Verkuil { 1798a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 1799a89bcd4cSHans Verkuil 1800a89bcd4cSHans Verkuil switch (state->mode) { 1801a89bcd4cSHans Verkuil case ADV7842_MODE_SDP: 1802a89bcd4cSHans Verkuil io_write(sd, 0x00, vid_std_select); /* video std: CVBS or YC mode */ 1803a89bcd4cSHans Verkuil io_write(sd, 0x01, 0); /* prim mode */ 1804a89bcd4cSHans Verkuil /* enable embedded syncs for auto graphics mode */ 1805a89bcd4cSHans Verkuil cp_write_and_or(sd, 0x81, 0xef, 0x10); 1806a89bcd4cSHans Verkuil 1807a89bcd4cSHans Verkuil afe_write(sd, 0x00, 0x00); /* power up ADC */ 1808a89bcd4cSHans Verkuil afe_write(sd, 0xc8, 0x00); /* phase control */ 1809a89bcd4cSHans Verkuil 1810a89bcd4cSHans Verkuil io_write(sd, 0xdd, 0x90); /* Manual 2x output clock */ 1811a89bcd4cSHans Verkuil /* script says register 0xde, which don't exist in manual */ 1812a89bcd4cSHans Verkuil 1813a89bcd4cSHans Verkuil /* Manual analog input muxing mode, CVBS (6.4)*/ 1814a89bcd4cSHans Verkuil afe_write_and_or(sd, 0x02, 0x7f, 0x80); 1815a89bcd4cSHans Verkuil if (vid_std_select == ADV7842_SDP_VID_STD_CVBS_SD_4x1) { 1816a89bcd4cSHans Verkuil afe_write(sd, 0x03, 0xa0); /* ADC0 to AIN10 (CVBS), ADC1 N/C*/ 1817a89bcd4cSHans Verkuil afe_write(sd, 0x04, 0x00); /* ADC2 N/C,ADC3 N/C*/ 1818a89bcd4cSHans Verkuil } else { 1819a89bcd4cSHans Verkuil afe_write(sd, 0x03, 0xa0); /* ADC0 to AIN10 (CVBS), ADC1 N/C*/ 1820a89bcd4cSHans Verkuil afe_write(sd, 0x04, 0xc0); /* ADC2 to AIN12, ADC3 N/C*/ 1821a89bcd4cSHans Verkuil } 1822a89bcd4cSHans Verkuil afe_write(sd, 0x0c, 0x1f); /* ADI recommend write */ 1823a89bcd4cSHans Verkuil afe_write(sd, 0x12, 0x63); /* ADI recommend write */ 1824a89bcd4cSHans Verkuil 1825a89bcd4cSHans Verkuil sdp_io_write(sd, 0xb2, 0x60); /* Disable AV codes */ 1826a89bcd4cSHans Verkuil sdp_io_write(sd, 0xc8, 0xe3); /* Disable Ancillary data */ 1827a89bcd4cSHans Verkuil 1828a89bcd4cSHans Verkuil /* SDP recommended settings */ 1829a89bcd4cSHans Verkuil sdp_write(sd, 0x00, 0x3F); /* Autodetect PAL NTSC (not SECAM) */ 1830a89bcd4cSHans Verkuil sdp_write(sd, 0x01, 0x00); /* Pedestal Off */ 1831a89bcd4cSHans Verkuil 1832a89bcd4cSHans Verkuil sdp_write(sd, 0x03, 0xE4); /* Manual VCR Gain Luma 0x40B */ 1833a89bcd4cSHans Verkuil sdp_write(sd, 0x04, 0x0B); /* Manual Luma setting */ 1834a89bcd4cSHans Verkuil sdp_write(sd, 0x05, 0xC3); /* Manual Chroma setting 0x3FE */ 1835a89bcd4cSHans Verkuil sdp_write(sd, 0x06, 0xFE); /* Manual Chroma setting */ 1836a89bcd4cSHans Verkuil sdp_write(sd, 0x12, 0x0D); /* Frame TBC,I_P, 3D comb enabled */ 1837a89bcd4cSHans Verkuil sdp_write(sd, 0xA7, 0x00); /* ADI Recommended Write */ 1838a89bcd4cSHans Verkuil sdp_io_write(sd, 0xB0, 0x00); /* Disable H and v blanking */ 1839a89bcd4cSHans Verkuil 1840a89bcd4cSHans Verkuil /* deinterlacer enabled and 3D comb */ 1841a89bcd4cSHans Verkuil sdp_write_and_or(sd, 0x12, 0xf6, 0x09); 1842a89bcd4cSHans Verkuil 1843a89bcd4cSHans Verkuil break; 1844a89bcd4cSHans Verkuil 1845a89bcd4cSHans Verkuil case ADV7842_MODE_COMP: 1846a89bcd4cSHans Verkuil case ADV7842_MODE_RGB: 1847a89bcd4cSHans Verkuil /* Automatic analog input muxing mode */ 1848a89bcd4cSHans Verkuil afe_write_and_or(sd, 0x02, 0x7f, 0x00); 1849a89bcd4cSHans Verkuil /* set mode and select free run resolution */ 1850a89bcd4cSHans Verkuil io_write(sd, 0x00, vid_std_select); /* video std */ 1851a89bcd4cSHans Verkuil io_write(sd, 0x01, 0x02); /* prim mode */ 1852a89bcd4cSHans Verkuil cp_write_and_or(sd, 0x81, 0xef, 0x10); /* enable embedded syncs 1853a89bcd4cSHans Verkuil for auto graphics mode */ 1854a89bcd4cSHans Verkuil 1855a89bcd4cSHans Verkuil afe_write(sd, 0x00, 0x00); /* power up ADC */ 1856a89bcd4cSHans Verkuil afe_write(sd, 0xc8, 0x00); /* phase control */ 185769e9ba6fSHans Verkuil if (state->mode == ADV7842_MODE_COMP) { 185869e9ba6fSHans Verkuil /* force to YCrCb */ 185969e9ba6fSHans Verkuil io_write_and_or(sd, 0x02, 0x0f, 0x60); 186069e9ba6fSHans Verkuil } else { 186169e9ba6fSHans Verkuil /* force to RGB */ 186269e9ba6fSHans Verkuil io_write_and_or(sd, 0x02, 0x0f, 0x10); 186369e9ba6fSHans Verkuil } 1864a89bcd4cSHans Verkuil 1865a89bcd4cSHans Verkuil /* set ADI recommended settings for digitizer */ 1866a89bcd4cSHans Verkuil /* "ADV7842 Register Settings Recommendations 1867a89bcd4cSHans Verkuil * (rev. 1.8, November 2010)" p. 9. */ 1868a89bcd4cSHans Verkuil afe_write(sd, 0x0c, 0x1f); /* ADC Range improvement */ 1869a89bcd4cSHans Verkuil afe_write(sd, 0x12, 0x63); /* ADC Range improvement */ 1870a89bcd4cSHans Verkuil 1871a89bcd4cSHans Verkuil /* set to default gain for RGB */ 1872a89bcd4cSHans Verkuil cp_write(sd, 0x73, 0x10); 1873a89bcd4cSHans Verkuil cp_write(sd, 0x74, 0x04); 1874a89bcd4cSHans Verkuil cp_write(sd, 0x75, 0x01); 1875a89bcd4cSHans Verkuil cp_write(sd, 0x76, 0x00); 1876a89bcd4cSHans Verkuil 1877a89bcd4cSHans Verkuil cp_write(sd, 0x3e, 0x04); /* CP core pre-gain control */ 1878a89bcd4cSHans Verkuil cp_write(sd, 0xc3, 0x39); /* CP coast control. Graphics mode */ 1879a89bcd4cSHans Verkuil cp_write(sd, 0x40, 0x5c); /* CP core pre-gain control. Graphics mode */ 1880a89bcd4cSHans Verkuil break; 1881a89bcd4cSHans Verkuil 1882a89bcd4cSHans Verkuil case ADV7842_MODE_HDMI: 1883a89bcd4cSHans Verkuil /* Automatic analog input muxing mode */ 1884a89bcd4cSHans Verkuil afe_write_and_or(sd, 0x02, 0x7f, 0x00); 1885a89bcd4cSHans Verkuil /* set mode and select free run resolution */ 1886a89bcd4cSHans Verkuil if (state->hdmi_port_a) 1887a89bcd4cSHans Verkuil hdmi_write(sd, 0x00, 0x02); /* select port A */ 1888a89bcd4cSHans Verkuil else 1889a89bcd4cSHans Verkuil hdmi_write(sd, 0x00, 0x03); /* select port B */ 1890a89bcd4cSHans Verkuil io_write(sd, 0x00, vid_std_select); /* video std */ 1891a89bcd4cSHans Verkuil io_write(sd, 0x01, 5); /* prim mode */ 1892a89bcd4cSHans Verkuil cp_write_and_or(sd, 0x81, 0xef, 0x00); /* disable embedded syncs 1893a89bcd4cSHans Verkuil for auto graphics mode */ 1894a89bcd4cSHans Verkuil 1895a89bcd4cSHans Verkuil /* set ADI recommended settings for HDMI: */ 1896a89bcd4cSHans Verkuil /* "ADV7842 Register Settings Recommendations 1897a89bcd4cSHans Verkuil * (rev. 1.8, November 2010)" p. 3. */ 1898a89bcd4cSHans Verkuil hdmi_write(sd, 0xc0, 0x00); 1899a89bcd4cSHans Verkuil hdmi_write(sd, 0x0d, 0x34); /* ADI recommended write */ 1900a89bcd4cSHans Verkuil hdmi_write(sd, 0x3d, 0x10); /* ADI recommended write */ 1901a89bcd4cSHans Verkuil hdmi_write(sd, 0x44, 0x85); /* TMDS PLL optimization */ 1902a89bcd4cSHans Verkuil hdmi_write(sd, 0x46, 0x1f); /* ADI recommended write */ 1903a89bcd4cSHans Verkuil hdmi_write(sd, 0x57, 0xb6); /* TMDS PLL optimization */ 1904a89bcd4cSHans Verkuil hdmi_write(sd, 0x58, 0x03); /* TMDS PLL optimization */ 1905a89bcd4cSHans Verkuil hdmi_write(sd, 0x60, 0x88); /* TMDS PLL optimization */ 1906a89bcd4cSHans Verkuil hdmi_write(sd, 0x61, 0x88); /* TMDS PLL optimization */ 1907a89bcd4cSHans Verkuil hdmi_write(sd, 0x6c, 0x18); /* Disable ISRC clearing bit, 1908a89bcd4cSHans Verkuil Improve robustness */ 1909a89bcd4cSHans Verkuil hdmi_write(sd, 0x75, 0x10); /* DDC drive strength */ 1910a89bcd4cSHans Verkuil hdmi_write(sd, 0x85, 0x1f); /* equaliser */ 1911a89bcd4cSHans Verkuil hdmi_write(sd, 0x87, 0x70); /* ADI recommended write */ 1912a89bcd4cSHans Verkuil hdmi_write(sd, 0x89, 0x04); /* equaliser */ 1913a89bcd4cSHans Verkuil hdmi_write(sd, 0x8a, 0x1e); /* equaliser */ 1914a89bcd4cSHans Verkuil hdmi_write(sd, 0x93, 0x04); /* equaliser */ 1915a89bcd4cSHans Verkuil hdmi_write(sd, 0x94, 0x1e); /* equaliser */ 1916a89bcd4cSHans Verkuil hdmi_write(sd, 0x99, 0xa1); /* ADI recommended write */ 1917a89bcd4cSHans Verkuil hdmi_write(sd, 0x9b, 0x09); /* ADI recommended write */ 1918a89bcd4cSHans Verkuil hdmi_write(sd, 0x9d, 0x02); /* equaliser */ 1919a89bcd4cSHans Verkuil 1920a89bcd4cSHans Verkuil afe_write(sd, 0x00, 0xff); /* power down ADC */ 1921a89bcd4cSHans Verkuil afe_write(sd, 0xc8, 0x40); /* phase control */ 1922a89bcd4cSHans Verkuil 1923a89bcd4cSHans Verkuil /* set to default gain for HDMI */ 1924a89bcd4cSHans Verkuil cp_write(sd, 0x73, 0x10); 1925a89bcd4cSHans Verkuil cp_write(sd, 0x74, 0x04); 1926a89bcd4cSHans Verkuil cp_write(sd, 0x75, 0x01); 1927a89bcd4cSHans Verkuil cp_write(sd, 0x76, 0x00); 1928a89bcd4cSHans Verkuil 1929a89bcd4cSHans Verkuil /* reset ADI recommended settings for digitizer */ 1930a89bcd4cSHans Verkuil /* "ADV7842 Register Settings Recommendations 1931a89bcd4cSHans Verkuil * (rev. 2.5, June 2010)" p. 17. */ 1932a89bcd4cSHans Verkuil afe_write(sd, 0x12, 0xfb); /* ADC noise shaping filter controls */ 1933a89bcd4cSHans Verkuil afe_write(sd, 0x0c, 0x0d); /* CP core gain controls */ 1934933913daSMartin Bugge cp_write(sd, 0x3e, 0x00); /* CP core pre-gain control */ 1935933913daSMartin Bugge 1936a89bcd4cSHans Verkuil /* CP coast control */ 1937a89bcd4cSHans Verkuil cp_write(sd, 0xc3, 0x33); /* Component mode */ 1938a89bcd4cSHans Verkuil 1939a89bcd4cSHans Verkuil /* color space conversion, autodetect color space */ 1940a89bcd4cSHans Verkuil io_write_and_or(sd, 0x02, 0x0f, 0xf0); 1941a89bcd4cSHans Verkuil break; 1942a89bcd4cSHans Verkuil 1943a89bcd4cSHans Verkuil default: 1944a89bcd4cSHans Verkuil v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", 1945a89bcd4cSHans Verkuil __func__, state->mode); 1946a89bcd4cSHans Verkuil break; 1947a89bcd4cSHans Verkuil } 1948a89bcd4cSHans Verkuil } 1949a89bcd4cSHans Verkuil 1950a89bcd4cSHans Verkuil static int adv7842_s_routing(struct v4l2_subdev *sd, 1951a89bcd4cSHans Verkuil u32 input, u32 output, u32 config) 1952a89bcd4cSHans Verkuil { 1953a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 1954a89bcd4cSHans Verkuil 1955a89bcd4cSHans Verkuil v4l2_dbg(2, debug, sd, "%s: input %d\n", __func__, input); 1956a89bcd4cSHans Verkuil 1957a89bcd4cSHans Verkuil switch (input) { 1958a89bcd4cSHans Verkuil case ADV7842_SELECT_HDMI_PORT_A: 1959a89bcd4cSHans Verkuil state->mode = ADV7842_MODE_HDMI; 1960a89bcd4cSHans Verkuil state->vid_std_select = ADV7842_HDMI_COMP_VID_STD_HD_1250P; 1961a89bcd4cSHans Verkuil state->hdmi_port_a = true; 1962a89bcd4cSHans Verkuil break; 1963a89bcd4cSHans Verkuil case ADV7842_SELECT_HDMI_PORT_B: 1964a89bcd4cSHans Verkuil state->mode = ADV7842_MODE_HDMI; 1965a89bcd4cSHans Verkuil state->vid_std_select = ADV7842_HDMI_COMP_VID_STD_HD_1250P; 1966a89bcd4cSHans Verkuil state->hdmi_port_a = false; 1967a89bcd4cSHans Verkuil break; 1968a89bcd4cSHans Verkuil case ADV7842_SELECT_VGA_COMP: 196969e9ba6fSHans Verkuil state->mode = ADV7842_MODE_COMP; 197069e9ba6fSHans Verkuil state->vid_std_select = ADV7842_RGB_VID_STD_AUTO_GRAPH_MODE; 197169e9ba6fSHans Verkuil break; 1972a89bcd4cSHans Verkuil case ADV7842_SELECT_VGA_RGB: 1973a89bcd4cSHans Verkuil state->mode = ADV7842_MODE_RGB; 1974a89bcd4cSHans Verkuil state->vid_std_select = ADV7842_RGB_VID_STD_AUTO_GRAPH_MODE; 1975a89bcd4cSHans Verkuil break; 1976a89bcd4cSHans Verkuil case ADV7842_SELECT_SDP_CVBS: 1977a89bcd4cSHans Verkuil state->mode = ADV7842_MODE_SDP; 1978a89bcd4cSHans Verkuil state->vid_std_select = ADV7842_SDP_VID_STD_CVBS_SD_4x1; 1979a89bcd4cSHans Verkuil break; 1980a89bcd4cSHans Verkuil case ADV7842_SELECT_SDP_YC: 1981a89bcd4cSHans Verkuil state->mode = ADV7842_MODE_SDP; 1982a89bcd4cSHans Verkuil state->vid_std_select = ADV7842_SDP_VID_STD_YC_SD4_x1; 1983a89bcd4cSHans Verkuil break; 1984a89bcd4cSHans Verkuil default: 1985a89bcd4cSHans Verkuil return -EINVAL; 1986a89bcd4cSHans Verkuil } 1987a89bcd4cSHans Verkuil 1988a89bcd4cSHans Verkuil disable_input(sd); 1989a89bcd4cSHans Verkuil select_input(sd, state->vid_std_select); 1990a89bcd4cSHans Verkuil enable_input(sd); 1991a89bcd4cSHans Verkuil 19922cf4090fSLars-Peter Clausen v4l2_subdev_notify_event(sd, &adv7842_ev_fmt); 1993a89bcd4cSHans Verkuil 1994a89bcd4cSHans Verkuil return 0; 1995a89bcd4cSHans Verkuil } 1996a89bcd4cSHans Verkuil 1997ebcff5fcSHans Verkuil static int adv7842_enum_mbus_code(struct v4l2_subdev *sd, 1998ebcff5fcSHans Verkuil struct v4l2_subdev_pad_config *cfg, 1999ebcff5fcSHans Verkuil struct v4l2_subdev_mbus_code_enum *code) 2000a89bcd4cSHans Verkuil { 2001f888ae7eSHans Verkuil if (code->index >= ARRAY_SIZE(adv7842_formats)) 2002a89bcd4cSHans Verkuil return -EINVAL; 2003f888ae7eSHans Verkuil code->code = adv7842_formats[code->index].code; 2004a89bcd4cSHans Verkuil return 0; 2005a89bcd4cSHans Verkuil } 2006a89bcd4cSHans Verkuil 2007f888ae7eSHans Verkuil static void adv7842_fill_format(struct adv7842_state *state, 2008f888ae7eSHans Verkuil struct v4l2_mbus_framefmt *format) 2009f888ae7eSHans Verkuil { 2010f888ae7eSHans Verkuil memset(format, 0, sizeof(*format)); 2011f888ae7eSHans Verkuil 2012f888ae7eSHans Verkuil format->width = state->timings.bt.width; 2013f888ae7eSHans Verkuil format->height = state->timings.bt.height; 2014f888ae7eSHans Verkuil format->field = V4L2_FIELD_NONE; 2015f888ae7eSHans Verkuil format->colorspace = V4L2_COLORSPACE_SRGB; 2016f888ae7eSHans Verkuil 2017f888ae7eSHans Verkuil if (state->timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) 2018f888ae7eSHans Verkuil format->colorspace = (state->timings.bt.height <= 576) ? 2019f888ae7eSHans Verkuil V4L2_COLORSPACE_SMPTE170M : V4L2_COLORSPACE_REC709; 2020f888ae7eSHans Verkuil } 2021f888ae7eSHans Verkuil 2022f888ae7eSHans Verkuil /* 2023f888ae7eSHans Verkuil * Compute the op_ch_sel value required to obtain on the bus the component order 2024f888ae7eSHans Verkuil * corresponding to the selected format taking into account bus reordering 2025f888ae7eSHans Verkuil * applied by the board at the output of the device. 2026f888ae7eSHans Verkuil * 2027f888ae7eSHans Verkuil * The following table gives the op_ch_value from the format component order 2028f888ae7eSHans Verkuil * (expressed as op_ch_sel value in column) and the bus reordering (expressed as 2029f888ae7eSHans Verkuil * adv7842_bus_order value in row). 2030f888ae7eSHans Verkuil * 2031f888ae7eSHans Verkuil * | GBR(0) GRB(1) BGR(2) RGB(3) BRG(4) RBG(5) 2032f888ae7eSHans Verkuil * ----------+------------------------------------------------- 2033f888ae7eSHans Verkuil * RGB (NOP) | GBR GRB BGR RGB BRG RBG 2034f888ae7eSHans Verkuil * GRB (1-2) | BGR RGB GBR GRB RBG BRG 2035f888ae7eSHans Verkuil * RBG (2-3) | GRB GBR BRG RBG BGR RGB 2036f888ae7eSHans Verkuil * BGR (1-3) | RBG BRG RGB BGR GRB GBR 2037f888ae7eSHans Verkuil * BRG (ROR) | BRG RBG GRB GBR RGB BGR 2038f888ae7eSHans Verkuil * GBR (ROL) | RGB BGR RBG BRG GBR GRB 2039f888ae7eSHans Verkuil */ 2040f888ae7eSHans Verkuil static unsigned int adv7842_op_ch_sel(struct adv7842_state *state) 2041f888ae7eSHans Verkuil { 2042f888ae7eSHans Verkuil #define _SEL(a, b, c, d, e, f) { \ 2043f888ae7eSHans Verkuil ADV7842_OP_CH_SEL_##a, ADV7842_OP_CH_SEL_##b, ADV7842_OP_CH_SEL_##c, \ 2044f888ae7eSHans Verkuil ADV7842_OP_CH_SEL_##d, ADV7842_OP_CH_SEL_##e, ADV7842_OP_CH_SEL_##f } 2045f888ae7eSHans Verkuil #define _BUS(x) [ADV7842_BUS_ORDER_##x] 2046f888ae7eSHans Verkuil 2047f888ae7eSHans Verkuil static const unsigned int op_ch_sel[6][6] = { 2048f888ae7eSHans Verkuil _BUS(RGB) /* NOP */ = _SEL(GBR, GRB, BGR, RGB, BRG, RBG), 2049f888ae7eSHans Verkuil _BUS(GRB) /* 1-2 */ = _SEL(BGR, RGB, GBR, GRB, RBG, BRG), 2050f888ae7eSHans Verkuil _BUS(RBG) /* 2-3 */ = _SEL(GRB, GBR, BRG, RBG, BGR, RGB), 2051f888ae7eSHans Verkuil _BUS(BGR) /* 1-3 */ = _SEL(RBG, BRG, RGB, BGR, GRB, GBR), 2052f888ae7eSHans Verkuil _BUS(BRG) /* ROR */ = _SEL(BRG, RBG, GRB, GBR, RGB, BGR), 2053f888ae7eSHans Verkuil _BUS(GBR) /* ROL */ = _SEL(RGB, BGR, RBG, BRG, GBR, GRB), 2054f888ae7eSHans Verkuil }; 2055f888ae7eSHans Verkuil 2056f888ae7eSHans Verkuil return op_ch_sel[state->pdata.bus_order][state->format->op_ch_sel >> 5]; 2057f888ae7eSHans Verkuil } 2058f888ae7eSHans Verkuil 2059f888ae7eSHans Verkuil static void adv7842_setup_format(struct adv7842_state *state) 2060f888ae7eSHans Verkuil { 2061f888ae7eSHans Verkuil struct v4l2_subdev *sd = &state->sd; 2062f888ae7eSHans Verkuil 2063f888ae7eSHans Verkuil io_write_clr_set(sd, 0x02, 0x02, 2064f888ae7eSHans Verkuil state->format->rgb_out ? ADV7842_RGB_OUT : 0); 2065f888ae7eSHans Verkuil io_write(sd, 0x03, state->format->op_format_sel | 2066f888ae7eSHans Verkuil state->pdata.op_format_mode_sel); 2067f888ae7eSHans Verkuil io_write_clr_set(sd, 0x04, 0xe0, adv7842_op_ch_sel(state)); 2068f888ae7eSHans Verkuil io_write_clr_set(sd, 0x05, 0x01, 2069f888ae7eSHans Verkuil state->format->swap_cb_cr ? ADV7842_OP_SWAP_CB_CR : 0); 2070fd74246dSHans Verkuil set_rgb_quantization_range(sd); 2071f888ae7eSHans Verkuil } 2072f888ae7eSHans Verkuil 2073f888ae7eSHans Verkuil static int adv7842_get_format(struct v4l2_subdev *sd, 2074da298c6dSHans Verkuil struct v4l2_subdev_pad_config *cfg, 2075da298c6dSHans Verkuil struct v4l2_subdev_format *format) 2076a89bcd4cSHans Verkuil { 2077a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 2078a89bcd4cSHans Verkuil 2079f888ae7eSHans Verkuil if (format->pad != ADV7842_PAD_SOURCE) 2080da298c6dSHans Verkuil return -EINVAL; 2081da298c6dSHans Verkuil 2082a89bcd4cSHans Verkuil if (state->mode == ADV7842_MODE_SDP) { 2083a89bcd4cSHans Verkuil /* SPD block */ 2084f888ae7eSHans Verkuil if (!(sdp_read(sd, 0x5a) & 0x01)) 2085a89bcd4cSHans Verkuil return -EINVAL; 2086f888ae7eSHans Verkuil format->format.code = MEDIA_BUS_FMT_YUYV8_2X8; 2087f888ae7eSHans Verkuil format->format.width = 720; 2088a89bcd4cSHans Verkuil /* valid signal */ 2089a89bcd4cSHans Verkuil if (state->norm & V4L2_STD_525_60) 2090f888ae7eSHans Verkuil format->format.height = 480; 2091a89bcd4cSHans Verkuil else 2092f888ae7eSHans Verkuil format->format.height = 576; 2093f888ae7eSHans Verkuil format->format.colorspace = V4L2_COLORSPACE_SMPTE170M; 2094a89bcd4cSHans Verkuil return 0; 2095a89bcd4cSHans Verkuil } 2096a89bcd4cSHans Verkuil 2097f888ae7eSHans Verkuil adv7842_fill_format(state, &format->format); 2098f888ae7eSHans Verkuil 2099f888ae7eSHans Verkuil if (format->which == V4L2_SUBDEV_FORMAT_TRY) { 2100f888ae7eSHans Verkuil struct v4l2_mbus_framefmt *fmt; 2101f888ae7eSHans Verkuil 2102f888ae7eSHans Verkuil fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); 2103f888ae7eSHans Verkuil format->format.code = fmt->code; 2104f888ae7eSHans Verkuil } else { 2105f888ae7eSHans Verkuil format->format.code = state->format->code; 2106a89bcd4cSHans Verkuil } 2107f888ae7eSHans Verkuil 2108f888ae7eSHans Verkuil return 0; 2109f888ae7eSHans Verkuil } 2110f888ae7eSHans Verkuil 2111f888ae7eSHans Verkuil static int adv7842_set_format(struct v4l2_subdev *sd, 2112f888ae7eSHans Verkuil struct v4l2_subdev_pad_config *cfg, 2113f888ae7eSHans Verkuil struct v4l2_subdev_format *format) 2114f888ae7eSHans Verkuil { 2115f888ae7eSHans Verkuil struct adv7842_state *state = to_state(sd); 2116f888ae7eSHans Verkuil const struct adv7842_format_info *info; 2117f888ae7eSHans Verkuil 2118f888ae7eSHans Verkuil if (format->pad != ADV7842_PAD_SOURCE) 2119f888ae7eSHans Verkuil return -EINVAL; 2120f888ae7eSHans Verkuil 2121f888ae7eSHans Verkuil if (state->mode == ADV7842_MODE_SDP) 2122f888ae7eSHans Verkuil return adv7842_get_format(sd, cfg, format); 2123f888ae7eSHans Verkuil 2124f888ae7eSHans Verkuil info = adv7842_format_info(state, format->format.code); 2125f888ae7eSHans Verkuil if (info == NULL) 2126f888ae7eSHans Verkuil info = adv7842_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8); 2127f888ae7eSHans Verkuil 2128f888ae7eSHans Verkuil adv7842_fill_format(state, &format->format); 2129f888ae7eSHans Verkuil format->format.code = info->code; 2130f888ae7eSHans Verkuil 2131f888ae7eSHans Verkuil if (format->which == V4L2_SUBDEV_FORMAT_TRY) { 2132f888ae7eSHans Verkuil struct v4l2_mbus_framefmt *fmt; 2133f888ae7eSHans Verkuil 2134f888ae7eSHans Verkuil fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); 2135f888ae7eSHans Verkuil fmt->code = format->format.code; 2136f888ae7eSHans Verkuil } else { 2137f888ae7eSHans Verkuil state->format = info; 2138f888ae7eSHans Verkuil adv7842_setup_format(state); 2139f888ae7eSHans Verkuil } 2140f888ae7eSHans Verkuil 2141a89bcd4cSHans Verkuil return 0; 2142a89bcd4cSHans Verkuil } 2143a89bcd4cSHans Verkuil 2144a89bcd4cSHans Verkuil static void adv7842_irq_enable(struct v4l2_subdev *sd, bool enable) 2145a89bcd4cSHans Verkuil { 2146a89bcd4cSHans Verkuil if (enable) { 2147a89bcd4cSHans Verkuil /* Enable SSPD, STDI and CP locked/unlocked interrupts */ 2148a89bcd4cSHans Verkuil io_write(sd, 0x46, 0x9c); 2149a89bcd4cSHans Verkuil /* ESDP_50HZ_DET interrupt */ 2150a89bcd4cSHans Verkuil io_write(sd, 0x5a, 0x10); 2151a89bcd4cSHans Verkuil /* Enable CABLE_DET_A/B_ST (+5v) interrupt */ 2152a89bcd4cSHans Verkuil io_write(sd, 0x73, 0x03); 2153a89bcd4cSHans Verkuil /* Enable V_LOCKED and DE_REGEN_LCK interrupts */ 2154a89bcd4cSHans Verkuil io_write(sd, 0x78, 0x03); 2155a89bcd4cSHans Verkuil /* Enable SDP Standard Detection Change and SDP Video Detected */ 2156a89bcd4cSHans Verkuil io_write(sd, 0xa0, 0x09); 2157019aa8beSMartin Bugge /* Enable HDMI_MODE interrupt */ 2158019aa8beSMartin Bugge io_write(sd, 0x69, 0x08); 2159a89bcd4cSHans Verkuil } else { 2160a89bcd4cSHans Verkuil io_write(sd, 0x46, 0x0); 2161a89bcd4cSHans Verkuil io_write(sd, 0x5a, 0x0); 2162a89bcd4cSHans Verkuil io_write(sd, 0x73, 0x0); 2163a89bcd4cSHans Verkuil io_write(sd, 0x78, 0x0); 2164a89bcd4cSHans Verkuil io_write(sd, 0xa0, 0x0); 2165019aa8beSMartin Bugge io_write(sd, 0x69, 0x0); 2166a89bcd4cSHans Verkuil } 2167a89bcd4cSHans Verkuil } 2168a89bcd4cSHans Verkuil 216925c84fb1SHans Verkuil #if IS_ENABLED(CONFIG_VIDEO_ADV7842_CEC) 217025c84fb1SHans Verkuil static void adv7842_cec_tx_raw_status(struct v4l2_subdev *sd, u8 tx_raw_status) 217125c84fb1SHans Verkuil { 217225c84fb1SHans Verkuil struct adv7842_state *state = to_state(sd); 217325c84fb1SHans Verkuil 217425c84fb1SHans Verkuil if ((cec_read(sd, 0x11) & 0x01) == 0) { 217525c84fb1SHans Verkuil v4l2_dbg(1, debug, sd, "%s: tx raw: tx disabled\n", __func__); 217625c84fb1SHans Verkuil return; 217725c84fb1SHans Verkuil } 217825c84fb1SHans Verkuil 217925c84fb1SHans Verkuil if (tx_raw_status & 0x02) { 218025c84fb1SHans Verkuil v4l2_dbg(1, debug, sd, "%s: tx raw: arbitration lost\n", 218125c84fb1SHans Verkuil __func__); 218225c84fb1SHans Verkuil cec_transmit_done(state->cec_adap, CEC_TX_STATUS_ARB_LOST, 218325c84fb1SHans Verkuil 1, 0, 0, 0); 218425c84fb1SHans Verkuil return; 218525c84fb1SHans Verkuil } 218625c84fb1SHans Verkuil if (tx_raw_status & 0x04) { 218725c84fb1SHans Verkuil u8 status; 218825c84fb1SHans Verkuil u8 nack_cnt; 218925c84fb1SHans Verkuil u8 low_drive_cnt; 219025c84fb1SHans Verkuil 219125c84fb1SHans Verkuil v4l2_dbg(1, debug, sd, "%s: tx raw: retry failed\n", __func__); 219225c84fb1SHans Verkuil /* 219325c84fb1SHans Verkuil * We set this status bit since this hardware performs 219425c84fb1SHans Verkuil * retransmissions. 219525c84fb1SHans Verkuil */ 219625c84fb1SHans Verkuil status = CEC_TX_STATUS_MAX_RETRIES; 219725c84fb1SHans Verkuil nack_cnt = cec_read(sd, 0x14) & 0xf; 219825c84fb1SHans Verkuil if (nack_cnt) 219925c84fb1SHans Verkuil status |= CEC_TX_STATUS_NACK; 220025c84fb1SHans Verkuil low_drive_cnt = cec_read(sd, 0x14) >> 4; 220125c84fb1SHans Verkuil if (low_drive_cnt) 220225c84fb1SHans Verkuil status |= CEC_TX_STATUS_LOW_DRIVE; 220325c84fb1SHans Verkuil cec_transmit_done(state->cec_adap, status, 220425c84fb1SHans Verkuil 0, nack_cnt, low_drive_cnt, 0); 220525c84fb1SHans Verkuil return; 220625c84fb1SHans Verkuil } 220725c84fb1SHans Verkuil if (tx_raw_status & 0x01) { 220825c84fb1SHans Verkuil v4l2_dbg(1, debug, sd, "%s: tx raw: ready ok\n", __func__); 220925c84fb1SHans Verkuil cec_transmit_done(state->cec_adap, CEC_TX_STATUS_OK, 0, 0, 0, 0); 221025c84fb1SHans Verkuil return; 221125c84fb1SHans Verkuil } 221225c84fb1SHans Verkuil } 221325c84fb1SHans Verkuil 221425c84fb1SHans Verkuil static void adv7842_cec_isr(struct v4l2_subdev *sd, bool *handled) 221525c84fb1SHans Verkuil { 221625c84fb1SHans Verkuil u8 cec_irq; 221725c84fb1SHans Verkuil 221825c84fb1SHans Verkuil /* cec controller */ 221925c84fb1SHans Verkuil cec_irq = io_read(sd, 0x93) & 0x0f; 222025c84fb1SHans Verkuil if (!cec_irq) 222125c84fb1SHans Verkuil return; 222225c84fb1SHans Verkuil 222325c84fb1SHans Verkuil v4l2_dbg(1, debug, sd, "%s: cec: irq 0x%x\n", __func__, cec_irq); 222425c84fb1SHans Verkuil adv7842_cec_tx_raw_status(sd, cec_irq); 222525c84fb1SHans Verkuil if (cec_irq & 0x08) { 222625c84fb1SHans Verkuil struct adv7842_state *state = to_state(sd); 222725c84fb1SHans Verkuil struct cec_msg msg; 222825c84fb1SHans Verkuil 222925c84fb1SHans Verkuil msg.len = cec_read(sd, 0x25) & 0x1f; 223025c84fb1SHans Verkuil if (msg.len > 16) 223125c84fb1SHans Verkuil msg.len = 16; 223225c84fb1SHans Verkuil 223325c84fb1SHans Verkuil if (msg.len) { 223425c84fb1SHans Verkuil u8 i; 223525c84fb1SHans Verkuil 223625c84fb1SHans Verkuil for (i = 0; i < msg.len; i++) 223725c84fb1SHans Verkuil msg.msg[i] = cec_read(sd, i + 0x15); 223825c84fb1SHans Verkuil cec_write(sd, 0x26, 0x01); /* re-enable rx */ 223925c84fb1SHans Verkuil cec_received_msg(state->cec_adap, &msg); 224025c84fb1SHans Verkuil } 224125c84fb1SHans Verkuil } 224225c84fb1SHans Verkuil 224325c84fb1SHans Verkuil io_write(sd, 0x94, cec_irq); 224425c84fb1SHans Verkuil 224525c84fb1SHans Verkuil if (handled) 224625c84fb1SHans Verkuil *handled = true; 224725c84fb1SHans Verkuil } 224825c84fb1SHans Verkuil 224925c84fb1SHans Verkuil static int adv7842_cec_adap_enable(struct cec_adapter *adap, bool enable) 225025c84fb1SHans Verkuil { 22512e60ad17SJose Abreu struct adv7842_state *state = cec_get_drvdata(adap); 225225c84fb1SHans Verkuil struct v4l2_subdev *sd = &state->sd; 225325c84fb1SHans Verkuil 225425c84fb1SHans Verkuil if (!state->cec_enabled_adap && enable) { 225525c84fb1SHans Verkuil cec_write_clr_set(sd, 0x2a, 0x01, 0x01); /* power up cec */ 225625c84fb1SHans Verkuil cec_write(sd, 0x2c, 0x01); /* cec soft reset */ 225725c84fb1SHans Verkuil cec_write_clr_set(sd, 0x11, 0x01, 0); /* initially disable tx */ 225825c84fb1SHans Verkuil /* enabled irqs: */ 225925c84fb1SHans Verkuil /* tx: ready */ 226025c84fb1SHans Verkuil /* tx: arbitration lost */ 226125c84fb1SHans Verkuil /* tx: retry timeout */ 226225c84fb1SHans Verkuil /* rx: ready */ 226325c84fb1SHans Verkuil io_write_clr_set(sd, 0x96, 0x0f, 0x0f); 226425c84fb1SHans Verkuil cec_write(sd, 0x26, 0x01); /* enable rx */ 226525c84fb1SHans Verkuil } else if (state->cec_enabled_adap && !enable) { 226625c84fb1SHans Verkuil /* disable cec interrupts */ 226725c84fb1SHans Verkuil io_write_clr_set(sd, 0x96, 0x0f, 0x00); 226825c84fb1SHans Verkuil /* disable address mask 1-3 */ 226925c84fb1SHans Verkuil cec_write_clr_set(sd, 0x27, 0x70, 0x00); 227025c84fb1SHans Verkuil /* power down cec section */ 227125c84fb1SHans Verkuil cec_write_clr_set(sd, 0x2a, 0x01, 0x00); 227225c84fb1SHans Verkuil state->cec_valid_addrs = 0; 227325c84fb1SHans Verkuil } 227425c84fb1SHans Verkuil state->cec_enabled_adap = enable; 227525c84fb1SHans Verkuil return 0; 227625c84fb1SHans Verkuil } 227725c84fb1SHans Verkuil 227825c84fb1SHans Verkuil static int adv7842_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) 227925c84fb1SHans Verkuil { 22802e60ad17SJose Abreu struct adv7842_state *state = cec_get_drvdata(adap); 228125c84fb1SHans Verkuil struct v4l2_subdev *sd = &state->sd; 228225c84fb1SHans Verkuil unsigned int i, free_idx = ADV7842_MAX_ADDRS; 228325c84fb1SHans Verkuil 228425c84fb1SHans Verkuil if (!state->cec_enabled_adap) 228525c84fb1SHans Verkuil return addr == CEC_LOG_ADDR_INVALID ? 0 : -EIO; 228625c84fb1SHans Verkuil 228725c84fb1SHans Verkuil if (addr == CEC_LOG_ADDR_INVALID) { 228825c84fb1SHans Verkuil cec_write_clr_set(sd, 0x27, 0x70, 0); 228925c84fb1SHans Verkuil state->cec_valid_addrs = 0; 229025c84fb1SHans Verkuil return 0; 229125c84fb1SHans Verkuil } 229225c84fb1SHans Verkuil 229325c84fb1SHans Verkuil for (i = 0; i < ADV7842_MAX_ADDRS; i++) { 229425c84fb1SHans Verkuil bool is_valid = state->cec_valid_addrs & (1 << i); 229525c84fb1SHans Verkuil 229625c84fb1SHans Verkuil if (free_idx == ADV7842_MAX_ADDRS && !is_valid) 229725c84fb1SHans Verkuil free_idx = i; 229825c84fb1SHans Verkuil if (is_valid && state->cec_addr[i] == addr) 229925c84fb1SHans Verkuil return 0; 230025c84fb1SHans Verkuil } 230125c84fb1SHans Verkuil if (i == ADV7842_MAX_ADDRS) { 230225c84fb1SHans Verkuil i = free_idx; 230325c84fb1SHans Verkuil if (i == ADV7842_MAX_ADDRS) 230425c84fb1SHans Verkuil return -ENXIO; 230525c84fb1SHans Verkuil } 230625c84fb1SHans Verkuil state->cec_addr[i] = addr; 230725c84fb1SHans Verkuil state->cec_valid_addrs |= 1 << i; 230825c84fb1SHans Verkuil 230925c84fb1SHans Verkuil switch (i) { 231025c84fb1SHans Verkuil case 0: 231125c84fb1SHans Verkuil /* enable address mask 0 */ 231225c84fb1SHans Verkuil cec_write_clr_set(sd, 0x27, 0x10, 0x10); 231325c84fb1SHans Verkuil /* set address for mask 0 */ 231425c84fb1SHans Verkuil cec_write_clr_set(sd, 0x28, 0x0f, addr); 231525c84fb1SHans Verkuil break; 231625c84fb1SHans Verkuil case 1: 231725c84fb1SHans Verkuil /* enable address mask 1 */ 231825c84fb1SHans Verkuil cec_write_clr_set(sd, 0x27, 0x20, 0x20); 231925c84fb1SHans Verkuil /* set address for mask 1 */ 232025c84fb1SHans Verkuil cec_write_clr_set(sd, 0x28, 0xf0, addr << 4); 232125c84fb1SHans Verkuil break; 232225c84fb1SHans Verkuil case 2: 232325c84fb1SHans Verkuil /* enable address mask 2 */ 232425c84fb1SHans Verkuil cec_write_clr_set(sd, 0x27, 0x40, 0x40); 232525c84fb1SHans Verkuil /* set address for mask 1 */ 232625c84fb1SHans Verkuil cec_write_clr_set(sd, 0x29, 0x0f, addr); 232725c84fb1SHans Verkuil break; 232825c84fb1SHans Verkuil } 232925c84fb1SHans Verkuil return 0; 233025c84fb1SHans Verkuil } 233125c84fb1SHans Verkuil 233225c84fb1SHans Verkuil static int adv7842_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, 233325c84fb1SHans Verkuil u32 signal_free_time, struct cec_msg *msg) 233425c84fb1SHans Verkuil { 23352e60ad17SJose Abreu struct adv7842_state *state = cec_get_drvdata(adap); 233625c84fb1SHans Verkuil struct v4l2_subdev *sd = &state->sd; 233725c84fb1SHans Verkuil u8 len = msg->len; 233825c84fb1SHans Verkuil unsigned int i; 233925c84fb1SHans Verkuil 234025c84fb1SHans Verkuil /* 234125c84fb1SHans Verkuil * The number of retries is the number of attempts - 1, but retry 234225c84fb1SHans Verkuil * at least once. It's not clear if a value of 0 is allowed, so 234325c84fb1SHans Verkuil * let's do at least one retry. 234425c84fb1SHans Verkuil */ 234525c84fb1SHans Verkuil cec_write_clr_set(sd, 0x12, 0x70, max(1, attempts - 1) << 4); 234625c84fb1SHans Verkuil 234725c84fb1SHans Verkuil if (len > 16) { 234825c84fb1SHans Verkuil v4l2_err(sd, "%s: len exceeded 16 (%d)\n", __func__, len); 234925c84fb1SHans Verkuil return -EINVAL; 235025c84fb1SHans Verkuil } 235125c84fb1SHans Verkuil 235225c84fb1SHans Verkuil /* write data */ 235325c84fb1SHans Verkuil for (i = 0; i < len; i++) 235425c84fb1SHans Verkuil cec_write(sd, i, msg->msg[i]); 235525c84fb1SHans Verkuil 235625c84fb1SHans Verkuil /* set length (data + header) */ 235725c84fb1SHans Verkuil cec_write(sd, 0x10, len); 235825c84fb1SHans Verkuil /* start transmit, enable tx */ 235925c84fb1SHans Verkuil cec_write(sd, 0x11, 0x01); 236025c84fb1SHans Verkuil return 0; 236125c84fb1SHans Verkuil } 236225c84fb1SHans Verkuil 236325c84fb1SHans Verkuil static const struct cec_adap_ops adv7842_cec_adap_ops = { 236425c84fb1SHans Verkuil .adap_enable = adv7842_cec_adap_enable, 236525c84fb1SHans Verkuil .adap_log_addr = adv7842_cec_adap_log_addr, 236625c84fb1SHans Verkuil .adap_transmit = adv7842_cec_adap_transmit, 236725c84fb1SHans Verkuil }; 236825c84fb1SHans Verkuil #endif 236925c84fb1SHans Verkuil 2370a89bcd4cSHans Verkuil static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled) 2371a89bcd4cSHans Verkuil { 2372a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 2373a89bcd4cSHans Verkuil u8 fmt_change_cp, fmt_change_digital, fmt_change_sdp; 2374019aa8beSMartin Bugge u8 irq_status[6]; 2375a89bcd4cSHans Verkuil 2376c9f1f271SMartin Bugge adv7842_irq_enable(sd, false); 2377a89bcd4cSHans Verkuil 2378a89bcd4cSHans Verkuil /* read status */ 2379a89bcd4cSHans Verkuil irq_status[0] = io_read(sd, 0x43); 2380a89bcd4cSHans Verkuil irq_status[1] = io_read(sd, 0x57); 2381a89bcd4cSHans Verkuil irq_status[2] = io_read(sd, 0x70); 2382a89bcd4cSHans Verkuil irq_status[3] = io_read(sd, 0x75); 2383a89bcd4cSHans Verkuil irq_status[4] = io_read(sd, 0x9d); 2384019aa8beSMartin Bugge irq_status[5] = io_read(sd, 0x66); 2385a89bcd4cSHans Verkuil 2386a89bcd4cSHans Verkuil /* and clear */ 2387a89bcd4cSHans Verkuil if (irq_status[0]) 2388a89bcd4cSHans Verkuil io_write(sd, 0x44, irq_status[0]); 2389a89bcd4cSHans Verkuil if (irq_status[1]) 2390a89bcd4cSHans Verkuil io_write(sd, 0x58, irq_status[1]); 2391a89bcd4cSHans Verkuil if (irq_status[2]) 2392a89bcd4cSHans Verkuil io_write(sd, 0x71, irq_status[2]); 2393a89bcd4cSHans Verkuil if (irq_status[3]) 2394a89bcd4cSHans Verkuil io_write(sd, 0x76, irq_status[3]); 2395a89bcd4cSHans Verkuil if (irq_status[4]) 2396a89bcd4cSHans Verkuil io_write(sd, 0x9e, irq_status[4]); 2397019aa8beSMartin Bugge if (irq_status[5]) 2398019aa8beSMartin Bugge io_write(sd, 0x67, irq_status[5]); 2399a89bcd4cSHans Verkuil 2400c9f1f271SMartin Bugge adv7842_irq_enable(sd, true); 2401c9f1f271SMartin Bugge 2402019aa8beSMartin Bugge v4l2_dbg(1, debug, sd, "%s: irq %x, %x, %x, %x, %x, %x\n", __func__, 2403a89bcd4cSHans Verkuil irq_status[0], irq_status[1], irq_status[2], 2404019aa8beSMartin Bugge irq_status[3], irq_status[4], irq_status[5]); 2405a89bcd4cSHans Verkuil 2406a89bcd4cSHans Verkuil /* format change CP */ 2407a89bcd4cSHans Verkuil fmt_change_cp = irq_status[0] & 0x9c; 2408a89bcd4cSHans Verkuil 2409a89bcd4cSHans Verkuil /* format change SDP */ 2410a89bcd4cSHans Verkuil if (state->mode == ADV7842_MODE_SDP) 2411a89bcd4cSHans Verkuil fmt_change_sdp = (irq_status[1] & 0x30) | (irq_status[4] & 0x09); 2412a89bcd4cSHans Verkuil else 2413a89bcd4cSHans Verkuil fmt_change_sdp = 0; 2414a89bcd4cSHans Verkuil 2415a89bcd4cSHans Verkuil /* digital format CP */ 2416a89bcd4cSHans Verkuil if (is_digital_input(sd)) 2417a89bcd4cSHans Verkuil fmt_change_digital = irq_status[3] & 0x03; 2418a89bcd4cSHans Verkuil else 2419a89bcd4cSHans Verkuil fmt_change_digital = 0; 2420a89bcd4cSHans Verkuil 2421019aa8beSMartin Bugge /* format change */ 2422a89bcd4cSHans Verkuil if (fmt_change_cp || fmt_change_digital || fmt_change_sdp) { 2423a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, 2424a89bcd4cSHans Verkuil "%s: fmt_change_cp = 0x%x, fmt_change_digital = 0x%x, fmt_change_sdp = 0x%x\n", 2425a89bcd4cSHans Verkuil __func__, fmt_change_cp, fmt_change_digital, 2426a89bcd4cSHans Verkuil fmt_change_sdp); 24272cf4090fSLars-Peter Clausen v4l2_subdev_notify_event(sd, &adv7842_ev_fmt); 2428a89bcd4cSHans Verkuil if (handled) 2429a89bcd4cSHans Verkuil *handled = true; 2430019aa8beSMartin Bugge } 2431a89bcd4cSHans Verkuil 2432019aa8beSMartin Bugge /* HDMI/DVI mode */ 2433019aa8beSMartin Bugge if (irq_status[5] & 0x08) { 2434019aa8beSMartin Bugge v4l2_dbg(1, debug, sd, "%s: irq %s mode\n", __func__, 2435019aa8beSMartin Bugge (io_read(sd, 0x65) & 0x08) ? "HDMI" : "DVI"); 24365046f26bSMartin Bugge set_rgb_quantization_range(sd); 2437019aa8beSMartin Bugge if (handled) 2438019aa8beSMartin Bugge *handled = true; 2439019aa8beSMartin Bugge } 2440019aa8beSMartin Bugge 244125c84fb1SHans Verkuil #if IS_ENABLED(CONFIG_VIDEO_ADV7842_CEC) 244225c84fb1SHans Verkuil /* cec */ 244325c84fb1SHans Verkuil adv7842_cec_isr(sd, handled); 244425c84fb1SHans Verkuil #endif 244525c84fb1SHans Verkuil 2446019aa8beSMartin Bugge /* tx 5v detect */ 2447019aa8beSMartin Bugge if (irq_status[2] & 0x3) { 2448019aa8beSMartin Bugge v4l2_dbg(1, debug, sd, "%s: irq tx_5v\n", __func__); 2449019aa8beSMartin Bugge adv7842_s_detect_tx_5v_ctrl(sd); 2450019aa8beSMartin Bugge if (handled) 2451019aa8beSMartin Bugge *handled = true; 2452019aa8beSMartin Bugge } 2453a89bcd4cSHans Verkuil return 0; 2454a89bcd4cSHans Verkuil } 2455a89bcd4cSHans Verkuil 2456b09dfac8SHans Verkuil static int adv7842_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) 2457245b2b67SMartin Bugge { 2458245b2b67SMartin Bugge struct adv7842_state *state = to_state(sd); 2459245b2b67SMartin Bugge u8 *data = NULL; 2460245b2b67SMartin Bugge 2461c909e5baSHans Verkuil memset(edid->reserved, 0, sizeof(edid->reserved)); 2462245b2b67SMartin Bugge 2463245b2b67SMartin Bugge switch (edid->pad) { 2464245b2b67SMartin Bugge case ADV7842_EDID_PORT_A: 2465245b2b67SMartin Bugge case ADV7842_EDID_PORT_B: 2466245b2b67SMartin Bugge if (state->hdmi_edid.present & (0x04 << edid->pad)) 2467245b2b67SMartin Bugge data = state->hdmi_edid.edid; 2468245b2b67SMartin Bugge break; 2469245b2b67SMartin Bugge case ADV7842_EDID_PORT_VGA: 2470245b2b67SMartin Bugge if (state->vga_edid.present) 2471245b2b67SMartin Bugge data = state->vga_edid.edid; 2472245b2b67SMartin Bugge break; 2473245b2b67SMartin Bugge default: 2474245b2b67SMartin Bugge return -EINVAL; 2475245b2b67SMartin Bugge } 2476c909e5baSHans Verkuil 2477c909e5baSHans Verkuil if (edid->start_block == 0 && edid->blocks == 0) { 2478c909e5baSHans Verkuil edid->blocks = data ? 2 : 0; 2479c909e5baSHans Verkuil return 0; 2480c909e5baSHans Verkuil } 2481c909e5baSHans Verkuil 2482245b2b67SMartin Bugge if (!data) 2483245b2b67SMartin Bugge return -ENODATA; 2484245b2b67SMartin Bugge 2485c909e5baSHans Verkuil if (edid->start_block >= 2) 2486c909e5baSHans Verkuil return -EINVAL; 2487c909e5baSHans Verkuil 2488c909e5baSHans Verkuil if (edid->start_block + edid->blocks > 2) 2489c909e5baSHans Verkuil edid->blocks = 2 - edid->start_block; 2490c909e5baSHans Verkuil 2491c909e5baSHans Verkuil memcpy(edid->edid, data + edid->start_block * 128, edid->blocks * 128); 2492c909e5baSHans Verkuil 2493245b2b67SMartin Bugge return 0; 2494245b2b67SMartin Bugge } 2495245b2b67SMartin Bugge 2496b09dfac8SHans Verkuil static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e) 2497a89bcd4cSHans Verkuil { 2498a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 2499a89bcd4cSHans Verkuil int err = 0; 2500a89bcd4cSHans Verkuil 2501c909e5baSHans Verkuil memset(e->reserved, 0, sizeof(e->reserved)); 2502c909e5baSHans Verkuil 25037de6fab1SMats Randgaard if (e->pad > ADV7842_EDID_PORT_VGA) 2504a89bcd4cSHans Verkuil return -EINVAL; 2505a89bcd4cSHans Verkuil if (e->start_block != 0) 2506a89bcd4cSHans Verkuil return -EINVAL; 2507c909e5baSHans Verkuil if (e->blocks > 2) { 2508c909e5baSHans Verkuil e->blocks = 2; 2509a89bcd4cSHans Verkuil return -E2BIG; 2510c909e5baSHans Verkuil } 2511a89bcd4cSHans Verkuil 2512a89bcd4cSHans Verkuil /* todo, per edid */ 2513a89bcd4cSHans Verkuil state->aspect_ratio = v4l2_calc_aspect_ratio(e->edid[0x15], 2514a89bcd4cSHans Verkuil e->edid[0x16]); 2515a89bcd4cSHans Verkuil 25167de6fab1SMats Randgaard switch (e->pad) { 25177de6fab1SMats Randgaard case ADV7842_EDID_PORT_VGA: 2518a89bcd4cSHans Verkuil memset(&state->vga_edid.edid, 0, 256); 2519a89bcd4cSHans Verkuil state->vga_edid.present = e->blocks ? 0x1 : 0x0; 2520a89bcd4cSHans Verkuil memcpy(&state->vga_edid.edid, e->edid, 128 * e->blocks); 2521a89bcd4cSHans Verkuil err = edid_write_vga_segment(sd); 25227de6fab1SMats Randgaard break; 25237de6fab1SMats Randgaard case ADV7842_EDID_PORT_A: 25247de6fab1SMats Randgaard case ADV7842_EDID_PORT_B: 2525a89bcd4cSHans Verkuil memset(&state->hdmi_edid.edid, 0, 256); 252625c84fb1SHans Verkuil if (e->blocks) { 25277de6fab1SMats Randgaard state->hdmi_edid.present |= 0x04 << e->pad; 252825c84fb1SHans Verkuil } else { 25297de6fab1SMats Randgaard state->hdmi_edid.present &= ~(0x04 << e->pad); 253025c84fb1SHans Verkuil adv7842_s_detect_tx_5v_ctrl(sd); 253125c84fb1SHans Verkuil } 2532a89bcd4cSHans Verkuil memcpy(&state->hdmi_edid.edid, e->edid, 128 * e->blocks); 2533a89bcd4cSHans Verkuil err = edid_write_hdmi_segment(sd, e->pad); 25347de6fab1SMats Randgaard break; 25357de6fab1SMats Randgaard default: 25367de6fab1SMats Randgaard return -EINVAL; 2537a89bcd4cSHans Verkuil } 2538a89bcd4cSHans Verkuil if (err < 0) 2539a89bcd4cSHans Verkuil v4l2_err(sd, "error %d writing edid on port %d\n", err, e->pad); 2540a89bcd4cSHans Verkuil return err; 2541a89bcd4cSHans Verkuil } 2542a89bcd4cSHans Verkuil 254309f90c53SMartin Bugge struct adv7842_cfg_read_infoframe { 254409f90c53SMartin Bugge const char *desc; 254509f90c53SMartin Bugge u8 present_mask; 254609f90c53SMartin Bugge u8 head_addr; 254709f90c53SMartin Bugge u8 payload_addr; 2548a89bcd4cSHans Verkuil }; 2549a89bcd4cSHans Verkuil 255009f90c53SMartin Bugge static void log_infoframe(struct v4l2_subdev *sd, struct adv7842_cfg_read_infoframe *cri) 2551a89bcd4cSHans Verkuil { 2552a89bcd4cSHans Verkuil int i; 255328a769f1SHans Verkuil u8 buffer[32]; 255409f90c53SMartin Bugge union hdmi_infoframe frame; 255509f90c53SMartin Bugge u8 len; 255609f90c53SMartin Bugge struct i2c_client *client = v4l2_get_subdevdata(sd); 255709f90c53SMartin Bugge struct device *dev = &client->dev; 255809f90c53SMartin Bugge 255909f90c53SMartin Bugge if (!(io_read(sd, 0x60) & cri->present_mask)) { 256009f90c53SMartin Bugge v4l2_info(sd, "%s infoframe not received\n", cri->desc); 256109f90c53SMartin Bugge return; 256209f90c53SMartin Bugge } 256309f90c53SMartin Bugge 256409f90c53SMartin Bugge for (i = 0; i < 3; i++) 256509f90c53SMartin Bugge buffer[i] = infoframe_read(sd, cri->head_addr + i); 256609f90c53SMartin Bugge 256709f90c53SMartin Bugge len = buffer[2] + 1; 256809f90c53SMartin Bugge 256909f90c53SMartin Bugge if (len + 3 > sizeof(buffer)) { 257009f90c53SMartin Bugge v4l2_err(sd, "%s: invalid %s infoframe length %d\n", __func__, cri->desc, len); 257109f90c53SMartin Bugge return; 257209f90c53SMartin Bugge } 257309f90c53SMartin Bugge 257409f90c53SMartin Bugge for (i = 0; i < len; i++) 257509f90c53SMartin Bugge buffer[i + 3] = infoframe_read(sd, cri->payload_addr + i); 257609f90c53SMartin Bugge 257709f90c53SMartin Bugge if (hdmi_infoframe_unpack(&frame, buffer) < 0) { 257809f90c53SMartin Bugge v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc); 257909f90c53SMartin Bugge return; 258009f90c53SMartin Bugge } 258109f90c53SMartin Bugge 258209f90c53SMartin Bugge hdmi_infoframe_log(KERN_INFO, dev, &frame); 258309f90c53SMartin Bugge } 258409f90c53SMartin Bugge 258509f90c53SMartin Bugge static void adv7842_log_infoframes(struct v4l2_subdev *sd) 258609f90c53SMartin Bugge { 258709f90c53SMartin Bugge int i; 258809f90c53SMartin Bugge struct adv7842_cfg_read_infoframe cri[] = { 258909f90c53SMartin Bugge { "AVI", 0x01, 0xe0, 0x00 }, 259009f90c53SMartin Bugge { "Audio", 0x02, 0xe3, 0x1c }, 259109f90c53SMartin Bugge { "SDP", 0x04, 0xe6, 0x2a }, 259209f90c53SMartin Bugge { "Vendor", 0x10, 0xec, 0x54 } 259309f90c53SMartin Bugge }; 2594a89bcd4cSHans Verkuil 2595a89bcd4cSHans Verkuil if (!(hdmi_read(sd, 0x05) & 0x80)) { 259609f90c53SMartin Bugge v4l2_info(sd, "receive DVI-D signal, no infoframes\n"); 2597a89bcd4cSHans Verkuil return; 2598a89bcd4cSHans Verkuil } 2599a89bcd4cSHans Verkuil 260009f90c53SMartin Bugge for (i = 0; i < ARRAY_SIZE(cri); i++) 260109f90c53SMartin Bugge log_infoframe(sd, &cri[i]); 2602a89bcd4cSHans Verkuil } 2603a89bcd4cSHans Verkuil 260460eb9579SMauro Carvalho Chehab #if 0 260560eb9579SMauro Carvalho Chehab /* Let's keep it here for now, as it could be useful for debug */ 2606a89bcd4cSHans Verkuil static const char * const prim_mode_txt[] = { 2607a89bcd4cSHans Verkuil "SDP", 2608a89bcd4cSHans Verkuil "Component", 2609a89bcd4cSHans Verkuil "Graphics", 2610a89bcd4cSHans Verkuil "Reserved", 2611a89bcd4cSHans Verkuil "CVBS & HDMI AUDIO", 2612a89bcd4cSHans Verkuil "HDMI-Comp", 2613a89bcd4cSHans Verkuil "HDMI-GR", 2614a89bcd4cSHans Verkuil "Reserved", 2615a89bcd4cSHans Verkuil "Reserved", 2616a89bcd4cSHans Verkuil "Reserved", 2617a89bcd4cSHans Verkuil "Reserved", 2618a89bcd4cSHans Verkuil "Reserved", 2619a89bcd4cSHans Verkuil "Reserved", 2620a89bcd4cSHans Verkuil "Reserved", 2621a89bcd4cSHans Verkuil "Reserved", 2622a89bcd4cSHans Verkuil "Reserved", 2623a89bcd4cSHans Verkuil }; 262460eb9579SMauro Carvalho Chehab #endif 2625a89bcd4cSHans Verkuil 2626a89bcd4cSHans Verkuil static int adv7842_sdp_log_status(struct v4l2_subdev *sd) 2627a89bcd4cSHans Verkuil { 2628a89bcd4cSHans Verkuil /* SDP (Standard definition processor) block */ 262928a769f1SHans Verkuil u8 sdp_signal_detected = sdp_read(sd, 0x5A) & 0x01; 2630a89bcd4cSHans Verkuil 2631a89bcd4cSHans Verkuil v4l2_info(sd, "Chip powered %s\n", no_power(sd) ? "off" : "on"); 2632a89bcd4cSHans Verkuil v4l2_info(sd, "Prim-mode = 0x%x, video std = 0x%x\n", 2633a89bcd4cSHans Verkuil io_read(sd, 0x01) & 0x0f, io_read(sd, 0x00) & 0x3f); 2634a89bcd4cSHans Verkuil 2635a89bcd4cSHans Verkuil v4l2_info(sd, "SDP: free run: %s\n", 2636a89bcd4cSHans Verkuil (sdp_read(sd, 0x56) & 0x01) ? "on" : "off"); 2637a89bcd4cSHans Verkuil v4l2_info(sd, "SDP: %s\n", sdp_signal_detected ? 2638a89bcd4cSHans Verkuil "valid SD/PR signal detected" : "invalid/no signal"); 2639a89bcd4cSHans Verkuil if (sdp_signal_detected) { 2640a89bcd4cSHans Verkuil static const char * const sdp_std_txt[] = { 2641a89bcd4cSHans Verkuil "NTSC-M/J", 2642a89bcd4cSHans Verkuil "1?", 2643a89bcd4cSHans Verkuil "NTSC-443", 2644a89bcd4cSHans Verkuil "60HzSECAM", 2645a89bcd4cSHans Verkuil "PAL-M", 2646a89bcd4cSHans Verkuil "5?", 2647a89bcd4cSHans Verkuil "PAL-60", 2648a89bcd4cSHans Verkuil "7?", "8?", "9?", "a?", "b?", 2649a89bcd4cSHans Verkuil "PAL-CombN", 2650a89bcd4cSHans Verkuil "d?", 2651a89bcd4cSHans Verkuil "PAL-BGHID", 2652a89bcd4cSHans Verkuil "SECAM" 2653a89bcd4cSHans Verkuil }; 2654a89bcd4cSHans Verkuil v4l2_info(sd, "SDP: standard %s\n", 2655a89bcd4cSHans Verkuil sdp_std_txt[sdp_read(sd, 0x52) & 0x0f]); 2656a89bcd4cSHans Verkuil v4l2_info(sd, "SDP: %s\n", 2657a89bcd4cSHans Verkuil (sdp_read(sd, 0x59) & 0x08) ? "50Hz" : "60Hz"); 2658a89bcd4cSHans Verkuil v4l2_info(sd, "SDP: %s\n", 2659a89bcd4cSHans Verkuil (sdp_read(sd, 0x57) & 0x08) ? "Interlaced" : "Progressive"); 2660a89bcd4cSHans Verkuil v4l2_info(sd, "SDP: deinterlacer %s\n", 2661a89bcd4cSHans Verkuil (sdp_read(sd, 0x12) & 0x08) ? "enabled" : "disabled"); 2662a89bcd4cSHans Verkuil v4l2_info(sd, "SDP: csc %s mode\n", 2663a89bcd4cSHans Verkuil (sdp_io_read(sd, 0xe0) & 0x40) ? "auto" : "manual"); 2664a89bcd4cSHans Verkuil } 2665a89bcd4cSHans Verkuil return 0; 2666a89bcd4cSHans Verkuil } 2667a89bcd4cSHans Verkuil 2668a89bcd4cSHans Verkuil static int adv7842_cp_log_status(struct v4l2_subdev *sd) 2669a89bcd4cSHans Verkuil { 2670a89bcd4cSHans Verkuil /* CP block */ 2671a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 2672a89bcd4cSHans Verkuil struct v4l2_dv_timings timings; 267328a769f1SHans Verkuil u8 reg_io_0x02 = io_read(sd, 0x02); 267428a769f1SHans Verkuil u8 reg_io_0x21 = io_read(sd, 0x21); 267528a769f1SHans Verkuil u8 reg_rep_0x77 = rep_read(sd, 0x77); 267628a769f1SHans Verkuil u8 reg_rep_0x7d = rep_read(sd, 0x7d); 2677a89bcd4cSHans Verkuil bool audio_pll_locked = hdmi_read(sd, 0x04) & 0x01; 2678a89bcd4cSHans Verkuil bool audio_sample_packet_detect = hdmi_read(sd, 0x18) & 0x01; 2679a89bcd4cSHans Verkuil bool audio_mute = io_read(sd, 0x65) & 0x40; 2680a89bcd4cSHans Verkuil 2681a89bcd4cSHans Verkuil static const char * const csc_coeff_sel_rb[16] = { 2682a89bcd4cSHans Verkuil "bypassed", "YPbPr601 -> RGB", "reserved", "YPbPr709 -> RGB", 2683a89bcd4cSHans Verkuil "reserved", "RGB -> YPbPr601", "reserved", "RGB -> YPbPr709", 2684a89bcd4cSHans Verkuil "reserved", "YPbPr709 -> YPbPr601", "YPbPr601 -> YPbPr709", 2685a89bcd4cSHans Verkuil "reserved", "reserved", "reserved", "reserved", "manual" 2686a89bcd4cSHans Verkuil }; 2687a89bcd4cSHans Verkuil static const char * const input_color_space_txt[16] = { 2688a89bcd4cSHans Verkuil "RGB limited range (16-235)", "RGB full range (0-255)", 2689a89bcd4cSHans Verkuil "YCbCr Bt.601 (16-235)", "YCbCr Bt.709 (16-235)", 269069e9ba6fSHans Verkuil "xvYCC Bt.601", "xvYCC Bt.709", 2691a89bcd4cSHans Verkuil "YCbCr Bt.601 (0-255)", "YCbCr Bt.709 (0-255)", 2692a89bcd4cSHans Verkuil "invalid", "invalid", "invalid", "invalid", "invalid", 2693a89bcd4cSHans Verkuil "invalid", "invalid", "automatic" 2694a89bcd4cSHans Verkuil }; 2695a89bcd4cSHans Verkuil static const char * const rgb_quantization_range_txt[] = { 2696a89bcd4cSHans Verkuil "Automatic", 2697a89bcd4cSHans Verkuil "RGB limited range (16-235)", 2698a89bcd4cSHans Verkuil "RGB full range (0-255)", 2699a89bcd4cSHans Verkuil }; 2700a89bcd4cSHans Verkuil static const char * const deep_color_mode_txt[4] = { 2701a89bcd4cSHans Verkuil "8-bits per channel", 2702a89bcd4cSHans Verkuil "10-bits per channel", 2703a89bcd4cSHans Verkuil "12-bits per channel", 2704a89bcd4cSHans Verkuil "16-bits per channel (not supported)" 2705a89bcd4cSHans Verkuil }; 2706a89bcd4cSHans Verkuil 2707a89bcd4cSHans Verkuil v4l2_info(sd, "-----Chip status-----\n"); 2708a89bcd4cSHans Verkuil v4l2_info(sd, "Chip power: %s\n", no_power(sd) ? "off" : "on"); 2709a89bcd4cSHans Verkuil v4l2_info(sd, "HDMI/DVI-D port selected: %s\n", 2710a89bcd4cSHans Verkuil state->hdmi_port_a ? "A" : "B"); 2711a89bcd4cSHans Verkuil v4l2_info(sd, "EDID A %s, B %s\n", 2712a89bcd4cSHans Verkuil ((reg_rep_0x7d & 0x04) && (reg_rep_0x77 & 0x04)) ? 2713a89bcd4cSHans Verkuil "enabled" : "disabled", 2714a89bcd4cSHans Verkuil ((reg_rep_0x7d & 0x08) && (reg_rep_0x77 & 0x08)) ? 2715a89bcd4cSHans Verkuil "enabled" : "disabled"); 2716a89bcd4cSHans Verkuil v4l2_info(sd, "HPD A %s, B %s\n", 2717a89bcd4cSHans Verkuil reg_io_0x21 & 0x02 ? "enabled" : "disabled", 2718a89bcd4cSHans Verkuil reg_io_0x21 & 0x01 ? "enabled" : "disabled"); 271925c84fb1SHans Verkuil v4l2_info(sd, "CEC: %s\n", state->cec_enabled_adap ? 2720a89bcd4cSHans Verkuil "enabled" : "disabled"); 272125c84fb1SHans Verkuil if (state->cec_enabled_adap) { 272225c84fb1SHans Verkuil int i; 272325c84fb1SHans Verkuil 272425c84fb1SHans Verkuil for (i = 0; i < ADV7842_MAX_ADDRS; i++) { 272525c84fb1SHans Verkuil bool is_valid = state->cec_valid_addrs & (1 << i); 272625c84fb1SHans Verkuil 272725c84fb1SHans Verkuil if (is_valid) 272825c84fb1SHans Verkuil v4l2_info(sd, "CEC Logical Address: 0x%x\n", 272925c84fb1SHans Verkuil state->cec_addr[i]); 273025c84fb1SHans Verkuil } 273125c84fb1SHans Verkuil } 2732a89bcd4cSHans Verkuil 2733a89bcd4cSHans Verkuil v4l2_info(sd, "-----Signal status-----\n"); 2734a89bcd4cSHans Verkuil if (state->hdmi_port_a) { 2735a89bcd4cSHans Verkuil v4l2_info(sd, "Cable detected (+5V power): %s\n", 2736a89bcd4cSHans Verkuil io_read(sd, 0x6f) & 0x02 ? "true" : "false"); 2737a89bcd4cSHans Verkuil v4l2_info(sd, "TMDS signal detected: %s\n", 2738a89bcd4cSHans Verkuil (io_read(sd, 0x6a) & 0x02) ? "true" : "false"); 2739a89bcd4cSHans Verkuil v4l2_info(sd, "TMDS signal locked: %s\n", 2740a89bcd4cSHans Verkuil (io_read(sd, 0x6a) & 0x20) ? "true" : "false"); 2741a89bcd4cSHans Verkuil } else { 2742a89bcd4cSHans Verkuil v4l2_info(sd, "Cable detected (+5V power):%s\n", 2743a89bcd4cSHans Verkuil io_read(sd, 0x6f) & 0x01 ? "true" : "false"); 2744a89bcd4cSHans Verkuil v4l2_info(sd, "TMDS signal detected: %s\n", 2745a89bcd4cSHans Verkuil (io_read(sd, 0x6a) & 0x01) ? "true" : "false"); 2746a89bcd4cSHans Verkuil v4l2_info(sd, "TMDS signal locked: %s\n", 2747a89bcd4cSHans Verkuil (io_read(sd, 0x6a) & 0x10) ? "true" : "false"); 2748a89bcd4cSHans Verkuil } 2749a89bcd4cSHans Verkuil v4l2_info(sd, "CP free run: %s\n", 2750a89bcd4cSHans Verkuil (!!(cp_read(sd, 0xff) & 0x10) ? "on" : "off")); 2751a89bcd4cSHans Verkuil v4l2_info(sd, "Prim-mode = 0x%x, video std = 0x%x, v_freq = 0x%x\n", 2752a89bcd4cSHans Verkuil io_read(sd, 0x01) & 0x0f, io_read(sd, 0x00) & 0x3f, 2753a89bcd4cSHans Verkuil (io_read(sd, 0x01) & 0x70) >> 4); 2754a89bcd4cSHans Verkuil 2755a89bcd4cSHans Verkuil v4l2_info(sd, "-----Video Timings-----\n"); 2756a89bcd4cSHans Verkuil if (no_cp_signal(sd)) { 2757a89bcd4cSHans Verkuil v4l2_info(sd, "STDI: not locked\n"); 2758a89bcd4cSHans Verkuil } else { 275928a769f1SHans Verkuil u32 bl = ((cp_read(sd, 0xb1) & 0x3f) << 8) | cp_read(sd, 0xb2); 276028a769f1SHans Verkuil u32 lcf = ((cp_read(sd, 0xb3) & 0x7) << 8) | cp_read(sd, 0xb4); 276128a769f1SHans Verkuil u32 lcvs = cp_read(sd, 0xb3) >> 3; 276228a769f1SHans Verkuil u32 fcl = ((cp_read(sd, 0xb8) & 0x1f) << 8) | cp_read(sd, 0xb9); 2763a89bcd4cSHans Verkuil char hs_pol = ((cp_read(sd, 0xb5) & 0x10) ? 2764a89bcd4cSHans Verkuil ((cp_read(sd, 0xb5) & 0x08) ? '+' : '-') : 'x'); 2765a89bcd4cSHans Verkuil char vs_pol = ((cp_read(sd, 0xb5) & 0x40) ? 2766a89bcd4cSHans Verkuil ((cp_read(sd, 0xb5) & 0x20) ? '+' : '-') : 'x'); 2767a89bcd4cSHans Verkuil v4l2_info(sd, 2768a89bcd4cSHans Verkuil "STDI: lcf (frame height - 1) = %d, bl = %d, lcvs (vsync) = %d, fcl = %d, %s, %chsync, %cvsync\n", 2769a89bcd4cSHans Verkuil lcf, bl, lcvs, fcl, 2770a89bcd4cSHans Verkuil (cp_read(sd, 0xb1) & 0x40) ? 2771a89bcd4cSHans Verkuil "interlaced" : "progressive", 2772a89bcd4cSHans Verkuil hs_pol, vs_pol); 2773a89bcd4cSHans Verkuil } 2774a89bcd4cSHans Verkuil if (adv7842_query_dv_timings(sd, &timings)) 2775a89bcd4cSHans Verkuil v4l2_info(sd, "No video detected\n"); 2776a89bcd4cSHans Verkuil else 2777a89bcd4cSHans Verkuil v4l2_print_dv_timings(sd->name, "Detected format: ", 2778a89bcd4cSHans Verkuil &timings, true); 2779a89bcd4cSHans Verkuil v4l2_print_dv_timings(sd->name, "Configured format: ", 2780a89bcd4cSHans Verkuil &state->timings, true); 2781a89bcd4cSHans Verkuil 2782a89bcd4cSHans Verkuil if (no_cp_signal(sd)) 2783a89bcd4cSHans Verkuil return 0; 2784a89bcd4cSHans Verkuil 2785a89bcd4cSHans Verkuil v4l2_info(sd, "-----Color space-----\n"); 2786a89bcd4cSHans Verkuil v4l2_info(sd, "RGB quantization range ctrl: %s\n", 2787a89bcd4cSHans Verkuil rgb_quantization_range_txt[state->rgb_quantization_range]); 2788a89bcd4cSHans Verkuil v4l2_info(sd, "Input color space: %s\n", 2789a89bcd4cSHans Verkuil input_color_space_txt[reg_io_0x02 >> 4]); 2790fd74246dSHans Verkuil v4l2_info(sd, "Output color space: %s %s, alt-gamma %s\n", 2791a89bcd4cSHans Verkuil (reg_io_0x02 & 0x02) ? "RGB" : "YCbCr", 2792fd74246dSHans Verkuil (((reg_io_0x02 >> 2) & 0x01) ^ (reg_io_0x02 & 0x01)) ? 2793fd74246dSHans Verkuil "(16-235)" : "(0-255)", 2794fd74246dSHans Verkuil (reg_io_0x02 & 0x08) ? "enabled" : "disabled"); 2795a89bcd4cSHans Verkuil v4l2_info(sd, "Color space conversion: %s\n", 2796a89bcd4cSHans Verkuil csc_coeff_sel_rb[cp_read(sd, 0xf4) >> 4]); 2797a89bcd4cSHans Verkuil 2798a89bcd4cSHans Verkuil if (!is_digital_input(sd)) 2799a89bcd4cSHans Verkuil return 0; 2800a89bcd4cSHans Verkuil 2801a89bcd4cSHans Verkuil v4l2_info(sd, "-----%s status-----\n", is_hdmi(sd) ? "HDMI" : "DVI-D"); 2802a89bcd4cSHans Verkuil v4l2_info(sd, "HDCP encrypted content: %s\n", 2803a89bcd4cSHans Verkuil (hdmi_read(sd, 0x05) & 0x40) ? "true" : "false"); 2804a89bcd4cSHans Verkuil v4l2_info(sd, "HDCP keys read: %s%s\n", 2805a89bcd4cSHans Verkuil (hdmi_read(sd, 0x04) & 0x20) ? "yes" : "no", 2806a89bcd4cSHans Verkuil (hdmi_read(sd, 0x04) & 0x10) ? "ERROR" : ""); 2807a89bcd4cSHans Verkuil if (!is_hdmi(sd)) 2808a89bcd4cSHans Verkuil return 0; 2809a89bcd4cSHans Verkuil 2810a89bcd4cSHans Verkuil v4l2_info(sd, "Audio: pll %s, samples %s, %s\n", 2811a89bcd4cSHans Verkuil audio_pll_locked ? "locked" : "not locked", 2812a89bcd4cSHans Verkuil audio_sample_packet_detect ? "detected" : "not detected", 2813a89bcd4cSHans Verkuil audio_mute ? "muted" : "enabled"); 2814a89bcd4cSHans Verkuil if (audio_pll_locked && audio_sample_packet_detect) { 2815a89bcd4cSHans Verkuil v4l2_info(sd, "Audio format: %s\n", 2816a89bcd4cSHans Verkuil (hdmi_read(sd, 0x07) & 0x40) ? "multi-channel" : "stereo"); 2817a89bcd4cSHans Verkuil } 2818a89bcd4cSHans Verkuil v4l2_info(sd, "Audio CTS: %u\n", (hdmi_read(sd, 0x5b) << 12) + 2819a89bcd4cSHans Verkuil (hdmi_read(sd, 0x5c) << 8) + 2820a89bcd4cSHans Verkuil (hdmi_read(sd, 0x5d) & 0xf0)); 2821a89bcd4cSHans Verkuil v4l2_info(sd, "Audio N: %u\n", ((hdmi_read(sd, 0x5d) & 0x0f) << 16) + 2822a89bcd4cSHans Verkuil (hdmi_read(sd, 0x5e) << 8) + 2823a89bcd4cSHans Verkuil hdmi_read(sd, 0x5f)); 2824a89bcd4cSHans Verkuil v4l2_info(sd, "AV Mute: %s\n", 2825a89bcd4cSHans Verkuil (hdmi_read(sd, 0x04) & 0x40) ? "on" : "off"); 2826a89bcd4cSHans Verkuil v4l2_info(sd, "Deep color mode: %s\n", 2827a89bcd4cSHans Verkuil deep_color_mode_txt[hdmi_read(sd, 0x0b) >> 6]); 2828a89bcd4cSHans Verkuil 282909f90c53SMartin Bugge adv7842_log_infoframes(sd); 283009f90c53SMartin Bugge 2831a89bcd4cSHans Verkuil return 0; 2832a89bcd4cSHans Verkuil } 2833a89bcd4cSHans Verkuil 2834a89bcd4cSHans Verkuil static int adv7842_log_status(struct v4l2_subdev *sd) 2835a89bcd4cSHans Verkuil { 2836a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 2837a89bcd4cSHans Verkuil 2838a89bcd4cSHans Verkuil if (state->mode == ADV7842_MODE_SDP) 2839a89bcd4cSHans Verkuil return adv7842_sdp_log_status(sd); 2840a89bcd4cSHans Verkuil return adv7842_cp_log_status(sd); 2841a89bcd4cSHans Verkuil } 2842a89bcd4cSHans Verkuil 2843a89bcd4cSHans Verkuil static int adv7842_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) 2844a89bcd4cSHans Verkuil { 2845a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 2846a89bcd4cSHans Verkuil 2847a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, "%s:\n", __func__); 2848a89bcd4cSHans Verkuil 2849a89bcd4cSHans Verkuil if (state->mode != ADV7842_MODE_SDP) 2850a89bcd4cSHans Verkuil return -ENODATA; 2851a89bcd4cSHans Verkuil 2852a89bcd4cSHans Verkuil if (!(sdp_read(sd, 0x5A) & 0x01)) { 2853a89bcd4cSHans Verkuil *std = 0; 2854a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, "%s: no valid signal\n", __func__); 2855a89bcd4cSHans Verkuil return 0; 2856a89bcd4cSHans Verkuil } 2857a89bcd4cSHans Verkuil 2858a89bcd4cSHans Verkuil switch (sdp_read(sd, 0x52) & 0x0f) { 2859a89bcd4cSHans Verkuil case 0: 2860a89bcd4cSHans Verkuil /* NTSC-M/J */ 2861a89bcd4cSHans Verkuil *std &= V4L2_STD_NTSC; 2862a89bcd4cSHans Verkuil break; 2863a89bcd4cSHans Verkuil case 2: 2864a89bcd4cSHans Verkuil /* NTSC-443 */ 2865a89bcd4cSHans Verkuil *std &= V4L2_STD_NTSC_443; 2866a89bcd4cSHans Verkuil break; 2867a89bcd4cSHans Verkuil case 3: 2868a89bcd4cSHans Verkuil /* 60HzSECAM */ 2869a89bcd4cSHans Verkuil *std &= V4L2_STD_SECAM; 2870a89bcd4cSHans Verkuil break; 2871a89bcd4cSHans Verkuil case 4: 2872a89bcd4cSHans Verkuil /* PAL-M */ 2873a89bcd4cSHans Verkuil *std &= V4L2_STD_PAL_M; 2874a89bcd4cSHans Verkuil break; 2875a89bcd4cSHans Verkuil case 6: 2876a89bcd4cSHans Verkuil /* PAL-60 */ 2877a89bcd4cSHans Verkuil *std &= V4L2_STD_PAL_60; 2878a89bcd4cSHans Verkuil break; 2879a89bcd4cSHans Verkuil case 0xc: 2880a89bcd4cSHans Verkuil /* PAL-CombN */ 2881a89bcd4cSHans Verkuil *std &= V4L2_STD_PAL_Nc; 2882a89bcd4cSHans Verkuil break; 2883a89bcd4cSHans Verkuil case 0xe: 2884a89bcd4cSHans Verkuil /* PAL-BGHID */ 2885a89bcd4cSHans Verkuil *std &= V4L2_STD_PAL; 2886a89bcd4cSHans Verkuil break; 2887a89bcd4cSHans Verkuil case 0xf: 2888a89bcd4cSHans Verkuil /* SECAM */ 2889a89bcd4cSHans Verkuil *std &= V4L2_STD_SECAM; 2890a89bcd4cSHans Verkuil break; 2891a89bcd4cSHans Verkuil default: 2892a89bcd4cSHans Verkuil *std &= V4L2_STD_ALL; 2893a89bcd4cSHans Verkuil break; 2894a89bcd4cSHans Verkuil } 2895a89bcd4cSHans Verkuil return 0; 2896a89bcd4cSHans Verkuil } 2897a89bcd4cSHans Verkuil 28983c4da74fSMartin Bugge static void adv7842_s_sdp_io(struct v4l2_subdev *sd, struct adv7842_sdp_io_sync_adjustment *s) 28993c4da74fSMartin Bugge { 29003c4da74fSMartin Bugge if (s && s->adjust) { 29013c4da74fSMartin Bugge sdp_io_write(sd, 0x94, (s->hs_beg >> 8) & 0xf); 29023c4da74fSMartin Bugge sdp_io_write(sd, 0x95, s->hs_beg & 0xff); 29033c4da74fSMartin Bugge sdp_io_write(sd, 0x96, (s->hs_width >> 8) & 0xf); 29043c4da74fSMartin Bugge sdp_io_write(sd, 0x97, s->hs_width & 0xff); 29053c4da74fSMartin Bugge sdp_io_write(sd, 0x98, (s->de_beg >> 8) & 0xf); 29063c4da74fSMartin Bugge sdp_io_write(sd, 0x99, s->de_beg & 0xff); 29073c4da74fSMartin Bugge sdp_io_write(sd, 0x9a, (s->de_end >> 8) & 0xf); 29083c4da74fSMartin Bugge sdp_io_write(sd, 0x9b, s->de_end & 0xff); 290915058aacSMartin Bugge sdp_io_write(sd, 0xa8, s->vs_beg_o); 291015058aacSMartin Bugge sdp_io_write(sd, 0xa9, s->vs_beg_e); 291115058aacSMartin Bugge sdp_io_write(sd, 0xaa, s->vs_end_o); 291215058aacSMartin Bugge sdp_io_write(sd, 0xab, s->vs_end_e); 29133c4da74fSMartin Bugge sdp_io_write(sd, 0xac, s->de_v_beg_o); 29143c4da74fSMartin Bugge sdp_io_write(sd, 0xad, s->de_v_beg_e); 29153c4da74fSMartin Bugge sdp_io_write(sd, 0xae, s->de_v_end_o); 29163c4da74fSMartin Bugge sdp_io_write(sd, 0xaf, s->de_v_end_e); 29173c4da74fSMartin Bugge } else { 29183c4da74fSMartin Bugge /* set to default */ 29193c4da74fSMartin Bugge sdp_io_write(sd, 0x94, 0x00); 29203c4da74fSMartin Bugge sdp_io_write(sd, 0x95, 0x00); 29213c4da74fSMartin Bugge sdp_io_write(sd, 0x96, 0x00); 29223c4da74fSMartin Bugge sdp_io_write(sd, 0x97, 0x20); 29233c4da74fSMartin Bugge sdp_io_write(sd, 0x98, 0x00); 29243c4da74fSMartin Bugge sdp_io_write(sd, 0x99, 0x00); 29253c4da74fSMartin Bugge sdp_io_write(sd, 0x9a, 0x00); 29263c4da74fSMartin Bugge sdp_io_write(sd, 0x9b, 0x00); 292715058aacSMartin Bugge sdp_io_write(sd, 0xa8, 0x04); 292815058aacSMartin Bugge sdp_io_write(sd, 0xa9, 0x04); 292915058aacSMartin Bugge sdp_io_write(sd, 0xaa, 0x04); 293015058aacSMartin Bugge sdp_io_write(sd, 0xab, 0x04); 29313c4da74fSMartin Bugge sdp_io_write(sd, 0xac, 0x04); 29323c4da74fSMartin Bugge sdp_io_write(sd, 0xad, 0x04); 29333c4da74fSMartin Bugge sdp_io_write(sd, 0xae, 0x04); 29343c4da74fSMartin Bugge sdp_io_write(sd, 0xaf, 0x04); 29353c4da74fSMartin Bugge } 29363c4da74fSMartin Bugge } 29373c4da74fSMartin Bugge 2938a89bcd4cSHans Verkuil static int adv7842_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) 2939a89bcd4cSHans Verkuil { 2940a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 29413c4da74fSMartin Bugge struct adv7842_platform_data *pdata = &state->pdata; 2942a89bcd4cSHans Verkuil 2943a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, "%s:\n", __func__); 2944a89bcd4cSHans Verkuil 2945a89bcd4cSHans Verkuil if (state->mode != ADV7842_MODE_SDP) 2946a89bcd4cSHans Verkuil return -ENODATA; 2947a89bcd4cSHans Verkuil 29483c4da74fSMartin Bugge if (norm & V4L2_STD_625_50) 29493c4da74fSMartin Bugge adv7842_s_sdp_io(sd, &pdata->sdp_io_sync_625); 29503c4da74fSMartin Bugge else if (norm & V4L2_STD_525_60) 29513c4da74fSMartin Bugge adv7842_s_sdp_io(sd, &pdata->sdp_io_sync_525); 29523c4da74fSMartin Bugge else 29533c4da74fSMartin Bugge adv7842_s_sdp_io(sd, NULL); 29543c4da74fSMartin Bugge 2955a89bcd4cSHans Verkuil if (norm & V4L2_STD_ALL) { 2956a89bcd4cSHans Verkuil state->norm = norm; 2957a89bcd4cSHans Verkuil return 0; 2958a89bcd4cSHans Verkuil } 2959a89bcd4cSHans Verkuil return -EINVAL; 2960a89bcd4cSHans Verkuil } 2961a89bcd4cSHans Verkuil 2962a89bcd4cSHans Verkuil static int adv7842_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm) 2963a89bcd4cSHans Verkuil { 2964a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 2965a89bcd4cSHans Verkuil 2966a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, "%s:\n", __func__); 2967a89bcd4cSHans Verkuil 2968a89bcd4cSHans Verkuil if (state->mode != ADV7842_MODE_SDP) 2969a89bcd4cSHans Verkuil return -ENODATA; 2970a89bcd4cSHans Verkuil 2971a89bcd4cSHans Verkuil *norm = state->norm; 2972a89bcd4cSHans Verkuil return 0; 2973a89bcd4cSHans Verkuil } 2974a89bcd4cSHans Verkuil 2975a89bcd4cSHans Verkuil /* ----------------------------------------------------------------------- */ 2976a89bcd4cSHans Verkuil 297769e9ba6fSHans Verkuil static int adv7842_core_init(struct v4l2_subdev *sd) 2978a89bcd4cSHans Verkuil { 297969e9ba6fSHans Verkuil struct adv7842_state *state = to_state(sd); 298069e9ba6fSHans Verkuil struct adv7842_platform_data *pdata = &state->pdata; 2981a89bcd4cSHans Verkuil hdmi_write(sd, 0x48, 2982a89bcd4cSHans Verkuil (pdata->disable_pwrdnb ? 0x80 : 0) | 2983a89bcd4cSHans Verkuil (pdata->disable_cable_det_rst ? 0x40 : 0)); 2984a89bcd4cSHans Verkuil 2985a89bcd4cSHans Verkuil disable_input(sd); 2986a89bcd4cSHans Verkuil 29872ff0f16dSMartin Bugge /* 29882ff0f16dSMartin Bugge * Disable I2C access to internal EDID ram from HDMI DDC ports 29892ff0f16dSMartin Bugge * Disable auto edid enable when leaving powerdown mode 29902ff0f16dSMartin Bugge */ 29912ff0f16dSMartin Bugge rep_write_and_or(sd, 0x77, 0xd3, 0x20); 29922ff0f16dSMartin Bugge 2993a89bcd4cSHans Verkuil /* power */ 2994a89bcd4cSHans Verkuil io_write(sd, 0x0c, 0x42); /* Power up part and power down VDP */ 2995a89bcd4cSHans Verkuil io_write(sd, 0x15, 0x80); /* Power up pads */ 2996a89bcd4cSHans Verkuil 2997a89bcd4cSHans Verkuil /* video format */ 2998fd74246dSHans Verkuil io_write(sd, 0x02, 0xf0 | pdata->alt_gamma << 3); 2999a89bcd4cSHans Verkuil io_write_and_or(sd, 0x05, 0xf0, pdata->blank_data << 3 | 3000a89bcd4cSHans Verkuil pdata->insert_av_codes << 2 | 3001f888ae7eSHans Verkuil pdata->replicate_av_codes << 1); 3002f888ae7eSHans Verkuil adv7842_setup_format(state); 3003a89bcd4cSHans Verkuil 30045b64b205SMats Randgaard /* HDMI audio */ 30055b64b205SMats Randgaard hdmi_write_and_or(sd, 0x1a, 0xf1, 0x08); /* Wait 1 s before unmute */ 30065b64b205SMats Randgaard 3007a89bcd4cSHans Verkuil /* Drive strength */ 30087f95c904SHans Verkuil io_write_and_or(sd, 0x14, 0xc0, 30097f95c904SHans Verkuil pdata->dr_str_data << 4 | 30107f95c904SHans Verkuil pdata->dr_str_clk << 2 | 30117f95c904SHans Verkuil pdata->dr_str_sync); 3012a89bcd4cSHans Verkuil 3013a89bcd4cSHans Verkuil /* HDMI free run */ 3014f0ec1742SMartin Bugge cp_write_and_or(sd, 0xba, 0xfc, pdata->hdmi_free_run_enable | 3015f0ec1742SMartin Bugge (pdata->hdmi_free_run_mode << 1)); 3016f0ec1742SMartin Bugge 3017f0ec1742SMartin Bugge /* SPD free run */ 3018f0ec1742SMartin Bugge sdp_write_and_or(sd, 0xdd, 0xf0, pdata->sdp_free_run_force | 3019f0ec1742SMartin Bugge (pdata->sdp_free_run_cbar_en << 1) | 3020f0ec1742SMartin Bugge (pdata->sdp_free_run_man_col_en << 2) | 302157f0547fSMartin Bugge (pdata->sdp_free_run_auto << 3)); 3022a89bcd4cSHans Verkuil 3023a89bcd4cSHans Verkuil /* TODO from platform data */ 3024a89bcd4cSHans Verkuil cp_write(sd, 0x69, 0x14); /* Enable CP CSC */ 3025a89bcd4cSHans Verkuil io_write(sd, 0x06, 0xa6); /* positive VS and HS and DE */ 3026a89bcd4cSHans Verkuil cp_write(sd, 0xf3, 0xdc); /* Low threshold to enter/exit free run mode */ 3027a89bcd4cSHans Verkuil afe_write(sd, 0xb5, 0x01); /* Setting MCLK to 256Fs */ 3028a89bcd4cSHans Verkuil 3029a89bcd4cSHans Verkuil afe_write(sd, 0x02, pdata->ain_sel); /* Select analog input muxing mode */ 3030a89bcd4cSHans Verkuil io_write_and_or(sd, 0x30, ~(1 << 4), pdata->output_bus_lsb_to_msb << 4); 3031a89bcd4cSHans Verkuil 3032a89bcd4cSHans Verkuil sdp_csc_coeff(sd, &pdata->sdp_csc_coeff); 3033a89bcd4cSHans Verkuil 3034a89bcd4cSHans Verkuil /* todo, improve settings for sdram */ 3035a89bcd4cSHans Verkuil if (pdata->sd_ram_size >= 128) { 3036a89bcd4cSHans Verkuil sdp_write(sd, 0x12, 0x0d); /* Frame TBC,3D comb enabled */ 3037a89bcd4cSHans Verkuil if (pdata->sd_ram_ddr) { 3038a89bcd4cSHans Verkuil /* SDP setup for the AD eval board */ 3039a89bcd4cSHans Verkuil sdp_io_write(sd, 0x6f, 0x00); /* DDR mode */ 3040a89bcd4cSHans Verkuil sdp_io_write(sd, 0x75, 0x0a); /* 128 MB memory size */ 3041a89bcd4cSHans Verkuil sdp_io_write(sd, 0x7a, 0xa5); /* Timing Adjustment */ 3042a89bcd4cSHans Verkuil sdp_io_write(sd, 0x7b, 0x8f); /* Timing Adjustment */ 3043a89bcd4cSHans Verkuil sdp_io_write(sd, 0x60, 0x01); /* SDRAM reset */ 3044a89bcd4cSHans Verkuil } else { 3045a89bcd4cSHans Verkuil sdp_io_write(sd, 0x75, 0x0a); /* 64 MB memory size ?*/ 3046a89bcd4cSHans Verkuil sdp_io_write(sd, 0x74, 0x00); /* must be zero for sdr sdram */ 3047a89bcd4cSHans Verkuil sdp_io_write(sd, 0x79, 0x33); /* CAS latency to 3, 3048a89bcd4cSHans Verkuil depends on memory */ 3049a89bcd4cSHans Verkuil sdp_io_write(sd, 0x6f, 0x01); /* SDR mode */ 3050a89bcd4cSHans Verkuil sdp_io_write(sd, 0x7a, 0xa5); /* Timing Adjustment */ 3051a89bcd4cSHans Verkuil sdp_io_write(sd, 0x7b, 0x8f); /* Timing Adjustment */ 3052a89bcd4cSHans Verkuil sdp_io_write(sd, 0x60, 0x01); /* SDRAM reset */ 3053a89bcd4cSHans Verkuil } 3054a89bcd4cSHans Verkuil } else { 3055a89bcd4cSHans Verkuil /* 3056a89bcd4cSHans Verkuil * Manual UG-214, rev 0 is bit confusing on this bit 3057a89bcd4cSHans Verkuil * but a '1' disables any signal if the Ram is active. 3058a89bcd4cSHans Verkuil */ 3059a89bcd4cSHans Verkuil sdp_io_write(sd, 0x29, 0x10); /* Tristate memory interface */ 3060a89bcd4cSHans Verkuil } 3061a89bcd4cSHans Verkuil 3062a89bcd4cSHans Verkuil select_input(sd, pdata->vid_std_select); 3063a89bcd4cSHans Verkuil 3064a89bcd4cSHans Verkuil enable_input(sd); 3065a89bcd4cSHans Verkuil 3066ce2d2b2dSMartin Bugge if (pdata->hpa_auto) { 3067ce2d2b2dSMartin Bugge /* HPA auto, HPA 0.5s after Edid set and Cable detect */ 3068ce2d2b2dSMartin Bugge hdmi_write(sd, 0x69, 0x5c); 3069ce2d2b2dSMartin Bugge } else { 3070ce2d2b2dSMartin Bugge /* HPA manual */ 3071ce2d2b2dSMartin Bugge hdmi_write(sd, 0x69, 0xa3); 3072a89bcd4cSHans Verkuil /* HPA disable on port A and B */ 3073a89bcd4cSHans Verkuil io_write_and_or(sd, 0x20, 0xcf, 0x00); 3074ce2d2b2dSMartin Bugge } 3075a89bcd4cSHans Verkuil 3076a89bcd4cSHans Verkuil /* LLC */ 3077fe808f3cSHans Verkuil io_write(sd, 0x19, 0x80 | pdata->llc_dll_phase); 3078a89bcd4cSHans Verkuil io_write(sd, 0x33, 0x40); 3079a89bcd4cSHans Verkuil 3080a89bcd4cSHans Verkuil /* interrupts */ 3081c9f1f271SMartin Bugge io_write(sd, 0x40, 0xf2); /* Configure INT1 */ 3082a89bcd4cSHans Verkuil 3083a89bcd4cSHans Verkuil adv7842_irq_enable(sd, true); 3084a89bcd4cSHans Verkuil 3085a89bcd4cSHans Verkuil return v4l2_ctrl_handler_setup(sd->ctrl_handler); 3086a89bcd4cSHans Verkuil } 3087a89bcd4cSHans Verkuil 3088a89bcd4cSHans Verkuil /* ----------------------------------------------------------------------- */ 3089a89bcd4cSHans Verkuil 3090a89bcd4cSHans Verkuil static int adv7842_ddr_ram_test(struct v4l2_subdev *sd) 3091a89bcd4cSHans Verkuil { 3092a89bcd4cSHans Verkuil /* 3093a89bcd4cSHans Verkuil * From ADV784x external Memory test.pdf 3094a89bcd4cSHans Verkuil * 3095a89bcd4cSHans Verkuil * Reset must just been performed before running test. 3096a89bcd4cSHans Verkuil * Recommended to reset after test. 3097a89bcd4cSHans Verkuil */ 3098a89bcd4cSHans Verkuil int i; 3099a89bcd4cSHans Verkuil int pass = 0; 3100a89bcd4cSHans Verkuil int fail = 0; 3101a89bcd4cSHans Verkuil int complete = 0; 3102a89bcd4cSHans Verkuil 3103a89bcd4cSHans Verkuil io_write(sd, 0x00, 0x01); /* Program SDP 4x1 */ 3104a89bcd4cSHans Verkuil io_write(sd, 0x01, 0x00); /* Program SDP mode */ 3105a89bcd4cSHans Verkuil afe_write(sd, 0x80, 0x92); /* SDP Recommeneded Write */ 3106a89bcd4cSHans Verkuil afe_write(sd, 0x9B, 0x01); /* SDP Recommeneded Write ADV7844ES1 */ 3107a89bcd4cSHans Verkuil afe_write(sd, 0x9C, 0x60); /* SDP Recommeneded Write ADV7844ES1 */ 3108a89bcd4cSHans Verkuil afe_write(sd, 0x9E, 0x02); /* SDP Recommeneded Write ADV7844ES1 */ 3109a89bcd4cSHans Verkuil afe_write(sd, 0xA0, 0x0B); /* SDP Recommeneded Write ADV7844ES1 */ 3110a89bcd4cSHans Verkuil afe_write(sd, 0xC3, 0x02); /* Memory BIST Initialisation */ 3111a89bcd4cSHans Verkuil io_write(sd, 0x0C, 0x40); /* Power up ADV7844 */ 3112a89bcd4cSHans Verkuil io_write(sd, 0x15, 0xBA); /* Enable outputs */ 3113a89bcd4cSHans Verkuil sdp_write(sd, 0x12, 0x00); /* Disable 3D comb, Frame TBC & 3DNR */ 3114a89bcd4cSHans Verkuil io_write(sd, 0xFF, 0x04); /* Reset memory controller */ 3115a89bcd4cSHans Verkuil 31162b5c5798SJia-Ju Bai usleep_range(5000, 6000); 3117a89bcd4cSHans Verkuil 3118a89bcd4cSHans Verkuil sdp_write(sd, 0x12, 0x00); /* Disable 3D Comb, Frame TBC & 3DNR */ 3119a89bcd4cSHans Verkuil sdp_io_write(sd, 0x2A, 0x01); /* Memory BIST Initialisation */ 3120a89bcd4cSHans Verkuil sdp_io_write(sd, 0x7c, 0x19); /* Memory BIST Initialisation */ 3121a89bcd4cSHans Verkuil sdp_io_write(sd, 0x80, 0x87); /* Memory BIST Initialisation */ 3122a89bcd4cSHans Verkuil sdp_io_write(sd, 0x81, 0x4a); /* Memory BIST Initialisation */ 3123a89bcd4cSHans Verkuil sdp_io_write(sd, 0x82, 0x2c); /* Memory BIST Initialisation */ 3124a89bcd4cSHans Verkuil sdp_io_write(sd, 0x83, 0x0e); /* Memory BIST Initialisation */ 3125a89bcd4cSHans Verkuil sdp_io_write(sd, 0x84, 0x94); /* Memory BIST Initialisation */ 3126a89bcd4cSHans Verkuil sdp_io_write(sd, 0x85, 0x62); /* Memory BIST Initialisation */ 3127a89bcd4cSHans Verkuil sdp_io_write(sd, 0x7d, 0x00); /* Memory BIST Initialisation */ 3128a89bcd4cSHans Verkuil sdp_io_write(sd, 0x7e, 0x1a); /* Memory BIST Initialisation */ 3129a89bcd4cSHans Verkuil 31302b5c5798SJia-Ju Bai usleep_range(5000, 6000); 3131a89bcd4cSHans Verkuil 3132a89bcd4cSHans Verkuil sdp_io_write(sd, 0xd9, 0xd5); /* Enable BIST Test */ 3133a89bcd4cSHans Verkuil sdp_write(sd, 0x12, 0x05); /* Enable FRAME TBC & 3D COMB */ 3134a89bcd4cSHans Verkuil 31352b5c5798SJia-Ju Bai msleep(20); 3136a89bcd4cSHans Verkuil 3137a89bcd4cSHans Verkuil for (i = 0; i < 10; i++) { 3138a89bcd4cSHans Verkuil u8 result = sdp_io_read(sd, 0xdb); 3139a89bcd4cSHans Verkuil if (result & 0x10) { 3140a89bcd4cSHans Verkuil complete++; 3141a89bcd4cSHans Verkuil if (result & 0x20) 3142a89bcd4cSHans Verkuil fail++; 3143a89bcd4cSHans Verkuil else 3144a89bcd4cSHans Verkuil pass++; 3145a89bcd4cSHans Verkuil } 31462b5c5798SJia-Ju Bai msleep(20); 3147a89bcd4cSHans Verkuil } 3148a89bcd4cSHans Verkuil 3149a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, 3150a89bcd4cSHans Verkuil "Ram Test: completed %d of %d: pass %d, fail %d\n", 3151a89bcd4cSHans Verkuil complete, i, pass, fail); 3152a89bcd4cSHans Verkuil 3153a89bcd4cSHans Verkuil if (!complete || fail) 3154a89bcd4cSHans Verkuil return -EIO; 3155a89bcd4cSHans Verkuil return 0; 3156a89bcd4cSHans Verkuil } 3157a89bcd4cSHans Verkuil 3158a89bcd4cSHans Verkuil static void adv7842_rewrite_i2c_addresses(struct v4l2_subdev *sd, 3159a89bcd4cSHans Verkuil struct adv7842_platform_data *pdata) 3160a89bcd4cSHans Verkuil { 3161a89bcd4cSHans Verkuil io_write(sd, 0xf1, pdata->i2c_sdp << 1); 3162a89bcd4cSHans Verkuil io_write(sd, 0xf2, pdata->i2c_sdp_io << 1); 3163a89bcd4cSHans Verkuil io_write(sd, 0xf3, pdata->i2c_avlink << 1); 3164a89bcd4cSHans Verkuil io_write(sd, 0xf4, pdata->i2c_cec << 1); 3165a89bcd4cSHans Verkuil io_write(sd, 0xf5, pdata->i2c_infoframe << 1); 3166a89bcd4cSHans Verkuil 3167a89bcd4cSHans Verkuil io_write(sd, 0xf8, pdata->i2c_afe << 1); 3168a89bcd4cSHans Verkuil io_write(sd, 0xf9, pdata->i2c_repeater << 1); 3169a89bcd4cSHans Verkuil io_write(sd, 0xfa, pdata->i2c_edid << 1); 3170a89bcd4cSHans Verkuil io_write(sd, 0xfb, pdata->i2c_hdmi << 1); 3171a89bcd4cSHans Verkuil 3172a89bcd4cSHans Verkuil io_write(sd, 0xfd, pdata->i2c_cp << 1); 3173a89bcd4cSHans Verkuil io_write(sd, 0xfe, pdata->i2c_vdp << 1); 3174a89bcd4cSHans Verkuil } 3175a89bcd4cSHans Verkuil 3176a89bcd4cSHans Verkuil static int adv7842_command_ram_test(struct v4l2_subdev *sd) 3177a89bcd4cSHans Verkuil { 3178a89bcd4cSHans Verkuil struct i2c_client *client = v4l2_get_subdevdata(sd); 3179a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 3180a89bcd4cSHans Verkuil struct adv7842_platform_data *pdata = client->dev.platform_data; 31811961b720SMartin Bugge struct v4l2_dv_timings timings; 3182a89bcd4cSHans Verkuil int ret = 0; 3183a89bcd4cSHans Verkuil 3184a89bcd4cSHans Verkuil if (!pdata) 3185a89bcd4cSHans Verkuil return -ENODEV; 3186a89bcd4cSHans Verkuil 3187a89bcd4cSHans Verkuil if (!pdata->sd_ram_size || !pdata->sd_ram_ddr) { 3188a89bcd4cSHans Verkuil v4l2_info(sd, "no sdram or no ddr sdram\n"); 3189a89bcd4cSHans Verkuil return -EINVAL; 3190a89bcd4cSHans Verkuil } 3191a89bcd4cSHans Verkuil 3192a89bcd4cSHans Verkuil main_reset(sd); 3193a89bcd4cSHans Verkuil 3194a89bcd4cSHans Verkuil adv7842_rewrite_i2c_addresses(sd, pdata); 3195a89bcd4cSHans Verkuil 3196a89bcd4cSHans Verkuil /* run ram test */ 3197a89bcd4cSHans Verkuil ret = adv7842_ddr_ram_test(sd); 3198a89bcd4cSHans Verkuil 3199a89bcd4cSHans Verkuil main_reset(sd); 3200a89bcd4cSHans Verkuil 3201a89bcd4cSHans Verkuil adv7842_rewrite_i2c_addresses(sd, pdata); 3202a89bcd4cSHans Verkuil 3203a89bcd4cSHans Verkuil /* and re-init chip and state */ 320469e9ba6fSHans Verkuil adv7842_core_init(sd); 3205a89bcd4cSHans Verkuil 3206a89bcd4cSHans Verkuil disable_input(sd); 3207a89bcd4cSHans Verkuil 3208a89bcd4cSHans Verkuil select_input(sd, state->vid_std_select); 3209a89bcd4cSHans Verkuil 3210a89bcd4cSHans Verkuil enable_input(sd); 3211a89bcd4cSHans Verkuil 3212a89bcd4cSHans Verkuil edid_write_vga_segment(sd); 3213fc2e991eSMartin Bugge edid_write_hdmi_segment(sd, ADV7842_EDID_PORT_A); 3214fc2e991eSMartin Bugge edid_write_hdmi_segment(sd, ADV7842_EDID_PORT_B); 3215a89bcd4cSHans Verkuil 32161961b720SMartin Bugge timings = state->timings; 32171961b720SMartin Bugge 32181961b720SMartin Bugge memset(&state->timings, 0, sizeof(struct v4l2_dv_timings)); 32191961b720SMartin Bugge 32201961b720SMartin Bugge adv7842_s_dv_timings(sd, &timings); 32211961b720SMartin Bugge 3222a89bcd4cSHans Verkuil return ret; 3223a89bcd4cSHans Verkuil } 3224a89bcd4cSHans Verkuil 3225a89bcd4cSHans Verkuil static long adv7842_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) 3226a89bcd4cSHans Verkuil { 3227a89bcd4cSHans Verkuil switch (cmd) { 3228a89bcd4cSHans Verkuil case ADV7842_CMD_RAM_TEST: 3229a89bcd4cSHans Verkuil return adv7842_command_ram_test(sd); 3230a89bcd4cSHans Verkuil } 3231a89bcd4cSHans Verkuil return -ENOTTY; 3232a89bcd4cSHans Verkuil } 3233a89bcd4cSHans Verkuil 32342cf4090fSLars-Peter Clausen static int adv7842_subscribe_event(struct v4l2_subdev *sd, 32352cf4090fSLars-Peter Clausen struct v4l2_fh *fh, 32362cf4090fSLars-Peter Clausen struct v4l2_event_subscription *sub) 32372cf4090fSLars-Peter Clausen { 32382cf4090fSLars-Peter Clausen switch (sub->type) { 32392cf4090fSLars-Peter Clausen case V4L2_EVENT_SOURCE_CHANGE: 32402cf4090fSLars-Peter Clausen return v4l2_src_change_event_subdev_subscribe(sd, fh, sub); 32412cf4090fSLars-Peter Clausen case V4L2_EVENT_CTRL: 32422cf4090fSLars-Peter Clausen return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub); 32432cf4090fSLars-Peter Clausen default: 32442cf4090fSLars-Peter Clausen return -EINVAL; 32452cf4090fSLars-Peter Clausen } 32462cf4090fSLars-Peter Clausen } 32472cf4090fSLars-Peter Clausen 324825c84fb1SHans Verkuil static int adv7842_registered(struct v4l2_subdev *sd) 324925c84fb1SHans Verkuil { 325025c84fb1SHans Verkuil struct adv7842_state *state = to_state(sd); 3251f51e8080SHans Verkuil struct i2c_client *client = v4l2_get_subdevdata(sd); 325225c84fb1SHans Verkuil int err; 325325c84fb1SHans Verkuil 3254f51e8080SHans Verkuil err = cec_register_adapter(state->cec_adap, &client->dev); 325525c84fb1SHans Verkuil if (err) 325625c84fb1SHans Verkuil cec_delete_adapter(state->cec_adap); 325725c84fb1SHans Verkuil return err; 325825c84fb1SHans Verkuil } 325925c84fb1SHans Verkuil 326025c84fb1SHans Verkuil static void adv7842_unregistered(struct v4l2_subdev *sd) 326125c84fb1SHans Verkuil { 326225c84fb1SHans Verkuil struct adv7842_state *state = to_state(sd); 326325c84fb1SHans Verkuil 326425c84fb1SHans Verkuil cec_unregister_adapter(state->cec_adap); 326525c84fb1SHans Verkuil } 326625c84fb1SHans Verkuil 3267a89bcd4cSHans Verkuil /* ----------------------------------------------------------------------- */ 3268a89bcd4cSHans Verkuil 3269a89bcd4cSHans Verkuil static const struct v4l2_ctrl_ops adv7842_ctrl_ops = { 3270a89bcd4cSHans Verkuil .s_ctrl = adv7842_s_ctrl, 3271e8979274SHans Verkuil .g_volatile_ctrl = adv7842_g_volatile_ctrl, 3272a89bcd4cSHans Verkuil }; 3273a89bcd4cSHans Verkuil 3274a89bcd4cSHans Verkuil static const struct v4l2_subdev_core_ops adv7842_core_ops = { 3275a89bcd4cSHans Verkuil .log_status = adv7842_log_status, 3276a89bcd4cSHans Verkuil .ioctl = adv7842_ioctl, 3277a89bcd4cSHans Verkuil .interrupt_service_routine = adv7842_isr, 32782cf4090fSLars-Peter Clausen .subscribe_event = adv7842_subscribe_event, 3279aef5159fSLars-Peter Clausen .unsubscribe_event = v4l2_event_subdev_unsubscribe, 3280a89bcd4cSHans Verkuil #ifdef CONFIG_VIDEO_ADV_DEBUG 3281a89bcd4cSHans Verkuil .g_register = adv7842_g_register, 3282a89bcd4cSHans Verkuil .s_register = adv7842_s_register, 3283a89bcd4cSHans Verkuil #endif 3284a89bcd4cSHans Verkuil }; 3285a89bcd4cSHans Verkuil 3286a89bcd4cSHans Verkuil static const struct v4l2_subdev_video_ops adv7842_video_ops = { 32878774bed9SLaurent Pinchart .g_std = adv7842_g_std, 32888774bed9SLaurent Pinchart .s_std = adv7842_s_std, 3289a89bcd4cSHans Verkuil .s_routing = adv7842_s_routing, 3290a89bcd4cSHans Verkuil .querystd = adv7842_querystd, 3291a89bcd4cSHans Verkuil .g_input_status = adv7842_g_input_status, 3292a89bcd4cSHans Verkuil .s_dv_timings = adv7842_s_dv_timings, 3293a89bcd4cSHans Verkuil .g_dv_timings = adv7842_g_dv_timings, 3294a89bcd4cSHans Verkuil .query_dv_timings = adv7842_query_dv_timings, 3295a89bcd4cSHans Verkuil }; 3296a89bcd4cSHans Verkuil 3297a89bcd4cSHans Verkuil static const struct v4l2_subdev_pad_ops adv7842_pad_ops = { 3298f888ae7eSHans Verkuil .enum_mbus_code = adv7842_enum_mbus_code, 3299f888ae7eSHans Verkuil .get_fmt = adv7842_get_format, 3300f888ae7eSHans Verkuil .set_fmt = adv7842_set_format, 3301245b2b67SMartin Bugge .get_edid = adv7842_get_edid, 3302a89bcd4cSHans Verkuil .set_edid = adv7842_set_edid, 3303c916194cSLaurent Pinchart .enum_dv_timings = adv7842_enum_dv_timings, 3304c916194cSLaurent Pinchart .dv_timings_cap = adv7842_dv_timings_cap, 3305a89bcd4cSHans Verkuil }; 3306a89bcd4cSHans Verkuil 3307a89bcd4cSHans Verkuil static const struct v4l2_subdev_ops adv7842_ops = { 3308a89bcd4cSHans Verkuil .core = &adv7842_core_ops, 3309a89bcd4cSHans Verkuil .video = &adv7842_video_ops, 3310a89bcd4cSHans Verkuil .pad = &adv7842_pad_ops, 3311a89bcd4cSHans Verkuil }; 3312a89bcd4cSHans Verkuil 331325c84fb1SHans Verkuil static const struct v4l2_subdev_internal_ops adv7842_int_ops = { 331425c84fb1SHans Verkuil .registered = adv7842_registered, 331525c84fb1SHans Verkuil .unregistered = adv7842_unregistered, 331625c84fb1SHans Verkuil }; 331725c84fb1SHans Verkuil 3318a89bcd4cSHans Verkuil /* -------------------------- custom ctrls ---------------------------------- */ 3319a89bcd4cSHans Verkuil 3320a89bcd4cSHans Verkuil static const struct v4l2_ctrl_config adv7842_ctrl_analog_sampling_phase = { 3321a89bcd4cSHans Verkuil .ops = &adv7842_ctrl_ops, 3322a89bcd4cSHans Verkuil .id = V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE, 3323a89bcd4cSHans Verkuil .name = "Analog Sampling Phase", 3324a89bcd4cSHans Verkuil .type = V4L2_CTRL_TYPE_INTEGER, 3325a89bcd4cSHans Verkuil .min = 0, 3326a89bcd4cSHans Verkuil .max = 0x1f, 3327a89bcd4cSHans Verkuil .step = 1, 3328a89bcd4cSHans Verkuil .def = 0, 3329a89bcd4cSHans Verkuil }; 3330a89bcd4cSHans Verkuil 3331a89bcd4cSHans Verkuil static const struct v4l2_ctrl_config adv7842_ctrl_free_run_color_manual = { 3332a89bcd4cSHans Verkuil .ops = &adv7842_ctrl_ops, 3333a89bcd4cSHans Verkuil .id = V4L2_CID_ADV_RX_FREE_RUN_COLOR_MANUAL, 3334a89bcd4cSHans Verkuil .name = "Free Running Color, Manual", 3335a89bcd4cSHans Verkuil .type = V4L2_CTRL_TYPE_BOOLEAN, 3336a89bcd4cSHans Verkuil .max = 1, 3337a89bcd4cSHans Verkuil .step = 1, 3338a89bcd4cSHans Verkuil .def = 1, 3339a89bcd4cSHans Verkuil }; 3340a89bcd4cSHans Verkuil 3341a89bcd4cSHans Verkuil static const struct v4l2_ctrl_config adv7842_ctrl_free_run_color = { 3342a89bcd4cSHans Verkuil .ops = &adv7842_ctrl_ops, 3343a89bcd4cSHans Verkuil .id = V4L2_CID_ADV_RX_FREE_RUN_COLOR, 3344a89bcd4cSHans Verkuil .name = "Free Running Color", 3345a89bcd4cSHans Verkuil .type = V4L2_CTRL_TYPE_INTEGER, 3346a89bcd4cSHans Verkuil .max = 0xffffff, 3347a89bcd4cSHans Verkuil .step = 0x1, 3348a89bcd4cSHans Verkuil }; 3349a89bcd4cSHans Verkuil 3350a89bcd4cSHans Verkuil 3351b82e2793SMartin Bugge static void adv7842_unregister_clients(struct v4l2_subdev *sd) 3352a89bcd4cSHans Verkuil { 3353b82e2793SMartin Bugge struct adv7842_state *state = to_state(sd); 3354a89bcd4cSHans Verkuil if (state->i2c_avlink) 3355a89bcd4cSHans Verkuil i2c_unregister_device(state->i2c_avlink); 3356a89bcd4cSHans Verkuil if (state->i2c_cec) 3357a89bcd4cSHans Verkuil i2c_unregister_device(state->i2c_cec); 3358a89bcd4cSHans Verkuil if (state->i2c_infoframe) 3359a89bcd4cSHans Verkuil i2c_unregister_device(state->i2c_infoframe); 3360a89bcd4cSHans Verkuil if (state->i2c_sdp_io) 3361a89bcd4cSHans Verkuil i2c_unregister_device(state->i2c_sdp_io); 3362a89bcd4cSHans Verkuil if (state->i2c_sdp) 3363a89bcd4cSHans Verkuil i2c_unregister_device(state->i2c_sdp); 3364a89bcd4cSHans Verkuil if (state->i2c_afe) 3365a89bcd4cSHans Verkuil i2c_unregister_device(state->i2c_afe); 3366a89bcd4cSHans Verkuil if (state->i2c_repeater) 3367a89bcd4cSHans Verkuil i2c_unregister_device(state->i2c_repeater); 3368a89bcd4cSHans Verkuil if (state->i2c_edid) 3369a89bcd4cSHans Verkuil i2c_unregister_device(state->i2c_edid); 3370a89bcd4cSHans Verkuil if (state->i2c_hdmi) 3371a89bcd4cSHans Verkuil i2c_unregister_device(state->i2c_hdmi); 3372a89bcd4cSHans Verkuil if (state->i2c_cp) 3373a89bcd4cSHans Verkuil i2c_unregister_device(state->i2c_cp); 3374a89bcd4cSHans Verkuil if (state->i2c_vdp) 3375a89bcd4cSHans Verkuil i2c_unregister_device(state->i2c_vdp); 3376b82e2793SMartin Bugge 3377b82e2793SMartin Bugge state->i2c_avlink = NULL; 3378b82e2793SMartin Bugge state->i2c_cec = NULL; 3379b82e2793SMartin Bugge state->i2c_infoframe = NULL; 3380b82e2793SMartin Bugge state->i2c_sdp_io = NULL; 3381b82e2793SMartin Bugge state->i2c_sdp = NULL; 3382b82e2793SMartin Bugge state->i2c_afe = NULL; 3383b82e2793SMartin Bugge state->i2c_repeater = NULL; 3384b82e2793SMartin Bugge state->i2c_edid = NULL; 3385b82e2793SMartin Bugge state->i2c_hdmi = NULL; 3386b82e2793SMartin Bugge state->i2c_cp = NULL; 3387b82e2793SMartin Bugge state->i2c_vdp = NULL; 3388a89bcd4cSHans Verkuil } 3389a89bcd4cSHans Verkuil 3390b82e2793SMartin Bugge static struct i2c_client *adv7842_dummy_client(struct v4l2_subdev *sd, const char *desc, 3391a89bcd4cSHans Verkuil u8 addr, u8 io_reg) 3392a89bcd4cSHans Verkuil { 3393a89bcd4cSHans Verkuil struct i2c_client *client = v4l2_get_subdevdata(sd); 3394b82e2793SMartin Bugge struct i2c_client *cp; 3395a89bcd4cSHans Verkuil 3396a89bcd4cSHans Verkuil io_write(sd, io_reg, addr << 1); 3397b82e2793SMartin Bugge 3398b82e2793SMartin Bugge if (addr == 0) { 3399b82e2793SMartin Bugge v4l2_err(sd, "no %s i2c addr configured\n", desc); 3400b82e2793SMartin Bugge return NULL; 3401b82e2793SMartin Bugge } 3402b82e2793SMartin Bugge 3403b82e2793SMartin Bugge cp = i2c_new_dummy(client->adapter, io_read(sd, io_reg) >> 1); 3404b82e2793SMartin Bugge if (!cp) 3405b82e2793SMartin Bugge v4l2_err(sd, "register %s on i2c addr 0x%x failed\n", desc, addr); 3406b82e2793SMartin Bugge 3407b82e2793SMartin Bugge return cp; 3408b82e2793SMartin Bugge } 3409b82e2793SMartin Bugge 3410b82e2793SMartin Bugge static int adv7842_register_clients(struct v4l2_subdev *sd) 3411b82e2793SMartin Bugge { 3412b82e2793SMartin Bugge struct adv7842_state *state = to_state(sd); 3413b82e2793SMartin Bugge struct adv7842_platform_data *pdata = &state->pdata; 3414b82e2793SMartin Bugge 3415b82e2793SMartin Bugge state->i2c_avlink = adv7842_dummy_client(sd, "avlink", pdata->i2c_avlink, 0xf3); 3416b82e2793SMartin Bugge state->i2c_cec = adv7842_dummy_client(sd, "cec", pdata->i2c_cec, 0xf4); 3417b82e2793SMartin Bugge state->i2c_infoframe = adv7842_dummy_client(sd, "infoframe", pdata->i2c_infoframe, 0xf5); 3418b82e2793SMartin Bugge state->i2c_sdp_io = adv7842_dummy_client(sd, "sdp_io", pdata->i2c_sdp_io, 0xf2); 3419b82e2793SMartin Bugge state->i2c_sdp = adv7842_dummy_client(sd, "sdp", pdata->i2c_sdp, 0xf1); 3420b82e2793SMartin Bugge state->i2c_afe = adv7842_dummy_client(sd, "afe", pdata->i2c_afe, 0xf8); 3421b82e2793SMartin Bugge state->i2c_repeater = adv7842_dummy_client(sd, "repeater", pdata->i2c_repeater, 0xf9); 3422b82e2793SMartin Bugge state->i2c_edid = adv7842_dummy_client(sd, "edid", pdata->i2c_edid, 0xfa); 3423b82e2793SMartin Bugge state->i2c_hdmi = adv7842_dummy_client(sd, "hdmi", pdata->i2c_hdmi, 0xfb); 3424b82e2793SMartin Bugge state->i2c_cp = adv7842_dummy_client(sd, "cp", pdata->i2c_cp, 0xfd); 3425b82e2793SMartin Bugge state->i2c_vdp = adv7842_dummy_client(sd, "vdp", pdata->i2c_vdp, 0xfe); 3426b82e2793SMartin Bugge 3427b82e2793SMartin Bugge if (!state->i2c_avlink || 3428b82e2793SMartin Bugge !state->i2c_cec || 3429b82e2793SMartin Bugge !state->i2c_infoframe || 3430b82e2793SMartin Bugge !state->i2c_sdp_io || 3431b82e2793SMartin Bugge !state->i2c_sdp || 3432b82e2793SMartin Bugge !state->i2c_afe || 3433b82e2793SMartin Bugge !state->i2c_repeater || 3434b82e2793SMartin Bugge !state->i2c_edid || 3435b82e2793SMartin Bugge !state->i2c_hdmi || 3436b82e2793SMartin Bugge !state->i2c_cp || 3437b82e2793SMartin Bugge !state->i2c_vdp) 3438b82e2793SMartin Bugge return -1; 3439b82e2793SMartin Bugge 3440b82e2793SMartin Bugge return 0; 3441a89bcd4cSHans Verkuil } 3442a89bcd4cSHans Verkuil 3443a89bcd4cSHans Verkuil static int adv7842_probe(struct i2c_client *client, 3444a89bcd4cSHans Verkuil const struct i2c_device_id *id) 3445a89bcd4cSHans Verkuil { 3446a89bcd4cSHans Verkuil struct adv7842_state *state; 34470bb4e7abSHans Verkuil static const struct v4l2_dv_timings cea640x480 = 34480bb4e7abSHans Verkuil V4L2_DV_BT_CEA_640X480P59_94; 3449a89bcd4cSHans Verkuil struct adv7842_platform_data *pdata = client->dev.platform_data; 3450a89bcd4cSHans Verkuil struct v4l2_ctrl_handler *hdl; 3451e8979274SHans Verkuil struct v4l2_ctrl *ctrl; 3452a89bcd4cSHans Verkuil struct v4l2_subdev *sd; 3453a89bcd4cSHans Verkuil u16 rev; 3454a89bcd4cSHans Verkuil int err; 3455a89bcd4cSHans Verkuil 3456a89bcd4cSHans Verkuil /* Check if the adapter supports the needed features */ 3457a89bcd4cSHans Verkuil if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 3458a89bcd4cSHans Verkuil return -EIO; 3459a89bcd4cSHans Verkuil 3460a89bcd4cSHans Verkuil v4l_dbg(1, debug, client, "detecting adv7842 client on address 0x%x\n", 3461a89bcd4cSHans Verkuil client->addr << 1); 3462a89bcd4cSHans Verkuil 3463a89bcd4cSHans Verkuil if (!pdata) { 3464a89bcd4cSHans Verkuil v4l_err(client, "No platform data!\n"); 3465a89bcd4cSHans Verkuil return -ENODEV; 3466a89bcd4cSHans Verkuil } 3467a89bcd4cSHans Verkuil 34682d3da59fSMarkus Elfring state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL); 3469c38e8657SMarkus Elfring if (!state) 3470a89bcd4cSHans Verkuil return -ENOMEM; 3471a89bcd4cSHans Verkuil 34727de5be44SMartin Bugge /* platform data */ 34737de5be44SMartin Bugge state->pdata = *pdata; 34740bb4e7abSHans Verkuil state->timings = cea640x480; 3475f888ae7eSHans Verkuil state->format = adv7842_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8); 34767de5be44SMartin Bugge 3477a89bcd4cSHans Verkuil sd = &state->sd; 3478a89bcd4cSHans Verkuil v4l2_i2c_subdev_init(sd, client, &adv7842_ops); 3479aef5159fSLars-Peter Clausen sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; 348025c84fb1SHans Verkuil sd->internal_ops = &adv7842_int_ops; 3481a89bcd4cSHans Verkuil state->mode = pdata->mode; 3482a89bcd4cSHans Verkuil 34838e4e3631SMartin Bugge state->hdmi_port_a = pdata->input == ADV7842_SELECT_HDMI_PORT_A; 34846e9071f2SMartin Bugge state->restart_stdi_once = true; 3485a89bcd4cSHans Verkuil 3486a89bcd4cSHans Verkuil /* i2c access to adv7842? */ 3487a89bcd4cSHans Verkuil rev = adv_smbus_read_byte_data_check(client, 0xea, false) << 8 | 3488a89bcd4cSHans Verkuil adv_smbus_read_byte_data_check(client, 0xeb, false); 3489a89bcd4cSHans Verkuil if (rev != 0x2012) { 3490a89bcd4cSHans Verkuil v4l2_info(sd, "got rev=0x%04x on first read attempt\n", rev); 3491a89bcd4cSHans Verkuil rev = adv_smbus_read_byte_data_check(client, 0xea, false) << 8 | 3492a89bcd4cSHans Verkuil adv_smbus_read_byte_data_check(client, 0xeb, false); 3493a89bcd4cSHans Verkuil } 3494a89bcd4cSHans Verkuil if (rev != 0x2012) { 3495a89bcd4cSHans Verkuil v4l2_info(sd, "not an adv7842 on address 0x%x (rev=0x%04x)\n", 3496a89bcd4cSHans Verkuil client->addr << 1, rev); 3497a89bcd4cSHans Verkuil return -ENODEV; 3498a89bcd4cSHans Verkuil } 3499a89bcd4cSHans Verkuil 3500a89bcd4cSHans Verkuil if (pdata->chip_reset) 3501a89bcd4cSHans Verkuil main_reset(sd); 3502a89bcd4cSHans Verkuil 3503a89bcd4cSHans Verkuil /* control handlers */ 3504a89bcd4cSHans Verkuil hdl = &state->hdl; 3505a89bcd4cSHans Verkuil v4l2_ctrl_handler_init(hdl, 6); 3506a89bcd4cSHans Verkuil 3507a89bcd4cSHans Verkuil /* add in ascending ID order */ 3508a89bcd4cSHans Verkuil v4l2_ctrl_new_std(hdl, &adv7842_ctrl_ops, 3509a89bcd4cSHans Verkuil V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); 3510a89bcd4cSHans Verkuil v4l2_ctrl_new_std(hdl, &adv7842_ctrl_ops, 3511a89bcd4cSHans Verkuil V4L2_CID_CONTRAST, 0, 255, 1, 128); 3512a89bcd4cSHans Verkuil v4l2_ctrl_new_std(hdl, &adv7842_ctrl_ops, 3513a89bcd4cSHans Verkuil V4L2_CID_SATURATION, 0, 255, 1, 128); 3514a89bcd4cSHans Verkuil v4l2_ctrl_new_std(hdl, &adv7842_ctrl_ops, 3515a89bcd4cSHans Verkuil V4L2_CID_HUE, 0, 128, 1, 0); 3516e8979274SHans Verkuil ctrl = v4l2_ctrl_new_std_menu(hdl, &adv7842_ctrl_ops, 3517e8979274SHans Verkuil V4L2_CID_DV_RX_IT_CONTENT_TYPE, V4L2_DV_IT_CONTENT_TYPE_NO_ITC, 3518e8979274SHans Verkuil 0, V4L2_DV_IT_CONTENT_TYPE_NO_ITC); 3519e8979274SHans Verkuil if (ctrl) 3520e8979274SHans Verkuil ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; 3521a89bcd4cSHans Verkuil 3522a89bcd4cSHans Verkuil /* custom controls */ 3523a89bcd4cSHans Verkuil state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL, 3524a89bcd4cSHans Verkuil V4L2_CID_DV_RX_POWER_PRESENT, 0, 3, 0, 0); 3525a89bcd4cSHans Verkuil state->analog_sampling_phase_ctrl = v4l2_ctrl_new_custom(hdl, 3526a89bcd4cSHans Verkuil &adv7842_ctrl_analog_sampling_phase, NULL); 3527a89bcd4cSHans Verkuil state->free_run_color_ctrl_manual = v4l2_ctrl_new_custom(hdl, 3528a89bcd4cSHans Verkuil &adv7842_ctrl_free_run_color_manual, NULL); 3529a89bcd4cSHans Verkuil state->free_run_color_ctrl = v4l2_ctrl_new_custom(hdl, 3530a89bcd4cSHans Verkuil &adv7842_ctrl_free_run_color, NULL); 3531a89bcd4cSHans Verkuil state->rgb_quantization_range_ctrl = 3532a89bcd4cSHans Verkuil v4l2_ctrl_new_std_menu(hdl, &adv7842_ctrl_ops, 3533a89bcd4cSHans Verkuil V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, 3534a89bcd4cSHans Verkuil 0, V4L2_DV_RGB_RANGE_AUTO); 3535a89bcd4cSHans Verkuil sd->ctrl_handler = hdl; 3536a89bcd4cSHans Verkuil if (hdl->error) { 3537a89bcd4cSHans Verkuil err = hdl->error; 3538a89bcd4cSHans Verkuil goto err_hdl; 3539a89bcd4cSHans Verkuil } 3540a89bcd4cSHans Verkuil if (adv7842_s_detect_tx_5v_ctrl(sd)) { 3541a89bcd4cSHans Verkuil err = -ENODEV; 3542a89bcd4cSHans Verkuil goto err_hdl; 3543a89bcd4cSHans Verkuil } 3544a89bcd4cSHans Verkuil 3545b82e2793SMartin Bugge if (adv7842_register_clients(sd) < 0) { 3546a89bcd4cSHans Verkuil err = -ENOMEM; 3547a89bcd4cSHans Verkuil v4l2_err(sd, "failed to create all i2c clients\n"); 3548a89bcd4cSHans Verkuil goto err_i2c; 3549a89bcd4cSHans Verkuil } 3550a89bcd4cSHans Verkuil 3551a89bcd4cSHans Verkuil 3552a89bcd4cSHans Verkuil INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug, 3553a89bcd4cSHans Verkuil adv7842_delayed_work_enable_hotplug); 3554a89bcd4cSHans Verkuil 3555d272bc92SHans Verkuil sd->entity.function = MEDIA_ENT_F_DV_DECODER; 3556a89bcd4cSHans Verkuil state->pad.flags = MEDIA_PAD_FL_SOURCE; 3557ab22e77cSMauro Carvalho Chehab err = media_entity_pads_init(&sd->entity, 1, &state->pad); 3558a89bcd4cSHans Verkuil if (err) 3559a89bcd4cSHans Verkuil goto err_work_queues; 3560a89bcd4cSHans Verkuil 35617de5be44SMartin Bugge err = adv7842_core_init(sd); 3562a89bcd4cSHans Verkuil if (err) 3563a89bcd4cSHans Verkuil goto err_entity; 3564a89bcd4cSHans Verkuil 356525c84fb1SHans Verkuil #if IS_ENABLED(CONFIG_VIDEO_ADV7842_CEC) 356625c84fb1SHans Verkuil state->cec_adap = cec_allocate_adapter(&adv7842_cec_adap_ops, 356725c84fb1SHans Verkuil state, dev_name(&client->dev), 356857b79636SHans Verkuil CEC_CAP_DEFAULTS, ADV7842_MAX_ADDRS); 356925c84fb1SHans Verkuil err = PTR_ERR_OR_ZERO(state->cec_adap); 357025c84fb1SHans Verkuil if (err) 357125c84fb1SHans Verkuil goto err_entity; 357225c84fb1SHans Verkuil #endif 357325c84fb1SHans Verkuil 3574a89bcd4cSHans Verkuil v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, 3575a89bcd4cSHans Verkuil client->addr << 1, client->adapter->name); 3576a89bcd4cSHans Verkuil return 0; 3577a89bcd4cSHans Verkuil 3578a89bcd4cSHans Verkuil err_entity: 3579a89bcd4cSHans Verkuil media_entity_cleanup(&sd->entity); 3580a89bcd4cSHans Verkuil err_work_queues: 3581a89bcd4cSHans Verkuil cancel_delayed_work(&state->delayed_work_enable_hotplug); 3582a89bcd4cSHans Verkuil err_i2c: 3583b82e2793SMartin Bugge adv7842_unregister_clients(sd); 3584a89bcd4cSHans Verkuil err_hdl: 3585a89bcd4cSHans Verkuil v4l2_ctrl_handler_free(hdl); 3586a89bcd4cSHans Verkuil return err; 3587a89bcd4cSHans Verkuil } 3588a89bcd4cSHans Verkuil 3589a89bcd4cSHans Verkuil /* ----------------------------------------------------------------------- */ 3590a89bcd4cSHans Verkuil 3591a89bcd4cSHans Verkuil static int adv7842_remove(struct i2c_client *client) 3592a89bcd4cSHans Verkuil { 3593a89bcd4cSHans Verkuil struct v4l2_subdev *sd = i2c_get_clientdata(client); 3594a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 3595a89bcd4cSHans Verkuil 3596a89bcd4cSHans Verkuil adv7842_irq_enable(sd, false); 3597a89bcd4cSHans Verkuil cancel_delayed_work(&state->delayed_work_enable_hotplug); 3598a89bcd4cSHans Verkuil v4l2_device_unregister_subdev(sd); 3599a89bcd4cSHans Verkuil media_entity_cleanup(&sd->entity); 3600b82e2793SMartin Bugge adv7842_unregister_clients(sd); 3601a89bcd4cSHans Verkuil v4l2_ctrl_handler_free(sd->ctrl_handler); 3602a89bcd4cSHans Verkuil return 0; 3603a89bcd4cSHans Verkuil } 3604a89bcd4cSHans Verkuil 3605a89bcd4cSHans Verkuil /* ----------------------------------------------------------------------- */ 3606a89bcd4cSHans Verkuil 360777c6cba3SArvind Yadav static const struct i2c_device_id adv7842_id[] = { 3608a89bcd4cSHans Verkuil { "adv7842", 0 }, 3609a89bcd4cSHans Verkuil { } 3610a89bcd4cSHans Verkuil }; 3611a89bcd4cSHans Verkuil MODULE_DEVICE_TABLE(i2c, adv7842_id); 3612a89bcd4cSHans Verkuil 3613a89bcd4cSHans Verkuil /* ----------------------------------------------------------------------- */ 3614a89bcd4cSHans Verkuil 3615a89bcd4cSHans Verkuil static struct i2c_driver adv7842_driver = { 3616a89bcd4cSHans Verkuil .driver = { 3617a89bcd4cSHans Verkuil .name = "adv7842", 3618a89bcd4cSHans Verkuil }, 3619a89bcd4cSHans Verkuil .probe = adv7842_probe, 3620a89bcd4cSHans Verkuil .remove = adv7842_remove, 3621a89bcd4cSHans Verkuil .id_table = adv7842_id, 3622a89bcd4cSHans Verkuil }; 3623a89bcd4cSHans Verkuil 3624a89bcd4cSHans Verkuil module_i2c_driver(adv7842_driver); 3625