Skip to content

Commit d3f5e0c

Browse files
Sylwester Nawrockimchehab
authored andcommitted
[media] exynos4-is: Add clock provider for the SCLK_CAM clock outputs
This patch adds clock provider so the the SCLK_CAM0/1 output clocks can be accessed by image sensor devices through the clk API. Signed-off-by: Sylwester Nawrocki <[email protected]> Acked-by: Kyungmin Park <[email protected]> Signed-off-by: Mauro Carvalho Chehab <[email protected]>
1 parent d265d9a commit d3f5e0c

File tree

2 files changed

+136
-1
lines changed

2 files changed

+136
-1
lines changed

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

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
*/
1212

1313
#include <linux/bug.h>
14+
#include <linux/clk.h>
15+
#include <linux/clk-provider.h>
1416
#include <linux/device.h>
1517
#include <linux/errno.h>
1618
#include <linux/i2c.h>
@@ -1276,6 +1278,14 @@ int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on)
12761278
struct fimc_source_info *si = v4l2_get_subdev_hostdata(sd);
12771279
struct fimc_md *fmd = entity_to_fimc_mdev(&sd->entity);
12781280

1281+
/*
1282+
* If there is a clock provider registered the sensors will
1283+
* handle their clock themselves, no need to control it on
1284+
* the host interface side.
1285+
*/
1286+
if (fmd->clk_provider.num_clocks > 0)
1287+
return 0;
1288+
12791289
return __fimc_md_set_camclk(fmd, si, on);
12801290
}
12811291

@@ -1437,6 +1447,103 @@ static int fimc_md_get_pinctrl(struct fimc_md *fmd)
14371447
return 0;
14381448
}
14391449

1450+
#ifdef CONFIG_OF
1451+
static int cam_clk_prepare(struct clk_hw *hw)
1452+
{
1453+
struct cam_clk *camclk = to_cam_clk(hw);
1454+
int ret;
1455+
1456+
if (camclk->fmd->pmf == NULL)
1457+
return -ENODEV;
1458+
1459+
ret = pm_runtime_get_sync(camclk->fmd->pmf);
1460+
return ret < 0 ? ret : 0;
1461+
}
1462+
1463+
static void cam_clk_unprepare(struct clk_hw *hw)
1464+
{
1465+
struct cam_clk *camclk = to_cam_clk(hw);
1466+
1467+
if (camclk->fmd->pmf == NULL)
1468+
return;
1469+
1470+
pm_runtime_put_sync(camclk->fmd->pmf);
1471+
}
1472+
1473+
static const struct clk_ops cam_clk_ops = {
1474+
.prepare = cam_clk_prepare,
1475+
.unprepare = cam_clk_unprepare,
1476+
};
1477+
1478+
static void fimc_md_unregister_clk_provider(struct fimc_md *fmd)
1479+
{
1480+
struct cam_clk_provider *cp = &fmd->clk_provider;
1481+
unsigned int i;
1482+
1483+
if (cp->of_node)
1484+
of_clk_del_provider(cp->of_node);
1485+
1486+
for (i = 0; i < cp->num_clocks; i++)
1487+
clk_unregister(cp->clks[i]);
1488+
}
1489+
1490+
static int fimc_md_register_clk_provider(struct fimc_md *fmd)
1491+
{
1492+
struct cam_clk_provider *cp = &fmd->clk_provider;
1493+
struct device *dev = &fmd->pdev->dev;
1494+
int i, ret;
1495+
1496+
for (i = 0; i < FIMC_MAX_CAMCLKS; i++) {
1497+
struct cam_clk *camclk = &cp->camclk[i];
1498+
struct clk_init_data init;
1499+
const char *p_name;
1500+
1501+
ret = of_property_read_string_index(dev->of_node,
1502+
"clock-output-names", i, &init.name);
1503+
if (ret < 0)
1504+
break;
1505+
1506+
p_name = __clk_get_name(fmd->camclk[i].clock);
1507+
1508+
/* It's safe since clk_register() will duplicate the string. */
1509+
init.parent_names = &p_name;
1510+
init.num_parents = 1;
1511+
init.ops = &cam_clk_ops;
1512+
init.flags = CLK_SET_RATE_PARENT;
1513+
camclk->hw.init = &init;
1514+
camclk->fmd = fmd;
1515+
1516+
cp->clks[i] = clk_register(NULL, &camclk->hw);
1517+
if (IS_ERR(cp->clks[i])) {
1518+
dev_err(dev, "failed to register clock: %s (%ld)\n",
1519+
init.name, PTR_ERR(cp->clks[i]));
1520+
ret = PTR_ERR(cp->clks[i]);
1521+
goto err;
1522+
}
1523+
cp->num_clocks++;
1524+
}
1525+
1526+
if (cp->num_clocks == 0) {
1527+
dev_warn(dev, "clk provider not registered\n");
1528+
return 0;
1529+
}
1530+
1531+
cp->clk_data.clks = cp->clks;
1532+
cp->clk_data.clk_num = cp->num_clocks;
1533+
cp->of_node = dev->of_node;
1534+
ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
1535+
&cp->clk_data);
1536+
if (ret == 0)
1537+
return 0;
1538+
err:
1539+
fimc_md_unregister_clk_provider(fmd);
1540+
return ret;
1541+
}
1542+
#else
1543+
#define fimc_md_register_clk_provider(fmd) (0)
1544+
#define fimc_md_unregister_clk_provider(fmd) (0)
1545+
#endif
1546+
14401547
static int fimc_md_probe(struct platform_device *pdev)
14411548
{
14421549
struct device *dev = &pdev->dev;
@@ -1464,16 +1571,24 @@ static int fimc_md_probe(struct platform_device *pdev)
14641571

14651572
fmd->use_isp = fimc_md_is_isp_available(dev->of_node);
14661573

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+
14671580
ret = v4l2_device_register(dev, &fmd->v4l2_dev);
14681581
if (ret < 0) {
14691582
v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret);
14701583
return ret;
14711584
}
1585+
14721586
ret = media_device_register(&fmd->media_dev);
14731587
if (ret < 0) {
14741588
v4l2_err(v4l2_dev, "Failed to register media device: %d\n", ret);
14751589
goto err_md;
14761590
}
1591+
14771592
ret = fimc_md_get_clocks(fmd);
14781593
if (ret)
14791594
goto err_clk;
@@ -1507,6 +1622,7 @@ static int fimc_md_probe(struct platform_device *pdev)
15071622
ret = fimc_md_create_links(fmd);
15081623
if (ret)
15091624
goto err_unlock;
1625+
15101626
ret = v4l2_device_register_subdev_nodes(&fmd->v4l2_dev);
15111627
if (ret)
15121628
goto err_unlock;
@@ -1527,6 +1643,7 @@ static int fimc_md_probe(struct platform_device *pdev)
15271643
media_device_unregister(&fmd->media_dev);
15281644
err_md:
15291645
v4l2_device_unregister(&fmd->v4l2_dev);
1646+
fimc_md_unregister_clk_provider(fmd);
15301647
return ret;
15311648
}
15321649

@@ -1537,6 +1654,7 @@ static int fimc_md_remove(struct platform_device *pdev)
15371654
if (!fmd)
15381655
return 0;
15391656

1657+
fimc_md_unregister_clk_provider(fmd);
15401658
v4l2_device_unregister(&fmd->v4l2_dev);
15411659
device_remove_file(&pdev->dev, &dev_attr_subdev_conf_mode);
15421660
fimc_md_unregister_entities(fmd);

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

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define FIMC_MDEVICE_H_
1111

1212
#include <linux/clk.h>
13+
#include <linux/clk-provider.h>
1314
#include <linux/platform_device.h>
1415
#include <linux/mutex.h>
1516
#include <linux/of.h>
@@ -89,6 +90,12 @@ struct fimc_sensor_info {
8990
struct fimc_dev *host;
9091
};
9192

93+
struct cam_clk {
94+
struct clk_hw hw;
95+
struct fimc_md *fmd;
96+
};
97+
#define to_cam_clk(_hw) container_of(_hw, struct cam_clk, hw)
98+
9299
/**
93100
* struct fimc_md - fimc media device information
94101
* @csis: MIPI CSIS subdevs data
@@ -105,6 +112,7 @@ struct fimc_sensor_info {
105112
* @pinctrl: camera port pinctrl handle
106113
* @state_default: pinctrl default state handle
107114
* @state_idle: pinctrl idle state handle
115+
* @cam_clk_provider: CAMCLK clock provider structure
108116
* @user_subdev_api: true if subdevs are not configured by the host driver
109117
* @slock: spinlock protecting @sensor array
110118
*/
@@ -122,13 +130,22 @@ struct fimc_md {
122130
struct media_device media_dev;
123131
struct v4l2_device v4l2_dev;
124132
struct platform_device *pdev;
133+
125134
struct fimc_pinctrl {
126135
struct pinctrl *pinctrl;
127136
struct pinctrl_state *state_default;
128137
struct pinctrl_state *state_idle;
129138
} pinctl;
130-
bool user_subdev_api;
131139

140+
struct cam_clk_provider {
141+
struct clk *clks[FIMC_MAX_CAMCLKS];
142+
struct clk_onecell_data clk_data;
143+
struct device_node *of_node;
144+
struct cam_clk camclk[FIMC_MAX_CAMCLKS];
145+
int num_clocks;
146+
} clk_provider;
147+
148+
bool user_subdev_api;
132149
spinlock_t slock;
133150
struct list_head pipelines;
134151
};

0 commit comments

Comments
 (0)