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