From 74d8c7c97115950405ad56cba7fbd4a3afca6ad6 Mon Sep 17 00:00:00 2001 From: Charlie Huang Date: Fri, 2 Nov 2012 16:16:04 -0700 Subject: drivers: tegra: imx091: flash control support add support of the on-sensor flash control bug 1170146 Change-Id: Ie8f48c5f8065ce4b35f24e7839f78fc6d8579482 Signed-off-by: Charlie Huang Reviewed-on: http://git-master/r/161015 Reviewed-by: Rohan Somvanshi Tested-by: Rohan Somvanshi --- drivers/media/video/tegra/as364x.c | 104 ++++++++++++---------- drivers/media/video/tegra/imx091.c | 92 ++++++++++++++++++- drivers/media/video/tegra/max77665-flash.c | 136 ++++++++++++++--------------- drivers/media/video/tegra/ov9772.c | 2 +- 4 files changed, 216 insertions(+), 118 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/video/tegra/as364x.c b/drivers/media/video/tegra/as364x.c index 31e223380ea6..cbe8fb1c5be2 100644 --- a/drivers/media/video/tegra/as364x.c +++ b/drivers/media/video/tegra/as364x.c @@ -60,7 +60,10 @@ #define AS364X_MAX_FLASH_LEVEL 256 #define AS364X_MAX_TORCH_LEVEL 128 -#define SUSTAINTIME_DEF 820 +#define SUSTAINTIME_DEF 558 +#define DEFAULT_FLASHTIME ((SUSTAINTIME_DEF > 256) ? \ + ((SUSTAINTIME_DEF - 249) / 8 + 128) : \ + ((SUSTAINTIME_DEF - 1) / 2)) #define RECHARGEFACTOR_DEF 197 #define as364x_max_flash_cap_size (sizeof(u32) \ @@ -192,28 +195,36 @@ static int as364x_reg_rd(struct as364x_info *info, u8 reg, u8 *val) return 0; } -static int as364x_reg_wr(struct as364x_info *info, u8 reg, u8 val) +static int as364x_reg_raw_wr(struct as364x_info *info, u8 *buf, u8 num) { struct i2c_msg msg; - u8 buf[2]; - buf[0] = reg; - buf[1] = val; msg.addr = info->i2c_client->addr; msg.flags = 0; - msg.len = 2; - msg.buf = &buf[0]; + msg.len = num; + msg.buf = buf; if (i2c_transfer(info->i2c_client->adapter, &msg, 1) != 1) return -EIO; + dev_dbg(&info->i2c_client->dev, "%s %x %x\n", __func__, buf[0], buf[1]); return 0; } +static int as364x_reg_wr(struct as364x_info *info, u8 reg, u8 val) +{ + u8 buf[2]; + + dev_dbg(&info->i2c_client->dev, "%s\n", __func__); + buf[0] = reg; + buf[1] = val; + return as364x_reg_raw_wr(info, buf, sizeof(buf)); +} + static int as364x_set_leds(struct as364x_info *info, u8 mask, u8 curr1, u8 curr2) { int err = 0; - u8 val = 0; + u8 regs[7]; if (mask & 1) { if (info->flash_mode == AS364X_REG_CONTROL_MODE_FLASH) { @@ -223,13 +234,8 @@ static int as364x_set_leds(struct as364x_info *info, if (curr1 >= info->torch_cap->numberoflevels) curr1 = info->torch_cap->numberoflevels - 1; } - - err = as364x_reg_wr(info, AS364X_REG_LED1_SET_CURR, curr1); - if (!err) - info->regs.led1_curr = curr1; - else - goto set_led_end; - } + } else + curr1 = 0; if (mask & 2 && info->caps.led2_support) { if (info->flash_mode == AS364X_REG_CONTROL_MODE_FLASH) { @@ -239,25 +245,28 @@ static int as364x_set_leds(struct as364x_info *info, if (curr2 >= info->torch_cap->numberoflevels) curr2 = info->torch_cap->numberoflevels - 1; } - - err = as364x_reg_wr(info, AS364X_REG_LED2_SET_CURR, curr2); - if (!err) - info->regs.led2_curr = curr2; - else - goto set_led_end; - } - - err = as364x_reg_wr(info, AS364X_REG_FLASHTIMER, info->regs.ftime); - val = info->flash_mode; + } else + curr2 = 0; + + regs[0] = AS364X_REG_LED1_SET_CURR; + regs[1] = curr1; + regs[2] = curr2; + regs[3] = info->regs.txmask; + regs[4] = info->regs.vlow; + regs[5] = info->regs.ftime; if (mask == 0 || (curr1 == 0 && curr2 == 0)) - val &= ~0x08; + regs[6] = info->flash_mode & (~0x08); else - val |= 0x08; - dev_dbg(&info->i2c_client->dev, "%s %x %x %x val = %x\n", - __func__, mask, curr1, curr2, val); - err |= as364x_reg_wr(info, AS364X_REG_CONTROL, val); + regs[6] = info->flash_mode | 0x08; + err = as364x_reg_raw_wr(info, regs, sizeof(regs)); + if (!err) { + info->regs.led1_curr = curr1; + info->regs.led2_curr = curr2; + } -set_led_end: + dev_dbg(&info->i2c_client->dev, "%s %x %x %x %x control = %x\n", + __func__, mask, curr1, curr2, + info->regs.ftime, regs[6]); return err; } @@ -309,7 +318,7 @@ static int as364x_get_vin_index(u16 mV) return vin; } -static void as364x_update_config(struct as364x_info *info) +static void as364x_config_init(struct as364x_info *info) { struct as364x_config *pcfg = &info->config; struct as364x_config *pcfg_cust = &info->pdata->config; @@ -388,6 +397,8 @@ static int as364x_update_settings(struct as364x_info *info) err |= as364x_set_leds(info, info->led_mask, info->regs.led1_curr, info->regs.led2_curr); + dev_dbg(&info->i2c_client->dev, "UP: strobe: %x pwm_ind: %x vlow: %x\n", + info->regs.strobe, info->regs.pwm_ind, info->regs.vlow); return err; } @@ -418,9 +429,11 @@ static int as364x_configure(struct as364x_info *info, bool update) if (pcfg->load_balance_on) info->regs.pwm_ind |= 0x20; - info->regs.strobe = pcfg->strobe_type ? 0xc0 : 0x80; + info->regs.strobe = pcfg->strobe_type == 2 ? 0xc0 : 0x80; info->led_mask = info->pdata->led_mask; + info->regs.ftime = DEFAULT_FLASHTIME; + if (pcfg->max_peak_current_mA > pcap->max_peak_curr_mA || !pcfg->max_peak_current_mA) { dev_warn(&info->i2c_client->dev, @@ -789,8 +802,6 @@ static int as364x_set_param(struct as364x_info *info, case NVC_PARAM_FLASH_LEVEL: dev_dbg(&info->i2c_client->dev, "%s FLASH_LEVEL: %d\n", __func__, val); - info->regs.ftime = - info->flash_cap->levels[val].rechargefactor; info->flash_mode = AS364X_REG_CONTROL_MODE_FLASH; err = as364x_set_leds(info, info->led_mask, val, val); @@ -1160,7 +1171,7 @@ static int as364x_probe( memcpy(&info->caps, &as364x_caps[info->pdata->type], sizeof(info->caps)); - as364x_update_config(info); + as364x_config_init(info); info->flash_mode = AS364X_REG_CONTROL_MODE_ASSIST; /* torch mode */ @@ -1211,6 +1222,7 @@ static int as364x_probe( static int as364x_status_show(struct seq_file *s, void *data) { struct as364x_info *k_info = s->private; + struct as364x_config *pcfg = &k_info->config; pr_info("%s\n", __func__); @@ -1221,6 +1233,7 @@ static int as364x_status_show(struct seq_file *s, void *data) " Led2 Current = 0x%02x\n" " Flash Mode = 0x%02x\n" " Flash TimeOut = 0x%02x\n" + " Flash Strobe = 0x%02x\n" " Max_Peak_Current = 0x%04dmA\n" " Use_TxMask = 0x%02x\n" " TxMask_Current = 0x%04dmA\n" @@ -1238,13 +1251,14 @@ static int as364x_status_show(struct seq_file *s, void *data) k_info->regs.led1_curr, k_info->regs.led2_curr, k_info->flash_mode, k_info->regs.ftime, - k_info->config.max_peak_current_mA, - k_info->config.use_tx_mask, - k_info->config.txmasked_current_mA, - k_info->config.freq_switch_on ? "TRUE" : "FALSE", - k_info->config.vin_low_v_run_mV, - k_info->config.vin_low_v_mV, - k_info->config.led_off_when_vin_low ? "TRUE" : "FALSE", + pcfg->strobe_type, + pcfg->max_peak_current_mA, + pcfg->use_tx_mask, + pcfg->txmasked_current_mA, + pcfg->freq_switch_on ? "TRUE" : "FALSE", + pcfg->vin_low_v_run_mV, + pcfg->vin_low_v_mV, + pcfg->led_off_when_vin_low ? "TRUE" : "FALSE", k_info->pdata->pinstate.mask, k_info->pdata->pinstate.values ); @@ -1331,9 +1345,9 @@ set_attr: break; case 'x': if (val & 0xf) - k_info->flash_mode = (val & 0xf); + k_info->flash_mode = (val & 0xf) - 1; if (val & 0xf0) - k_info->config.strobe_type = (val & 0xf0) >> 4; + k_info->config.strobe_type = ((val & 0xf0) >> 4) - 1; if (val & 0xf00) k_info->config.freq_switch_on = ((val & 0xf00) == 0x200); diff --git a/drivers/media/video/tegra/imx091.c b/drivers/media/video/tegra/imx091.c index ebebc57c4b21..df576aabb7af 100644 --- a/drivers/media/video/tegra/imx091.c +++ b/drivers/media/video/tegra/imx091.c @@ -120,7 +120,7 @@ static struct nvc_imager_cap imx091_dflt_cap = { .preferred_mode_index = 1, .focuser_guid = NVC_FOCUS_GUID(0), .torch_guid = NVC_TORCH_GUID(0), - .cap_end = NVC_IMAGER_CAPABILITIES_END, + .cap_version = NVC_IMAGER_CAPABILITIES_VERSION2, }; static struct imx091_platform_data imx091_dflt_pdata = { @@ -1240,6 +1240,79 @@ static int imx091_test_pattern_wr(struct imx091_info *info, unsigned pattern) return imx091_i2c_wr_table(info, test_patterns[pattern]); } +static int imx091_set_flash_output(struct imx091_info *info) +{ + struct imx091_flash_config *fcfg; + u8 val = 0; + int ret = 0; + + if (!info->pdata) + return 0; + + fcfg = &info->pdata->flash_cap; + if (fcfg->xvs_trigger_enabled) + val |= 0x0c; + if (fcfg->sdo_trigger_enabled) + val |= 0x02; + dev_dbg(&info->i2c_client->dev, "%s: %02x\n", __func__, val); + ret = imx091_i2c_wr8(info, 0x3240, val); + /* set the control pulse width settings - Gain + Step + * Pulse width(sec) = 64 * 2^(Gain) * (Step + 1) / Logic Clk + * Logic Clk = ExtClk * PLL Multipiler / Pre_Div / Post_Div + * / Logic Clk Division Ratio + * Logic Clk Division Ratio = 5 @4lane, 10 @2lane, 20 @1lane + */ + ret |= imx091_i2c_wr8(info, 0x307C, 0x07); + ret |= imx091_i2c_wr8(info, 0x307D, 0x3F); + return ret; +} + +static void imx091_get_flash_cap(struct imx091_info *info) +{ + struct nvc_imager_cap *fcap = info->cap; + struct imx091_flash_config *fcfg; + + if (!info->pdata) + return; + + fcfg = &info->pdata->flash_cap; + fcap->flash_control_enabled = + fcfg->xvs_trigger_enabled | fcfg->sdo_trigger_enabled; + fcap->adjustable_flash_timing = fcfg->adjustable_flash_timing; +} + +static int imx091_flash_control( + struct imx091_info *info, union nvc_imager_flash_control *fm) +{ + int ret; + u8 f_cntl; + u8 f_tim; + + if (!info->pdata) + return -EFAULT; + + ret = imx091_i2c_wr8(info, 0x304a, 0); + f_tim = 0; + f_cntl = 0; + if (fm->settings.enable) { + if (fm->settings.edge_trig_en) { + f_cntl |= 0x10; + if (fm->settings.start_edge) + f_tim |= 0x08; + if (fm->settings.repeat) + f_tim |= 0x04; + f_tim |= fm->settings.delay_frm & 0x03; + } else + f_cntl |= 0x20; + } + ret |= imx091_i2c_wr8(info, 0x307B, f_tim); + ret |= imx091_i2c_wr8(info, 0x304A, f_cntl); + + dev_dbg(&info->i2c_client->dev, + "%s: %04x %02x %02x\n", __func__, fm->mode, f_tim, f_cntl); + return ret; +} + static int imx091_gpio_rd(struct imx091_info *info, enum imx091_gpio i) { @@ -1706,7 +1779,9 @@ static int imx091_mode_wr(struct imx091_info *info, goto imx091_mode_wr_err; } - err = imx091_mode_able(info, true); + err = imx091_set_flash_output(info); + + err |= imx091_mode_able(info, true); if (err < 0) goto imx091_mode_wr_err; @@ -1868,7 +1943,6 @@ static int imx091_param_rd(struct imx091_info *info, unsigned long arg) } kfree(p_i2c_table); return err; - default: dev_dbg(&info->i2c_client->dev, "%s unsupported parameter: %d\n", @@ -1978,6 +2052,17 @@ static int imx091_param_wr_s(struct imx091_info *info, kfree(p_i2c_table); return err; + case NVC_PARAM_SET_SENSOR_FLASH_MODE: + { + union nvc_imager_flash_control fm; + if (copy_from_user(&fm, + (const void __user *)params->p_value, sizeof(fm))) { + pr_info("%s:fail set flash mode.\n", __func__); + return -EFAULT; + } + return imx091_flash_control(info, &fm); + } + default: dev_dbg(&info->i2c_client->dev, "%s unsupported parameter: %d\n", @@ -2499,6 +2584,7 @@ static int imx091_probe( spin_unlock(&imx091_spinlock); imx091_pm_init(info); imx091_sdata_init(info); + imx091_get_flash_cap(info); if (info->pdata->cfg & (NVC_CFG_NODEV | NVC_CFG_BOOT_INIT)) { if (info->pdata->probe_clock) { if (info->cap->initial_clock_rate_khz) diff --git a/drivers/media/video/tegra/max77665-flash.c b/drivers/media/video/tegra/max77665-flash.c index ef40641921cb..442390d43ffc 100644 --- a/drivers/media/video/tegra/max77665-flash.c +++ b/drivers/media/video/tegra/max77665-flash.c @@ -173,6 +173,7 @@ DIV_ROUND_UP(((x) * MAX77665_F_MAX_TORCH_LEVEL), 1000) #define SUSTAINTIME_DEF 558 +#define DEFAULT_FLASH_TMR_DUR ((SUSTAINTIME_DEF * 10 - 1) / 625) /* minimium debounce time 600uS */ #define RECHARGEFACTOR_DEF 600 @@ -241,6 +242,8 @@ struct max77665_f_info { u8 op_mode; u8 power_is_on; u8 s_mode; + u8 ftimer_mode; + u8 ttimer_mode; u8 new_ftimer; u8 new_ttimer; }; @@ -278,44 +281,51 @@ static DEFINE_SPINLOCK(max77665_f_spinlock); static inline int max77665_f_reg_wr(struct max77665_f_info *info, u8 reg, u8 val, bool refresh) { + dev_dbg(info->dev, "%s: %02x - %02x, %s %s\n", __func__, reg, val, + info->regs.regs_stale ? "STALE" : "NONE", + refresh ? "REFRESH" : "NONE"); if (likely(info->regs.regs_stale || refresh)) return regmap_write(info->regmap, reg, val); return 0; } +static inline int max77665_f_reg_raw_wr(struct max77665_f_info *info, + u8 reg, u8 *val, u8 num) +{ + dev_dbg(info->dev, "%s: %02x - %02x %02x ...\n", + __func__, reg, val[0], val[1]); + return regmap_raw_write(info->regmap, reg, val, num); +} + static int max77665_f_set_leds(struct max77665_f_info *info, u8 mask, u8 curr1, u8 curr2) { int err = 0; - u32 f_levels = info->flash_cap->numberoflevels - 2; - u32 t_levels = info->torch_cap->numberoflevels - 2; + u16 f_levels = info->flash_cap->numberoflevels - 2; + u16 t_levels = info->torch_cap->numberoflevels - 2; u8 fled_en = 0; u8 t_curr = 0; - u8 val = 0; + u8 regs[6]; - if (info->op_mode == MAXFLASH_MODE_NONE) - goto update_led_en_reg; + memset(regs, 0, sizeof(regs)); + if (info->op_mode == MAXFLASH_MODE_NONE) { + err |= max77665_f_reg_wr( + info, MAX77665_F_RW_FLED_ENABLE, 0, true); + info->regs.leds_en = 0; + goto set_leds_end; + } if (mask & 1) { if (info->op_mode == MAXFLASH_MODE_FLASH) { if (curr1 > f_levels) curr1 = f_levels; - - err = max77665_f_reg_wr(info, - MAX77665_F_RW_FLASH_FLED1CURR, curr1, - info->regs.led1_curr != curr1); - if (!err) - info->regs.led1_curr = curr1; - else - goto set_led_end; - fled_en |= (info->fled_settings & LED1_FLASH_TRIG_MASK); + regs[0] = curr1; } else { if (curr1 > t_levels) curr1 = t_levels; - - t_curr = curr1; fled_en |= (info->fled_settings & LED1_TORCH_TRIG_MASK); + t_curr = curr1; } } @@ -323,68 +333,57 @@ static int max77665_f_set_leds(struct max77665_f_info *info, if (info->op_mode == MAXFLASH_MODE_FLASH) { if (curr2 > f_levels) curr2 = f_levels; - - err = max77665_f_reg_wr(info, - MAX77665_F_RW_FLASH_FLED2CURR, curr2, - info->regs.led2_curr != curr2); - if (!err) - info->regs.led2_curr = curr2; - else - goto set_led_end; - fled_en |= (info->fled_settings & LED2_FLASH_TRIG_MASK); + regs[1] = curr2; } else { if (curr2 > t_levels) curr2 = t_levels; - - t_curr |= curr2 << 4; fled_en |= (info->fled_settings & LED2_TORCH_TRIG_MASK); + t_curr |= curr2 << 4; } } /* if any led is set as flash, update the flash timer register */ - if (fled_en & (LED1_FLASH_TRIG_MASK | LED2_FLASH_TRIG_MASK)) { - val = (info->regs.f_timer & FIELD(TIMER_MAX, 7)) | - info->new_ftimer; - err = max77665_f_reg_wr(info, - MAX77665_F_RW_FLASH_TIMER, val, - (info->regs.f_timer & 0x0f) != info->new_ftimer); - if (err) - goto set_led_end; - info->regs.f_timer = val; - } + if (fled_en & (LED1_FLASH_TRIG_MASK | LED2_FLASH_TRIG_MASK)) + regs[4] = (info->ftimer_mode & FIELD(TIMER_MAX, 7)) | + info->new_ftimer; /* if any led is set as torch, update the torch timer register */ if (fled_en & (LED1_TORCH_TRIG_MASK | LED2_TORCH_TRIG_MASK)) { - err = max77665_f_reg_wr(info, - MAX77665_F_RW_TORCH_FLEDCURR, t_curr, - info->regs.led_tcurr != t_curr); - if (!err) - info->regs.led_tcurr = t_curr; - else - goto set_led_end; - - val = (info->regs.t_timer & TORCH_TIMER_CTL_MASK) | - (info->new_ttimer & 0x0f); - err = max77665_f_reg_wr(info, MAX77665_F_RW_TORCH_TIMER, - val, true); - if (err) - goto set_led_end; - info->regs.t_timer = val; + regs[3] = (info->ttimer_mode & TORCH_TIMER_CTL_MASK) | + (info->new_ttimer & 0x0f); + regs[2] = t_curr; } -update_led_en_reg: - err = max77665_f_reg_wr(info, - MAX77665_F_RW_FLED_ENABLE, fled_en, - info->regs.leds_en != fled_en); - if (err) - goto set_led_end; - info->regs.leds_en = fled_en; - - dev_dbg(info->dev, "%s %x %x %x en = %x\n", - __func__, mask, curr1, curr2, fled_en); + regs[5] = fled_en; + if ((info->regs.led1_curr != regs[0]) || + (info->regs.led2_curr != regs[1]) || + (info->regs.led_tcurr != regs[2]) || + (info->regs.t_timer != regs[3]) || + (info->regs.f_timer != regs[4]) || + (info->regs.leds_en != regs[5])) + info->regs.regs_stale = true; + + if (info->regs.regs_stale) { + err = max77665_f_reg_raw_wr(info, + MAX77665_F_RW_FLASH_FLED1CURR, regs, sizeof(regs)); + + if (!err) { + info->regs.led1_curr = regs[0]; + info->regs.led2_curr = regs[1]; + info->regs.led_tcurr = regs[2]; + info->regs.t_timer = regs[3]; + info->regs.f_timer = regs[4]; + info->regs.leds_en = regs[5]; + info->regs.regs_stale = false; + } + } -set_led_end: +set_leds_end: + dev_dbg(info->dev, + "%s led %x flash: %02x %02x %02x, torch: %02x %02x, en = %x\n", + __func__, mask, curr1, curr2, info->regs.f_timer, + info->regs.led_tcurr, info->regs.t_timer, fled_en); return err; } @@ -505,20 +504,20 @@ update_end: info->regs.boost_vout_flash = max77665_f_get_boost_volt(pcfg->boost_vout_flash_mV); - info->regs.f_timer = (pcfg->flash_mode == 1) ? + info->ftimer_mode = (pcfg->flash_mode == 1) ? FIELD(TIMER_ONESHOT, 7) : FIELD(TIMER_MAX, 7); switch (pcfg->torch_mode) { case 1: - info->regs.t_timer = FIELD(TIMER_MAX, 7) | + info->ttimer_mode = FIELD(TIMER_MAX, 7) | FIELD(TORCH_TIMER_SAFETY_DIS, 6); break; case 2: - info->regs.t_timer = FIELD(TIMER_ONESHOT, 7); + info->ttimer_mode = FIELD(TIMER_ONESHOT, 7); break; case 3: default: - info->regs.t_timer = FIELD(TIMER_MAX, 7); + info->ttimer_mode = FIELD(TIMER_MAX, 7); break; } @@ -995,8 +994,7 @@ static int max77665_f_param_update(struct max77665_f_info *info, case NVC_PARAM_FLASH_LEVEL: dev_dbg(info->dev, "%s FLASH_LEVEL: %d\n", __func__, val); if (val) { - info->new_ftimer = - info->flash_cap->levels[val].sustaintime & 0X0F; + info->new_ftimer = DEFAULT_FLASH_TMR_DUR; info->op_mode = MAXFLASH_MODE_FLASH; val--; } else diff --git a/drivers/media/video/tegra/ov9772.c b/drivers/media/video/tegra/ov9772.c index 603f6a4cce35..70a2f9504125 100644 --- a/drivers/media/video/tegra/ov9772.c +++ b/drivers/media/video/tegra/ov9772.c @@ -243,7 +243,7 @@ static struct nvc_imager_cap ov9772_dflt_cap = { .preferred_mode_index = 0, .focuser_guid = 0, .torch_guid = 0, - .cap_end = NVC_IMAGER_CAPABILITIES_END, + .cap_version = NVC_IMAGER_CAPABILITIES_VERSION2, }; static struct ov9772_platform_data ov9772_dflt_pdata = { -- cgit v1.2.3