Skip to content

Commit 1ddc6a6

Browse files
bjdooks-ctmchehab
authored andcommitted
[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 <[email protected]> [[email protected] add check for multiple subdevices] Tested-by: Robert Jarzmik <[email protected]> Tested-by: Josh Wu <[email protected]> Signed-off-by: Guennadi Liakhovetski <[email protected]> Signed-off-by: Mauro Carvalho Chehab <[email protected]>
1 parent ff493ee commit 1ddc6a6

File tree

1 file changed

+128
-1
lines changed

1 file changed

+128
-1
lines changed

Diff for: drivers/media/platform/soc_camera/soc_camera.c

+128-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <media/v4l2-common.h>
3737
#include <media/v4l2-ioctl.h>
3838
#include <media/v4l2-dev.h>
39+
#include <media/v4l2-of.h>
3940
#include <media/videobuf-core.h>
4041
#include <media/videobuf2-core.h>
4142

@@ -1585,6 +1586,130 @@ static void scan_async_host(struct soc_camera_host *ici)
15851586
#define scan_async_host(ici) do {} while (0)
15861587
#endif
15871588

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+
15881713
/* Called during host-driver probe */
15891714
static int soc_camera_probe(struct soc_camera_host *ici,
15901715
struct soc_camera_device *icd)
@@ -1836,7 +1961,9 @@ int soc_camera_host_register(struct soc_camera_host *ici)
18361961
mutex_init(&ici->host_lock);
18371962
mutex_init(&ici->clk_lock);
18381963

1839-
if (ici->asd_sizes)
1964+
if (ici->v4l2_dev.dev->of_node)
1965+
scan_of_host(ici);
1966+
else if (ici->asd_sizes)
18401967
/*
18411968
* No OF, host with a list of subdevices. Don't try to mix
18421969
* modes by initialising some groups statically and some

0 commit comments

Comments
 (0)