aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/s5p-fimc/fimc-mdevice.c
diff options
context:
space:
mode:
authorSylwester Nawrocki <s.nawrocki@samsung.com>2012-04-27 04:29:05 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-05-20 08:26:24 -0400
commit4af813108b880e96a4b8b01e162f950a4aaa2475 (patch)
tree43d66e2ed014d2cf9101a242b957644f4d055d75 /drivers/media/video/s5p-fimc/fimc-mdevice.c
parent5af86c2691b9e0fc1f993cdcd4aa27eb684c1c17 (diff)
[media] s5p-fimc: Add support for Exynos4x12 FIMC-LITE
This patch adds driver for FIMC-LITE camera host interface. This new IP differs from the regular FIMC IP in that it doesn't have input DMA, scaler and color space conversion support. So it just plain camera host interface for MIPI-CSI2 and ITU-R interfaces. For the serial bus support it interworks with MIPI-CSIS and the exisiting s5p-csis driver. The FIMC-LITE and MIPI-CSIS drivers can also be reused in the Exynos5 SoC series. Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/s5p-fimc/fimc-mdevice.c')
-rw-r--r--drivers/media/video/s5p-fimc/fimc-mdevice.c152
1 files changed, 133 insertions, 19 deletions
diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.c b/drivers/media/video/s5p-fimc/fimc-mdevice.c
index 212474130dfb..6753c45631b8 100644
--- a/drivers/media/video/s5p-fimc/fimc-mdevice.c
+++ b/drivers/media/video/s5p-fimc/fimc-mdevice.c
@@ -66,6 +66,9 @@ void fimc_pipeline_prepare(struct fimc_pipeline *p, struct media_entity *me)
66 case CSIS_GROUP_ID: 66 case CSIS_GROUP_ID:
67 p->subdevs[IDX_CSIS] = sd; 67 p->subdevs[IDX_CSIS] = sd;
68 break; 68 break;
69 case FLITE_GROUP_ID:
70 p->subdevs[IDX_FLITE] = sd;
71 break;
69 case FIMC_GROUP_ID: 72 case FIMC_GROUP_ID:
70 /* No need to control FIMC subdev through subdev ops */ 73 /* No need to control FIMC subdev through subdev ops */
71 break; 74 break;
@@ -336,6 +339,7 @@ static int fimc_register_callback(struct device *dev, void *p)
336 339
337 if (!fimc || !fimc->pdev) 340 if (!fimc || !fimc->pdev)
338 return 0; 341 return 0;
342
339 if (fimc->pdev->id < 0 || fimc->pdev->id >= FIMC_MAX_DEVS) 343 if (fimc->pdev->id < 0 || fimc->pdev->id >= FIMC_MAX_DEVS)
340 return 0; 344 return 0;
341 345
@@ -351,6 +355,31 @@ static int fimc_register_callback(struct device *dev, void *p)
351 return ret; 355 return ret;
352} 356}
353 357
358static int fimc_lite_register_callback(struct device *dev, void *p)
359{
360 struct fimc_lite *fimc = dev_get_drvdata(dev);
361 struct v4l2_subdev *sd = &fimc->subdev;
362 struct fimc_md *fmd = p;
363 int ret;
364
365 if (fimc == NULL)
366 return 0;
367
368 if (fimc->index >= FIMC_LITE_MAX_DEVS)
369 return 0;
370
371 fmd->fimc_lite[fimc->index] = fimc;
372 sd->grp_id = FLITE_GROUP_ID;
373
374 ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
375 if (ret) {
376 v4l2_err(&fmd->v4l2_dev,
377 "Failed to register FIMC-LITE.%d (%d)\n",
378 fimc->index, ret);
379 }
380 return ret;
381}
382
354static int csis_register_callback(struct device *dev, void *p) 383static int csis_register_callback(struct device *dev, void *p)
355{ 384{
356 struct v4l2_subdev *sd = dev_get_drvdata(dev); 385 struct v4l2_subdev *sd = dev_get_drvdata(dev);
@@ -396,6 +425,15 @@ static int fimc_md_register_platform_entities(struct fimc_md *fmd)
396 fimc_register_callback); 425 fimc_register_callback);
397 if (ret) 426 if (ret)
398 return ret; 427 return ret;
428
429 driver = driver_find(FIMC_LITE_DRV_NAME, &platform_bus_type);
430 if (driver && try_module_get(driver->owner)) {
431 ret = driver_for_each_device(driver, NULL, fmd,
432 fimc_lite_register_callback);
433 if (ret)
434 return ret;
435 module_put(driver->owner);
436 }
399 /* 437 /*
400 * Check if there is any sensor on the MIPI-CSI2 bus and 438 * Check if there is any sensor on the MIPI-CSI2 bus and
401 * if not skip the s5p-csis module loading. 439 * if not skip the s5p-csis module loading.
@@ -433,6 +471,12 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd)
433 v4l2_device_unregister_subdev(&fmd->fimc[i]->vid_cap.subdev); 471 v4l2_device_unregister_subdev(&fmd->fimc[i]->vid_cap.subdev);
434 fmd->fimc[i] = NULL; 472 fmd->fimc[i] = NULL;
435 } 473 }
474 for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
475 if (fmd->fimc_lite[i] == NULL)
476 continue;
477 v4l2_device_unregister_subdev(&fmd->fimc_lite[i]->subdev);
478 fmd->fimc_lite[i] = NULL;
479 }
436 for (i = 0; i < CSIS_MAX_ENTITIES; i++) { 480 for (i = 0; i < CSIS_MAX_ENTITIES; i++) {
437 if (fmd->csis[i].sd == NULL) 481 if (fmd->csis[i].sd == NULL)
438 continue; 482 continue;
@@ -456,28 +500,28 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd)
456 * @pad: the source entity pad index 500 * @pad: the source entity pad index
457 * @fimc_id: index of the fimc device for which link should be enabled 501 * @fimc_id: index of the fimc device for which link should be enabled
458 */ 502 */
459static int __fimc_md_create_fimc_links(struct fimc_md *fmd, 503static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
460 struct media_entity *source, 504 struct media_entity *source,
461 struct v4l2_subdev *sensor, 505 struct v4l2_subdev *sensor,
462 int pad, int fimc_id) 506 int pad, int fimc_id)
463{ 507{
464 struct fimc_sensor_info *s_info; 508 struct fimc_sensor_info *s_info;
465 struct media_entity *sink; 509 struct media_entity *sink;
466 unsigned int flags; 510 unsigned int flags = 0;
467 int ret, i; 511 int ret, i;
468 512
469 for (i = 0; i < FIMC_MAX_DEVS; i++) { 513 for (i = 0; i < FIMC_MAX_DEVS; i++) {
470 if (!fmd->fimc[i]) 514 if (!fmd->fimc[i])
471 break; 515 continue;
472 /* 516 /*
473 * Some FIMC variants are not fitted with camera capture 517 * Some FIMC variants are not fitted with camera capture
474 * interface. Skip creating a link from sensor for those. 518 * interface. Skip creating a link from sensor for those.
475 */ 519 */
476 if (sensor->grp_id == SENSOR_GROUP_ID && 520 if (!fmd->fimc[i]->variant->has_cam_if)
477 !fmd->fimc[i]->variant->has_cam_if)
478 continue; 521 continue;
479 522
480 flags = (i == fimc_id) ? MEDIA_LNK_FL_ENABLED : 0; 523 flags = (i == fimc_id) ? MEDIA_LNK_FL_ENABLED : 0;
524
481 sink = &fmd->fimc[i]->vid_cap.subdev.entity; 525 sink = &fmd->fimc[i]->vid_cap.subdev.entity;
482 ret = media_entity_create_link(source, pad, sink, 526 ret = media_entity_create_link(source, pad, sink,
483 FIMC_SD_PAD_SINK, flags); 527 FIMC_SD_PAD_SINK, flags);
@@ -493,7 +537,7 @@ static int __fimc_md_create_fimc_links(struct fimc_md *fmd,
493 v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]", 537 v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]",
494 source->name, flags ? '=' : '-', sink->name); 538 source->name, flags ? '=' : '-', sink->name);
495 539
496 if (flags == 0) 540 if (flags == 0 || sensor == NULL)
497 continue; 541 continue;
498 s_info = v4l2_get_subdev_hostdata(sensor); 542 s_info = v4l2_get_subdev_hostdata(sensor);
499 if (!WARN_ON(s_info == NULL)) { 543 if (!WARN_ON(s_info == NULL)) {
@@ -503,9 +547,55 @@ static int __fimc_md_create_fimc_links(struct fimc_md *fmd,
503 spin_unlock_irqrestore(&fmd->slock, irq_flags); 547 spin_unlock_irqrestore(&fmd->slock, irq_flags);
504 } 548 }
505 } 549 }
550
551 for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
552 if (!fmd->fimc_lite[i])
553 continue;
554
555 flags = (i == fimc_id) ? MEDIA_LNK_FL_ENABLED : 0;
556
557 sink = &fmd->fimc_lite[i]->subdev.entity;
558 ret = media_entity_create_link(source, pad, sink,
559 FLITE_SD_PAD_SINK, flags);
560 if (ret)
561 return ret;
562
563 /* Notify FIMC-LITE subdev entity */
564 ret = media_entity_call(sink, link_setup, &sink->pads[0],
565 &source->pads[pad], flags);
566 if (ret)
567 break;
568
569 v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]",
570 source->name, flags ? '=' : '-', sink->name);
571 }
506 return 0; 572 return 0;
507} 573}
508 574
575/* Create links from FIMC-LITE source pads to other entities */
576static int __fimc_md_create_flite_source_links(struct fimc_md *fmd)
577{
578 struct media_entity *source, *sink;
579 unsigned int flags = MEDIA_LNK_FL_ENABLED;
580 int i, ret;
581
582 for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
583 struct fimc_lite *fimc = fmd->fimc_lite[i];
584 if (fimc == NULL)
585 continue;
586 source = &fimc->subdev.entity;
587 sink = &fimc->vfd->entity;
588 /* FIMC-LITE's subdev and video node */
589 ret = media_entity_create_link(source, FIMC_SD_PAD_SOURCE,
590 sink, 0, flags);
591 if (ret)
592 break;
593 /* TODO: create links to other entities */
594 }
595
596 return ret;
597}
598
509/** 599/**
510 * fimc_md_create_links - create default links between registered entities 600 * fimc_md_create_links - create default links between registered entities
511 * 601 *
@@ -562,8 +652,7 @@ static int fimc_md_create_links(struct fimc_md *fmd)
562 v4l2_info(&fmd->v4l2_dev, "created link [%s] => [%s]", 652 v4l2_info(&fmd->v4l2_dev, "created link [%s] => [%s]",
563 sensor->entity.name, csis->entity.name); 653 sensor->entity.name, csis->entity.name);
564 654
565 source = &csis->entity; 655 source = NULL;
566 pad = CSIS_PAD_SOURCE;
567 break; 656 break;
568 657
569 case FIMC_ITU_601...FIMC_ITU_656: 658 case FIMC_ITU_601...FIMC_ITU_656:
@@ -579,9 +668,21 @@ static int fimc_md_create_links(struct fimc_md *fmd)
579 if (source == NULL) 668 if (source == NULL)
580 continue; 669 continue;
581 670
582 ret = __fimc_md_create_fimc_links(fmd, source, sensor, pad, 671 ret = __fimc_md_create_fimc_sink_links(fmd, source, sensor,
583 fimc_id++); 672 pad, fimc_id++);
673 }
674
675 fimc_id = 0;
676 for (i = 0; i < ARRAY_SIZE(fmd->csis); i++) {
677 if (fmd->csis[i].sd == NULL)
678 continue;
679 source = &fmd->csis[i].sd->entity;
680 pad = CSIS_PAD_SOURCE;
681
682 ret = __fimc_md_create_fimc_sink_links(fmd, source, NULL,
683 pad, fimc_id++);
584 } 684 }
685
585 /* Create immutable links between each FIMC's subdev and video node */ 686 /* Create immutable links between each FIMC's subdev and video node */
586 flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED; 687 flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED;
587 for (i = 0; i < FIMC_MAX_DEVS; i++) { 688 for (i = 0; i < FIMC_MAX_DEVS; i++) {
@@ -595,7 +696,7 @@ static int fimc_md_create_links(struct fimc_md *fmd)
595 break; 696 break;
596 } 697 }
597 698
598 return ret; 699 return __fimc_md_create_flite_source_links(fmd);
599} 700}
600 701
601/* 702/*
@@ -703,9 +804,10 @@ int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on)
703static int fimc_md_link_notify(struct media_pad *source, 804static int fimc_md_link_notify(struct media_pad *source,
704 struct media_pad *sink, u32 flags) 805 struct media_pad *sink, u32 flags)
705{ 806{
807 struct fimc_lite *fimc_lite = NULL;
808 struct fimc_dev *fimc = NULL;
706 struct fimc_pipeline *pipeline; 809 struct fimc_pipeline *pipeline;
707 struct v4l2_subdev *sd; 810 struct v4l2_subdev *sd;
708 struct fimc_dev *fimc;
709 int ret = 0; 811 int ret = 0;
710 812
711 if (media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV) 813 if (media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
@@ -714,6 +816,10 @@ static int fimc_md_link_notify(struct media_pad *source,
714 sd = media_entity_to_v4l2_subdev(sink->entity); 816 sd = media_entity_to_v4l2_subdev(sink->entity);
715 817
716 switch (sd->grp_id) { 818 switch (sd->grp_id) {
819 case FLITE_GROUP_ID:
820 fimc_lite = v4l2_get_subdevdata(sd);
821 pipeline = &fimc_lite->pipeline;
822 break;
717 case FIMC_GROUP_ID: 823 case FIMC_GROUP_ID:
718 fimc = v4l2_get_subdevdata(sd); 824 fimc = v4l2_get_subdevdata(sd);
719 pipeline = &fimc->pipeline; 825 pipeline = &fimc->pipeline;
@@ -739,15 +845,23 @@ static int fimc_md_link_notify(struct media_pad *source,
739 * pipeline is already in use, i.e. its video node is opened. 845 * pipeline is already in use, i.e. its video node is opened.
740 * Recreate the controls destroyed during the link deactivation. 846 * Recreate the controls destroyed during the link deactivation.
741 */ 847 */
742 mutex_lock(&fimc->lock); 848 if (fimc) {
743 if (fimc->vid_cap.refcnt > 0) { 849 mutex_lock(&fimc->lock);
850 if (fimc->vid_cap.refcnt > 0) {
744 ret = __fimc_pipeline_initialize(pipeline, 851 ret = __fimc_pipeline_initialize(pipeline,
745 source->entity, true); 852 source->entity, true);
746 if (!ret) 853 if (!ret)
747 ret = fimc_capture_ctrls_create(fimc); 854 ret = fimc_capture_ctrls_create(fimc);
855 }
856 mutex_unlock(&fimc->lock);
857 } else {
858 mutex_lock(&fimc_lite->lock);
859 if (fimc_lite->ref_count > 0) {
860 ret = __fimc_pipeline_initialize(pipeline,
861 source->entity, true);
862 }
863 mutex_unlock(&fimc_lite->lock);
748 } 864 }
749 mutex_unlock(&fimc->lock);
750
751 return ret ? -EPIPE : ret; 865 return ret ? -EPIPE : ret;
752} 866}
753 867