Merge tag 'media/v4.20-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[muen/linux.git] / drivers / staging / media / imx / imx-media-dev.c
1 /*
2  * V4L2 Media Controller Driver for Freescale i.MX5/6 SOC
3  *
4  * Copyright (c) 2016 Mentor Graphics Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  */
11 #include <linux/delay.h>
12 #include <linux/fs.h>
13 #include <linux/module.h>
14 #include <linux/of_graph.h>
15 #include <linux/of_platform.h>
16 #include <linux/pinctrl/consumer.h>
17 #include <linux/platform_device.h>
18 #include <linux/sched.h>
19 #include <linux/slab.h>
20 #include <linux/spinlock.h>
21 #include <linux/timer.h>
22 #include <media/v4l2-ctrls.h>
23 #include <media/v4l2-event.h>
24 #include <media/v4l2-ioctl.h>
25 #include <media/v4l2-mc.h>
26 #include <video/imx-ipu-v3.h>
27 #include <media/imx.h>
28 #include "imx-media.h"
29
30 static inline struct imx_media_dev *notifier2dev(struct v4l2_async_notifier *n)
31 {
32         return container_of(n, struct imx_media_dev, notifier);
33 }
34
35 /*
36  * Adds a subdev to the root notifier's async subdev list. If fwnode is
37  * non-NULL, adds the async as a V4L2_ASYNC_MATCH_FWNODE match type,
38  * otherwise as a V4L2_ASYNC_MATCH_DEVNAME match type using the dev_name
39  * of the given platform_device. This is called during driver load when
40  * forming the async subdev list.
41  */
42 int imx_media_add_async_subdev(struct imx_media_dev *imxmd,
43                                struct fwnode_handle *fwnode,
44                                struct platform_device *pdev)
45 {
46         struct device_node *np = to_of_node(fwnode);
47         struct imx_media_async_subdev *imxasd;
48         struct v4l2_async_subdev *asd;
49         const char *devname = NULL;
50         int ret;
51
52         if (fwnode) {
53                 asd = v4l2_async_notifier_add_fwnode_subdev(
54                         &imxmd->notifier, fwnode, sizeof(*imxasd));
55         } else {
56                 devname = dev_name(&pdev->dev);
57                 asd = v4l2_async_notifier_add_devname_subdev(
58                         &imxmd->notifier, devname, sizeof(*imxasd));
59         }
60
61         if (IS_ERR(asd)) {
62                 ret = PTR_ERR(asd);
63                 if (ret == -EEXIST) {
64                         if (np)
65                                 dev_dbg(imxmd->md.dev, "%s: already added %pOFn\n",
66                                         __func__, np);
67                         else
68                                 dev_dbg(imxmd->md.dev, "%s: already added %s\n",
69                                         __func__, devname);
70                 }
71                 return ret;
72         }
73
74         imxasd = to_imx_media_asd(asd);
75
76         if (devname)
77                 imxasd->pdev = pdev;
78
79         if (np)
80                 dev_dbg(imxmd->md.dev, "%s: added %pOFn, match type FWNODE\n",
81                         __func__, np);
82         else
83                 dev_dbg(imxmd->md.dev, "%s: added %s, match type DEVNAME\n",
84                         __func__, devname);
85
86         return 0;
87 }
88
89 /*
90  * get IPU from this CSI and add it to the list of IPUs
91  * the media driver will control.
92  */
93 static int imx_media_get_ipu(struct imx_media_dev *imxmd,
94                              struct v4l2_subdev *csi_sd)
95 {
96         struct ipu_soc *ipu;
97         int ipu_id;
98
99         ipu = dev_get_drvdata(csi_sd->dev->parent);
100         if (!ipu) {
101                 v4l2_err(&imxmd->v4l2_dev,
102                          "CSI %s has no parent IPU!\n", csi_sd->name);
103                 return -ENODEV;
104         }
105
106         ipu_id = ipu_get_num(ipu);
107         if (ipu_id > 1) {
108                 v4l2_err(&imxmd->v4l2_dev, "invalid IPU id %d!\n", ipu_id);
109                 return -ENODEV;
110         }
111
112         if (!imxmd->ipu[ipu_id])
113                 imxmd->ipu[ipu_id] = ipu;
114
115         return 0;
116 }
117
118 /* async subdev bound notifier */
119 static int imx_media_subdev_bound(struct v4l2_async_notifier *notifier,
120                                   struct v4l2_subdev *sd,
121                                   struct v4l2_async_subdev *asd)
122 {
123         struct imx_media_dev *imxmd = notifier2dev(notifier);
124         int ret = 0;
125
126         mutex_lock(&imxmd->mutex);
127
128         if (sd->grp_id & IMX_MEDIA_GRP_ID_CSI) {
129                 ret = imx_media_get_ipu(imxmd, sd);
130                 if (ret)
131                         goto out;
132         }
133
134         v4l2_info(&imxmd->v4l2_dev, "subdev %s bound\n", sd->name);
135 out:
136         mutex_unlock(&imxmd->mutex);
137         return ret;
138 }
139
140 /*
141  * Create the media links for all subdevs that registered.
142  * Called after all async subdevs have bound.
143  */
144 static int imx_media_create_links(struct v4l2_async_notifier *notifier)
145 {
146         struct imx_media_dev *imxmd = notifier2dev(notifier);
147         struct v4l2_subdev *sd;
148         int ret;
149
150         list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
151                 switch (sd->grp_id) {
152                 case IMX_MEDIA_GRP_ID_VDIC:
153                 case IMX_MEDIA_GRP_ID_IC_PRP:
154                 case IMX_MEDIA_GRP_ID_IC_PRPENC:
155                 case IMX_MEDIA_GRP_ID_IC_PRPVF:
156                 case IMX_MEDIA_GRP_ID_CSI0:
157                 case IMX_MEDIA_GRP_ID_CSI1:
158                         ret = imx_media_create_internal_links(imxmd, sd);
159                         if (ret)
160                                 return ret;
161                         /*
162                          * the CSIs straddle between the external and the IPU
163                          * internal entities, so create the external links
164                          * to the CSI sink pads.
165                          */
166                         if (sd->grp_id & IMX_MEDIA_GRP_ID_CSI)
167                                 imx_media_create_csi_of_links(imxmd, sd);
168                         break;
169                 default:
170                         /*
171                          * if this subdev has fwnode links, create media
172                          * links for them.
173                          */
174                         imx_media_create_of_links(imxmd, sd);
175                         break;
176                 }
177         }
178
179         return 0;
180 }
181
182 /*
183  * adds given video device to given imx-media source pad vdev list.
184  * Continues upstream from the pad entity's sink pads.
185  */
186 static int imx_media_add_vdev_to_pad(struct imx_media_dev *imxmd,
187                                      struct imx_media_video_dev *vdev,
188                                      struct media_pad *srcpad)
189 {
190         struct media_entity *entity = srcpad->entity;
191         struct imx_media_pad_vdev *pad_vdev;
192         struct list_head *pad_vdev_list;
193         struct media_link *link;
194         struct v4l2_subdev *sd;
195         int i, ret;
196
197         /* skip this entity if not a v4l2_subdev */
198         if (!is_media_entity_v4l2_subdev(entity))
199                 return 0;
200
201         sd = media_entity_to_v4l2_subdev(entity);
202
203         pad_vdev_list = to_pad_vdev_list(sd, srcpad->index);
204         if (!pad_vdev_list) {
205                 v4l2_warn(&imxmd->v4l2_dev, "%s:%u has no vdev list!\n",
206                           entity->name, srcpad->index);
207                 /*
208                  * shouldn't happen, but no reason to fail driver load,
209                  * just skip this entity.
210                  */
211                 return 0;
212         }
213
214         /* just return if we've been here before */
215         list_for_each_entry(pad_vdev, pad_vdev_list, list) {
216                 if (pad_vdev->vdev == vdev)
217                         return 0;
218         }
219
220         dev_dbg(imxmd->md.dev, "adding %s to pad %s:%u\n",
221                 vdev->vfd->entity.name, entity->name, srcpad->index);
222
223         pad_vdev = devm_kzalloc(imxmd->md.dev, sizeof(*pad_vdev), GFP_KERNEL);
224         if (!pad_vdev)
225                 return -ENOMEM;
226
227         /* attach this vdev to this pad */
228         pad_vdev->vdev = vdev;
229         list_add_tail(&pad_vdev->list, pad_vdev_list);
230
231         /* move upstream from this entity's sink pads */
232         for (i = 0; i < entity->num_pads; i++) {
233                 struct media_pad *pad = &entity->pads[i];
234
235                 if (!(pad->flags & MEDIA_PAD_FL_SINK))
236                         continue;
237
238                 list_for_each_entry(link, &entity->links, list) {
239                         if (link->sink != pad)
240                                 continue;
241                         ret = imx_media_add_vdev_to_pad(imxmd, vdev,
242                                                         link->source);
243                         if (ret)
244                                 return ret;
245                 }
246         }
247
248         return 0;
249 }
250
251 /*
252  * For every subdevice, allocate an array of list_head's, one list_head
253  * for each pad, to hold the list of video devices reachable from that
254  * pad.
255  */
256 static int imx_media_alloc_pad_vdev_lists(struct imx_media_dev *imxmd)
257 {
258         struct list_head *vdev_lists;
259         struct media_entity *entity;
260         struct v4l2_subdev *sd;
261         int i;
262
263         list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) {
264                 entity = &sd->entity;
265                 vdev_lists = devm_kcalloc(
266                         imxmd->md.dev,
267                         entity->num_pads, sizeof(*vdev_lists),
268                         GFP_KERNEL);
269                 if (!vdev_lists)
270                         return -ENOMEM;
271
272                 /* attach to the subdev's host private pointer */
273                 sd->host_priv = vdev_lists;
274
275                 for (i = 0; i < entity->num_pads; i++)
276                         INIT_LIST_HEAD(to_pad_vdev_list(sd, i));
277         }
278
279         return 0;
280 }
281
282 /* form the vdev lists in all imx-media source pads */
283 static int imx_media_create_pad_vdev_lists(struct imx_media_dev *imxmd)
284 {
285         struct imx_media_video_dev *vdev;
286         struct media_link *link;
287         int ret;
288
289         ret = imx_media_alloc_pad_vdev_lists(imxmd);
290         if (ret)
291                 return ret;
292
293         list_for_each_entry(vdev, &imxmd->vdev_list, list) {
294                 link = list_first_entry(&vdev->vfd->entity.links,
295                                         struct media_link, list);
296                 ret = imx_media_add_vdev_to_pad(imxmd, vdev, link->source);
297                 if (ret)
298                         return ret;
299         }
300
301         return 0;
302 }
303
304 /* async subdev complete notifier */
305 static int imx_media_probe_complete(struct v4l2_async_notifier *notifier)
306 {
307         struct imx_media_dev *imxmd = notifier2dev(notifier);
308         int ret;
309
310         mutex_lock(&imxmd->mutex);
311
312         ret = imx_media_create_links(notifier);
313         if (ret)
314                 goto unlock;
315
316         ret = imx_media_create_pad_vdev_lists(imxmd);
317         if (ret)
318                 goto unlock;
319
320         ret = v4l2_device_register_subdev_nodes(&imxmd->v4l2_dev);
321 unlock:
322         mutex_unlock(&imxmd->mutex);
323         if (ret)
324                 return ret;
325
326         return media_device_register(&imxmd->md);
327 }
328
329 static const struct v4l2_async_notifier_operations imx_media_subdev_ops = {
330         .bound = imx_media_subdev_bound,
331         .complete = imx_media_probe_complete,
332 };
333
334 /*
335  * adds controls to a video device from an entity subdevice.
336  * Continues upstream from the entity's sink pads.
337  */
338 static int imx_media_inherit_controls(struct imx_media_dev *imxmd,
339                                       struct video_device *vfd,
340                                       struct media_entity *entity)
341 {
342         int i, ret = 0;
343
344         if (is_media_entity_v4l2_subdev(entity)) {
345                 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
346
347                 dev_dbg(imxmd->md.dev,
348                         "adding controls to %s from %s\n",
349                         vfd->entity.name, sd->entity.name);
350
351                 ret = v4l2_ctrl_add_handler(vfd->ctrl_handler,
352                                             sd->ctrl_handler,
353                                             NULL, true);
354                 if (ret)
355                         return ret;
356         }
357
358         /* move upstream */
359         for (i = 0; i < entity->num_pads; i++) {
360                 struct media_pad *pad, *spad = &entity->pads[i];
361
362                 if (!(spad->flags & MEDIA_PAD_FL_SINK))
363                         continue;
364
365                 pad = media_entity_remote_pad(spad);
366                 if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
367                         continue;
368
369                 ret = imx_media_inherit_controls(imxmd, vfd, pad->entity);
370                 if (ret)
371                         break;
372         }
373
374         return ret;
375 }
376
377 static int imx_media_link_notify(struct media_link *link, u32 flags,
378                                  unsigned int notification)
379 {
380         struct media_entity *source = link->source->entity;
381         struct imx_media_pad_vdev *pad_vdev;
382         struct list_head *pad_vdev_list;
383         struct imx_media_dev *imxmd;
384         struct video_device *vfd;
385         struct v4l2_subdev *sd;
386         int pad_idx, ret;
387
388         ret = v4l2_pipeline_link_notify(link, flags, notification);
389         if (ret)
390                 return ret;
391
392         /* don't bother if source is not a subdev */
393         if (!is_media_entity_v4l2_subdev(source))
394                 return 0;
395
396         sd = media_entity_to_v4l2_subdev(source);
397         pad_idx = link->source->index;
398
399         imxmd = dev_get_drvdata(sd->v4l2_dev->dev);
400
401         pad_vdev_list = to_pad_vdev_list(sd, pad_idx);
402         if (!pad_vdev_list) {
403                 /* shouldn't happen, but no reason to fail link setup */
404                 return 0;
405         }
406
407         /*
408          * Before disabling a link, reset controls for all video
409          * devices reachable from this link.
410          *
411          * After enabling a link, refresh controls for all video
412          * devices reachable from this link.
413          */
414         if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH &&
415             !(flags & MEDIA_LNK_FL_ENABLED)) {
416                 list_for_each_entry(pad_vdev, pad_vdev_list, list) {
417                         vfd = pad_vdev->vdev->vfd;
418                         dev_dbg(imxmd->md.dev,
419                                 "reset controls for %s\n",
420                                 vfd->entity.name);
421                         v4l2_ctrl_handler_free(vfd->ctrl_handler);
422                         v4l2_ctrl_handler_init(vfd->ctrl_handler, 0);
423                 }
424         } else if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
425                    (link->flags & MEDIA_LNK_FL_ENABLED)) {
426                 list_for_each_entry(pad_vdev, pad_vdev_list, list) {
427                         vfd = pad_vdev->vdev->vfd;
428                         dev_dbg(imxmd->md.dev,
429                                 "refresh controls for %s\n",
430                                 vfd->entity.name);
431                         ret = imx_media_inherit_controls(imxmd, vfd,
432                                                          &vfd->entity);
433                         if (ret)
434                                 break;
435                 }
436         }
437
438         return ret;
439 }
440
441 static const struct media_device_ops imx_media_md_ops = {
442         .link_notify = imx_media_link_notify,
443 };
444
445 static int imx_media_probe(struct platform_device *pdev)
446 {
447         struct device *dev = &pdev->dev;
448         struct device_node *node = dev->of_node;
449         struct imx_media_dev *imxmd;
450         int ret;
451
452         imxmd = devm_kzalloc(dev, sizeof(*imxmd), GFP_KERNEL);
453         if (!imxmd)
454                 return -ENOMEM;
455
456         dev_set_drvdata(dev, imxmd);
457
458         strscpy(imxmd->md.model, "imx-media", sizeof(imxmd->md.model));
459         imxmd->md.ops = &imx_media_md_ops;
460         imxmd->md.dev = dev;
461
462         mutex_init(&imxmd->mutex);
463
464         imxmd->v4l2_dev.mdev = &imxmd->md;
465         strscpy(imxmd->v4l2_dev.name, "imx-media",
466                 sizeof(imxmd->v4l2_dev.name));
467
468         media_device_init(&imxmd->md);
469
470         ret = v4l2_device_register(dev, &imxmd->v4l2_dev);
471         if (ret < 0) {
472                 v4l2_err(&imxmd->v4l2_dev,
473                          "Failed to register v4l2_device: %d\n", ret);
474                 goto cleanup;
475         }
476
477         dev_set_drvdata(imxmd->v4l2_dev.dev, imxmd);
478
479         INIT_LIST_HEAD(&imxmd->vdev_list);
480
481         v4l2_async_notifier_init(&imxmd->notifier);
482
483         ret = imx_media_add_of_subdevs(imxmd, node);
484         if (ret) {
485                 v4l2_err(&imxmd->v4l2_dev,
486                          "add_of_subdevs failed with %d\n", ret);
487                 goto notifier_cleanup;
488         }
489
490         ret = imx_media_add_internal_subdevs(imxmd);
491         if (ret) {
492                 v4l2_err(&imxmd->v4l2_dev,
493                          "add_internal_subdevs failed with %d\n", ret);
494                 goto notifier_cleanup;
495         }
496
497         /* no subdevs? just bail */
498         if (list_empty(&imxmd->notifier.asd_list)) {
499                 ret = -ENODEV;
500                 goto notifier_cleanup;
501         }
502
503         /* prepare the async subdev notifier and register it */
504         imxmd->notifier.ops = &imx_media_subdev_ops;
505         ret = v4l2_async_notifier_register(&imxmd->v4l2_dev,
506                                            &imxmd->notifier);
507         if (ret) {
508                 v4l2_err(&imxmd->v4l2_dev,
509                          "v4l2_async_notifier_register failed with %d\n", ret);
510                 goto del_int;
511         }
512
513         return 0;
514
515 del_int:
516         imx_media_remove_internal_subdevs(imxmd);
517 notifier_cleanup:
518         v4l2_async_notifier_cleanup(&imxmd->notifier);
519         v4l2_device_unregister(&imxmd->v4l2_dev);
520 cleanup:
521         media_device_cleanup(&imxmd->md);
522         return ret;
523 }
524
525 static int imx_media_remove(struct platform_device *pdev)
526 {
527         struct imx_media_dev *imxmd =
528                 (struct imx_media_dev *)platform_get_drvdata(pdev);
529
530         v4l2_info(&imxmd->v4l2_dev, "Removing imx-media\n");
531
532         v4l2_async_notifier_unregister(&imxmd->notifier);
533         imx_media_remove_internal_subdevs(imxmd);
534         v4l2_async_notifier_cleanup(&imxmd->notifier);
535         v4l2_device_unregister(&imxmd->v4l2_dev);
536         media_device_unregister(&imxmd->md);
537         media_device_cleanup(&imxmd->md);
538
539         return 0;
540 }
541
542 static const struct of_device_id imx_media_dt_ids[] = {
543         { .compatible = "fsl,imx-capture-subsystem" },
544         { /* sentinel */ }
545 };
546 MODULE_DEVICE_TABLE(of, imx_media_dt_ids);
547
548 static struct platform_driver imx_media_pdrv = {
549         .probe          = imx_media_probe,
550         .remove         = imx_media_remove,
551         .driver         = {
552                 .name   = "imx-media",
553                 .of_match_table = imx_media_dt_ids,
554         },
555 };
556
557 module_platform_driver(imx_media_pdrv);
558
559 MODULE_DESCRIPTION("i.MX5/6 v4l2 media controller driver");
560 MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>");
561 MODULE_LICENSE("GPL");