summaryrefslogtreecommitdiff
path: root/drivers/media
diff options
context:
space:
mode:
authorPradeep Kumar <pgoudagunta@nvidia.com>2012-08-06 23:01:18 +0530
committerVarun Colbert <vcolbert@nvidia.com>2012-08-07 15:23:08 -0700
commitb8b641f5e81434ebb721b3998218645b5190bc25 (patch)
treed82cd59ef84d3ddde0478abb38b2f329db87b4da /drivers/media
parente3c885a945febae6e9b2bc1c82863494d5db9a79 (diff)
Merge commit 'main-jb-2012.08.03-B4' into t114-0806
Conflicts: arch/arm/boot/compressed/Makefile arch/arm/boot/compressed/atags_to_fdt.c arch/arm/boot/compressed/head.S arch/arm/boot/dts/tegra30.dtsi arch/arm/include/asm/bug.h arch/arm/kernel/traps.c arch/arm/mach-tegra/Makefile.boot arch/arm/mach-tegra/board-cardhu-sdhci.c arch/arm/mach-tegra/board-cardhu.c arch/arm/mach-tegra/board-enterprise-sdhci.c arch/arm/mach-tegra/board-enterprise.c arch/arm/mach-tegra/board-harmony.c arch/arm/mach-tegra/board-kai-sdhci.c arch/arm/mach-tegra/board-ventana.c arch/arm/mach-tegra/board-whistler.c arch/arm/mach-tegra/clock.h arch/arm/mach-tegra/fuse.h arch/arm/mach-tegra/tegra2_usb_phy.c arch/arm/mach-tegra/tegra3_clocks.c arch/arm/mach-tegra/tegra3_dvfs.c arch/arm/mach-tegra/tegra3_speedo.c arch/arm/mach-tegra/timer.c arch/arm/mach-tegra/usb_phy.c arch/arm/mach-tegra/wakeups-t3.c drivers/cpufreq/cpufreq_interactive.c drivers/input/touchscreen/atmel_mxt_ts.c drivers/mfd/tps65090.c drivers/mmc/core/mmc.c drivers/mmc/host/sdhci-tegra.c drivers/mmc/host/sdhci.c drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c drivers/regulator/Kconfig drivers/regulator/core.c drivers/regulator/tps80031-regulator.c drivers/spi/Makefile drivers/staging/nvec/nvec.c drivers/tty/serial/Makefile include/linux/mmc/card.h sound/soc/tegra/tegra_max98095.c sound/usb/card.c Change-Id: I65043bc6ce9e97d0592683462215a39e50f403fd Reviewed-on: http://git-master/r/121392 Reviewed-by: Bo Yan <byan@nvidia.com> Tested-by: Bo Yan <byan@nvidia.com> Reviewed-by: Automatic_Commit_Validation_User
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/video/tegra/ad5816.c135
-rw-r--r--drivers/media/video/tegra/nvavp/nvavp_dev.c149
-rw-r--r--drivers/media/video/tegra/ov5650.c5
-rw-r--r--drivers/media/video/tegra/ov9726.c57
4 files changed, 291 insertions, 55 deletions
diff --git a/drivers/media/video/tegra/ad5816.c b/drivers/media/video/tegra/ad5816.c
index fd1468f677f6..e5ec9545918c 100644
--- a/drivers/media/video/tegra/ad5816.c
+++ b/drivers/media/video/tegra/ad5816.c
@@ -97,12 +97,14 @@
#define AD5816_ID 0x04
#define AD5816_FOCAL_LENGTH (4.570f)
#define AD5816_FNUMBER (2.8f)
-#define AD5816_ACTUATOR_RANGE 680
-#define AD5816_SETTLETIME 110
+#define AD5816_SLEW_RATE 1
+#define AD5816_ACTUATOR_RANGE 1023
+#define AD5816_SETTLETIME 50
#define AD5816_FOCUS_MACRO 810
#define AD5816_FOCUS_INFINITY 50 /* Exact value needs to be decided */
-#define AD5816_POS_LOW_DEFAULT 220
-#define AD5816_POS_HIGH_DEFAULT 900
+#define AD5816_POS_LOW_DEFAULT 0
+#define AD5816_POS_HIGH_DEFAULT 1023
+#define AD5816_POS_CLAMP 0x03ff
/* Need to decide exact value of VCM_THRESHOLD and its use */
/* define AD5816_VCM_THRESHOLD 20 */
@@ -141,6 +143,7 @@ struct ad5816_info {
struct ad5816_info *s_info;
struct nvc_focus_nvc nvc;
struct nvc_focus_cap cap;
+ struct nv_focuser_config nv_config;
struct ad5816_pdata_info config;
};
@@ -155,10 +158,12 @@ static struct ad5816_pdata_info ad5816_default_info = {
static struct nvc_focus_cap ad5816_default_cap = {
.version = NVC_FOCUS_CAP_VER2,
+ .slew_rate = AD5816_SLEW_RATE,
.actuator_range = AD5816_ACTUATOR_RANGE,
.settle_time = AD5816_SETTLETIME,
.focus_macro = AD5816_FOCUS_MACRO,
.focus_infinity = AD5816_FOCUS_INFINITY,
+ .focus_hyper = AD5816_FOCUS_INFINITY,
};
static struct nvc_focus_nvc ad5816_default_nvc = {
@@ -640,28 +645,76 @@ static int ad5816_position_rd(struct ad5816_info *info, unsigned *position)
int err = 0;
err = ad5816_i2c_rd8(info, 0, VCM_CODE_MSB, &t1);
- pos = t1 & 0x03;
+ pos = t1;
err = ad5816_i2c_rd8(info, 0, VCM_CODE_LSB, &t1);
pos = (pos << 8) | t1;
- if(pos)
- *position = pos - info->config.pos_low;
- else
- *position = info->config.pos_low;
- return 0;
+ if (pos < info->config.pos_low)
+ pos = info->config.pos_low;
+ else if (pos > info->config.pos_high)
+ pos = info->config.pos_high;
+
+ *position = pos;
+
+ return err;
}
-static int ad5816_position_wr(struct ad5816_info *info, unsigned position)
+static int ad5816_position_wr(struct ad5816_info *info, s32 position)
{
- u16 data;
+ s16 data;
- position = position + info->config.pos_low;
- if(position > info->config.pos_high)
- position = info->config.pos_high;
+ ad5816_set_arc_mode(info);
- data = position & 0x03ff;
+ if (position > info->config.pos_high)
+ return -EINVAL;
+ data = position & AD5816_POS_CLAMP;
return ad5816_i2c_wr16(info, VCM_CODE_MSB, data);
+
+}
+
+static void ad5816_get_focuser_capabilities(struct ad5816_info *info)
+{
+ memset(&info->nv_config, 0, sizeof(info->nv_config));
+
+ info->nv_config.focal_length = info->nvc.focal_length;
+ info->nv_config.fnumber = info->nvc.fnumber;
+ info->nv_config.max_aperture = info->nvc.fnumber;
+ info->nv_config.range_ends_reversed = 0;
+ info->nv_config.settle_time = info->cap.settle_time;
+
+ info->nv_config.pos_working_low = AF_POS_INVALID_VALUE;
+ info->nv_config.pos_working_high = AF_POS_INVALID_VALUE;
+
+ info->nv_config.pos_actual_low = info->config.pos_low;
+ info->nv_config.pos_actual_high = info->config.pos_high;
+
+ info->nv_config.slew_rate = info->cap.slew_rate;
+ info->nv_config.circle_of_confusion = -1;
+ info->nv_config.num_focuser_sets = 1;
+ info->nv_config.focuser_set[0].macro = info->cap.focus_macro;
+ info->nv_config.focuser_set[0].hyper = info->cap.focus_hyper;
+ info->nv_config.focuser_set[0].inf = info->cap.focus_infinity;
+ info->nv_config.focuser_set[0].settle_time = info->cap.settle_time;
+}
+
+static int ad5816_set_focuser_capabilities(struct ad5816_info *info,
+ struct nvc_param *params)
+{
+ if (copy_from_user(&info->nv_config, (const void __user *)params->p_value,
+ sizeof(struct nv_focuser_config))) {
+ dev_err(&info->i2c_client->dev, "%s Error: copy_from_user bytes %d\n",
+ __func__, sizeof(struct nv_focuser_config));
+ return -EFAULT;
+ }
+
+ /* set pre-set value, as currently ODM sets incorrect value */
+ info->cap.settle_time = AD5816_SETTLETIME;
+
+ dev_dbg(&info->i2c_client->dev, "%s: copy_from_user bytes %d info->cap.settle_time %d\n",
+ __func__, sizeof(struct nv_focuser_config), info->cap.settle_time);
+
+ return 0;
}
static int ad5816_param_rd(struct ad5816_info *info, unsigned long arg)
@@ -709,13 +762,10 @@ static int ad5816_param_rd(struct ad5816_info *info, unsigned long arg)
__func__, info->nvc.fnumber);
break;
case NVC_PARAM_CAPS:
- data_ptr = &info->cap;
- /* there are different sizes depending on the version */
/* send back just what's requested or our max size */
- if (params.sizeofvalue < sizeof(info->cap))
- data_size = params.sizeofvalue;
- else
- data_size = sizeof(info->cap);
+ ad5816_get_focuser_capabilities(info);
+ data_ptr = &info->nv_config;
+ data_size = sizeof(info->nv_config);
dev_err(&info->i2c_client->dev, "%s CAPS\n", __func__);
break;
case NVC_PARAM_STS:
@@ -748,17 +798,17 @@ static int ad5816_param_rd(struct ad5816_info *info, unsigned long arg)
}
static int ad5816_param_wr_s(struct ad5816_info *info,
- struct nvc_param *params, u32 u32val)
+ struct nvc_param *params, s32 s32val)
{
int err = 0;
switch (params->param) {
case NVC_PARAM_LOCUS:
- dev_dbg(&info->i2c_client->dev, "%s LOCUS: %u\n", __func__, u32val);
- err = ad5816_position_wr(info, u32val);
+ dev_dbg(&info->i2c_client->dev, "%s LOCUS: %d\n", __func__, s32val);
+ err = ad5816_position_wr(info, s32val);
return err;
case NVC_PARAM_RESET:
- err = ad5816_reset(info, u32val);
+ err = ad5816_reset(info, s32val);
dev_dbg(&info->i2c_client->dev, "%s RESET: %d\n", __func__, err);
return err;
case NVC_PARAM_SELF_TEST:
@@ -777,7 +827,7 @@ static int ad5816_param_wr(struct ad5816_info *info, unsigned long arg)
{
struct nvc_param params;
u8 u8val;
- u32 u32val;
+ s32 s32val;
int err = 0;
if (copy_from_user(&params, (const void __user *)arg,
sizeof(struct nvc_param))) {
@@ -785,11 +835,11 @@ static int ad5816_param_wr(struct ad5816_info *info, unsigned long arg)
__func__, __LINE__);
return -EFAULT;
}
- if (copy_from_user(&u32val, (const void __user *)params.p_value, sizeof(u32val))) {
+ if (copy_from_user(&s32val, (const void __user *)params.p_value, sizeof(s32val))) {
dev_err(&info->i2c_client->dev, "%s %d copy_from_user err\n", __func__, __LINE__);
return -EFAULT;
}
- u8val = (u8)u32val;
+ u8val = (u8)s32val;
/* parameters independent of sync mode */
switch (params.param) {
case NVC_PARAM_STEREO:
@@ -837,7 +887,7 @@ static int ad5816_param_wr(struct ad5816_info *info, unsigned long arg)
/* sync power */
info->s_info->pwr_api = info->pwr_api;
/* move slave lens to master position */
- err = ad5816_position_wr(info->s_info, info->pos);
+ err = ad5816_position_wr(info->s_info, (s32)info->pos);
if (!err) {
info->s_mode = u8val;
info->s_info->s_mode = u8val;
@@ -858,20 +908,29 @@ static int ad5816_param_wr(struct ad5816_info *info, unsigned long arg)
if (info->pdata->cfg & NVC_CFG_NOERR)
return 0;
return err;
+
+ case NVC_PARAM_CAPS:
+ if (ad5816_set_focuser_capabilities(info, &params)) {
+ dev_err(&info->i2c_client->dev, "%s: Error: copy_from_user bytes %d\n",
+ __func__, params.sizeofvalue);
+ return -EFAULT;
+ }
+ return 0;
+
default:
/* parameters dependent on sync mode */
switch (info->s_mode) {
case NVC_SYNC_OFF:
case NVC_SYNC_MASTER:
- return ad5816_param_wr_s(info, &params, u32val);
+ return ad5816_param_wr_s(info, &params, s32val);
case NVC_SYNC_SLAVE:
- return ad5816_param_wr_s(info->s_info, &params, u32val);
+ return ad5816_param_wr_s(info->s_info, &params, s32val);
case NVC_SYNC_STEREO:
- err = ad5816_param_wr_s(info, &params, u32val);
+ err = ad5816_param_wr_s(info, &params, s32val);
if (!(info->pdata->cfg & NVC_CFG_SYNC_I2C_MUX))
err |= ad5816_param_wr_s(info->s_info,
&params,
- u32val);
+ s32val);
return err;
default:
dev_err(&info->i2c_client->dev, "%s %d internal err\n",
@@ -890,10 +949,14 @@ static long ad5816_ioctl(struct file *file,
int err = 0;
switch (cmd) {
case NVC_IOCTL_PARAM_WR:
+ ad5816_pm_dev_wr(info, NVC_PWR_ON);
err = ad5816_param_wr(info, arg);
+ ad5816_pm_dev_wr(info, NVC_PWR_OFF);
return err;
case NVC_IOCTL_PARAM_RD:
+ ad5816_pm_dev_wr(info, NVC_PWR_ON);
err = ad5816_param_rd(info, arg);
+ ad5816_pm_dev_wr(info, NVC_PWR_OFF);
return err;
case NVC_IOCTL_PWR_WR:
/* This is a Guaranteed Level of Service (GLOS) call */
@@ -1036,8 +1099,8 @@ static int ad5816_open(struct inode *inode, struct file *file)
}
file->private_data = info;
ad5816_pm_dev_wr(info, NVC_PWR_ON);
- /* set ARC Mode to ensure faster focus */
- ad5816_set_arc_mode(info);
+ ad5816_position_wr(info, info->cap.focus_infinity);
+ ad5816_pm_dev_wr(info, NVC_PWR_OFF);
dev_dbg(&info->i2c_client->dev, "%s\n", __func__);
return 0;
diff --git a/drivers/media/video/tegra/nvavp/nvavp_dev.c b/drivers/media/video/tegra/nvavp/nvavp_dev.c
index ab9a351de79d..78e7b0a0b2bb 100644
--- a/drivers/media/video/tegra/nvavp/nvavp_dev.c
+++ b/drivers/media/video/tegra/nvavp/nvavp_dev.c
@@ -1,7 +1,7 @@
/*
* drivers/media/video/tegra/nvavp/nvavp_dev.c
*
- * Copyright (C) 2011-2012 NVIDIA Corp.
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
@@ -102,6 +102,10 @@ struct nvavp_info {
struct clk *bsev_clk;
struct clk *vde_clk;
struct clk *cop_clk;
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ struct clk *bsea_clk;
+ struct clk *vcp_clk;
+#endif
/* used for dvfs */
struct clk *sclk;
@@ -116,6 +120,7 @@ struct nvavp_info {
int video_initialized;
#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
int audio_initialized;
+ struct work_struct app_notify_work;
#endif
struct work_struct clock_disable_work;
@@ -263,14 +268,26 @@ static void nvavp_clks_disable(struct nvavp_info *nvavp)
}
}
-static u32 nvavp_check_idle(struct nvavp_info *nvavp)
+static u32 nvavp_check_idle(struct nvavp_info *nvavp, int channel_id)
{
- struct nvavp_channel *channel_info = nvavp_get_channel_info(nvavp, NVAVP_VIDEO_CHANNEL);
+ struct nvavp_channel *channel_info = nvavp_get_channel_info(nvavp, channel_id);
struct nv_e276_control *control = channel_info->os_control;
return (control->put == control->get) ? 1 : 0;
}
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+static void app_notify_handler(struct work_struct *work)
+{
+ struct nvavp_info *nvavp;
+
+ nvavp = container_of(work, struct nvavp_info,
+ app_notify_work);
+
+ kobject_uevent(&nvavp->nvhost_dev->dev.kobj, KOBJ_CHANGE);
+}
+#endif
+
static void clock_disable_handler(struct work_struct *work)
{
struct nvavp_info *nvavp;
@@ -282,7 +299,7 @@ static void clock_disable_handler(struct work_struct *work)
channel_info = nvavp_get_channel_info(nvavp, NVAVP_VIDEO_CHANNEL);
mutex_lock(&channel_info->pushbuffer_lock);
mutex_lock(&nvavp->open_lock);
- if (nvavp_check_idle(nvavp) && nvavp->pending) {
+ if (nvavp_check_idle(nvavp, NVAVP_VIDEO_CHANNEL) && nvavp->pending) {
nvavp->pending = false;
nvavp_clks_disable(nvavp);
}
@@ -328,6 +345,13 @@ static int nvavp_service(struct nvavp_info *nvavp)
dev_err(&nvavp->nvhost_dev->dev, "AVP timeout\n");
writel(inbox & NVAVP_INBOX_VALID, NVAVP_OS_INBOX);
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ if (inbox & NVE276_OS_INTERRUPT_APP_NOTIFY) {
+ pr_debug("nvavp_service NVE276_OS_INTERRUPT_APP_NOTIFY\n");
+ schedule_work(&nvavp->app_notify_work);
+ }
+#endif
+
return 0;
}
@@ -968,18 +992,14 @@ static void nvavp_uninit(struct nvavp_info *nvavp)
if (video_initialized) {
pr_debug("nvavp_uninit nvavp->video_initialized\n");
cancel_work_sync(&nvavp->clock_disable_work);
-
nvavp_halt_vde(nvavp);
-
- clk_disable(nvavp->sclk);
- clk_disable(nvavp->emc_clk);
-
nvavp_set_video_init_status(nvavp, 0);
video_initialized = 0;
}
#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
if (audio_initialized) {
+ cancel_work_sync(&nvavp->app_notify_work);
nvavp_set_audio_init_status(nvavp, 0);
audio_initialized = 0;
}
@@ -988,6 +1008,9 @@ static void nvavp_uninit(struct nvavp_info *nvavp)
/* Video and Audio both becomes uninitialized */
if (video_initialized == audio_initialized) {
pr_debug("nvavp_uninit both channels unitialized\n");
+
+ clk_disable(nvavp->sclk);
+ clk_disable(nvavp->emc_clk);
disable_irq(nvavp->mbox_from_avp_pend_irq);
nvavp_pushbuffer_deinit(nvavp);
nvavp_halt_avp(nvavp);
@@ -1248,6 +1271,62 @@ static int nvavp_force_clock_stay_on_ioctl(struct file *filp, unsigned int cmd,
return 0;
}
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+static int nvavp_enable_audio_clocks(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct nvavp_clientctx *clientctx = filp->private_data;
+ struct nvavp_info *nvavp = clientctx->nvavp;
+ struct nvavp_clock_args config;
+
+ if (copy_from_user(&config, (void __user *)arg, sizeof(struct nvavp_clock_args)))
+ return -EFAULT;
+
+ dev_dbg(&nvavp->nvhost_dev->dev, "%s: clk_id=%d\n",
+ __func__, config.id);
+
+ if (config.id == NVAVP_MODULE_ID_VCP)
+ clk_enable(nvavp->vcp_clk);
+ else if (config.id == NVAVP_MODULE_ID_BSEA)
+ clk_enable(nvavp->bsea_clk);
+
+ return 0;
+}
+
+static int nvavp_disable_audio_clocks(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct nvavp_clientctx *clientctx = filp->private_data;
+ struct nvavp_info *nvavp = clientctx->nvavp;
+ struct nvavp_clock_args config;
+
+ if (copy_from_user(&config, (void __user *)arg, sizeof(struct nvavp_clock_args)))
+ return -EFAULT;
+
+ dev_dbg(&nvavp->nvhost_dev->dev, "%s: clk_id=%d\n",
+ __func__, config.id);
+
+ if (config.id == NVAVP_MODULE_ID_VCP)
+ clk_disable(nvavp->vcp_clk);
+ else if (config.id == NVAVP_MODULE_ID_BSEA)
+ clk_disable(nvavp->bsea_clk);
+
+ return 0;
+}
+#else
+static int nvavp_enable_audio_clocks(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ return 0;
+}
+
+static int nvavp_disable_audio_clocks(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ return 0;
+}
+#endif
+
static int tegra_nvavp_open(struct inode *inode, struct file *filp, int channel_id)
{
struct miscdevice *miscdev = filp->private_data;
@@ -1365,6 +1444,12 @@ static long tegra_nvavp_ioctl(struct file *filp, unsigned int cmd,
case NVAVP_IOCTL_FORCE_CLOCK_STAY_ON:
ret = nvavp_force_clock_stay_on_ioctl(filp, cmd, arg);
break;
+ case NVAVP_IOCTL_ENABLE_AUDIO_CLOCKS:
+ ret = nvavp_enable_audio_clocks(filp, cmd, arg);
+ break;
+ case NVAVP_IOCTL_DISABLE_AUDIO_CLOCKS:
+ ret = nvavp_disable_audio_clocks(filp, cmd, arg);
+ break;
default:
ret = -EINVAL;
break;
@@ -1538,6 +1623,22 @@ static int tegra_nvavp_probe(struct nvhost_device *ndev,
goto err_get_emc_clk;
}
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ nvavp->bsea_clk = clk_get(&ndev->dev, "bsea");
+ if (IS_ERR(nvavp->bsea_clk)) {
+ dev_err(&ndev->dev, "cannot get bsea clock\n");
+ ret = -ENOENT;
+ goto err_get_bsea_clk;
+ }
+
+ nvavp->vcp_clk = clk_get(&ndev->dev, "vcp");
+ if (IS_ERR(nvavp->vcp_clk)) {
+ dev_err(&ndev->dev, "cannot get vcp clock\n");
+ ret = -ENOENT;
+ goto err_get_vcp_clk;
+ }
+#endif
+
nvavp->clk_enabled = 0;
nvavp_halt_avp(nvavp);
@@ -1556,6 +1657,7 @@ static int tegra_nvavp_probe(struct nvhost_device *ndev,
}
#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ INIT_WORK(&nvavp->app_notify_work, app_notify_handler);
nvavp->audio_misc_dev.minor = MISC_DYNAMIC_MINOR;
nvavp->audio_misc_dev.name = "tegra_audio_avpchannel";
nvavp->audio_misc_dev.fops = &tegra_audio_nvavp_fops;
@@ -1589,6 +1691,12 @@ err_audio_misc_reg:
#endif
misc_deregister(&nvavp->video_misc_dev);
err_misc_reg:
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ clk_put(nvavp->vcp_clk);
+err_get_vcp_clk:
+ clk_put(nvavp->bsea_clk);
+err_get_bsea_clk:
+#endif
clk_put(nvavp->emc_clk);
err_get_emc_clk:
clk_put(nvavp->sclk);
@@ -1637,6 +1745,8 @@ static int tegra_nvavp_remove(struct nvhost_device *ndev)
#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
misc_deregister(&nvavp->audio_misc_dev);
+ clk_put(nvavp->vcp_clk);
+ clk_put(nvavp->bsea_clk);
#endif
clk_put(nvavp->bsev_clk);
clk_put(nvavp->vde_clk);
@@ -1660,14 +1770,22 @@ static int tegra_nvavp_suspend(struct nvhost_device *ndev, pm_message_t state)
mutex_lock(&nvavp->open_lock);
if (nvavp->refcount) {
- if (!nvavp->clk_enabled)
+ if (!nvavp->clk_enabled) {
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ if (nvavp_check_idle(nvavp, NVAVP_AUDIO_CHANNEL))
+ nvavp_uninit(nvavp);
+ else
+ ret = -EBUSY;
+#else
nvavp_uninit(nvavp);
- else
+#endif
+ }
+ else {
ret = -EBUSY;
+ }
}
mutex_unlock(&nvavp->open_lock);
-
return ret;
}
@@ -1677,9 +1795,12 @@ static int tegra_nvavp_resume(struct nvhost_device *ndev)
mutex_lock(&nvavp->open_lock);
- if (nvavp->refcount)
+ if (nvavp->refcount) {
nvavp_init(nvavp, NVAVP_VIDEO_CHANNEL);
-
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ nvavp_init(nvavp, NVAVP_AUDIO_CHANNEL);
+#endif
+ }
mutex_unlock(&nvavp->open_lock);
return 0;
diff --git a/drivers/media/video/tegra/ov5650.c b/drivers/media/video/tegra/ov5650.c
index c5fce649ebca..09ad9e64ce12 100644
--- a/drivers/media/video/tegra/ov5650.c
+++ b/drivers/media/video/tegra/ov5650.c
@@ -641,6 +641,11 @@ static struct ov5650_reg mode_320x240[] = {
{0x380f, 0x38},
+ {0x3500, 0x00},
+ {0x3501, 0x13},
+ {0x3502, 0x80},
+ {0x350b, 0x7f},
+
{0x3815, 0x81},
{0x3824, 0x23},
{0x3825, 0x20},
diff --git a/drivers/media/video/tegra/ov9726.c b/drivers/media/video/tegra/ov9726.c
index 27400516488d..52b3b075dd0e 100644
--- a/drivers/media/video/tegra/ov9726.c
+++ b/drivers/media/video/tegra/ov9726.c
@@ -38,6 +38,7 @@ struct ov9726_devinfo {
struct ov9726_power_rail power_rail;
atomic_t in_use;
__u32 mode;
+ struct ov9726_reg grphold_temp[10];
};
static struct ov9726_reg mode_1280x720[] = {
@@ -603,6 +604,46 @@ static int ov9726_set_gain(struct i2c_client *i2c_client, u16 gain)
return ret;
}
+static int ov9726_set_group_hold(struct ov9726_devinfo *dev,
+ struct ov9726_ae *ae)
+{
+#define OV9726_REG_PUSH8(p, a, v) \
+ do { \
+ (p)->addr = (a); \
+ (p)->val = (v); \
+ (p)++; \
+ } while (0)
+
+#define OV9726_REG_PUSH16(ptr, addr, val) do { \
+ OV9726_REG_PUSH8(ptr, (addr), (val) >> 8); \
+ OV9726_REG_PUSH8(ptr, (addr) + 1, (val) & 0xff); \
+ } while (0)
+
+ struct ov9726_reg *gptr = &dev->grphold_temp[0];
+
+ if (!ae->gain_enable &&
+ !ae->coarse_time_enable &&
+ !ae->frame_length_enable)
+ return 0;
+
+ OV9726_REG_PUSH8(gptr, 0x0104, 0x01);
+ if (ae->gain_enable)
+ OV9726_REG_PUSH16(gptr,
+ OV9726_REG_GAIN_HI, ae->gain);
+ if (ae->coarse_time_enable)
+ OV9726_REG_PUSH16(gptr,
+ OV9726_REG_COARSE_TIME_HI, ae->coarse_time);
+ if (ae->frame_length_enable) {
+ OV9726_REG_PUSH16(gptr,
+ OV9726_REG_FRAME_LENGTH_HI, ae->frame_length);
+ }
+ OV9726_REG_PUSH8(gptr, 0x0104, 0x00);
+ OV9726_REG_PUSH8(gptr, OV9726_TABLE_END, 0x00);
+
+ return ov9726_write_table(dev->i2c_client,
+ dev->grphold_temp, NULL, 0);
+}
+
static int ov9726_get_status(struct i2c_client *i2c_client, u8 *status)
{
int err;
@@ -681,19 +722,26 @@ ov9726_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
}
-
case OV9726_IOCTL_SET_FRAME_LENGTH:
err = ov9726_set_frame_length(i2c_client, (u32)arg);
break;
-
case OV9726_IOCTL_SET_COARSE_TIME:
err = ov9726_set_coarse_time(i2c_client, (u32)arg);
break;
-
case OV9726_IOCTL_SET_GAIN:
err = ov9726_set_gain(i2c_client, (u16)arg);
break;
-
+ case OV9726_IOCTL_SET_GROUP_HOLD:
+ {
+ struct ov9726_ae ae;
+ if (copy_from_user(&ae,
+ (const void __user *)arg, sizeof(struct ov9726_ae))) {
+ pr_info("%s %d\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ err = ov9726_set_group_hold(dev, &ae);
+ break;
+ }
case OV9726_IOCTL_GET_STATUS:
{
u8 status;
@@ -706,7 +754,6 @@ ov9726_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
break;
}
-
default:
err = -EINVAL;
break;