1 // SPDX-License-Identifier: GPL-2.0+
3 * Driver for Renesas R-Car VIN
5 * Copyright (C) 2016 Renesas Electronics Corp.
6 * Copyright (C) 2011-2013 Renesas Solutions Corp.
7 * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com>
8 * Copyright (C) 2008 Magnus Damm
10 * Based on the soc-camera rcar_vin driver
13 #include <linux/module.h>
15 #include <linux/of_device.h>
16 #include <linux/of_graph.h>
17 #include <linux/platform_device.h>
18 #include <linux/pm_runtime.h>
19 #include <linux/slab.h>
20 #include <linux/sys_soc.h>
22 #include <media/v4l2-async.h>
23 #include <media/v4l2-fwnode.h>
24 #include <media/v4l2-mc.h>
29 * The companion CSI-2 receiver driver (rcar-csi2) is known
30 * and we know it has one source pad (pad 0) and four sink
31 * pads (pad 1-4). So to translate a pad on the remote
32 * CSI-2 receiver to/from the VIN internal channel number simply
33 * subtract/add one from the pad/channel number.
35 #define rvin_group_csi_pad_to_channel(pad) ((pad) - 1)
36 #define rvin_group_csi_channel_to_pad(channel) ((channel) + 1)
39 * Not all VINs are created equal, master VINs control the
40 * routing for other VIN's. We can figure out which VIN is
41 * master by looking at a VINs id.
43 #define rvin_group_id_to_master(vin) ((vin) < 4 ? 0 : 4)
45 #define v4l2_dev_to_vin(d) container_of(d, struct rvin_dev, v4l2_dev)
47 /* -----------------------------------------------------------------------------
48 * Media Controller link notification
51 /* group lock should be held when calling this function. */
52 static int rvin_group_entity_to_csi_id(struct rvin_group
*group
,
53 struct media_entity
*entity
)
55 struct v4l2_subdev
*sd
;
58 sd
= media_entity_to_v4l2_subdev(entity
);
60 for (i
= 0; i
< RVIN_CSI_MAX
; i
++)
61 if (group
->csi
[i
].subdev
== sd
)
67 static unsigned int rvin_group_get_mask(struct rvin_dev
*vin
,
68 enum rvin_csi_id csi_id
,
69 unsigned char channel
)
71 const struct rvin_group_route
*route
;
72 unsigned int mask
= 0;
74 for (route
= vin
->info
->routes
; route
->mask
; route
++) {
75 if (route
->vin
== vin
->id
&&
76 route
->csi
== csi_id
&&
77 route
->channel
== channel
) {
79 "Adding route: vin: %d csi: %d channel: %d\n",
80 route
->vin
, route
->csi
, route
->channel
);
89 * Link setup for the links between a VIN and a CSI-2 receiver is a bit
90 * complex. The reason for this is that the register controlling routing
91 * is not present in each VIN instance. There are special VINs which
92 * control routing for themselves and other VINs. There are not many
93 * different possible links combinations that can be enabled at the same
94 * time, therefor all already enabled links which are controlled by a
95 * master VIN need to be taken into account when making the decision
96 * if a new link can be enabled or not.
98 * 1. Find out which VIN the link the user tries to enable is connected to.
99 * 2. Lookup which master VIN controls the links for this VIN.
100 * 3. Start with a bitmask with all bits set.
101 * 4. For each previously enabled link from the master VIN bitwise AND its
102 * route mask (see documentation for mask in struct rvin_group_route)
104 * 5. Bitwise AND the mask for the link the user tries to enable to the bitmask.
105 * 6. If the bitmask is not empty at this point the new link can be enabled
106 * while keeping all previous links enabled. Update the CHSEL value of the
107 * master VIN and inform the user that the link could be enabled.
109 * Please note that no link can be enabled if any VIN in the group is
112 static int rvin_group_link_notify(struct media_link
*link
, u32 flags
,
113 unsigned int notification
)
115 struct rvin_group
*group
= container_of(link
->graph_obj
.mdev
,
116 struct rvin_group
, mdev
);
117 unsigned int master_id
, channel
, mask_new
, i
;
118 unsigned int mask
= ~0;
119 struct media_entity
*entity
;
120 struct video_device
*vdev
;
121 struct media_pad
*csi_pad
;
122 struct rvin_dev
*vin
= NULL
;
125 ret
= v4l2_pipeline_link_notify(link
, flags
, notification
);
129 /* Only care about link enablement for VIN nodes. */
130 if (!(flags
& MEDIA_LNK_FL_ENABLED
) ||
131 !is_media_entity_v4l2_video_device(link
->sink
->entity
))
135 * Don't allow link changes if any entity in the graph is
136 * streaming, modifying the CHSEL register fields can disrupt
139 media_device_for_each_entity(entity
, &group
->mdev
)
140 if (entity
->stream_count
)
143 mutex_lock(&group
->lock
);
145 /* Find the master VIN that controls the routes. */
146 vdev
= media_entity_to_video_device(link
->sink
->entity
);
147 vin
= container_of(vdev
, struct rvin_dev
, vdev
);
148 master_id
= rvin_group_id_to_master(vin
->id
);
150 if (WARN_ON(!group
->vin
[master_id
])) {
155 /* Build a mask for already enabled links. */
156 for (i
= master_id
; i
< master_id
+ 4; i
++) {
160 /* Get remote CSI-2, if any. */
161 csi_pad
= media_entity_remote_pad(
162 &group
->vin
[i
]->vdev
.entity
.pads
[0]);
166 csi_id
= rvin_group_entity_to_csi_id(group
, csi_pad
->entity
);
167 channel
= rvin_group_csi_pad_to_channel(csi_pad
->index
);
169 mask
&= rvin_group_get_mask(group
->vin
[i
], csi_id
, channel
);
172 /* Add the new link to the existing mask and check if it works. */
173 csi_id
= rvin_group_entity_to_csi_id(group
, link
->source
->entity
);
175 if (csi_id
== -ENODEV
) {
176 struct v4l2_subdev
*sd
;
179 * Make sure the source entity subdevice is registered as
180 * a parallel input of one of the enabled VINs if it is not
181 * one of the CSI-2 subdevices.
183 * No hardware configuration required for parallel inputs,
184 * we can return here.
186 sd
= media_entity_to_v4l2_subdev(link
->source
->entity
);
187 for (i
= 0; i
< RCAR_VIN_NUM
; i
++) {
189 group
->vin
[i
]->parallel
.subdev
== sd
) {
190 group
->vin
[i
]->is_csi
= false;
196 vin_err(vin
, "Subdevice %s not registered to any VIN\n",
197 link
->source
->entity
->name
);
202 channel
= rvin_group_csi_pad_to_channel(link
->source
->index
);
203 mask_new
= mask
& rvin_group_get_mask(vin
, csi_id
, channel
);
204 vin_dbg(vin
, "Try link change mask: 0x%x new: 0x%x\n", mask
, mask_new
);
211 /* New valid CHSEL found, set the new value. */
212 ret
= rvin_set_channel_routing(group
->vin
[master_id
], __ffs(mask_new
));
219 mutex_unlock(&group
->lock
);
224 static const struct media_device_ops rvin_media_ops
= {
225 .link_notify
= rvin_group_link_notify
,
228 /* -----------------------------------------------------------------------------
229 * Gen3 CSI2 Group Allocator
232 /* FIXME: This should if we find a system that supports more
233 * than one group for the whole system be replaced with a linked
234 * list of groups. And eventually all of this should be replaced
235 * with a global device allocator API.
237 * But for now this works as on all supported systems there will
238 * be only one group for all instances.
241 static DEFINE_MUTEX(rvin_group_lock
);
242 static struct rvin_group
*rvin_group_data
;
244 static void rvin_group_cleanup(struct rvin_group
*group
)
246 media_device_cleanup(&group
->mdev
);
247 mutex_destroy(&group
->lock
);
250 static int rvin_group_init(struct rvin_group
*group
, struct rvin_dev
*vin
)
252 struct media_device
*mdev
= &group
->mdev
;
253 const struct of_device_id
*match
;
254 struct device_node
*np
;
256 mutex_init(&group
->lock
);
258 /* Count number of VINs in the system */
260 for_each_matching_node(np
, vin
->dev
->driver
->of_match_table
)
261 if (of_device_is_available(np
))
264 vin_dbg(vin
, "found %u enabled VIN's in DT", group
->count
);
266 mdev
->dev
= vin
->dev
;
267 mdev
->ops
= &rvin_media_ops
;
269 match
= of_match_node(vin
->dev
->driver
->of_match_table
,
272 strscpy(mdev
->driver_name
, KBUILD_MODNAME
, sizeof(mdev
->driver_name
));
273 strscpy(mdev
->model
, match
->compatible
, sizeof(mdev
->model
));
274 snprintf(mdev
->bus_info
, sizeof(mdev
->bus_info
), "platform:%s",
275 dev_name(mdev
->dev
));
277 media_device_init(mdev
);
282 static void rvin_group_release(struct kref
*kref
)
284 struct rvin_group
*group
=
285 container_of(kref
, struct rvin_group
, refcount
);
287 mutex_lock(&rvin_group_lock
);
289 rvin_group_data
= NULL
;
291 rvin_group_cleanup(group
);
295 mutex_unlock(&rvin_group_lock
);
298 static int rvin_group_get(struct rvin_dev
*vin
)
300 struct rvin_group
*group
;
304 /* Make sure VIN id is present and sane */
305 ret
= of_property_read_u32(vin
->dev
->of_node
, "renesas,id", &id
);
307 vin_err(vin
, "%pOF: No renesas,id property found\n",
312 if (id
>= RCAR_VIN_NUM
) {
313 vin_err(vin
, "%pOF: Invalid renesas,id '%u'\n",
314 vin
->dev
->of_node
, id
);
318 /* Join or create a VIN group */
319 mutex_lock(&rvin_group_lock
);
320 if (rvin_group_data
) {
321 group
= rvin_group_data
;
322 kref_get(&group
->refcount
);
324 group
= kzalloc(sizeof(*group
), GFP_KERNEL
);
330 ret
= rvin_group_init(group
, vin
);
333 vin_err(vin
, "Failed to initialize group\n");
337 kref_init(&group
->refcount
);
339 rvin_group_data
= group
;
341 mutex_unlock(&rvin_group_lock
);
343 /* Add VIN to group */
344 mutex_lock(&group
->lock
);
346 if (group
->vin
[id
]) {
347 vin_err(vin
, "Duplicate renesas,id property value %u\n", id
);
348 mutex_unlock(&group
->lock
);
349 kref_put(&group
->refcount
, rvin_group_release
);
353 group
->vin
[id
] = vin
;
357 vin
->v4l2_dev
.mdev
= &group
->mdev
;
359 mutex_unlock(&group
->lock
);
363 mutex_unlock(&rvin_group_lock
);
367 static void rvin_group_put(struct rvin_dev
*vin
)
369 struct rvin_group
*group
= vin
->group
;
371 mutex_lock(&group
->lock
);
374 vin
->v4l2_dev
.mdev
= NULL
;
376 if (WARN_ON(group
->vin
[vin
->id
] != vin
))
379 group
->vin
[vin
->id
] = NULL
;
381 mutex_unlock(&group
->lock
);
383 kref_put(&group
->refcount
, rvin_group_release
);
386 /* -----------------------------------------------------------------------------
390 static int rvin_s_ctrl(struct v4l2_ctrl
*ctrl
)
392 struct rvin_dev
*vin
=
393 container_of(ctrl
->handler
, struct rvin_dev
, ctrl_handler
);
396 case V4L2_CID_ALPHA_COMPONENT
:
397 rvin_set_alpha(vin
, ctrl
->val
);
404 static const struct v4l2_ctrl_ops rvin_ctrl_ops
= {
405 .s_ctrl
= rvin_s_ctrl
,
408 /* -----------------------------------------------------------------------------
412 static int rvin_find_pad(struct v4l2_subdev
*sd
, int direction
)
416 if (sd
->entity
.num_pads
<= 1)
419 for (pad
= 0; pad
< sd
->entity
.num_pads
; pad
++)
420 if (sd
->entity
.pads
[pad
].flags
& direction
)
426 /* -----------------------------------------------------------------------------
427 * Parallel async notifier
430 /* The vin lock should be held when calling the subdevice attach and detach */
431 static int rvin_parallel_subdevice_attach(struct rvin_dev
*vin
,
432 struct v4l2_subdev
*subdev
)
434 struct v4l2_subdev_mbus_code_enum code
= {
435 .which
= V4L2_SUBDEV_FORMAT_ACTIVE
,
439 /* Find source and sink pad of remote subdevice */
440 ret
= rvin_find_pad(subdev
, MEDIA_PAD_FL_SOURCE
);
443 vin
->parallel
.source_pad
= ret
;
445 ret
= rvin_find_pad(subdev
, MEDIA_PAD_FL_SINK
);
446 vin
->parallel
.sink_pad
= ret
< 0 ? 0 : ret
;
448 if (vin
->info
->use_mc
) {
449 vin
->parallel
.subdev
= subdev
;
453 /* Find compatible subdevices mbus format */
456 code
.pad
= vin
->parallel
.source_pad
;
457 while (!vin
->mbus_code
&&
458 !v4l2_subdev_call(subdev
, pad
, enum_mbus_code
, NULL
, &code
)) {
461 case MEDIA_BUS_FMT_YUYV8_1X16
:
462 case MEDIA_BUS_FMT_UYVY8_1X16
:
463 case MEDIA_BUS_FMT_UYVY8_2X8
:
464 case MEDIA_BUS_FMT_UYVY10_2X10
:
465 case MEDIA_BUS_FMT_RGB888_1X24
:
466 vin
->mbus_code
= code
.code
;
467 vin_dbg(vin
, "Found media bus format for %s: %d\n",
468 subdev
->name
, vin
->mbus_code
);
475 if (!vin
->mbus_code
) {
476 vin_err(vin
, "Unsupported media bus format for %s\n",
482 ret
= v4l2_subdev_call(subdev
, video
, g_tvnorms
, &vin
->vdev
.tvnorms
);
483 if (ret
< 0 && ret
!= -ENOIOCTLCMD
&& ret
!= -ENODEV
)
487 vin
->std
= V4L2_STD_UNKNOWN
;
488 ret
= v4l2_subdev_call(subdev
, video
, g_std
, &vin
->std
);
489 if (ret
< 0 && ret
!= -ENOIOCTLCMD
)
492 /* Add the controls */
493 ret
= v4l2_ctrl_handler_init(&vin
->ctrl_handler
, 16);
497 v4l2_ctrl_new_std(&vin
->ctrl_handler
, &rvin_ctrl_ops
,
498 V4L2_CID_ALPHA_COMPONENT
, 0, 255, 1, 255);
500 if (vin
->ctrl_handler
.error
) {
501 ret
= vin
->ctrl_handler
.error
;
502 v4l2_ctrl_handler_free(&vin
->ctrl_handler
);
506 ret
= v4l2_ctrl_add_handler(&vin
->ctrl_handler
, subdev
->ctrl_handler
,
509 v4l2_ctrl_handler_free(&vin
->ctrl_handler
);
513 vin
->vdev
.ctrl_handler
= &vin
->ctrl_handler
;
515 vin
->parallel
.subdev
= subdev
;
520 static void rvin_parallel_subdevice_detach(struct rvin_dev
*vin
)
522 rvin_v4l2_unregister(vin
);
523 vin
->parallel
.subdev
= NULL
;
525 if (!vin
->info
->use_mc
) {
526 v4l2_ctrl_handler_free(&vin
->ctrl_handler
);
527 vin
->vdev
.ctrl_handler
= NULL
;
531 static int rvin_parallel_notify_complete(struct v4l2_async_notifier
*notifier
)
533 struct rvin_dev
*vin
= v4l2_dev_to_vin(notifier
->v4l2_dev
);
534 struct media_entity
*source
;
535 struct media_entity
*sink
;
538 ret
= v4l2_device_register_subdev_nodes(&vin
->v4l2_dev
);
540 vin_err(vin
, "Failed to register subdev nodes\n");
544 if (!video_is_registered(&vin
->vdev
)) {
545 ret
= rvin_v4l2_register(vin
);
550 if (!vin
->info
->use_mc
)
553 /* If we're running with media-controller, link the subdevs. */
554 source
= &vin
->parallel
.subdev
->entity
;
555 sink
= &vin
->vdev
.entity
;
557 ret
= media_create_pad_link(source
, vin
->parallel
.source_pad
,
558 sink
, vin
->parallel
.sink_pad
, 0);
560 vin_err(vin
, "Error adding link from %s to %s: %d\n",
561 source
->name
, sink
->name
, ret
);
566 static void rvin_parallel_notify_unbind(struct v4l2_async_notifier
*notifier
,
567 struct v4l2_subdev
*subdev
,
568 struct v4l2_async_subdev
*asd
)
570 struct rvin_dev
*vin
= v4l2_dev_to_vin(notifier
->v4l2_dev
);
572 vin_dbg(vin
, "unbind parallel subdev %s\n", subdev
->name
);
574 mutex_lock(&vin
->lock
);
575 rvin_parallel_subdevice_detach(vin
);
576 mutex_unlock(&vin
->lock
);
579 static int rvin_parallel_notify_bound(struct v4l2_async_notifier
*notifier
,
580 struct v4l2_subdev
*subdev
,
581 struct v4l2_async_subdev
*asd
)
583 struct rvin_dev
*vin
= v4l2_dev_to_vin(notifier
->v4l2_dev
);
586 mutex_lock(&vin
->lock
);
587 ret
= rvin_parallel_subdevice_attach(vin
, subdev
);
588 mutex_unlock(&vin
->lock
);
592 v4l2_set_subdev_hostdata(subdev
, vin
);
594 vin_dbg(vin
, "bound subdev %s source pad: %u sink pad: %u\n",
595 subdev
->name
, vin
->parallel
.source_pad
,
596 vin
->parallel
.sink_pad
);
601 static const struct v4l2_async_notifier_operations rvin_parallel_notify_ops
= {
602 .bound
= rvin_parallel_notify_bound
,
603 .unbind
= rvin_parallel_notify_unbind
,
604 .complete
= rvin_parallel_notify_complete
,
607 static int rvin_parallel_parse_of(struct rvin_dev
*vin
)
609 struct fwnode_handle
*ep
, *fwnode
;
610 struct v4l2_fwnode_endpoint vep
= {
611 .bus_type
= V4L2_MBUS_UNKNOWN
,
613 struct v4l2_async_subdev
*asd
;
616 ep
= fwnode_graph_get_endpoint_by_id(dev_fwnode(vin
->dev
), 0, 0, 0);
620 fwnode
= fwnode_graph_get_remote_endpoint(ep
);
621 ret
= v4l2_fwnode_endpoint_parse(ep
, &vep
);
622 fwnode_handle_put(ep
);
624 vin_err(vin
, "Failed to parse %pOF\n", to_of_node(fwnode
));
629 switch (vep
.bus_type
) {
630 case V4L2_MBUS_PARALLEL
:
631 case V4L2_MBUS_BT656
:
632 vin_dbg(vin
, "Found %s media bus\n",
633 vep
.bus_type
== V4L2_MBUS_PARALLEL
?
634 "PARALLEL" : "BT656");
635 vin
->parallel
.mbus_type
= vep
.bus_type
;
636 vin
->parallel
.bus
= vep
.bus
.parallel
;
639 vin_err(vin
, "Unknown media bus type\n");
644 asd
= v4l2_async_notifier_add_fwnode_subdev(&vin
->notifier
, fwnode
,
651 vin
->parallel
.asd
= asd
;
653 vin_dbg(vin
, "Add parallel OF device %pOF\n", to_of_node(fwnode
));
655 fwnode_handle_put(fwnode
);
660 static int rvin_parallel_init(struct rvin_dev
*vin
)
664 v4l2_async_notifier_init(&vin
->notifier
);
666 ret
= rvin_parallel_parse_of(vin
);
670 /* If using mc, it's fine not to have any input registered. */
671 if (!vin
->parallel
.asd
)
672 return vin
->info
->use_mc
? 0 : -ENODEV
;
674 vin_dbg(vin
, "Found parallel subdevice %pOF\n",
675 to_of_node(vin
->parallel
.asd
->match
.fwnode
));
677 vin
->notifier
.ops
= &rvin_parallel_notify_ops
;
678 ret
= v4l2_async_notifier_register(&vin
->v4l2_dev
, &vin
->notifier
);
680 vin_err(vin
, "Notifier registration failed\n");
681 v4l2_async_notifier_cleanup(&vin
->notifier
);
688 /* -----------------------------------------------------------------------------
689 * Group async notifier
692 static int rvin_group_notify_complete(struct v4l2_async_notifier
*notifier
)
694 struct rvin_dev
*vin
= v4l2_dev_to_vin(notifier
->v4l2_dev
);
695 const struct rvin_group_route
*route
;
699 ret
= media_device_register(&vin
->group
->mdev
);
703 ret
= v4l2_device_register_subdev_nodes(&vin
->v4l2_dev
);
705 vin_err(vin
, "Failed to register subdev nodes\n");
709 /* Register all video nodes for the group. */
710 for (i
= 0; i
< RCAR_VIN_NUM
; i
++) {
711 if (vin
->group
->vin
[i
] &&
712 !video_is_registered(&vin
->group
->vin
[i
]->vdev
)) {
713 ret
= rvin_v4l2_register(vin
->group
->vin
[i
]);
719 /* Create all media device links between VINs and CSI-2's. */
720 mutex_lock(&vin
->group
->lock
);
721 for (route
= vin
->info
->routes
; route
->mask
; route
++) {
722 struct media_pad
*source_pad
, *sink_pad
;
723 struct media_entity
*source
, *sink
;
724 unsigned int source_idx
;
726 /* Check that VIN is part of the group. */
727 if (!vin
->group
->vin
[route
->vin
])
730 /* Check that VIN' master is part of the group. */
731 if (!vin
->group
->vin
[rvin_group_id_to_master(route
->vin
)])
734 /* Check that CSI-2 is part of the group. */
735 if (!vin
->group
->csi
[route
->csi
].subdev
)
738 source
= &vin
->group
->csi
[route
->csi
].subdev
->entity
;
739 source_idx
= rvin_group_csi_channel_to_pad(route
->channel
);
740 source_pad
= &source
->pads
[source_idx
];
742 sink
= &vin
->group
->vin
[route
->vin
]->vdev
.entity
;
743 sink_pad
= &sink
->pads
[0];
745 /* Skip if link already exists. */
746 if (media_entity_find_link(source_pad
, sink_pad
))
749 ret
= media_create_pad_link(source
, source_idx
, sink
, 0, 0);
751 vin_err(vin
, "Error adding link from %s to %s\n",
752 source
->name
, sink
->name
);
756 mutex_unlock(&vin
->group
->lock
);
761 static void rvin_group_notify_unbind(struct v4l2_async_notifier
*notifier
,
762 struct v4l2_subdev
*subdev
,
763 struct v4l2_async_subdev
*asd
)
765 struct rvin_dev
*vin
= v4l2_dev_to_vin(notifier
->v4l2_dev
);
768 for (i
= 0; i
< RCAR_VIN_NUM
; i
++)
769 if (vin
->group
->vin
[i
])
770 rvin_v4l2_unregister(vin
->group
->vin
[i
]);
772 mutex_lock(&vin
->group
->lock
);
774 for (i
= 0; i
< RVIN_CSI_MAX
; i
++) {
775 if (vin
->group
->csi
[i
].asd
!= asd
)
777 vin
->group
->csi
[i
].subdev
= NULL
;
778 vin_dbg(vin
, "Unbind CSI-2 %s from slot %u\n", subdev
->name
, i
);
782 mutex_unlock(&vin
->group
->lock
);
784 media_device_unregister(&vin
->group
->mdev
);
787 static int rvin_group_notify_bound(struct v4l2_async_notifier
*notifier
,
788 struct v4l2_subdev
*subdev
,
789 struct v4l2_async_subdev
*asd
)
791 struct rvin_dev
*vin
= v4l2_dev_to_vin(notifier
->v4l2_dev
);
794 mutex_lock(&vin
->group
->lock
);
796 for (i
= 0; i
< RVIN_CSI_MAX
; i
++) {
797 if (vin
->group
->csi
[i
].asd
!= asd
)
799 vin
->group
->csi
[i
].subdev
= subdev
;
800 vin_dbg(vin
, "Bound CSI-2 %s to slot %u\n", subdev
->name
, i
);
804 mutex_unlock(&vin
->group
->lock
);
809 static const struct v4l2_async_notifier_operations rvin_group_notify_ops
= {
810 .bound
= rvin_group_notify_bound
,
811 .unbind
= rvin_group_notify_unbind
,
812 .complete
= rvin_group_notify_complete
,
815 static int rvin_mc_parse_of(struct rvin_dev
*vin
, unsigned int id
)
817 struct fwnode_handle
*ep
, *fwnode
;
818 struct v4l2_fwnode_endpoint vep
= {
819 .bus_type
= V4L2_MBUS_CSI2_DPHY
,
821 struct v4l2_async_subdev
*asd
;
824 ep
= fwnode_graph_get_endpoint_by_id(dev_fwnode(vin
->dev
), 1, id
, 0);
828 fwnode
= fwnode_graph_get_remote_endpoint(ep
);
829 ret
= v4l2_fwnode_endpoint_parse(ep
, &vep
);
830 fwnode_handle_put(ep
);
832 vin_err(vin
, "Failed to parse %pOF\n", to_of_node(fwnode
));
837 if (!of_device_is_available(to_of_node(fwnode
))) {
838 vin_dbg(vin
, "OF device %pOF disabled, ignoring\n",
844 asd
= v4l2_async_notifier_add_fwnode_subdev(&vin
->group
->notifier
,
845 fwnode
, sizeof(*asd
));
851 vin
->group
->csi
[vep
.base
.id
].asd
= asd
;
853 vin_dbg(vin
, "Add group OF device %pOF to slot %u\n",
854 to_of_node(fwnode
), vep
.base
.id
);
856 fwnode_handle_put(fwnode
);
861 static int rvin_mc_parse_of_graph(struct rvin_dev
*vin
)
863 unsigned int count
= 0, vin_mask
= 0;
867 mutex_lock(&vin
->group
->lock
);
869 /* If not all VIN's are registered don't register the notifier. */
870 for (i
= 0; i
< RCAR_VIN_NUM
; i
++) {
871 if (vin
->group
->vin
[i
]) {
877 if (vin
->group
->count
!= count
) {
878 mutex_unlock(&vin
->group
->lock
);
882 mutex_unlock(&vin
->group
->lock
);
884 v4l2_async_notifier_init(&vin
->group
->notifier
);
887 * Have all VIN's look for CSI-2 subdevices. Some subdevices will
888 * overlap but the parser function can handle it, so each subdevice
889 * will only be registered once with the group notifier.
891 for (i
= 0; i
< RCAR_VIN_NUM
; i
++) {
892 if (!(vin_mask
& BIT(i
)))
895 for (id
= 0; id
< RVIN_CSI_MAX
; id
++) {
896 if (vin
->group
->csi
[id
].asd
)
899 ret
= rvin_mc_parse_of(vin
->group
->vin
[i
], id
);
905 if (list_empty(&vin
->group
->notifier
.asd_list
))
908 vin
->group
->notifier
.ops
= &rvin_group_notify_ops
;
909 ret
= v4l2_async_notifier_register(&vin
->v4l2_dev
,
910 &vin
->group
->notifier
);
912 vin_err(vin
, "Notifier registration failed\n");
913 v4l2_async_notifier_cleanup(&vin
->group
->notifier
);
920 static int rvin_mc_init(struct rvin_dev
*vin
)
924 vin
->pad
.flags
= MEDIA_PAD_FL_SINK
;
925 ret
= media_entity_pads_init(&vin
->vdev
.entity
, 1, &vin
->pad
);
929 ret
= rvin_group_get(vin
);
933 ret
= rvin_mc_parse_of_graph(vin
);
937 ret
= v4l2_ctrl_handler_init(&vin
->ctrl_handler
, 1);
941 v4l2_ctrl_new_std(&vin
->ctrl_handler
, &rvin_ctrl_ops
,
942 V4L2_CID_ALPHA_COMPONENT
, 0, 255, 1, 255);
944 if (vin
->ctrl_handler
.error
) {
945 ret
= vin
->ctrl_handler
.error
;
946 v4l2_ctrl_handler_free(&vin
->ctrl_handler
);
950 vin
->vdev
.ctrl_handler
= &vin
->ctrl_handler
;
955 /* -----------------------------------------------------------------------------
959 static int __maybe_unused
rvin_suspend(struct device
*dev
)
961 struct rvin_dev
*vin
= dev_get_drvdata(dev
);
963 if (vin
->state
!= RUNNING
)
966 rvin_stop_streaming(vin
);
968 vin
->state
= SUSPENDED
;
973 static int __maybe_unused
rvin_resume(struct device
*dev
)
975 struct rvin_dev
*vin
= dev_get_drvdata(dev
);
977 if (vin
->state
!= SUSPENDED
)
981 * Restore group master CHSEL setting.
983 * This needs to be done by every VIN resuming not only the master
984 * as we don't know if and in which order the master VINs will
987 if (vin
->info
->use_mc
) {
988 unsigned int master_id
= rvin_group_id_to_master(vin
->id
);
989 struct rvin_dev
*master
= vin
->group
->vin
[master_id
];
992 if (WARN_ON(!master
))
995 ret
= rvin_set_channel_routing(master
, master
->chsel
);
1000 return rvin_start_streaming(vin
);
1003 /* -----------------------------------------------------------------------------
1004 * Platform Device Driver
1007 static const struct rvin_info rcar_info_h1
= {
1014 static const struct rvin_info rcar_info_m1
= {
1021 static const struct rvin_info rcar_info_gen2
= {
1028 static const struct rvin_group_route rcar_info_r8a774e1_routes
[] = {
1029 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 0, .mask
= BIT(0) | BIT(3) },
1030 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 0, .mask
= BIT(1) | BIT(4) },
1031 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 0, .mask
= BIT(2) },
1032 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 1, .mask
= BIT(0) },
1033 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 1, .mask
= BIT(1) | BIT(3) },
1034 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 1, .mask
= BIT(2) },
1035 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 1, .mask
= BIT(4) },
1036 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 2, .mask
= BIT(0) },
1037 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 2, .mask
= BIT(1) },
1038 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 2, .mask
= BIT(2) },
1039 { .csi
= RVIN_CSI40
, .channel
= 2, .vin
= 2, .mask
= BIT(3) },
1040 { .csi
= RVIN_CSI20
, .channel
= 2, .vin
= 2, .mask
= BIT(4) },
1041 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 3, .mask
= BIT(0) },
1042 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 3, .mask
= BIT(1) | BIT(2) },
1043 { .csi
= RVIN_CSI40
, .channel
= 3, .vin
= 3, .mask
= BIT(3) },
1044 { .csi
= RVIN_CSI20
, .channel
= 3, .vin
= 3, .mask
= BIT(4) },
1045 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 4, .mask
= BIT(1) | BIT(4) },
1046 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 5, .mask
= BIT(0) },
1047 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 5, .mask
= BIT(4) },
1048 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 6, .mask
= BIT(0) },
1049 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 6, .mask
= BIT(2) },
1050 { .csi
= RVIN_CSI20
, .channel
= 2, .vin
= 6, .mask
= BIT(4) },
1051 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 7, .mask
= BIT(1) | BIT(2) },
1052 { .csi
= RVIN_CSI20
, .channel
= 3, .vin
= 7, .mask
= BIT(4) },
1056 static const struct rvin_info rcar_info_r8a774e1
= {
1061 .routes
= rcar_info_r8a774e1_routes
,
1064 static const struct rvin_group_route rcar_info_r8a7795_routes
[] = {
1065 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 0, .mask
= BIT(0) | BIT(3) },
1066 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 0, .mask
= BIT(1) | BIT(4) },
1067 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 0, .mask
= BIT(2) },
1068 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 1, .mask
= BIT(0) },
1069 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 1, .mask
= BIT(1) | BIT(3) },
1070 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 1, .mask
= BIT(2) },
1071 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 1, .mask
= BIT(4) },
1072 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 2, .mask
= BIT(0) },
1073 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 2, .mask
= BIT(1) },
1074 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 2, .mask
= BIT(2) },
1075 { .csi
= RVIN_CSI40
, .channel
= 2, .vin
= 2, .mask
= BIT(3) },
1076 { .csi
= RVIN_CSI20
, .channel
= 2, .vin
= 2, .mask
= BIT(4) },
1077 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 3, .mask
= BIT(0) },
1078 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 3, .mask
= BIT(1) | BIT(2) },
1079 { .csi
= RVIN_CSI40
, .channel
= 3, .vin
= 3, .mask
= BIT(3) },
1080 { .csi
= RVIN_CSI20
, .channel
= 3, .vin
= 3, .mask
= BIT(4) },
1081 { .csi
= RVIN_CSI41
, .channel
= 0, .vin
= 4, .mask
= BIT(0) | BIT(3) },
1082 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 4, .mask
= BIT(1) | BIT(4) },
1083 { .csi
= RVIN_CSI41
, .channel
= 1, .vin
= 4, .mask
= BIT(2) },
1084 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 5, .mask
= BIT(0) },
1085 { .csi
= RVIN_CSI41
, .channel
= 1, .vin
= 5, .mask
= BIT(1) | BIT(3) },
1086 { .csi
= RVIN_CSI41
, .channel
= 0, .vin
= 5, .mask
= BIT(2) },
1087 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 5, .mask
= BIT(4) },
1088 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 6, .mask
= BIT(0) },
1089 { .csi
= RVIN_CSI41
, .channel
= 0, .vin
= 6, .mask
= BIT(1) },
1090 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 6, .mask
= BIT(2) },
1091 { .csi
= RVIN_CSI41
, .channel
= 2, .vin
= 6, .mask
= BIT(3) },
1092 { .csi
= RVIN_CSI20
, .channel
= 2, .vin
= 6, .mask
= BIT(4) },
1093 { .csi
= RVIN_CSI41
, .channel
= 1, .vin
= 7, .mask
= BIT(0) },
1094 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 7, .mask
= BIT(1) | BIT(2) },
1095 { .csi
= RVIN_CSI41
, .channel
= 3, .vin
= 7, .mask
= BIT(3) },
1096 { .csi
= RVIN_CSI20
, .channel
= 3, .vin
= 7, .mask
= BIT(4) },
1100 static const struct rvin_info rcar_info_r8a7795
= {
1106 .routes
= rcar_info_r8a7795_routes
,
1109 static const struct rvin_group_route rcar_info_r8a7795es1_routes
[] = {
1110 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 0, .mask
= BIT(0) | BIT(3) },
1111 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 0, .mask
= BIT(1) | BIT(4) },
1112 { .csi
= RVIN_CSI21
, .channel
= 0, .vin
= 0, .mask
= BIT(2) | BIT(5) },
1113 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 1, .mask
= BIT(0) },
1114 { .csi
= RVIN_CSI21
, .channel
= 0, .vin
= 1, .mask
= BIT(1) },
1115 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 1, .mask
= BIT(2) },
1116 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 1, .mask
= BIT(3) },
1117 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 1, .mask
= BIT(4) },
1118 { .csi
= RVIN_CSI21
, .channel
= 1, .vin
= 1, .mask
= BIT(5) },
1119 { .csi
= RVIN_CSI21
, .channel
= 0, .vin
= 2, .mask
= BIT(0) },
1120 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 2, .mask
= BIT(1) },
1121 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 2, .mask
= BIT(2) },
1122 { .csi
= RVIN_CSI40
, .channel
= 2, .vin
= 2, .mask
= BIT(3) },
1123 { .csi
= RVIN_CSI20
, .channel
= 2, .vin
= 2, .mask
= BIT(4) },
1124 { .csi
= RVIN_CSI21
, .channel
= 2, .vin
= 2, .mask
= BIT(5) },
1125 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 3, .mask
= BIT(0) },
1126 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 3, .mask
= BIT(1) },
1127 { .csi
= RVIN_CSI21
, .channel
= 1, .vin
= 3, .mask
= BIT(2) },
1128 { .csi
= RVIN_CSI40
, .channel
= 3, .vin
= 3, .mask
= BIT(3) },
1129 { .csi
= RVIN_CSI20
, .channel
= 3, .vin
= 3, .mask
= BIT(4) },
1130 { .csi
= RVIN_CSI21
, .channel
= 3, .vin
= 3, .mask
= BIT(5) },
1131 { .csi
= RVIN_CSI41
, .channel
= 0, .vin
= 4, .mask
= BIT(0) | BIT(3) },
1132 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 4, .mask
= BIT(1) | BIT(4) },
1133 { .csi
= RVIN_CSI21
, .channel
= 0, .vin
= 4, .mask
= BIT(2) | BIT(5) },
1134 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 5, .mask
= BIT(0) },
1135 { .csi
= RVIN_CSI21
, .channel
= 0, .vin
= 5, .mask
= BIT(1) },
1136 { .csi
= RVIN_CSI41
, .channel
= 0, .vin
= 5, .mask
= BIT(2) },
1137 { .csi
= RVIN_CSI41
, .channel
= 1, .vin
= 5, .mask
= BIT(3) },
1138 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 5, .mask
= BIT(4) },
1139 { .csi
= RVIN_CSI21
, .channel
= 1, .vin
= 5, .mask
= BIT(5) },
1140 { .csi
= RVIN_CSI21
, .channel
= 0, .vin
= 6, .mask
= BIT(0) },
1141 { .csi
= RVIN_CSI41
, .channel
= 0, .vin
= 6, .mask
= BIT(1) },
1142 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 6, .mask
= BIT(2) },
1143 { .csi
= RVIN_CSI41
, .channel
= 2, .vin
= 6, .mask
= BIT(3) },
1144 { .csi
= RVIN_CSI20
, .channel
= 2, .vin
= 6, .mask
= BIT(4) },
1145 { .csi
= RVIN_CSI21
, .channel
= 2, .vin
= 6, .mask
= BIT(5) },
1146 { .csi
= RVIN_CSI41
, .channel
= 1, .vin
= 7, .mask
= BIT(0) },
1147 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 7, .mask
= BIT(1) },
1148 { .csi
= RVIN_CSI21
, .channel
= 1, .vin
= 7, .mask
= BIT(2) },
1149 { .csi
= RVIN_CSI41
, .channel
= 3, .vin
= 7, .mask
= BIT(3) },
1150 { .csi
= RVIN_CSI20
, .channel
= 3, .vin
= 7, .mask
= BIT(4) },
1151 { .csi
= RVIN_CSI21
, .channel
= 3, .vin
= 7, .mask
= BIT(5) },
1155 static const struct rvin_info rcar_info_r8a7795es1
= {
1160 .routes
= rcar_info_r8a7795es1_routes
,
1163 static const struct rvin_group_route rcar_info_r8a7796_routes
[] = {
1164 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 0, .mask
= BIT(0) | BIT(3) },
1165 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 0, .mask
= BIT(1) | BIT(4) },
1166 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 1, .mask
= BIT(0) },
1167 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 1, .mask
= BIT(2) },
1168 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 1, .mask
= BIT(3) },
1169 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 1, .mask
= BIT(4) },
1170 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 2, .mask
= BIT(1) },
1171 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 2, .mask
= BIT(2) },
1172 { .csi
= RVIN_CSI40
, .channel
= 2, .vin
= 2, .mask
= BIT(3) },
1173 { .csi
= RVIN_CSI20
, .channel
= 2, .vin
= 2, .mask
= BIT(4) },
1174 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 3, .mask
= BIT(0) },
1175 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 3, .mask
= BIT(1) },
1176 { .csi
= RVIN_CSI40
, .channel
= 3, .vin
= 3, .mask
= BIT(3) },
1177 { .csi
= RVIN_CSI20
, .channel
= 3, .vin
= 3, .mask
= BIT(4) },
1178 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 4, .mask
= BIT(0) | BIT(3) },
1179 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 4, .mask
= BIT(1) | BIT(4) },
1180 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 5, .mask
= BIT(0) },
1181 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 5, .mask
= BIT(2) },
1182 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 5, .mask
= BIT(3) },
1183 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 5, .mask
= BIT(4) },
1184 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 6, .mask
= BIT(1) },
1185 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 6, .mask
= BIT(2) },
1186 { .csi
= RVIN_CSI40
, .channel
= 2, .vin
= 6, .mask
= BIT(3) },
1187 { .csi
= RVIN_CSI20
, .channel
= 2, .vin
= 6, .mask
= BIT(4) },
1188 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 7, .mask
= BIT(0) },
1189 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 7, .mask
= BIT(1) },
1190 { .csi
= RVIN_CSI40
, .channel
= 3, .vin
= 7, .mask
= BIT(3) },
1191 { .csi
= RVIN_CSI20
, .channel
= 3, .vin
= 7, .mask
= BIT(4) },
1195 static const struct rvin_info rcar_info_r8a7796
= {
1201 .routes
= rcar_info_r8a7796_routes
,
1204 static const struct rvin_group_route rcar_info_r8a77965_routes
[] = {
1205 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 0, .mask
= BIT(0) | BIT(3) },
1206 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 0, .mask
= BIT(1) | BIT(4) },
1207 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 0, .mask
= BIT(2) },
1208 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 1, .mask
= BIT(0) },
1209 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 1, .mask
= BIT(1) | BIT(3) },
1210 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 1, .mask
= BIT(2) },
1211 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 1, .mask
= BIT(4) },
1212 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 2, .mask
= BIT(0) },
1213 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 2, .mask
= BIT(1) },
1214 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 2, .mask
= BIT(2) },
1215 { .csi
= RVIN_CSI40
, .channel
= 2, .vin
= 2, .mask
= BIT(3) },
1216 { .csi
= RVIN_CSI20
, .channel
= 2, .vin
= 2, .mask
= BIT(4) },
1217 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 3, .mask
= BIT(0) },
1218 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 3, .mask
= BIT(1) | BIT(2) },
1219 { .csi
= RVIN_CSI40
, .channel
= 3, .vin
= 3, .mask
= BIT(3) },
1220 { .csi
= RVIN_CSI20
, .channel
= 3, .vin
= 3, .mask
= BIT(4) },
1221 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 4, .mask
= BIT(0) | BIT(3) },
1222 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 4, .mask
= BIT(1) | BIT(4) },
1223 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 4, .mask
= BIT(2) },
1224 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 5, .mask
= BIT(0) },
1225 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 5, .mask
= BIT(1) | BIT(3) },
1226 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 5, .mask
= BIT(2) },
1227 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 5, .mask
= BIT(4) },
1228 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 6, .mask
= BIT(0) },
1229 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 6, .mask
= BIT(1) },
1230 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 6, .mask
= BIT(2) },
1231 { .csi
= RVIN_CSI40
, .channel
= 2, .vin
= 6, .mask
= BIT(3) },
1232 { .csi
= RVIN_CSI20
, .channel
= 2, .vin
= 6, .mask
= BIT(4) },
1233 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 7, .mask
= BIT(0) },
1234 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 7, .mask
= BIT(1) | BIT(2) },
1235 { .csi
= RVIN_CSI40
, .channel
= 3, .vin
= 7, .mask
= BIT(3) },
1236 { .csi
= RVIN_CSI20
, .channel
= 3, .vin
= 7, .mask
= BIT(4) },
1240 static const struct rvin_info rcar_info_r8a77965
= {
1246 .routes
= rcar_info_r8a77965_routes
,
1249 static const struct rvin_group_route rcar_info_r8a77970_routes
[] = {
1250 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 0, .mask
= BIT(0) | BIT(3) },
1251 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 1, .mask
= BIT(2) },
1252 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 1, .mask
= BIT(3) },
1253 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 2, .mask
= BIT(1) },
1254 { .csi
= RVIN_CSI40
, .channel
= 2, .vin
= 2, .mask
= BIT(3) },
1255 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 3, .mask
= BIT(0) },
1256 { .csi
= RVIN_CSI40
, .channel
= 3, .vin
= 3, .mask
= BIT(3) },
1260 static const struct rvin_info rcar_info_r8a77970
= {
1265 .routes
= rcar_info_r8a77970_routes
,
1268 static const struct rvin_group_route rcar_info_r8a77980_routes
[] = {
1269 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 0, .mask
= BIT(0) | BIT(3) },
1270 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 0, .mask
= BIT(2) },
1271 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 1, .mask
= BIT(2) },
1272 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 1, .mask
= BIT(1) | BIT(3) },
1273 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 2, .mask
= BIT(1) },
1274 { .csi
= RVIN_CSI40
, .channel
= 2, .vin
= 2, .mask
= BIT(3) },
1275 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 3, .mask
= BIT(0) },
1276 { .csi
= RVIN_CSI40
, .channel
= 3, .vin
= 3, .mask
= BIT(3) },
1277 { .csi
= RVIN_CSI41
, .channel
= 0, .vin
= 4, .mask
= BIT(0) | BIT(3) },
1278 { .csi
= RVIN_CSI41
, .channel
= 1, .vin
= 4, .mask
= BIT(2) },
1279 { .csi
= RVIN_CSI41
, .channel
= 0, .vin
= 5, .mask
= BIT(2) },
1280 { .csi
= RVIN_CSI41
, .channel
= 1, .vin
= 5, .mask
= BIT(1) | BIT(3) },
1281 { .csi
= RVIN_CSI41
, .channel
= 0, .vin
= 6, .mask
= BIT(1) },
1282 { .csi
= RVIN_CSI41
, .channel
= 2, .vin
= 6, .mask
= BIT(3) },
1283 { .csi
= RVIN_CSI41
, .channel
= 1, .vin
= 7, .mask
= BIT(0) },
1284 { .csi
= RVIN_CSI41
, .channel
= 3, .vin
= 7, .mask
= BIT(3) },
1288 static const struct rvin_info rcar_info_r8a77980
= {
1294 .routes
= rcar_info_r8a77980_routes
,
1297 static const struct rvin_group_route rcar_info_r8a77990_routes
[] = {
1298 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 4, .mask
= BIT(0) | BIT(3) },
1299 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 5, .mask
= BIT(2) },
1300 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 4, .mask
= BIT(2) },
1301 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 5, .mask
= BIT(1) | BIT(3) },
1305 static const struct rvin_info rcar_info_r8a77990
= {
1311 .routes
= rcar_info_r8a77990_routes
,
1314 static const struct rvin_group_route rcar_info_r8a77995_routes
[] = {
1318 static const struct rvin_info rcar_info_r8a77995
= {
1324 .routes
= rcar_info_r8a77995_routes
,
1327 static const struct of_device_id rvin_of_id_table
[] = {
1329 .compatible
= "renesas,vin-r8a774a1",
1330 .data
= &rcar_info_r8a7796
,
1333 .compatible
= "renesas,vin-r8a774b1",
1334 .data
= &rcar_info_r8a77965
,
1337 .compatible
= "renesas,vin-r8a774c0",
1338 .data
= &rcar_info_r8a77990
,
1341 .compatible
= "renesas,vin-r8a774e1",
1342 .data
= &rcar_info_r8a774e1
,
1345 .compatible
= "renesas,vin-r8a7778",
1346 .data
= &rcar_info_m1
,
1349 .compatible
= "renesas,vin-r8a7779",
1350 .data
= &rcar_info_h1
,
1353 .compatible
= "renesas,rcar-gen2-vin",
1354 .data
= &rcar_info_gen2
,
1357 .compatible
= "renesas,vin-r8a7795",
1358 .data
= &rcar_info_r8a7795
,
1361 .compatible
= "renesas,vin-r8a7796",
1362 .data
= &rcar_info_r8a7796
,
1365 .compatible
= "renesas,vin-r8a77965",
1366 .data
= &rcar_info_r8a77965
,
1369 .compatible
= "renesas,vin-r8a77970",
1370 .data
= &rcar_info_r8a77970
,
1373 .compatible
= "renesas,vin-r8a77980",
1374 .data
= &rcar_info_r8a77980
,
1377 .compatible
= "renesas,vin-r8a77990",
1378 .data
= &rcar_info_r8a77990
,
1381 .compatible
= "renesas,vin-r8a77995",
1382 .data
= &rcar_info_r8a77995
,
1386 MODULE_DEVICE_TABLE(of
, rvin_of_id_table
);
1388 static const struct soc_device_attribute r8a7795es1
[] = {
1390 .soc_id
= "r8a7795", .revision
= "ES1.*",
1391 .data
= &rcar_info_r8a7795es1
,
1396 static int rcar_vin_probe(struct platform_device
*pdev
)
1398 const struct soc_device_attribute
*attr
;
1399 struct rvin_dev
*vin
;
1402 vin
= devm_kzalloc(&pdev
->dev
, sizeof(*vin
), GFP_KERNEL
);
1406 vin
->dev
= &pdev
->dev
;
1407 vin
->info
= of_device_get_match_data(&pdev
->dev
);
1411 * Special care is needed on r8a7795 ES1.x since it
1412 * uses different routing than r8a7795 ES2.0.
1414 attr
= soc_device_match(r8a7795es1
);
1416 vin
->info
= attr
->data
;
1418 vin
->base
= devm_platform_ioremap_resource(pdev
, 0);
1419 if (IS_ERR(vin
->base
))
1420 return PTR_ERR(vin
->base
);
1422 irq
= platform_get_irq(pdev
, 0);
1426 ret
= rvin_dma_register(vin
, irq
);
1430 platform_set_drvdata(pdev
, vin
);
1432 if (vin
->info
->use_mc
) {
1433 ret
= rvin_mc_init(vin
);
1435 goto error_dma_unregister
;
1438 ret
= rvin_parallel_init(vin
);
1440 goto error_group_unregister
;
1442 pm_suspend_ignore_children(&pdev
->dev
, true);
1443 pm_runtime_enable(&pdev
->dev
);
1447 error_group_unregister
:
1448 v4l2_ctrl_handler_free(&vin
->ctrl_handler
);
1450 if (vin
->info
->use_mc
) {
1451 mutex_lock(&vin
->group
->lock
);
1452 if (&vin
->v4l2_dev
== vin
->group
->notifier
.v4l2_dev
) {
1453 v4l2_async_notifier_unregister(&vin
->group
->notifier
);
1454 v4l2_async_notifier_cleanup(&vin
->group
->notifier
);
1456 mutex_unlock(&vin
->group
->lock
);
1457 rvin_group_put(vin
);
1460 error_dma_unregister
:
1461 rvin_dma_unregister(vin
);
1466 static int rcar_vin_remove(struct platform_device
*pdev
)
1468 struct rvin_dev
*vin
= platform_get_drvdata(pdev
);
1470 pm_runtime_disable(&pdev
->dev
);
1472 rvin_v4l2_unregister(vin
);
1474 v4l2_async_notifier_unregister(&vin
->notifier
);
1475 v4l2_async_notifier_cleanup(&vin
->notifier
);
1477 if (vin
->info
->use_mc
) {
1478 v4l2_async_notifier_unregister(&vin
->group
->notifier
);
1479 v4l2_async_notifier_cleanup(&vin
->group
->notifier
);
1480 rvin_group_put(vin
);
1483 v4l2_ctrl_handler_free(&vin
->ctrl_handler
);
1485 rvin_dma_unregister(vin
);
1490 static SIMPLE_DEV_PM_OPS(rvin_pm_ops
, rvin_suspend
, rvin_resume
);
1492 static struct platform_driver rcar_vin_driver
= {
1496 .of_match_table
= rvin_of_id_table
,
1498 .probe
= rcar_vin_probe
,
1499 .remove
= rcar_vin_remove
,
1502 module_platform_driver(rcar_vin_driver
);
1504 MODULE_AUTHOR("Niklas Söderlund <niklas.soderlund@ragnatech.se>");
1505 MODULE_DESCRIPTION("Renesas R-Car VIN camera host driver");
1506 MODULE_LICENSE("GPL");