Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

media: i2c: add lt6911uxe hdmi bridge driver

Lontium LT9611UXE is a HDMI to MIPI CSI-2 bridge. The device supports
modes up to 4k@60fps, obtains the video information and switches the
current mode once the video signal changes.

Signed-off-by: Dongcheng Yan <dongcheng.yan@intel.com>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
[hverkuil: fix smatch warning: missing error code 'ret']
[hverkuil: fix coccinelle IRQF_ONESHOT warning]

authored by

Dongcheng Yan and committed by
Hans Verkuil
e49563c3 36cef585

+719
+11
drivers/media/i2c/Kconfig
··· 1147 1147 Support for Intersil ISL7998x analog to MIPI-CSI2 or 1148 1148 BT.656 decoder. 1149 1149 1150 + config VIDEO_LT6911UXE 1151 + tristate "Lontium LT6911UXE decoder" 1152 + depends on ACPI && VIDEO_DEV 1153 + select V4L2_FWNODE 1154 + help 1155 + This is a Video4Linux2 sensor-level driver for the Lontium 1156 + LT6911UXE HDMI to MIPI CSI-2 bridge. 1157 + 1158 + To compile this driver as a module, choose M here: the 1159 + module will be called lt6911uxe. 1160 + 1150 1161 config VIDEO_KS0127 1151 1162 tristate "KS0127 video decoder" 1152 1163 depends on VIDEO_DEV && I2C
+1
drivers/media/i2c/Makefile
··· 64 64 obj-$(CONFIG_VIDEO_KS0127) += ks0127.o 65 65 obj-$(CONFIG_VIDEO_LM3560) += lm3560.o 66 66 obj-$(CONFIG_VIDEO_LM3646) += lm3646.o 67 + obj-$(CONFIG_VIDEO_LT6911UXE) += lt6911uxe.o 67 68 obj-$(CONFIG_VIDEO_M52790) += m52790.o 68 69 obj-$(CONFIG_VIDEO_MAX9271_LIB) += max9271.o 69 70 obj-$(CONFIG_VIDEO_MAX9286) += max9286.o
+707
drivers/media/i2c/lt6911uxe.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (c) 2023 - 2025 Intel Corporation. 3 + 4 + #include <linux/acpi.h> 5 + #include <linux/delay.h> 6 + #include <linux/gpio/consumer.h> 7 + #include <linux/i2c.h> 8 + #include <linux/interrupt.h> 9 + #include <linux/module.h> 10 + #include <linux/pm_runtime.h> 11 + #include <linux/regmap.h> 12 + #include <linux/v4l2-dv-timings.h> 13 + 14 + #include <media/v4l2-cci.h> 15 + #include <media/v4l2-ctrls.h> 16 + #include <media/v4l2-device.h> 17 + #include <media/v4l2-dv-timings.h> 18 + #include <media/v4l2-event.h> 19 + #include <media/v4l2-fwnode.h> 20 + 21 + #define LT6911UXE_CHIP_ID 0x2102 22 + #define REG_CHIP_ID CCI_REG16(0xe100) 23 + 24 + #define REG_ENABLE_I2C CCI_REG8(0xe0ee) 25 + #define REG_HALF_PIX_CLK CCI_REG24(0xe085) 26 + #define REG_BYTE_CLK CCI_REG24(0xe092) 27 + #define REG_HALF_H_TOTAL CCI_REG16(0xe088) 28 + #define REG_V_TOTAL CCI_REG16(0xe08a) 29 + #define REG_HALF_H_ACTIVE CCI_REG16(0xe08c) 30 + #define REG_V_ACTIVE CCI_REG16(0xe08e) 31 + #define REG_MIPI_FORMAT CCI_REG8(0xe096) 32 + #define REG_MIPI_TX_CTRL CCI_REG8(0xe0b0) 33 + 34 + /* Interrupts */ 35 + #define REG_INT_HDMI CCI_REG8(0xe084) 36 + #define INT_VIDEO_DISAPPEAR 0x0 37 + #define INT_VIDEO_READY 0x1 38 + 39 + #define LT6911UXE_DEFAULT_LANES 4 40 + #define LT6911_PAGE_CONTROL 0xff 41 + #define YUV422_8_BIT 0x7 42 + 43 + static const struct v4l2_dv_timings_cap lt6911uxe_timings_cap_4kp30 = { 44 + .type = V4L2_DV_BT_656_1120, 45 + /* keep this initialization for compatibility with CLANG */ 46 + .reserved = { 0 }, 47 + /* Pixel clock from REF_01 p. 20. Min/max height/width are unknown */ 48 + V4L2_INIT_BT_TIMINGS(160, 3840, /* min/max width */ 49 + 120, 2160, /* min/max height */ 50 + 50000000, 594000000, /* min/max pixelclock */ 51 + V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | 52 + V4L2_DV_BT_STD_CVT, 53 + V4L2_DV_BT_CAP_PROGRESSIVE | 54 + V4L2_DV_BT_CAP_CUSTOM | 55 + V4L2_DV_BT_CAP_REDUCED_BLANKING) 56 + }; 57 + 58 + static const struct regmap_range_cfg lt6911uxe_ranges[] = { 59 + { 60 + .name = "register_range", 61 + .range_min = 0, 62 + .range_max = 0xffff, 63 + .selector_reg = LT6911_PAGE_CONTROL, 64 + .selector_mask = 0xff, 65 + .selector_shift = 0, 66 + .window_start = 0, 67 + .window_len = 0x100, 68 + }, 69 + }; 70 + 71 + static const struct regmap_config lt6911uxe_regmap_config = { 72 + .reg_bits = 8, 73 + .val_bits = 8, 74 + .max_register = 0xffff, 75 + .ranges = lt6911uxe_ranges, 76 + .num_ranges = ARRAY_SIZE(lt6911uxe_ranges), 77 + }; 78 + 79 + struct lt6911uxe_mode { 80 + u32 width; 81 + u32 height; 82 + u32 htotal; 83 + u32 vtotal; 84 + u32 code; 85 + u32 fps; 86 + u32 lanes; 87 + s64 link_freq; 88 + u64 pixel_clk; 89 + }; 90 + 91 + struct lt6911uxe { 92 + struct v4l2_subdev sd; 93 + struct media_pad pad; 94 + struct v4l2_ctrl_handler ctrl_handler; 95 + struct v4l2_ctrl *pixel_rate; 96 + struct v4l2_dv_timings timings; 97 + struct lt6911uxe_mode cur_mode; 98 + struct regmap *regmap; 99 + struct gpio_desc *reset_gpio; 100 + struct gpio_desc *irq_gpio; 101 + }; 102 + 103 + static const struct v4l2_event lt6911uxe_ev_source_change = { 104 + .type = V4L2_EVENT_SOURCE_CHANGE, 105 + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, 106 + }; 107 + 108 + static inline struct lt6911uxe *to_lt6911uxe(struct v4l2_subdev *sd) 109 + { 110 + return container_of(sd, struct lt6911uxe, sd); 111 + } 112 + 113 + static s64 get_pixel_rate(struct lt6911uxe *lt6911uxe) 114 + { 115 + s64 pixel_rate; 116 + 117 + pixel_rate = (s64)lt6911uxe->cur_mode.width * 118 + lt6911uxe->cur_mode.height * 119 + lt6911uxe->cur_mode.fps * 16; 120 + do_div(pixel_rate, lt6911uxe->cur_mode.lanes); 121 + 122 + return pixel_rate; 123 + } 124 + 125 + static int lt6911uxe_get_detected_timings(struct v4l2_subdev *sd, 126 + struct v4l2_dv_timings *timings) 127 + { 128 + struct lt6911uxe *lt6911uxe = to_lt6911uxe(sd); 129 + struct v4l2_bt_timings *bt = &timings->bt; 130 + 131 + memset(timings, 0, sizeof(struct v4l2_dv_timings)); 132 + 133 + timings->type = V4L2_DV_BT_656_1120; 134 + 135 + bt->width = lt6911uxe->cur_mode.width; 136 + bt->height = lt6911uxe->cur_mode.height; 137 + bt->vsync = lt6911uxe->cur_mode.vtotal - lt6911uxe->cur_mode.height; 138 + bt->hsync = lt6911uxe->cur_mode.htotal - lt6911uxe->cur_mode.width; 139 + bt->pixelclock = lt6911uxe->cur_mode.pixel_clk; 140 + 141 + return 0; 142 + } 143 + 144 + static int lt6911uxe_s_dv_timings(struct v4l2_subdev *sd, unsigned int pad, 145 + struct v4l2_dv_timings *timings) 146 + { 147 + struct lt6911uxe *lt6911uxe = to_lt6911uxe(sd); 148 + struct v4l2_subdev_state *state; 149 + 150 + state = v4l2_subdev_lock_and_get_active_state(sd); 151 + if (v4l2_match_dv_timings(&lt6911uxe->timings, timings, 0, false)) { 152 + v4l2_subdev_unlock_state(state); 153 + return 0; 154 + } 155 + 156 + if (!v4l2_valid_dv_timings(timings, &lt6911uxe_timings_cap_4kp30, 157 + NULL, NULL)) { 158 + v4l2_subdev_unlock_state(state); 159 + return -ERANGE; 160 + } 161 + lt6911uxe->timings = *timings; 162 + v4l2_subdev_unlock_state(state); 163 + 164 + return 0; 165 + } 166 + 167 + static int lt6911uxe_g_dv_timings(struct v4l2_subdev *sd, unsigned int pad, 168 + struct v4l2_dv_timings *timings) 169 + { 170 + struct lt6911uxe *lt6911uxe = to_lt6911uxe(sd); 171 + struct v4l2_subdev_state *state; 172 + 173 + state = v4l2_subdev_lock_and_get_active_state(sd); 174 + 175 + *timings = lt6911uxe->timings; 176 + v4l2_subdev_unlock_state(state); 177 + 178 + return 0; 179 + } 180 + 181 + static int lt6911uxe_query_dv_timings(struct v4l2_subdev *sd, unsigned int pad, 182 + struct v4l2_dv_timings *timings) 183 + { 184 + struct v4l2_subdev_state *state; 185 + int ret; 186 + 187 + state = v4l2_subdev_lock_and_get_active_state(sd); 188 + ret = lt6911uxe_get_detected_timings(sd, timings); 189 + if (ret) { 190 + v4l2_subdev_unlock_state(state); 191 + return ret; 192 + } 193 + 194 + if (!v4l2_valid_dv_timings(timings, &lt6911uxe_timings_cap_4kp30, 195 + NULL, NULL)) { 196 + v4l2_subdev_unlock_state(state); 197 + return -ERANGE; 198 + } 199 + 200 + v4l2_subdev_unlock_state(state); 201 + return 0; 202 + } 203 + 204 + static int lt6911uxe_enum_dv_timings(struct v4l2_subdev *sd, 205 + struct v4l2_enum_dv_timings *timings) 206 + { 207 + return v4l2_enum_dv_timings_cap(timings, 208 + &lt6911uxe_timings_cap_4kp30, NULL, NULL); 209 + } 210 + 211 + static int lt6911uxe_dv_timings_cap(struct v4l2_subdev *sd, 212 + struct v4l2_dv_timings_cap *cap) 213 + { 214 + *cap = lt6911uxe_timings_cap_4kp30; 215 + return 0; 216 + } 217 + 218 + static int lt6911uxe_status_update(struct lt6911uxe *lt6911uxe) 219 + { 220 + struct i2c_client *client = v4l2_get_subdevdata(&lt6911uxe->sd); 221 + u64 int_event; 222 + u64 byte_clk, half_pix_clk, fps, format; 223 + u64 half_htotal, vtotal, half_width, height; 224 + int ret = 0; 225 + 226 + /* Read interrupt event */ 227 + cci_read(lt6911uxe->regmap, REG_INT_HDMI, &int_event, &ret); 228 + if (ret) { 229 + dev_err(&client->dev, "failed to read interrupt event: %d\n", 230 + ret); 231 + return ret; 232 + } 233 + 234 + switch (int_event) { 235 + case INT_VIDEO_READY: 236 + cci_read(lt6911uxe->regmap, REG_BYTE_CLK, &byte_clk, &ret); 237 + byte_clk *= 1000; 238 + cci_read(lt6911uxe->regmap, REG_HALF_PIX_CLK, 239 + &half_pix_clk, &ret); 240 + half_pix_clk *= 1000; 241 + 242 + if (ret || byte_clk == 0 || half_pix_clk == 0) { 243 + dev_dbg(&client->dev, 244 + "invalid ByteClock or PixelClock\n"); 245 + return -EINVAL; 246 + } 247 + 248 + cci_read(lt6911uxe->regmap, REG_HALF_H_TOTAL, 249 + &half_htotal, &ret); 250 + cci_read(lt6911uxe->regmap, REG_V_TOTAL, &vtotal, &ret); 251 + if (ret || half_htotal == 0 || vtotal == 0) { 252 + dev_dbg(&client->dev, "invalid htotal or vtotal\n"); 253 + return -EINVAL; 254 + } 255 + 256 + fps = div_u64(half_pix_clk, half_htotal * vtotal); 257 + if (fps > 60) { 258 + dev_dbg(&client->dev, 259 + "max fps is 60, current fps: %llu\n", fps); 260 + return -EINVAL; 261 + } 262 + 263 + cci_read(lt6911uxe->regmap, REG_HALF_H_ACTIVE, 264 + &half_width, &ret); 265 + cci_read(lt6911uxe->regmap, REG_V_ACTIVE, &height, &ret); 266 + if (ret || half_width == 0 || half_width * 2 > 3840 || 267 + height == 0 || height > 2160) { 268 + dev_dbg(&client->dev, "invalid width or height\n"); 269 + return -EINVAL; 270 + } 271 + 272 + /* 273 + * Get MIPI format, YUV422_8_BIT is expected in lt6911uxe 274 + */ 275 + cci_read(lt6911uxe->regmap, REG_MIPI_FORMAT, &format, &ret); 276 + if (format != YUV422_8_BIT) { 277 + dev_dbg(&client->dev, "invalid MIPI format\n"); 278 + return -EINVAL; 279 + } 280 + 281 + lt6911uxe->cur_mode.height = height; 282 + lt6911uxe->cur_mode.width = half_width * 2; 283 + lt6911uxe->cur_mode.fps = fps; 284 + /* MIPI Clock Rate = ByteClock × 4, defined in lt6911uxe spec */ 285 + lt6911uxe->cur_mode.link_freq = byte_clk * 4; 286 + lt6911uxe->cur_mode.pixel_clk = half_pix_clk * 2; 287 + lt6911uxe->cur_mode.vtotal = vtotal; 288 + lt6911uxe->cur_mode.htotal = half_htotal * 2; 289 + break; 290 + 291 + case INT_VIDEO_DISAPPEAR: 292 + cci_write(lt6911uxe->regmap, REG_MIPI_TX_CTRL, 0x0, &ret); 293 + lt6911uxe->cur_mode.height = 0; 294 + lt6911uxe->cur_mode.width = 0; 295 + lt6911uxe->cur_mode.fps = 0; 296 + lt6911uxe->cur_mode.link_freq = 0; 297 + break; 298 + 299 + default: 300 + ret = -ENOLINK; 301 + } 302 + v4l2_subdev_notify_event(&lt6911uxe->sd, &lt6911uxe_ev_source_change); 303 + return ret; 304 + } 305 + 306 + static int lt6911uxe_init_controls(struct lt6911uxe *lt6911uxe) 307 + { 308 + struct v4l2_ctrl_handler *ctrl_hdlr; 309 + s64 pixel_rate; 310 + int ret; 311 + 312 + ctrl_hdlr = &lt6911uxe->ctrl_handler; 313 + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8); 314 + if (ret) 315 + return ret; 316 + 317 + pixel_rate = get_pixel_rate(lt6911uxe); 318 + lt6911uxe->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, NULL, 319 + V4L2_CID_PIXEL_RATE, 320 + pixel_rate, pixel_rate, 1, 321 + pixel_rate); 322 + 323 + if (ctrl_hdlr->error) { 324 + ret = ctrl_hdlr->error; 325 + goto hdlr_free; 326 + } 327 + lt6911uxe->sd.ctrl_handler = ctrl_hdlr; 328 + 329 + return 0; 330 + 331 + hdlr_free: 332 + v4l2_ctrl_handler_free(ctrl_hdlr); 333 + return ret; 334 + } 335 + 336 + static void lt6911uxe_update_pad_format(const struct lt6911uxe_mode *mode, 337 + struct v4l2_mbus_framefmt *fmt) 338 + { 339 + fmt->width = mode->width; 340 + fmt->height = mode->height; 341 + fmt->code = mode->code; 342 + fmt->field = V4L2_FIELD_NONE; 343 + } 344 + 345 + static int lt6911uxe_enable_streams(struct v4l2_subdev *sd, 346 + struct v4l2_subdev_state *state, 347 + u32 pad, u64 streams_mask) 348 + { 349 + struct i2c_client *client = v4l2_get_subdevdata(sd); 350 + struct lt6911uxe *lt6911uxe = to_lt6911uxe(sd); 351 + int ret; 352 + 353 + ret = pm_runtime_resume_and_get(&client->dev); 354 + if (ret < 0) 355 + return ret; 356 + 357 + cci_write(lt6911uxe->regmap, REG_MIPI_TX_CTRL, 0x1, &ret); 358 + if (ret) { 359 + dev_err(&client->dev, "failed to start stream: %d\n", ret); 360 + goto err_rpm_put; 361 + } 362 + 363 + return 0; 364 + 365 + err_rpm_put: 366 + pm_runtime_put(&client->dev); 367 + return ret; 368 + } 369 + 370 + static int lt6911uxe_disable_streams(struct v4l2_subdev *sd, 371 + struct v4l2_subdev_state *state, 372 + u32 pad, u64 streams_mask) 373 + { 374 + struct lt6911uxe *lt6911uxe = to_lt6911uxe(sd); 375 + struct i2c_client *client = v4l2_get_subdevdata(&lt6911uxe->sd); 376 + int ret; 377 + 378 + ret = cci_write(lt6911uxe->regmap, REG_MIPI_TX_CTRL, 0x0, NULL); 379 + if (ret) 380 + dev_err(&client->dev, "failed to stop stream: %d\n", ret); 381 + 382 + pm_runtime_put(&client->dev); 383 + return 0; 384 + } 385 + 386 + static int lt6911uxe_set_format(struct v4l2_subdev *sd, 387 + struct v4l2_subdev_state *sd_state, 388 + struct v4l2_subdev_format *fmt) 389 + { 390 + struct lt6911uxe *lt6911uxe = to_lt6911uxe(sd); 391 + u64 pixel_rate; 392 + 393 + lt6911uxe_update_pad_format(&lt6911uxe->cur_mode, &fmt->format); 394 + *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format; 395 + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) 396 + return 0; 397 + 398 + pixel_rate = get_pixel_rate(lt6911uxe); 399 + __v4l2_ctrl_modify_range(lt6911uxe->pixel_rate, pixel_rate, 400 + pixel_rate, 1, pixel_rate); 401 + 402 + return 0; 403 + } 404 + 405 + static int lt6911uxe_enum_mbus_code(struct v4l2_subdev *sd, 406 + struct v4l2_subdev_state *sd_state, 407 + struct v4l2_subdev_mbus_code_enum *code) 408 + { 409 + struct lt6911uxe *lt6911uxe = to_lt6911uxe(sd); 410 + 411 + if (code->index) 412 + return -EINVAL; 413 + 414 + code->code = lt6911uxe->cur_mode.code; 415 + 416 + return 0; 417 + } 418 + 419 + static int lt6911uxe_get_mbus_config(struct v4l2_subdev *sd, 420 + unsigned int pad, 421 + struct v4l2_mbus_config *cfg) 422 + { 423 + struct lt6911uxe *lt6911uxe = to_lt6911uxe(sd); 424 + struct v4l2_subdev_state *state; 425 + 426 + state = v4l2_subdev_lock_and_get_active_state(sd); 427 + cfg->type = V4L2_MBUS_CSI2_DPHY; 428 + cfg->link_freq = lt6911uxe->cur_mode.link_freq; 429 + v4l2_subdev_unlock_state(state); 430 + 431 + return 0; 432 + } 433 + 434 + static int lt6911uxe_init_state(struct v4l2_subdev *sd, 435 + struct v4l2_subdev_state *sd_state) 436 + { 437 + struct v4l2_subdev_format fmt = { 438 + .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY 439 + : V4L2_SUBDEV_FORMAT_ACTIVE, 440 + }; 441 + 442 + return lt6911uxe_set_format(sd, sd_state, &fmt); 443 + } 444 + 445 + static const struct v4l2_subdev_video_ops lt6911uxe_video_ops = { 446 + .s_stream = v4l2_subdev_s_stream_helper, 447 + }; 448 + 449 + /* 450 + * lt6911uxe provides editable EDID for customers, but only can be edited like 451 + * updating flash. Due to this limitation, it is not possible to implement 452 + * EDID support. 453 + */ 454 + static const struct v4l2_subdev_pad_ops lt6911uxe_pad_ops = { 455 + .set_fmt = lt6911uxe_set_format, 456 + .get_fmt = v4l2_subdev_get_fmt, 457 + .enable_streams = lt6911uxe_enable_streams, 458 + .disable_streams = lt6911uxe_disable_streams, 459 + .enum_mbus_code = lt6911uxe_enum_mbus_code, 460 + .get_frame_interval = v4l2_subdev_get_frame_interval, 461 + .s_dv_timings = lt6911uxe_s_dv_timings, 462 + .g_dv_timings = lt6911uxe_g_dv_timings, 463 + .query_dv_timings = lt6911uxe_query_dv_timings, 464 + .enum_dv_timings = lt6911uxe_enum_dv_timings, 465 + .dv_timings_cap = lt6911uxe_dv_timings_cap, 466 + .get_mbus_config = lt6911uxe_get_mbus_config, 467 + }; 468 + 469 + static const struct v4l2_subdev_core_ops lt6911uxe_subdev_core_ops = { 470 + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, 471 + .unsubscribe_event = v4l2_event_subdev_unsubscribe, 472 + }; 473 + 474 + static const struct v4l2_subdev_ops lt6911uxe_subdev_ops = { 475 + .core = &lt6911uxe_subdev_core_ops, 476 + .video = &lt6911uxe_video_ops, 477 + .pad = &lt6911uxe_pad_ops, 478 + }; 479 + 480 + static const struct media_entity_operations lt6911uxe_subdev_entity_ops = { 481 + .link_validate = v4l2_subdev_link_validate, 482 + }; 483 + 484 + static const struct v4l2_subdev_internal_ops lt6911uxe_internal_ops = { 485 + .init_state = lt6911uxe_init_state, 486 + }; 487 + 488 + static int lt6911uxe_fwnode_parse(struct lt6911uxe *lt6911uxe, 489 + struct device *dev) 490 + { 491 + struct fwnode_handle *endpoint; 492 + struct v4l2_fwnode_endpoint bus_cfg = { 493 + .bus_type = V4L2_MBUS_CSI2_DPHY, 494 + }; 495 + int ret; 496 + 497 + endpoint = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 498 + FWNODE_GRAPH_ENDPOINT_NEXT); 499 + if (!endpoint) 500 + return dev_err_probe(dev, -EPROBE_DEFER, 501 + "endpoint node not found\n"); 502 + 503 + ret = v4l2_fwnode_endpoint_parse(endpoint, &bus_cfg); 504 + fwnode_handle_put(endpoint); 505 + if (ret) { 506 + dev_err(dev, "failed to parse endpoint node: %d\n", ret); 507 + goto out_err; 508 + } 509 + 510 + /* 511 + * Check the number of MIPI CSI2 data lanes, 512 + * lt6911uxe only support 4 lanes. 513 + */ 514 + if (bus_cfg.bus.mipi_csi2.num_data_lanes != LT6911UXE_DEFAULT_LANES) { 515 + dev_err(dev, "only 4 data lanes are currently supported\n"); 516 + ret = -EINVAL; 517 + goto out_err; 518 + } 519 + lt6911uxe->cur_mode.lanes = bus_cfg.bus.mipi_csi2.num_data_lanes; 520 + lt6911uxe->cur_mode.code = MEDIA_BUS_FMT_UYVY8_1X16; 521 + 522 + return 0; 523 + 524 + out_err: 525 + v4l2_fwnode_endpoint_free(&bus_cfg); 526 + return ret; 527 + } 528 + 529 + static int lt6911uxe_identify_module(struct lt6911uxe *lt6911uxe, 530 + struct device *dev) 531 + { 532 + u64 val; 533 + int ret = 0; 534 + 535 + /* Chip ID should be confirmed when the I2C slave is active */ 536 + cci_write(lt6911uxe->regmap, REG_ENABLE_I2C, 0x1, &ret); 537 + cci_read(lt6911uxe->regmap, REG_CHIP_ID, &val, &ret); 538 + cci_write(lt6911uxe->regmap, REG_ENABLE_I2C, 0x0, &ret); 539 + if (ret) 540 + return dev_err_probe(dev, ret, "fail to read chip id\n"); 541 + 542 + if (val != LT6911UXE_CHIP_ID) { 543 + return dev_err_probe(dev, -ENXIO, "chip id mismatch: %x!=%x\n", 544 + LT6911UXE_CHIP_ID, (u16)val); 545 + } 546 + 547 + return 0; 548 + } 549 + 550 + static irqreturn_t lt6911uxe_threaded_irq_fn(int irq, void *dev_id) 551 + { 552 + struct v4l2_subdev *sd = dev_id; 553 + struct lt6911uxe *lt6911uxe = to_lt6911uxe(sd); 554 + struct v4l2_subdev_state *state; 555 + struct v4l2_subdev_format fmt = { 556 + .which = V4L2_SUBDEV_FORMAT_ACTIVE 557 + }; 558 + 559 + lt6911uxe_status_update(lt6911uxe); 560 + state = v4l2_subdev_lock_and_get_active_state(sd); 561 + /* 562 + * As a HDMI to CSI2 bridge, it needs to update the format in time 563 + * when the HDMI source changes. 564 + */ 565 + lt6911uxe_set_format(sd, state, &fmt); 566 + v4l2_subdev_unlock_state(state); 567 + 568 + return IRQ_HANDLED; 569 + } 570 + 571 + static void lt6911uxe_remove(struct i2c_client *client) 572 + { 573 + struct v4l2_subdev *sd = i2c_get_clientdata(client); 574 + struct lt6911uxe *lt6911uxe = to_lt6911uxe(sd); 575 + 576 + free_irq(gpiod_to_irq(lt6911uxe->irq_gpio), lt6911uxe); 577 + v4l2_async_unregister_subdev(sd); 578 + v4l2_subdev_cleanup(sd); 579 + media_entity_cleanup(&sd->entity); 580 + v4l2_ctrl_handler_free(&lt6911uxe->ctrl_handler); 581 + pm_runtime_disable(&client->dev); 582 + pm_runtime_set_suspended(&client->dev); 583 + } 584 + 585 + static int lt6911uxe_probe(struct i2c_client *client) 586 + { 587 + struct lt6911uxe *lt6911uxe; 588 + struct device *dev = &client->dev; 589 + int ret; 590 + 591 + lt6911uxe = devm_kzalloc(dev, sizeof(*lt6911uxe), GFP_KERNEL); 592 + if (!lt6911uxe) 593 + return -ENOMEM; 594 + 595 + lt6911uxe->regmap = devm_regmap_init_i2c(client, 596 + &lt6911uxe_regmap_config); 597 + if (IS_ERR(lt6911uxe->regmap)) 598 + return dev_err_probe(dev, PTR_ERR(lt6911uxe->regmap), 599 + "failed to init CCI\n"); 600 + 601 + v4l2_i2c_subdev_init(&lt6911uxe->sd, client, &lt6911uxe_subdev_ops); 602 + 603 + lt6911uxe->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_IN); 604 + if (IS_ERR(lt6911uxe->reset_gpio)) 605 + return dev_err_probe(dev, PTR_ERR(lt6911uxe->reset_gpio), 606 + "failed to get reset gpio\n"); 607 + 608 + lt6911uxe->irq_gpio = devm_gpiod_get(dev, "readystat", GPIOD_IN); 609 + if (IS_ERR(lt6911uxe->irq_gpio)) 610 + return dev_err_probe(dev, PTR_ERR(lt6911uxe->irq_gpio), 611 + "failed to get ready_stat gpio\n"); 612 + 613 + ret = lt6911uxe_fwnode_parse(lt6911uxe, dev); 614 + if (ret) 615 + return ret; 616 + 617 + usleep_range(10000, 10500); 618 + 619 + ret = lt6911uxe_identify_module(lt6911uxe, dev); 620 + if (ret) 621 + return dev_err_probe(dev, ret, "failed to find chip\n"); 622 + 623 + ret = lt6911uxe_init_controls(lt6911uxe); 624 + if (ret) 625 + return dev_err_probe(dev, ret, "failed to init control\n"); 626 + 627 + lt6911uxe->sd.dev = dev; 628 + lt6911uxe->sd.internal_ops = &lt6911uxe_internal_ops; 629 + lt6911uxe->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 630 + lt6911uxe->sd.entity.ops = &lt6911uxe_subdev_entity_ops; 631 + lt6911uxe->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; 632 + lt6911uxe->pad.flags = MEDIA_PAD_FL_SOURCE; 633 + ret = media_entity_pads_init(&lt6911uxe->sd.entity, 1, &lt6911uxe->pad); 634 + if (ret) { 635 + dev_err(dev, "failed to init entity pads: %d\n", ret); 636 + goto v4l2_ctrl_handler_free; 637 + } 638 + 639 + /* 640 + * Device is already turned on by i2c-core with ACPI domain PM. 641 + * Enable runtime PM and turn off the device. 642 + */ 643 + pm_runtime_set_active(dev); 644 + pm_runtime_enable(dev); 645 + pm_runtime_idle(dev); 646 + 647 + ret = v4l2_subdev_init_finalize(&lt6911uxe->sd); 648 + if (ret) { 649 + dev_err(dev, "failed to init v4l2 subdev: %d\n", ret); 650 + goto media_entity_cleanup; 651 + } 652 + 653 + /* Setting irq */ 654 + ret = request_threaded_irq(gpiod_to_irq(lt6911uxe->irq_gpio), NULL, 655 + lt6911uxe_threaded_irq_fn, 656 + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | 657 + IRQF_ONESHOT, NULL, lt6911uxe); 658 + if (ret) { 659 + dev_err(dev, "failed to request IRQ: %d\n", ret); 660 + goto subdev_cleanup; 661 + } 662 + 663 + ret = v4l2_async_register_subdev_sensor(&lt6911uxe->sd); 664 + if (ret) { 665 + dev_err(dev, "failed to register V4L2 subdev: %d\n", ret); 666 + goto free_irq; 667 + } 668 + 669 + return 0; 670 + 671 + free_irq: 672 + free_irq(gpiod_to_irq(lt6911uxe->irq_gpio), lt6911uxe); 673 + 674 + subdev_cleanup: 675 + v4l2_subdev_cleanup(&lt6911uxe->sd); 676 + 677 + media_entity_cleanup: 678 + pm_runtime_disable(dev); 679 + pm_runtime_set_suspended(dev); 680 + media_entity_cleanup(&lt6911uxe->sd.entity); 681 + 682 + v4l2_ctrl_handler_free: 683 + v4l2_ctrl_handler_free(lt6911uxe->sd.ctrl_handler); 684 + 685 + return ret; 686 + } 687 + 688 + static const struct acpi_device_id lt6911uxe_acpi_ids[] = { 689 + { "INTC10C5" }, 690 + {} 691 + }; 692 + MODULE_DEVICE_TABLE(acpi, lt6911uxe_acpi_ids); 693 + 694 + static struct i2c_driver lt6911uxe_i2c_driver = { 695 + .driver = { 696 + .name = "lt6911uxe", 697 + .acpi_match_table = ACPI_PTR(lt6911uxe_acpi_ids), 698 + }, 699 + .probe = lt6911uxe_probe, 700 + .remove = lt6911uxe_remove, 701 + }; 702 + 703 + module_i2c_driver(lt6911uxe_i2c_driver); 704 + 705 + MODULE_AUTHOR("Yan Dongcheng <dongcheng.yan@intel.com>"); 706 + MODULE_DESCRIPTION("Lontium lt6911uxe HDMI to MIPI Bridge Driver"); 707 + MODULE_LICENSE("GPL");