1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2023 Intel Corporation. All rights reserved.
4 * Intel Visual Sensing Controller CSI Linux driver
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.
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/pci.h>
23 #include <linux/pm_runtime.h>
24 #include <linux/slab.h>
25 #include <linux/units.h>
26 #include <linux/uuid.h>
27 #include <linux/workqueue.h>
29 #include <media/ipu-bridge.h>
30 #include <media/ipu6-pci-table.h>
31 #include <media/v4l2-async.h>
32 #include <media/v4l2-ctrls.h>
33 #include <media/v4l2-fwnode.h>
34 #include <media/v4l2-subdev.h>
36 #define MEI_CSI_ENTITY_NAME "Intel IVSC CSI"
38 #define MEI_CSI_LINK_FREQ_400MHZ 400000000ULL
40 /* the 5s used here is based on experiment */
41 #define CSI_CMD_TIMEOUT (5 * HZ)
42 /* to setup CSI-2 link an extra delay needed and determined experimentally */
43 #define CSI_FW_READY_DELAY_MS 100
44 /* link frequency unit is 100kHz */
45 #define CSI_LINK_FREQ(x) ((u32)(div_u64(x, 100 * HZ_PER_KHZ)))
48 * identify the command id supported by firmware
49 * IPC, as well as the privacy notification id
50 * used when processing privacy event.
53 /* used to set csi ownership */
56 /* used to configure CSI-2 link */
59 /* privacy notification id used when privacy state changes */
60 CSI_PRIVACY_NOTIF
= 6,
63 /* CSI-2 link ownership definition */
69 /* privacy status definition */
70 enum ivsc_privacy_status
{
82 /* configuration of the CSI-2 link between host and IVSC */
84 /* number of data lanes used on the CSI-2 link */
87 /* frequency of the CSI-2 link */
94 /* CSI command structure */
99 struct csi_link_cfg conf
;
103 /* CSI notification structure */
109 struct csi_link_cfg conf
;
114 struct mei_cl_device
*cldev
;
116 /* command response */
117 struct csi_notif cmd_response
;
118 /* used to wait for command response from firmware */
119 struct completion cmd_completion
;
120 /* protect command download */
123 struct v4l2_subdev subdev
;
124 struct v4l2_subdev
*remote
;
125 struct v4l2_async_notifier notifier
;
126 struct v4l2_ctrl_handler ctrl_handler
;
127 struct v4l2_ctrl
*freq_ctrl
;
128 struct v4l2_ctrl
*privacy_ctrl
;
129 /* lock for v4l2 controls */
130 struct mutex ctrl_lock
;
131 unsigned int remote_pad
;
132 /* start streaming or not */
135 struct media_pad pads
[CSI_NUM_PADS
];
137 /* number of data lanes used on the CSI-2 link */
139 /* frequency of the CSI-2 link */
143 static const struct v4l2_mbus_framefmt mei_csi_format_mbus_default
= {
146 .code
= MEDIA_BUS_FMT_Y8_1X8
,
147 .field
= V4L2_FIELD_NONE
,
150 static s64 link_freq_menu_items
[] = {
151 MEI_CSI_LINK_FREQ_400MHZ
154 static inline struct mei_csi
*notifier_to_csi(struct v4l2_async_notifier
*n
)
156 return container_of(n
, struct mei_csi
, notifier
);
159 static inline struct mei_csi
*sd_to_csi(struct v4l2_subdev
*sd
)
161 return container_of(sd
, struct mei_csi
, subdev
);
164 static inline struct mei_csi
*ctrl_to_csi(struct v4l2_ctrl
*ctrl
)
166 return container_of(ctrl
->handler
, struct mei_csi
, ctrl_handler
);
169 /* send a command to firmware and mutex must be held by caller */
170 static int mei_csi_send(struct mei_csi
*csi
, u8
*buf
, size_t len
)
172 struct csi_cmd
*cmd
= (struct csi_cmd
*)buf
;
175 reinit_completion(&csi
->cmd_completion
);
177 ret
= mei_cldev_send(csi
->cldev
, buf
, len
);
181 ret
= wait_for_completion_killable_timeout(&csi
->cmd_completion
,
190 /* command response status */
191 ret
= csi
->cmd_response
.status
;
193 /* notify privacy on instead of reporting error */
195 v4l2_ctrl_s_ctrl(csi
->privacy_ctrl
, 1);
201 if (csi
->cmd_response
.cmd_id
!= cmd
->cmd_id
)
208 /* set CSI-2 link ownership */
209 static int csi_set_link_owner(struct mei_csi
*csi
, enum csi_link_owner owner
)
211 struct csi_cmd cmd
= { 0 };
215 cmd
.cmd_id
= CSI_SET_OWNER
;
216 cmd
.param
.param
= owner
;
217 cmd_size
= sizeof(cmd
.cmd_id
) + sizeof(cmd
.param
.param
);
219 mutex_lock(&csi
->lock
);
221 ret
= mei_csi_send(csi
, (u8
*)&cmd
, cmd_size
);
223 mutex_unlock(&csi
->lock
);
228 /* configure CSI-2 link between host and IVSC */
229 static int csi_set_link_cfg(struct mei_csi
*csi
)
231 struct csi_cmd cmd
= { 0 };
235 cmd
.cmd_id
= CSI_SET_CONF
;
236 cmd
.param
.conf
.nr_of_lanes
= csi
->nr_of_lanes
;
237 cmd
.param
.conf
.link_freq
= CSI_LINK_FREQ(csi
->link_freq
);
238 cmd_size
= sizeof(cmd
.cmd_id
) + sizeof(cmd
.param
.conf
);
240 mutex_lock(&csi
->lock
);
242 ret
= mei_csi_send(csi
, (u8
*)&cmd
, cmd_size
);
244 * wait configuration ready if download success. placing
245 * delay under mutex is to make sure current command flow
246 * completed before starting a possible new one.
249 msleep(CSI_FW_READY_DELAY_MS
);
251 mutex_unlock(&csi
->lock
);
256 /* callback for receive */
257 static void mei_csi_rx(struct mei_cl_device
*cldev
)
259 struct mei_csi
*csi
= mei_cldev_get_drvdata(cldev
);
260 struct csi_notif notif
= { 0 };
263 ret
= mei_cldev_recv(cldev
, (u8
*)¬if
, sizeof(notif
));
265 dev_err(&cldev
->dev
, "recv error: %d\n", ret
);
269 switch (notif
.cmd_id
) {
270 case CSI_PRIVACY_NOTIF
:
271 if (notif
.cont
.cont
< CSI_PRIVACY_MAX
)
272 v4l2_ctrl_s_ctrl(csi
->privacy_ctrl
,
273 notif
.cont
.cont
== CSI_PRIVACY_ON
);
277 memcpy(&csi
->cmd_response
, ¬if
, ret
);
279 complete(&csi
->cmd_completion
);
286 static int mei_csi_set_stream(struct v4l2_subdev
*sd
, int enable
)
288 struct mei_csi
*csi
= sd_to_csi(sd
);
292 if (enable
&& csi
->streaming
== 0) {
293 freq
= v4l2_get_link_freq(csi
->remote
->ctrl_handler
, 0, 0);
295 dev_err(&csi
->cldev
->dev
,
296 "error %lld, invalid link_freq\n", freq
);
300 csi
->link_freq
= freq
;
302 /* switch CSI-2 link to host */
303 ret
= csi_set_link_owner(csi
, CSI_LINK_HOST
);
307 /* configure CSI-2 link */
308 ret
= csi_set_link_cfg(csi
);
312 ret
= v4l2_subdev_call(csi
->remote
, video
, s_stream
, 1);
315 } else if (!enable
&& csi
->streaming
== 1) {
316 v4l2_subdev_call(csi
->remote
, video
, s_stream
, 0);
318 /* switch CSI-2 link to IVSC */
319 ret
= csi_set_link_owner(csi
, CSI_LINK_IVSC
);
321 dev_warn(&csi
->cldev
->dev
,
322 "failed to switch CSI2 link: %d\n", ret
);
325 csi
->streaming
= enable
;
330 csi_set_link_owner(csi
, CSI_LINK_IVSC
);
336 static int mei_csi_init_state(struct v4l2_subdev
*sd
,
337 struct v4l2_subdev_state
*sd_state
)
339 struct v4l2_mbus_framefmt
*mbusformat
;
342 for (i
= 0; i
< sd
->entity
.num_pads
; i
++) {
343 mbusformat
= v4l2_subdev_state_get_format(sd_state
, i
);
344 *mbusformat
= mei_csi_format_mbus_default
;
350 static int mei_csi_set_fmt(struct v4l2_subdev
*sd
,
351 struct v4l2_subdev_state
*sd_state
,
352 struct v4l2_subdev_format
*format
)
354 struct v4l2_mbus_framefmt
*source_fmt
;
355 struct v4l2_mbus_framefmt
*sink_fmt
;
357 sink_fmt
= v4l2_subdev_state_get_format(sd_state
, CSI_PAD_SINK
);
358 source_fmt
= v4l2_subdev_state_get_format(sd_state
, CSI_PAD_SOURCE
);
361 *source_fmt
= *sink_fmt
;
366 v4l_bound_align_image(&format
->format
.width
, 1, 65536, 0,
367 &format
->format
.height
, 1, 65536, 0, 0);
369 switch (format
->format
.code
) {
370 case MEDIA_BUS_FMT_RGB444_1X12
:
371 case MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE
:
372 case MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE
:
373 case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE
:
374 case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE
:
375 case MEDIA_BUS_FMT_RGB565_1X16
:
376 case MEDIA_BUS_FMT_BGR565_2X8_BE
:
377 case MEDIA_BUS_FMT_BGR565_2X8_LE
:
378 case MEDIA_BUS_FMT_RGB565_2X8_BE
:
379 case MEDIA_BUS_FMT_RGB565_2X8_LE
:
380 case MEDIA_BUS_FMT_RGB666_1X18
:
381 case MEDIA_BUS_FMT_RBG888_1X24
:
382 case MEDIA_BUS_FMT_RGB666_1X24_CPADHI
:
383 case MEDIA_BUS_FMT_BGR888_1X24
:
384 case MEDIA_BUS_FMT_GBR888_1X24
:
385 case MEDIA_BUS_FMT_RGB888_1X24
:
386 case MEDIA_BUS_FMT_RGB888_2X12_BE
:
387 case MEDIA_BUS_FMT_RGB888_2X12_LE
:
388 case MEDIA_BUS_FMT_ARGB8888_1X32
:
389 case MEDIA_BUS_FMT_RGB888_1X32_PADHI
:
390 case MEDIA_BUS_FMT_RGB101010_1X30
:
391 case MEDIA_BUS_FMT_RGB121212_1X36
:
392 case MEDIA_BUS_FMT_RGB161616_1X48
:
393 case MEDIA_BUS_FMT_Y8_1X8
:
394 case MEDIA_BUS_FMT_UV8_1X8
:
395 case MEDIA_BUS_FMT_UYVY8_1_5X8
:
396 case MEDIA_BUS_FMT_VYUY8_1_5X8
:
397 case MEDIA_BUS_FMT_YUYV8_1_5X8
:
398 case MEDIA_BUS_FMT_YVYU8_1_5X8
:
399 case MEDIA_BUS_FMT_UYVY8_2X8
:
400 case MEDIA_BUS_FMT_VYUY8_2X8
:
401 case MEDIA_BUS_FMT_YUYV8_2X8
:
402 case MEDIA_BUS_FMT_YVYU8_2X8
:
403 case MEDIA_BUS_FMT_Y10_1X10
:
404 case MEDIA_BUS_FMT_UYVY10_2X10
:
405 case MEDIA_BUS_FMT_VYUY10_2X10
:
406 case MEDIA_BUS_FMT_YUYV10_2X10
:
407 case MEDIA_BUS_FMT_YVYU10_2X10
:
408 case MEDIA_BUS_FMT_Y12_1X12
:
409 case MEDIA_BUS_FMT_UYVY12_2X12
:
410 case MEDIA_BUS_FMT_VYUY12_2X12
:
411 case MEDIA_BUS_FMT_YUYV12_2X12
:
412 case MEDIA_BUS_FMT_YVYU12_2X12
:
413 case MEDIA_BUS_FMT_UYVY8_1X16
:
414 case MEDIA_BUS_FMT_VYUY8_1X16
:
415 case MEDIA_BUS_FMT_YUYV8_1X16
:
416 case MEDIA_BUS_FMT_YVYU8_1X16
:
417 case MEDIA_BUS_FMT_YDYUYDYV8_1X16
:
418 case MEDIA_BUS_FMT_UYVY10_1X20
:
419 case MEDIA_BUS_FMT_VYUY10_1X20
:
420 case MEDIA_BUS_FMT_YUYV10_1X20
:
421 case MEDIA_BUS_FMT_YVYU10_1X20
:
422 case MEDIA_BUS_FMT_VUY8_1X24
:
423 case MEDIA_BUS_FMT_YUV8_1X24
:
424 case MEDIA_BUS_FMT_UYYVYY8_0_5X24
:
425 case MEDIA_BUS_FMT_UYVY12_1X24
:
426 case MEDIA_BUS_FMT_VYUY12_1X24
:
427 case MEDIA_BUS_FMT_YUYV12_1X24
:
428 case MEDIA_BUS_FMT_YVYU12_1X24
:
429 case MEDIA_BUS_FMT_YUV10_1X30
:
430 case MEDIA_BUS_FMT_UYYVYY10_0_5X30
:
431 case MEDIA_BUS_FMT_AYUV8_1X32
:
432 case MEDIA_BUS_FMT_UYYVYY12_0_5X36
:
433 case MEDIA_BUS_FMT_YUV12_1X36
:
434 case MEDIA_BUS_FMT_YUV16_1X48
:
435 case MEDIA_BUS_FMT_UYYVYY16_0_5X48
:
436 case MEDIA_BUS_FMT_JPEG_1X8
:
437 case MEDIA_BUS_FMT_AHSV8888_1X32
:
438 case MEDIA_BUS_FMT_SBGGR8_1X8
:
439 case MEDIA_BUS_FMT_SGBRG8_1X8
:
440 case MEDIA_BUS_FMT_SGRBG8_1X8
:
441 case MEDIA_BUS_FMT_SRGGB8_1X8
:
442 case MEDIA_BUS_FMT_SBGGR10_1X10
:
443 case MEDIA_BUS_FMT_SGBRG10_1X10
:
444 case MEDIA_BUS_FMT_SGRBG10_1X10
:
445 case MEDIA_BUS_FMT_SRGGB10_1X10
:
446 case MEDIA_BUS_FMT_SBGGR12_1X12
:
447 case MEDIA_BUS_FMT_SGBRG12_1X12
:
448 case MEDIA_BUS_FMT_SGRBG12_1X12
:
449 case MEDIA_BUS_FMT_SRGGB12_1X12
:
450 case MEDIA_BUS_FMT_SBGGR14_1X14
:
451 case MEDIA_BUS_FMT_SGBRG14_1X14
:
452 case MEDIA_BUS_FMT_SGRBG14_1X14
:
453 case MEDIA_BUS_FMT_SRGGB14_1X14
:
454 case MEDIA_BUS_FMT_SBGGR16_1X16
:
455 case MEDIA_BUS_FMT_SGBRG16_1X16
:
456 case MEDIA_BUS_FMT_SGRBG16_1X16
:
457 case MEDIA_BUS_FMT_SRGGB16_1X16
:
460 format
->format
.code
= MEDIA_BUS_FMT_Y8_1X8
;
464 if (format
->format
.field
== V4L2_FIELD_ANY
)
465 format
->format
.field
= V4L2_FIELD_NONE
;
467 *sink_fmt
= format
->format
;
468 *source_fmt
= *sink_fmt
;
473 static int mei_csi_g_volatile_ctrl(struct v4l2_ctrl
*ctrl
)
475 struct mei_csi
*csi
= ctrl_to_csi(ctrl
);
478 if (ctrl
->id
== V4L2_CID_LINK_FREQ
) {
482 freq
= v4l2_get_link_freq(csi
->remote
->ctrl_handler
, 0, 0);
484 dev_err(&csi
->cldev
->dev
,
485 "error %lld, invalid link_freq\n", freq
);
489 link_freq_menu_items
[0] = freq
;
498 static const struct v4l2_ctrl_ops mei_csi_ctrl_ops
= {
499 .g_volatile_ctrl
= mei_csi_g_volatile_ctrl
,
502 static const struct v4l2_subdev_video_ops mei_csi_video_ops
= {
503 .s_stream
= mei_csi_set_stream
,
506 static const struct v4l2_subdev_pad_ops mei_csi_pad_ops
= {
507 .get_fmt
= v4l2_subdev_get_fmt
,
508 .set_fmt
= mei_csi_set_fmt
,
511 static const struct v4l2_subdev_ops mei_csi_subdev_ops
= {
512 .video
= &mei_csi_video_ops
,
513 .pad
= &mei_csi_pad_ops
,
516 static const struct v4l2_subdev_internal_ops mei_csi_internal_ops
= {
517 .init_state
= mei_csi_init_state
,
520 static const struct media_entity_operations mei_csi_entity_ops
= {
521 .link_validate
= v4l2_subdev_link_validate
,
524 static int mei_csi_notify_bound(struct v4l2_async_notifier
*notifier
,
525 struct v4l2_subdev
*subdev
,
526 struct v4l2_async_connection
*asd
)
528 struct mei_csi
*csi
= notifier_to_csi(notifier
);
531 pad
= media_entity_get_fwnode_pad(&subdev
->entity
, asd
->match
.fwnode
,
532 MEDIA_PAD_FL_SOURCE
);
536 csi
->remote
= subdev
;
537 csi
->remote_pad
= pad
;
539 return media_create_pad_link(&subdev
->entity
, pad
,
540 &csi
->subdev
.entity
, CSI_PAD_SINK
,
541 MEDIA_LNK_FL_ENABLED
|
542 MEDIA_LNK_FL_IMMUTABLE
);
545 static void mei_csi_notify_unbind(struct v4l2_async_notifier
*notifier
,
546 struct v4l2_subdev
*subdev
,
547 struct v4l2_async_connection
*asd
)
549 struct mei_csi
*csi
= notifier_to_csi(notifier
);
554 static const struct v4l2_async_notifier_operations mei_csi_notify_ops
= {
555 .bound
= mei_csi_notify_bound
,
556 .unbind
= mei_csi_notify_unbind
,
559 static int mei_csi_init_controls(struct mei_csi
*csi
)
564 mutex_init(&csi
->ctrl_lock
);
566 ret
= v4l2_ctrl_handler_init(&csi
->ctrl_handler
, 2);
570 csi
->ctrl_handler
.lock
= &csi
->ctrl_lock
;
572 max
= ARRAY_SIZE(link_freq_menu_items
) - 1;
573 csi
->freq_ctrl
= v4l2_ctrl_new_int_menu(&csi
->ctrl_handler
,
578 link_freq_menu_items
);
580 csi
->freq_ctrl
->flags
|= V4L2_CTRL_FLAG_READ_ONLY
|
581 V4L2_CTRL_FLAG_VOLATILE
;
583 csi
->privacy_ctrl
= v4l2_ctrl_new_std(&csi
->ctrl_handler
, NULL
,
584 V4L2_CID_PRIVACY
, 0, 1, 1, 0);
585 if (csi
->privacy_ctrl
)
586 csi
->privacy_ctrl
->flags
|= V4L2_CTRL_FLAG_READ_ONLY
;
588 if (csi
->ctrl_handler
.error
)
589 return csi
->ctrl_handler
.error
;
591 csi
->subdev
.ctrl_handler
= &csi
->ctrl_handler
;
596 static int mei_csi_parse_firmware(struct mei_csi
*csi
)
598 struct v4l2_fwnode_endpoint v4l2_ep
= {
599 .bus_type
= V4L2_MBUS_CSI2_DPHY
,
601 struct device
*dev
= &csi
->cldev
->dev
;
602 struct v4l2_async_connection
*asd
;
603 struct fwnode_handle
*sink_ep
, *source_ep
;
606 sink_ep
= fwnode_graph_get_endpoint_by_id(dev_fwnode(dev
), 0, 0, 0);
608 dev_err(dev
, "can't obtain sink endpoint\n");
612 v4l2_async_subdev_nf_init(&csi
->notifier
, &csi
->subdev
);
613 csi
->notifier
.ops
= &mei_csi_notify_ops
;
615 ret
= v4l2_fwnode_endpoint_parse(sink_ep
, &v4l2_ep
);
617 dev_err(dev
, "could not parse v4l2 sink endpoint\n");
621 csi
->nr_of_lanes
= v4l2_ep
.bus
.mipi_csi2
.num_data_lanes
;
623 source_ep
= fwnode_graph_get_endpoint_by_id(dev_fwnode(dev
), 1, 0, 0);
626 dev_err(dev
, "can't obtain source endpoint\n");
630 ret
= v4l2_fwnode_endpoint_parse(source_ep
, &v4l2_ep
);
631 fwnode_handle_put(source_ep
);
633 dev_err(dev
, "could not parse v4l2 source endpoint\n");
637 if (csi
->nr_of_lanes
!= v4l2_ep
.bus
.mipi_csi2
.num_data_lanes
) {
640 "the number of lanes does not match (%u vs. %u)\n",
641 csi
->nr_of_lanes
, v4l2_ep
.bus
.mipi_csi2
.num_data_lanes
);
645 asd
= v4l2_async_nf_add_fwnode_remote(&csi
->notifier
, sink_ep
,
646 struct v4l2_async_connection
);
652 ret
= v4l2_async_nf_register(&csi
->notifier
);
656 fwnode_handle_put(sink_ep
);
661 v4l2_async_nf_cleanup(&csi
->notifier
);
662 fwnode_handle_put(sink_ep
);
667 static int mei_csi_probe(struct mei_cl_device
*cldev
,
668 const struct mei_cl_device_id
*id
)
670 struct device
*dev
= &cldev
->dev
;
676 for (i
= 0, ipu
= NULL
; !ipu
&& ipu6_pci_tbl
[i
].vendor
; i
++)
677 ipu
= pci_get_device(ipu6_pci_tbl
[i
].vendor
,
678 ipu6_pci_tbl
[i
].device
, NULL
);
683 ret
= ipu_bridge_init(&ipu
->dev
, ipu_bridge_parse_ssdb
);
684 put_device(&ipu
->dev
);
687 if (!dev_fwnode(dev
)) {
688 dev_err(dev
, "mei-csi probed without device fwnode!\n");
692 csi
= devm_kzalloc(dev
, sizeof(struct mei_csi
), GFP_KERNEL
);
697 mutex_init(&csi
->lock
);
698 init_completion(&csi
->cmd_completion
);
700 mei_cldev_set_drvdata(cldev
, csi
);
702 ret
= mei_cldev_enable(cldev
);
704 dev_err(dev
, "mei_cldev_enable failed: %d\n", ret
);
708 ret
= mei_cldev_register_rx_cb(cldev
, mei_csi_rx
);
710 dev_err(dev
, "event cb registration failed: %d\n", ret
);
714 ret
= mei_csi_parse_firmware(csi
);
718 csi
->subdev
.dev
= &cldev
->dev
;
719 csi
->subdev
.state_lock
= &csi
->lock
;
720 v4l2_subdev_init(&csi
->subdev
, &mei_csi_subdev_ops
);
721 csi
->subdev
.internal_ops
= &mei_csi_internal_ops
;
722 v4l2_set_subdevdata(&csi
->subdev
, csi
);
723 csi
->subdev
.flags
= V4L2_SUBDEV_FL_HAS_DEVNODE
|
724 V4L2_SUBDEV_FL_HAS_EVENTS
;
725 csi
->subdev
.entity
.function
= MEDIA_ENT_F_VID_IF_BRIDGE
;
726 csi
->subdev
.entity
.ops
= &mei_csi_entity_ops
;
728 snprintf(csi
->subdev
.name
, sizeof(csi
->subdev
.name
),
729 MEI_CSI_ENTITY_NAME
);
731 ret
= mei_csi_init_controls(csi
);
733 goto err_ctrl_handler
;
735 csi
->pads
[CSI_PAD_SOURCE
].flags
= MEDIA_PAD_FL_SOURCE
;
736 csi
->pads
[CSI_PAD_SINK
].flags
= MEDIA_PAD_FL_SINK
;
737 ret
= media_entity_pads_init(&csi
->subdev
.entity
, CSI_NUM_PADS
,
740 goto err_ctrl_handler
;
742 ret
= v4l2_subdev_init_finalize(&csi
->subdev
);
746 ret
= v4l2_async_register_subdev(&csi
->subdev
);
750 pm_runtime_enable(&cldev
->dev
);
755 v4l2_subdev_cleanup(&csi
->subdev
);
758 media_entity_cleanup(&csi
->subdev
.entity
);
761 v4l2_ctrl_handler_free(&csi
->ctrl_handler
);
762 mutex_destroy(&csi
->ctrl_lock
);
763 v4l2_async_nf_unregister(&csi
->notifier
);
764 v4l2_async_nf_cleanup(&csi
->notifier
);
767 mei_cldev_disable(cldev
);
770 mutex_destroy(&csi
->lock
);
775 static void mei_csi_remove(struct mei_cl_device
*cldev
)
777 struct mei_csi
*csi
= mei_cldev_get_drvdata(cldev
);
779 v4l2_async_nf_unregister(&csi
->notifier
);
780 v4l2_async_nf_cleanup(&csi
->notifier
);
781 v4l2_ctrl_handler_free(&csi
->ctrl_handler
);
782 mutex_destroy(&csi
->ctrl_lock
);
783 v4l2_async_unregister_subdev(&csi
->subdev
);
784 v4l2_subdev_cleanup(&csi
->subdev
);
785 media_entity_cleanup(&csi
->subdev
.entity
);
787 pm_runtime_disable(&cldev
->dev
);
789 mutex_destroy(&csi
->lock
);
792 #define MEI_CSI_UUID UUID_LE(0x92335FCF, 0x3203, 0x4472, \
793 0xAF, 0x93, 0x7b, 0x44, 0x53, 0xAC, 0x29, 0xDA)
795 static const struct mei_cl_device_id mei_csi_tbl
[] = {
796 { .uuid
= MEI_CSI_UUID
, .version
= MEI_CL_VERSION_ANY
},
799 MODULE_DEVICE_TABLE(mei
, mei_csi_tbl
);
801 static struct mei_cl_driver mei_csi_driver
= {
802 .id_table
= mei_csi_tbl
,
803 .name
= KBUILD_MODNAME
,
805 .probe
= mei_csi_probe
,
806 .remove
= mei_csi_remove
,
809 module_mei_cl_driver(mei_csi_driver
);
811 MODULE_IMPORT_NS("INTEL_IPU_BRIDGE");
812 MODULE_AUTHOR("Wentong Wu <wentong.wu@intel.com>");
813 MODULE_AUTHOR("Zhifeng Wang <zhifeng.wang@intel.com>");
814 MODULE_DESCRIPTION("Device driver for IVSC CSI");
815 MODULE_LICENSE("GPL");