summaryrefslogtreecommitdiff
path: root/drivers/media/video
diff options
context:
space:
mode:
authorPablo Ceballos <pceballos@nvidia.com>2013-07-01 17:51:48 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 13:30:07 -0700
commit6e07573549936931a3596f9affcd449d14aad2b3 (patch)
treec34cc1dec9ccb7d36e0b62e2c1eae14f047b41e0 /drivers/media/video
parentcbbcf23330ecc14073ef19687ccb539b216de34e (diff)
media: video: tegra: ar0261: move MCLK into sensor
Move MCLK control from tegra_camera into sensor driver, to allow for full controll over MCLK rate and enable timing, per sensor power-on/off sequence specification. Bug 1298672 Change-Id: Iec76d84197c82fcacfb4f21edf375d724a1e3fe1 Signed-off-by: Pablo Ceballos <pceballos@nvidia.com> Reviewed-on: http://git-master/r/244059 Reviewed-by: Amit Arora <amita@nvidia.com> Tested-by: Amit Arora <amita@nvidia.com>
Diffstat (limited to 'drivers/media/video')
-rw-r--r--drivers/media/video/tegra/ar0261.c50
1 files changed, 48 insertions, 2 deletions
diff --git a/drivers/media/video/tegra/ar0261.c b/drivers/media/video/tegra/ar0261.c
index beef9eda3026..d5f111326497 100644
--- a/drivers/media/video/tegra/ar0261.c
+++ b/drivers/media/video/tegra/ar0261.c
@@ -19,6 +19,7 @@
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/i2c.h>
+#include <linux/clk.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
@@ -39,6 +40,7 @@ struct ar0261_info {
struct ar0261_sensordata sensor_data;
struct i2c_client *i2c_client;
struct ar0261_platform_data *pdata;
+ struct clk *mclk;
atomic_t in_use;
int mode;
};
@@ -693,6 +695,26 @@ static int ar0261_get_sensor_id(struct ar0261_info *info)
return 0;
}
+static void ar0261_mclk_disable(struct ar0261_info *info)
+{
+ dev_dbg(&info->i2c_client->dev, "%s: disable MCLK\n", __func__);
+ clk_disable_unprepare(info->mclk);
+}
+
+static int ar0261_mclk_enable(struct ar0261_info *info)
+{
+ int err;
+ unsigned long mclk_init_rate = 24000000;
+
+ dev_dbg(&info->i2c_client->dev, "%s: enable MCLK with %lu Hz\n",
+ __func__, mclk_init_rate);
+
+ err = clk_set_rate(info->mclk, mclk_init_rate);
+ if (!err)
+ err = clk_prepare_enable(info->mclk);
+ return err;
+}
+
static long
ar0261_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
@@ -772,6 +794,7 @@ ar0261_ioctl(struct file *file,
static int
ar0261_open(struct inode *inode, struct file *file)
{
+ int err;
struct miscdevice *miscdev = file->private_data;
struct ar0261_info *info;
@@ -784,15 +807,25 @@ ar0261_open(struct inode *inode, struct file *file)
file->private_data = info;
+ err = ar0261_mclk_enable(info);
+ if (err < 0)
+ return err;
+
if (info->pdata && info->pdata->power_on)
- info->pdata->power_on(&info->power);
+ err = info->pdata->power_on(&info->power);
else {
dev_err(&info->i2c_client->dev,
"%s:no valid power_on function.\n", __func__);
- return -EEXIST;
+ err = -EEXIST;
}
+ if (err < 0)
+ goto ar0261_open_fail;
return 0;
+
+ar0261_open_fail:
+ ar0261_mclk_disable(info);
+ return err;
}
static int
@@ -802,6 +835,9 @@ ar0261_release(struct inode *inode, struct file *file)
if (info->pdata && info->pdata->power_off)
info->pdata->power_off(&info->power);
+
+ ar0261_mclk_disable(info);
+
file->private_data = NULL;
/* warn if device is already released */
@@ -876,6 +912,7 @@ ar0261_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct ar0261_info *info;
+ const char *mclk_name;
int err = 0;
pr_info("[ar0261]: probing sensor.\n");
@@ -892,6 +929,15 @@ ar0261_probe(struct i2c_client *client,
atomic_set(&info->in_use, 0);
info->mode = -1;
+ mclk_name = info->pdata->mclk_name ?
+ info->pdata->mclk_name : "default_mclk";
+ info->mclk = devm_clk_get(&client->dev, mclk_name);
+ if (IS_ERR(info->mclk)) {
+ dev_err(&client->dev, "%s: unable to get clock %s\n",
+ __func__, mclk_name);
+ return PTR_ERR(info->mclk);
+ }
+
i2c_set_clientdata(client, info);
ar0261_power_get(info);