diff options
author | Phil Breczinski <pbreczinski@nvidia.com> | 2012-12-06 15:17:50 -0800 |
---|---|---|
committer | Harshada Kale <hkale@nvidia.com> | 2013-06-12 05:02:46 -0700 |
commit | 74c042d0666dd32f6f0a314bcbf618c08cafbd11 (patch) | |
tree | cac455555c53e857ef0a4c54d8c2e449aa0e5850 /drivers/media | |
parent | 753d1b6a2a7b8d360e868d28637411d77ebf5ac4 (diff) |
media: video: tegra: fuse id support
Adds support to read fuse ID from OTP memory on
ov2710, ov9726, ov9772, ar0832, and imx091 sensors.
Also includes macro-enabled fuse ID programming for
ov2710. Adjusts data structure used by fuse ID ioctl
to include a field for fuse ID size.
Required by nvcamera version 1.8.0
Required by NVCS version 4.10.0
Bug 1198663
Change-Id: Ib3bb0e100e49aea2c6ce13cd069862476d7f4bb6
Signed-off-by: Phil Breczinski <pbreczinski@nvidia.com>
Reviewed-on: http://git-master/r/169187
(cherry picked from commit 0ce57617ee1f735759333a589aa2890559053fe0)
Reviewed-on: http://git-master/r/232254
Reviewed-by: Brian Bamsch <bbamsch@nvidia.com>
Tested-by: Brian Bamsch <bbamsch@nvidia.com>
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Jon Mayo <jmayo@nvidia.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/video/tegra/ar0832_main.c | 85 | ||||
-rw-r--r-- | drivers/media/video/tegra/imx091.c | 39 | ||||
-rw-r--r-- | drivers/media/video/tegra/imx132.c | 25 | ||||
-rw-r--r-- | drivers/media/video/tegra/imx135.c | 14 | ||||
-rw-r--r-- | drivers/media/video/tegra/ov2710.c | 75 | ||||
-rw-r--r-- | drivers/media/video/tegra/ov5650.c | 26 | ||||
-rw-r--r-- | drivers/media/video/tegra/ov9726.c | 50 | ||||
-rw-r--r-- | drivers/media/video/tegra/ov9772.c | 40 |
8 files changed, 319 insertions, 35 deletions
diff --git a/drivers/media/video/tegra/ar0832_main.c b/drivers/media/video/tegra/ar0832_main.c index c8859acc5929..58d07b53d41f 100644 --- a/drivers/media/video/tegra/ar0832_main.c +++ b/drivers/media/video/tegra/ar0832_main.c @@ -1,7 +1,7 @@ /* * ar0832_main.c - Aptina AR0832 8M Bayer type sensor driver * -* Copyright (c) 2011, NVIDIA, All Rights Reserved. +* Copyright (c) 2011-2013, 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 @@ -24,13 +24,14 @@ #include <linux/module.h> #include <media/ar0832_main.h> - +#include <media/nvc.h> #define POS_ACTUAL_LOW 0 #define POS_ACTUAL_HIGH 255 -#define SETTLE_TIME 100 -#define AR0832_SLEW_RATE_DISABLED 0 -#define AR0832_SLEW_RATE_SLOWEST 7 +#define SETTLE_TIME 100 +#define AR0832_SLEW_RATE_DISABLED 0 +#define AR0832_SLEW_RATE_SLOWEST 7 +#define AR0832_FUSE_ID_SIZE 16 struct ar0832_sensor_info { @@ -63,6 +64,7 @@ struct ar0832_dev { int is_stereo; u16 sensor_id_data; struct dentry *debugdir; + struct nvc_fuseid fuse_id; }; #define UpperByte16to8(x) ((u8)((x & 0xFF00) >> 8)) @@ -2116,6 +2118,63 @@ static long ar0832_set_focuser_capabilities(struct ar0832_dev *dev, return 0; } +static int ar0832_get_fuseid(struct ar0832_dev *dev) +{ + int ret = 0; + int i, timeout; + __u16 bak; + struct i2c_client *i2c_client = dev->i2c_client; + + if (dev->fuse_id.size) + return 0; + + ret = ar0832_write_reg16(i2c_client, 0x3052, 0x2704); + ret |= ar0832_read_reg16(i2c_client, 0x3054, &bak); + ret |= ar0832_write_reg16(i2c_client, 0x3054, bak | 0x0100); + ret |= ar0832_read_reg16(i2c_client, 0x3050, &bak); + ret |= ar0832_write_reg16(i2c_client, 0x3050, bak & 0x00ff); + ret |= ar0832_write_reg16(i2c_client, 0x3054, 0x0008); + ret |= ar0832_read_reg16(i2c_client, 0x304a, &bak); + ret |= ar0832_write_reg16(i2c_client, 0x304a, bak | 0x0010); + + timeout = 0; + while (!(bak & 0x0020)) { + ret |= ar0832_read_reg16(i2c_client, 0x304a, &bak); + timeout += 1; + if (timeout >= 100) { + pr_info("ar0832: fuse ID read timed out\n"); + return -EFAULT; + } + } + + if (bak & 0x0040) + pr_info("ar0832: fuse ID read successfully\n"); + else { + pr_info("ar0832: fuse ID read failed\n"); + return -EFAULT; + } + + /* OTP memory on ar0832 is larger than we are checking - may + * may want to change which bytes are read in the future + */ + dev->fuse_id.size = AR0832_FUSE_ID_SIZE; + for (i = 0; i < 8; i++) { + if (i * 2 < dev->fuse_id.size) { + ret |= ar0832_read_reg16(i2c_client, 0x3800 + i, &bak); + dev->fuse_id.data[i * 2] = + (__u8)((bak >> 8) & 0x00ff); + if (i * 2 + 1 < dev->fuse_id.size) + dev->fuse_id.data[i * 2 + 1] = + (__u8)(bak & 0x00ff); + } + } + + if (ret) + dev->fuse_id.size = 0; + + return ret; +} + static long ar0832_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -2283,6 +2342,22 @@ static long ar0832_ioctl(struct file *file, } return 0; + case AR0832_IOCTL_GET_FUSEID: + { + err = ar0832_get_fuseid(dev); + if (err) { + pr_err("%s %d %d\n", __func__, __LINE__, err); + return err; + } + if (copy_to_user((void __user *)arg, + &dev->fuse_id, + sizeof(struct nvc_fuseid))) { + pr_info("%s %d\n", __func__, __LINE__); + return -EFAULT; + } + return 0; + } + default: dev_err(&i2c_client->dev, "(error) %s NONE IOCTL\n", __func__); diff --git a/drivers/media/video/tegra/imx091.c b/drivers/media/video/tegra/imx091.c index 4137f0387622..59cde73af54d 100644 --- a/drivers/media/video/tegra/imx091.c +++ b/drivers/media/video/tegra/imx091.c @@ -44,6 +44,7 @@ #define IMX091_LENS_VIEW_ANGLE_V 60400 /* / _INT2FLOAT_DIVISOR */ #define IMX091_WAIT_MS 3 #define IMX091_I2C_TABLE_MAX_ENTRIES 400 +#define IMX091_FUSE_ID_SIZE 8 static u16 imx091_ids[] = { 0x0091, @@ -88,6 +89,7 @@ struct imx091_info { struct dentry *debugfs_root; u16 i2c_reg; #endif + struct nvc_fuseid fuse_id; }; struct imx091_reg { @@ -2273,6 +2275,27 @@ static int imx091_param_wr(struct imx091_info *info, unsigned long arg) } } +static int imx091_get_fuse_id(struct imx091_info *info) +{ + int ret, i; + + if (info->fuse_id.size) + return 0; + + ret = imx091_i2c_wr8(info, 0x34C9, 0x10); + + for (i = 0; i < IMX091_FUSE_ID_SIZE ; i++) { + ret |= imx091_i2c_rd8(info, + 0x3580 + i, + &info->fuse_id.data[i]); + } + + if (!ret) + info->fuse_id.size = i; + + return ret; +} + static long imx091_ioctl(struct file *file, unsigned int cmd, unsigned long arg) @@ -2289,6 +2312,22 @@ static long imx091_ioctl(struct file *file, int err; switch (cmd) { + case NVC_IOCTL_FUSE_ID: + err = imx091_get_fuse_id(info); + + if (err) { + pr_err("%s %d %d\n", __func__, __LINE__, err); + return err; + } + if (copy_to_user((void __user *)arg, + &info->fuse_id, + sizeof(struct nvc_fuseid))) { + pr_err("%s: %d: fail copy fuse id to user space\n", + __func__, __LINE__); + return -EFAULT; + } + return 0; + case NVC_IOCTL_PARAM_WR: err = imx091_param_wr(info, arg); return err; diff --git a/drivers/media/video/tegra/imx132.c b/drivers/media/video/tegra/imx132.c index d2e3abf656d5..2dcb211cdbcd 100644 --- a/drivers/media/video/tegra/imx132.c +++ b/drivers/media/video/tegra/imx132.c @@ -24,6 +24,10 @@ #include <linux/uaccess.h> #include <linux/regulator/consumer.h> #include <media/imx132.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> +#include <media/nvc.h> #include <linux/gpio.h> #include <linux/module.h> #include <linux/moduleparam.h> @@ -39,7 +43,7 @@ struct imx132_info { struct miscdevice miscdev_info; int mode; struct imx132_power_rail power; - struct imx132_sensordata sensor_data; + struct nvc_fuseid fuse_id; struct i2c_client *i2c_client; struct imx132_platform_data *pdata; atomic_t in_use; @@ -48,6 +52,7 @@ struct imx132_info { #define IMX132_TABLE_WAIT_MS 0 #define IMX132_TABLE_END 1 #define IMX132_WAIT_MS 5 +#define IMX132_FUSE_ID_SIZE 8 static struct imx132_reg mode_1976x1200[] = { /* Stand by */ @@ -505,13 +510,13 @@ imx132_set_group_hold(struct imx132_info *info, struct imx132_ae *ae) return 0; } -static int imx132_get_sensor_id(struct imx132_info *info) +static int imx132_get_fuse_id(struct imx132_info *info) { int ret = 0; int i; u8 bak = 0; - if (info->sensor_data.fuse_id_size) + if (info->fuse_id.size) return 0; /* @@ -520,13 +525,13 @@ static int imx132_get_sensor_id(struct imx132_info *info) */ ret |= imx132_write_reg(info->i2c_client, 0x34C9, 0x10); - for (i = 0; i < NUM_OF_SENSOR_ID_SPECIFIC_REG ; i++) { + for (i = 0; i < IMX132_FUSE_ID_SIZE ; i++) { ret |= imx132_read_reg(info->i2c_client, 0x3580 + i, &bak); - info->sensor_data.fuse_id[i] = bak; + info->fuse_id.data[i] = bak; } if (!ret) - info->sensor_data.fuse_id_size = i; + info->fuse_id.size = i; return ret; } @@ -572,9 +577,9 @@ imx132_ioctl(struct file *file, } return 0; } - case IMX132_IOCTL_GET_SENSORDATA: + case IMX132_IOCTL_GET_FUSEID: { - err = imx132_get_sensor_id(info); + err = imx132_get_fuse_id(info); if (err) { dev_err(dev, "%s:Failed to get fuse id info.\n", @@ -582,8 +587,8 @@ imx132_ioctl(struct file *file, return err; } if (copy_to_user((void __user *)arg, - &info->sensor_data, - sizeof(struct imx132_sensordata))) { + &info->fuse_id, + sizeof(struct nvc_fuseid))) { dev_info(dev, "%s:Fail copy fuse id to user space\n", __func__); return -EFAULT; diff --git a/drivers/media/video/tegra/imx135.c b/drivers/media/video/tegra/imx135.c index efff02e05fd5..0e123fe6915d 100644 --- a/drivers/media/video/tegra/imx135.c +++ b/drivers/media/video/tegra/imx135.c @@ -40,7 +40,7 @@ struct imx135_info { struct miscdevice miscdev_info; int mode; struct imx135_power_rail power; - struct imx135_sensordata sensor_data; + struct nvc_fuseid fuse_id; struct i2c_client *i2c_client; struct imx135_platform_data *pdata; struct mutex imx135_camera_lock; @@ -2056,7 +2056,7 @@ static int imx135_get_sensor_id(struct imx135_info *info) u8 bak = 0; pr_info("%s\n", __func__); - if (info->sensor_data.fuse_id_size) + if (info->fuse_id.size) return 0; /* Note 1: If the sensor does not have power at this point @@ -2066,11 +2066,11 @@ static int imx135_get_sensor_id(struct imx135_info *info) ret |= imx135_write_reg(info->i2c_client, 0x3B00, 0x01); for (i = 0; i < 9 ; i++) { ret |= imx135_read_reg(info->i2c_client, 0x3B24 + i, &bak); - info->sensor_data.fuse_id[i] = bak; + info->fuse_id.data[i] = bak; } if (!ret) - info->sensor_data.fuse_id_size = i; + info->fuse_id.size = i; /* Note 2: Need to clean up any action carried out in Note 1 */ @@ -2123,7 +2123,7 @@ imx135_ioctl(struct file *file, } return 0; } - case IMX135_IOCTL_GET_SENSORDATA: + case IMX135_IOCTL_GET_FUSEID: { err = imx135_get_sensor_id(info); @@ -2131,8 +2131,8 @@ imx135_ioctl(struct file *file, pr_err("%s:Failed to get fuse id info.\n", __func__); return err; } - if (copy_to_user((void __user *)arg, &info->sensor_data, - sizeof(struct imx135_sensordata))) { + if (copy_to_user((void __user *)arg, &info->fuse_id, + sizeof(struct nvc_fuseid))) { pr_info("%s:Failed to copy fuse id to user space\n", __func__); return -EFAULT; diff --git a/drivers/media/video/tegra/ov2710.c b/drivers/media/video/tegra/ov2710.c index a0ad166bd36c..28c041befb3a 100644 --- a/drivers/media/video/tegra/ov2710.c +++ b/drivers/media/video/tegra/ov2710.c @@ -1,7 +1,7 @@ /* * ov2710.c - ov2710 sensor driver * - * Copyright (c) 2011, NVIDIA, All Rights Reserved. + * Copyright (c) 2011-2013, NVIDIA CORPORATION, All Rights Reserved. * * Contributors: * erik lilliebjerg <elilliebjerg@nvidia.com> @@ -22,6 +22,7 @@ #include <linux/module.h> #include <media/ov2710.h> +#include <media/nvc.h> #define SIZEOF_I2C_TRANSBUF 32 @@ -35,8 +36,15 @@ struct ov2710_info { struct i2c_client *i2c_client; struct ov2710_platform_data *pdata; u8 i2c_trans_buf[SIZEOF_I2C_TRANSBUF]; + struct nvc_fuseid fuse_id; }; +#define OV2710_FUSE_ID_SIZE 5 + +#define OV2710_FUSE_ID_PROGRAM_ENABLE 0 +#define OV2710_FUSE_ID_PROGRAM_TARGET (0x3d00 + 0) +#define OV2710_FUSE_ID_PROGRAM_VALUE 0x00 + #define OV2710_TABLE_WAIT_MS 0 #define OV2710_TABLE_END 1 #define OV2710_MAX_RETRIES 3 @@ -618,6 +626,55 @@ static int ov2710_get_status(struct ov2710_info *info, u8 *status) } +static int ov2710_get_fuse_id(struct ov2710_info *info) +{ + int err, i; + +#if OV2710_FUSE_ID_PROGRAM_ENABLE +/* Program the OTP fuse id memory on the sensor. + * NOTE: This cannot be reversed. + */ + err = ov2710_write_reg(info->i2c_client, 0x3d10, 0x00); + for (i = 0; i < 16; i++) + err = ov2710_write_reg(info->i2c_client, 0x3d00 + i, 0x00); + err = ov2710_write_reg(info->i2c_client, 0x3d10, 0x01); + msleep(20); + err = ov2710_write_reg(info->i2c_client, 0x3d10, 0x00); + msleep(20); + for (i = 0; i < 16; i++) + ov2710_read_reg(info->i2c_client, + 0x3d00 + i, + &(info->fuse_id.data[i])); + pr_info("ov2710: fuse id: program reg 0x%x to 0x%x\n", + OV2710_FUSE_ID_PROGRAM_TARGET, + OV2710_FUSE_ID_PROGRAM_VALUE); + err = ov2710_write_reg(info->i2c_client, + OV2710_FUSE_ID_PROGRAM_TARGET, + OV2710_FUSE_ID_PROGRAM_VALUE); + err = ov2710_write_reg(info->i2c_client, 0x3d10, 0x02); + msleep(20); + err = ov2710_write_reg(info->i2c_client, 0x3d10, 0x03); +#endif + + if (info->fuse_id.size) + return 0; + + err = ov2710_write_reg(info->i2c_client, 0x3d10, 0x01); + err = ov2710_write_reg(info->i2c_client, 0x3d10, 0x00); + + for (i = 0; i < OV2710_FUSE_ID_SIZE; i++) { + err |= ov2710_read_reg(info->i2c_client, + 0x3d00 + i, + &(info->fuse_id.data[i])); + } + + if (!err) + info->fuse_id.size = i; + + return err; +} + + static long ov2710_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -666,6 +723,22 @@ static long ov2710_ioctl(struct file *file, } return 0; } + case OV2710_IOCTL_GET_FUSEID: + { + err = ov2710_get_fuse_id(info); + if (err) { + pr_err("%s %d %d\n", __func__, __LINE__, err); + return err; + } + if (copy_to_user((void __user *)arg, + &info->fuse_id, + sizeof(struct nvc_fuseid))) { + pr_err("%s: %d: fail copy fuse id to user space\n", + __func__, __LINE__); + return -EFAULT; + } + return 0; + } default: return -EINVAL; } diff --git a/drivers/media/video/tegra/ov5650.c b/drivers/media/video/tegra/ov5650.c index 1ef23a403486..35cec0805936 100644 --- a/drivers/media/video/tegra/ov5650.c +++ b/drivers/media/video/tegra/ov5650.c @@ -2,6 +2,7 @@ * ov5650.c - ov5650 sensor driver * * Copyright (C) 2011 Google Inc. + * Copyright (c) 2013, NVIDIA CORPORATION. All Rights Reserved. * * Contributors: * Rebecca Schultz Zavin <rebecca@android.com> @@ -23,6 +24,7 @@ #include <media/ov5650.h> #include <video/tegra_camera.h> +#include <media/nvc.h> #define SIZEOF_I2C_TRANSBUF 32 @@ -41,7 +43,7 @@ struct ov5650_info { enum StereoCameraMode camera_mode; struct ov5650_sensor left; struct ov5650_sensor right; - struct ov5650_sensordata sensor_data; + struct nvc_fuseid fuse_id; struct mutex mutex_le; struct mutex mutex_ri; int power_refcnt_le; @@ -54,6 +56,7 @@ static struct ov5650_info *stereo_ov5650_info; #define OV5650_TABLE_WAIT_MS 0 #define OV5650_TABLE_END 1 #define OV5650_MAX_RETRIES 3 +#define OV5650_FUSE_ID_SIZE 5 static struct ov5650_reg tp_none_seq[] = { {0x5046, 0x00}, @@ -1293,27 +1296,27 @@ static int ov5650_set_power(struct ov5650_info *info, int powerLevel) return 0; } -static int ov5650_get_sensor_id(struct ov5650_info *info) +static int ov5650_get_fuseid(struct ov5650_info *info) { int ret = 0; int i; u8 bak; pr_info("%s\n", __func__); - if (info->sensor_data.fuse_id_size) + if (info->fuse_id.size) return 0; ov5650_set_power(info, 1); - for (i = 0; i < 5; i++) { + for (i = 0; i < OV5650_FUSE_ID_SIZE; i++) { ret |= ov5650_write_reg_helper(info, 0x3d00, i); ret |= ov5650_read_reg_helper(info, 0x3d04, &bak); - info->sensor_data.fuse_id[i] = bak; + info->fuse_id.data[i] = bak; } if (!ret) - info->sensor_data.fuse_id_size = i; + info->fuse_id.size = i; ov5650_set_power(info, 0); return ret; @@ -1393,17 +1396,18 @@ static long ov5650_ioctl(struct file *file, } return ov5650_set_group_hold(info, &ae); } - case OV5650_IOCTL_GET_SENSORDATA: + case OV5650_IOCTL_GET_FUSEID: { - err = ov5650_get_sensor_id(info); + err = ov5650_get_fuseid(info); if (err) { pr_err("%s %d %d\n", __func__, __LINE__, err); return err; } if (copy_to_user((void __user *)arg, - &info->sensor_data, - sizeof(struct ov5650_sensordata))) { - pr_info("%s %d\n", __func__, __LINE__); + &info->fuse_id, + sizeof(struct nvc_fuseid))) { + pr_err("%s: %d: fail copy fuse id to user space\n", + __func__, __LINE__); return -EFAULT; } return 0; diff --git a/drivers/media/video/tegra/ov9726.c b/drivers/media/video/tegra/ov9726.c index 129591b9af10..04a87a5c1f2a 100644 --- a/drivers/media/video/tegra/ov9726.c +++ b/drivers/media/video/tegra/ov9726.c @@ -1,7 +1,7 @@ /* * ov9726.c - ov9726 sensor driver * - * Copyright (c) 2011, NVIDIA, All Rights Reserved. + * Copyright (c) 2011-2013, NVIDIA CORPORATION, All Rights Reserved. * * Contributors: * Charlie Huang <chahuang@nvidia.com> @@ -25,6 +25,9 @@ #include <linux/module.h> #include <media/ov9726.h> +#include <media/nvc.h> + +#define OV9726_FUSE_ID_SIZE 5 struct ov9726_power_rail { struct regulator *sen_1v8_reg; @@ -39,6 +42,7 @@ struct ov9726_devinfo { atomic_t in_use; __u32 mode; struct ov9726_reg grphold_temp[10]; + struct nvc_fuseid fuse_id; }; static struct ov9726_reg mode_1280x720[] = { @@ -699,6 +703,34 @@ ov9726_set_mode_exit: return err; } +static int ov9726_get_fuse_id(struct ov9726_devinfo *dev) +{ + int ret, i; + __u8 bak; + struct i2c_client *i2c_client = dev->i2c_client; + + if (dev->fuse_id.size) + return 0; + + ret = ov9726_write_reg8(i2c_client, 0x3d21, 0x01); + + bak = 0x80; + while (bak & 0x80) + ret |= ov9726_read_reg8(i2c_client, 0x3d21, &bak); + + for (i = 0; i < OV9726_FUSE_ID_SIZE; i++) { + ret |= ov9726_read_reg8(i2c_client, + 0x3d00 + i, + &dev->fuse_id.data[i]); + } + ret = ov9726_write_reg8(i2c_client, 0x3d21, 0x00); + + if (!ret) + dev->fuse_id.size = i; + + return ret; +} + static long ov9726_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -754,6 +786,22 @@ ov9726_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } break; } + case OV9726_IOCTL_GET_FUSEID: + { + err = ov9726_get_fuse_id(dev); + if (err) { + pr_err("%s %d %d\n", __func__, __LINE__, err); + return err; + } + if (copy_to_user((void __user *)arg, + &dev->fuse_id, + sizeof(struct nvc_fuseid))) { + pr_err("%s: %d: fail copy fuse id to user space\n", + __func__, __LINE__); + return -EFAULT; + } + return 0; + } default: err = -EINVAL; break; diff --git a/drivers/media/video/tegra/ov9772.c b/drivers/media/video/tegra/ov9772.c index 1bdad09d1fd2..9b6041baed29 100644 --- a/drivers/media/video/tegra/ov9772.c +++ b/drivers/media/video/tegra/ov9772.c @@ -141,6 +141,7 @@ #include <linux/module.h> #include <media/ov9772.h> +#include <media/nvc.h> #define OV9772_ID 0x9772 #define OV9772_SENSOR_TYPE NVC_IMAGER_TYPE_RAW @@ -159,6 +160,7 @@ #define OV9772_LENS_VIEW_ANGLE_H 60000 /* / _INT2FLOAT_DIVISOR */ #define OV9772_LENS_VIEW_ANGLE_V 60000 /* / _INT2FLOAT_DIVISOR */ #define OV9772_I2C_TABLE_MAX_ENTRIES 400 +#define OV9772_FUSE_ID_SIZE 5 /* comment out definition to disable mode */ #define OV9772_ENABLE_1284x724 @@ -198,6 +200,7 @@ struct ov9772_info { struct nvc_imager_static_nvc sdata; u8 i2c_buf[OV9772_SIZEOF_I2C_BUF]; u8 bin_en; + struct nvc_fuseid fuse_id; }; struct ov9772_reg { @@ -1822,6 +1825,27 @@ static int ov9772_param_wr(struct ov9772_info *info, unsigned long arg) } } +static int ov9772_get_fuse_id(struct ov9772_info *info) +{ + int err, i; + + if (info->fuse_id.size) + return 0; + + err = ov9772_i2c_wr8(info, 0x3d81, 0x01); + + for (i = 0; i < OV9772_FUSE_ID_SIZE; i++) { + err |= ov9772_i2c_rd8(info, + 0x3d00 + i, + &info->fuse_id.data[i]); + } + + if (!err) + info->fuse_id.size = OV9772_FUSE_ID_SIZE; + + return err; +} + static long ov9772_ioctl(struct file *file, unsigned int cmd, unsigned long arg) @@ -1838,6 +1862,22 @@ static long ov9772_ioctl(struct file *file, int err; switch (cmd) { + case NVC_IOCTL_FUSE_ID: + err = ov9772_get_fuse_id(info); + if (err) { + pr_err("%s %d %d\n", __func__, __LINE__, err); + return err; + } + if (copy_to_user((void __user *)arg, + &info->fuse_id, + sizeof(struct nvc_fuseid))) { + pr_err("%s: %d: fail copy fuse id to user space\n", + __func__, __LINE__); + return -EFAULT; + } + + return 0; + case NVC_IOCTL_PARAM_WR: err = ov9772_param_wr(info, arg); return err; |