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> 3225614824SPhilipp Zabel #include <linux/clk.h> 33d32d9864SMats Randgaard #include <linux/delay.h> 3425614824SPhilipp Zabel #include <linux/gpio/consumer.h> 35d747b806SPhilipp Zabel #include <linux/interrupt.h> 36d32d9864SMats Randgaard #include <linux/videodev2.h> 37d32d9864SMats Randgaard #include <linux/workqueue.h> 38d32d9864SMats Randgaard #include <linux/v4l2-dv-timings.h> 39d32d9864SMats Randgaard #include <linux/hdmi.h> 40d32d9864SMats Randgaard #include <media/v4l2-dv-timings.h> 41d32d9864SMats Randgaard #include <media/v4l2-device.h> 42d32d9864SMats Randgaard #include <media/v4l2-ctrls.h> 431140f919SPhilipp Zabel #include <media/v4l2-event.h> 4425614824SPhilipp Zabel #include <media/v4l2-of.h> 45b5dcee22SMauro Carvalho Chehab #include <media/i2c/tc358743.h> 46d32d9864SMats Randgaard 47d32d9864SMats Randgaard #include "tc358743_regs.h" 48d32d9864SMats Randgaard 49d32d9864SMats Randgaard static int debug; 50d32d9864SMats Randgaard module_param(debug, int, 0644); 51d32d9864SMats Randgaard MODULE_PARM_DESC(debug, "debug level (0-3)"); 52d32d9864SMats Randgaard 53d32d9864SMats Randgaard MODULE_DESCRIPTION("Toshiba TC358743 HDMI to CSI-2 bridge driver"); 54d32d9864SMats Randgaard MODULE_AUTHOR("Ramakrishnan Muthukrishnan <ram@rkrishnan.org>"); 55d32d9864SMats Randgaard MODULE_AUTHOR("Mikhail Khelik <mkhelik@cisco.com>"); 56d32d9864SMats Randgaard MODULE_AUTHOR("Mats Randgaard <matrandg@cisco.com>"); 57d32d9864SMats Randgaard MODULE_LICENSE("GPL"); 58d32d9864SMats Randgaard 59d32d9864SMats Randgaard #define EDID_NUM_BLOCKS_MAX 8 60d32d9864SMats Randgaard #define EDID_BLOCK_SIZE 128 61d32d9864SMats Randgaard 62fcae73faSMats Randgaard #define I2C_MAX_XFER_SIZE (EDID_BLOCK_SIZE + 2) 631d88f831SMauro Carvalho Chehab 64d32d9864SMats Randgaard static const struct v4l2_dv_timings_cap tc358743_timings_cap = { 65d32d9864SMats Randgaard .type = V4L2_DV_BT_656_1120, 66d32d9864SMats Randgaard /* keep this initialization for compatibility with GCC < 4.4.6 */ 67d32d9864SMats Randgaard .reserved = { 0 }, 68d32d9864SMats Randgaard /* Pixel clock from REF_01 p. 20. Min/max height/width are unknown */ 69d32d9864SMats Randgaard V4L2_INIT_BT_TIMINGS(1, 10000, 1, 10000, 0, 165000000, 70d32d9864SMats Randgaard V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | 71d32d9864SMats Randgaard V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT, 72d32d9864SMats Randgaard V4L2_DV_BT_CAP_PROGRESSIVE | 73d32d9864SMats Randgaard V4L2_DV_BT_CAP_REDUCED_BLANKING | 74d32d9864SMats Randgaard V4L2_DV_BT_CAP_CUSTOM) 75d32d9864SMats Randgaard }; 76d32d9864SMats Randgaard 77d32d9864SMats Randgaard struct tc358743_state { 78d32d9864SMats Randgaard struct tc358743_platform_data pdata; 7925614824SPhilipp Zabel struct v4l2_of_bus_mipi_csi2 bus; 80d32d9864SMats Randgaard struct v4l2_subdev sd; 81d32d9864SMats Randgaard struct media_pad pad; 82d32d9864SMats Randgaard struct v4l2_ctrl_handler hdl; 83d32d9864SMats Randgaard struct i2c_client *i2c_client; 84d32d9864SMats Randgaard /* CONFCTL is modified in ops and tc358743_hdmi_sys_int_handler */ 85d32d9864SMats Randgaard struct mutex confctl_mutex; 86d32d9864SMats Randgaard 87d32d9864SMats Randgaard /* controls */ 88d32d9864SMats Randgaard struct v4l2_ctrl *detect_tx_5v_ctrl; 89d32d9864SMats Randgaard struct v4l2_ctrl *audio_sampling_rate_ctrl; 90d32d9864SMats Randgaard struct v4l2_ctrl *audio_present_ctrl; 91d32d9864SMats Randgaard 92d32d9864SMats Randgaard struct delayed_work delayed_work_enable_hotplug; 93d32d9864SMats Randgaard 94d32d9864SMats Randgaard /* edid */ 95d32d9864SMats Randgaard u8 edid_blocks_written; 96d32d9864SMats Randgaard 97d32d9864SMats Randgaard struct v4l2_dv_timings timings; 98d32d9864SMats Randgaard u32 mbus_fmt_code; 9925614824SPhilipp Zabel 10025614824SPhilipp Zabel struct gpio_desc *reset_gpio; 101d32d9864SMats Randgaard }; 102d32d9864SMats Randgaard 103d32d9864SMats Randgaard static void tc358743_enable_interrupts(struct v4l2_subdev *sd, 104d32d9864SMats Randgaard bool cable_connected); 105d32d9864SMats Randgaard static int tc358743_s_ctrl_detect_tx_5v(struct v4l2_subdev *sd); 106d32d9864SMats Randgaard 107d32d9864SMats Randgaard static inline struct tc358743_state *to_state(struct v4l2_subdev *sd) 108d32d9864SMats Randgaard { 109d32d9864SMats Randgaard return container_of(sd, struct tc358743_state, sd); 110d32d9864SMats Randgaard } 111d32d9864SMats Randgaard 112d32d9864SMats Randgaard /* --------------- I2C --------------- */ 113d32d9864SMats Randgaard 114d32d9864SMats Randgaard static void i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) 115d32d9864SMats Randgaard { 116d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 117d32d9864SMats Randgaard struct i2c_client *client = state->i2c_client; 118d32d9864SMats Randgaard int err; 119d32d9864SMats Randgaard u8 buf[2] = { reg >> 8, reg & 0xff }; 120d32d9864SMats Randgaard struct i2c_msg msgs[] = { 121d32d9864SMats Randgaard { 122d32d9864SMats Randgaard .addr = client->addr, 123d32d9864SMats Randgaard .flags = 0, 124d32d9864SMats Randgaard .len = 2, 125d32d9864SMats Randgaard .buf = buf, 126d32d9864SMats Randgaard }, 127d32d9864SMats Randgaard { 128d32d9864SMats Randgaard .addr = client->addr, 129d32d9864SMats Randgaard .flags = I2C_M_RD, 130d32d9864SMats Randgaard .len = n, 131d32d9864SMats Randgaard .buf = values, 132d32d9864SMats Randgaard }, 133d32d9864SMats Randgaard }; 134d32d9864SMats Randgaard 135d32d9864SMats Randgaard err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 136d32d9864SMats Randgaard if (err != ARRAY_SIZE(msgs)) { 137d32d9864SMats Randgaard v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed\n", 138d32d9864SMats Randgaard __func__, reg, client->addr); 139d32d9864SMats Randgaard } 140d32d9864SMats Randgaard } 141d32d9864SMats Randgaard 142d32d9864SMats Randgaard static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) 143d32d9864SMats Randgaard { 144d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 145d32d9864SMats Randgaard struct i2c_client *client = state->i2c_client; 146d32d9864SMats Randgaard int err, i; 147d32d9864SMats Randgaard struct i2c_msg msg; 148fcae73faSMats Randgaard u8 data[I2C_MAX_XFER_SIZE]; 1491d88f831SMauro Carvalho Chehab 150fcae73faSMats Randgaard if ((2 + n) > I2C_MAX_XFER_SIZE) { 151fcae73faSMats Randgaard n = I2C_MAX_XFER_SIZE - 2; 1521d88f831SMauro Carvalho Chehab v4l2_warn(sd, "i2c wr reg=%04x: len=%d is too big!\n", 1531d88f831SMauro Carvalho Chehab reg, 2 + n); 154fcae73faSMats Randgaard } 155d32d9864SMats Randgaard 156d32d9864SMats Randgaard msg.addr = client->addr; 157d32d9864SMats Randgaard msg.buf = data; 158d32d9864SMats Randgaard msg.len = 2 + n; 159d32d9864SMats Randgaard msg.flags = 0; 160d32d9864SMats Randgaard 161d32d9864SMats Randgaard data[0] = reg >> 8; 162d32d9864SMats Randgaard data[1] = reg & 0xff; 163d32d9864SMats Randgaard 164d32d9864SMats Randgaard for (i = 0; i < n; i++) 165d32d9864SMats Randgaard data[2 + i] = values[i]; 166d32d9864SMats Randgaard 167d32d9864SMats Randgaard err = i2c_transfer(client->adapter, &msg, 1); 168d32d9864SMats Randgaard if (err != 1) { 169d32d9864SMats Randgaard v4l2_err(sd, "%s: writing register 0x%x from 0x%x failed\n", 170d32d9864SMats Randgaard __func__, reg, client->addr); 171d32d9864SMats Randgaard return; 172d32d9864SMats Randgaard } 173d32d9864SMats Randgaard 174d32d9864SMats Randgaard if (debug < 3) 175d32d9864SMats Randgaard return; 176d32d9864SMats Randgaard 177d32d9864SMats Randgaard switch (n) { 178d32d9864SMats Randgaard case 1: 179d32d9864SMats Randgaard v4l2_info(sd, "I2C write 0x%04x = 0x%02x", 180d32d9864SMats Randgaard reg, data[2]); 181d32d9864SMats Randgaard break; 182d32d9864SMats Randgaard case 2: 183d32d9864SMats Randgaard v4l2_info(sd, "I2C write 0x%04x = 0x%02x%02x", 184d32d9864SMats Randgaard reg, data[3], data[2]); 185d32d9864SMats Randgaard break; 186d32d9864SMats Randgaard case 4: 187d32d9864SMats Randgaard v4l2_info(sd, "I2C write 0x%04x = 0x%02x%02x%02x%02x", 188d32d9864SMats Randgaard reg, data[5], data[4], data[3], data[2]); 189d32d9864SMats Randgaard break; 190d32d9864SMats Randgaard default: 191d32d9864SMats Randgaard v4l2_info(sd, "I2C write %d bytes from address 0x%04x\n", 192d32d9864SMats Randgaard n, reg); 193d32d9864SMats Randgaard } 194d32d9864SMats Randgaard } 195d32d9864SMats Randgaard 196d32d9864SMats Randgaard static u8 i2c_rd8(struct v4l2_subdev *sd, u16 reg) 197d32d9864SMats Randgaard { 198d32d9864SMats Randgaard u8 val; 199d32d9864SMats Randgaard 200d32d9864SMats Randgaard i2c_rd(sd, reg, &val, 1); 201d32d9864SMats Randgaard 202d32d9864SMats Randgaard return val; 203d32d9864SMats Randgaard } 204d32d9864SMats Randgaard 205d32d9864SMats Randgaard static void i2c_wr8(struct v4l2_subdev *sd, u16 reg, u8 val) 206d32d9864SMats Randgaard { 207d32d9864SMats Randgaard i2c_wr(sd, reg, &val, 1); 208d32d9864SMats Randgaard } 209d32d9864SMats Randgaard 210d32d9864SMats Randgaard static void i2c_wr8_and_or(struct v4l2_subdev *sd, u16 reg, 211d32d9864SMats Randgaard u8 mask, u8 val) 212d32d9864SMats Randgaard { 213d32d9864SMats Randgaard i2c_wr8(sd, reg, (i2c_rd8(sd, reg) & mask) | val); 214d32d9864SMats Randgaard } 215d32d9864SMats Randgaard 216d32d9864SMats Randgaard static u16 i2c_rd16(struct v4l2_subdev *sd, u16 reg) 217d32d9864SMats Randgaard { 218d32d9864SMats Randgaard u16 val; 219d32d9864SMats Randgaard 220d32d9864SMats Randgaard i2c_rd(sd, reg, (u8 *)&val, 2); 221d32d9864SMats Randgaard 222d32d9864SMats Randgaard return val; 223d32d9864SMats Randgaard } 224d32d9864SMats Randgaard 225d32d9864SMats Randgaard static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val) 226d32d9864SMats Randgaard { 227d32d9864SMats Randgaard i2c_wr(sd, reg, (u8 *)&val, 2); 228d32d9864SMats Randgaard } 229d32d9864SMats Randgaard 230d32d9864SMats Randgaard static void i2c_wr16_and_or(struct v4l2_subdev *sd, u16 reg, u16 mask, u16 val) 231d32d9864SMats Randgaard { 232d32d9864SMats Randgaard i2c_wr16(sd, reg, (i2c_rd16(sd, reg) & mask) | val); 233d32d9864SMats Randgaard } 234d32d9864SMats Randgaard 235d32d9864SMats Randgaard static u32 i2c_rd32(struct v4l2_subdev *sd, u16 reg) 236d32d9864SMats Randgaard { 237d32d9864SMats Randgaard u32 val; 238d32d9864SMats Randgaard 239d32d9864SMats Randgaard i2c_rd(sd, reg, (u8 *)&val, 4); 240d32d9864SMats Randgaard 241d32d9864SMats Randgaard return val; 242d32d9864SMats Randgaard } 243d32d9864SMats Randgaard 244d32d9864SMats Randgaard static void i2c_wr32(struct v4l2_subdev *sd, u16 reg, u32 val) 245d32d9864SMats Randgaard { 246d32d9864SMats Randgaard i2c_wr(sd, reg, (u8 *)&val, 4); 247d32d9864SMats Randgaard } 248d32d9864SMats Randgaard 249d32d9864SMats Randgaard /* --------------- STATUS --------------- */ 250d32d9864SMats Randgaard 251d32d9864SMats Randgaard static inline bool is_hdmi(struct v4l2_subdev *sd) 252d32d9864SMats Randgaard { 253d32d9864SMats Randgaard return i2c_rd8(sd, SYS_STATUS) & MASK_S_HDMI; 254d32d9864SMats Randgaard } 255d32d9864SMats Randgaard 256d32d9864SMats Randgaard static inline bool tx_5v_power_present(struct v4l2_subdev *sd) 257d32d9864SMats Randgaard { 258d32d9864SMats Randgaard return i2c_rd8(sd, SYS_STATUS) & MASK_S_DDC5V; 259d32d9864SMats Randgaard } 260d32d9864SMats Randgaard 261d32d9864SMats Randgaard static inline bool no_signal(struct v4l2_subdev *sd) 262d32d9864SMats Randgaard { 263d32d9864SMats Randgaard return !(i2c_rd8(sd, SYS_STATUS) & MASK_S_TMDS); 264d32d9864SMats Randgaard } 265d32d9864SMats Randgaard 266d32d9864SMats Randgaard static inline bool no_sync(struct v4l2_subdev *sd) 267d32d9864SMats Randgaard { 268d32d9864SMats Randgaard return !(i2c_rd8(sd, SYS_STATUS) & MASK_S_SYNC); 269d32d9864SMats Randgaard } 270d32d9864SMats Randgaard 271d32d9864SMats Randgaard static inline bool audio_present(struct v4l2_subdev *sd) 272d32d9864SMats Randgaard { 273d32d9864SMats Randgaard return i2c_rd8(sd, AU_STATUS0) & MASK_S_A_SAMPLE; 274d32d9864SMats Randgaard } 275d32d9864SMats Randgaard 276d32d9864SMats Randgaard static int get_audio_sampling_rate(struct v4l2_subdev *sd) 277d32d9864SMats Randgaard { 278d32d9864SMats Randgaard static const int code_to_rate[] = { 279d32d9864SMats Randgaard 44100, 0, 48000, 32000, 22050, 384000, 24000, 352800, 280d32d9864SMats Randgaard 88200, 768000, 96000, 705600, 176400, 0, 192000, 0 281d32d9864SMats Randgaard }; 282d32d9864SMats Randgaard 283d32d9864SMats Randgaard /* Register FS_SET is not cleared when the cable is disconnected */ 284d32d9864SMats Randgaard if (no_signal(sd)) 285d32d9864SMats Randgaard return 0; 286d32d9864SMats Randgaard 287d32d9864SMats Randgaard return code_to_rate[i2c_rd8(sd, FS_SET) & MASK_FS]; 288d32d9864SMats Randgaard } 289d32d9864SMats Randgaard 290d32d9864SMats Randgaard static unsigned tc358743_num_csi_lanes_in_use(struct v4l2_subdev *sd) 291d32d9864SMats Randgaard { 292d32d9864SMats Randgaard return ((i2c_rd32(sd, CSI_CONTROL) & MASK_NOL) >> 1) + 1; 293d32d9864SMats Randgaard } 294d32d9864SMats Randgaard 295d32d9864SMats Randgaard /* --------------- TIMINGS --------------- */ 296d32d9864SMats Randgaard 297d32d9864SMats Randgaard static inline unsigned fps(const struct v4l2_bt_timings *t) 298d32d9864SMats Randgaard { 299d32d9864SMats Randgaard if (!V4L2_DV_BT_FRAME_HEIGHT(t) || !V4L2_DV_BT_FRAME_WIDTH(t)) 300d32d9864SMats Randgaard return 0; 301d32d9864SMats Randgaard 302d32d9864SMats Randgaard return DIV_ROUND_CLOSEST((unsigned)t->pixelclock, 303d32d9864SMats Randgaard V4L2_DV_BT_FRAME_HEIGHT(t) * V4L2_DV_BT_FRAME_WIDTH(t)); 304d32d9864SMats Randgaard } 305d32d9864SMats Randgaard 306d32d9864SMats Randgaard static int tc358743_get_detected_timings(struct v4l2_subdev *sd, 307d32d9864SMats Randgaard struct v4l2_dv_timings *timings) 308d32d9864SMats Randgaard { 309d32d9864SMats Randgaard struct v4l2_bt_timings *bt = &timings->bt; 310d32d9864SMats Randgaard unsigned width, height, frame_width, frame_height, frame_interval, fps; 311d32d9864SMats Randgaard 312d32d9864SMats Randgaard memset(timings, 0, sizeof(struct v4l2_dv_timings)); 313d32d9864SMats Randgaard 314d32d9864SMats Randgaard if (no_signal(sd)) { 315d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: no valid signal\n", __func__); 316d32d9864SMats Randgaard return -ENOLINK; 317d32d9864SMats Randgaard } 318d32d9864SMats Randgaard if (no_sync(sd)) { 319d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: no sync on signal\n", __func__); 320d32d9864SMats Randgaard return -ENOLCK; 321d32d9864SMats Randgaard } 322d32d9864SMats Randgaard 323d32d9864SMats Randgaard timings->type = V4L2_DV_BT_656_1120; 324d32d9864SMats Randgaard bt->interlaced = i2c_rd8(sd, VI_STATUS1) & MASK_S_V_INTERLACE ? 325d32d9864SMats Randgaard V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE; 326d32d9864SMats Randgaard 327d32d9864SMats Randgaard width = ((i2c_rd8(sd, DE_WIDTH_H_HI) & 0x1f) << 8) + 328d32d9864SMats Randgaard i2c_rd8(sd, DE_WIDTH_H_LO); 329d32d9864SMats Randgaard height = ((i2c_rd8(sd, DE_WIDTH_V_HI) & 0x1f) << 8) + 330d32d9864SMats Randgaard i2c_rd8(sd, DE_WIDTH_V_LO); 331d32d9864SMats Randgaard frame_width = ((i2c_rd8(sd, H_SIZE_HI) & 0x1f) << 8) + 332d32d9864SMats Randgaard i2c_rd8(sd, H_SIZE_LO); 333d32d9864SMats Randgaard frame_height = (((i2c_rd8(sd, V_SIZE_HI) & 0x3f) << 8) + 334d32d9864SMats Randgaard i2c_rd8(sd, V_SIZE_LO)) / 2; 335d32d9864SMats Randgaard /* frame interval in milliseconds * 10 336d32d9864SMats Randgaard * Require SYS_FREQ0 and SYS_FREQ1 are precisely set */ 337d32d9864SMats Randgaard frame_interval = ((i2c_rd8(sd, FV_CNT_HI) & 0x3) << 8) + 338d32d9864SMats Randgaard i2c_rd8(sd, FV_CNT_LO); 339d32d9864SMats Randgaard fps = (frame_interval > 0) ? 340d32d9864SMats Randgaard DIV_ROUND_CLOSEST(10000, frame_interval) : 0; 341d32d9864SMats Randgaard 342d32d9864SMats Randgaard bt->width = width; 343d32d9864SMats Randgaard bt->height = height; 344d32d9864SMats Randgaard bt->vsync = frame_height - height; 345d32d9864SMats Randgaard bt->hsync = frame_width - width; 346d32d9864SMats Randgaard bt->pixelclock = frame_width * frame_height * fps; 347d32d9864SMats Randgaard if (bt->interlaced == V4L2_DV_INTERLACED) { 348d32d9864SMats Randgaard bt->height *= 2; 349d32d9864SMats Randgaard bt->il_vsync = bt->vsync + 1; 350d32d9864SMats Randgaard bt->pixelclock /= 2; 351d32d9864SMats Randgaard } 352d32d9864SMats Randgaard 353d32d9864SMats Randgaard return 0; 354d32d9864SMats Randgaard } 355d32d9864SMats Randgaard 356d32d9864SMats Randgaard /* --------------- HOTPLUG / HDCP / EDID --------------- */ 357d32d9864SMats Randgaard 358d32d9864SMats Randgaard static void tc358743_delayed_work_enable_hotplug(struct work_struct *work) 359d32d9864SMats Randgaard { 360d32d9864SMats Randgaard struct delayed_work *dwork = to_delayed_work(work); 361d32d9864SMats Randgaard struct tc358743_state *state = container_of(dwork, 362d32d9864SMats Randgaard struct tc358743_state, delayed_work_enable_hotplug); 363d32d9864SMats Randgaard struct v4l2_subdev *sd = &state->sd; 364d32d9864SMats Randgaard 365d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s:\n", __func__); 366d32d9864SMats Randgaard 367d32d9864SMats Randgaard i2c_wr8_and_or(sd, HPD_CTL, ~MASK_HPD_OUT0, MASK_HPD_OUT0); 368d32d9864SMats Randgaard } 369d32d9864SMats Randgaard 370d32d9864SMats Randgaard static void tc358743_set_hdmi_hdcp(struct v4l2_subdev *sd, bool enable) 371d32d9864SMats Randgaard { 372d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s: %s\n", __func__, enable ? 373d32d9864SMats Randgaard "enable" : "disable"); 374d32d9864SMats Randgaard 375d32d9864SMats Randgaard i2c_wr8_and_or(sd, HDCP_REG1, 376d32d9864SMats Randgaard ~(MASK_AUTH_UNAUTH_SEL | MASK_AUTH_UNAUTH), 377d32d9864SMats Randgaard MASK_AUTH_UNAUTH_SEL_16_FRAMES | MASK_AUTH_UNAUTH_AUTO); 378d32d9864SMats Randgaard 379d32d9864SMats Randgaard i2c_wr8_and_or(sd, HDCP_REG2, ~MASK_AUTO_P3_RESET, 380d32d9864SMats Randgaard SET_AUTO_P3_RESET_FRAMES(0x0f)); 381d32d9864SMats Randgaard 382d32d9864SMats Randgaard /* HDCP is disabled by configuring the receiver as HDCP repeater. The 383d32d9864SMats Randgaard * repeater mode require software support to work, so HDCP 384d32d9864SMats Randgaard * authentication will fail. 385d32d9864SMats Randgaard */ 386d32d9864SMats Randgaard i2c_wr8_and_or(sd, HDCP_REG3, ~KEY_RD_CMD, enable ? KEY_RD_CMD : 0); 387d32d9864SMats Randgaard i2c_wr8_and_or(sd, HDCP_MODE, ~(MASK_AUTO_CLR | MASK_MODE_RST_TN), 388d32d9864SMats Randgaard enable ? (MASK_AUTO_CLR | MASK_MODE_RST_TN) : 0); 389d32d9864SMats Randgaard 390d32d9864SMats Randgaard /* Apple MacBook Pro gen.8 has a bug that makes it freeze every fifth 391d32d9864SMats Randgaard * second when HDCP is disabled, but the MAX_EXCED bit is handled 392d32d9864SMats Randgaard * correctly and HDCP is disabled on the HDMI output. 393d32d9864SMats Randgaard */ 394d32d9864SMats Randgaard i2c_wr8_and_or(sd, BSTATUS1, ~MASK_MAX_EXCED, 395d32d9864SMats Randgaard enable ? 0 : MASK_MAX_EXCED); 396d32d9864SMats Randgaard i2c_wr8_and_or(sd, BCAPS, ~(MASK_REPEATER | MASK_READY), 397d32d9864SMats Randgaard enable ? 0 : MASK_REPEATER | MASK_READY); 398d32d9864SMats Randgaard } 399d32d9864SMats Randgaard 400d32d9864SMats Randgaard static void tc358743_disable_edid(struct v4l2_subdev *sd) 401d32d9864SMats Randgaard { 402d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 403d32d9864SMats Randgaard 404d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s:\n", __func__); 405d32d9864SMats Randgaard 406d32d9864SMats Randgaard cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); 407d32d9864SMats Randgaard 408d32d9864SMats Randgaard /* DDC access to EDID is also disabled when hotplug is disabled. See 409d32d9864SMats Randgaard * register DDC_CTL */ 410d32d9864SMats Randgaard i2c_wr8_and_or(sd, HPD_CTL, ~MASK_HPD_OUT0, 0x0); 411d32d9864SMats Randgaard } 412d32d9864SMats Randgaard 413d32d9864SMats Randgaard static void tc358743_enable_edid(struct v4l2_subdev *sd) 414d32d9864SMats Randgaard { 415d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 416d32d9864SMats Randgaard 417d32d9864SMats Randgaard if (state->edid_blocks_written == 0) { 418d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s: no EDID -> no hotplug\n", __func__); 419d32d9864SMats Randgaard return; 420d32d9864SMats Randgaard } 421d32d9864SMats Randgaard 422d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s:\n", __func__); 423d32d9864SMats Randgaard 424d32d9864SMats Randgaard /* Enable hotplug after 100 ms. DDC access to EDID is also enabled when 425d32d9864SMats Randgaard * hotplug is enabled. See register DDC_CTL */ 426*1ce39546SBhaktipriya Shridhar schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 10); 427d32d9864SMats Randgaard 428d32d9864SMats Randgaard tc358743_enable_interrupts(sd, true); 429d32d9864SMats Randgaard tc358743_s_ctrl_detect_tx_5v(sd); 430d32d9864SMats Randgaard } 431d32d9864SMats Randgaard 432d32d9864SMats Randgaard static void tc358743_erase_bksv(struct v4l2_subdev *sd) 433d32d9864SMats Randgaard { 434d32d9864SMats Randgaard int i; 435d32d9864SMats Randgaard 436d32d9864SMats Randgaard for (i = 0; i < 5; i++) 437d32d9864SMats Randgaard i2c_wr8(sd, BKSV + i, 0); 438d32d9864SMats Randgaard } 439d32d9864SMats Randgaard 440d32d9864SMats Randgaard /* --------------- AVI infoframe --------------- */ 441d32d9864SMats Randgaard 442d32d9864SMats Randgaard static void print_avi_infoframe(struct v4l2_subdev *sd) 443d32d9864SMats Randgaard { 444d32d9864SMats Randgaard struct i2c_client *client = v4l2_get_subdevdata(sd); 445d32d9864SMats Randgaard struct device *dev = &client->dev; 446d32d9864SMats Randgaard union hdmi_infoframe frame; 447d32d9864SMats Randgaard u8 buffer[HDMI_INFOFRAME_SIZE(AVI)]; 448d32d9864SMats Randgaard 449d32d9864SMats Randgaard if (!is_hdmi(sd)) { 450d32d9864SMats Randgaard v4l2_info(sd, "DVI-D signal - AVI infoframe not supported\n"); 451d32d9864SMats Randgaard return; 452d32d9864SMats Randgaard } 453d32d9864SMats Randgaard 454d32d9864SMats Randgaard i2c_rd(sd, PK_AVI_0HEAD, buffer, HDMI_INFOFRAME_SIZE(AVI)); 455d32d9864SMats Randgaard 456d32d9864SMats Randgaard if (hdmi_infoframe_unpack(&frame, buffer) < 0) { 457d32d9864SMats Randgaard v4l2_err(sd, "%s: unpack of AVI infoframe failed\n", __func__); 458d32d9864SMats Randgaard return; 459d32d9864SMats Randgaard } 460d32d9864SMats Randgaard 461d32d9864SMats Randgaard hdmi_infoframe_log(KERN_INFO, dev, &frame); 462d32d9864SMats Randgaard } 463d32d9864SMats Randgaard 464d32d9864SMats Randgaard /* --------------- CTRLS --------------- */ 465d32d9864SMats Randgaard 466d32d9864SMats Randgaard static int tc358743_s_ctrl_detect_tx_5v(struct v4l2_subdev *sd) 467d32d9864SMats Randgaard { 468d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 469d32d9864SMats Randgaard 470d32d9864SMats Randgaard return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, 471d32d9864SMats Randgaard tx_5v_power_present(sd)); 472d32d9864SMats Randgaard } 473d32d9864SMats Randgaard 474d32d9864SMats Randgaard static int tc358743_s_ctrl_audio_sampling_rate(struct v4l2_subdev *sd) 475d32d9864SMats Randgaard { 476d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 477d32d9864SMats Randgaard 478d32d9864SMats Randgaard return v4l2_ctrl_s_ctrl(state->audio_sampling_rate_ctrl, 479d32d9864SMats Randgaard get_audio_sampling_rate(sd)); 480d32d9864SMats Randgaard } 481d32d9864SMats Randgaard 482d32d9864SMats Randgaard static int tc358743_s_ctrl_audio_present(struct v4l2_subdev *sd) 483d32d9864SMats Randgaard { 484d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 485d32d9864SMats Randgaard 486d32d9864SMats Randgaard return v4l2_ctrl_s_ctrl(state->audio_present_ctrl, 487d32d9864SMats Randgaard audio_present(sd)); 488d32d9864SMats Randgaard } 489d32d9864SMats Randgaard 490d32d9864SMats Randgaard static int tc358743_update_controls(struct v4l2_subdev *sd) 491d32d9864SMats Randgaard { 492d32d9864SMats Randgaard int ret = 0; 493d32d9864SMats Randgaard 494d32d9864SMats Randgaard ret |= tc358743_s_ctrl_detect_tx_5v(sd); 495d32d9864SMats Randgaard ret |= tc358743_s_ctrl_audio_sampling_rate(sd); 496d32d9864SMats Randgaard ret |= tc358743_s_ctrl_audio_present(sd); 497d32d9864SMats Randgaard 498d32d9864SMats Randgaard return ret; 499d32d9864SMats Randgaard } 500d32d9864SMats Randgaard 501d32d9864SMats Randgaard /* --------------- INIT --------------- */ 502d32d9864SMats Randgaard 503d32d9864SMats Randgaard static void tc358743_reset_phy(struct v4l2_subdev *sd) 504d32d9864SMats Randgaard { 505d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s:\n", __func__); 506d32d9864SMats Randgaard 507d32d9864SMats Randgaard i2c_wr8_and_or(sd, PHY_RST, ~MASK_RESET_CTRL, 0); 508d32d9864SMats Randgaard i2c_wr8_and_or(sd, PHY_RST, ~MASK_RESET_CTRL, MASK_RESET_CTRL); 509d32d9864SMats Randgaard } 510d32d9864SMats Randgaard 511d32d9864SMats Randgaard static void tc358743_reset(struct v4l2_subdev *sd, uint16_t mask) 512d32d9864SMats Randgaard { 513d32d9864SMats Randgaard u16 sysctl = i2c_rd16(sd, SYSCTL); 514d32d9864SMats Randgaard 515d32d9864SMats Randgaard i2c_wr16(sd, SYSCTL, sysctl | mask); 516d32d9864SMats Randgaard i2c_wr16(sd, SYSCTL, sysctl & ~mask); 517d32d9864SMats Randgaard } 518d32d9864SMats Randgaard 519d32d9864SMats Randgaard static inline void tc358743_sleep_mode(struct v4l2_subdev *sd, bool enable) 520d32d9864SMats Randgaard { 521d32d9864SMats Randgaard i2c_wr16_and_or(sd, SYSCTL, ~MASK_SLEEP, 522d32d9864SMats Randgaard enable ? MASK_SLEEP : 0); 523d32d9864SMats Randgaard } 524d32d9864SMats Randgaard 525d32d9864SMats Randgaard static inline void enable_stream(struct v4l2_subdev *sd, bool enable) 526d32d9864SMats Randgaard { 527d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 528d32d9864SMats Randgaard 529d32d9864SMats Randgaard v4l2_dbg(3, debug, sd, "%s: %sable\n", 530d32d9864SMats Randgaard __func__, enable ? "en" : "dis"); 531d32d9864SMats Randgaard 532d32d9864SMats Randgaard if (enable) { 533d32d9864SMats Randgaard /* It is critical for CSI receiver to see lane transition 534d32d9864SMats Randgaard * LP11->HS. Set to non-continuous mode to enable clock lane 535d32d9864SMats Randgaard * LP11 state. */ 536d32d9864SMats Randgaard i2c_wr32(sd, TXOPTIONCNTRL, 0); 537d32d9864SMats Randgaard /* Set to continuous mode to trigger LP11->HS transition */ 538d32d9864SMats Randgaard i2c_wr32(sd, TXOPTIONCNTRL, MASK_CONTCLKMODE); 539d32d9864SMats Randgaard /* Unmute video */ 540d32d9864SMats Randgaard i2c_wr8(sd, VI_MUTE, MASK_AUTO_MUTE); 541d32d9864SMats Randgaard } else { 542d32d9864SMats Randgaard /* Mute video so that all data lanes go to LSP11 state. 543d32d9864SMats Randgaard * No data is output to CSI Tx block. */ 544d32d9864SMats Randgaard i2c_wr8(sd, VI_MUTE, MASK_AUTO_MUTE | MASK_VI_MUTE); 545d32d9864SMats Randgaard } 546d32d9864SMats Randgaard 547d32d9864SMats Randgaard mutex_lock(&state->confctl_mutex); 548d32d9864SMats Randgaard i2c_wr16_and_or(sd, CONFCTL, ~(MASK_VBUFEN | MASK_ABUFEN), 549d32d9864SMats Randgaard enable ? (MASK_VBUFEN | MASK_ABUFEN) : 0x0); 550d32d9864SMats Randgaard mutex_unlock(&state->confctl_mutex); 551d32d9864SMats Randgaard } 552d32d9864SMats Randgaard 553d32d9864SMats Randgaard static void tc358743_set_pll(struct v4l2_subdev *sd) 554d32d9864SMats Randgaard { 555d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 556d32d9864SMats Randgaard struct tc358743_platform_data *pdata = &state->pdata; 557d32d9864SMats Randgaard u16 pllctl0 = i2c_rd16(sd, PLLCTL0); 558d32d9864SMats Randgaard u16 pllctl1 = i2c_rd16(sd, PLLCTL1); 559d32d9864SMats Randgaard u16 pllctl0_new = SET_PLL_PRD(pdata->pll_prd) | 560d32d9864SMats Randgaard SET_PLL_FBD(pdata->pll_fbd); 561d32d9864SMats Randgaard u32 hsck = (pdata->refclk_hz / pdata->pll_prd) * pdata->pll_fbd; 562d32d9864SMats Randgaard 563d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s:\n", __func__); 564d32d9864SMats Randgaard 565d32d9864SMats Randgaard /* Only rewrite when needed (new value or disabled), since rewriting 566d32d9864SMats Randgaard * triggers another format change event. */ 567d32d9864SMats Randgaard if ((pllctl0 != pllctl0_new) || ((pllctl1 & MASK_PLL_EN) == 0)) { 568d32d9864SMats Randgaard u16 pll_frs; 569d32d9864SMats Randgaard 570d32d9864SMats Randgaard if (hsck > 500000000) 571d32d9864SMats Randgaard pll_frs = 0x0; 572d32d9864SMats Randgaard else if (hsck > 250000000) 573d32d9864SMats Randgaard pll_frs = 0x1; 574d32d9864SMats Randgaard else if (hsck > 125000000) 575d32d9864SMats Randgaard pll_frs = 0x2; 576d32d9864SMats Randgaard else 577d32d9864SMats Randgaard pll_frs = 0x3; 578d32d9864SMats Randgaard 579d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: updating PLL clock\n", __func__); 580d32d9864SMats Randgaard tc358743_sleep_mode(sd, true); 581d32d9864SMats Randgaard i2c_wr16(sd, PLLCTL0, pllctl0_new); 582d32d9864SMats Randgaard i2c_wr16_and_or(sd, PLLCTL1, 583d32d9864SMats Randgaard ~(MASK_PLL_FRS | MASK_RESETB | MASK_PLL_EN), 584d32d9864SMats Randgaard (SET_PLL_FRS(pll_frs) | MASK_RESETB | 585d32d9864SMats Randgaard MASK_PLL_EN)); 586d32d9864SMats Randgaard udelay(10); /* REF_02, Sheet "Source HDMI" */ 587d32d9864SMats Randgaard i2c_wr16_and_or(sd, PLLCTL1, ~MASK_CKEN, MASK_CKEN); 588d32d9864SMats Randgaard tc358743_sleep_mode(sd, false); 589d32d9864SMats Randgaard } 590d32d9864SMats Randgaard } 591d32d9864SMats Randgaard 592d32d9864SMats Randgaard static void tc358743_set_ref_clk(struct v4l2_subdev *sd) 593d32d9864SMats Randgaard { 594d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 595d32d9864SMats Randgaard struct tc358743_platform_data *pdata = &state->pdata; 596d32d9864SMats Randgaard u32 sys_freq; 597d32d9864SMats Randgaard u32 lockdet_ref; 598d32d9864SMats Randgaard u16 fh_min; 599d32d9864SMats Randgaard u16 fh_max; 600d32d9864SMats Randgaard 601d32d9864SMats Randgaard BUG_ON(!(pdata->refclk_hz == 26000000 || 602d32d9864SMats Randgaard pdata->refclk_hz == 27000000 || 603d32d9864SMats Randgaard pdata->refclk_hz == 42000000)); 604d32d9864SMats Randgaard 605d32d9864SMats Randgaard sys_freq = pdata->refclk_hz / 10000; 606d32d9864SMats Randgaard i2c_wr8(sd, SYS_FREQ0, sys_freq & 0x00ff); 607d32d9864SMats Randgaard i2c_wr8(sd, SYS_FREQ1, (sys_freq & 0xff00) >> 8); 608d32d9864SMats Randgaard 609d32d9864SMats Randgaard i2c_wr8_and_or(sd, PHY_CTL0, ~MASK_PHY_SYSCLK_IND, 610d32d9864SMats Randgaard (pdata->refclk_hz == 42000000) ? 611d32d9864SMats Randgaard MASK_PHY_SYSCLK_IND : 0x0); 612d32d9864SMats Randgaard 613d32d9864SMats Randgaard fh_min = pdata->refclk_hz / 100000; 614d32d9864SMats Randgaard i2c_wr8(sd, FH_MIN0, fh_min & 0x00ff); 615d32d9864SMats Randgaard i2c_wr8(sd, FH_MIN1, (fh_min & 0xff00) >> 8); 616d32d9864SMats Randgaard 617d32d9864SMats Randgaard fh_max = (fh_min * 66) / 10; 618d32d9864SMats Randgaard i2c_wr8(sd, FH_MAX0, fh_max & 0x00ff); 619d32d9864SMats Randgaard i2c_wr8(sd, FH_MAX1, (fh_max & 0xff00) >> 8); 620d32d9864SMats Randgaard 621d32d9864SMats Randgaard lockdet_ref = pdata->refclk_hz / 100; 622d32d9864SMats Randgaard i2c_wr8(sd, LOCKDET_REF0, lockdet_ref & 0x0000ff); 623d32d9864SMats Randgaard i2c_wr8(sd, LOCKDET_REF1, (lockdet_ref & 0x00ff00) >> 8); 624d32d9864SMats Randgaard i2c_wr8(sd, LOCKDET_REF2, (lockdet_ref & 0x0f0000) >> 16); 625d32d9864SMats Randgaard 626d32d9864SMats Randgaard i2c_wr8_and_or(sd, NCO_F0_MOD, ~MASK_NCO_F0_MOD, 627d32d9864SMats Randgaard (pdata->refclk_hz == 27000000) ? 628d32d9864SMats Randgaard MASK_NCO_F0_MOD_27MHZ : 0x0); 629d32d9864SMats Randgaard } 630d32d9864SMats Randgaard 631d32d9864SMats Randgaard static void tc358743_set_csi_color_space(struct v4l2_subdev *sd) 632d32d9864SMats Randgaard { 633d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 634d32d9864SMats Randgaard 635d32d9864SMats Randgaard switch (state->mbus_fmt_code) { 636d32d9864SMats Randgaard case MEDIA_BUS_FMT_UYVY8_1X16: 637d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s: YCbCr 422 16-bit\n", __func__); 638d32d9864SMats Randgaard i2c_wr8_and_or(sd, VOUT_SET2, 639d32d9864SMats Randgaard ~(MASK_SEL422 | MASK_VOUT_422FIL_100) & 0xff, 640d32d9864SMats Randgaard MASK_SEL422 | MASK_VOUT_422FIL_100); 641d32d9864SMats Randgaard i2c_wr8_and_or(sd, VI_REP, ~MASK_VOUT_COLOR_SEL & 0xff, 642d32d9864SMats Randgaard MASK_VOUT_COLOR_601_YCBCR_LIMITED); 643d32d9864SMats Randgaard mutex_lock(&state->confctl_mutex); 644d32d9864SMats Randgaard i2c_wr16_and_or(sd, CONFCTL, ~MASK_YCBCRFMT, 645d32d9864SMats Randgaard MASK_YCBCRFMT_422_8_BIT); 646d32d9864SMats Randgaard mutex_unlock(&state->confctl_mutex); 647d32d9864SMats Randgaard break; 648d32d9864SMats Randgaard case MEDIA_BUS_FMT_RGB888_1X24: 649d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s: RGB 888 24-bit\n", __func__); 650d32d9864SMats Randgaard i2c_wr8_and_or(sd, VOUT_SET2, 651d32d9864SMats Randgaard ~(MASK_SEL422 | MASK_VOUT_422FIL_100) & 0xff, 652d32d9864SMats Randgaard 0x00); 653d32d9864SMats Randgaard i2c_wr8_and_or(sd, VI_REP, ~MASK_VOUT_COLOR_SEL & 0xff, 654d32d9864SMats Randgaard MASK_VOUT_COLOR_RGB_FULL); 655d32d9864SMats Randgaard mutex_lock(&state->confctl_mutex); 656d32d9864SMats Randgaard i2c_wr16_and_or(sd, CONFCTL, ~MASK_YCBCRFMT, 0); 657d32d9864SMats Randgaard mutex_unlock(&state->confctl_mutex); 658d32d9864SMats Randgaard break; 659d32d9864SMats Randgaard default: 660d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s: Unsupported format code 0x%x\n", 661d32d9864SMats Randgaard __func__, state->mbus_fmt_code); 662d32d9864SMats Randgaard } 663d32d9864SMats Randgaard } 664d32d9864SMats Randgaard 665d32d9864SMats Randgaard static unsigned tc358743_num_csi_lanes_needed(struct v4l2_subdev *sd) 666d32d9864SMats Randgaard { 667d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 668d32d9864SMats Randgaard struct v4l2_bt_timings *bt = &state->timings.bt; 669d32d9864SMats Randgaard struct tc358743_platform_data *pdata = &state->pdata; 670d32d9864SMats Randgaard u32 bits_pr_pixel = 671d32d9864SMats Randgaard (state->mbus_fmt_code == MEDIA_BUS_FMT_UYVY8_1X16) ? 16 : 24; 672d32d9864SMats Randgaard u32 bps = bt->width * bt->height * fps(bt) * bits_pr_pixel; 673d32d9864SMats Randgaard u32 bps_pr_lane = (pdata->refclk_hz / pdata->pll_prd) * pdata->pll_fbd; 674d32d9864SMats Randgaard 675d32d9864SMats Randgaard return DIV_ROUND_UP(bps, bps_pr_lane); 676d32d9864SMats Randgaard } 677d32d9864SMats Randgaard 678d32d9864SMats Randgaard static void tc358743_set_csi(struct v4l2_subdev *sd) 679d32d9864SMats Randgaard { 680d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 681d32d9864SMats Randgaard struct tc358743_platform_data *pdata = &state->pdata; 682d32d9864SMats Randgaard unsigned lanes = tc358743_num_csi_lanes_needed(sd); 683d32d9864SMats Randgaard 684d32d9864SMats Randgaard v4l2_dbg(3, debug, sd, "%s:\n", __func__); 685d32d9864SMats Randgaard 686d32d9864SMats Randgaard tc358743_reset(sd, MASK_CTXRST); 687d32d9864SMats Randgaard 688d32d9864SMats Randgaard if (lanes < 1) 689d32d9864SMats Randgaard i2c_wr32(sd, CLW_CNTRL, MASK_CLW_LANEDISABLE); 690d32d9864SMats Randgaard if (lanes < 1) 691d32d9864SMats Randgaard i2c_wr32(sd, D0W_CNTRL, MASK_D0W_LANEDISABLE); 692d32d9864SMats Randgaard if (lanes < 2) 693d32d9864SMats Randgaard i2c_wr32(sd, D1W_CNTRL, MASK_D1W_LANEDISABLE); 694d32d9864SMats Randgaard if (lanes < 3) 695d32d9864SMats Randgaard i2c_wr32(sd, D2W_CNTRL, MASK_D2W_LANEDISABLE); 696d32d9864SMats Randgaard if (lanes < 4) 697d32d9864SMats Randgaard i2c_wr32(sd, D3W_CNTRL, MASK_D3W_LANEDISABLE); 698d32d9864SMats Randgaard 699d32d9864SMats Randgaard i2c_wr32(sd, LINEINITCNT, pdata->lineinitcnt); 700d32d9864SMats Randgaard i2c_wr32(sd, LPTXTIMECNT, pdata->lptxtimecnt); 701d32d9864SMats Randgaard i2c_wr32(sd, TCLK_HEADERCNT, pdata->tclk_headercnt); 702d32d9864SMats Randgaard i2c_wr32(sd, TCLK_TRAILCNT, pdata->tclk_trailcnt); 703d32d9864SMats Randgaard i2c_wr32(sd, THS_HEADERCNT, pdata->ths_headercnt); 704d32d9864SMats Randgaard i2c_wr32(sd, TWAKEUP, pdata->twakeup); 705d32d9864SMats Randgaard i2c_wr32(sd, TCLK_POSTCNT, pdata->tclk_postcnt); 706d32d9864SMats Randgaard i2c_wr32(sd, THS_TRAILCNT, pdata->ths_trailcnt); 707d32d9864SMats Randgaard i2c_wr32(sd, HSTXVREGCNT, pdata->hstxvregcnt); 708d32d9864SMats Randgaard 709d32d9864SMats Randgaard i2c_wr32(sd, HSTXVREGEN, 710d32d9864SMats Randgaard ((lanes > 0) ? MASK_CLM_HSTXVREGEN : 0x0) | 711d32d9864SMats Randgaard ((lanes > 0) ? MASK_D0M_HSTXVREGEN : 0x0) | 712d32d9864SMats Randgaard ((lanes > 1) ? MASK_D1M_HSTXVREGEN : 0x0) | 713d32d9864SMats Randgaard ((lanes > 2) ? MASK_D2M_HSTXVREGEN : 0x0) | 714d32d9864SMats Randgaard ((lanes > 3) ? MASK_D3M_HSTXVREGEN : 0x0)); 715d32d9864SMats Randgaard 71625614824SPhilipp Zabel i2c_wr32(sd, TXOPTIONCNTRL, (state->bus.flags & 71725614824SPhilipp Zabel V4L2_MBUS_CSI2_CONTINUOUS_CLOCK) ? MASK_CONTCLKMODE : 0); 718d32d9864SMats Randgaard i2c_wr32(sd, STARTCNTRL, MASK_START); 719d32d9864SMats Randgaard i2c_wr32(sd, CSI_START, MASK_STRT); 720d32d9864SMats Randgaard 721d32d9864SMats Randgaard i2c_wr32(sd, CSI_CONFW, MASK_MODE_SET | 722d32d9864SMats Randgaard MASK_ADDRESS_CSI_CONTROL | 723d32d9864SMats Randgaard MASK_CSI_MODE | 724d32d9864SMats Randgaard MASK_TXHSMD | 725d32d9864SMats Randgaard ((lanes == 4) ? MASK_NOL_4 : 726d32d9864SMats Randgaard (lanes == 3) ? MASK_NOL_3 : 727d32d9864SMats Randgaard (lanes == 2) ? MASK_NOL_2 : MASK_NOL_1)); 728d32d9864SMats Randgaard 729d32d9864SMats Randgaard i2c_wr32(sd, CSI_CONFW, MASK_MODE_SET | 730d32d9864SMats Randgaard MASK_ADDRESS_CSI_ERR_INTENA | MASK_TXBRK | MASK_QUNK | 731d32d9864SMats Randgaard MASK_WCER | MASK_INER); 732d32d9864SMats Randgaard 733d32d9864SMats Randgaard i2c_wr32(sd, CSI_CONFW, MASK_MODE_CLEAR | 734d32d9864SMats Randgaard MASK_ADDRESS_CSI_ERR_HALT | MASK_TXBRK | MASK_QUNK); 735d32d9864SMats Randgaard 736d32d9864SMats Randgaard i2c_wr32(sd, CSI_CONFW, MASK_MODE_SET | 737d32d9864SMats Randgaard MASK_ADDRESS_CSI_INT_ENA | MASK_INTER); 738d32d9864SMats Randgaard } 739d32d9864SMats Randgaard 740d32d9864SMats Randgaard static void tc358743_set_hdmi_phy(struct v4l2_subdev *sd) 741d32d9864SMats Randgaard { 742d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 743d32d9864SMats Randgaard struct tc358743_platform_data *pdata = &state->pdata; 744d32d9864SMats Randgaard 745d32d9864SMats Randgaard /* Default settings from REF_02, sheet "Source HDMI" 746d32d9864SMats Randgaard * and custom settings as platform data */ 747d32d9864SMats Randgaard i2c_wr8_and_or(sd, PHY_EN, ~MASK_ENABLE_PHY, 0x0); 748d32d9864SMats Randgaard i2c_wr8(sd, PHY_CTL1, SET_PHY_AUTO_RST1_US(1600) | 749d32d9864SMats Randgaard SET_FREQ_RANGE_MODE_CYCLES(1)); 750d32d9864SMats Randgaard i2c_wr8_and_or(sd, PHY_CTL2, ~MASK_PHY_AUTO_RSTn, 751d32d9864SMats Randgaard (pdata->hdmi_phy_auto_reset_tmds_detected ? 752d32d9864SMats Randgaard MASK_PHY_AUTO_RST2 : 0) | 753d32d9864SMats Randgaard (pdata->hdmi_phy_auto_reset_tmds_in_range ? 754d32d9864SMats Randgaard MASK_PHY_AUTO_RST3 : 0) | 755d32d9864SMats Randgaard (pdata->hdmi_phy_auto_reset_tmds_valid ? 756d32d9864SMats Randgaard MASK_PHY_AUTO_RST4 : 0)); 757d32d9864SMats Randgaard i2c_wr8(sd, PHY_BIAS, 0x40); 758d32d9864SMats Randgaard i2c_wr8(sd, PHY_CSQ, SET_CSQ_CNT_LEVEL(0x0a)); 759d32d9864SMats Randgaard i2c_wr8(sd, AVM_CTL, 45); 760d32d9864SMats Randgaard i2c_wr8_and_or(sd, HDMI_DET, ~MASK_HDMI_DET_V, 761d32d9864SMats Randgaard pdata->hdmi_detection_delay << 4); 762d32d9864SMats Randgaard i2c_wr8_and_or(sd, HV_RST, ~(MASK_H_PI_RST | MASK_V_PI_RST), 763d32d9864SMats Randgaard (pdata->hdmi_phy_auto_reset_hsync_out_of_range ? 764d32d9864SMats Randgaard MASK_H_PI_RST : 0) | 765d32d9864SMats Randgaard (pdata->hdmi_phy_auto_reset_vsync_out_of_range ? 766d32d9864SMats Randgaard MASK_V_PI_RST : 0)); 767d32d9864SMats Randgaard i2c_wr8_and_or(sd, PHY_EN, ~MASK_ENABLE_PHY, MASK_ENABLE_PHY); 768d32d9864SMats Randgaard } 769d32d9864SMats Randgaard 770d32d9864SMats Randgaard static void tc358743_set_hdmi_audio(struct v4l2_subdev *sd) 771d32d9864SMats Randgaard { 772d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 773d32d9864SMats Randgaard 774d32d9864SMats Randgaard /* Default settings from REF_02, sheet "Source HDMI" */ 775d32d9864SMats Randgaard i2c_wr8(sd, FORCE_MUTE, 0x00); 776d32d9864SMats Randgaard i2c_wr8(sd, AUTO_CMD0, MASK_AUTO_MUTE7 | MASK_AUTO_MUTE6 | 777d32d9864SMats Randgaard MASK_AUTO_MUTE5 | MASK_AUTO_MUTE4 | 778d32d9864SMats Randgaard MASK_AUTO_MUTE1 | MASK_AUTO_MUTE0); 779d32d9864SMats Randgaard i2c_wr8(sd, AUTO_CMD1, MASK_AUTO_MUTE9); 780d32d9864SMats Randgaard i2c_wr8(sd, AUTO_CMD2, MASK_AUTO_PLAY3 | MASK_AUTO_PLAY2); 781d32d9864SMats Randgaard i2c_wr8(sd, BUFINIT_START, SET_BUFINIT_START_MS(500)); 782d32d9864SMats Randgaard i2c_wr8(sd, FS_MUTE, 0x00); 783d32d9864SMats Randgaard i2c_wr8(sd, FS_IMODE, MASK_NLPCM_SMODE | MASK_FS_SMODE); 784d32d9864SMats Randgaard i2c_wr8(sd, ACR_MODE, MASK_CTS_MODE); 785d32d9864SMats Randgaard i2c_wr8(sd, ACR_MDF0, MASK_ACR_L2MDF_1976_PPM | MASK_ACR_L1MDF_976_PPM); 786d32d9864SMats Randgaard i2c_wr8(sd, ACR_MDF1, MASK_ACR_L3MDF_3906_PPM); 787d32d9864SMats Randgaard i2c_wr8(sd, SDO_MODE1, MASK_SDO_FMT_I2S); 788d32d9864SMats Randgaard i2c_wr8(sd, DIV_MODE, SET_DIV_DLY_MS(100)); 789d32d9864SMats Randgaard 790d32d9864SMats Randgaard mutex_lock(&state->confctl_mutex); 791d32d9864SMats Randgaard i2c_wr16_and_or(sd, CONFCTL, 0xffff, MASK_AUDCHNUM_2 | 792d32d9864SMats Randgaard MASK_AUDOUTSEL_I2S | MASK_AUTOINDEX); 793d32d9864SMats Randgaard mutex_unlock(&state->confctl_mutex); 794d32d9864SMats Randgaard } 795d32d9864SMats Randgaard 796d32d9864SMats Randgaard static void tc358743_set_hdmi_info_frame_mode(struct v4l2_subdev *sd) 797d32d9864SMats Randgaard { 798d32d9864SMats Randgaard /* Default settings from REF_02, sheet "Source HDMI" */ 799d32d9864SMats Randgaard i2c_wr8(sd, PK_INT_MODE, MASK_ISRC2_INT_MODE | MASK_ISRC_INT_MODE | 800d32d9864SMats Randgaard MASK_ACP_INT_MODE | MASK_VS_INT_MODE | 801d32d9864SMats Randgaard MASK_SPD_INT_MODE | MASK_MS_INT_MODE | 802d32d9864SMats Randgaard MASK_AUD_INT_MODE | MASK_AVI_INT_MODE); 803d32d9864SMats Randgaard i2c_wr8(sd, NO_PKT_LIMIT, 0x2c); 804d32d9864SMats Randgaard i2c_wr8(sd, NO_PKT_CLR, 0x53); 805d32d9864SMats Randgaard i2c_wr8(sd, ERR_PK_LIMIT, 0x01); 806d32d9864SMats Randgaard i2c_wr8(sd, NO_PKT_LIMIT2, 0x30); 807d32d9864SMats Randgaard i2c_wr8(sd, NO_GDB_LIMIT, 0x10); 808d32d9864SMats Randgaard } 809d32d9864SMats Randgaard 810d32d9864SMats Randgaard static void tc358743_initial_setup(struct v4l2_subdev *sd) 811d32d9864SMats Randgaard { 812d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 813d32d9864SMats Randgaard struct tc358743_platform_data *pdata = &state->pdata; 814d32d9864SMats Randgaard 815d32d9864SMats Randgaard /* CEC and IR are not supported by this driver */ 816d32d9864SMats Randgaard i2c_wr16_and_or(sd, SYSCTL, ~(MASK_CECRST | MASK_IRRST), 817d32d9864SMats Randgaard (MASK_CECRST | MASK_IRRST)); 818d32d9864SMats Randgaard 819d32d9864SMats Randgaard tc358743_reset(sd, MASK_CTXRST | MASK_HDMIRST); 820d32d9864SMats Randgaard tc358743_sleep_mode(sd, false); 821d32d9864SMats Randgaard 822d32d9864SMats Randgaard i2c_wr16(sd, FIFOCTL, pdata->fifo_level); 823d32d9864SMats Randgaard 824d32d9864SMats Randgaard tc358743_set_ref_clk(sd); 825d32d9864SMats Randgaard 826d32d9864SMats Randgaard i2c_wr8_and_or(sd, DDC_CTL, ~MASK_DDC5V_MODE, 827d32d9864SMats Randgaard pdata->ddc5v_delay & MASK_DDC5V_MODE); 828d32d9864SMats Randgaard i2c_wr8_and_or(sd, EDID_MODE, ~MASK_EDID_MODE, MASK_EDID_MODE_E_DDC); 829d32d9864SMats Randgaard 830d32d9864SMats Randgaard tc358743_set_hdmi_phy(sd); 831d32d9864SMats Randgaard tc358743_set_hdmi_hdcp(sd, pdata->enable_hdcp); 832d32d9864SMats Randgaard tc358743_set_hdmi_audio(sd); 833d32d9864SMats Randgaard tc358743_set_hdmi_info_frame_mode(sd); 834d32d9864SMats Randgaard 835d32d9864SMats Randgaard /* All CE and IT formats are detected as RGB full range in DVI mode */ 836d32d9864SMats Randgaard i2c_wr8_and_or(sd, VI_MODE, ~MASK_RGB_DVI, 0); 837d32d9864SMats Randgaard 838d32d9864SMats Randgaard i2c_wr8_and_or(sd, VOUT_SET2, ~MASK_VOUTCOLORMODE, 839d32d9864SMats Randgaard MASK_VOUTCOLORMODE_AUTO); 840d32d9864SMats Randgaard i2c_wr8(sd, VOUT_SET3, MASK_VOUT_EXTCNT); 841d32d9864SMats Randgaard } 842d32d9864SMats Randgaard 843d32d9864SMats Randgaard /* --------------- IRQ --------------- */ 844d32d9864SMats Randgaard 845d32d9864SMats Randgaard static void tc358743_format_change(struct v4l2_subdev *sd) 846d32d9864SMats Randgaard { 847d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 848d32d9864SMats Randgaard struct v4l2_dv_timings timings; 849d32d9864SMats Randgaard const struct v4l2_event tc358743_ev_fmt = { 850d32d9864SMats Randgaard .type = V4L2_EVENT_SOURCE_CHANGE, 851d32d9864SMats Randgaard .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, 852d32d9864SMats Randgaard }; 853d32d9864SMats Randgaard 854d32d9864SMats Randgaard if (tc358743_get_detected_timings(sd, &timings)) { 855d32d9864SMats Randgaard enable_stream(sd, false); 856d32d9864SMats Randgaard 8572874bf3eSMats Randgaard v4l2_dbg(1, debug, sd, "%s: No signal\n", 858d32d9864SMats Randgaard __func__); 859d32d9864SMats Randgaard } else { 86085f9e06cSHans Verkuil if (!v4l2_match_dv_timings(&state->timings, &timings, 0, false)) 861d32d9864SMats Randgaard enable_stream(sd, false); 862d32d9864SMats Randgaard 8632874bf3eSMats Randgaard if (debug) 864d32d9864SMats Randgaard v4l2_print_dv_timings(sd->name, 8652874bf3eSMats Randgaard "tc358743_format_change: New format: ", 866d32d9864SMats Randgaard &timings, false); 867d32d9864SMats Randgaard } 868d32d9864SMats Randgaard 869abeaca0fSPhilipp Zabel if (sd->devnode) 8701140f919SPhilipp Zabel v4l2_subdev_notify_event(sd, &tc358743_ev_fmt); 871d32d9864SMats Randgaard } 872d32d9864SMats Randgaard 873d32d9864SMats Randgaard static void tc358743_init_interrupts(struct v4l2_subdev *sd) 874d32d9864SMats Randgaard { 875d32d9864SMats Randgaard u16 i; 876d32d9864SMats Randgaard 877d32d9864SMats Randgaard /* clear interrupt status registers */ 878d32d9864SMats Randgaard for (i = SYS_INT; i <= KEY_INT; i++) 879d32d9864SMats Randgaard i2c_wr8(sd, i, 0xff); 880d32d9864SMats Randgaard 881d32d9864SMats Randgaard i2c_wr16(sd, INTSTATUS, 0xffff); 882d32d9864SMats Randgaard } 883d32d9864SMats Randgaard 884d32d9864SMats Randgaard static void tc358743_enable_interrupts(struct v4l2_subdev *sd, 885d32d9864SMats Randgaard bool cable_connected) 886d32d9864SMats Randgaard { 887d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s: cable connected = %d\n", __func__, 888d32d9864SMats Randgaard cable_connected); 889d32d9864SMats Randgaard 890d32d9864SMats Randgaard if (cable_connected) { 891d32d9864SMats Randgaard i2c_wr8(sd, SYS_INTM, ~(MASK_M_DDC | MASK_M_DVI_DET | 892d32d9864SMats Randgaard MASK_M_HDMI_DET) & 0xff); 893d32d9864SMats Randgaard i2c_wr8(sd, CLK_INTM, ~MASK_M_IN_DE_CHG); 894d32d9864SMats Randgaard i2c_wr8(sd, CBIT_INTM, ~(MASK_M_CBIT_FS | MASK_M_AF_LOCK | 895d32d9864SMats Randgaard MASK_M_AF_UNLOCK) & 0xff); 896d32d9864SMats Randgaard i2c_wr8(sd, AUDIO_INTM, ~MASK_M_BUFINIT_END); 897d32d9864SMats Randgaard i2c_wr8(sd, MISC_INTM, ~MASK_M_SYNC_CHG); 898d32d9864SMats Randgaard } else { 899d32d9864SMats Randgaard i2c_wr8(sd, SYS_INTM, ~MASK_M_DDC & 0xff); 900d32d9864SMats Randgaard i2c_wr8(sd, CLK_INTM, 0xff); 901d32d9864SMats Randgaard i2c_wr8(sd, CBIT_INTM, 0xff); 902d32d9864SMats Randgaard i2c_wr8(sd, AUDIO_INTM, 0xff); 903d32d9864SMats Randgaard i2c_wr8(sd, MISC_INTM, 0xff); 904d32d9864SMats Randgaard } 905d32d9864SMats Randgaard } 906d32d9864SMats Randgaard 907d32d9864SMats Randgaard static void tc358743_hdmi_audio_int_handler(struct v4l2_subdev *sd, 908d32d9864SMats Randgaard bool *handled) 909d32d9864SMats Randgaard { 910d32d9864SMats Randgaard u8 audio_int_mask = i2c_rd8(sd, AUDIO_INTM); 911d32d9864SMats Randgaard u8 audio_int = i2c_rd8(sd, AUDIO_INT) & ~audio_int_mask; 912d32d9864SMats Randgaard 913d32d9864SMats Randgaard i2c_wr8(sd, AUDIO_INT, audio_int); 914d32d9864SMats Randgaard 915d32d9864SMats Randgaard v4l2_dbg(3, debug, sd, "%s: AUDIO_INT = 0x%02x\n", __func__, audio_int); 916d32d9864SMats Randgaard 917d32d9864SMats Randgaard tc358743_s_ctrl_audio_sampling_rate(sd); 918d32d9864SMats Randgaard tc358743_s_ctrl_audio_present(sd); 919d32d9864SMats Randgaard } 920d32d9864SMats Randgaard 921d32d9864SMats Randgaard static void tc358743_csi_err_int_handler(struct v4l2_subdev *sd, bool *handled) 922d32d9864SMats Randgaard { 923d32d9864SMats Randgaard v4l2_err(sd, "%s: CSI_ERR = 0x%x\n", __func__, i2c_rd32(sd, CSI_ERR)); 924d32d9864SMats Randgaard 925d32d9864SMats Randgaard i2c_wr32(sd, CSI_INT_CLR, MASK_ICRER); 926d32d9864SMats Randgaard } 927d32d9864SMats Randgaard 928d32d9864SMats Randgaard static void tc358743_hdmi_misc_int_handler(struct v4l2_subdev *sd, 929d32d9864SMats Randgaard bool *handled) 930d32d9864SMats Randgaard { 931d32d9864SMats Randgaard u8 misc_int_mask = i2c_rd8(sd, MISC_INTM); 932d32d9864SMats Randgaard u8 misc_int = i2c_rd8(sd, MISC_INT) & ~misc_int_mask; 933d32d9864SMats Randgaard 934d32d9864SMats Randgaard i2c_wr8(sd, MISC_INT, misc_int); 935d32d9864SMats Randgaard 936d32d9864SMats Randgaard v4l2_dbg(3, debug, sd, "%s: MISC_INT = 0x%02x\n", __func__, misc_int); 937d32d9864SMats Randgaard 938d32d9864SMats Randgaard if (misc_int & MASK_I_SYNC_CHG) { 939d32d9864SMats Randgaard /* Reset the HDMI PHY to try to trigger proper lock on the 940d32d9864SMats Randgaard * incoming video format. Erase BKSV to prevent that old keys 941d32d9864SMats Randgaard * are used when a new source is connected. */ 942d32d9864SMats Randgaard if (no_sync(sd) || no_signal(sd)) { 943d32d9864SMats Randgaard tc358743_reset_phy(sd); 944d32d9864SMats Randgaard tc358743_erase_bksv(sd); 945d32d9864SMats Randgaard } 946d32d9864SMats Randgaard 947d32d9864SMats Randgaard tc358743_format_change(sd); 948d32d9864SMats Randgaard 949d32d9864SMats Randgaard misc_int &= ~MASK_I_SYNC_CHG; 950d32d9864SMats Randgaard if (handled) 951d32d9864SMats Randgaard *handled = true; 952d32d9864SMats Randgaard } 953d32d9864SMats Randgaard 954d32d9864SMats Randgaard if (misc_int) { 955d32d9864SMats Randgaard v4l2_err(sd, "%s: Unhandled MISC_INT interrupts: 0x%02x\n", 956d32d9864SMats Randgaard __func__, misc_int); 957d32d9864SMats Randgaard } 958d32d9864SMats Randgaard } 959d32d9864SMats Randgaard 960d32d9864SMats Randgaard static void tc358743_hdmi_cbit_int_handler(struct v4l2_subdev *sd, 961d32d9864SMats Randgaard bool *handled) 962d32d9864SMats Randgaard { 963d32d9864SMats Randgaard u8 cbit_int_mask = i2c_rd8(sd, CBIT_INTM); 964d32d9864SMats Randgaard u8 cbit_int = i2c_rd8(sd, CBIT_INT) & ~cbit_int_mask; 965d32d9864SMats Randgaard 966d32d9864SMats Randgaard i2c_wr8(sd, CBIT_INT, cbit_int); 967d32d9864SMats Randgaard 968d32d9864SMats Randgaard v4l2_dbg(3, debug, sd, "%s: CBIT_INT = 0x%02x\n", __func__, cbit_int); 969d32d9864SMats Randgaard 970d32d9864SMats Randgaard if (cbit_int & MASK_I_CBIT_FS) { 971d32d9864SMats Randgaard 972d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: Audio sample rate changed\n", 973d32d9864SMats Randgaard __func__); 974d32d9864SMats Randgaard tc358743_s_ctrl_audio_sampling_rate(sd); 975d32d9864SMats Randgaard 976d32d9864SMats Randgaard cbit_int &= ~MASK_I_CBIT_FS; 977d32d9864SMats Randgaard if (handled) 978d32d9864SMats Randgaard *handled = true; 979d32d9864SMats Randgaard } 980d32d9864SMats Randgaard 981d32d9864SMats Randgaard if (cbit_int & (MASK_I_AF_LOCK | MASK_I_AF_UNLOCK)) { 982d32d9864SMats Randgaard 983d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: Audio present changed\n", 984d32d9864SMats Randgaard __func__); 985d32d9864SMats Randgaard tc358743_s_ctrl_audio_present(sd); 986d32d9864SMats Randgaard 987d32d9864SMats Randgaard cbit_int &= ~(MASK_I_AF_LOCK | MASK_I_AF_UNLOCK); 988d32d9864SMats Randgaard if (handled) 989d32d9864SMats Randgaard *handled = true; 990d32d9864SMats Randgaard } 991d32d9864SMats Randgaard 992d32d9864SMats Randgaard if (cbit_int) { 993d32d9864SMats Randgaard v4l2_err(sd, "%s: Unhandled CBIT_INT interrupts: 0x%02x\n", 994d32d9864SMats Randgaard __func__, cbit_int); 995d32d9864SMats Randgaard } 996d32d9864SMats Randgaard } 997d32d9864SMats Randgaard 998d32d9864SMats Randgaard static void tc358743_hdmi_clk_int_handler(struct v4l2_subdev *sd, bool *handled) 999d32d9864SMats Randgaard { 1000d32d9864SMats Randgaard u8 clk_int_mask = i2c_rd8(sd, CLK_INTM); 1001d32d9864SMats Randgaard u8 clk_int = i2c_rd8(sd, CLK_INT) & ~clk_int_mask; 1002d32d9864SMats Randgaard 1003d32d9864SMats Randgaard /* Bit 7 and bit 6 are set even when they are masked */ 1004d32d9864SMats Randgaard i2c_wr8(sd, CLK_INT, clk_int | 0x80 | MASK_I_OUT_H_CHG); 1005d32d9864SMats Randgaard 1006d32d9864SMats Randgaard v4l2_dbg(3, debug, sd, "%s: CLK_INT = 0x%02x\n", __func__, clk_int); 1007d32d9864SMats Randgaard 1008d32d9864SMats Randgaard if (clk_int & (MASK_I_IN_DE_CHG)) { 1009d32d9864SMats Randgaard 1010d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: DE size or position has changed\n", 1011d32d9864SMats Randgaard __func__); 1012d32d9864SMats Randgaard 1013d32d9864SMats Randgaard /* If the source switch to a new resolution with the same pixel 1014d32d9864SMats Randgaard * frequency as the existing (e.g. 1080p25 -> 720p50), the 1015d32d9864SMats Randgaard * I_SYNC_CHG interrupt is not always triggered, while the 1016d32d9864SMats Randgaard * I_IN_DE_CHG interrupt seems to work fine. Format change 1017d32d9864SMats Randgaard * notifications are only sent when the signal is stable to 1018d32d9864SMats Randgaard * reduce the number of notifications. */ 1019d32d9864SMats Randgaard if (!no_signal(sd) && !no_sync(sd)) 1020d32d9864SMats Randgaard tc358743_format_change(sd); 1021d32d9864SMats Randgaard 1022d32d9864SMats Randgaard clk_int &= ~(MASK_I_IN_DE_CHG); 1023d32d9864SMats Randgaard if (handled) 1024d32d9864SMats Randgaard *handled = true; 1025d32d9864SMats Randgaard } 1026d32d9864SMats Randgaard 1027d32d9864SMats Randgaard if (clk_int) { 1028d32d9864SMats Randgaard v4l2_err(sd, "%s: Unhandled CLK_INT interrupts: 0x%02x\n", 1029d32d9864SMats Randgaard __func__, clk_int); 1030d32d9864SMats Randgaard } 1031d32d9864SMats Randgaard } 1032d32d9864SMats Randgaard 1033d32d9864SMats Randgaard static void tc358743_hdmi_sys_int_handler(struct v4l2_subdev *sd, bool *handled) 1034d32d9864SMats Randgaard { 1035d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 1036d32d9864SMats Randgaard u8 sys_int_mask = i2c_rd8(sd, SYS_INTM); 1037d32d9864SMats Randgaard u8 sys_int = i2c_rd8(sd, SYS_INT) & ~sys_int_mask; 1038d32d9864SMats Randgaard 1039d32d9864SMats Randgaard i2c_wr8(sd, SYS_INT, sys_int); 1040d32d9864SMats Randgaard 1041d32d9864SMats Randgaard v4l2_dbg(3, debug, sd, "%s: SYS_INT = 0x%02x\n", __func__, sys_int); 1042d32d9864SMats Randgaard 1043d32d9864SMats Randgaard if (sys_int & MASK_I_DDC) { 1044d32d9864SMats Randgaard bool tx_5v = tx_5v_power_present(sd); 1045d32d9864SMats Randgaard 1046d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: Tx 5V power present: %s\n", 1047d32d9864SMats Randgaard __func__, tx_5v ? "yes" : "no"); 1048d32d9864SMats Randgaard 1049d32d9864SMats Randgaard if (tx_5v) { 1050d32d9864SMats Randgaard tc358743_enable_edid(sd); 1051d32d9864SMats Randgaard } else { 1052d32d9864SMats Randgaard tc358743_enable_interrupts(sd, false); 1053d32d9864SMats Randgaard tc358743_disable_edid(sd); 1054d32d9864SMats Randgaard memset(&state->timings, 0, sizeof(state->timings)); 1055d32d9864SMats Randgaard tc358743_erase_bksv(sd); 1056d32d9864SMats Randgaard tc358743_update_controls(sd); 1057d32d9864SMats Randgaard } 1058d32d9864SMats Randgaard 1059d32d9864SMats Randgaard sys_int &= ~MASK_I_DDC; 1060d32d9864SMats Randgaard if (handled) 1061d32d9864SMats Randgaard *handled = true; 1062d32d9864SMats Randgaard } 1063d32d9864SMats Randgaard 1064d32d9864SMats Randgaard if (sys_int & MASK_I_DVI) { 1065d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: HDMI->DVI change detected\n", 1066d32d9864SMats Randgaard __func__); 1067d32d9864SMats Randgaard 1068d32d9864SMats Randgaard /* Reset the HDMI PHY to try to trigger proper lock on the 1069d32d9864SMats Randgaard * incoming video format. Erase BKSV to prevent that old keys 1070d32d9864SMats Randgaard * are used when a new source is connected. */ 1071d32d9864SMats Randgaard if (no_sync(sd) || no_signal(sd)) { 1072d32d9864SMats Randgaard tc358743_reset_phy(sd); 1073d32d9864SMats Randgaard tc358743_erase_bksv(sd); 1074d32d9864SMats Randgaard } 1075d32d9864SMats Randgaard 1076d32d9864SMats Randgaard sys_int &= ~MASK_I_DVI; 1077d32d9864SMats Randgaard if (handled) 1078d32d9864SMats Randgaard *handled = true; 1079d32d9864SMats Randgaard } 1080d32d9864SMats Randgaard 1081d32d9864SMats Randgaard if (sys_int & MASK_I_HDMI) { 1082d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: DVI->HDMI change detected\n", 1083d32d9864SMats Randgaard __func__); 1084d32d9864SMats Randgaard 1085d32d9864SMats Randgaard /* Register is reset in DVI mode (REF_01, c. 6.6.41) */ 1086d32d9864SMats Randgaard i2c_wr8(sd, ANA_CTL, MASK_APPL_PCSX_NORMAL | MASK_ANALOG_ON); 1087d32d9864SMats Randgaard 1088d32d9864SMats Randgaard sys_int &= ~MASK_I_HDMI; 1089d32d9864SMats Randgaard if (handled) 1090d32d9864SMats Randgaard *handled = true; 1091d32d9864SMats Randgaard } 1092d32d9864SMats Randgaard 1093d32d9864SMats Randgaard if (sys_int) { 1094d32d9864SMats Randgaard v4l2_err(sd, "%s: Unhandled SYS_INT interrupts: 0x%02x\n", 1095d32d9864SMats Randgaard __func__, sys_int); 1096d32d9864SMats Randgaard } 1097d32d9864SMats Randgaard } 1098d32d9864SMats Randgaard 1099d32d9864SMats Randgaard /* --------------- CORE OPS --------------- */ 1100d32d9864SMats Randgaard 1101d32d9864SMats Randgaard static int tc358743_log_status(struct v4l2_subdev *sd) 1102d32d9864SMats Randgaard { 1103d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 1104d32d9864SMats Randgaard struct v4l2_dv_timings timings; 1105d32d9864SMats Randgaard uint8_t hdmi_sys_status = i2c_rd8(sd, SYS_STATUS); 1106d32d9864SMats Randgaard uint16_t sysctl = i2c_rd16(sd, SYSCTL); 1107d32d9864SMats Randgaard u8 vi_status3 = i2c_rd8(sd, VI_STATUS3); 1108d32d9864SMats Randgaard const int deep_color_mode[4] = { 8, 10, 12, 16 }; 1109d32d9864SMats Randgaard static const char * const input_color_space[] = { 1110d32d9864SMats Randgaard "RGB", "YCbCr 601", "Adobe RGB", "YCbCr 709", "NA (4)", 1111d32d9864SMats Randgaard "xvYCC 601", "NA(6)", "xvYCC 709", "NA(8)", "sYCC601", 1112d32d9864SMats Randgaard "NA(10)", "NA(11)", "NA(12)", "Adobe YCC 601"}; 1113d32d9864SMats Randgaard 1114d32d9864SMats Randgaard v4l2_info(sd, "-----Chip status-----\n"); 1115d32d9864SMats Randgaard v4l2_info(sd, "Chip ID: 0x%02x\n", 1116d32d9864SMats Randgaard (i2c_rd16(sd, CHIPID) & MASK_CHIPID) >> 8); 1117d32d9864SMats Randgaard v4l2_info(sd, "Chip revision: 0x%02x\n", 1118d32d9864SMats Randgaard i2c_rd16(sd, CHIPID) & MASK_REVID); 1119d32d9864SMats Randgaard v4l2_info(sd, "Reset: IR: %d, CEC: %d, CSI TX: %d, HDMI: %d\n", 1120d32d9864SMats Randgaard !!(sysctl & MASK_IRRST), 1121d32d9864SMats Randgaard !!(sysctl & MASK_CECRST), 1122d32d9864SMats Randgaard !!(sysctl & MASK_CTXRST), 1123d32d9864SMats Randgaard !!(sysctl & MASK_HDMIRST)); 1124d32d9864SMats Randgaard v4l2_info(sd, "Sleep mode: %s\n", sysctl & MASK_SLEEP ? "on" : "off"); 1125d32d9864SMats Randgaard v4l2_info(sd, "Cable detected (+5V power): %s\n", 1126d32d9864SMats Randgaard hdmi_sys_status & MASK_S_DDC5V ? "yes" : "no"); 1127d32d9864SMats Randgaard v4l2_info(sd, "DDC lines enabled: %s\n", 1128d32d9864SMats Randgaard (i2c_rd8(sd, EDID_MODE) & MASK_EDID_MODE_E_DDC) ? 1129d32d9864SMats Randgaard "yes" : "no"); 1130d32d9864SMats Randgaard v4l2_info(sd, "Hotplug enabled: %s\n", 1131d32d9864SMats Randgaard (i2c_rd8(sd, HPD_CTL) & MASK_HPD_OUT0) ? 1132d32d9864SMats Randgaard "yes" : "no"); 1133d32d9864SMats Randgaard v4l2_info(sd, "CEC enabled: %s\n", 1134d32d9864SMats Randgaard (i2c_rd16(sd, CECEN) & MASK_CECEN) ? "yes" : "no"); 1135d32d9864SMats Randgaard v4l2_info(sd, "-----Signal status-----\n"); 1136d32d9864SMats Randgaard v4l2_info(sd, "TMDS signal detected: %s\n", 1137d32d9864SMats Randgaard hdmi_sys_status & MASK_S_TMDS ? "yes" : "no"); 1138d32d9864SMats Randgaard v4l2_info(sd, "Stable sync signal: %s\n", 1139d32d9864SMats Randgaard hdmi_sys_status & MASK_S_SYNC ? "yes" : "no"); 1140d32d9864SMats Randgaard v4l2_info(sd, "PHY PLL locked: %s\n", 1141d32d9864SMats Randgaard hdmi_sys_status & MASK_S_PHY_PLL ? "yes" : "no"); 1142d32d9864SMats Randgaard v4l2_info(sd, "PHY DE detected: %s\n", 1143d32d9864SMats Randgaard hdmi_sys_status & MASK_S_PHY_SCDT ? "yes" : "no"); 1144d32d9864SMats Randgaard 1145d32d9864SMats Randgaard if (tc358743_get_detected_timings(sd, &timings)) { 1146d32d9864SMats Randgaard v4l2_info(sd, "No video detected\n"); 1147d32d9864SMats Randgaard } else { 1148d32d9864SMats Randgaard v4l2_print_dv_timings(sd->name, "Detected format: ", &timings, 1149d32d9864SMats Randgaard true); 1150d32d9864SMats Randgaard } 1151d32d9864SMats Randgaard v4l2_print_dv_timings(sd->name, "Configured format: ", &state->timings, 1152d32d9864SMats Randgaard true); 1153d32d9864SMats Randgaard 1154d32d9864SMats Randgaard v4l2_info(sd, "-----CSI-TX status-----\n"); 1155d32d9864SMats Randgaard v4l2_info(sd, "Lanes needed: %d\n", 1156d32d9864SMats Randgaard tc358743_num_csi_lanes_needed(sd)); 1157d32d9864SMats Randgaard v4l2_info(sd, "Lanes in use: %d\n", 1158d32d9864SMats Randgaard tc358743_num_csi_lanes_in_use(sd)); 1159d32d9864SMats Randgaard v4l2_info(sd, "Waiting for particular sync signal: %s\n", 1160d32d9864SMats Randgaard (i2c_rd16(sd, CSI_STATUS) & MASK_S_WSYNC) ? 1161d32d9864SMats Randgaard "yes" : "no"); 1162d32d9864SMats Randgaard v4l2_info(sd, "Transmit mode: %s\n", 1163d32d9864SMats Randgaard (i2c_rd16(sd, CSI_STATUS) & MASK_S_TXACT) ? 1164d32d9864SMats Randgaard "yes" : "no"); 1165d32d9864SMats Randgaard v4l2_info(sd, "Receive mode: %s\n", 1166d32d9864SMats Randgaard (i2c_rd16(sd, CSI_STATUS) & MASK_S_RXACT) ? 1167d32d9864SMats Randgaard "yes" : "no"); 1168d32d9864SMats Randgaard v4l2_info(sd, "Stopped: %s\n", 1169d32d9864SMats Randgaard (i2c_rd16(sd, CSI_STATUS) & MASK_S_HLT) ? 1170d32d9864SMats Randgaard "yes" : "no"); 1171d32d9864SMats Randgaard v4l2_info(sd, "Color space: %s\n", 1172d32d9864SMats Randgaard state->mbus_fmt_code == MEDIA_BUS_FMT_UYVY8_1X16 ? 1173d32d9864SMats Randgaard "YCbCr 422 16-bit" : 1174d32d9864SMats Randgaard state->mbus_fmt_code == MEDIA_BUS_FMT_RGB888_1X24 ? 1175d32d9864SMats Randgaard "RGB 888 24-bit" : "Unsupported"); 1176d32d9864SMats Randgaard 1177d32d9864SMats Randgaard v4l2_info(sd, "-----%s status-----\n", is_hdmi(sd) ? "HDMI" : "DVI-D"); 1178d32d9864SMats Randgaard v4l2_info(sd, "HDCP encrypted content: %s\n", 1179d32d9864SMats Randgaard hdmi_sys_status & MASK_S_HDCP ? "yes" : "no"); 1180d32d9864SMats Randgaard v4l2_info(sd, "Input color space: %s %s range\n", 1181d32d9864SMats Randgaard input_color_space[(vi_status3 & MASK_S_V_COLOR) >> 1], 1182d32d9864SMats Randgaard (vi_status3 & MASK_LIMITED) ? "limited" : "full"); 1183d32d9864SMats Randgaard if (!is_hdmi(sd)) 1184d32d9864SMats Randgaard return 0; 1185d32d9864SMats Randgaard v4l2_info(sd, "AV Mute: %s\n", hdmi_sys_status & MASK_S_AVMUTE ? "on" : 1186d32d9864SMats Randgaard "off"); 1187d32d9864SMats Randgaard v4l2_info(sd, "Deep color mode: %d-bits per channel\n", 1188d32d9864SMats Randgaard deep_color_mode[(i2c_rd8(sd, VI_STATUS1) & 1189d32d9864SMats Randgaard MASK_S_DEEPCOLOR) >> 2]); 1190d32d9864SMats Randgaard print_avi_infoframe(sd); 1191d32d9864SMats Randgaard 1192d32d9864SMats Randgaard return 0; 1193d32d9864SMats Randgaard } 1194d32d9864SMats Randgaard 1195d32d9864SMats Randgaard #ifdef CONFIG_VIDEO_ADV_DEBUG 1196d32d9864SMats Randgaard static void tc358743_print_register_map(struct v4l2_subdev *sd) 1197d32d9864SMats Randgaard { 119885e510a1SHans Verkuil v4l2_info(sd, "0x0000-0x00FF: Global Control Register\n"); 119985e510a1SHans Verkuil v4l2_info(sd, "0x0100-0x01FF: CSI2-TX PHY Register\n"); 120085e510a1SHans Verkuil v4l2_info(sd, "0x0200-0x03FF: CSI2-TX PPI Register\n"); 120185e510a1SHans Verkuil v4l2_info(sd, "0x0400-0x05FF: Reserved\n"); 120285e510a1SHans Verkuil v4l2_info(sd, "0x0600-0x06FF: CEC Register\n"); 120385e510a1SHans Verkuil v4l2_info(sd, "0x0700-0x84FF: Reserved\n"); 120485e510a1SHans Verkuil v4l2_info(sd, "0x8500-0x85FF: HDMIRX System Control Register\n"); 120585e510a1SHans Verkuil v4l2_info(sd, "0x8600-0x86FF: HDMIRX Audio Control Register\n"); 120685e510a1SHans Verkuil v4l2_info(sd, "0x8700-0x87FF: HDMIRX InfoFrame packet data Register\n"); 120785e510a1SHans Verkuil v4l2_info(sd, "0x8800-0x88FF: HDMIRX HDCP Port Register\n"); 120885e510a1SHans Verkuil v4l2_info(sd, "0x8900-0x89FF: HDMIRX Video Output Port & 3D Register\n"); 120985e510a1SHans Verkuil v4l2_info(sd, "0x8A00-0x8BFF: Reserved\n"); 121085e510a1SHans Verkuil v4l2_info(sd, "0x8C00-0x8FFF: HDMIRX EDID-RAM (1024bytes)\n"); 121185e510a1SHans Verkuil v4l2_info(sd, "0x9000-0x90FF: HDMIRX GBD Extraction Control\n"); 121285e510a1SHans Verkuil v4l2_info(sd, "0x9100-0x92FF: HDMIRX GBD RAM read\n"); 1213d32d9864SMats Randgaard v4l2_info(sd, "0x9300- : Reserved\n"); 1214d32d9864SMats Randgaard } 1215d32d9864SMats Randgaard 1216d32d9864SMats Randgaard static int tc358743_get_reg_size(u16 address) 1217d32d9864SMats Randgaard { 1218d32d9864SMats Randgaard /* REF_01 p. 66-72 */ 1219d32d9864SMats Randgaard if (address <= 0x00ff) 1220d32d9864SMats Randgaard return 2; 1221d32d9864SMats Randgaard else if ((address >= 0x0100) && (address <= 0x06FF)) 1222d32d9864SMats Randgaard return 4; 1223d32d9864SMats Randgaard else if ((address >= 0x0700) && (address <= 0x84ff)) 1224d32d9864SMats Randgaard return 2; 1225d32d9864SMats Randgaard else 1226d32d9864SMats Randgaard return 1; 1227d32d9864SMats Randgaard } 1228d32d9864SMats Randgaard 1229d32d9864SMats Randgaard static int tc358743_g_register(struct v4l2_subdev *sd, 1230d32d9864SMats Randgaard 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 reg->size = tc358743_get_reg_size(reg->reg); 1238d32d9864SMats Randgaard 1239d32d9864SMats Randgaard i2c_rd(sd, reg->reg, (u8 *)®->val, reg->size); 1240d32d9864SMats Randgaard 1241d32d9864SMats Randgaard return 0; 1242d32d9864SMats Randgaard } 1243d32d9864SMats Randgaard 1244d32d9864SMats Randgaard static int tc358743_s_register(struct v4l2_subdev *sd, 1245d32d9864SMats Randgaard const struct v4l2_dbg_register *reg) 1246d32d9864SMats Randgaard { 1247d32d9864SMats Randgaard if (reg->reg > 0xffff) { 1248d32d9864SMats Randgaard tc358743_print_register_map(sd); 1249d32d9864SMats Randgaard return -EINVAL; 1250d32d9864SMats Randgaard } 1251d32d9864SMats Randgaard 1252d32d9864SMats Randgaard /* It should not be possible for the user to enable HDCP with a simple 1253d32d9864SMats Randgaard * v4l2-dbg command. 1254d32d9864SMats Randgaard * 1255d32d9864SMats Randgaard * DO NOT REMOVE THIS unless all other issues with HDCP have been 1256d32d9864SMats Randgaard * resolved. 1257d32d9864SMats Randgaard */ 1258d32d9864SMats Randgaard if (reg->reg == HDCP_MODE || 1259d32d9864SMats Randgaard reg->reg == HDCP_REG1 || 1260d32d9864SMats Randgaard reg->reg == HDCP_REG2 || 1261d32d9864SMats Randgaard reg->reg == HDCP_REG3 || 1262d32d9864SMats Randgaard reg->reg == BCAPS) 1263d32d9864SMats Randgaard return 0; 1264d32d9864SMats Randgaard 1265d32d9864SMats Randgaard i2c_wr(sd, (u16)reg->reg, (u8 *)®->val, 1266d32d9864SMats Randgaard tc358743_get_reg_size(reg->reg)); 1267d32d9864SMats Randgaard 1268d32d9864SMats Randgaard return 0; 1269d32d9864SMats Randgaard } 1270d32d9864SMats Randgaard #endif 1271d32d9864SMats Randgaard 1272d32d9864SMats Randgaard static int tc358743_isr(struct v4l2_subdev *sd, u32 status, bool *handled) 1273d32d9864SMats Randgaard { 1274d32d9864SMats Randgaard u16 intstatus = i2c_rd16(sd, INTSTATUS); 1275d32d9864SMats Randgaard 1276d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: IntStatus = 0x%04x\n", __func__, intstatus); 1277d32d9864SMats Randgaard 1278d32d9864SMats Randgaard if (intstatus & MASK_HDMI_INT) { 1279d32d9864SMats Randgaard u8 hdmi_int0 = i2c_rd8(sd, HDMI_INT0); 1280d32d9864SMats Randgaard u8 hdmi_int1 = i2c_rd8(sd, HDMI_INT1); 1281d32d9864SMats Randgaard 1282d32d9864SMats Randgaard if (hdmi_int0 & MASK_I_MISC) 1283d32d9864SMats Randgaard tc358743_hdmi_misc_int_handler(sd, handled); 1284d32d9864SMats Randgaard if (hdmi_int1 & MASK_I_CBIT) 1285d32d9864SMats Randgaard tc358743_hdmi_cbit_int_handler(sd, handled); 1286d32d9864SMats Randgaard if (hdmi_int1 & MASK_I_CLK) 1287d32d9864SMats Randgaard tc358743_hdmi_clk_int_handler(sd, handled); 1288d32d9864SMats Randgaard if (hdmi_int1 & MASK_I_SYS) 1289d32d9864SMats Randgaard tc358743_hdmi_sys_int_handler(sd, handled); 1290d32d9864SMats Randgaard if (hdmi_int1 & MASK_I_AUD) 1291d32d9864SMats Randgaard tc358743_hdmi_audio_int_handler(sd, handled); 1292d32d9864SMats Randgaard 1293d32d9864SMats Randgaard i2c_wr16(sd, INTSTATUS, MASK_HDMI_INT); 1294d32d9864SMats Randgaard intstatus &= ~MASK_HDMI_INT; 1295d32d9864SMats Randgaard } 1296d32d9864SMats Randgaard 1297d32d9864SMats Randgaard if (intstatus & MASK_CSI_INT) { 1298d32d9864SMats Randgaard u32 csi_int = i2c_rd32(sd, CSI_INT); 1299d32d9864SMats Randgaard 1300d32d9864SMats Randgaard if (csi_int & MASK_INTER) 1301d32d9864SMats Randgaard tc358743_csi_err_int_handler(sd, handled); 1302d32d9864SMats Randgaard 1303d32d9864SMats Randgaard i2c_wr16(sd, INTSTATUS, MASK_CSI_INT); 1304d32d9864SMats Randgaard intstatus &= ~MASK_CSI_INT; 1305d32d9864SMats Randgaard } 1306d32d9864SMats Randgaard 1307d32d9864SMats Randgaard intstatus = i2c_rd16(sd, INTSTATUS); 1308d32d9864SMats Randgaard if (intstatus) { 1309d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, 1310d32d9864SMats Randgaard "%s: Unhandled IntStatus interrupts: 0x%02x\n", 1311d32d9864SMats Randgaard __func__, intstatus); 1312d32d9864SMats Randgaard } 1313d32d9864SMats Randgaard 1314d32d9864SMats Randgaard return 0; 1315d32d9864SMats Randgaard } 1316d32d9864SMats Randgaard 1317d747b806SPhilipp Zabel static irqreturn_t tc358743_irq_handler(int irq, void *dev_id) 1318d747b806SPhilipp Zabel { 1319d747b806SPhilipp Zabel struct tc358743_state *state = dev_id; 1320d747b806SPhilipp Zabel bool handled; 1321d747b806SPhilipp Zabel 1322d747b806SPhilipp Zabel tc358743_isr(&state->sd, 0, &handled); 1323d747b806SPhilipp Zabel 1324d747b806SPhilipp Zabel return handled ? IRQ_HANDLED : IRQ_NONE; 1325d747b806SPhilipp Zabel } 1326d747b806SPhilipp Zabel 13271140f919SPhilipp Zabel static int tc358743_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, 13281140f919SPhilipp Zabel struct v4l2_event_subscription *sub) 13291140f919SPhilipp Zabel { 13301140f919SPhilipp Zabel switch (sub->type) { 13311140f919SPhilipp Zabel case V4L2_EVENT_SOURCE_CHANGE: 13321140f919SPhilipp Zabel return v4l2_src_change_event_subdev_subscribe(sd, fh, sub); 13331140f919SPhilipp Zabel case V4L2_EVENT_CTRL: 13341140f919SPhilipp Zabel return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub); 13351140f919SPhilipp Zabel default: 13361140f919SPhilipp Zabel return -EINVAL; 13371140f919SPhilipp Zabel } 13381140f919SPhilipp Zabel } 13391140f919SPhilipp Zabel 1340d32d9864SMats Randgaard /* --------------- VIDEO OPS --------------- */ 1341d32d9864SMats Randgaard 1342d32d9864SMats Randgaard static int tc358743_g_input_status(struct v4l2_subdev *sd, u32 *status) 1343d32d9864SMats Randgaard { 1344d32d9864SMats Randgaard *status = 0; 1345d32d9864SMats Randgaard *status |= no_signal(sd) ? V4L2_IN_ST_NO_SIGNAL : 0; 1346d32d9864SMats Randgaard *status |= no_sync(sd) ? V4L2_IN_ST_NO_SYNC : 0; 1347d32d9864SMats Randgaard 1348d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: status = 0x%x\n", __func__, *status); 1349d32d9864SMats Randgaard 1350d32d9864SMats Randgaard return 0; 1351d32d9864SMats Randgaard } 1352d32d9864SMats Randgaard 1353d32d9864SMats Randgaard static int tc358743_s_dv_timings(struct v4l2_subdev *sd, 1354d32d9864SMats Randgaard struct v4l2_dv_timings *timings) 1355d32d9864SMats Randgaard { 1356d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 1357d32d9864SMats Randgaard 1358d32d9864SMats Randgaard if (!timings) 1359d32d9864SMats Randgaard return -EINVAL; 1360d32d9864SMats Randgaard 1361d32d9864SMats Randgaard if (debug) 1362d32d9864SMats Randgaard v4l2_print_dv_timings(sd->name, "tc358743_s_dv_timings: ", 1363d32d9864SMats Randgaard timings, false); 1364d32d9864SMats Randgaard 136585f9e06cSHans Verkuil if (v4l2_match_dv_timings(&state->timings, timings, 0, false)) { 1366d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: no change\n", __func__); 1367d32d9864SMats Randgaard return 0; 1368d32d9864SMats Randgaard } 1369d32d9864SMats Randgaard 1370d32d9864SMats Randgaard if (!v4l2_valid_dv_timings(timings, 1371d32d9864SMats Randgaard &tc358743_timings_cap, NULL, NULL)) { 1372d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: timings out of range\n", __func__); 1373d32d9864SMats Randgaard return -ERANGE; 1374d32d9864SMats Randgaard } 1375d32d9864SMats Randgaard 1376d32d9864SMats Randgaard state->timings = *timings; 1377d32d9864SMats Randgaard 1378d32d9864SMats Randgaard enable_stream(sd, false); 1379d32d9864SMats Randgaard tc358743_set_pll(sd); 1380d32d9864SMats Randgaard tc358743_set_csi(sd); 1381d32d9864SMats Randgaard 1382d32d9864SMats Randgaard return 0; 1383d32d9864SMats Randgaard } 1384d32d9864SMats Randgaard 1385d32d9864SMats Randgaard static int tc358743_g_dv_timings(struct v4l2_subdev *sd, 1386d32d9864SMats Randgaard struct v4l2_dv_timings *timings) 1387d32d9864SMats Randgaard { 1388d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 1389d32d9864SMats Randgaard 1390d32d9864SMats Randgaard *timings = state->timings; 1391d32d9864SMats Randgaard 1392d32d9864SMats Randgaard return 0; 1393d32d9864SMats Randgaard } 1394d32d9864SMats Randgaard 1395d32d9864SMats Randgaard static int tc358743_enum_dv_timings(struct v4l2_subdev *sd, 1396d32d9864SMats Randgaard struct v4l2_enum_dv_timings *timings) 1397d32d9864SMats Randgaard { 1398d32d9864SMats Randgaard if (timings->pad != 0) 1399d32d9864SMats Randgaard return -EINVAL; 1400d32d9864SMats Randgaard 1401d32d9864SMats Randgaard return v4l2_enum_dv_timings_cap(timings, 1402d32d9864SMats Randgaard &tc358743_timings_cap, NULL, NULL); 1403d32d9864SMats Randgaard } 1404d32d9864SMats Randgaard 1405d32d9864SMats Randgaard static int tc358743_query_dv_timings(struct v4l2_subdev *sd, 1406d32d9864SMats Randgaard struct v4l2_dv_timings *timings) 1407d32d9864SMats Randgaard { 1408d32d9864SMats Randgaard int ret; 1409d32d9864SMats Randgaard 1410d32d9864SMats Randgaard ret = tc358743_get_detected_timings(sd, timings); 1411d32d9864SMats Randgaard if (ret) 1412d32d9864SMats Randgaard return ret; 1413d32d9864SMats Randgaard 1414d32d9864SMats Randgaard if (debug) 1415d32d9864SMats Randgaard v4l2_print_dv_timings(sd->name, "tc358743_query_dv_timings: ", 1416d32d9864SMats Randgaard timings, false); 1417d32d9864SMats Randgaard 1418d32d9864SMats Randgaard if (!v4l2_valid_dv_timings(timings, 1419d32d9864SMats Randgaard &tc358743_timings_cap, NULL, NULL)) { 1420d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: timings out of range\n", __func__); 1421d32d9864SMats Randgaard return -ERANGE; 1422d32d9864SMats Randgaard } 1423d32d9864SMats Randgaard 1424d32d9864SMats Randgaard return 0; 1425d32d9864SMats Randgaard } 1426d32d9864SMats Randgaard 1427d32d9864SMats Randgaard static int tc358743_dv_timings_cap(struct v4l2_subdev *sd, 1428d32d9864SMats Randgaard struct v4l2_dv_timings_cap *cap) 1429d32d9864SMats Randgaard { 1430d32d9864SMats Randgaard if (cap->pad != 0) 1431d32d9864SMats Randgaard return -EINVAL; 1432d32d9864SMats Randgaard 1433d32d9864SMats Randgaard *cap = tc358743_timings_cap; 1434d32d9864SMats Randgaard 1435d32d9864SMats Randgaard return 0; 1436d32d9864SMats Randgaard } 1437d32d9864SMats Randgaard 1438d32d9864SMats Randgaard static int tc358743_g_mbus_config(struct v4l2_subdev *sd, 1439d32d9864SMats Randgaard struct v4l2_mbus_config *cfg) 1440d32d9864SMats Randgaard { 1441d32d9864SMats Randgaard cfg->type = V4L2_MBUS_CSI2; 1442d32d9864SMats Randgaard 1443d32d9864SMats Randgaard /* Support for non-continuous CSI-2 clock is missing in the driver */ 1444d32d9864SMats Randgaard cfg->flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; 1445d32d9864SMats Randgaard 1446d32d9864SMats Randgaard switch (tc358743_num_csi_lanes_in_use(sd)) { 1447d32d9864SMats Randgaard case 1: 1448d32d9864SMats Randgaard cfg->flags |= V4L2_MBUS_CSI2_1_LANE; 1449d32d9864SMats Randgaard break; 1450d32d9864SMats Randgaard case 2: 1451d32d9864SMats Randgaard cfg->flags |= V4L2_MBUS_CSI2_2_LANE; 1452d32d9864SMats Randgaard break; 1453d32d9864SMats Randgaard case 3: 1454d32d9864SMats Randgaard cfg->flags |= V4L2_MBUS_CSI2_3_LANE; 1455d32d9864SMats Randgaard break; 1456d32d9864SMats Randgaard case 4: 1457d32d9864SMats Randgaard cfg->flags |= V4L2_MBUS_CSI2_4_LANE; 1458d32d9864SMats Randgaard break; 1459d32d9864SMats Randgaard default: 1460d32d9864SMats Randgaard return -EINVAL; 1461d32d9864SMats Randgaard } 1462d32d9864SMats Randgaard 1463d32d9864SMats Randgaard return 0; 1464d32d9864SMats Randgaard } 1465d32d9864SMats Randgaard 1466d32d9864SMats Randgaard static int tc358743_s_stream(struct v4l2_subdev *sd, int enable) 1467d32d9864SMats Randgaard { 1468d32d9864SMats Randgaard enable_stream(sd, enable); 1469d32d9864SMats Randgaard 1470d32d9864SMats Randgaard return 0; 1471d32d9864SMats Randgaard } 1472d32d9864SMats Randgaard 1473d32d9864SMats Randgaard /* --------------- PAD OPS --------------- */ 1474d32d9864SMats Randgaard 1475d32d9864SMats Randgaard static int tc358743_get_fmt(struct v4l2_subdev *sd, 1476d32d9864SMats Randgaard struct v4l2_subdev_pad_config *cfg, 1477d32d9864SMats Randgaard struct v4l2_subdev_format *format) 1478d32d9864SMats Randgaard { 1479d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 1480d32d9864SMats Randgaard u8 vi_rep = i2c_rd8(sd, VI_REP); 1481d32d9864SMats Randgaard 1482d32d9864SMats Randgaard if (format->pad != 0) 1483d32d9864SMats Randgaard return -EINVAL; 1484d32d9864SMats Randgaard 1485d32d9864SMats Randgaard format->format.code = state->mbus_fmt_code; 1486d32d9864SMats Randgaard format->format.width = state->timings.bt.width; 1487d32d9864SMats Randgaard format->format.height = state->timings.bt.height; 1488d32d9864SMats Randgaard format->format.field = V4L2_FIELD_NONE; 1489d32d9864SMats Randgaard 1490d32d9864SMats Randgaard switch (vi_rep & MASK_VOUT_COLOR_SEL) { 1491d32d9864SMats Randgaard case MASK_VOUT_COLOR_RGB_FULL: 1492d32d9864SMats Randgaard case MASK_VOUT_COLOR_RGB_LIMITED: 1493d32d9864SMats Randgaard format->format.colorspace = V4L2_COLORSPACE_SRGB; 1494d32d9864SMats Randgaard break; 1495d32d9864SMats Randgaard case MASK_VOUT_COLOR_601_YCBCR_LIMITED: 1496d32d9864SMats Randgaard case MASK_VOUT_COLOR_601_YCBCR_FULL: 1497d32d9864SMats Randgaard format->format.colorspace = V4L2_COLORSPACE_SMPTE170M; 1498d32d9864SMats Randgaard break; 1499d32d9864SMats Randgaard case MASK_VOUT_COLOR_709_YCBCR_FULL: 1500d32d9864SMats Randgaard case MASK_VOUT_COLOR_709_YCBCR_LIMITED: 1501d32d9864SMats Randgaard format->format.colorspace = V4L2_COLORSPACE_REC709; 1502d32d9864SMats Randgaard break; 1503d32d9864SMats Randgaard default: 1504d32d9864SMats Randgaard format->format.colorspace = 0; 1505d32d9864SMats Randgaard break; 1506d32d9864SMats Randgaard } 1507d32d9864SMats Randgaard 1508d32d9864SMats Randgaard return 0; 1509d32d9864SMats Randgaard } 1510d32d9864SMats Randgaard 1511d32d9864SMats Randgaard static int tc358743_set_fmt(struct v4l2_subdev *sd, 1512d32d9864SMats Randgaard struct v4l2_subdev_pad_config *cfg, 1513d32d9864SMats Randgaard struct v4l2_subdev_format *format) 1514d32d9864SMats Randgaard { 1515d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 1516d32d9864SMats Randgaard 1517d32d9864SMats Randgaard u32 code = format->format.code; /* is overwritten by get_fmt */ 1518d32d9864SMats Randgaard int ret = tc358743_get_fmt(sd, cfg, format); 1519d32d9864SMats Randgaard 1520d32d9864SMats Randgaard format->format.code = code; 1521d32d9864SMats Randgaard 1522d32d9864SMats Randgaard if (ret) 1523d32d9864SMats Randgaard return ret; 1524d32d9864SMats Randgaard 1525d32d9864SMats Randgaard switch (code) { 1526d32d9864SMats Randgaard case MEDIA_BUS_FMT_RGB888_1X24: 1527d32d9864SMats Randgaard case MEDIA_BUS_FMT_UYVY8_1X16: 1528d32d9864SMats Randgaard break; 1529d32d9864SMats Randgaard default: 1530d32d9864SMats Randgaard return -EINVAL; 1531d32d9864SMats Randgaard } 1532d32d9864SMats Randgaard 1533d32d9864SMats Randgaard if (format->which == V4L2_SUBDEV_FORMAT_TRY) 1534d32d9864SMats Randgaard return 0; 1535d32d9864SMats Randgaard 1536d32d9864SMats Randgaard state->mbus_fmt_code = format->format.code; 1537d32d9864SMats Randgaard 1538d32d9864SMats Randgaard enable_stream(sd, false); 1539d32d9864SMats Randgaard tc358743_set_pll(sd); 1540d32d9864SMats Randgaard tc358743_set_csi(sd); 1541d32d9864SMats Randgaard tc358743_set_csi_color_space(sd); 1542d32d9864SMats Randgaard 1543d32d9864SMats Randgaard return 0; 1544d32d9864SMats Randgaard } 1545d32d9864SMats Randgaard 1546d32d9864SMats Randgaard static int tc358743_g_edid(struct v4l2_subdev *sd, 1547d32d9864SMats Randgaard struct v4l2_subdev_edid *edid) 1548d32d9864SMats Randgaard { 1549d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 1550d32d9864SMats Randgaard 155172777724SHans Verkuil memset(edid->reserved, 0, sizeof(edid->reserved)); 155272777724SHans Verkuil 1553d32d9864SMats Randgaard if (edid->pad != 0) 1554d32d9864SMats Randgaard return -EINVAL; 1555d32d9864SMats Randgaard 1556d32d9864SMats Randgaard if (edid->start_block == 0 && edid->blocks == 0) { 1557d32d9864SMats Randgaard edid->blocks = state->edid_blocks_written; 1558d32d9864SMats Randgaard return 0; 1559d32d9864SMats Randgaard } 1560d32d9864SMats Randgaard 1561d32d9864SMats Randgaard if (state->edid_blocks_written == 0) 1562d32d9864SMats Randgaard return -ENODATA; 1563d32d9864SMats Randgaard 1564d32d9864SMats Randgaard if (edid->start_block >= state->edid_blocks_written || 1565d32d9864SMats Randgaard edid->blocks == 0) 1566d32d9864SMats Randgaard return -EINVAL; 1567d32d9864SMats Randgaard 1568d32d9864SMats Randgaard if (edid->start_block + edid->blocks > state->edid_blocks_written) 1569d32d9864SMats Randgaard edid->blocks = state->edid_blocks_written - edid->start_block; 1570d32d9864SMats Randgaard 1571d32d9864SMats Randgaard i2c_rd(sd, EDID_RAM + (edid->start_block * EDID_BLOCK_SIZE), edid->edid, 1572d32d9864SMats Randgaard edid->blocks * EDID_BLOCK_SIZE); 1573d32d9864SMats Randgaard 1574d32d9864SMats Randgaard return 0; 1575d32d9864SMats Randgaard } 1576d32d9864SMats Randgaard 1577d32d9864SMats Randgaard static int tc358743_s_edid(struct v4l2_subdev *sd, 1578d32d9864SMats Randgaard struct v4l2_subdev_edid *edid) 1579d32d9864SMats Randgaard { 1580d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 1581d32d9864SMats Randgaard u16 edid_len = edid->blocks * EDID_BLOCK_SIZE; 1582fcae73faSMats Randgaard int i; 1583d32d9864SMats Randgaard 1584d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s, pad %d, start block %d, blocks %d\n", 1585d32d9864SMats Randgaard __func__, edid->pad, edid->start_block, edid->blocks); 1586d32d9864SMats Randgaard 158772777724SHans Verkuil memset(edid->reserved, 0, sizeof(edid->reserved)); 158872777724SHans Verkuil 1589d32d9864SMats Randgaard if (edid->pad != 0) 1590d32d9864SMats Randgaard return -EINVAL; 1591d32d9864SMats Randgaard 1592d32d9864SMats Randgaard if (edid->start_block != 0) 1593d32d9864SMats Randgaard return -EINVAL; 1594d32d9864SMats Randgaard 1595d32d9864SMats Randgaard if (edid->blocks > EDID_NUM_BLOCKS_MAX) { 1596d32d9864SMats Randgaard edid->blocks = EDID_NUM_BLOCKS_MAX; 1597d32d9864SMats Randgaard return -E2BIG; 1598d32d9864SMats Randgaard } 1599d32d9864SMats Randgaard 1600d32d9864SMats Randgaard tc358743_disable_edid(sd); 1601d32d9864SMats Randgaard 1602d32d9864SMats Randgaard i2c_wr8(sd, EDID_LEN1, edid_len & 0xff); 1603d32d9864SMats Randgaard i2c_wr8(sd, EDID_LEN2, edid_len >> 8); 1604d32d9864SMats Randgaard 1605d32d9864SMats Randgaard if (edid->blocks == 0) { 1606d32d9864SMats Randgaard state->edid_blocks_written = 0; 1607d32d9864SMats Randgaard return 0; 1608d32d9864SMats Randgaard } 1609d32d9864SMats Randgaard 1610fcae73faSMats Randgaard for (i = 0; i < edid_len; i += EDID_BLOCK_SIZE) 1611fcae73faSMats Randgaard i2c_wr(sd, EDID_RAM + i, edid->edid + i, EDID_BLOCK_SIZE); 1612d32d9864SMats Randgaard 1613d32d9864SMats Randgaard state->edid_blocks_written = edid->blocks; 1614d32d9864SMats Randgaard 1615d32d9864SMats Randgaard if (tx_5v_power_present(sd)) 1616d32d9864SMats Randgaard tc358743_enable_edid(sd); 1617d32d9864SMats Randgaard 1618d32d9864SMats Randgaard return 0; 1619d32d9864SMats Randgaard } 1620d32d9864SMats Randgaard 1621d32d9864SMats Randgaard /* -------------------------------------------------------------------------- */ 1622d32d9864SMats Randgaard 1623d32d9864SMats Randgaard static const struct v4l2_subdev_core_ops tc358743_core_ops = { 1624d32d9864SMats Randgaard .log_status = tc358743_log_status, 1625d32d9864SMats Randgaard #ifdef CONFIG_VIDEO_ADV_DEBUG 1626d32d9864SMats Randgaard .g_register = tc358743_g_register, 1627d32d9864SMats Randgaard .s_register = tc358743_s_register, 1628d32d9864SMats Randgaard #endif 1629d32d9864SMats Randgaard .interrupt_service_routine = tc358743_isr, 16301140f919SPhilipp Zabel .subscribe_event = tc358743_subscribe_event, 16311140f919SPhilipp Zabel .unsubscribe_event = v4l2_event_subdev_unsubscribe, 1632d32d9864SMats Randgaard }; 1633d32d9864SMats Randgaard 1634d32d9864SMats Randgaard static const struct v4l2_subdev_video_ops tc358743_video_ops = { 1635d32d9864SMats Randgaard .g_input_status = tc358743_g_input_status, 1636d32d9864SMats Randgaard .s_dv_timings = tc358743_s_dv_timings, 1637d32d9864SMats Randgaard .g_dv_timings = tc358743_g_dv_timings, 1638d32d9864SMats Randgaard .query_dv_timings = tc358743_query_dv_timings, 1639d32d9864SMats Randgaard .g_mbus_config = tc358743_g_mbus_config, 1640d32d9864SMats Randgaard .s_stream = tc358743_s_stream, 1641d32d9864SMats Randgaard }; 1642d32d9864SMats Randgaard 1643d32d9864SMats Randgaard static const struct v4l2_subdev_pad_ops tc358743_pad_ops = { 1644d32d9864SMats Randgaard .set_fmt = tc358743_set_fmt, 1645d32d9864SMats Randgaard .get_fmt = tc358743_get_fmt, 1646d32d9864SMats Randgaard .get_edid = tc358743_g_edid, 1647d32d9864SMats Randgaard .set_edid = tc358743_s_edid, 1648d32d9864SMats Randgaard .enum_dv_timings = tc358743_enum_dv_timings, 1649d32d9864SMats Randgaard .dv_timings_cap = tc358743_dv_timings_cap, 1650d32d9864SMats Randgaard }; 1651d32d9864SMats Randgaard 1652d32d9864SMats Randgaard static const struct v4l2_subdev_ops tc358743_ops = { 1653d32d9864SMats Randgaard .core = &tc358743_core_ops, 1654d32d9864SMats Randgaard .video = &tc358743_video_ops, 1655d32d9864SMats Randgaard .pad = &tc358743_pad_ops, 1656d32d9864SMats Randgaard }; 1657d32d9864SMats Randgaard 1658d32d9864SMats Randgaard /* --------------- CUSTOM CTRLS --------------- */ 1659d32d9864SMats Randgaard 1660d32d9864SMats Randgaard static const struct v4l2_ctrl_config tc358743_ctrl_audio_sampling_rate = { 1661d32d9864SMats Randgaard .id = TC358743_CID_AUDIO_SAMPLING_RATE, 1662d32d9864SMats Randgaard .name = "Audio sampling rate", 1663d32d9864SMats Randgaard .type = V4L2_CTRL_TYPE_INTEGER, 1664d32d9864SMats Randgaard .min = 0, 1665d32d9864SMats Randgaard .max = 768000, 1666d32d9864SMats Randgaard .step = 1, 1667d32d9864SMats Randgaard .def = 0, 1668d32d9864SMats Randgaard .flags = V4L2_CTRL_FLAG_READ_ONLY, 1669d32d9864SMats Randgaard }; 1670d32d9864SMats Randgaard 1671d32d9864SMats Randgaard static const struct v4l2_ctrl_config tc358743_ctrl_audio_present = { 1672d32d9864SMats Randgaard .id = TC358743_CID_AUDIO_PRESENT, 1673d32d9864SMats Randgaard .name = "Audio present", 1674d32d9864SMats Randgaard .type = V4L2_CTRL_TYPE_BOOLEAN, 1675d32d9864SMats Randgaard .min = 0, 1676d32d9864SMats Randgaard .max = 1, 1677d32d9864SMats Randgaard .step = 1, 1678d32d9864SMats Randgaard .def = 0, 1679d32d9864SMats Randgaard .flags = V4L2_CTRL_FLAG_READ_ONLY, 1680d32d9864SMats Randgaard }; 1681d32d9864SMats Randgaard 1682d32d9864SMats Randgaard /* --------------- PROBE / REMOVE --------------- */ 1683d32d9864SMats Randgaard 168425614824SPhilipp Zabel #ifdef CONFIG_OF 168525614824SPhilipp Zabel static void tc358743_gpio_reset(struct tc358743_state *state) 168625614824SPhilipp Zabel { 168725614824SPhilipp Zabel usleep_range(5000, 10000); 168825614824SPhilipp Zabel gpiod_set_value(state->reset_gpio, 1); 168925614824SPhilipp Zabel usleep_range(1000, 2000); 169025614824SPhilipp Zabel gpiod_set_value(state->reset_gpio, 0); 169125614824SPhilipp Zabel msleep(20); 169225614824SPhilipp Zabel } 169325614824SPhilipp Zabel 169425614824SPhilipp Zabel static int tc358743_probe_of(struct tc358743_state *state) 169525614824SPhilipp Zabel { 169625614824SPhilipp Zabel struct device *dev = &state->i2c_client->dev; 169725614824SPhilipp Zabel struct v4l2_of_endpoint *endpoint; 169825614824SPhilipp Zabel struct device_node *ep; 169925614824SPhilipp Zabel struct clk *refclk; 170025614824SPhilipp Zabel u32 bps_pr_lane; 170125614824SPhilipp Zabel int ret = -EINVAL; 170225614824SPhilipp Zabel 170325614824SPhilipp Zabel refclk = devm_clk_get(dev, "refclk"); 170425614824SPhilipp Zabel if (IS_ERR(refclk)) { 170525614824SPhilipp Zabel if (PTR_ERR(refclk) != -EPROBE_DEFER) 170625614824SPhilipp Zabel dev_err(dev, "failed to get refclk: %ld\n", 170725614824SPhilipp Zabel PTR_ERR(refclk)); 170825614824SPhilipp Zabel return PTR_ERR(refclk); 170925614824SPhilipp Zabel } 171025614824SPhilipp Zabel 171125614824SPhilipp Zabel ep = of_graph_get_next_endpoint(dev->of_node, NULL); 171225614824SPhilipp Zabel if (!ep) { 171325614824SPhilipp Zabel dev_err(dev, "missing endpoint node\n"); 171425614824SPhilipp Zabel return -EINVAL; 171525614824SPhilipp Zabel } 171625614824SPhilipp Zabel 171725614824SPhilipp Zabel endpoint = v4l2_of_alloc_parse_endpoint(ep); 171825614824SPhilipp Zabel if (IS_ERR(endpoint)) { 171925614824SPhilipp Zabel dev_err(dev, "failed to parse endpoint\n"); 172025614824SPhilipp Zabel return PTR_ERR(endpoint); 172125614824SPhilipp Zabel } 172225614824SPhilipp Zabel 172325614824SPhilipp Zabel if (endpoint->bus_type != V4L2_MBUS_CSI2 || 172425614824SPhilipp Zabel endpoint->bus.mipi_csi2.num_data_lanes == 0 || 172525614824SPhilipp Zabel endpoint->nr_of_link_frequencies == 0) { 172625614824SPhilipp Zabel dev_err(dev, "missing CSI-2 properties in endpoint\n"); 172725614824SPhilipp Zabel goto free_endpoint; 172825614824SPhilipp Zabel } 172925614824SPhilipp Zabel 173025614824SPhilipp Zabel state->bus = endpoint->bus.mipi_csi2; 173125614824SPhilipp Zabel 173225614824SPhilipp Zabel clk_prepare_enable(refclk); 173325614824SPhilipp Zabel 173425614824SPhilipp Zabel state->pdata.refclk_hz = clk_get_rate(refclk); 173525614824SPhilipp Zabel state->pdata.ddc5v_delay = DDC5V_DELAY_100_MS; 173625614824SPhilipp Zabel state->pdata.enable_hdcp = false; 173725614824SPhilipp Zabel /* A FIFO level of 16 should be enough for 2-lane 720p60 at 594 MHz. */ 173825614824SPhilipp Zabel state->pdata.fifo_level = 16; 173925614824SPhilipp Zabel /* 174025614824SPhilipp Zabel * The PLL input clock is obtained by dividing refclk by pll_prd. 174125614824SPhilipp Zabel * It must be between 6 MHz and 40 MHz, lower frequency is better. 174225614824SPhilipp Zabel */ 174325614824SPhilipp Zabel switch (state->pdata.refclk_hz) { 174425614824SPhilipp Zabel case 26000000: 174525614824SPhilipp Zabel case 27000000: 174625614824SPhilipp Zabel case 42000000: 174725614824SPhilipp Zabel state->pdata.pll_prd = state->pdata.refclk_hz / 6000000; 174825614824SPhilipp Zabel break; 174925614824SPhilipp Zabel default: 175025614824SPhilipp Zabel dev_err(dev, "unsupported refclk rate: %u Hz\n", 175125614824SPhilipp Zabel state->pdata.refclk_hz); 175225614824SPhilipp Zabel goto disable_clk; 175325614824SPhilipp Zabel } 175425614824SPhilipp Zabel 175525614824SPhilipp Zabel /* 175625614824SPhilipp Zabel * The CSI bps per lane must be between 62.5 Mbps and 1 Gbps. 175725614824SPhilipp Zabel * The default is 594 Mbps for 4-lane 1080p60 or 2-lane 720p60. 175825614824SPhilipp Zabel */ 175925614824SPhilipp Zabel bps_pr_lane = 2 * endpoint->link_frequencies[0]; 176025614824SPhilipp Zabel if (bps_pr_lane < 62500000U || bps_pr_lane > 1000000000U) { 176125614824SPhilipp Zabel dev_err(dev, "unsupported bps per lane: %u bps\n", bps_pr_lane); 176225614824SPhilipp Zabel goto disable_clk; 176325614824SPhilipp Zabel } 176425614824SPhilipp Zabel 176525614824SPhilipp Zabel /* The CSI speed per lane is refclk / pll_prd * pll_fbd */ 176625614824SPhilipp Zabel state->pdata.pll_fbd = bps_pr_lane / 176725614824SPhilipp Zabel state->pdata.refclk_hz * state->pdata.pll_prd; 176825614824SPhilipp Zabel 176925614824SPhilipp Zabel /* 177025614824SPhilipp Zabel * FIXME: These timings are from REF_02 for 594 Mbps per lane (297 MHz 177125614824SPhilipp Zabel * link frequency). In principle it should be possible to calculate 177225614824SPhilipp Zabel * them based on link frequency and resolution. 177325614824SPhilipp Zabel */ 177425614824SPhilipp Zabel if (bps_pr_lane != 594000000U) 177525614824SPhilipp Zabel dev_warn(dev, "untested bps per lane: %u bps\n", bps_pr_lane); 177625614824SPhilipp Zabel state->pdata.lineinitcnt = 0xe80; 177725614824SPhilipp Zabel state->pdata.lptxtimecnt = 0x003; 177825614824SPhilipp Zabel /* tclk-preparecnt: 3, tclk-zerocnt: 20 */ 177925614824SPhilipp Zabel state->pdata.tclk_headercnt = 0x1403; 178025614824SPhilipp Zabel state->pdata.tclk_trailcnt = 0x00; 178125614824SPhilipp Zabel /* ths-preparecnt: 3, ths-zerocnt: 1 */ 178225614824SPhilipp Zabel state->pdata.ths_headercnt = 0x0103; 178325614824SPhilipp Zabel state->pdata.twakeup = 0x4882; 178425614824SPhilipp Zabel state->pdata.tclk_postcnt = 0x008; 178525614824SPhilipp Zabel state->pdata.ths_trailcnt = 0x2; 178625614824SPhilipp Zabel state->pdata.hstxvregcnt = 0; 178725614824SPhilipp Zabel 17881e137d92SUwe Kleine-König state->reset_gpio = devm_gpiod_get_optional(dev, "reset", 17891e137d92SUwe Kleine-König GPIOD_OUT_LOW); 179025614824SPhilipp Zabel if (IS_ERR(state->reset_gpio)) { 179125614824SPhilipp Zabel dev_err(dev, "failed to get reset gpio\n"); 179225614824SPhilipp Zabel ret = PTR_ERR(state->reset_gpio); 179325614824SPhilipp Zabel goto disable_clk; 179425614824SPhilipp Zabel } 179525614824SPhilipp Zabel 17961e137d92SUwe Kleine-König if (state->reset_gpio) 179725614824SPhilipp Zabel tc358743_gpio_reset(state); 179825614824SPhilipp Zabel 179925614824SPhilipp Zabel ret = 0; 180025614824SPhilipp Zabel goto free_endpoint; 180125614824SPhilipp Zabel 180225614824SPhilipp Zabel disable_clk: 180325614824SPhilipp Zabel clk_disable_unprepare(refclk); 180425614824SPhilipp Zabel free_endpoint: 180525614824SPhilipp Zabel v4l2_of_free_endpoint(endpoint); 180625614824SPhilipp Zabel return ret; 180725614824SPhilipp Zabel } 180825614824SPhilipp Zabel #else 180925614824SPhilipp Zabel static inline int tc358743_probe_of(struct tc358743_state *state) 181025614824SPhilipp Zabel { 181125614824SPhilipp Zabel return -ENODEV; 181225614824SPhilipp Zabel } 181325614824SPhilipp Zabel #endif 181425614824SPhilipp Zabel 1815d32d9864SMats Randgaard static int tc358743_probe(struct i2c_client *client, 1816d32d9864SMats Randgaard const struct i2c_device_id *id) 1817d32d9864SMats Randgaard { 1818d32d9864SMats Randgaard static struct v4l2_dv_timings default_timing = 1819d32d9864SMats Randgaard V4L2_DV_BT_CEA_640X480P59_94; 1820d32d9864SMats Randgaard struct tc358743_state *state; 1821d32d9864SMats Randgaard struct tc358743_platform_data *pdata = client->dev.platform_data; 1822d32d9864SMats Randgaard struct v4l2_subdev *sd; 1823d32d9864SMats Randgaard int err; 1824d32d9864SMats Randgaard 1825d32d9864SMats Randgaard if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 1826d32d9864SMats Randgaard return -EIO; 1827d32d9864SMats Randgaard v4l_dbg(1, debug, client, "chip found @ 0x%x (%s)\n", 1828d32d9864SMats Randgaard client->addr << 1, client->adapter->name); 1829d32d9864SMats Randgaard 1830d32d9864SMats Randgaard state = devm_kzalloc(&client->dev, sizeof(struct tc358743_state), 1831d32d9864SMats Randgaard GFP_KERNEL); 1832d32d9864SMats Randgaard if (!state) 1833d32d9864SMats Randgaard return -ENOMEM; 1834d32d9864SMats Randgaard 1835d32d9864SMats Randgaard state->i2c_client = client; 183625614824SPhilipp Zabel 183725614824SPhilipp Zabel /* platform data */ 183825614824SPhilipp Zabel if (pdata) { 183925614824SPhilipp Zabel state->pdata = *pdata; 184025614824SPhilipp Zabel state->bus.flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; 184125614824SPhilipp Zabel } else { 184225614824SPhilipp Zabel err = tc358743_probe_of(state); 184325614824SPhilipp Zabel if (err == -ENODEV) 184425614824SPhilipp Zabel v4l_err(client, "No platform data!\n"); 184525614824SPhilipp Zabel if (err) 184625614824SPhilipp Zabel return err; 184725614824SPhilipp Zabel } 184825614824SPhilipp Zabel 1849d32d9864SMats Randgaard sd = &state->sd; 1850d32d9864SMats Randgaard v4l2_i2c_subdev_init(sd, client, &tc358743_ops); 18518ec23da7SPhilipp Zabel sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; 1852d32d9864SMats Randgaard 1853d32d9864SMats Randgaard /* i2c access */ 1854d32d9864SMats Randgaard if ((i2c_rd16(sd, CHIPID) & MASK_CHIPID) != 0) { 1855d32d9864SMats Randgaard v4l2_info(sd, "not a TC358743 on address 0x%x\n", 1856d32d9864SMats Randgaard client->addr << 1); 1857d32d9864SMats Randgaard return -ENODEV; 1858d32d9864SMats Randgaard } 1859d32d9864SMats Randgaard 1860d32d9864SMats Randgaard /* control handlers */ 1861d32d9864SMats Randgaard v4l2_ctrl_handler_init(&state->hdl, 3); 1862d32d9864SMats Randgaard 1863d32d9864SMats Randgaard state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(&state->hdl, NULL, 1864d32d9864SMats Randgaard V4L2_CID_DV_RX_POWER_PRESENT, 0, 1, 0, 0); 1865d32d9864SMats Randgaard 1866d32d9864SMats Randgaard /* custom controls */ 1867d32d9864SMats Randgaard state->audio_sampling_rate_ctrl = v4l2_ctrl_new_custom(&state->hdl, 1868d32d9864SMats Randgaard &tc358743_ctrl_audio_sampling_rate, NULL); 1869d32d9864SMats Randgaard 1870d32d9864SMats Randgaard state->audio_present_ctrl = v4l2_ctrl_new_custom(&state->hdl, 1871d32d9864SMats Randgaard &tc358743_ctrl_audio_present, NULL); 1872d32d9864SMats Randgaard 1873d32d9864SMats Randgaard sd->ctrl_handler = &state->hdl; 1874d32d9864SMats Randgaard if (state->hdl.error) { 1875d32d9864SMats Randgaard err = state->hdl.error; 1876d32d9864SMats Randgaard goto err_hdl; 1877d32d9864SMats Randgaard } 1878d32d9864SMats Randgaard 1879d32d9864SMats Randgaard if (tc358743_update_controls(sd)) { 1880d32d9864SMats Randgaard err = -ENODEV; 1881d32d9864SMats Randgaard goto err_hdl; 1882d32d9864SMats Randgaard } 1883d32d9864SMats Randgaard 18844c5211a1SPhilipp Zabel state->pad.flags = MEDIA_PAD_FL_SOURCE; 1885ab22e77cSMauro Carvalho Chehab err = media_entity_pads_init(&sd->entity, 1, &state->pad); 18864c5211a1SPhilipp Zabel if (err < 0) 18874c5211a1SPhilipp Zabel goto err_hdl; 18884c5211a1SPhilipp Zabel 18894c5211a1SPhilipp Zabel sd->dev = &client->dev; 18904c5211a1SPhilipp Zabel err = v4l2_async_register_subdev(sd); 18914c5211a1SPhilipp Zabel if (err < 0) 18924c5211a1SPhilipp Zabel goto err_hdl; 18934c5211a1SPhilipp Zabel 1894d32d9864SMats Randgaard mutex_init(&state->confctl_mutex); 1895d32d9864SMats Randgaard 1896d32d9864SMats Randgaard INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug, 1897d32d9864SMats Randgaard tc358743_delayed_work_enable_hotplug); 1898d32d9864SMats Randgaard 1899d32d9864SMats Randgaard tc358743_initial_setup(sd); 1900d32d9864SMats Randgaard 1901d32d9864SMats Randgaard tc358743_s_dv_timings(sd, &default_timing); 1902d32d9864SMats Randgaard 1903d32d9864SMats Randgaard state->mbus_fmt_code = MEDIA_BUS_FMT_RGB888_1X24; 1904d32d9864SMats Randgaard tc358743_set_csi_color_space(sd); 1905d32d9864SMats Randgaard 1906d32d9864SMats Randgaard tc358743_init_interrupts(sd); 1907d747b806SPhilipp Zabel 1908d747b806SPhilipp Zabel if (state->i2c_client->irq) { 1909d747b806SPhilipp Zabel err = devm_request_threaded_irq(&client->dev, 1910d747b806SPhilipp Zabel state->i2c_client->irq, 1911d747b806SPhilipp Zabel NULL, tc358743_irq_handler, 1912d747b806SPhilipp Zabel IRQF_TRIGGER_HIGH | IRQF_ONESHOT, 1913d747b806SPhilipp Zabel "tc358743", state); 1914d747b806SPhilipp Zabel if (err) 1915d747b806SPhilipp Zabel goto err_work_queues; 1916d747b806SPhilipp Zabel } 1917d747b806SPhilipp Zabel 1918d32d9864SMats Randgaard tc358743_enable_interrupts(sd, tx_5v_power_present(sd)); 1919d32d9864SMats Randgaard i2c_wr16(sd, INTMASK, ~(MASK_HDMI_MSK | MASK_CSI_MSK) & 0xffff); 1920d32d9864SMats Randgaard 1921d32d9864SMats Randgaard err = v4l2_ctrl_handler_setup(sd->ctrl_handler); 1922d32d9864SMats Randgaard if (err) 1923d32d9864SMats Randgaard goto err_work_queues; 1924d32d9864SMats Randgaard 1925d32d9864SMats Randgaard v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, 1926d32d9864SMats Randgaard client->addr << 1, client->adapter->name); 1927d32d9864SMats Randgaard 1928d32d9864SMats Randgaard return 0; 1929d32d9864SMats Randgaard 1930d32d9864SMats Randgaard err_work_queues: 1931d32d9864SMats Randgaard cancel_delayed_work(&state->delayed_work_enable_hotplug); 1932d32d9864SMats Randgaard mutex_destroy(&state->confctl_mutex); 1933d32d9864SMats Randgaard err_hdl: 19344c5211a1SPhilipp Zabel media_entity_cleanup(&sd->entity); 1935d32d9864SMats Randgaard v4l2_ctrl_handler_free(&state->hdl); 1936d32d9864SMats Randgaard return err; 1937d32d9864SMats Randgaard } 1938d32d9864SMats Randgaard 1939d32d9864SMats Randgaard static int tc358743_remove(struct i2c_client *client) 1940d32d9864SMats Randgaard { 1941d32d9864SMats Randgaard struct v4l2_subdev *sd = i2c_get_clientdata(client); 1942d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 1943d32d9864SMats Randgaard 1944d32d9864SMats Randgaard cancel_delayed_work(&state->delayed_work_enable_hotplug); 19454c5211a1SPhilipp Zabel v4l2_async_unregister_subdev(sd); 1946d32d9864SMats Randgaard v4l2_device_unregister_subdev(sd); 1947d32d9864SMats Randgaard mutex_destroy(&state->confctl_mutex); 19484c5211a1SPhilipp Zabel media_entity_cleanup(&sd->entity); 1949d32d9864SMats Randgaard v4l2_ctrl_handler_free(&state->hdl); 1950d32d9864SMats Randgaard 1951d32d9864SMats Randgaard return 0; 1952d32d9864SMats Randgaard } 1953d32d9864SMats Randgaard 1954d32d9864SMats Randgaard static struct i2c_device_id tc358743_id[] = { 1955d32d9864SMats Randgaard {"tc358743", 0}, 1956d32d9864SMats Randgaard {} 1957d32d9864SMats Randgaard }; 1958d32d9864SMats Randgaard 1959d32d9864SMats Randgaard MODULE_DEVICE_TABLE(i2c, tc358743_id); 1960d32d9864SMats Randgaard 1961d32d9864SMats Randgaard static struct i2c_driver tc358743_driver = { 1962d32d9864SMats Randgaard .driver = { 1963d32d9864SMats Randgaard .name = "tc358743", 1964d32d9864SMats Randgaard }, 1965d32d9864SMats Randgaard .probe = tc358743_probe, 1966d32d9864SMats Randgaard .remove = tc358743_remove, 1967d32d9864SMats Randgaard .id_table = tc358743_id, 1968d32d9864SMats Randgaard }; 1969d32d9864SMats Randgaard 1970d32d9864SMats Randgaard module_i2c_driver(tc358743_driver); 1971