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> 364e66a52aSDave Stevenson #include <linux/timer.h> 37859969b3SSakari Ailus #include <linux/of_graph.h> 38d32d9864SMats Randgaard #include <linux/videodev2.h> 39d32d9864SMats Randgaard #include <linux/workqueue.h> 40d32d9864SMats Randgaard #include <linux/v4l2-dv-timings.h> 41d32d9864SMats Randgaard #include <linux/hdmi.h> 42a0ec8d1dSHans Verkuil #include <media/cec.h> 43d32d9864SMats Randgaard #include <media/v4l2-dv-timings.h> 44d32d9864SMats Randgaard #include <media/v4l2-device.h> 45d32d9864SMats Randgaard #include <media/v4l2-ctrls.h> 461140f919SPhilipp Zabel #include <media/v4l2-event.h> 47859969b3SSakari Ailus #include <media/v4l2-fwnode.h> 48b5dcee22SMauro Carvalho Chehab #include <media/i2c/tc358743.h> 49d32d9864SMats Randgaard 50d32d9864SMats Randgaard #include "tc358743_regs.h" 51d32d9864SMats Randgaard 52d32d9864SMats Randgaard static int debug; 53d32d9864SMats Randgaard module_param(debug, int, 0644); 54d32d9864SMats Randgaard MODULE_PARM_DESC(debug, "debug level (0-3)"); 55d32d9864SMats Randgaard 56d32d9864SMats Randgaard MODULE_DESCRIPTION("Toshiba TC358743 HDMI to CSI-2 bridge driver"); 57d32d9864SMats Randgaard MODULE_AUTHOR("Ramakrishnan Muthukrishnan <ram@rkrishnan.org>"); 58d32d9864SMats Randgaard MODULE_AUTHOR("Mikhail Khelik <mkhelik@cisco.com>"); 59d32d9864SMats Randgaard MODULE_AUTHOR("Mats Randgaard <matrandg@cisco.com>"); 60d32d9864SMats Randgaard MODULE_LICENSE("GPL"); 61d32d9864SMats Randgaard 62d32d9864SMats Randgaard #define EDID_NUM_BLOCKS_MAX 8 63d32d9864SMats Randgaard #define EDID_BLOCK_SIZE 128 64d32d9864SMats Randgaard 65fcae73faSMats Randgaard #define I2C_MAX_XFER_SIZE (EDID_BLOCK_SIZE + 2) 661d88f831SMauro Carvalho Chehab 67a0ec8d1dSHans Verkuil #define POLL_INTERVAL_CEC_MS 10 684e66a52aSDave Stevenson #define POLL_INTERVAL_MS 1000 694e66a52aSDave Stevenson 70d32d9864SMats Randgaard static const struct v4l2_dv_timings_cap tc358743_timings_cap = { 71d32d9864SMats Randgaard .type = V4L2_DV_BT_656_1120, 72d32d9864SMats Randgaard /* keep this initialization for compatibility with GCC < 4.4.6 */ 73d32d9864SMats Randgaard .reserved = { 0 }, 74d32d9864SMats Randgaard /* Pixel clock from REF_01 p. 20. Min/max height/width are unknown */ 75d32d9864SMats Randgaard V4L2_INIT_BT_TIMINGS(1, 10000, 1, 10000, 0, 165000000, 76d32d9864SMats Randgaard V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | 77d32d9864SMats Randgaard V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT, 78d32d9864SMats Randgaard V4L2_DV_BT_CAP_PROGRESSIVE | 79d32d9864SMats Randgaard V4L2_DV_BT_CAP_REDUCED_BLANKING | 80d32d9864SMats Randgaard V4L2_DV_BT_CAP_CUSTOM) 81d32d9864SMats Randgaard }; 82d32d9864SMats Randgaard 83d32d9864SMats Randgaard struct tc358743_state { 84d32d9864SMats Randgaard struct tc358743_platform_data pdata; 85859969b3SSakari Ailus struct v4l2_fwnode_bus_mipi_csi2 bus; 86d32d9864SMats Randgaard struct v4l2_subdev sd; 87d32d9864SMats Randgaard struct media_pad pad; 88d32d9864SMats Randgaard struct v4l2_ctrl_handler hdl; 89d32d9864SMats Randgaard struct i2c_client *i2c_client; 90d32d9864SMats Randgaard /* CONFCTL is modified in ops and tc358743_hdmi_sys_int_handler */ 91d32d9864SMats Randgaard struct mutex confctl_mutex; 92d32d9864SMats Randgaard 93d32d9864SMats Randgaard /* controls */ 94d32d9864SMats Randgaard struct v4l2_ctrl *detect_tx_5v_ctrl; 95d32d9864SMats Randgaard struct v4l2_ctrl *audio_sampling_rate_ctrl; 96d32d9864SMats Randgaard struct v4l2_ctrl *audio_present_ctrl; 97d32d9864SMats Randgaard 98d32d9864SMats Randgaard struct delayed_work delayed_work_enable_hotplug; 99d32d9864SMats Randgaard 1004e66a52aSDave Stevenson struct timer_list timer; 1014e66a52aSDave Stevenson struct work_struct work_i2c_poll; 1024e66a52aSDave Stevenson 103d32d9864SMats Randgaard /* edid */ 104d32d9864SMats Randgaard u8 edid_blocks_written; 105d32d9864SMats Randgaard 106d32d9864SMats Randgaard struct v4l2_dv_timings timings; 107d32d9864SMats Randgaard u32 mbus_fmt_code; 10859e34ba8SMats Randgaard u8 csi_lanes_in_use; 10925614824SPhilipp Zabel 11025614824SPhilipp Zabel struct gpio_desc *reset_gpio; 111a0ec8d1dSHans Verkuil 112a0ec8d1dSHans Verkuil struct cec_adapter *cec_adap; 113d32d9864SMats Randgaard }; 114d32d9864SMats Randgaard 115d32d9864SMats Randgaard static void tc358743_enable_interrupts(struct v4l2_subdev *sd, 116d32d9864SMats Randgaard bool cable_connected); 117d32d9864SMats Randgaard static int tc358743_s_ctrl_detect_tx_5v(struct v4l2_subdev *sd); 118d32d9864SMats Randgaard 119d32d9864SMats Randgaard static inline struct tc358743_state *to_state(struct v4l2_subdev *sd) 120d32d9864SMats Randgaard { 121d32d9864SMats Randgaard return container_of(sd, struct tc358743_state, sd); 122d32d9864SMats Randgaard } 123d32d9864SMats Randgaard 124d32d9864SMats Randgaard /* --------------- I2C --------------- */ 125d32d9864SMats Randgaard 126d32d9864SMats Randgaard static void i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) 127d32d9864SMats Randgaard { 128d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 129d32d9864SMats Randgaard struct i2c_client *client = state->i2c_client; 130d32d9864SMats Randgaard int err; 131d32d9864SMats Randgaard u8 buf[2] = { reg >> 8, reg & 0xff }; 132d32d9864SMats Randgaard struct i2c_msg msgs[] = { 133d32d9864SMats Randgaard { 134d32d9864SMats Randgaard .addr = client->addr, 135d32d9864SMats Randgaard .flags = 0, 136d32d9864SMats Randgaard .len = 2, 137d32d9864SMats Randgaard .buf = buf, 138d32d9864SMats Randgaard }, 139d32d9864SMats Randgaard { 140d32d9864SMats Randgaard .addr = client->addr, 141d32d9864SMats Randgaard .flags = I2C_M_RD, 142d32d9864SMats Randgaard .len = n, 143d32d9864SMats Randgaard .buf = values, 144d32d9864SMats Randgaard }, 145d32d9864SMats Randgaard }; 146d32d9864SMats Randgaard 147d32d9864SMats Randgaard err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 148d32d9864SMats Randgaard if (err != ARRAY_SIZE(msgs)) { 149d32d9864SMats Randgaard v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed\n", 150d32d9864SMats Randgaard __func__, reg, client->addr); 151d32d9864SMats Randgaard } 152d32d9864SMats Randgaard } 153d32d9864SMats Randgaard 154d32d9864SMats Randgaard static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) 155d32d9864SMats Randgaard { 156d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 157d32d9864SMats Randgaard struct i2c_client *client = state->i2c_client; 158d32d9864SMats Randgaard int err, i; 159d32d9864SMats Randgaard struct i2c_msg msg; 160fcae73faSMats Randgaard u8 data[I2C_MAX_XFER_SIZE]; 1611d88f831SMauro Carvalho Chehab 162fcae73faSMats Randgaard if ((2 + n) > I2C_MAX_XFER_SIZE) { 163fcae73faSMats Randgaard n = I2C_MAX_XFER_SIZE - 2; 1641d88f831SMauro Carvalho Chehab v4l2_warn(sd, "i2c wr reg=%04x: len=%d is too big!\n", 1651d88f831SMauro Carvalho Chehab reg, 2 + n); 166fcae73faSMats Randgaard } 167d32d9864SMats Randgaard 168d32d9864SMats Randgaard msg.addr = client->addr; 169d32d9864SMats Randgaard msg.buf = data; 170d32d9864SMats Randgaard msg.len = 2 + n; 171d32d9864SMats Randgaard msg.flags = 0; 172d32d9864SMats Randgaard 173d32d9864SMats Randgaard data[0] = reg >> 8; 174d32d9864SMats Randgaard data[1] = reg & 0xff; 175d32d9864SMats Randgaard 176d32d9864SMats Randgaard for (i = 0; i < n; i++) 177d32d9864SMats Randgaard data[2 + i] = values[i]; 178d32d9864SMats Randgaard 179d32d9864SMats Randgaard err = i2c_transfer(client->adapter, &msg, 1); 180d32d9864SMats Randgaard if (err != 1) { 181d32d9864SMats Randgaard v4l2_err(sd, "%s: writing register 0x%x from 0x%x failed\n", 182d32d9864SMats Randgaard __func__, reg, client->addr); 183d32d9864SMats Randgaard return; 184d32d9864SMats Randgaard } 185d32d9864SMats Randgaard 186d32d9864SMats Randgaard if (debug < 3) 187d32d9864SMats Randgaard return; 188d32d9864SMats Randgaard 189d32d9864SMats Randgaard switch (n) { 190d32d9864SMats Randgaard case 1: 191d32d9864SMats Randgaard v4l2_info(sd, "I2C write 0x%04x = 0x%02x", 192d32d9864SMats Randgaard reg, data[2]); 193d32d9864SMats Randgaard break; 194d32d9864SMats Randgaard case 2: 195d32d9864SMats Randgaard v4l2_info(sd, "I2C write 0x%04x = 0x%02x%02x", 196d32d9864SMats Randgaard reg, data[3], data[2]); 197d32d9864SMats Randgaard break; 198d32d9864SMats Randgaard case 4: 199d32d9864SMats Randgaard v4l2_info(sd, "I2C write 0x%04x = 0x%02x%02x%02x%02x", 200d32d9864SMats Randgaard reg, data[5], data[4], data[3], data[2]); 201d32d9864SMats Randgaard break; 202d32d9864SMats Randgaard default: 203d32d9864SMats Randgaard v4l2_info(sd, "I2C write %d bytes from address 0x%04x\n", 204d32d9864SMats Randgaard n, reg); 205d32d9864SMats Randgaard } 206d32d9864SMats Randgaard } 207d32d9864SMats Randgaard 2083538aa6eSArnd Bergmann static noinline u32 i2c_rdreg(struct v4l2_subdev *sd, u16 reg, u32 n) 2093538aa6eSArnd Bergmann { 2103538aa6eSArnd Bergmann __le32 val = 0; 2113538aa6eSArnd Bergmann 2123538aa6eSArnd Bergmann i2c_rd(sd, reg, (u8 __force *)&val, n); 2133538aa6eSArnd Bergmann 2143538aa6eSArnd Bergmann return le32_to_cpu(val); 2153538aa6eSArnd Bergmann } 2163538aa6eSArnd Bergmann 2173538aa6eSArnd Bergmann static noinline void i2c_wrreg(struct v4l2_subdev *sd, u16 reg, u32 val, u32 n) 2183538aa6eSArnd Bergmann { 2193538aa6eSArnd Bergmann __le32 raw = cpu_to_le32(val); 2203538aa6eSArnd Bergmann 2213538aa6eSArnd Bergmann i2c_wr(sd, reg, (u8 __force *)&raw, n); 2223538aa6eSArnd Bergmann } 2233538aa6eSArnd Bergmann 224d32d9864SMats Randgaard static u8 i2c_rd8(struct v4l2_subdev *sd, u16 reg) 225d32d9864SMats Randgaard { 2263538aa6eSArnd Bergmann return i2c_rdreg(sd, reg, 1); 227d32d9864SMats Randgaard } 228d32d9864SMats Randgaard 229d32d9864SMats Randgaard static void i2c_wr8(struct v4l2_subdev *sd, u16 reg, u8 val) 230d32d9864SMats Randgaard { 2313538aa6eSArnd Bergmann i2c_wrreg(sd, reg, val, 1); 232d32d9864SMats Randgaard } 233d32d9864SMats Randgaard 234d32d9864SMats Randgaard static void i2c_wr8_and_or(struct v4l2_subdev *sd, u16 reg, 235d32d9864SMats Randgaard u8 mask, u8 val) 236d32d9864SMats Randgaard { 237f2c61f98SPhilipp Zabel i2c_wrreg(sd, reg, (i2c_rdreg(sd, reg, 1) & mask) | val, 1); 238d32d9864SMats Randgaard } 239d32d9864SMats Randgaard 240d32d9864SMats Randgaard static u16 i2c_rd16(struct v4l2_subdev *sd, u16 reg) 241d32d9864SMats Randgaard { 2423538aa6eSArnd Bergmann return i2c_rdreg(sd, reg, 2); 243d32d9864SMats Randgaard } 244d32d9864SMats Randgaard 245d32d9864SMats Randgaard static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val) 246d32d9864SMats Randgaard { 2473538aa6eSArnd Bergmann i2c_wrreg(sd, reg, val, 2); 248d32d9864SMats Randgaard } 249d32d9864SMats Randgaard 250d32d9864SMats Randgaard static void i2c_wr16_and_or(struct v4l2_subdev *sd, u16 reg, u16 mask, u16 val) 251d32d9864SMats Randgaard { 2523538aa6eSArnd Bergmann i2c_wrreg(sd, reg, (i2c_rdreg(sd, reg, 2) & mask) | val, 2); 253d32d9864SMats Randgaard } 254d32d9864SMats Randgaard 255d32d9864SMats Randgaard static u32 i2c_rd32(struct v4l2_subdev *sd, u16 reg) 256d32d9864SMats Randgaard { 2573538aa6eSArnd Bergmann return i2c_rdreg(sd, reg, 4); 258d32d9864SMats Randgaard } 259d32d9864SMats Randgaard 260d32d9864SMats Randgaard static void i2c_wr32(struct v4l2_subdev *sd, u16 reg, u32 val) 261d32d9864SMats Randgaard { 2623538aa6eSArnd Bergmann i2c_wrreg(sd, reg, val, 4); 263d32d9864SMats Randgaard } 264d32d9864SMats Randgaard 265d32d9864SMats Randgaard /* --------------- STATUS --------------- */ 266d32d9864SMats Randgaard 267d32d9864SMats Randgaard static inline bool is_hdmi(struct v4l2_subdev *sd) 268d32d9864SMats Randgaard { 269d32d9864SMats Randgaard return i2c_rd8(sd, SYS_STATUS) & MASK_S_HDMI; 270d32d9864SMats Randgaard } 271d32d9864SMats Randgaard 272d32d9864SMats Randgaard static inline bool tx_5v_power_present(struct v4l2_subdev *sd) 273d32d9864SMats Randgaard { 274d32d9864SMats Randgaard return i2c_rd8(sd, SYS_STATUS) & MASK_S_DDC5V; 275d32d9864SMats Randgaard } 276d32d9864SMats Randgaard 277d32d9864SMats Randgaard static inline bool no_signal(struct v4l2_subdev *sd) 278d32d9864SMats Randgaard { 279d32d9864SMats Randgaard return !(i2c_rd8(sd, SYS_STATUS) & MASK_S_TMDS); 280d32d9864SMats Randgaard } 281d32d9864SMats Randgaard 282d32d9864SMats Randgaard static inline bool no_sync(struct v4l2_subdev *sd) 283d32d9864SMats Randgaard { 284d32d9864SMats Randgaard return !(i2c_rd8(sd, SYS_STATUS) & MASK_S_SYNC); 285d32d9864SMats Randgaard } 286d32d9864SMats Randgaard 287d32d9864SMats Randgaard static inline bool audio_present(struct v4l2_subdev *sd) 288d32d9864SMats Randgaard { 289d32d9864SMats Randgaard return i2c_rd8(sd, AU_STATUS0) & MASK_S_A_SAMPLE; 290d32d9864SMats Randgaard } 291d32d9864SMats Randgaard 292d32d9864SMats Randgaard static int get_audio_sampling_rate(struct v4l2_subdev *sd) 293d32d9864SMats Randgaard { 294d32d9864SMats Randgaard static const int code_to_rate[] = { 295d32d9864SMats Randgaard 44100, 0, 48000, 32000, 22050, 384000, 24000, 352800, 296d32d9864SMats Randgaard 88200, 768000, 96000, 705600, 176400, 0, 192000, 0 297d32d9864SMats Randgaard }; 298d32d9864SMats Randgaard 299d32d9864SMats Randgaard /* Register FS_SET is not cleared when the cable is disconnected */ 300d32d9864SMats Randgaard if (no_signal(sd)) 301d32d9864SMats Randgaard return 0; 302d32d9864SMats Randgaard 303d32d9864SMats Randgaard return code_to_rate[i2c_rd8(sd, FS_SET) & MASK_FS]; 304d32d9864SMats Randgaard } 305d32d9864SMats Randgaard 306d32d9864SMats Randgaard /* --------------- TIMINGS --------------- */ 307d32d9864SMats Randgaard 308d32d9864SMats Randgaard static inline unsigned fps(const struct v4l2_bt_timings *t) 309d32d9864SMats Randgaard { 310d32d9864SMats Randgaard if (!V4L2_DV_BT_FRAME_HEIGHT(t) || !V4L2_DV_BT_FRAME_WIDTH(t)) 311d32d9864SMats Randgaard return 0; 312d32d9864SMats Randgaard 313d32d9864SMats Randgaard return DIV_ROUND_CLOSEST((unsigned)t->pixelclock, 314d32d9864SMats Randgaard V4L2_DV_BT_FRAME_HEIGHT(t) * V4L2_DV_BT_FRAME_WIDTH(t)); 315d32d9864SMats Randgaard } 316d32d9864SMats Randgaard 317d32d9864SMats Randgaard static int tc358743_get_detected_timings(struct v4l2_subdev *sd, 318d32d9864SMats Randgaard struct v4l2_dv_timings *timings) 319d32d9864SMats Randgaard { 320d32d9864SMats Randgaard struct v4l2_bt_timings *bt = &timings->bt; 321d32d9864SMats Randgaard unsigned width, height, frame_width, frame_height, frame_interval, fps; 322d32d9864SMats Randgaard 323d32d9864SMats Randgaard memset(timings, 0, sizeof(struct v4l2_dv_timings)); 324d32d9864SMats Randgaard 325d32d9864SMats Randgaard if (no_signal(sd)) { 326d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: no valid signal\n", __func__); 327d32d9864SMats Randgaard return -ENOLINK; 328d32d9864SMats Randgaard } 329d32d9864SMats Randgaard if (no_sync(sd)) { 330d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: no sync on signal\n", __func__); 331d32d9864SMats Randgaard return -ENOLCK; 332d32d9864SMats Randgaard } 333d32d9864SMats Randgaard 334d32d9864SMats Randgaard timings->type = V4L2_DV_BT_656_1120; 335d32d9864SMats Randgaard bt->interlaced = i2c_rd8(sd, VI_STATUS1) & MASK_S_V_INTERLACE ? 336d32d9864SMats Randgaard V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE; 337d32d9864SMats Randgaard 338d32d9864SMats Randgaard width = ((i2c_rd8(sd, DE_WIDTH_H_HI) & 0x1f) << 8) + 339d32d9864SMats Randgaard i2c_rd8(sd, DE_WIDTH_H_LO); 340d32d9864SMats Randgaard height = ((i2c_rd8(sd, DE_WIDTH_V_HI) & 0x1f) << 8) + 341d32d9864SMats Randgaard i2c_rd8(sd, DE_WIDTH_V_LO); 342d32d9864SMats Randgaard frame_width = ((i2c_rd8(sd, H_SIZE_HI) & 0x1f) << 8) + 343d32d9864SMats Randgaard i2c_rd8(sd, H_SIZE_LO); 344d32d9864SMats Randgaard frame_height = (((i2c_rd8(sd, V_SIZE_HI) & 0x3f) << 8) + 345d32d9864SMats Randgaard i2c_rd8(sd, V_SIZE_LO)) / 2; 346d32d9864SMats Randgaard /* frame interval in milliseconds * 10 347d32d9864SMats Randgaard * Require SYS_FREQ0 and SYS_FREQ1 are precisely set */ 348d32d9864SMats Randgaard frame_interval = ((i2c_rd8(sd, FV_CNT_HI) & 0x3) << 8) + 349d32d9864SMats Randgaard i2c_rd8(sd, FV_CNT_LO); 350d32d9864SMats Randgaard fps = (frame_interval > 0) ? 351d32d9864SMats Randgaard DIV_ROUND_CLOSEST(10000, frame_interval) : 0; 352d32d9864SMats Randgaard 353d32d9864SMats Randgaard bt->width = width; 354d32d9864SMats Randgaard bt->height = height; 355d32d9864SMats Randgaard bt->vsync = frame_height - height; 356d32d9864SMats Randgaard bt->hsync = frame_width - width; 357d32d9864SMats Randgaard bt->pixelclock = frame_width * frame_height * fps; 358d32d9864SMats Randgaard if (bt->interlaced == V4L2_DV_INTERLACED) { 359d32d9864SMats Randgaard bt->height *= 2; 360d32d9864SMats Randgaard bt->il_vsync = bt->vsync + 1; 361d32d9864SMats Randgaard bt->pixelclock /= 2; 362d32d9864SMats Randgaard } 363d32d9864SMats Randgaard 364d32d9864SMats Randgaard return 0; 365d32d9864SMats Randgaard } 366d32d9864SMats Randgaard 367d32d9864SMats Randgaard /* --------------- HOTPLUG / HDCP / EDID --------------- */ 368d32d9864SMats Randgaard 369d32d9864SMats Randgaard static void tc358743_delayed_work_enable_hotplug(struct work_struct *work) 370d32d9864SMats Randgaard { 371d32d9864SMats Randgaard struct delayed_work *dwork = to_delayed_work(work); 372d32d9864SMats Randgaard struct tc358743_state *state = container_of(dwork, 373d32d9864SMats Randgaard struct tc358743_state, delayed_work_enable_hotplug); 374d32d9864SMats Randgaard struct v4l2_subdev *sd = &state->sd; 375d32d9864SMats Randgaard 376d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s:\n", __func__); 377d32d9864SMats Randgaard 378d32d9864SMats Randgaard i2c_wr8_and_or(sd, HPD_CTL, ~MASK_HPD_OUT0, MASK_HPD_OUT0); 379d32d9864SMats Randgaard } 380d32d9864SMats Randgaard 381d32d9864SMats Randgaard static void tc358743_set_hdmi_hdcp(struct v4l2_subdev *sd, bool enable) 382d32d9864SMats Randgaard { 383d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s: %s\n", __func__, enable ? 384d32d9864SMats Randgaard "enable" : "disable"); 385d32d9864SMats Randgaard 3860a1f0850SMats Randgaard if (enable) { 3870a1f0850SMats Randgaard i2c_wr8_and_or(sd, HDCP_REG3, ~KEY_RD_CMD, KEY_RD_CMD); 3880a1f0850SMats Randgaard 3890a1f0850SMats Randgaard i2c_wr8_and_or(sd, HDCP_MODE, ~MASK_MANUAL_AUTHENTICATION, 0); 3900a1f0850SMats Randgaard 3910a1f0850SMats Randgaard i2c_wr8_and_or(sd, HDCP_REG1, 0xff, 3920a1f0850SMats Randgaard MASK_AUTH_UNAUTH_SEL_16_FRAMES | 3930a1f0850SMats Randgaard MASK_AUTH_UNAUTH_AUTO); 394d32d9864SMats Randgaard 395d32d9864SMats Randgaard i2c_wr8_and_or(sd, HDCP_REG2, ~MASK_AUTO_P3_RESET, 396d32d9864SMats Randgaard SET_AUTO_P3_RESET_FRAMES(0x0f)); 3970a1f0850SMats Randgaard } else { 3980a1f0850SMats Randgaard i2c_wr8_and_or(sd, HDCP_MODE, ~MASK_MANUAL_AUTHENTICATION, 3990a1f0850SMats Randgaard MASK_MANUAL_AUTHENTICATION); 4000a1f0850SMats Randgaard } 401d32d9864SMats Randgaard } 402d32d9864SMats Randgaard 403d32d9864SMats Randgaard static void tc358743_disable_edid(struct v4l2_subdev *sd) 404d32d9864SMats Randgaard { 405d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 406d32d9864SMats Randgaard 407d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s:\n", __func__); 408d32d9864SMats Randgaard 409d32d9864SMats Randgaard cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); 410d32d9864SMats Randgaard 411d32d9864SMats Randgaard /* DDC access to EDID is also disabled when hotplug is disabled. See 412d32d9864SMats Randgaard * register DDC_CTL */ 413d32d9864SMats Randgaard i2c_wr8_and_or(sd, HPD_CTL, ~MASK_HPD_OUT0, 0x0); 414d32d9864SMats Randgaard } 415d32d9864SMats Randgaard 416d32d9864SMats Randgaard static void tc358743_enable_edid(struct v4l2_subdev *sd) 417d32d9864SMats Randgaard { 418d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 419d32d9864SMats Randgaard 420d32d9864SMats Randgaard if (state->edid_blocks_written == 0) { 421d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s: no EDID -> no hotplug\n", __func__); 422676c002aSMats Randgaard tc358743_s_ctrl_detect_tx_5v(sd); 423d32d9864SMats Randgaard return; 424d32d9864SMats Randgaard } 425d32d9864SMats Randgaard 426d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s:\n", __func__); 427d32d9864SMats Randgaard 428d32d9864SMats Randgaard /* Enable hotplug after 100 ms. DDC access to EDID is also enabled when 429d32d9864SMats Randgaard * hotplug is enabled. See register DDC_CTL */ 4301ce39546SBhaktipriya Shridhar schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 10); 431d32d9864SMats Randgaard 432d32d9864SMats Randgaard tc358743_enable_interrupts(sd, true); 433d32d9864SMats Randgaard tc358743_s_ctrl_detect_tx_5v(sd); 434d32d9864SMats Randgaard } 435d32d9864SMats Randgaard 436d32d9864SMats Randgaard static void tc358743_erase_bksv(struct v4l2_subdev *sd) 437d32d9864SMats Randgaard { 438d32d9864SMats Randgaard int i; 439d32d9864SMats Randgaard 440d32d9864SMats Randgaard for (i = 0; i < 5; i++) 441d32d9864SMats Randgaard i2c_wr8(sd, BKSV + i, 0); 442d32d9864SMats Randgaard } 443d32d9864SMats Randgaard 444d32d9864SMats Randgaard /* --------------- AVI infoframe --------------- */ 445d32d9864SMats Randgaard 446d32d9864SMats Randgaard static void print_avi_infoframe(struct v4l2_subdev *sd) 447d32d9864SMats Randgaard { 448d32d9864SMats Randgaard struct i2c_client *client = v4l2_get_subdevdata(sd); 449d32d9864SMats Randgaard struct device *dev = &client->dev; 450d32d9864SMats Randgaard union hdmi_infoframe frame; 451d32d9864SMats Randgaard u8 buffer[HDMI_INFOFRAME_SIZE(AVI)]; 452d32d9864SMats Randgaard 453d32d9864SMats Randgaard if (!is_hdmi(sd)) { 454d32d9864SMats Randgaard v4l2_info(sd, "DVI-D signal - AVI infoframe not supported\n"); 455d32d9864SMats Randgaard return; 456d32d9864SMats Randgaard } 457d32d9864SMats Randgaard 458d32d9864SMats Randgaard i2c_rd(sd, PK_AVI_0HEAD, buffer, HDMI_INFOFRAME_SIZE(AVI)); 459d32d9864SMats Randgaard 460d32d9864SMats Randgaard if (hdmi_infoframe_unpack(&frame, buffer) < 0) { 461d32d9864SMats Randgaard v4l2_err(sd, "%s: unpack of AVI infoframe failed\n", __func__); 462d32d9864SMats Randgaard return; 463d32d9864SMats Randgaard } 464d32d9864SMats Randgaard 465d32d9864SMats Randgaard hdmi_infoframe_log(KERN_INFO, dev, &frame); 466d32d9864SMats Randgaard } 467d32d9864SMats Randgaard 468d32d9864SMats Randgaard /* --------------- CTRLS --------------- */ 469d32d9864SMats Randgaard 470d32d9864SMats Randgaard static int tc358743_s_ctrl_detect_tx_5v(struct v4l2_subdev *sd) 471d32d9864SMats Randgaard { 472d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 473d32d9864SMats Randgaard 474d32d9864SMats Randgaard return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, 475d32d9864SMats Randgaard tx_5v_power_present(sd)); 476d32d9864SMats Randgaard } 477d32d9864SMats Randgaard 478d32d9864SMats Randgaard static int tc358743_s_ctrl_audio_sampling_rate(struct v4l2_subdev *sd) 479d32d9864SMats Randgaard { 480d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 481d32d9864SMats Randgaard 482d32d9864SMats Randgaard return v4l2_ctrl_s_ctrl(state->audio_sampling_rate_ctrl, 483d32d9864SMats Randgaard get_audio_sampling_rate(sd)); 484d32d9864SMats Randgaard } 485d32d9864SMats Randgaard 486d32d9864SMats Randgaard static int tc358743_s_ctrl_audio_present(struct v4l2_subdev *sd) 487d32d9864SMats Randgaard { 488d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 489d32d9864SMats Randgaard 490d32d9864SMats Randgaard return v4l2_ctrl_s_ctrl(state->audio_present_ctrl, 491d32d9864SMats Randgaard audio_present(sd)); 492d32d9864SMats Randgaard } 493d32d9864SMats Randgaard 494d32d9864SMats Randgaard static int tc358743_update_controls(struct v4l2_subdev *sd) 495d32d9864SMats Randgaard { 496d32d9864SMats Randgaard int ret = 0; 497d32d9864SMats Randgaard 498d32d9864SMats Randgaard ret |= tc358743_s_ctrl_detect_tx_5v(sd); 499d32d9864SMats Randgaard ret |= tc358743_s_ctrl_audio_sampling_rate(sd); 500d32d9864SMats Randgaard ret |= tc358743_s_ctrl_audio_present(sd); 501d32d9864SMats Randgaard 502d32d9864SMats Randgaard return ret; 503d32d9864SMats Randgaard } 504d32d9864SMats Randgaard 505d32d9864SMats Randgaard /* --------------- INIT --------------- */ 506d32d9864SMats Randgaard 507d32d9864SMats Randgaard static void tc358743_reset_phy(struct v4l2_subdev *sd) 508d32d9864SMats Randgaard { 509d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s:\n", __func__); 510d32d9864SMats Randgaard 511d32d9864SMats Randgaard i2c_wr8_and_or(sd, PHY_RST, ~MASK_RESET_CTRL, 0); 512d32d9864SMats Randgaard i2c_wr8_and_or(sd, PHY_RST, ~MASK_RESET_CTRL, MASK_RESET_CTRL); 513d32d9864SMats Randgaard } 514d32d9864SMats Randgaard 515d32d9864SMats Randgaard static void tc358743_reset(struct v4l2_subdev *sd, uint16_t mask) 516d32d9864SMats Randgaard { 517d32d9864SMats Randgaard u16 sysctl = i2c_rd16(sd, SYSCTL); 518d32d9864SMats Randgaard 519d32d9864SMats Randgaard i2c_wr16(sd, SYSCTL, sysctl | mask); 520d32d9864SMats Randgaard i2c_wr16(sd, SYSCTL, sysctl & ~mask); 521d32d9864SMats Randgaard } 522d32d9864SMats Randgaard 523d32d9864SMats Randgaard static inline void tc358743_sleep_mode(struct v4l2_subdev *sd, bool enable) 524d32d9864SMats Randgaard { 525d32d9864SMats Randgaard i2c_wr16_and_or(sd, SYSCTL, ~MASK_SLEEP, 526d32d9864SMats Randgaard enable ? MASK_SLEEP : 0); 527d32d9864SMats Randgaard } 528d32d9864SMats Randgaard 529d32d9864SMats Randgaard static inline void enable_stream(struct v4l2_subdev *sd, bool enable) 530d32d9864SMats Randgaard { 531d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 532d32d9864SMats Randgaard 533d32d9864SMats Randgaard v4l2_dbg(3, debug, sd, "%s: %sable\n", 534d32d9864SMats Randgaard __func__, enable ? "en" : "dis"); 535d32d9864SMats Randgaard 536d32d9864SMats Randgaard if (enable) { 537d32d9864SMats Randgaard /* It is critical for CSI receiver to see lane transition 538d32d9864SMats Randgaard * LP11->HS. Set to non-continuous mode to enable clock lane 539d32d9864SMats Randgaard * LP11 state. */ 540d32d9864SMats Randgaard i2c_wr32(sd, TXOPTIONCNTRL, 0); 541d32d9864SMats Randgaard /* Set to continuous mode to trigger LP11->HS transition */ 542d32d9864SMats Randgaard i2c_wr32(sd, TXOPTIONCNTRL, MASK_CONTCLKMODE); 543d32d9864SMats Randgaard /* Unmute video */ 544d32d9864SMats Randgaard i2c_wr8(sd, VI_MUTE, MASK_AUTO_MUTE); 545d32d9864SMats Randgaard } else { 546d32d9864SMats Randgaard /* Mute video so that all data lanes go to LSP11 state. 547d32d9864SMats Randgaard * No data is output to CSI Tx block. */ 548d32d9864SMats Randgaard i2c_wr8(sd, VI_MUTE, MASK_AUTO_MUTE | MASK_VI_MUTE); 549d32d9864SMats Randgaard } 550d32d9864SMats Randgaard 551d32d9864SMats Randgaard mutex_lock(&state->confctl_mutex); 552d32d9864SMats Randgaard i2c_wr16_and_or(sd, CONFCTL, ~(MASK_VBUFEN | MASK_ABUFEN), 553d32d9864SMats Randgaard enable ? (MASK_VBUFEN | MASK_ABUFEN) : 0x0); 554d32d9864SMats Randgaard mutex_unlock(&state->confctl_mutex); 555d32d9864SMats Randgaard } 556d32d9864SMats Randgaard 557d32d9864SMats Randgaard static void tc358743_set_pll(struct v4l2_subdev *sd) 558d32d9864SMats Randgaard { 559d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 560d32d9864SMats Randgaard struct tc358743_platform_data *pdata = &state->pdata; 561d32d9864SMats Randgaard u16 pllctl0 = i2c_rd16(sd, PLLCTL0); 562d32d9864SMats Randgaard u16 pllctl1 = i2c_rd16(sd, PLLCTL1); 563d32d9864SMats Randgaard u16 pllctl0_new = SET_PLL_PRD(pdata->pll_prd) | 564d32d9864SMats Randgaard SET_PLL_FBD(pdata->pll_fbd); 565d32d9864SMats Randgaard u32 hsck = (pdata->refclk_hz / pdata->pll_prd) * pdata->pll_fbd; 566d32d9864SMats Randgaard 567d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s:\n", __func__); 568d32d9864SMats Randgaard 569d32d9864SMats Randgaard /* Only rewrite when needed (new value or disabled), since rewriting 570d32d9864SMats Randgaard * triggers another format change event. */ 571d32d9864SMats Randgaard if ((pllctl0 != pllctl0_new) || ((pllctl1 & MASK_PLL_EN) == 0)) { 572d32d9864SMats Randgaard u16 pll_frs; 573d32d9864SMats Randgaard 574d32d9864SMats Randgaard if (hsck > 500000000) 575d32d9864SMats Randgaard pll_frs = 0x0; 576d32d9864SMats Randgaard else if (hsck > 250000000) 577d32d9864SMats Randgaard pll_frs = 0x1; 578d32d9864SMats Randgaard else if (hsck > 125000000) 579d32d9864SMats Randgaard pll_frs = 0x2; 580d32d9864SMats Randgaard else 581d32d9864SMats Randgaard pll_frs = 0x3; 582d32d9864SMats Randgaard 583d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: updating PLL clock\n", __func__); 584d32d9864SMats Randgaard tc358743_sleep_mode(sd, true); 585d32d9864SMats Randgaard i2c_wr16(sd, PLLCTL0, pllctl0_new); 586d32d9864SMats Randgaard i2c_wr16_and_or(sd, PLLCTL1, 587d32d9864SMats Randgaard ~(MASK_PLL_FRS | MASK_RESETB | MASK_PLL_EN), 588d32d9864SMats Randgaard (SET_PLL_FRS(pll_frs) | MASK_RESETB | 589d32d9864SMats Randgaard MASK_PLL_EN)); 590d32d9864SMats Randgaard udelay(10); /* REF_02, Sheet "Source HDMI" */ 591d32d9864SMats Randgaard i2c_wr16_and_or(sd, PLLCTL1, ~MASK_CKEN, MASK_CKEN); 592d32d9864SMats Randgaard tc358743_sleep_mode(sd, false); 593d32d9864SMats Randgaard } 594d32d9864SMats Randgaard } 595d32d9864SMats Randgaard 596d32d9864SMats Randgaard static void tc358743_set_ref_clk(struct v4l2_subdev *sd) 597d32d9864SMats Randgaard { 598d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 599d32d9864SMats Randgaard struct tc358743_platform_data *pdata = &state->pdata; 600d32d9864SMats Randgaard u32 sys_freq; 601d32d9864SMats Randgaard u32 lockdet_ref; 602a0ec8d1dSHans Verkuil u32 cec_freq; 603d32d9864SMats Randgaard u16 fh_min; 604d32d9864SMats Randgaard u16 fh_max; 605d32d9864SMats Randgaard 606d32d9864SMats Randgaard BUG_ON(!(pdata->refclk_hz == 26000000 || 607d32d9864SMats Randgaard pdata->refclk_hz == 27000000 || 608d32d9864SMats Randgaard pdata->refclk_hz == 42000000)); 609d32d9864SMats Randgaard 610d32d9864SMats Randgaard sys_freq = pdata->refclk_hz / 10000; 611d32d9864SMats Randgaard i2c_wr8(sd, SYS_FREQ0, sys_freq & 0x00ff); 612d32d9864SMats Randgaard i2c_wr8(sd, SYS_FREQ1, (sys_freq & 0xff00) >> 8); 613d32d9864SMats Randgaard 614d32d9864SMats Randgaard i2c_wr8_and_or(sd, PHY_CTL0, ~MASK_PHY_SYSCLK_IND, 615d32d9864SMats Randgaard (pdata->refclk_hz == 42000000) ? 616d32d9864SMats Randgaard MASK_PHY_SYSCLK_IND : 0x0); 617d32d9864SMats Randgaard 618d32d9864SMats Randgaard fh_min = pdata->refclk_hz / 100000; 619d32d9864SMats Randgaard i2c_wr8(sd, FH_MIN0, fh_min & 0x00ff); 620d32d9864SMats Randgaard i2c_wr8(sd, FH_MIN1, (fh_min & 0xff00) >> 8); 621d32d9864SMats Randgaard 622d32d9864SMats Randgaard fh_max = (fh_min * 66) / 10; 623d32d9864SMats Randgaard i2c_wr8(sd, FH_MAX0, fh_max & 0x00ff); 624d32d9864SMats Randgaard i2c_wr8(sd, FH_MAX1, (fh_max & 0xff00) >> 8); 625d32d9864SMats Randgaard 626d32d9864SMats Randgaard lockdet_ref = pdata->refclk_hz / 100; 627d32d9864SMats Randgaard i2c_wr8(sd, LOCKDET_REF0, lockdet_ref & 0x0000ff); 628d32d9864SMats Randgaard i2c_wr8(sd, LOCKDET_REF1, (lockdet_ref & 0x00ff00) >> 8); 629d32d9864SMats Randgaard i2c_wr8(sd, LOCKDET_REF2, (lockdet_ref & 0x0f0000) >> 16); 630d32d9864SMats Randgaard 631d32d9864SMats Randgaard i2c_wr8_and_or(sd, NCO_F0_MOD, ~MASK_NCO_F0_MOD, 632d32d9864SMats Randgaard (pdata->refclk_hz == 27000000) ? 633d32d9864SMats Randgaard MASK_NCO_F0_MOD_27MHZ : 0x0); 634a0ec8d1dSHans Verkuil 635a0ec8d1dSHans Verkuil /* 636a0ec8d1dSHans Verkuil * Trial and error suggests that the default register value 637a0ec8d1dSHans Verkuil * of 656 is for a 42 MHz reference clock. Use that to derive 638a0ec8d1dSHans Verkuil * a new value based on the actual reference clock. 639a0ec8d1dSHans Verkuil */ 640a0ec8d1dSHans Verkuil cec_freq = (656 * sys_freq) / 4200; 641a0ec8d1dSHans Verkuil i2c_wr16(sd, CECHCLK, cec_freq); 642a0ec8d1dSHans Verkuil i2c_wr16(sd, CECLCLK, cec_freq); 643d32d9864SMats Randgaard } 644d32d9864SMats Randgaard 645d32d9864SMats Randgaard static void tc358743_set_csi_color_space(struct v4l2_subdev *sd) 646d32d9864SMats Randgaard { 647d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 648d32d9864SMats Randgaard 649d32d9864SMats Randgaard switch (state->mbus_fmt_code) { 650d32d9864SMats Randgaard case MEDIA_BUS_FMT_UYVY8_1X16: 651d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s: YCbCr 422 16-bit\n", __func__); 652d32d9864SMats Randgaard i2c_wr8_and_or(sd, VOUT_SET2, 653d32d9864SMats Randgaard ~(MASK_SEL422 | MASK_VOUT_422FIL_100) & 0xff, 654d32d9864SMats Randgaard MASK_SEL422 | MASK_VOUT_422FIL_100); 655d32d9864SMats Randgaard i2c_wr8_and_or(sd, VI_REP, ~MASK_VOUT_COLOR_SEL & 0xff, 656d32d9864SMats Randgaard MASK_VOUT_COLOR_601_YCBCR_LIMITED); 657d32d9864SMats Randgaard mutex_lock(&state->confctl_mutex); 658d32d9864SMats Randgaard i2c_wr16_and_or(sd, CONFCTL, ~MASK_YCBCRFMT, 659d32d9864SMats Randgaard MASK_YCBCRFMT_422_8_BIT); 660d32d9864SMats Randgaard mutex_unlock(&state->confctl_mutex); 661d32d9864SMats Randgaard break; 662d32d9864SMats Randgaard case MEDIA_BUS_FMT_RGB888_1X24: 663d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s: RGB 888 24-bit\n", __func__); 664d32d9864SMats Randgaard i2c_wr8_and_or(sd, VOUT_SET2, 665d32d9864SMats Randgaard ~(MASK_SEL422 | MASK_VOUT_422FIL_100) & 0xff, 666d32d9864SMats Randgaard 0x00); 667d32d9864SMats Randgaard i2c_wr8_and_or(sd, VI_REP, ~MASK_VOUT_COLOR_SEL & 0xff, 668d32d9864SMats Randgaard MASK_VOUT_COLOR_RGB_FULL); 669d32d9864SMats Randgaard mutex_lock(&state->confctl_mutex); 670d32d9864SMats Randgaard i2c_wr16_and_or(sd, CONFCTL, ~MASK_YCBCRFMT, 0); 671d32d9864SMats Randgaard mutex_unlock(&state->confctl_mutex); 672d32d9864SMats Randgaard break; 673d32d9864SMats Randgaard default: 674d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s: Unsupported format code 0x%x\n", 675d32d9864SMats Randgaard __func__, state->mbus_fmt_code); 676d32d9864SMats Randgaard } 677d32d9864SMats Randgaard } 678d32d9864SMats Randgaard 679d32d9864SMats Randgaard static unsigned tc358743_num_csi_lanes_needed(struct v4l2_subdev *sd) 680d32d9864SMats Randgaard { 681d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 682d32d9864SMats Randgaard struct v4l2_bt_timings *bt = &state->timings.bt; 683d32d9864SMats Randgaard struct tc358743_platform_data *pdata = &state->pdata; 684d32d9864SMats Randgaard u32 bits_pr_pixel = 685d32d9864SMats Randgaard (state->mbus_fmt_code == MEDIA_BUS_FMT_UYVY8_1X16) ? 16 : 24; 686d32d9864SMats Randgaard u32 bps = bt->width * bt->height * fps(bt) * bits_pr_pixel; 687d32d9864SMats Randgaard u32 bps_pr_lane = (pdata->refclk_hz / pdata->pll_prd) * pdata->pll_fbd; 688d32d9864SMats Randgaard 689d32d9864SMats Randgaard return DIV_ROUND_UP(bps, bps_pr_lane); 690d32d9864SMats Randgaard } 691d32d9864SMats Randgaard 692d32d9864SMats Randgaard static void tc358743_set_csi(struct v4l2_subdev *sd) 693d32d9864SMats Randgaard { 694d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 695d32d9864SMats Randgaard struct tc358743_platform_data *pdata = &state->pdata; 696d32d9864SMats Randgaard unsigned lanes = tc358743_num_csi_lanes_needed(sd); 697d32d9864SMats Randgaard 698d32d9864SMats Randgaard v4l2_dbg(3, debug, sd, "%s:\n", __func__); 699d32d9864SMats Randgaard 70059e34ba8SMats Randgaard state->csi_lanes_in_use = lanes; 70159e34ba8SMats Randgaard 702d32d9864SMats Randgaard tc358743_reset(sd, MASK_CTXRST); 703d32d9864SMats Randgaard 704d32d9864SMats Randgaard if (lanes < 1) 705d32d9864SMats Randgaard i2c_wr32(sd, CLW_CNTRL, MASK_CLW_LANEDISABLE); 706d32d9864SMats Randgaard if (lanes < 1) 707d32d9864SMats Randgaard i2c_wr32(sd, D0W_CNTRL, MASK_D0W_LANEDISABLE); 708d32d9864SMats Randgaard if (lanes < 2) 709d32d9864SMats Randgaard i2c_wr32(sd, D1W_CNTRL, MASK_D1W_LANEDISABLE); 710d32d9864SMats Randgaard if (lanes < 3) 711d32d9864SMats Randgaard i2c_wr32(sd, D2W_CNTRL, MASK_D2W_LANEDISABLE); 712d32d9864SMats Randgaard if (lanes < 4) 713d32d9864SMats Randgaard i2c_wr32(sd, D3W_CNTRL, MASK_D3W_LANEDISABLE); 714d32d9864SMats Randgaard 715d32d9864SMats Randgaard i2c_wr32(sd, LINEINITCNT, pdata->lineinitcnt); 716d32d9864SMats Randgaard i2c_wr32(sd, LPTXTIMECNT, pdata->lptxtimecnt); 717d32d9864SMats Randgaard i2c_wr32(sd, TCLK_HEADERCNT, pdata->tclk_headercnt); 718d32d9864SMats Randgaard i2c_wr32(sd, TCLK_TRAILCNT, pdata->tclk_trailcnt); 719d32d9864SMats Randgaard i2c_wr32(sd, THS_HEADERCNT, pdata->ths_headercnt); 720d32d9864SMats Randgaard i2c_wr32(sd, TWAKEUP, pdata->twakeup); 721d32d9864SMats Randgaard i2c_wr32(sd, TCLK_POSTCNT, pdata->tclk_postcnt); 722d32d9864SMats Randgaard i2c_wr32(sd, THS_TRAILCNT, pdata->ths_trailcnt); 723d32d9864SMats Randgaard i2c_wr32(sd, HSTXVREGCNT, pdata->hstxvregcnt); 724d32d9864SMats Randgaard 725d32d9864SMats Randgaard i2c_wr32(sd, HSTXVREGEN, 726d32d9864SMats Randgaard ((lanes > 0) ? MASK_CLM_HSTXVREGEN : 0x0) | 727d32d9864SMats Randgaard ((lanes > 0) ? MASK_D0M_HSTXVREGEN : 0x0) | 728d32d9864SMats Randgaard ((lanes > 1) ? MASK_D1M_HSTXVREGEN : 0x0) | 729d32d9864SMats Randgaard ((lanes > 2) ? MASK_D2M_HSTXVREGEN : 0x0) | 730d32d9864SMats Randgaard ((lanes > 3) ? MASK_D3M_HSTXVREGEN : 0x0)); 731d32d9864SMats Randgaard 73225614824SPhilipp Zabel i2c_wr32(sd, TXOPTIONCNTRL, (state->bus.flags & 73325614824SPhilipp Zabel V4L2_MBUS_CSI2_CONTINUOUS_CLOCK) ? MASK_CONTCLKMODE : 0); 734d32d9864SMats Randgaard i2c_wr32(sd, STARTCNTRL, MASK_START); 735d32d9864SMats Randgaard i2c_wr32(sd, CSI_START, MASK_STRT); 736d32d9864SMats Randgaard 737d32d9864SMats Randgaard i2c_wr32(sd, CSI_CONFW, MASK_MODE_SET | 738d32d9864SMats Randgaard MASK_ADDRESS_CSI_CONTROL | 739d32d9864SMats Randgaard MASK_CSI_MODE | 740d32d9864SMats Randgaard MASK_TXHSMD | 741d32d9864SMats Randgaard ((lanes == 4) ? MASK_NOL_4 : 742d32d9864SMats Randgaard (lanes == 3) ? MASK_NOL_3 : 743d32d9864SMats Randgaard (lanes == 2) ? MASK_NOL_2 : MASK_NOL_1)); 744d32d9864SMats Randgaard 745d32d9864SMats Randgaard i2c_wr32(sd, CSI_CONFW, MASK_MODE_SET | 746d32d9864SMats Randgaard MASK_ADDRESS_CSI_ERR_INTENA | MASK_TXBRK | MASK_QUNK | 747d32d9864SMats Randgaard MASK_WCER | MASK_INER); 748d32d9864SMats Randgaard 749d32d9864SMats Randgaard i2c_wr32(sd, CSI_CONFW, MASK_MODE_CLEAR | 750d32d9864SMats Randgaard MASK_ADDRESS_CSI_ERR_HALT | MASK_TXBRK | MASK_QUNK); 751d32d9864SMats Randgaard 752d32d9864SMats Randgaard i2c_wr32(sd, CSI_CONFW, MASK_MODE_SET | 753d32d9864SMats Randgaard MASK_ADDRESS_CSI_INT_ENA | MASK_INTER); 754d32d9864SMats Randgaard } 755d32d9864SMats Randgaard 756d32d9864SMats Randgaard static void tc358743_set_hdmi_phy(struct v4l2_subdev *sd) 757d32d9864SMats Randgaard { 758d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 759d32d9864SMats Randgaard struct tc358743_platform_data *pdata = &state->pdata; 760d32d9864SMats Randgaard 761d32d9864SMats Randgaard /* Default settings from REF_02, sheet "Source HDMI" 762d32d9864SMats Randgaard * and custom settings as platform data */ 763d32d9864SMats Randgaard i2c_wr8_and_or(sd, PHY_EN, ~MASK_ENABLE_PHY, 0x0); 764d32d9864SMats Randgaard i2c_wr8(sd, PHY_CTL1, SET_PHY_AUTO_RST1_US(1600) | 765d32d9864SMats Randgaard SET_FREQ_RANGE_MODE_CYCLES(1)); 766d32d9864SMats Randgaard i2c_wr8_and_or(sd, PHY_CTL2, ~MASK_PHY_AUTO_RSTn, 767d32d9864SMats Randgaard (pdata->hdmi_phy_auto_reset_tmds_detected ? 768d32d9864SMats Randgaard MASK_PHY_AUTO_RST2 : 0) | 769d32d9864SMats Randgaard (pdata->hdmi_phy_auto_reset_tmds_in_range ? 770d32d9864SMats Randgaard MASK_PHY_AUTO_RST3 : 0) | 771d32d9864SMats Randgaard (pdata->hdmi_phy_auto_reset_tmds_valid ? 772d32d9864SMats Randgaard MASK_PHY_AUTO_RST4 : 0)); 773d32d9864SMats Randgaard i2c_wr8(sd, PHY_BIAS, 0x40); 774d32d9864SMats Randgaard i2c_wr8(sd, PHY_CSQ, SET_CSQ_CNT_LEVEL(0x0a)); 775d32d9864SMats Randgaard i2c_wr8(sd, AVM_CTL, 45); 776d32d9864SMats Randgaard i2c_wr8_and_or(sd, HDMI_DET, ~MASK_HDMI_DET_V, 777d32d9864SMats Randgaard pdata->hdmi_detection_delay << 4); 778d32d9864SMats Randgaard i2c_wr8_and_or(sd, HV_RST, ~(MASK_H_PI_RST | MASK_V_PI_RST), 779d32d9864SMats Randgaard (pdata->hdmi_phy_auto_reset_hsync_out_of_range ? 780d32d9864SMats Randgaard MASK_H_PI_RST : 0) | 781d32d9864SMats Randgaard (pdata->hdmi_phy_auto_reset_vsync_out_of_range ? 782d32d9864SMats Randgaard MASK_V_PI_RST : 0)); 783d32d9864SMats Randgaard i2c_wr8_and_or(sd, PHY_EN, ~MASK_ENABLE_PHY, MASK_ENABLE_PHY); 784d32d9864SMats Randgaard } 785d32d9864SMats Randgaard 786d32d9864SMats Randgaard static void tc358743_set_hdmi_audio(struct v4l2_subdev *sd) 787d32d9864SMats Randgaard { 788d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 789d32d9864SMats Randgaard 790d32d9864SMats Randgaard /* Default settings from REF_02, sheet "Source HDMI" */ 791d32d9864SMats Randgaard i2c_wr8(sd, FORCE_MUTE, 0x00); 792d32d9864SMats Randgaard i2c_wr8(sd, AUTO_CMD0, MASK_AUTO_MUTE7 | MASK_AUTO_MUTE6 | 793d32d9864SMats Randgaard MASK_AUTO_MUTE5 | MASK_AUTO_MUTE4 | 794d32d9864SMats Randgaard MASK_AUTO_MUTE1 | MASK_AUTO_MUTE0); 795d32d9864SMats Randgaard i2c_wr8(sd, AUTO_CMD1, MASK_AUTO_MUTE9); 796d32d9864SMats Randgaard i2c_wr8(sd, AUTO_CMD2, MASK_AUTO_PLAY3 | MASK_AUTO_PLAY2); 797d32d9864SMats Randgaard i2c_wr8(sd, BUFINIT_START, SET_BUFINIT_START_MS(500)); 798d32d9864SMats Randgaard i2c_wr8(sd, FS_MUTE, 0x00); 799d32d9864SMats Randgaard i2c_wr8(sd, FS_IMODE, MASK_NLPCM_SMODE | MASK_FS_SMODE); 800d32d9864SMats Randgaard i2c_wr8(sd, ACR_MODE, MASK_CTS_MODE); 801d32d9864SMats Randgaard i2c_wr8(sd, ACR_MDF0, MASK_ACR_L2MDF_1976_PPM | MASK_ACR_L1MDF_976_PPM); 802d32d9864SMats Randgaard i2c_wr8(sd, ACR_MDF1, MASK_ACR_L3MDF_3906_PPM); 803d32d9864SMats Randgaard i2c_wr8(sd, SDO_MODE1, MASK_SDO_FMT_I2S); 804d32d9864SMats Randgaard i2c_wr8(sd, DIV_MODE, SET_DIV_DLY_MS(100)); 805d32d9864SMats Randgaard 806d32d9864SMats Randgaard mutex_lock(&state->confctl_mutex); 807d32d9864SMats Randgaard i2c_wr16_and_or(sd, CONFCTL, 0xffff, MASK_AUDCHNUM_2 | 808d32d9864SMats Randgaard MASK_AUDOUTSEL_I2S | MASK_AUTOINDEX); 809d32d9864SMats Randgaard mutex_unlock(&state->confctl_mutex); 810d32d9864SMats Randgaard } 811d32d9864SMats Randgaard 812d32d9864SMats Randgaard static void tc358743_set_hdmi_info_frame_mode(struct v4l2_subdev *sd) 813d32d9864SMats Randgaard { 814d32d9864SMats Randgaard /* Default settings from REF_02, sheet "Source HDMI" */ 815d32d9864SMats Randgaard i2c_wr8(sd, PK_INT_MODE, MASK_ISRC2_INT_MODE | MASK_ISRC_INT_MODE | 816d32d9864SMats Randgaard MASK_ACP_INT_MODE | MASK_VS_INT_MODE | 817d32d9864SMats Randgaard MASK_SPD_INT_MODE | MASK_MS_INT_MODE | 818d32d9864SMats Randgaard MASK_AUD_INT_MODE | MASK_AVI_INT_MODE); 819d32d9864SMats Randgaard i2c_wr8(sd, NO_PKT_LIMIT, 0x2c); 820d32d9864SMats Randgaard i2c_wr8(sd, NO_PKT_CLR, 0x53); 821d32d9864SMats Randgaard i2c_wr8(sd, ERR_PK_LIMIT, 0x01); 822d32d9864SMats Randgaard i2c_wr8(sd, NO_PKT_LIMIT2, 0x30); 823d32d9864SMats Randgaard i2c_wr8(sd, NO_GDB_LIMIT, 0x10); 824d32d9864SMats Randgaard } 825d32d9864SMats Randgaard 826d32d9864SMats Randgaard static void tc358743_initial_setup(struct v4l2_subdev *sd) 827d32d9864SMats Randgaard { 828d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 829d32d9864SMats Randgaard struct tc358743_platform_data *pdata = &state->pdata; 830d32d9864SMats Randgaard 831a0ec8d1dSHans Verkuil /* 832a0ec8d1dSHans Verkuil * IR is not supported by this driver. 833a0ec8d1dSHans Verkuil * CEC is only enabled if needed. 834a0ec8d1dSHans Verkuil */ 835a0ec8d1dSHans Verkuil i2c_wr16_and_or(sd, SYSCTL, ~(MASK_IRRST | MASK_CECRST), 836a0ec8d1dSHans Verkuil (MASK_IRRST | MASK_CECRST)); 837d32d9864SMats Randgaard 838d32d9864SMats Randgaard tc358743_reset(sd, MASK_CTXRST | MASK_HDMIRST); 839a0ec8d1dSHans Verkuil #ifdef CONFIG_VIDEO_TC358743_CEC 840a0ec8d1dSHans Verkuil tc358743_reset(sd, MASK_CECRST); 841a0ec8d1dSHans Verkuil #endif 842d32d9864SMats Randgaard tc358743_sleep_mode(sd, false); 843d32d9864SMats Randgaard 844d32d9864SMats Randgaard i2c_wr16(sd, FIFOCTL, pdata->fifo_level); 845d32d9864SMats Randgaard 846d32d9864SMats Randgaard tc358743_set_ref_clk(sd); 847d32d9864SMats Randgaard 848d32d9864SMats Randgaard i2c_wr8_and_or(sd, DDC_CTL, ~MASK_DDC5V_MODE, 849d32d9864SMats Randgaard pdata->ddc5v_delay & MASK_DDC5V_MODE); 850d32d9864SMats Randgaard i2c_wr8_and_or(sd, EDID_MODE, ~MASK_EDID_MODE, MASK_EDID_MODE_E_DDC); 851d32d9864SMats Randgaard 852d32d9864SMats Randgaard tc358743_set_hdmi_phy(sd); 853d32d9864SMats Randgaard tc358743_set_hdmi_hdcp(sd, pdata->enable_hdcp); 854d32d9864SMats Randgaard tc358743_set_hdmi_audio(sd); 855d32d9864SMats Randgaard tc358743_set_hdmi_info_frame_mode(sd); 856d32d9864SMats Randgaard 857d32d9864SMats Randgaard /* All CE and IT formats are detected as RGB full range in DVI mode */ 858d32d9864SMats Randgaard i2c_wr8_and_or(sd, VI_MODE, ~MASK_RGB_DVI, 0); 859d32d9864SMats Randgaard 860d32d9864SMats Randgaard i2c_wr8_and_or(sd, VOUT_SET2, ~MASK_VOUTCOLORMODE, 861d32d9864SMats Randgaard MASK_VOUTCOLORMODE_AUTO); 862d32d9864SMats Randgaard i2c_wr8(sd, VOUT_SET3, MASK_VOUT_EXTCNT); 863d32d9864SMats Randgaard } 864d32d9864SMats Randgaard 865a0ec8d1dSHans Verkuil /* --------------- CEC --------------- */ 866a0ec8d1dSHans Verkuil 867a0ec8d1dSHans Verkuil #ifdef CONFIG_VIDEO_TC358743_CEC 868a0ec8d1dSHans Verkuil static int tc358743_cec_adap_enable(struct cec_adapter *adap, bool enable) 869a0ec8d1dSHans Verkuil { 870a0ec8d1dSHans Verkuil struct tc358743_state *state = adap->priv; 871a0ec8d1dSHans Verkuil struct v4l2_subdev *sd = &state->sd; 872a0ec8d1dSHans Verkuil 873a0ec8d1dSHans Verkuil i2c_wr32(sd, CECIMSK, enable ? MASK_CECTIM | MASK_CECRIM : 0); 874a0ec8d1dSHans Verkuil i2c_wr32(sd, CECICLR, MASK_CECTICLR | MASK_CECRICLR); 875a0ec8d1dSHans Verkuil i2c_wr32(sd, CECEN, enable); 876a0ec8d1dSHans Verkuil if (enable) 877a0ec8d1dSHans Verkuil i2c_wr32(sd, CECREN, MASK_CECREN); 878a0ec8d1dSHans Verkuil return 0; 879a0ec8d1dSHans Verkuil } 880a0ec8d1dSHans Verkuil 881a0ec8d1dSHans Verkuil static int tc358743_cec_adap_monitor_all_enable(struct cec_adapter *adap, 882a0ec8d1dSHans Verkuil bool enable) 883a0ec8d1dSHans Verkuil { 884a0ec8d1dSHans Verkuil struct tc358743_state *state = adap->priv; 885a0ec8d1dSHans Verkuil struct v4l2_subdev *sd = &state->sd; 886a0ec8d1dSHans Verkuil u32 reg; 887a0ec8d1dSHans Verkuil 888a0ec8d1dSHans Verkuil reg = i2c_rd32(sd, CECRCTL1); 889a0ec8d1dSHans Verkuil if (enable) 890a0ec8d1dSHans Verkuil reg |= MASK_CECOTH; 891a0ec8d1dSHans Verkuil else 892a0ec8d1dSHans Verkuil reg &= ~MASK_CECOTH; 893a0ec8d1dSHans Verkuil i2c_wr32(sd, CECRCTL1, reg); 894a0ec8d1dSHans Verkuil return 0; 895a0ec8d1dSHans Verkuil } 896a0ec8d1dSHans Verkuil 897a0ec8d1dSHans Verkuil static int tc358743_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr) 898a0ec8d1dSHans Verkuil { 899a0ec8d1dSHans Verkuil struct tc358743_state *state = adap->priv; 900a0ec8d1dSHans Verkuil struct v4l2_subdev *sd = &state->sd; 901a0ec8d1dSHans Verkuil unsigned int la = 0; 902a0ec8d1dSHans Verkuil 903a0ec8d1dSHans Verkuil if (log_addr != CEC_LOG_ADDR_INVALID) { 904a0ec8d1dSHans Verkuil la = i2c_rd32(sd, CECADD); 905a0ec8d1dSHans Verkuil la |= 1 << log_addr; 906a0ec8d1dSHans Verkuil } 907a0ec8d1dSHans Verkuil i2c_wr32(sd, CECADD, la); 908a0ec8d1dSHans Verkuil return 0; 909a0ec8d1dSHans Verkuil } 910a0ec8d1dSHans Verkuil 911a0ec8d1dSHans Verkuil static int tc358743_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, 912a0ec8d1dSHans Verkuil u32 signal_free_time, struct cec_msg *msg) 913a0ec8d1dSHans Verkuil { 914a0ec8d1dSHans Verkuil struct tc358743_state *state = adap->priv; 915a0ec8d1dSHans Verkuil struct v4l2_subdev *sd = &state->sd; 916a0ec8d1dSHans Verkuil unsigned int i; 917a0ec8d1dSHans Verkuil 918a0ec8d1dSHans Verkuil i2c_wr32(sd, CECTCTL, 919a0ec8d1dSHans Verkuil (cec_msg_is_broadcast(msg) ? MASK_CECBRD : 0) | 920a0ec8d1dSHans Verkuil (signal_free_time - 1)); 921a0ec8d1dSHans Verkuil for (i = 0; i < msg->len; i++) 922a0ec8d1dSHans Verkuil i2c_wr32(sd, CECTBUF1 + i * 4, 923a0ec8d1dSHans Verkuil msg->msg[i] | ((i == msg->len - 1) ? MASK_CECTEOM : 0)); 924a0ec8d1dSHans Verkuil i2c_wr32(sd, CECTEN, MASK_CECTEN); 925a0ec8d1dSHans Verkuil return 0; 926a0ec8d1dSHans Verkuil } 927a0ec8d1dSHans Verkuil 928a0ec8d1dSHans Verkuil static const struct cec_adap_ops tc358743_cec_adap_ops = { 929a0ec8d1dSHans Verkuil .adap_enable = tc358743_cec_adap_enable, 930a0ec8d1dSHans Verkuil .adap_log_addr = tc358743_cec_adap_log_addr, 931a0ec8d1dSHans Verkuil .adap_transmit = tc358743_cec_adap_transmit, 932a0ec8d1dSHans Verkuil .adap_monitor_all_enable = tc358743_cec_adap_monitor_all_enable, 933a0ec8d1dSHans Verkuil }; 934a0ec8d1dSHans Verkuil 935a0ec8d1dSHans Verkuil static void tc358743_cec_isr(struct v4l2_subdev *sd, u16 intstatus, 936a0ec8d1dSHans Verkuil bool *handled) 937a0ec8d1dSHans Verkuil { 938a0ec8d1dSHans Verkuil struct tc358743_state *state = to_state(sd); 939a0ec8d1dSHans Verkuil unsigned int cec_rxint, cec_txint; 940a0ec8d1dSHans Verkuil unsigned int clr = 0; 941a0ec8d1dSHans Verkuil 942a0ec8d1dSHans Verkuil cec_rxint = i2c_rd32(sd, CECRSTAT); 943a0ec8d1dSHans Verkuil cec_txint = i2c_rd32(sd, CECTSTAT); 944a0ec8d1dSHans Verkuil 945a0ec8d1dSHans Verkuil if (intstatus & MASK_CEC_RINT) 946a0ec8d1dSHans Verkuil clr |= MASK_CECRICLR; 947a0ec8d1dSHans Verkuil if (intstatus & MASK_CEC_TINT) 948a0ec8d1dSHans Verkuil clr |= MASK_CECTICLR; 949a0ec8d1dSHans Verkuil i2c_wr32(sd, CECICLR, clr); 950a0ec8d1dSHans Verkuil 951a0ec8d1dSHans Verkuil if ((intstatus & MASK_CEC_TINT) && cec_txint) { 952a0ec8d1dSHans Verkuil if (cec_txint & MASK_CECTIEND) 953a0ec8d1dSHans Verkuil cec_transmit_attempt_done(state->cec_adap, 954a0ec8d1dSHans Verkuil CEC_TX_STATUS_OK); 955a0ec8d1dSHans Verkuil else if (cec_txint & MASK_CECTIAL) 956a0ec8d1dSHans Verkuil cec_transmit_attempt_done(state->cec_adap, 957a0ec8d1dSHans Verkuil CEC_TX_STATUS_ARB_LOST); 958a0ec8d1dSHans Verkuil else if (cec_txint & MASK_CECTIACK) 959a0ec8d1dSHans Verkuil cec_transmit_attempt_done(state->cec_adap, 960a0ec8d1dSHans Verkuil CEC_TX_STATUS_NACK); 961a0ec8d1dSHans Verkuil else if (cec_txint & MASK_CECTIUR) { 962a0ec8d1dSHans Verkuil /* 963a0ec8d1dSHans Verkuil * Not sure when this bit is set. Treat 964a0ec8d1dSHans Verkuil * it as an error for now. 965a0ec8d1dSHans Verkuil */ 966a0ec8d1dSHans Verkuil cec_transmit_attempt_done(state->cec_adap, 967a0ec8d1dSHans Verkuil CEC_TX_STATUS_ERROR); 968a0ec8d1dSHans Verkuil } 969a0ec8d1dSHans Verkuil *handled = true; 970a0ec8d1dSHans Verkuil } 971a0ec8d1dSHans Verkuil if ((intstatus & MASK_CEC_RINT) && 972a0ec8d1dSHans Verkuil (cec_rxint & MASK_CECRIEND)) { 973a0ec8d1dSHans Verkuil struct cec_msg msg = {}; 974a0ec8d1dSHans Verkuil unsigned int i; 975a0ec8d1dSHans Verkuil unsigned int v; 976a0ec8d1dSHans Verkuil 977a0ec8d1dSHans Verkuil v = i2c_rd32(sd, CECRCTR); 978a0ec8d1dSHans Verkuil msg.len = v & 0x1f; 979a0ec8d1dSHans Verkuil for (i = 0; i < msg.len; i++) { 980a0ec8d1dSHans Verkuil v = i2c_rd32(sd, CECRBUF1 + i * 4); 981a0ec8d1dSHans Verkuil msg.msg[i] = v & 0xff; 982a0ec8d1dSHans Verkuil } 983a0ec8d1dSHans Verkuil cec_received_msg(state->cec_adap, &msg); 984a0ec8d1dSHans Verkuil *handled = true; 985a0ec8d1dSHans Verkuil } 986a0ec8d1dSHans Verkuil i2c_wr16(sd, INTSTATUS, 987a0ec8d1dSHans Verkuil intstatus & (MASK_CEC_RINT | MASK_CEC_TINT)); 988a0ec8d1dSHans Verkuil } 989a0ec8d1dSHans Verkuil 990a0ec8d1dSHans Verkuil #endif 991a0ec8d1dSHans Verkuil 992d32d9864SMats Randgaard /* --------------- IRQ --------------- */ 993d32d9864SMats Randgaard 994d32d9864SMats Randgaard static void tc358743_format_change(struct v4l2_subdev *sd) 995d32d9864SMats Randgaard { 996d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 997d32d9864SMats Randgaard struct v4l2_dv_timings timings; 998d32d9864SMats Randgaard const struct v4l2_event tc358743_ev_fmt = { 999d32d9864SMats Randgaard .type = V4L2_EVENT_SOURCE_CHANGE, 1000d32d9864SMats Randgaard .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, 1001d32d9864SMats Randgaard }; 1002d32d9864SMats Randgaard 1003d32d9864SMats Randgaard if (tc358743_get_detected_timings(sd, &timings)) { 1004d32d9864SMats Randgaard enable_stream(sd, false); 1005d32d9864SMats Randgaard 10062874bf3eSMats Randgaard v4l2_dbg(1, debug, sd, "%s: No signal\n", 1007d32d9864SMats Randgaard __func__); 1008d32d9864SMats Randgaard } else { 100985f9e06cSHans Verkuil if (!v4l2_match_dv_timings(&state->timings, &timings, 0, false)) 1010d32d9864SMats Randgaard enable_stream(sd, false); 1011d32d9864SMats Randgaard 10122874bf3eSMats Randgaard if (debug) 1013d32d9864SMats Randgaard v4l2_print_dv_timings(sd->name, 10142874bf3eSMats Randgaard "tc358743_format_change: New format: ", 1015d32d9864SMats Randgaard &timings, false); 1016d32d9864SMats Randgaard } 1017d32d9864SMats Randgaard 1018abeaca0fSPhilipp Zabel if (sd->devnode) 10191140f919SPhilipp Zabel v4l2_subdev_notify_event(sd, &tc358743_ev_fmt); 1020d32d9864SMats Randgaard } 1021d32d9864SMats Randgaard 1022d32d9864SMats Randgaard static void tc358743_init_interrupts(struct v4l2_subdev *sd) 1023d32d9864SMats Randgaard { 1024d32d9864SMats Randgaard u16 i; 1025d32d9864SMats Randgaard 1026d32d9864SMats Randgaard /* clear interrupt status registers */ 1027d32d9864SMats Randgaard for (i = SYS_INT; i <= KEY_INT; i++) 1028d32d9864SMats Randgaard i2c_wr8(sd, i, 0xff); 1029d32d9864SMats Randgaard 1030d32d9864SMats Randgaard i2c_wr16(sd, INTSTATUS, 0xffff); 1031d32d9864SMats Randgaard } 1032d32d9864SMats Randgaard 1033d32d9864SMats Randgaard static void tc358743_enable_interrupts(struct v4l2_subdev *sd, 1034d32d9864SMats Randgaard bool cable_connected) 1035d32d9864SMats Randgaard { 1036d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s: cable connected = %d\n", __func__, 1037d32d9864SMats Randgaard cable_connected); 1038d32d9864SMats Randgaard 1039d32d9864SMats Randgaard if (cable_connected) { 1040d32d9864SMats Randgaard i2c_wr8(sd, SYS_INTM, ~(MASK_M_DDC | MASK_M_DVI_DET | 1041d32d9864SMats Randgaard MASK_M_HDMI_DET) & 0xff); 1042d32d9864SMats Randgaard i2c_wr8(sd, CLK_INTM, ~MASK_M_IN_DE_CHG); 1043d32d9864SMats Randgaard i2c_wr8(sd, CBIT_INTM, ~(MASK_M_CBIT_FS | MASK_M_AF_LOCK | 1044d32d9864SMats Randgaard MASK_M_AF_UNLOCK) & 0xff); 1045d32d9864SMats Randgaard i2c_wr8(sd, AUDIO_INTM, ~MASK_M_BUFINIT_END); 1046d32d9864SMats Randgaard i2c_wr8(sd, MISC_INTM, ~MASK_M_SYNC_CHG); 1047d32d9864SMats Randgaard } else { 1048d32d9864SMats Randgaard i2c_wr8(sd, SYS_INTM, ~MASK_M_DDC & 0xff); 1049d32d9864SMats Randgaard i2c_wr8(sd, CLK_INTM, 0xff); 1050d32d9864SMats Randgaard i2c_wr8(sd, CBIT_INTM, 0xff); 1051d32d9864SMats Randgaard i2c_wr8(sd, AUDIO_INTM, 0xff); 1052d32d9864SMats Randgaard i2c_wr8(sd, MISC_INTM, 0xff); 1053d32d9864SMats Randgaard } 1054d32d9864SMats Randgaard } 1055d32d9864SMats Randgaard 1056d32d9864SMats Randgaard static void tc358743_hdmi_audio_int_handler(struct v4l2_subdev *sd, 1057d32d9864SMats Randgaard bool *handled) 1058d32d9864SMats Randgaard { 1059d32d9864SMats Randgaard u8 audio_int_mask = i2c_rd8(sd, AUDIO_INTM); 1060d32d9864SMats Randgaard u8 audio_int = i2c_rd8(sd, AUDIO_INT) & ~audio_int_mask; 1061d32d9864SMats Randgaard 1062d32d9864SMats Randgaard i2c_wr8(sd, AUDIO_INT, audio_int); 1063d32d9864SMats Randgaard 1064d32d9864SMats Randgaard v4l2_dbg(3, debug, sd, "%s: AUDIO_INT = 0x%02x\n", __func__, audio_int); 1065d32d9864SMats Randgaard 1066d32d9864SMats Randgaard tc358743_s_ctrl_audio_sampling_rate(sd); 1067d32d9864SMats Randgaard tc358743_s_ctrl_audio_present(sd); 1068d32d9864SMats Randgaard } 1069d32d9864SMats Randgaard 1070d32d9864SMats Randgaard static void tc358743_csi_err_int_handler(struct v4l2_subdev *sd, bool *handled) 1071d32d9864SMats Randgaard { 1072d32d9864SMats Randgaard v4l2_err(sd, "%s: CSI_ERR = 0x%x\n", __func__, i2c_rd32(sd, CSI_ERR)); 1073d32d9864SMats Randgaard 1074d32d9864SMats Randgaard i2c_wr32(sd, CSI_INT_CLR, MASK_ICRER); 1075d32d9864SMats Randgaard } 1076d32d9864SMats Randgaard 1077d32d9864SMats Randgaard static void tc358743_hdmi_misc_int_handler(struct v4l2_subdev *sd, 1078d32d9864SMats Randgaard bool *handled) 1079d32d9864SMats Randgaard { 1080d32d9864SMats Randgaard u8 misc_int_mask = i2c_rd8(sd, MISC_INTM); 1081d32d9864SMats Randgaard u8 misc_int = i2c_rd8(sd, MISC_INT) & ~misc_int_mask; 1082d32d9864SMats Randgaard 1083d32d9864SMats Randgaard i2c_wr8(sd, MISC_INT, misc_int); 1084d32d9864SMats Randgaard 1085d32d9864SMats Randgaard v4l2_dbg(3, debug, sd, "%s: MISC_INT = 0x%02x\n", __func__, misc_int); 1086d32d9864SMats Randgaard 1087d32d9864SMats Randgaard if (misc_int & MASK_I_SYNC_CHG) { 1088d32d9864SMats Randgaard /* Reset the HDMI PHY to try to trigger proper lock on the 1089d32d9864SMats Randgaard * incoming video format. Erase BKSV to prevent that old keys 1090d32d9864SMats Randgaard * are used when a new source is connected. */ 1091d32d9864SMats Randgaard if (no_sync(sd) || no_signal(sd)) { 1092d32d9864SMats Randgaard tc358743_reset_phy(sd); 1093d32d9864SMats Randgaard tc358743_erase_bksv(sd); 1094d32d9864SMats Randgaard } 1095d32d9864SMats Randgaard 1096d32d9864SMats Randgaard tc358743_format_change(sd); 1097d32d9864SMats Randgaard 1098d32d9864SMats Randgaard misc_int &= ~MASK_I_SYNC_CHG; 1099d32d9864SMats Randgaard if (handled) 1100d32d9864SMats Randgaard *handled = true; 1101d32d9864SMats Randgaard } 1102d32d9864SMats Randgaard 1103d32d9864SMats Randgaard if (misc_int) { 1104d32d9864SMats Randgaard v4l2_err(sd, "%s: Unhandled MISC_INT interrupts: 0x%02x\n", 1105d32d9864SMats Randgaard __func__, misc_int); 1106d32d9864SMats Randgaard } 1107d32d9864SMats Randgaard } 1108d32d9864SMats Randgaard 1109d32d9864SMats Randgaard static void tc358743_hdmi_cbit_int_handler(struct v4l2_subdev *sd, 1110d32d9864SMats Randgaard bool *handled) 1111d32d9864SMats Randgaard { 1112d32d9864SMats Randgaard u8 cbit_int_mask = i2c_rd8(sd, CBIT_INTM); 1113d32d9864SMats Randgaard u8 cbit_int = i2c_rd8(sd, CBIT_INT) & ~cbit_int_mask; 1114d32d9864SMats Randgaard 1115d32d9864SMats Randgaard i2c_wr8(sd, CBIT_INT, cbit_int); 1116d32d9864SMats Randgaard 1117d32d9864SMats Randgaard v4l2_dbg(3, debug, sd, "%s: CBIT_INT = 0x%02x\n", __func__, cbit_int); 1118d32d9864SMats Randgaard 1119d32d9864SMats Randgaard if (cbit_int & MASK_I_CBIT_FS) { 1120d32d9864SMats Randgaard 1121d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: Audio sample rate changed\n", 1122d32d9864SMats Randgaard __func__); 1123d32d9864SMats Randgaard tc358743_s_ctrl_audio_sampling_rate(sd); 1124d32d9864SMats Randgaard 1125d32d9864SMats Randgaard cbit_int &= ~MASK_I_CBIT_FS; 1126d32d9864SMats Randgaard if (handled) 1127d32d9864SMats Randgaard *handled = true; 1128d32d9864SMats Randgaard } 1129d32d9864SMats Randgaard 1130d32d9864SMats Randgaard if (cbit_int & (MASK_I_AF_LOCK | MASK_I_AF_UNLOCK)) { 1131d32d9864SMats Randgaard 1132d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: Audio present changed\n", 1133d32d9864SMats Randgaard __func__); 1134d32d9864SMats Randgaard tc358743_s_ctrl_audio_present(sd); 1135d32d9864SMats Randgaard 1136d32d9864SMats Randgaard cbit_int &= ~(MASK_I_AF_LOCK | MASK_I_AF_UNLOCK); 1137d32d9864SMats Randgaard if (handled) 1138d32d9864SMats Randgaard *handled = true; 1139d32d9864SMats Randgaard } 1140d32d9864SMats Randgaard 1141d32d9864SMats Randgaard if (cbit_int) { 1142d32d9864SMats Randgaard v4l2_err(sd, "%s: Unhandled CBIT_INT interrupts: 0x%02x\n", 1143d32d9864SMats Randgaard __func__, cbit_int); 1144d32d9864SMats Randgaard } 1145d32d9864SMats Randgaard } 1146d32d9864SMats Randgaard 1147d32d9864SMats Randgaard static void tc358743_hdmi_clk_int_handler(struct v4l2_subdev *sd, bool *handled) 1148d32d9864SMats Randgaard { 1149d32d9864SMats Randgaard u8 clk_int_mask = i2c_rd8(sd, CLK_INTM); 1150d32d9864SMats Randgaard u8 clk_int = i2c_rd8(sd, CLK_INT) & ~clk_int_mask; 1151d32d9864SMats Randgaard 1152d32d9864SMats Randgaard /* Bit 7 and bit 6 are set even when they are masked */ 1153d32d9864SMats Randgaard i2c_wr8(sd, CLK_INT, clk_int | 0x80 | MASK_I_OUT_H_CHG); 1154d32d9864SMats Randgaard 1155d32d9864SMats Randgaard v4l2_dbg(3, debug, sd, "%s: CLK_INT = 0x%02x\n", __func__, clk_int); 1156d32d9864SMats Randgaard 1157d32d9864SMats Randgaard if (clk_int & (MASK_I_IN_DE_CHG)) { 1158d32d9864SMats Randgaard 1159d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: DE size or position has changed\n", 1160d32d9864SMats Randgaard __func__); 1161d32d9864SMats Randgaard 1162d32d9864SMats Randgaard /* If the source switch to a new resolution with the same pixel 1163d32d9864SMats Randgaard * frequency as the existing (e.g. 1080p25 -> 720p50), the 1164d32d9864SMats Randgaard * I_SYNC_CHG interrupt is not always triggered, while the 1165d32d9864SMats Randgaard * I_IN_DE_CHG interrupt seems to work fine. Format change 1166d32d9864SMats Randgaard * notifications are only sent when the signal is stable to 1167d32d9864SMats Randgaard * reduce the number of notifications. */ 1168d32d9864SMats Randgaard if (!no_signal(sd) && !no_sync(sd)) 1169d32d9864SMats Randgaard tc358743_format_change(sd); 1170d32d9864SMats Randgaard 1171d32d9864SMats Randgaard clk_int &= ~(MASK_I_IN_DE_CHG); 1172d32d9864SMats Randgaard if (handled) 1173d32d9864SMats Randgaard *handled = true; 1174d32d9864SMats Randgaard } 1175d32d9864SMats Randgaard 1176d32d9864SMats Randgaard if (clk_int) { 1177d32d9864SMats Randgaard v4l2_err(sd, "%s: Unhandled CLK_INT interrupts: 0x%02x\n", 1178d32d9864SMats Randgaard __func__, clk_int); 1179d32d9864SMats Randgaard } 1180d32d9864SMats Randgaard } 1181d32d9864SMats Randgaard 1182d32d9864SMats Randgaard static void tc358743_hdmi_sys_int_handler(struct v4l2_subdev *sd, bool *handled) 1183d32d9864SMats Randgaard { 1184d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 1185d32d9864SMats Randgaard u8 sys_int_mask = i2c_rd8(sd, SYS_INTM); 1186d32d9864SMats Randgaard u8 sys_int = i2c_rd8(sd, SYS_INT) & ~sys_int_mask; 1187d32d9864SMats Randgaard 1188d32d9864SMats Randgaard i2c_wr8(sd, SYS_INT, sys_int); 1189d32d9864SMats Randgaard 1190d32d9864SMats Randgaard v4l2_dbg(3, debug, sd, "%s: SYS_INT = 0x%02x\n", __func__, sys_int); 1191d32d9864SMats Randgaard 1192d32d9864SMats Randgaard if (sys_int & MASK_I_DDC) { 1193d32d9864SMats Randgaard bool tx_5v = tx_5v_power_present(sd); 1194d32d9864SMats Randgaard 1195d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: Tx 5V power present: %s\n", 1196d32d9864SMats Randgaard __func__, tx_5v ? "yes" : "no"); 1197d32d9864SMats Randgaard 1198d32d9864SMats Randgaard if (tx_5v) { 1199d32d9864SMats Randgaard tc358743_enable_edid(sd); 1200d32d9864SMats Randgaard } else { 1201d32d9864SMats Randgaard tc358743_enable_interrupts(sd, false); 1202d32d9864SMats Randgaard tc358743_disable_edid(sd); 1203d32d9864SMats Randgaard memset(&state->timings, 0, sizeof(state->timings)); 1204d32d9864SMats Randgaard tc358743_erase_bksv(sd); 1205d32d9864SMats Randgaard tc358743_update_controls(sd); 1206d32d9864SMats Randgaard } 1207d32d9864SMats Randgaard 1208d32d9864SMats Randgaard sys_int &= ~MASK_I_DDC; 1209d32d9864SMats Randgaard if (handled) 1210d32d9864SMats Randgaard *handled = true; 1211d32d9864SMats Randgaard } 1212d32d9864SMats Randgaard 1213d32d9864SMats Randgaard if (sys_int & MASK_I_DVI) { 1214d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: HDMI->DVI change detected\n", 1215d32d9864SMats Randgaard __func__); 1216d32d9864SMats Randgaard 1217d32d9864SMats Randgaard /* Reset the HDMI PHY to try to trigger proper lock on the 1218d32d9864SMats Randgaard * incoming video format. Erase BKSV to prevent that old keys 1219d32d9864SMats Randgaard * are used when a new source is connected. */ 1220d32d9864SMats Randgaard if (no_sync(sd) || no_signal(sd)) { 1221d32d9864SMats Randgaard tc358743_reset_phy(sd); 1222d32d9864SMats Randgaard tc358743_erase_bksv(sd); 1223d32d9864SMats Randgaard } 1224d32d9864SMats Randgaard 1225d32d9864SMats Randgaard sys_int &= ~MASK_I_DVI; 1226d32d9864SMats Randgaard if (handled) 1227d32d9864SMats Randgaard *handled = true; 1228d32d9864SMats Randgaard } 1229d32d9864SMats Randgaard 1230d32d9864SMats Randgaard if (sys_int & MASK_I_HDMI) { 1231d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: DVI->HDMI change detected\n", 1232d32d9864SMats Randgaard __func__); 1233d32d9864SMats Randgaard 1234d32d9864SMats Randgaard /* Register is reset in DVI mode (REF_01, c. 6.6.41) */ 1235d32d9864SMats Randgaard i2c_wr8(sd, ANA_CTL, MASK_APPL_PCSX_NORMAL | MASK_ANALOG_ON); 1236d32d9864SMats Randgaard 1237d32d9864SMats Randgaard sys_int &= ~MASK_I_HDMI; 1238d32d9864SMats Randgaard if (handled) 1239d32d9864SMats Randgaard *handled = true; 1240d32d9864SMats Randgaard } 1241d32d9864SMats Randgaard 1242d32d9864SMats Randgaard if (sys_int) { 1243d32d9864SMats Randgaard v4l2_err(sd, "%s: Unhandled SYS_INT interrupts: 0x%02x\n", 1244d32d9864SMats Randgaard __func__, sys_int); 1245d32d9864SMats Randgaard } 1246d32d9864SMats Randgaard } 1247d32d9864SMats Randgaard 1248d32d9864SMats Randgaard /* --------------- CORE OPS --------------- */ 1249d32d9864SMats Randgaard 1250d32d9864SMats Randgaard static int tc358743_log_status(struct v4l2_subdev *sd) 1251d32d9864SMats Randgaard { 1252d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 1253d32d9864SMats Randgaard struct v4l2_dv_timings timings; 1254d32d9864SMats Randgaard uint8_t hdmi_sys_status = i2c_rd8(sd, SYS_STATUS); 1255d32d9864SMats Randgaard uint16_t sysctl = i2c_rd16(sd, SYSCTL); 1256d32d9864SMats Randgaard u8 vi_status3 = i2c_rd8(sd, VI_STATUS3); 1257d32d9864SMats Randgaard const int deep_color_mode[4] = { 8, 10, 12, 16 }; 1258d32d9864SMats Randgaard static const char * const input_color_space[] = { 1259d32d9864SMats Randgaard "RGB", "YCbCr 601", "Adobe RGB", "YCbCr 709", "NA (4)", 1260d32d9864SMats Randgaard "xvYCC 601", "NA(6)", "xvYCC 709", "NA(8)", "sYCC601", 1261d32d9864SMats Randgaard "NA(10)", "NA(11)", "NA(12)", "Adobe YCC 601"}; 1262d32d9864SMats Randgaard 1263d32d9864SMats Randgaard v4l2_info(sd, "-----Chip status-----\n"); 1264d32d9864SMats Randgaard v4l2_info(sd, "Chip ID: 0x%02x\n", 1265d32d9864SMats Randgaard (i2c_rd16(sd, CHIPID) & MASK_CHIPID) >> 8); 1266d32d9864SMats Randgaard v4l2_info(sd, "Chip revision: 0x%02x\n", 1267d32d9864SMats Randgaard i2c_rd16(sd, CHIPID) & MASK_REVID); 1268d32d9864SMats Randgaard v4l2_info(sd, "Reset: IR: %d, CEC: %d, CSI TX: %d, HDMI: %d\n", 1269d32d9864SMats Randgaard !!(sysctl & MASK_IRRST), 1270d32d9864SMats Randgaard !!(sysctl & MASK_CECRST), 1271d32d9864SMats Randgaard !!(sysctl & MASK_CTXRST), 1272d32d9864SMats Randgaard !!(sysctl & MASK_HDMIRST)); 1273d32d9864SMats Randgaard v4l2_info(sd, "Sleep mode: %s\n", sysctl & MASK_SLEEP ? "on" : "off"); 1274d32d9864SMats Randgaard v4l2_info(sd, "Cable detected (+5V power): %s\n", 1275d32d9864SMats Randgaard hdmi_sys_status & MASK_S_DDC5V ? "yes" : "no"); 1276d32d9864SMats Randgaard v4l2_info(sd, "DDC lines enabled: %s\n", 1277d32d9864SMats Randgaard (i2c_rd8(sd, EDID_MODE) & MASK_EDID_MODE_E_DDC) ? 1278d32d9864SMats Randgaard "yes" : "no"); 1279d32d9864SMats Randgaard v4l2_info(sd, "Hotplug enabled: %s\n", 1280d32d9864SMats Randgaard (i2c_rd8(sd, HPD_CTL) & MASK_HPD_OUT0) ? 1281d32d9864SMats Randgaard "yes" : "no"); 1282d32d9864SMats Randgaard v4l2_info(sd, "CEC enabled: %s\n", 1283d32d9864SMats Randgaard (i2c_rd16(sd, CECEN) & MASK_CECEN) ? "yes" : "no"); 1284d32d9864SMats Randgaard v4l2_info(sd, "-----Signal status-----\n"); 1285d32d9864SMats Randgaard v4l2_info(sd, "TMDS signal detected: %s\n", 1286d32d9864SMats Randgaard hdmi_sys_status & MASK_S_TMDS ? "yes" : "no"); 1287d32d9864SMats Randgaard v4l2_info(sd, "Stable sync signal: %s\n", 1288d32d9864SMats Randgaard hdmi_sys_status & MASK_S_SYNC ? "yes" : "no"); 1289d32d9864SMats Randgaard v4l2_info(sd, "PHY PLL locked: %s\n", 1290d32d9864SMats Randgaard hdmi_sys_status & MASK_S_PHY_PLL ? "yes" : "no"); 1291d32d9864SMats Randgaard v4l2_info(sd, "PHY DE detected: %s\n", 1292d32d9864SMats Randgaard hdmi_sys_status & MASK_S_PHY_SCDT ? "yes" : "no"); 1293d32d9864SMats Randgaard 1294d32d9864SMats Randgaard if (tc358743_get_detected_timings(sd, &timings)) { 1295d32d9864SMats Randgaard v4l2_info(sd, "No video detected\n"); 1296d32d9864SMats Randgaard } else { 1297d32d9864SMats Randgaard v4l2_print_dv_timings(sd->name, "Detected format: ", &timings, 1298d32d9864SMats Randgaard true); 1299d32d9864SMats Randgaard } 1300d32d9864SMats Randgaard v4l2_print_dv_timings(sd->name, "Configured format: ", &state->timings, 1301d32d9864SMats Randgaard true); 1302d32d9864SMats Randgaard 1303d32d9864SMats Randgaard v4l2_info(sd, "-----CSI-TX status-----\n"); 1304d32d9864SMats Randgaard v4l2_info(sd, "Lanes needed: %d\n", 1305d32d9864SMats Randgaard tc358743_num_csi_lanes_needed(sd)); 1306d32d9864SMats Randgaard v4l2_info(sd, "Lanes in use: %d\n", 130759e34ba8SMats Randgaard state->csi_lanes_in_use); 1308d32d9864SMats Randgaard v4l2_info(sd, "Waiting for particular sync signal: %s\n", 1309d32d9864SMats Randgaard (i2c_rd16(sd, CSI_STATUS) & MASK_S_WSYNC) ? 1310d32d9864SMats Randgaard "yes" : "no"); 1311d32d9864SMats Randgaard v4l2_info(sd, "Transmit mode: %s\n", 1312d32d9864SMats Randgaard (i2c_rd16(sd, CSI_STATUS) & MASK_S_TXACT) ? 1313d32d9864SMats Randgaard "yes" : "no"); 1314d32d9864SMats Randgaard v4l2_info(sd, "Receive mode: %s\n", 1315d32d9864SMats Randgaard (i2c_rd16(sd, CSI_STATUS) & MASK_S_RXACT) ? 1316d32d9864SMats Randgaard "yes" : "no"); 1317d32d9864SMats Randgaard v4l2_info(sd, "Stopped: %s\n", 1318d32d9864SMats Randgaard (i2c_rd16(sd, CSI_STATUS) & MASK_S_HLT) ? 1319d32d9864SMats Randgaard "yes" : "no"); 1320d32d9864SMats Randgaard v4l2_info(sd, "Color space: %s\n", 1321d32d9864SMats Randgaard state->mbus_fmt_code == MEDIA_BUS_FMT_UYVY8_1X16 ? 1322d32d9864SMats Randgaard "YCbCr 422 16-bit" : 1323d32d9864SMats Randgaard state->mbus_fmt_code == MEDIA_BUS_FMT_RGB888_1X24 ? 1324d32d9864SMats Randgaard "RGB 888 24-bit" : "Unsupported"); 1325d32d9864SMats Randgaard 1326d32d9864SMats Randgaard v4l2_info(sd, "-----%s status-----\n", is_hdmi(sd) ? "HDMI" : "DVI-D"); 1327d32d9864SMats Randgaard v4l2_info(sd, "HDCP encrypted content: %s\n", 1328d32d9864SMats Randgaard hdmi_sys_status & MASK_S_HDCP ? "yes" : "no"); 1329d32d9864SMats Randgaard v4l2_info(sd, "Input color space: %s %s range\n", 1330d32d9864SMats Randgaard input_color_space[(vi_status3 & MASK_S_V_COLOR) >> 1], 1331d32d9864SMats Randgaard (vi_status3 & MASK_LIMITED) ? "limited" : "full"); 1332d32d9864SMats Randgaard if (!is_hdmi(sd)) 1333d32d9864SMats Randgaard return 0; 1334d32d9864SMats Randgaard v4l2_info(sd, "AV Mute: %s\n", hdmi_sys_status & MASK_S_AVMUTE ? "on" : 1335d32d9864SMats Randgaard "off"); 1336d32d9864SMats Randgaard v4l2_info(sd, "Deep color mode: %d-bits per channel\n", 1337d32d9864SMats Randgaard deep_color_mode[(i2c_rd8(sd, VI_STATUS1) & 1338d32d9864SMats Randgaard MASK_S_DEEPCOLOR) >> 2]); 1339d32d9864SMats Randgaard print_avi_infoframe(sd); 1340d32d9864SMats Randgaard 1341d32d9864SMats Randgaard return 0; 1342d32d9864SMats Randgaard } 1343d32d9864SMats Randgaard 1344d32d9864SMats Randgaard #ifdef CONFIG_VIDEO_ADV_DEBUG 1345d32d9864SMats Randgaard static void tc358743_print_register_map(struct v4l2_subdev *sd) 1346d32d9864SMats Randgaard { 134785e510a1SHans Verkuil v4l2_info(sd, "0x0000-0x00FF: Global Control Register\n"); 134885e510a1SHans Verkuil v4l2_info(sd, "0x0100-0x01FF: CSI2-TX PHY Register\n"); 134985e510a1SHans Verkuil v4l2_info(sd, "0x0200-0x03FF: CSI2-TX PPI Register\n"); 135085e510a1SHans Verkuil v4l2_info(sd, "0x0400-0x05FF: Reserved\n"); 135185e510a1SHans Verkuil v4l2_info(sd, "0x0600-0x06FF: CEC Register\n"); 135285e510a1SHans Verkuil v4l2_info(sd, "0x0700-0x84FF: Reserved\n"); 135385e510a1SHans Verkuil v4l2_info(sd, "0x8500-0x85FF: HDMIRX System Control Register\n"); 135485e510a1SHans Verkuil v4l2_info(sd, "0x8600-0x86FF: HDMIRX Audio Control Register\n"); 135585e510a1SHans Verkuil v4l2_info(sd, "0x8700-0x87FF: HDMIRX InfoFrame packet data Register\n"); 135685e510a1SHans Verkuil v4l2_info(sd, "0x8800-0x88FF: HDMIRX HDCP Port Register\n"); 135785e510a1SHans Verkuil v4l2_info(sd, "0x8900-0x89FF: HDMIRX Video Output Port & 3D Register\n"); 135885e510a1SHans Verkuil v4l2_info(sd, "0x8A00-0x8BFF: Reserved\n"); 135985e510a1SHans Verkuil v4l2_info(sd, "0x8C00-0x8FFF: HDMIRX EDID-RAM (1024bytes)\n"); 136085e510a1SHans Verkuil v4l2_info(sd, "0x9000-0x90FF: HDMIRX GBD Extraction Control\n"); 136185e510a1SHans Verkuil v4l2_info(sd, "0x9100-0x92FF: HDMIRX GBD RAM read\n"); 1362d32d9864SMats Randgaard v4l2_info(sd, "0x9300- : Reserved\n"); 1363d32d9864SMats Randgaard } 1364d32d9864SMats Randgaard 1365d32d9864SMats Randgaard static int tc358743_get_reg_size(u16 address) 1366d32d9864SMats Randgaard { 1367d32d9864SMats Randgaard /* REF_01 p. 66-72 */ 1368d32d9864SMats Randgaard if (address <= 0x00ff) 1369d32d9864SMats Randgaard return 2; 1370d32d9864SMats Randgaard else if ((address >= 0x0100) && (address <= 0x06FF)) 1371d32d9864SMats Randgaard return 4; 1372d32d9864SMats Randgaard else if ((address >= 0x0700) && (address <= 0x84ff)) 1373d32d9864SMats Randgaard return 2; 1374d32d9864SMats Randgaard else 1375d32d9864SMats Randgaard return 1; 1376d32d9864SMats Randgaard } 1377d32d9864SMats Randgaard 1378d32d9864SMats Randgaard static int tc358743_g_register(struct v4l2_subdev *sd, 1379d32d9864SMats Randgaard struct v4l2_dbg_register *reg) 1380d32d9864SMats Randgaard { 1381d32d9864SMats Randgaard if (reg->reg > 0xffff) { 1382d32d9864SMats Randgaard tc358743_print_register_map(sd); 1383d32d9864SMats Randgaard return -EINVAL; 1384d32d9864SMats Randgaard } 1385d32d9864SMats Randgaard 1386d32d9864SMats Randgaard reg->size = tc358743_get_reg_size(reg->reg); 1387d32d9864SMats Randgaard 13883538aa6eSArnd Bergmann reg->val = i2c_rdreg(sd, reg->reg, reg->size); 1389d32d9864SMats Randgaard 1390d32d9864SMats Randgaard return 0; 1391d32d9864SMats Randgaard } 1392d32d9864SMats Randgaard 1393d32d9864SMats Randgaard static int tc358743_s_register(struct v4l2_subdev *sd, 1394d32d9864SMats Randgaard const struct v4l2_dbg_register *reg) 1395d32d9864SMats Randgaard { 1396d32d9864SMats Randgaard if (reg->reg > 0xffff) { 1397d32d9864SMats Randgaard tc358743_print_register_map(sd); 1398d32d9864SMats Randgaard return -EINVAL; 1399d32d9864SMats Randgaard } 1400d32d9864SMats Randgaard 1401d32d9864SMats Randgaard /* It should not be possible for the user to enable HDCP with a simple 1402d32d9864SMats Randgaard * v4l2-dbg command. 1403d32d9864SMats Randgaard * 1404d32d9864SMats Randgaard * DO NOT REMOVE THIS unless all other issues with HDCP have been 1405d32d9864SMats Randgaard * resolved. 1406d32d9864SMats Randgaard */ 1407d32d9864SMats Randgaard if (reg->reg == HDCP_MODE || 1408d32d9864SMats Randgaard reg->reg == HDCP_REG1 || 1409d32d9864SMats Randgaard reg->reg == HDCP_REG2 || 1410d32d9864SMats Randgaard reg->reg == HDCP_REG3 || 1411d32d9864SMats Randgaard reg->reg == BCAPS) 1412d32d9864SMats Randgaard return 0; 1413d32d9864SMats Randgaard 14143538aa6eSArnd Bergmann i2c_wrreg(sd, (u16)reg->reg, reg->val, 1415d32d9864SMats Randgaard tc358743_get_reg_size(reg->reg)); 1416d32d9864SMats Randgaard 1417d32d9864SMats Randgaard return 0; 1418d32d9864SMats Randgaard } 1419d32d9864SMats Randgaard #endif 1420d32d9864SMats Randgaard 1421d32d9864SMats Randgaard static int tc358743_isr(struct v4l2_subdev *sd, u32 status, bool *handled) 1422d32d9864SMats Randgaard { 1423d32d9864SMats Randgaard u16 intstatus = i2c_rd16(sd, INTSTATUS); 1424d32d9864SMats Randgaard 1425d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: IntStatus = 0x%04x\n", __func__, intstatus); 1426d32d9864SMats Randgaard 1427d32d9864SMats Randgaard if (intstatus & MASK_HDMI_INT) { 1428d32d9864SMats Randgaard u8 hdmi_int0 = i2c_rd8(sd, HDMI_INT0); 1429d32d9864SMats Randgaard u8 hdmi_int1 = i2c_rd8(sd, HDMI_INT1); 1430d32d9864SMats Randgaard 1431d32d9864SMats Randgaard if (hdmi_int0 & MASK_I_MISC) 1432d32d9864SMats Randgaard tc358743_hdmi_misc_int_handler(sd, handled); 1433d32d9864SMats Randgaard if (hdmi_int1 & MASK_I_CBIT) 1434d32d9864SMats Randgaard tc358743_hdmi_cbit_int_handler(sd, handled); 1435d32d9864SMats Randgaard if (hdmi_int1 & MASK_I_CLK) 1436d32d9864SMats Randgaard tc358743_hdmi_clk_int_handler(sd, handled); 1437d32d9864SMats Randgaard if (hdmi_int1 & MASK_I_SYS) 1438d32d9864SMats Randgaard tc358743_hdmi_sys_int_handler(sd, handled); 1439d32d9864SMats Randgaard if (hdmi_int1 & MASK_I_AUD) 1440d32d9864SMats Randgaard tc358743_hdmi_audio_int_handler(sd, handled); 1441d32d9864SMats Randgaard 1442d32d9864SMats Randgaard i2c_wr16(sd, INTSTATUS, MASK_HDMI_INT); 1443d32d9864SMats Randgaard intstatus &= ~MASK_HDMI_INT; 1444d32d9864SMats Randgaard } 1445d32d9864SMats Randgaard 1446a0ec8d1dSHans Verkuil #ifdef CONFIG_VIDEO_TC358743_CEC 1447a0ec8d1dSHans Verkuil if (intstatus & (MASK_CEC_RINT | MASK_CEC_TINT)) { 1448a0ec8d1dSHans Verkuil tc358743_cec_isr(sd, intstatus, handled); 1449a0ec8d1dSHans Verkuil i2c_wr16(sd, INTSTATUS, 1450a0ec8d1dSHans Verkuil intstatus & (MASK_CEC_RINT | MASK_CEC_TINT)); 1451a0ec8d1dSHans Verkuil intstatus &= ~(MASK_CEC_RINT | MASK_CEC_TINT); 1452a0ec8d1dSHans Verkuil } 1453a0ec8d1dSHans Verkuil #endif 1454a0ec8d1dSHans Verkuil 1455d32d9864SMats Randgaard if (intstatus & MASK_CSI_INT) { 1456d32d9864SMats Randgaard u32 csi_int = i2c_rd32(sd, CSI_INT); 1457d32d9864SMats Randgaard 1458d32d9864SMats Randgaard if (csi_int & MASK_INTER) 1459d32d9864SMats Randgaard tc358743_csi_err_int_handler(sd, handled); 1460d32d9864SMats Randgaard 1461d32d9864SMats Randgaard i2c_wr16(sd, INTSTATUS, MASK_CSI_INT); 1462d32d9864SMats Randgaard } 1463d32d9864SMats Randgaard 1464d32d9864SMats Randgaard intstatus = i2c_rd16(sd, INTSTATUS); 1465d32d9864SMats Randgaard if (intstatus) { 1466d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, 1467d32d9864SMats Randgaard "%s: Unhandled IntStatus interrupts: 0x%02x\n", 1468d32d9864SMats Randgaard __func__, intstatus); 1469d32d9864SMats Randgaard } 1470d32d9864SMats Randgaard 1471d32d9864SMats Randgaard return 0; 1472d32d9864SMats Randgaard } 1473d32d9864SMats Randgaard 1474d747b806SPhilipp Zabel static irqreturn_t tc358743_irq_handler(int irq, void *dev_id) 1475d747b806SPhilipp Zabel { 1476d747b806SPhilipp Zabel struct tc358743_state *state = dev_id; 1477d747b806SPhilipp Zabel bool handled; 1478d747b806SPhilipp Zabel 1479d747b806SPhilipp Zabel tc358743_isr(&state->sd, 0, &handled); 1480d747b806SPhilipp Zabel 1481d747b806SPhilipp Zabel return handled ? IRQ_HANDLED : IRQ_NONE; 1482d747b806SPhilipp Zabel } 1483d747b806SPhilipp Zabel 14844e66a52aSDave Stevenson static void tc358743_irq_poll_timer(unsigned long arg) 14854e66a52aSDave Stevenson { 14864e66a52aSDave Stevenson struct tc358743_state *state = (struct tc358743_state *)arg; 1487a0ec8d1dSHans Verkuil unsigned int msecs; 14884e66a52aSDave Stevenson 14894e66a52aSDave Stevenson schedule_work(&state->work_i2c_poll); 1490a0ec8d1dSHans Verkuil /* 1491a0ec8d1dSHans Verkuil * If CEC is present, then we need to poll more frequently, 1492a0ec8d1dSHans Verkuil * otherwise we will miss CEC messages. 1493a0ec8d1dSHans Verkuil */ 1494a0ec8d1dSHans Verkuil msecs = state->cec_adap ? POLL_INTERVAL_CEC_MS : POLL_INTERVAL_MS; 1495a0ec8d1dSHans Verkuil mod_timer(&state->timer, jiffies + msecs_to_jiffies(msecs)); 14964e66a52aSDave Stevenson } 14974e66a52aSDave Stevenson 14984e66a52aSDave Stevenson static void tc358743_work_i2c_poll(struct work_struct *work) 14994e66a52aSDave Stevenson { 15004e66a52aSDave Stevenson struct tc358743_state *state = container_of(work, 15014e66a52aSDave Stevenson struct tc358743_state, work_i2c_poll); 15024e66a52aSDave Stevenson bool handled; 15034e66a52aSDave Stevenson 15044e66a52aSDave Stevenson tc358743_isr(&state->sd, 0, &handled); 15054e66a52aSDave Stevenson } 15064e66a52aSDave Stevenson 15071140f919SPhilipp Zabel static int tc358743_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, 15081140f919SPhilipp Zabel struct v4l2_event_subscription *sub) 15091140f919SPhilipp Zabel { 15101140f919SPhilipp Zabel switch (sub->type) { 15111140f919SPhilipp Zabel case V4L2_EVENT_SOURCE_CHANGE: 15121140f919SPhilipp Zabel return v4l2_src_change_event_subdev_subscribe(sd, fh, sub); 15131140f919SPhilipp Zabel case V4L2_EVENT_CTRL: 15141140f919SPhilipp Zabel return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub); 15151140f919SPhilipp Zabel default: 15161140f919SPhilipp Zabel return -EINVAL; 15171140f919SPhilipp Zabel } 15181140f919SPhilipp Zabel } 15191140f919SPhilipp Zabel 1520d32d9864SMats Randgaard /* --------------- VIDEO OPS --------------- */ 1521d32d9864SMats Randgaard 1522d32d9864SMats Randgaard static int tc358743_g_input_status(struct v4l2_subdev *sd, u32 *status) 1523d32d9864SMats Randgaard { 1524d32d9864SMats Randgaard *status = 0; 1525d32d9864SMats Randgaard *status |= no_signal(sd) ? V4L2_IN_ST_NO_SIGNAL : 0; 1526d32d9864SMats Randgaard *status |= no_sync(sd) ? V4L2_IN_ST_NO_SYNC : 0; 1527d32d9864SMats Randgaard 1528d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: status = 0x%x\n", __func__, *status); 1529d32d9864SMats Randgaard 1530d32d9864SMats Randgaard return 0; 1531d32d9864SMats Randgaard } 1532d32d9864SMats Randgaard 1533d32d9864SMats Randgaard static int tc358743_s_dv_timings(struct v4l2_subdev *sd, 1534d32d9864SMats Randgaard struct v4l2_dv_timings *timings) 1535d32d9864SMats Randgaard { 1536d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 1537d32d9864SMats Randgaard 1538d32d9864SMats Randgaard if (!timings) 1539d32d9864SMats Randgaard return -EINVAL; 1540d32d9864SMats Randgaard 1541d32d9864SMats Randgaard if (debug) 1542d32d9864SMats Randgaard v4l2_print_dv_timings(sd->name, "tc358743_s_dv_timings: ", 1543d32d9864SMats Randgaard timings, false); 1544d32d9864SMats Randgaard 154585f9e06cSHans Verkuil if (v4l2_match_dv_timings(&state->timings, timings, 0, false)) { 1546d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: no change\n", __func__); 1547d32d9864SMats Randgaard return 0; 1548d32d9864SMats Randgaard } 1549d32d9864SMats Randgaard 1550d32d9864SMats Randgaard if (!v4l2_valid_dv_timings(timings, 1551d32d9864SMats Randgaard &tc358743_timings_cap, NULL, NULL)) { 1552d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: timings out of range\n", __func__); 1553d32d9864SMats Randgaard return -ERANGE; 1554d32d9864SMats Randgaard } 1555d32d9864SMats Randgaard 1556d32d9864SMats Randgaard state->timings = *timings; 1557d32d9864SMats Randgaard 1558d32d9864SMats Randgaard enable_stream(sd, false); 1559d32d9864SMats Randgaard tc358743_set_pll(sd); 1560d32d9864SMats Randgaard tc358743_set_csi(sd); 1561d32d9864SMats Randgaard 1562d32d9864SMats Randgaard return 0; 1563d32d9864SMats Randgaard } 1564d32d9864SMats Randgaard 1565d32d9864SMats Randgaard static int tc358743_g_dv_timings(struct v4l2_subdev *sd, 1566d32d9864SMats Randgaard struct v4l2_dv_timings *timings) 1567d32d9864SMats Randgaard { 1568d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 1569d32d9864SMats Randgaard 1570d32d9864SMats Randgaard *timings = state->timings; 1571d32d9864SMats Randgaard 1572d32d9864SMats Randgaard return 0; 1573d32d9864SMats Randgaard } 1574d32d9864SMats Randgaard 1575d32d9864SMats Randgaard static int tc358743_enum_dv_timings(struct v4l2_subdev *sd, 1576d32d9864SMats Randgaard struct v4l2_enum_dv_timings *timings) 1577d32d9864SMats Randgaard { 1578d32d9864SMats Randgaard if (timings->pad != 0) 1579d32d9864SMats Randgaard return -EINVAL; 1580d32d9864SMats Randgaard 1581d32d9864SMats Randgaard return v4l2_enum_dv_timings_cap(timings, 1582d32d9864SMats Randgaard &tc358743_timings_cap, NULL, NULL); 1583d32d9864SMats Randgaard } 1584d32d9864SMats Randgaard 1585d32d9864SMats Randgaard static int tc358743_query_dv_timings(struct v4l2_subdev *sd, 1586d32d9864SMats Randgaard struct v4l2_dv_timings *timings) 1587d32d9864SMats Randgaard { 1588d32d9864SMats Randgaard int ret; 1589d32d9864SMats Randgaard 1590d32d9864SMats Randgaard ret = tc358743_get_detected_timings(sd, timings); 1591d32d9864SMats Randgaard if (ret) 1592d32d9864SMats Randgaard return ret; 1593d32d9864SMats Randgaard 1594d32d9864SMats Randgaard if (debug) 1595d32d9864SMats Randgaard v4l2_print_dv_timings(sd->name, "tc358743_query_dv_timings: ", 1596d32d9864SMats Randgaard timings, false); 1597d32d9864SMats Randgaard 1598d32d9864SMats Randgaard if (!v4l2_valid_dv_timings(timings, 1599d32d9864SMats Randgaard &tc358743_timings_cap, NULL, NULL)) { 1600d32d9864SMats Randgaard v4l2_dbg(1, debug, sd, "%s: timings out of range\n", __func__); 1601d32d9864SMats Randgaard return -ERANGE; 1602d32d9864SMats Randgaard } 1603d32d9864SMats Randgaard 1604d32d9864SMats Randgaard return 0; 1605d32d9864SMats Randgaard } 1606d32d9864SMats Randgaard 1607d32d9864SMats Randgaard static int tc358743_dv_timings_cap(struct v4l2_subdev *sd, 1608d32d9864SMats Randgaard struct v4l2_dv_timings_cap *cap) 1609d32d9864SMats Randgaard { 1610d32d9864SMats Randgaard if (cap->pad != 0) 1611d32d9864SMats Randgaard return -EINVAL; 1612d32d9864SMats Randgaard 1613d32d9864SMats Randgaard *cap = tc358743_timings_cap; 1614d32d9864SMats Randgaard 1615d32d9864SMats Randgaard return 0; 1616d32d9864SMats Randgaard } 1617d32d9864SMats Randgaard 1618d32d9864SMats Randgaard static int tc358743_g_mbus_config(struct v4l2_subdev *sd, 1619d32d9864SMats Randgaard struct v4l2_mbus_config *cfg) 1620d32d9864SMats Randgaard { 162159e34ba8SMats Randgaard struct tc358743_state *state = to_state(sd); 162259e34ba8SMats Randgaard 1623d32d9864SMats Randgaard cfg->type = V4L2_MBUS_CSI2; 1624d32d9864SMats Randgaard 1625d32d9864SMats Randgaard /* Support for non-continuous CSI-2 clock is missing in the driver */ 1626d32d9864SMats Randgaard cfg->flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; 1627d32d9864SMats Randgaard 162859e34ba8SMats Randgaard switch (state->csi_lanes_in_use) { 1629d32d9864SMats Randgaard case 1: 1630d32d9864SMats Randgaard cfg->flags |= V4L2_MBUS_CSI2_1_LANE; 1631d32d9864SMats Randgaard break; 1632d32d9864SMats Randgaard case 2: 1633d32d9864SMats Randgaard cfg->flags |= V4L2_MBUS_CSI2_2_LANE; 1634d32d9864SMats Randgaard break; 1635d32d9864SMats Randgaard case 3: 1636d32d9864SMats Randgaard cfg->flags |= V4L2_MBUS_CSI2_3_LANE; 1637d32d9864SMats Randgaard break; 1638d32d9864SMats Randgaard case 4: 1639d32d9864SMats Randgaard cfg->flags |= V4L2_MBUS_CSI2_4_LANE; 1640d32d9864SMats Randgaard break; 1641d32d9864SMats Randgaard default: 1642d32d9864SMats Randgaard return -EINVAL; 1643d32d9864SMats Randgaard } 1644d32d9864SMats Randgaard 1645d32d9864SMats Randgaard return 0; 1646d32d9864SMats Randgaard } 1647d32d9864SMats Randgaard 1648d32d9864SMats Randgaard static int tc358743_s_stream(struct v4l2_subdev *sd, int enable) 1649d32d9864SMats Randgaard { 1650d32d9864SMats Randgaard enable_stream(sd, enable); 1651fbd4676cSPhilipp Zabel if (!enable) { 16523863d4bbSJacob Chen /* Put all lanes in LP-11 state (STOPSTATE) */ 1653fbd4676cSPhilipp Zabel tc358743_set_csi(sd); 1654fbd4676cSPhilipp Zabel } 1655d32d9864SMats Randgaard 1656d32d9864SMats Randgaard return 0; 1657d32d9864SMats Randgaard } 1658d32d9864SMats Randgaard 1659d32d9864SMats Randgaard /* --------------- PAD OPS --------------- */ 1660d32d9864SMats Randgaard 16613cb0fe6fSDave Stevenson static int tc358743_enum_mbus_code(struct v4l2_subdev *sd, 16623cb0fe6fSDave Stevenson struct v4l2_subdev_pad_config *cfg, 16633cb0fe6fSDave Stevenson struct v4l2_subdev_mbus_code_enum *code) 16643cb0fe6fSDave Stevenson { 16653cb0fe6fSDave Stevenson switch (code->index) { 16663cb0fe6fSDave Stevenson case 0: 16673cb0fe6fSDave Stevenson code->code = MEDIA_BUS_FMT_RGB888_1X24; 16683cb0fe6fSDave Stevenson break; 16693cb0fe6fSDave Stevenson case 1: 16703cb0fe6fSDave Stevenson code->code = MEDIA_BUS_FMT_UYVY8_1X16; 16713cb0fe6fSDave Stevenson break; 16723cb0fe6fSDave Stevenson default: 16733cb0fe6fSDave Stevenson return -EINVAL; 16743cb0fe6fSDave Stevenson } 16753cb0fe6fSDave Stevenson return 0; 16763cb0fe6fSDave Stevenson } 16773cb0fe6fSDave Stevenson 1678d32d9864SMats Randgaard static int tc358743_get_fmt(struct v4l2_subdev *sd, 1679d32d9864SMats Randgaard struct v4l2_subdev_pad_config *cfg, 1680d32d9864SMats Randgaard struct v4l2_subdev_format *format) 1681d32d9864SMats Randgaard { 1682d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 1683d32d9864SMats Randgaard u8 vi_rep = i2c_rd8(sd, VI_REP); 1684d32d9864SMats Randgaard 1685d32d9864SMats Randgaard if (format->pad != 0) 1686d32d9864SMats Randgaard return -EINVAL; 1687d32d9864SMats Randgaard 1688d32d9864SMats Randgaard format->format.code = state->mbus_fmt_code; 1689d32d9864SMats Randgaard format->format.width = state->timings.bt.width; 1690d32d9864SMats Randgaard format->format.height = state->timings.bt.height; 1691d32d9864SMats Randgaard format->format.field = V4L2_FIELD_NONE; 1692d32d9864SMats Randgaard 1693d32d9864SMats Randgaard switch (vi_rep & MASK_VOUT_COLOR_SEL) { 1694d32d9864SMats Randgaard case MASK_VOUT_COLOR_RGB_FULL: 1695d32d9864SMats Randgaard case MASK_VOUT_COLOR_RGB_LIMITED: 1696d32d9864SMats Randgaard format->format.colorspace = V4L2_COLORSPACE_SRGB; 1697d32d9864SMats Randgaard break; 1698d32d9864SMats Randgaard case MASK_VOUT_COLOR_601_YCBCR_LIMITED: 1699d32d9864SMats Randgaard case MASK_VOUT_COLOR_601_YCBCR_FULL: 1700d32d9864SMats Randgaard format->format.colorspace = V4L2_COLORSPACE_SMPTE170M; 1701d32d9864SMats Randgaard break; 1702d32d9864SMats Randgaard case MASK_VOUT_COLOR_709_YCBCR_FULL: 1703d32d9864SMats Randgaard case MASK_VOUT_COLOR_709_YCBCR_LIMITED: 1704d32d9864SMats Randgaard format->format.colorspace = V4L2_COLORSPACE_REC709; 1705d32d9864SMats Randgaard break; 1706d32d9864SMats Randgaard default: 1707d32d9864SMats Randgaard format->format.colorspace = 0; 1708d32d9864SMats Randgaard break; 1709d32d9864SMats Randgaard } 1710d32d9864SMats Randgaard 1711d32d9864SMats Randgaard return 0; 1712d32d9864SMats Randgaard } 1713d32d9864SMats Randgaard 1714d32d9864SMats Randgaard static int tc358743_set_fmt(struct v4l2_subdev *sd, 1715d32d9864SMats Randgaard struct v4l2_subdev_pad_config *cfg, 1716d32d9864SMats Randgaard struct v4l2_subdev_format *format) 1717d32d9864SMats Randgaard { 1718d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 1719d32d9864SMats Randgaard 1720d32d9864SMats Randgaard u32 code = format->format.code; /* is overwritten by get_fmt */ 1721d32d9864SMats Randgaard int ret = tc358743_get_fmt(sd, cfg, format); 1722d32d9864SMats Randgaard 1723d32d9864SMats Randgaard format->format.code = code; 1724d32d9864SMats Randgaard 1725d32d9864SMats Randgaard if (ret) 1726d32d9864SMats Randgaard return ret; 1727d32d9864SMats Randgaard 1728d32d9864SMats Randgaard switch (code) { 1729d32d9864SMats Randgaard case MEDIA_BUS_FMT_RGB888_1X24: 1730d32d9864SMats Randgaard case MEDIA_BUS_FMT_UYVY8_1X16: 1731d32d9864SMats Randgaard break; 1732d32d9864SMats Randgaard default: 1733d32d9864SMats Randgaard return -EINVAL; 1734d32d9864SMats Randgaard } 1735d32d9864SMats Randgaard 1736d32d9864SMats Randgaard if (format->which == V4L2_SUBDEV_FORMAT_TRY) 1737d32d9864SMats Randgaard return 0; 1738d32d9864SMats Randgaard 1739d32d9864SMats Randgaard state->mbus_fmt_code = format->format.code; 1740d32d9864SMats Randgaard 1741d32d9864SMats Randgaard enable_stream(sd, false); 1742d32d9864SMats Randgaard tc358743_set_pll(sd); 1743d32d9864SMats Randgaard tc358743_set_csi(sd); 1744d32d9864SMats Randgaard tc358743_set_csi_color_space(sd); 1745d32d9864SMats Randgaard 1746d32d9864SMats Randgaard return 0; 1747d32d9864SMats Randgaard } 1748d32d9864SMats Randgaard 1749d32d9864SMats Randgaard static int tc358743_g_edid(struct v4l2_subdev *sd, 1750d32d9864SMats Randgaard struct v4l2_subdev_edid *edid) 1751d32d9864SMats Randgaard { 1752d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 1753d32d9864SMats Randgaard 175472777724SHans Verkuil memset(edid->reserved, 0, sizeof(edid->reserved)); 175572777724SHans Verkuil 1756d32d9864SMats Randgaard if (edid->pad != 0) 1757d32d9864SMats Randgaard return -EINVAL; 1758d32d9864SMats Randgaard 1759d32d9864SMats Randgaard if (edid->start_block == 0 && edid->blocks == 0) { 1760d32d9864SMats Randgaard edid->blocks = state->edid_blocks_written; 1761d32d9864SMats Randgaard return 0; 1762d32d9864SMats Randgaard } 1763d32d9864SMats Randgaard 1764d32d9864SMats Randgaard if (state->edid_blocks_written == 0) 1765d32d9864SMats Randgaard return -ENODATA; 1766d32d9864SMats Randgaard 1767d32d9864SMats Randgaard if (edid->start_block >= state->edid_blocks_written || 1768d32d9864SMats Randgaard edid->blocks == 0) 1769d32d9864SMats Randgaard return -EINVAL; 1770d32d9864SMats Randgaard 1771d32d9864SMats Randgaard if (edid->start_block + edid->blocks > state->edid_blocks_written) 1772d32d9864SMats Randgaard edid->blocks = state->edid_blocks_written - edid->start_block; 1773d32d9864SMats Randgaard 1774d32d9864SMats Randgaard i2c_rd(sd, EDID_RAM + (edid->start_block * EDID_BLOCK_SIZE), edid->edid, 1775d32d9864SMats Randgaard edid->blocks * EDID_BLOCK_SIZE); 1776d32d9864SMats Randgaard 1777d32d9864SMats Randgaard return 0; 1778d32d9864SMats Randgaard } 1779d32d9864SMats Randgaard 1780d32d9864SMats Randgaard static int tc358743_s_edid(struct v4l2_subdev *sd, 1781d32d9864SMats Randgaard struct v4l2_subdev_edid *edid) 1782d32d9864SMats Randgaard { 1783d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 1784d32d9864SMats Randgaard u16 edid_len = edid->blocks * EDID_BLOCK_SIZE; 1785a0ec8d1dSHans Verkuil u16 pa; 1786a0ec8d1dSHans Verkuil int err; 1787fcae73faSMats Randgaard int i; 1788d32d9864SMats Randgaard 1789d32d9864SMats Randgaard v4l2_dbg(2, debug, sd, "%s, pad %d, start block %d, blocks %d\n", 1790d32d9864SMats Randgaard __func__, edid->pad, edid->start_block, edid->blocks); 1791d32d9864SMats Randgaard 179272777724SHans Verkuil memset(edid->reserved, 0, sizeof(edid->reserved)); 179372777724SHans Verkuil 1794d32d9864SMats Randgaard if (edid->pad != 0) 1795d32d9864SMats Randgaard return -EINVAL; 1796d32d9864SMats Randgaard 1797d32d9864SMats Randgaard if (edid->start_block != 0) 1798d32d9864SMats Randgaard return -EINVAL; 1799d32d9864SMats Randgaard 1800d32d9864SMats Randgaard if (edid->blocks > EDID_NUM_BLOCKS_MAX) { 1801d32d9864SMats Randgaard edid->blocks = EDID_NUM_BLOCKS_MAX; 1802d32d9864SMats Randgaard return -E2BIG; 1803d32d9864SMats Randgaard } 1804a0ec8d1dSHans Verkuil pa = cec_get_edid_phys_addr(edid->edid, edid->blocks * 128, NULL); 1805a0ec8d1dSHans Verkuil err = cec_phys_addr_validate(pa, &pa, NULL); 1806a0ec8d1dSHans Verkuil if (err) 1807a0ec8d1dSHans Verkuil return err; 1808a0ec8d1dSHans Verkuil 1809a0ec8d1dSHans Verkuil cec_phys_addr_invalidate(state->cec_adap); 1810d32d9864SMats Randgaard 1811d32d9864SMats Randgaard tc358743_disable_edid(sd); 1812d32d9864SMats Randgaard 1813d32d9864SMats Randgaard i2c_wr8(sd, EDID_LEN1, edid_len & 0xff); 1814d32d9864SMats Randgaard i2c_wr8(sd, EDID_LEN2, edid_len >> 8); 1815d32d9864SMats Randgaard 1816d32d9864SMats Randgaard if (edid->blocks == 0) { 1817d32d9864SMats Randgaard state->edid_blocks_written = 0; 1818d32d9864SMats Randgaard return 0; 1819d32d9864SMats Randgaard } 1820d32d9864SMats Randgaard 1821fcae73faSMats Randgaard for (i = 0; i < edid_len; i += EDID_BLOCK_SIZE) 1822fcae73faSMats Randgaard i2c_wr(sd, EDID_RAM + i, edid->edid + i, EDID_BLOCK_SIZE); 1823d32d9864SMats Randgaard 1824d32d9864SMats Randgaard state->edid_blocks_written = edid->blocks; 1825d32d9864SMats Randgaard 1826a0ec8d1dSHans Verkuil cec_s_phys_addr(state->cec_adap, pa, false); 1827a0ec8d1dSHans Verkuil 1828d32d9864SMats Randgaard if (tx_5v_power_present(sd)) 1829d32d9864SMats Randgaard tc358743_enable_edid(sd); 1830d32d9864SMats Randgaard 1831d32d9864SMats Randgaard return 0; 1832d32d9864SMats Randgaard } 1833d32d9864SMats Randgaard 1834d32d9864SMats Randgaard /* -------------------------------------------------------------------------- */ 1835d32d9864SMats Randgaard 1836d32d9864SMats Randgaard static const struct v4l2_subdev_core_ops tc358743_core_ops = { 1837d32d9864SMats Randgaard .log_status = tc358743_log_status, 1838d32d9864SMats Randgaard #ifdef CONFIG_VIDEO_ADV_DEBUG 1839d32d9864SMats Randgaard .g_register = tc358743_g_register, 1840d32d9864SMats Randgaard .s_register = tc358743_s_register, 1841d32d9864SMats Randgaard #endif 1842d32d9864SMats Randgaard .interrupt_service_routine = tc358743_isr, 18431140f919SPhilipp Zabel .subscribe_event = tc358743_subscribe_event, 18441140f919SPhilipp Zabel .unsubscribe_event = v4l2_event_subdev_unsubscribe, 1845d32d9864SMats Randgaard }; 1846d32d9864SMats Randgaard 1847d32d9864SMats Randgaard static const struct v4l2_subdev_video_ops tc358743_video_ops = { 1848d32d9864SMats Randgaard .g_input_status = tc358743_g_input_status, 1849d32d9864SMats Randgaard .s_dv_timings = tc358743_s_dv_timings, 1850d32d9864SMats Randgaard .g_dv_timings = tc358743_g_dv_timings, 1851d32d9864SMats Randgaard .query_dv_timings = tc358743_query_dv_timings, 1852d32d9864SMats Randgaard .g_mbus_config = tc358743_g_mbus_config, 1853d32d9864SMats Randgaard .s_stream = tc358743_s_stream, 1854d32d9864SMats Randgaard }; 1855d32d9864SMats Randgaard 1856d32d9864SMats Randgaard static const struct v4l2_subdev_pad_ops tc358743_pad_ops = { 18573cb0fe6fSDave Stevenson .enum_mbus_code = tc358743_enum_mbus_code, 1858d32d9864SMats Randgaard .set_fmt = tc358743_set_fmt, 1859d32d9864SMats Randgaard .get_fmt = tc358743_get_fmt, 1860d32d9864SMats Randgaard .get_edid = tc358743_g_edid, 1861d32d9864SMats Randgaard .set_edid = tc358743_s_edid, 1862d32d9864SMats Randgaard .enum_dv_timings = tc358743_enum_dv_timings, 1863d32d9864SMats Randgaard .dv_timings_cap = tc358743_dv_timings_cap, 1864d32d9864SMats Randgaard }; 1865d32d9864SMats Randgaard 1866d32d9864SMats Randgaard static const struct v4l2_subdev_ops tc358743_ops = { 1867d32d9864SMats Randgaard .core = &tc358743_core_ops, 1868d32d9864SMats Randgaard .video = &tc358743_video_ops, 1869d32d9864SMats Randgaard .pad = &tc358743_pad_ops, 1870d32d9864SMats Randgaard }; 1871d32d9864SMats Randgaard 1872d32d9864SMats Randgaard /* --------------- CUSTOM CTRLS --------------- */ 1873d32d9864SMats Randgaard 1874d32d9864SMats Randgaard static const struct v4l2_ctrl_config tc358743_ctrl_audio_sampling_rate = { 1875d32d9864SMats Randgaard .id = TC358743_CID_AUDIO_SAMPLING_RATE, 1876d32d9864SMats Randgaard .name = "Audio sampling rate", 1877d32d9864SMats Randgaard .type = V4L2_CTRL_TYPE_INTEGER, 1878d32d9864SMats Randgaard .min = 0, 1879d32d9864SMats Randgaard .max = 768000, 1880d32d9864SMats Randgaard .step = 1, 1881d32d9864SMats Randgaard .def = 0, 1882d32d9864SMats Randgaard .flags = V4L2_CTRL_FLAG_READ_ONLY, 1883d32d9864SMats Randgaard }; 1884d32d9864SMats Randgaard 1885d32d9864SMats Randgaard static const struct v4l2_ctrl_config tc358743_ctrl_audio_present = { 1886d32d9864SMats Randgaard .id = TC358743_CID_AUDIO_PRESENT, 1887d32d9864SMats Randgaard .name = "Audio present", 1888d32d9864SMats Randgaard .type = V4L2_CTRL_TYPE_BOOLEAN, 1889d32d9864SMats Randgaard .min = 0, 1890d32d9864SMats Randgaard .max = 1, 1891d32d9864SMats Randgaard .step = 1, 1892d32d9864SMats Randgaard .def = 0, 1893d32d9864SMats Randgaard .flags = V4L2_CTRL_FLAG_READ_ONLY, 1894d32d9864SMats Randgaard }; 1895d32d9864SMats Randgaard 1896d32d9864SMats Randgaard /* --------------- PROBE / REMOVE --------------- */ 1897d32d9864SMats Randgaard 189825614824SPhilipp Zabel #ifdef CONFIG_OF 189925614824SPhilipp Zabel static void tc358743_gpio_reset(struct tc358743_state *state) 190025614824SPhilipp Zabel { 190125614824SPhilipp Zabel usleep_range(5000, 10000); 190225614824SPhilipp Zabel gpiod_set_value(state->reset_gpio, 1); 190325614824SPhilipp Zabel usleep_range(1000, 2000); 190425614824SPhilipp Zabel gpiod_set_value(state->reset_gpio, 0); 190525614824SPhilipp Zabel msleep(20); 190625614824SPhilipp Zabel } 190725614824SPhilipp Zabel 190825614824SPhilipp Zabel static int tc358743_probe_of(struct tc358743_state *state) 190925614824SPhilipp Zabel { 191025614824SPhilipp Zabel struct device *dev = &state->i2c_client->dev; 1911859969b3SSakari Ailus struct v4l2_fwnode_endpoint *endpoint; 191225614824SPhilipp Zabel struct device_node *ep; 191325614824SPhilipp Zabel struct clk *refclk; 191425614824SPhilipp Zabel u32 bps_pr_lane; 191525614824SPhilipp Zabel int ret = -EINVAL; 191625614824SPhilipp Zabel 191725614824SPhilipp Zabel refclk = devm_clk_get(dev, "refclk"); 191825614824SPhilipp Zabel if (IS_ERR(refclk)) { 191925614824SPhilipp Zabel if (PTR_ERR(refclk) != -EPROBE_DEFER) 192025614824SPhilipp Zabel dev_err(dev, "failed to get refclk: %ld\n", 192125614824SPhilipp Zabel PTR_ERR(refclk)); 192225614824SPhilipp Zabel return PTR_ERR(refclk); 192325614824SPhilipp Zabel } 192425614824SPhilipp Zabel 192525614824SPhilipp Zabel ep = of_graph_get_next_endpoint(dev->of_node, NULL); 192625614824SPhilipp Zabel if (!ep) { 192725614824SPhilipp Zabel dev_err(dev, "missing endpoint node\n"); 192825614824SPhilipp Zabel return -EINVAL; 192925614824SPhilipp Zabel } 193025614824SPhilipp Zabel 1931859969b3SSakari Ailus endpoint = v4l2_fwnode_endpoint_alloc_parse(of_fwnode_handle(ep)); 193225614824SPhilipp Zabel if (IS_ERR(endpoint)) { 193325614824SPhilipp Zabel dev_err(dev, "failed to parse endpoint\n"); 193425614824SPhilipp Zabel return PTR_ERR(endpoint); 193525614824SPhilipp Zabel } 193625614824SPhilipp Zabel 193725614824SPhilipp Zabel if (endpoint->bus_type != V4L2_MBUS_CSI2 || 193825614824SPhilipp Zabel endpoint->bus.mipi_csi2.num_data_lanes == 0 || 193925614824SPhilipp Zabel endpoint->nr_of_link_frequencies == 0) { 194025614824SPhilipp Zabel dev_err(dev, "missing CSI-2 properties in endpoint\n"); 194125614824SPhilipp Zabel goto free_endpoint; 194225614824SPhilipp Zabel } 194325614824SPhilipp Zabel 194425614824SPhilipp Zabel state->bus = endpoint->bus.mipi_csi2; 194525614824SPhilipp Zabel 194643b288baSArvind Yadav ret = clk_prepare_enable(refclk); 194743b288baSArvind Yadav if (ret) { 194843b288baSArvind Yadav dev_err(dev, "Failed! to enable clock\n"); 194943b288baSArvind Yadav goto free_endpoint; 195043b288baSArvind Yadav } 195125614824SPhilipp Zabel 195225614824SPhilipp Zabel state->pdata.refclk_hz = clk_get_rate(refclk); 195325614824SPhilipp Zabel state->pdata.ddc5v_delay = DDC5V_DELAY_100_MS; 195425614824SPhilipp Zabel state->pdata.enable_hdcp = false; 195525614824SPhilipp Zabel /* A FIFO level of 16 should be enough for 2-lane 720p60 at 594 MHz. */ 195625614824SPhilipp Zabel state->pdata.fifo_level = 16; 195725614824SPhilipp Zabel /* 195825614824SPhilipp Zabel * The PLL input clock is obtained by dividing refclk by pll_prd. 195925614824SPhilipp Zabel * It must be between 6 MHz and 40 MHz, lower frequency is better. 196025614824SPhilipp Zabel */ 196125614824SPhilipp Zabel switch (state->pdata.refclk_hz) { 196225614824SPhilipp Zabel case 26000000: 196325614824SPhilipp Zabel case 27000000: 196425614824SPhilipp Zabel case 42000000: 196525614824SPhilipp Zabel state->pdata.pll_prd = state->pdata.refclk_hz / 6000000; 196625614824SPhilipp Zabel break; 196725614824SPhilipp Zabel default: 196825614824SPhilipp Zabel dev_err(dev, "unsupported refclk rate: %u Hz\n", 196925614824SPhilipp Zabel state->pdata.refclk_hz); 197025614824SPhilipp Zabel goto disable_clk; 197125614824SPhilipp Zabel } 197225614824SPhilipp Zabel 197325614824SPhilipp Zabel /* 197425614824SPhilipp Zabel * The CSI bps per lane must be between 62.5 Mbps and 1 Gbps. 197525614824SPhilipp Zabel * The default is 594 Mbps for 4-lane 1080p60 or 2-lane 720p60. 197625614824SPhilipp Zabel */ 197725614824SPhilipp Zabel bps_pr_lane = 2 * endpoint->link_frequencies[0]; 197825614824SPhilipp Zabel if (bps_pr_lane < 62500000U || bps_pr_lane > 1000000000U) { 197925614824SPhilipp Zabel dev_err(dev, "unsupported bps per lane: %u bps\n", bps_pr_lane); 198025614824SPhilipp Zabel goto disable_clk; 198125614824SPhilipp Zabel } 198225614824SPhilipp Zabel 198325614824SPhilipp Zabel /* The CSI speed per lane is refclk / pll_prd * pll_fbd */ 198425614824SPhilipp Zabel state->pdata.pll_fbd = bps_pr_lane / 198525614824SPhilipp Zabel state->pdata.refclk_hz * state->pdata.pll_prd; 198625614824SPhilipp Zabel 198725614824SPhilipp Zabel /* 198825614824SPhilipp Zabel * FIXME: These timings are from REF_02 for 594 Mbps per lane (297 MHz 198925614824SPhilipp Zabel * link frequency). In principle it should be possible to calculate 199025614824SPhilipp Zabel * them based on link frequency and resolution. 199125614824SPhilipp Zabel */ 199225614824SPhilipp Zabel if (bps_pr_lane != 594000000U) 199325614824SPhilipp Zabel dev_warn(dev, "untested bps per lane: %u bps\n", bps_pr_lane); 199425614824SPhilipp Zabel state->pdata.lineinitcnt = 0xe80; 199525614824SPhilipp Zabel state->pdata.lptxtimecnt = 0x003; 199625614824SPhilipp Zabel /* tclk-preparecnt: 3, tclk-zerocnt: 20 */ 199725614824SPhilipp Zabel state->pdata.tclk_headercnt = 0x1403; 199825614824SPhilipp Zabel state->pdata.tclk_trailcnt = 0x00; 199925614824SPhilipp Zabel /* ths-preparecnt: 3, ths-zerocnt: 1 */ 200025614824SPhilipp Zabel state->pdata.ths_headercnt = 0x0103; 200125614824SPhilipp Zabel state->pdata.twakeup = 0x4882; 200225614824SPhilipp Zabel state->pdata.tclk_postcnt = 0x008; 200325614824SPhilipp Zabel state->pdata.ths_trailcnt = 0x2; 200425614824SPhilipp Zabel state->pdata.hstxvregcnt = 0; 200525614824SPhilipp Zabel 20061e137d92SUwe Kleine-König state->reset_gpio = devm_gpiod_get_optional(dev, "reset", 20071e137d92SUwe Kleine-König GPIOD_OUT_LOW); 200825614824SPhilipp Zabel if (IS_ERR(state->reset_gpio)) { 200925614824SPhilipp Zabel dev_err(dev, "failed to get reset gpio\n"); 201025614824SPhilipp Zabel ret = PTR_ERR(state->reset_gpio); 201125614824SPhilipp Zabel goto disable_clk; 201225614824SPhilipp Zabel } 201325614824SPhilipp Zabel 20141e137d92SUwe Kleine-König if (state->reset_gpio) 201525614824SPhilipp Zabel tc358743_gpio_reset(state); 201625614824SPhilipp Zabel 201725614824SPhilipp Zabel ret = 0; 201825614824SPhilipp Zabel goto free_endpoint; 201925614824SPhilipp Zabel 202025614824SPhilipp Zabel disable_clk: 202125614824SPhilipp Zabel clk_disable_unprepare(refclk); 202225614824SPhilipp Zabel free_endpoint: 2023859969b3SSakari Ailus v4l2_fwnode_endpoint_free(endpoint); 202425614824SPhilipp Zabel return ret; 202525614824SPhilipp Zabel } 202625614824SPhilipp Zabel #else 202725614824SPhilipp Zabel static inline int tc358743_probe_of(struct tc358743_state *state) 202825614824SPhilipp Zabel { 202925614824SPhilipp Zabel return -ENODEV; 203025614824SPhilipp Zabel } 203125614824SPhilipp Zabel #endif 203225614824SPhilipp Zabel 2033d32d9864SMats Randgaard static int tc358743_probe(struct i2c_client *client, 2034d32d9864SMats Randgaard const struct i2c_device_id *id) 2035d32d9864SMats Randgaard { 2036d32d9864SMats Randgaard static struct v4l2_dv_timings default_timing = 2037d32d9864SMats Randgaard V4L2_DV_BT_CEA_640X480P59_94; 2038d32d9864SMats Randgaard struct tc358743_state *state; 2039d32d9864SMats Randgaard struct tc358743_platform_data *pdata = client->dev.platform_data; 2040d32d9864SMats Randgaard struct v4l2_subdev *sd; 2041a0ec8d1dSHans Verkuil u16 irq_mask = MASK_HDMI_MSK | MASK_CSI_MSK; 2042d32d9864SMats Randgaard int err; 2043d32d9864SMats Randgaard 2044d32d9864SMats Randgaard if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 2045d32d9864SMats Randgaard return -EIO; 2046d32d9864SMats Randgaard v4l_dbg(1, debug, client, "chip found @ 0x%x (%s)\n", 2047d32d9864SMats Randgaard client->addr << 1, client->adapter->name); 2048d32d9864SMats Randgaard 2049d32d9864SMats Randgaard state = devm_kzalloc(&client->dev, sizeof(struct tc358743_state), 2050d32d9864SMats Randgaard GFP_KERNEL); 2051d32d9864SMats Randgaard if (!state) 2052d32d9864SMats Randgaard return -ENOMEM; 2053d32d9864SMats Randgaard 2054d32d9864SMats Randgaard state->i2c_client = client; 205525614824SPhilipp Zabel 205625614824SPhilipp Zabel /* platform data */ 205725614824SPhilipp Zabel if (pdata) { 205825614824SPhilipp Zabel state->pdata = *pdata; 205925614824SPhilipp Zabel state->bus.flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; 206025614824SPhilipp Zabel } else { 206125614824SPhilipp Zabel err = tc358743_probe_of(state); 206225614824SPhilipp Zabel if (err == -ENODEV) 206325614824SPhilipp Zabel v4l_err(client, "No platform data!\n"); 206425614824SPhilipp Zabel if (err) 206525614824SPhilipp Zabel return err; 206625614824SPhilipp Zabel } 206725614824SPhilipp Zabel 2068d32d9864SMats Randgaard sd = &state->sd; 2069d32d9864SMats Randgaard v4l2_i2c_subdev_init(sd, client, &tc358743_ops); 20708ec23da7SPhilipp Zabel sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; 2071d32d9864SMats Randgaard 2072d32d9864SMats Randgaard /* i2c access */ 2073d32d9864SMats Randgaard if ((i2c_rd16(sd, CHIPID) & MASK_CHIPID) != 0) { 2074d32d9864SMats Randgaard v4l2_info(sd, "not a TC358743 on address 0x%x\n", 2075d32d9864SMats Randgaard client->addr << 1); 2076d32d9864SMats Randgaard return -ENODEV; 2077d32d9864SMats Randgaard } 2078d32d9864SMats Randgaard 2079d32d9864SMats Randgaard /* control handlers */ 2080d32d9864SMats Randgaard v4l2_ctrl_handler_init(&state->hdl, 3); 2081d32d9864SMats Randgaard 2082d32d9864SMats Randgaard state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(&state->hdl, NULL, 2083d32d9864SMats Randgaard V4L2_CID_DV_RX_POWER_PRESENT, 0, 1, 0, 0); 2084d32d9864SMats Randgaard 2085d32d9864SMats Randgaard /* custom controls */ 2086d32d9864SMats Randgaard state->audio_sampling_rate_ctrl = v4l2_ctrl_new_custom(&state->hdl, 2087d32d9864SMats Randgaard &tc358743_ctrl_audio_sampling_rate, NULL); 2088d32d9864SMats Randgaard 2089d32d9864SMats Randgaard state->audio_present_ctrl = v4l2_ctrl_new_custom(&state->hdl, 2090d32d9864SMats Randgaard &tc358743_ctrl_audio_present, NULL); 2091d32d9864SMats Randgaard 2092d32d9864SMats Randgaard sd->ctrl_handler = &state->hdl; 2093d32d9864SMats Randgaard if (state->hdl.error) { 2094d32d9864SMats Randgaard err = state->hdl.error; 2095d32d9864SMats Randgaard goto err_hdl; 2096d32d9864SMats Randgaard } 2097d32d9864SMats Randgaard 2098d32d9864SMats Randgaard if (tc358743_update_controls(sd)) { 2099d32d9864SMats Randgaard err = -ENODEV; 2100d32d9864SMats Randgaard goto err_hdl; 2101d32d9864SMats Randgaard } 2102d32d9864SMats Randgaard 21034c5211a1SPhilipp Zabel state->pad.flags = MEDIA_PAD_FL_SOURCE; 2104*f7480ad0SPhilipp Zabel sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; 2105ab22e77cSMauro Carvalho Chehab err = media_entity_pads_init(&sd->entity, 1, &state->pad); 21064c5211a1SPhilipp Zabel if (err < 0) 21074c5211a1SPhilipp Zabel goto err_hdl; 21084c5211a1SPhilipp Zabel 21092da2391cSDave Stevenson state->mbus_fmt_code = MEDIA_BUS_FMT_RGB888_1X24; 21102da2391cSDave Stevenson 21114c5211a1SPhilipp Zabel sd->dev = &client->dev; 21124c5211a1SPhilipp Zabel err = v4l2_async_register_subdev(sd); 21134c5211a1SPhilipp Zabel if (err < 0) 21144c5211a1SPhilipp Zabel goto err_hdl; 21154c5211a1SPhilipp Zabel 2116d32d9864SMats Randgaard mutex_init(&state->confctl_mutex); 2117d32d9864SMats Randgaard 2118d32d9864SMats Randgaard INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug, 2119d32d9864SMats Randgaard tc358743_delayed_work_enable_hotplug); 2120d32d9864SMats Randgaard 2121a0ec8d1dSHans Verkuil #ifdef CONFIG_VIDEO_TC358743_CEC 2122a0ec8d1dSHans Verkuil state->cec_adap = cec_allocate_adapter(&tc358743_cec_adap_ops, 2123a0ec8d1dSHans Verkuil state, dev_name(&client->dev), 2124a0ec8d1dSHans Verkuil CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL, CEC_MAX_LOG_ADDRS); 2125a0ec8d1dSHans Verkuil if (IS_ERR(state->cec_adap)) { 21267996e5c4SDan Carpenter err = PTR_ERR(state->cec_adap); 2127a0ec8d1dSHans Verkuil goto err_hdl; 2128a0ec8d1dSHans Verkuil } 2129a0ec8d1dSHans Verkuil irq_mask |= MASK_CEC_RMSK | MASK_CEC_TMSK; 2130a0ec8d1dSHans Verkuil #endif 2131a0ec8d1dSHans Verkuil 2132d32d9864SMats Randgaard tc358743_initial_setup(sd); 2133d32d9864SMats Randgaard 2134d32d9864SMats Randgaard tc358743_s_dv_timings(sd, &default_timing); 2135d32d9864SMats Randgaard 2136d32d9864SMats Randgaard tc358743_set_csi_color_space(sd); 2137d32d9864SMats Randgaard 2138d32d9864SMats Randgaard tc358743_init_interrupts(sd); 2139d747b806SPhilipp Zabel 2140d747b806SPhilipp Zabel if (state->i2c_client->irq) { 2141d747b806SPhilipp Zabel err = devm_request_threaded_irq(&client->dev, 2142d747b806SPhilipp Zabel state->i2c_client->irq, 2143d747b806SPhilipp Zabel NULL, tc358743_irq_handler, 2144d747b806SPhilipp Zabel IRQF_TRIGGER_HIGH | IRQF_ONESHOT, 2145d747b806SPhilipp Zabel "tc358743", state); 2146d747b806SPhilipp Zabel if (err) 2147d747b806SPhilipp Zabel goto err_work_queues; 21484e66a52aSDave Stevenson } else { 21494e66a52aSDave Stevenson INIT_WORK(&state->work_i2c_poll, 21504e66a52aSDave Stevenson tc358743_work_i2c_poll); 2151d17dd2dbSKees Cook setup_timer(&state->timer, tc358743_irq_poll_timer, 2152d17dd2dbSKees Cook (unsigned long)state); 21534e66a52aSDave Stevenson state->timer.expires = jiffies + 21544e66a52aSDave Stevenson msecs_to_jiffies(POLL_INTERVAL_MS); 21554e66a52aSDave Stevenson add_timer(&state->timer); 2156d747b806SPhilipp Zabel } 2157d747b806SPhilipp Zabel 2158a0ec8d1dSHans Verkuil err = cec_register_adapter(state->cec_adap, &client->dev); 2159a0ec8d1dSHans Verkuil if (err < 0) { 2160a0ec8d1dSHans Verkuil pr_err("%s: failed to register the cec device\n", __func__); 2161a0ec8d1dSHans Verkuil cec_delete_adapter(state->cec_adap); 2162a0ec8d1dSHans Verkuil state->cec_adap = NULL; 2163a0ec8d1dSHans Verkuil goto err_work_queues; 2164a0ec8d1dSHans Verkuil } 2165a0ec8d1dSHans Verkuil 2166d32d9864SMats Randgaard tc358743_enable_interrupts(sd, tx_5v_power_present(sd)); 2167a0ec8d1dSHans Verkuil i2c_wr16(sd, INTMASK, ~irq_mask); 2168d32d9864SMats Randgaard 2169d32d9864SMats Randgaard err = v4l2_ctrl_handler_setup(sd->ctrl_handler); 2170d32d9864SMats Randgaard if (err) 2171d32d9864SMats Randgaard goto err_work_queues; 2172d32d9864SMats Randgaard 2173d32d9864SMats Randgaard v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, 2174d32d9864SMats Randgaard client->addr << 1, client->adapter->name); 2175d32d9864SMats Randgaard 2176d32d9864SMats Randgaard return 0; 2177d32d9864SMats Randgaard 2178d32d9864SMats Randgaard err_work_queues: 2179a0ec8d1dSHans Verkuil cec_unregister_adapter(state->cec_adap); 21804e66a52aSDave Stevenson if (!state->i2c_client->irq) 21814e66a52aSDave Stevenson flush_work(&state->work_i2c_poll); 2182d32d9864SMats Randgaard cancel_delayed_work(&state->delayed_work_enable_hotplug); 2183d32d9864SMats Randgaard mutex_destroy(&state->confctl_mutex); 2184d32d9864SMats Randgaard err_hdl: 21854c5211a1SPhilipp Zabel media_entity_cleanup(&sd->entity); 2186d32d9864SMats Randgaard v4l2_ctrl_handler_free(&state->hdl); 2187d32d9864SMats Randgaard return err; 2188d32d9864SMats Randgaard } 2189d32d9864SMats Randgaard 2190d32d9864SMats Randgaard static int tc358743_remove(struct i2c_client *client) 2191d32d9864SMats Randgaard { 2192d32d9864SMats Randgaard struct v4l2_subdev *sd = i2c_get_clientdata(client); 2193d32d9864SMats Randgaard struct tc358743_state *state = to_state(sd); 2194d32d9864SMats Randgaard 21954e66a52aSDave Stevenson if (!state->i2c_client->irq) { 21964e66a52aSDave Stevenson del_timer_sync(&state->timer); 21974e66a52aSDave Stevenson flush_work(&state->work_i2c_poll); 21984e66a52aSDave Stevenson } 2199d32d9864SMats Randgaard cancel_delayed_work(&state->delayed_work_enable_hotplug); 2200a0ec8d1dSHans Verkuil cec_unregister_adapter(state->cec_adap); 22014c5211a1SPhilipp Zabel v4l2_async_unregister_subdev(sd); 2202d32d9864SMats Randgaard v4l2_device_unregister_subdev(sd); 2203d32d9864SMats Randgaard mutex_destroy(&state->confctl_mutex); 22044c5211a1SPhilipp Zabel media_entity_cleanup(&sd->entity); 2205d32d9864SMats Randgaard v4l2_ctrl_handler_free(&state->hdl); 2206d32d9864SMats Randgaard 2207d32d9864SMats Randgaard return 0; 2208d32d9864SMats Randgaard } 2209d32d9864SMats Randgaard 22102f8dfed8SArvind Yadav static const struct i2c_device_id tc358743_id[] = { 2211d32d9864SMats Randgaard {"tc358743", 0}, 2212d32d9864SMats Randgaard {} 2213d32d9864SMats Randgaard }; 2214d32d9864SMats Randgaard 2215d32d9864SMats Randgaard MODULE_DEVICE_TABLE(i2c, tc358743_id); 2216d32d9864SMats Randgaard 2217c0746c1aSJavier Martinez Canillas #if IS_ENABLED(CONFIG_OF) 2218c0746c1aSJavier Martinez Canillas static const struct of_device_id tc358743_of_match[] = { 2219c0746c1aSJavier Martinez Canillas { .compatible = "toshiba,tc358743" }, 2220c0746c1aSJavier Martinez Canillas {}, 2221c0746c1aSJavier Martinez Canillas }; 2222c0746c1aSJavier Martinez Canillas MODULE_DEVICE_TABLE(of, tc358743_of_match); 2223c0746c1aSJavier Martinez Canillas #endif 2224c0746c1aSJavier Martinez Canillas 2225d32d9864SMats Randgaard static struct i2c_driver tc358743_driver = { 2226d32d9864SMats Randgaard .driver = { 2227d32d9864SMats Randgaard .name = "tc358743", 2228c0746c1aSJavier Martinez Canillas .of_match_table = of_match_ptr(tc358743_of_match), 2229d32d9864SMats Randgaard }, 2230d32d9864SMats Randgaard .probe = tc358743_probe, 2231d32d9864SMats Randgaard .remove = tc358743_remove, 2232d32d9864SMats Randgaard .id_table = tc358743_id, 2233d32d9864SMats Randgaard }; 2234d32d9864SMats Randgaard 2235d32d9864SMats Randgaard module_i2c_driver(tc358743_driver); 2236