aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/platform/vimc/vimc-capture.c
diff options
context:
space:
mode:
authorHelen Fornazier <helen.koike@collabora.com>2017-06-19 13:00:18 -0400
committerMauro Carvalho Chehab <mchehab@s-opensource.com>2017-06-23 08:12:07 -0400
commit4a29b70907496aa9da79112ec31cf9cf2b972c3f (patch)
tree9be42df7b467e369899f96e2e4d2e25869bf42f8 /drivers/media/platform/vimc/vimc-capture.c
parent535d296f4841ffbd7f773ff2a559daa6e117f315 (diff)
[media] vimc: Subdevices as modules
Change the core structure for adding subdevices in the topology. Instead of calling the specific create function for each subdevice, inject a child platform_device with the driver's name. Each type of node in the topology (sensor, capture, debayer, scaler) will register a platform_driver with the corresponding name through the component subsystem. Implementing a new subdevice type doesn't require vimc-core to be altered. This facilitates future implementation of dynamic entities, where hotpluging an entity in the topology is just a matter of registering/unregistering a platform_device in the system. It also facilitates other implementations of different nodes without touching the core code and remove the need of a header file for each type of node. Signed-off-by: Helen Koike <helen.koike@collabora.com> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Diffstat (limited to 'drivers/media/platform/vimc/vimc-capture.c')
-rw-r--r--drivers/media/platform/vimc/vimc-capture.c99
1 files changed, 69 insertions, 30 deletions
diff --git a/drivers/media/platform/vimc/vimc-capture.c b/drivers/media/platform/vimc/vimc-capture.c
index 359f59efb44e..14cb32e21130 100644
--- a/drivers/media/platform/vimc/vimc-capture.c
+++ b/drivers/media/platform/vimc/vimc-capture.c
@@ -15,15 +15,21 @@
15 * 15 *
16 */ 16 */
17 17
18#include <linux/component.h>
19#include <linux/module.h>
20#include <linux/platform_device.h>
18#include <media/v4l2-ioctl.h> 21#include <media/v4l2-ioctl.h>
19#include <media/videobuf2-core.h> 22#include <media/videobuf2-core.h>
20#include <media/videobuf2-vmalloc.h> 23#include <media/videobuf2-vmalloc.h>
21 24
22#include "vimc-capture.h" 25#include "vimc-common.h"
26
27#define VIMC_CAP_DRV_NAME "vimc-capture"
23 28
24struct vimc_cap_device { 29struct vimc_cap_device {
25 struct vimc_ent_device ved; 30 struct vimc_ent_device ved;
26 struct video_device vdev; 31 struct video_device vdev;
32 struct device *dev;
27 struct v4l2_pix_format format; 33 struct v4l2_pix_format format;
28 struct vb2_queue queue; 34 struct vb2_queue queue;
29 struct list_head buf_list; 35 struct list_head buf_list;
@@ -131,7 +137,7 @@ static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv,
131 137
132 vimc_cap_try_fmt_vid_cap(file, priv, f); 138 vimc_cap_try_fmt_vid_cap(file, priv, f);
133 139
134 dev_dbg(vcap->vdev.v4l2_dev->dev, "%s: format update: " 140 dev_dbg(vcap->dev, "%s: format update: "
135 "old:%dx%d (0x%x, %d, %d, %d, %d) " 141 "old:%dx%d (0x%x, %d, %d, %d, %d) "
136 "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vcap->vdev.name, 142 "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vcap->vdev.name,
137 /* old */ 143 /* old */
@@ -309,8 +315,7 @@ static int vimc_cap_buffer_prepare(struct vb2_buffer *vb)
309 unsigned long size = vcap->format.sizeimage; 315 unsigned long size = vcap->format.sizeimage;
310 316
311 if (vb2_plane_size(vb, 0) < size) { 317 if (vb2_plane_size(vb, 0) < size) {
312 dev_err(vcap->vdev.v4l2_dev->dev, 318 dev_err(vcap->dev, "%s: buffer too small (%lu < %lu)\n",
313 "%s: buffer too small (%lu < %lu)\n",
314 vcap->vdev.name, vb2_plane_size(vb, 0), size); 319 vcap->vdev.name, vb2_plane_size(vb, 0), size);
315 return -EINVAL; 320 return -EINVAL;
316 } 321 }
@@ -335,8 +340,10 @@ static const struct media_entity_operations vimc_cap_mops = {
335 .link_validate = vimc_link_validate, 340 .link_validate = vimc_link_validate,
336}; 341};
337 342
338static void vimc_cap_destroy(struct vimc_ent_device *ved) 343static void vimc_cap_comp_unbind(struct device *comp, struct device *master,
344 void *master_data)
339{ 345{
346 struct vimc_ent_device *ved = dev_get_drvdata(comp);
340 struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, 347 struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device,
341 ved); 348 ved);
342 349
@@ -385,42 +392,35 @@ static void vimc_cap_process_frame(struct vimc_ent_device *ved,
385 vb2_buffer_done(&vimc_buf->vb2.vb2_buf, VB2_BUF_STATE_DONE); 392 vb2_buffer_done(&vimc_buf->vb2.vb2_buf, VB2_BUF_STATE_DONE);
386} 393}
387 394
388struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, 395static int vimc_cap_comp_bind(struct device *comp, struct device *master,
389 const char *const name, 396 void *master_data)
390 u16 num_pads,
391 const unsigned long *pads_flag)
392{ 397{
398 struct v4l2_device *v4l2_dev = master_data;
399 struct vimc_platform_data *pdata = comp->platform_data;
393 const struct vimc_pix_map *vpix; 400 const struct vimc_pix_map *vpix;
394 struct vimc_cap_device *vcap; 401 struct vimc_cap_device *vcap;
395 struct video_device *vdev; 402 struct video_device *vdev;
396 struct vb2_queue *q; 403 struct vb2_queue *q;
397 int ret; 404 int ret;
398 405
399 /*
400 * Check entity configuration params
401 * NOTE: we only support a single sink pad
402 */
403 if (!name || num_pads != 1 || !pads_flag ||
404 !(pads_flag[0] & MEDIA_PAD_FL_SINK))
405 return ERR_PTR(-EINVAL);
406
407 /* Allocate the vimc_cap_device struct */ 406 /* Allocate the vimc_cap_device struct */
408 vcap = kzalloc(sizeof(*vcap), GFP_KERNEL); 407 vcap = kzalloc(sizeof(*vcap), GFP_KERNEL);
409 if (!vcap) 408 if (!vcap)
410 return ERR_PTR(-ENOMEM); 409 return -ENOMEM;
411 410
412 /* Allocate the pads */ 411 /* Allocate the pads */
413 vcap->ved.pads = vimc_pads_init(num_pads, pads_flag); 412 vcap->ved.pads =
413 vimc_pads_init(1, (const unsigned long[1]) {MEDIA_PAD_FL_SINK});
414 if (IS_ERR(vcap->ved.pads)) { 414 if (IS_ERR(vcap->ved.pads)) {
415 ret = PTR_ERR(vcap->ved.pads); 415 ret = PTR_ERR(vcap->ved.pads);
416 goto err_free_vcap; 416 goto err_free_vcap;
417 } 417 }
418 418
419 /* Initialize the media entity */ 419 /* Initialize the media entity */
420 vcap->vdev.entity.name = name; 420 vcap->vdev.entity.name = pdata->entity_name;
421 vcap->vdev.entity.function = MEDIA_ENT_F_IO_V4L; 421 vcap->vdev.entity.function = MEDIA_ENT_F_IO_V4L;
422 ret = media_entity_pads_init(&vcap->vdev.entity, 422 ret = media_entity_pads_init(&vcap->vdev.entity,
423 num_pads, vcap->ved.pads); 423 1, vcap->ved.pads);
424 if (ret) 424 if (ret)
425 goto err_clean_pads; 425 goto err_clean_pads;
426 426
@@ -441,9 +441,8 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev,
441 441
442 ret = vb2_queue_init(q); 442 ret = vb2_queue_init(q);
443 if (ret) { 443 if (ret) {
444 dev_err(vcap->vdev.v4l2_dev->dev, 444 dev_err(comp, "%s: vb2 queue init failed (err=%d)\n",
445 "%s: vb2 queue init failed (err=%d)\n", 445 pdata->entity_name, ret);
446 vcap->vdev.name, ret);
447 goto err_clean_m_ent; 446 goto err_clean_m_ent;
448 } 447 }
449 448
@@ -459,10 +458,11 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev,
459 vcap->format.height; 458 vcap->format.height;
460 459
461 /* Fill the vimc_ent_device struct */ 460 /* Fill the vimc_ent_device struct */
462 vcap->ved.destroy = vimc_cap_destroy;
463 vcap->ved.ent = &vcap->vdev.entity; 461 vcap->ved.ent = &vcap->vdev.entity;
464 vcap->ved.process_frame = vimc_cap_process_frame; 462 vcap->ved.process_frame = vimc_cap_process_frame;
465 vcap->ved.vdev_get_format = vimc_cap_get_format; 463 vcap->ved.vdev_get_format = vimc_cap_get_format;
464 dev_set_drvdata(comp, &vcap->ved);
465 vcap->dev = comp;
466 466
467 /* Initialize the video_device struct */ 467 /* Initialize the video_device struct */
468 vdev = &vcap->vdev; 468 vdev = &vcap->vdev;
@@ -475,19 +475,18 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev,
475 vdev->queue = q; 475 vdev->queue = q;
476 vdev->v4l2_dev = v4l2_dev; 476 vdev->v4l2_dev = v4l2_dev;
477 vdev->vfl_dir = VFL_DIR_RX; 477 vdev->vfl_dir = VFL_DIR_RX;
478 strlcpy(vdev->name, name, sizeof(vdev->name)); 478 strlcpy(vdev->name, pdata->entity_name, sizeof(vdev->name));
479 video_set_drvdata(vdev, &vcap->ved); 479 video_set_drvdata(vdev, &vcap->ved);
480 480
481 /* Register the video_device with the v4l2 and the media framework */ 481 /* Register the video_device with the v4l2 and the media framework */
482 ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); 482 ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
483 if (ret) { 483 if (ret) {
484 dev_err(vcap->vdev.v4l2_dev->dev, 484 dev_err(comp, "%s: video register failed (err=%d)\n",
485 "%s: video register failed (err=%d)\n",
486 vcap->vdev.name, ret); 485 vcap->vdev.name, ret);
487 goto err_release_queue; 486 goto err_release_queue;
488 } 487 }
489 488
490 return &vcap->ved; 489 return 0;
491 490
492err_release_queue: 491err_release_queue:
493 vb2_queue_release(q); 492 vb2_queue_release(q);
@@ -498,5 +497,45 @@ err_clean_pads:
498err_free_vcap: 497err_free_vcap:
499 kfree(vcap); 498 kfree(vcap);
500 499
501 return ERR_PTR(ret); 500 return ret;
502} 501}
502
503static const struct component_ops vimc_cap_comp_ops = {
504 .bind = vimc_cap_comp_bind,
505 .unbind = vimc_cap_comp_unbind,
506};
507
508static int vimc_cap_probe(struct platform_device *pdev)
509{
510 return component_add(&pdev->dev, &vimc_cap_comp_ops);
511}
512
513static int vimc_cap_remove(struct platform_device *pdev)
514{
515 component_del(&pdev->dev, &vimc_cap_comp_ops);
516
517 return 0;
518}
519
520static struct platform_driver vimc_cap_pdrv = {
521 .probe = vimc_cap_probe,
522 .remove = vimc_cap_remove,
523 .driver = {
524 .name = VIMC_CAP_DRV_NAME,
525 },
526};
527
528static const struct platform_device_id vimc_cap_driver_ids[] = {
529 {
530 .name = VIMC_CAP_DRV_NAME,
531 },
532 { }
533};
534
535module_platform_driver(vimc_cap_pdrv);
536
537MODULE_DEVICE_TABLE(platform, vimc_cap_driver_ids);
538
539MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC) Capture");
540MODULE_AUTHOR("Helen Mae Koike Fornazier <helen.fornazier@gmail.com>");
541MODULE_LICENSE("GPL");