#include <asm/unaligned.h>
#include <linux/acpi.h>
+#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/module.h>
};
struct og01a1b {
+ struct clk *xvclk;
+
struct v4l2_subdev sd;
struct media_pad pad;
struct v4l2_ctrl_handler ctrl_handler;
return 0;
}
-static int og01a1b_check_hwcfg(struct device *dev)
+static int og01a1b_check_hwcfg(struct og01a1b *og01a1b)
{
+ struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd);
+ struct device *dev = &client->dev;
struct fwnode_handle *ep;
struct fwnode_handle *fwnode = dev_fwnode(dev);
struct v4l2_fwnode_endpoint bus_cfg = {
return -ENXIO;
ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk);
-
if (ret) {
- dev_err(dev, "can't get clock frequency");
- return ret;
+ if (!og01a1b->xvclk) {
+ dev_err(dev, "can't get clock frequency");
+ return ret;
+ }
+
+ mclk = clk_get_rate(og01a1b->xvclk);
}
if (mclk != OG01A1B_MCLK) {
/* Power/clock management functions */
static int og01a1b_power_on(struct device *dev)
{
- /* Device is already turned on by i2c-core with ACPI domain PM. */
+ unsigned long delay = DIV_ROUND_UP(8192UL * USEC_PER_SEC, OG01A1B_MCLK);
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct og01a1b *og01a1b = to_og01a1b(sd);
+ int ret;
+
+ ret = clk_prepare_enable(og01a1b->xvclk);
+ if (ret)
+ return ret;
+
+ if (og01a1b->xvclk)
+ usleep_range(delay, 2 * delay);
return 0;
}
static int og01a1b_power_off(struct device *dev)
{
+ unsigned long delay = DIV_ROUND_UP(512 * USEC_PER_SEC, OG01A1B_MCLK);
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct og01a1b *og01a1b = to_og01a1b(sd);
+
+ if (og01a1b->xvclk)
+ usleep_range(delay, 2 * delay);
+
+ clk_disable_unprepare(og01a1b->xvclk);
+
return 0;
}
v4l2_i2c_subdev_init(&og01a1b->sd, client, &og01a1b_subdev_ops);
- ret = og01a1b_check_hwcfg(&client->dev);
+ og01a1b->xvclk = devm_clk_get_optional(&client->dev, NULL);
+ if (IS_ERR(og01a1b->xvclk)) {
+ ret = PTR_ERR(og01a1b->xvclk);
+ dev_err(&client->dev, "failed to get xvclk clock: %d\n", ret);
+ return ret;
+ }
+
+ ret = og01a1b_check_hwcfg(og01a1b);
if (ret) {
dev_err(&client->dev, "failed to check HW configuration: %d",
ret);