diff options
author | Naren Bhat <nbhat@nvidia.com> | 2011-11-10 15:21:04 -0800 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:50:12 -0800 |
commit | 9e9acaf50905ad1c485123b98368f3169bf4b17d (patch) | |
tree | 08fe86faef1838eec8554a5fc6309ae8f75f2f09 /drivers/media | |
parent | 3401252a468d1af8e30cde693fca0045447e8fd4 (diff) |
media: video: tegra: ar0832: Many fixes for focuser
For Enterprise focuser. Fix focuser range, steptime,
re-initialization of focuser registers after resolution
mode switch, back up and restore of the focuser position
during mode switch.
bug 881045
Reviewed-on: http://git-master/r/63698
(cherry picked from commit 2d83f0bbc13b8a0c760fc86223b15d32f731d36c)
Change-Id: I84916884930f21b085ea17899c051b0d61248e07
Reviewed-on: http://git-master/r/64594
Reviewed-by: Simone Willett <swillett@nvidia.com>
Tested-by: Simone Willett <swillett@nvidia.com>
Rebase-Id: R7ccb1393d5e31a11030f892e9cb663d03581c561
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/video/tegra/ar0832_main.c | 118 |
1 files changed, 108 insertions, 10 deletions
diff --git a/drivers/media/video/tegra/ar0832_main.c b/drivers/media/video/tegra/ar0832_main.c index 6deddca96b61..ba22b11686d3 100644 --- a/drivers/media/video/tegra/ar0832_main.c +++ b/drivers/media/video/tegra/ar0832_main.c @@ -23,7 +23,7 @@ #include <linux/regulator/consumer.h> #include <media/ar0832_main.h> -#define POS_LOW 50 +#define POS_LOW 0 #define POS_HIGH 1000 #define SETTLETIME_MS 100 @@ -35,6 +35,7 @@ struct ar0832_sensor_info { struct ar0832_focuser_info { struct ar0832_focuser_config config; int focuser_init_flag; + u16 last_position; }; struct ar0832_power_rail { @@ -1974,6 +1975,7 @@ ar0832_pwdn_exit: static int ar0832_focuser_set_config(struct ar0832_dev *dev) { + struct i2c_client *i2c_client = dev->i2c_client; struct ar0832_reg reg_vcm_ctrl, reg_vcm_step_time; int ret = 0; u8 vcm_slew = 1; @@ -1982,18 +1984,30 @@ static int ar0832_focuser_set_config(struct ar0832_dev *dev) /* bit3(0x08) means that keep VCM(AF position) */ /* while sensor is in soft standby mode during mode transitions. */ u16 vcm_control_data = (0x80 << 8 | (0x08 | (vcm_slew & 0x07))); - u16 vcm_step_time = 2048; + u16 vcm_step_time = 1024; ar0832_get_focuser_vcm_control_regs(®_vcm_ctrl, vcm_control_data); ret = ar0832_write_reg16(dev->i2c_client, reg_vcm_ctrl.addr, reg_vcm_ctrl.val); - if (ret) + + dev_dbg(&i2c_client->dev, "%s Reg 0x%X Value 0x%X\n", __func__, + reg_vcm_ctrl.addr, reg_vcm_ctrl.val); + + if (ret) { + dev_dbg(&i2c_client->dev, "%s Error writing to register 0x%X\n", + __func__, reg_vcm_ctrl.addr); return ret; + } ar0832_get_focuser_vcm_step_time_regs(®_vcm_step_time, vcm_step_time); ret = ar0832_write_reg16(dev->i2c_client, reg_vcm_step_time.addr, reg_vcm_step_time.val); + + dev_dbg(&i2c_client->dev, "%s Reg step_time 0x%X Value 0x%X\n", + __func__, reg_vcm_step_time.addr, + reg_vcm_step_time.val); + return ret; } @@ -2003,16 +2017,73 @@ static int ar0832_focuser_set_position(struct ar0832_dev *dev, int ret = 0; struct ar0832_reg reg_data; - if (position < dev->focuser_info->config.pos_low || - position > dev->focuser_info->config.pos_high) - return -EINVAL; - ar0832_get_focuser_data_regs(®_data, position); ret = ar0832_write_reg16(dev->i2c_client, reg_data.addr, reg_data.val); + dev->focuser_info->last_position = position; + return ret; } + +/* + * This function is not currently called as we have the hardcoded + * step time in ar0832_focuser_set_config function. If we need to + * compute the actual step time based on a number of clocks, we need + * to use this function. The formula for computing the clock-based + * step time is obtained from Aptina and is not part of external + * documentation and hence this code needs to be saved. + */ +static u16 ar0832_get_focuser_vcm_step_time(struct ar0832_dev *dev) +{ + struct i2c_client *i2c_client = dev->i2c_client; + int ret; + u16 pll_multiplier = 0; + u16 pre_pll_clk_div = 0; + u16 vt_sys_clk_div = 0; + u16 vt_pix_clk_div = 0; + u16 vt_pix_clk_freq_mhz = 0; + + ret = ar0832_read_reg16(dev->i2c_client, 0x306, &pll_multiplier); + if (ret) { + dev_err(&i2c_client->dev, "%s pll_multiplier read failed\n", + __func__); + } + + ret = ar0832_read_reg16(dev->i2c_client, 0x304, &pre_pll_clk_div); + if (ret) { + dev_err(&i2c_client->dev, "%s pre_pll_clk_div read failed\n", + __func__); + } + + ret = ar0832_read_reg16(dev->i2c_client, 0x302, &vt_sys_clk_div); + if (ret) { + dev_err(&i2c_client->dev, "%s vt_sys_clk_div read failed\n", + __func__); + } + + ret = ar0832_read_reg16(dev->i2c_client, 0x300, &vt_pix_clk_div); + if (ret) { + dev_err(&i2c_client->dev, "%s vt_pix_clk_div read failed\n", + __func__); + } + + vt_pix_clk_freq_mhz = + (24 * pll_multiplier) / (pre_pll_clk_div * vt_sys_clk_div * + vt_pix_clk_div); + + dev_dbg(&i2c_client->dev, "%s pll_multiplier 0x%X pre_pll_clk_div 0x%X " + "vt_sys_clk_div 0x%X vt_pix_clk_div 0x%X vt_pix_clk_freq_mhz 0x%X\n", + __func__, pll_multiplier, + pre_pll_clk_div, vt_sys_clk_div, + vt_pix_clk_div, vt_pix_clk_freq_mhz); + + return vt_pix_clk_freq_mhz; + +} + + + static inline int ar0832_get_sensorid(struct ar0832_dev *dev, u16 *sensor_id) { @@ -2039,6 +2110,7 @@ static long ar0832_ioctl(struct file *file, struct ar0832_dev *dev = file->private_data; struct i2c_client *i2c_client = dev->i2c_client; struct ar0832_mode mode; + u16 pos; switch (cmd) { case AR0832_IOCTL_SET_POWER_ON: @@ -2066,9 +2138,29 @@ static long ar0832_ioctl(struct file *file, } mutex_lock(&dev->ar0832_camera_lock); err = ar0832_set_mode(dev, &mode); - if (dev->focuser_info->focuser_init_flag == false) { - ar0832_focuser_set_config(dev); - dev->focuser_info->focuser_init_flag = true; + + /* + * We need to re-initialize the Focuser registers during mode + * switch due to the known issue of focuser retracting + */ + ar0832_focuser_set_config(dev); + dev->focuser_info->focuser_init_flag = true; + + /* + * If the last focuser position is not at infinity when we + * did the mode switch, we need to go there. Before that, + * we need to come back to 0. + */ + if (dev->focuser_info->last_position > 0) { + pos = dev->focuser_info->last_position; + dev_err(&i2c_client->dev, "%s: AR0832_IOCTL_SET_MODE: " + " Move to 0, restore the backedup focuser position of %d\n", + __func__, pos); + ar0832_focuser_set_position(dev, 0); + ar0832_msleep(10); + + ar0832_focuser_set_position(dev, pos); + ar0832_msleep(10); } mutex_unlock(&dev->ar0832_camera_lock); return err; @@ -2137,6 +2229,10 @@ static long ar0832_ioctl(struct file *file, dev_dbg(&i2c_client->dev, "%s AR0832_FOCUSER_IOCTL_SET_POSITION\n", __func__); mutex_lock(&dev->ar0832_camera_lock); + if (dev->focuser_info->focuser_init_flag == false) { + ar0832_focuser_set_config(dev); + dev->focuser_info->focuser_init_flag = true; + } err = ar0832_focuser_set_position(dev, (u32)arg); mutex_unlock(&dev->ar0832_camera_lock); return err; @@ -2200,6 +2296,8 @@ static int ar0832_release(struct inode *inode, struct file *file) file->private_data = NULL; + dev->focuser_info->focuser_init_flag = false; + WARN_ON(!atomic_xchg(&dev->in_use, 0)); return 0; } |