diff options
-rw-r--r-- | drivers/media/platform/soc_camera/soc_camera.c | 129 |
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 | |||
1591 | struct 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 | |||
1597 | static 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; | ||
1664 | eclkreg: | ||
1665 | icd->clk = NULL; | ||
1666 | platform_device_del(sasc->pdev); | ||
1667 | eaddpdev: | ||
1668 | platform_device_put(sasc->pdev); | ||
1669 | eallocpdev: | ||
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 | |||
1676 | static 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 | ||
1710 | static 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 */ |
1589 | static int soc_camera_probe(struct soc_camera_host *ici, | 1714 | static 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 |