aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSylwester Nawrocki <s.nawrocki@samsung.com>2013-03-08 10:59:33 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2013-03-31 09:46:12 -0400
commite2985a260e6615503b4fa8e66788708e750c7750 (patch)
tree4a793ca4e1cce65a6f0e3d993d04b2a56f300b5a
parenteb62d9e9d6327322a5fd3894bfecb3a3aa9391ba (diff)
[media] s5p-fimc: Add device tree support for the media device driver
This patch adds changes required for the main camera media device driver corresponding to the top level 'camera' device node. The drivers of devices corresponding to child nodes of the 'camera' node are looked up and and registered as sub-devices to the top level driver. The main driver's probing is deferred if any of the sub-device drivers is not yet initialized and ready. Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com> Signed-off-by: Andrzej Hajda <a.hajda@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-core.c1
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-mdevice.c108
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-mdevice.h5
-rw-r--r--include/media/s5p_fimc.h1
4 files changed, 98 insertions, 17 deletions
diff --git a/drivers/media/platform/s5p-fimc/fimc-core.c b/drivers/media/platform/s5p-fimc/fimc-core.c
index d39e47abb229..6a8098c42cc8 100644
--- a/drivers/media/platform/s5p-fimc/fimc-core.c
+++ b/drivers/media/platform/s5p-fimc/fimc-core.c
@@ -1281,7 +1281,6 @@ static const struct platform_device_id fimc_driver_ids[] = {
1281 }, 1281 },
1282 { }, 1282 { },
1283}; 1283};
1284MODULE_DEVICE_TABLE(platform, fimc_driver_ids);
1285 1284
1286static const struct of_device_id fimc_of_match[] = { 1285static const struct of_device_id fimc_of_match[] = {
1287 { 1286 {
diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c
index a17fcb2d5d41..d34106c66427 100644
--- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c
+++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c
@@ -17,11 +17,16 @@
17#include <linux/kernel.h> 17#include <linux/kernel.h>
18#include <linux/list.h> 18#include <linux/list.h>
19#include <linux/module.h> 19#include <linux/module.h>
20#include <linux/of.h>
21#include <linux/of_platform.h>
22#include <linux/of_device.h>
23#include <linux/of_i2c.h>
20#include <linux/platform_device.h> 24#include <linux/platform_device.h>
21#include <linux/pm_runtime.h> 25#include <linux/pm_runtime.h>
22#include <linux/types.h> 26#include <linux/types.h>
23#include <linux/slab.h> 27#include <linux/slab.h>
24#include <media/v4l2-ctrls.h> 28#include <media/v4l2-ctrls.h>
29#include <media/v4l2-of.h>
25#include <media/media-device.h> 30#include <media/media-device.h>
26#include <media/s5p_fimc.h> 31#include <media/s5p_fimc.h>
27 32
@@ -264,6 +269,21 @@ static void fimc_md_unregister_sensor(struct v4l2_subdev *sd)
264 i2c_put_adapter(adapter); 269 i2c_put_adapter(adapter);
265} 270}
266 271
272#ifdef CONFIG_OF
273static int __of_get_csis_id(struct device_node *np)
274{
275 u32 reg = 0;
276
277 np = of_get_child_by_name(np, "port");
278 if (!np)
279 return -EINVAL;
280 of_property_read_u32(np, "reg", &reg);
281 return reg - FIMC_INPUT_MIPI_CSI2_0;
282}
283#else
284#define __of_get_csis_id(np) (-ENOSYS)
285#endif
286
267static int fimc_md_register_sensor_entities(struct fimc_md *fmd) 287static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
268{ 288{
269 struct s5p_platform_fimc *pdata = fmd->pdev->dev.platform_data; 289 struct s5p_platform_fimc *pdata = fmd->pdev->dev.platform_data;
@@ -368,13 +388,13 @@ static int register_csis_entity(struct fimc_md *fmd,
368 struct device_node *node = pdev->dev.of_node; 388 struct device_node *node = pdev->dev.of_node;
369 int id, ret; 389 int id, ret;
370 390
371 id = node ? of_alias_get_id(node, "csis") : max(0, pdev->id); 391 id = node ? __of_get_csis_id(node) : max(0, pdev->id);
372 392
373 if (WARN_ON(id >= CSIS_MAX_ENTITIES || fmd->csis[id].sd)) 393 if (WARN_ON(id < 0 || id >= CSIS_MAX_ENTITIES))
374 return -EBUSY; 394 return -ENOENT;
375 395
376 if (WARN_ON(id >= CSIS_MAX_ENTITIES)) 396 if (WARN_ON(fmd->csis[id].sd))
377 return 0; 397 return -EBUSY;
378 398
379 sd->grp_id = GRP_ID_CSIS; 399 sd->grp_id = GRP_ID_CSIS;
380 ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); 400 ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
@@ -457,6 +477,45 @@ static int fimc_md_pdev_match(struct device *dev, void *data)
457 return 0; 477 return 0;
458} 478}
459 479
480/* Register FIMC, FIMC-LITE and CSIS media entities */
481#ifdef CONFIG_OF
482static int fimc_md_register_of_platform_entities(struct fimc_md *fmd,
483 struct device_node *parent)
484{
485 struct device_node *node;
486 int ret = 0;
487
488 for_each_available_child_of_node(parent, node) {
489 struct platform_device *pdev;
490 int plat_entity = -1;
491
492 pdev = of_find_device_by_node(node);
493 if (!pdev)
494 continue;
495
496 /* If driver of any entity isn't ready try all again later. */
497 if (!strcmp(node->name, CSIS_OF_NODE_NAME))
498 plat_entity = IDX_CSIS;
499 else if (!strcmp(node->name, FIMC_LITE_OF_NODE_NAME))
500 plat_entity = IDX_FLITE;
501 else if (!strcmp(node->name, FIMC_OF_NODE_NAME) &&
502 !of_property_read_bool(node, "samsung,lcd-wb"))
503 plat_entity = IDX_FIMC;
504
505 if (plat_entity >= 0)
506 ret = fimc_md_register_platform_entity(fmd, pdev,
507 plat_entity);
508 put_device(&pdev->dev);
509 if (ret < 0)
510 break;
511 }
512
513 return ret;
514}
515#else
516#define fimc_md_register_of_platform_entities(fmd, node) (-ENOSYS)
517#endif
518
460static void fimc_md_unregister_entities(struct fimc_md *fmd) 519static void fimc_md_unregister_entities(struct fimc_md *fmd)
461{ 520{
462 int i; 521 int i;
@@ -929,11 +988,12 @@ static DEVICE_ATTR(subdev_conf_mode, S_IWUSR | S_IRUGO,
929 988
930static int fimc_md_probe(struct platform_device *pdev) 989static int fimc_md_probe(struct platform_device *pdev)
931{ 990{
991 struct device *dev = &pdev->dev;
932 struct v4l2_device *v4l2_dev; 992 struct v4l2_device *v4l2_dev;
933 struct fimc_md *fmd; 993 struct fimc_md *fmd;
934 int ret; 994 int ret;
935 995
936 fmd = devm_kzalloc(&pdev->dev, sizeof(*fmd), GFP_KERNEL); 996 fmd = devm_kzalloc(dev, sizeof(*fmd), GFP_KERNEL);
937 if (!fmd) 997 if (!fmd)
938 return -ENOMEM; 998 return -ENOMEM;
939 999
@@ -943,15 +1003,14 @@ static int fimc_md_probe(struct platform_device *pdev)
943 strlcpy(fmd->media_dev.model, "SAMSUNG S5P FIMC", 1003 strlcpy(fmd->media_dev.model, "SAMSUNG S5P FIMC",
944 sizeof(fmd->media_dev.model)); 1004 sizeof(fmd->media_dev.model));
945 fmd->media_dev.link_notify = fimc_md_link_notify; 1005 fmd->media_dev.link_notify = fimc_md_link_notify;
946 fmd->media_dev.dev = &pdev->dev; 1006 fmd->media_dev.dev = dev;
947 1007
948 v4l2_dev = &fmd->v4l2_dev; 1008 v4l2_dev = &fmd->v4l2_dev;
949 v4l2_dev->mdev = &fmd->media_dev; 1009 v4l2_dev->mdev = &fmd->media_dev;
950 v4l2_dev->notify = fimc_sensor_notify; 1010 v4l2_dev->notify = fimc_sensor_notify;
951 snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s", 1011 strlcpy(v4l2_dev->name, "s5p-fimc-md", sizeof(v4l2_dev->name));
952 dev_name(&pdev->dev));
953 1012
954 ret = v4l2_device_register(&pdev->dev, &fmd->v4l2_dev); 1013 ret = v4l2_device_register(dev, &fmd->v4l2_dev);
955 if (ret < 0) { 1014 if (ret < 0) {
956 v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret); 1015 v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret);
957 return ret; 1016 return ret;
@@ -965,21 +1024,25 @@ static int fimc_md_probe(struct platform_device *pdev)
965 if (ret) 1024 if (ret)
966 goto err_clk; 1025 goto err_clk;
967 1026
968 fmd->user_subdev_api = false; 1027 fmd->user_subdev_api = (dev->of_node != NULL);
969 1028
970 /* Protect the media graph while we're registering entities */ 1029 /* Protect the media graph while we're registering entities */
971 mutex_lock(&fmd->media_dev.graph_mutex); 1030 mutex_lock(&fmd->media_dev.graph_mutex);
972 1031
973 ret = bus_for_each_dev(&platform_bus_type, NULL, fmd, 1032 if (dev->of_node)
974 fimc_md_pdev_match); 1033 ret = fimc_md_register_of_platform_entities(fmd, dev->of_node);
1034 else
1035 ret = bus_for_each_dev(&platform_bus_type, NULL, fmd,
1036 fimc_md_pdev_match);
975 if (ret) 1037 if (ret)
976 goto err_unlock; 1038 goto err_unlock;
977 1039
978 if (pdev->dev.platform_data) { 1040 if (dev->platform_data) {
979 ret = fimc_md_register_sensor_entities(fmd); 1041 ret = fimc_md_register_sensor_entities(fmd);
980 if (ret) 1042 if (ret)
981 goto err_unlock; 1043 goto err_unlock;
982 } 1044 }
1045
983 ret = fimc_md_create_links(fmd); 1046 ret = fimc_md_create_links(fmd);
984 if (ret) 1047 if (ret)
985 goto err_unlock; 1048 goto err_unlock;
@@ -1019,12 +1082,25 @@ static int fimc_md_remove(struct platform_device *pdev)
1019 return 0; 1082 return 0;
1020} 1083}
1021 1084
1085static struct platform_device_id fimc_driver_ids[] __always_unused = {
1086 { .name = "s5p-fimc-md" },
1087 { },
1088};
1089MODULE_DEVICE_TABLE(platform, fimc_driver_ids);
1090
1091static const struct of_device_id fimc_md_of_match[] = {
1092 { .compatible = "samsung,fimc" },
1093 { },
1094};
1095MODULE_DEVICE_TABLE(of, fimc_md_of_match);
1096
1022static struct platform_driver fimc_md_driver = { 1097static struct platform_driver fimc_md_driver = {
1023 .probe = fimc_md_probe, 1098 .probe = fimc_md_probe,
1024 .remove = fimc_md_remove, 1099 .remove = fimc_md_remove,
1025 .driver = { 1100 .driver = {
1026 .name = "s5p-fimc-md", 1101 .of_match_table = of_match_ptr(fimc_md_of_match),
1027 .owner = THIS_MODULE, 1102 .name = "s5p-fimc-md",
1103 .owner = THIS_MODULE,
1028 } 1104 }
1029}; 1105};
1030 1106
diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.h b/drivers/media/platform/s5p-fimc/fimc-mdevice.h
index 06b0d8276fd2..b6ceb5984664 100644
--- a/drivers/media/platform/s5p-fimc/fimc-mdevice.h
+++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.h
@@ -21,6 +21,11 @@
21#include "fimc-lite.h" 21#include "fimc-lite.h"
22#include "mipi-csis.h" 22#include "mipi-csis.h"
23 23
24#define FIMC_OF_NODE_NAME "fimc"
25#define FIMC_LITE_OF_NODE_NAME "fimc-lite"
26#define FIMC_IS_OF_NODE_NAME "fimc-is"
27#define CSIS_OF_NODE_NAME "csis"
28
24/* Group IDs of sensor, MIPI-CSIS, FIMC-LITE and the writeback subdevs. */ 29/* Group IDs of sensor, MIPI-CSIS, FIMC-LITE and the writeback subdevs. */
25#define GRP_ID_SENSOR (1 << 8) 30#define GRP_ID_SENSOR (1 << 8)
26#define GRP_ID_FIMC_IS_SENSOR (1 << 9) 31#define GRP_ID_FIMC_IS_SENSOR (1 << 9)
diff --git a/include/media/s5p_fimc.h b/include/media/s5p_fimc.h
index d6dbb791f423..e2c598962698 100644
--- a/include/media/s5p_fimc.h
+++ b/include/media/s5p_fimc.h
@@ -94,6 +94,7 @@ enum fimc_subdev_index {
94 IDX_SENSOR, 94 IDX_SENSOR,
95 IDX_CSIS, 95 IDX_CSIS,
96 IDX_FLITE, 96 IDX_FLITE,
97 IDX_IS_ISP,
97 IDX_FIMC, 98 IDX_FIMC,
98 IDX_MAX, 99 IDX_MAX,
99}; 100};