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] &&
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_cleanup(&group->mdev);
247 mutex_destroy(&group->lock);
248}
249
250static int rvin_group_init(struct rvin_group *group, struct rvin_dev *vin)
251{
252 struct media_device *mdev = &group->mdev;
253 const struct of_device_id *match;
254 struct device_node *np;
255
256 mutex_init(&group->lock);
257
258
259 group->count = 0;
260 for_each_matching_node(np, vin->dev->driver->of_match_table)
261 if (of_device_is_available(np))
262 group->count++;
263
264 vin_dbg(vin, "found %u enabled VIN's in DT", group->count);
265
266 mdev->dev = vin->dev;
267 mdev->ops = &rvin_media_ops;
268
269 match = of_match_node(vin->dev->driver->of_match_table,
270 vin->dev->of_node);
271
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));
276
277 media_device_init(mdev);
278
279 return 0;
280}
281
282static void rvin_group_release(struct kref *kref)
283{
284 struct rvin_group *group =
285 container_of(kref, struct rvin_group, refcount);
286
287 mutex_lock(&rvin_group_lock);
288
289 rvin_group_data = NULL;
290
291 rvin_group_cleanup(group);
292
293 kfree(group);
294
295 mutex_unlock(&rvin_group_lock);
296}
297
298static int rvin_group_get(struct rvin_dev *vin)
299{
300 struct rvin_group *group;
301 u32 id;
302 int ret;
303
304
305 ret = of_property_read_u32(vin->dev->of_node, "renesas,id", &id);
306 if (ret) {
307 vin_err(vin, "%pOF: No renesas,id property found\n",
308 vin->dev->of_node);
309 return -EINVAL;
310 }
311
312 if (id >= RCAR_VIN_NUM) {
313 vin_err(vin, "%pOF: Invalid renesas,id '%u'\n",
314 vin->dev->of_node, id);
315 return -EINVAL;
316 }
317
318
319 mutex_lock(&rvin_group_lock);
320 if (rvin_group_data) {
321 group = rvin_group_data;
322 kref_get(&group->refcount);
323 } else {
324 group = kzalloc(sizeof(*group), GFP_KERNEL);
325 if (!group) {
326 ret = -ENOMEM;
327 goto err_group;
328 }
329
330 ret = rvin_group_init(group, vin);
331 if (ret) {
332 kfree(group);
333 vin_err(vin, "Failed to initialize group\n");
334 goto err_group;
335 }
336
337 kref_init(&group->refcount);
338
339 rvin_group_data = group;
340 }
341 mutex_unlock(&rvin_group_lock);
342
343
344 mutex_lock(&group->lock);
345
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);
350 return -EINVAL;
351 }
352
353 group->vin[id] = vin;
354
355 vin->id = id;
356 vin->group = group;
357 vin->v4l2_dev.mdev = &group->mdev;
358
359 mutex_unlock(&group->lock);
360
361 return 0;
362err_group:
363 mutex_unlock(&rvin_group_lock);
364 return ret;
365}
366
367static void rvin_group_put(struct rvin_dev *vin)
368{
369 struct rvin_group *group = vin->group;
370
371 mutex_lock(&group->lock);
372
373 vin->group = NULL;
374 vin->v4l2_dev.mdev = NULL;
375
376 if (WARN_ON(group->vin[vin->id] != vin))
377 goto out;
378
379 group->vin[vin->id] = NULL;
380out:
381 mutex_unlock(&group->lock);
382
383 kref_put(&group->refcount, rvin_group_release);
384}
385
386
387
388
389
390static int rvin_s_ctrl(struct v4l2_ctrl *ctrl)
391{
392 struct rvin_dev *vin =
393 container_of(ctrl->handler, struct rvin_dev, ctrl_handler);
394
395 switch (ctrl->id) {
396 case V4L2_CID_ALPHA_COMPONENT:
397 rvin_set_alpha(vin, ctrl->val);
398 break;
399 }
400
401 return 0;
402}
403
404static const struct v4l2_ctrl_ops rvin_ctrl_ops = {
405 .s_ctrl = rvin_s_ctrl,
406};
407
408
409
410
411
412static int rvin_find_pad(struct v4l2_subdev *sd, int direction)
413{
414 unsigned int pad;
415
416 if (sd->entity.num_pads <= 1)
417 return 0;
418
419 for (pad = 0; pad < sd->entity.num_pads; pad++)
420 if (sd->entity.pads[pad].flags & direction)
421 return pad;
422
423 return -EINVAL;
424}
425
426
427
428
429
430
431static int rvin_parallel_subdevice_attach(struct rvin_dev *vin,
432 struct v4l2_subdev *subdev)
433{
434 struct v4l2_subdev_mbus_code_enum code = {
435 .which = V4L2_SUBDEV_FORMAT_ACTIVE,
436 };
437 int ret;
438
439
440 ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SOURCE);
441 if (ret < 0)
442 return ret;
443 vin->parallel.source_pad = ret;
444
445 ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SINK);
446 vin->parallel.sink_pad = ret < 0 ? 0 : ret;
447
448 if (vin->info->use_mc) {
449 vin->parallel.subdev = subdev;
450 return 0;
451 }
452
453
454 vin->mbus_code = 0;
455 code.index = 0;
456 code.pad = vin->parallel.source_pad;
457 while (!vin->mbus_code &&
458 !v4l2_subdev_call(subdev, pad, enum_mbus_code, NULL, &code)) {
459 code.index++;
460 switch (code.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);
469 break;
470 default:
471 break;
472 }
473 }
474
475 if (!vin->mbus_code) {
476 vin_err(vin, "Unsupported media bus format for %s\n",
477 subdev->name);
478 return -EINVAL;
479 }
480
481
482 ret = v4l2_subdev_call(subdev, video, g_tvnorms, &vin->vdev.tvnorms);
483 if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
484 return ret;
485
486
487 vin->std = V4L2_STD_UNKNOWN;
488 ret = v4l2_subdev_call(subdev, video, g_std, &vin->std);
489 if (ret < 0 && ret != -ENOIOCTLCMD)
490 return ret;
491
492
493 ret = v4l2_ctrl_handler_init(&vin->ctrl_handler, 16);
494 if (ret < 0)
495 return ret;
496
497 v4l2_ctrl_new_std(&vin->ctrl_handler, &rvin_ctrl_ops,
498 V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255);
499
500 if (vin->ctrl_handler.error) {
501 ret = vin->ctrl_handler.error;
502 v4l2_ctrl_handler_free(&vin->ctrl_handler);
503 return ret;
504 }
505
506 ret = v4l2_ctrl_add_handler(&vin->ctrl_handler, subdev->ctrl_handler,
507 NULL, true);
508 if (ret < 0) {
509 v4l2_ctrl_handler_free(&vin->ctrl_handler);
510 return ret;
511 }
512
513 vin->vdev.ctrl_handler = &vin->ctrl_handler;
514
515 vin->parallel.subdev = subdev;
516
517 return 0;
518}
519
520static void rvin_parallel_subdevice_detach(struct rvin_dev *vin)
521{
522 rvin_v4l2_unregister(vin);
523 vin->parallel.subdev = NULL;
524
525 if (!vin->info->use_mc) {
526 v4l2_ctrl_handler_free(&vin->ctrl_handler);
527 vin->vdev.ctrl_handler = NULL;
528 }
529}
530
531static int rvin_parallel_notify_complete(struct v4l2_async_notifier *notifier)
532{
533 struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev);
534 struct media_entity *source;
535 struct media_entity *sink;
536 int ret;
537
538 ret = v4l2_device_register_subdev_nodes(&vin->v4l2_dev);
539 if (ret < 0) {
540 vin_err(vin, "Failed to register subdev nodes\n");
541 return ret;
542 }
543
544 if (!video_is_registered(&vin->vdev)) {
545 ret = rvin_v4l2_register(vin);
546 if (ret < 0)
547 return ret;
548 }
549
550 if (!vin->info->use_mc)
551 return 0;
552
553
554 source = &vin->parallel.subdev->entity;
555 sink = &vin->vdev.entity;
556
557 ret = media_create_pad_link(source, vin->parallel.source_pad,
558 sink, vin->parallel.sink_pad, 0);
559 if (ret)
560 vin_err(vin, "Error adding link from %s to %s: %d\n",
561 source->name, sink->name, ret);
562
563 return ret;
564}
565
566static void rvin_parallel_notify_unbind(struct v4l2_async_notifier *notifier,
567 struct v4l2_subdev *subdev,
568 struct v4l2_async_subdev *asd)
569{
570 struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev);
571
572 vin_dbg(vin, "unbind parallel subdev %s\n", subdev->name);
573
574 mutex_lock(&vin->lock);
575 rvin_parallel_subdevice_detach(vin);
576 mutex_unlock(&vin->lock);
577}
578
579static int rvin_parallel_notify_bound(struct v4l2_async_notifier *notifier,
580 struct v4l2_subdev *subdev,
581 struct v4l2_async_subdev *asd)
582{
583 struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev);
584 int ret;
585
586 mutex_lock(&vin->lock);
587 ret = rvin_parallel_subdevice_attach(vin, subdev);
588 mutex_unlock(&vin->lock);
589 if (ret)
590 return ret;
591
592 v4l2_set_subdev_hostdata(subdev, vin);
593
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);
597
598 return 0;
599}
600
601static 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,
605};
606
607static int rvin_parallel_parse_of(struct rvin_dev *vin)
608{
609 struct fwnode_handle *ep, *fwnode;
610 struct v4l2_fwnode_endpoint vep = {
611 .bus_type = V4L2_MBUS_UNKNOWN,
612 };
613 struct v4l2_async_subdev *asd;
614 int ret;
615
616 ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(vin->dev), 0, 0, 0);
617 if (!ep)
618 return 0;
619
620 fwnode = fwnode_graph_get_remote_endpoint(ep);
621 ret = v4l2_fwnode_endpoint_parse(ep, &vep);
622 fwnode_handle_put(ep);
623 if (ret) {
624 vin_err(vin, "Failed to parse %pOF\n", to_of_node(fwnode));
625 ret = -EINVAL;
626 goto out;
627 }
628
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;
637 break;
638 default:
639 vin_err(vin, "Unknown media bus type\n");
640 ret = -EINVAL;
641 goto out;
642 }
643
644 asd = v4l2_async_notifier_add_fwnode_subdev(&vin->notifier, fwnode,
645 struct v4l2_async_subdev);
646 if (IS_ERR(asd)) {
647 ret = PTR_ERR(asd);
648 goto out;
649 }
650
651 vin->parallel.asd = asd;
652
653 vin_dbg(vin, "Add parallel OF device %pOF\n", to_of_node(fwnode));
654out:
655 fwnode_handle_put(fwnode);
656
657 return ret;
658}
659
660static int rvin_parallel_init(struct rvin_dev *vin)
661{
662 int ret;
663
664 v4l2_async_notifier_init(&vin->notifier);
665
666 ret = rvin_parallel_parse_of(vin);
667 if (ret)
668 return ret;
669
670
671 if (!vin->parallel.asd)
672 return vin->info->use_mc ? 0 : -ENODEV;
673
674 vin_dbg(vin, "Found parallel subdevice %pOF\n",
675 to_of_node(vin->parallel.asd->match.fwnode));
676
677 vin->notifier.ops = &rvin_parallel_notify_ops;
678 ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier);
679 if (ret < 0) {
680 vin_err(vin, "Notifier registration failed\n");
681 v4l2_async_notifier_cleanup(&vin->notifier);
682 return ret;
683 }
684
685 return 0;
686}
687
688
689
690
691
692static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier)
693{
694 struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev);
695 const struct rvin_group_route *route;
696 unsigned int i;
697 int ret;
698
699 ret = media_device_register(&vin->group->mdev);
700 if (ret)
701 return ret;
702
703 ret = v4l2_device_register_subdev_nodes(&vin->v4l2_dev);
704 if (ret) {
705 vin_err(vin, "Failed to register subdev nodes\n");
706 return ret;
707 }
708
709
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]);
714 if (ret)
715 return ret;
716 }
717 }
718
719
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;
725
726
727 if (!vin->group->vin[route->vin])
728 continue;
729
730
731 if (!vin->group->vin[rvin_group_id_to_master(route->vin)])
732 continue;
733
734
735 if (!vin->group->csi[route->csi].subdev)
736 continue;
737
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];
741
742 sink = &vin->group->vin[route->vin]->vdev.entity;
743 sink_pad = &sink->pads[0];
744
745
746 if (media_entity_find_link(source_pad, sink_pad))
747 continue;
748
749 ret = media_create_pad_link(source, source_idx, sink, 0, 0);
750 if (ret) {
751 vin_err(vin, "Error adding link from %s to %s\n",
752 source->name, sink->name);
753 break;
754 }
755 }
756 mutex_unlock(&vin->group->lock);
757
758 return ret;
759}
760
761static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier,
762 struct v4l2_subdev *subdev,
763 struct v4l2_async_subdev *asd)
764{
765 struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev);
766 unsigned int i;
767
768 for (i = 0; i < RCAR_VIN_NUM; i++)
769 if (vin->group->vin[i])
770 rvin_v4l2_unregister(vin->group->vin[i]);
771
772 mutex_lock(&vin->group->lock);
773
774 for (i = 0; i < RVIN_CSI_MAX; i++) {
775 if (vin->group->csi[i].asd != asd)
776 continue;
777 vin->group->csi[i].subdev = NULL;
778 vin_dbg(vin, "Unbind CSI-2 %s from slot %u\n", subdev->name, i);
779 break;
780 }
781
782 mutex_unlock(&vin->group->lock);
783
784 media_device_unregister(&vin->group->mdev);
785}
786
787static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier,
788 struct v4l2_subdev *subdev,
789 struct v4l2_async_subdev *asd)
790{
791 struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev);
792 unsigned int i;
793
794 mutex_lock(&vin->group->lock);
795
796 for (i = 0; i < RVIN_CSI_MAX; i++) {
797 if (vin->group->csi[i].asd != asd)
798 continue;
799 vin->group->csi[i].subdev = subdev;
800 vin_dbg(vin, "Bound CSI-2 %s to slot %u\n", subdev->name, i);
801 break;
802 }
803
804 mutex_unlock(&vin->group->lock);
805
806 return 0;
807}
808
809static 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,
813};
814
815static int rvin_mc_parse_of(struct rvin_dev *vin, unsigned int id)
816{
817 struct fwnode_handle *ep, *fwnode;
818 struct v4l2_fwnode_endpoint vep = {
819 .bus_type = V4L2_MBUS_CSI2_DPHY,
820 };
821 struct v4l2_async_subdev *asd;
822 int ret;
823
824 ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(vin->dev), 1, id, 0);
825 if (!ep)
826 return 0;
827
828 fwnode = fwnode_graph_get_remote_endpoint(ep);
829 ret = v4l2_fwnode_endpoint_parse(ep, &vep);
830 fwnode_handle_put(ep);
831 if (ret) {
832 vin_err(vin, "Failed to parse %pOF\n", to_of_node(fwnode));
833 ret = -EINVAL;
834 goto out;
835 }
836
837 if (!of_device_is_available(to_of_node(fwnode))) {
838 vin_dbg(vin, "OF device %pOF disabled, ignoring\n",
839 to_of_node(fwnode));
840 ret = -ENOTCONN;
841 goto out;
842 }
843
844 asd = v4l2_async_notifier_add_fwnode_subdev(&vin->group->notifier,
845 fwnode,
846 struct v4l2_async_subdev);
847 if (IS_ERR(asd)) {
848 ret = PTR_ERR(asd);
849 goto out;
850 }
851
852 vin->group->csi[vep.base.id].asd = asd;
853
854 vin_dbg(vin, "Add group OF device %pOF to slot %u\n",
855 to_of_node(fwnode), vep.base.id);
856out:
857 fwnode_handle_put(fwnode);
858
859 return ret;
860}
861
862static int rvin_mc_parse_of_graph(struct rvin_dev *vin)
863{
864 unsigned int count = 0, vin_mask = 0;
865 unsigned int i, id;
866 int ret;
867
868 mutex_lock(&vin->group->lock);
869
870
871 for (i = 0; i < RCAR_VIN_NUM; i++) {
872 if (vin->group->vin[i]) {
873 count++;
874 vin_mask |= BIT(i);
875 }
876 }
877
878 if (vin->group->count != count) {
879 mutex_unlock(&vin->group->lock);
880 return 0;
881 }
882
883 mutex_unlock(&vin->group->lock);
884
885 v4l2_async_notifier_init(&vin->group->notifier);
886
887
888
889
890
891
892 for (i = 0; i < RCAR_VIN_NUM; i++) {
893 if (!(vin_mask & BIT(i)))
894 continue;
895
896 for (id = 0; id < RVIN_CSI_MAX; id++) {
897 if (vin->group->csi[id].asd)
898 continue;
899
900 ret = rvin_mc_parse_of(vin->group->vin[i], id);
901 if (ret)
902 return ret;
903 }
904 }
905
906 if (list_empty(&vin->group->notifier.asd_list))
907 return 0;
908
909 vin->group->notifier.ops = &rvin_group_notify_ops;
910 ret = v4l2_async_notifier_register(&vin->v4l2_dev,
911 &vin->group->notifier);
912 if (ret < 0) {
913 vin_err(vin, "Notifier registration failed\n");
914 v4l2_async_notifier_cleanup(&vin->group->notifier);
915 return ret;
916 }
917
918 return 0;
919}
920
921static int rvin_mc_init(struct rvin_dev *vin)
922{
923 int ret;
924
925 vin->pad.flags = MEDIA_PAD_FL_SINK;
926 ret = media_entity_pads_init(&vin->vdev.entity, 1, &vin->pad);
927 if (ret)
928 return ret;
929
930 ret = rvin_group_get(vin);
931 if (ret)
932 return ret;
933
934 ret = rvin_mc_parse_of_graph(vin);
935 if (ret)
936 rvin_group_put(vin);
937
938 ret = v4l2_ctrl_handler_init(&vin->ctrl_handler, 1);
939 if (ret < 0)
940 return ret;
941
942 v4l2_ctrl_new_std(&vin->ctrl_handler, &rvin_ctrl_ops,
943 V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255);
944
945 if (vin->ctrl_handler.error) {
946 ret = vin->ctrl_handler.error;
947 v4l2_ctrl_handler_free(&vin->ctrl_handler);
948 return ret;
949 }
950
951 vin->vdev.ctrl_handler = &vin->ctrl_handler;
952
953 return ret;
954}
955
956
957
958
959
960static int __maybe_unused rvin_suspend(struct device *dev)
961{
962 struct rvin_dev *vin = dev_get_drvdata(dev);
963
964 if (vin->state != RUNNING)
965 return 0;
966
967 rvin_stop_streaming(vin);
968
969 vin->state = SUSPENDED;
970
971 return 0;
972}
973
974static int __maybe_unused rvin_resume(struct device *dev)
975{
976 struct rvin_dev *vin = dev_get_drvdata(dev);
977
978 if (vin->state != SUSPENDED)
979 return 0;
980
981
982
983
984
985
986
987
988 if (vin->info->use_mc) {
989 unsigned int master_id = rvin_group_id_to_master(vin->id);
990 struct rvin_dev *master = vin->group->vin[master_id];
991 int ret;
992
993 if (WARN_ON(!master))
994 return -ENODEV;
995
996 ret = rvin_set_channel_routing(master, master->chsel);
997 if (ret)
998 return ret;
999 }
1000
1001 return rvin_start_streaming(vin);
1002}
1003
1004
1005
1006
1007
1008static const struct rvin_info rcar_info_h1 = {
1009 .model = RCAR_H1,
1010 .use_mc = false,
1011 .max_width = 2048,
1012 .max_height = 2048,
1013};
1014
1015static const struct rvin_info rcar_info_m1 = {
1016 .model = RCAR_M1,
1017 .use_mc = false,
1018 .max_width = 2048,
1019 .max_height = 2048,
1020};
1021
1022static const struct rvin_info rcar_info_gen2 = {
1023 .model = RCAR_GEN2,
1024 .use_mc = false,
1025 .max_width = 2048,
1026 .max_height = 2048,
1027};
1028
1029static const struct rvin_group_route rcar_info_r8a774e1_routes[] = {
1030 { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) },
1031 { .csi = RVIN_CSI20, .channel = 0, .vin = 0, .mask = BIT(1) | BIT(4) },
1032 { .csi = RVIN_CSI40, .channel = 1, .vin = 0, .mask = BIT(2) },
1033 { .csi = RVIN_CSI20, .channel = 0, .vin = 1, .mask = BIT(0) },
1034 { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(1) | BIT(3) },
1035 { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) },
1036 { .csi = RVIN_CSI20, .channel = 1, .vin = 1, .mask = BIT(4) },
1037 { .csi = RVIN_CSI20, .channel = 1, .vin = 2, .mask = BIT(0) },
1038 { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) },
1039 { .csi = RVIN_CSI20, .channel = 0, .vin = 2, .mask = BIT(2) },
1040 { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) },
1041 { .csi = RVIN_CSI20, .channel = 2, .vin = 2, .mask = BIT(4) },
1042 { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) },
1043 { .csi = RVIN_CSI20, .channel = 1, .vin = 3, .mask = BIT(1) | BIT(2) },
1044 { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) },
1045 { .csi = RVIN_CSI20, .channel = 3, .vin = 3, .mask = BIT(4) },
1046 { .csi = RVIN_CSI20, .channel = 0, .vin = 4, .mask = BIT(1) | BIT(4) },
1047 { .csi = RVIN_CSI20, .channel = 0, .vin = 5, .mask = BIT(0) },
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_CSI20, .channel = 0, .vin = 6, .mask = BIT(2) },
1051 { .csi = RVIN_CSI20, .channel = 2, .vin = 6, .mask = BIT(4) },
1052 { .csi = RVIN_CSI20, .channel = 1, .vin = 7, .mask = BIT(1) | BIT(2) },
1053 { .csi = RVIN_CSI20, .channel = 3, .vin = 7, .mask = BIT(4) },
1054 { }
1055};
1056
1057static const struct rvin_info rcar_info_r8a774e1 = {
1058 .model = RCAR_GEN3,
1059 .use_mc = true,
1060 .max_width = 4096,
1061 .max_height = 4096,
1062 .routes = rcar_info_r8a774e1_routes,
1063};
1064
1065static const struct rvin_group_route rcar_info_r8a7795_routes[] = {
1066 { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) },
1067 { .csi = RVIN_CSI20, .channel = 0, .vin = 0, .mask = BIT(1) | BIT(4) },
1068 { .csi = RVIN_CSI40, .channel = 1, .vin = 0, .mask = BIT(2) },
1069 { .csi = RVIN_CSI20, .channel = 0, .vin = 1, .mask = BIT(0) },
1070 { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(1) | BIT(3) },
1071 { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) },
1072 { .csi = RVIN_CSI20, .channel = 1, .vin = 1, .mask = BIT(4) },
1073 { .csi = RVIN_CSI20, .channel = 1, .vin = 2, .mask = BIT(0) },
1074 { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) },
1075 { .csi = RVIN_CSI20, .channel = 0, .vin = 2, .mask = BIT(2) },
1076 { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) },
1077 { .csi = RVIN_CSI20, .channel = 2, .vin = 2, .mask = BIT(4) },
1078 { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) },
1079 { .csi = RVIN_CSI20, .channel = 1, .vin = 3, .mask = BIT(1) | BIT(2) },
1080 { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) },
1081 { .csi = RVIN_CSI20, .channel = 3, .vin = 3, .mask = BIT(4) },
1082 { .csi = RVIN_CSI41, .channel = 0, .vin = 4, .mask = BIT(0) | BIT(3) },
1083 { .csi = RVIN_CSI20, .channel = 0, .vin = 4, .mask = BIT(1) | BIT(4) },
1084 { .csi = RVIN_CSI41, .channel = 1, .vin = 4, .mask = BIT(2) },
1085 { .csi = RVIN_CSI20, .channel = 0, .vin = 5, .mask = BIT(0) },
1086 { .csi = RVIN_CSI41, .channel = 1, .vin = 5, .mask = BIT(1) | BIT(3) },
1087 { .csi = RVIN_CSI41, .channel = 0, .vin = 5, .mask = BIT(2) },
1088 { .csi = RVIN_CSI20, .channel = 1, .vin = 5, .mask = BIT(4) },
1089 { .csi = RVIN_CSI20, .channel = 1, .vin = 6, .mask = BIT(0) },
1090 { .csi = RVIN_CSI41, .channel = 0, .vin = 6, .mask = BIT(1) },
1091 { .csi = RVIN_CSI20, .channel = 0, .vin = 6, .mask = BIT(2) },
1092 { .csi = RVIN_CSI41, .channel = 2, .vin = 6, .mask = BIT(3) },
1093 { .csi = RVIN_CSI20, .channel = 2, .vin = 6, .mask = BIT(4) },
1094 { .csi = RVIN_CSI41, .channel = 1, .vin = 7, .mask = BIT(0) },
1095 { .csi = RVIN_CSI20, .channel = 1, .vin = 7, .mask = BIT(1) | BIT(2) },
1096 { .csi = RVIN_CSI41, .channel = 3, .vin = 7, .mask = BIT(3) },
1097 { .csi = RVIN_CSI20, .channel = 3, .vin = 7, .mask = BIT(4) },
1098 { }
1099};
1100
1101static const struct rvin_info rcar_info_r8a7795 = {
1102 .model = RCAR_GEN3,
1103 .use_mc = true,
1104 .nv12 = true,
1105 .max_width = 4096,
1106 .max_height = 4096,
1107 .routes = rcar_info_r8a7795_routes,
1108};
1109
1110static const struct rvin_group_route rcar_info_r8a7795es1_routes[] = {
1111 { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) },
1112 { .csi = RVIN_CSI20, .channel = 0, .vin = 0, .mask = BIT(1) | BIT(4) },
1113 { .csi = RVIN_CSI21, .channel = 0, .vin = 0, .mask = BIT(2) | BIT(5) },
1114 { .csi = RVIN_CSI20, .channel = 0, .vin = 1, .mask = BIT(0) },
1115 { .csi = RVIN_CSI21, .channel = 0, .vin = 1, .mask = BIT(1) },
1116 { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) },
1117 { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(3) },
1118 { .csi = RVIN_CSI20, .channel = 1, .vin = 1, .mask = BIT(4) },
1119 { .csi = RVIN_CSI21, .channel = 1, .vin = 1, .mask = BIT(5) },
1120 { .csi = RVIN_CSI21, .channel = 0, .vin = 2, .mask = BIT(0) },
1121 { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) },
1122 { .csi = RVIN_CSI20, .channel = 0, .vin = 2, .mask = BIT(2) },
1123 { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) },
1124 { .csi = RVIN_CSI20, .channel = 2, .vin = 2, .mask = BIT(4) },
1125 { .csi = RVIN_CSI21, .channel = 2, .vin = 2, .mask = BIT(5) },
1126 { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) },
1127 { .csi = RVIN_CSI20, .channel = 1, .vin = 3, .mask = BIT(1) },
1128 { .csi = RVIN_CSI21, .channel = 1, .vin = 3, .mask = BIT(2) },
1129 { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) },
1130 { .csi = RVIN_CSI20, .channel = 3, .vin = 3, .mask = BIT(4) },
1131 { .csi = RVIN_CSI21, .channel = 3, .vin = 3, .mask = BIT(5) },
1132 { .csi = RVIN_CSI41, .channel = 0, .vin = 4, .mask = BIT(0) | BIT(3) },
1133 { .csi = RVIN_CSI20, .channel = 0, .vin = 4, .mask = BIT(1) | BIT(4) },
1134 { .csi = RVIN_CSI21, .channel = 0, .vin = 4, .mask = BIT(2) | BIT(5) },
1135 { .csi = RVIN_CSI20, .channel = 0, .vin = 5, .mask = BIT(0) },
1136 { .csi = RVIN_CSI21, .channel = 0, .vin = 5, .mask = BIT(1) },
1137 { .csi = RVIN_CSI41, .channel = 0, .vin = 5, .mask = BIT(2) },
1138 { .csi = RVIN_CSI41, .channel = 1, .vin = 5, .mask = BIT(3) },
1139 { .csi = RVIN_CSI20, .channel = 1, .vin = 5, .mask = BIT(4) },
1140 { .csi = RVIN_CSI21, .channel = 1, .vin = 5, .mask = BIT(5) },
1141 { .csi = RVIN_CSI21, .channel = 0, .vin = 6, .mask = BIT(0) },
1142 { .csi = RVIN_CSI41, .channel = 0, .vin = 6, .mask = BIT(1) },
1143 { .csi = RVIN_CSI20, .channel = 0, .vin = 6, .mask = BIT(2) },
1144 { .csi = RVIN_CSI41, .channel = 2, .vin = 6, .mask = BIT(3) },
1145 { .csi = RVIN_CSI20, .channel = 2, .vin = 6, .mask = BIT(4) },
1146 { .csi = RVIN_CSI21, .channel = 2, .vin = 6, .mask = BIT(5) },
1147 { .csi = RVIN_CSI41, .channel = 1, .vin = 7, .mask = BIT(0) },
1148 { .csi = RVIN_CSI20, .channel = 1, .vin = 7, .mask = BIT(1) },
1149 { .csi = RVIN_CSI21, .channel = 1, .vin = 7, .mask = BIT(2) },
1150 { .csi = RVIN_CSI41, .channel = 3, .vin = 7, .mask = BIT(3) },
1151 { .csi = RVIN_CSI20, .channel = 3, .vin = 7, .mask = BIT(4) },
1152 { .csi = RVIN_CSI21, .channel = 3, .vin = 7, .mask = BIT(5) },
1153 { }
1154};
1155
1156static const struct rvin_info rcar_info_r8a7795es1 = {
1157 .model = RCAR_GEN3,
1158 .use_mc = true,
1159 .max_width = 4096,
1160 .max_height = 4096,
1161 .routes = rcar_info_r8a7795es1_routes,
1162};
1163
1164static const struct rvin_group_route rcar_info_r8a7796_routes[] = {
1165 { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) },
1166 { .csi = RVIN_CSI20, .channel = 0, .vin = 0, .mask = BIT(1) | BIT(4) },
1167 { .csi = RVIN_CSI20, .channel = 0, .vin = 1, .mask = BIT(0) },
1168 { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) },
1169 { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(3) },
1170 { .csi = RVIN_CSI20, .channel = 1, .vin = 1, .mask = BIT(4) },
1171 { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) },
1172 { .csi = RVIN_CSI20, .channel = 0, .vin = 2, .mask = BIT(2) },
1173 { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) },
1174 { .csi = RVIN_CSI20, .channel = 2, .vin = 2, .mask = BIT(4) },
1175 { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) },
1176 { .csi = RVIN_CSI20, .channel = 1, .vin = 3, .mask = BIT(1) },
1177 { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) },
1178 { .csi = RVIN_CSI20, .channel = 3, .vin = 3, .mask = BIT(4) },
1179 { .csi = RVIN_CSI40, .channel = 0, .vin = 4, .mask = BIT(0) | BIT(3) },
1180 { .csi = RVIN_CSI20, .channel = 0, .vin = 4, .mask = BIT(1) | BIT(4) },
1181 { .csi = RVIN_CSI20, .channel = 0, .vin = 5, .mask = BIT(0) },
1182 { .csi = RVIN_CSI40, .channel = 0, .vin = 5, .mask = BIT(2) },
1183 { .csi = RVIN_CSI40, .channel = 1, .vin = 5, .mask = BIT(3) },
1184 { .csi = RVIN_CSI20, .channel = 1, .vin = 5, .mask = BIT(4) },
1185 { .csi = RVIN_CSI40, .channel = 0, .vin = 6, .mask = BIT(1) },
1186 { .csi = RVIN_CSI20, .channel = 0, .vin = 6, .mask = BIT(2) },
1187 { .csi = RVIN_CSI40, .channel = 2, .vin = 6, .mask = BIT(3) },
1188 { .csi = RVIN_CSI20, .channel = 2, .vin = 6, .mask = BIT(4) },
1189 { .csi = RVIN_CSI40, .channel = 1, .vin = 7, .mask = BIT(0) },
1190 { .csi = RVIN_CSI20, .channel = 1, .vin = 7, .mask = BIT(1) },
1191 { .csi = RVIN_CSI40, .channel = 3, .vin = 7, .mask = BIT(3) },
1192 { .csi = RVIN_CSI20, .channel = 3, .vin = 7, .mask = BIT(4) },
1193 { }
1194};
1195
1196static const struct rvin_info rcar_info_r8a7796 = {
1197 .model = RCAR_GEN3,
1198 .use_mc = true,
1199 .nv12 = true,
1200 .max_width = 4096,
1201 .max_height = 4096,
1202 .routes = rcar_info_r8a7796_routes,
1203};
1204
1205static const struct rvin_group_route rcar_info_r8a77965_routes[] = {
1206 { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) },
1207 { .csi = RVIN_CSI20, .channel = 0, .vin = 0, .mask = BIT(1) | BIT(4) },
1208 { .csi = RVIN_CSI40, .channel = 1, .vin = 0, .mask = BIT(2) },
1209 { .csi = RVIN_CSI20, .channel = 0, .vin = 1, .mask = BIT(0) },
1210 { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(1) | BIT(3) },
1211 { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) },
1212 { .csi = RVIN_CSI20, .channel = 1, .vin = 1, .mask = BIT(4) },
1213 { .csi = RVIN_CSI20, .channel = 1, .vin = 2, .mask = BIT(0) },
1214 { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) },
1215 { .csi = RVIN_CSI20, .channel = 0, .vin = 2, .mask = BIT(2) },
1216 { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) },
1217 { .csi = RVIN_CSI20, .channel = 2, .vin = 2, .mask = BIT(4) },
1218 { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) },
1219 { .csi = RVIN_CSI20, .channel = 1, .vin = 3, .mask = BIT(1) | BIT(2) },
1220 { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) },
1221 { .csi = RVIN_CSI20, .channel = 3, .vin = 3, .mask = BIT(4) },
1222 { .csi = RVIN_CSI40, .channel = 0, .vin = 4, .mask = BIT(0) | BIT(3) },
1223 { .csi = RVIN_CSI20, .channel = 0, .vin = 4, .mask = BIT(1) | BIT(4) },
1224 { .csi = RVIN_CSI40, .channel = 1, .vin = 4, .mask = BIT(2) },
1225 { .csi = RVIN_CSI20, .channel = 0, .vin = 5, .mask = BIT(0) },
1226 { .csi = RVIN_CSI40, .channel = 1, .vin = 5, .mask = BIT(1) | BIT(3) },
1227 { .csi = RVIN_CSI40, .channel = 0, .vin = 5, .mask = BIT(2) },
1228 { .csi = RVIN_CSI20, .channel = 1, .vin = 5, .mask = BIT(4) },
1229 { .csi = RVIN_CSI20, .channel = 1, .vin = 6, .mask = BIT(0) },
1230 { .csi = RVIN_CSI40, .channel = 0, .vin = 6, .mask = BIT(1) },
1231 { .csi = RVIN_CSI20, .channel = 0, .vin = 6, .mask = BIT(2) },
1232 { .csi = RVIN_CSI40, .channel = 2, .vin = 6, .mask = BIT(3) },
1233 { .csi = RVIN_CSI20, .channel = 2, .vin = 6, .mask = BIT(4) },
1234 { .csi = RVIN_CSI40, .channel = 1, .vin = 7, .mask = BIT(0) },
1235 { .csi = RVIN_CSI20, .channel = 1, .vin = 7, .mask = BIT(1) | BIT(2) },
1236 { .csi = RVIN_CSI40, .channel = 3, .vin = 7, .mask = BIT(3) },
1237 { .csi = RVIN_CSI20, .channel = 3, .vin = 7, .mask = BIT(4) },
1238 { }
1239};
1240
1241static const struct rvin_info rcar_info_r8a77965 = {
1242 .model = RCAR_GEN3,
1243 .use_mc = true,
1244 .nv12 = true,
1245 .max_width = 4096,
1246 .max_height = 4096,
1247 .routes = rcar_info_r8a77965_routes,
1248};
1249
1250static const struct rvin_group_route rcar_info_r8a77970_routes[] = {
1251 { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) },
1252 { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) },
1253 { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(3) },
1254 { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) },
1255 { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) },
1256 { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) },
1257 { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) },
1258 { }
1259};
1260
1261static const struct rvin_info rcar_info_r8a77970 = {
1262 .model = RCAR_GEN3,
1263 .use_mc = true,
1264 .max_width = 4096,
1265 .max_height = 4096,
1266 .routes = rcar_info_r8a77970_routes,
1267};
1268
1269static const struct rvin_group_route rcar_info_r8a77980_routes[] = {
1270 { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) },
1271 { .csi = RVIN_CSI40, .channel = 1, .vin = 0, .mask = BIT(2) },
1272 { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) },
1273 { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(1) | BIT(3) },
1274 { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) },
1275 { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) },
1276 { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) },
1277 { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) },
1278 { .csi = RVIN_CSI41, .channel = 0, .vin = 4, .mask = BIT(0) | BIT(3) },
1279 { .csi = RVIN_CSI41, .channel = 1, .vin = 4, .mask = BIT(2) },
1280 { .csi = RVIN_CSI41, .channel = 0, .vin = 5, .mask = BIT(2) },
1281 { .csi = RVIN_CSI41, .channel = 1, .vin = 5, .mask = BIT(1) | BIT(3) },
1282 { .csi = RVIN_CSI41, .channel = 0, .vin = 6, .mask = BIT(1) },
1283 { .csi = RVIN_CSI41, .channel = 2, .vin = 6, .mask = BIT(3) },
1284 { .csi = RVIN_CSI41, .channel = 1, .vin = 7, .mask = BIT(0) },
1285 { .csi = RVIN_CSI41, .channel = 3, .vin = 7, .mask = BIT(3) },
1286 { }
1287};
1288
1289static const struct rvin_info rcar_info_r8a77980 = {
1290 .model = RCAR_GEN3,
1291 .use_mc = true,
1292 .nv12 = true,
1293 .max_width = 4096,
1294 .max_height = 4096,
1295 .routes = rcar_info_r8a77980_routes,
1296};
1297
1298static const struct rvin_group_route rcar_info_r8a77990_routes[] = {
1299 { .csi = RVIN_CSI40, .channel = 0, .vin = 4, .mask = BIT(0) | BIT(3) },
1300 { .csi = RVIN_CSI40, .channel = 0, .vin = 5, .mask = BIT(2) },
1301 { .csi = RVIN_CSI40, .channel = 1, .vin = 4, .mask = BIT(2) },
1302 { .csi = RVIN_CSI40, .channel = 1, .vin = 5, .mask = BIT(1) | BIT(3) },
1303 { }
1304};
1305
1306static const struct rvin_info rcar_info_r8a77990 = {
1307 .model = RCAR_GEN3,
1308 .use_mc = true,
1309 .nv12 = true,
1310 .max_width = 4096,
1311 .max_height = 4096,
1312 .routes = rcar_info_r8a77990_routes,
1313};
1314
1315static const struct rvin_group_route rcar_info_r8a77995_routes[] = {
1316 { }
1317};
1318
1319static const struct rvin_info rcar_info_r8a77995 = {
1320 .model = RCAR_GEN3,
1321 .use_mc = true,
1322 .nv12 = true,
1323 .max_width = 4096,
1324 .max_height = 4096,
1325 .routes = rcar_info_r8a77995_routes,
1326};
1327
1328static const struct of_device_id rvin_of_id_table[] = {
1329 {
1330 .compatible = "renesas,vin-r8a774a1",
1331 .data = &rcar_info_r8a7796,
1332 },
1333 {
1334 .compatible = "renesas,vin-r8a774b1",
1335 .data = &rcar_info_r8a77965,
1336 },
1337 {
1338 .compatible = "renesas,vin-r8a774c0",
1339 .data = &rcar_info_r8a77990,
1340 },
1341 {
1342 .compatible = "renesas,vin-r8a774e1",
1343 .data = &rcar_info_r8a774e1,
1344 },
1345 {
1346 .compatible = "renesas,vin-r8a7778",
1347 .data = &rcar_info_m1,
1348 },
1349 {
1350 .compatible = "renesas,vin-r8a7779",
1351 .data = &rcar_info_h1,
1352 },
1353 {
1354 .compatible = "renesas,rcar-gen2-vin",
1355 .data = &rcar_info_gen2,
1356 },
1357 {
1358 .compatible = "renesas,vin-r8a7795",
1359 .data = &rcar_info_r8a7795,
1360 },
1361 {
1362 .compatible = "renesas,vin-r8a7796",
1363 .data = &rcar_info_r8a7796,
1364 },
1365 {
1366 .compatible = "renesas,vin-r8a77965",
1367 .data = &rcar_info_r8a77965,
1368 },
1369 {
1370 .compatible = "renesas,vin-r8a77970",
1371 .data = &rcar_info_r8a77970,
1372 },
1373 {
1374 .compatible = "renesas,vin-r8a77980",
1375 .data = &rcar_info_r8a77980,
1376 },
1377 {
1378 .compatible = "renesas,vin-r8a77990",
1379 .data = &rcar_info_r8a77990,
1380 },
1381 {
1382 .compatible = "renesas,vin-r8a77995",
1383 .data = &rcar_info_r8a77995,
1384 },
1385 { },
1386};
1387MODULE_DEVICE_TABLE(of, rvin_of_id_table);
1388
1389static const struct soc_device_attribute r8a7795es1[] = {
1390 {
1391 .soc_id = "r8a7795", .revision = "ES1.*",
1392 .data = &rcar_info_r8a7795es1,
1393 },
1394 { }
1395};
1396
1397static int rcar_vin_probe(struct platform_device *pdev)
1398{
1399 const struct soc_device_attribute *attr;
1400 struct rvin_dev *vin;
1401 int irq, ret;
1402
1403 vin = devm_kzalloc(&pdev->dev, sizeof(*vin), GFP_KERNEL);
1404 if (!vin)
1405 return -ENOMEM;
1406
1407 vin->dev = &pdev->dev;
1408 vin->info = of_device_get_match_data(&pdev->dev);
1409 vin->alpha = 0xff;
1410
1411
1412
1413
1414
1415 attr = soc_device_match(r8a7795es1);
1416 if (attr)
1417 vin->info = attr->data;
1418
1419 vin->base = devm_platform_ioremap_resource(pdev, 0);
1420 if (IS_ERR(vin->base))
1421 return PTR_ERR(vin->base);
1422
1423 irq = platform_get_irq(pdev, 0);
1424 if (irq < 0)
1425 return irq;
1426
1427 ret = rvin_dma_register(vin, irq);
1428 if (ret)
1429 return ret;
1430
1431 platform_set_drvdata(pdev, vin);
1432
1433 if (vin->info->use_mc) {
1434 ret = rvin_mc_init(vin);
1435 if (ret)
1436 goto error_dma_unregister;
1437 }
1438
1439 ret = rvin_parallel_init(vin);
1440 if (ret)
1441 goto error_group_unregister;
1442
1443 pm_suspend_ignore_children(&pdev->dev, true);
1444 pm_runtime_enable(&pdev->dev);
1445
1446 return 0;
1447
1448error_group_unregister:
1449 v4l2_ctrl_handler_free(&vin->ctrl_handler);
1450
1451 if (vin->info->use_mc) {
1452 mutex_lock(&vin->group->lock);
1453 if (&vin->v4l2_dev == vin->group->notifier.v4l2_dev) {
1454 v4l2_async_notifier_unregister(&vin->group->notifier);
1455 v4l2_async_notifier_cleanup(&vin->group->notifier);
1456 }
1457 mutex_unlock(&vin->group->lock);
1458 rvin_group_put(vin);
1459 }
1460
1461error_dma_unregister:
1462 rvin_dma_unregister(vin);
1463
1464 return ret;
1465}
1466
1467static int rcar_vin_remove(struct platform_device *pdev)
1468{
1469 struct rvin_dev *vin = platform_get_drvdata(pdev);
1470
1471 pm_runtime_disable(&pdev->dev);
1472
1473 rvin_v4l2_unregister(vin);
1474
1475 v4l2_async_notifier_unregister(&vin->notifier);
1476 v4l2_async_notifier_cleanup(&vin->notifier);
1477
1478 if (vin->info->use_mc) {
1479 v4l2_async_notifier_unregister(&vin->group->notifier);
1480 v4l2_async_notifier_cleanup(&vin->group->notifier);
1481 rvin_group_put(vin);
1482 }
1483
1484 v4l2_ctrl_handler_free(&vin->ctrl_handler);
1485
1486 rvin_dma_unregister(vin);
1487
1488 return 0;
1489}
1490
1491static SIMPLE_DEV_PM_OPS(rvin_pm_ops, rvin_suspend, rvin_resume);
1492
1493static struct platform_driver rcar_vin_driver = {
1494 .driver = {
1495 .name = "rcar-vin",
1496 .pm = &rvin_pm_ops,
1497 .of_match_table = rvin_of_id_table,
1498 },
1499 .probe = rcar_vin_probe,
1500 .remove = rcar_vin_remove,
1501};
1502
1503module_platform_driver(rcar_vin_driver);
1504
1505MODULE_AUTHOR("Niklas Söderlund <niklas.soderlund@ragnatech.se>");
1506MODULE_DESCRIPTION("Renesas R-Car VIN camera host driver");
1507MODULE_LICENSE("GPL");
1508