1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2023 Intel Corporation. All rights reserved. 4 * Intel Visual Sensing Controller CSI Linux driver 5 */ 6 7 /* 8 * To set ownership of CSI-2 link and to configure CSI-2 link, there 9 * are specific commands, which are sent via MEI protocol. The send 10 * command function uses "completion" as a synchronization mechanism. 11 * The response for command is received via a mei callback which wakes 12 * up the caller. There can be only one outstanding command at a time. 13 */ 14 15 #include <linux/completion.h> 16 #include <linux/delay.h> 17 #include <linux/kernel.h> 18 #include <linux/math64.h> 19 #include <linux/mei_cl_bus.h> 20 #include <linux/module.h> 21 #include <linux/mutex.h> 22 #include <linux/pm_runtime.h> 23 #include <linux/slab.h> 24 #include <linux/units.h> 25 #include <linux/uuid.h> 26 #include <linux/workqueue.h> 27 28 #include <media/v4l2-async.h> 29 #include <media/v4l2-ctrls.h> 30 #include <media/v4l2-fwnode.h> 31 #include <media/v4l2-subdev.h> 32 33 #define MEI_CSI_DRIVER_NAME "ivsc_csi" 34 #define MEI_CSI_ENTITY_NAME "Intel IVSC CSI" 35 36 #define MEI_CSI_LINK_FREQ_400MHZ 400000000ULL 37 38 /* the 5s used here is based on experiment */ 39 #define CSI_CMD_TIMEOUT (5 * HZ) 40 /* to setup CSI-2 link an extra delay needed and determined experimentally */ 41 #define CSI_FW_READY_DELAY_MS 100 42 /* link frequency unit is 100kHz */ 43 #define CSI_LINK_FREQ(x) ((u32)(div_u64(x, 100 * HZ_PER_KHZ))) 44 45 /* 46 * identify the command id supported by firmware 47 * IPC, as well as the privacy notification id 48 * used when processing privacy event. 49 */ 50 enum csi_cmd_id { 51 /* used to set csi ownership */ 52 CSI_SET_OWNER = 0, 53 54 /* used to configure CSI-2 link */ 55 CSI_SET_CONF = 2, 56 57 /* privacy notification id used when privacy state changes */ 58 CSI_PRIVACY_NOTIF = 6, 59 }; 60 61 /* CSI-2 link ownership definition */ 62 enum csi_link_owner { 63 CSI_LINK_IVSC, 64 CSI_LINK_HOST, 65 }; 66 67 /* privacy status definition */ 68 enum ivsc_privacy_status { 69 CSI_PRIVACY_OFF, 70 CSI_PRIVACY_ON, 71 CSI_PRIVACY_MAX, 72 }; 73 74 enum csi_pads { 75 CSI_PAD_SINK, 76 CSI_PAD_SOURCE, 77 CSI_NUM_PADS 78 }; 79 80 /* configuration of the CSI-2 link between host and IVSC */ 81 struct csi_link_cfg { 82 /* number of data lanes used on the CSI-2 link */ 83 u32 nr_of_lanes; 84 85 /* frequency of the CSI-2 link */ 86 u32 link_freq; 87 88 /* for future use */ 89 u32 rsvd[2]; 90 } __packed; 91 92 /* CSI command structure */ 93 struct csi_cmd { 94 u32 cmd_id; 95 union _cmd_param { 96 u32 param; 97 struct csi_link_cfg conf; 98 } param; 99 } __packed; 100 101 /* CSI notification structure */ 102 struct csi_notif { 103 u32 cmd_id; 104 int status; 105 union _resp_cont { 106 u32 cont; 107 struct csi_link_cfg conf; 108 } cont; 109 } __packed; 110 111 struct mei_csi { 112 struct mei_cl_device *cldev; 113 114 /* command response */ 115 struct csi_notif cmd_response; 116 /* used to wait for command response from firmware */ 117 struct completion cmd_completion; 118 /* protect command download */ 119 struct mutex lock; 120 121 struct v4l2_subdev subdev; 122 struct v4l2_subdev *remote; 123 struct v4l2_async_notifier notifier; 124 struct v4l2_ctrl_handler ctrl_handler; 125 struct v4l2_ctrl *freq_ctrl; 126 struct v4l2_ctrl *privacy_ctrl; 127 /* lock for v4l2 controls */ 128 struct mutex ctrl_lock; 129 unsigned int remote_pad; 130 /* start streaming or not */ 131 int streaming; 132 133 struct media_pad pads[CSI_NUM_PADS]; 134 struct v4l2_mbus_framefmt format_mbus[CSI_NUM_PADS]; 135 136 /* number of data lanes used on the CSI-2 link */ 137 u32 nr_of_lanes; 138 /* frequency of the CSI-2 link */ 139 u64 link_freq; 140 141 /* privacy status */ 142 enum ivsc_privacy_status status; 143 }; 144 145 static const struct v4l2_mbus_framefmt mei_csi_format_mbus_default = { 146 .width = 1, 147 .height = 1, 148 .code = MEDIA_BUS_FMT_Y8_1X8, 149 .field = V4L2_FIELD_NONE, 150 }; 151 152 static s64 link_freq_menu_items[] = { 153 MEI_CSI_LINK_FREQ_400MHZ 154 }; 155 156 static inline struct mei_csi *notifier_to_csi(struct v4l2_async_notifier *n) 157 { 158 return container_of(n, struct mei_csi, notifier); 159 } 160 161 static inline struct mei_csi *sd_to_csi(struct v4l2_subdev *sd) 162 { 163 return container_of(sd, struct mei_csi, subdev); 164 } 165 166 static inline struct mei_csi *ctrl_to_csi(struct v4l2_ctrl *ctrl) 167 { 168 return container_of(ctrl->handler, struct mei_csi, ctrl_handler); 169 } 170 171 /* send a command to firmware and mutex must be held by caller */ 172 static int mei_csi_send(struct mei_csi *csi, u8 *buf, size_t len) 173 { 174 struct csi_cmd *cmd = (struct csi_cmd *)buf; 175 int ret; 176 177 reinit_completion(&csi->cmd_completion); 178 179 ret = mei_cldev_send(csi->cldev, buf, len); 180 if (ret < 0) 181 goto out; 182 183 ret = wait_for_completion_killable_timeout(&csi->cmd_completion, 184 CSI_CMD_TIMEOUT); 185 if (ret < 0) { 186 goto out; 187 } else if (!ret) { 188 ret = -ETIMEDOUT; 189 goto out; 190 } 191 192 /* command response status */ 193 ret = csi->cmd_response.status; 194 if (ret == -1) { 195 /* notify privacy on instead of reporting error */ 196 ret = 0; 197 v4l2_ctrl_s_ctrl(csi->privacy_ctrl, 1); 198 } else if (ret) { 199 ret = -EINVAL; 200 goto out; 201 } 202 203 if (csi->cmd_response.cmd_id != cmd->cmd_id) 204 ret = -EINVAL; 205 206 out: 207 return ret; 208 } 209 210 /* set CSI-2 link ownership */ 211 static int csi_set_link_owner(struct mei_csi *csi, enum csi_link_owner owner) 212 { 213 struct csi_cmd cmd = { 0 }; 214 size_t cmd_size; 215 int ret; 216 217 cmd.cmd_id = CSI_SET_OWNER; 218 cmd.param.param = owner; 219 cmd_size = sizeof(cmd.cmd_id) + sizeof(cmd.param.param); 220 221 mutex_lock(&csi->lock); 222 223 ret = mei_csi_send(csi, (u8 *)&cmd, cmd_size); 224 225 mutex_unlock(&csi->lock); 226 227 return ret; 228 } 229 230 /* configure CSI-2 link between host and IVSC */ 231 static int csi_set_link_cfg(struct mei_csi *csi) 232 { 233 struct csi_cmd cmd = { 0 }; 234 size_t cmd_size; 235 int ret; 236 237 cmd.cmd_id = CSI_SET_CONF; 238 cmd.param.conf.nr_of_lanes = csi->nr_of_lanes; 239 cmd.param.conf.link_freq = CSI_LINK_FREQ(csi->link_freq); 240 cmd_size = sizeof(cmd.cmd_id) + sizeof(cmd.param.conf); 241 242 mutex_lock(&csi->lock); 243 244 ret = mei_csi_send(csi, (u8 *)&cmd, cmd_size); 245 /* 246 * wait configuration ready if download success. placing 247 * delay under mutex is to make sure current command flow 248 * completed before starting a possible new one. 249 */ 250 if (!ret) 251 msleep(CSI_FW_READY_DELAY_MS); 252 253 mutex_unlock(&csi->lock); 254 255 return ret; 256 } 257 258 /* callback for receive */ 259 static void mei_csi_rx(struct mei_cl_device *cldev) 260 { 261 struct mei_csi *csi = mei_cldev_get_drvdata(cldev); 262 struct csi_notif notif = { 0 }; 263 int ret; 264 265 ret = mei_cldev_recv(cldev, (u8 *)¬if, sizeof(notif)); 266 if (ret < 0) { 267 dev_err(&cldev->dev, "recv error: %d\n", ret); 268 return; 269 } 270 271 switch (notif.cmd_id) { 272 case CSI_PRIVACY_NOTIF: 273 if (notif.cont.cont < CSI_PRIVACY_MAX) { 274 csi->status = notif.cont.cont; 275 v4l2_ctrl_s_ctrl(csi->privacy_ctrl, csi->status); 276 } 277 break; 278 case CSI_SET_OWNER: 279 case CSI_SET_CONF: 280 memcpy(&csi->cmd_response, ¬if, ret); 281 282 complete(&csi->cmd_completion); 283 break; 284 default: 285 break; 286 } 287 } 288 289 static int mei_csi_set_stream(struct v4l2_subdev *sd, int enable) 290 { 291 struct mei_csi *csi = sd_to_csi(sd); 292 s64 freq; 293 int ret; 294 295 if (enable && csi->streaming == 0) { 296 freq = v4l2_get_link_freq(csi->remote->ctrl_handler, 0, 0); 297 if (freq < 0) { 298 dev_err(&csi->cldev->dev, 299 "error %lld, invalid link_freq\n", freq); 300 ret = freq; 301 goto err; 302 } 303 csi->link_freq = freq; 304 305 /* switch CSI-2 link to host */ 306 ret = csi_set_link_owner(csi, CSI_LINK_HOST); 307 if (ret < 0) 308 goto err; 309 310 /* configure CSI-2 link */ 311 ret = csi_set_link_cfg(csi); 312 if (ret < 0) 313 goto err_switch; 314 315 ret = v4l2_subdev_call(csi->remote, video, s_stream, 1); 316 if (ret) 317 goto err_switch; 318 } else if (!enable && csi->streaming == 1) { 319 v4l2_subdev_call(csi->remote, video, s_stream, 0); 320 321 /* switch CSI-2 link to IVSC */ 322 ret = csi_set_link_owner(csi, CSI_LINK_IVSC); 323 if (ret < 0) 324 dev_warn(&csi->cldev->dev, 325 "failed to switch CSI2 link: %d\n", ret); 326 } 327 328 csi->streaming = enable; 329 330 return 0; 331 332 err_switch: 333 csi_set_link_owner(csi, CSI_LINK_IVSC); 334 335 err: 336 return ret; 337 } 338 339 static struct v4l2_mbus_framefmt * 340 mei_csi_get_pad_format(struct v4l2_subdev *sd, 341 struct v4l2_subdev_state *sd_state, 342 unsigned int pad, u32 which) 343 { 344 struct mei_csi *csi = sd_to_csi(sd); 345 346 switch (which) { 347 case V4L2_SUBDEV_FORMAT_TRY: 348 return v4l2_subdev_get_try_format(sd, sd_state, pad); 349 case V4L2_SUBDEV_FORMAT_ACTIVE: 350 return &csi->format_mbus[pad]; 351 default: 352 return NULL; 353 } 354 } 355 356 static int mei_csi_init_cfg(struct v4l2_subdev *sd, 357 struct v4l2_subdev_state *sd_state) 358 { 359 struct v4l2_mbus_framefmt *mbusformat; 360 struct mei_csi *csi = sd_to_csi(sd); 361 unsigned int i; 362 363 mutex_lock(&csi->lock); 364 365 for (i = 0; i < sd->entity.num_pads; i++) { 366 mbusformat = v4l2_subdev_get_try_format(sd, sd_state, i); 367 *mbusformat = mei_csi_format_mbus_default; 368 } 369 370 mutex_unlock(&csi->lock); 371 372 return 0; 373 } 374 375 static int mei_csi_get_fmt(struct v4l2_subdev *sd, 376 struct v4l2_subdev_state *sd_state, 377 struct v4l2_subdev_format *format) 378 { 379 struct v4l2_mbus_framefmt *mbusformat; 380 struct mei_csi *csi = sd_to_csi(sd); 381 382 mutex_lock(&csi->lock); 383 384 mbusformat = mei_csi_get_pad_format(sd, sd_state, format->pad, 385 format->which); 386 if (mbusformat) 387 format->format = *mbusformat; 388 389 mutex_unlock(&csi->lock); 390 391 return 0; 392 } 393 394 static int mei_csi_set_fmt(struct v4l2_subdev *sd, 395 struct v4l2_subdev_state *sd_state, 396 struct v4l2_subdev_format *format) 397 { 398 struct v4l2_mbus_framefmt *source_mbusformat; 399 struct v4l2_mbus_framefmt *mbusformat; 400 struct mei_csi *csi = sd_to_csi(sd); 401 struct media_pad *pad; 402 403 mbusformat = mei_csi_get_pad_format(sd, sd_state, format->pad, 404 format->which); 405 if (!mbusformat) 406 return -EINVAL; 407 408 source_mbusformat = mei_csi_get_pad_format(sd, sd_state, CSI_PAD_SOURCE, 409 format->which); 410 if (!source_mbusformat) 411 return -EINVAL; 412 413 v4l_bound_align_image(&format->format.width, 1, 65536, 0, 414 &format->format.height, 1, 65536, 0, 0); 415 416 switch (format->format.code) { 417 case MEDIA_BUS_FMT_RGB444_1X12: 418 case MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE: 419 case MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE: 420 case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE: 421 case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE: 422 case MEDIA_BUS_FMT_RGB565_1X16: 423 case MEDIA_BUS_FMT_BGR565_2X8_BE: 424 case MEDIA_BUS_FMT_BGR565_2X8_LE: 425 case MEDIA_BUS_FMT_RGB565_2X8_BE: 426 case MEDIA_BUS_FMT_RGB565_2X8_LE: 427 case MEDIA_BUS_FMT_RGB666_1X18: 428 case MEDIA_BUS_FMT_RBG888_1X24: 429 case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: 430 case MEDIA_BUS_FMT_BGR888_1X24: 431 case MEDIA_BUS_FMT_GBR888_1X24: 432 case MEDIA_BUS_FMT_RGB888_1X24: 433 case MEDIA_BUS_FMT_RGB888_2X12_BE: 434 case MEDIA_BUS_FMT_RGB888_2X12_LE: 435 case MEDIA_BUS_FMT_ARGB8888_1X32: 436 case MEDIA_BUS_FMT_RGB888_1X32_PADHI: 437 case MEDIA_BUS_FMT_RGB101010_1X30: 438 case MEDIA_BUS_FMT_RGB121212_1X36: 439 case MEDIA_BUS_FMT_RGB161616_1X48: 440 case MEDIA_BUS_FMT_Y8_1X8: 441 case MEDIA_BUS_FMT_UV8_1X8: 442 case MEDIA_BUS_FMT_UYVY8_1_5X8: 443 case MEDIA_BUS_FMT_VYUY8_1_5X8: 444 case MEDIA_BUS_FMT_YUYV8_1_5X8: 445 case MEDIA_BUS_FMT_YVYU8_1_5X8: 446 case MEDIA_BUS_FMT_UYVY8_2X8: 447 case MEDIA_BUS_FMT_VYUY8_2X8: 448 case MEDIA_BUS_FMT_YUYV8_2X8: 449 case MEDIA_BUS_FMT_YVYU8_2X8: 450 case MEDIA_BUS_FMT_Y10_1X10: 451 case MEDIA_BUS_FMT_UYVY10_2X10: 452 case MEDIA_BUS_FMT_VYUY10_2X10: 453 case MEDIA_BUS_FMT_YUYV10_2X10: 454 case MEDIA_BUS_FMT_YVYU10_2X10: 455 case MEDIA_BUS_FMT_Y12_1X12: 456 case MEDIA_BUS_FMT_UYVY12_2X12: 457 case MEDIA_BUS_FMT_VYUY12_2X12: 458 case MEDIA_BUS_FMT_YUYV12_2X12: 459 case MEDIA_BUS_FMT_YVYU12_2X12: 460 case MEDIA_BUS_FMT_UYVY8_1X16: 461 case MEDIA_BUS_FMT_VYUY8_1X16: 462 case MEDIA_BUS_FMT_YUYV8_1X16: 463 case MEDIA_BUS_FMT_YVYU8_1X16: 464 case MEDIA_BUS_FMT_YDYUYDYV8_1X16: 465 case MEDIA_BUS_FMT_UYVY10_1X20: 466 case MEDIA_BUS_FMT_VYUY10_1X20: 467 case MEDIA_BUS_FMT_YUYV10_1X20: 468 case MEDIA_BUS_FMT_YVYU10_1X20: 469 case MEDIA_BUS_FMT_VUY8_1X24: 470 case MEDIA_BUS_FMT_YUV8_1X24: 471 case MEDIA_BUS_FMT_UYYVYY8_0_5X24: 472 case MEDIA_BUS_FMT_UYVY12_1X24: 473 case MEDIA_BUS_FMT_VYUY12_1X24: 474 case MEDIA_BUS_FMT_YUYV12_1X24: 475 case MEDIA_BUS_FMT_YVYU12_1X24: 476 case MEDIA_BUS_FMT_YUV10_1X30: 477 case MEDIA_BUS_FMT_UYYVYY10_0_5X30: 478 case MEDIA_BUS_FMT_AYUV8_1X32: 479 case MEDIA_BUS_FMT_UYYVYY12_0_5X36: 480 case MEDIA_BUS_FMT_YUV12_1X36: 481 case MEDIA_BUS_FMT_YUV16_1X48: 482 case MEDIA_BUS_FMT_UYYVYY16_0_5X48: 483 case MEDIA_BUS_FMT_JPEG_1X8: 484 case MEDIA_BUS_FMT_AHSV8888_1X32: 485 case MEDIA_BUS_FMT_SBGGR8_1X8: 486 case MEDIA_BUS_FMT_SGBRG8_1X8: 487 case MEDIA_BUS_FMT_SGRBG8_1X8: 488 case MEDIA_BUS_FMT_SRGGB8_1X8: 489 case MEDIA_BUS_FMT_SBGGR10_1X10: 490 case MEDIA_BUS_FMT_SGBRG10_1X10: 491 case MEDIA_BUS_FMT_SGRBG10_1X10: 492 case MEDIA_BUS_FMT_SRGGB10_1X10: 493 case MEDIA_BUS_FMT_SBGGR12_1X12: 494 case MEDIA_BUS_FMT_SGBRG12_1X12: 495 case MEDIA_BUS_FMT_SGRBG12_1X12: 496 case MEDIA_BUS_FMT_SRGGB12_1X12: 497 case MEDIA_BUS_FMT_SBGGR14_1X14: 498 case MEDIA_BUS_FMT_SGBRG14_1X14: 499 case MEDIA_BUS_FMT_SGRBG14_1X14: 500 case MEDIA_BUS_FMT_SRGGB14_1X14: 501 case MEDIA_BUS_FMT_SBGGR16_1X16: 502 case MEDIA_BUS_FMT_SGBRG16_1X16: 503 case MEDIA_BUS_FMT_SGRBG16_1X16: 504 case MEDIA_BUS_FMT_SRGGB16_1X16: 505 break; 506 default: 507 format->format.code = MEDIA_BUS_FMT_Y8_1X8; 508 break; 509 } 510 511 if (format->format.field == V4L2_FIELD_ANY) 512 format->format.field = V4L2_FIELD_NONE; 513 514 mutex_lock(&csi->lock); 515 516 pad = &csi->pads[format->pad]; 517 if (pad->flags & MEDIA_PAD_FL_SOURCE) 518 format->format = csi->format_mbus[CSI_PAD_SINK]; 519 520 *mbusformat = format->format; 521 522 if (pad->flags & MEDIA_PAD_FL_SINK) 523 *source_mbusformat = format->format; 524 525 mutex_unlock(&csi->lock); 526 527 return 0; 528 } 529 530 static int mei_csi_g_volatile_ctrl(struct v4l2_ctrl *ctrl) 531 { 532 struct mei_csi *csi = ctrl_to_csi(ctrl); 533 s64 freq; 534 535 if (ctrl->id == V4L2_CID_LINK_FREQ) { 536 if (!csi->remote) 537 return -EINVAL; 538 539 freq = v4l2_get_link_freq(csi->remote->ctrl_handler, 0, 0); 540 if (freq < 0) { 541 dev_err(&csi->cldev->dev, 542 "error %lld, invalid link_freq\n", freq); 543 return -EINVAL; 544 } 545 546 link_freq_menu_items[0] = freq; 547 ctrl->val = 0; 548 549 return 0; 550 } 551 552 return -EINVAL; 553 } 554 555 static const struct v4l2_ctrl_ops mei_csi_ctrl_ops = { 556 .g_volatile_ctrl = mei_csi_g_volatile_ctrl, 557 }; 558 559 static const struct v4l2_subdev_video_ops mei_csi_video_ops = { 560 .s_stream = mei_csi_set_stream, 561 }; 562 563 static const struct v4l2_subdev_pad_ops mei_csi_pad_ops = { 564 .init_cfg = mei_csi_init_cfg, 565 .get_fmt = mei_csi_get_fmt, 566 .set_fmt = mei_csi_set_fmt, 567 }; 568 569 static const struct v4l2_subdev_ops mei_csi_subdev_ops = { 570 .video = &mei_csi_video_ops, 571 .pad = &mei_csi_pad_ops, 572 }; 573 574 static const struct media_entity_operations mei_csi_entity_ops = { 575 .link_validate = v4l2_subdev_link_validate, 576 }; 577 578 static int mei_csi_notify_bound(struct v4l2_async_notifier *notifier, 579 struct v4l2_subdev *subdev, 580 struct v4l2_async_connection *asd) 581 { 582 struct mei_csi *csi = notifier_to_csi(notifier); 583 int pad; 584 585 pad = media_entity_get_fwnode_pad(&subdev->entity, asd->match.fwnode, 586 MEDIA_PAD_FL_SOURCE); 587 if (pad < 0) 588 return pad; 589 590 csi->remote = subdev; 591 csi->remote_pad = pad; 592 593 return media_create_pad_link(&subdev->entity, pad, 594 &csi->subdev.entity, CSI_PAD_SINK, 595 MEDIA_LNK_FL_ENABLED | 596 MEDIA_LNK_FL_IMMUTABLE); 597 } 598 599 static void mei_csi_notify_unbind(struct v4l2_async_notifier *notifier, 600 struct v4l2_subdev *subdev, 601 struct v4l2_async_connection *asd) 602 { 603 struct mei_csi *csi = notifier_to_csi(notifier); 604 605 csi->remote = NULL; 606 } 607 608 static const struct v4l2_async_notifier_operations mei_csi_notify_ops = { 609 .bound = mei_csi_notify_bound, 610 .unbind = mei_csi_notify_unbind, 611 }; 612 613 static int mei_csi_init_controls(struct mei_csi *csi) 614 { 615 u32 max; 616 int ret; 617 618 mutex_init(&csi->ctrl_lock); 619 620 ret = v4l2_ctrl_handler_init(&csi->ctrl_handler, 2); 621 if (ret) 622 return ret; 623 624 csi->ctrl_handler.lock = &csi->ctrl_lock; 625 626 max = ARRAY_SIZE(link_freq_menu_items) - 1; 627 csi->freq_ctrl = v4l2_ctrl_new_int_menu(&csi->ctrl_handler, 628 &mei_csi_ctrl_ops, 629 V4L2_CID_LINK_FREQ, 630 max, 631 0, 632 link_freq_menu_items); 633 if (csi->freq_ctrl) 634 csi->freq_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY | 635 V4L2_CTRL_FLAG_VOLATILE; 636 637 csi->privacy_ctrl = v4l2_ctrl_new_std(&csi->ctrl_handler, NULL, 638 V4L2_CID_PRIVACY, 0, 1, 1, 0); 639 if (csi->privacy_ctrl) 640 csi->privacy_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; 641 642 if (csi->ctrl_handler.error) 643 return csi->ctrl_handler.error; 644 645 csi->subdev.ctrl_handler = &csi->ctrl_handler; 646 647 return 0; 648 } 649 650 static int mei_csi_parse_firmware(struct mei_csi *csi) 651 { 652 struct v4l2_fwnode_endpoint v4l2_ep = { 653 .bus_type = V4L2_MBUS_CSI2_DPHY, 654 }; 655 struct device *dev = &csi->cldev->dev; 656 struct v4l2_async_connection *asd; 657 struct fwnode_handle *fwnode; 658 struct fwnode_handle *ep; 659 int ret; 660 661 ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0); 662 if (!ep) { 663 dev_err(dev, "not connected to subdevice\n"); 664 return -EINVAL; 665 } 666 667 ret = v4l2_fwnode_endpoint_parse(ep, &v4l2_ep); 668 if (ret) { 669 dev_err(dev, "could not parse v4l2 endpoint\n"); 670 fwnode_handle_put(ep); 671 return -EINVAL; 672 } 673 674 fwnode = fwnode_graph_get_remote_endpoint(ep); 675 fwnode_handle_put(ep); 676 677 v4l2_async_subdev_nf_init(&csi->notifier, &csi->subdev); 678 csi->notifier.ops = &mei_csi_notify_ops; 679 680 asd = v4l2_async_nf_add_fwnode(&csi->notifier, fwnode, 681 struct v4l2_async_connection); 682 if (IS_ERR(asd)) { 683 fwnode_handle_put(fwnode); 684 return PTR_ERR(asd); 685 } 686 687 ret = v4l2_fwnode_endpoint_alloc_parse(fwnode, &v4l2_ep); 688 fwnode_handle_put(fwnode); 689 if (ret) 690 return ret; 691 csi->nr_of_lanes = v4l2_ep.bus.mipi_csi2.num_data_lanes; 692 693 ret = v4l2_async_nf_register(&csi->notifier); 694 if (ret) 695 v4l2_async_nf_cleanup(&csi->notifier); 696 697 v4l2_fwnode_endpoint_free(&v4l2_ep); 698 699 return ret; 700 } 701 702 static int mei_csi_probe(struct mei_cl_device *cldev, 703 const struct mei_cl_device_id *id) 704 { 705 struct device *dev = &cldev->dev; 706 struct mei_csi *csi; 707 int ret; 708 709 if (!dev_fwnode(dev)) 710 return -EPROBE_DEFER; 711 712 csi = devm_kzalloc(dev, sizeof(struct mei_csi), GFP_KERNEL); 713 if (!csi) 714 return -ENOMEM; 715 716 csi->cldev = cldev; 717 mutex_init(&csi->lock); 718 init_completion(&csi->cmd_completion); 719 720 mei_cldev_set_drvdata(cldev, csi); 721 722 ret = mei_cldev_enable(cldev); 723 if (ret < 0) { 724 dev_err(dev, "mei_cldev_enable failed: %d\n", ret); 725 goto destroy_mutex; 726 } 727 728 ret = mei_cldev_register_rx_cb(cldev, mei_csi_rx); 729 if (ret) { 730 dev_err(dev, "event cb registration failed: %d\n", ret); 731 goto err_disable; 732 } 733 734 ret = mei_csi_parse_firmware(csi); 735 if (ret) 736 goto err_disable; 737 738 csi->subdev.dev = &cldev->dev; 739 v4l2_subdev_init(&csi->subdev, &mei_csi_subdev_ops); 740 v4l2_set_subdevdata(&csi->subdev, csi); 741 csi->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE | 742 V4L2_SUBDEV_FL_HAS_EVENTS; 743 csi->subdev.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; 744 csi->subdev.entity.ops = &mei_csi_entity_ops; 745 746 snprintf(csi->subdev.name, sizeof(csi->subdev.name), 747 MEI_CSI_ENTITY_NAME); 748 749 ret = mei_csi_init_controls(csi); 750 if (ret) 751 goto err_ctrl_handler; 752 753 csi->format_mbus[CSI_PAD_SOURCE] = mei_csi_format_mbus_default; 754 csi->format_mbus[CSI_PAD_SINK] = mei_csi_format_mbus_default; 755 756 csi->pads[CSI_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; 757 csi->pads[CSI_PAD_SINK].flags = MEDIA_PAD_FL_SINK; 758 ret = media_entity_pads_init(&csi->subdev.entity, CSI_NUM_PADS, 759 csi->pads); 760 if (ret) 761 goto err_ctrl_handler; 762 763 ret = v4l2_subdev_init_finalize(&csi->subdev); 764 if (ret < 0) 765 goto err_entity; 766 767 ret = v4l2_async_register_subdev(&csi->subdev); 768 if (ret < 0) 769 goto err_subdev; 770 771 pm_runtime_enable(&cldev->dev); 772 773 return 0; 774 775 err_subdev: 776 v4l2_subdev_cleanup(&csi->subdev); 777 778 err_entity: 779 media_entity_cleanup(&csi->subdev.entity); 780 781 err_ctrl_handler: 782 v4l2_ctrl_handler_free(&csi->ctrl_handler); 783 mutex_destroy(&csi->ctrl_lock); 784 v4l2_async_nf_unregister(&csi->notifier); 785 v4l2_async_nf_cleanup(&csi->notifier); 786 787 err_disable: 788 mei_cldev_disable(cldev); 789 790 destroy_mutex: 791 mutex_destroy(&csi->lock); 792 793 return ret; 794 } 795 796 static void mei_csi_remove(struct mei_cl_device *cldev) 797 { 798 struct mei_csi *csi = mei_cldev_get_drvdata(cldev); 799 800 v4l2_async_nf_unregister(&csi->notifier); 801 v4l2_async_nf_cleanup(&csi->notifier); 802 v4l2_ctrl_handler_free(&csi->ctrl_handler); 803 mutex_destroy(&csi->ctrl_lock); 804 v4l2_async_unregister_subdev(&csi->subdev); 805 v4l2_subdev_cleanup(&csi->subdev); 806 media_entity_cleanup(&csi->subdev.entity); 807 808 pm_runtime_disable(&cldev->dev); 809 810 mutex_destroy(&csi->lock); 811 } 812 813 #define MEI_CSI_UUID UUID_LE(0x92335FCF, 0x3203, 0x4472, \ 814 0xAF, 0x93, 0x7b, 0x44, 0x53, 0xAC, 0x29, 0xDA) 815 816 static const struct mei_cl_device_id mei_csi_tbl[] = { 817 { MEI_CSI_DRIVER_NAME, MEI_CSI_UUID, MEI_CL_VERSION_ANY }, 818 { /* sentinel */ } 819 }; 820 MODULE_DEVICE_TABLE(mei, mei_csi_tbl); 821 822 static struct mei_cl_driver mei_csi_driver = { 823 .id_table = mei_csi_tbl, 824 .name = MEI_CSI_DRIVER_NAME, 825 826 .probe = mei_csi_probe, 827 .remove = mei_csi_remove, 828 }; 829 830 module_mei_cl_driver(mei_csi_driver); 831 832 MODULE_AUTHOR("Wentong Wu <wentong.wu@intel.com>"); 833 MODULE_AUTHOR("Zhifeng Wang <zhifeng.wang@intel.com>"); 834 MODULE_DESCRIPTION("Device driver for IVSC CSI"); 835 MODULE_LICENSE("GPL"); 836