1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/module.h>
14#include <linux/of.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>
21
22#include <media/v4l2-async.h>
23#include <media/v4l2-fwnode.h>
24#include <media/v4l2-mc.h>
25
26#include "rcar-vin.h"
27
28
29
30
31
32
33
34
35#define rvin_group_csi_pad_to_channel(pad) ((pad) - 1)
36#define rvin_group_csi_channel_to_pad(channel) ((channel) + 1)
37
38
39
40
41
42
43#define rvin_group_id_to_master(vin) ((vin) < 4 ? 0 : 4)
44
45#define v4l2_dev_to_vin(d) container_of(d, struct rvin_dev, v4l2_dev)
46
47
48
49
50
51
52static int rvin_group_entity_to_csi_id(struct rvin_group *group,
53 struct media_entity *entity)
54{
55 struct v4l2_subdev *sd;
56 unsigned int i;
57
58 sd = media_entity_to_v4l2_subdev(entity);
59
60 for (i = 0; i < RVIN_CSI_MAX; i++)
61 if (group->csi[i].subdev == sd)
62 return i;
63
64 return -ENODEV;
65}
66
67static unsigned int rvin_group_get_mask(struct rvin_dev *vin,
68 enum rvin_csi_id csi_id,
69 unsigned char channel)
70{
71 const struct rvin_group_route *route;
72 unsigned int mask = 0;
73
74 for (route = vin->info->routes; route->mask; route++) {
75 if (route->vin == vin->id &&
76 route->csi == csi_id &&
77 route->channel == channel) {
78 vin_dbg(vin,
79 "Adding route: vin: %d csi: %d channel: %d\n",
80 route->vin, route->csi, route->channel);
81 mask |= route->mask;
82 }
83 }
84
85 return mask;
86}
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112static int rvin_group_link_notify(struct media_link *link, u32 flags,
113 unsigned int notification)
114{
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;
123 int csi_id, ret;
124
125 ret = v4l2_pipeline_link_notify(link, flags, notification);
126 if (ret)
127 return ret;
128
129
130 if (!(flags & MEDIA_LNK_FL_ENABLED) ||
131 !is_media_entity_v4l2_video_device(link->sink->entity))
132 return 0;
133
134
135
136
137
138
139 media_device_for_each_entity(entity, &group->mdev)
140 if (entity->stream_count)
141 return -EBUSY;
142
143 mutex_lock(&group->lock);
144
145
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);
149
150 if (WARN_ON(!group->vin[master_id])) {
151 ret = -ENODEV;
152 goto out;
153 }
154
155
156 for (i = master_id; i < master_id + 4; i++) {
157 if (!group->vin[i])
158 continue;
159
160
161 csi_pad = media_entity_remote_pad(
162 &group->vin[i]->vdev.entity.pads[0]);
163 if (!csi_pad)
164 continue;
165
166 csi_id = rvin_group_entity_to_csi_id(group, csi_pad->entity);
167 channel = rvin_group_csi_pad_to_channel(csi_pad->index);
168
169 mask &= rvin_group_get_mask(group->vin[i], csi_id, channel);
170 }
171
172
173 csi_id = rvin_group_entity_to_csi_id(group, link->source->entity);
174
175 if (csi_id == -ENODEV) {
176 struct v4l2_subdev *sd;
177
178
179
180
181
182
183
184
185
186 sd = media_entity_to_v4l2_subdev(link->source->entity);
187 for (i = 0; i < RCAR_VIN_NUM; i++) {
188 if (group->vin[i] && group->vin[i]->parallel &&
189 group->vin[i]->parallel->subdev == sd) {
190 group->vin[i]->is_csi = false;
191 ret = 0;
192 goto out;
193 }
194 }
195
196 vin_err(vin, "Subdevice %s not registered to any VIN\n",
197 link->source->entity->name);
198 ret = -ENODEV;
199 goto out;
200 }
201
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);
205
206 if (!mask_new) {
207 ret = -EMLINK;
208 goto out;
209 }
210
211
212 ret = rvin_set_channel_routing(group->vin[master_id], __ffs(mask_new));
213 if (ret)
214 goto out;
215
216 vin->is_csi = true;
217
218out:
219 mutex_unlock(&group->lock);
220
221 return ret;
222}
223
224static const struct media_device_ops rvin_media_ops = {
225 .link_notify = rvin_group_link_notify,
226};
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241static DEFINE_MUTEX(rvin_group_lock);
242static struct rvin_group *rvin_group_data;
243
244static void rvin_group_cleanup(struct rvin_group *group)
245{
246 media_device_unregister(&group->mdev);
247 media_device_cleanup(&group->mdev);
248 mutex_destroy(&group->lock);
249}
250
251static int rvin_group_init(struct rvin_group *group, struct rvin_dev *vin)
252{
253 struct media_device *mdev = &group->mdev;
254 const struct of_device_id *match;
255 struct device_node *np;
256 int ret;
257
258 mutex_init(&group->lock);
259
260
261 group->count = 0;
262 for_each_matching_node(np, vin->dev->driver->of_match_table)
263 if (of_device_is_available(np))
264 group->count++;
265
266 vin_dbg(vin, "found %u enabled VIN's in DT", group->count);
267
268 mdev->dev = vin->dev;
269 mdev->ops = &rvin_media_ops;
270
271 match = of_match_node(vin->dev->driver->of_match_table,
272 vin->dev->of_node);
273
274 strscpy(mdev->driver_name, KBUILD_MODNAME, sizeof(mdev->driver_name));
275 strscpy(mdev->model, match->compatible, sizeof(mdev->model));
276 snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s",
277 dev_name(mdev->dev));
278
279 media_device_init(mdev);
280
281 ret = media_device_register(&group->mdev);
282 if (ret)
283 rvin_group_cleanup(group);
284
285 return ret;
286}
287
288static void rvin_group_release(struct kref *kref)
289{
290 struct rvin_group *group =
291 container_of(kref, struct rvin_group, refcount);
292
293 mutex_lock(&rvin_group_lock);
294
295 rvin_group_data = NULL;
296
297 rvin_group_cleanup(group);
298
299 kfree(group);
300
301 mutex_unlock(&rvin_group_lock);
302}
303
304static int rvin_group_get(struct rvin_dev *vin)
305{
306 struct rvin_group *group;
307 u32 id;
308 int ret;
309
310
311 ret = of_property_read_u32(vin->dev->of_node, "renesas,id", &id);
312 if (ret) {
313 vin_err(vin, "%pOF: No renesas,id property found\n",
314 vin->dev->of_node);
315 return -EINVAL;
316 }
317
318 if (id >= RCAR_VIN_NUM) {
319 vin_err(vin, "%pOF: Invalid renesas,id '%u'\n",
320 vin->dev->of_node, id);
321 return -EINVAL;
322 }
323
324
325 mutex_lock(&rvin_group_lock);
326 if (rvin_group_data) {
327 group = rvin_group_data;
328 kref_get(&group->refcount);
329 } else {
330 group = kzalloc(sizeof(*group), GFP_KERNEL);
331 if (!group) {
332 ret = -ENOMEM;
333 goto err_group;
334 }
335
336 ret = rvin_group_init(group, vin);
337 if (ret) {
338 kfree(group);
339 vin_err(vin, "Failed to initialize group\n");
340 goto err_group;
341 }
342
343 kref_init(&group->refcount);
344
345 rvin_group_data = group;
346 }
347 mutex_unlock(&rvin_group_lock);
348
349
350 mutex_lock(&group->lock);
351
352 if (group->vin[id]) {
353 vin_err(vin, "Duplicate renesas,id property value %u\n", id);
354 mutex_unlock(&group->lock);
355 kref_put(&group->refcount, rvin_group_release);
356 return -EINVAL;
357 }
358
359 group->vin[id] = vin;
360
361 vin->id = id;
362 vin->group = group;
363 vin->v4l2_dev.mdev = &group->mdev;
364
365 mutex_unlock(&group->lock);
366
367 return 0;
368err_group:
369 mutex_unlock(&rvin_group_lock);
370 return ret;
371}
372
373static void rvin_group_put(struct rvin_dev *vin)
374{
375 struct rvin_group *group = vin->group;
376
377 mutex_lock(&group->lock);
378
379 vin->group = NULL;
380 vin->v4l2_dev.mdev = NULL;
381
382 if (WARN_ON(group->vin[vin->id] != vin))
383 goto out;
384
385 group->vin[vin->id] = NULL;
386out:
387 mutex_unlock(&group->lock);
388
389 kref_put(&group->refcount, rvin_group_release);
390}
391
392
393
394
395
396static int rvin_s_ctrl(struct v4l2_ctrl *ctrl)
397{
398 struct rvin_dev *vin =
399 container_of(ctrl->handler, struct rvin_dev, ctrl_handler);
400
401 switch (ctrl->id) {
402 case V4L2_CID_ALPHA_COMPONENT:
403 rvin_set_alpha(vin, ctrl->val);
404 break;
405 }
406
407 return 0;
408}
409
410static const struct v4l2_ctrl_ops rvin_ctrl_ops = {
411 .s_ctrl = rvin_s_ctrl,
412};
413
414
415
416
417
418static int rvin_find_pad(struct v4l2_subdev *sd, int direction)
419{
420 unsigned int pad;
421
422 if (sd->entity.num_pads <= 1)
423 return 0;
424
425 for (pad = 0; pad < sd->entity.num_pads; pad++)
426 if (sd->entity.pads[pad].flags & direction)
427 return pad;
428
429 return -EINVAL;
430}
431
432
433
434
435
436
437static int rvin_parallel_subdevice_attach(struct rvin_dev *vin,
438 struct v4l2_subdev *subdev)
439{
440 struct v4l2_subdev_mbus_code_enum code = {
441 .which = V4L2_SUBDEV_FORMAT_ACTIVE,
442 };
443 int ret;
444
445
446 ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SOURCE);
447 if (ret < 0)
448 return ret;
449 vin->parallel->source_pad = ret;
450
451 ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SINK);
452 vin->parallel->sink_pad = ret < 0 ? 0 : ret;
453
454 if (vin->info->use_mc) {
455 vin->parallel->subdev = subdev;
456 return 0;
457 }
458
459
460 vin->mbus_code = 0;
461 code.index = 0;
462 code.pad = vin->parallel->source_pad;
463 while (!vin->mbus_code &&
464 !v4l2_subdev_call(subdev, pad, enum_mbus_code, NULL, &code)) {
465 code.index++;
466 switch (code.code) {
467 case MEDIA_BUS_FMT_YUYV8_1X16:
468 case MEDIA_BUS_FMT_UYVY8_1X16:
469 case MEDIA_BUS_FMT_UYVY8_2X8:
470 case MEDIA_BUS_FMT_UYVY10_2X10:
471 case MEDIA_BUS_FMT_RGB888_1X24:
472 vin->mbus_code = code.code;
473 vin_dbg(vin, "Found media bus format for %s: %d\n",
474 subdev->name, vin->mbus_code);
475 break;
476 default:
477 break;
478 }
479 }
480
481 if (!vin->mbus_code) {
482 vin_err(vin, "Unsupported media bus format for %s\n",
483 subdev->name);
484 return -EINVAL;
485 }
486
487
488 ret = v4l2_subdev_call(subdev, video, g_tvnorms, &vin->vdev.tvnorms);
489 if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
490 return ret;
491
492
493 vin->std = V4L2_STD_UNKNOWN;
494 ret = v4l2_subdev_call(subdev, video, g_std, &vin->std);
495 if (ret < 0 && ret != -ENOIOCTLCMD)
496 return ret;
497
498
499 ret = v4l2_ctrl_handler_init(&vin->ctrl_handler, 16);
500 if (ret < 0)
501 return ret;
502
503 v4l2_ctrl_new_std(&vin->ctrl_handler, &rvin_ctrl_ops,
504 V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255);
505
506 if (vin->ctrl_handler.error) {
507 ret = vin->ctrl_handler.error;
508 v4l2_ctrl_handler_free(&vin->ctrl_handler);
509 return ret;
510 }
511
512 ret = v4l2_ctrl_add_handler(&vin->ctrl_handler, subdev->ctrl_handler,
513 NULL, true);
514 if (ret < 0) {
515 v4l2_ctrl_handler_free(&vin->ctrl_handler);
516 return ret;
517 }
518
519 vin->vdev.ctrl_handler = &vin->ctrl_handler;
520
521 vin->parallel->subdev = subdev;
522
523 return 0;
524}
525
526static void rvin_parallel_subdevice_detach(struct rvin_dev *vin)
527{
528 rvin_v4l2_unregister(vin);
529 vin->parallel->subdev = NULL;
530
531 if (!vin->info->use_mc) {
532 v4l2_ctrl_handler_free(&vin->ctrl_handler);
533 vin->vdev.ctrl_handler = NULL;
534 }
535}
536
537static int rvin_parallel_notify_complete(struct v4l2_async_notifier *notifier)
538{
539 struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev);
540 struct media_entity *source;
541 struct media_entity *sink;
542 int ret;
543
544 ret = v4l2_device_register_subdev_nodes(&vin->v4l2_dev);
545 if (ret < 0) {
546 vin_err(vin, "Failed to register subdev nodes\n");
547 return ret;
548 }
549
550 if (!video_is_registered(&vin->vdev)) {
551 ret = rvin_v4l2_register(vin);
552 if (ret < 0)
553 return ret;
554 }
555
556 if (!vin->info->use_mc)
557 return 0;
558
559
560 source = &vin->parallel->subdev->entity;
561 sink = &vin->vdev.entity;
562
563 ret = media_create_pad_link(source, vin->parallel->source_pad,
564 sink, vin->parallel->sink_pad, 0);
565 if (ret)
566 vin_err(vin, "Error adding link from %s to %s: %d\n",
567 source->name, sink->name, ret);
568
569 return ret;
570}
571
572static void rvin_parallel_notify_unbind(struct v4l2_async_notifier *notifier,
573 struct v4l2_subdev *subdev,
574 struct v4l2_async_subdev *asd)
575{
576 struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev);
577
578 vin_dbg(vin, "unbind parallel subdev %s\n", subdev->name);
579
580 mutex_lock(&vin->lock);
581 rvin_parallel_subdevice_detach(vin);
582 mutex_unlock(&vin->lock);
583}
584
585static int rvin_parallel_notify_bound(struct v4l2_async_notifier *notifier,
586 struct v4l2_subdev *subdev,
587 struct v4l2_async_subdev *asd)
588{
589 struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev);
590 int ret;
591
592 mutex_lock(&vin->lock);
593 ret = rvin_parallel_subdevice_attach(vin, subdev);
594 mutex_unlock(&vin->lock);
595 if (ret)
596 return ret;
597
598 v4l2_set_subdev_hostdata(subdev, vin);
599
600 vin_dbg(vin, "bound subdev %s source pad: %u sink pad: %u\n",
601 subdev->name, vin->parallel->source_pad,
602 vin->parallel->sink_pad);
603
604 return 0;
605}
606
607static const struct v4l2_async_notifier_operations rvin_parallel_notify_ops = {
608 .bound = rvin_parallel_notify_bound,
609 .unbind = rvin_parallel_notify_unbind,
610 .complete = rvin_parallel_notify_complete,
611};
612
613static int rvin_parallel_parse_v4l2(struct device *dev,
614 struct v4l2_fwnode_endpoint *vep,
615 struct v4l2_async_subdev *asd)
616{
617 struct rvin_dev *vin = dev_get_drvdata(dev);
618 struct rvin_parallel_entity *rvpe =
619 container_of(asd, struct rvin_parallel_entity, asd);
620
621 if (vep->base.port || vep->base.id)
622 return -ENOTCONN;
623
624 vin->parallel = rvpe;
625 vin->parallel->mbus_type = vep->bus_type;
626
627 switch (vin->parallel->mbus_type) {
628 case V4L2_MBUS_PARALLEL:
629 vin_dbg(vin, "Found PARALLEL media bus\n");
630 vin->parallel->mbus_flags = vep->bus.parallel.flags;
631 break;
632 case V4L2_MBUS_BT656:
633 vin_dbg(vin, "Found BT656 media bus\n");
634 vin->parallel->mbus_flags = 0;
635 break;
636 default:
637 vin_err(vin, "Unknown media bus type\n");
638 return -EINVAL;
639 }
640
641 return 0;
642}
643
644static int rvin_parallel_init(struct rvin_dev *vin)
645{
646 int ret;
647
648 v4l2_async_notifier_init(&vin->notifier);
649
650 ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(
651 vin->dev, &vin->notifier, sizeof(struct rvin_parallel_entity),
652 0, rvin_parallel_parse_v4l2);
653 if (ret)
654 return ret;
655
656
657 if (!vin->parallel)
658 return vin->info->use_mc ? 0 : -ENODEV;
659
660 vin_dbg(vin, "Found parallel subdevice %pOF\n",
661 to_of_node(vin->parallel->asd.match.fwnode));
662
663 vin->notifier.ops = &rvin_parallel_notify_ops;
664 ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier);
665 if (ret < 0) {
666 vin_err(vin, "Notifier registration failed\n");
667 v4l2_async_notifier_cleanup(&vin->notifier);
668 return ret;
669 }
670
671 return 0;
672}
673
674
675
676
677
678static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier)
679{
680 struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev);
681 const struct rvin_group_route *route;
682 unsigned int i;
683 int ret;
684
685 ret = v4l2_device_register_subdev_nodes(&vin->v4l2_dev);
686 if (ret) {
687 vin_err(vin, "Failed to register subdev nodes\n");
688 return ret;
689 }
690
691
692 for (i = 0; i < RCAR_VIN_NUM; i++) {
693 if (vin->group->vin[i] &&
694 !video_is_registered(&vin->group->vin[i]->vdev)) {
695 ret = rvin_v4l2_register(vin->group->vin[i]);
696 if (ret)
697 return ret;
698 }
699 }
700
701
702 mutex_lock(&vin->group->lock);
703 for (route = vin->info->routes; route->mask; route++) {
704 struct media_pad *source_pad, *sink_pad;
705 struct media_entity *source, *sink;
706 unsigned int source_idx;
707
708
709 if (!vin->group->vin[route->vin])
710 continue;
711
712
713 if (!vin->group->vin[rvin_group_id_to_master(route->vin)])
714 continue;
715
716
717 if (!vin->group->csi[route->csi].subdev)
718 continue;
719
720 source = &vin->group->csi[route->csi].subdev->entity;
721 source_idx = rvin_group_csi_channel_to_pad(route->channel);
722 source_pad = &source->pads[source_idx];
723
724 sink = &vin->group->vin[route->vin]->vdev.entity;
725 sink_pad = &sink->pads[0];
726
727
728 if (media_entity_find_link(source_pad, sink_pad))
729 continue;
730
731 ret = media_create_pad_link(source, source_idx, sink, 0, 0);
732 if (ret) {
733 vin_err(vin, "Error adding link from %s to %s\n",
734 source->name, sink->name);
735 break;
736 }
737 }
738 mutex_unlock(&vin->group->lock);
739
740 return ret;
741}
742
743static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier,
744 struct v4l2_subdev *subdev,
745 struct v4l2_async_subdev *asd)
746{
747 struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev);
748 unsigned int i;
749
750 for (i = 0; i < RCAR_VIN_NUM; i++)
751 if (vin->group->vin[i])
752 rvin_v4l2_unregister(vin->group->vin[i]);
753
754 mutex_lock(&vin->group->lock);
755
756 for (i = 0; i < RVIN_CSI_MAX; i++) {
757 if (vin->group->csi[i].fwnode != asd->match.fwnode)
758 continue;
759 vin->group->csi[i].subdev = NULL;
760 vin_dbg(vin, "Unbind CSI-2 %s from slot %u\n", subdev->name, i);
761 break;
762 }
763
764 mutex_unlock(&vin->group->lock);
765}
766
767static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier,
768 struct v4l2_subdev *subdev,
769 struct v4l2_async_subdev *asd)
770{
771 struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev);
772 unsigned int i;
773
774 mutex_lock(&vin->group->lock);
775
776 for (i = 0; i < RVIN_CSI_MAX; i++) {
777 if (vin->group->csi[i].fwnode != asd->match.fwnode)
778 continue;
779 vin->group->csi[i].subdev = subdev;
780 vin_dbg(vin, "Bound CSI-2 %s to slot %u\n", subdev->name, i);
781 break;
782 }
783
784 mutex_unlock(&vin->group->lock);
785
786 return 0;
787}
788
789static const struct v4l2_async_notifier_operations rvin_group_notify_ops = {
790 .bound = rvin_group_notify_bound,
791 .unbind = rvin_group_notify_unbind,
792 .complete = rvin_group_notify_complete,
793};
794
795static int rvin_mc_parse_of_endpoint(struct device *dev,
796 struct v4l2_fwnode_endpoint *vep,
797 struct v4l2_async_subdev *asd)
798{
799 struct rvin_dev *vin = dev_get_drvdata(dev);
800 int ret = 0;
801
802 if (vep->base.port != 1 || vep->base.id >= RVIN_CSI_MAX)
803 return -EINVAL;
804
805 if (!of_device_is_available(to_of_node(asd->match.fwnode))) {
806 vin_dbg(vin, "OF device %pOF disabled, ignoring\n",
807 to_of_node(asd->match.fwnode));
808 return -ENOTCONN;
809 }
810
811 mutex_lock(&vin->group->lock);
812
813 if (vin->group->csi[vep->base.id].fwnode) {
814 vin_dbg(vin, "OF device %pOF already handled\n",
815 to_of_node(asd->match.fwnode));
816 ret = -ENOTCONN;
817 goto out;
818 }
819
820 vin->group->csi[vep->base.id].fwnode = asd->match.fwnode;
821
822 vin_dbg(vin, "Add group OF device %pOF to slot %u\n",
823 to_of_node(asd->match.fwnode), vep->base.id);
824out:
825 mutex_unlock(&vin->group->lock);
826
827 return ret;
828}
829
830static int rvin_mc_parse_of_graph(struct rvin_dev *vin)
831{
832 unsigned int count = 0, vin_mask = 0;
833 unsigned int i;
834 int ret;
835
836 mutex_lock(&vin->group->lock);
837
838
839 for (i = 0; i < RCAR_VIN_NUM; i++) {
840 if (vin->group->vin[i]) {
841 count++;
842 vin_mask |= BIT(i);
843 }
844 }
845
846 if (vin->group->count != count) {
847 mutex_unlock(&vin->group->lock);
848 return 0;
849 }
850
851 mutex_unlock(&vin->group->lock);
852
853 v4l2_async_notifier_init(&vin->group->notifier);
854
855
856
857
858
859
860 for (i = 0; i < RCAR_VIN_NUM; i++) {
861 if (!(vin_mask & BIT(i)))
862 continue;
863
864 ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(
865 vin->group->vin[i]->dev, &vin->group->notifier,
866 sizeof(struct v4l2_async_subdev), 1,
867 rvin_mc_parse_of_endpoint);
868 if (ret)
869 return ret;
870 }
871
872 if (list_empty(&vin->group->notifier.asd_list))
873 return 0;
874
875 vin->group->notifier.ops = &rvin_group_notify_ops;
876 ret = v4l2_async_notifier_register(&vin->v4l2_dev,
877 &vin->group->notifier);
878 if (ret < 0) {
879 vin_err(vin, "Notifier registration failed\n");
880 v4l2_async_notifier_cleanup(&vin->group->notifier);
881 return ret;
882 }
883
884 return 0;
885}
886
887static int rvin_mc_init(struct rvin_dev *vin)
888{
889 int ret;
890
891 vin->pad.flags = MEDIA_PAD_FL_SINK;
892 ret = media_entity_pads_init(&vin->vdev.entity, 1, &vin->pad);
893 if (ret)
894 return ret;
895
896 ret = rvin_group_get(vin);
897 if (ret)
898 return ret;
899
900 ret = rvin_mc_parse_of_graph(vin);
901 if (ret)
902 rvin_group_put(vin);
903
904 ret = v4l2_ctrl_handler_init(&vin->ctrl_handler, 1);
905 if (ret < 0)
906 return ret;
907
908 v4l2_ctrl_new_std(&vin->ctrl_handler, &rvin_ctrl_ops,
909 V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255);
910
911 if (vin->ctrl_handler.error) {
912 ret = vin->ctrl_handler.error;
913 v4l2_ctrl_handler_free(&vin->ctrl_handler);
914 return ret;
915 }
916
917 vin->vdev.ctrl_handler = &vin->ctrl_handler;
918
919 return ret;
920}
921
922
923
924
925
926static const struct rvin_info rcar_info_h1 = {
927 .model = RCAR_H1,
928 .use_mc = false,
929 .max_width = 2048,
930 .max_height = 2048,
931};
932
933static const struct rvin_info rcar_info_m1 = {
934 .model = RCAR_M1,
935 .use_mc = false,
936 .max_width = 2048,
937 .max_height = 2048,
938};
939
940static const struct rvin_info rcar_info_gen2 = {
941 .model = RCAR_GEN2,
942 .use_mc = false,
943 .max_width = 2048,
944 .max_height = 2048,
945};
946
947static const struct rvin_group_route rcar_info_r8a7795_routes[] = {
948 { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) },
949 { .csi = RVIN_CSI20, .channel = 0, .vin = 0, .mask = BIT(1) | BIT(4) },
950 { .csi = RVIN_CSI40, .channel = 1, .vin = 0, .mask = BIT(2) },
951 { .csi = RVIN_CSI20, .channel = 0, .vin = 1, .mask = BIT(0) },
952 { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(1) | BIT(3) },
953 { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) },
954 { .csi = RVIN_CSI20, .channel = 1, .vin = 1, .mask = BIT(4) },
955 { .csi = RVIN_CSI20, .channel = 1, .vin = 2, .mask = BIT(0) },
956 { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) },
957 { .csi = RVIN_CSI20, .channel = 0, .vin = 2, .mask = BIT(2) },
958 { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) },
959 { .csi = RVIN_CSI20, .channel = 2, .vin = 2, .mask = BIT(4) },
960 { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) },
961 { .csi = RVIN_CSI20, .channel = 1, .vin = 3, .mask = BIT(1) | BIT(2) },
962 { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) },
963 { .csi = RVIN_CSI20, .channel = 3, .vin = 3, .mask = BIT(4) },
964 { .csi = RVIN_CSI41, .channel = 0, .vin = 4, .mask = BIT(0) | BIT(3) },
965 { .csi = RVIN_CSI20, .channel = 0, .vin = 4, .mask = BIT(1) | BIT(4) },
966 { .csi = RVIN_CSI41, .channel = 1, .vin = 4, .mask = BIT(2) },
967 { .csi = RVIN_CSI20, .channel = 0, .vin = 5, .mask = BIT(0) },
968 { .csi = RVIN_CSI41, .channel = 1, .vin = 5, .mask = BIT(1) | BIT(3) },
969 { .csi = RVIN_CSI41, .channel = 0, .vin = 5, .mask = BIT(2) },
970 { .csi = RVIN_CSI20, .channel = 1, .vin = 5, .mask = BIT(4) },
971 { .csi = RVIN_CSI20, .channel = 1, .vin = 6, .mask = BIT(0) },
972 { .csi = RVIN_CSI41, .channel = 0, .vin = 6, .mask = BIT(1) },
973 { .csi = RVIN_CSI20, .channel = 0, .vin = 6, .mask = BIT(2) },
974 { .csi = RVIN_CSI41, .channel = 2, .vin = 6, .mask = BIT(3) },
975 { .csi = RVIN_CSI20, .channel = 2, .vin = 6, .mask = BIT(4) },
976 { .csi = RVIN_CSI41, .channel = 1, .vin = 7, .mask = BIT(0) },
977 { .csi = RVIN_CSI20, .channel = 1, .vin = 7, .mask = BIT(1) | BIT(2) },
978 { .csi = RVIN_CSI41, .channel = 3, .vin = 7, .mask = BIT(3) },
979 { .csi = RVIN_CSI20, .channel = 3, .vin = 7, .mask = BIT(4) },
980 { }
981};
982
983static const struct rvin_info rcar_info_r8a7795 = {
984 .model = RCAR_GEN3,
985 .use_mc = true,
986 .nv12 = true,
987 .max_width = 4096,
988 .max_height = 4096,
989 .routes = rcar_info_r8a7795_routes,
990};
991
992static const struct rvin_group_route rcar_info_r8a7795es1_routes[] = {
993 { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) },
994 { .csi = RVIN_CSI20, .channel = 0, .vin = 0, .mask = BIT(1) | BIT(4) },
995 { .csi = RVIN_CSI21, .channel = 0, .vin = 0, .mask = BIT(2) | BIT(5) },
996 { .csi = RVIN_CSI20, .channel = 0, .vin = 1, .mask = BIT(0) },
997 { .csi = RVIN_CSI21, .channel = 0, .vin = 1, .mask = BIT(1) },
998 { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) },
999 { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(3) },
1000 { .csi = RVIN_CSI20, .channel = 1, .vin = 1, .mask = BIT(4) },
1001 { .csi = RVIN_CSI21, .channel = 1, .vin = 1, .mask = BIT(5) },
1002 { .csi = RVIN_CSI21, .channel = 0, .vin = 2, .mask = BIT(0) },
1003 { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) },
1004 { .csi = RVIN_CSI20, .channel = 0, .vin = 2, .mask = BIT(2) },
1005 { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) },
1006 { .csi = RVIN_CSI20, .channel = 2, .vin = 2, .mask = BIT(4) },
1007 { .csi = RVIN_CSI21, .channel = 2, .vin = 2, .mask = BIT(5) },
1008 { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) },
1009 { .csi = RVIN_CSI20, .channel = 1, .vin = 3, .mask = BIT(1) },
1010 { .csi = RVIN_CSI21, .channel = 1, .vin = 3, .mask = BIT(2) },
1011 { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) },
1012 { .csi = RVIN_CSI20, .channel = 3, .vin = 3, .mask = BIT(4) },
1013 { .csi = RVIN_CSI21, .channel = 3, .vin = 3, .mask = BIT(5) },
1014 { .csi = RVIN_CSI41, .channel = 0, .vin = 4, .mask = BIT(0) | BIT(3) },
1015 { .csi = RVIN_CSI20, .channel = 0, .vin = 4, .mask = BIT(1) | BIT(4) },
1016 { .csi = RVIN_CSI21, .channel = 0, .vin = 4, .mask = BIT(2) | BIT(5) },
1017 { .csi = RVIN_CSI20, .channel = 0, .vin = 5, .mask = BIT(0) },
1018 { .csi = RVIN_CSI21, .channel = 0, .vin = 5, .mask = BIT(1) },
1019 { .csi = RVIN_CSI41, .channel = 0, .vin = 5, .mask = BIT(2) },
1020 { .csi = RVIN_CSI41, .channel = 1, .vin = 5, .mask = BIT(3) },
1021 { .csi = RVIN_CSI20, .channel = 1, .vin = 5, .mask = BIT(4) },
1022 { .csi = RVIN_CSI21, .channel = 1, .vin = 5, .mask = BIT(5) },
1023 { .csi = RVIN_CSI21, .channel = 0, .vin = 6, .mask = BIT(0) },
1024 { .csi = RVIN_CSI41, .channel = 0, .vin = 6, .mask = BIT(1) },
1025 { .csi = RVIN_CSI20, .channel = 0, .vin = 6, .mask = BIT(2) },
1026 { .csi = RVIN_CSI41, .channel = 2, .vin = 6, .mask = BIT(3) },
1027 { .csi = RVIN_CSI20, .channel = 2, .vin = 6, .mask = BIT(4) },
1028 { .csi = RVIN_CSI21, .channel = 2, .vin = 6, .mask = BIT(5) },
1029 { .csi = RVIN_CSI41, .channel = 1, .vin = 7, .mask = BIT(0) },
1030 { .csi = RVIN_CSI20, .channel = 1, .vin = 7, .mask = BIT(1) },
1031 { .csi = RVIN_CSI21, .channel = 1, .vin = 7, .mask = BIT(2) },
1032 { .csi = RVIN_CSI41, .channel = 3, .vin = 7, .mask = BIT(3) },
1033 { .csi = RVIN_CSI20, .channel = 3, .vin = 7, .mask = BIT(4) },
1034 { .csi = RVIN_CSI21, .channel = 3, .vin = 7, .mask = BIT(5) },
1035 { }
1036};
1037
1038static const struct rvin_info rcar_info_r8a7795es1 = {
1039 .model = RCAR_GEN3,
1040 .use_mc = true,
1041 .max_width = 4096,
1042 .max_height = 4096,
1043 .routes = rcar_info_r8a7795es1_routes,
1044};
1045
1046static const struct rvin_group_route rcar_info_r8a7796_routes[] = {
1047 { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) },
1048 { .csi = RVIN_CSI20, .channel = 0, .vin = 0, .mask = BIT(1) | BIT(4) },
1049 { .csi = RVIN_CSI20, .channel = 0, .vin = 1, .mask = BIT(0) },
1050 { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) },
1051 { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(3) },
1052 { .csi = RVIN_CSI20, .channel = 1, .vin = 1, .mask = BIT(4) },
1053 { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) },
1054 { .csi = RVIN_CSI20, .channel = 0, .vin = 2, .mask = BIT(2) },
1055 { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) },
1056 { .csi = RVIN_CSI20, .channel = 2, .vin = 2, .mask = BIT(4) },
1057 { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) },
1058 { .csi = RVIN_CSI20, .channel = 1, .vin = 3, .mask = BIT(1) },
1059 { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) },
1060 { .csi = RVIN_CSI20, .channel = 3, .vin = 3, .mask = BIT(4) },
1061 { .csi = RVIN_CSI40, .channel = 0, .vin = 4, .mask = BIT(0) | BIT(3) },
1062 { .csi = RVIN_CSI20, .channel = 0, .vin = 4, .mask = BIT(1) | BIT(4) },
1063 { .csi = RVIN_CSI20, .channel = 0, .vin = 5, .mask = BIT(0) },
1064 { .csi = RVIN_CSI40, .channel = 0, .vin = 5, .mask = BIT(2) },
1065 { .csi = RVIN_CSI40, .channel = 1, .vin = 5, .mask = BIT(3) },
1066 { .csi = RVIN_CSI20, .channel = 1, .vin = 5, .mask = BIT(4) },
1067 { .csi = RVIN_CSI40, .channel = 0, .vin = 6, .mask = BIT(1) },
1068 { .csi = RVIN_CSI20, .channel = 0, .vin = 6, .mask = BIT(2) },
1069 { .csi = RVIN_CSI40, .channel = 2, .vin = 6, .mask = BIT(3) },
1070 { .csi = RVIN_CSI20, .channel = 2, .vin = 6, .mask = BIT(4) },
1071 { .csi = RVIN_CSI40, .channel = 1, .vin = 7, .mask = BIT(0) },
1072 { .csi = RVIN_CSI20, .channel = 1, .vin = 7, .mask = BIT(1) },
1073 { .csi = RVIN_CSI40, .channel = 3, .vin = 7, .mask = BIT(3) },
1074 { .csi = RVIN_CSI20, .channel = 3, .vin = 7, .mask = BIT(4) },
1075 { }
1076};
1077
1078static const struct rvin_info rcar_info_r8a7796 = {
1079 .model = RCAR_GEN3,
1080 .use_mc = true,
1081 .nv12 = true,
1082 .max_width = 4096,
1083 .max_height = 4096,
1084 .routes = rcar_info_r8a7796_routes,
1085};
1086
1087static const struct rvin_group_route rcar_info_r8a77965_routes[] = {
1088 { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) },
1089 { .csi = RVIN_CSI20, .channel = 0, .vin = 0, .mask = BIT(1) | BIT(4) },
1090 { .csi = RVIN_CSI40, .channel = 1, .vin = 0, .mask = BIT(2) },
1091 { .csi = RVIN_CSI20, .channel = 0, .vin = 1, .mask = BIT(0) },
1092 { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(1) | BIT(3) },
1093 { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) },
1094 { .csi = RVIN_CSI20, .channel = 1, .vin = 1, .mask = BIT(4) },
1095 { .csi = RVIN_CSI20, .channel = 1, .vin = 2, .mask = BIT(0) },
1096 { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) },
1097 { .csi = RVIN_CSI20, .channel = 0, .vin = 2, .mask = BIT(2) },
1098 { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) },
1099 { .csi = RVIN_CSI20, .channel = 2, .vin = 2, .mask = BIT(4) },
1100 { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) },
1101 { .csi = RVIN_CSI20, .channel = 1, .vin = 3, .mask = BIT(1) | BIT(2) },
1102 { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) },
1103 { .csi = RVIN_CSI20, .channel = 3, .vin = 3, .mask = BIT(4) },
1104 { .csi = RVIN_CSI40, .channel = 0, .vin = 4, .mask = BIT(0) | BIT(3) },
1105 { .csi = RVIN_CSI20, .channel = 0, .vin = 4, .mask = BIT(1) | BIT(4) },
1106 { .csi = RVIN_CSI40, .channel = 1, .vin = 4, .mask = BIT(2) },
1107 { .csi = RVIN_CSI20, .channel = 0, .vin = 5, .mask = BIT(0) },
1108 { .csi = RVIN_CSI40, .channel = 1, .vin = 5, .mask = BIT(1) | BIT(3) },
1109 { .csi = RVIN_CSI40, .channel = 0, .vin = 5, .mask = BIT(2) },
1110 { .csi = RVIN_CSI20, .channel = 1, .vin = 5, .mask = BIT(4) },
1111 { .csi = RVIN_CSI20, .channel = 1, .vin = 6, .mask = BIT(0) },
1112 { .csi = RVIN_CSI40, .channel = 0, .vin = 6, .mask = BIT(1) },
1113 { .csi = RVIN_CSI20, .channel = 0, .vin = 6, .mask = BIT(2) },
1114 { .csi = RVIN_CSI40, .channel = 2, .vin = 6, .mask = BIT(3) },
1115 { .csi = RVIN_CSI20, .channel = 2, .vin = 6, .mask = BIT(4) },
1116 { .csi = RVIN_CSI40, .channel = 1, .vin = 7, .mask = BIT(0) },
1117 { .csi = RVIN_CSI20, .channel = 1, .vin = 7, .mask = BIT(1) | BIT(2) },
1118 { .csi = RVIN_CSI40, .channel = 3, .vin = 7, .mask = BIT(3) },
1119 { .csi = RVIN_CSI20, .channel = 3, .vin = 7, .mask = BIT(4) },
1120 { }
1121};
1122
1123static const struct rvin_info rcar_info_r8a77965 = {
1124 .model = RCAR_GEN3,
1125 .use_mc = true,
1126 .nv12 = true,
1127 .max_width = 4096,
1128 .max_height = 4096,
1129 .routes = rcar_info_r8a77965_routes,
1130};
1131
1132static const struct rvin_group_route rcar_info_r8a77970_routes[] = {
1133 { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) },
1134 { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) },
1135 { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(3) },
1136 { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) },
1137 { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) },
1138 { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) },
1139 { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) },
1140 { }
1141};
1142
1143static const struct rvin_info rcar_info_r8a77970 = {
1144 .model = RCAR_GEN3,
1145 .use_mc = true,
1146 .max_width = 4096,
1147 .max_height = 4096,
1148 .routes = rcar_info_r8a77970_routes,
1149};
1150
1151static const struct rvin_group_route rcar_info_r8a77980_routes[] = {
1152 { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) },
1153 { .csi = RVIN_CSI40, .channel = 1, .vin = 0, .mask = BIT(2) },
1154 { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) },
1155 { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(1) | BIT(3) },
1156 { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) },
1157 { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) },
1158 { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) },
1159 { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) },
1160 { .csi = RVIN_CSI41, .channel = 0, .vin = 4, .mask = BIT(0) | BIT(3) },
1161 { .csi = RVIN_CSI41, .channel = 1, .vin = 4, .mask = BIT(2) },
1162 { .csi = RVIN_CSI41, .channel = 0, .vin = 5, .mask = BIT(2) },
1163 { .csi = RVIN_CSI41, .channel = 1, .vin = 5, .mask = BIT(1) | BIT(3) },
1164 { .csi = RVIN_CSI41, .channel = 0, .vin = 6, .mask = BIT(1) },
1165 { .csi = RVIN_CSI41, .channel = 2, .vin = 6, .mask = BIT(3) },
1166 { .csi = RVIN_CSI41, .channel = 1, .vin = 7, .mask = BIT(0) },
1167 { .csi = RVIN_CSI41, .channel = 3, .vin = 7, .mask = BIT(3) },
1168 { }
1169};
1170
1171static const struct rvin_info rcar_info_r8a77980 = {
1172 .model = RCAR_GEN3,
1173 .use_mc = true,
1174 .nv12 = true,
1175 .max_width = 4096,
1176 .max_height = 4096,
1177 .routes = rcar_info_r8a77980_routes,
1178};
1179
1180static const struct rvin_group_route rcar_info_r8a77990_routes[] = {
1181 { .csi = RVIN_CSI40, .channel = 0, .vin = 4, .mask = BIT(0) | BIT(3) },
1182 { .csi = RVIN_CSI40, .channel = 0, .vin = 5, .mask = BIT(2) },
1183 { .csi = RVIN_CSI40, .channel = 1, .vin = 4, .mask = BIT(2) },
1184 { .csi = RVIN_CSI40, .channel = 1, .vin = 5, .mask = BIT(1) | BIT(3) },
1185 { }
1186};
1187
1188static const struct rvin_info rcar_info_r8a77990 = {
1189 .model = RCAR_GEN3,
1190 .use_mc = true,
1191 .nv12 = true,
1192 .max_width = 4096,
1193 .max_height = 4096,
1194 .routes = rcar_info_r8a77990_routes,
1195};
1196
1197static const struct rvin_group_route rcar_info_r8a77995_routes[] = {
1198 { }
1199};
1200
1201static const struct rvin_info rcar_info_r8a77995 = {
1202 .model = RCAR_GEN3,
1203 .use_mc = true,
1204 .nv12 = true,
1205 .max_width = 4096,
1206 .max_height = 4096,
1207 .routes = rcar_info_r8a77995_routes,
1208};
1209
1210static const struct of_device_id rvin_of_id_table[] = {
1211 {
1212 .compatible = "renesas,vin-r8a774a1",
1213 .data = &rcar_info_r8a7796,
1214 },
1215 {
1216 .compatible = "renesas,vin-r8a774b1",
1217 .data = &rcar_info_r8a77965,
1218 },
1219 {
1220 .compatible = "renesas,vin-r8a774c0",
1221 .data = &rcar_info_r8a77990,
1222 },
1223 {
1224 .compatible = "renesas,vin-r8a7778",
1225 .data = &rcar_info_m1,
1226 },
1227 {
1228 .compatible = "renesas,vin-r8a7779",
1229 .data = &rcar_info_h1,
1230 },
1231 {
1232 .compatible = "renesas,vin-r8a7790",
1233 .data = &rcar_info_gen2,
1234 },
1235 {
1236 .compatible = "renesas,vin-r8a7791",
1237 .data = &rcar_info_gen2,
1238 },
1239 {
1240 .compatible = "renesas,vin-r8a7793",
1241 .data = &rcar_info_gen2,
1242 },
1243 {
1244 .compatible = "renesas,vin-r8a7794",
1245 .data = &rcar_info_gen2,
1246 },
1247 {
1248 .compatible = "renesas,rcar-gen2-vin",
1249 .data = &rcar_info_gen2,
1250 },
1251 {
1252 .compatible = "renesas,vin-r8a7795",
1253 .data = &rcar_info_r8a7795,
1254 },
1255 {
1256 .compatible = "renesas,vin-r8a7796",
1257 .data = &rcar_info_r8a7796,
1258 },
1259 {
1260 .compatible = "renesas,vin-r8a77965",
1261 .data = &rcar_info_r8a77965,
1262 },
1263 {
1264 .compatible = "renesas,vin-r8a77970",
1265 .data = &rcar_info_r8a77970,
1266 },
1267 {
1268 .compatible = "renesas,vin-r8a77980",
1269 .data = &rcar_info_r8a77980,
1270 },
1271 {
1272 .compatible = "renesas,vin-r8a77990",
1273 .data = &rcar_info_r8a77990,
1274 },
1275 {
1276 .compatible = "renesas,vin-r8a77995",
1277 .data = &rcar_info_r8a77995,
1278 },
1279 { },
1280};
1281MODULE_DEVICE_TABLE(of, rvin_of_id_table);
1282
1283static const struct soc_device_attribute r8a7795es1[] = {
1284 {
1285 .soc_id = "r8a7795", .revision = "ES1.*",
1286 .data = &rcar_info_r8a7795es1,
1287 },
1288 { }
1289};
1290
1291static int rcar_vin_probe(struct platform_device *pdev)
1292{
1293 const struct soc_device_attribute *attr;
1294 struct rvin_dev *vin;
1295 int irq, ret;
1296
1297 vin = devm_kzalloc(&pdev->dev, sizeof(*vin), GFP_KERNEL);
1298 if (!vin)
1299 return -ENOMEM;
1300
1301 vin->dev = &pdev->dev;
1302 vin->info = of_device_get_match_data(&pdev->dev);
1303 vin->alpha = 0xff;
1304
1305
1306
1307
1308
1309 attr = soc_device_match(r8a7795es1);
1310 if (attr)
1311 vin->info = attr->data;
1312
1313 vin->base = devm_platform_ioremap_resource(pdev, 0);
1314 if (IS_ERR(vin->base))
1315 return PTR_ERR(vin->base);
1316
1317 irq = platform_get_irq(pdev, 0);
1318 if (irq < 0)
1319 return irq;
1320
1321 ret = rvin_dma_register(vin, irq);
1322 if (ret)
1323 return ret;
1324
1325 platform_set_drvdata(pdev, vin);
1326
1327 if (vin->info->use_mc) {
1328 ret = rvin_mc_init(vin);
1329 if (ret)
1330 goto error_dma_unregister;
1331 }
1332
1333 ret = rvin_parallel_init(vin);
1334 if (ret)
1335 goto error_group_unregister;
1336
1337 pm_suspend_ignore_children(&pdev->dev, true);
1338 pm_runtime_enable(&pdev->dev);
1339
1340 return 0;
1341
1342error_group_unregister:
1343 v4l2_ctrl_handler_free(&vin->ctrl_handler);
1344
1345 if (vin->info->use_mc) {
1346 mutex_lock(&vin->group->lock);
1347 if (&vin->v4l2_dev == vin->group->notifier.v4l2_dev) {
1348 v4l2_async_notifier_unregister(&vin->group->notifier);
1349 v4l2_async_notifier_cleanup(&vin->group->notifier);
1350 }
1351 mutex_unlock(&vin->group->lock);
1352 rvin_group_put(vin);
1353 }
1354
1355error_dma_unregister:
1356 rvin_dma_unregister(vin);
1357
1358 return ret;
1359}
1360
1361static int rcar_vin_remove(struct platform_device *pdev)
1362{
1363 struct rvin_dev *vin = platform_get_drvdata(pdev);
1364
1365 pm_runtime_disable(&pdev->dev);
1366
1367 rvin_v4l2_unregister(vin);
1368
1369 v4l2_async_notifier_unregister(&vin->notifier);
1370 v4l2_async_notifier_cleanup(&vin->notifier);
1371
1372 if (vin->info->use_mc) {
1373 mutex_lock(&vin->group->lock);
1374 if (&vin->v4l2_dev == vin->group->notifier.v4l2_dev) {
1375 v4l2_async_notifier_unregister(&vin->group->notifier);
1376 v4l2_async_notifier_cleanup(&vin->group->notifier);
1377 }
1378 mutex_unlock(&vin->group->lock);
1379 rvin_group_put(vin);
1380 }
1381
1382 v4l2_ctrl_handler_free(&vin->ctrl_handler);
1383
1384 rvin_dma_unregister(vin);
1385
1386 return 0;
1387}
1388
1389static struct platform_driver rcar_vin_driver = {
1390 .driver = {
1391 .name = "rcar-vin",
1392 .of_match_table = rvin_of_id_table,
1393 },
1394 .probe = rcar_vin_probe,
1395 .remove = rcar_vin_remove,
1396};
1397
1398module_platform_driver(rcar_vin_driver);
1399
1400MODULE_AUTHOR("Niklas Söderlund <niklas.soderlund@ragnatech.se>");
1401MODULE_DESCRIPTION("Renesas R-Car VIN camera host driver");
1402MODULE_LICENSE("GPL");
1403