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
))
134 /* If any entity is in use don't allow link changes. */
135 media_device_for_each_entity(entity
, &group
->mdev
)
136 if (entity
->use_count
)
139 mutex_lock(&group
->lock
);
141 /* Find the master VIN that controls the routes. */
142 vdev
= media_entity_to_video_device(link
->sink
->entity
);
143 vin
= container_of(vdev
, struct rvin_dev
, vdev
);
144 master_id
= rvin_group_id_to_master(vin
->id
);
146 if (WARN_ON(!group
->vin
[master_id
])) {
151 /* Build a mask for already enabled links. */
152 for (i
= master_id
; i
< master_id
+ 4; i
++) {
156 /* Get remote CSI-2, if any. */
157 csi_pad
= media_entity_remote_pad(
158 &group
->vin
[i
]->vdev
.entity
.pads
[0]);
162 csi_id
= rvin_group_entity_to_csi_id(group
, csi_pad
->entity
);
163 channel
= rvin_group_csi_pad_to_channel(csi_pad
->index
);
165 mask
&= rvin_group_get_mask(group
->vin
[i
], csi_id
, channel
);
168 /* Add the new link to the existing mask and check if it works. */
169 csi_id
= rvin_group_entity_to_csi_id(group
, link
->source
->entity
);
171 if (csi_id
== -ENODEV
) {
172 struct v4l2_subdev
*sd
;
176 * Make sure the source entity subdevice is registered as
177 * a parallel input of one of the enabled VINs if it is not
178 * one of the CSI-2 subdevices.
180 * No hardware configuration required for parallel inputs,
181 * we can return here.
183 sd
= media_entity_to_v4l2_subdev(link
->source
->entity
);
184 for (i
= 0; i
< RCAR_VIN_NUM
; i
++) {
185 if (group
->vin
[i
] && group
->vin
[i
]->parallel
&&
186 group
->vin
[i
]->parallel
->subdev
== sd
) {
187 group
->vin
[i
]->is_csi
= false;
193 vin_err(vin
, "Subdevice %s not registered to any VIN\n",
194 link
->source
->entity
->name
);
199 channel
= rvin_group_csi_pad_to_channel(link
->source
->index
);
200 mask_new
= mask
& rvin_group_get_mask(vin
, csi_id
, channel
);
201 vin_dbg(vin
, "Try link change mask: 0x%x new: 0x%x\n", mask
, mask_new
);
208 /* New valid CHSEL found, set the new value. */
209 ret
= rvin_set_channel_routing(group
->vin
[master_id
], __ffs(mask_new
));
216 mutex_unlock(&group
->lock
);
221 static const struct media_device_ops rvin_media_ops
= {
222 .link_notify
= rvin_group_link_notify
,
225 /* -----------------------------------------------------------------------------
226 * Gen3 CSI2 Group Allocator
229 /* FIXME: This should if we find a system that supports more
230 * than one group for the whole system be replaced with a linked
231 * list of groups. And eventually all of this should be replaced
232 * with a global device allocator API.
234 * But for now this works as on all supported systems there will
235 * be only one group for all instances.
238 static DEFINE_MUTEX(rvin_group_lock
);
239 static struct rvin_group
*rvin_group_data
;
241 static void rvin_group_cleanup(struct rvin_group
*group
)
243 media_device_unregister(&group
->mdev
);
244 media_device_cleanup(&group
->mdev
);
245 mutex_destroy(&group
->lock
);
248 static int rvin_group_init(struct rvin_group
*group
, struct rvin_dev
*vin
)
250 struct media_device
*mdev
= &group
->mdev
;
251 const struct of_device_id
*match
;
252 struct device_node
*np
;
255 mutex_init(&group
->lock
);
257 /* Count number of VINs in the system */
259 for_each_matching_node(np
, vin
->dev
->driver
->of_match_table
)
260 if (of_device_is_available(np
))
263 vin_dbg(vin
, "found %u enabled VIN's in DT", group
->count
);
265 mdev
->dev
= vin
->dev
;
266 mdev
->ops
= &rvin_media_ops
;
268 match
= of_match_node(vin
->dev
->driver
->of_match_table
,
271 strlcpy(mdev
->driver_name
, KBUILD_MODNAME
, sizeof(mdev
->driver_name
));
272 strlcpy(mdev
->model
, match
->compatible
, sizeof(mdev
->model
));
273 snprintf(mdev
->bus_info
, sizeof(mdev
->bus_info
), "platform:%s",
274 dev_name(mdev
->dev
));
276 media_device_init(mdev
);
278 ret
= media_device_register(&group
->mdev
);
280 rvin_group_cleanup(group
);
285 static void rvin_group_release(struct kref
*kref
)
287 struct rvin_group
*group
=
288 container_of(kref
, struct rvin_group
, refcount
);
290 mutex_lock(&rvin_group_lock
);
292 rvin_group_data
= NULL
;
294 rvin_group_cleanup(group
);
298 mutex_unlock(&rvin_group_lock
);
301 static int rvin_group_get(struct rvin_dev
*vin
)
303 struct rvin_group
*group
;
307 /* Make sure VIN id is present and sane */
308 ret
= of_property_read_u32(vin
->dev
->of_node
, "renesas,id", &id
);
310 vin_err(vin
, "%pOF: No renesas,id property found\n",
315 if (id
>= RCAR_VIN_NUM
) {
316 vin_err(vin
, "%pOF: Invalid renesas,id '%u'\n",
317 vin
->dev
->of_node
, id
);
321 /* Join or create a VIN group */
322 mutex_lock(&rvin_group_lock
);
323 if (rvin_group_data
) {
324 group
= rvin_group_data
;
325 kref_get(&group
->refcount
);
327 group
= kzalloc(sizeof(*group
), GFP_KERNEL
);
333 ret
= rvin_group_init(group
, vin
);
336 vin_err(vin
, "Failed to initialize group\n");
340 kref_init(&group
->refcount
);
342 rvin_group_data
= group
;
344 mutex_unlock(&rvin_group_lock
);
346 /* Add VIN to group */
347 mutex_lock(&group
->lock
);
349 if (group
->vin
[id
]) {
350 vin_err(vin
, "Duplicate renesas,id property value %u\n", id
);
351 mutex_unlock(&group
->lock
);
352 kref_put(&group
->refcount
, rvin_group_release
);
356 group
->vin
[id
] = vin
;
360 vin
->v4l2_dev
.mdev
= &group
->mdev
;
362 mutex_unlock(&group
->lock
);
366 mutex_unlock(&rvin_group_lock
);
370 static void rvin_group_put(struct rvin_dev
*vin
)
372 struct rvin_group
*group
= vin
->group
;
374 mutex_lock(&group
->lock
);
377 vin
->v4l2_dev
.mdev
= NULL
;
379 if (WARN_ON(group
->vin
[vin
->id
] != vin
))
382 group
->vin
[vin
->id
] = NULL
;
384 mutex_unlock(&group
->lock
);
386 kref_put(&group
->refcount
, rvin_group_release
);
389 /* -----------------------------------------------------------------------------
393 static int rvin_find_pad(struct v4l2_subdev
*sd
, int direction
)
397 if (sd
->entity
.num_pads
<= 1)
400 for (pad
= 0; pad
< sd
->entity
.num_pads
; pad
++)
401 if (sd
->entity
.pads
[pad
].flags
& direction
)
407 /* -----------------------------------------------------------------------------
408 * Parallel async notifier
411 /* The vin lock should be held when calling the subdevice attach and detach */
412 static int rvin_parallel_subdevice_attach(struct rvin_dev
*vin
,
413 struct v4l2_subdev
*subdev
)
415 struct v4l2_subdev_mbus_code_enum code
= {
416 .which
= V4L2_SUBDEV_FORMAT_ACTIVE
,
420 /* Find source and sink pad of remote subdevice */
421 ret
= rvin_find_pad(subdev
, MEDIA_PAD_FL_SOURCE
);
424 vin
->parallel
->source_pad
= ret
;
426 ret
= rvin_find_pad(subdev
, MEDIA_PAD_FL_SINK
);
427 vin
->parallel
->sink_pad
= ret
< 0 ? 0 : ret
;
429 if (vin
->info
->use_mc
) {
430 vin
->parallel
->subdev
= subdev
;
434 /* Find compatible subdevices mbus format */
437 code
.pad
= vin
->parallel
->source_pad
;
438 while (!vin
->mbus_code
&&
439 !v4l2_subdev_call(subdev
, pad
, enum_mbus_code
, NULL
, &code
)) {
442 case MEDIA_BUS_FMT_YUYV8_1X16
:
443 case MEDIA_BUS_FMT_UYVY8_1X16
:
444 case MEDIA_BUS_FMT_UYVY8_2X8
:
445 case MEDIA_BUS_FMT_UYVY10_2X10
:
446 case MEDIA_BUS_FMT_RGB888_1X24
:
447 vin
->mbus_code
= code
.code
;
448 vin_dbg(vin
, "Found media bus format for %s: %d\n",
449 subdev
->name
, vin
->mbus_code
);
456 if (!vin
->mbus_code
) {
457 vin_err(vin
, "Unsupported media bus format for %s\n",
463 ret
= v4l2_subdev_call(subdev
, video
, g_tvnorms
, &vin
->vdev
.tvnorms
);
464 if (ret
< 0 && ret
!= -ENOIOCTLCMD
&& ret
!= -ENODEV
)
468 vin
->std
= V4L2_STD_UNKNOWN
;
469 ret
= v4l2_subdev_call(subdev
, video
, g_std
, &vin
->std
);
470 if (ret
< 0 && ret
!= -ENOIOCTLCMD
)
473 /* Add the controls */
474 ret
= v4l2_ctrl_handler_init(&vin
->ctrl_handler
, 16);
478 ret
= v4l2_ctrl_add_handler(&vin
->ctrl_handler
, subdev
->ctrl_handler
,
481 v4l2_ctrl_handler_free(&vin
->ctrl_handler
);
485 vin
->vdev
.ctrl_handler
= &vin
->ctrl_handler
;
487 vin
->parallel
->subdev
= subdev
;
492 static void rvin_parallel_subdevice_detach(struct rvin_dev
*vin
)
494 rvin_v4l2_unregister(vin
);
495 vin
->parallel
->subdev
= NULL
;
497 if (!vin
->info
->use_mc
) {
498 v4l2_ctrl_handler_free(&vin
->ctrl_handler
);
499 vin
->vdev
.ctrl_handler
= NULL
;
503 static int rvin_parallel_notify_complete(struct v4l2_async_notifier
*notifier
)
505 struct rvin_dev
*vin
= v4l2_dev_to_vin(notifier
->v4l2_dev
);
506 struct media_entity
*source
;
507 struct media_entity
*sink
;
510 ret
= v4l2_device_register_subdev_nodes(&vin
->v4l2_dev
);
512 vin_err(vin
, "Failed to register subdev nodes\n");
516 if (!video_is_registered(&vin
->vdev
)) {
517 ret
= rvin_v4l2_register(vin
);
522 if (!vin
->info
->use_mc
)
525 /* If we're running with media-controller, link the subdevs. */
526 source
= &vin
->parallel
->subdev
->entity
;
527 sink
= &vin
->vdev
.entity
;
529 ret
= media_create_pad_link(source
, vin
->parallel
->source_pad
,
530 sink
, vin
->parallel
->sink_pad
, 0);
532 vin_err(vin
, "Error adding link from %s to %s: %d\n",
533 source
->name
, sink
->name
, ret
);
538 static void rvin_parallel_notify_unbind(struct v4l2_async_notifier
*notifier
,
539 struct v4l2_subdev
*subdev
,
540 struct v4l2_async_subdev
*asd
)
542 struct rvin_dev
*vin
= v4l2_dev_to_vin(notifier
->v4l2_dev
);
544 vin_dbg(vin
, "unbind parallel subdev %s\n", subdev
->name
);
546 mutex_lock(&vin
->lock
);
547 rvin_parallel_subdevice_detach(vin
);
548 mutex_unlock(&vin
->lock
);
551 static int rvin_parallel_notify_bound(struct v4l2_async_notifier
*notifier
,
552 struct v4l2_subdev
*subdev
,
553 struct v4l2_async_subdev
*asd
)
555 struct rvin_dev
*vin
= v4l2_dev_to_vin(notifier
->v4l2_dev
);
558 mutex_lock(&vin
->lock
);
559 ret
= rvin_parallel_subdevice_attach(vin
, subdev
);
560 mutex_unlock(&vin
->lock
);
564 v4l2_set_subdev_hostdata(subdev
, vin
);
566 vin_dbg(vin
, "bound subdev %s source pad: %u sink pad: %u\n",
567 subdev
->name
, vin
->parallel
->source_pad
,
568 vin
->parallel
->sink_pad
);
573 static const struct v4l2_async_notifier_operations rvin_parallel_notify_ops
= {
574 .bound
= rvin_parallel_notify_bound
,
575 .unbind
= rvin_parallel_notify_unbind
,
576 .complete
= rvin_parallel_notify_complete
,
579 static int rvin_parallel_parse_v4l2(struct device
*dev
,
580 struct v4l2_fwnode_endpoint
*vep
,
581 struct v4l2_async_subdev
*asd
)
583 struct rvin_dev
*vin
= dev_get_drvdata(dev
);
584 struct rvin_parallel_entity
*rvpe
=
585 container_of(asd
, struct rvin_parallel_entity
, asd
);
587 if (vep
->base
.port
|| vep
->base
.id
)
590 vin
->parallel
= rvpe
;
591 vin
->parallel
->mbus_type
= vep
->bus_type
;
593 switch (vin
->parallel
->mbus_type
) {
594 case V4L2_MBUS_PARALLEL
:
595 vin_dbg(vin
, "Found PARALLEL media bus\n");
596 vin
->parallel
->mbus_flags
= vep
->bus
.parallel
.flags
;
598 case V4L2_MBUS_BT656
:
599 vin_dbg(vin
, "Found BT656 media bus\n");
600 vin
->parallel
->mbus_flags
= 0;
603 vin_err(vin
, "Unknown media bus type\n");
610 static int rvin_parallel_init(struct rvin_dev
*vin
)
614 ret
= v4l2_async_notifier_parse_fwnode_endpoints_by_port(
615 vin
->dev
, &vin
->notifier
, sizeof(struct rvin_parallel_entity
),
616 0, rvin_parallel_parse_v4l2
);
620 /* If using mc, it's fine not to have any input registered. */
622 return vin
->info
->use_mc
? 0 : -ENODEV
;
624 vin_dbg(vin
, "Found parallel subdevice %pOF\n",
625 to_of_node(vin
->parallel
->asd
.match
.fwnode
));
627 vin
->notifier
.ops
= &rvin_parallel_notify_ops
;
628 ret
= v4l2_async_notifier_register(&vin
->v4l2_dev
, &vin
->notifier
);
630 vin_err(vin
, "Notifier registration failed\n");
631 v4l2_async_notifier_cleanup(&vin
->group
->notifier
);
638 /* -----------------------------------------------------------------------------
639 * Group async notifier
642 static int rvin_group_notify_complete(struct v4l2_async_notifier
*notifier
)
644 struct rvin_dev
*vin
= v4l2_dev_to_vin(notifier
->v4l2_dev
);
645 const struct rvin_group_route
*route
;
649 ret
= v4l2_device_register_subdev_nodes(&vin
->v4l2_dev
);
651 vin_err(vin
, "Failed to register subdev nodes\n");
655 /* Register all video nodes for the group. */
656 for (i
= 0; i
< RCAR_VIN_NUM
; i
++) {
657 if (vin
->group
->vin
[i
] &&
658 !video_is_registered(&vin
->group
->vin
[i
]->vdev
)) {
659 ret
= rvin_v4l2_register(vin
->group
->vin
[i
]);
665 /* Create all media device links between VINs and CSI-2's. */
666 mutex_lock(&vin
->group
->lock
);
667 for (route
= vin
->info
->routes
; route
->mask
; route
++) {
668 struct media_pad
*source_pad
, *sink_pad
;
669 struct media_entity
*source
, *sink
;
670 unsigned int source_idx
;
672 /* Check that VIN is part of the group. */
673 if (!vin
->group
->vin
[route
->vin
])
676 /* Check that VIN' master is part of the group. */
677 if (!vin
->group
->vin
[rvin_group_id_to_master(route
->vin
)])
680 /* Check that CSI-2 is part of the group. */
681 if (!vin
->group
->csi
[route
->csi
].subdev
)
684 source
= &vin
->group
->csi
[route
->csi
].subdev
->entity
;
685 source_idx
= rvin_group_csi_channel_to_pad(route
->channel
);
686 source_pad
= &source
->pads
[source_idx
];
688 sink
= &vin
->group
->vin
[route
->vin
]->vdev
.entity
;
689 sink_pad
= &sink
->pads
[0];
691 /* Skip if link already exists. */
692 if (media_entity_find_link(source_pad
, sink_pad
))
695 ret
= media_create_pad_link(source
, source_idx
, sink
, 0, 0);
697 vin_err(vin
, "Error adding link from %s to %s\n",
698 source
->name
, sink
->name
);
702 mutex_unlock(&vin
->group
->lock
);
707 static void rvin_group_notify_unbind(struct v4l2_async_notifier
*notifier
,
708 struct v4l2_subdev
*subdev
,
709 struct v4l2_async_subdev
*asd
)
711 struct rvin_dev
*vin
= v4l2_dev_to_vin(notifier
->v4l2_dev
);
714 for (i
= 0; i
< RCAR_VIN_NUM
; i
++)
715 if (vin
->group
->vin
[i
])
716 rvin_v4l2_unregister(vin
->group
->vin
[i
]);
718 mutex_lock(&vin
->group
->lock
);
720 for (i
= 0; i
< RVIN_CSI_MAX
; i
++) {
721 if (vin
->group
->csi
[i
].fwnode
!= asd
->match
.fwnode
)
723 vin
->group
->csi
[i
].subdev
= NULL
;
724 vin_dbg(vin
, "Unbind CSI-2 %s from slot %u\n", subdev
->name
, i
);
728 mutex_unlock(&vin
->group
->lock
);
731 static int rvin_group_notify_bound(struct v4l2_async_notifier
*notifier
,
732 struct v4l2_subdev
*subdev
,
733 struct v4l2_async_subdev
*asd
)
735 struct rvin_dev
*vin
= v4l2_dev_to_vin(notifier
->v4l2_dev
);
738 mutex_lock(&vin
->group
->lock
);
740 for (i
= 0; i
< RVIN_CSI_MAX
; i
++) {
741 if (vin
->group
->csi
[i
].fwnode
!= asd
->match
.fwnode
)
743 vin
->group
->csi
[i
].subdev
= subdev
;
744 vin_dbg(vin
, "Bound CSI-2 %s to slot %u\n", subdev
->name
, i
);
748 mutex_unlock(&vin
->group
->lock
);
753 static const struct v4l2_async_notifier_operations rvin_group_notify_ops
= {
754 .bound
= rvin_group_notify_bound
,
755 .unbind
= rvin_group_notify_unbind
,
756 .complete
= rvin_group_notify_complete
,
759 static int rvin_mc_parse_of_endpoint(struct device
*dev
,
760 struct v4l2_fwnode_endpoint
*vep
,
761 struct v4l2_async_subdev
*asd
)
763 struct rvin_dev
*vin
= dev_get_drvdata(dev
);
765 if (vep
->base
.port
!= 1 || vep
->base
.id
>= RVIN_CSI_MAX
)
768 if (!of_device_is_available(to_of_node(asd
->match
.fwnode
))) {
769 vin_dbg(vin
, "OF device %pOF disabled, ignoring\n",
770 to_of_node(asd
->match
.fwnode
));
774 if (vin
->group
->csi
[vep
->base
.id
].fwnode
) {
775 vin_dbg(vin
, "OF device %pOF already handled\n",
776 to_of_node(asd
->match
.fwnode
));
780 vin
->group
->csi
[vep
->base
.id
].fwnode
= asd
->match
.fwnode
;
782 vin_dbg(vin
, "Add group OF device %pOF to slot %u\n",
783 to_of_node(asd
->match
.fwnode
), vep
->base
.id
);
788 static int rvin_mc_parse_of_graph(struct rvin_dev
*vin
)
790 unsigned int count
= 0;
794 mutex_lock(&vin
->group
->lock
);
796 /* If not all VIN's are registered don't register the notifier. */
797 for (i
= 0; i
< RCAR_VIN_NUM
; i
++)
798 if (vin
->group
->vin
[i
])
801 if (vin
->group
->count
!= count
) {
802 mutex_unlock(&vin
->group
->lock
);
807 * Have all VIN's look for CSI-2 subdevices. Some subdevices will
808 * overlap but the parser function can handle it, so each subdevice
809 * will only be registered once with the group notifier.
811 for (i
= 0; i
< RCAR_VIN_NUM
; i
++) {
812 if (!vin
->group
->vin
[i
])
815 ret
= v4l2_async_notifier_parse_fwnode_endpoints_by_port(
816 vin
->group
->vin
[i
]->dev
, &vin
->group
->notifier
,
817 sizeof(struct v4l2_async_subdev
), 1,
818 rvin_mc_parse_of_endpoint
);
820 mutex_unlock(&vin
->group
->lock
);
825 mutex_unlock(&vin
->group
->lock
);
827 if (!vin
->group
->notifier
.num_subdevs
)
830 vin
->group
->notifier
.ops
= &rvin_group_notify_ops
;
831 ret
= v4l2_async_notifier_register(&vin
->v4l2_dev
,
832 &vin
->group
->notifier
);
834 vin_err(vin
, "Notifier registration failed\n");
835 v4l2_async_notifier_cleanup(&vin
->group
->notifier
);
842 static int rvin_mc_init(struct rvin_dev
*vin
)
846 vin
->pad
.flags
= MEDIA_PAD_FL_SINK
;
847 ret
= media_entity_pads_init(&vin
->vdev
.entity
, 1, &vin
->pad
);
851 ret
= rvin_group_get(vin
);
855 ret
= rvin_mc_parse_of_graph(vin
);
862 /* -----------------------------------------------------------------------------
863 * Platform Device Driver
866 static const struct rvin_info rcar_info_h1
= {
873 static const struct rvin_info rcar_info_m1
= {
880 static const struct rvin_info rcar_info_gen2
= {
887 static const struct rvin_group_route rcar_info_r8a7795_routes
[] = {
888 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 0, .mask
= BIT(0) | BIT(3) },
889 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 0, .mask
= BIT(1) | BIT(4) },
890 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 0, .mask
= BIT(2) },
891 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 1, .mask
= BIT(0) },
892 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 1, .mask
= BIT(1) | BIT(3) },
893 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 1, .mask
= BIT(2) },
894 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 1, .mask
= BIT(4) },
895 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 2, .mask
= BIT(0) },
896 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 2, .mask
= BIT(1) },
897 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 2, .mask
= BIT(2) },
898 { .csi
= RVIN_CSI40
, .channel
= 2, .vin
= 2, .mask
= BIT(3) },
899 { .csi
= RVIN_CSI20
, .channel
= 2, .vin
= 2, .mask
= BIT(4) },
900 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 3, .mask
= BIT(0) },
901 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 3, .mask
= BIT(1) | BIT(2) },
902 { .csi
= RVIN_CSI40
, .channel
= 3, .vin
= 3, .mask
= BIT(3) },
903 { .csi
= RVIN_CSI20
, .channel
= 3, .vin
= 3, .mask
= BIT(4) },
904 { .csi
= RVIN_CSI41
, .channel
= 0, .vin
= 4, .mask
= BIT(0) | BIT(3) },
905 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 4, .mask
= BIT(1) | BIT(4) },
906 { .csi
= RVIN_CSI41
, .channel
= 1, .vin
= 4, .mask
= BIT(2) },
907 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 5, .mask
= BIT(0) },
908 { .csi
= RVIN_CSI41
, .channel
= 1, .vin
= 5, .mask
= BIT(1) | BIT(3) },
909 { .csi
= RVIN_CSI41
, .channel
= 0, .vin
= 5, .mask
= BIT(2) },
910 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 5, .mask
= BIT(4) },
911 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 6, .mask
= BIT(0) },
912 { .csi
= RVIN_CSI41
, .channel
= 0, .vin
= 6, .mask
= BIT(1) },
913 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 6, .mask
= BIT(2) },
914 { .csi
= RVIN_CSI41
, .channel
= 2, .vin
= 6, .mask
= BIT(3) },
915 { .csi
= RVIN_CSI20
, .channel
= 2, .vin
= 6, .mask
= BIT(4) },
916 { .csi
= RVIN_CSI41
, .channel
= 1, .vin
= 7, .mask
= BIT(0) },
917 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 7, .mask
= BIT(1) | BIT(2) },
918 { .csi
= RVIN_CSI41
, .channel
= 3, .vin
= 7, .mask
= BIT(3) },
919 { .csi
= RVIN_CSI20
, .channel
= 3, .vin
= 7, .mask
= BIT(4) },
923 static const struct rvin_info rcar_info_r8a7795
= {
928 .routes
= rcar_info_r8a7795_routes
,
931 static const struct rvin_group_route rcar_info_r8a7795es1_routes
[] = {
932 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 0, .mask
= BIT(0) | BIT(3) },
933 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 0, .mask
= BIT(1) | BIT(4) },
934 { .csi
= RVIN_CSI21
, .channel
= 0, .vin
= 0, .mask
= BIT(2) | BIT(5) },
935 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 1, .mask
= BIT(0) },
936 { .csi
= RVIN_CSI21
, .channel
= 0, .vin
= 1, .mask
= BIT(1) },
937 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 1, .mask
= BIT(2) },
938 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 1, .mask
= BIT(3) },
939 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 1, .mask
= BIT(4) },
940 { .csi
= RVIN_CSI21
, .channel
= 1, .vin
= 1, .mask
= BIT(5) },
941 { .csi
= RVIN_CSI21
, .channel
= 0, .vin
= 2, .mask
= BIT(0) },
942 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 2, .mask
= BIT(1) },
943 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 2, .mask
= BIT(2) },
944 { .csi
= RVIN_CSI40
, .channel
= 2, .vin
= 2, .mask
= BIT(3) },
945 { .csi
= RVIN_CSI20
, .channel
= 2, .vin
= 2, .mask
= BIT(4) },
946 { .csi
= RVIN_CSI21
, .channel
= 2, .vin
= 2, .mask
= BIT(5) },
947 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 3, .mask
= BIT(0) },
948 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 3, .mask
= BIT(1) },
949 { .csi
= RVIN_CSI21
, .channel
= 1, .vin
= 3, .mask
= BIT(2) },
950 { .csi
= RVIN_CSI40
, .channel
= 3, .vin
= 3, .mask
= BIT(3) },
951 { .csi
= RVIN_CSI20
, .channel
= 3, .vin
= 3, .mask
= BIT(4) },
952 { .csi
= RVIN_CSI21
, .channel
= 3, .vin
= 3, .mask
= BIT(5) },
953 { .csi
= RVIN_CSI41
, .channel
= 0, .vin
= 4, .mask
= BIT(0) | BIT(3) },
954 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 4, .mask
= BIT(1) | BIT(4) },
955 { .csi
= RVIN_CSI21
, .channel
= 0, .vin
= 4, .mask
= BIT(2) | BIT(5) },
956 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 5, .mask
= BIT(0) },
957 { .csi
= RVIN_CSI21
, .channel
= 0, .vin
= 5, .mask
= BIT(1) },
958 { .csi
= RVIN_CSI41
, .channel
= 0, .vin
= 5, .mask
= BIT(2) },
959 { .csi
= RVIN_CSI41
, .channel
= 1, .vin
= 5, .mask
= BIT(3) },
960 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 5, .mask
= BIT(4) },
961 { .csi
= RVIN_CSI21
, .channel
= 1, .vin
= 5, .mask
= BIT(5) },
962 { .csi
= RVIN_CSI21
, .channel
= 0, .vin
= 6, .mask
= BIT(0) },
963 { .csi
= RVIN_CSI41
, .channel
= 0, .vin
= 6, .mask
= BIT(1) },
964 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 6, .mask
= BIT(2) },
965 { .csi
= RVIN_CSI41
, .channel
= 2, .vin
= 6, .mask
= BIT(3) },
966 { .csi
= RVIN_CSI20
, .channel
= 2, .vin
= 6, .mask
= BIT(4) },
967 { .csi
= RVIN_CSI21
, .channel
= 2, .vin
= 6, .mask
= BIT(5) },
968 { .csi
= RVIN_CSI41
, .channel
= 1, .vin
= 7, .mask
= BIT(0) },
969 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 7, .mask
= BIT(1) },
970 { .csi
= RVIN_CSI21
, .channel
= 1, .vin
= 7, .mask
= BIT(2) },
971 { .csi
= RVIN_CSI41
, .channel
= 3, .vin
= 7, .mask
= BIT(3) },
972 { .csi
= RVIN_CSI20
, .channel
= 3, .vin
= 7, .mask
= BIT(4) },
973 { .csi
= RVIN_CSI21
, .channel
= 3, .vin
= 7, .mask
= BIT(5) },
977 static const struct rvin_info rcar_info_r8a7795es1
= {
982 .routes
= rcar_info_r8a7795es1_routes
,
985 static const struct rvin_group_route rcar_info_r8a7796_routes
[] = {
986 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 0, .mask
= BIT(0) | BIT(3) },
987 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 0, .mask
= BIT(1) | BIT(4) },
988 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 1, .mask
= BIT(0) },
989 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 1, .mask
= BIT(2) },
990 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 1, .mask
= BIT(3) },
991 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 1, .mask
= BIT(4) },
992 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 2, .mask
= BIT(1) },
993 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 2, .mask
= BIT(2) },
994 { .csi
= RVIN_CSI40
, .channel
= 2, .vin
= 2, .mask
= BIT(3) },
995 { .csi
= RVIN_CSI20
, .channel
= 2, .vin
= 2, .mask
= BIT(4) },
996 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 3, .mask
= BIT(0) },
997 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 3, .mask
= BIT(1) },
998 { .csi
= RVIN_CSI40
, .channel
= 3, .vin
= 3, .mask
= BIT(3) },
999 { .csi
= RVIN_CSI20
, .channel
= 3, .vin
= 3, .mask
= BIT(4) },
1000 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 4, .mask
= BIT(0) | BIT(3) },
1001 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 4, .mask
= BIT(1) | BIT(4) },
1002 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 5, .mask
= BIT(0) },
1003 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 5, .mask
= BIT(2) },
1004 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 5, .mask
= BIT(3) },
1005 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 5, .mask
= BIT(4) },
1006 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 6, .mask
= BIT(1) },
1007 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 6, .mask
= BIT(2) },
1008 { .csi
= RVIN_CSI40
, .channel
= 2, .vin
= 6, .mask
= BIT(3) },
1009 { .csi
= RVIN_CSI20
, .channel
= 2, .vin
= 6, .mask
= BIT(4) },
1010 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 7, .mask
= BIT(0) },
1011 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 7, .mask
= BIT(1) },
1012 { .csi
= RVIN_CSI40
, .channel
= 3, .vin
= 7, .mask
= BIT(3) },
1013 { .csi
= RVIN_CSI20
, .channel
= 3, .vin
= 7, .mask
= BIT(4) },
1017 static const struct rvin_info rcar_info_r8a7796
= {
1022 .routes
= rcar_info_r8a7796_routes
,
1025 static const struct rvin_group_route rcar_info_r8a77965_routes
[] = {
1026 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 0, .mask
= BIT(0) | BIT(3) },
1027 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 0, .mask
= BIT(1) | BIT(4) },
1028 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 0, .mask
= BIT(2) },
1029 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 1, .mask
= BIT(0) },
1030 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 1, .mask
= BIT(1) | BIT(3) },
1031 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 1, .mask
= BIT(2) },
1032 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 1, .mask
= BIT(4) },
1033 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 2, .mask
= BIT(0) },
1034 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 2, .mask
= BIT(1) },
1035 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 2, .mask
= BIT(2) },
1036 { .csi
= RVIN_CSI40
, .channel
= 2, .vin
= 2, .mask
= BIT(3) },
1037 { .csi
= RVIN_CSI20
, .channel
= 2, .vin
= 2, .mask
= BIT(4) },
1038 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 3, .mask
= BIT(0) },
1039 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 3, .mask
= BIT(1) | BIT(2) },
1040 { .csi
= RVIN_CSI40
, .channel
= 3, .vin
= 3, .mask
= BIT(3) },
1041 { .csi
= RVIN_CSI20
, .channel
= 3, .vin
= 3, .mask
= BIT(4) },
1042 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 4, .mask
= BIT(0) | BIT(3) },
1043 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 4, .mask
= BIT(1) | BIT(4) },
1044 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 4, .mask
= BIT(2) },
1045 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 5, .mask
= BIT(0) },
1046 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 5, .mask
= BIT(1) | BIT(3) },
1047 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 5, .mask
= BIT(2) },
1048 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 5, .mask
= BIT(4) },
1049 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 6, .mask
= BIT(0) },
1050 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 6, .mask
= BIT(1) },
1051 { .csi
= RVIN_CSI20
, .channel
= 0, .vin
= 6, .mask
= BIT(2) },
1052 { .csi
= RVIN_CSI40
, .channel
= 2, .vin
= 6, .mask
= BIT(3) },
1053 { .csi
= RVIN_CSI20
, .channel
= 2, .vin
= 6, .mask
= BIT(4) },
1054 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 7, .mask
= BIT(0) },
1055 { .csi
= RVIN_CSI20
, .channel
= 1, .vin
= 7, .mask
= BIT(1) | BIT(2) },
1056 { .csi
= RVIN_CSI40
, .channel
= 3, .vin
= 7, .mask
= BIT(3) },
1057 { .csi
= RVIN_CSI20
, .channel
= 3, .vin
= 7, .mask
= BIT(4) },
1061 static const struct rvin_info rcar_info_r8a77965
= {
1066 .routes
= rcar_info_r8a77965_routes
,
1069 static const struct rvin_group_route rcar_info_r8a77970_routes
[] = {
1070 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 0, .mask
= BIT(0) | BIT(3) },
1071 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 1, .mask
= BIT(2) },
1072 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 1, .mask
= BIT(3) },
1073 { .csi
= RVIN_CSI40
, .channel
= 0, .vin
= 2, .mask
= BIT(1) },
1074 { .csi
= RVIN_CSI40
, .channel
= 2, .vin
= 2, .mask
= BIT(3) },
1075 { .csi
= RVIN_CSI40
, .channel
= 1, .vin
= 3, .mask
= BIT(0) },
1076 { .csi
= RVIN_CSI40
, .channel
= 3, .vin
= 3, .mask
= BIT(3) },
1080 static const struct rvin_info rcar_info_r8a77970
= {
1085 .routes
= rcar_info_r8a77970_routes
,
1088 static const struct rvin_group_route rcar_info_r8a77995_routes
[] = {
1092 static const struct rvin_info rcar_info_r8a77995
= {
1097 .routes
= rcar_info_r8a77995_routes
,
1100 static const struct of_device_id rvin_of_id_table
[] = {
1102 .compatible
= "renesas,vin-r8a7778",
1103 .data
= &rcar_info_m1
,
1106 .compatible
= "renesas,vin-r8a7779",
1107 .data
= &rcar_info_h1
,
1110 .compatible
= "renesas,vin-r8a7790",
1111 .data
= &rcar_info_gen2
,
1114 .compatible
= "renesas,vin-r8a7791",
1115 .data
= &rcar_info_gen2
,
1118 .compatible
= "renesas,vin-r8a7793",
1119 .data
= &rcar_info_gen2
,
1122 .compatible
= "renesas,vin-r8a7794",
1123 .data
= &rcar_info_gen2
,
1126 .compatible
= "renesas,rcar-gen2-vin",
1127 .data
= &rcar_info_gen2
,
1130 .compatible
= "renesas,vin-r8a7795",
1131 .data
= &rcar_info_r8a7795
,
1134 .compatible
= "renesas,vin-r8a7796",
1135 .data
= &rcar_info_r8a7796
,
1138 .compatible
= "renesas,vin-r8a77965",
1139 .data
= &rcar_info_r8a77965
,
1142 .compatible
= "renesas,vin-r8a77970",
1143 .data
= &rcar_info_r8a77970
,
1146 .compatible
= "renesas,vin-r8a77995",
1147 .data
= &rcar_info_r8a77995
,
1151 MODULE_DEVICE_TABLE(of
, rvin_of_id_table
);
1153 static const struct soc_device_attribute r8a7795es1
[] = {
1155 .soc_id
= "r8a7795", .revision
= "ES1.*",
1156 .data
= &rcar_info_r8a7795es1
,
1161 static int rcar_vin_probe(struct platform_device
*pdev
)
1163 const struct soc_device_attribute
*attr
;
1164 struct rvin_dev
*vin
;
1165 struct resource
*mem
;
1168 vin
= devm_kzalloc(&pdev
->dev
, sizeof(*vin
), GFP_KERNEL
);
1172 vin
->dev
= &pdev
->dev
;
1173 vin
->info
= of_device_get_match_data(&pdev
->dev
);
1176 * Special care is needed on r8a7795 ES1.x since it
1177 * uses different routing than r8a7795 ES2.0.
1179 attr
= soc_device_match(r8a7795es1
);
1181 vin
->info
= attr
->data
;
1183 mem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
1187 vin
->base
= devm_ioremap_resource(vin
->dev
, mem
);
1188 if (IS_ERR(vin
->base
))
1189 return PTR_ERR(vin
->base
);
1191 irq
= platform_get_irq(pdev
, 0);
1195 ret
= rvin_dma_register(vin
, irq
);
1199 platform_set_drvdata(pdev
, vin
);
1201 if (vin
->info
->use_mc
) {
1202 ret
= rvin_mc_init(vin
);
1204 goto error_dma_unregister
;
1207 ret
= rvin_parallel_init(vin
);
1209 goto error_group_unregister
;
1211 pm_suspend_ignore_children(&pdev
->dev
, true);
1212 pm_runtime_enable(&pdev
->dev
);
1216 error_group_unregister
:
1217 if (vin
->info
->use_mc
) {
1218 mutex_lock(&vin
->group
->lock
);
1219 if (&vin
->v4l2_dev
== vin
->group
->notifier
.v4l2_dev
) {
1220 v4l2_async_notifier_unregister(&vin
->group
->notifier
);
1221 v4l2_async_notifier_cleanup(&vin
->group
->notifier
);
1223 mutex_unlock(&vin
->group
->lock
);
1224 rvin_group_put(vin
);
1227 error_dma_unregister
:
1228 rvin_dma_unregister(vin
);
1233 static int rcar_vin_remove(struct platform_device
*pdev
)
1235 struct rvin_dev
*vin
= platform_get_drvdata(pdev
);
1237 pm_runtime_disable(&pdev
->dev
);
1239 rvin_v4l2_unregister(vin
);
1241 v4l2_async_notifier_unregister(&vin
->notifier
);
1242 v4l2_async_notifier_cleanup(&vin
->notifier
);
1244 if (vin
->info
->use_mc
) {
1245 mutex_lock(&vin
->group
->lock
);
1246 if (&vin
->v4l2_dev
== vin
->group
->notifier
.v4l2_dev
) {
1247 v4l2_async_notifier_unregister(&vin
->group
->notifier
);
1248 v4l2_async_notifier_cleanup(&vin
->group
->notifier
);
1250 mutex_unlock(&vin
->group
->lock
);
1251 rvin_group_put(vin
);
1253 v4l2_ctrl_handler_free(&vin
->ctrl_handler
);
1256 rvin_dma_unregister(vin
);
1261 static struct platform_driver rcar_vin_driver
= {
1264 .of_match_table
= rvin_of_id_table
,
1266 .probe
= rcar_vin_probe
,
1267 .remove
= rcar_vin_remove
,
1270 module_platform_driver(rcar_vin_driver
);
1272 MODULE_AUTHOR("Niklas Söderlund <niklas.soderlund@ragnatech.se>");
1273 MODULE_DESCRIPTION("Renesas R-Car VIN camera host driver");
1274 MODULE_LICENSE("GPL");