aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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