Skip to content

Commit fa91f10

Browse files
Sylwester Nawrockimchehab
authored andcommitted
[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 <[email protected]> Acked-by: Kyungmin Park <[email protected]> Signed-off-by: Mauro Carvalho Chehab <[email protected]>
1 parent d3f5e0c commit fa91f10

File tree

2 files changed

+147
-104
lines changed

2 files changed

+147
-104
lines changed

drivers/media/platform/exynos4-is/media-dev.c

Lines changed: 135 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <linux/pm_runtime.h>
2727
#include <linux/types.h>
2828
#include <linux/slab.h>
29+
#include <media/v4l2-async.h>
2930
#include <media/v4l2-ctrls.h>
3031
#include <media/v4l2-of.h>
3132
#include <media/media-device.h>
@@ -220,6 +221,7 @@ static int __fimc_pipeline_open(struct exynos_media_pipeline *ep,
220221
if (ret < 0)
221222
return ret;
222223
}
224+
223225
ret = fimc_md_set_camclk(sd, true);
224226
if (ret < 0)
225227
goto err_wbclk;
@@ -380,77 +382,18 @@ static void fimc_md_unregister_sensor(struct v4l2_subdev *sd)
380382
struct i2c_client *client = v4l2_get_subdevdata(sd);
381383
struct i2c_adapter *adapter;
382384

383-
if (!client)
385+
if (!client || client->dev.of_node)
384386
return;
385387

386388
v4l2_device_unregister_subdev(sd);
387389

388-
if (!client->dev.of_node) {
389-
adapter = client->adapter;
390-
i2c_unregister_device(client);
391-
if (adapter)
392-
i2c_put_adapter(adapter);
393-
}
390+
adapter = client->adapter;
391+
i2c_unregister_device(client);
392+
if (adapter)
393+
i2c_put_adapter(adapter);
394394
}
395395

396396
#ifdef CONFIG_OF
397-
/* Register I2C client subdev associated with @node. */
398-
static 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-
446-
mod_put:
447-
module_put(client->dev.driver->owner);
448-
dev_put:
449-
device_unlock(&client->dev);
450-
put_device(&client->dev);
451-
return ret;
452-
}
453-
454397
/* Parse port node and register as a sub-device any sensor specified there. */
455398
static int fimc_md_parse_port_node(struct fimc_md *fmd,
456399
struct device_node *port,
@@ -459,7 +402,6 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
459402
struct device_node *rem, *ep, *np;
460403
struct fimc_source_info *pd;
461404
struct v4l2_of_endpoint endpoint;
462-
int ret;
463405
u32 val;
464406

465407
pd = &fmd->sensor[index].pdata;
@@ -487,6 +429,8 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
487429

488430
if (!of_property_read_u32(rem, "clock-frequency", &val))
489431
pd->clk_frequency = val;
432+
else
433+
pd->clk_frequency = DEFAULT_SENSOR_CLK_FREQ;
490434

491435
if (pd->clk_frequency == 0) {
492436
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,
526470
else
527471
pd->fimc_bus_type = pd->sensor_bus_type;
528472

529-
ret = fimc_md_of_add_sensor(fmd, rem, index);
530-
of_node_put(rem);
473+
if (WARN_ON(index >= ARRAY_SIZE(fmd->sensor)))
474+
return -EINVAL;
531475

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;
533484
}
534485

535486
/* Register all SoC external sub-devices */
@@ -885,11 +836,13 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd)
885836
v4l2_device_unregister_subdev(fmd->csis[i].sd);
886837
fmd->csis[i].sd = NULL;
887838
}
888-
for (i = 0; i < fmd->num_sensors; i++) {
889-
if (fmd->sensor[i].subdev == NULL)
890-
continue;
891-
fimc_md_unregister_sensor(fmd->sensor[i].subdev);
892-
fmd->sensor[i].subdev = NULL;
839+
if (fmd->pdev->dev.of_node == NULL) {
840+
for (i = 0; i < fmd->num_sensors; i++) {
841+
if (fmd->sensor[i].subdev == NULL)
842+
continue;
843+
fimc_md_unregister_sensor(fmd->sensor[i].subdev);
844+
fmd->sensor[i].subdev = NULL;
845+
}
893846
}
894847

895848
if (fmd->fimc_is)
@@ -1224,6 +1177,14 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd,
12241177
struct fimc_camclk_info *camclk;
12251178
int ret = 0;
12261179

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+
12271188
if (WARN_ON(si->clk_id >= FIMC_MAX_CAMCLKS) || !fmd || !fmd->pmf)
12281189
return -EINVAL;
12291190

@@ -1544,6 +1505,56 @@ static int fimc_md_register_clk_provider(struct fimc_md *fmd)
15441505
#define fimc_md_unregister_clk_provider(fmd) (0)
15451506
#endif
15461507

1508+
static 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+
1541+
static 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);
1553+
unlock:
1554+
mutex_unlock(&fmd->media_dev.graph_mutex);
1555+
return ret;
1556+
}
1557+
15471558
static int fimc_md_probe(struct platform_device *pdev)
15481559
{
15491560
struct device *dev = &pdev->dev;
@@ -1571,12 +1582,6 @@ static int fimc_md_probe(struct platform_device *pdev)
15711582

15721583
fmd->use_isp = fimc_md_is_isp_available(dev->of_node);
15731584

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-
15801585
ret = v4l2_device_register(dev, &fmd->v4l2_dev);
15811586
if (ret < 0) {
15821587
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)
15861591
ret = media_device_register(&fmd->media_dev);
15871592
if (ret < 0) {
15881593
v4l2_err(v4l2_dev, "Failed to register media device: %d\n", ret);
1589-
goto err_md;
1594+
goto err_v4l2_dev;
15901595
}
15911596

15921597
ret = fimc_md_get_clocks(fmd);
15931598
if (ret)
1594-
goto err_clk;
1599+
goto err_md;
15951600

15961601
fmd->user_subdev_api = (dev->of_node != NULL);
15971602

1598-
/* Protect the media graph while we're registering entities */
1599-
mutex_lock(&fmd->media_dev.graph_mutex);
1600-
16011603
ret = fimc_md_get_pinctrl(fmd);
16021604
if (ret < 0) {
16031605
if (ret != EPROBE_DEFER)
16041606
dev_err(dev, "Failed to get pinctrl: %d\n", ret);
1605-
goto err_unlock;
1607+
goto err_clk;
16061608
}
16071609

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+
16081615
if (dev->of_node)
16091616
ret = fimc_md_register_of_platform_entities(fmd, dev->of_node);
16101617
else
16111618
ret = bus_for_each_dev(&platform_bus_type, NULL, fmd,
16121619
fimc_md_pdev_match);
1613-
if (ret)
1614-
goto err_unlock;
1620+
if (ret) {
1621+
mutex_unlock(&fmd->media_dev.graph_mutex);
1622+
goto err_clk;
1623+
}
16151624

16161625
if (dev->platform_data || dev->of_node) {
16171626
ret = fimc_md_register_sensor_entities(fmd);
1618-
if (ret)
1619-
goto err_unlock;
1627+
if (ret) {
1628+
mutex_unlock(&fmd->media_dev.graph_mutex);
1629+
goto err_m_ent;
1630+
}
16201631
}
16211632

1622-
ret = fimc_md_create_links(fmd);
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;
1633+
mutex_unlock(&fmd->media_dev.graph_mutex);
16291634

16301635
ret = device_create_file(&pdev->dev, &dev_attr_subdev_conf_mode);
16311636
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+
}
16331661

1634-
platform_set_drvdata(pdev, fmd);
1635-
mutex_unlock(&fmd->media_dev.graph_mutex);
16361662
return 0;
16371663

1638-
err_unlock:
1639-
mutex_unlock(&fmd->media_dev.graph_mutex);
1664+
err_clk_p:
1665+
fimc_md_unregister_clk_provider(fmd);
1666+
err_attr:
1667+
device_remove_file(&pdev->dev, &dev_attr_subdev_conf_mode);
16401668
err_clk:
16411669
fimc_md_put_clocks(fmd);
1670+
err_m_ent:
16421671
fimc_md_unregister_entities(fmd);
1643-
media_device_unregister(&fmd->media_dev);
16441672
err_md:
1673+
media_device_unregister(&fmd->media_dev);
1674+
err_v4l2_dev:
16451675
v4l2_device_unregister(&fmd->v4l2_dev);
1646-
fimc_md_unregister_clk_provider(fmd);
16471676
return ret;
16481677
}
16491678

@@ -1655,12 +1684,15 @@ static int fimc_md_remove(struct platform_device *pdev)
16551684
return 0;
16561685

16571686
fimc_md_unregister_clk_provider(fmd);
1687+
v4l2_async_notifier_unregister(&fmd->subdev_notifier);
1688+
16581689
v4l2_device_unregister(&fmd->v4l2_dev);
16591690
device_remove_file(&pdev->dev, &dev_attr_subdev_conf_mode);
16601691
fimc_md_unregister_entities(fmd);
16611692
fimc_md_pipelines_free(fmd);
16621693
media_device_unregister(&fmd->media_dev);
16631694
fimc_md_put_clocks(fmd);
1695+
16641696
return 0;
16651697
}
16661698

0 commit comments

Comments
 (0)