aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSylwester Nawrocki <s.nawrocki@samsung.com>2014-02-24 09:44:50 -0500
committerMauro Carvalho Chehab <m.chehab@samsung.com>2014-03-14 09:35:28 -0400
commitfa91f1056f17c87bc0fa601f80d1b1a4487fd701 (patch)
tree5b11033aa1a1399a0952639465b70ec5168e4043
parentd3f5e0c54f1bfa5f48e92ac45a279fa8cfdc55b7 (diff)
[media] exynos4-is: Add support for asynchronous subdevices registration
Add support for registering external sensor subdevs using v4l2-async API. The async API is used only for sensor subdevs and only for booting from DT. Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com> Acked-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.c238
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.h13
2 files changed, 147 insertions, 104 deletions
diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
index f047a9f1043c..c670d67001f7 100644
--- a/drivers/media/platform/exynos4-is/media-dev.c
+++ b/drivers/media/platform/exynos4-is/media-dev.c
@@ -26,6 +26,7 @@
26#include <linux/pm_runtime.h> 26#include <linux/pm_runtime.h>
27#include <linux/types.h> 27#include <linux/types.h>
28#include <linux/slab.h> 28#include <linux/slab.h>
29#include <media/v4l2-async.h>
29#include <media/v4l2-ctrls.h> 30#include <media/v4l2-ctrls.h>
30#include <media/v4l2-of.h> 31#include <media/v4l2-of.h>
31#include <media/media-device.h> 32#include <media/media-device.h>
@@ -220,6 +221,7 @@ static int __fimc_pipeline_open(struct exynos_media_pipeline *ep,
220 if (ret < 0) 221 if (ret < 0)
221 return ret; 222 return ret;
222 } 223 }
224
223 ret = fimc_md_set_camclk(sd, true); 225 ret = fimc_md_set_camclk(sd, true);
224 if (ret < 0) 226 if (ret < 0)
225 goto err_wbclk; 227 goto err_wbclk;
@@ -380,77 +382,18 @@ static void fimc_md_unregister_sensor(struct v4l2_subdev *sd)
380 struct i2c_client *client = v4l2_get_subdevdata(sd); 382 struct i2c_client *client = v4l2_get_subdevdata(sd);
381 struct i2c_adapter *adapter; 383 struct i2c_adapter *adapter;
382 384
383 if (!client) 385 if (!client || client->dev.of_node)
384 return; 386 return;
385 387
386 v4l2_device_unregister_subdev(sd); 388 v4l2_device_unregister_subdev(sd);
387 389
388 if (!client->dev.of_node) { 390 adapter = client->adapter;
389 adapter = client->adapter; 391 i2c_unregister_device(client);
390 i2c_unregister_device(client); 392 if (adapter)
391 if (adapter) 393 i2c_put_adapter(adapter);
392 i2c_put_adapter(adapter);
393 }
394} 394}
395 395
396#ifdef CONFIG_OF 396#ifdef CONFIG_OF
397/* Register I2C client subdev associated with @node. */
398static int fimc_md_of_add_sensor(struct fimc_md *fmd,
399 struct device_node *node, int index)
400{
401 struct fimc_sensor_info *si;
402 struct i2c_client *client;
403 struct v4l2_subdev *sd;
404 int ret;
405
406 if (WARN_ON(index >= ARRAY_SIZE(fmd->sensor)))
407 return -EINVAL;
408 si = &fmd->sensor[index];
409
410 client = of_find_i2c_device_by_node(node);
411 if (!client)
412 return -EPROBE_DEFER;
413
414 device_lock(&client->dev);
415
416 if (!client->dev.driver ||
417 !try_module_get(client->dev.driver->owner)) {
418 ret = -EPROBE_DEFER;
419 v4l2_info(&fmd->v4l2_dev, "No driver found for %s\n",
420 node->full_name);
421 goto dev_put;
422 }
423
424 /* Enable sensor's master clock */
425 ret = __fimc_md_set_camclk(fmd, &si->pdata, true);
426 if (ret < 0)
427 goto mod_put;
428 sd = i2c_get_clientdata(client);
429
430 ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
431 __fimc_md_set_camclk(fmd, &si->pdata, false);
432 if (ret < 0)
433 goto mod_put;
434
435 v4l2_set_subdev_hostdata(sd, &si->pdata);
436 if (si->pdata.fimc_bus_type == FIMC_BUS_TYPE_ISP_WRITEBACK)
437 sd->grp_id = GRP_ID_FIMC_IS_SENSOR;
438 else
439 sd->grp_id = GRP_ID_SENSOR;
440
441 si->subdev = sd;
442 v4l2_info(&fmd->v4l2_dev, "Registered sensor subdevice: %s (%d)\n",
443 sd->name, fmd->num_sensors);
444 fmd->num_sensors++;
445
446mod_put:
447 module_put(client->dev.driver->owner);
448dev_put:
449 device_unlock(&client->dev);
450 put_device(&client->dev);
451 return ret;
452}
453
454/* Parse port node and register as a sub-device any sensor specified there. */ 397/* Parse port node and register as a sub-device any sensor specified there. */
455static int fimc_md_parse_port_node(struct fimc_md *fmd, 398static int fimc_md_parse_port_node(struct fimc_md *fmd,
456 struct device_node *port, 399 struct device_node *port,
@@ -459,7 +402,6 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
459 struct device_node *rem, *ep, *np; 402 struct device_node *rem, *ep, *np;
460 struct fimc_source_info *pd; 403 struct fimc_source_info *pd;
461 struct v4l2_of_endpoint endpoint; 404 struct v4l2_of_endpoint endpoint;
462 int ret;
463 u32 val; 405 u32 val;
464 406
465 pd = &fmd->sensor[index].pdata; 407 pd = &fmd->sensor[index].pdata;
@@ -487,6 +429,8 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
487 429
488 if (!of_property_read_u32(rem, "clock-frequency", &val)) 430 if (!of_property_read_u32(rem, "clock-frequency", &val))
489 pd->clk_frequency = val; 431 pd->clk_frequency = val;
432 else
433 pd->clk_frequency = DEFAULT_SENSOR_CLK_FREQ;
490 434
491 if (pd->clk_frequency == 0) { 435 if (pd->clk_frequency == 0) {
492 v4l2_err(&fmd->v4l2_dev, "Wrong clock frequency at node %s\n", 436 v4l2_err(&fmd->v4l2_dev, "Wrong clock frequency at node %s\n",
@@ -526,10 +470,17 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
526 else 470 else
527 pd->fimc_bus_type = pd->sensor_bus_type; 471 pd->fimc_bus_type = pd->sensor_bus_type;
528 472
529 ret = fimc_md_of_add_sensor(fmd, rem, index); 473 if (WARN_ON(index >= ARRAY_SIZE(fmd->sensor)))
530 of_node_put(rem); 474 return -EINVAL;
531 475
532 return ret; 476 fmd->sensor[index].asd.match_type = V4L2_ASYNC_MATCH_OF;
477 fmd->sensor[index].asd.match.of.node = rem;
478 fmd->async_subdevs[index] = &fmd->sensor[index].asd;
479
480 fmd->num_sensors++;
481
482 of_node_put(rem);
483 return 0;
533} 484}
534 485
535/* Register all SoC external sub-devices */ 486/* Register all SoC external sub-devices */
@@ -885,11 +836,13 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd)
885 v4l2_device_unregister_subdev(fmd->csis[i].sd); 836 v4l2_device_unregister_subdev(fmd->csis[i].sd);
886 fmd->csis[i].sd = NULL; 837 fmd->csis[i].sd = NULL;
887 } 838 }
888 for (i = 0; i < fmd->num_sensors; i++) { 839 if (fmd->pdev->dev.of_node == NULL) {
889 if (fmd->sensor[i].subdev == NULL) 840 for (i = 0; i < fmd->num_sensors; i++) {
890 continue; 841 if (fmd->sensor[i].subdev == NULL)
891 fimc_md_unregister_sensor(fmd->sensor[i].subdev); 842 continue;
892 fmd->sensor[i].subdev = NULL; 843 fimc_md_unregister_sensor(fmd->sensor[i].subdev);
844 fmd->sensor[i].subdev = NULL;
845 }
893 } 846 }
894 847
895 if (fmd->fimc_is) 848 if (fmd->fimc_is)
@@ -1224,6 +1177,14 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd,
1224 struct fimc_camclk_info *camclk; 1177 struct fimc_camclk_info *camclk;
1225 int ret = 0; 1178 int ret = 0;
1226 1179
1180 /*
1181 * When device tree is used the sensor drivers are supposed to
1182 * control the clock themselves. This whole function will be
1183 * removed once S5PV210 platform is converted to the device tree.
1184 */
1185 if (fmd->pdev->dev.of_node)
1186 return 0;
1187
1227 if (WARN_ON(si->clk_id >= FIMC_MAX_CAMCLKS) || !fmd || !fmd->pmf) 1188 if (WARN_ON(si->clk_id >= FIMC_MAX_CAMCLKS) || !fmd || !fmd->pmf)
1228 return -EINVAL; 1189 return -EINVAL;
1229 1190
@@ -1544,6 +1505,56 @@ err:
1544#define fimc_md_unregister_clk_provider(fmd) (0) 1505#define fimc_md_unregister_clk_provider(fmd) (0)
1545#endif 1506#endif
1546 1507
1508static int subdev_notifier_bound(struct v4l2_async_notifier *notifier,
1509 struct v4l2_subdev *subdev,
1510 struct v4l2_async_subdev *asd)
1511{
1512 struct fimc_md *fmd = notifier_to_fimc_md(notifier);
1513 struct fimc_sensor_info *si = NULL;
1514 int i;
1515
1516 /* Find platform data for this sensor subdev */
1517 for (i = 0; i < ARRAY_SIZE(fmd->sensor); i++)
1518 if (fmd->sensor[i].asd.match.of.node == subdev->dev->of_node)
1519 si = &fmd->sensor[i];
1520
1521 if (si == NULL)
1522 return -EINVAL;
1523
1524 v4l2_set_subdev_hostdata(subdev, &si->pdata);
1525
1526 if (si->pdata.fimc_bus_type == FIMC_BUS_TYPE_ISP_WRITEBACK)
1527 subdev->grp_id = GRP_ID_FIMC_IS_SENSOR;
1528 else
1529 subdev->grp_id = GRP_ID_SENSOR;
1530
1531 si->subdev = subdev;
1532
1533 v4l2_info(&fmd->v4l2_dev, "Registered sensor subdevice: %s (%d)\n",
1534 subdev->name, fmd->num_sensors);
1535
1536 fmd->num_sensors++;
1537
1538 return 0;
1539}
1540
1541static int subdev_notifier_complete(struct v4l2_async_notifier *notifier)
1542{
1543 struct fimc_md *fmd = notifier_to_fimc_md(notifier);
1544 int ret;
1545
1546 mutex_lock(&fmd->media_dev.graph_mutex);
1547
1548 ret = fimc_md_create_links(fmd);
1549 if (ret < 0)
1550 goto unlock;
1551
1552 ret = v4l2_device_register_subdev_nodes(&fmd->v4l2_dev);
1553unlock:
1554 mutex_unlock(&fmd->media_dev.graph_mutex);
1555 return ret;
1556}
1557
1547static int fimc_md_probe(struct platform_device *pdev) 1558static int fimc_md_probe(struct platform_device *pdev)
1548{ 1559{
1549 struct device *dev = &pdev->dev; 1560 struct device *dev = &pdev->dev;
@@ -1571,12 +1582,6 @@ static int fimc_md_probe(struct platform_device *pdev)
1571 1582
1572 fmd->use_isp = fimc_md_is_isp_available(dev->of_node); 1583 fmd->use_isp = fimc_md_is_isp_available(dev->of_node);
1573 1584
1574 ret = fimc_md_register_clk_provider(fmd);
1575 if (ret < 0) {
1576 v4l2_err(v4l2_dev, "clock provider registration failed\n");
1577 return ret;
1578 }
1579
1580 ret = v4l2_device_register(dev, &fmd->v4l2_dev); 1585 ret = v4l2_device_register(dev, &fmd->v4l2_dev);
1581 if (ret < 0) { 1586 if (ret < 0) {
1582 v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret); 1587 v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret);
@@ -1586,64 +1591,88 @@ static int fimc_md_probe(struct platform_device *pdev)
1586 ret = media_device_register(&fmd->media_dev); 1591 ret = media_device_register(&fmd->media_dev);
1587 if (ret < 0) { 1592 if (ret < 0) {
1588 v4l2_err(v4l2_dev, "Failed to register media device: %d\n", ret); 1593 v4l2_err(v4l2_dev, "Failed to register media device: %d\n", ret);
1589 goto err_md; 1594 goto err_v4l2_dev;
1590 } 1595 }
1591 1596
1592 ret = fimc_md_get_clocks(fmd); 1597 ret = fimc_md_get_clocks(fmd);
1593 if (ret) 1598 if (ret)
1594 goto err_clk; 1599 goto err_md;
1595 1600
1596 fmd->user_subdev_api = (dev->of_node != NULL); 1601 fmd->user_subdev_api = (dev->of_node != NULL);
1597 1602
1598 /* Protect the media graph while we're registering entities */
1599 mutex_lock(&fmd->media_dev.graph_mutex);
1600
1601 ret = fimc_md_get_pinctrl(fmd); 1603 ret = fimc_md_get_pinctrl(fmd);
1602 if (ret < 0) { 1604 if (ret < 0) {
1603 if (ret != EPROBE_DEFER) 1605 if (ret != EPROBE_DEFER)
1604 dev_err(dev, "Failed to get pinctrl: %d\n", ret); 1606 dev_err(dev, "Failed to get pinctrl: %d\n", ret);
1605 goto err_unlock; 1607 goto err_clk;
1606 } 1608 }
1607 1609
1610 platform_set_drvdata(pdev, fmd);
1611
1612 /* Protect the media graph while we're registering entities */
1613 mutex_lock(&fmd->media_dev.graph_mutex);
1614
1608 if (dev->of_node) 1615 if (dev->of_node)
1609 ret = fimc_md_register_of_platform_entities(fmd, dev->of_node); 1616 ret = fimc_md_register_of_platform_entities(fmd, dev->of_node);
1610 else 1617 else
1611 ret = bus_for_each_dev(&platform_bus_type, NULL, fmd, 1618 ret = bus_for_each_dev(&platform_bus_type, NULL, fmd,
1612 fimc_md_pdev_match); 1619 fimc_md_pdev_match);
1613 if (ret) 1620 if (ret) {
1614 goto err_unlock; 1621 mutex_unlock(&fmd->media_dev.graph_mutex);
1622 goto err_clk;
1623 }
1615 1624
1616 if (dev->platform_data || dev->of_node) { 1625 if (dev->platform_data || dev->of_node) {
1617 ret = fimc_md_register_sensor_entities(fmd); 1626 ret = fimc_md_register_sensor_entities(fmd);
1618 if (ret) 1627 if (ret) {
1619 goto err_unlock; 1628 mutex_unlock(&fmd->media_dev.graph_mutex);
1629 goto err_m_ent;
1630 }
1620 } 1631 }
1621 1632
1622 ret = fimc_md_create_links(fmd); 1633 mutex_unlock(&fmd->media_dev.graph_mutex);
1623 if (ret)
1624 goto err_unlock;
1625
1626 ret = v4l2_device_register_subdev_nodes(&fmd->v4l2_dev);
1627 if (ret)
1628 goto err_unlock;
1629 1634
1630 ret = device_create_file(&pdev->dev, &dev_attr_subdev_conf_mode); 1635 ret = device_create_file(&pdev->dev, &dev_attr_subdev_conf_mode);
1631 if (ret) 1636 if (ret)
1632 goto err_unlock; 1637 goto err_m_ent;
1638 /*
1639 * FIMC platform devices need to be registered before the sclk_cam
1640 * clocks provider, as one of these devices needs to be activated
1641 * to enable the clock.
1642 */
1643 ret = fimc_md_register_clk_provider(fmd);
1644 if (ret < 0) {
1645 v4l2_err(v4l2_dev, "clock provider registration failed\n");
1646 goto err_attr;
1647 }
1648
1649 if (fmd->num_sensors > 0) {
1650 fmd->subdev_notifier.subdevs = fmd->async_subdevs;
1651 fmd->subdev_notifier.num_subdevs = fmd->num_sensors;
1652 fmd->subdev_notifier.bound = subdev_notifier_bound;
1653 fmd->subdev_notifier.complete = subdev_notifier_complete;
1654 fmd->num_sensors = 0;
1655
1656 ret = v4l2_async_notifier_register(&fmd->v4l2_dev,
1657 &fmd->subdev_notifier);
1658 if (ret)
1659 goto err_clk_p;
1660 }
1633 1661
1634 platform_set_drvdata(pdev, fmd);
1635 mutex_unlock(&fmd->media_dev.graph_mutex);
1636 return 0; 1662 return 0;
1637 1663
1638err_unlock: 1664err_clk_p:
1639 mutex_unlock(&fmd->media_dev.graph_mutex); 1665 fimc_md_unregister_clk_provider(fmd);
1666err_attr:
1667 device_remove_file(&pdev->dev, &dev_attr_subdev_conf_mode);
1640err_clk: 1668err_clk:
1641 fimc_md_put_clocks(fmd); 1669 fimc_md_put_clocks(fmd);
1670err_m_ent:
1642 fimc_md_unregister_entities(fmd); 1671 fimc_md_unregister_entities(fmd);
1643 media_device_unregister(&fmd->media_dev);
1644err_md: 1672err_md:
1673 media_device_unregister(&fmd->media_dev);
1674err_v4l2_dev:
1645 v4l2_device_unregister(&fmd->v4l2_dev); 1675 v4l2_device_unregister(&fmd->v4l2_dev);
1646 fimc_md_unregister_clk_provider(fmd);
1647 return ret; 1676 return ret;
1648} 1677}
1649 1678
@@ -1655,12 +1684,15 @@ static int fimc_md_remove(struct platform_device *pdev)
1655 return 0; 1684 return 0;
1656 1685
1657 fimc_md_unregister_clk_provider(fmd); 1686 fimc_md_unregister_clk_provider(fmd);
1687 v4l2_async_notifier_unregister(&fmd->subdev_notifier);
1688
1658 v4l2_device_unregister(&fmd->v4l2_dev); 1689 v4l2_device_unregister(&fmd->v4l2_dev);
1659 device_remove_file(&pdev->dev, &dev_attr_subdev_conf_mode); 1690 device_remove_file(&pdev->dev, &dev_attr_subdev_conf_mode);
1660 fimc_md_unregister_entities(fmd); 1691 fimc_md_unregister_entities(fmd);
1661 fimc_md_pipelines_free(fmd); 1692 fimc_md_pipelines_free(fmd);
1662 media_device_unregister(&fmd->media_dev); 1693 media_device_unregister(&fmd->media_dev);
1663 fimc_md_put_clocks(fmd); 1694 fimc_md_put_clocks(fmd);
1695
1664 return 0; 1696 return 0;
1665} 1697}
1666 1698
diff --git a/drivers/media/platform/exynos4-is/media-dev.h b/drivers/media/platform/exynos4-is/media-dev.h
index a88cee59fd2f..ee1e2519f728 100644
--- a/drivers/media/platform/exynos4-is/media-dev.h
+++ b/drivers/media/platform/exynos4-is/media-dev.h
@@ -32,8 +32,9 @@
32 32
33#define PINCTRL_STATE_IDLE "idle" 33#define PINCTRL_STATE_IDLE "idle"
34 34
35#define FIMC_MAX_SENSORS 8 35#define FIMC_MAX_SENSORS 4
36#define FIMC_MAX_CAMCLKS 2 36#define FIMC_MAX_CAMCLKS 2
37#define DEFAULT_SENSOR_CLK_FREQ 24000000U
37 38
38/* LCD/ISP Writeback clocks (PIXELASYNCMx) */ 39/* LCD/ISP Writeback clocks (PIXELASYNCMx) */
39enum { 40enum {
@@ -79,6 +80,7 @@ struct fimc_camclk_info {
79/** 80/**
80 * struct fimc_sensor_info - image data source subdev information 81 * struct fimc_sensor_info - image data source subdev information
81 * @pdata: sensor's atrributes passed as media device's platform data 82 * @pdata: sensor's atrributes passed as media device's platform data
83 * @asd: asynchronous subdev registration data structure
82 * @subdev: image sensor v4l2 subdev 84 * @subdev: image sensor v4l2 subdev
83 * @host: fimc device the sensor is currently linked to 85 * @host: fimc device the sensor is currently linked to
84 * 86 *
@@ -86,6 +88,7 @@ struct fimc_camclk_info {
86 */ 88 */
87struct fimc_sensor_info { 89struct fimc_sensor_info {
88 struct fimc_source_info pdata; 90 struct fimc_source_info pdata;
91 struct v4l2_async_subdev asd;
89 struct v4l2_subdev *subdev; 92 struct v4l2_subdev *subdev;
90 struct fimc_dev *host; 93 struct fimc_dev *host;
91}; 94};
@@ -145,6 +148,9 @@ struct fimc_md {
145 int num_clocks; 148 int num_clocks;
146 } clk_provider; 149 } clk_provider;
147 150
151 struct v4l2_async_notifier subdev_notifier;
152 struct v4l2_async_subdev *async_subdevs[FIMC_MAX_SENSORS];
153
148 bool user_subdev_api; 154 bool user_subdev_api;
149 spinlock_t slock; 155 spinlock_t slock;
150 struct list_head pipelines; 156 struct list_head pipelines;
@@ -162,6 +168,11 @@ static inline struct fimc_md *entity_to_fimc_mdev(struct media_entity *me)
162 container_of(me->parent, struct fimc_md, media_dev); 168 container_of(me->parent, struct fimc_md, media_dev);
163} 169}
164 170
171static inline struct fimc_md *notifier_to_fimc_md(struct v4l2_async_notifier *n)
172{
173 return container_of(n, struct fimc_md, subdev_notifier);
174}
175
165static inline void fimc_md_graph_lock(struct exynos_video_entity *ve) 176static inline void fimc_md_graph_lock(struct exynos_video_entity *ve)
166{ 177{
167 mutex_lock(&ve->vdev.entity.parent->graph_mutex); 178 mutex_lock(&ve->vdev.entity.parent->graph_mutex);