hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/drivers/staging/media/imx/imx6-mipi-csi2.c
....@@ -1,12 +1,8 @@
1
+// SPDX-License-Identifier: GPL-2.0+
12 /*
23 * MIPI CSI-2 Receiver Subdev for Freescale i.MX6 SOC.
34 *
45 * Copyright (c) 2012-2017 Mentor Graphics Inc.
5
- *
6
- * This program is free software; you can redistribute it and/or modify
7
- * it under the terms of the GNU General Public License as published by
8
- * the Free Software Foundation; either version 2 of the License, or
9
- * (at your option) any later version.
106 */
117 #include <linux/clk.h>
128 #include <linux/interrupt.h>
....@@ -18,6 +14,7 @@
1814 #include <linux/platform_device.h>
1915 #include <media/v4l2-device.h>
2016 #include <media/v4l2-fwnode.h>
17
+#include <media/v4l2-mc.h>
2118 #include <media/v4l2-subdev.h>
2219 #include "imx-media.h"
2320
....@@ -39,6 +36,7 @@
3936 struct csi2_dev {
4037 struct device *dev;
4138 struct v4l2_subdev sd;
39
+ struct v4l2_async_notifier notifier;
4240 struct media_pad pad[CSI2_NUM_PADS];
4341 struct clk *dphy_clk;
4442 struct clk *pllref_clk;
....@@ -92,6 +90,11 @@
9290 static inline struct csi2_dev *sd_to_dev(struct v4l2_subdev *sdev)
9391 {
9492 return container_of(sdev, struct csi2_dev, sd);
93
+}
94
+
95
+static inline struct csi2_dev *notifier_to_dev(struct v4l2_async_notifier *n)
96
+{
97
+ return container_of(n, struct csi2_dev, notifier);
9598 }
9699
97100 /*
....@@ -501,31 +504,19 @@
501504 return ret;
502505 }
503506
504
-/*
505
- * retrieve our pads parsed from the OF graph by the media device
506
- */
507507 static int csi2_registered(struct v4l2_subdev *sd)
508508 {
509509 struct csi2_dev *csi2 = sd_to_dev(sd);
510
- int i, ret;
511
-
512
- for (i = 0; i < CSI2_NUM_PADS; i++) {
513
- csi2->pad[i].flags = (i == CSI2_SINK_PAD) ?
514
- MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
515
- }
516510
517511 /* set a default mbus format */
518
- ret = imx_media_init_mbus_fmt(&csi2->format_mbus,
512
+ return imx_media_init_mbus_fmt(&csi2->format_mbus,
519513 640, 480, 0, V4L2_FIELD_NONE, NULL);
520
- if (ret)
521
- return ret;
522
-
523
- return media_entity_pads_init(&sd->entity, CSI2_NUM_PADS, csi2->pad);
524514 }
525515
526516 static const struct media_entity_operations csi2_entity_ops = {
527517 .link_setup = csi2_link_setup,
528518 .link_validate = v4l2_subdev_link_validate,
519
+ .get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1,
529520 };
530521
531522 static const struct v4l2_subdev_video_ops csi2_video_ops = {
....@@ -547,38 +538,71 @@
547538 .registered = csi2_registered,
548539 };
549540
550
-static int csi2_parse_endpoints(struct csi2_dev *csi2)
541
+static int csi2_notify_bound(struct v4l2_async_notifier *notifier,
542
+ struct v4l2_subdev *sd,
543
+ struct v4l2_async_subdev *asd)
551544 {
552
- struct device_node *node = csi2->dev->of_node;
553
- struct device_node *epnode;
554
- struct v4l2_fwnode_endpoint ep;
545
+ struct csi2_dev *csi2 = notifier_to_dev(notifier);
546
+ struct media_pad *sink = &csi2->sd.entity.pads[CSI2_SINK_PAD];
555547
556
- epnode = of_graph_get_endpoint_by_regs(node, 0, -1);
557
- if (!epnode) {
558
- v4l2_err(&csi2->sd, "failed to get sink endpoint node\n");
559
- return -EINVAL;
560
- }
548
+ return v4l2_create_fwnode_links_to_pad(sd, sink);
549
+}
561550
562
- v4l2_fwnode_endpoint_parse(of_fwnode_handle(epnode), &ep);
563
- of_node_put(epnode);
551
+static const struct v4l2_async_notifier_operations csi2_notify_ops = {
552
+ .bound = csi2_notify_bound,
553
+};
564554
565
- if (ep.bus_type != V4L2_MBUS_CSI2) {
566
- v4l2_err(&csi2->sd, "invalid bus type, must be MIPI CSI2\n");
567
- return -EINVAL;
568
- }
555
+static int csi2_async_register(struct csi2_dev *csi2)
556
+{
557
+ struct v4l2_fwnode_endpoint vep = {
558
+ .bus_type = V4L2_MBUS_CSI2_DPHY,
559
+ };
560
+ struct v4l2_async_subdev *asd;
561
+ struct fwnode_handle *ep;
562
+ int ret;
569563
570
- csi2->bus = ep.bus.mipi_csi2;
564
+ v4l2_async_notifier_init(&csi2->notifier);
565
+
566
+ ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csi2->dev), 0, 0,
567
+ FWNODE_GRAPH_ENDPOINT_NEXT);
568
+ if (!ep)
569
+ return -ENOTCONN;
570
+
571
+ ret = v4l2_fwnode_endpoint_parse(ep, &vep);
572
+ if (ret)
573
+ goto err_parse;
574
+
575
+ csi2->bus = vep.bus.mipi_csi2;
571576
572577 dev_dbg(csi2->dev, "data lanes: %d\n", csi2->bus.num_data_lanes);
573578 dev_dbg(csi2->dev, "flags: 0x%08x\n", csi2->bus.flags);
574
- return 0;
579
+
580
+ asd = v4l2_async_notifier_add_fwnode_remote_subdev(
581
+ &csi2->notifier, ep, sizeof(*asd));
582
+ fwnode_handle_put(ep);
583
+
584
+ if (IS_ERR(asd))
585
+ return PTR_ERR(asd);
586
+
587
+ csi2->notifier.ops = &csi2_notify_ops;
588
+
589
+ ret = v4l2_async_subdev_notifier_register(&csi2->sd,
590
+ &csi2->notifier);
591
+ if (ret)
592
+ return ret;
593
+
594
+ return v4l2_async_register_subdev(&csi2->sd);
595
+
596
+err_parse:
597
+ fwnode_handle_put(ep);
598
+ return ret;
575599 }
576600
577601 static int csi2_probe(struct platform_device *pdev)
578602 {
579603 struct csi2_dev *csi2;
580604 struct resource *res;
581
- int ret;
605
+ int i, ret;
582606
583607 csi2 = devm_kzalloc(&pdev->dev, sizeof(*csi2), GFP_KERNEL);
584608 if (!csi2)
....@@ -593,33 +617,36 @@
593617 csi2->sd.dev = &pdev->dev;
594618 csi2->sd.owner = THIS_MODULE;
595619 csi2->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
596
- strcpy(csi2->sd.name, DEVICE_NAME);
620
+ strscpy(csi2->sd.name, DEVICE_NAME, sizeof(csi2->sd.name));
597621 csi2->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
598622 csi2->sd.grp_id = IMX_MEDIA_GRP_ID_CSI2;
599623
600
- ret = csi2_parse_endpoints(csi2);
624
+ for (i = 0; i < CSI2_NUM_PADS; i++) {
625
+ csi2->pad[i].flags = (i == CSI2_SINK_PAD) ?
626
+ MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
627
+ }
628
+
629
+ ret = media_entity_pads_init(&csi2->sd.entity, CSI2_NUM_PADS,
630
+ csi2->pad);
601631 if (ret)
602632 return ret;
603633
604634 csi2->pllref_clk = devm_clk_get(&pdev->dev, "ref");
605635 if (IS_ERR(csi2->pllref_clk)) {
606636 v4l2_err(&csi2->sd, "failed to get pll reference clock\n");
607
- ret = PTR_ERR(csi2->pllref_clk);
608
- return ret;
637
+ return PTR_ERR(csi2->pllref_clk);
609638 }
610639
611640 csi2->dphy_clk = devm_clk_get(&pdev->dev, "dphy");
612641 if (IS_ERR(csi2->dphy_clk)) {
613642 v4l2_err(&csi2->sd, "failed to get dphy clock\n");
614
- ret = PTR_ERR(csi2->dphy_clk);
615
- return ret;
643
+ return PTR_ERR(csi2->dphy_clk);
616644 }
617645
618646 csi2->pix_clk = devm_clk_get(&pdev->dev, "pix");
619647 if (IS_ERR(csi2->pix_clk)) {
620648 v4l2_err(&csi2->sd, "failed to get pixel clock\n");
621
- ret = PTR_ERR(csi2->pix_clk);
622
- return ret;
649
+ return PTR_ERR(csi2->pix_clk);
623650 }
624651
625652 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
....@@ -629,10 +656,8 @@
629656 }
630657
631658 csi2->base = devm_ioremap(&pdev->dev, res->start, PAGE_SIZE);
632
- if (!csi2->base) {
633
- v4l2_err(&csi2->sd, "failed to map CSI-2 registers\n");
659
+ if (!csi2->base)
634660 return -ENOMEM;
635
- }
636661
637662 mutex_init(&csi2->lock);
638663
....@@ -650,13 +675,15 @@
650675
651676 platform_set_drvdata(pdev, &csi2->sd);
652677
653
- ret = v4l2_async_register_subdev(&csi2->sd);
678
+ ret = csi2_async_register(csi2);
654679 if (ret)
655
- goto dphy_off;
680
+ goto clean_notifier;
656681
657682 return 0;
658683
659
-dphy_off:
684
+clean_notifier:
685
+ v4l2_async_notifier_unregister(&csi2->notifier);
686
+ v4l2_async_notifier_cleanup(&csi2->notifier);
660687 clk_disable_unprepare(csi2->dphy_clk);
661688 pllref_off:
662689 clk_disable_unprepare(csi2->pllref_clk);
....@@ -670,6 +697,8 @@
670697 struct v4l2_subdev *sd = platform_get_drvdata(pdev);
671698 struct csi2_dev *csi2 = sd_to_dev(sd);
672699
700
+ v4l2_async_notifier_unregister(&csi2->notifier);
701
+ v4l2_async_notifier_cleanup(&csi2->notifier);
673702 v4l2_async_unregister_subdev(sd);
674703 clk_disable_unprepare(csi2->dphy_clk);
675704 clk_disable_unprepare(csi2->pllref_clk);