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