diff options
author | Pablo Ceballos <pceballos@nvidia.com> | 2013-07-01 17:51:48 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2013-09-14 13:30:07 -0700 |
commit | 6e07573549936931a3596f9affcd449d14aad2b3 (patch) | |
tree | c34cc1dec9ccb7d36e0b62e2c1eae14f047b41e0 /drivers/media/video | |
parent | cbbcf23330ecc14073ef19687ccb539b216de34e (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.c | 50 |
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); |