From: Andrei Warkentin Date: Mon, 20 Sep 2010 20:32:56 +0000 (-0500) Subject: media: video: tegra: dw9714l: Make focuser driver more generic X-Git-Tag: firefly_0821_release~9834^2~532 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=cb0a27a5fbb9e68a4ea00d8eb371eed2df890755;p=firefly-linux-kernel-4.4.55.git media: video: tegra: dw9714l: Make focuser driver more generic Exposes more parameters and settings to focuser HAL, putting all specifics in the driver, queryable from the HAL. Change-Id: Id3d8764b7f9f1853982ca9c0d403fb0e455c7185 Signed-off-by: Andrei Warkentin --- diff --git a/drivers/media/video/tegra/dw9714l.c b/drivers/media/video/tegra/dw9714l.c index 7ac4f3c13fa8..26c36c3a0803 100644 --- a/drivers/media/video/tegra/dw9714l.c +++ b/drivers/media/video/tegra/dw9714l.c @@ -19,15 +19,49 @@ #include #include #include +#include #include -#define DW9714L_MAX_RETRIES (3) +#define POS_LOW (144) +#define POS_HIGH (520) +#define SETTLETIME_MS (50) +#define FOCAL_LENGTH (4.42f) +#define FNUMBER (2.8f) +#define DEFAULT_MODE (MODE_LSC); + +#define PROT_OFF (0xECA3) +#define PROT_ON (0xDC51) +#define DLC_MCLK (0x2) +#define DLC_TSRC (0x17) +#define LSC_MCLK (0x1) +#define LSC_S10 (0x3) +#define LSC_S32 (0x3) +#define LSC_TSRC (0x3) +#define LSC_GOAL(pos) ((pos << 4) | (LSC_S32 << 2) | LSC_S10) +#define GOAL(pos) (pos << 4) -#define POS_PER_STEP (3) +#define DW9714L_MAX_RETRIES (3) struct dw9714l_info { struct i2c_client *i2c_client; struct regulator *regulator; + struct dw9714l_config config; +}; + +static u16 dlc_pre_set_pos[] = +{ + PROT_OFF, + 0xA10C | DLC_MCLK, + 0xF200 | (DLC_TSRC << 3), + PROT_ON +}; + +static u16 lsc_pre_set_pos[] = +{ + PROT_OFF, + 0xA104 | LSC_MCLK, + 0xF200 | (LSC_TSRC << 3), + PROT_ON }; static int dw9714l_write(struct i2c_client *client, u16 value) @@ -60,31 +94,66 @@ static int dw9714l_write(struct i2c_client *client, u16 value) return -EIO; } -static int dw9714l_set_position(struct dw9714l_info *info, u32 position) +static int dw9714l_write_many(struct i2c_client *client, + u16 *values, + size_t count) { - int ret; + int ix = 0; + int ret = 0; + while (ix < count && ret == 0) + ret = dw9714l_write(client, values[ix++]); - /* Protection off. */ - ret = dw9714l_write(info->i2c_client, 0xECA3); - if (ret) - return ret; + return ret; +} - ret = dw9714l_write(info->i2c_client, 0xF200 | (0x0F << 3)); - if (ret) - return ret; +static int dw9714l_set_position(struct dw9714l_info *info, u32 position) +{ + int ret; - /* Protection on. */ - ret = dw9714l_write(info->i2c_client, 0xDC51); - if (ret) - return ret; + if (position < info->config.pos_low || + position > info->config.pos_high) + return -EINVAL; - ret = dw9714l_write(info->i2c_client, - (position << 4) | - (POS_PER_STEP << 2)); - if (ret) - return ret; + /* + As we calibrate the focuser, we might go back and forth on + the actual mode of setting the position. To + make this least painful, we'll make the mode a settable + parameter exposed to the focuser HAL. + */ + + switch(info->config.mode) + { + case MODE_LSC: + ret = dw9714l_write_many(info->i2c_client, + lsc_pre_set_pos, + ARRAY_SIZE(lsc_pre_set_pos)); + + if (ret) + return ret; + + ret = dw9714l_write(info->i2c_client, + LSC_GOAL(position)); + + break; + case MODE_DLC: + ret = dw9714l_write_many(info->i2c_client, + dlc_pre_set_pos, + ARRAY_SIZE(dlc_pre_set_pos)); + + if (ret) + return ret; + + /* Fall through */ + case MODE_DIRECT: + ret = dw9714l_write(info->i2c_client, + GOAL(position)); + break; + case MODE_INVALID: + default: + WARN_ON(info->config.mode); + } - return 0; + return ret; } static int dw9714l_ioctl(struct inode *inode, struct file *file, @@ -93,11 +162,39 @@ static int dw9714l_ioctl(struct inode *inode, struct file *file, struct dw9714l_info *info = file->private_data; switch (cmd) { + case DW9714L_IOCTL_GET_CONFIG: + { + if (copy_to_user((void __user *) arg, + &info->config, + sizeof(info->config))) { + pr_err("%s: 0x%x\n", __func__, __LINE__); + return -EFAULT; + } + + break; + } + case DW9714L_IOCTL_SET_CAL: + { + struct dw9714l_cal cal; + if (copy_from_user(&cal, + (const void __user *) arg, + sizeof(cal))) { + pr_err("%s: 0x%x\n", __func__, __LINE__); + return -EFAULT; + } + + if (cal.mode >= MODE_INVALID) + return -EINVAL; + + info->config.mode = cal.mode; + break; + } case DW9714L_IOCTL_SET_POSITION: return dw9714l_set_position(info, (u32) arg); default: return -EINVAL; } + return 0; } @@ -105,9 +202,7 @@ struct dw9714l_info *info = NULL; static int dw9714l_open(struct inode *inode, struct file *file) { - u8 status; - pr_info("%s\n", __func__); file->private_data = info; if (info->regulator) regulator_enable(info->regulator); @@ -116,7 +211,6 @@ static int dw9714l_open(struct inode *inode, struct file *file) int dw9714l_release(struct inode *inode, struct file *file) { - pr_info("%s\n", __func__); if (info->regulator) regulator_disable(info->regulator); file->private_data = NULL; @@ -167,6 +261,12 @@ static int dw9714l_probe(struct i2c_client *client, } info->i2c_client = client; + info->config.settle_time = SETTLETIME_MS; + info->config.focal_length = FOCAL_LENGTH; + info->config.fnumber = FNUMBER; + info->config.pos_low = POS_LOW; + info->config.pos_high = POS_HIGH; + info->config.mode = DEFAULT_MODE; i2c_set_clientdata(client, info); return 0; } diff --git a/include/media/dw9714l.h b/include/media/dw9714l.h index 3d91140dd37f..cac2abb9537b 100644 --- a/include/media/dw9714l.h +++ b/include/media/dw9714l.h @@ -24,7 +24,31 @@ #include /* For IOCTL macros */ -#define DW9714L_IOCTL_SET_POSITION _IOW('o', 1, u32) +#define DW9714L_IOCTL_GET_CONFIG _IOR('o', 1, struct dw9714l_config) +#define DW9714L_IOCTL_SET_CAL _IOW('o', 2, struct dw9714l_cal) +#define DW9714L_IOCTL_SET_POSITION _IOW('o', 3, u32) + +enum dw9714l_mode { + MODE_DIRECT, + MODE_LSC, + MODE_DLC, + MODE_INVALID +}; + +struct dw9714l_config +{ + __u32 settle_time; + float focal_length; + float fnumber; + __u32 pos_low; + __u32 pos_high; + enum dw9714l_mode mode; +}; + +struct dw9714l_cal +{ + enum dw9714l_mode mode; +}; #endif /* __DW9714L_H__ */