summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorJihoon Bang <jbang@nvidia.com>2011-06-24 10:05:32 -0700
committerVarun Colbert <vcolbert@nvidia.com>2011-07-15 10:39:06 -0700
commit21e4505d8515ce7a952bc66c4923fcf31d23c742 (patch)
tree6a241213d80401d534a62ff3770c47da83a11490 /drivers
parentb03316f4f00d70d9cc18376252ccc9f62a768019 (diff)
media: video: tegra: support multiple cameras
Separate board specific sequence from ar0832 driver and add it to board files. Add function that changes device slave address in real time to support multiple devices in the same I2C bus. Bug 844021 Change-Id: I48641909eb531b4ba827096bc30fa4eccf83469e Reviewed-on: http://git-master/r/40385 Reviewed-by: Daniel Willemsen <dwillemsen@nvidia.com> Reviewed-by: Jihoon Bang <jbang@nvidia.com> Tested-by: Jihoon Bang <jbang@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/video/tegra/ar0832_main.c270
1 files changed, 218 insertions, 52 deletions
diff --git a/drivers/media/video/tegra/ar0832_main.c b/drivers/media/video/tegra/ar0832_main.c
index e4a144ac250b..1fb93158dbb2 100644
--- a/drivers/media/video/tegra/ar0832_main.c
+++ b/drivers/media/video/tegra/ar0832_main.c
@@ -18,11 +18,9 @@
#include <mach/hardware.h>
#include <linux/gpio.h>
#include <asm/atomic.h>
-
+#include <linux/regulator/consumer.h>
#include <media/ar0832_main.h>
-#define USE_I2C_DATA_2BYTES
-
#define POS_LOW 50
#define POS_HIGH 1000
#define SETTLETIME_MS 100
@@ -37,6 +35,11 @@ struct ar0832_focuser_info {
int focuser_init_flag;
};
+struct ar0832_power_rail {
+ struct regulator *sen_1v8_reg;
+ struct regulator *sen_2v8_reg;
+};
+
struct ar0832_dev {
struct ar0832_sensor_info *sensor_info;
struct ar0832_focuser_info *focuser_info;
@@ -44,7 +47,10 @@ struct ar0832_dev {
struct i2c_client *i2c_client;
struct mutex ar0832_camera_lock;
struct miscdevice misc_dev;
+ struct ar0832_power_rail power_rail;
atomic_t in_use;
+ char dname[20];
+ int is_stereo;
};
/* stereo */
@@ -57,7 +63,23 @@ static u16 DefaultImageHeight = 680;
#define ar0832_TABLE_END 1
#define ar0832_MAX_RETRIES 3
-#define USE_DIGITAL_GAIN 0
+#define AR0832_RESET_REG 0x301A
+#define AR0832_ID_REG 0x31FC
+
+/* AR0832_RESET_REG */
+#define AR0832_RESET_REG_GROUPED_PARAMETER_HOLD (1 << 15)
+#define AR0832_RESET_REG_GAIN_INSERT (1 << 14)
+#define AR0832_RESET_REG_SMIA_SERIALIZER_DIS (1 << 12)
+#define AR0832_RESET_REG_RESTART_BAD (1 << 10)
+#define AR0832_RESET_REG_MASK_BAD (1 << 9)
+#define AR0832_RESET_REG_GPI_EN (1 << 8)
+#define AR0832_RESET_REG_PARALLEL_EN (1 << 7)
+#define AR0832_RESET_REG_DRIVE_PINS (1 << 6)
+#define AR0832_RESET_REG_STDBY_EOF (1 << 4)
+#define AR0832_RESET_REG_LOCK_REG (1 << 3)
+#define AR0832_RESET_REG_STREAM (1 << 2)
+#define AR0832_RESET_REG_RESTART (1 << 1)
+#define AR0832_RESET_REG_RESET (1 << 0)
static struct ar0832_reg mode_start[] = {
{ar0832_TABLE_END, 0x0000}
@@ -568,6 +590,8 @@ static int ar0832_write_reg8(struct i2c_client *client, u16 addr, u8 val)
msg.len = 3;
msg.buf = data;
+ dev_dbg(&client->dev, "0x%x = 0x%x\n", addr, val);
+
do {
err = i2c_transfer(client->adapter, &msg, 1);
if (err > 0)
@@ -602,6 +626,8 @@ static int ar0832_write_reg16(struct i2c_client *client, u16 addr, u16 val)
msg.len = 4;
msg.buf = data;
+ dev_dbg(&client->dev, "0x%x = 0x%x\n", addr, val);
+
do {
count = i2c_transfer(client->adapter, &msg, 1);
if (count == 1)
@@ -616,6 +642,34 @@ static int ar0832_write_reg16(struct i2c_client *client, u16 addr, u16 val)
return -EIO;
}
+static int ar0832_read_reg16(struct i2c_client *client, u16 addr, u16 *val)
+{
+ struct i2c_msg msg[2];
+ u8 data[4];
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 2;
+ msg[0].buf = data;
+ data[0] = (addr >> 8);
+ data[1] = (addr & 0xff);
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = 2;
+ msg[1].buf = data + 2;
+
+ if (i2c_transfer(client->adapter, msg, 2) == 2) {
+ *val = ((data[2] << 8) | data[3]);
+ dev_dbg(&client->dev, "0x%x = 0x%x\n", addr, *val);
+ return 0;
+ } else {
+ *val = 0;
+ dev_err(&client->dev,
+ "%s: i2c read failed.\n", __func__);
+ return -1;
+ }
+}
+
static int ar0832_write_reg_helper(struct ar0832_dev *dev,
u16 addr,
u16 val)
@@ -658,7 +712,7 @@ static int ar0832_set_frame_length(struct ar0832_dev *dev,
struct i2c_client *i2c_client = dev->i2c_client;
int ret;
- dev_info(&i2c_client->dev, "[%s] (0x%08x)\n", __func__, frame_length);
+ dev_dbg(&i2c_client->dev, "[%s] (0x%08x)\n", __func__, frame_length);
ar0832_get_frame_length_regs(&reg_list, frame_length);
ret = ar0832_write_reg8(i2c_client, 0x0104, 0x1);
@@ -684,7 +738,7 @@ static int ar0832_set_coarse_time(struct ar0832_dev *dev,
struct ar0832_reg reg_list;
struct i2c_client *i2c_client = dev->i2c_client;
- dev_info(&i2c_client->dev, "[%s] (0x%08x)\n", __func__, coarse_time);
+ dev_dbg(&i2c_client->dev, "[%s] (0x%08x)\n", __func__, coarse_time);
ar0832_get_coarse_time_regs(&reg_list, coarse_time);
ret = ar0832_write_reg8(i2c_client, 0x0104, 0x1);
@@ -721,6 +775,8 @@ static int ar0832_set_gain(struct ar0832_dev *dev, __u16 gain)
}
/* Gain register End */
ret |= ar0832_write_reg8(dev->i2c_client, 0x0104, 0x0);
+
+ return ret;
}
static int ar0832_set_mode(struct ar0832_dev *dev,
@@ -732,6 +788,8 @@ static int ar0832_set_mode(struct ar0832_dev *dev,
struct i2c_client *i2c_client = dev->i2c_client;
struct ar0832_reg reg_frame_length, reg_coarse_time;
+ dev_info(&i2c_client->dev, "%s: ++\n", __func__);
+
if (mode->xres == 3264 && mode->yres == 2448)
sensor_mode = ar0832_MODE_3264X2448;
else if (mode->xres == 2880 && mode->yres == 1620)
@@ -777,7 +835,8 @@ static int ar0832_set_mode(struct ar0832_dev *dev,
return err;
dev->sensor_info->mode = sensor_mode;
- dev_info(&i2c_client->dev, "%s: end\n", __func__);
+ dev_dbg(&i2c_client->dev, "%s: --\n", __func__);
+
return 0;
}
@@ -791,7 +850,7 @@ static int ar0832_get_status(struct ar0832_dev *dev, u8 *status)
/*
err = ar0832_read_reg(dev->i2c_client, 0x001, status);
*/
- dev_info(&i2c_client->dev, "%s: %u %d\n", __func__, *status, err);
+ dev_dbg(&i2c_client->dev, "%s: %u %d\n", __func__, *status, err);
return err;
}
@@ -802,7 +861,7 @@ static int ar0832_set_region(struct ar0832_dev *dev,
u16 image_height = region->image_end.y - region->image_start.y+1;
struct i2c_client *i2c_client = dev->i2c_client;
- dev_info(&i2c_client->dev, "%s: %d\n", __func__, region->camera_index);
+ dev_dbg(&i2c_client->dev, "%s: %d\n", __func__, region->camera_index);
if (region->camera_index == 0)
i2c_client = dev->i2c_client;
#if 0
@@ -811,7 +870,7 @@ static int ar0832_set_region(struct ar0832_dev *dev,
#endif
else
return -1;
- dev_info(&i2c_client->dev, "%s: width = %d height = %d\n",
+ dev_dbg(&i2c_client->dev, "%s: width = %d height = %d\n",
__func__, image_width, image_height);
#if 0
ar0832_write_reg(i2c_client, 0x0104, 1);
@@ -855,20 +914,85 @@ static int ar0832_set_region(struct ar0832_dev *dev,
return 0;
}
+static int ar0832_set_alternate_addr(struct i2c_client *client)
+{
+ int ret = 0;
+ u8 new_addr = client->addr;
+ u16 val;
+
+ /* Default slave address of ar0832 is 0x36 */
+ client->addr = 0x36;
+ ret = ar0832_read_reg16(client, AR0832_RESET_REG, &val);
+ val &= ~AR0832_RESET_REG_LOCK_REG;
+ ret |= ar0832_write_reg16(client, AR0832_RESET_REG, val);
+ ret |= ar0832_write_reg16(client, AR0832_ID_REG, new_addr << 1);
+
+ if (!ret) {
+ client->addr = new_addr;
+ dev_info(&client->dev,
+ "new slave address is set to 0x%x\n", new_addr);
+ }
+
+ ret |= ar0832_read_reg16(client, AR0832_RESET_REG, &val);
+ val |= AR0832_RESET_REG_LOCK_REG;
+ ret |= ar0832_write_reg16(client, AR0832_RESET_REG, val);
+
+ return ret;
+}
+
static int ar0832_power_on(struct ar0832_dev *dev)
{
struct i2c_client *i2c_client = dev->i2c_client;
+ int ret = 0;
+
+ dev_info(&i2c_client->dev, "%s: ++ %d\n", __func__, dev->is_stereo);
+
+ /* Plug 1.8V and 2.8V power to sensor */
+ if (dev->power_rail.sen_1v8_reg) {
+ ret = regulator_enable(dev->power_rail.sen_1v8_reg);
+ if (ret) {
+ dev_err(&i2c_client->dev, "%s: failed to enable vdd\n",
+ __func__);
+ goto fail_regulator_1v8_reg;
+ }
+ }
+
+ ar0832_msleep(20);
+
+ if (dev->power_rail.sen_2v8_reg) {
+ ret = regulator_enable(dev->power_rail.sen_2v8_reg);
+ if (ret) {
+ dev_err(&i2c_client->dev, "%s: failed to enable vaa\n",
+ __func__);
+ goto fail_regulator_2v8_reg;
+ }
+ }
+
+ /* Board specific power-on sequence */
+ dev->pdata->power_on(dev->is_stereo);
+
+ /* Change slave address */
+ if (i2c_client->addr)
+ ret = ar0832_set_alternate_addr(i2c_client);
- dev_info(&i2c_client->dev, "%s: ++\n", __func__);
- dev->pdata->power_on();
return 0;
+
+fail_regulator_2v8_reg:
+ regulator_put(dev->power_rail.sen_2v8_reg);
+ dev->power_rail.sen_2v8_reg = NULL;
+ regulator_disable(dev->power_rail.sen_1v8_reg);
+fail_regulator_1v8_reg:
+ regulator_put(dev->power_rail.sen_1v8_reg);
+ dev->power_rail.sen_1v8_reg = NULL;
+ return ret;
}
static int ar0832_focuser_set_config(struct ar0832_dev *dev)
{
struct ar0832_reg reg_vcm_ctrl, reg_vcm_step_time;
- int ret;
+ int ret = 0;
u8 vcm_slew = 1;
+
/* bit15(0x80) means that VCM driver enable bit. */
/* bit3(0x08) means that keep VCM(AF position) */
/* while sensor is in soft standby mode during mode transitions. */
@@ -885,16 +1009,13 @@ static int ar0832_focuser_set_config(struct ar0832_dev *dev)
vcm_step_time);
ret = ar0832_write_reg16(dev->i2c_client, reg_vcm_step_time.addr,
reg_vcm_step_time.val);
- if (ret)
- return ret;
-
- return 0;
+ return ret;
}
static int ar0832_focuser_set_position(struct ar0832_dev *dev,
u32 position)
{
- int ret;
+ int ret = 0;
struct ar0832_reg reg_data;
if (position < dev->focuser_info->config.pos_low ||
@@ -904,9 +1025,7 @@ static int ar0832_focuser_set_position(struct ar0832_dev *dev,
ar0832_get_focuser_data_regs(&reg_data, position);
ret = ar0832_write_reg16(dev->i2c_client, reg_data.addr,
reg_data.val);
- if (ret)
- return ret;
- return 0;
+ return ret;
}
static long ar0832_ioctl(struct file *file,
@@ -915,15 +1034,24 @@ static long ar0832_ioctl(struct file *file,
int err;
struct ar0832_dev *dev = file->private_data;
struct i2c_client *i2c_client = dev->i2c_client;
+ struct ar0832_mode mode;
switch (cmd) {
case AR0832_IOCTL_SET_POWER_ON:
- dev_info(&i2c_client->dev, "AR0832_IOCTL_SET_POWER_ON\n");
+ dev_dbg(&i2c_client->dev, "AR0832_IOCTL_SET_POWER_ON\n");
+ if (copy_from_user(&mode,
+ (const void __user *)arg,
+ sizeof(struct ar0832_mode))) {
+ dev_err(&i2c_client->dev,
+ "%s: AR0832_IOCTL_SET_POWER_ON failed\n",
+ __func__);
+ return -EFAULT;
+ }
+ dev->is_stereo = mode.stereo;
return ar0832_power_on(dev);
case AR0832_IOCTL_SET_MODE:
{
- struct ar0832_mode mode;
- dev_info(&i2c_client->dev, "AR0832_IOCTL_SET_MODE\n");
+ dev_dbg(&i2c_client->dev, "AR0832_IOCTL_SET_MODE\n");
if (copy_from_user(&mode,
(const void __user *)arg,
sizeof(struct ar0832_mode))) {
@@ -952,16 +1080,14 @@ static long ar0832_ioctl(struct file *file,
mutex_unlock(&dev->ar0832_camera_lock);
return err;
case AR0832_IOCTL_SET_GAIN:
- {
mutex_lock(&dev->ar0832_camera_lock);
err = ar0832_set_gain(dev, (u16)arg);
mutex_unlock(&dev->ar0832_camera_lock);
return err;
- }
case AR0832_IOCTL_GET_STATUS:
{
u8 status;
- dev_info(&i2c_client->dev, "AR0832_IOCTL_GET_STATUS\n");
+ dev_dbg(&i2c_client->dev, "AR0832_IOCTL_GET_STATUS\n");
err = ar0832_get_status(dev, &status);
if (err)
return err;
@@ -977,7 +1103,7 @@ static long ar0832_ioctl(struct file *file,
case AR0832_IOCTL_SET_SENSOR_REGION:
{
struct ar0832_stereo_region region;
- dev_info(&i2c_client->dev, "AR0832_IOCTL_SET_SENSOR_REGION\n");
+ dev_dbg(&i2c_client->dev, "AR0832_IOCTL_SET_SENSOR_REGION\n");
if (copy_from_user(&region,
(const void __user *)arg,
sizeof(struct ar0832_stereo_region))) {
@@ -986,12 +1112,12 @@ static long ar0832_ioctl(struct file *file,
__func__);
return -EFAULT;
}
+ err = ar0832_set_region(dev, &region);
return err;
}
case AR0832_FOCUSER_IOCTL_GET_CONFIG:
- {
- dev_info(&i2c_client->dev,
+ dev_dbg(&i2c_client->dev,
"%s AR0832_FOCUSER_IOCTL_GET_CONFIG\n", __func__);
if (copy_to_user((void __user *) arg,
&dev->focuser_info->config,
@@ -1002,16 +1128,17 @@ static long ar0832_ioctl(struct file *file,
return -EFAULT;
}
return 0;
- }
+
case AR0832_FOCUSER_IOCTL_SET_POSITION:
- dev_info(&i2c_client->dev,
+ dev_dbg(&i2c_client->dev,
"%s AR0832_FOCUSER_IOCTL_SET_POSITION\n", __func__);
mutex_lock(&dev->ar0832_camera_lock);
err = ar0832_focuser_set_position(dev, (u32)arg);
mutex_unlock(&dev->ar0832_camera_lock);
return err;
+
default:
- dev_info(&i2c_client->dev, "(error) %s NONE IOCTL\n",
+ dev_err(&i2c_client->dev, "(error) %s NONE IOCTL\n",
__func__);
return -EINVAL;
}
@@ -1039,7 +1166,16 @@ static int ar0832_release(struct inode *inode, struct file *file)
struct i2c_client *i2c_client = dev->i2c_client;
dev_info(&i2c_client->dev, "%s: ++\n", __func__);
- dev->pdata->power_off();
+
+ /* Unplug 1.8V and 2.8V power from sensor */
+ if (dev->power_rail.sen_2v8_reg)
+ regulator_disable(dev->power_rail.sen_2v8_reg);
+ if (dev->power_rail.sen_1v8_reg)
+ regulator_disable(dev->power_rail.sen_1v8_reg);
+
+ /* Board specific power-down sequence */
+ dev->pdata->power_off(dev->is_stereo);
+
file->private_data = NULL;
WARN_ON(!atomic_xchg(&dev->in_use, 0));
@@ -1058,34 +1194,24 @@ static int ar0832_probe(struct i2c_client *client,
{
int err;
struct ar0832_dev *dev = NULL;
+ int ret;
dev_info(&client->dev, "ar0832: probing sensor.(id:%s)\n",
id->name);
dev = kzalloc(sizeof(struct ar0832_dev), GFP_KERNEL);
if (!dev)
- goto fail_ar0832_probe;
+ goto probe_fail_release;
dev->sensor_info = kzalloc(sizeof(struct ar0832_sensor_info),
GFP_KERNEL);
if (!dev->sensor_info)
- goto fail_ar0832_probe;
+ goto probe_fail_release;
dev->focuser_info = kzalloc(sizeof(struct ar0832_focuser_info),
GFP_KERNEL);
if (!dev->focuser_info)
- goto fail_ar0832_probe;
-
- dev->misc_dev.minor = MISC_DYNAMIC_MINOR;
- dev->misc_dev.name = "ar0832";
- dev->misc_dev.fops = &ar0832_fileops;
- dev->misc_dev.mode = S_IRWXUGO;
- dev->misc_dev.parent = &client->dev;
- err = misc_register(&dev->misc_dev);
- if (err) {
- dev_err(&client->dev, "Unable to register misc device!\n");
- goto fail_ar0832_misc_reg;
- }
+ goto probe_fail_release;
/* sensor */
dev->pdata = client->dev.platform_data;
@@ -1096,25 +1222,64 @@ static int ar0832_probe(struct i2c_client *client,
dev->focuser_info->config.pos_low = POS_LOW;
dev->focuser_info->config.pos_high = POS_HIGH;
+ snprintf(dev->dname, sizeof(dev->dname), "%s-%s",
+ id->name, dev->pdata->id);
+ dev->misc_dev.minor = MISC_DYNAMIC_MINOR;
+ dev->misc_dev.name = dev->dname;
+ dev->misc_dev.fops = &ar0832_fileops;
+ dev->misc_dev.mode = S_IRWXUGO;
+ dev->misc_dev.parent = &client->dev;
+ err = misc_register(&dev->misc_dev);
+ if (err) {
+ dev_err(&client->dev, "Unable to register misc device!\n");
+ ret = -ENOMEM;
+ goto probe_fail_free;
+ }
+
i2c_set_clientdata(client, dev);
mutex_init(&dev->ar0832_camera_lock);
+
+ dev->power_rail.sen_1v8_reg = regulator_get(&client->dev, "vdd");
+ if (IS_ERR_OR_NULL(dev->power_rail.sen_1v8_reg)) {
+ dev_err(&client->dev, "%s: failed to get vdd\n",
+ __func__);
+ ret = PTR_ERR(dev->power_rail.sen_1v8_reg);
+ goto probe_fail_free;
+ }
+
+ dev->power_rail.sen_2v8_reg = regulator_get(&client->dev, "vaa");
+ if (IS_ERR_OR_NULL(dev->power_rail.sen_2v8_reg)) {
+ dev_err(&client->dev, "%s: failed to get vaa\n",
+ __func__);
+ ret = PTR_ERR(dev->power_rail.sen_2v8_reg);
+ regulator_put(dev->power_rail.sen_1v8_reg);
+ dev->power_rail.sen_1v8_reg = NULL;
+ goto probe_fail_free;
+ }
+
return 0;
-fail_ar0832_probe:
- dev_err(&client->dev, "%s: Unable to allocate memory!\n", __func__);
-fail_ar0832_misc_reg:
+probe_fail_release:
+ dev_err(&client->dev, "%s: unable to allocate memory!\n", __func__);
+ ret = -ENOMEM;
+probe_fail_free:
if (dev) {
kfree(dev->focuser_info);
kfree(dev->sensor_info);
}
kfree(dev);
- return -ENOMEM;
+ return ret;
}
static int ar0832_remove(struct i2c_client *client)
{
struct ar0832_dev *dev = i2c_get_clientdata(client);
+ if (dev->power_rail.sen_1v8_reg)
+ regulator_put(dev->power_rail.sen_1v8_reg);
+ if (dev->power_rail.sen_2v8_reg)
+ regulator_put(dev->power_rail.sen_2v8_reg);
+
misc_deregister(&dev->misc_dev);
if (dev) {
kfree(dev->sensor_info);
@@ -1126,6 +1291,7 @@ static int ar0832_remove(struct i2c_client *client)
static const struct i2c_device_id ar0832_id[] = {
{ "ar0832", 0 },
+ { }
};
static struct i2c_driver ar0832_i2c_driver = {