1d32d9864SMats Randgaard /* 2d32d9864SMats Randgaard * tc358743 - Toshiba HDMI to CSI-2 bridge 3d32d9864SMats Randgaard * 4d32d9864SMats Randgaard * Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights 5d32d9864SMats Randgaard * reserved. 6d32d9864SMats Randgaard * 7d32d9864SMats Randgaard * This program is free software; you may redistribute it and/or modify 8d32d9864SMats Randgaard * it under the terms of the GNU General Public License as published by 9d32d9864SMats Randgaard * the Free Software Foundation; version 2 of the License. 10d32d9864SMats Randgaard * 11d32d9864SMats Randgaard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 12d32d9864SMats Randgaard * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 13d32d9864SMats Randgaard * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 14d32d9864SMats Randgaard * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 15d32d9864SMats Randgaard * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 16d32d9864SMats Randgaard * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 17d32d9864SMats Randgaard * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18d32d9864SMats Randgaard * SOFTWARE. 19d32d9864SMats Randgaard * 20d32d9864SMats Randgaard */ 21d32d9864SMats Randgaard 22d32d9864SMats Randgaard /* 23d32d9864SMats Randgaard * References (c = chapter, p = page): 24d32d9864SMats Randgaard * REF_01 - Toshiba, TC358743XBG (H2C), Functional Specification, Rev 0.60 25d32d9864SMats Randgaard * REF_02 - Toshiba, TC358743XBG_HDMI-CSI_Tv11p_nm.xls 26d32d9864SMats Randgaard */ 27d32d9864SMats Randgaard 28d32d9864SMats Randgaard #include <linux/kernel.h> 29d32d9864SMats Randgaard #include <linux/module.h> 30d32d9864SMats Randgaard #include <linux/slab.h> 31d32d9864SMats Randgaard #include <linux/i2c.h> 32d32d9864SMats Randgaard #include <linux/delay.h> 33d32d9864SMats Randgaard #include <linux/videodev2.h> 34d32d9864SMats Randgaard #include <linux/workqueue.h> 35d32d9864SMats Randgaard #include <linux/v4l2-dv-timings.h> 36d32d9864SMats Randgaard #include <linux/hdmi.h> 37d32d9864SMats Randgaard #include <media/v4l2-dv-timings.h> 38d32d9864SMats Randgaard #include <media/v4l2-device.h> 39d32d9864SMats Randgaard #include <media/v4l2-ctrls.h> 40d32d9864SMats Randgaard #include <media/tc358743.h> 41d32d9864SMats Randgaard 42d32d9864SMats Randgaard #include "tc358743_regs.h" 43d32d9864SMats Randgaard 44d32d9864SMats Randgaard static int debug; 45d32d9864SMats Randgaard module_param(debug, int, 0644); 46d32d9864SMats Randgaard MODULE_PARM_DESC(debug, "debug level (0-3)"); 47d32d9864SMats Randgaard 48d32d9864SMats Randgaard MODULE_DESCRIPTION("Toshiba TC358743 HDMI to CSI-2 bridge driver"); 49d32d9864SMats Randgaard MODULE_AUTHOR("Ramakrishnan Muthukrishnan <ram@rkrishnan.org>"); 50d32d9864SMats Randgaard MODULE_AUTHOR("Mikhail Khelik <mkhelik@cisco.com>"); 51d32d9864SMats Randgaard MODULE_AUTHOR("Mats Randgaard <matrandg@cisco.com>"); 52d32d9864SMats Randgaard MODULE_LICENSE("GPL"); 53d32d9864SMats Randgaard 54d32d9864SMats Randgaard #define EDID_NUM_BLOCKS_MAX 8 55d32d9864SMats Randgaard #define EDID_BLOCK_SIZE 128 56d32d9864SMats Randgaard 57d32d9864SMats Randgaard static const struct v4l2_dv_timings_cap tc358743_timings_cap = { 58d32d9864SMats Randgaard .type = V4L2_DV_BT_656_1120, 59d32d9864SMats Randgaard /* keep this initialization for compatibility with GCC < 4.4.6 */ 60d32d9864SMats Randgaard .reserved = { 0 }, 61d32d9864SMats Randgaard /* Pixel clock from REF_01 p. 20. Min/max height/width are unknown */ 62d32d9864SMats Randgaard V4L2_INIT_BT_TIMINGS(1, 10000, 1, 10000, 0, 165000000, 63d32d9864SMats Randgaard V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | 64d32d9864SMats Randgaard V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT, 65d32d9864SMats Randgaard V4L2_DV_BT_CAP_PROGRESSIVE | 66d32d9864SMats Randgaard V4L2_DV_BT_CAP_REDUCED_BLANKING | 67d32d9864SMats Randgaard V4L2_DV_BT_CAP_CUSTOM) 68d32d9864SMats Randgaard }; 69d32d9864SMats Randgaard 70d32d9864SMats Randgaard struct tc358743_state { 71d32d9864SMats Randgaard struct tc358743_platform_data pdata; 72d32d9864SMats Randgaard struct v4l2_subdev sd; 73d32d9864SMats Randgaard struct media_pad pad; 74d32d9864SMats Randgaard struct v4l2_ctrl_handler hdl; 75d32d9864SMats Randgaard struct i2c_client *i2c_client; 76d32d9864SMats Randgaard /* CONFCTL is modified in ops and tc358743_hdmi_sys_int_handler */ 77d32d9864SMats Randgaard struct mutex confctl_mutex; 78d32d9864SMats Randgaard 79d32d9864SMats Randgaard /* controls */ 80d32d9864SMats Randgaard struct v4l2_ctrl *detect_tx_5v_ctrl; 81d32d9864SMats Randgaard struct v4l2_ctrl *audio_sampling_rate_ctrl; 82d32d9864SMats Randgaard struct v4l2_ctrl *audio_present_ctrl; 83d32d9864SMats Randgaard 84d32d9864SMats Randgaard /* work queues */ 85d32d9864SMats Randgaard struct workqueue_struct *work_queues; 86d32d9864SMats Randgaard struct delayed_work delayed_work_enable_hotplug; 87d32d9864SMats Randgaard 88d32d9864SMats Randgaard /* edid */ 89d32d9864SMats Randgaard u8 edid_blocks_written; 90d32d9864SMats Randgaard 91d32d9864SMats Randgaard struct v4l2_dv_timings timings; 92d32d9864SMats Randgaard u32 mbus_fmt_code; 93d32d9864SMats Randgaard }; 94d32d9864SMats Randgaard 95d32d9864SMats Randgaard static void tc358743_enable_interrupts(struct v4l2_subdev *sd, 96d32d9864SMats Randgaard bool cable_connected); 97d32d9864SMats Randgaard static int tc358743_s_ctrl_detect_tx_5v(struct v4l2_subdev *sd); 98d32d9864SMats Randgaard 99d32d9864SMats Randgaard static inline struct tc358743_state *to_state(struct v4l2_subdev *sd) 100d32d9864SMats Randgaard { 101d32d9864SMats Randgaard return container_of(sd, struct tc358743_state, sd); 102d32d9864SMats Randgaard } 103d32d9864SMats Randgaard 104d32d9864SMats Randgaard /* --------------- I2C --------------- */ 105d32d9864SMats Randgaard 106d32d9864SMats Randgaard static void i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) 107d32d9864SMats Randgaard { 108d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 109d32d9864SMats Randgaard struct i2c_client *client = state->i2c_client; 110d32d9864SMats Randgaard int err; 111d32d9864SMats Randgaard u8 buf[2] = { reg >> 8, reg & 0xff }; 112d32d9864SMats Randgaard struct i2c_msg msgs[] = { 113d32d9864SMats Randgaard { 114d32d9864SMats Randgaard .addr = client->addr, 115d32d9864SMats Randgaard .flags = 0, 116d32d9864SMats Randgaard .len = 2, 117d32d9864SMats Randgaard .buf = buf, 118d32d9864SMats Randgaard }, 119d32d9864SMats Randgaard { 120d32d9864SMats Randgaard .addr = client->addr, 121d32d9864SMats Randgaard .flags = I2C_M_RD, 122d32d9864SMats Randgaard .len = n, 123d32d9864SMats Randgaard .buf = values, 124d32d9864SMats Randgaard }, 125d32d9864SMats Randgaard }; 126d32d9864SMats Randgaard 127d32d9864SMats Randgaard err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 128d32d9864SMats Randgaard if (err != ARRAY_SIZE(msgs)) { 129d32d9864SMats Randgaard v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed\n", 130d32d9864SMats Randgaard __func__, reg, client->addr); 131d32d9864SMats Randgaard } 132d32d9864SMats Randgaard } 133d32d9864SMats Randgaard 134d32d9864SMats Randgaard static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) 135d32d9864SMats Randgaard { 136d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 137d32d9864SMats Randgaard struct i2c_client *client = state->i2c_client; 138d32d9864SMats Randgaard int err, i; 139d32d9864SMats Randgaard struct i2c_msg msg; 140d32d9864SMats Randgaard u8 data[2 + n]; 141d32d9864SMats Randgaard 142d32d9864SMats Randgaard msg.addr = client->addr; 143d32d9864SMats Randgaard msg.buf = data; 144d32d9864SMats Randgaard msg.len = 2 + n; 145d32d9864SMats Randgaard msg.flags = 0; 146d32d9864SMats Randgaard 147d32d9864SMats Randgaard data[0] = reg >> 8; 148d32d9864SMats Randgaard data[1] = reg & 0xff; 149d32d9864SMats Randgaard 150d32d9864SMats Randgaard for (i = 0; i < n; i++) 151d32d9864SMats Randgaard data[2 + i] = values[i]; 152d32d9864SMats Randgaard 153d32d9864SMats Randgaard err = i2c_transfer(client->adapter, &msg, 1); 154d32d9864SMats Randgaard if (err != 1) { 155d32d9864SMats Randgaard v4l2_err(sd, "%s: writing register 0x%x from 0x%x failed\n", 156d32d9864SMats Randgaard __func__, reg, client->addr); 157d32d9864SMats Randgaard return; 158d32d9864SMats Randgaard } 159d32d9864SMats Randgaard 160d32d9864SMats Randgaard if (debug < 3) 161d32d9864SMats Randgaard return; 162d32d9864SMats Randgaard 163d32d9864SMats Randgaard switch (n) { 164d32d9864SMats Randgaard case 1: 165d32d9864SMats Randgaard v4l2_info(sd, "I2C write 0x%04x = 0x%02x", 166d32d9864SMats Randgaard reg, data[2]); 167d32d9864SMats Randgaard break; 168d32d9864SMats Randgaard case 2: 169d32d9864SMats Randgaard v4l2_info(sd, "I2C write 0x%04x = 0x%02x%02x", 170d32d9864SMats Randgaard reg, data[3], data[2]); 171d32d9864SMats Randgaard break; 172d32d9864SMats Randgaard case 4: 173d32d9864SMats Randgaard v4l2_info(sd, "I2C write 0x%04x = 0x%02x%02x%02x%02x", 174d32d9864SMats Randgaard reg, data[5], data[4], data[3], data[2]); 175d32d9864SMats Randgaard break; 176d32d9864SMats Randgaard default: 177d32d9864SMats Randgaard v4l2_info(sd, "I2C write %d bytes from address 0x%04x\n", 178d32d9864SMats Randgaard n, reg); 179d32d9864SMats Randgaard } 180d32d9864SMats Randgaard } 181d32d9864SMats Randgaard 182d32d9864SMats Randgaard static u8 i2c_rd8(struct v4l2_subdev *sd, u16 reg) 183d32d9864SMats Randgaard { 184d32d9864SMats Randgaard u8 val; 185d32d9864SMats Randgaard 186d32d9864SMats Randgaard i2c_rd(sd, reg, &val, 1); 187d32d9864SMats Randgaard 188d32d9864SMats Randgaard return val; 189d32d9864SMats Randgaard } 190d32d9864SMats Randgaard 191d32d9864SMats Randgaard static void i2c_wr8(struct v4l2_subdev *sd, u16 reg, u8 val) 192d32d9864SMats Randgaard { 193d32d9864SMats Randgaard i2c_wr(sd, reg, &val, 1); 194d32d9864SMats Randgaard } 195d32d9864SMats Randgaard 196d32d9864SMats Randgaard static void i2c_wr8_and_or(struct v4l2_subdev *sd, u16 reg, 197d32d9864SMats Randgaard u8 mask, u8 val) 198d32d9864SMats Randgaard { 199d32d9864SMats Randgaard i2c_wr8(sd, reg, (i2c_rd8(sd, reg) & mask) | val); 200d32d9864SMats Randgaard } 201d32d9864SMats Randgaard 202d32d9864SMats Randgaard static u16 i2c_rd16(struct v4l2_subdev *sd, u16 reg) 203d32d9864SMats Randgaard { 204d32d9864SMats Randgaard u16 val; 205d32d9864SMats Randgaard 206d32d9864SMats Randgaard i2c_rd(sd, reg, (u8 *)&val, 2); 207d32d9864SMats Randgaard 208d32d9864SMats Randgaard return val; 209d32d9864SMats Randgaard } 210d32d9864SMats Randgaard 211d32d9864SMats Randgaard static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val) 212d32d9864SMats Randgaard { 213d32d9864SMats Randgaard i2c_wr(sd, reg, (u8 *)&val, 2); 214d32d9864SMats Randgaard } 215d32d9864SMats Randgaard 216d32d9864SMats Randgaard static void i2c_wr16_and_or(struct v4l2_subdev *sd, u16 reg, u16 mask, u16 val) 217d32d9864SMats Randgaard { 218d32d9864SMats Randgaard i2c_wr16(sd, reg, (i2c_rd16(sd, reg) & mask) | val); 219d32d9864SMats Randgaard } 220d32d9864SMats Randgaard 221d32d9864SMats Randgaard static u32 i2c_rd32(struct v4l2_subdev *sd, u16 reg) 222d32d9864SMats Randgaard { 223d32d9864SMats Randgaard u32 val; 224d32d9864SMats Randgaard 225d32d9864SMats Randgaard i2c_rd(sd, reg, (u8 *)&val, 4); 226d32d9864SMats Randgaard 227d32d9864SMats Randgaard return val; 228d32d9864SMats Randgaard } 229d32d9864SMats Randgaard 230d32d9864SMats Randgaard static void i2c_wr32(struct v4l2_subdev *sd, u16 reg, u32 val) 231d32d9864SMats Randgaard { 232d32d9864SMats Randgaard i2c_wr(sd, reg, (u8 *)&val, 4); 233d32d9864SMats Randgaard } 234d32d9864SMats Randgaard 235d32d9864SMats Randgaard /* --------------- STATUS --------------- */ 236d32d9864SMats Randgaard 237d32d9864SMats Randgaard static inline bool is_hdmi(struct v4l2_subdev *sd) 238d32d9864SMats Randgaard { 239d32d9864SMats Randgaard return i2c_rd8(sd, SYS_STATUS) & MASK_S_HDMI; 240d32d9864SMats Randgaard } 241d32d9864SMats Randgaard 242d32d9864SMats Randgaard static inline bool tx_5v_power_present(struct v4l2_subdev *sd) 243d32d9864SMats Randgaard { 244d32d9864SMats Randgaard return i2c_rd8(sd, SYS_STATUS) & MASK_S_DDC5V; 245d32d9864SMats Randgaard } 246d32d9864SMats Randgaard 247d32d9864SMats Randgaard static inline bool no_signal(struct v4l2_subdev *sd) 248d32d9864SMats Randgaard { 249d32d9864SMats Randgaard return !(i2c_rd8(sd, SYS_STATUS) & MASK_S_TMDS); 250d32d9864SMats Randgaard } 251d32d9864SMats Randgaard 252d32d9864SMats Randgaard static inline bool no_sync(struct v4l2_subdev *sd) 253d32d9864SMats Randgaard { 254d32d9864SMats Randgaard return !(i2c_rd8(sd, SYS_STATUS) & MASK_S_SYNC); 255d32d9864SMats Randgaard } 256d32d9864SMats Randgaard 257d32d9864SMats Randgaard static inline bool audio_present(struct v4l2_subdev *sd) 258d32d9864SMats Randgaard { 259d32d9864SMats Randgaard return i2c_rd8(sd, AU_STATUS0) & MASK_S_A_SAMPLE; 260d32d9864SMats Randgaard } 261d32d9864SMats Randgaard 262d32d9864SMats Randgaard static int get_audio_sampling_rate(struct v4l2_subdev *sd) 263d32d9864SMats Randgaard { 264d32d9864SMats Randgaard static const int code_to_rate[] = { 265d32d9864SMats Randgaard 44100, 0, 48000, 32000, 22050, 384000, 24000, 352800, 266d32d9864SMats Randgaard 88200, 768000, 96000, 705600, 176400, 0, 192000, 0 267d32d9864SMats Randgaard }; 268d32d9864SMats Randgaard 269d32d9864SMats Randgaard /* Register FS_SET is not cleared when the cable is disconnected */ 270d32d9864SMats Randgaard if (no_signal(sd)) 271d32d9864SMats Randgaard return 0; 272d32d9864SMats Randgaard 273d32d9864SMats Randgaard return code_to_rate[i2c_rd8(sd, FS_SET) & MASK_FS]; 274d32d9864SMats Randgaard } 275d32d9864SMats Randgaard 276d32d9864SMats Randgaard static unsigned tc358743_num_csi_lanes_in_use(struct v4l2_subdev *sd) 277d32d9864SMats Randgaard { 278d32d9864SMats Randgaard return ((i2c_rd32(sd, CSI_CONTROL) & MASK_NOL) >> 1) + 1; 279d32d9864SMats Randgaard } 280d32d9864SMats Randgaard 281d32d9864SMats Randgaard /* --------------- TIMINGS --------------- */ 282d32d9864SMats Randgaard 283d32d9864SMats Randgaard static inline unsigned fps(const struct v4l2_bt_timings *t) 284d32d9864SMats Randgaard { 285d32d9864SMats Randgaard if (!V4L2_DV_BT_FRAME_HEIGHT(t) || !V4L2_DV_BT_FRAME_WIDTH(t)) 286d32d9864SMats Randgaard return 0; 287d32d9864SMats Randgaard 288d32d9864SMats Randgaard return DIV_ROUND_CLOSEST((unsigned)t->pixelclock, 289d32d9864SMats Randgaard V4L2_DV_BT_FRAME_HEIGHT(t) * V4L2_DV_BT_FRAME_WIDTH(t)); 290d32d9864SMats Randgaard } 291d32d9864SMats Randgaard 292d32d9864SMats Randgaard static int tc358743_get_detected_timings(struct v4l2_subdev *sd, 293d32d9864SMats Randgaard struct v4l2_dv_timings *timings) 294d32d9864SMats Randgaard { 295d32d9864SMats Randgaard struct v4l2_bt_timings *bt = &timings->bt; 296d32d9864SMats Randgaard unsigned width, height, frame_width, frame_height, frame_interval, fps; 297d32d9864SMats Randgaard 298d32d9864SMats Randgaard memset(timings, 0, sizeof(struct v4l2_dv_timings)); 299d32d9864SMats Randgaard 300d32d9864SMats Randgaard if (no_signal(sd)) { 301d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: no valid signal\n", __func__); 302d32d9864SMats Randgaard return -ENOLINK; 303d32d9864SMats Randgaard } 304d32d9864SMats Randgaard if (no_sync(sd)) { 305d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: no sync on signal\n", __func__); 306d32d9864SMats Randgaard return -ENOLCK; 307d32d9864SMats Randgaard } 308d32d9864SMats Randgaard 309d32d9864SMats Randgaard timings->type = V4L2_DV_BT_656_1120; 310d32d9864SMats Randgaard bt->interlaced = i2c_rd8(sd, VI_STATUS1) & MASK_S_V_INTERLACE ? 311d32d9864SMats Randgaard V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE; 312d32d9864SMats Randgaard 313d32d9864SMats Randgaard width = ((i2c_rd8(sd, DE_WIDTH_H_HI) & 0x1f) << 8) + 314d32d9864SMats Randgaard i2c_rd8(sd, DE_WIDTH_H_LO); 315d32d9864SMats Randgaard height = ((i2c_rd8(sd, DE_WIDTH_V_HI) & 0x1f) << 8) + 316d32d9864SMats Randgaard i2c_rd8(sd, DE_WIDTH_V_LO); 317d32d9864SMats Randgaard frame_width = ((i2c_rd8(sd, H_SIZE_HI) & 0x1f) << 8) + 318d32d9864SMats Randgaard i2c_rd8(sd, H_SIZE_LO); 319d32d9864SMats Randgaard frame_height = (((i2c_rd8(sd, V_SIZE_HI) & 0x3f) << 8) + 320d32d9864SMats Randgaard i2c_rd8(sd, V_SIZE_LO)) / 2; 321d32d9864SMats Randgaard /* frame interval in milliseconds * 10 322d32d9864SMats Randgaard * Require SYS_FREQ0 and SYS_FREQ1 are precisely set */ 323d32d9864SMats Randgaard frame_interval = ((i2c_rd8(sd, FV_CNT_HI) & 0x3) << 8) + 324d32d9864SMats Randgaard i2c_rd8(sd, FV_CNT_LO); 325d32d9864SMats Randgaard fps = (frame_interval > 0) ? 326d32d9864SMats Randgaard DIV_ROUND_CLOSEST(10000, frame_interval) : 0; 327d32d9864SMats Randgaard 328d32d9864SMats Randgaard bt->width = width; 329d32d9864SMats Randgaard bt->height = height; 330d32d9864SMats Randgaard bt->vsync = frame_height - height; 331d32d9864SMats Randgaard bt->hsync = frame_width - width; 332d32d9864SMats Randgaard bt->pixelclock = frame_width * frame_height * fps; 333d32d9864SMats Randgaard if (bt->interlaced == V4L2_DV_INTERLACED) { 334d32d9864SMats Randgaard bt->height *= 2; 335d32d9864SMats Randgaard bt->il_vsync = bt->vsync + 1; 336d32d9864SMats Randgaard bt->pixelclock /= 2; 337d32d9864SMats Randgaard } 338d32d9864SMats Randgaard 339d32d9864SMats Randgaard return 0; 340d32d9864SMats Randgaard } 341d32d9864SMats Randgaard 342d32d9864SMats Randgaard /* --------------- HOTPLUG / HDCP / EDID --------------- */ 343d32d9864SMats Randgaard 344d32d9864SMats Randgaard static void tc358743_delayed_work_enable_hotplug(struct work_struct *work) 345d32d9864SMats Randgaard { 346d32d9864SMats Randgaard struct delayed_work *dwork = to_delayed_work(work); 347d32d9864SMats Randgaard struct tc358743_state *state = container_of(dwork, 348d32d9864SMats Randgaard struct tc358743_state, delayed_work_enable_hotplug); 349d32d9864SMats Randgaard struct v4l2_subdev *sd = &state->sd; 350d32d9864SMats Randgaard 351d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s:\n", __func__); 352d32d9864SMats Randgaard 353d32d9864SMats Randgaard i2c_wr8_and_or(sd, HPD_CTL, ~MASK_HPD_OUT0, MASK_HPD_OUT0); 354d32d9864SMats Randgaard } 355d32d9864SMats Randgaard 356d32d9864SMats Randgaard static void tc358743_set_hdmi_hdcp(struct v4l2_subdev *sd, bool enable) 357d32d9864SMats Randgaard { 358d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s: %s\n", __func__, enable ? 359d32d9864SMats Randgaard "enable" : "disable"); 360d32d9864SMats Randgaard 361d32d9864SMats Randgaard i2c_wr8_and_or(sd, HDCP_REG1, 362d32d9864SMats Randgaard ~(MASK_AUTH_UNAUTH_SEL | MASK_AUTH_UNAUTH), 363d32d9864SMats Randgaard MASK_AUTH_UNAUTH_SEL_16_FRAMES | MASK_AUTH_UNAUTH_AUTO); 364d32d9864SMats Randgaard 365d32d9864SMats Randgaard i2c_wr8_and_or(sd, HDCP_REG2, ~MASK_AUTO_P3_RESET, 366d32d9864SMats Randgaard SET_AUTO_P3_RESET_FRAMES(0x0f)); 367d32d9864SMats Randgaard 368d32d9864SMats Randgaard /* HDCP is disabled by configuring the receiver as HDCP repeater. The 369d32d9864SMats Randgaard * repeater mode require software support to work, so HDCP 370d32d9864SMats Randgaard * authentication will fail. 371d32d9864SMats Randgaard */ 372d32d9864SMats Randgaard i2c_wr8_and_or(sd, HDCP_REG3, ~KEY_RD_CMD, enable ? KEY_RD_CMD : 0); 373d32d9864SMats Randgaard i2c_wr8_and_or(sd, HDCP_MODE, ~(MASK_AUTO_CLR | MASK_MODE_RST_TN), 374d32d9864SMats Randgaard enable ? (MASK_AUTO_CLR | MASK_MODE_RST_TN) : 0); 375d32d9864SMats Randgaard 376d32d9864SMats Randgaard /* Apple MacBook Pro gen.8 has a bug that makes it freeze every fifth 377d32d9864SMats Randgaard * second when HDCP is disabled, but the MAX_EXCED bit is handled 378d32d9864SMats Randgaard * correctly and HDCP is disabled on the HDMI output. 379d32d9864SMats Randgaard */ 380d32d9864SMats Randgaard i2c_wr8_and_or(sd, BSTATUS1, ~MASK_MAX_EXCED, 381d32d9864SMats Randgaard enable ? 0 : MASK_MAX_EXCED); 382d32d9864SMats Randgaard i2c_wr8_and_or(sd, BCAPS, ~(MASK_REPEATER | MASK_READY), 383d32d9864SMats Randgaard enable ? 0 : MASK_REPEATER | MASK_READY); 384d32d9864SMats Randgaard } 385d32d9864SMats Randgaard 386d32d9864SMats Randgaard static void tc358743_disable_edid(struct v4l2_subdev *sd) 387d32d9864SMats Randgaard { 388d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 389d32d9864SMats Randgaard 390d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s:\n", __func__); 391d32d9864SMats Randgaard 392d32d9864SMats Randgaard cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); 393d32d9864SMats Randgaard 394d32d9864SMats Randgaard /* DDC access to EDID is also disabled when hotplug is disabled. See 395d32d9864SMats Randgaard * register DDC_CTL */ 396d32d9864SMats Randgaard i2c_wr8_and_or(sd, HPD_CTL, ~MASK_HPD_OUT0, 0x0); 397d32d9864SMats Randgaard } 398d32d9864SMats Randgaard 399d32d9864SMats Randgaard static void tc358743_enable_edid(struct v4l2_subdev *sd) 400d32d9864SMats Randgaard { 401d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 402d32d9864SMats Randgaard 403d32d9864SMats Randgaard if (state->edid_blocks_written == 0) { 404d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s: no EDID -> no hotplug\n", __func__); 405d32d9864SMats Randgaard return; 406d32d9864SMats Randgaard } 407d32d9864SMats Randgaard 408d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s:\n", __func__); 409d32d9864SMats Randgaard 410d32d9864SMats Randgaard /* Enable hotplug after 100 ms. DDC access to EDID is also enabled when 411d32d9864SMats Randgaard * hotplug is enabled. See register DDC_CTL */ 412d32d9864SMats Randgaard queue_delayed_work(state->work_queues, 413d32d9864SMats Randgaard &state->delayed_work_enable_hotplug, HZ / 10); 414d32d9864SMats Randgaard 415d32d9864SMats Randgaard tc358743_enable_interrupts(sd, true); 416d32d9864SMats Randgaard tc358743_s_ctrl_detect_tx_5v(sd); 417d32d9864SMats Randgaard } 418d32d9864SMats Randgaard 419d32d9864SMats Randgaard static void tc358743_erase_bksv(struct v4l2_subdev *sd) 420d32d9864SMats Randgaard { 421d32d9864SMats Randgaard int i; 422d32d9864SMats Randgaard 423d32d9864SMats Randgaard for (i = 0; i < 5; i++) 424d32d9864SMats Randgaard i2c_wr8(sd, BKSV + i, 0); 425d32d9864SMats Randgaard } 426d32d9864SMats Randgaard 427d32d9864SMats Randgaard /* --------------- AVI infoframe --------------- */ 428d32d9864SMats Randgaard 429d32d9864SMats Randgaard static void print_avi_infoframe(struct v4l2_subdev *sd) 430d32d9864SMats Randgaard { 431d32d9864SMats Randgaard struct i2c_client *client = v4l2_get_subdevdata(sd); 432d32d9864SMats Randgaard struct device *dev = &client->dev; 433d32d9864SMats Randgaard union hdmi_infoframe frame; 434d32d9864SMats Randgaard u8 buffer[HDMI_INFOFRAME_SIZE(AVI)]; 435d32d9864SMats Randgaard 436d32d9864SMats Randgaard if (!is_hdmi(sd)) { 437d32d9864SMats Randgaard v4l2_info(sd, "DVI-D signal - AVI infoframe not supported\n"); 438d32d9864SMats Randgaard return; 439d32d9864SMats Randgaard } 440d32d9864SMats Randgaard 441d32d9864SMats Randgaard i2c_rd(sd, PK_AVI_0HEAD, buffer, HDMI_INFOFRAME_SIZE(AVI)); 442d32d9864SMats Randgaard 443d32d9864SMats Randgaard if (hdmi_infoframe_unpack(&frame, buffer) < 0) { 444d32d9864SMats Randgaard v4l2_err(sd, "%s: unpack of AVI infoframe failed\n", __func__); 445d32d9864SMats Randgaard return; 446d32d9864SMats Randgaard } 447d32d9864SMats Randgaard 448d32d9864SMats Randgaard hdmi_infoframe_log(KERN_INFO, dev, &frame); 449d32d9864SMats Randgaard } 450d32d9864SMats Randgaard 451d32d9864SMats Randgaard /* --------------- CTRLS --------------- */ 452d32d9864SMats Randgaard 453d32d9864SMats Randgaard static int tc358743_s_ctrl_detect_tx_5v(struct v4l2_subdev *sd) 454d32d9864SMats Randgaard { 455d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 456d32d9864SMats Randgaard 457d32d9864SMats Randgaard return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, 458d32d9864SMats Randgaard tx_5v_power_present(sd)); 459d32d9864SMats Randgaard } 460d32d9864SMats Randgaard 461d32d9864SMats Randgaard static int tc358743_s_ctrl_audio_sampling_rate(struct v4l2_subdev *sd) 462d32d9864SMats Randgaard { 463d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 464d32d9864SMats Randgaard 465d32d9864SMats Randgaard return v4l2_ctrl_s_ctrl(state->audio_sampling_rate_ctrl, 466d32d9864SMats Randgaard get_audio_sampling_rate(sd)); 467d32d9864SMats Randgaard } 468d32d9864SMats Randgaard 469d32d9864SMats Randgaard static int tc358743_s_ctrl_audio_present(struct v4l2_subdev *sd) 470d32d9864SMats Randgaard { 471d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 472d32d9864SMats Randgaard 473d32d9864SMats Randgaard return v4l2_ctrl_s_ctrl(state->audio_present_ctrl, 474d32d9864SMats Randgaard audio_present(sd)); 475d32d9864SMats Randgaard } 476d32d9864SMats Randgaard 477d32d9864SMats Randgaard static int tc358743_update_controls(struct v4l2_subdev *sd) 478d32d9864SMats Randgaard { 479d32d9864SMats Randgaard int ret = 0; 480d32d9864SMats Randgaard 481d32d9864SMats Randgaard ret |= tc358743_s_ctrl_detect_tx_5v(sd); 482d32d9864SMats Randgaard ret |= tc358743_s_ctrl_audio_sampling_rate(sd); 483d32d9864SMats Randgaard ret |= tc358743_s_ctrl_audio_present(sd); 484d32d9864SMats Randgaard 485d32d9864SMats Randgaard return ret; 486d32d9864SMats Randgaard } 487d32d9864SMats Randgaard 488d32d9864SMats Randgaard /* --------------- INIT --------------- */ 489d32d9864SMats Randgaard 490d32d9864SMats Randgaard static void tc358743_reset_phy(struct v4l2_subdev *sd) 491d32d9864SMats Randgaard { 492d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s:\n", __func__); 493d32d9864SMats Randgaard 494d32d9864SMats Randgaard i2c_wr8_and_or(sd, PHY_RST, ~MASK_RESET_CTRL, 0); 495d32d9864SMats Randgaard i2c_wr8_and_or(sd, PHY_RST, ~MASK_RESET_CTRL, MASK_RESET_CTRL); 496d32d9864SMats Randgaard } 497d32d9864SMats Randgaard 498d32d9864SMats Randgaard static void tc358743_reset(struct v4l2_subdev *sd, uint16_t mask) 499d32d9864SMats Randgaard { 500d32d9864SMats Randgaard u16 sysctl = i2c_rd16(sd, SYSCTL); 501d32d9864SMats Randgaard 502d32d9864SMats Randgaard i2c_wr16(sd, SYSCTL, sysctl | mask); 503d32d9864SMats Randgaard i2c_wr16(sd, SYSCTL, sysctl & ~mask); 504d32d9864SMats Randgaard } 505d32d9864SMats Randgaard 506d32d9864SMats Randgaard static inline void tc358743_sleep_mode(struct v4l2_subdev *sd, bool enable) 507d32d9864SMats Randgaard { 508d32d9864SMats Randgaard i2c_wr16_and_or(sd, SYSCTL, ~MASK_SLEEP, 509d32d9864SMats Randgaard enable ? MASK_SLEEP : 0); 510d32d9864SMats Randgaard } 511d32d9864SMats Randgaard 512d32d9864SMats Randgaard static inline void enable_stream(struct v4l2_subdev *sd, bool enable) 513d32d9864SMats Randgaard { 514d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 515d32d9864SMats Randgaard 516d32d9864SMats Randgaard v4l2_dbg(3, debug, sd, "%s: %sable\n", 517d32d9864SMats Randgaard __func__, enable ? "en" : "dis"); 518d32d9864SMats Randgaard 519d32d9864SMats Randgaard if (enable) { 520d32d9864SMats Randgaard /* It is critical for CSI receiver to see lane transition 521d32d9864SMats Randgaard * LP11->HS. Set to non-continuous mode to enable clock lane 522d32d9864SMats Randgaard * LP11 state. */ 523d32d9864SMats Randgaard i2c_wr32(sd, TXOPTIONCNTRL, 0); 524d32d9864SMats Randgaard /* Set to continuous mode to trigger LP11->HS transition */ 525d32d9864SMats Randgaard i2c_wr32(sd, TXOPTIONCNTRL, MASK_CONTCLKMODE); 526d32d9864SMats Randgaard /* Unmute video */ 527d32d9864SMats Randgaard i2c_wr8(sd, VI_MUTE, MASK_AUTO_MUTE); 528d32d9864SMats Randgaard } else { 529d32d9864SMats Randgaard /* Mute video so that all data lanes go to LSP11 state. 530d32d9864SMats Randgaard * No data is output to CSI Tx block. */ 531d32d9864SMats Randgaard i2c_wr8(sd, VI_MUTE, MASK_AUTO_MUTE | MASK_VI_MUTE); 532d32d9864SMats Randgaard } 533d32d9864SMats Randgaard 534d32d9864SMats Randgaard mutex_lock(&state->confctl_mutex); 535d32d9864SMats Randgaard i2c_wr16_and_or(sd, CONFCTL, ~(MASK_VBUFEN | MASK_ABUFEN), 536d32d9864SMats Randgaard enable ? (MASK_VBUFEN | MASK_ABUFEN) : 0x0); 537d32d9864SMats Randgaard mutex_unlock(&state->confctl_mutex); 538d32d9864SMats Randgaard } 539d32d9864SMats Randgaard 540d32d9864SMats Randgaard static void tc358743_set_pll(struct v4l2_subdev *sd) 541d32d9864SMats Randgaard { 542d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 543d32d9864SMats Randgaard struct tc358743_platform_data *pdata = &state->pdata; 544d32d9864SMats Randgaard u16 pllctl0 = i2c_rd16(sd, PLLCTL0); 545d32d9864SMats Randgaard u16 pllctl1 = i2c_rd16(sd, PLLCTL1); 546d32d9864SMats Randgaard u16 pllctl0_new = SET_PLL_PRD(pdata->pll_prd) | 547d32d9864SMats Randgaard SET_PLL_FBD(pdata->pll_fbd); 548d32d9864SMats Randgaard u32 hsck = (pdata->refclk_hz / pdata->pll_prd) * pdata->pll_fbd; 549d32d9864SMats Randgaard 550d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s:\n", __func__); 551d32d9864SMats Randgaard 552d32d9864SMats Randgaard /* Only rewrite when needed (new value or disabled), since rewriting 553d32d9864SMats Randgaard * triggers another format change event. */ 554d32d9864SMats Randgaard if ((pllctl0 != pllctl0_new) || ((pllctl1 & MASK_PLL_EN) == 0)) { 555d32d9864SMats Randgaard u16 pll_frs; 556d32d9864SMats Randgaard 557d32d9864SMats Randgaard if (hsck > 500000000) 558d32d9864SMats Randgaard pll_frs = 0x0; 559d32d9864SMats Randgaard else if (hsck > 250000000) 560d32d9864SMats Randgaard pll_frs = 0x1; 561d32d9864SMats Randgaard else if (hsck > 125000000) 562d32d9864SMats Randgaard pll_frs = 0x2; 563d32d9864SMats Randgaard else 564d32d9864SMats Randgaard pll_frs = 0x3; 565d32d9864SMats Randgaard 566d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: updating PLL clock\n", __func__); 567d32d9864SMats Randgaard tc358743_sleep_mode(sd, true); 568d32d9864SMats Randgaard i2c_wr16(sd, PLLCTL0, pllctl0_new); 569d32d9864SMats Randgaard i2c_wr16_and_or(sd, PLLCTL1, 570d32d9864SMats Randgaard ~(MASK_PLL_FRS | MASK_RESETB | MASK_PLL_EN), 571d32d9864SMats Randgaard (SET_PLL_FRS(pll_frs) | MASK_RESETB | 572d32d9864SMats Randgaard MASK_PLL_EN)); 573d32d9864SMats Randgaard udelay(10); /* REF_02, Sheet "Source HDMI" */ 574d32d9864SMats Randgaard i2c_wr16_and_or(sd, PLLCTL1, ~MASK_CKEN, MASK_CKEN); 575d32d9864SMats Randgaard tc358743_sleep_mode(sd, false); 576d32d9864SMats Randgaard } 577d32d9864SMats Randgaard } 578d32d9864SMats Randgaard 579d32d9864SMats Randgaard static void tc358743_set_ref_clk(struct v4l2_subdev *sd) 580d32d9864SMats Randgaard { 581d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 582d32d9864SMats Randgaard struct tc358743_platform_data *pdata = &state->pdata; 583d32d9864SMats Randgaard u32 sys_freq; 584d32d9864SMats Randgaard u32 lockdet_ref; 585d32d9864SMats Randgaard u16 fh_min; 586d32d9864SMats Randgaard u16 fh_max; 587d32d9864SMats Randgaard 588d32d9864SMats Randgaard BUG_ON(!(pdata->refclk_hz == 26000000 || 589d32d9864SMats Randgaard pdata->refclk_hz == 27000000 || 590d32d9864SMats Randgaard pdata->refclk_hz == 42000000)); 591d32d9864SMats Randgaard 592d32d9864SMats Randgaard sys_freq = pdata->refclk_hz / 10000; 593d32d9864SMats Randgaard i2c_wr8(sd, SYS_FREQ0, sys_freq & 0x00ff); 594d32d9864SMats Randgaard i2c_wr8(sd, SYS_FREQ1, (sys_freq & 0xff00) >> 8); 595d32d9864SMats Randgaard 596d32d9864SMats Randgaard i2c_wr8_and_or(sd, PHY_CTL0, ~MASK_PHY_SYSCLK_IND, 597d32d9864SMats Randgaard (pdata->refclk_hz == 42000000) ? 598d32d9864SMats Randgaard MASK_PHY_SYSCLK_IND : 0x0); 599d32d9864SMats Randgaard 600d32d9864SMats Randgaard fh_min = pdata->refclk_hz / 100000; 601d32d9864SMats Randgaard i2c_wr8(sd, FH_MIN0, fh_min & 0x00ff); 602d32d9864SMats Randgaard i2c_wr8(sd, FH_MIN1, (fh_min & 0xff00) >> 8); 603d32d9864SMats Randgaard 604d32d9864SMats Randgaard fh_max = (fh_min * 66) / 10; 605d32d9864SMats Randgaard i2c_wr8(sd, FH_MAX0, fh_max & 0x00ff); 606d32d9864SMats Randgaard i2c_wr8(sd, FH_MAX1, (fh_max & 0xff00) >> 8); 607d32d9864SMats Randgaard 608d32d9864SMats Randgaard lockdet_ref = pdata->refclk_hz / 100; 609d32d9864SMats Randgaard i2c_wr8(sd, LOCKDET_REF0, lockdet_ref & 0x0000ff); 610d32d9864SMats Randgaard i2c_wr8(sd, LOCKDET_REF1, (lockdet_ref & 0x00ff00) >> 8); 611d32d9864SMats Randgaard i2c_wr8(sd, LOCKDET_REF2, (lockdet_ref & 0x0f0000) >> 16); 612d32d9864SMats Randgaard 613d32d9864SMats Randgaard i2c_wr8_and_or(sd, NCO_F0_MOD, ~MASK_NCO_F0_MOD, 614d32d9864SMats Randgaard (pdata->refclk_hz == 27000000) ? 615d32d9864SMats Randgaard MASK_NCO_F0_MOD_27MHZ : 0x0); 616d32d9864SMats Randgaard } 617d32d9864SMats Randgaard 618d32d9864SMats Randgaard static void tc358743_set_csi_color_space(struct v4l2_subdev *sd) 619d32d9864SMats Randgaard { 620d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 621d32d9864SMats Randgaard 622d32d9864SMats Randgaard switch (state->mbus_fmt_code) { 623d32d9864SMats Randgaard case MEDIA_BUS_FMT_UYVY8_1X16: 624d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s: YCbCr 422 16-bit\n", __func__); 625d32d9864SMats Randgaard i2c_wr8_and_or(sd, VOUT_SET2, 626d32d9864SMats Randgaard ~(MASK_SEL422 | MASK_VOUT_422FIL_100) & 0xff, 627d32d9864SMats Randgaard MASK_SEL422 | MASK_VOUT_422FIL_100); 628d32d9864SMats Randgaard i2c_wr8_and_or(sd, VI_REP, ~MASK_VOUT_COLOR_SEL & 0xff, 629d32d9864SMats Randgaard MASK_VOUT_COLOR_601_YCBCR_LIMITED); 630d32d9864SMats Randgaard mutex_lock(&state->confctl_mutex); 631d32d9864SMats Randgaard i2c_wr16_and_or(sd, CONFCTL, ~MASK_YCBCRFMT, 632d32d9864SMats Randgaard MASK_YCBCRFMT_422_8_BIT); 633d32d9864SMats Randgaard mutex_unlock(&state->confctl_mutex); 634d32d9864SMats Randgaard break; 635d32d9864SMats Randgaard case MEDIA_BUS_FMT_RGB888_1X24: 636d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s: RGB 888 24-bit\n", __func__); 637d32d9864SMats Randgaard i2c_wr8_and_or(sd, VOUT_SET2, 638d32d9864SMats Randgaard ~(MASK_SEL422 | MASK_VOUT_422FIL_100) & 0xff, 639d32d9864SMats Randgaard 0x00); 640d32d9864SMats Randgaard i2c_wr8_and_or(sd, VI_REP, ~MASK_VOUT_COLOR_SEL & 0xff, 641d32d9864SMats Randgaard MASK_VOUT_COLOR_RGB_FULL); 642d32d9864SMats Randgaard mutex_lock(&state->confctl_mutex); 643d32d9864SMats Randgaard i2c_wr16_and_or(sd, CONFCTL, ~MASK_YCBCRFMT, 0); 644d32d9864SMats Randgaard mutex_unlock(&state->confctl_mutex); 645d32d9864SMats Randgaard break; 646d32d9864SMats Randgaard default: 647d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s: Unsupported format code 0x%x\n", 648d32d9864SMats Randgaard __func__, state->mbus_fmt_code); 649d32d9864SMats Randgaard } 650d32d9864SMats Randgaard } 651d32d9864SMats Randgaard 652d32d9864SMats Randgaard static unsigned tc358743_num_csi_lanes_needed(struct v4l2_subdev *sd) 653d32d9864SMats Randgaard { 654d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 655d32d9864SMats Randgaard struct v4l2_bt_timings *bt = &state->timings.bt; 656d32d9864SMats Randgaard struct tc358743_platform_data *pdata = &state->pdata; 657d32d9864SMats Randgaard u32 bits_pr_pixel = 658d32d9864SMats Randgaard (state->mbus_fmt_code == MEDIA_BUS_FMT_UYVY8_1X16) ? 16 : 24; 659d32d9864SMats Randgaard u32 bps = bt->width * bt->height * fps(bt) * bits_pr_pixel; 660d32d9864SMats Randgaard u32 bps_pr_lane = (pdata->refclk_hz / pdata->pll_prd) * pdata->pll_fbd; 661d32d9864SMats Randgaard 662d32d9864SMats Randgaard return DIV_ROUND_UP(bps, bps_pr_lane); 663d32d9864SMats Randgaard } 664d32d9864SMats Randgaard 665d32d9864SMats Randgaard static void tc358743_set_csi(struct v4l2_subdev *sd) 666d32d9864SMats Randgaard { 667d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 668d32d9864SMats Randgaard struct tc358743_platform_data *pdata = &state->pdata; 669d32d9864SMats Randgaard unsigned lanes = tc358743_num_csi_lanes_needed(sd); 670d32d9864SMats Randgaard 671d32d9864SMats Randgaard v4l2_dbg(3, debug, sd, "%s:\n", __func__); 672d32d9864SMats Randgaard 673d32d9864SMats Randgaard tc358743_reset(sd, MASK_CTXRST); 674d32d9864SMats Randgaard 675d32d9864SMats Randgaard if (lanes < 1) 676d32d9864SMats Randgaard i2c_wr32(sd, CLW_CNTRL, MASK_CLW_LANEDISABLE); 677d32d9864SMats Randgaard if (lanes < 1) 678d32d9864SMats Randgaard i2c_wr32(sd, D0W_CNTRL, MASK_D0W_LANEDISABLE); 679d32d9864SMats Randgaard if (lanes < 2) 680d32d9864SMats Randgaard i2c_wr32(sd, D1W_CNTRL, MASK_D1W_LANEDISABLE); 681d32d9864SMats Randgaard if (lanes < 3) 682d32d9864SMats Randgaard i2c_wr32(sd, D2W_CNTRL, MASK_D2W_LANEDISABLE); 683d32d9864SMats Randgaard if (lanes < 4) 684d32d9864SMats Randgaard i2c_wr32(sd, D3W_CNTRL, MASK_D3W_LANEDISABLE); 685d32d9864SMats Randgaard 686d32d9864SMats Randgaard i2c_wr32(sd, LINEINITCNT, pdata->lineinitcnt); 687d32d9864SMats Randgaard i2c_wr32(sd, LPTXTIMECNT, pdata->lptxtimecnt); 688d32d9864SMats Randgaard i2c_wr32(sd, TCLK_HEADERCNT, pdata->tclk_headercnt); 689d32d9864SMats Randgaard i2c_wr32(sd, TCLK_TRAILCNT, pdata->tclk_trailcnt); 690d32d9864SMats Randgaard i2c_wr32(sd, THS_HEADERCNT, pdata->ths_headercnt); 691d32d9864SMats Randgaard i2c_wr32(sd, TWAKEUP, pdata->twakeup); 692d32d9864SMats Randgaard i2c_wr32(sd, TCLK_POSTCNT, pdata->tclk_postcnt); 693d32d9864SMats Randgaard i2c_wr32(sd, THS_TRAILCNT, pdata->ths_trailcnt); 694d32d9864SMats Randgaard i2c_wr32(sd, HSTXVREGCNT, pdata->hstxvregcnt); 695d32d9864SMats Randgaard 696d32d9864SMats Randgaard i2c_wr32(sd, HSTXVREGEN, 697d32d9864SMats Randgaard ((lanes > 0) ? MASK_CLM_HSTXVREGEN : 0x0) | 698d32d9864SMats Randgaard ((lanes > 0) ? MASK_D0M_HSTXVREGEN : 0x0) | 699d32d9864SMats Randgaard ((lanes > 1) ? MASK_D1M_HSTXVREGEN : 0x0) | 700d32d9864SMats Randgaard ((lanes > 2) ? MASK_D2M_HSTXVREGEN : 0x0) | 701d32d9864SMats Randgaard ((lanes > 3) ? MASK_D3M_HSTXVREGEN : 0x0)); 702d32d9864SMats Randgaard 703d32d9864SMats Randgaard i2c_wr32(sd, TXOPTIONCNTRL, MASK_CONTCLKMODE); 704d32d9864SMats Randgaard i2c_wr32(sd, STARTCNTRL, MASK_START); 705d32d9864SMats Randgaard i2c_wr32(sd, CSI_START, MASK_STRT); 706d32d9864SMats Randgaard 707d32d9864SMats Randgaard i2c_wr32(sd, CSI_CONFW, MASK_MODE_SET | 708d32d9864SMats Randgaard MASK_ADDRESS_CSI_CONTROL | 709d32d9864SMats Randgaard MASK_CSI_MODE | 710d32d9864SMats Randgaard MASK_TXHSMD | 711d32d9864SMats Randgaard ((lanes == 4) ? MASK_NOL_4 : 712d32d9864SMats Randgaard (lanes == 3) ? MASK_NOL_3 : 713d32d9864SMats Randgaard (lanes == 2) ? MASK_NOL_2 : MASK_NOL_1)); 714d32d9864SMats Randgaard 715d32d9864SMats Randgaard i2c_wr32(sd, CSI_CONFW, MASK_MODE_SET | 716d32d9864SMats Randgaard MASK_ADDRESS_CSI_ERR_INTENA | MASK_TXBRK | MASK_QUNK | 717d32d9864SMats Randgaard MASK_WCER | MASK_INER); 718d32d9864SMats Randgaard 719d32d9864SMats Randgaard i2c_wr32(sd, CSI_CONFW, MASK_MODE_CLEAR | 720d32d9864SMats Randgaard MASK_ADDRESS_CSI_ERR_HALT | MASK_TXBRK | MASK_QUNK); 721d32d9864SMats Randgaard 722d32d9864SMats Randgaard i2c_wr32(sd, CSI_CONFW, MASK_MODE_SET | 723d32d9864SMats Randgaard MASK_ADDRESS_CSI_INT_ENA | MASK_INTER); 724d32d9864SMats Randgaard } 725d32d9864SMats Randgaard 726d32d9864SMats Randgaard static void tc358743_set_hdmi_phy(struct v4l2_subdev *sd) 727d32d9864SMats Randgaard { 728d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 729d32d9864SMats Randgaard struct tc358743_platform_data *pdata = &state->pdata; 730d32d9864SMats Randgaard 731d32d9864SMats Randgaard /* Default settings from REF_02, sheet "Source HDMI" 732d32d9864SMats Randgaard * and custom settings as platform data */ 733d32d9864SMats Randgaard i2c_wr8_and_or(sd, PHY_EN, ~MASK_ENABLE_PHY, 0x0); 734d32d9864SMats Randgaard i2c_wr8(sd, PHY_CTL1, SET_PHY_AUTO_RST1_US(1600) | 735d32d9864SMats Randgaard SET_FREQ_RANGE_MODE_CYCLES(1)); 736d32d9864SMats Randgaard i2c_wr8_and_or(sd, PHY_CTL2, ~MASK_PHY_AUTO_RSTn, 737d32d9864SMats Randgaard (pdata->hdmi_phy_auto_reset_tmds_detected ? 738d32d9864SMats Randgaard MASK_PHY_AUTO_RST2 : 0) | 739d32d9864SMats Randgaard (pdata->hdmi_phy_auto_reset_tmds_in_range ? 740d32d9864SMats Randgaard MASK_PHY_AUTO_RST3 : 0) | 741d32d9864SMats Randgaard (pdata->hdmi_phy_auto_reset_tmds_valid ? 742d32d9864SMats Randgaard MASK_PHY_AUTO_RST4 : 0)); 743d32d9864SMats Randgaard i2c_wr8(sd, PHY_BIAS, 0x40); 744d32d9864SMats Randgaard i2c_wr8(sd, PHY_CSQ, SET_CSQ_CNT_LEVEL(0x0a)); 745d32d9864SMats Randgaard i2c_wr8(sd, AVM_CTL, 45); 746d32d9864SMats Randgaard i2c_wr8_and_or(sd, HDMI_DET, ~MASK_HDMI_DET_V, 747d32d9864SMats Randgaard pdata->hdmi_detection_delay << 4); 748d32d9864SMats Randgaard i2c_wr8_and_or(sd, HV_RST, ~(MASK_H_PI_RST | MASK_V_PI_RST), 749d32d9864SMats Randgaard (pdata->hdmi_phy_auto_reset_hsync_out_of_range ? 750d32d9864SMats Randgaard MASK_H_PI_RST : 0) | 751d32d9864SMats Randgaard (pdata->hdmi_phy_auto_reset_vsync_out_of_range ? 752d32d9864SMats Randgaard MASK_V_PI_RST : 0)); 753d32d9864SMats Randgaard i2c_wr8_and_or(sd, PHY_EN, ~MASK_ENABLE_PHY, MASK_ENABLE_PHY); 754d32d9864SMats Randgaard } 755d32d9864SMats Randgaard 756d32d9864SMats Randgaard static void tc358743_set_hdmi_audio(struct v4l2_subdev *sd) 757d32d9864SMats Randgaard { 758d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 759d32d9864SMats Randgaard 760d32d9864SMats Randgaard /* Default settings from REF_02, sheet "Source HDMI" */ 761d32d9864SMats Randgaard i2c_wr8(sd, FORCE_MUTE, 0x00); 762d32d9864SMats Randgaard i2c_wr8(sd, AUTO_CMD0, MASK_AUTO_MUTE7 | MASK_AUTO_MUTE6 | 763d32d9864SMats Randgaard MASK_AUTO_MUTE5 | MASK_AUTO_MUTE4 | 764d32d9864SMats Randgaard MASK_AUTO_MUTE1 | MASK_AUTO_MUTE0); 765d32d9864SMats Randgaard i2c_wr8(sd, AUTO_CMD1, MASK_AUTO_MUTE9); 766d32d9864SMats Randgaard i2c_wr8(sd, AUTO_CMD2, MASK_AUTO_PLAY3 | MASK_AUTO_PLAY2); 767d32d9864SMats Randgaard i2c_wr8(sd, BUFINIT_START, SET_BUFINIT_START_MS(500)); 768d32d9864SMats Randgaard i2c_wr8(sd, FS_MUTE, 0x00); 769d32d9864SMats Randgaard i2c_wr8(sd, FS_IMODE, MASK_NLPCM_SMODE | MASK_FS_SMODE); 770d32d9864SMats Randgaard i2c_wr8(sd, ACR_MODE, MASK_CTS_MODE); 771d32d9864SMats Randgaard i2c_wr8(sd, ACR_MDF0, MASK_ACR_L2MDF_1976_PPM | MASK_ACR_L1MDF_976_PPM); 772d32d9864SMats Randgaard i2c_wr8(sd, ACR_MDF1, MASK_ACR_L3MDF_3906_PPM); 773d32d9864SMats Randgaard i2c_wr8(sd, SDO_MODE1, MASK_SDO_FMT_I2S); 774d32d9864SMats Randgaard i2c_wr8(sd, DIV_MODE, SET_DIV_DLY_MS(100)); 775d32d9864SMats Randgaard 776d32d9864SMats Randgaard mutex_lock(&state->confctl_mutex); 777d32d9864SMats Randgaard i2c_wr16_and_or(sd, CONFCTL, 0xffff, MASK_AUDCHNUM_2 | 778d32d9864SMats Randgaard MASK_AUDOUTSEL_I2S | MASK_AUTOINDEX); 779d32d9864SMats Randgaard mutex_unlock(&state->confctl_mutex); 780d32d9864SMats Randgaard } 781d32d9864SMats Randgaard 782d32d9864SMats Randgaard static void tc358743_set_hdmi_info_frame_mode(struct v4l2_subdev *sd) 783d32d9864SMats Randgaard { 784d32d9864SMats Randgaard /* Default settings from REF_02, sheet "Source HDMI" */ 785d32d9864SMats Randgaard i2c_wr8(sd, PK_INT_MODE, MASK_ISRC2_INT_MODE | MASK_ISRC_INT_MODE | 786d32d9864SMats Randgaard MASK_ACP_INT_MODE | MASK_VS_INT_MODE | 787d32d9864SMats Randgaard MASK_SPD_INT_MODE | MASK_MS_INT_MODE | 788d32d9864SMats Randgaard MASK_AUD_INT_MODE | MASK_AVI_INT_MODE); 789d32d9864SMats Randgaard i2c_wr8(sd, NO_PKT_LIMIT, 0x2c); 790d32d9864SMats Randgaard i2c_wr8(sd, NO_PKT_CLR, 0x53); 791d32d9864SMats Randgaard i2c_wr8(sd, ERR_PK_LIMIT, 0x01); 792d32d9864SMats Randgaard i2c_wr8(sd, NO_PKT_LIMIT2, 0x30); 793d32d9864SMats Randgaard i2c_wr8(sd, NO_GDB_LIMIT, 0x10); 794d32d9864SMats Randgaard } 795d32d9864SMats Randgaard 796d32d9864SMats Randgaard static void tc358743_initial_setup(struct v4l2_subdev *sd) 797d32d9864SMats Randgaard { 798d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 799d32d9864SMats Randgaard struct tc358743_platform_data *pdata = &state->pdata; 800d32d9864SMats Randgaard 801d32d9864SMats Randgaard /* CEC and IR are not supported by this driver */ 802d32d9864SMats Randgaard i2c_wr16_and_or(sd, SYSCTL, ~(MASK_CECRST | MASK_IRRST), 803d32d9864SMats Randgaard (MASK_CECRST | MASK_IRRST)); 804d32d9864SMats Randgaard 805d32d9864SMats Randgaard tc358743_reset(sd, MASK_CTXRST | MASK_HDMIRST); 806d32d9864SMats Randgaard tc358743_sleep_mode(sd, false); 807d32d9864SMats Randgaard 808d32d9864SMats Randgaard i2c_wr16(sd, FIFOCTL, pdata->fifo_level); 809d32d9864SMats Randgaard 810d32d9864SMats Randgaard tc358743_set_ref_clk(sd); 811d32d9864SMats Randgaard 812d32d9864SMats Randgaard i2c_wr8_and_or(sd, DDC_CTL, ~MASK_DDC5V_MODE, 813d32d9864SMats Randgaard pdata->ddc5v_delay & MASK_DDC5V_MODE); 814d32d9864SMats Randgaard i2c_wr8_and_or(sd, EDID_MODE, ~MASK_EDID_MODE, MASK_EDID_MODE_E_DDC); 815d32d9864SMats Randgaard 816d32d9864SMats Randgaard tc358743_set_hdmi_phy(sd); 817d32d9864SMats Randgaard tc358743_set_hdmi_hdcp(sd, pdata->enable_hdcp); 818d32d9864SMats Randgaard tc358743_set_hdmi_audio(sd); 819d32d9864SMats Randgaard tc358743_set_hdmi_info_frame_mode(sd); 820d32d9864SMats Randgaard 821d32d9864SMats Randgaard /* All CE and IT formats are detected as RGB full range in DVI mode */ 822d32d9864SMats Randgaard i2c_wr8_and_or(sd, VI_MODE, ~MASK_RGB_DVI, 0); 823d32d9864SMats Randgaard 824d32d9864SMats Randgaard i2c_wr8_and_or(sd, VOUT_SET2, ~MASK_VOUTCOLORMODE, 825d32d9864SMats Randgaard MASK_VOUTCOLORMODE_AUTO); 826d32d9864SMats Randgaard i2c_wr8(sd, VOUT_SET3, MASK_VOUT_EXTCNT); 827d32d9864SMats Randgaard } 828d32d9864SMats Randgaard 829d32d9864SMats Randgaard /* --------------- IRQ --------------- */ 830d32d9864SMats Randgaard 831d32d9864SMats Randgaard static void tc358743_format_change(struct v4l2_subdev *sd) 832d32d9864SMats Randgaard { 833d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 834d32d9864SMats Randgaard struct v4l2_dv_timings timings; 835d32d9864SMats Randgaard const struct v4l2_event tc358743_ev_fmt = { 836d32d9864SMats Randgaard .type = V4L2_EVENT_SOURCE_CHANGE, 837d32d9864SMats Randgaard .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, 838d32d9864SMats Randgaard }; 839d32d9864SMats Randgaard 840d32d9864SMats Randgaard if (tc358743_get_detected_timings(sd, &timings)) { 841d32d9864SMats Randgaard enable_stream(sd, false); 842d32d9864SMats Randgaard 843d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: Format changed. No signal\n", 844d32d9864SMats Randgaard __func__); 845d32d9864SMats Randgaard } else { 846d32d9864SMats Randgaard if (!v4l2_match_dv_timings(&state->timings, &timings, 0)) 847d32d9864SMats Randgaard enable_stream(sd, false); 848d32d9864SMats Randgaard 849d32d9864SMats Randgaard v4l2_print_dv_timings(sd->name, 850d32d9864SMats Randgaard "tc358743_format_change: Format changed. New format: ", 851d32d9864SMats Randgaard &timings, false); 852d32d9864SMats Randgaard } 853d32d9864SMats Randgaard 854d32d9864SMats Randgaard v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT, 855d32d9864SMats Randgaard (void *)&tc358743_ev_fmt); 856d32d9864SMats Randgaard } 857d32d9864SMats Randgaard 858d32d9864SMats Randgaard static void tc358743_init_interrupts(struct v4l2_subdev *sd) 859d32d9864SMats Randgaard { 860d32d9864SMats Randgaard u16 i; 861d32d9864SMats Randgaard 862d32d9864SMats Randgaard /* clear interrupt status registers */ 863d32d9864SMats Randgaard for (i = SYS_INT; i <= KEY_INT; i++) 864d32d9864SMats Randgaard i2c_wr8(sd, i, 0xff); 865d32d9864SMats Randgaard 866d32d9864SMats Randgaard i2c_wr16(sd, INTSTATUS, 0xffff); 867d32d9864SMats Randgaard } 868d32d9864SMats Randgaard 869d32d9864SMats Randgaard static void tc358743_enable_interrupts(struct v4l2_subdev *sd, 870d32d9864SMats Randgaard bool cable_connected) 871d32d9864SMats Randgaard { 872d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s: cable connected = %d\n", __func__, 873d32d9864SMats Randgaard cable_connected); 874d32d9864SMats Randgaard 875d32d9864SMats Randgaard if (cable_connected) { 876d32d9864SMats Randgaard i2c_wr8(sd, SYS_INTM, ~(MASK_M_DDC | MASK_M_DVI_DET | 877d32d9864SMats Randgaard MASK_M_HDMI_DET) & 0xff); 878d32d9864SMats Randgaard i2c_wr8(sd, CLK_INTM, ~MASK_M_IN_DE_CHG); 879d32d9864SMats Randgaard i2c_wr8(sd, CBIT_INTM, ~(MASK_M_CBIT_FS | MASK_M_AF_LOCK | 880d32d9864SMats Randgaard MASK_M_AF_UNLOCK) & 0xff); 881d32d9864SMats Randgaard i2c_wr8(sd, AUDIO_INTM, ~MASK_M_BUFINIT_END); 882d32d9864SMats Randgaard i2c_wr8(sd, MISC_INTM, ~MASK_M_SYNC_CHG); 883d32d9864SMats Randgaard } else { 884d32d9864SMats Randgaard i2c_wr8(sd, SYS_INTM, ~MASK_M_DDC & 0xff); 885d32d9864SMats Randgaard i2c_wr8(sd, CLK_INTM, 0xff); 886d32d9864SMats Randgaard i2c_wr8(sd, CBIT_INTM, 0xff); 887d32d9864SMats Randgaard i2c_wr8(sd, AUDIO_INTM, 0xff); 888d32d9864SMats Randgaard i2c_wr8(sd, MISC_INTM, 0xff); 889d32d9864SMats Randgaard } 890d32d9864SMats Randgaard } 891d32d9864SMats Randgaard 892d32d9864SMats Randgaard static void tc358743_hdmi_audio_int_handler(struct v4l2_subdev *sd, 893d32d9864SMats Randgaard bool *handled) 894d32d9864SMats Randgaard { 895d32d9864SMats Randgaard u8 audio_int_mask = i2c_rd8(sd, AUDIO_INTM); 896d32d9864SMats Randgaard u8 audio_int = i2c_rd8(sd, AUDIO_INT) & ~audio_int_mask; 897d32d9864SMats Randgaard 898d32d9864SMats Randgaard i2c_wr8(sd, AUDIO_INT, audio_int); 899d32d9864SMats Randgaard 900d32d9864SMats Randgaard v4l2_dbg(3, debug, sd, "%s: AUDIO_INT = 0x%02x\n", __func__, audio_int); 901d32d9864SMats Randgaard 902d32d9864SMats Randgaard tc358743_s_ctrl_audio_sampling_rate(sd); 903d32d9864SMats Randgaard tc358743_s_ctrl_audio_present(sd); 904d32d9864SMats Randgaard } 905d32d9864SMats Randgaard 906d32d9864SMats Randgaard static void tc358743_csi_err_int_handler(struct v4l2_subdev *sd, bool *handled) 907d32d9864SMats Randgaard { 908d32d9864SMats Randgaard v4l2_err(sd, "%s: CSI_ERR = 0x%x\n", __func__, i2c_rd32(sd, CSI_ERR)); 909d32d9864SMats Randgaard 910d32d9864SMats Randgaard i2c_wr32(sd, CSI_INT_CLR, MASK_ICRER); 911d32d9864SMats Randgaard } 912d32d9864SMats Randgaard 913d32d9864SMats Randgaard static void tc358743_hdmi_misc_int_handler(struct v4l2_subdev *sd, 914d32d9864SMats Randgaard bool *handled) 915d32d9864SMats Randgaard { 916d32d9864SMats Randgaard u8 misc_int_mask = i2c_rd8(sd, MISC_INTM); 917d32d9864SMats Randgaard u8 misc_int = i2c_rd8(sd, MISC_INT) & ~misc_int_mask; 918d32d9864SMats Randgaard 919d32d9864SMats Randgaard i2c_wr8(sd, MISC_INT, misc_int); 920d32d9864SMats Randgaard 921d32d9864SMats Randgaard v4l2_dbg(3, debug, sd, "%s: MISC_INT = 0x%02x\n", __func__, misc_int); 922d32d9864SMats Randgaard 923d32d9864SMats Randgaard if (misc_int & MASK_I_SYNC_CHG) { 924d32d9864SMats Randgaard /* Reset the HDMI PHY to try to trigger proper lock on the 925d32d9864SMats Randgaard * incoming video format. Erase BKSV to prevent that old keys 926d32d9864SMats Randgaard * are used when a new source is connected. */ 927d32d9864SMats Randgaard if (no_sync(sd) || no_signal(sd)) { 928d32d9864SMats Randgaard tc358743_reset_phy(sd); 929d32d9864SMats Randgaard tc358743_erase_bksv(sd); 930d32d9864SMats Randgaard } 931d32d9864SMats Randgaard 932d32d9864SMats Randgaard tc358743_format_change(sd); 933d32d9864SMats Randgaard 934d32d9864SMats Randgaard misc_int &= ~MASK_I_SYNC_CHG; 935d32d9864SMats Randgaard if (handled) 936d32d9864SMats Randgaard *handled = true; 937d32d9864SMats Randgaard } 938d32d9864SMats Randgaard 939d32d9864SMats Randgaard if (misc_int) { 940d32d9864SMats Randgaard v4l2_err(sd, "%s: Unhandled MISC_INT interrupts: 0x%02x\n", 941d32d9864SMats Randgaard __func__, misc_int); 942d32d9864SMats Randgaard } 943d32d9864SMats Randgaard } 944d32d9864SMats Randgaard 945d32d9864SMats Randgaard static void tc358743_hdmi_cbit_int_handler(struct v4l2_subdev *sd, 946d32d9864SMats Randgaard bool *handled) 947d32d9864SMats Randgaard { 948d32d9864SMats Randgaard u8 cbit_int_mask = i2c_rd8(sd, CBIT_INTM); 949d32d9864SMats Randgaard u8 cbit_int = i2c_rd8(sd, CBIT_INT) & ~cbit_int_mask; 950d32d9864SMats Randgaard 951d32d9864SMats Randgaard i2c_wr8(sd, CBIT_INT, cbit_int); 952d32d9864SMats Randgaard 953d32d9864SMats Randgaard v4l2_dbg(3, debug, sd, "%s: CBIT_INT = 0x%02x\n", __func__, cbit_int); 954d32d9864SMats Randgaard 955d32d9864SMats Randgaard if (cbit_int & MASK_I_CBIT_FS) { 956d32d9864SMats Randgaard 957d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: Audio sample rate changed\n", 958d32d9864SMats Randgaard __func__); 959d32d9864SMats Randgaard tc358743_s_ctrl_audio_sampling_rate(sd); 960d32d9864SMats Randgaard 961d32d9864SMats Randgaard cbit_int &= ~MASK_I_CBIT_FS; 962d32d9864SMats Randgaard if (handled) 963d32d9864SMats Randgaard *handled = true; 964d32d9864SMats Randgaard } 965d32d9864SMats Randgaard 966d32d9864SMats Randgaard if (cbit_int & (MASK_I_AF_LOCK | MASK_I_AF_UNLOCK)) { 967d32d9864SMats Randgaard 968d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: Audio present changed\n", 969d32d9864SMats Randgaard __func__); 970d32d9864SMats Randgaard tc358743_s_ctrl_audio_present(sd); 971d32d9864SMats Randgaard 972d32d9864SMats Randgaard cbit_int &= ~(MASK_I_AF_LOCK | MASK_I_AF_UNLOCK); 973d32d9864SMats Randgaard if (handled) 974d32d9864SMats Randgaard *handled = true; 975d32d9864SMats Randgaard } 976d32d9864SMats Randgaard 977d32d9864SMats Randgaard if (cbit_int) { 978d32d9864SMats Randgaard v4l2_err(sd, "%s: Unhandled CBIT_INT interrupts: 0x%02x\n", 979d32d9864SMats Randgaard __func__, cbit_int); 980d32d9864SMats Randgaard } 981d32d9864SMats Randgaard } 982d32d9864SMats Randgaard 983d32d9864SMats Randgaard static void tc358743_hdmi_clk_int_handler(struct v4l2_subdev *sd, bool *handled) 984d32d9864SMats Randgaard { 985d32d9864SMats Randgaard u8 clk_int_mask = i2c_rd8(sd, CLK_INTM); 986d32d9864SMats Randgaard u8 clk_int = i2c_rd8(sd, CLK_INT) & ~clk_int_mask; 987d32d9864SMats Randgaard 988d32d9864SMats Randgaard /* Bit 7 and bit 6 are set even when they are masked */ 989d32d9864SMats Randgaard i2c_wr8(sd, CLK_INT, clk_int | 0x80 | MASK_I_OUT_H_CHG); 990d32d9864SMats Randgaard 991d32d9864SMats Randgaard v4l2_dbg(3, debug, sd, "%s: CLK_INT = 0x%02x\n", __func__, clk_int); 992d32d9864SMats Randgaard 993d32d9864SMats Randgaard if (clk_int & (MASK_I_IN_DE_CHG)) { 994d32d9864SMats Randgaard 995d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: DE size or position has changed\n", 996d32d9864SMats Randgaard __func__); 997d32d9864SMats Randgaard 998d32d9864SMats Randgaard /* If the source switch to a new resolution with the same pixel 999d32d9864SMats Randgaard * frequency as the existing (e.g. 1080p25 -> 720p50), the 1000d32d9864SMats Randgaard * I_SYNC_CHG interrupt is not always triggered, while the 1001d32d9864SMats Randgaard * I_IN_DE_CHG interrupt seems to work fine. Format change 1002d32d9864SMats Randgaard * notifications are only sent when the signal is stable to 1003d32d9864SMats Randgaard * reduce the number of notifications. */ 1004d32d9864SMats Randgaard if (!no_signal(sd) && !no_sync(sd)) 1005d32d9864SMats Randgaard tc358743_format_change(sd); 1006d32d9864SMats Randgaard 1007d32d9864SMats Randgaard clk_int &= ~(MASK_I_IN_DE_CHG); 1008d32d9864SMats Randgaard if (handled) 1009d32d9864SMats Randgaard *handled = true; 1010d32d9864SMats Randgaard } 1011d32d9864SMats Randgaard 1012d32d9864SMats Randgaard if (clk_int) { 1013d32d9864SMats Randgaard v4l2_err(sd, "%s: Unhandled CLK_INT interrupts: 0x%02x\n", 1014d32d9864SMats Randgaard __func__, clk_int); 1015d32d9864SMats Randgaard } 1016d32d9864SMats Randgaard } 1017d32d9864SMats Randgaard 1018d32d9864SMats Randgaard static void tc358743_hdmi_sys_int_handler(struct v4l2_subdev *sd, bool *handled) 1019d32d9864SMats Randgaard { 1020d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 1021d32d9864SMats Randgaard u8 sys_int_mask = i2c_rd8(sd, SYS_INTM); 1022d32d9864SMats Randgaard u8 sys_int = i2c_rd8(sd, SYS_INT) & ~sys_int_mask; 1023d32d9864SMats Randgaard 1024d32d9864SMats Randgaard i2c_wr8(sd, SYS_INT, sys_int); 1025d32d9864SMats Randgaard 1026d32d9864SMats Randgaard v4l2_dbg(3, debug, sd, "%s: SYS_INT = 0x%02x\n", __func__, sys_int); 1027d32d9864SMats Randgaard 1028d32d9864SMats Randgaard if (sys_int & MASK_I_DDC) { 1029d32d9864SMats Randgaard bool tx_5v = tx_5v_power_present(sd); 1030d32d9864SMats Randgaard 1031d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: Tx 5V power present: %s\n", 1032d32d9864SMats Randgaard __func__, tx_5v ? "yes" : "no"); 1033d32d9864SMats Randgaard 1034d32d9864SMats Randgaard if (tx_5v) { 1035d32d9864SMats Randgaard tc358743_enable_edid(sd); 1036d32d9864SMats Randgaard } else { 1037d32d9864SMats Randgaard tc358743_enable_interrupts(sd, false); 1038d32d9864SMats Randgaard tc358743_disable_edid(sd); 1039d32d9864SMats Randgaard memset(&state->timings, 0, sizeof(state->timings)); 1040d32d9864SMats Randgaard tc358743_erase_bksv(sd); 1041d32d9864SMats Randgaard tc358743_update_controls(sd); 1042d32d9864SMats Randgaard } 1043d32d9864SMats Randgaard 1044d32d9864SMats Randgaard sys_int &= ~MASK_I_DDC; 1045d32d9864SMats Randgaard if (handled) 1046d32d9864SMats Randgaard *handled = true; 1047d32d9864SMats Randgaard } 1048d32d9864SMats Randgaard 1049d32d9864SMats Randgaard if (sys_int & MASK_I_DVI) { 1050d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: HDMI->DVI change detected\n", 1051d32d9864SMats Randgaard __func__); 1052d32d9864SMats Randgaard 1053d32d9864SMats Randgaard /* Reset the HDMI PHY to try to trigger proper lock on the 1054d32d9864SMats Randgaard * incoming video format. Erase BKSV to prevent that old keys 1055d32d9864SMats Randgaard * are used when a new source is connected. */ 1056d32d9864SMats Randgaard if (no_sync(sd) || no_signal(sd)) { 1057d32d9864SMats Randgaard tc358743_reset_phy(sd); 1058d32d9864SMats Randgaard tc358743_erase_bksv(sd); 1059d32d9864SMats Randgaard } 1060d32d9864SMats Randgaard 1061d32d9864SMats Randgaard sys_int &= ~MASK_I_DVI; 1062d32d9864SMats Randgaard if (handled) 1063d32d9864SMats Randgaard *handled = true; 1064d32d9864SMats Randgaard } 1065d32d9864SMats Randgaard 1066d32d9864SMats Randgaard if (sys_int & MASK_I_HDMI) { 1067d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: DVI->HDMI change detected\n", 1068d32d9864SMats Randgaard __func__); 1069d32d9864SMats Randgaard 1070d32d9864SMats Randgaard /* Register is reset in DVI mode (REF_01, c. 6.6.41) */ 1071d32d9864SMats Randgaard i2c_wr8(sd, ANA_CTL, MASK_APPL_PCSX_NORMAL | MASK_ANALOG_ON); 1072d32d9864SMats Randgaard 1073d32d9864SMats Randgaard sys_int &= ~MASK_I_HDMI; 1074d32d9864SMats Randgaard if (handled) 1075d32d9864SMats Randgaard *handled = true; 1076d32d9864SMats Randgaard } 1077d32d9864SMats Randgaard 1078d32d9864SMats Randgaard if (sys_int) { 1079d32d9864SMats Randgaard v4l2_err(sd, "%s: Unhandled SYS_INT interrupts: 0x%02x\n", 1080d32d9864SMats Randgaard __func__, sys_int); 1081d32d9864SMats Randgaard } 1082d32d9864SMats Randgaard } 1083d32d9864SMats Randgaard 1084d32d9864SMats Randgaard /* --------------- CORE OPS --------------- */ 1085d32d9864SMats Randgaard 1086d32d9864SMats Randgaard static int tc358743_log_status(struct v4l2_subdev *sd) 1087d32d9864SMats Randgaard { 1088d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 1089d32d9864SMats Randgaard struct v4l2_dv_timings timings; 1090d32d9864SMats Randgaard uint8_t hdmi_sys_status = i2c_rd8(sd, SYS_STATUS); 1091d32d9864SMats Randgaard uint16_t sysctl = i2c_rd16(sd, SYSCTL); 1092d32d9864SMats Randgaard u8 vi_status3 = i2c_rd8(sd, VI_STATUS3); 1093d32d9864SMats Randgaard const int deep_color_mode[4] = { 8, 10, 12, 16 }; 1094d32d9864SMats Randgaard static const char * const input_color_space[] = { 1095d32d9864SMats Randgaard "RGB", "YCbCr 601", "Adobe RGB", "YCbCr 709", "NA (4)", 1096d32d9864SMats Randgaard "xvYCC 601", "NA(6)", "xvYCC 709", "NA(8)", "sYCC601", 1097d32d9864SMats Randgaard "NA(10)", "NA(11)", "NA(12)", "Adobe YCC 601"}; 1098d32d9864SMats Randgaard 1099d32d9864SMats Randgaard v4l2_info(sd, "-----Chip status-----\n"); 1100d32d9864SMats Randgaard v4l2_info(sd, "Chip ID: 0x%02x\n", 1101d32d9864SMats Randgaard (i2c_rd16(sd, CHIPID) & MASK_CHIPID) >> 8); 1102d32d9864SMats Randgaard v4l2_info(sd, "Chip revision: 0x%02x\n", 1103d32d9864SMats Randgaard i2c_rd16(sd, CHIPID) & MASK_REVID); 1104d32d9864SMats Randgaard v4l2_info(sd, "Reset: IR: %d, CEC: %d, CSI TX: %d, HDMI: %d\n", 1105d32d9864SMats Randgaard !!(sysctl & MASK_IRRST), 1106d32d9864SMats Randgaard !!(sysctl & MASK_CECRST), 1107d32d9864SMats Randgaard !!(sysctl & MASK_CTXRST), 1108d32d9864SMats Randgaard !!(sysctl & MASK_HDMIRST)); 1109d32d9864SMats Randgaard v4l2_info(sd, "Sleep mode: %s\n", sysctl & MASK_SLEEP ? "on" : "off"); 1110d32d9864SMats Randgaard v4l2_info(sd, "Cable detected (+5V power): %s\n", 1111d32d9864SMats Randgaard hdmi_sys_status & MASK_S_DDC5V ? "yes" : "no"); 1112d32d9864SMats Randgaard v4l2_info(sd, "DDC lines enabled: %s\n", 1113d32d9864SMats Randgaard (i2c_rd8(sd, EDID_MODE) & MASK_EDID_MODE_E_DDC) ? 1114d32d9864SMats Randgaard "yes" : "no"); 1115d32d9864SMats Randgaard v4l2_info(sd, "Hotplug enabled: %s\n", 1116d32d9864SMats Randgaard (i2c_rd8(sd, HPD_CTL) & MASK_HPD_OUT0) ? 1117d32d9864SMats Randgaard "yes" : "no"); 1118d32d9864SMats Randgaard v4l2_info(sd, "CEC enabled: %s\n", 1119d32d9864SMats Randgaard (i2c_rd16(sd, CECEN) & MASK_CECEN) ? "yes" : "no"); 1120d32d9864SMats Randgaard v4l2_info(sd, "-----Signal status-----\n"); 1121d32d9864SMats Randgaard v4l2_info(sd, "TMDS signal detected: %s\n", 1122d32d9864SMats Randgaard hdmi_sys_status & MASK_S_TMDS ? "yes" : "no"); 1123d32d9864SMats Randgaard v4l2_info(sd, "Stable sync signal: %s\n", 1124d32d9864SMats Randgaard hdmi_sys_status & MASK_S_SYNC ? "yes" : "no"); 1125d32d9864SMats Randgaard v4l2_info(sd, "PHY PLL locked: %s\n", 1126d32d9864SMats Randgaard hdmi_sys_status & MASK_S_PHY_PLL ? "yes" : "no"); 1127d32d9864SMats Randgaard v4l2_info(sd, "PHY DE detected: %s\n", 1128d32d9864SMats Randgaard hdmi_sys_status & MASK_S_PHY_SCDT ? "yes" : "no"); 1129d32d9864SMats Randgaard 1130d32d9864SMats Randgaard if (tc358743_get_detected_timings(sd, &timings)) { 1131d32d9864SMats Randgaard v4l2_info(sd, "No video detected\n"); 1132d32d9864SMats Randgaard } else { 1133d32d9864SMats Randgaard v4l2_print_dv_timings(sd->name, "Detected format: ", &timings, 1134d32d9864SMats Randgaard true); 1135d32d9864SMats Randgaard } 1136d32d9864SMats Randgaard v4l2_print_dv_timings(sd->name, "Configured format: ", &state->timings, 1137d32d9864SMats Randgaard true); 1138d32d9864SMats Randgaard 1139d32d9864SMats Randgaard v4l2_info(sd, "-----CSI-TX status-----\n"); 1140d32d9864SMats Randgaard v4l2_info(sd, "Lanes needed: %d\n", 1141d32d9864SMats Randgaard tc358743_num_csi_lanes_needed(sd)); 1142d32d9864SMats Randgaard v4l2_info(sd, "Lanes in use: %d\n", 1143d32d9864SMats Randgaard tc358743_num_csi_lanes_in_use(sd)); 1144d32d9864SMats Randgaard v4l2_info(sd, "Waiting for particular sync signal: %s\n", 1145d32d9864SMats Randgaard (i2c_rd16(sd, CSI_STATUS) & MASK_S_WSYNC) ? 1146d32d9864SMats Randgaard "yes" : "no"); 1147d32d9864SMats Randgaard v4l2_info(sd, "Transmit mode: %s\n", 1148d32d9864SMats Randgaard (i2c_rd16(sd, CSI_STATUS) & MASK_S_TXACT) ? 1149d32d9864SMats Randgaard "yes" : "no"); 1150d32d9864SMats Randgaard v4l2_info(sd, "Receive mode: %s\n", 1151d32d9864SMats Randgaard (i2c_rd16(sd, CSI_STATUS) & MASK_S_RXACT) ? 1152d32d9864SMats Randgaard "yes" : "no"); 1153d32d9864SMats Randgaard v4l2_info(sd, "Stopped: %s\n", 1154d32d9864SMats Randgaard (i2c_rd16(sd, CSI_STATUS) & MASK_S_HLT) ? 1155d32d9864SMats Randgaard "yes" : "no"); 1156d32d9864SMats Randgaard v4l2_info(sd, "Color space: %s\n", 1157d32d9864SMats Randgaard state->mbus_fmt_code == MEDIA_BUS_FMT_UYVY8_1X16 ? 1158d32d9864SMats Randgaard "YCbCr 422 16-bit" : 1159d32d9864SMats Randgaard state->mbus_fmt_code == MEDIA_BUS_FMT_RGB888_1X24 ? 1160d32d9864SMats Randgaard "RGB 888 24-bit" : "Unsupported"); 1161d32d9864SMats Randgaard 1162d32d9864SMats Randgaard v4l2_info(sd, "-----%s status-----\n", is_hdmi(sd) ? "HDMI" : "DVI-D"); 1163d32d9864SMats Randgaard v4l2_info(sd, "HDCP encrypted content: %s\n", 1164d32d9864SMats Randgaard hdmi_sys_status & MASK_S_HDCP ? "yes" : "no"); 1165d32d9864SMats Randgaard v4l2_info(sd, "Input color space: %s %s range\n", 1166d32d9864SMats Randgaard input_color_space[(vi_status3 & MASK_S_V_COLOR) >> 1], 1167d32d9864SMats Randgaard (vi_status3 & MASK_LIMITED) ? "limited" : "full"); 1168d32d9864SMats Randgaard if (!is_hdmi(sd)) 1169d32d9864SMats Randgaard return 0; 1170d32d9864SMats Randgaard v4l2_info(sd, "AV Mute: %s\n", hdmi_sys_status & MASK_S_AVMUTE ? "on" : 1171d32d9864SMats Randgaard "off"); 1172d32d9864SMats Randgaard v4l2_info(sd, "Deep color mode: %d-bits per channel\n", 1173d32d9864SMats Randgaard deep_color_mode[(i2c_rd8(sd, VI_STATUS1) & 1174d32d9864SMats Randgaard MASK_S_DEEPCOLOR) >> 2]); 1175d32d9864SMats Randgaard print_avi_infoframe(sd); 1176d32d9864SMats Randgaard 1177d32d9864SMats Randgaard return 0; 1178d32d9864SMats Randgaard } 1179d32d9864SMats Randgaard 1180d32d9864SMats Randgaard #ifdef CONFIG_VIDEO_ADV_DEBUG 1181d32d9864SMats Randgaard static void tc358743_print_register_map(struct v4l2_subdev *sd) 1182d32d9864SMats Randgaard { 1183d32d9864SMats Randgaard v4l2_info(sd, "0x0000–0x00FF: Global Control Register\n"); 1184d32d9864SMats Randgaard v4l2_info(sd, "0x0100–0x01FF: CSI2-TX PHY Register\n"); 1185d32d9864SMats Randgaard v4l2_info(sd, "0x0200–0x03FF: CSI2-TX PPI Register\n"); 1186d32d9864SMats Randgaard v4l2_info(sd, "0x0400–0x05FF: Reserved\n"); 1187d32d9864SMats Randgaard v4l2_info(sd, "0x0600–0x06FF: CEC Register\n"); 1188d32d9864SMats Randgaard v4l2_info(sd, "0x0700–0x84FF: Reserved\n"); 1189d32d9864SMats Randgaard v4l2_info(sd, "0x8500–0x85FF: HDMIRX System Control Register\n"); 1190d32d9864SMats Randgaard v4l2_info(sd, "0x8600–0x86FF: HDMIRX Audio Control Register\n"); 1191d32d9864SMats Randgaard v4l2_info(sd, "0x8700–0x87FF: HDMIRX InfoFrame packet data Register\n"); 1192d32d9864SMats Randgaard v4l2_info(sd, "0x8800–0x88FF: HDMIRX HDCP Port Register\n"); 1193d32d9864SMats Randgaard v4l2_info(sd, "0x8900–0x89FF: HDMIRX Video Output Port & 3D Register\n"); 1194d32d9864SMats Randgaard v4l2_info(sd, "0x8A00–0x8BFF: Reserved\n"); 1195d32d9864SMats Randgaard v4l2_info(sd, "0x8C00–0x8FFF: HDMIRX EDID-RAM (1024bytes)\n"); 1196d32d9864SMats Randgaard v4l2_info(sd, "0x9000–0x90FF: HDMIRX GBD Extraction Control\n"); 1197d32d9864SMats Randgaard v4l2_info(sd, "0x9100–0x92FF: HDMIRX GBD RAM read\n"); 1198d32d9864SMats Randgaard v4l2_info(sd, "0x9300- : Reserved\n"); 1199d32d9864SMats Randgaard } 1200d32d9864SMats Randgaard 1201d32d9864SMats Randgaard static int tc358743_get_reg_size(u16 address) 1202d32d9864SMats Randgaard { 1203d32d9864SMats Randgaard /* REF_01 p. 66-72 */ 1204d32d9864SMats Randgaard if (address <= 0x00ff) 1205d32d9864SMats Randgaard return 2; 1206d32d9864SMats Randgaard else if ((address >= 0x0100) && (address <= 0x06FF)) 1207d32d9864SMats Randgaard return 4; 1208d32d9864SMats Randgaard else if ((address >= 0x0700) && (address <= 0x84ff)) 1209d32d9864SMats Randgaard return 2; 1210d32d9864SMats Randgaard else 1211d32d9864SMats Randgaard return 1; 1212d32d9864SMats Randgaard } 1213d32d9864SMats Randgaard 1214d32d9864SMats Randgaard static int tc358743_g_register(struct v4l2_subdev *sd, 1215d32d9864SMats Randgaard struct v4l2_dbg_register *reg) 1216d32d9864SMats Randgaard { 1217d32d9864SMats Randgaard if (reg->reg > 0xffff) { 1218d32d9864SMats Randgaard tc358743_print_register_map(sd); 1219d32d9864SMats Randgaard return -EINVAL; 1220d32d9864SMats Randgaard } 1221d32d9864SMats Randgaard 1222d32d9864SMats Randgaard reg->size = tc358743_get_reg_size(reg->reg); 1223d32d9864SMats Randgaard 1224d32d9864SMats Randgaard i2c_rd(sd, reg->reg, (u8 *)®->val, reg->size); 1225d32d9864SMats Randgaard 1226d32d9864SMats Randgaard return 0; 1227d32d9864SMats Randgaard } 1228d32d9864SMats Randgaard 1229d32d9864SMats Randgaard static int tc358743_s_register(struct v4l2_subdev *sd, 1230d32d9864SMats Randgaard const struct v4l2_dbg_register *reg) 1231d32d9864SMats Randgaard { 1232d32d9864SMats Randgaard if (reg->reg > 0xffff) { 1233d32d9864SMats Randgaard tc358743_print_register_map(sd); 1234d32d9864SMats Randgaard return -EINVAL; 1235d32d9864SMats Randgaard } 1236d32d9864SMats Randgaard 1237d32d9864SMats Randgaard /* It should not be possible for the user to enable HDCP with a simple 1238d32d9864SMats Randgaard * v4l2-dbg command. 1239d32d9864SMats Randgaard * 1240d32d9864SMats Randgaard * DO NOT REMOVE THIS unless all other issues with HDCP have been 1241d32d9864SMats Randgaard * resolved. 1242d32d9864SMats Randgaard */ 1243d32d9864SMats Randgaard if (reg->reg == HDCP_MODE || 1244d32d9864SMats Randgaard reg->reg == HDCP_REG1 || 1245d32d9864SMats Randgaard reg->reg == HDCP_REG2 || 1246d32d9864SMats Randgaard reg->reg == HDCP_REG3 || 1247d32d9864SMats Randgaard reg->reg == BCAPS) 1248d32d9864SMats Randgaard return 0; 1249d32d9864SMats Randgaard 1250d32d9864SMats Randgaard i2c_wr(sd, (u16)reg->reg, (u8 *)®->val, 1251d32d9864SMats Randgaard tc358743_get_reg_size(reg->reg)); 1252d32d9864SMats Randgaard 1253d32d9864SMats Randgaard return 0; 1254d32d9864SMats Randgaard } 1255d32d9864SMats Randgaard #endif 1256d32d9864SMats Randgaard 1257d32d9864SMats Randgaard static int tc358743_isr(struct v4l2_subdev *sd, u32 status, bool *handled) 1258d32d9864SMats Randgaard { 1259d32d9864SMats Randgaard u16 intstatus = i2c_rd16(sd, INTSTATUS); 1260d32d9864SMats Randgaard 1261d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: IntStatus = 0x%04x\n", __func__, intstatus); 1262d32d9864SMats Randgaard 1263d32d9864SMats Randgaard if (intstatus & MASK_HDMI_INT) { 1264d32d9864SMats Randgaard u8 hdmi_int0 = i2c_rd8(sd, HDMI_INT0); 1265d32d9864SMats Randgaard u8 hdmi_int1 = i2c_rd8(sd, HDMI_INT1); 1266d32d9864SMats Randgaard 1267d32d9864SMats Randgaard if (hdmi_int0 & MASK_I_MISC) 1268d32d9864SMats Randgaard tc358743_hdmi_misc_int_handler(sd, handled); 1269d32d9864SMats Randgaard if (hdmi_int1 & MASK_I_CBIT) 1270d32d9864SMats Randgaard tc358743_hdmi_cbit_int_handler(sd, handled); 1271d32d9864SMats Randgaard if (hdmi_int1 & MASK_I_CLK) 1272d32d9864SMats Randgaard tc358743_hdmi_clk_int_handler(sd, handled); 1273d32d9864SMats Randgaard if (hdmi_int1 & MASK_I_SYS) 1274d32d9864SMats Randgaard tc358743_hdmi_sys_int_handler(sd, handled); 1275d32d9864SMats Randgaard if (hdmi_int1 & MASK_I_AUD) 1276d32d9864SMats Randgaard tc358743_hdmi_audio_int_handler(sd, handled); 1277d32d9864SMats Randgaard 1278d32d9864SMats Randgaard i2c_wr16(sd, INTSTATUS, MASK_HDMI_INT); 1279d32d9864SMats Randgaard intstatus &= ~MASK_HDMI_INT; 1280d32d9864SMats Randgaard } 1281d32d9864SMats Randgaard 1282d32d9864SMats Randgaard if (intstatus & MASK_CSI_INT) { 1283d32d9864SMats Randgaard u32 csi_int = i2c_rd32(sd, CSI_INT); 1284d32d9864SMats Randgaard 1285d32d9864SMats Randgaard if (csi_int & MASK_INTER) 1286d32d9864SMats Randgaard tc358743_csi_err_int_handler(sd, handled); 1287d32d9864SMats Randgaard 1288d32d9864SMats Randgaard i2c_wr16(sd, INTSTATUS, MASK_CSI_INT); 1289d32d9864SMats Randgaard intstatus &= ~MASK_CSI_INT; 1290d32d9864SMats Randgaard } 1291d32d9864SMats Randgaard 1292d32d9864SMats Randgaard intstatus = i2c_rd16(sd, INTSTATUS); 1293d32d9864SMats Randgaard if (intstatus) { 1294d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, 1295d32d9864SMats Randgaard "%s: Unhandled IntStatus interrupts: 0x%02x\n", 1296d32d9864SMats Randgaard __func__, intstatus); 1297d32d9864SMats Randgaard } 1298d32d9864SMats Randgaard 1299d32d9864SMats Randgaard return 0; 1300d32d9864SMats Randgaard } 1301d32d9864SMats Randgaard 1302d32d9864SMats Randgaard /* --------------- VIDEO OPS --------------- */ 1303d32d9864SMats Randgaard 1304d32d9864SMats Randgaard static int tc358743_g_input_status(struct v4l2_subdev *sd, u32 *status) 1305d32d9864SMats Randgaard { 1306d32d9864SMats Randgaard *status = 0; 1307d32d9864SMats Randgaard *status |= no_signal(sd) ? V4L2_IN_ST_NO_SIGNAL : 0; 1308d32d9864SMats Randgaard *status |= no_sync(sd) ? V4L2_IN_ST_NO_SYNC : 0; 1309d32d9864SMats Randgaard 1310d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: status = 0x%x\n", __func__, *status); 1311d32d9864SMats Randgaard 1312d32d9864SMats Randgaard return 0; 1313d32d9864SMats Randgaard } 1314d32d9864SMats Randgaard 1315d32d9864SMats Randgaard static int tc358743_s_dv_timings(struct v4l2_subdev *sd, 1316d32d9864SMats Randgaard struct v4l2_dv_timings *timings) 1317d32d9864SMats Randgaard { 1318d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 1319d32d9864SMats Randgaard struct v4l2_bt_timings *bt; 1320d32d9864SMats Randgaard 1321d32d9864SMats Randgaard if (!timings) 1322d32d9864SMats Randgaard return -EINVAL; 1323d32d9864SMats Randgaard 1324d32d9864SMats Randgaard if (debug) 1325d32d9864SMats Randgaard v4l2_print_dv_timings(sd->name, "tc358743_s_dv_timings: ", 1326d32d9864SMats Randgaard timings, false); 1327d32d9864SMats Randgaard 1328d32d9864SMats Randgaard if (v4l2_match_dv_timings(&state->timings, timings, 0)) { 1329d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: no change\n", __func__); 1330d32d9864SMats Randgaard return 0; 1331d32d9864SMats Randgaard } 1332d32d9864SMats Randgaard 1333d32d9864SMats Randgaard bt = &timings->bt; 1334d32d9864SMats Randgaard 1335d32d9864SMats Randgaard if (!v4l2_valid_dv_timings(timings, 1336d32d9864SMats Randgaard &tc358743_timings_cap, NULL, NULL)) { 1337d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: timings out of range\n", __func__); 1338d32d9864SMats Randgaard return -ERANGE; 1339d32d9864SMats Randgaard } 1340d32d9864SMats Randgaard 1341d32d9864SMats Randgaard state->timings = *timings; 1342d32d9864SMats Randgaard 1343d32d9864SMats Randgaard enable_stream(sd, false); 1344d32d9864SMats Randgaard tc358743_set_pll(sd); 1345d32d9864SMats Randgaard tc358743_set_csi(sd); 1346d32d9864SMats Randgaard 1347d32d9864SMats Randgaard return 0; 1348d32d9864SMats Randgaard } 1349d32d9864SMats Randgaard 1350d32d9864SMats Randgaard static int tc358743_g_dv_timings(struct v4l2_subdev *sd, 1351d32d9864SMats Randgaard struct v4l2_dv_timings *timings) 1352d32d9864SMats Randgaard { 1353d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 1354d32d9864SMats Randgaard 1355d32d9864SMats Randgaard *timings = state->timings; 1356d32d9864SMats Randgaard 1357d32d9864SMats Randgaard return 0; 1358d32d9864SMats Randgaard } 1359d32d9864SMats Randgaard 1360d32d9864SMats Randgaard static int tc358743_enum_dv_timings(struct v4l2_subdev *sd, 1361d32d9864SMats Randgaard struct v4l2_enum_dv_timings *timings) 1362d32d9864SMats Randgaard { 1363d32d9864SMats Randgaard if (timings->pad != 0) 1364d32d9864SMats Randgaard return -EINVAL; 1365d32d9864SMats Randgaard 1366d32d9864SMats Randgaard return v4l2_enum_dv_timings_cap(timings, 1367d32d9864SMats Randgaard &tc358743_timings_cap, NULL, NULL); 1368d32d9864SMats Randgaard } 1369d32d9864SMats Randgaard 1370d32d9864SMats Randgaard static int tc358743_query_dv_timings(struct v4l2_subdev *sd, 1371d32d9864SMats Randgaard struct v4l2_dv_timings *timings) 1372d32d9864SMats Randgaard { 1373d32d9864SMats Randgaard int ret; 1374d32d9864SMats Randgaard 1375d32d9864SMats Randgaard ret = tc358743_get_detected_timings(sd, timings); 1376d32d9864SMats Randgaard if (ret) 1377d32d9864SMats Randgaard return ret; 1378d32d9864SMats Randgaard 1379d32d9864SMats Randgaard if (debug) 1380d32d9864SMats Randgaard v4l2_print_dv_timings(sd->name, "tc358743_query_dv_timings: ", 1381d32d9864SMats Randgaard timings, false); 1382d32d9864SMats Randgaard 1383d32d9864SMats Randgaard if (!v4l2_valid_dv_timings(timings, 1384d32d9864SMats Randgaard &tc358743_timings_cap, NULL, NULL)) { 1385d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: timings out of range\n", __func__); 1386d32d9864SMats Randgaard return -ERANGE; 1387d32d9864SMats Randgaard } 1388d32d9864SMats Randgaard 1389d32d9864SMats Randgaard return 0; 1390d32d9864SMats Randgaard } 1391d32d9864SMats Randgaard 1392d32d9864SMats Randgaard static int tc358743_dv_timings_cap(struct v4l2_subdev *sd, 1393d32d9864SMats Randgaard struct v4l2_dv_timings_cap *cap) 1394d32d9864SMats Randgaard { 1395d32d9864SMats Randgaard if (cap->pad != 0) 1396d32d9864SMats Randgaard return -EINVAL; 1397d32d9864SMats Randgaard 1398d32d9864SMats Randgaard *cap = tc358743_timings_cap; 1399d32d9864SMats Randgaard 1400d32d9864SMats Randgaard return 0; 1401d32d9864SMats Randgaard } 1402d32d9864SMats Randgaard 1403d32d9864SMats Randgaard static int tc358743_g_mbus_config(struct v4l2_subdev *sd, 1404d32d9864SMats Randgaard struct v4l2_mbus_config *cfg) 1405d32d9864SMats Randgaard { 1406d32d9864SMats Randgaard cfg->type = V4L2_MBUS_CSI2; 1407d32d9864SMats Randgaard 1408d32d9864SMats Randgaard /* Support for non-continuous CSI-2 clock is missing in the driver */ 1409d32d9864SMats Randgaard cfg->flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; 1410d32d9864SMats Randgaard 1411d32d9864SMats Randgaard switch (tc358743_num_csi_lanes_in_use(sd)) { 1412d32d9864SMats Randgaard case 1: 1413d32d9864SMats Randgaard cfg->flags |= V4L2_MBUS_CSI2_1_LANE; 1414d32d9864SMats Randgaard break; 1415d32d9864SMats Randgaard case 2: 1416d32d9864SMats Randgaard cfg->flags |= V4L2_MBUS_CSI2_2_LANE; 1417d32d9864SMats Randgaard break; 1418d32d9864SMats Randgaard case 3: 1419d32d9864SMats Randgaard cfg->flags |= V4L2_MBUS_CSI2_3_LANE; 1420d32d9864SMats Randgaard break; 1421d32d9864SMats Randgaard case 4: 1422d32d9864SMats Randgaard cfg->flags |= V4L2_MBUS_CSI2_4_LANE; 1423d32d9864SMats Randgaard break; 1424d32d9864SMats Randgaard default: 1425d32d9864SMats Randgaard return -EINVAL; 1426d32d9864SMats Randgaard } 1427d32d9864SMats Randgaard 1428d32d9864SMats Randgaard return 0; 1429d32d9864SMats Randgaard } 1430d32d9864SMats Randgaard 1431d32d9864SMats Randgaard static int tc358743_s_stream(struct v4l2_subdev *sd, int enable) 1432d32d9864SMats Randgaard { 1433d32d9864SMats Randgaard enable_stream(sd, enable); 1434d32d9864SMats Randgaard 1435d32d9864SMats Randgaard return 0; 1436d32d9864SMats Randgaard } 1437d32d9864SMats Randgaard 1438d32d9864SMats Randgaard /* --------------- PAD OPS --------------- */ 1439d32d9864SMats Randgaard 1440d32d9864SMats Randgaard static int tc358743_get_fmt(struct v4l2_subdev *sd, 1441d32d9864SMats Randgaard struct v4l2_subdev_pad_config *cfg, 1442d32d9864SMats Randgaard struct v4l2_subdev_format *format) 1443d32d9864SMats Randgaard { 1444d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 1445d32d9864SMats Randgaard u8 vi_rep = i2c_rd8(sd, VI_REP); 1446d32d9864SMats Randgaard 1447d32d9864SMats Randgaard if (format->pad != 0) 1448d32d9864SMats Randgaard return -EINVAL; 1449d32d9864SMats Randgaard 1450d32d9864SMats Randgaard format->format.code = state->mbus_fmt_code; 1451d32d9864SMats Randgaard format->format.width = state->timings.bt.width; 1452d32d9864SMats Randgaard format->format.height = state->timings.bt.height; 1453d32d9864SMats Randgaard format->format.field = V4L2_FIELD_NONE; 1454d32d9864SMats Randgaard 1455d32d9864SMats Randgaard switch (vi_rep & MASK_VOUT_COLOR_SEL) { 1456d32d9864SMats Randgaard case MASK_VOUT_COLOR_RGB_FULL: 1457d32d9864SMats Randgaard case MASK_VOUT_COLOR_RGB_LIMITED: 1458d32d9864SMats Randgaard format->format.colorspace = V4L2_COLORSPACE_SRGB; 1459d32d9864SMats Randgaard break; 1460d32d9864SMats Randgaard case MASK_VOUT_COLOR_601_YCBCR_LIMITED: 1461d32d9864SMats Randgaard case MASK_VOUT_COLOR_601_YCBCR_FULL: 1462d32d9864SMats Randgaard format->format.colorspace = V4L2_COLORSPACE_SMPTE170M; 1463d32d9864SMats Randgaard break; 1464d32d9864SMats Randgaard case MASK_VOUT_COLOR_709_YCBCR_FULL: 1465d32d9864SMats Randgaard case MASK_VOUT_COLOR_709_YCBCR_LIMITED: 1466d32d9864SMats Randgaard format->format.colorspace = V4L2_COLORSPACE_REC709; 1467d32d9864SMats Randgaard break; 1468d32d9864SMats Randgaard default: 1469d32d9864SMats Randgaard format->format.colorspace = 0; 1470d32d9864SMats Randgaard break; 1471d32d9864SMats Randgaard } 1472d32d9864SMats Randgaard 1473d32d9864SMats Randgaard return 0; 1474d32d9864SMats Randgaard } 1475d32d9864SMats Randgaard 1476d32d9864SMats Randgaard static int tc358743_set_fmt(struct v4l2_subdev *sd, 1477d32d9864SMats Randgaard struct v4l2_subdev_pad_config *cfg, 1478d32d9864SMats Randgaard struct v4l2_subdev_format *format) 1479d32d9864SMats Randgaard { 1480d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 1481d32d9864SMats Randgaard 1482d32d9864SMats Randgaard u32 code = format->format.code; /* is overwritten by get_fmt */ 1483d32d9864SMats Randgaard int ret = tc358743_get_fmt(sd, cfg, format); 1484d32d9864SMats Randgaard 1485d32d9864SMats Randgaard format->format.code = code; 1486d32d9864SMats Randgaard 1487d32d9864SMats Randgaard if (ret) 1488d32d9864SMats Randgaard return ret; 1489d32d9864SMats Randgaard 1490d32d9864SMats Randgaard switch (code) { 1491d32d9864SMats Randgaard case MEDIA_BUS_FMT_RGB888_1X24: 1492d32d9864SMats Randgaard case MEDIA_BUS_FMT_UYVY8_1X16: 1493d32d9864SMats Randgaard break; 1494d32d9864SMats Randgaard default: 1495d32d9864SMats Randgaard return -EINVAL; 1496d32d9864SMats Randgaard } 1497d32d9864SMats Randgaard 1498d32d9864SMats Randgaard if (format->which == V4L2_SUBDEV_FORMAT_TRY) 1499d32d9864SMats Randgaard return 0; 1500d32d9864SMats Randgaard 1501d32d9864SMats Randgaard state->mbus_fmt_code = format->format.code; 1502d32d9864SMats Randgaard 1503d32d9864SMats Randgaard enable_stream(sd, false); 1504d32d9864SMats Randgaard tc358743_set_pll(sd); 1505d32d9864SMats Randgaard tc358743_set_csi(sd); 1506d32d9864SMats Randgaard tc358743_set_csi_color_space(sd); 1507d32d9864SMats Randgaard 1508d32d9864SMats Randgaard return 0; 1509d32d9864SMats Randgaard } 1510d32d9864SMats Randgaard 1511d32d9864SMats Randgaard static int tc358743_g_edid(struct v4l2_subdev *sd, 1512d32d9864SMats Randgaard struct v4l2_subdev_edid *edid) 1513d32d9864SMats Randgaard { 1514d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 1515d32d9864SMats Randgaard 1516d32d9864SMats Randgaard if (edid->pad != 0) 1517d32d9864SMats Randgaard return -EINVAL; 1518d32d9864SMats Randgaard 1519d32d9864SMats Randgaard if (edid->start_block == 0 && edid->blocks == 0) { 1520d32d9864SMats Randgaard edid->blocks = state->edid_blocks_written; 1521d32d9864SMats Randgaard return 0; 1522d32d9864SMats Randgaard } 1523d32d9864SMats Randgaard 1524d32d9864SMats Randgaard if (state->edid_blocks_written == 0) 1525d32d9864SMats Randgaard return -ENODATA; 1526d32d9864SMats Randgaard 1527d32d9864SMats Randgaard if (edid->start_block >= state->edid_blocks_written || 1528d32d9864SMats Randgaard edid->blocks == 0) 1529d32d9864SMats Randgaard return -EINVAL; 1530d32d9864SMats Randgaard 1531d32d9864SMats Randgaard if (edid->start_block + edid->blocks > state->edid_blocks_written) 1532d32d9864SMats Randgaard edid->blocks = state->edid_blocks_written - edid->start_block; 1533d32d9864SMats Randgaard 1534d32d9864SMats Randgaard i2c_rd(sd, EDID_RAM + (edid->start_block * EDID_BLOCK_SIZE), edid->edid, 1535d32d9864SMats Randgaard edid->blocks * EDID_BLOCK_SIZE); 1536d32d9864SMats Randgaard 1537d32d9864SMats Randgaard return 0; 1538d32d9864SMats Randgaard } 1539d32d9864SMats Randgaard 1540d32d9864SMats Randgaard static int tc358743_s_edid(struct v4l2_subdev *sd, 1541d32d9864SMats Randgaard struct v4l2_subdev_edid *edid) 1542d32d9864SMats Randgaard { 1543d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 1544d32d9864SMats Randgaard u16 edid_len = edid->blocks * EDID_BLOCK_SIZE; 1545d32d9864SMats Randgaard 1546d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s, pad %d, start block %d, blocks %d\n", 1547d32d9864SMats Randgaard __func__, edid->pad, edid->start_block, edid->blocks); 1548d32d9864SMats Randgaard 1549d32d9864SMats Randgaard if (edid->pad != 0) 1550d32d9864SMats Randgaard return -EINVAL; 1551d32d9864SMats Randgaard 1552d32d9864SMats Randgaard if (edid->start_block != 0) 1553d32d9864SMats Randgaard return -EINVAL; 1554d32d9864SMats Randgaard 1555d32d9864SMats Randgaard if (edid->blocks > EDID_NUM_BLOCKS_MAX) { 1556d32d9864SMats Randgaard edid->blocks = EDID_NUM_BLOCKS_MAX; 1557d32d9864SMats Randgaard return -E2BIG; 1558d32d9864SMats Randgaard } 1559d32d9864SMats Randgaard 1560d32d9864SMats Randgaard tc358743_disable_edid(sd); 1561d32d9864SMats Randgaard 1562d32d9864SMats Randgaard i2c_wr8(sd, EDID_LEN1, edid_len & 0xff); 1563d32d9864SMats Randgaard i2c_wr8(sd, EDID_LEN2, edid_len >> 8); 1564d32d9864SMats Randgaard 1565d32d9864SMats Randgaard if (edid->blocks == 0) { 1566d32d9864SMats Randgaard state->edid_blocks_written = 0; 1567d32d9864SMats Randgaard return 0; 1568d32d9864SMats Randgaard } 1569d32d9864SMats Randgaard 1570d32d9864SMats Randgaard i2c_wr(sd, EDID_RAM, edid->edid, edid_len); 1571d32d9864SMats Randgaard 1572d32d9864SMats Randgaard state->edid_blocks_written = edid->blocks; 1573d32d9864SMats Randgaard 1574d32d9864SMats Randgaard if (tx_5v_power_present(sd)) 1575d32d9864SMats Randgaard tc358743_enable_edid(sd); 1576d32d9864SMats Randgaard 1577d32d9864SMats Randgaard return 0; 1578d32d9864SMats Randgaard } 1579d32d9864SMats Randgaard 1580d32d9864SMats Randgaard /* -------------------------------------------------------------------------- */ 1581d32d9864SMats Randgaard 1582d32d9864SMats Randgaard static const struct v4l2_subdev_core_ops tc358743_core_ops = { 1583d32d9864SMats Randgaard .log_status = tc358743_log_status, 1584d32d9864SMats Randgaard #ifdef CONFIG_VIDEO_ADV_DEBUG 1585d32d9864SMats Randgaard .g_register = tc358743_g_register, 1586d32d9864SMats Randgaard .s_register = tc358743_s_register, 1587d32d9864SMats Randgaard #endif 1588d32d9864SMats Randgaard .interrupt_service_routine = tc358743_isr, 1589d32d9864SMats Randgaard }; 1590d32d9864SMats Randgaard 1591d32d9864SMats Randgaard static const struct v4l2_subdev_video_ops tc358743_video_ops = { 1592d32d9864SMats Randgaard .g_input_status = tc358743_g_input_status, 1593d32d9864SMats Randgaard .s_dv_timings = tc358743_s_dv_timings, 1594d32d9864SMats Randgaard .g_dv_timings = tc358743_g_dv_timings, 1595d32d9864SMats Randgaard .query_dv_timings = tc358743_query_dv_timings, 1596d32d9864SMats Randgaard .g_mbus_config = tc358743_g_mbus_config, 1597d32d9864SMats Randgaard .s_stream = tc358743_s_stream, 1598d32d9864SMats Randgaard }; 1599d32d9864SMats Randgaard 1600d32d9864SMats Randgaard static const struct v4l2_subdev_pad_ops tc358743_pad_ops = { 1601d32d9864SMats Randgaard .set_fmt = tc358743_set_fmt, 1602d32d9864SMats Randgaard .get_fmt = tc358743_get_fmt, 1603d32d9864SMats Randgaard .get_edid = tc358743_g_edid, 1604d32d9864SMats Randgaard .set_edid = tc358743_s_edid, 1605d32d9864SMats Randgaard .enum_dv_timings = tc358743_enum_dv_timings, 1606d32d9864SMats Randgaard .dv_timings_cap = tc358743_dv_timings_cap, 1607d32d9864SMats Randgaard }; 1608d32d9864SMats Randgaard 1609d32d9864SMats Randgaard static const struct v4l2_subdev_ops tc358743_ops = { 1610d32d9864SMats Randgaard .core = &tc358743_core_ops, 1611d32d9864SMats Randgaard .video = &tc358743_video_ops, 1612d32d9864SMats Randgaard .pad = &tc358743_pad_ops, 1613d32d9864SMats Randgaard }; 1614d32d9864SMats Randgaard 1615d32d9864SMats Randgaard /* --------------- CUSTOM CTRLS --------------- */ 1616d32d9864SMats Randgaard 1617d32d9864SMats Randgaard static const struct v4l2_ctrl_config tc358743_ctrl_audio_sampling_rate = { 1618d32d9864SMats Randgaard .id = TC358743_CID_AUDIO_SAMPLING_RATE, 1619d32d9864SMats Randgaard .name = "Audio sampling rate", 1620d32d9864SMats Randgaard .type = V4L2_CTRL_TYPE_INTEGER, 1621d32d9864SMats Randgaard .min = 0, 1622d32d9864SMats Randgaard .max = 768000, 1623d32d9864SMats Randgaard .step = 1, 1624d32d9864SMats Randgaard .def = 0, 1625d32d9864SMats Randgaard .flags = V4L2_CTRL_FLAG_READ_ONLY, 1626d32d9864SMats Randgaard }; 1627d32d9864SMats Randgaard 1628d32d9864SMats Randgaard static const struct v4l2_ctrl_config tc358743_ctrl_audio_present = { 1629d32d9864SMats Randgaard .id = TC358743_CID_AUDIO_PRESENT, 1630d32d9864SMats Randgaard .name = "Audio present", 1631d32d9864SMats Randgaard .type = V4L2_CTRL_TYPE_BOOLEAN, 1632d32d9864SMats Randgaard .min = 0, 1633d32d9864SMats Randgaard .max = 1, 1634d32d9864SMats Randgaard .step = 1, 1635d32d9864SMats Randgaard .def = 0, 1636d32d9864SMats Randgaard .flags = V4L2_CTRL_FLAG_READ_ONLY, 1637d32d9864SMats Randgaard }; 1638d32d9864SMats Randgaard 1639d32d9864SMats Randgaard /* --------------- PROBE / REMOVE --------------- */ 1640d32d9864SMats Randgaard 1641d32d9864SMats Randgaard static int tc358743_probe(struct i2c_client *client, 1642d32d9864SMats Randgaard const struct i2c_device_id *id) 1643d32d9864SMats Randgaard { 1644d32d9864SMats Randgaard static struct v4l2_dv_timings default_timing = 1645d32d9864SMats Randgaard V4L2_DV_BT_CEA_640X480P59_94; 1646d32d9864SMats Randgaard struct tc358743_state *state; 1647d32d9864SMats Randgaard struct tc358743_platform_data *pdata = client->dev.platform_data; 1648d32d9864SMats Randgaard struct v4l2_subdev *sd; 1649d32d9864SMats Randgaard int err; 1650d32d9864SMats Randgaard 1651d32d9864SMats Randgaard if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 1652d32d9864SMats Randgaard return -EIO; 1653d32d9864SMats Randgaard v4l_dbg(1, debug, client, "chip found @ 0x%x (%s)\n", 1654d32d9864SMats Randgaard client->addr << 1, client->adapter->name); 1655d32d9864SMats Randgaard 1656d32d9864SMats Randgaard state = devm_kzalloc(&client->dev, sizeof(struct tc358743_state), 1657d32d9864SMats Randgaard GFP_KERNEL); 1658d32d9864SMats Randgaard if (!state) 1659d32d9864SMats Randgaard return -ENOMEM; 1660d32d9864SMats Randgaard 1661d32d9864SMats Randgaard /* platform data */ 1662d32d9864SMats Randgaard if (!pdata) { 1663d32d9864SMats Randgaard v4l_err(client, "No platform data!\n"); 1664d32d9864SMats Randgaard return -ENODEV; 1665d32d9864SMats Randgaard } 1666d32d9864SMats Randgaard state->pdata = *pdata; 1667d32d9864SMats Randgaard 1668d32d9864SMats Randgaard state->i2c_client = client; 1669d32d9864SMats Randgaard sd = &state->sd; 1670d32d9864SMats Randgaard v4l2_i2c_subdev_init(sd, client, &tc358743_ops); 1671d32d9864SMats Randgaard sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS; 1672d32d9864SMats Randgaard 1673d32d9864SMats Randgaard /* i2c access */ 1674d32d9864SMats Randgaard if ((i2c_rd16(sd, CHIPID) & MASK_CHIPID) != 0) { 1675d32d9864SMats Randgaard v4l2_info(sd, "not a TC358743 on address 0x%x\n", 1676d32d9864SMats Randgaard client->addr << 1); 1677d32d9864SMats Randgaard return -ENODEV; 1678d32d9864SMats Randgaard } 1679d32d9864SMats Randgaard 1680d32d9864SMats Randgaard /* control handlers */ 1681d32d9864SMats Randgaard v4l2_ctrl_handler_init(&state->hdl, 3); 1682d32d9864SMats Randgaard 1683d32d9864SMats Randgaard /* private controls */ 1684d32d9864SMats Randgaard state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(&state->hdl, NULL, 1685d32d9864SMats Randgaard V4L2_CID_DV_RX_POWER_PRESENT, 0, 1, 0, 0); 1686d32d9864SMats Randgaard 1687d32d9864SMats Randgaard /* custom controls */ 1688d32d9864SMats Randgaard state->audio_sampling_rate_ctrl = v4l2_ctrl_new_custom(&state->hdl, 1689d32d9864SMats Randgaard &tc358743_ctrl_audio_sampling_rate, NULL); 1690d32d9864SMats Randgaard 1691d32d9864SMats Randgaard state->audio_present_ctrl = v4l2_ctrl_new_custom(&state->hdl, 1692d32d9864SMats Randgaard &tc358743_ctrl_audio_present, NULL); 1693d32d9864SMats Randgaard 1694d32d9864SMats Randgaard sd->ctrl_handler = &state->hdl; 1695d32d9864SMats Randgaard if (state->hdl.error) { 1696d32d9864SMats Randgaard err = state->hdl.error; 1697d32d9864SMats Randgaard goto err_hdl; 1698d32d9864SMats Randgaard } 1699d32d9864SMats Randgaard 1700d32d9864SMats Randgaard if (tc358743_update_controls(sd)) { 1701d32d9864SMats Randgaard err = -ENODEV; 1702d32d9864SMats Randgaard goto err_hdl; 1703d32d9864SMats Randgaard } 1704d32d9864SMats Randgaard 1705d32d9864SMats Randgaard /* work queues */ 1706d32d9864SMats Randgaard state->work_queues = create_singlethread_workqueue(client->name); 1707d32d9864SMats Randgaard if (!state->work_queues) { 1708d32d9864SMats Randgaard v4l2_err(sd, "Could not create work queue\n"); 1709d32d9864SMats Randgaard err = -ENOMEM; 1710d32d9864SMats Randgaard goto err_hdl; 1711d32d9864SMats Randgaard } 1712d32d9864SMats Randgaard 17134c5211a1SPhilipp Zabel state->pad.flags = MEDIA_PAD_FL_SOURCE; 17144c5211a1SPhilipp Zabel err = media_entity_init(&sd->entity, 1, &state->pad, 0); 17154c5211a1SPhilipp Zabel if (err < 0) 17164c5211a1SPhilipp Zabel goto err_hdl; 17174c5211a1SPhilipp Zabel 17184c5211a1SPhilipp Zabel sd->dev = &client->dev; 17194c5211a1SPhilipp Zabel err = v4l2_async_register_subdev(sd); 17204c5211a1SPhilipp Zabel if (err < 0) 17214c5211a1SPhilipp Zabel goto err_hdl; 17224c5211a1SPhilipp Zabel 1723d32d9864SMats Randgaard mutex_init(&state->confctl_mutex); 1724d32d9864SMats Randgaard 1725d32d9864SMats Randgaard INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug, 1726d32d9864SMats Randgaard tc358743_delayed_work_enable_hotplug); 1727d32d9864SMats Randgaard 1728d32d9864SMats Randgaard tc358743_initial_setup(sd); 1729d32d9864SMats Randgaard 1730d32d9864SMats Randgaard tc358743_s_dv_timings(sd, &default_timing); 1731d32d9864SMats Randgaard 1732d32d9864SMats Randgaard state->mbus_fmt_code = MEDIA_BUS_FMT_RGB888_1X24; 1733d32d9864SMats Randgaard tc358743_set_csi_color_space(sd); 1734d32d9864SMats Randgaard 1735d32d9864SMats Randgaard tc358743_init_interrupts(sd); 1736d32d9864SMats Randgaard tc358743_enable_interrupts(sd, tx_5v_power_present(sd)); 1737d32d9864SMats Randgaard i2c_wr16(sd, INTMASK, ~(MASK_HDMI_MSK | MASK_CSI_MSK) & 0xffff); 1738d32d9864SMats Randgaard 1739d32d9864SMats Randgaard err = v4l2_ctrl_handler_setup(sd->ctrl_handler); 1740d32d9864SMats Randgaard if (err) 1741d32d9864SMats Randgaard goto err_work_queues; 1742d32d9864SMats Randgaard 1743d32d9864SMats Randgaard v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, 1744d32d9864SMats Randgaard client->addr << 1, client->adapter->name); 1745d32d9864SMats Randgaard 1746d32d9864SMats Randgaard return 0; 1747d32d9864SMats Randgaard 1748d32d9864SMats Randgaard err_work_queues: 1749d32d9864SMats Randgaard cancel_delayed_work(&state->delayed_work_enable_hotplug); 1750d32d9864SMats Randgaard destroy_workqueue(state->work_queues); 1751d32d9864SMats Randgaard mutex_destroy(&state->confctl_mutex); 1752d32d9864SMats Randgaard err_hdl: 17534c5211a1SPhilipp Zabel media_entity_cleanup(&sd->entity); 1754d32d9864SMats Randgaard v4l2_ctrl_handler_free(&state->hdl); 1755d32d9864SMats Randgaard return err; 1756d32d9864SMats Randgaard } 1757d32d9864SMats Randgaard 1758d32d9864SMats Randgaard static int tc358743_remove(struct i2c_client *client) 1759d32d9864SMats Randgaard { 1760d32d9864SMats Randgaard struct v4l2_subdev *sd = i2c_get_clientdata(client); 1761d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 1762d32d9864SMats Randgaard 1763d32d9864SMats Randgaard cancel_delayed_work(&state->delayed_work_enable_hotplug); 1764d32d9864SMats Randgaard destroy_workqueue(state->work_queues); 17654c5211a1SPhilipp Zabel v4l2_async_unregister_subdev(sd); 1766d32d9864SMats Randgaard v4l2_device_unregister_subdev(sd); 1767d32d9864SMats Randgaard mutex_destroy(&state->confctl_mutex); 17684c5211a1SPhilipp Zabel media_entity_cleanup(&sd->entity); 1769d32d9864SMats Randgaard v4l2_ctrl_handler_free(&state->hdl); 1770d32d9864SMats Randgaard 1771d32d9864SMats Randgaard return 0; 1772d32d9864SMats Randgaard } 1773d32d9864SMats Randgaard 1774d32d9864SMats Randgaard static struct i2c_device_id tc358743_id[] = { 1775d32d9864SMats Randgaard {"tc358743", 0}, 1776d32d9864SMats Randgaard {} 1777d32d9864SMats Randgaard }; 1778d32d9864SMats Randgaard 1779d32d9864SMats Randgaard MODULE_DEVICE_TABLE(i2c, tc358743_id); 1780d32d9864SMats Randgaard 1781d32d9864SMats Randgaard static struct i2c_driver tc358743_driver = { 1782d32d9864SMats Randgaard .driver = { 1783d32d9864SMats Randgaard .owner = THIS_MODULE, 1784d32d9864SMats Randgaard .name = "tc358743", 1785d32d9864SMats Randgaard }, 1786d32d9864SMats Randgaard .probe = tc358743_probe, 1787d32d9864SMats Randgaard .remove = tc358743_remove, 1788d32d9864SMats Randgaard .id_table = tc358743_id, 1789d32d9864SMats Randgaard }; 1790d32d9864SMats Randgaard 1791d32d9864SMats Randgaard module_i2c_driver(tc358743_driver); 1792