1a89bcd4cSHans Verkuil /* 2a89bcd4cSHans Verkuil * adv7842 - Analog Devices ADV7842 video decoder driver 3a89bcd4cSHans Verkuil * 4a89bcd4cSHans Verkuil * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved. 5a89bcd4cSHans Verkuil * 6a89bcd4cSHans Verkuil * This program is free software; you may redistribute it and/or modify 7a89bcd4cSHans Verkuil * it under the terms of the GNU General Public License as published by 8a89bcd4cSHans Verkuil * the Free Software Foundation; version 2 of the License. 9a89bcd4cSHans Verkuil * 10a89bcd4cSHans Verkuil * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 11a89bcd4cSHans Verkuil * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 12a89bcd4cSHans Verkuil * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 13a89bcd4cSHans Verkuil * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 14a89bcd4cSHans Verkuil * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 15a89bcd4cSHans Verkuil * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 16a89bcd4cSHans Verkuil * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 17a89bcd4cSHans Verkuil * SOFTWARE. 18a89bcd4cSHans Verkuil * 19a89bcd4cSHans Verkuil */ 20a89bcd4cSHans Verkuil 21a89bcd4cSHans Verkuil /* 22a89bcd4cSHans Verkuil * References (c = chapter, p = page): 235b64b205SMats Randgaard * REF_01 - Analog devices, ADV7842, 245b64b205SMats Randgaard * Register Settings Recommendations, Rev. 1.9, April 2011 257de6fab1SMats Randgaard * REF_02 - Analog devices, Software User Guide, UG-206, 267de6fab1SMats Randgaard * ADV7842 I2C Register Maps, Rev. 0, November 2010 275b64b205SMats Randgaard * REF_03 - Analog devices, Hardware User Guide, UG-214, 285b64b205SMats Randgaard * ADV7842 Fast Switching 2:1 HDMI 1.4 Receiver with 3D-Comb 295b64b205SMats Randgaard * Decoder and Digitizer , Rev. 0, January 2011 30a89bcd4cSHans Verkuil */ 31a89bcd4cSHans Verkuil 32a89bcd4cSHans Verkuil 33a89bcd4cSHans Verkuil #include <linux/kernel.h> 34a89bcd4cSHans Verkuil #include <linux/module.h> 35a89bcd4cSHans Verkuil #include <linux/slab.h> 36a89bcd4cSHans Verkuil #include <linux/i2c.h> 37a89bcd4cSHans Verkuil #include <linux/delay.h> 38a89bcd4cSHans Verkuil #include <linux/videodev2.h> 39a89bcd4cSHans Verkuil #include <linux/workqueue.h> 40a89bcd4cSHans Verkuil #include <linux/v4l2-dv-timings.h> 41a89bcd4cSHans Verkuil #include <media/v4l2-device.h> 42a89bcd4cSHans Verkuil #include <media/v4l2-ctrls.h> 43a89bcd4cSHans Verkuil #include <media/v4l2-dv-timings.h> 44a89bcd4cSHans Verkuil #include <media/adv7842.h> 45a89bcd4cSHans Verkuil 46a89bcd4cSHans Verkuil static int debug; 47a89bcd4cSHans Verkuil module_param(debug, int, 0644); 48a89bcd4cSHans Verkuil MODULE_PARM_DESC(debug, "debug level (0-2)"); 49a89bcd4cSHans Verkuil 50a89bcd4cSHans Verkuil MODULE_DESCRIPTION("Analog Devices ADV7842 video decoder driver"); 51a89bcd4cSHans Verkuil MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>"); 52a89bcd4cSHans Verkuil MODULE_AUTHOR("Martin Bugge <marbugge@cisco.com>"); 53a89bcd4cSHans Verkuil MODULE_LICENSE("GPL"); 54a89bcd4cSHans Verkuil 55a89bcd4cSHans Verkuil /* ADV7842 system clock frequency */ 56a89bcd4cSHans Verkuil #define ADV7842_fsc (28636360) 57a89bcd4cSHans Verkuil 58a89bcd4cSHans Verkuil /* 59a89bcd4cSHans Verkuil ********************************************************************** 60a89bcd4cSHans Verkuil * 61a89bcd4cSHans Verkuil * Arrays with configuration parameters for the ADV7842 62a89bcd4cSHans Verkuil * 63a89bcd4cSHans Verkuil ********************************************************************** 64a89bcd4cSHans Verkuil */ 65a89bcd4cSHans Verkuil 66a89bcd4cSHans Verkuil struct adv7842_state { 677de5be44SMartin Bugge struct adv7842_platform_data pdata; 68a89bcd4cSHans Verkuil struct v4l2_subdev sd; 69a89bcd4cSHans Verkuil struct media_pad pad; 70a89bcd4cSHans Verkuil struct v4l2_ctrl_handler hdl; 71a89bcd4cSHans Verkuil enum adv7842_mode mode; 72a89bcd4cSHans Verkuil struct v4l2_dv_timings timings; 73a89bcd4cSHans Verkuil enum adv7842_vid_std_select vid_std_select; 74a89bcd4cSHans Verkuil v4l2_std_id norm; 75a89bcd4cSHans Verkuil struct { 76a89bcd4cSHans Verkuil u8 edid[256]; 77a89bcd4cSHans Verkuil u32 present; 78a89bcd4cSHans Verkuil } hdmi_edid; 79a89bcd4cSHans Verkuil struct { 80a89bcd4cSHans Verkuil u8 edid[256]; 81a89bcd4cSHans Verkuil u32 present; 82a89bcd4cSHans Verkuil } vga_edid; 83a89bcd4cSHans Verkuil struct v4l2_fract aspect_ratio; 84a89bcd4cSHans Verkuil u32 rgb_quantization_range; 85a89bcd4cSHans Verkuil bool is_cea_format; 86a89bcd4cSHans Verkuil struct workqueue_struct *work_queues; 87a89bcd4cSHans Verkuil struct delayed_work delayed_work_enable_hotplug; 886e9071f2SMartin Bugge bool restart_stdi_once; 89a89bcd4cSHans Verkuil bool hdmi_port_a; 90a89bcd4cSHans Verkuil 91a89bcd4cSHans Verkuil /* i2c clients */ 92a89bcd4cSHans Verkuil struct i2c_client *i2c_sdp_io; 93a89bcd4cSHans Verkuil struct i2c_client *i2c_sdp; 94a89bcd4cSHans Verkuil struct i2c_client *i2c_cp; 95a89bcd4cSHans Verkuil struct i2c_client *i2c_vdp; 96a89bcd4cSHans Verkuil struct i2c_client *i2c_afe; 97a89bcd4cSHans Verkuil struct i2c_client *i2c_hdmi; 98a89bcd4cSHans Verkuil struct i2c_client *i2c_repeater; 99a89bcd4cSHans Verkuil struct i2c_client *i2c_edid; 100a89bcd4cSHans Verkuil struct i2c_client *i2c_infoframe; 101a89bcd4cSHans Verkuil struct i2c_client *i2c_cec; 102a89bcd4cSHans Verkuil struct i2c_client *i2c_avlink; 103a89bcd4cSHans Verkuil 104a89bcd4cSHans Verkuil /* controls */ 105a89bcd4cSHans Verkuil struct v4l2_ctrl *detect_tx_5v_ctrl; 106a89bcd4cSHans Verkuil struct v4l2_ctrl *analog_sampling_phase_ctrl; 107a89bcd4cSHans Verkuil struct v4l2_ctrl *free_run_color_ctrl_manual; 108a89bcd4cSHans Verkuil struct v4l2_ctrl *free_run_color_ctrl; 109a89bcd4cSHans Verkuil struct v4l2_ctrl *rgb_quantization_range_ctrl; 110a89bcd4cSHans Verkuil }; 111a89bcd4cSHans Verkuil 112a89bcd4cSHans Verkuil /* Unsupported timings. This device cannot support 720p30. */ 113a89bcd4cSHans Verkuil static const struct v4l2_dv_timings adv7842_timings_exceptions[] = { 114a89bcd4cSHans Verkuil V4L2_DV_BT_CEA_1280X720P30, 115a89bcd4cSHans Verkuil { } 116a89bcd4cSHans Verkuil }; 117a89bcd4cSHans Verkuil 118a89bcd4cSHans Verkuil static bool adv7842_check_dv_timings(const struct v4l2_dv_timings *t, void *hdl) 119a89bcd4cSHans Verkuil { 120a89bcd4cSHans Verkuil int i; 121a89bcd4cSHans Verkuil 122a89bcd4cSHans Verkuil for (i = 0; adv7842_timings_exceptions[i].bt.width; i++) 123a89bcd4cSHans Verkuil if (v4l2_match_dv_timings(t, adv7842_timings_exceptions + i, 0)) 124a89bcd4cSHans Verkuil return false; 125a89bcd4cSHans Verkuil return true; 126a89bcd4cSHans Verkuil } 127a89bcd4cSHans Verkuil 128a89bcd4cSHans Verkuil struct adv7842_video_standards { 129a89bcd4cSHans Verkuil struct v4l2_dv_timings timings; 130a89bcd4cSHans Verkuil u8 vid_std; 131a89bcd4cSHans Verkuil u8 v_freq; 132a89bcd4cSHans Verkuil }; 133a89bcd4cSHans Verkuil 134a89bcd4cSHans Verkuil /* sorted by number of lines */ 135a89bcd4cSHans Verkuil static const struct adv7842_video_standards adv7842_prim_mode_comp[] = { 136a89bcd4cSHans Verkuil /* { V4L2_DV_BT_CEA_720X480P59_94, 0x0a, 0x00 }, TODO flickering */ 137a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_720X576P50, 0x0b, 0x00 }, 138a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1280X720P50, 0x19, 0x01 }, 139a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1280X720P60, 0x19, 0x00 }, 140a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1920X1080P24, 0x1e, 0x04 }, 141a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1920X1080P25, 0x1e, 0x03 }, 142a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1920X1080P30, 0x1e, 0x02 }, 143a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1920X1080P50, 0x1e, 0x01 }, 144a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1920X1080P60, 0x1e, 0x00 }, 145a89bcd4cSHans Verkuil /* TODO add 1920x1080P60_RB (CVT timing) */ 146a89bcd4cSHans Verkuil { }, 147a89bcd4cSHans Verkuil }; 148a89bcd4cSHans Verkuil 149a89bcd4cSHans Verkuil /* sorted by number of lines */ 150a89bcd4cSHans Verkuil static const struct adv7842_video_standards adv7842_prim_mode_gr[] = { 151a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_640X480P60, 0x08, 0x00 }, 152a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_640X480P72, 0x09, 0x00 }, 153a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_640X480P75, 0x0a, 0x00 }, 154a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_640X480P85, 0x0b, 0x00 }, 155a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_800X600P56, 0x00, 0x00 }, 156a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_800X600P60, 0x01, 0x00 }, 157a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_800X600P72, 0x02, 0x00 }, 158a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_800X600P75, 0x03, 0x00 }, 159a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_800X600P85, 0x04, 0x00 }, 160a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1024X768P60, 0x0c, 0x00 }, 161a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1024X768P70, 0x0d, 0x00 }, 162a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1024X768P75, 0x0e, 0x00 }, 163a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1024X768P85, 0x0f, 0x00 }, 164a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1280X1024P60, 0x05, 0x00 }, 165a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1280X1024P75, 0x06, 0x00 }, 166a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1360X768P60, 0x12, 0x00 }, 167a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1366X768P60, 0x13, 0x00 }, 168a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1400X1050P60, 0x14, 0x00 }, 169a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1400X1050P75, 0x15, 0x00 }, 170a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1600X1200P60, 0x16, 0x00 }, /* TODO not tested */ 171a89bcd4cSHans Verkuil /* TODO add 1600X1200P60_RB (not a DMT timing) */ 172a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1680X1050P60, 0x18, 0x00 }, 173a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1920X1200P60_RB, 0x19, 0x00 }, /* TODO not tested */ 174a89bcd4cSHans Verkuil { }, 175a89bcd4cSHans Verkuil }; 176a89bcd4cSHans Verkuil 177a89bcd4cSHans Verkuil /* sorted by number of lines */ 178a89bcd4cSHans Verkuil static const struct adv7842_video_standards adv7842_prim_mode_hdmi_comp[] = { 179a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_720X480P59_94, 0x0a, 0x00 }, 180a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_720X576P50, 0x0b, 0x00 }, 181a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1280X720P50, 0x13, 0x01 }, 182a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1280X720P60, 0x13, 0x00 }, 183a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1920X1080P24, 0x1e, 0x04 }, 184a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1920X1080P25, 0x1e, 0x03 }, 185a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1920X1080P30, 0x1e, 0x02 }, 186a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1920X1080P50, 0x1e, 0x01 }, 187a89bcd4cSHans Verkuil { V4L2_DV_BT_CEA_1920X1080P60, 0x1e, 0x00 }, 188a89bcd4cSHans Verkuil { }, 189a89bcd4cSHans Verkuil }; 190a89bcd4cSHans Verkuil 191a89bcd4cSHans Verkuil /* sorted by number of lines */ 192a89bcd4cSHans Verkuil static const struct adv7842_video_standards adv7842_prim_mode_hdmi_gr[] = { 193a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_640X480P60, 0x08, 0x00 }, 194a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_640X480P72, 0x09, 0x00 }, 195a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_640X480P75, 0x0a, 0x00 }, 196a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_640X480P85, 0x0b, 0x00 }, 197a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_800X600P56, 0x00, 0x00 }, 198a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_800X600P60, 0x01, 0x00 }, 199a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_800X600P72, 0x02, 0x00 }, 200a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_800X600P75, 0x03, 0x00 }, 201a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_800X600P85, 0x04, 0x00 }, 202a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1024X768P60, 0x0c, 0x00 }, 203a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1024X768P70, 0x0d, 0x00 }, 204a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1024X768P75, 0x0e, 0x00 }, 205a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1024X768P85, 0x0f, 0x00 }, 206a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1280X1024P60, 0x05, 0x00 }, 207a89bcd4cSHans Verkuil { V4L2_DV_BT_DMT_1280X1024P75, 0x06, 0x00 }, 208a89bcd4cSHans Verkuil { }, 209a89bcd4cSHans Verkuil }; 210a89bcd4cSHans Verkuil 211a89bcd4cSHans Verkuil /* ----------------------------------------------------------------------- */ 212a89bcd4cSHans Verkuil 213a89bcd4cSHans Verkuil static inline struct adv7842_state *to_state(struct v4l2_subdev *sd) 214a89bcd4cSHans Verkuil { 215a89bcd4cSHans Verkuil return container_of(sd, struct adv7842_state, sd); 216a89bcd4cSHans Verkuil } 217a89bcd4cSHans Verkuil 218a89bcd4cSHans Verkuil static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) 219a89bcd4cSHans Verkuil { 220a89bcd4cSHans Verkuil return &container_of(ctrl->handler, struct adv7842_state, hdl)->sd; 221a89bcd4cSHans Verkuil } 222a89bcd4cSHans Verkuil 223a89bcd4cSHans Verkuil static inline unsigned hblanking(const struct v4l2_bt_timings *t) 224a89bcd4cSHans Verkuil { 225a89bcd4cSHans Verkuil return V4L2_DV_BT_BLANKING_WIDTH(t); 226a89bcd4cSHans Verkuil } 227a89bcd4cSHans Verkuil 228a89bcd4cSHans Verkuil static inline unsigned htotal(const struct v4l2_bt_timings *t) 229a89bcd4cSHans Verkuil { 230a89bcd4cSHans Verkuil return V4L2_DV_BT_FRAME_WIDTH(t); 231a89bcd4cSHans Verkuil } 232a89bcd4cSHans Verkuil 233a89bcd4cSHans Verkuil static inline unsigned vblanking(const struct v4l2_bt_timings *t) 234a89bcd4cSHans Verkuil { 235a89bcd4cSHans Verkuil return V4L2_DV_BT_BLANKING_HEIGHT(t); 236a89bcd4cSHans Verkuil } 237a89bcd4cSHans Verkuil 238a89bcd4cSHans Verkuil static inline unsigned vtotal(const struct v4l2_bt_timings *t) 239a89bcd4cSHans Verkuil { 240a89bcd4cSHans Verkuil return V4L2_DV_BT_FRAME_HEIGHT(t); 241a89bcd4cSHans Verkuil } 242a89bcd4cSHans Verkuil 243a89bcd4cSHans Verkuil 244a89bcd4cSHans Verkuil /* ----------------------------------------------------------------------- */ 245a89bcd4cSHans Verkuil 246a89bcd4cSHans Verkuil static s32 adv_smbus_read_byte_data_check(struct i2c_client *client, 247a89bcd4cSHans Verkuil u8 command, bool check) 248a89bcd4cSHans Verkuil { 249a89bcd4cSHans Verkuil union i2c_smbus_data data; 250a89bcd4cSHans Verkuil 251a89bcd4cSHans Verkuil if (!i2c_smbus_xfer(client->adapter, client->addr, client->flags, 252a89bcd4cSHans Verkuil I2C_SMBUS_READ, command, 253a89bcd4cSHans Verkuil I2C_SMBUS_BYTE_DATA, &data)) 254a89bcd4cSHans Verkuil return data.byte; 255a89bcd4cSHans Verkuil if (check) 256a89bcd4cSHans Verkuil v4l_err(client, "error reading %02x, %02x\n", 257a89bcd4cSHans Verkuil client->addr, command); 258a89bcd4cSHans Verkuil return -EIO; 259a89bcd4cSHans Verkuil } 260a89bcd4cSHans Verkuil 261a89bcd4cSHans Verkuil static s32 adv_smbus_read_byte_data(struct i2c_client *client, u8 command) 262a89bcd4cSHans Verkuil { 263a89bcd4cSHans Verkuil int i; 264a89bcd4cSHans Verkuil 265a89bcd4cSHans Verkuil for (i = 0; i < 3; i++) { 266a89bcd4cSHans Verkuil int ret = adv_smbus_read_byte_data_check(client, command, true); 267a89bcd4cSHans Verkuil 268a89bcd4cSHans Verkuil if (ret >= 0) { 269a89bcd4cSHans Verkuil if (i) 270a89bcd4cSHans Verkuil v4l_err(client, "read ok after %d retries\n", i); 271a89bcd4cSHans Verkuil return ret; 272a89bcd4cSHans Verkuil } 273a89bcd4cSHans Verkuil } 274a89bcd4cSHans Verkuil v4l_err(client, "read failed\n"); 275a89bcd4cSHans Verkuil return -EIO; 276a89bcd4cSHans Verkuil } 277a89bcd4cSHans Verkuil 278a89bcd4cSHans Verkuil static s32 adv_smbus_write_byte_data(struct i2c_client *client, 279a89bcd4cSHans Verkuil u8 command, u8 value) 280a89bcd4cSHans Verkuil { 281a89bcd4cSHans Verkuil union i2c_smbus_data data; 282a89bcd4cSHans Verkuil int err; 283a89bcd4cSHans Verkuil int i; 284a89bcd4cSHans Verkuil 285a89bcd4cSHans Verkuil data.byte = value; 286a89bcd4cSHans Verkuil for (i = 0; i < 3; i++) { 287a89bcd4cSHans Verkuil err = i2c_smbus_xfer(client->adapter, client->addr, 288a89bcd4cSHans Verkuil client->flags, 289a89bcd4cSHans Verkuil I2C_SMBUS_WRITE, command, 290a89bcd4cSHans Verkuil I2C_SMBUS_BYTE_DATA, &data); 291a89bcd4cSHans Verkuil if (!err) 292a89bcd4cSHans Verkuil break; 293a89bcd4cSHans Verkuil } 294a89bcd4cSHans Verkuil if (err < 0) 295a89bcd4cSHans Verkuil v4l_err(client, "error writing %02x, %02x, %02x\n", 296a89bcd4cSHans Verkuil client->addr, command, value); 297a89bcd4cSHans Verkuil return err; 298a89bcd4cSHans Verkuil } 299a89bcd4cSHans Verkuil 300a89bcd4cSHans Verkuil static void adv_smbus_write_byte_no_check(struct i2c_client *client, 301a89bcd4cSHans Verkuil u8 command, u8 value) 302a89bcd4cSHans Verkuil { 303a89bcd4cSHans Verkuil union i2c_smbus_data data; 304a89bcd4cSHans Verkuil data.byte = value; 305a89bcd4cSHans Verkuil 306a89bcd4cSHans Verkuil i2c_smbus_xfer(client->adapter, client->addr, 307a89bcd4cSHans Verkuil client->flags, 308a89bcd4cSHans Verkuil I2C_SMBUS_WRITE, command, 309a89bcd4cSHans Verkuil I2C_SMBUS_BYTE_DATA, &data); 310a89bcd4cSHans Verkuil } 311a89bcd4cSHans Verkuil 312a89bcd4cSHans Verkuil static s32 adv_smbus_write_i2c_block_data(struct i2c_client *client, 313a89bcd4cSHans Verkuil u8 command, unsigned length, const u8 *values) 314a89bcd4cSHans Verkuil { 315a89bcd4cSHans Verkuil union i2c_smbus_data data; 316a89bcd4cSHans Verkuil 317a89bcd4cSHans Verkuil if (length > I2C_SMBUS_BLOCK_MAX) 318a89bcd4cSHans Verkuil length = I2C_SMBUS_BLOCK_MAX; 319a89bcd4cSHans Verkuil data.block[0] = length; 320a89bcd4cSHans Verkuil memcpy(data.block + 1, values, length); 321a89bcd4cSHans Verkuil return i2c_smbus_xfer(client->adapter, client->addr, client->flags, 322a89bcd4cSHans Verkuil I2C_SMBUS_WRITE, command, 323a89bcd4cSHans Verkuil I2C_SMBUS_I2C_BLOCK_DATA, &data); 324a89bcd4cSHans Verkuil } 325a89bcd4cSHans Verkuil 326a89bcd4cSHans Verkuil /* ----------------------------------------------------------------------- */ 327a89bcd4cSHans Verkuil 328a89bcd4cSHans Verkuil static inline int io_read(struct v4l2_subdev *sd, u8 reg) 329a89bcd4cSHans Verkuil { 330a89bcd4cSHans Verkuil struct i2c_client *client = v4l2_get_subdevdata(sd); 331a89bcd4cSHans Verkuil 332a89bcd4cSHans Verkuil return adv_smbus_read_byte_data(client, reg); 333a89bcd4cSHans Verkuil } 334a89bcd4cSHans Verkuil 335a89bcd4cSHans Verkuil static inline int io_write(struct v4l2_subdev *sd, u8 reg, u8 val) 336a89bcd4cSHans Verkuil { 337a89bcd4cSHans Verkuil struct i2c_client *client = v4l2_get_subdevdata(sd); 338a89bcd4cSHans Verkuil 339a89bcd4cSHans Verkuil return adv_smbus_write_byte_data(client, reg, val); 340a89bcd4cSHans Verkuil } 341a89bcd4cSHans Verkuil 342a89bcd4cSHans Verkuil static inline int io_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) 343a89bcd4cSHans Verkuil { 344a89bcd4cSHans Verkuil return io_write(sd, reg, (io_read(sd, reg) & mask) | val); 345a89bcd4cSHans Verkuil } 346a89bcd4cSHans Verkuil 347a89bcd4cSHans Verkuil static inline int avlink_read(struct v4l2_subdev *sd, u8 reg) 348a89bcd4cSHans Verkuil { 349a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 350a89bcd4cSHans Verkuil 351a89bcd4cSHans Verkuil return adv_smbus_read_byte_data(state->i2c_avlink, reg); 352a89bcd4cSHans Verkuil } 353a89bcd4cSHans Verkuil 354a89bcd4cSHans Verkuil static inline int avlink_write(struct v4l2_subdev *sd, u8 reg, u8 val) 355a89bcd4cSHans Verkuil { 356a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 357a89bcd4cSHans Verkuil 358a89bcd4cSHans Verkuil return adv_smbus_write_byte_data(state->i2c_avlink, reg, val); 359a89bcd4cSHans Verkuil } 360a89bcd4cSHans Verkuil 361a89bcd4cSHans Verkuil static inline int cec_read(struct v4l2_subdev *sd, u8 reg) 362a89bcd4cSHans Verkuil { 363a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 364a89bcd4cSHans Verkuil 365a89bcd4cSHans Verkuil return adv_smbus_read_byte_data(state->i2c_cec, reg); 366a89bcd4cSHans Verkuil } 367a89bcd4cSHans Verkuil 368a89bcd4cSHans Verkuil static inline int cec_write(struct v4l2_subdev *sd, u8 reg, u8 val) 369a89bcd4cSHans Verkuil { 370a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 371a89bcd4cSHans Verkuil 372a89bcd4cSHans Verkuil return adv_smbus_write_byte_data(state->i2c_cec, reg, val); 373a89bcd4cSHans Verkuil } 374a89bcd4cSHans Verkuil 375a89bcd4cSHans Verkuil static inline int cec_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) 376a89bcd4cSHans Verkuil { 377a89bcd4cSHans Verkuil return cec_write(sd, reg, (cec_read(sd, reg) & mask) | val); 378a89bcd4cSHans Verkuil } 379a89bcd4cSHans Verkuil 380a89bcd4cSHans Verkuil static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg) 381a89bcd4cSHans Verkuil { 382a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 383a89bcd4cSHans Verkuil 384a89bcd4cSHans Verkuil return adv_smbus_read_byte_data(state->i2c_infoframe, reg); 385a89bcd4cSHans Verkuil } 386a89bcd4cSHans Verkuil 387a89bcd4cSHans Verkuil static inline int infoframe_write(struct v4l2_subdev *sd, u8 reg, u8 val) 388a89bcd4cSHans Verkuil { 389a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 390a89bcd4cSHans Verkuil 391a89bcd4cSHans Verkuil return adv_smbus_write_byte_data(state->i2c_infoframe, reg, val); 392a89bcd4cSHans Verkuil } 393a89bcd4cSHans Verkuil 394a89bcd4cSHans Verkuil static inline int sdp_io_read(struct v4l2_subdev *sd, u8 reg) 395a89bcd4cSHans Verkuil { 396a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 397a89bcd4cSHans Verkuil 398a89bcd4cSHans Verkuil return adv_smbus_read_byte_data(state->i2c_sdp_io, reg); 399a89bcd4cSHans Verkuil } 400a89bcd4cSHans Verkuil 401a89bcd4cSHans Verkuil static inline int sdp_io_write(struct v4l2_subdev *sd, u8 reg, u8 val) 402a89bcd4cSHans Verkuil { 403a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 404a89bcd4cSHans Verkuil 405a89bcd4cSHans Verkuil return adv_smbus_write_byte_data(state->i2c_sdp_io, reg, val); 406a89bcd4cSHans Verkuil } 407a89bcd4cSHans Verkuil 408a89bcd4cSHans Verkuil static inline int sdp_io_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) 409a89bcd4cSHans Verkuil { 410a89bcd4cSHans Verkuil return sdp_io_write(sd, reg, (sdp_io_read(sd, reg) & mask) | val); 411a89bcd4cSHans Verkuil } 412a89bcd4cSHans Verkuil 413a89bcd4cSHans Verkuil static inline int sdp_read(struct v4l2_subdev *sd, u8 reg) 414a89bcd4cSHans Verkuil { 415a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 416a89bcd4cSHans Verkuil 417a89bcd4cSHans Verkuil return adv_smbus_read_byte_data(state->i2c_sdp, reg); 418a89bcd4cSHans Verkuil } 419a89bcd4cSHans Verkuil 420a89bcd4cSHans Verkuil static inline int sdp_write(struct v4l2_subdev *sd, u8 reg, u8 val) 421a89bcd4cSHans Verkuil { 422a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 423a89bcd4cSHans Verkuil 424a89bcd4cSHans Verkuil return adv_smbus_write_byte_data(state->i2c_sdp, reg, val); 425a89bcd4cSHans Verkuil } 426a89bcd4cSHans Verkuil 427a89bcd4cSHans Verkuil static inline int sdp_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) 428a89bcd4cSHans Verkuil { 429a89bcd4cSHans Verkuil return sdp_write(sd, reg, (sdp_read(sd, reg) & mask) | val); 430a89bcd4cSHans Verkuil } 431a89bcd4cSHans Verkuil 432a89bcd4cSHans Verkuil static inline int afe_read(struct v4l2_subdev *sd, u8 reg) 433a89bcd4cSHans Verkuil { 434a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 435a89bcd4cSHans Verkuil 436a89bcd4cSHans Verkuil return adv_smbus_read_byte_data(state->i2c_afe, reg); 437a89bcd4cSHans Verkuil } 438a89bcd4cSHans Verkuil 439a89bcd4cSHans Verkuil static inline int afe_write(struct v4l2_subdev *sd, u8 reg, u8 val) 440a89bcd4cSHans Verkuil { 441a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 442a89bcd4cSHans Verkuil 443a89bcd4cSHans Verkuil return adv_smbus_write_byte_data(state->i2c_afe, reg, val); 444a89bcd4cSHans Verkuil } 445a89bcd4cSHans Verkuil 446a89bcd4cSHans Verkuil static inline int afe_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) 447a89bcd4cSHans Verkuil { 448a89bcd4cSHans Verkuil return afe_write(sd, reg, (afe_read(sd, reg) & mask) | val); 449a89bcd4cSHans Verkuil } 450a89bcd4cSHans Verkuil 451a89bcd4cSHans Verkuil static inline int rep_read(struct v4l2_subdev *sd, u8 reg) 452a89bcd4cSHans Verkuil { 453a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 454a89bcd4cSHans Verkuil 455a89bcd4cSHans Verkuil return adv_smbus_read_byte_data(state->i2c_repeater, reg); 456a89bcd4cSHans Verkuil } 457a89bcd4cSHans Verkuil 458a89bcd4cSHans Verkuil static inline int rep_write(struct v4l2_subdev *sd, u8 reg, u8 val) 459a89bcd4cSHans Verkuil { 460a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 461a89bcd4cSHans Verkuil 462a89bcd4cSHans Verkuil return adv_smbus_write_byte_data(state->i2c_repeater, reg, val); 463a89bcd4cSHans Verkuil } 464a89bcd4cSHans Verkuil 465a89bcd4cSHans Verkuil static inline int rep_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) 466a89bcd4cSHans Verkuil { 467a89bcd4cSHans Verkuil return rep_write(sd, reg, (rep_read(sd, reg) & mask) | val); 468a89bcd4cSHans Verkuil } 469a89bcd4cSHans Verkuil 470a89bcd4cSHans Verkuil static inline int edid_read(struct v4l2_subdev *sd, u8 reg) 471a89bcd4cSHans Verkuil { 472a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 473a89bcd4cSHans Verkuil 474a89bcd4cSHans Verkuil return adv_smbus_read_byte_data(state->i2c_edid, reg); 475a89bcd4cSHans Verkuil } 476a89bcd4cSHans Verkuil 477a89bcd4cSHans Verkuil static inline int edid_write(struct v4l2_subdev *sd, u8 reg, u8 val) 478a89bcd4cSHans Verkuil { 479a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 480a89bcd4cSHans Verkuil 481a89bcd4cSHans Verkuil return adv_smbus_write_byte_data(state->i2c_edid, reg, val); 482a89bcd4cSHans Verkuil } 483a89bcd4cSHans Verkuil 484a89bcd4cSHans Verkuil static inline int hdmi_read(struct v4l2_subdev *sd, u8 reg) 485a89bcd4cSHans Verkuil { 486a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 487a89bcd4cSHans Verkuil 488a89bcd4cSHans Verkuil return adv_smbus_read_byte_data(state->i2c_hdmi, reg); 489a89bcd4cSHans Verkuil } 490a89bcd4cSHans Verkuil 491a89bcd4cSHans Verkuil static inline int hdmi_write(struct v4l2_subdev *sd, u8 reg, u8 val) 492a89bcd4cSHans Verkuil { 493a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 494a89bcd4cSHans Verkuil 495a89bcd4cSHans Verkuil return adv_smbus_write_byte_data(state->i2c_hdmi, reg, val); 496a89bcd4cSHans Verkuil } 497a89bcd4cSHans Verkuil 4985b64b205SMats Randgaard static inline int hdmi_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) 4995b64b205SMats Randgaard { 5005b64b205SMats Randgaard return hdmi_write(sd, reg, (hdmi_read(sd, reg) & mask) | val); 5015b64b205SMats Randgaard } 5025b64b205SMats Randgaard 503a89bcd4cSHans Verkuil static inline int cp_read(struct v4l2_subdev *sd, u8 reg) 504a89bcd4cSHans Verkuil { 505a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 506a89bcd4cSHans Verkuil 507a89bcd4cSHans Verkuil return adv_smbus_read_byte_data(state->i2c_cp, reg); 508a89bcd4cSHans Verkuil } 509a89bcd4cSHans Verkuil 510a89bcd4cSHans Verkuil static inline int cp_write(struct v4l2_subdev *sd, u8 reg, u8 val) 511a89bcd4cSHans Verkuil { 512a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 513a89bcd4cSHans Verkuil 514a89bcd4cSHans Verkuil return adv_smbus_write_byte_data(state->i2c_cp, reg, val); 515a89bcd4cSHans Verkuil } 516a89bcd4cSHans Verkuil 517a89bcd4cSHans Verkuil static inline int cp_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) 518a89bcd4cSHans Verkuil { 519a89bcd4cSHans Verkuil return cp_write(sd, reg, (cp_read(sd, reg) & mask) | val); 520a89bcd4cSHans Verkuil } 521a89bcd4cSHans Verkuil 522a89bcd4cSHans Verkuil static inline int vdp_read(struct v4l2_subdev *sd, u8 reg) 523a89bcd4cSHans Verkuil { 524a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 525a89bcd4cSHans Verkuil 526a89bcd4cSHans Verkuil return adv_smbus_read_byte_data(state->i2c_vdp, reg); 527a89bcd4cSHans Verkuil } 528a89bcd4cSHans Verkuil 529a89bcd4cSHans Verkuil static inline int vdp_write(struct v4l2_subdev *sd, u8 reg, u8 val) 530a89bcd4cSHans Verkuil { 531a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 532a89bcd4cSHans Verkuil 533a89bcd4cSHans Verkuil return adv_smbus_write_byte_data(state->i2c_vdp, reg, val); 534a89bcd4cSHans Verkuil } 535a89bcd4cSHans Verkuil 536a89bcd4cSHans Verkuil static void main_reset(struct v4l2_subdev *sd) 537a89bcd4cSHans Verkuil { 538a89bcd4cSHans Verkuil struct i2c_client *client = v4l2_get_subdevdata(sd); 539a89bcd4cSHans Verkuil 540a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, "%s:\n", __func__); 541a89bcd4cSHans Verkuil 542a89bcd4cSHans Verkuil adv_smbus_write_byte_no_check(client, 0xff, 0x80); 543a89bcd4cSHans Verkuil 54484aeed53SMartin Bugge mdelay(5); 545a89bcd4cSHans Verkuil } 546a89bcd4cSHans Verkuil 547a89bcd4cSHans Verkuil /* ----------------------------------------------------------------------- */ 548a89bcd4cSHans Verkuil 549a89bcd4cSHans Verkuil static inline bool is_digital_input(struct v4l2_subdev *sd) 550a89bcd4cSHans Verkuil { 551a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 552a89bcd4cSHans Verkuil 553a89bcd4cSHans Verkuil return state->mode == ADV7842_MODE_HDMI; 554a89bcd4cSHans Verkuil } 555a89bcd4cSHans Verkuil 556a89bcd4cSHans Verkuil static const struct v4l2_dv_timings_cap adv7842_timings_cap_analog = { 557a89bcd4cSHans Verkuil .type = V4L2_DV_BT_656_1120, 5589b51f175SGianluca Gennari /* keep this initialization for compatibility with GCC < 4.4.6 */ 5599b51f175SGianluca Gennari .reserved = { 0 }, 5609b51f175SGianluca Gennari V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1200, 25000000, 170000000, 5619b51f175SGianluca Gennari V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | 562a89bcd4cSHans Verkuil V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT, 5639b51f175SGianluca Gennari V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING | 5649b51f175SGianluca Gennari V4L2_DV_BT_CAP_CUSTOM) 565a89bcd4cSHans Verkuil }; 566a89bcd4cSHans Verkuil 567a89bcd4cSHans Verkuil static const struct v4l2_dv_timings_cap adv7842_timings_cap_digital = { 568a89bcd4cSHans Verkuil .type = V4L2_DV_BT_656_1120, 5699b51f175SGianluca Gennari /* keep this initialization for compatibility with GCC < 4.4.6 */ 5709b51f175SGianluca Gennari .reserved = { 0 }, 5719b51f175SGianluca Gennari V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1200, 25000000, 225000000, 5729b51f175SGianluca Gennari V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | 573a89bcd4cSHans Verkuil V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT, 5749b51f175SGianluca Gennari V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING | 5759b51f175SGianluca Gennari V4L2_DV_BT_CAP_CUSTOM) 576a89bcd4cSHans Verkuil }; 577a89bcd4cSHans Verkuil 578a89bcd4cSHans Verkuil static inline const struct v4l2_dv_timings_cap * 579a89bcd4cSHans Verkuil adv7842_get_dv_timings_cap(struct v4l2_subdev *sd) 580a89bcd4cSHans Verkuil { 581a89bcd4cSHans Verkuil return is_digital_input(sd) ? &adv7842_timings_cap_digital : 582a89bcd4cSHans Verkuil &adv7842_timings_cap_analog; 583a89bcd4cSHans Verkuil } 584a89bcd4cSHans Verkuil 585a89bcd4cSHans Verkuil /* ----------------------------------------------------------------------- */ 586a89bcd4cSHans Verkuil 587a89bcd4cSHans Verkuil static void adv7842_delayed_work_enable_hotplug(struct work_struct *work) 588a89bcd4cSHans Verkuil { 589a89bcd4cSHans Verkuil struct delayed_work *dwork = to_delayed_work(work); 590a89bcd4cSHans Verkuil struct adv7842_state *state = container_of(dwork, 591a89bcd4cSHans Verkuil struct adv7842_state, delayed_work_enable_hotplug); 592a89bcd4cSHans Verkuil struct v4l2_subdev *sd = &state->sd; 593a89bcd4cSHans Verkuil int present = state->hdmi_edid.present; 594a89bcd4cSHans Verkuil u8 mask = 0; 595a89bcd4cSHans Verkuil 596a89bcd4cSHans Verkuil v4l2_dbg(2, debug, sd, "%s: enable hotplug on ports: 0x%x\n", 597a89bcd4cSHans Verkuil __func__, present); 598a89bcd4cSHans Verkuil 5997de6fab1SMats Randgaard if (present & (0x04 << ADV7842_EDID_PORT_A)) 6007de6fab1SMats Randgaard mask |= 0x20; 6017de6fab1SMats Randgaard if (present & (0x04 << ADV7842_EDID_PORT_B)) 6027de6fab1SMats Randgaard mask |= 0x10; 603a89bcd4cSHans Verkuil io_write_and_or(sd, 0x20, 0xcf, mask); 604a89bcd4cSHans Verkuil } 605a89bcd4cSHans Verkuil 606a89bcd4cSHans Verkuil static int edid_write_vga_segment(struct v4l2_subdev *sd) 607a89bcd4cSHans Verkuil { 608a89bcd4cSHans Verkuil struct i2c_client *client = v4l2_get_subdevdata(sd); 609a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 610a89bcd4cSHans Verkuil const u8 *val = state->vga_edid.edid; 611a89bcd4cSHans Verkuil int err = 0; 612a89bcd4cSHans Verkuil int i; 613a89bcd4cSHans Verkuil 614a89bcd4cSHans Verkuil v4l2_dbg(2, debug, sd, "%s: write EDID on VGA port\n", __func__); 615a89bcd4cSHans Verkuil 616a89bcd4cSHans Verkuil /* HPA disable on port A and B */ 617a89bcd4cSHans Verkuil io_write_and_or(sd, 0x20, 0xcf, 0x00); 618a89bcd4cSHans Verkuil 619a89bcd4cSHans Verkuil /* Disable I2C access to internal EDID ram from VGA DDC port */ 620a89bcd4cSHans Verkuil rep_write_and_or(sd, 0x7f, 0x7f, 0x00); 621a89bcd4cSHans Verkuil 622a89bcd4cSHans Verkuil /* edid segment pointer '1' for VGA port */ 623a89bcd4cSHans Verkuil rep_write_and_or(sd, 0x77, 0xef, 0x10); 624a89bcd4cSHans Verkuil 625a89bcd4cSHans Verkuil for (i = 0; !err && i < 256; i += I2C_SMBUS_BLOCK_MAX) 626a89bcd4cSHans Verkuil err = adv_smbus_write_i2c_block_data(state->i2c_edid, i, 627a89bcd4cSHans Verkuil I2C_SMBUS_BLOCK_MAX, val + i); 628a89bcd4cSHans Verkuil if (err) 629a89bcd4cSHans Verkuil return err; 630a89bcd4cSHans Verkuil 631a89bcd4cSHans Verkuil /* Calculates the checksums and enables I2C access 632a89bcd4cSHans Verkuil * to internal EDID ram from VGA DDC port. 633a89bcd4cSHans Verkuil */ 634a89bcd4cSHans Verkuil rep_write_and_or(sd, 0x7f, 0x7f, 0x80); 635a89bcd4cSHans Verkuil 636a89bcd4cSHans Verkuil for (i = 0; i < 1000; i++) { 637a89bcd4cSHans Verkuil if (rep_read(sd, 0x79) & 0x20) 638a89bcd4cSHans Verkuil break; 639a89bcd4cSHans Verkuil mdelay(1); 640a89bcd4cSHans Verkuil } 641a89bcd4cSHans Verkuil if (i == 1000) { 642a89bcd4cSHans Verkuil v4l_err(client, "error enabling edid on VGA port\n"); 643a89bcd4cSHans Verkuil return -EIO; 644a89bcd4cSHans Verkuil } 645a89bcd4cSHans Verkuil 646a89bcd4cSHans Verkuil /* enable hotplug after 200 ms */ 647a89bcd4cSHans Verkuil queue_delayed_work(state->work_queues, 648a89bcd4cSHans Verkuil &state->delayed_work_enable_hotplug, HZ / 5); 649a89bcd4cSHans Verkuil 650a89bcd4cSHans Verkuil return 0; 651a89bcd4cSHans Verkuil } 652a89bcd4cSHans Verkuil 653a89bcd4cSHans Verkuil static int edid_spa_location(const u8 *edid) 654a89bcd4cSHans Verkuil { 655a89bcd4cSHans Verkuil u8 d; 656a89bcd4cSHans Verkuil 657a89bcd4cSHans Verkuil /* 658a89bcd4cSHans Verkuil * TODO, improve and update for other CEA extensions 659a89bcd4cSHans Verkuil * currently only for 1 segment (256 bytes), 660a89bcd4cSHans Verkuil * i.e. 1 extension block and CEA revision 3. 661a89bcd4cSHans Verkuil */ 662a89bcd4cSHans Verkuil if ((edid[0x7e] != 1) || 663a89bcd4cSHans Verkuil (edid[0x80] != 0x02) || 664a89bcd4cSHans Verkuil (edid[0x81] != 0x03)) { 665a89bcd4cSHans Verkuil return -EINVAL; 666a89bcd4cSHans Verkuil } 667a89bcd4cSHans Verkuil /* 668a89bcd4cSHans Verkuil * search Vendor Specific Data Block (tag 3) 669a89bcd4cSHans Verkuil */ 670a89bcd4cSHans Verkuil d = edid[0x82] & 0x7f; 671a89bcd4cSHans Verkuil if (d > 4) { 672a89bcd4cSHans Verkuil int i = 0x84; 673a89bcd4cSHans Verkuil int end = 0x80 + d; 674a89bcd4cSHans Verkuil do { 675a89bcd4cSHans Verkuil u8 tag = edid[i]>>5; 676a89bcd4cSHans Verkuil u8 len = edid[i] & 0x1f; 677a89bcd4cSHans Verkuil 678a89bcd4cSHans Verkuil if ((tag == 3) && (len >= 5)) 679a89bcd4cSHans Verkuil return i + 4; 680a89bcd4cSHans Verkuil i += len + 1; 681a89bcd4cSHans Verkuil } while (i < end); 682a89bcd4cSHans Verkuil } 683a89bcd4cSHans Verkuil return -EINVAL; 684a89bcd4cSHans Verkuil } 685a89bcd4cSHans Verkuil 686a89bcd4cSHans Verkuil static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port) 687a89bcd4cSHans Verkuil { 688a89bcd4cSHans Verkuil struct i2c_client *client = v4l2_get_subdevdata(sd); 689a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 690a89bcd4cSHans Verkuil const u8 *val = state->hdmi_edid.edid; 691a89bcd4cSHans Verkuil int spa_loc = edid_spa_location(val); 692a89bcd4cSHans Verkuil int err = 0; 693a89bcd4cSHans Verkuil int i; 694a89bcd4cSHans Verkuil 6957de6fab1SMats Randgaard v4l2_dbg(2, debug, sd, "%s: write EDID on port %c (spa at 0x%x)\n", 6967de6fab1SMats Randgaard __func__, (port == ADV7842_EDID_PORT_A) ? 'A' : 'B', spa_loc); 697a89bcd4cSHans Verkuil 698a89bcd4cSHans Verkuil /* HPA disable on port A and B */ 699a89bcd4cSHans Verkuil io_write_and_or(sd, 0x20, 0xcf, 0x00); 700a89bcd4cSHans Verkuil 701a89bcd4cSHans Verkuil /* Disable I2C access to internal EDID ram from HDMI DDC ports */ 702a89bcd4cSHans Verkuil rep_write_and_or(sd, 0x77, 0xf3, 0x00); 703a89bcd4cSHans Verkuil 704fc2e991eSMartin Bugge if (!state->hdmi_edid.present) 705fc2e991eSMartin Bugge return 0; 706fc2e991eSMartin Bugge 707a89bcd4cSHans Verkuil /* edid segment pointer '0' for HDMI ports */ 708a89bcd4cSHans Verkuil rep_write_and_or(sd, 0x77, 0xef, 0x00); 709a89bcd4cSHans Verkuil 710a89bcd4cSHans Verkuil for (i = 0; !err && i < 256; i += I2C_SMBUS_BLOCK_MAX) 711a89bcd4cSHans Verkuil err = adv_smbus_write_i2c_block_data(state->i2c_edid, i, 712a89bcd4cSHans Verkuil I2C_SMBUS_BLOCK_MAX, val + i); 713a89bcd4cSHans Verkuil if (err) 714a89bcd4cSHans Verkuil return err; 715a89bcd4cSHans Verkuil 7167de6fab1SMats Randgaard if (spa_loc < 0) 7177de6fab1SMats Randgaard spa_loc = 0xc0; /* Default value [REF_02, p. 199] */ 7187de6fab1SMats Randgaard 7197de6fab1SMats Randgaard if (port == ADV7842_EDID_PORT_A) { 720a89bcd4cSHans Verkuil rep_write(sd, 0x72, val[spa_loc]); 721a89bcd4cSHans Verkuil rep_write(sd, 0x73, val[spa_loc + 1]); 722a89bcd4cSHans Verkuil } else { 723a89bcd4cSHans Verkuil rep_write(sd, 0x74, val[spa_loc]); 724a89bcd4cSHans Verkuil rep_write(sd, 0x75, val[spa_loc + 1]); 725a89bcd4cSHans Verkuil } 7267de6fab1SMats Randgaard rep_write(sd, 0x76, spa_loc & 0xff); 7277de6fab1SMats Randgaard rep_write_and_or(sd, 0x77, 0xbf, (spa_loc >> 2) & 0x40); 728a89bcd4cSHans Verkuil 729a89bcd4cSHans Verkuil /* Calculates the checksums and enables I2C access to internal 730a89bcd4cSHans Verkuil * EDID ram from HDMI DDC ports 731a89bcd4cSHans Verkuil */ 7327de6fab1SMats Randgaard rep_write_and_or(sd, 0x77, 0xf3, state->hdmi_edid.present); 733a89bcd4cSHans Verkuil 734a89bcd4cSHans Verkuil for (i = 0; i < 1000; i++) { 7357de6fab1SMats Randgaard if (rep_read(sd, 0x7d) & state->hdmi_edid.present) 736a89bcd4cSHans Verkuil break; 737a89bcd4cSHans Verkuil mdelay(1); 738a89bcd4cSHans Verkuil } 739a89bcd4cSHans Verkuil if (i == 1000) { 7407de6fab1SMats Randgaard v4l_err(client, "error enabling edid on port %c\n", 7417de6fab1SMats Randgaard (port == ADV7842_EDID_PORT_A) ? 'A' : 'B'); 742a89bcd4cSHans Verkuil return -EIO; 743a89bcd4cSHans Verkuil } 744a89bcd4cSHans Verkuil 745a89bcd4cSHans Verkuil /* enable hotplug after 200 ms */ 746a89bcd4cSHans Verkuil queue_delayed_work(state->work_queues, 747a89bcd4cSHans Verkuil &state->delayed_work_enable_hotplug, HZ / 5); 748a89bcd4cSHans Verkuil 749a89bcd4cSHans Verkuil return 0; 750a89bcd4cSHans Verkuil } 751a89bcd4cSHans Verkuil 752a89bcd4cSHans Verkuil /* ----------------------------------------------------------------------- */ 753a89bcd4cSHans Verkuil 754a89bcd4cSHans Verkuil #ifdef CONFIG_VIDEO_ADV_DEBUG 755a89bcd4cSHans Verkuil static void adv7842_inv_register(struct v4l2_subdev *sd) 756a89bcd4cSHans Verkuil { 757a89bcd4cSHans Verkuil v4l2_info(sd, "0x000-0x0ff: IO Map\n"); 758a89bcd4cSHans Verkuil v4l2_info(sd, "0x100-0x1ff: AVLink Map\n"); 759a89bcd4cSHans Verkuil v4l2_info(sd, "0x200-0x2ff: CEC Map\n"); 760a89bcd4cSHans Verkuil v4l2_info(sd, "0x300-0x3ff: InfoFrame Map\n"); 761a89bcd4cSHans Verkuil v4l2_info(sd, "0x400-0x4ff: SDP_IO Map\n"); 762a89bcd4cSHans Verkuil v4l2_info(sd, "0x500-0x5ff: SDP Map\n"); 763a89bcd4cSHans Verkuil v4l2_info(sd, "0x600-0x6ff: AFE Map\n"); 764a89bcd4cSHans Verkuil v4l2_info(sd, "0x700-0x7ff: Repeater Map\n"); 765a89bcd4cSHans Verkuil v4l2_info(sd, "0x800-0x8ff: EDID Map\n"); 766a89bcd4cSHans Verkuil v4l2_info(sd, "0x900-0x9ff: HDMI Map\n"); 767a89bcd4cSHans Verkuil v4l2_info(sd, "0xa00-0xaff: CP Map\n"); 768a89bcd4cSHans Verkuil v4l2_info(sd, "0xb00-0xbff: VDP Map\n"); 769a89bcd4cSHans Verkuil } 770a89bcd4cSHans Verkuil 771a89bcd4cSHans Verkuil static int adv7842_g_register(struct v4l2_subdev *sd, 772a89bcd4cSHans Verkuil struct v4l2_dbg_register *reg) 773a89bcd4cSHans Verkuil { 774a89bcd4cSHans Verkuil reg->size = 1; 775a89bcd4cSHans Verkuil switch (reg->reg >> 8) { 776a89bcd4cSHans Verkuil case 0: 777a89bcd4cSHans Verkuil reg->val = io_read(sd, reg->reg & 0xff); 778a89bcd4cSHans Verkuil break; 779a89bcd4cSHans Verkuil case 1: 780a89bcd4cSHans Verkuil reg->val = avlink_read(sd, reg->reg & 0xff); 781a89bcd4cSHans Verkuil break; 782a89bcd4cSHans Verkuil case 2: 783a89bcd4cSHans Verkuil reg->val = cec_read(sd, reg->reg & 0xff); 784a89bcd4cSHans Verkuil break; 785a89bcd4cSHans Verkuil case 3: 786a89bcd4cSHans Verkuil reg->val = infoframe_read(sd, reg->reg & 0xff); 787a89bcd4cSHans Verkuil break; 788a89bcd4cSHans Verkuil case 4: 789a89bcd4cSHans Verkuil reg->val = sdp_io_read(sd, reg->reg & 0xff); 790a89bcd4cSHans Verkuil break; 791a89bcd4cSHans Verkuil case 5: 792a89bcd4cSHans Verkuil reg->val = sdp_read(sd, reg->reg & 0xff); 793a89bcd4cSHans Verkuil break; 794a89bcd4cSHans Verkuil case 6: 795a89bcd4cSHans Verkuil reg->val = afe_read(sd, reg->reg & 0xff); 796a89bcd4cSHans Verkuil break; 797a89bcd4cSHans Verkuil case 7: 798a89bcd4cSHans Verkuil reg->val = rep_read(sd, reg->reg & 0xff); 799a89bcd4cSHans Verkuil break; 800a89bcd4cSHans Verkuil case 8: 801a89bcd4cSHans Verkuil reg->val = edid_read(sd, reg->reg & 0xff); 802a89bcd4cSHans Verkuil break; 803a89bcd4cSHans Verkuil case 9: 804a89bcd4cSHans Verkuil reg->val = hdmi_read(sd, reg->reg & 0xff); 805a89bcd4cSHans Verkuil break; 806a89bcd4cSHans Verkuil case 0xa: 807a89bcd4cSHans Verkuil reg->val = cp_read(sd, reg->reg & 0xff); 808a89bcd4cSHans Verkuil break; 809a89bcd4cSHans Verkuil case 0xb: 810a89bcd4cSHans Verkuil reg->val = vdp_read(sd, reg->reg & 0xff); 811a89bcd4cSHans Verkuil break; 812a89bcd4cSHans Verkuil default: 813a89bcd4cSHans Verkuil v4l2_info(sd, "Register %03llx not supported\n", reg->reg); 814a89bcd4cSHans Verkuil adv7842_inv_register(sd); 815a89bcd4cSHans Verkuil break; 816a89bcd4cSHans Verkuil } 817a89bcd4cSHans Verkuil return 0; 818a89bcd4cSHans Verkuil } 819a89bcd4cSHans Verkuil 820a89bcd4cSHans Verkuil static int adv7842_s_register(struct v4l2_subdev *sd, 821a89bcd4cSHans Verkuil const struct v4l2_dbg_register *reg) 822a89bcd4cSHans Verkuil { 823a89bcd4cSHans Verkuil u8 val = reg->val & 0xff; 824a89bcd4cSHans Verkuil 825a89bcd4cSHans Verkuil switch (reg->reg >> 8) { 826a89bcd4cSHans Verkuil case 0: 827a89bcd4cSHans Verkuil io_write(sd, reg->reg & 0xff, val); 828a89bcd4cSHans Verkuil break; 829a89bcd4cSHans Verkuil case 1: 830a89bcd4cSHans Verkuil avlink_write(sd, reg->reg & 0xff, val); 831a89bcd4cSHans Verkuil break; 832a89bcd4cSHans Verkuil case 2: 833a89bcd4cSHans Verkuil cec_write(sd, reg->reg & 0xff, val); 834a89bcd4cSHans Verkuil break; 835a89bcd4cSHans Verkuil case 3: 836a89bcd4cSHans Verkuil infoframe_write(sd, reg->reg & 0xff, val); 837a89bcd4cSHans Verkuil break; 838a89bcd4cSHans Verkuil case 4: 839a89bcd4cSHans Verkuil sdp_io_write(sd, reg->reg & 0xff, val); 840a89bcd4cSHans Verkuil break; 841a89bcd4cSHans Verkuil case 5: 842a89bcd4cSHans Verkuil sdp_write(sd, reg->reg & 0xff, val); 843a89bcd4cSHans Verkuil break; 844a89bcd4cSHans Verkuil case 6: 845a89bcd4cSHans Verkuil afe_write(sd, reg->reg & 0xff, val); 846a89bcd4cSHans Verkuil break; 847a89bcd4cSHans Verkuil case 7: 848a89bcd4cSHans Verkuil rep_write(sd, reg->reg & 0xff, val); 849a89bcd4cSHans Verkuil break; 850a89bcd4cSHans Verkuil case 8: 851a89bcd4cSHans Verkuil edid_write(sd, reg->reg & 0xff, val); 852a89bcd4cSHans Verkuil break; 853a89bcd4cSHans Verkuil case 9: 854a89bcd4cSHans Verkuil hdmi_write(sd, reg->reg & 0xff, val); 855a89bcd4cSHans Verkuil break; 856a89bcd4cSHans Verkuil case 0xa: 857a89bcd4cSHans Verkuil cp_write(sd, reg->reg & 0xff, val); 858a89bcd4cSHans Verkuil break; 859a89bcd4cSHans Verkuil case 0xb: 860a89bcd4cSHans Verkuil vdp_write(sd, reg->reg & 0xff, val); 861a89bcd4cSHans Verkuil break; 862a89bcd4cSHans Verkuil default: 863a89bcd4cSHans Verkuil v4l2_info(sd, "Register %03llx not supported\n", reg->reg); 864a89bcd4cSHans Verkuil adv7842_inv_register(sd); 865a89bcd4cSHans Verkuil break; 866a89bcd4cSHans Verkuil } 867a89bcd4cSHans Verkuil return 0; 868a89bcd4cSHans Verkuil } 869a89bcd4cSHans Verkuil #endif 870a89bcd4cSHans Verkuil 871a89bcd4cSHans Verkuil static int adv7842_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd) 872a89bcd4cSHans Verkuil { 873a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 874a89bcd4cSHans Verkuil int prev = v4l2_ctrl_g_ctrl(state->detect_tx_5v_ctrl); 875a89bcd4cSHans Verkuil u8 reg_io_6f = io_read(sd, 0x6f); 876a89bcd4cSHans Verkuil int val = 0; 877a89bcd4cSHans Verkuil 878a89bcd4cSHans Verkuil if (reg_io_6f & 0x02) 879a89bcd4cSHans Verkuil val |= 1; /* port A */ 880a89bcd4cSHans Verkuil if (reg_io_6f & 0x01) 881a89bcd4cSHans Verkuil val |= 2; /* port B */ 882a89bcd4cSHans Verkuil 883a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, "%s: 0x%x -> 0x%x\n", __func__, prev, val); 884a89bcd4cSHans Verkuil 885a89bcd4cSHans Verkuil if (val != prev) 886a89bcd4cSHans Verkuil return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, val); 887a89bcd4cSHans Verkuil return 0; 888a89bcd4cSHans Verkuil } 889a89bcd4cSHans Verkuil 890a89bcd4cSHans Verkuil static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd, 891a89bcd4cSHans Verkuil u8 prim_mode, 892a89bcd4cSHans Verkuil const struct adv7842_video_standards *predef_vid_timings, 893a89bcd4cSHans Verkuil const struct v4l2_dv_timings *timings) 894a89bcd4cSHans Verkuil { 895a89bcd4cSHans Verkuil int i; 896a89bcd4cSHans Verkuil 897a89bcd4cSHans Verkuil for (i = 0; predef_vid_timings[i].timings.bt.width; i++) { 898a89bcd4cSHans Verkuil if (!v4l2_match_dv_timings(timings, &predef_vid_timings[i].timings, 899a89bcd4cSHans Verkuil is_digital_input(sd) ? 250000 : 1000000)) 900a89bcd4cSHans Verkuil continue; 901a89bcd4cSHans Verkuil /* video std */ 902a89bcd4cSHans Verkuil io_write(sd, 0x00, predef_vid_timings[i].vid_std); 903a89bcd4cSHans Verkuil /* v_freq and prim mode */ 904a89bcd4cSHans Verkuil io_write(sd, 0x01, (predef_vid_timings[i].v_freq << 4) + prim_mode); 905a89bcd4cSHans Verkuil return 0; 906a89bcd4cSHans Verkuil } 907a89bcd4cSHans Verkuil 908a89bcd4cSHans Verkuil return -1; 909a89bcd4cSHans Verkuil } 910a89bcd4cSHans Verkuil 911a89bcd4cSHans Verkuil static int configure_predefined_video_timings(struct v4l2_subdev *sd, 912a89bcd4cSHans Verkuil struct v4l2_dv_timings *timings) 913a89bcd4cSHans Verkuil { 914a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 915a89bcd4cSHans Verkuil int err; 916a89bcd4cSHans Verkuil 917a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, "%s\n", __func__); 918a89bcd4cSHans Verkuil 919a89bcd4cSHans Verkuil /* reset to default values */ 920a89bcd4cSHans Verkuil io_write(sd, 0x16, 0x43); 921a89bcd4cSHans Verkuil io_write(sd, 0x17, 0x5a); 922a89bcd4cSHans Verkuil /* disable embedded syncs for auto graphics mode */ 923a89bcd4cSHans Verkuil cp_write_and_or(sd, 0x81, 0xef, 0x00); 924a89bcd4cSHans Verkuil cp_write(sd, 0x26, 0x00); 925a89bcd4cSHans Verkuil cp_write(sd, 0x27, 0x00); 926a89bcd4cSHans Verkuil cp_write(sd, 0x28, 0x00); 927a89bcd4cSHans Verkuil cp_write(sd, 0x29, 0x00); 9286251e65fSMartin Bugge cp_write(sd, 0x8f, 0x40); 929a89bcd4cSHans Verkuil cp_write(sd, 0x90, 0x00); 930a89bcd4cSHans Verkuil cp_write(sd, 0xa5, 0x00); 931a89bcd4cSHans Verkuil cp_write(sd, 0xa6, 0x00); 932a89bcd4cSHans Verkuil cp_write(sd, 0xa7, 0x00); 933a89bcd4cSHans Verkuil cp_write(sd, 0xab, 0x00); 934a89bcd4cSHans Verkuil cp_write(sd, 0xac, 0x00); 935a89bcd4cSHans Verkuil 936a89bcd4cSHans Verkuil switch (state->mode) { 937a89bcd4cSHans Verkuil case ADV7842_MODE_COMP: 938a89bcd4cSHans Verkuil case ADV7842_MODE_RGB: 939a89bcd4cSHans Verkuil err = find_and_set_predefined_video_timings(sd, 940a89bcd4cSHans Verkuil 0x01, adv7842_prim_mode_comp, timings); 941a89bcd4cSHans Verkuil if (err) 942a89bcd4cSHans Verkuil err = find_and_set_predefined_video_timings(sd, 943a89bcd4cSHans Verkuil 0x02, adv7842_prim_mode_gr, timings); 944a89bcd4cSHans Verkuil break; 945a89bcd4cSHans Verkuil case ADV7842_MODE_HDMI: 946a89bcd4cSHans Verkuil err = find_and_set_predefined_video_timings(sd, 947a89bcd4cSHans Verkuil 0x05, adv7842_prim_mode_hdmi_comp, timings); 948a89bcd4cSHans Verkuil if (err) 949a89bcd4cSHans Verkuil err = find_and_set_predefined_video_timings(sd, 950a89bcd4cSHans Verkuil 0x06, adv7842_prim_mode_hdmi_gr, timings); 951a89bcd4cSHans Verkuil break; 952a89bcd4cSHans Verkuil default: 953a89bcd4cSHans Verkuil v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", 954a89bcd4cSHans Verkuil __func__, state->mode); 955a89bcd4cSHans Verkuil err = -1; 956a89bcd4cSHans Verkuil break; 957a89bcd4cSHans Verkuil } 958a89bcd4cSHans Verkuil 959a89bcd4cSHans Verkuil 960a89bcd4cSHans Verkuil return err; 961a89bcd4cSHans Verkuil } 962a89bcd4cSHans Verkuil 963a89bcd4cSHans Verkuil static void configure_custom_video_timings(struct v4l2_subdev *sd, 964a89bcd4cSHans Verkuil const struct v4l2_bt_timings *bt) 965a89bcd4cSHans Verkuil { 966a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 967a89bcd4cSHans Verkuil struct i2c_client *client = v4l2_get_subdevdata(sd); 968a89bcd4cSHans Verkuil u32 width = htotal(bt); 969a89bcd4cSHans Verkuil u32 height = vtotal(bt); 970a89bcd4cSHans Verkuil u16 cp_start_sav = bt->hsync + bt->hbackporch - 4; 971a89bcd4cSHans Verkuil u16 cp_start_eav = width - bt->hfrontporch; 972a89bcd4cSHans Verkuil u16 cp_start_vbi = height - bt->vfrontporch + 1; 973a89bcd4cSHans Verkuil u16 cp_end_vbi = bt->vsync + bt->vbackporch + 1; 974a89bcd4cSHans Verkuil u16 ch1_fr_ll = (((u32)bt->pixelclock / 100) > 0) ? 975a89bcd4cSHans Verkuil ((width * (ADV7842_fsc / 100)) / ((u32)bt->pixelclock / 100)) : 0; 976a89bcd4cSHans Verkuil const u8 pll[2] = { 977a89bcd4cSHans Verkuil 0xc0 | ((width >> 8) & 0x1f), 978a89bcd4cSHans Verkuil width & 0xff 979a89bcd4cSHans Verkuil }; 980a89bcd4cSHans Verkuil 981a89bcd4cSHans Verkuil v4l2_dbg(2, debug, sd, "%s\n", __func__); 982a89bcd4cSHans Verkuil 983a89bcd4cSHans Verkuil switch (state->mode) { 984a89bcd4cSHans Verkuil case ADV7842_MODE_COMP: 985a89bcd4cSHans Verkuil case ADV7842_MODE_RGB: 986a89bcd4cSHans Verkuil /* auto graphics */ 987a89bcd4cSHans Verkuil io_write(sd, 0x00, 0x07); /* video std */ 988a89bcd4cSHans Verkuil io_write(sd, 0x01, 0x02); /* prim mode */ 989a89bcd4cSHans Verkuil /* enable embedded syncs for auto graphics mode */ 990a89bcd4cSHans Verkuil cp_write_and_or(sd, 0x81, 0xef, 0x10); 991a89bcd4cSHans Verkuil 992a89bcd4cSHans Verkuil /* Should only be set in auto-graphics mode [REF_02, p. 91-92] */ 993a89bcd4cSHans Verkuil /* setup PLL_DIV_MAN_EN and PLL_DIV_RATIO */ 994a89bcd4cSHans Verkuil /* IO-map reg. 0x16 and 0x17 should be written in sequence */ 995a89bcd4cSHans Verkuil if (adv_smbus_write_i2c_block_data(client, 0x16, 2, pll)) { 996a89bcd4cSHans Verkuil v4l2_err(sd, "writing to reg 0x16 and 0x17 failed\n"); 997a89bcd4cSHans Verkuil break; 998a89bcd4cSHans Verkuil } 999a89bcd4cSHans Verkuil 1000a89bcd4cSHans Verkuil /* active video - horizontal timing */ 1001a89bcd4cSHans Verkuil cp_write(sd, 0x26, (cp_start_sav >> 8) & 0xf); 1002a89bcd4cSHans Verkuil cp_write(sd, 0x27, (cp_start_sav & 0xff)); 1003a89bcd4cSHans Verkuil cp_write(sd, 0x28, (cp_start_eav >> 8) & 0xf); 1004a89bcd4cSHans Verkuil cp_write(sd, 0x29, (cp_start_eav & 0xff)); 1005a89bcd4cSHans Verkuil 1006a89bcd4cSHans Verkuil /* active video - vertical timing */ 1007a89bcd4cSHans Verkuil cp_write(sd, 0xa5, (cp_start_vbi >> 4) & 0xff); 1008a89bcd4cSHans Verkuil cp_write(sd, 0xa6, ((cp_start_vbi & 0xf) << 4) | 1009a89bcd4cSHans Verkuil ((cp_end_vbi >> 8) & 0xf)); 1010a89bcd4cSHans Verkuil cp_write(sd, 0xa7, cp_end_vbi & 0xff); 1011a89bcd4cSHans Verkuil break; 1012a89bcd4cSHans Verkuil case ADV7842_MODE_HDMI: 1013a89bcd4cSHans Verkuil /* set default prim_mode/vid_std for HDMI 101439c1cb2bSJonathan McCrohan according to [REF_03, c. 4.2] */ 1015a89bcd4cSHans Verkuil io_write(sd, 0x00, 0x02); /* video std */ 1016a89bcd4cSHans Verkuil io_write(sd, 0x01, 0x06); /* prim mode */ 1017a89bcd4cSHans Verkuil break; 1018a89bcd4cSHans Verkuil default: 1019a89bcd4cSHans Verkuil v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", 1020a89bcd4cSHans Verkuil __func__, state->mode); 1021a89bcd4cSHans Verkuil break; 1022a89bcd4cSHans Verkuil } 1023a89bcd4cSHans Verkuil 1024a89bcd4cSHans Verkuil cp_write(sd, 0x8f, (ch1_fr_ll >> 8) & 0x7); 1025a89bcd4cSHans Verkuil cp_write(sd, 0x90, ch1_fr_ll & 0xff); 1026a89bcd4cSHans Verkuil cp_write(sd, 0xab, (height >> 4) & 0xff); 1027a89bcd4cSHans Verkuil cp_write(sd, 0xac, (height & 0x0f) << 4); 1028a89bcd4cSHans Verkuil } 1029a89bcd4cSHans Verkuil 1030a89bcd4cSHans Verkuil static void set_rgb_quantization_range(struct v4l2_subdev *sd) 1031a89bcd4cSHans Verkuil { 1032a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 1033a89bcd4cSHans Verkuil 103469e9ba6fSHans Verkuil v4l2_dbg(2, debug, sd, "%s: rgb_quantization_range = %d\n", 103569e9ba6fSHans Verkuil __func__, state->rgb_quantization_range); 103669e9ba6fSHans Verkuil 1037a89bcd4cSHans Verkuil switch (state->rgb_quantization_range) { 1038a89bcd4cSHans Verkuil case V4L2_DV_RGB_RANGE_AUTO: 103969e9ba6fSHans Verkuil if (state->mode == ADV7842_MODE_RGB) { 104069e9ba6fSHans Verkuil /* Receiving analog RGB signal 104169e9ba6fSHans Verkuil * Set RGB full range (0-255) */ 104269e9ba6fSHans Verkuil io_write_and_or(sd, 0x02, 0x0f, 0x10); 104369e9ba6fSHans Verkuil break; 104469e9ba6fSHans Verkuil } 1045a89bcd4cSHans Verkuil 104669e9ba6fSHans Verkuil if (state->mode == ADV7842_MODE_COMP) { 104769e9ba6fSHans Verkuil /* Receiving analog YPbPr signal 104869e9ba6fSHans Verkuil * Set automode */ 104969e9ba6fSHans Verkuil io_write_and_or(sd, 0x02, 0x0f, 0xf0); 105069e9ba6fSHans Verkuil break; 105169e9ba6fSHans Verkuil } 105269e9ba6fSHans Verkuil 105369e9ba6fSHans Verkuil if (hdmi_read(sd, 0x05) & 0x80) { 105469e9ba6fSHans Verkuil /* Receiving HDMI signal 105569e9ba6fSHans Verkuil * Set automode */ 105669e9ba6fSHans Verkuil io_write_and_or(sd, 0x02, 0x0f, 0xf0); 105769e9ba6fSHans Verkuil break; 105869e9ba6fSHans Verkuil } 105969e9ba6fSHans Verkuil 106069e9ba6fSHans Verkuil /* Receiving DVI-D signal 106169e9ba6fSHans Verkuil * ADV7842 selects RGB limited range regardless of 106269e9ba6fSHans Verkuil * input format (CE/IT) in automatic mode */ 1063a89bcd4cSHans Verkuil if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) { 1064a89bcd4cSHans Verkuil /* RGB limited range (16-235) */ 1065a89bcd4cSHans Verkuil io_write_and_or(sd, 0x02, 0x0f, 0x00); 1066a89bcd4cSHans Verkuil } else { 1067a89bcd4cSHans Verkuil /* RGB full range (0-255) */ 1068a89bcd4cSHans Verkuil io_write_and_or(sd, 0x02, 0x0f, 0x10); 1069a89bcd4cSHans Verkuil } 1070a89bcd4cSHans Verkuil break; 1071a89bcd4cSHans Verkuil case V4L2_DV_RGB_RANGE_LIMITED: 107269e9ba6fSHans Verkuil if (state->mode == ADV7842_MODE_COMP) { 107369e9ba6fSHans Verkuil /* YCrCb limited range (16-235) */ 107469e9ba6fSHans Verkuil io_write_and_or(sd, 0x02, 0x0f, 0x20); 107569e9ba6fSHans Verkuil } else { 1076a89bcd4cSHans Verkuil /* RGB limited range (16-235) */ 1077a89bcd4cSHans Verkuil io_write_and_or(sd, 0x02, 0x0f, 0x00); 107869e9ba6fSHans Verkuil } 1079a89bcd4cSHans Verkuil break; 1080a89bcd4cSHans Verkuil case V4L2_DV_RGB_RANGE_FULL: 108169e9ba6fSHans Verkuil if (state->mode == ADV7842_MODE_COMP) { 108269e9ba6fSHans Verkuil /* YCrCb full range (0-255) */ 108369e9ba6fSHans Verkuil io_write_and_or(sd, 0x02, 0x0f, 0x60); 108469e9ba6fSHans Verkuil } else { 1085a89bcd4cSHans Verkuil /* RGB full range (0-255) */ 1086a89bcd4cSHans Verkuil io_write_and_or(sd, 0x02, 0x0f, 0x10); 108769e9ba6fSHans Verkuil } 1088a89bcd4cSHans Verkuil break; 1089a89bcd4cSHans Verkuil } 1090a89bcd4cSHans Verkuil } 1091a89bcd4cSHans Verkuil 1092a89bcd4cSHans Verkuil static int adv7842_s_ctrl(struct v4l2_ctrl *ctrl) 1093a89bcd4cSHans Verkuil { 1094a89bcd4cSHans Verkuil struct v4l2_subdev *sd = to_sd(ctrl); 1095a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 1096a89bcd4cSHans Verkuil 1097a89bcd4cSHans Verkuil /* TODO SDP ctrls 1098a89bcd4cSHans Verkuil contrast/brightness/hue/free run is acting a bit strange, 1099a89bcd4cSHans Verkuil not sure if sdp csc is correct. 1100a89bcd4cSHans Verkuil */ 1101a89bcd4cSHans Verkuil switch (ctrl->id) { 1102a89bcd4cSHans Verkuil /* standard ctrls */ 1103a89bcd4cSHans Verkuil case V4L2_CID_BRIGHTNESS: 1104a89bcd4cSHans Verkuil cp_write(sd, 0x3c, ctrl->val); 1105a89bcd4cSHans Verkuil sdp_write(sd, 0x14, ctrl->val); 1106a89bcd4cSHans Verkuil /* ignore lsb sdp 0x17[3:2] */ 1107a89bcd4cSHans Verkuil return 0; 1108a89bcd4cSHans Verkuil case V4L2_CID_CONTRAST: 1109a89bcd4cSHans Verkuil cp_write(sd, 0x3a, ctrl->val); 1110a89bcd4cSHans Verkuil sdp_write(sd, 0x13, ctrl->val); 1111a89bcd4cSHans Verkuil /* ignore lsb sdp 0x17[1:0] */ 1112a89bcd4cSHans Verkuil return 0; 1113a89bcd4cSHans Verkuil case V4L2_CID_SATURATION: 1114a89bcd4cSHans Verkuil cp_write(sd, 0x3b, ctrl->val); 1115a89bcd4cSHans Verkuil sdp_write(sd, 0x15, ctrl->val); 1116a89bcd4cSHans Verkuil /* ignore lsb sdp 0x17[5:4] */ 1117a89bcd4cSHans Verkuil return 0; 1118a89bcd4cSHans Verkuil case V4L2_CID_HUE: 1119a89bcd4cSHans Verkuil cp_write(sd, 0x3d, ctrl->val); 1120a89bcd4cSHans Verkuil sdp_write(sd, 0x16, ctrl->val); 1121a89bcd4cSHans Verkuil /* ignore lsb sdp 0x17[7:6] */ 1122a89bcd4cSHans Verkuil return 0; 1123a89bcd4cSHans Verkuil /* custom ctrls */ 1124a89bcd4cSHans Verkuil case V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE: 1125a89bcd4cSHans Verkuil afe_write(sd, 0xc8, ctrl->val); 1126a89bcd4cSHans Verkuil return 0; 1127a89bcd4cSHans Verkuil case V4L2_CID_ADV_RX_FREE_RUN_COLOR_MANUAL: 1128a89bcd4cSHans Verkuil cp_write_and_or(sd, 0xbf, ~0x04, (ctrl->val << 2)); 1129a89bcd4cSHans Verkuil sdp_write_and_or(sd, 0xdd, ~0x04, (ctrl->val << 2)); 1130a89bcd4cSHans Verkuil return 0; 1131a89bcd4cSHans Verkuil case V4L2_CID_ADV_RX_FREE_RUN_COLOR: { 1132a89bcd4cSHans Verkuil u8 R = (ctrl->val & 0xff0000) >> 16; 1133a89bcd4cSHans Verkuil u8 G = (ctrl->val & 0x00ff00) >> 8; 1134a89bcd4cSHans Verkuil u8 B = (ctrl->val & 0x0000ff); 1135a89bcd4cSHans Verkuil /* RGB -> YUV, numerical approximation */ 1136a89bcd4cSHans Verkuil int Y = 66 * R + 129 * G + 25 * B; 1137a89bcd4cSHans Verkuil int U = -38 * R - 74 * G + 112 * B; 1138a89bcd4cSHans Verkuil int V = 112 * R - 94 * G - 18 * B; 1139a89bcd4cSHans Verkuil 1140a89bcd4cSHans Verkuil /* Scale down to 8 bits with rounding */ 1141a89bcd4cSHans Verkuil Y = (Y + 128) >> 8; 1142a89bcd4cSHans Verkuil U = (U + 128) >> 8; 1143a89bcd4cSHans Verkuil V = (V + 128) >> 8; 1144a89bcd4cSHans Verkuil /* make U,V positive */ 1145a89bcd4cSHans Verkuil Y += 16; 1146a89bcd4cSHans Verkuil U += 128; 1147a89bcd4cSHans Verkuil V += 128; 1148a89bcd4cSHans Verkuil 1149a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, "R %x, G %x, B %x\n", R, G, B); 1150a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, "Y %x, U %x, V %x\n", Y, U, V); 1151a89bcd4cSHans Verkuil 1152a89bcd4cSHans Verkuil /* CP */ 1153a89bcd4cSHans Verkuil cp_write(sd, 0xc1, R); 1154a89bcd4cSHans Verkuil cp_write(sd, 0xc0, G); 1155a89bcd4cSHans Verkuil cp_write(sd, 0xc2, B); 1156a89bcd4cSHans Verkuil /* SDP */ 1157a89bcd4cSHans Verkuil sdp_write(sd, 0xde, Y); 1158a89bcd4cSHans Verkuil sdp_write(sd, 0xdf, (V & 0xf0) | ((U >> 4) & 0x0f)); 1159a89bcd4cSHans Verkuil return 0; 1160a89bcd4cSHans Verkuil } 1161a89bcd4cSHans Verkuil case V4L2_CID_DV_RX_RGB_RANGE: 1162a89bcd4cSHans Verkuil state->rgb_quantization_range = ctrl->val; 1163a89bcd4cSHans Verkuil set_rgb_quantization_range(sd); 1164a89bcd4cSHans Verkuil return 0; 1165a89bcd4cSHans Verkuil } 1166a89bcd4cSHans Verkuil return -EINVAL; 1167a89bcd4cSHans Verkuil } 1168a89bcd4cSHans Verkuil 1169a89bcd4cSHans Verkuil static inline bool no_power(struct v4l2_subdev *sd) 1170a89bcd4cSHans Verkuil { 1171a89bcd4cSHans Verkuil return io_read(sd, 0x0c) & 0x24; 1172a89bcd4cSHans Verkuil } 1173a89bcd4cSHans Verkuil 1174a89bcd4cSHans Verkuil static inline bool no_cp_signal(struct v4l2_subdev *sd) 1175a89bcd4cSHans Verkuil { 1176a89bcd4cSHans Verkuil return ((cp_read(sd, 0xb5) & 0xd0) != 0xd0) || !(cp_read(sd, 0xb1) & 0x80); 1177a89bcd4cSHans Verkuil } 1178a89bcd4cSHans Verkuil 1179a89bcd4cSHans Verkuil static inline bool is_hdmi(struct v4l2_subdev *sd) 1180a89bcd4cSHans Verkuil { 1181a89bcd4cSHans Verkuil return hdmi_read(sd, 0x05) & 0x80; 1182a89bcd4cSHans Verkuil } 1183a89bcd4cSHans Verkuil 1184a89bcd4cSHans Verkuil static int adv7842_g_input_status(struct v4l2_subdev *sd, u32 *status) 1185a89bcd4cSHans Verkuil { 1186a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 1187a89bcd4cSHans Verkuil 1188a89bcd4cSHans Verkuil *status = 0; 1189a89bcd4cSHans Verkuil 1190a89bcd4cSHans Verkuil if (io_read(sd, 0x0c) & 0x24) 1191a89bcd4cSHans Verkuil *status |= V4L2_IN_ST_NO_POWER; 1192a89bcd4cSHans Verkuil 1193a89bcd4cSHans Verkuil if (state->mode == ADV7842_MODE_SDP) { 1194a89bcd4cSHans Verkuil /* status from SDP block */ 1195a89bcd4cSHans Verkuil if (!(sdp_read(sd, 0x5A) & 0x01)) 1196a89bcd4cSHans Verkuil *status |= V4L2_IN_ST_NO_SIGNAL; 1197a89bcd4cSHans Verkuil 1198a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, "%s: SDP status = 0x%x\n", 1199a89bcd4cSHans Verkuil __func__, *status); 1200a89bcd4cSHans Verkuil return 0; 1201a89bcd4cSHans Verkuil } 1202a89bcd4cSHans Verkuil /* status from CP block */ 1203a89bcd4cSHans Verkuil if ((cp_read(sd, 0xb5) & 0xd0) != 0xd0 || 1204a89bcd4cSHans Verkuil !(cp_read(sd, 0xb1) & 0x80)) 1205a89bcd4cSHans Verkuil /* TODO channel 2 */ 1206a89bcd4cSHans Verkuil *status |= V4L2_IN_ST_NO_SIGNAL; 1207a89bcd4cSHans Verkuil 1208a89bcd4cSHans Verkuil if (is_digital_input(sd) && ((io_read(sd, 0x74) & 0x03) != 0x03)) 1209a89bcd4cSHans Verkuil *status |= V4L2_IN_ST_NO_SIGNAL; 1210a89bcd4cSHans Verkuil 1211a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, "%s: CP status = 0x%x\n", 1212a89bcd4cSHans Verkuil __func__, *status); 1213a89bcd4cSHans Verkuil 1214a89bcd4cSHans Verkuil return 0; 1215a89bcd4cSHans Verkuil } 1216a89bcd4cSHans Verkuil 1217a89bcd4cSHans Verkuil struct stdi_readback { 1218a89bcd4cSHans Verkuil u16 bl, lcf, lcvs; 1219a89bcd4cSHans Verkuil u8 hs_pol, vs_pol; 1220a89bcd4cSHans Verkuil bool interlaced; 1221a89bcd4cSHans Verkuil }; 1222a89bcd4cSHans Verkuil 1223a89bcd4cSHans Verkuil static int stdi2dv_timings(struct v4l2_subdev *sd, 1224a89bcd4cSHans Verkuil struct stdi_readback *stdi, 1225a89bcd4cSHans Verkuil struct v4l2_dv_timings *timings) 1226a89bcd4cSHans Verkuil { 1227a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 1228a89bcd4cSHans Verkuil u32 hfreq = (ADV7842_fsc * 8) / stdi->bl; 1229a89bcd4cSHans Verkuil u32 pix_clk; 1230a89bcd4cSHans Verkuil int i; 1231a89bcd4cSHans Verkuil 1232a89bcd4cSHans Verkuil for (i = 0; v4l2_dv_timings_presets[i].bt.width; i++) { 1233a89bcd4cSHans Verkuil const struct v4l2_bt_timings *bt = &v4l2_dv_timings_presets[i].bt; 1234a89bcd4cSHans Verkuil 1235a89bcd4cSHans Verkuil if (!v4l2_valid_dv_timings(&v4l2_dv_timings_presets[i], 1236a89bcd4cSHans Verkuil adv7842_get_dv_timings_cap(sd), 1237a89bcd4cSHans Verkuil adv7842_check_dv_timings, NULL)) 1238a89bcd4cSHans Verkuil continue; 1239a89bcd4cSHans Verkuil if (vtotal(bt) != stdi->lcf + 1) 1240a89bcd4cSHans Verkuil continue; 1241a89bcd4cSHans Verkuil if (bt->vsync != stdi->lcvs) 1242a89bcd4cSHans Verkuil continue; 1243a89bcd4cSHans Verkuil 1244a89bcd4cSHans Verkuil pix_clk = hfreq * htotal(bt); 1245a89bcd4cSHans Verkuil 1246a89bcd4cSHans Verkuil if ((pix_clk < bt->pixelclock + 1000000) && 1247a89bcd4cSHans Verkuil (pix_clk > bt->pixelclock - 1000000)) { 1248a89bcd4cSHans Verkuil *timings = v4l2_dv_timings_presets[i]; 1249a89bcd4cSHans Verkuil return 0; 1250a89bcd4cSHans Verkuil } 1251a89bcd4cSHans Verkuil } 1252a89bcd4cSHans Verkuil 1253a89bcd4cSHans Verkuil if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs, 1254a89bcd4cSHans Verkuil (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) | 1255a89bcd4cSHans Verkuil (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0), 1256a89bcd4cSHans Verkuil timings)) 1257a89bcd4cSHans Verkuil return 0; 1258a89bcd4cSHans Verkuil if (v4l2_detect_gtf(stdi->lcf + 1, hfreq, stdi->lcvs, 1259a89bcd4cSHans Verkuil (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) | 1260a89bcd4cSHans Verkuil (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0), 1261a89bcd4cSHans Verkuil state->aspect_ratio, timings)) 1262a89bcd4cSHans Verkuil return 0; 1263a89bcd4cSHans Verkuil 1264a89bcd4cSHans Verkuil v4l2_dbg(2, debug, sd, 1265a89bcd4cSHans Verkuil "%s: No format candidate found for lcvs = %d, lcf=%d, bl = %d, %chsync, %cvsync\n", 1266a89bcd4cSHans Verkuil __func__, stdi->lcvs, stdi->lcf, stdi->bl, 1267a89bcd4cSHans Verkuil stdi->hs_pol, stdi->vs_pol); 1268a89bcd4cSHans Verkuil return -1; 1269a89bcd4cSHans Verkuil } 1270a89bcd4cSHans Verkuil 1271a89bcd4cSHans Verkuil static int read_stdi(struct v4l2_subdev *sd, struct stdi_readback *stdi) 1272a89bcd4cSHans Verkuil { 1273a89bcd4cSHans Verkuil u32 status; 1274a89bcd4cSHans Verkuil 1275a89bcd4cSHans Verkuil adv7842_g_input_status(sd, &status); 1276a89bcd4cSHans Verkuil if (status & V4L2_IN_ST_NO_SIGNAL) { 1277a89bcd4cSHans Verkuil v4l2_dbg(2, debug, sd, "%s: no signal\n", __func__); 1278a89bcd4cSHans Verkuil return -ENOLINK; 1279a89bcd4cSHans Verkuil } 1280a89bcd4cSHans Verkuil 1281a89bcd4cSHans Verkuil stdi->bl = ((cp_read(sd, 0xb1) & 0x3f) << 8) | cp_read(sd, 0xb2); 1282a89bcd4cSHans Verkuil stdi->lcf = ((cp_read(sd, 0xb3) & 0x7) << 8) | cp_read(sd, 0xb4); 1283a89bcd4cSHans Verkuil stdi->lcvs = cp_read(sd, 0xb3) >> 3; 1284a89bcd4cSHans Verkuil 1285a89bcd4cSHans Verkuil if ((cp_read(sd, 0xb5) & 0x80) && ((cp_read(sd, 0xb5) & 0x03) == 0x01)) { 1286a89bcd4cSHans Verkuil stdi->hs_pol = ((cp_read(sd, 0xb5) & 0x10) ? 1287a89bcd4cSHans Verkuil ((cp_read(sd, 0xb5) & 0x08) ? '+' : '-') : 'x'); 1288a89bcd4cSHans Verkuil stdi->vs_pol = ((cp_read(sd, 0xb5) & 0x40) ? 1289a89bcd4cSHans Verkuil ((cp_read(sd, 0xb5) & 0x20) ? '+' : '-') : 'x'); 1290a89bcd4cSHans Verkuil } else { 1291a89bcd4cSHans Verkuil stdi->hs_pol = 'x'; 1292a89bcd4cSHans Verkuil stdi->vs_pol = 'x'; 1293a89bcd4cSHans Verkuil } 1294a89bcd4cSHans Verkuil stdi->interlaced = (cp_read(sd, 0xb1) & 0x40) ? true : false; 1295a89bcd4cSHans Verkuil 1296a89bcd4cSHans Verkuil if (stdi->lcf < 239 || stdi->bl < 8 || stdi->bl == 0x3fff) { 1297a89bcd4cSHans Verkuil v4l2_dbg(2, debug, sd, "%s: invalid signal\n", __func__); 1298a89bcd4cSHans Verkuil return -ENOLINK; 1299a89bcd4cSHans Verkuil } 1300a89bcd4cSHans Verkuil 1301a89bcd4cSHans Verkuil v4l2_dbg(2, debug, sd, 1302a89bcd4cSHans Verkuil "%s: lcf (frame height - 1) = %d, bl = %d, lcvs (vsync) = %d, %chsync, %cvsync, %s\n", 1303a89bcd4cSHans Verkuil __func__, stdi->lcf, stdi->bl, stdi->lcvs, 1304a89bcd4cSHans Verkuil stdi->hs_pol, stdi->vs_pol, 1305a89bcd4cSHans Verkuil stdi->interlaced ? "interlaced" : "progressive"); 1306a89bcd4cSHans Verkuil 1307a89bcd4cSHans Verkuil return 0; 1308a89bcd4cSHans Verkuil } 1309a89bcd4cSHans Verkuil 1310a89bcd4cSHans Verkuil static int adv7842_enum_dv_timings(struct v4l2_subdev *sd, 1311a89bcd4cSHans Verkuil struct v4l2_enum_dv_timings *timings) 1312a89bcd4cSHans Verkuil { 1313a89bcd4cSHans Verkuil return v4l2_enum_dv_timings_cap(timings, 1314a89bcd4cSHans Verkuil adv7842_get_dv_timings_cap(sd), adv7842_check_dv_timings, NULL); 1315a89bcd4cSHans Verkuil } 1316a89bcd4cSHans Verkuil 1317a89bcd4cSHans Verkuil static int adv7842_dv_timings_cap(struct v4l2_subdev *sd, 1318a89bcd4cSHans Verkuil struct v4l2_dv_timings_cap *cap) 1319a89bcd4cSHans Verkuil { 1320a89bcd4cSHans Verkuil *cap = *adv7842_get_dv_timings_cap(sd); 1321a89bcd4cSHans Verkuil return 0; 1322a89bcd4cSHans Verkuil } 1323a89bcd4cSHans Verkuil 1324a89bcd4cSHans Verkuil /* Fill the optional fields .standards and .flags in struct v4l2_dv_timings 132569e9ba6fSHans Verkuil if the format is listed in adv7842_timings[] */ 1326a89bcd4cSHans Verkuil static void adv7842_fill_optional_dv_timings_fields(struct v4l2_subdev *sd, 1327a89bcd4cSHans Verkuil struct v4l2_dv_timings *timings) 1328a89bcd4cSHans Verkuil { 1329a89bcd4cSHans Verkuil v4l2_find_dv_timings_cap(timings, adv7842_get_dv_timings_cap(sd), 1330a89bcd4cSHans Verkuil is_digital_input(sd) ? 250000 : 1000000, 1331a89bcd4cSHans Verkuil adv7842_check_dv_timings, NULL); 1332a89bcd4cSHans Verkuil } 1333a89bcd4cSHans Verkuil 1334a89bcd4cSHans Verkuil static int adv7842_query_dv_timings(struct v4l2_subdev *sd, 1335a89bcd4cSHans Verkuil struct v4l2_dv_timings *timings) 1336a89bcd4cSHans Verkuil { 1337a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 1338a89bcd4cSHans Verkuil struct v4l2_bt_timings *bt = &timings->bt; 1339a89bcd4cSHans Verkuil struct stdi_readback stdi = { 0 }; 1340a89bcd4cSHans Verkuil 1341e78d834aSMartin Bugge v4l2_dbg(1, debug, sd, "%s:\n", __func__); 1342e78d834aSMartin Bugge 1343a89bcd4cSHans Verkuil /* SDP block */ 1344a89bcd4cSHans Verkuil if (state->mode == ADV7842_MODE_SDP) 1345a89bcd4cSHans Verkuil return -ENODATA; 1346a89bcd4cSHans Verkuil 1347a89bcd4cSHans Verkuil /* read STDI */ 1348a89bcd4cSHans Verkuil if (read_stdi(sd, &stdi)) { 13496e9071f2SMartin Bugge state->restart_stdi_once = true; 1350a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, "%s: no valid signal\n", __func__); 1351a89bcd4cSHans Verkuil return -ENOLINK; 1352a89bcd4cSHans Verkuil } 1353a89bcd4cSHans Verkuil bt->interlaced = stdi.interlaced ? 1354a89bcd4cSHans Verkuil V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE; 1355a89bcd4cSHans Verkuil 1356a89bcd4cSHans Verkuil if (is_digital_input(sd)) { 1357e78d834aSMartin Bugge uint32_t freq; 1358e78d834aSMartin Bugge 1359e78d834aSMartin Bugge timings->type = V4L2_DV_BT_656_1120; 13606e9071f2SMartin Bugge 1361e78d834aSMartin Bugge bt->width = (hdmi_read(sd, 0x07) & 0x0f) * 256 + hdmi_read(sd, 0x08); 1362e78d834aSMartin Bugge bt->height = (hdmi_read(sd, 0x09) & 0x0f) * 256 + hdmi_read(sd, 0x0a); 1363e78d834aSMartin Bugge freq = (hdmi_read(sd, 0x06) * 1000000) + 1364e78d834aSMartin Bugge ((hdmi_read(sd, 0x3b) & 0x30) >> 4) * 250000; 1365a89bcd4cSHans Verkuil 1366a89bcd4cSHans Verkuil if (is_hdmi(sd)) { 1367a89bcd4cSHans Verkuil /* adjust for deep color mode */ 1368e78d834aSMartin Bugge freq = freq * 8 / (((hdmi_read(sd, 0x0b) & 0xc0) >> 5) + 8); 1369a89bcd4cSHans Verkuil } 1370e78d834aSMartin Bugge bt->pixelclock = freq; 1371e78d834aSMartin Bugge bt->hfrontporch = (hdmi_read(sd, 0x20) & 0x03) * 256 + 1372a89bcd4cSHans Verkuil hdmi_read(sd, 0x21); 1373e78d834aSMartin Bugge bt->hsync = (hdmi_read(sd, 0x22) & 0x03) * 256 + 1374a89bcd4cSHans Verkuil hdmi_read(sd, 0x23); 1375e78d834aSMartin Bugge bt->hbackporch = (hdmi_read(sd, 0x24) & 0x03) * 256 + 1376a89bcd4cSHans Verkuil hdmi_read(sd, 0x25); 1377e78d834aSMartin Bugge bt->vfrontporch = ((hdmi_read(sd, 0x2a) & 0x1f) * 256 + 1378a89bcd4cSHans Verkuil hdmi_read(sd, 0x2b)) / 2; 1379e78d834aSMartin Bugge bt->vsync = ((hdmi_read(sd, 0x2e) & 0x1f) * 256 + 1380a89bcd4cSHans Verkuil hdmi_read(sd, 0x2f)) / 2; 1381e78d834aSMartin Bugge bt->vbackporch = ((hdmi_read(sd, 0x32) & 0x1f) * 256 + 1382a89bcd4cSHans Verkuil hdmi_read(sd, 0x33)) / 2; 1383e78d834aSMartin Bugge bt->polarities = ((hdmi_read(sd, 0x05) & 0x10) ? V4L2_DV_VSYNC_POS_POL : 0) | 1384e78d834aSMartin Bugge ((hdmi_read(sd, 0x05) & 0x20) ? V4L2_DV_HSYNC_POS_POL : 0); 1385e78d834aSMartin Bugge if (bt->interlaced == V4L2_DV_INTERLACED) { 1386e78d834aSMartin Bugge bt->height += (hdmi_read(sd, 0x0b) & 0x0f) * 256 + 1387e78d834aSMartin Bugge hdmi_read(sd, 0x0c); 1388e78d834aSMartin Bugge bt->il_vfrontporch = ((hdmi_read(sd, 0x2c) & 0x1f) * 256 + 1389e78d834aSMartin Bugge hdmi_read(sd, 0x2d)) / 2; 1390e78d834aSMartin Bugge bt->il_vsync = ((hdmi_read(sd, 0x30) & 0x1f) * 256 + 1391e78d834aSMartin Bugge hdmi_read(sd, 0x31)) / 2; 1392e78d834aSMartin Bugge bt->vbackporch = ((hdmi_read(sd, 0x34) & 0x1f) * 256 + 1393a89bcd4cSHans Verkuil hdmi_read(sd, 0x35)) / 2; 1394e78d834aSMartin Bugge } 1395e78d834aSMartin Bugge adv7842_fill_optional_dv_timings_fields(sd, timings); 1396a89bcd4cSHans Verkuil } else { 13976e9071f2SMartin Bugge /* find format 13986e9071f2SMartin Bugge * Since LCVS values are inaccurate [REF_03, p. 339-340], 13996e9071f2SMartin Bugge * stdi2dv_timings() is called with lcvs +-1 if the first attempt fails. 14006e9071f2SMartin Bugge */ 14016e9071f2SMartin Bugge if (!stdi2dv_timings(sd, &stdi, timings)) 14026e9071f2SMartin Bugge goto found; 14036e9071f2SMartin Bugge stdi.lcvs += 1; 14046e9071f2SMartin Bugge v4l2_dbg(1, debug, sd, "%s: lcvs + 1 = %d\n", __func__, stdi.lcvs); 14056e9071f2SMartin Bugge if (!stdi2dv_timings(sd, &stdi, timings)) 14066e9071f2SMartin Bugge goto found; 14076e9071f2SMartin Bugge stdi.lcvs -= 2; 14086e9071f2SMartin Bugge v4l2_dbg(1, debug, sd, "%s: lcvs - 1 = %d\n", __func__, stdi.lcvs); 1409a89bcd4cSHans Verkuil if (stdi2dv_timings(sd, &stdi, timings)) { 14106e9071f2SMartin Bugge /* 14116e9071f2SMartin Bugge * The STDI block may measure wrong values, especially 14126e9071f2SMartin Bugge * for lcvs and lcf. If the driver can not find any 14136e9071f2SMartin Bugge * valid timing, the STDI block is restarted to measure 14146e9071f2SMartin Bugge * the video timings again. The function will return an 14156e9071f2SMartin Bugge * error, but the restart of STDI will generate a new 14166e9071f2SMartin Bugge * STDI interrupt and the format detection process will 14176e9071f2SMartin Bugge * restart. 14186e9071f2SMartin Bugge */ 14196e9071f2SMartin Bugge if (state->restart_stdi_once) { 14206e9071f2SMartin Bugge v4l2_dbg(1, debug, sd, "%s: restart STDI\n", __func__); 14216e9071f2SMartin Bugge /* TODO restart STDI for Sync Channel 2 */ 14226e9071f2SMartin Bugge /* enter one-shot mode */ 14236e9071f2SMartin Bugge cp_write_and_or(sd, 0x86, 0xf9, 0x00); 14246e9071f2SMartin Bugge /* trigger STDI restart */ 14256e9071f2SMartin Bugge cp_write_and_or(sd, 0x86, 0xf9, 0x04); 14266e9071f2SMartin Bugge /* reset to continuous mode */ 14276e9071f2SMartin Bugge cp_write_and_or(sd, 0x86, 0xf9, 0x02); 14286e9071f2SMartin Bugge state->restart_stdi_once = false; 14296e9071f2SMartin Bugge return -ENOLINK; 14306e9071f2SMartin Bugge } 1431a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, "%s: format not supported\n", __func__); 1432a89bcd4cSHans Verkuil return -ERANGE; 1433a89bcd4cSHans Verkuil } 14346e9071f2SMartin Bugge state->restart_stdi_once = true; 1435a89bcd4cSHans Verkuil } 14366e9071f2SMartin Bugge found: 1437a89bcd4cSHans Verkuil 1438a89bcd4cSHans Verkuil if (debug > 1) 1439a89bcd4cSHans Verkuil v4l2_print_dv_timings(sd->name, "adv7842_query_dv_timings:", 1440a89bcd4cSHans Verkuil timings, true); 1441a89bcd4cSHans Verkuil return 0; 1442a89bcd4cSHans Verkuil } 1443a89bcd4cSHans Verkuil 1444a89bcd4cSHans Verkuil static int adv7842_s_dv_timings(struct v4l2_subdev *sd, 1445a89bcd4cSHans Verkuil struct v4l2_dv_timings *timings) 1446a89bcd4cSHans Verkuil { 1447a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 1448a89bcd4cSHans Verkuil struct v4l2_bt_timings *bt; 1449a89bcd4cSHans Verkuil int err; 1450a89bcd4cSHans Verkuil 1451e78d834aSMartin Bugge v4l2_dbg(1, debug, sd, "%s:\n", __func__); 1452e78d834aSMartin Bugge 1453a89bcd4cSHans Verkuil if (state->mode == ADV7842_MODE_SDP) 1454a89bcd4cSHans Verkuil return -ENODATA; 1455a89bcd4cSHans Verkuil 1456a89bcd4cSHans Verkuil bt = &timings->bt; 1457a89bcd4cSHans Verkuil 1458a89bcd4cSHans Verkuil if (!v4l2_valid_dv_timings(timings, adv7842_get_dv_timings_cap(sd), 1459a89bcd4cSHans Verkuil adv7842_check_dv_timings, NULL)) 1460a89bcd4cSHans Verkuil return -ERANGE; 1461a89bcd4cSHans Verkuil 1462a89bcd4cSHans Verkuil adv7842_fill_optional_dv_timings_fields(sd, timings); 1463a89bcd4cSHans Verkuil 1464a89bcd4cSHans Verkuil state->timings = *timings; 1465a89bcd4cSHans Verkuil 14666251e65fSMartin Bugge cp_write(sd, 0x91, bt->interlaced ? 0x40 : 0x00); 1467a89bcd4cSHans Verkuil 1468a89bcd4cSHans Verkuil /* Use prim_mode and vid_std when available */ 1469a89bcd4cSHans Verkuil err = configure_predefined_video_timings(sd, timings); 1470a89bcd4cSHans Verkuil if (err) { 1471a89bcd4cSHans Verkuil /* custom settings when the video format 1472a89bcd4cSHans Verkuil does not have prim_mode/vid_std */ 1473a89bcd4cSHans Verkuil configure_custom_video_timings(sd, bt); 1474a89bcd4cSHans Verkuil } 1475a89bcd4cSHans Verkuil 1476a89bcd4cSHans Verkuil set_rgb_quantization_range(sd); 1477a89bcd4cSHans Verkuil 1478a89bcd4cSHans Verkuil 1479a89bcd4cSHans Verkuil if (debug > 1) 1480a89bcd4cSHans Verkuil v4l2_print_dv_timings(sd->name, "adv7842_s_dv_timings: ", 1481a89bcd4cSHans Verkuil timings, true); 1482a89bcd4cSHans Verkuil return 0; 1483a89bcd4cSHans Verkuil } 1484a89bcd4cSHans Verkuil 1485a89bcd4cSHans Verkuil static int adv7842_g_dv_timings(struct v4l2_subdev *sd, 1486a89bcd4cSHans Verkuil struct v4l2_dv_timings *timings) 1487a89bcd4cSHans Verkuil { 1488a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 1489a89bcd4cSHans Verkuil 1490a89bcd4cSHans Verkuil if (state->mode == ADV7842_MODE_SDP) 1491a89bcd4cSHans Verkuil return -ENODATA; 1492a89bcd4cSHans Verkuil *timings = state->timings; 1493a89bcd4cSHans Verkuil return 0; 1494a89bcd4cSHans Verkuil } 1495a89bcd4cSHans Verkuil 1496a89bcd4cSHans Verkuil static void enable_input(struct v4l2_subdev *sd) 1497a89bcd4cSHans Verkuil { 1498a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 149969e9ba6fSHans Verkuil 150069e9ba6fSHans Verkuil set_rgb_quantization_range(sd); 1501a89bcd4cSHans Verkuil switch (state->mode) { 1502a89bcd4cSHans Verkuil case ADV7842_MODE_SDP: 1503a89bcd4cSHans Verkuil case ADV7842_MODE_COMP: 1504a89bcd4cSHans Verkuil case ADV7842_MODE_RGB: 1505a89bcd4cSHans Verkuil io_write(sd, 0x15, 0xb0); /* Disable Tristate of Pins (no audio) */ 1506a89bcd4cSHans Verkuil break; 1507a89bcd4cSHans Verkuil case ADV7842_MODE_HDMI: 1508a89bcd4cSHans Verkuil hdmi_write(sd, 0x01, 0x00); /* Enable HDMI clock terminators */ 1509a89bcd4cSHans Verkuil io_write(sd, 0x15, 0xa0); /* Disable Tristate of Pins */ 15105b64b205SMats Randgaard hdmi_write_and_or(sd, 0x1a, 0xef, 0x00); /* Unmute audio */ 1511a89bcd4cSHans Verkuil break; 1512a89bcd4cSHans Verkuil default: 1513a89bcd4cSHans Verkuil v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", 1514a89bcd4cSHans Verkuil __func__, state->mode); 1515a89bcd4cSHans Verkuil break; 1516a89bcd4cSHans Verkuil } 1517a89bcd4cSHans Verkuil } 1518a89bcd4cSHans Verkuil 1519a89bcd4cSHans Verkuil static void disable_input(struct v4l2_subdev *sd) 1520a89bcd4cSHans Verkuil { 15215b64b205SMats Randgaard hdmi_write_and_or(sd, 0x1a, 0xef, 0x10); /* Mute audio [REF_01, c. 2.2.2] */ 15225b64b205SMats Randgaard msleep(16); /* 512 samples with >= 32 kHz sample rate [REF_03, c. 8.29] */ 1523a89bcd4cSHans Verkuil io_write(sd, 0x15, 0xbe); /* Tristate all outputs from video core */ 1524a89bcd4cSHans Verkuil hdmi_write(sd, 0x01, 0x78); /* Disable HDMI clock terminators */ 1525a89bcd4cSHans Verkuil } 1526a89bcd4cSHans Verkuil 1527a89bcd4cSHans Verkuil static void sdp_csc_coeff(struct v4l2_subdev *sd, 1528a89bcd4cSHans Verkuil const struct adv7842_sdp_csc_coeff *c) 1529a89bcd4cSHans Verkuil { 1530a89bcd4cSHans Verkuil /* csc auto/manual */ 1531a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xe0, 0xbf, c->manual ? 0x00 : 0x40); 1532a89bcd4cSHans Verkuil 1533a89bcd4cSHans Verkuil if (!c->manual) 1534a89bcd4cSHans Verkuil return; 1535a89bcd4cSHans Verkuil 1536a89bcd4cSHans Verkuil /* csc scaling */ 1537a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xe0, 0x7f, c->scaling == 2 ? 0x80 : 0x00); 1538a89bcd4cSHans Verkuil 1539a89bcd4cSHans Verkuil /* A coeff */ 1540a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xe0, 0xe0, c->A1 >> 8); 1541a89bcd4cSHans Verkuil sdp_io_write(sd, 0xe1, c->A1); 1542a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xe2, 0xe0, c->A2 >> 8); 1543a89bcd4cSHans Verkuil sdp_io_write(sd, 0xe3, c->A2); 1544a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xe4, 0xe0, c->A3 >> 8); 1545a89bcd4cSHans Verkuil sdp_io_write(sd, 0xe5, c->A3); 1546a89bcd4cSHans Verkuil 1547a89bcd4cSHans Verkuil /* A scale */ 1548a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xe6, 0x80, c->A4 >> 8); 1549a89bcd4cSHans Verkuil sdp_io_write(sd, 0xe7, c->A4); 1550a89bcd4cSHans Verkuil 1551a89bcd4cSHans Verkuil /* B coeff */ 1552a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xe8, 0xe0, c->B1 >> 8); 1553a89bcd4cSHans Verkuil sdp_io_write(sd, 0xe9, c->B1); 1554a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xea, 0xe0, c->B2 >> 8); 1555a89bcd4cSHans Verkuil sdp_io_write(sd, 0xeb, c->B2); 1556a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xec, 0xe0, c->B3 >> 8); 1557a89bcd4cSHans Verkuil sdp_io_write(sd, 0xed, c->B3); 1558a89bcd4cSHans Verkuil 1559a89bcd4cSHans Verkuil /* B scale */ 1560a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xee, 0x80, c->B4 >> 8); 1561a89bcd4cSHans Verkuil sdp_io_write(sd, 0xef, c->B4); 1562a89bcd4cSHans Verkuil 1563a89bcd4cSHans Verkuil /* C coeff */ 1564a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xf0, 0xe0, c->C1 >> 8); 1565a89bcd4cSHans Verkuil sdp_io_write(sd, 0xf1, c->C1); 1566a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xf2, 0xe0, c->C2 >> 8); 1567a89bcd4cSHans Verkuil sdp_io_write(sd, 0xf3, c->C2); 1568a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xf4, 0xe0, c->C3 >> 8); 1569a89bcd4cSHans Verkuil sdp_io_write(sd, 0xf5, c->C3); 1570a89bcd4cSHans Verkuil 1571a89bcd4cSHans Verkuil /* C scale */ 1572a89bcd4cSHans Verkuil sdp_io_write_and_or(sd, 0xf6, 0x80, c->C4 >> 8); 1573a89bcd4cSHans Verkuil sdp_io_write(sd, 0xf7, c->C4); 1574a89bcd4cSHans Verkuil } 1575a89bcd4cSHans Verkuil 1576a89bcd4cSHans Verkuil static void select_input(struct v4l2_subdev *sd, 1577a89bcd4cSHans Verkuil enum adv7842_vid_std_select vid_std_select) 1578a89bcd4cSHans Verkuil { 1579a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 1580a89bcd4cSHans Verkuil 1581a89bcd4cSHans Verkuil switch (state->mode) { 1582a89bcd4cSHans Verkuil case ADV7842_MODE_SDP: 1583a89bcd4cSHans Verkuil io_write(sd, 0x00, vid_std_select); /* video std: CVBS or YC mode */ 1584a89bcd4cSHans Verkuil io_write(sd, 0x01, 0); /* prim mode */ 1585a89bcd4cSHans Verkuil /* enable embedded syncs for auto graphics mode */ 1586a89bcd4cSHans Verkuil cp_write_and_or(sd, 0x81, 0xef, 0x10); 1587a89bcd4cSHans Verkuil 1588a89bcd4cSHans Verkuil afe_write(sd, 0x00, 0x00); /* power up ADC */ 1589a89bcd4cSHans Verkuil afe_write(sd, 0xc8, 0x00); /* phase control */ 1590a89bcd4cSHans Verkuil 1591a89bcd4cSHans Verkuil io_write(sd, 0x19, 0x83); /* LLC DLL phase */ 1592a89bcd4cSHans Verkuil io_write(sd, 0x33, 0x40); /* LLC DLL enable */ 1593a89bcd4cSHans Verkuil 1594a89bcd4cSHans Verkuil io_write(sd, 0xdd, 0x90); /* Manual 2x output clock */ 1595a89bcd4cSHans Verkuil /* script says register 0xde, which don't exist in manual */ 1596a89bcd4cSHans Verkuil 1597a89bcd4cSHans Verkuil /* Manual analog input muxing mode, CVBS (6.4)*/ 1598a89bcd4cSHans Verkuil afe_write_and_or(sd, 0x02, 0x7f, 0x80); 1599a89bcd4cSHans Verkuil if (vid_std_select == ADV7842_SDP_VID_STD_CVBS_SD_4x1) { 1600a89bcd4cSHans Verkuil afe_write(sd, 0x03, 0xa0); /* ADC0 to AIN10 (CVBS), ADC1 N/C*/ 1601a89bcd4cSHans Verkuil afe_write(sd, 0x04, 0x00); /* ADC2 N/C,ADC3 N/C*/ 1602a89bcd4cSHans Verkuil } else { 1603a89bcd4cSHans Verkuil afe_write(sd, 0x03, 0xa0); /* ADC0 to AIN10 (CVBS), ADC1 N/C*/ 1604a89bcd4cSHans Verkuil afe_write(sd, 0x04, 0xc0); /* ADC2 to AIN12, ADC3 N/C*/ 1605a89bcd4cSHans Verkuil } 1606a89bcd4cSHans Verkuil afe_write(sd, 0x0c, 0x1f); /* ADI recommend write */ 1607a89bcd4cSHans Verkuil afe_write(sd, 0x12, 0x63); /* ADI recommend write */ 1608a89bcd4cSHans Verkuil 1609a89bcd4cSHans Verkuil sdp_io_write(sd, 0xb2, 0x60); /* Disable AV codes */ 1610a89bcd4cSHans Verkuil sdp_io_write(sd, 0xc8, 0xe3); /* Disable Ancillary data */ 1611a89bcd4cSHans Verkuil 1612a89bcd4cSHans Verkuil /* SDP recommended settings */ 1613a89bcd4cSHans Verkuil sdp_write(sd, 0x00, 0x3F); /* Autodetect PAL NTSC (not SECAM) */ 1614a89bcd4cSHans Verkuil sdp_write(sd, 0x01, 0x00); /* Pedestal Off */ 1615a89bcd4cSHans Verkuil 1616a89bcd4cSHans Verkuil sdp_write(sd, 0x03, 0xE4); /* Manual VCR Gain Luma 0x40B */ 1617a89bcd4cSHans Verkuil sdp_write(sd, 0x04, 0x0B); /* Manual Luma setting */ 1618a89bcd4cSHans Verkuil sdp_write(sd, 0x05, 0xC3); /* Manual Chroma setting 0x3FE */ 1619a89bcd4cSHans Verkuil sdp_write(sd, 0x06, 0xFE); /* Manual Chroma setting */ 1620a89bcd4cSHans Verkuil sdp_write(sd, 0x12, 0x0D); /* Frame TBC,I_P, 3D comb enabled */ 1621a89bcd4cSHans Verkuil sdp_write(sd, 0xA7, 0x00); /* ADI Recommended Write */ 1622a89bcd4cSHans Verkuil sdp_io_write(sd, 0xB0, 0x00); /* Disable H and v blanking */ 1623a89bcd4cSHans Verkuil 1624a89bcd4cSHans Verkuil /* deinterlacer enabled and 3D comb */ 1625a89bcd4cSHans Verkuil sdp_write_and_or(sd, 0x12, 0xf6, 0x09); 1626a89bcd4cSHans Verkuil 1627a89bcd4cSHans Verkuil sdp_write(sd, 0xdd, 0x08); /* free run auto */ 1628a89bcd4cSHans Verkuil 1629a89bcd4cSHans Verkuil break; 1630a89bcd4cSHans Verkuil 1631a89bcd4cSHans Verkuil case ADV7842_MODE_COMP: 1632a89bcd4cSHans Verkuil case ADV7842_MODE_RGB: 1633a89bcd4cSHans Verkuil /* Automatic analog input muxing mode */ 1634a89bcd4cSHans Verkuil afe_write_and_or(sd, 0x02, 0x7f, 0x00); 1635a89bcd4cSHans Verkuil /* set mode and select free run resolution */ 1636a89bcd4cSHans Verkuil io_write(sd, 0x00, vid_std_select); /* video std */ 1637a89bcd4cSHans Verkuil io_write(sd, 0x01, 0x02); /* prim mode */ 1638a89bcd4cSHans Verkuil cp_write_and_or(sd, 0x81, 0xef, 0x10); /* enable embedded syncs 1639a89bcd4cSHans Verkuil for auto graphics mode */ 1640a89bcd4cSHans Verkuil 1641a89bcd4cSHans Verkuil afe_write(sd, 0x00, 0x00); /* power up ADC */ 1642a89bcd4cSHans Verkuil afe_write(sd, 0xc8, 0x00); /* phase control */ 164369e9ba6fSHans Verkuil if (state->mode == ADV7842_MODE_COMP) { 164469e9ba6fSHans Verkuil /* force to YCrCb */ 164569e9ba6fSHans Verkuil io_write_and_or(sd, 0x02, 0x0f, 0x60); 164669e9ba6fSHans Verkuil } else { 164769e9ba6fSHans Verkuil /* force to RGB */ 164869e9ba6fSHans Verkuil io_write_and_or(sd, 0x02, 0x0f, 0x10); 164969e9ba6fSHans Verkuil } 1650a89bcd4cSHans Verkuil 1651a89bcd4cSHans Verkuil /* set ADI recommended settings for digitizer */ 1652a89bcd4cSHans Verkuil /* "ADV7842 Register Settings Recommendations 1653a89bcd4cSHans Verkuil * (rev. 1.8, November 2010)" p. 9. */ 1654a89bcd4cSHans Verkuil afe_write(sd, 0x0c, 0x1f); /* ADC Range improvement */ 1655a89bcd4cSHans Verkuil afe_write(sd, 0x12, 0x63); /* ADC Range improvement */ 1656a89bcd4cSHans Verkuil 1657a89bcd4cSHans Verkuil /* set to default gain for RGB */ 1658a89bcd4cSHans Verkuil cp_write(sd, 0x73, 0x10); 1659a89bcd4cSHans Verkuil cp_write(sd, 0x74, 0x04); 1660a89bcd4cSHans Verkuil cp_write(sd, 0x75, 0x01); 1661a89bcd4cSHans Verkuil cp_write(sd, 0x76, 0x00); 1662a89bcd4cSHans Verkuil 1663a89bcd4cSHans Verkuil cp_write(sd, 0x3e, 0x04); /* CP core pre-gain control */ 1664a89bcd4cSHans Verkuil cp_write(sd, 0xc3, 0x39); /* CP coast control. Graphics mode */ 1665a89bcd4cSHans Verkuil cp_write(sd, 0x40, 0x5c); /* CP core pre-gain control. Graphics mode */ 1666a89bcd4cSHans Verkuil break; 1667a89bcd4cSHans Verkuil 1668a89bcd4cSHans Verkuil case ADV7842_MODE_HDMI: 1669a89bcd4cSHans Verkuil /* Automatic analog input muxing mode */ 1670a89bcd4cSHans Verkuil afe_write_and_or(sd, 0x02, 0x7f, 0x00); 1671a89bcd4cSHans Verkuil /* set mode and select free run resolution */ 1672a89bcd4cSHans Verkuil if (state->hdmi_port_a) 1673a89bcd4cSHans Verkuil hdmi_write(sd, 0x00, 0x02); /* select port A */ 1674a89bcd4cSHans Verkuil else 1675a89bcd4cSHans Verkuil hdmi_write(sd, 0x00, 0x03); /* select port B */ 1676a89bcd4cSHans Verkuil io_write(sd, 0x00, vid_std_select); /* video std */ 1677a89bcd4cSHans Verkuil io_write(sd, 0x01, 5); /* prim mode */ 1678a89bcd4cSHans Verkuil cp_write_and_or(sd, 0x81, 0xef, 0x00); /* disable embedded syncs 1679a89bcd4cSHans Verkuil for auto graphics mode */ 1680a89bcd4cSHans Verkuil 1681a89bcd4cSHans Verkuil /* set ADI recommended settings for HDMI: */ 1682a89bcd4cSHans Verkuil /* "ADV7842 Register Settings Recommendations 1683a89bcd4cSHans Verkuil * (rev. 1.8, November 2010)" p. 3. */ 1684a89bcd4cSHans Verkuil hdmi_write(sd, 0xc0, 0x00); 1685a89bcd4cSHans Verkuil hdmi_write(sd, 0x0d, 0x34); /* ADI recommended write */ 1686a89bcd4cSHans Verkuil hdmi_write(sd, 0x3d, 0x10); /* ADI recommended write */ 1687a89bcd4cSHans Verkuil hdmi_write(sd, 0x44, 0x85); /* TMDS PLL optimization */ 1688a89bcd4cSHans Verkuil hdmi_write(sd, 0x46, 0x1f); /* ADI recommended write */ 1689a89bcd4cSHans Verkuil hdmi_write(sd, 0x57, 0xb6); /* TMDS PLL optimization */ 1690a89bcd4cSHans Verkuil hdmi_write(sd, 0x58, 0x03); /* TMDS PLL optimization */ 1691a89bcd4cSHans Verkuil hdmi_write(sd, 0x60, 0x88); /* TMDS PLL optimization */ 1692a89bcd4cSHans Verkuil hdmi_write(sd, 0x61, 0x88); /* TMDS PLL optimization */ 1693a89bcd4cSHans Verkuil hdmi_write(sd, 0x6c, 0x18); /* Disable ISRC clearing bit, 1694a89bcd4cSHans Verkuil Improve robustness */ 1695a89bcd4cSHans Verkuil hdmi_write(sd, 0x75, 0x10); /* DDC drive strength */ 1696a89bcd4cSHans Verkuil hdmi_write(sd, 0x85, 0x1f); /* equaliser */ 1697a89bcd4cSHans Verkuil hdmi_write(sd, 0x87, 0x70); /* ADI recommended write */ 1698a89bcd4cSHans Verkuil hdmi_write(sd, 0x89, 0x04); /* equaliser */ 1699a89bcd4cSHans Verkuil hdmi_write(sd, 0x8a, 0x1e); /* equaliser */ 1700a89bcd4cSHans Verkuil hdmi_write(sd, 0x93, 0x04); /* equaliser */ 1701a89bcd4cSHans Verkuil hdmi_write(sd, 0x94, 0x1e); /* equaliser */ 1702a89bcd4cSHans Verkuil hdmi_write(sd, 0x99, 0xa1); /* ADI recommended write */ 1703a89bcd4cSHans Verkuil hdmi_write(sd, 0x9b, 0x09); /* ADI recommended write */ 1704a89bcd4cSHans Verkuil hdmi_write(sd, 0x9d, 0x02); /* equaliser */ 1705a89bcd4cSHans Verkuil 1706a89bcd4cSHans Verkuil afe_write(sd, 0x00, 0xff); /* power down ADC */ 1707a89bcd4cSHans Verkuil afe_write(sd, 0xc8, 0x40); /* phase control */ 1708a89bcd4cSHans Verkuil 1709a89bcd4cSHans Verkuil /* set to default gain for HDMI */ 1710a89bcd4cSHans Verkuil cp_write(sd, 0x73, 0x10); 1711a89bcd4cSHans Verkuil cp_write(sd, 0x74, 0x04); 1712a89bcd4cSHans Verkuil cp_write(sd, 0x75, 0x01); 1713a89bcd4cSHans Verkuil cp_write(sd, 0x76, 0x00); 1714a89bcd4cSHans Verkuil 1715a89bcd4cSHans Verkuil /* reset ADI recommended settings for digitizer */ 1716a89bcd4cSHans Verkuil /* "ADV7842 Register Settings Recommendations 1717a89bcd4cSHans Verkuil * (rev. 2.5, June 2010)" p. 17. */ 1718a89bcd4cSHans Verkuil afe_write(sd, 0x12, 0xfb); /* ADC noise shaping filter controls */ 1719a89bcd4cSHans Verkuil afe_write(sd, 0x0c, 0x0d); /* CP core gain controls */ 1720a89bcd4cSHans Verkuil cp_write(sd, 0x3e, 0x80); /* CP core pre-gain control, 1721a89bcd4cSHans Verkuil enable color control */ 1722a89bcd4cSHans Verkuil /* CP coast control */ 1723a89bcd4cSHans Verkuil cp_write(sd, 0xc3, 0x33); /* Component mode */ 1724a89bcd4cSHans Verkuil 1725a89bcd4cSHans Verkuil /* color space conversion, autodetect color space */ 1726a89bcd4cSHans Verkuil io_write_and_or(sd, 0x02, 0x0f, 0xf0); 1727a89bcd4cSHans Verkuil break; 1728a89bcd4cSHans Verkuil 1729a89bcd4cSHans Verkuil default: 1730a89bcd4cSHans Verkuil v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", 1731a89bcd4cSHans Verkuil __func__, state->mode); 1732a89bcd4cSHans Verkuil break; 1733a89bcd4cSHans Verkuil } 1734a89bcd4cSHans Verkuil } 1735a89bcd4cSHans Verkuil 1736a89bcd4cSHans Verkuil static int adv7842_s_routing(struct v4l2_subdev *sd, 1737a89bcd4cSHans Verkuil u32 input, u32 output, u32 config) 1738a89bcd4cSHans Verkuil { 1739a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 1740a89bcd4cSHans Verkuil 1741a89bcd4cSHans Verkuil v4l2_dbg(2, debug, sd, "%s: input %d\n", __func__, input); 1742a89bcd4cSHans Verkuil 1743a89bcd4cSHans Verkuil switch (input) { 1744a89bcd4cSHans Verkuil case ADV7842_SELECT_HDMI_PORT_A: 1745a89bcd4cSHans Verkuil state->mode = ADV7842_MODE_HDMI; 1746a89bcd4cSHans Verkuil state->vid_std_select = ADV7842_HDMI_COMP_VID_STD_HD_1250P; 1747a89bcd4cSHans Verkuil state->hdmi_port_a = true; 1748a89bcd4cSHans Verkuil break; 1749a89bcd4cSHans Verkuil case ADV7842_SELECT_HDMI_PORT_B: 1750a89bcd4cSHans Verkuil state->mode = ADV7842_MODE_HDMI; 1751a89bcd4cSHans Verkuil state->vid_std_select = ADV7842_HDMI_COMP_VID_STD_HD_1250P; 1752a89bcd4cSHans Verkuil state->hdmi_port_a = false; 1753a89bcd4cSHans Verkuil break; 1754a89bcd4cSHans Verkuil case ADV7842_SELECT_VGA_COMP: 175569e9ba6fSHans Verkuil state->mode = ADV7842_MODE_COMP; 175669e9ba6fSHans Verkuil state->vid_std_select = ADV7842_RGB_VID_STD_AUTO_GRAPH_MODE; 175769e9ba6fSHans Verkuil break; 1758a89bcd4cSHans Verkuil case ADV7842_SELECT_VGA_RGB: 1759a89bcd4cSHans Verkuil state->mode = ADV7842_MODE_RGB; 1760a89bcd4cSHans Verkuil state->vid_std_select = ADV7842_RGB_VID_STD_AUTO_GRAPH_MODE; 1761a89bcd4cSHans Verkuil break; 1762a89bcd4cSHans Verkuil case ADV7842_SELECT_SDP_CVBS: 1763a89bcd4cSHans Verkuil state->mode = ADV7842_MODE_SDP; 1764a89bcd4cSHans Verkuil state->vid_std_select = ADV7842_SDP_VID_STD_CVBS_SD_4x1; 1765a89bcd4cSHans Verkuil break; 1766a89bcd4cSHans Verkuil case ADV7842_SELECT_SDP_YC: 1767a89bcd4cSHans Verkuil state->mode = ADV7842_MODE_SDP; 1768a89bcd4cSHans Verkuil state->vid_std_select = ADV7842_SDP_VID_STD_YC_SD4_x1; 1769a89bcd4cSHans Verkuil break; 1770a89bcd4cSHans Verkuil default: 1771a89bcd4cSHans Verkuil return -EINVAL; 1772a89bcd4cSHans Verkuil } 1773a89bcd4cSHans Verkuil 1774a89bcd4cSHans Verkuil disable_input(sd); 1775a89bcd4cSHans Verkuil select_input(sd, state->vid_std_select); 1776a89bcd4cSHans Verkuil enable_input(sd); 1777a89bcd4cSHans Verkuil 1778a89bcd4cSHans Verkuil v4l2_subdev_notify(sd, ADV7842_FMT_CHANGE, NULL); 1779a89bcd4cSHans Verkuil 1780a89bcd4cSHans Verkuil return 0; 1781a89bcd4cSHans Verkuil } 1782a89bcd4cSHans Verkuil 1783a89bcd4cSHans Verkuil static int adv7842_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index, 1784a89bcd4cSHans Verkuil enum v4l2_mbus_pixelcode *code) 1785a89bcd4cSHans Verkuil { 1786a89bcd4cSHans Verkuil if (index) 1787a89bcd4cSHans Verkuil return -EINVAL; 1788a89bcd4cSHans Verkuil /* Good enough for now */ 1789a89bcd4cSHans Verkuil *code = V4L2_MBUS_FMT_FIXED; 1790a89bcd4cSHans Verkuil return 0; 1791a89bcd4cSHans Verkuil } 1792a89bcd4cSHans Verkuil 1793a89bcd4cSHans Verkuil static int adv7842_g_mbus_fmt(struct v4l2_subdev *sd, 1794a89bcd4cSHans Verkuil struct v4l2_mbus_framefmt *fmt) 1795a89bcd4cSHans Verkuil { 1796a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 1797a89bcd4cSHans Verkuil 1798a89bcd4cSHans Verkuil fmt->width = state->timings.bt.width; 1799a89bcd4cSHans Verkuil fmt->height = state->timings.bt.height; 1800a89bcd4cSHans Verkuil fmt->code = V4L2_MBUS_FMT_FIXED; 1801a89bcd4cSHans Verkuil fmt->field = V4L2_FIELD_NONE; 1802a89bcd4cSHans Verkuil 1803a89bcd4cSHans Verkuil if (state->mode == ADV7842_MODE_SDP) { 1804a89bcd4cSHans Verkuil /* SPD block */ 1805a89bcd4cSHans Verkuil if (!(sdp_read(sd, 0x5A) & 0x01)) 1806a89bcd4cSHans Verkuil return -EINVAL; 1807a89bcd4cSHans Verkuil fmt->width = 720; 1808a89bcd4cSHans Verkuil /* valid signal */ 1809a89bcd4cSHans Verkuil if (state->norm & V4L2_STD_525_60) 1810a89bcd4cSHans Verkuil fmt->height = 480; 1811a89bcd4cSHans Verkuil else 1812a89bcd4cSHans Verkuil fmt->height = 576; 1813a89bcd4cSHans Verkuil fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; 1814a89bcd4cSHans Verkuil return 0; 1815a89bcd4cSHans Verkuil } 1816a89bcd4cSHans Verkuil 1817a89bcd4cSHans Verkuil if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) { 1818a89bcd4cSHans Verkuil fmt->colorspace = (state->timings.bt.height <= 576) ? 1819a89bcd4cSHans Verkuil V4L2_COLORSPACE_SMPTE170M : V4L2_COLORSPACE_REC709; 1820a89bcd4cSHans Verkuil } 1821a89bcd4cSHans Verkuil return 0; 1822a89bcd4cSHans Verkuil } 1823a89bcd4cSHans Verkuil 1824a89bcd4cSHans Verkuil static void adv7842_irq_enable(struct v4l2_subdev *sd, bool enable) 1825a89bcd4cSHans Verkuil { 1826a89bcd4cSHans Verkuil if (enable) { 1827a89bcd4cSHans Verkuil /* Enable SSPD, STDI and CP locked/unlocked interrupts */ 1828a89bcd4cSHans Verkuil io_write(sd, 0x46, 0x9c); 1829a89bcd4cSHans Verkuil /* ESDP_50HZ_DET interrupt */ 1830a89bcd4cSHans Verkuil io_write(sd, 0x5a, 0x10); 1831a89bcd4cSHans Verkuil /* Enable CABLE_DET_A/B_ST (+5v) interrupt */ 1832a89bcd4cSHans Verkuil io_write(sd, 0x73, 0x03); 1833a89bcd4cSHans Verkuil /* Enable V_LOCKED and DE_REGEN_LCK interrupts */ 1834a89bcd4cSHans Verkuil io_write(sd, 0x78, 0x03); 1835a89bcd4cSHans Verkuil /* Enable SDP Standard Detection Change and SDP Video Detected */ 1836a89bcd4cSHans Verkuil io_write(sd, 0xa0, 0x09); 1837019aa8beSMartin Bugge /* Enable HDMI_MODE interrupt */ 1838019aa8beSMartin Bugge io_write(sd, 0x69, 0x08); 1839a89bcd4cSHans Verkuil } else { 1840a89bcd4cSHans Verkuil io_write(sd, 0x46, 0x0); 1841a89bcd4cSHans Verkuil io_write(sd, 0x5a, 0x0); 1842a89bcd4cSHans Verkuil io_write(sd, 0x73, 0x0); 1843a89bcd4cSHans Verkuil io_write(sd, 0x78, 0x0); 1844a89bcd4cSHans Verkuil io_write(sd, 0xa0, 0x0); 1845019aa8beSMartin Bugge io_write(sd, 0x69, 0x0); 1846a89bcd4cSHans Verkuil } 1847a89bcd4cSHans Verkuil } 1848a89bcd4cSHans Verkuil 1849a89bcd4cSHans Verkuil static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled) 1850a89bcd4cSHans Verkuil { 1851a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 1852a89bcd4cSHans Verkuil u8 fmt_change_cp, fmt_change_digital, fmt_change_sdp; 1853019aa8beSMartin Bugge u8 irq_status[6]; 1854a89bcd4cSHans Verkuil 1855c9f1f271SMartin Bugge adv7842_irq_enable(sd, false); 1856a89bcd4cSHans Verkuil 1857a89bcd4cSHans Verkuil /* read status */ 1858a89bcd4cSHans Verkuil irq_status[0] = io_read(sd, 0x43); 1859a89bcd4cSHans Verkuil irq_status[1] = io_read(sd, 0x57); 1860a89bcd4cSHans Verkuil irq_status[2] = io_read(sd, 0x70); 1861a89bcd4cSHans Verkuil irq_status[3] = io_read(sd, 0x75); 1862a89bcd4cSHans Verkuil irq_status[4] = io_read(sd, 0x9d); 1863019aa8beSMartin Bugge irq_status[5] = io_read(sd, 0x66); 1864a89bcd4cSHans Verkuil 1865a89bcd4cSHans Verkuil /* and clear */ 1866a89bcd4cSHans Verkuil if (irq_status[0]) 1867a89bcd4cSHans Verkuil io_write(sd, 0x44, irq_status[0]); 1868a89bcd4cSHans Verkuil if (irq_status[1]) 1869a89bcd4cSHans Verkuil io_write(sd, 0x58, irq_status[1]); 1870a89bcd4cSHans Verkuil if (irq_status[2]) 1871a89bcd4cSHans Verkuil io_write(sd, 0x71, irq_status[2]); 1872a89bcd4cSHans Verkuil if (irq_status[3]) 1873a89bcd4cSHans Verkuil io_write(sd, 0x76, irq_status[3]); 1874a89bcd4cSHans Verkuil if (irq_status[4]) 1875a89bcd4cSHans Verkuil io_write(sd, 0x9e, irq_status[4]); 1876019aa8beSMartin Bugge if (irq_status[5]) 1877019aa8beSMartin Bugge io_write(sd, 0x67, irq_status[5]); 1878a89bcd4cSHans Verkuil 1879c9f1f271SMartin Bugge adv7842_irq_enable(sd, true); 1880c9f1f271SMartin Bugge 1881019aa8beSMartin Bugge v4l2_dbg(1, debug, sd, "%s: irq %x, %x, %x, %x, %x, %x\n", __func__, 1882a89bcd4cSHans Verkuil irq_status[0], irq_status[1], irq_status[2], 1883019aa8beSMartin Bugge irq_status[3], irq_status[4], irq_status[5]); 1884a89bcd4cSHans Verkuil 1885a89bcd4cSHans Verkuil /* format change CP */ 1886a89bcd4cSHans Verkuil fmt_change_cp = irq_status[0] & 0x9c; 1887a89bcd4cSHans Verkuil 1888a89bcd4cSHans Verkuil /* format change SDP */ 1889a89bcd4cSHans Verkuil if (state->mode == ADV7842_MODE_SDP) 1890a89bcd4cSHans Verkuil fmt_change_sdp = (irq_status[1] & 0x30) | (irq_status[4] & 0x09); 1891a89bcd4cSHans Verkuil else 1892a89bcd4cSHans Verkuil fmt_change_sdp = 0; 1893a89bcd4cSHans Verkuil 1894a89bcd4cSHans Verkuil /* digital format CP */ 1895a89bcd4cSHans Verkuil if (is_digital_input(sd)) 1896a89bcd4cSHans Verkuil fmt_change_digital = irq_status[3] & 0x03; 1897a89bcd4cSHans Verkuil else 1898a89bcd4cSHans Verkuil fmt_change_digital = 0; 1899a89bcd4cSHans Verkuil 1900019aa8beSMartin Bugge /* format change */ 1901a89bcd4cSHans Verkuil if (fmt_change_cp || fmt_change_digital || fmt_change_sdp) { 1902a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, 1903a89bcd4cSHans Verkuil "%s: fmt_change_cp = 0x%x, fmt_change_digital = 0x%x, fmt_change_sdp = 0x%x\n", 1904a89bcd4cSHans Verkuil __func__, fmt_change_cp, fmt_change_digital, 1905a89bcd4cSHans Verkuil fmt_change_sdp); 1906a89bcd4cSHans Verkuil v4l2_subdev_notify(sd, ADV7842_FMT_CHANGE, NULL); 1907a89bcd4cSHans Verkuil if (handled) 1908a89bcd4cSHans Verkuil *handled = true; 1909019aa8beSMartin Bugge } 1910a89bcd4cSHans Verkuil 1911019aa8beSMartin Bugge /* HDMI/DVI mode */ 1912019aa8beSMartin Bugge if (irq_status[5] & 0x08) { 1913019aa8beSMartin Bugge v4l2_dbg(1, debug, sd, "%s: irq %s mode\n", __func__, 1914019aa8beSMartin Bugge (io_read(sd, 0x65) & 0x08) ? "HDMI" : "DVI"); 1915019aa8beSMartin Bugge if (handled) 1916019aa8beSMartin Bugge *handled = true; 1917019aa8beSMartin Bugge } 1918019aa8beSMartin Bugge 1919019aa8beSMartin Bugge /* tx 5v detect */ 1920019aa8beSMartin Bugge if (irq_status[2] & 0x3) { 1921019aa8beSMartin Bugge v4l2_dbg(1, debug, sd, "%s: irq tx_5v\n", __func__); 1922019aa8beSMartin Bugge adv7842_s_detect_tx_5v_ctrl(sd); 1923019aa8beSMartin Bugge if (handled) 1924019aa8beSMartin Bugge *handled = true; 1925019aa8beSMartin Bugge } 1926a89bcd4cSHans Verkuil return 0; 1927a89bcd4cSHans Verkuil } 1928a89bcd4cSHans Verkuil 1929245b2b67SMartin Bugge static int adv7842_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) 1930245b2b67SMartin Bugge { 1931245b2b67SMartin Bugge struct adv7842_state *state = to_state(sd); 1932245b2b67SMartin Bugge u8 *data = NULL; 1933245b2b67SMartin Bugge 1934245b2b67SMartin Bugge if (edid->pad > ADV7842_EDID_PORT_VGA) 1935245b2b67SMartin Bugge return -EINVAL; 1936245b2b67SMartin Bugge if (edid->blocks == 0) 1937245b2b67SMartin Bugge return -EINVAL; 1938245b2b67SMartin Bugge if (edid->blocks > 2) 1939245b2b67SMartin Bugge return -EINVAL; 1940245b2b67SMartin Bugge if (edid->start_block > 1) 1941245b2b67SMartin Bugge return -EINVAL; 1942245b2b67SMartin Bugge if (edid->start_block == 1) 1943245b2b67SMartin Bugge edid->blocks = 1; 1944245b2b67SMartin Bugge if (!edid->edid) 1945245b2b67SMartin Bugge return -EINVAL; 1946245b2b67SMartin Bugge 1947245b2b67SMartin Bugge switch (edid->pad) { 1948245b2b67SMartin Bugge case ADV7842_EDID_PORT_A: 1949245b2b67SMartin Bugge case ADV7842_EDID_PORT_B: 1950245b2b67SMartin Bugge if (state->hdmi_edid.present & (0x04 << edid->pad)) 1951245b2b67SMartin Bugge data = state->hdmi_edid.edid; 1952245b2b67SMartin Bugge break; 1953245b2b67SMartin Bugge case ADV7842_EDID_PORT_VGA: 1954245b2b67SMartin Bugge if (state->vga_edid.present) 1955245b2b67SMartin Bugge data = state->vga_edid.edid; 1956245b2b67SMartin Bugge break; 1957245b2b67SMartin Bugge default: 1958245b2b67SMartin Bugge return -EINVAL; 1959245b2b67SMartin Bugge } 1960245b2b67SMartin Bugge if (!data) 1961245b2b67SMartin Bugge return -ENODATA; 1962245b2b67SMartin Bugge 1963245b2b67SMartin Bugge memcpy(edid->edid, 1964245b2b67SMartin Bugge data + edid->start_block * 128, 1965245b2b67SMartin Bugge edid->blocks * 128); 1966245b2b67SMartin Bugge return 0; 1967245b2b67SMartin Bugge } 1968245b2b67SMartin Bugge 1969a89bcd4cSHans Verkuil static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *e) 1970a89bcd4cSHans Verkuil { 1971a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 1972a89bcd4cSHans Verkuil int err = 0; 1973a89bcd4cSHans Verkuil 19747de6fab1SMats Randgaard if (e->pad > ADV7842_EDID_PORT_VGA) 1975a89bcd4cSHans Verkuil return -EINVAL; 1976a89bcd4cSHans Verkuil if (e->start_block != 0) 1977a89bcd4cSHans Verkuil return -EINVAL; 1978a89bcd4cSHans Verkuil if (e->blocks > 2) 1979a89bcd4cSHans Verkuil return -E2BIG; 1980a89bcd4cSHans Verkuil if (!e->edid) 1981a89bcd4cSHans Verkuil return -EINVAL; 1982a89bcd4cSHans Verkuil 1983a89bcd4cSHans Verkuil /* todo, per edid */ 1984a89bcd4cSHans Verkuil state->aspect_ratio = v4l2_calc_aspect_ratio(e->edid[0x15], 1985a89bcd4cSHans Verkuil e->edid[0x16]); 1986a89bcd4cSHans Verkuil 19877de6fab1SMats Randgaard switch (e->pad) { 19887de6fab1SMats Randgaard case ADV7842_EDID_PORT_VGA: 1989a89bcd4cSHans Verkuil memset(&state->vga_edid.edid, 0, 256); 1990a89bcd4cSHans Verkuil state->vga_edid.present = e->blocks ? 0x1 : 0x0; 1991a89bcd4cSHans Verkuil memcpy(&state->vga_edid.edid, e->edid, 128 * e->blocks); 1992a89bcd4cSHans Verkuil err = edid_write_vga_segment(sd); 19937de6fab1SMats Randgaard break; 19947de6fab1SMats Randgaard case ADV7842_EDID_PORT_A: 19957de6fab1SMats Randgaard case ADV7842_EDID_PORT_B: 1996a89bcd4cSHans Verkuil memset(&state->hdmi_edid.edid, 0, 256); 1997a89bcd4cSHans Verkuil if (e->blocks) 19987de6fab1SMats Randgaard state->hdmi_edid.present |= 0x04 << e->pad; 1999a89bcd4cSHans Verkuil else 20007de6fab1SMats Randgaard state->hdmi_edid.present &= ~(0x04 << e->pad); 2001a89bcd4cSHans Verkuil memcpy(&state->hdmi_edid.edid, e->edid, 128 * e->blocks); 2002a89bcd4cSHans Verkuil err = edid_write_hdmi_segment(sd, e->pad); 20037de6fab1SMats Randgaard break; 20047de6fab1SMats Randgaard default: 20057de6fab1SMats Randgaard return -EINVAL; 2006a89bcd4cSHans Verkuil } 2007a89bcd4cSHans Verkuil if (err < 0) 2008a89bcd4cSHans Verkuil v4l2_err(sd, "error %d writing edid on port %d\n", err, e->pad); 2009a89bcd4cSHans Verkuil return err; 2010a89bcd4cSHans Verkuil } 2011a89bcd4cSHans Verkuil 2012a89bcd4cSHans Verkuil /*********** avi info frame CEA-861-E **************/ 2013a89bcd4cSHans Verkuil /* TODO move to common library */ 2014a89bcd4cSHans Verkuil 2015a89bcd4cSHans Verkuil struct avi_info_frame { 2016a89bcd4cSHans Verkuil uint8_t f17; 2017a89bcd4cSHans Verkuil uint8_t y10; 2018a89bcd4cSHans Verkuil uint8_t a0; 2019a89bcd4cSHans Verkuil uint8_t b10; 2020a89bcd4cSHans Verkuil uint8_t s10; 2021a89bcd4cSHans Verkuil uint8_t c10; 2022a89bcd4cSHans Verkuil uint8_t m10; 2023a89bcd4cSHans Verkuil uint8_t r3210; 2024a89bcd4cSHans Verkuil uint8_t itc; 2025a89bcd4cSHans Verkuil uint8_t ec210; 2026a89bcd4cSHans Verkuil uint8_t q10; 2027a89bcd4cSHans Verkuil uint8_t sc10; 2028a89bcd4cSHans Verkuil uint8_t f47; 2029a89bcd4cSHans Verkuil uint8_t vic; 2030a89bcd4cSHans Verkuil uint8_t yq10; 2031a89bcd4cSHans Verkuil uint8_t cn10; 2032a89bcd4cSHans Verkuil uint8_t pr3210; 2033a89bcd4cSHans Verkuil uint16_t etb; 2034a89bcd4cSHans Verkuil uint16_t sbb; 2035a89bcd4cSHans Verkuil uint16_t elb; 2036a89bcd4cSHans Verkuil uint16_t srb; 2037a89bcd4cSHans Verkuil }; 2038a89bcd4cSHans Verkuil 2039a89bcd4cSHans Verkuil static const char *y10_txt[4] = { 2040a89bcd4cSHans Verkuil "RGB", 2041a89bcd4cSHans Verkuil "YCbCr 4:2:2", 2042a89bcd4cSHans Verkuil "YCbCr 4:4:4", 2043a89bcd4cSHans Verkuil "Future", 2044a89bcd4cSHans Verkuil }; 2045a89bcd4cSHans Verkuil 2046a89bcd4cSHans Verkuil static const char *c10_txt[4] = { 2047a89bcd4cSHans Verkuil "No Data", 2048a89bcd4cSHans Verkuil "SMPTE 170M", 2049a89bcd4cSHans Verkuil "ITU-R 709", 2050a89bcd4cSHans Verkuil "Extended Colorimetry information valied", 2051a89bcd4cSHans Verkuil }; 2052a89bcd4cSHans Verkuil 2053a89bcd4cSHans Verkuil static const char *itc_txt[2] = { 2054a89bcd4cSHans Verkuil "No Data", 2055a89bcd4cSHans Verkuil "IT content", 2056a89bcd4cSHans Verkuil }; 2057a89bcd4cSHans Verkuil 2058a89bcd4cSHans Verkuil static const char *ec210_txt[8] = { 2059a89bcd4cSHans Verkuil "xvYCC601", 2060a89bcd4cSHans Verkuil "xvYCC709", 2061a89bcd4cSHans Verkuil "sYCC601", 2062a89bcd4cSHans Verkuil "AdobeYCC601", 2063a89bcd4cSHans Verkuil "AdobeRGB", 2064a89bcd4cSHans Verkuil "5 reserved", 2065a89bcd4cSHans Verkuil "6 reserved", 2066a89bcd4cSHans Verkuil "7 reserved", 2067a89bcd4cSHans Verkuil }; 2068a89bcd4cSHans Verkuil 2069a89bcd4cSHans Verkuil static const char *q10_txt[4] = { 2070a89bcd4cSHans Verkuil "Default", 2071a89bcd4cSHans Verkuil "Limited Range", 2072a89bcd4cSHans Verkuil "Full Range", 2073a89bcd4cSHans Verkuil "Reserved", 2074a89bcd4cSHans Verkuil }; 2075a89bcd4cSHans Verkuil 2076a89bcd4cSHans Verkuil static void parse_avi_infoframe(struct v4l2_subdev *sd, uint8_t *buf, 2077a89bcd4cSHans Verkuil struct avi_info_frame *avi) 2078a89bcd4cSHans Verkuil { 2079a89bcd4cSHans Verkuil avi->f17 = (buf[1] >> 7) & 0x1; 2080a89bcd4cSHans Verkuil avi->y10 = (buf[1] >> 5) & 0x3; 2081a89bcd4cSHans Verkuil avi->a0 = (buf[1] >> 4) & 0x1; 2082a89bcd4cSHans Verkuil avi->b10 = (buf[1] >> 2) & 0x3; 2083a89bcd4cSHans Verkuil avi->s10 = buf[1] & 0x3; 2084a89bcd4cSHans Verkuil avi->c10 = (buf[2] >> 6) & 0x3; 2085a89bcd4cSHans Verkuil avi->m10 = (buf[2] >> 4) & 0x3; 2086a89bcd4cSHans Verkuil avi->r3210 = buf[2] & 0xf; 2087a89bcd4cSHans Verkuil avi->itc = (buf[3] >> 7) & 0x1; 2088a89bcd4cSHans Verkuil avi->ec210 = (buf[3] >> 4) & 0x7; 2089a89bcd4cSHans Verkuil avi->q10 = (buf[3] >> 2) & 0x3; 2090a89bcd4cSHans Verkuil avi->sc10 = buf[3] & 0x3; 2091a89bcd4cSHans Verkuil avi->f47 = (buf[4] >> 7) & 0x1; 2092a89bcd4cSHans Verkuil avi->vic = buf[4] & 0x7f; 2093a89bcd4cSHans Verkuil avi->yq10 = (buf[5] >> 6) & 0x3; 2094a89bcd4cSHans Verkuil avi->cn10 = (buf[5] >> 4) & 0x3; 2095a89bcd4cSHans Verkuil avi->pr3210 = buf[5] & 0xf; 2096a89bcd4cSHans Verkuil avi->etb = buf[6] + 256*buf[7]; 2097a89bcd4cSHans Verkuil avi->sbb = buf[8] + 256*buf[9]; 2098a89bcd4cSHans Verkuil avi->elb = buf[10] + 256*buf[11]; 2099a89bcd4cSHans Verkuil avi->srb = buf[12] + 256*buf[13]; 2100a89bcd4cSHans Verkuil } 2101a89bcd4cSHans Verkuil 2102a89bcd4cSHans Verkuil static void print_avi_infoframe(struct v4l2_subdev *sd) 2103a89bcd4cSHans Verkuil { 2104a89bcd4cSHans Verkuil int i; 2105a89bcd4cSHans Verkuil uint8_t buf[14]; 2106a89bcd4cSHans Verkuil uint8_t avi_inf_len; 2107a89bcd4cSHans Verkuil struct avi_info_frame avi; 2108a89bcd4cSHans Verkuil 2109a89bcd4cSHans Verkuil if (!(hdmi_read(sd, 0x05) & 0x80)) { 2110a89bcd4cSHans Verkuil v4l2_info(sd, "receive DVI-D signal (AVI infoframe not supported)\n"); 2111a89bcd4cSHans Verkuil return; 2112a89bcd4cSHans Verkuil } 2113a89bcd4cSHans Verkuil if (!(io_read(sd, 0x60) & 0x01)) { 2114a89bcd4cSHans Verkuil v4l2_info(sd, "AVI infoframe not received\n"); 2115a89bcd4cSHans Verkuil return; 2116a89bcd4cSHans Verkuil } 2117a89bcd4cSHans Verkuil 2118a89bcd4cSHans Verkuil if (io_read(sd, 0x88) & 0x10) { 2119a89bcd4cSHans Verkuil /* Note: the ADV7842 calculated incorrect checksums for InfoFrames 2120a89bcd4cSHans Verkuil with a length of 14 or 15. See the ADV7842 Register Settings 2121a89bcd4cSHans Verkuil Recommendations document for more details. */ 2122a89bcd4cSHans Verkuil v4l2_info(sd, "AVI infoframe checksum error\n"); 2123a89bcd4cSHans Verkuil return; 2124a89bcd4cSHans Verkuil } 2125a89bcd4cSHans Verkuil 2126a89bcd4cSHans Verkuil avi_inf_len = infoframe_read(sd, 0xe2); 2127a89bcd4cSHans Verkuil v4l2_info(sd, "AVI infoframe version %d (%d byte)\n", 2128a89bcd4cSHans Verkuil infoframe_read(sd, 0xe1), avi_inf_len); 2129a89bcd4cSHans Verkuil 2130a89bcd4cSHans Verkuil if (infoframe_read(sd, 0xe1) != 0x02) 2131a89bcd4cSHans Verkuil return; 2132a89bcd4cSHans Verkuil 2133a89bcd4cSHans Verkuil for (i = 0; i < 14; i++) 2134a89bcd4cSHans Verkuil buf[i] = infoframe_read(sd, i); 2135a89bcd4cSHans Verkuil 2136a89bcd4cSHans Verkuil v4l2_info(sd, "\t%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", 2137a89bcd4cSHans Verkuil buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], 2138a89bcd4cSHans Verkuil buf[8], buf[9], buf[10], buf[11], buf[12], buf[13]); 2139a89bcd4cSHans Verkuil 2140a89bcd4cSHans Verkuil parse_avi_infoframe(sd, buf, &avi); 2141a89bcd4cSHans Verkuil 2142a89bcd4cSHans Verkuil if (avi.vic) 2143a89bcd4cSHans Verkuil v4l2_info(sd, "\tVIC: %d\n", avi.vic); 2144a89bcd4cSHans Verkuil if (avi.itc) 2145a89bcd4cSHans Verkuil v4l2_info(sd, "\t%s\n", itc_txt[avi.itc]); 2146a89bcd4cSHans Verkuil 2147a89bcd4cSHans Verkuil if (avi.y10) 2148a89bcd4cSHans Verkuil v4l2_info(sd, "\t%s %s\n", y10_txt[avi.y10], !avi.c10 ? "" : 2149a89bcd4cSHans Verkuil (avi.c10 == 0x3 ? ec210_txt[avi.ec210] : c10_txt[avi.c10])); 2150a89bcd4cSHans Verkuil else 2151a89bcd4cSHans Verkuil v4l2_info(sd, "\t%s %s\n", y10_txt[avi.y10], q10_txt[avi.q10]); 2152a89bcd4cSHans Verkuil } 2153a89bcd4cSHans Verkuil 2154a89bcd4cSHans Verkuil static const char * const prim_mode_txt[] = { 2155a89bcd4cSHans Verkuil "SDP", 2156a89bcd4cSHans Verkuil "Component", 2157a89bcd4cSHans Verkuil "Graphics", 2158a89bcd4cSHans Verkuil "Reserved", 2159a89bcd4cSHans Verkuil "CVBS & HDMI AUDIO", 2160a89bcd4cSHans Verkuil "HDMI-Comp", 2161a89bcd4cSHans Verkuil "HDMI-GR", 2162a89bcd4cSHans Verkuil "Reserved", 2163a89bcd4cSHans Verkuil "Reserved", 2164a89bcd4cSHans Verkuil "Reserved", 2165a89bcd4cSHans Verkuil "Reserved", 2166a89bcd4cSHans Verkuil "Reserved", 2167a89bcd4cSHans Verkuil "Reserved", 2168a89bcd4cSHans Verkuil "Reserved", 2169a89bcd4cSHans Verkuil "Reserved", 2170a89bcd4cSHans Verkuil "Reserved", 2171a89bcd4cSHans Verkuil }; 2172a89bcd4cSHans Verkuil 2173a89bcd4cSHans Verkuil static int adv7842_sdp_log_status(struct v4l2_subdev *sd) 2174a89bcd4cSHans Verkuil { 2175a89bcd4cSHans Verkuil /* SDP (Standard definition processor) block */ 2176a89bcd4cSHans Verkuil uint8_t sdp_signal_detected = sdp_read(sd, 0x5A) & 0x01; 2177a89bcd4cSHans Verkuil 2178a89bcd4cSHans Verkuil v4l2_info(sd, "Chip powered %s\n", no_power(sd) ? "off" : "on"); 2179a89bcd4cSHans Verkuil v4l2_info(sd, "Prim-mode = 0x%x, video std = 0x%x\n", 2180a89bcd4cSHans Verkuil io_read(sd, 0x01) & 0x0f, io_read(sd, 0x00) & 0x3f); 2181a89bcd4cSHans Verkuil 2182a89bcd4cSHans Verkuil v4l2_info(sd, "SDP: free run: %s\n", 2183a89bcd4cSHans Verkuil (sdp_read(sd, 0x56) & 0x01) ? "on" : "off"); 2184a89bcd4cSHans Verkuil v4l2_info(sd, "SDP: %s\n", sdp_signal_detected ? 2185a89bcd4cSHans Verkuil "valid SD/PR signal detected" : "invalid/no signal"); 2186a89bcd4cSHans Verkuil if (sdp_signal_detected) { 2187a89bcd4cSHans Verkuil static const char * const sdp_std_txt[] = { 2188a89bcd4cSHans Verkuil "NTSC-M/J", 2189a89bcd4cSHans Verkuil "1?", 2190a89bcd4cSHans Verkuil "NTSC-443", 2191a89bcd4cSHans Verkuil "60HzSECAM", 2192a89bcd4cSHans Verkuil "PAL-M", 2193a89bcd4cSHans Verkuil "5?", 2194a89bcd4cSHans Verkuil "PAL-60", 2195a89bcd4cSHans Verkuil "7?", "8?", "9?", "a?", "b?", 2196a89bcd4cSHans Verkuil "PAL-CombN", 2197a89bcd4cSHans Verkuil "d?", 2198a89bcd4cSHans Verkuil "PAL-BGHID", 2199a89bcd4cSHans Verkuil "SECAM" 2200a89bcd4cSHans Verkuil }; 2201a89bcd4cSHans Verkuil v4l2_info(sd, "SDP: standard %s\n", 2202a89bcd4cSHans Verkuil sdp_std_txt[sdp_read(sd, 0x52) & 0x0f]); 2203a89bcd4cSHans Verkuil v4l2_info(sd, "SDP: %s\n", 2204a89bcd4cSHans Verkuil (sdp_read(sd, 0x59) & 0x08) ? "50Hz" : "60Hz"); 2205a89bcd4cSHans Verkuil v4l2_info(sd, "SDP: %s\n", 2206a89bcd4cSHans Verkuil (sdp_read(sd, 0x57) & 0x08) ? "Interlaced" : "Progressive"); 2207a89bcd4cSHans Verkuil v4l2_info(sd, "SDP: deinterlacer %s\n", 2208a89bcd4cSHans Verkuil (sdp_read(sd, 0x12) & 0x08) ? "enabled" : "disabled"); 2209a89bcd4cSHans Verkuil v4l2_info(sd, "SDP: csc %s mode\n", 2210a89bcd4cSHans Verkuil (sdp_io_read(sd, 0xe0) & 0x40) ? "auto" : "manual"); 2211a89bcd4cSHans Verkuil } 2212a89bcd4cSHans Verkuil return 0; 2213a89bcd4cSHans Verkuil } 2214a89bcd4cSHans Verkuil 2215a89bcd4cSHans Verkuil static int adv7842_cp_log_status(struct v4l2_subdev *sd) 2216a89bcd4cSHans Verkuil { 2217a89bcd4cSHans Verkuil /* CP block */ 2218a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 2219a89bcd4cSHans Verkuil struct v4l2_dv_timings timings; 2220a89bcd4cSHans Verkuil uint8_t reg_io_0x02 = io_read(sd, 0x02); 2221a89bcd4cSHans Verkuil uint8_t reg_io_0x21 = io_read(sd, 0x21); 2222a89bcd4cSHans Verkuil uint8_t reg_rep_0x77 = rep_read(sd, 0x77); 2223a89bcd4cSHans Verkuil uint8_t reg_rep_0x7d = rep_read(sd, 0x7d); 2224a89bcd4cSHans Verkuil bool audio_pll_locked = hdmi_read(sd, 0x04) & 0x01; 2225a89bcd4cSHans Verkuil bool audio_sample_packet_detect = hdmi_read(sd, 0x18) & 0x01; 2226a89bcd4cSHans Verkuil bool audio_mute = io_read(sd, 0x65) & 0x40; 2227a89bcd4cSHans Verkuil 2228a89bcd4cSHans Verkuil static const char * const csc_coeff_sel_rb[16] = { 2229a89bcd4cSHans Verkuil "bypassed", "YPbPr601 -> RGB", "reserved", "YPbPr709 -> RGB", 2230a89bcd4cSHans Verkuil "reserved", "RGB -> YPbPr601", "reserved", "RGB -> YPbPr709", 2231a89bcd4cSHans Verkuil "reserved", "YPbPr709 -> YPbPr601", "YPbPr601 -> YPbPr709", 2232a89bcd4cSHans Verkuil "reserved", "reserved", "reserved", "reserved", "manual" 2233a89bcd4cSHans Verkuil }; 2234a89bcd4cSHans Verkuil static const char * const input_color_space_txt[16] = { 2235a89bcd4cSHans Verkuil "RGB limited range (16-235)", "RGB full range (0-255)", 2236a89bcd4cSHans Verkuil "YCbCr Bt.601 (16-235)", "YCbCr Bt.709 (16-235)", 223769e9ba6fSHans Verkuil "xvYCC Bt.601", "xvYCC Bt.709", 2238a89bcd4cSHans Verkuil "YCbCr Bt.601 (0-255)", "YCbCr Bt.709 (0-255)", 2239a89bcd4cSHans Verkuil "invalid", "invalid", "invalid", "invalid", "invalid", 2240a89bcd4cSHans Verkuil "invalid", "invalid", "automatic" 2241a89bcd4cSHans Verkuil }; 2242a89bcd4cSHans Verkuil static const char * const rgb_quantization_range_txt[] = { 2243a89bcd4cSHans Verkuil "Automatic", 2244a89bcd4cSHans Verkuil "RGB limited range (16-235)", 2245a89bcd4cSHans Verkuil "RGB full range (0-255)", 2246a89bcd4cSHans Verkuil }; 2247a89bcd4cSHans Verkuil static const char * const deep_color_mode_txt[4] = { 2248a89bcd4cSHans Verkuil "8-bits per channel", 2249a89bcd4cSHans Verkuil "10-bits per channel", 2250a89bcd4cSHans Verkuil "12-bits per channel", 2251a89bcd4cSHans Verkuil "16-bits per channel (not supported)" 2252a89bcd4cSHans Verkuil }; 2253a89bcd4cSHans Verkuil 2254a89bcd4cSHans Verkuil v4l2_info(sd, "-----Chip status-----\n"); 2255a89bcd4cSHans Verkuil v4l2_info(sd, "Chip power: %s\n", no_power(sd) ? "off" : "on"); 2256a89bcd4cSHans Verkuil v4l2_info(sd, "HDMI/DVI-D port selected: %s\n", 2257a89bcd4cSHans Verkuil state->hdmi_port_a ? "A" : "B"); 2258a89bcd4cSHans Verkuil v4l2_info(sd, "EDID A %s, B %s\n", 2259a89bcd4cSHans Verkuil ((reg_rep_0x7d & 0x04) && (reg_rep_0x77 & 0x04)) ? 2260a89bcd4cSHans Verkuil "enabled" : "disabled", 2261a89bcd4cSHans Verkuil ((reg_rep_0x7d & 0x08) && (reg_rep_0x77 & 0x08)) ? 2262a89bcd4cSHans Verkuil "enabled" : "disabled"); 2263a89bcd4cSHans Verkuil v4l2_info(sd, "HPD A %s, B %s\n", 2264a89bcd4cSHans Verkuil reg_io_0x21 & 0x02 ? "enabled" : "disabled", 2265a89bcd4cSHans Verkuil reg_io_0x21 & 0x01 ? "enabled" : "disabled"); 2266a89bcd4cSHans Verkuil v4l2_info(sd, "CEC %s\n", !!(cec_read(sd, 0x2a) & 0x01) ? 2267a89bcd4cSHans Verkuil "enabled" : "disabled"); 2268a89bcd4cSHans Verkuil 2269a89bcd4cSHans Verkuil v4l2_info(sd, "-----Signal status-----\n"); 2270a89bcd4cSHans Verkuil if (state->hdmi_port_a) { 2271a89bcd4cSHans Verkuil v4l2_info(sd, "Cable detected (+5V power): %s\n", 2272a89bcd4cSHans Verkuil io_read(sd, 0x6f) & 0x02 ? "true" : "false"); 2273a89bcd4cSHans Verkuil v4l2_info(sd, "TMDS signal detected: %s\n", 2274a89bcd4cSHans Verkuil (io_read(sd, 0x6a) & 0x02) ? "true" : "false"); 2275a89bcd4cSHans Verkuil v4l2_info(sd, "TMDS signal locked: %s\n", 2276a89bcd4cSHans Verkuil (io_read(sd, 0x6a) & 0x20) ? "true" : "false"); 2277a89bcd4cSHans Verkuil } else { 2278a89bcd4cSHans Verkuil v4l2_info(sd, "Cable detected (+5V power):%s\n", 2279a89bcd4cSHans Verkuil io_read(sd, 0x6f) & 0x01 ? "true" : "false"); 2280a89bcd4cSHans Verkuil v4l2_info(sd, "TMDS signal detected: %s\n", 2281a89bcd4cSHans Verkuil (io_read(sd, 0x6a) & 0x01) ? "true" : "false"); 2282a89bcd4cSHans Verkuil v4l2_info(sd, "TMDS signal locked: %s\n", 2283a89bcd4cSHans Verkuil (io_read(sd, 0x6a) & 0x10) ? "true" : "false"); 2284a89bcd4cSHans Verkuil } 2285a89bcd4cSHans Verkuil v4l2_info(sd, "CP free run: %s\n", 2286a89bcd4cSHans Verkuil (!!(cp_read(sd, 0xff) & 0x10) ? "on" : "off")); 2287a89bcd4cSHans Verkuil v4l2_info(sd, "Prim-mode = 0x%x, video std = 0x%x, v_freq = 0x%x\n", 2288a89bcd4cSHans Verkuil io_read(sd, 0x01) & 0x0f, io_read(sd, 0x00) & 0x3f, 2289a89bcd4cSHans Verkuil (io_read(sd, 0x01) & 0x70) >> 4); 2290a89bcd4cSHans Verkuil 2291a89bcd4cSHans Verkuil v4l2_info(sd, "-----Video Timings-----\n"); 2292a89bcd4cSHans Verkuil if (no_cp_signal(sd)) { 2293a89bcd4cSHans Verkuil v4l2_info(sd, "STDI: not locked\n"); 2294a89bcd4cSHans Verkuil } else { 2295a89bcd4cSHans Verkuil uint32_t bl = ((cp_read(sd, 0xb1) & 0x3f) << 8) | cp_read(sd, 0xb2); 2296a89bcd4cSHans Verkuil uint32_t lcf = ((cp_read(sd, 0xb3) & 0x7) << 8) | cp_read(sd, 0xb4); 2297a89bcd4cSHans Verkuil uint32_t lcvs = cp_read(sd, 0xb3) >> 3; 2298a89bcd4cSHans Verkuil uint32_t fcl = ((cp_read(sd, 0xb8) & 0x1f) << 8) | cp_read(sd, 0xb9); 2299a89bcd4cSHans Verkuil char hs_pol = ((cp_read(sd, 0xb5) & 0x10) ? 2300a89bcd4cSHans Verkuil ((cp_read(sd, 0xb5) & 0x08) ? '+' : '-') : 'x'); 2301a89bcd4cSHans Verkuil char vs_pol = ((cp_read(sd, 0xb5) & 0x40) ? 2302a89bcd4cSHans Verkuil ((cp_read(sd, 0xb5) & 0x20) ? '+' : '-') : 'x'); 2303a89bcd4cSHans Verkuil v4l2_info(sd, 2304a89bcd4cSHans Verkuil "STDI: lcf (frame height - 1) = %d, bl = %d, lcvs (vsync) = %d, fcl = %d, %s, %chsync, %cvsync\n", 2305a89bcd4cSHans Verkuil lcf, bl, lcvs, fcl, 2306a89bcd4cSHans Verkuil (cp_read(sd, 0xb1) & 0x40) ? 2307a89bcd4cSHans Verkuil "interlaced" : "progressive", 2308a89bcd4cSHans Verkuil hs_pol, vs_pol); 2309a89bcd4cSHans Verkuil } 2310a89bcd4cSHans Verkuil if (adv7842_query_dv_timings(sd, &timings)) 2311a89bcd4cSHans Verkuil v4l2_info(sd, "No video detected\n"); 2312a89bcd4cSHans Verkuil else 2313a89bcd4cSHans Verkuil v4l2_print_dv_timings(sd->name, "Detected format: ", 2314a89bcd4cSHans Verkuil &timings, true); 2315a89bcd4cSHans Verkuil v4l2_print_dv_timings(sd->name, "Configured format: ", 2316a89bcd4cSHans Verkuil &state->timings, true); 2317a89bcd4cSHans Verkuil 2318a89bcd4cSHans Verkuil if (no_cp_signal(sd)) 2319a89bcd4cSHans Verkuil return 0; 2320a89bcd4cSHans Verkuil 2321a89bcd4cSHans Verkuil v4l2_info(sd, "-----Color space-----\n"); 2322a89bcd4cSHans Verkuil v4l2_info(sd, "RGB quantization range ctrl: %s\n", 2323a89bcd4cSHans Verkuil rgb_quantization_range_txt[state->rgb_quantization_range]); 2324a89bcd4cSHans Verkuil v4l2_info(sd, "Input color space: %s\n", 2325a89bcd4cSHans Verkuil input_color_space_txt[reg_io_0x02 >> 4]); 2326a89bcd4cSHans Verkuil v4l2_info(sd, "Output color space: %s %s, saturator %s\n", 2327a89bcd4cSHans Verkuil (reg_io_0x02 & 0x02) ? "RGB" : "YCbCr", 2328a89bcd4cSHans Verkuil (reg_io_0x02 & 0x04) ? "(16-235)" : "(0-255)", 2329a89bcd4cSHans Verkuil ((reg_io_0x02 & 0x04) ^ (reg_io_0x02 & 0x01)) ? 2330a89bcd4cSHans Verkuil "enabled" : "disabled"); 2331a89bcd4cSHans Verkuil v4l2_info(sd, "Color space conversion: %s\n", 2332a89bcd4cSHans Verkuil csc_coeff_sel_rb[cp_read(sd, 0xf4) >> 4]); 2333a89bcd4cSHans Verkuil 2334a89bcd4cSHans Verkuil if (!is_digital_input(sd)) 2335a89bcd4cSHans Verkuil return 0; 2336a89bcd4cSHans Verkuil 2337a89bcd4cSHans Verkuil v4l2_info(sd, "-----%s status-----\n", is_hdmi(sd) ? "HDMI" : "DVI-D"); 2338a89bcd4cSHans Verkuil v4l2_info(sd, "HDCP encrypted content: %s\n", 2339a89bcd4cSHans Verkuil (hdmi_read(sd, 0x05) & 0x40) ? "true" : "false"); 2340a89bcd4cSHans Verkuil v4l2_info(sd, "HDCP keys read: %s%s\n", 2341a89bcd4cSHans Verkuil (hdmi_read(sd, 0x04) & 0x20) ? "yes" : "no", 2342a89bcd4cSHans Verkuil (hdmi_read(sd, 0x04) & 0x10) ? "ERROR" : ""); 2343a89bcd4cSHans Verkuil if (!is_hdmi(sd)) 2344a89bcd4cSHans Verkuil return 0; 2345a89bcd4cSHans Verkuil 2346a89bcd4cSHans Verkuil v4l2_info(sd, "Audio: pll %s, samples %s, %s\n", 2347a89bcd4cSHans Verkuil audio_pll_locked ? "locked" : "not locked", 2348a89bcd4cSHans Verkuil audio_sample_packet_detect ? "detected" : "not detected", 2349a89bcd4cSHans Verkuil audio_mute ? "muted" : "enabled"); 2350a89bcd4cSHans Verkuil if (audio_pll_locked && audio_sample_packet_detect) { 2351a89bcd4cSHans Verkuil v4l2_info(sd, "Audio format: %s\n", 2352a89bcd4cSHans Verkuil (hdmi_read(sd, 0x07) & 0x40) ? "multi-channel" : "stereo"); 2353a89bcd4cSHans Verkuil } 2354a89bcd4cSHans Verkuil v4l2_info(sd, "Audio CTS: %u\n", (hdmi_read(sd, 0x5b) << 12) + 2355a89bcd4cSHans Verkuil (hdmi_read(sd, 0x5c) << 8) + 2356a89bcd4cSHans Verkuil (hdmi_read(sd, 0x5d) & 0xf0)); 2357a89bcd4cSHans Verkuil v4l2_info(sd, "Audio N: %u\n", ((hdmi_read(sd, 0x5d) & 0x0f) << 16) + 2358a89bcd4cSHans Verkuil (hdmi_read(sd, 0x5e) << 8) + 2359a89bcd4cSHans Verkuil hdmi_read(sd, 0x5f)); 2360a89bcd4cSHans Verkuil v4l2_info(sd, "AV Mute: %s\n", 2361a89bcd4cSHans Verkuil (hdmi_read(sd, 0x04) & 0x40) ? "on" : "off"); 2362a89bcd4cSHans Verkuil v4l2_info(sd, "Deep color mode: %s\n", 2363a89bcd4cSHans Verkuil deep_color_mode_txt[hdmi_read(sd, 0x0b) >> 6]); 2364a89bcd4cSHans Verkuil 2365a89bcd4cSHans Verkuil print_avi_infoframe(sd); 2366a89bcd4cSHans Verkuil return 0; 2367a89bcd4cSHans Verkuil } 2368a89bcd4cSHans Verkuil 2369a89bcd4cSHans Verkuil static int adv7842_log_status(struct v4l2_subdev *sd) 2370a89bcd4cSHans Verkuil { 2371a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 2372a89bcd4cSHans Verkuil 2373a89bcd4cSHans Verkuil if (state->mode == ADV7842_MODE_SDP) 2374a89bcd4cSHans Verkuil return adv7842_sdp_log_status(sd); 2375a89bcd4cSHans Verkuil return adv7842_cp_log_status(sd); 2376a89bcd4cSHans Verkuil } 2377a89bcd4cSHans Verkuil 2378a89bcd4cSHans Verkuil static int adv7842_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) 2379a89bcd4cSHans Verkuil { 2380a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 2381a89bcd4cSHans Verkuil 2382a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, "%s:\n", __func__); 2383a89bcd4cSHans Verkuil 2384a89bcd4cSHans Verkuil if (state->mode != ADV7842_MODE_SDP) 2385a89bcd4cSHans Verkuil return -ENODATA; 2386a89bcd4cSHans Verkuil 2387a89bcd4cSHans Verkuil if (!(sdp_read(sd, 0x5A) & 0x01)) { 2388a89bcd4cSHans Verkuil *std = 0; 2389a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, "%s: no valid signal\n", __func__); 2390a89bcd4cSHans Verkuil return 0; 2391a89bcd4cSHans Verkuil } 2392a89bcd4cSHans Verkuil 2393a89bcd4cSHans Verkuil switch (sdp_read(sd, 0x52) & 0x0f) { 2394a89bcd4cSHans Verkuil case 0: 2395a89bcd4cSHans Verkuil /* NTSC-M/J */ 2396a89bcd4cSHans Verkuil *std &= V4L2_STD_NTSC; 2397a89bcd4cSHans Verkuil break; 2398a89bcd4cSHans Verkuil case 2: 2399a89bcd4cSHans Verkuil /* NTSC-443 */ 2400a89bcd4cSHans Verkuil *std &= V4L2_STD_NTSC_443; 2401a89bcd4cSHans Verkuil break; 2402a89bcd4cSHans Verkuil case 3: 2403a89bcd4cSHans Verkuil /* 60HzSECAM */ 2404a89bcd4cSHans Verkuil *std &= V4L2_STD_SECAM; 2405a89bcd4cSHans Verkuil break; 2406a89bcd4cSHans Verkuil case 4: 2407a89bcd4cSHans Verkuil /* PAL-M */ 2408a89bcd4cSHans Verkuil *std &= V4L2_STD_PAL_M; 2409a89bcd4cSHans Verkuil break; 2410a89bcd4cSHans Verkuil case 6: 2411a89bcd4cSHans Verkuil /* PAL-60 */ 2412a89bcd4cSHans Verkuil *std &= V4L2_STD_PAL_60; 2413a89bcd4cSHans Verkuil break; 2414a89bcd4cSHans Verkuil case 0xc: 2415a89bcd4cSHans Verkuil /* PAL-CombN */ 2416a89bcd4cSHans Verkuil *std &= V4L2_STD_PAL_Nc; 2417a89bcd4cSHans Verkuil break; 2418a89bcd4cSHans Verkuil case 0xe: 2419a89bcd4cSHans Verkuil /* PAL-BGHID */ 2420a89bcd4cSHans Verkuil *std &= V4L2_STD_PAL; 2421a89bcd4cSHans Verkuil break; 2422a89bcd4cSHans Verkuil case 0xf: 2423a89bcd4cSHans Verkuil /* SECAM */ 2424a89bcd4cSHans Verkuil *std &= V4L2_STD_SECAM; 2425a89bcd4cSHans Verkuil break; 2426a89bcd4cSHans Verkuil default: 2427a89bcd4cSHans Verkuil *std &= V4L2_STD_ALL; 2428a89bcd4cSHans Verkuil break; 2429a89bcd4cSHans Verkuil } 2430a89bcd4cSHans Verkuil return 0; 2431a89bcd4cSHans Verkuil } 2432a89bcd4cSHans Verkuil 24333c4da74fSMartin Bugge static void adv7842_s_sdp_io(struct v4l2_subdev *sd, struct adv7842_sdp_io_sync_adjustment *s) 24343c4da74fSMartin Bugge { 24353c4da74fSMartin Bugge if (s && s->adjust) { 24363c4da74fSMartin Bugge sdp_io_write(sd, 0x94, (s->hs_beg >> 8) & 0xf); 24373c4da74fSMartin Bugge sdp_io_write(sd, 0x95, s->hs_beg & 0xff); 24383c4da74fSMartin Bugge sdp_io_write(sd, 0x96, (s->hs_width >> 8) & 0xf); 24393c4da74fSMartin Bugge sdp_io_write(sd, 0x97, s->hs_width & 0xff); 24403c4da74fSMartin Bugge sdp_io_write(sd, 0x98, (s->de_beg >> 8) & 0xf); 24413c4da74fSMartin Bugge sdp_io_write(sd, 0x99, s->de_beg & 0xff); 24423c4da74fSMartin Bugge sdp_io_write(sd, 0x9a, (s->de_end >> 8) & 0xf); 24433c4da74fSMartin Bugge sdp_io_write(sd, 0x9b, s->de_end & 0xff); 24443c4da74fSMartin Bugge sdp_io_write(sd, 0xac, s->de_v_beg_o); 24453c4da74fSMartin Bugge sdp_io_write(sd, 0xad, s->de_v_beg_e); 24463c4da74fSMartin Bugge sdp_io_write(sd, 0xae, s->de_v_end_o); 24473c4da74fSMartin Bugge sdp_io_write(sd, 0xaf, s->de_v_end_e); 24483c4da74fSMartin Bugge } else { 24493c4da74fSMartin Bugge /* set to default */ 24503c4da74fSMartin Bugge sdp_io_write(sd, 0x94, 0x00); 24513c4da74fSMartin Bugge sdp_io_write(sd, 0x95, 0x00); 24523c4da74fSMartin Bugge sdp_io_write(sd, 0x96, 0x00); 24533c4da74fSMartin Bugge sdp_io_write(sd, 0x97, 0x20); 24543c4da74fSMartin Bugge sdp_io_write(sd, 0x98, 0x00); 24553c4da74fSMartin Bugge sdp_io_write(sd, 0x99, 0x00); 24563c4da74fSMartin Bugge sdp_io_write(sd, 0x9a, 0x00); 24573c4da74fSMartin Bugge sdp_io_write(sd, 0x9b, 0x00); 24583c4da74fSMartin Bugge sdp_io_write(sd, 0xac, 0x04); 24593c4da74fSMartin Bugge sdp_io_write(sd, 0xad, 0x04); 24603c4da74fSMartin Bugge sdp_io_write(sd, 0xae, 0x04); 24613c4da74fSMartin Bugge sdp_io_write(sd, 0xaf, 0x04); 24623c4da74fSMartin Bugge } 24633c4da74fSMartin Bugge } 24643c4da74fSMartin Bugge 2465a89bcd4cSHans Verkuil static int adv7842_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) 2466a89bcd4cSHans Verkuil { 2467a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 24683c4da74fSMartin Bugge struct adv7842_platform_data *pdata = &state->pdata; 2469a89bcd4cSHans Verkuil 2470a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, "%s:\n", __func__); 2471a89bcd4cSHans Verkuil 2472a89bcd4cSHans Verkuil if (state->mode != ADV7842_MODE_SDP) 2473a89bcd4cSHans Verkuil return -ENODATA; 2474a89bcd4cSHans Verkuil 24753c4da74fSMartin Bugge if (norm & V4L2_STD_625_50) 24763c4da74fSMartin Bugge adv7842_s_sdp_io(sd, &pdata->sdp_io_sync_625); 24773c4da74fSMartin Bugge else if (norm & V4L2_STD_525_60) 24783c4da74fSMartin Bugge adv7842_s_sdp_io(sd, &pdata->sdp_io_sync_525); 24793c4da74fSMartin Bugge else 24803c4da74fSMartin Bugge adv7842_s_sdp_io(sd, NULL); 24813c4da74fSMartin Bugge 2482a89bcd4cSHans Verkuil if (norm & V4L2_STD_ALL) { 2483a89bcd4cSHans Verkuil state->norm = norm; 2484a89bcd4cSHans Verkuil return 0; 2485a89bcd4cSHans Verkuil } 2486a89bcd4cSHans Verkuil return -EINVAL; 2487a89bcd4cSHans Verkuil } 2488a89bcd4cSHans Verkuil 2489a89bcd4cSHans Verkuil static int adv7842_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm) 2490a89bcd4cSHans Verkuil { 2491a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 2492a89bcd4cSHans Verkuil 2493a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, "%s:\n", __func__); 2494a89bcd4cSHans Verkuil 2495a89bcd4cSHans Verkuil if (state->mode != ADV7842_MODE_SDP) 2496a89bcd4cSHans Verkuil return -ENODATA; 2497a89bcd4cSHans Verkuil 2498a89bcd4cSHans Verkuil *norm = state->norm; 2499a89bcd4cSHans Verkuil return 0; 2500a89bcd4cSHans Verkuil } 2501a89bcd4cSHans Verkuil 2502a89bcd4cSHans Verkuil /* ----------------------------------------------------------------------- */ 2503a89bcd4cSHans Verkuil 250469e9ba6fSHans Verkuil static int adv7842_core_init(struct v4l2_subdev *sd) 2505a89bcd4cSHans Verkuil { 250669e9ba6fSHans Verkuil struct adv7842_state *state = to_state(sd); 250769e9ba6fSHans Verkuil struct adv7842_platform_data *pdata = &state->pdata; 2508a89bcd4cSHans Verkuil hdmi_write(sd, 0x48, 2509a89bcd4cSHans Verkuil (pdata->disable_pwrdnb ? 0x80 : 0) | 2510a89bcd4cSHans Verkuil (pdata->disable_cable_det_rst ? 0x40 : 0)); 2511a89bcd4cSHans Verkuil 2512a89bcd4cSHans Verkuil disable_input(sd); 2513a89bcd4cSHans Verkuil 2514a89bcd4cSHans Verkuil /* power */ 2515a89bcd4cSHans Verkuil io_write(sd, 0x0c, 0x42); /* Power up part and power down VDP */ 2516a89bcd4cSHans Verkuil io_write(sd, 0x15, 0x80); /* Power up pads */ 2517a89bcd4cSHans Verkuil 2518a89bcd4cSHans Verkuil /* video format */ 2519a89bcd4cSHans Verkuil io_write(sd, 0x02, 252069e9ba6fSHans Verkuil 0xf0 | 2521a89bcd4cSHans Verkuil pdata->alt_gamma << 3 | 2522a89bcd4cSHans Verkuil pdata->op_656_range << 2 | 2523a89bcd4cSHans Verkuil pdata->rgb_out << 1 | 2524a89bcd4cSHans Verkuil pdata->alt_data_sat << 0); 2525a89bcd4cSHans Verkuil io_write(sd, 0x03, pdata->op_format_sel); 2526a89bcd4cSHans Verkuil io_write_and_or(sd, 0x04, 0x1f, pdata->op_ch_sel << 5); 2527a89bcd4cSHans Verkuil io_write_and_or(sd, 0x05, 0xf0, pdata->blank_data << 3 | 2528a89bcd4cSHans Verkuil pdata->insert_av_codes << 2 | 2529a89bcd4cSHans Verkuil pdata->replicate_av_codes << 1 | 2530a89bcd4cSHans Verkuil pdata->invert_cbcr << 0); 2531a89bcd4cSHans Verkuil 25325b64b205SMats Randgaard /* HDMI audio */ 25335b64b205SMats Randgaard hdmi_write_and_or(sd, 0x1a, 0xf1, 0x08); /* Wait 1 s before unmute */ 25345b64b205SMats Randgaard 2535a89bcd4cSHans Verkuil /* Drive strength */ 2536a89bcd4cSHans Verkuil io_write_and_or(sd, 0x14, 0xc0, pdata->drive_strength.data<<4 | 2537a89bcd4cSHans Verkuil pdata->drive_strength.clock<<2 | 2538a89bcd4cSHans Verkuil pdata->drive_strength.sync); 2539a89bcd4cSHans Verkuil 2540a89bcd4cSHans Verkuil /* HDMI free run */ 2541a89bcd4cSHans Verkuil cp_write(sd, 0xba, (pdata->hdmi_free_run_mode << 1) | 0x01); 2542a89bcd4cSHans Verkuil 2543a89bcd4cSHans Verkuil /* TODO from platform data */ 2544a89bcd4cSHans Verkuil cp_write(sd, 0x69, 0x14); /* Enable CP CSC */ 2545a89bcd4cSHans Verkuil io_write(sd, 0x06, 0xa6); /* positive VS and HS and DE */ 2546a89bcd4cSHans Verkuil cp_write(sd, 0xf3, 0xdc); /* Low threshold to enter/exit free run mode */ 2547a89bcd4cSHans Verkuil afe_write(sd, 0xb5, 0x01); /* Setting MCLK to 256Fs */ 2548a89bcd4cSHans Verkuil 2549a89bcd4cSHans Verkuil afe_write(sd, 0x02, pdata->ain_sel); /* Select analog input muxing mode */ 2550a89bcd4cSHans Verkuil io_write_and_or(sd, 0x30, ~(1 << 4), pdata->output_bus_lsb_to_msb << 4); 2551a89bcd4cSHans Verkuil 2552a89bcd4cSHans Verkuil sdp_csc_coeff(sd, &pdata->sdp_csc_coeff); 2553a89bcd4cSHans Verkuil 2554a89bcd4cSHans Verkuil /* todo, improve settings for sdram */ 2555a89bcd4cSHans Verkuil if (pdata->sd_ram_size >= 128) { 2556a89bcd4cSHans Verkuil sdp_write(sd, 0x12, 0x0d); /* Frame TBC,3D comb enabled */ 2557a89bcd4cSHans Verkuil if (pdata->sd_ram_ddr) { 2558a89bcd4cSHans Verkuil /* SDP setup for the AD eval board */ 2559a89bcd4cSHans Verkuil sdp_io_write(sd, 0x6f, 0x00); /* DDR mode */ 2560a89bcd4cSHans Verkuil sdp_io_write(sd, 0x75, 0x0a); /* 128 MB memory size */ 2561a89bcd4cSHans Verkuil sdp_io_write(sd, 0x7a, 0xa5); /* Timing Adjustment */ 2562a89bcd4cSHans Verkuil sdp_io_write(sd, 0x7b, 0x8f); /* Timing Adjustment */ 2563a89bcd4cSHans Verkuil sdp_io_write(sd, 0x60, 0x01); /* SDRAM reset */ 2564a89bcd4cSHans Verkuil } else { 2565a89bcd4cSHans Verkuil sdp_io_write(sd, 0x75, 0x0a); /* 64 MB memory size ?*/ 2566a89bcd4cSHans Verkuil sdp_io_write(sd, 0x74, 0x00); /* must be zero for sdr sdram */ 2567a89bcd4cSHans Verkuil sdp_io_write(sd, 0x79, 0x33); /* CAS latency to 3, 2568a89bcd4cSHans Verkuil depends on memory */ 2569a89bcd4cSHans Verkuil sdp_io_write(sd, 0x6f, 0x01); /* SDR mode */ 2570a89bcd4cSHans Verkuil sdp_io_write(sd, 0x7a, 0xa5); /* Timing Adjustment */ 2571a89bcd4cSHans Verkuil sdp_io_write(sd, 0x7b, 0x8f); /* Timing Adjustment */ 2572a89bcd4cSHans Verkuil sdp_io_write(sd, 0x60, 0x01); /* SDRAM reset */ 2573a89bcd4cSHans Verkuil } 2574a89bcd4cSHans Verkuil } else { 2575a89bcd4cSHans Verkuil /* 2576a89bcd4cSHans Verkuil * Manual UG-214, rev 0 is bit confusing on this bit 2577a89bcd4cSHans Verkuil * but a '1' disables any signal if the Ram is active. 2578a89bcd4cSHans Verkuil */ 2579a89bcd4cSHans Verkuil sdp_io_write(sd, 0x29, 0x10); /* Tristate memory interface */ 2580a89bcd4cSHans Verkuil } 2581a89bcd4cSHans Verkuil 2582a89bcd4cSHans Verkuil select_input(sd, pdata->vid_std_select); 2583a89bcd4cSHans Verkuil 2584a89bcd4cSHans Verkuil enable_input(sd); 2585a89bcd4cSHans Verkuil 2586a89bcd4cSHans Verkuil /* disable I2C access to internal EDID ram from HDMI DDC ports */ 2587a89bcd4cSHans Verkuil rep_write_and_or(sd, 0x77, 0xf3, 0x00); 2588a89bcd4cSHans Verkuil 2589a89bcd4cSHans Verkuil hdmi_write(sd, 0x69, 0xa3); /* HPA manual */ 2590a89bcd4cSHans Verkuil /* HPA disable on port A and B */ 2591a89bcd4cSHans Verkuil io_write_and_or(sd, 0x20, 0xcf, 0x00); 2592a89bcd4cSHans Verkuil 2593a89bcd4cSHans Verkuil /* LLC */ 2594a89bcd4cSHans Verkuil /* Set phase to 16. TODO: get this from platform_data */ 2595a89bcd4cSHans Verkuil io_write(sd, 0x19, 0x90); 2596a89bcd4cSHans Verkuil io_write(sd, 0x33, 0x40); 2597a89bcd4cSHans Verkuil 2598a89bcd4cSHans Verkuil /* interrupts */ 2599c9f1f271SMartin Bugge io_write(sd, 0x40, 0xf2); /* Configure INT1 */ 2600a89bcd4cSHans Verkuil 2601a89bcd4cSHans Verkuil adv7842_irq_enable(sd, true); 2602a89bcd4cSHans Verkuil 2603a89bcd4cSHans Verkuil return v4l2_ctrl_handler_setup(sd->ctrl_handler); 2604a89bcd4cSHans Verkuil } 2605a89bcd4cSHans Verkuil 2606a89bcd4cSHans Verkuil /* ----------------------------------------------------------------------- */ 2607a89bcd4cSHans Verkuil 2608a89bcd4cSHans Verkuil static int adv7842_ddr_ram_test(struct v4l2_subdev *sd) 2609a89bcd4cSHans Verkuil { 2610a89bcd4cSHans Verkuil /* 2611a89bcd4cSHans Verkuil * From ADV784x external Memory test.pdf 2612a89bcd4cSHans Verkuil * 2613a89bcd4cSHans Verkuil * Reset must just been performed before running test. 2614a89bcd4cSHans Verkuil * Recommended to reset after test. 2615a89bcd4cSHans Verkuil */ 2616a89bcd4cSHans Verkuil int i; 2617a89bcd4cSHans Verkuil int pass = 0; 2618a89bcd4cSHans Verkuil int fail = 0; 2619a89bcd4cSHans Verkuil int complete = 0; 2620a89bcd4cSHans Verkuil 2621a89bcd4cSHans Verkuil io_write(sd, 0x00, 0x01); /* Program SDP 4x1 */ 2622a89bcd4cSHans Verkuil io_write(sd, 0x01, 0x00); /* Program SDP mode */ 2623a89bcd4cSHans Verkuil afe_write(sd, 0x80, 0x92); /* SDP Recommeneded Write */ 2624a89bcd4cSHans Verkuil afe_write(sd, 0x9B, 0x01); /* SDP Recommeneded Write ADV7844ES1 */ 2625a89bcd4cSHans Verkuil afe_write(sd, 0x9C, 0x60); /* SDP Recommeneded Write ADV7844ES1 */ 2626a89bcd4cSHans Verkuil afe_write(sd, 0x9E, 0x02); /* SDP Recommeneded Write ADV7844ES1 */ 2627a89bcd4cSHans Verkuil afe_write(sd, 0xA0, 0x0B); /* SDP Recommeneded Write ADV7844ES1 */ 2628a89bcd4cSHans Verkuil afe_write(sd, 0xC3, 0x02); /* Memory BIST Initialisation */ 2629a89bcd4cSHans Verkuil io_write(sd, 0x0C, 0x40); /* Power up ADV7844 */ 2630a89bcd4cSHans Verkuil io_write(sd, 0x15, 0xBA); /* Enable outputs */ 2631a89bcd4cSHans Verkuil sdp_write(sd, 0x12, 0x00); /* Disable 3D comb, Frame TBC & 3DNR */ 2632a89bcd4cSHans Verkuil io_write(sd, 0xFF, 0x04); /* Reset memory controller */ 2633a89bcd4cSHans Verkuil 2634a89bcd4cSHans Verkuil mdelay(5); 2635a89bcd4cSHans Verkuil 2636a89bcd4cSHans Verkuil sdp_write(sd, 0x12, 0x00); /* Disable 3D Comb, Frame TBC & 3DNR */ 2637a89bcd4cSHans Verkuil sdp_io_write(sd, 0x2A, 0x01); /* Memory BIST Initialisation */ 2638a89bcd4cSHans Verkuil sdp_io_write(sd, 0x7c, 0x19); /* Memory BIST Initialisation */ 2639a89bcd4cSHans Verkuil sdp_io_write(sd, 0x80, 0x87); /* Memory BIST Initialisation */ 2640a89bcd4cSHans Verkuil sdp_io_write(sd, 0x81, 0x4a); /* Memory BIST Initialisation */ 2641a89bcd4cSHans Verkuil sdp_io_write(sd, 0x82, 0x2c); /* Memory BIST Initialisation */ 2642a89bcd4cSHans Verkuil sdp_io_write(sd, 0x83, 0x0e); /* Memory BIST Initialisation */ 2643a89bcd4cSHans Verkuil sdp_io_write(sd, 0x84, 0x94); /* Memory BIST Initialisation */ 2644a89bcd4cSHans Verkuil sdp_io_write(sd, 0x85, 0x62); /* Memory BIST Initialisation */ 2645a89bcd4cSHans Verkuil sdp_io_write(sd, 0x7d, 0x00); /* Memory BIST Initialisation */ 2646a89bcd4cSHans Verkuil sdp_io_write(sd, 0x7e, 0x1a); /* Memory BIST Initialisation */ 2647a89bcd4cSHans Verkuil 2648a89bcd4cSHans Verkuil mdelay(5); 2649a89bcd4cSHans Verkuil 2650a89bcd4cSHans Verkuil sdp_io_write(sd, 0xd9, 0xd5); /* Enable BIST Test */ 2651a89bcd4cSHans Verkuil sdp_write(sd, 0x12, 0x05); /* Enable FRAME TBC & 3D COMB */ 2652a89bcd4cSHans Verkuil 2653a89bcd4cSHans Verkuil mdelay(20); 2654a89bcd4cSHans Verkuil 2655a89bcd4cSHans Verkuil for (i = 0; i < 10; i++) { 2656a89bcd4cSHans Verkuil u8 result = sdp_io_read(sd, 0xdb); 2657a89bcd4cSHans Verkuil if (result & 0x10) { 2658a89bcd4cSHans Verkuil complete++; 2659a89bcd4cSHans Verkuil if (result & 0x20) 2660a89bcd4cSHans Verkuil fail++; 2661a89bcd4cSHans Verkuil else 2662a89bcd4cSHans Verkuil pass++; 2663a89bcd4cSHans Verkuil } 2664a89bcd4cSHans Verkuil mdelay(20); 2665a89bcd4cSHans Verkuil } 2666a89bcd4cSHans Verkuil 2667a89bcd4cSHans Verkuil v4l2_dbg(1, debug, sd, 2668a89bcd4cSHans Verkuil "Ram Test: completed %d of %d: pass %d, fail %d\n", 2669a89bcd4cSHans Verkuil complete, i, pass, fail); 2670a89bcd4cSHans Verkuil 2671a89bcd4cSHans Verkuil if (!complete || fail) 2672a89bcd4cSHans Verkuil return -EIO; 2673a89bcd4cSHans Verkuil return 0; 2674a89bcd4cSHans Verkuil } 2675a89bcd4cSHans Verkuil 2676a89bcd4cSHans Verkuil static void adv7842_rewrite_i2c_addresses(struct v4l2_subdev *sd, 2677a89bcd4cSHans Verkuil struct adv7842_platform_data *pdata) 2678a89bcd4cSHans Verkuil { 2679a89bcd4cSHans Verkuil io_write(sd, 0xf1, pdata->i2c_sdp << 1); 2680a89bcd4cSHans Verkuil io_write(sd, 0xf2, pdata->i2c_sdp_io << 1); 2681a89bcd4cSHans Verkuil io_write(sd, 0xf3, pdata->i2c_avlink << 1); 2682a89bcd4cSHans Verkuil io_write(sd, 0xf4, pdata->i2c_cec << 1); 2683a89bcd4cSHans Verkuil io_write(sd, 0xf5, pdata->i2c_infoframe << 1); 2684a89bcd4cSHans Verkuil 2685a89bcd4cSHans Verkuil io_write(sd, 0xf8, pdata->i2c_afe << 1); 2686a89bcd4cSHans Verkuil io_write(sd, 0xf9, pdata->i2c_repeater << 1); 2687a89bcd4cSHans Verkuil io_write(sd, 0xfa, pdata->i2c_edid << 1); 2688a89bcd4cSHans Verkuil io_write(sd, 0xfb, pdata->i2c_hdmi << 1); 2689a89bcd4cSHans Verkuil 2690a89bcd4cSHans Verkuil io_write(sd, 0xfd, pdata->i2c_cp << 1); 2691a89bcd4cSHans Verkuil io_write(sd, 0xfe, pdata->i2c_vdp << 1); 2692a89bcd4cSHans Verkuil } 2693a89bcd4cSHans Verkuil 2694a89bcd4cSHans Verkuil static int adv7842_command_ram_test(struct v4l2_subdev *sd) 2695a89bcd4cSHans Verkuil { 2696a89bcd4cSHans Verkuil struct i2c_client *client = v4l2_get_subdevdata(sd); 2697a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 2698a89bcd4cSHans Verkuil struct adv7842_platform_data *pdata = client->dev.platform_data; 2699a89bcd4cSHans Verkuil int ret = 0; 2700a89bcd4cSHans Verkuil 2701a89bcd4cSHans Verkuil if (!pdata) 2702a89bcd4cSHans Verkuil return -ENODEV; 2703a89bcd4cSHans Verkuil 2704a89bcd4cSHans Verkuil if (!pdata->sd_ram_size || !pdata->sd_ram_ddr) { 2705a89bcd4cSHans Verkuil v4l2_info(sd, "no sdram or no ddr sdram\n"); 2706a89bcd4cSHans Verkuil return -EINVAL; 2707a89bcd4cSHans Verkuil } 2708a89bcd4cSHans Verkuil 2709a89bcd4cSHans Verkuil main_reset(sd); 2710a89bcd4cSHans Verkuil 2711a89bcd4cSHans Verkuil adv7842_rewrite_i2c_addresses(sd, pdata); 2712a89bcd4cSHans Verkuil 2713a89bcd4cSHans Verkuil /* run ram test */ 2714a89bcd4cSHans Verkuil ret = adv7842_ddr_ram_test(sd); 2715a89bcd4cSHans Verkuil 2716a89bcd4cSHans Verkuil main_reset(sd); 2717a89bcd4cSHans Verkuil 2718a89bcd4cSHans Verkuil adv7842_rewrite_i2c_addresses(sd, pdata); 2719a89bcd4cSHans Verkuil 2720a89bcd4cSHans Verkuil /* and re-init chip and state */ 272169e9ba6fSHans Verkuil adv7842_core_init(sd); 2722a89bcd4cSHans Verkuil 2723a89bcd4cSHans Verkuil disable_input(sd); 2724a89bcd4cSHans Verkuil 2725a89bcd4cSHans Verkuil select_input(sd, state->vid_std_select); 2726a89bcd4cSHans Verkuil 2727a89bcd4cSHans Verkuil enable_input(sd); 2728a89bcd4cSHans Verkuil 2729a89bcd4cSHans Verkuil adv7842_s_dv_timings(sd, &state->timings); 2730a89bcd4cSHans Verkuil 2731a89bcd4cSHans Verkuil edid_write_vga_segment(sd); 2732fc2e991eSMartin Bugge edid_write_hdmi_segment(sd, ADV7842_EDID_PORT_A); 2733fc2e991eSMartin Bugge edid_write_hdmi_segment(sd, ADV7842_EDID_PORT_B); 2734a89bcd4cSHans Verkuil 2735a89bcd4cSHans Verkuil return ret; 2736a89bcd4cSHans Verkuil } 2737a89bcd4cSHans Verkuil 2738a89bcd4cSHans Verkuil static long adv7842_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) 2739a89bcd4cSHans Verkuil { 2740a89bcd4cSHans Verkuil switch (cmd) { 2741a89bcd4cSHans Verkuil case ADV7842_CMD_RAM_TEST: 2742a89bcd4cSHans Verkuil return adv7842_command_ram_test(sd); 2743a89bcd4cSHans Verkuil } 2744a89bcd4cSHans Verkuil return -ENOTTY; 2745a89bcd4cSHans Verkuil } 2746a89bcd4cSHans Verkuil 2747a89bcd4cSHans Verkuil /* ----------------------------------------------------------------------- */ 2748a89bcd4cSHans Verkuil 2749a89bcd4cSHans Verkuil static const struct v4l2_ctrl_ops adv7842_ctrl_ops = { 2750a89bcd4cSHans Verkuil .s_ctrl = adv7842_s_ctrl, 2751a89bcd4cSHans Verkuil }; 2752a89bcd4cSHans Verkuil 2753a89bcd4cSHans Verkuil static const struct v4l2_subdev_core_ops adv7842_core_ops = { 2754a89bcd4cSHans Verkuil .log_status = adv7842_log_status, 2755a89bcd4cSHans Verkuil .g_std = adv7842_g_std, 2756a89bcd4cSHans Verkuil .s_std = adv7842_s_std, 2757a89bcd4cSHans Verkuil .ioctl = adv7842_ioctl, 2758a89bcd4cSHans Verkuil .interrupt_service_routine = adv7842_isr, 2759a89bcd4cSHans Verkuil #ifdef CONFIG_VIDEO_ADV_DEBUG 2760a89bcd4cSHans Verkuil .g_register = adv7842_g_register, 2761a89bcd4cSHans Verkuil .s_register = adv7842_s_register, 2762a89bcd4cSHans Verkuil #endif 2763a89bcd4cSHans Verkuil }; 2764a89bcd4cSHans Verkuil 2765a89bcd4cSHans Verkuil static const struct v4l2_subdev_video_ops adv7842_video_ops = { 2766a89bcd4cSHans Verkuil .s_routing = adv7842_s_routing, 2767a89bcd4cSHans Verkuil .querystd = adv7842_querystd, 2768a89bcd4cSHans Verkuil .g_input_status = adv7842_g_input_status, 2769a89bcd4cSHans Verkuil .s_dv_timings = adv7842_s_dv_timings, 2770a89bcd4cSHans Verkuil .g_dv_timings = adv7842_g_dv_timings, 2771a89bcd4cSHans Verkuil .query_dv_timings = adv7842_query_dv_timings, 2772a89bcd4cSHans Verkuil .enum_dv_timings = adv7842_enum_dv_timings, 2773a89bcd4cSHans Verkuil .dv_timings_cap = adv7842_dv_timings_cap, 2774a89bcd4cSHans Verkuil .enum_mbus_fmt = adv7842_enum_mbus_fmt, 2775a89bcd4cSHans Verkuil .g_mbus_fmt = adv7842_g_mbus_fmt, 2776a89bcd4cSHans Verkuil .try_mbus_fmt = adv7842_g_mbus_fmt, 2777a89bcd4cSHans Verkuil .s_mbus_fmt = adv7842_g_mbus_fmt, 2778a89bcd4cSHans Verkuil }; 2779a89bcd4cSHans Verkuil 2780a89bcd4cSHans Verkuil static const struct v4l2_subdev_pad_ops adv7842_pad_ops = { 2781245b2b67SMartin Bugge .get_edid = adv7842_get_edid, 2782a89bcd4cSHans Verkuil .set_edid = adv7842_set_edid, 2783a89bcd4cSHans Verkuil }; 2784a89bcd4cSHans Verkuil 2785a89bcd4cSHans Verkuil static const struct v4l2_subdev_ops adv7842_ops = { 2786a89bcd4cSHans Verkuil .core = &adv7842_core_ops, 2787a89bcd4cSHans Verkuil .video = &adv7842_video_ops, 2788a89bcd4cSHans Verkuil .pad = &adv7842_pad_ops, 2789a89bcd4cSHans Verkuil }; 2790a89bcd4cSHans Verkuil 2791a89bcd4cSHans Verkuil /* -------------------------- custom ctrls ---------------------------------- */ 2792a89bcd4cSHans Verkuil 2793a89bcd4cSHans Verkuil static const struct v4l2_ctrl_config adv7842_ctrl_analog_sampling_phase = { 2794a89bcd4cSHans Verkuil .ops = &adv7842_ctrl_ops, 2795a89bcd4cSHans Verkuil .id = V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE, 2796a89bcd4cSHans Verkuil .name = "Analog Sampling Phase", 2797a89bcd4cSHans Verkuil .type = V4L2_CTRL_TYPE_INTEGER, 2798a89bcd4cSHans Verkuil .min = 0, 2799a89bcd4cSHans Verkuil .max = 0x1f, 2800a89bcd4cSHans Verkuil .step = 1, 2801a89bcd4cSHans Verkuil .def = 0, 2802a89bcd4cSHans Verkuil }; 2803a89bcd4cSHans Verkuil 2804a89bcd4cSHans Verkuil static const struct v4l2_ctrl_config adv7842_ctrl_free_run_color_manual = { 2805a89bcd4cSHans Verkuil .ops = &adv7842_ctrl_ops, 2806a89bcd4cSHans Verkuil .id = V4L2_CID_ADV_RX_FREE_RUN_COLOR_MANUAL, 2807a89bcd4cSHans Verkuil .name = "Free Running Color, Manual", 2808a89bcd4cSHans Verkuil .type = V4L2_CTRL_TYPE_BOOLEAN, 2809a89bcd4cSHans Verkuil .max = 1, 2810a89bcd4cSHans Verkuil .step = 1, 2811a89bcd4cSHans Verkuil .def = 1, 2812a89bcd4cSHans Verkuil }; 2813a89bcd4cSHans Verkuil 2814a89bcd4cSHans Verkuil static const struct v4l2_ctrl_config adv7842_ctrl_free_run_color = { 2815a89bcd4cSHans Verkuil .ops = &adv7842_ctrl_ops, 2816a89bcd4cSHans Verkuil .id = V4L2_CID_ADV_RX_FREE_RUN_COLOR, 2817a89bcd4cSHans Verkuil .name = "Free Running Color", 2818a89bcd4cSHans Verkuil .type = V4L2_CTRL_TYPE_INTEGER, 2819a89bcd4cSHans Verkuil .max = 0xffffff, 2820a89bcd4cSHans Verkuil .step = 0x1, 2821a89bcd4cSHans Verkuil }; 2822a89bcd4cSHans Verkuil 2823a89bcd4cSHans Verkuil 2824b82e2793SMartin Bugge static void adv7842_unregister_clients(struct v4l2_subdev *sd) 2825a89bcd4cSHans Verkuil { 2826b82e2793SMartin Bugge struct adv7842_state *state = to_state(sd); 2827a89bcd4cSHans Verkuil if (state->i2c_avlink) 2828a89bcd4cSHans Verkuil i2c_unregister_device(state->i2c_avlink); 2829a89bcd4cSHans Verkuil if (state->i2c_cec) 2830a89bcd4cSHans Verkuil i2c_unregister_device(state->i2c_cec); 2831a89bcd4cSHans Verkuil if (state->i2c_infoframe) 2832a89bcd4cSHans Verkuil i2c_unregister_device(state->i2c_infoframe); 2833a89bcd4cSHans Verkuil if (state->i2c_sdp_io) 2834a89bcd4cSHans Verkuil i2c_unregister_device(state->i2c_sdp_io); 2835a89bcd4cSHans Verkuil if (state->i2c_sdp) 2836a89bcd4cSHans Verkuil i2c_unregister_device(state->i2c_sdp); 2837a89bcd4cSHans Verkuil if (state->i2c_afe) 2838a89bcd4cSHans Verkuil i2c_unregister_device(state->i2c_afe); 2839a89bcd4cSHans Verkuil if (state->i2c_repeater) 2840a89bcd4cSHans Verkuil i2c_unregister_device(state->i2c_repeater); 2841a89bcd4cSHans Verkuil if (state->i2c_edid) 2842a89bcd4cSHans Verkuil i2c_unregister_device(state->i2c_edid); 2843a89bcd4cSHans Verkuil if (state->i2c_hdmi) 2844a89bcd4cSHans Verkuil i2c_unregister_device(state->i2c_hdmi); 2845a89bcd4cSHans Verkuil if (state->i2c_cp) 2846a89bcd4cSHans Verkuil i2c_unregister_device(state->i2c_cp); 2847a89bcd4cSHans Verkuil if (state->i2c_vdp) 2848a89bcd4cSHans Verkuil i2c_unregister_device(state->i2c_vdp); 2849b82e2793SMartin Bugge 2850b82e2793SMartin Bugge state->i2c_avlink = NULL; 2851b82e2793SMartin Bugge state->i2c_cec = NULL; 2852b82e2793SMartin Bugge state->i2c_infoframe = NULL; 2853b82e2793SMartin Bugge state->i2c_sdp_io = NULL; 2854b82e2793SMartin Bugge state->i2c_sdp = NULL; 2855b82e2793SMartin Bugge state->i2c_afe = NULL; 2856b82e2793SMartin Bugge state->i2c_repeater = NULL; 2857b82e2793SMartin Bugge state->i2c_edid = NULL; 2858b82e2793SMartin Bugge state->i2c_hdmi = NULL; 2859b82e2793SMartin Bugge state->i2c_cp = NULL; 2860b82e2793SMartin Bugge state->i2c_vdp = NULL; 2861a89bcd4cSHans Verkuil } 2862a89bcd4cSHans Verkuil 2863b82e2793SMartin Bugge static struct i2c_client *adv7842_dummy_client(struct v4l2_subdev *sd, const char *desc, 2864a89bcd4cSHans Verkuil u8 addr, u8 io_reg) 2865a89bcd4cSHans Verkuil { 2866a89bcd4cSHans Verkuil struct i2c_client *client = v4l2_get_subdevdata(sd); 2867b82e2793SMartin Bugge struct i2c_client *cp; 2868a89bcd4cSHans Verkuil 2869a89bcd4cSHans Verkuil io_write(sd, io_reg, addr << 1); 2870b82e2793SMartin Bugge 2871b82e2793SMartin Bugge if (addr == 0) { 2872b82e2793SMartin Bugge v4l2_err(sd, "no %s i2c addr configured\n", desc); 2873b82e2793SMartin Bugge return NULL; 2874b82e2793SMartin Bugge } 2875b82e2793SMartin Bugge 2876b82e2793SMartin Bugge cp = i2c_new_dummy(client->adapter, io_read(sd, io_reg) >> 1); 2877b82e2793SMartin Bugge if (!cp) 2878b82e2793SMartin Bugge v4l2_err(sd, "register %s on i2c addr 0x%x failed\n", desc, addr); 2879b82e2793SMartin Bugge 2880b82e2793SMartin Bugge return cp; 2881b82e2793SMartin Bugge } 2882b82e2793SMartin Bugge 2883b82e2793SMartin Bugge static int adv7842_register_clients(struct v4l2_subdev *sd) 2884b82e2793SMartin Bugge { 2885b82e2793SMartin Bugge struct adv7842_state *state = to_state(sd); 2886b82e2793SMartin Bugge struct adv7842_platform_data *pdata = &state->pdata; 2887b82e2793SMartin Bugge 2888b82e2793SMartin Bugge state->i2c_avlink = adv7842_dummy_client(sd, "avlink", pdata->i2c_avlink, 0xf3); 2889b82e2793SMartin Bugge state->i2c_cec = adv7842_dummy_client(sd, "cec", pdata->i2c_cec, 0xf4); 2890b82e2793SMartin Bugge state->i2c_infoframe = adv7842_dummy_client(sd, "infoframe", pdata->i2c_infoframe, 0xf5); 2891b82e2793SMartin Bugge state->i2c_sdp_io = adv7842_dummy_client(sd, "sdp_io", pdata->i2c_sdp_io, 0xf2); 2892b82e2793SMartin Bugge state->i2c_sdp = adv7842_dummy_client(sd, "sdp", pdata->i2c_sdp, 0xf1); 2893b82e2793SMartin Bugge state->i2c_afe = adv7842_dummy_client(sd, "afe", pdata->i2c_afe, 0xf8); 2894b82e2793SMartin Bugge state->i2c_repeater = adv7842_dummy_client(sd, "repeater", pdata->i2c_repeater, 0xf9); 2895b82e2793SMartin Bugge state->i2c_edid = adv7842_dummy_client(sd, "edid", pdata->i2c_edid, 0xfa); 2896b82e2793SMartin Bugge state->i2c_hdmi = adv7842_dummy_client(sd, "hdmi", pdata->i2c_hdmi, 0xfb); 2897b82e2793SMartin Bugge state->i2c_cp = adv7842_dummy_client(sd, "cp", pdata->i2c_cp, 0xfd); 2898b82e2793SMartin Bugge state->i2c_vdp = adv7842_dummy_client(sd, "vdp", pdata->i2c_vdp, 0xfe); 2899b82e2793SMartin Bugge 2900b82e2793SMartin Bugge if (!state->i2c_avlink || 2901b82e2793SMartin Bugge !state->i2c_cec || 2902b82e2793SMartin Bugge !state->i2c_infoframe || 2903b82e2793SMartin Bugge !state->i2c_sdp_io || 2904b82e2793SMartin Bugge !state->i2c_sdp || 2905b82e2793SMartin Bugge !state->i2c_afe || 2906b82e2793SMartin Bugge !state->i2c_repeater || 2907b82e2793SMartin Bugge !state->i2c_edid || 2908b82e2793SMartin Bugge !state->i2c_hdmi || 2909b82e2793SMartin Bugge !state->i2c_cp || 2910b82e2793SMartin Bugge !state->i2c_vdp) 2911b82e2793SMartin Bugge return -1; 2912b82e2793SMartin Bugge 2913b82e2793SMartin Bugge return 0; 2914a89bcd4cSHans Verkuil } 2915a89bcd4cSHans Verkuil 2916a89bcd4cSHans Verkuil static int adv7842_probe(struct i2c_client *client, 2917a89bcd4cSHans Verkuil const struct i2c_device_id *id) 2918a89bcd4cSHans Verkuil { 2919a89bcd4cSHans Verkuil struct adv7842_state *state; 2920a89bcd4cSHans Verkuil struct adv7842_platform_data *pdata = client->dev.platform_data; 2921a89bcd4cSHans Verkuil struct v4l2_ctrl_handler *hdl; 2922a89bcd4cSHans Verkuil struct v4l2_subdev *sd; 2923a89bcd4cSHans Verkuil u16 rev; 2924a89bcd4cSHans Verkuil int err; 2925a89bcd4cSHans Verkuil 2926a89bcd4cSHans Verkuil /* Check if the adapter supports the needed features */ 2927a89bcd4cSHans Verkuil if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 2928a89bcd4cSHans Verkuil return -EIO; 2929a89bcd4cSHans Verkuil 2930a89bcd4cSHans Verkuil v4l_dbg(1, debug, client, "detecting adv7842 client on address 0x%x\n", 2931a89bcd4cSHans Verkuil client->addr << 1); 2932a89bcd4cSHans Verkuil 2933a89bcd4cSHans Verkuil if (!pdata) { 2934a89bcd4cSHans Verkuil v4l_err(client, "No platform data!\n"); 2935a89bcd4cSHans Verkuil return -ENODEV; 2936a89bcd4cSHans Verkuil } 2937a89bcd4cSHans Verkuil 2938a89bcd4cSHans Verkuil state = devm_kzalloc(&client->dev, sizeof(struct adv7842_state), GFP_KERNEL); 2939a89bcd4cSHans Verkuil if (!state) { 2940a89bcd4cSHans Verkuil v4l_err(client, "Could not allocate adv7842_state memory!\n"); 2941a89bcd4cSHans Verkuil return -ENOMEM; 2942a89bcd4cSHans Verkuil } 2943a89bcd4cSHans Verkuil 29447de5be44SMartin Bugge /* platform data */ 29457de5be44SMartin Bugge state->pdata = *pdata; 29467de5be44SMartin Bugge 2947a89bcd4cSHans Verkuil sd = &state->sd; 2948a89bcd4cSHans Verkuil v4l2_i2c_subdev_init(sd, client, &adv7842_ops); 2949a89bcd4cSHans Verkuil sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 2950a89bcd4cSHans Verkuil state->mode = pdata->mode; 2951a89bcd4cSHans Verkuil 29528e4e3631SMartin Bugge state->hdmi_port_a = pdata->input == ADV7842_SELECT_HDMI_PORT_A; 29536e9071f2SMartin Bugge state->restart_stdi_once = true; 2954a89bcd4cSHans Verkuil 2955a89bcd4cSHans Verkuil /* i2c access to adv7842? */ 2956a89bcd4cSHans Verkuil rev = adv_smbus_read_byte_data_check(client, 0xea, false) << 8 | 2957a89bcd4cSHans Verkuil adv_smbus_read_byte_data_check(client, 0xeb, false); 2958a89bcd4cSHans Verkuil if (rev != 0x2012) { 2959a89bcd4cSHans Verkuil v4l2_info(sd, "got rev=0x%04x on first read attempt\n", rev); 2960a89bcd4cSHans Verkuil rev = adv_smbus_read_byte_data_check(client, 0xea, false) << 8 | 2961a89bcd4cSHans Verkuil adv_smbus_read_byte_data_check(client, 0xeb, false); 2962a89bcd4cSHans Verkuil } 2963a89bcd4cSHans Verkuil if (rev != 0x2012) { 2964a89bcd4cSHans Verkuil v4l2_info(sd, "not an adv7842 on address 0x%x (rev=0x%04x)\n", 2965a89bcd4cSHans Verkuil client->addr << 1, rev); 2966a89bcd4cSHans Verkuil return -ENODEV; 2967a89bcd4cSHans Verkuil } 2968a89bcd4cSHans Verkuil 2969a89bcd4cSHans Verkuil if (pdata->chip_reset) 2970a89bcd4cSHans Verkuil main_reset(sd); 2971a89bcd4cSHans Verkuil 2972a89bcd4cSHans Verkuil /* control handlers */ 2973a89bcd4cSHans Verkuil hdl = &state->hdl; 2974a89bcd4cSHans Verkuil v4l2_ctrl_handler_init(hdl, 6); 2975a89bcd4cSHans Verkuil 2976a89bcd4cSHans Verkuil /* add in ascending ID order */ 2977a89bcd4cSHans Verkuil v4l2_ctrl_new_std(hdl, &adv7842_ctrl_ops, 2978a89bcd4cSHans Verkuil V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); 2979a89bcd4cSHans Verkuil v4l2_ctrl_new_std(hdl, &adv7842_ctrl_ops, 2980a89bcd4cSHans Verkuil V4L2_CID_CONTRAST, 0, 255, 1, 128); 2981a89bcd4cSHans Verkuil v4l2_ctrl_new_std(hdl, &adv7842_ctrl_ops, 2982a89bcd4cSHans Verkuil V4L2_CID_SATURATION, 0, 255, 1, 128); 2983a89bcd4cSHans Verkuil v4l2_ctrl_new_std(hdl, &adv7842_ctrl_ops, 2984a89bcd4cSHans Verkuil V4L2_CID_HUE, 0, 128, 1, 0); 2985a89bcd4cSHans Verkuil 2986a89bcd4cSHans Verkuil /* custom controls */ 2987a89bcd4cSHans Verkuil state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL, 2988a89bcd4cSHans Verkuil V4L2_CID_DV_RX_POWER_PRESENT, 0, 3, 0, 0); 2989a89bcd4cSHans Verkuil state->analog_sampling_phase_ctrl = v4l2_ctrl_new_custom(hdl, 2990a89bcd4cSHans Verkuil &adv7842_ctrl_analog_sampling_phase, NULL); 2991a89bcd4cSHans Verkuil state->free_run_color_ctrl_manual = v4l2_ctrl_new_custom(hdl, 2992a89bcd4cSHans Verkuil &adv7842_ctrl_free_run_color_manual, NULL); 2993a89bcd4cSHans Verkuil state->free_run_color_ctrl = v4l2_ctrl_new_custom(hdl, 2994a89bcd4cSHans Verkuil &adv7842_ctrl_free_run_color, NULL); 2995a89bcd4cSHans Verkuil state->rgb_quantization_range_ctrl = 2996a89bcd4cSHans Verkuil v4l2_ctrl_new_std_menu(hdl, &adv7842_ctrl_ops, 2997a89bcd4cSHans Verkuil V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, 2998a89bcd4cSHans Verkuil 0, V4L2_DV_RGB_RANGE_AUTO); 2999a89bcd4cSHans Verkuil sd->ctrl_handler = hdl; 3000a89bcd4cSHans Verkuil if (hdl->error) { 3001a89bcd4cSHans Verkuil err = hdl->error; 3002a89bcd4cSHans Verkuil goto err_hdl; 3003a89bcd4cSHans Verkuil } 3004a89bcd4cSHans Verkuil state->detect_tx_5v_ctrl->is_private = true; 3005a89bcd4cSHans Verkuil state->rgb_quantization_range_ctrl->is_private = true; 3006a89bcd4cSHans Verkuil state->analog_sampling_phase_ctrl->is_private = true; 3007a89bcd4cSHans Verkuil state->free_run_color_ctrl_manual->is_private = true; 3008a89bcd4cSHans Verkuil state->free_run_color_ctrl->is_private = true; 3009a89bcd4cSHans Verkuil 3010a89bcd4cSHans Verkuil if (adv7842_s_detect_tx_5v_ctrl(sd)) { 3011a89bcd4cSHans Verkuil err = -ENODEV; 3012a89bcd4cSHans Verkuil goto err_hdl; 3013a89bcd4cSHans Verkuil } 3014a89bcd4cSHans Verkuil 3015b82e2793SMartin Bugge if (adv7842_register_clients(sd) < 0) { 3016a89bcd4cSHans Verkuil err = -ENOMEM; 3017a89bcd4cSHans Verkuil v4l2_err(sd, "failed to create all i2c clients\n"); 3018a89bcd4cSHans Verkuil goto err_i2c; 3019a89bcd4cSHans Verkuil } 3020a89bcd4cSHans Verkuil 3021a89bcd4cSHans Verkuil /* work queues */ 3022a89bcd4cSHans Verkuil state->work_queues = create_singlethread_workqueue(client->name); 3023a89bcd4cSHans Verkuil if (!state->work_queues) { 3024a89bcd4cSHans Verkuil v4l2_err(sd, "Could not create work queue\n"); 3025a89bcd4cSHans Verkuil err = -ENOMEM; 3026a89bcd4cSHans Verkuil goto err_i2c; 3027a89bcd4cSHans Verkuil } 3028a89bcd4cSHans Verkuil 3029a89bcd4cSHans Verkuil INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug, 3030a89bcd4cSHans Verkuil adv7842_delayed_work_enable_hotplug); 3031a89bcd4cSHans Verkuil 3032a89bcd4cSHans Verkuil state->pad.flags = MEDIA_PAD_FL_SOURCE; 3033a89bcd4cSHans Verkuil err = media_entity_init(&sd->entity, 1, &state->pad, 0); 3034a89bcd4cSHans Verkuil if (err) 3035a89bcd4cSHans Verkuil goto err_work_queues; 3036a89bcd4cSHans Verkuil 30377de5be44SMartin Bugge err = adv7842_core_init(sd); 3038a89bcd4cSHans Verkuil if (err) 3039a89bcd4cSHans Verkuil goto err_entity; 3040a89bcd4cSHans Verkuil 3041a89bcd4cSHans Verkuil v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, 3042a89bcd4cSHans Verkuil client->addr << 1, client->adapter->name); 3043a89bcd4cSHans Verkuil return 0; 3044a89bcd4cSHans Verkuil 3045a89bcd4cSHans Verkuil err_entity: 3046a89bcd4cSHans Verkuil media_entity_cleanup(&sd->entity); 3047a89bcd4cSHans Verkuil err_work_queues: 3048a89bcd4cSHans Verkuil cancel_delayed_work(&state->delayed_work_enable_hotplug); 3049a89bcd4cSHans Verkuil destroy_workqueue(state->work_queues); 3050a89bcd4cSHans Verkuil err_i2c: 3051b82e2793SMartin Bugge adv7842_unregister_clients(sd); 3052a89bcd4cSHans Verkuil err_hdl: 3053a89bcd4cSHans Verkuil v4l2_ctrl_handler_free(hdl); 3054a89bcd4cSHans Verkuil return err; 3055a89bcd4cSHans Verkuil } 3056a89bcd4cSHans Verkuil 3057a89bcd4cSHans Verkuil /* ----------------------------------------------------------------------- */ 3058a89bcd4cSHans Verkuil 3059a89bcd4cSHans Verkuil static int adv7842_remove(struct i2c_client *client) 3060a89bcd4cSHans Verkuil { 3061a89bcd4cSHans Verkuil struct v4l2_subdev *sd = i2c_get_clientdata(client); 3062a89bcd4cSHans Verkuil struct adv7842_state *state = to_state(sd); 3063a89bcd4cSHans Verkuil 3064a89bcd4cSHans Verkuil adv7842_irq_enable(sd, false); 3065a89bcd4cSHans Verkuil 3066a89bcd4cSHans Verkuil cancel_delayed_work(&state->delayed_work_enable_hotplug); 3067a89bcd4cSHans Verkuil destroy_workqueue(state->work_queues); 3068a89bcd4cSHans Verkuil v4l2_device_unregister_subdev(sd); 3069a89bcd4cSHans Verkuil media_entity_cleanup(&sd->entity); 3070b82e2793SMartin Bugge adv7842_unregister_clients(sd); 3071a89bcd4cSHans Verkuil v4l2_ctrl_handler_free(sd->ctrl_handler); 3072a89bcd4cSHans Verkuil return 0; 3073a89bcd4cSHans Verkuil } 3074a89bcd4cSHans Verkuil 3075a89bcd4cSHans Verkuil /* ----------------------------------------------------------------------- */ 3076a89bcd4cSHans Verkuil 3077a89bcd4cSHans Verkuil static struct i2c_device_id adv7842_id[] = { 3078a89bcd4cSHans Verkuil { "adv7842", 0 }, 3079a89bcd4cSHans Verkuil { } 3080a89bcd4cSHans Verkuil }; 3081a89bcd4cSHans Verkuil MODULE_DEVICE_TABLE(i2c, adv7842_id); 3082a89bcd4cSHans Verkuil 3083a89bcd4cSHans Verkuil /* ----------------------------------------------------------------------- */ 3084a89bcd4cSHans Verkuil 3085a89bcd4cSHans Verkuil static struct i2c_driver adv7842_driver = { 3086a89bcd4cSHans Verkuil .driver = { 3087a89bcd4cSHans Verkuil .owner = THIS_MODULE, 3088a89bcd4cSHans Verkuil .name = "adv7842", 3089a89bcd4cSHans Verkuil }, 3090a89bcd4cSHans Verkuil .probe = adv7842_probe, 3091a89bcd4cSHans Verkuil .remove = adv7842_remove, 3092a89bcd4cSHans Verkuil .id_table = adv7842_id, 3093a89bcd4cSHans Verkuil }; 3094a89bcd4cSHans Verkuil 3095a89bcd4cSHans Verkuil module_i2c_driver(adv7842_driver); 3096