aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
authorBen Dooks <ben.dooks@codethink.co.uk>2014-07-05 18:26:23 -0400
committerMauro Carvalho Chehab <m.chehab@samsung.com>2014-07-30 18:30:05 -0400
commit1ddc6a6caa94e1e19e8c657a9a6cbbecd39e63bd (patch)
tree7deb5c8baa6089e84012c70636efcf55f173781a /drivers/media
parentff493eef396b2480c270c1174264418739021e57 (diff)
[media] soc_camera: add support for dt binding soc_camera drivers
Add initial support for OF based soc-camera devices that may be used by any of the soc-camera drivers. The driver itself will need converting to use OF. These changes allow the soc-camera driver to do the connecting of any async capable v4l2 device to the soc-camera driver. This has currently been tested on the Renesas Lager board. It currently only supports one input device per driver as this seems to be the standard connection for these devices. Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk> [g.liakhovetski@gmx.de add check for multiple subdevices] Tested-by: Robert Jarzmik <robert.jarzmik@free.fr> Tested-by: Josh Wu <josh.wu@atmel.com> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/platform/soc_camera/soc_camera.c129
1 files changed, 128 insertions, 1 deletions
diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c
index dc626b9a177d..f4308fed5431 100644
--- a/drivers/media/platform/soc_camera/soc_camera.c
+++ b/drivers/media/platform/soc_camera/soc_camera.c
@@ -36,6 +36,7 @@
36#include <media/v4l2-common.h> 36#include <media/v4l2-common.h>
37#include <media/v4l2-ioctl.h> 37#include <media/v4l2-ioctl.h>
38#include <media/v4l2-dev.h> 38#include <media/v4l2-dev.h>
39#include <media/v4l2-of.h>
39#include <media/videobuf-core.h> 40#include <media/videobuf-core.h>
40#include <media/videobuf2-core.h> 41#include <media/videobuf2-core.h>
41 42
@@ -1585,6 +1586,130 @@ static void scan_async_host(struct soc_camera_host *ici)
1585#define scan_async_host(ici) do {} while (0) 1586#define scan_async_host(ici) do {} while (0)
1586#endif 1587#endif
1587 1588
1589#ifdef CONFIG_OF
1590
1591struct soc_of_info {
1592 struct soc_camera_async_subdev sasd;
1593 struct soc_camera_async_client sasc;
1594 struct v4l2_async_subdev *subdev;
1595};
1596
1597static int soc_of_bind(struct soc_camera_host *ici,
1598 struct device_node *ep,
1599 struct device_node *remote)
1600{
1601 struct soc_camera_device *icd;
1602 struct soc_camera_desc sdesc = {.host_desc.bus_id = ici->nr,};
1603 struct soc_camera_async_client *sasc;
1604 struct soc_of_info *info;
1605 struct i2c_client *client;
1606 char clk_name[V4L2_SUBDEV_NAME_SIZE];
1607 int ret;
1608
1609 /* allocate a new subdev and add match info to it */
1610 info = devm_kzalloc(ici->v4l2_dev.dev, sizeof(struct soc_of_info),
1611 GFP_KERNEL);
1612 if (!info)
1613 return -ENOMEM;
1614
1615 info->sasd.asd.match.of.node = remote;
1616 info->sasd.asd.match_type = V4L2_ASYNC_MATCH_OF;
1617 info->subdev = &info->sasd.asd;
1618
1619 /* Or shall this be managed by the soc-camera device? */
1620 sasc = &info->sasc;
1621
1622 /* HACK: just need a != NULL */
1623 sdesc.host_desc.board_info = ERR_PTR(-ENODATA);
1624
1625 ret = soc_camera_dyn_pdev(&sdesc, sasc);
1626 if (ret < 0)
1627 goto eallocpdev;
1628
1629 sasc->sensor = &info->sasd.asd;
1630
1631 icd = soc_camera_add_pdev(sasc);
1632 if (!icd) {
1633 ret = -ENOMEM;
1634 goto eaddpdev;
1635 }
1636
1637 sasc->notifier.subdevs = &info->subdev;
1638 sasc->notifier.num_subdevs = 1;
1639 sasc->notifier.bound = soc_camera_async_bound;
1640 sasc->notifier.unbind = soc_camera_async_unbind;
1641 sasc->notifier.complete = soc_camera_async_complete;
1642
1643 icd->sasc = sasc;
1644 icd->parent = ici->v4l2_dev.dev;
1645
1646 client = of_find_i2c_device_by_node(remote);
1647
1648 if (client)
1649 snprintf(clk_name, sizeof(clk_name), "%d-%04x",
1650 client->adapter->nr, client->addr);
1651 else
1652 snprintf(clk_name, sizeof(clk_name), "of-%s",
1653 of_node_full_name(remote));
1654
1655 icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, "mclk", icd);
1656 if (IS_ERR(icd->clk)) {
1657 ret = PTR_ERR(icd->clk);
1658 goto eclkreg;
1659 }
1660
1661 ret = v4l2_async_notifier_register(&ici->v4l2_dev, &sasc->notifier);
1662 if (!ret)
1663 return 0;
1664eclkreg:
1665 icd->clk = NULL;
1666 platform_device_del(sasc->pdev);
1667eaddpdev:
1668 platform_device_put(sasc->pdev);
1669eallocpdev:
1670 devm_kfree(ici->v4l2_dev.dev, sasc);
1671 dev_err(ici->v4l2_dev.dev, "group probe failed: %d\n", ret);
1672
1673 return ret;
1674}
1675
1676static void scan_of_host(struct soc_camera_host *ici)
1677{
1678 struct device *dev = ici->v4l2_dev.dev;
1679 struct device_node *np = dev->of_node;
1680 struct device_node *epn = NULL, *ren;
1681 unsigned int i;
1682
1683 for (i = 0; ; i++) {
1684 epn = of_graph_get_next_endpoint(np, epn);
1685 if (!epn)
1686 break;
1687
1688 ren = of_graph_get_remote_port(epn);
1689 if (!ren) {
1690 dev_notice(dev, "no remote for %s\n",
1691 of_node_full_name(epn));
1692 continue;
1693 }
1694
1695 /* so we now have a remote node to connect */
1696 if (!i)
1697 soc_of_bind(ici, epn, ren->parent);
1698
1699 of_node_put(epn);
1700 of_node_put(ren);
1701
1702 if (i) {
1703 dev_err(dev, "multiple subdevices aren't supported yet!\n");
1704 break;
1705 }
1706 }
1707}
1708
1709#else
1710static inline void scan_of_host(struct soc_camera_host *ici) { }
1711#endif
1712
1588/* Called during host-driver probe */ 1713/* Called during host-driver probe */
1589static int soc_camera_probe(struct soc_camera_host *ici, 1714static int soc_camera_probe(struct soc_camera_host *ici,
1590 struct soc_camera_device *icd) 1715 struct soc_camera_device *icd)
@@ -1836,7 +1961,9 @@ int soc_camera_host_register(struct soc_camera_host *ici)
1836 mutex_init(&ici->host_lock); 1961 mutex_init(&ici->host_lock);
1837 mutex_init(&ici->clk_lock); 1962 mutex_init(&ici->clk_lock);
1838 1963
1839 if (ici->asd_sizes) 1964 if (ici->v4l2_dev.dev->of_node)
1965 scan_of_host(ici);
1966 else if (ici->asd_sizes)
1840 /* 1967 /*
1841 * No OF, host with a list of subdevices. Don't try to mix 1968 * No OF, host with a list of subdevices. Don't try to mix
1842 * modes by initialising some groups statically and some 1969 * modes by initialising some groups statically and some