Merge tag 'clk-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux.git] / drivers / media / pci / intel / ivsc / mei_csi.c
blob6a893c4547b28da1f710ad6a9a6199ad3d442c5d
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 */
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.
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.
52 enum csi_cmd_id {
53 /* used to set csi ownership */
54 CSI_SET_OWNER = 0,
56 /* used to configure CSI-2 link */
57 CSI_SET_CONF = 2,
59 /* privacy notification id used when privacy state changes */
60 CSI_PRIVACY_NOTIF = 6,
63 /* CSI-2 link ownership definition */
64 enum csi_link_owner {
65 CSI_LINK_IVSC,
66 CSI_LINK_HOST,
69 /* privacy status definition */
70 enum ivsc_privacy_status {
71 CSI_PRIVACY_OFF,
72 CSI_PRIVACY_ON,
73 CSI_PRIVACY_MAX,
76 enum csi_pads {
77 CSI_PAD_SINK,
78 CSI_PAD_SOURCE,
79 CSI_NUM_PADS
82 /* configuration of the CSI-2 link between host and IVSC */
83 struct csi_link_cfg {
84 /* number of data lanes used on the CSI-2 link */
85 u32 nr_of_lanes;
87 /* frequency of the CSI-2 link */
88 u32 link_freq;
90 /* for future use */
91 u32 rsvd[2];
92 } __packed;
94 /* CSI command structure */
95 struct csi_cmd {
96 u32 cmd_id;
97 union _cmd_param {
98 u32 param;
99 struct csi_link_cfg conf;
100 } param;
101 } __packed;
103 /* CSI notification structure */
104 struct csi_notif {
105 u32 cmd_id;
106 int status;
107 union _resp_cont {
108 u32 cont;
109 struct csi_link_cfg conf;
110 } cont;
111 } __packed;
113 struct mei_csi {
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 */
121 struct mutex lock;
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 */
133 int streaming;
135 struct media_pad pads[CSI_NUM_PADS];
137 /* number of data lanes used on the CSI-2 link */
138 u32 nr_of_lanes;
139 /* frequency of the CSI-2 link */
140 u64 link_freq;
143 static const struct v4l2_mbus_framefmt mei_csi_format_mbus_default = {
144 .width = 1,
145 .height = 1,
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;
173 int ret;
175 reinit_completion(&csi->cmd_completion);
177 ret = mei_cldev_send(csi->cldev, buf, len);
178 if (ret < 0)
179 goto out;
181 ret = wait_for_completion_killable_timeout(&csi->cmd_completion,
182 CSI_CMD_TIMEOUT);
183 if (ret < 0) {
184 goto out;
185 } else if (!ret) {
186 ret = -ETIMEDOUT;
187 goto out;
190 /* command response status */
191 ret = csi->cmd_response.status;
192 if (ret == -1) {
193 /* notify privacy on instead of reporting error */
194 ret = 0;
195 v4l2_ctrl_s_ctrl(csi->privacy_ctrl, 1);
196 } else if (ret) {
197 ret = -EINVAL;
198 goto out;
201 if (csi->cmd_response.cmd_id != cmd->cmd_id)
202 ret = -EINVAL;
204 out:
205 return ret;
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 };
212 size_t cmd_size;
213 int ret;
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);
225 return ret;
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 };
232 size_t cmd_size;
233 int ret;
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.
248 if (!ret)
249 msleep(CSI_FW_READY_DELAY_MS);
251 mutex_unlock(&csi->lock);
253 return ret;
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 };
261 int ret;
263 ret = mei_cldev_recv(cldev, (u8 *)&notif, sizeof(notif));
264 if (ret < 0) {
265 dev_err(&cldev->dev, "recv error: %d\n", ret);
266 return;
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);
274 break;
275 case CSI_SET_OWNER:
276 case CSI_SET_CONF:
277 memcpy(&csi->cmd_response, &notif, ret);
279 complete(&csi->cmd_completion);
280 break;
281 default:
282 break;
286 static int mei_csi_set_stream(struct v4l2_subdev *sd, int enable)
288 struct mei_csi *csi = sd_to_csi(sd);
289 s64 freq;
290 int ret;
292 if (enable && csi->streaming == 0) {
293 freq = v4l2_get_link_freq(csi->remote->ctrl_handler, 0, 0);
294 if (freq < 0) {
295 dev_err(&csi->cldev->dev,
296 "error %lld, invalid link_freq\n", freq);
297 ret = freq;
298 goto err;
300 csi->link_freq = freq;
302 /* switch CSI-2 link to host */
303 ret = csi_set_link_owner(csi, CSI_LINK_HOST);
304 if (ret < 0)
305 goto err;
307 /* configure CSI-2 link */
308 ret = csi_set_link_cfg(csi);
309 if (ret < 0)
310 goto err_switch;
312 ret = v4l2_subdev_call(csi->remote, video, s_stream, 1);
313 if (ret)
314 goto err_switch;
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);
320 if (ret < 0)
321 dev_warn(&csi->cldev->dev,
322 "failed to switch CSI2 link: %d\n", ret);
325 csi->streaming = enable;
327 return 0;
329 err_switch:
330 csi_set_link_owner(csi, CSI_LINK_IVSC);
332 err:
333 return ret;
336 static int mei_csi_init_state(struct v4l2_subdev *sd,
337 struct v4l2_subdev_state *sd_state)
339 struct v4l2_mbus_framefmt *mbusformat;
340 unsigned int i;
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;
347 return 0;
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);
360 if (format->pad) {
361 *source_fmt = *sink_fmt;
363 return 0;
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:
458 break;
459 default:
460 format->format.code = MEDIA_BUS_FMT_Y8_1X8;
461 break;
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;
470 return 0;
473 static int mei_csi_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
475 struct mei_csi *csi = ctrl_to_csi(ctrl);
476 s64 freq;
478 if (ctrl->id == V4L2_CID_LINK_FREQ) {
479 if (!csi->remote)
480 return -EINVAL;
482 freq = v4l2_get_link_freq(csi->remote->ctrl_handler, 0, 0);
483 if (freq < 0) {
484 dev_err(&csi->cldev->dev,
485 "error %lld, invalid link_freq\n", freq);
486 return -EINVAL;
489 link_freq_menu_items[0] = freq;
490 ctrl->val = 0;
492 return 0;
495 return -EINVAL;
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);
529 int pad;
531 pad = media_entity_get_fwnode_pad(&subdev->entity, asd->match.fwnode,
532 MEDIA_PAD_FL_SOURCE);
533 if (pad < 0)
534 return pad;
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);
551 csi->remote = NULL;
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)
561 u32 max;
562 int ret;
564 mutex_init(&csi->ctrl_lock);
566 ret = v4l2_ctrl_handler_init(&csi->ctrl_handler, 2);
567 if (ret)
568 return ret;
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,
574 &mei_csi_ctrl_ops,
575 V4L2_CID_LINK_FREQ,
576 max,
578 link_freq_menu_items);
579 if (csi->freq_ctrl)
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;
593 return 0;
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;
604 int ret;
606 sink_ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0);
607 if (!sink_ep) {
608 dev_err(dev, "can't obtain sink endpoint\n");
609 return -EINVAL;
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);
616 if (ret) {
617 dev_err(dev, "could not parse v4l2 sink endpoint\n");
618 goto out_nf_cleanup;
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);
624 if (!source_ep) {
625 ret = -ENOTCONN;
626 dev_err(dev, "can't obtain source endpoint\n");
627 goto out_nf_cleanup;
630 ret = v4l2_fwnode_endpoint_parse(source_ep, &v4l2_ep);
631 fwnode_handle_put(source_ep);
632 if (ret) {
633 dev_err(dev, "could not parse v4l2 source endpoint\n");
634 goto out_nf_cleanup;
637 if (csi->nr_of_lanes != v4l2_ep.bus.mipi_csi2.num_data_lanes) {
638 ret = -EINVAL;
639 dev_err(dev,
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);
642 goto out_nf_cleanup;
645 asd = v4l2_async_nf_add_fwnode_remote(&csi->notifier, sink_ep,
646 struct v4l2_async_connection);
647 if (IS_ERR(asd)) {
648 ret = PTR_ERR(asd);
649 goto out_nf_cleanup;
652 ret = v4l2_async_nf_register(&csi->notifier);
653 if (ret)
654 goto out_nf_cleanup;
656 fwnode_handle_put(sink_ep);
658 return 0;
660 out_nf_cleanup:
661 v4l2_async_nf_cleanup(&csi->notifier);
662 fwnode_handle_put(sink_ep);
664 return ret;
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;
671 struct pci_dev *ipu;
672 struct mei_csi *csi;
673 unsigned int i;
674 int ret;
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);
680 if (!ipu)
681 return -ENODEV;
683 ret = ipu_bridge_init(&ipu->dev, ipu_bridge_parse_ssdb);
684 put_device(&ipu->dev);
685 if (ret < 0)
686 return ret;
687 if (!dev_fwnode(dev)) {
688 dev_err(dev, "mei-csi probed without device fwnode!\n");
689 return -ENXIO;
692 csi = devm_kzalloc(dev, sizeof(struct mei_csi), GFP_KERNEL);
693 if (!csi)
694 return -ENOMEM;
696 csi->cldev = cldev;
697 mutex_init(&csi->lock);
698 init_completion(&csi->cmd_completion);
700 mei_cldev_set_drvdata(cldev, csi);
702 ret = mei_cldev_enable(cldev);
703 if (ret < 0) {
704 dev_err(dev, "mei_cldev_enable failed: %d\n", ret);
705 goto destroy_mutex;
708 ret = mei_cldev_register_rx_cb(cldev, mei_csi_rx);
709 if (ret) {
710 dev_err(dev, "event cb registration failed: %d\n", ret);
711 goto err_disable;
714 ret = mei_csi_parse_firmware(csi);
715 if (ret)
716 goto err_disable;
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);
732 if (ret)
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,
738 csi->pads);
739 if (ret)
740 goto err_ctrl_handler;
742 ret = v4l2_subdev_init_finalize(&csi->subdev);
743 if (ret < 0)
744 goto err_entity;
746 ret = v4l2_async_register_subdev(&csi->subdev);
747 if (ret < 0)
748 goto err_subdev;
750 pm_runtime_enable(&cldev->dev);
752 return 0;
754 err_subdev:
755 v4l2_subdev_cleanup(&csi->subdev);
757 err_entity:
758 media_entity_cleanup(&csi->subdev.entity);
760 err_ctrl_handler:
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);
766 err_disable:
767 mei_cldev_disable(cldev);
769 destroy_mutex:
770 mutex_destroy(&csi->lock);
772 return ret;
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 },
797 { /* sentinel */ }
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");