diff options
author | Pradeep Kumar <pgoudagunta@nvidia.com> | 2012-08-06 23:01:18 +0530 |
---|---|---|
committer | Varun Colbert <vcolbert@nvidia.com> | 2012-08-07 15:23:08 -0700 |
commit | b8b641f5e81434ebb721b3998218645b5190bc25 (patch) | |
tree | d82cd59ef84d3ddde0478abb38b2f329db87b4da /drivers/media | |
parent | e3c885a945febae6e9b2bc1c82863494d5db9a79 (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.c | 135 | ||||
-rw-r--r-- | drivers/media/video/tegra/nvavp/nvavp_dev.c | 149 | ||||
-rw-r--r-- | drivers/media/video/tegra/ov5650.c | 5 | ||||
-rw-r--r-- | drivers/media/video/tegra/ov9726.c | 57 |
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(¶ms, (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, ¶ms)) { + 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, ¶ms, u32val); + return ad5816_param_wr_s(info, ¶ms, s32val); case NVC_SYNC_SLAVE: - return ad5816_param_wr_s(info->s_info, ¶ms, u32val); + return ad5816_param_wr_s(info->s_info, ¶ms, s32val); case NVC_SYNC_STEREO: - err = ad5816_param_wr_s(info, ¶ms, u32val); + err = ad5816_param_wr_s(info, ¶ms, s32val); if (!(info->pdata->cfg & NVC_CFG_SYNC_I2C_MUX)) err |= ad5816_param_wr_s(info->s_info, ¶ms, - 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; |