diff options
-rw-r--r-- | drivers/media/video/tegra/sh532u.c | 240 | ||||
-rw-r--r-- | include/media/nvc_focus.h | 25 |
2 files changed, 188 insertions, 77 deletions
diff --git a/drivers/media/video/tegra/sh532u.c b/drivers/media/video/tegra/sh532u.c index 4c7ef5aeaeab..84692d992154 100644 --- a/drivers/media/video/tegra/sh532u.c +++ b/drivers/media/video/tegra/sh532u.c @@ -113,7 +113,9 @@ #define SH532U_TIMEOUT_MS 200 #define SH532U_POS_LOW_DEFAULT 0xA000 #define SH532U_POS_HIGH_DEFAULT 0x6000 - +#define SH532U_SLEW_RATE 1 +#define SH532U_POS_TRANSLATE 0 +#define SH532U_POS_SIGN_CHANGER (-1) static u8 sh532u_ids[] = { 0xF0, @@ -148,6 +150,7 @@ struct sh532u_info { unsigned i2c_addr_rom; struct nvc_focus_nvc nvc; struct nvc_focus_cap cap; + struct nv_focuser_config config; enum nvc_focus_sts sts; struct sh532u_pdata_info cfg; bool reset_flag; @@ -172,6 +175,8 @@ static struct nvc_focus_cap sh532u_default_cap = { .focus_macro = SH532U_FOCUS_MACRO, .focus_hyper = SH532U_FOCUS_HYPER, .focus_infinity = SH532U_FOCUS_INFINITY, + .slew_rate = SH532U_SLEW_RATE, + .position_translate = SH532U_POS_TRANSLATE, }; static struct nvc_focus_nvc sh532u_default_nvc = { @@ -736,22 +741,31 @@ static void sh532u_sts_rd(struct sh532u_info *info) } } -static s16 sh532u_rel2abs(struct sh532u_info *info, u32 rel_position) +static s16 sh532u_rel2abs(struct sh532u_info *info, s32 rel_position) { s16 abs_pos; if (rel_position > info->cap.actuator_range) rel_position = info->cap.actuator_range; - rel_position = info->cap.actuator_range - rel_position; - if (rel_position) { - rel_position *= info->abs_range; - rel_position /= info->cap.actuator_range; + if (info->cap.position_translate) { + rel_position = info->cap.actuator_range - rel_position; + if (rel_position) { + rel_position *= info->abs_range; + rel_position /= info->cap.actuator_range; + } + abs_pos = (s16)(info->abs_base + rel_position); + } else { + abs_pos = rel_position * SH532U_POS_SIGN_CHANGER; } - abs_pos = (s16)(info->abs_base + rel_position); + if (abs_pos < info->cfg.limit_low) abs_pos = info->cfg.limit_low; if (abs_pos > info->cfg.limit_high) abs_pos = info->cfg.limit_high; + + dev_dbg(&info->i2c_client->dev, "%s: rel_position %d returning abs_pos %d\n", + __func__, rel_position, abs_pos); + return abs_pos; } @@ -763,12 +777,21 @@ static u32 sh532u_abs2rel(struct sh532u_info *info, s16 abs_position) abs_position = info->cfg.limit_high; if (abs_position < info->abs_base) abs_position = info->abs_base; - rel_pos = (u32)(abs_position - info->abs_base); - rel_pos *= info->cap.actuator_range; - rel_pos /= info->abs_range; - if (rel_pos > info->cap.actuator_range) - rel_pos = info->cap.actuator_range; - rel_pos = info->cap.actuator_range - rel_pos; + + if (info->cap.position_translate) { + rel_pos = (u32)(abs_position - info->abs_base); + rel_pos *= info->cap.actuator_range; + rel_pos /= info->abs_range; + + if (rel_pos > info->cap.actuator_range) + rel_pos = info->cap.actuator_range; + rel_pos = info->cap.actuator_range - rel_pos; + } else { + rel_pos = abs_position * SH532U_POS_SIGN_CHANGER; + } + dev_dbg(&info->i2c_client->dev, "%s: abs_position %d returning rel_pos %d", + __func__, abs_position, rel_pos); + return rel_pos; } @@ -782,7 +805,7 @@ static int sh532u_abs_pos_rd(struct sh532u_info *info, s16 *position) return err; } -static int sh532u_rel_pos_rd(struct sh532u_info *info, u32 *position) +static int sh532u_rel_pos_rd(struct sh532u_info *info, s32 *position) { s16 abs_pos; long msec; @@ -811,9 +834,11 @@ static int sh532u_rel_pos_rd(struct sh532u_info *info, u32 *position) pos = (int)info->pos_rel; } } - if (pos < 0) - pos = 0; - *position = (u32)pos; + if (info->cap.position_translate) { + if (pos < 0) + pos = 0; + } + *position = pos; return 0; } @@ -851,6 +876,8 @@ static void sh532u_calibration_caps(struct sh532u_info *info) rel_hi = info->cap.focus_infinity; info->abs_range = (u32)(info->cfg.pos_high - info->cfg.pos_low); loop_limit = (rel_lo > rel_hi) ? rel_lo : rel_hi; + dev_dbg(&info->i2c_client->dev, "%s: rel_lo %d rel_hi %d loop_limit %d\n", + __func__, rel_lo, rel_hi, loop_limit); for (i = 0; i <= loop_limit; i++) { rel_range = info->cap.actuator_range - (rel_lo + rel_hi); step = info->abs_range / rel_range; @@ -868,22 +895,36 @@ static void sh532u_calibration_caps(struct sh532u_info *info) abs_top <= info->cfg.limit_high) break; } + dev_dbg(&info->i2c_client->dev, "%s: info->abs_range %d abs_base %d abs_top %d\n", + __func__, info->abs_range, info->abs_base, abs_top); + + if (!info->cap.position_translate && info->abs_range) + info->cap.actuator_range = info->abs_range; + info->cap.focus_hyper = info->abs_range; info->abs_range = (u32)(abs_top - info->abs_base); /* calculate absolute hyperfocus position */ info->cap.focus_hyper *= info->cfg.focus_hyper_ratio; info->cap.focus_hyper /= info->cfg.focus_hyper_div; abs_top = (s16)(info->cfg.pos_high - info->cap.focus_hyper); + /* update actual relative positions */ info->cap.focus_hyper = sh532u_abs2rel(info, abs_top); + dev_dbg(&info->i2c_client->dev, "%s: focus_hyper abs %d rel %d\n", + __func__, abs_top, info->cap.focus_hyper); + info->cap.focus_infinity = sh532u_abs2rel(info, info->cfg.pos_high); + dev_dbg(&info->i2c_client->dev, "%s: focus_infinity abs %d rel %d\n", + __func__, info->cfg.pos_high, info->cap.focus_infinity); + info->cap.focus_macro = sh532u_abs2rel(info, info->cfg.pos_low); - dev_dbg(&info->i2c_client->dev, "%s focus_macro=%u\n", - __func__, info->cap.focus_macro); - dev_dbg(&info->i2c_client->dev, "%s focus_infinity=%u\n", - __func__, info->cap.focus_infinity); - dev_dbg(&info->i2c_client->dev, "%s focus_hyper=%u\n", - __func__, info->cap.focus_hyper); + dev_dbg(&info->i2c_client->dev, "%s: focus_macro abs %d rel %d\n", + __func__, info->cfg.pos_low, info->cap.focus_macro); + + dev_dbg(&info->i2c_client->dev, "%s: Version %d actuator_range %d " + "settle_time %d position_traslate %d\n", + __func__, info->cap.version, info->cap.actuator_range, + info->cap.settle_time, info->cap.position_translate); } static int sh532u_calibration(struct sh532u_info *info, bool use_defaults) @@ -892,8 +933,11 @@ static int sh532u_calibration(struct sh532u_info *info, bool use_defaults) int err; int ret = 0; - if (info->init_cal_flag) + if (info->init_cal_flag) { + dev_dbg(&info->i2c_client->dev, "%s: Already initialized" + "Returning\n", __func__); return 0; + } /* * Get Inf1, Mac1 @@ -965,8 +1009,9 @@ static int sh532u_calibration(struct sh532u_info *info, bool use_defaults) * 1 PASS PASS Continue to calculations */ /* err = DATA where FAIL = 1 */ - if (!info->cfg.pos_low || !info->cfg.pos_high || - !info->cfg.limit_low || !info->cfg.limit_high) + if (!info->cfg.pos_low || info->cfg.pos_high <= info->cfg.pos_low || + !info->cfg.limit_low || + info->cfg.limit_high <= info->cfg.limit_low) err = 1; else err = 0; @@ -998,6 +1043,7 @@ static int sh532u_calibration(struct sh532u_info *info, bool use_defaults) __func__, (int)info->cfg.limit_low); dev_dbg(&info->i2c_client->dev, "%s limit_high=%d\n", __func__, (int)info->cfg.limit_high); + sh532u_calibration_caps(info); info->init_cal_flag = 1; dev_dbg(&info->i2c_client->dev, "%s complete\n", __func__); @@ -1215,6 +1261,7 @@ static int sh532u_pos_abs_wr(struct sh532u_info *info, s16 tar_pos) STMLFF_OFF | STMVEN_ON)); } + dev_dbg(&info->i2c_client->dev, "%s: position %d\n", __func__, tar_pos); return err; } @@ -1289,30 +1336,101 @@ static int sh532u_hvca_pos_init(struct sh532u_info *info) return err; } -static int sh532u_pos_rel_wr(struct sh532u_info *info, u32 position) +static int sh532u_pos_rel_wr(struct sh532u_info *info, s32 position) { s16 abs_pos; - if (position > info->cap.actuator_range) { - dev_err(&info->i2c_client->dev, "%s invalid position %u\n", - __func__, position); - return -EINVAL; + if (info->cap.position_translate) { + if (position > info->cap.actuator_range) { + dev_err(&info->i2c_client->dev, "%s invalid position %d\n", + __func__, position); + return -EINVAL; + } } - abs_pos = sh532u_rel2abs(info, position); + info->pos_rel = position; info->pos_abs = abs_pos; info->pos_time_wr = jiffies; return sh532u_pos_abs_wr(info, abs_pos); } +static void sh532u_get_focuser_capabilities(struct sh532u_info *info) +{ + memset(&info->config, 0, sizeof(info->config)); + + info->config.focal_length = info->nvc.focal_length; + info->config.fnumber = info->nvc.fnumber; + info->config.max_aperture = info->nvc.fnumber; + info->config.range_ends_reversed = (SH532U_POS_SIGN_CHANGER == -1) + ? 1 : 0; + + info->config.settle_time = info->cap.settle_time; + + /* + * We do not use pos_working_low and pos_working_high + * in the kernel driver. + */ + info->config.pos_working_low = AF_POS_INVALID_VALUE; + info->config.pos_working_high = AF_POS_INVALID_VALUE; + + info->config.pos_actual_low = info->cfg.limit_high * + SH532U_POS_SIGN_CHANGER; + info->config.pos_actual_high = info->cfg.limit_low * + SH532U_POS_SIGN_CHANGER; + info->config.slew_rate = info->cap.slew_rate; + info->config.circle_of_confusion = -1; + + /* + * These need to be passed up once we have the EEPROM/OTP read + * routines in teh kernel. These need to be passed up much earlier on. + * Till we have these routines, we pass them up as part of the get call. + */ + info->config.num_focuser_sets = 1; + info->config.focuser_set[0].posture = 'S'; + info->config.focuser_set[0].macro = info->cap.focus_macro; + info->config.focuser_set[0].hyper = info->cap.focus_hyper; + info->config.focuser_set[0].inf = info->cap.focus_infinity; + info->config.focuser_set[0].hysteresis = 0; + info->config.focuser_set[0].settle_time = info->cap.settle_time; + info->config.focuser_set[0].num_dist_pairs = 0; + + dev_dbg(&info->i2c_client->dev, "%s: pos_actual_low %d pos_actual_high %d " + " settle_time %d\n", __func__, info->config.pos_actual_low, + info->config.pos_actual_high, info->cap.settle_time); + +} + + +static int sh532u_set_focuser_capabilities(struct sh532u_info *info, + struct nvc_param *params) +{ + if (copy_from_user(&info->config, (const void __user *)params->p_value, + params->sizeofvalue)) { + dev_err(&info->i2c_client->dev, "%s Error: copy_from_user bytes %d\n", + __func__, params->sizeofvalue); + return -EFAULT; + } + + /* info.config.focuser_set[0].posture, macro, hyper, infinity and + * hysterisis can remain there only. We need only settle_time & + * slew_rate for use here. + */ + info->cap.settle_time = info->config.focuser_set[0].settle_time; + info->config.slew_rate = info->config.slew_rate; + + dev_dbg(&info->i2c_client->dev, "%s: copy_from_user bytes %d\n", + __func__, params->sizeofvalue); + return 0; +} + static int sh532u_param_rd(struct sh532u_info *info, unsigned long arg) { struct nvc_param params; const void *data_ptr; u32 data_size = 0; - u32 position; + s32 position; int err; if (copy_from_user(¶ms, @@ -1366,16 +1484,14 @@ static int sh532u_param_rd(struct sh532u_info *info, unsigned long arg) sh532u_pm_dev_wr(info, NVC_PWR_STDBY); if (err) return -EIO; + dev_dbg(&info->i2c_client->dev, "%s: NVC_PARAM_CAPS: params.param %d " + "params.sizeofvalue %d\n", + __func__, params.param, params.sizeofvalue); - 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); - dev_dbg(&info->i2c_client->dev, "%s CAPS\n", - __func__); + sh532u_get_focuser_capabilities(info); + + data_ptr = &info->config; + data_size = params.sizeofvalue; break; case NVC_PARAM_STS: @@ -1421,16 +1537,15 @@ static int sh532u_param_wr_s(struct sh532u_info *info, struct nvc_param *params, u32 u32val) { - struct nvc_focus_cap cap; u8 u8val; int err; u8val = (u8)u32val; switch (params->param) { case NVC_PARAM_LOCUS: - dev_dbg(&info->i2c_client->dev, "%s LOCUS: %u\n", - __func__, u32val); - err = sh532u_pos_rel_wr(info, u32val); + dev_dbg(&info->i2c_client->dev, "%s LOCUS: %d\n", + __func__, (s32) u32val); + err = sh532u_pos_rel_wr(info, (s32) u32val); return err; case NVC_PARAM_RESET: @@ -1446,27 +1561,9 @@ static int sh532u_param_wr_s(struct sh532u_info *info, return err; case NVC_PARAM_CAPS: - dev_dbg(&info->i2c_client->dev, "%s CAPS\n", - __func__); - if (copy_from_user(&cap, (const void __user *)params->p_value, - sizeof(params->sizeofvalue))) { - dev_err(&info->i2c_client->dev, "%s %d copy_from_user err\n", - __func__, __LINE__); - return -EFAULT; - } - - if (!cap.version) - return -EINVAL; - - if (cap.version >= NVC_FOCUS_CAP_VER1) - info->cap.actuator_range = cap.actuator_range; - if (cap.version >= NVC_FOCUS_CAP_VER2) { - info->cap.focus_macro = cap.focus_macro; - info->cap.focus_hyper = cap.focus_hyper; - info->cap.focus_infinity = cap.focus_infinity; - } - sh532u_calibration_caps(info); - return 0; + dev_dbg(&info->i2c_client->dev, "%s CAPS. Error. sh532u_param_wr " + "should be called instead\n", __func__); + return -EFAULT; default: dev_dbg(&info->i2c_client->dev, @@ -1575,6 +1672,14 @@ static int sh532u_param_wr(struct sh532u_info *info, unsigned long arg) return err; + case NVC_PARAM_CAPS: + if (sh532u_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) { @@ -1829,7 +1934,6 @@ static int sh532u_probe( char dname[16]; int err; - dev_dbg(&client->dev, "%s\n", __func__); info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); if (info == NULL) { dev_err(&client->dev, "%s: kzalloc error\n", __func__); diff --git a/include/media/nvc_focus.h b/include/media/nvc_focus.h index c6ff1fa792c1..e37d897d8323 100644 --- a/include/media/nvc_focus.h +++ b/include/media/nvc_focus.h @@ -33,6 +33,8 @@ #define NVC_FOCUS_CAP_VER2 2 #define NVC_FOCUS_CAP_VER 2 /* latest version */ +#define AF_POS_INVALID_VALUE INT_MAX + enum nvc_focus_sts { NVC_FOCUS_STS_UNKNOWN = 1, NVC_FOCUS_STS_NO_DEVICE, @@ -52,11 +54,13 @@ struct nvc_focus_nvc { struct nvc_focus_cap { __u32 version; - __u32 actuator_range; + __s32 actuator_range; __u32 settle_time; - __u32 focus_macro; - __u32 focus_hyper; - __u32 focus_infinity; + __s32 focus_macro; + __s32 focus_hyper; + __s32 focus_infinity; + __u32 slew_rate; + __u32 position_translate; } __packed; @@ -66,7 +70,7 @@ struct nvc_focus_cap { struct nv_focuser_set_dist_pairs { __s32 fdn; __s32 distance; -}; +} __packed; struct nv_focuser_set { __s32 posture; @@ -78,23 +82,26 @@ struct nv_focuser_set { __s32 macro_offset; __s32 inf_offset; __u32 num_dist_pairs; - struct nv_focuser_set_dist_pairs dist_pair[NV_FOCUSER_SET_DISTANCE_PAIR]; -}; + struct nv_focuser_set_dist_pairs + dist_pair[NV_FOCUSER_SET_DISTANCE_PAIR]; +} __packed; struct nv_focuser_config { __u32 focal_length; __u32 fnumber; __u32 max_aperture; - __u32 actuator_range; + __s32 actuator_range; __u32 settle_time; + __u32 range_ends_reversed; __s32 pos_working_low; __s32 pos_working_high; __s32 pos_actual_low; __s32 pos_actual_high; __u32 slew_rate; __u32 circle_of_confusion; + __u32 num_focuser_sets; struct nv_focuser_set focuser_set[NV_FOCUSER_SET_MAX]; -}; +} __packed; #endif /* __NVC_FOCUS_H__ */ |