diff options
author | Frank Chen <frankc@nvidia.com> | 2011-04-06 18:44:36 -0700 |
---|---|---|
committer | Varun Colbert <vcolbert@nvidia.com> | 2011-04-15 18:34:49 -0700 |
commit | c20dd5116d966629a88536443121425b2655ef67 (patch) | |
tree | 2307bd90ebad75d24b25107253a8b5239b048902 | |
parent | 063b3c474383cb38a515e4460196bd8ed3946306 (diff) |
media: video: tegra: AD5820: Add AD5820 focuser driver.
Add AD5820 focuser driver for Whistler.
Bug 783488
Change-Id: I0d8a08e7df9f472ffc4edfe7bfa255357bff5126
Reviewed-on: http://git-master/r/26970
Reviewed-by: Varun Colbert <vcolbert@nvidia.com>
Tested-by: Varun Colbert <vcolbert@nvidia.com>
-rw-r--r-- | drivers/media/video/tegra/Kconfig | 6 | ||||
-rw-r--r-- | drivers/media/video/tegra/Makefile | 1 | ||||
-rw-r--r-- | drivers/media/video/tegra/ad5820.c | 215 | ||||
-rw-r--r-- | include/media/ad5820.h | 41 |
4 files changed, 263 insertions, 0 deletions
diff --git a/drivers/media/video/tegra/Kconfig b/drivers/media/video/tegra/Kconfig index 3d5467c26edf..fd1908ba781b 100644 --- a/drivers/media/video/tegra/Kconfig +++ b/drivers/media/video/tegra/Kconfig @@ -37,3 +37,9 @@ config VIDEO_SH532U This is a driver for the SEMCO SH532U focuser for use with the tegra isp. +config VIDEO_AD5820 + tristate "AD5820 focuser support" + depends on I2C && ARCH_TEGRA + ---help--- + This is a driver for the AD5820 focuser + for use with the tegra isp. diff --git a/drivers/media/video/tegra/Makefile b/drivers/media/video/tegra/Makefile index 45f77e00b155..60d2b5041974 100644 --- a/drivers/media/video/tegra/Makefile +++ b/drivers/media/video/tegra/Makefile @@ -8,5 +8,6 @@ obj-$(CONFIG_VIDEO_OV5650) += ov5650.o obj-$(CONFIG_VIDEO_OV2710) += ov2710.o obj-$(CONFIG_TORCH_SSL3250A) += ssl3250a.o obj-$(CONFIG_VIDEO_SH532U) += sh532u.o +obj-$(CONFIG_VIDEO_AD5820) += ad5820.o diff --git a/drivers/media/video/tegra/ad5820.c b/drivers/media/video/tegra/ad5820.c new file mode 100644 index 000000000000..365c0869dc86 --- /dev/null +++ b/drivers/media/video/tegra/ad5820.c @@ -0,0 +1,215 @@ +/* + * AD5820 focuser driver. + * + * Copyright (C) 2010-2011 NVIDIA Corporation. + * + * Contributors: + * Sachin Nikam <snikam@nvidia.com> + * + * Based on ov5650.c. + * + * 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 + * kind, whether express or implied. + */ + +#include <linux/delay.h> +#include <linux/fs.h> +#include <linux/i2c.h> +#include <linux/miscdevice.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <media/ad5820.h> + +#define POS_LOW (144) +#define POS_HIGH (520) +#define SETTLETIME_MS 100 +#define FOCAL_LENGTH (4.507f) +#define FNUMBER (2.8f) +#define FPOS_COUNT 1024 + +#define AD5820_MAX_RETRIES (3) + +struct ad5820_info { + struct i2c_client *i2c_client; + struct regulator *regulator; + struct ad5820_config config; +}; + +static int ad5820_write(struct i2c_client *client, u16 value) +{ + int count; + struct i2c_msg msg[1]; + unsigned char data[2]; + int retry = 0; + + if (!client->adapter) + return -ENODEV; + + data[1] = (u8) ((value >> 4) & 0x3F); + data[0] = (u8) ((value & 0xF) << 4); + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = ARRAY_SIZE(data); + msg[0].buf = data; + + do { + count = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + if (count == ARRAY_SIZE(msg)) + return 0; + retry++; + pr_err("ad5820: i2c transfer failed, retrying %x\n", + value); + msleep(3); + } while (retry <= AD5820_MAX_RETRIES); + return -EIO; +} + +static int ad5820_set_position(struct ad5820_info *info, u32 position) +{ + if (position < info->config.pos_low || + position > info->config.pos_high) + return -EINVAL; + + return ad5820_write(info->i2c_client, position); +} + +static long ad5820_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct ad5820_info *info = file->private_data; + + switch (cmd) { + case AD5820_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 AD5820_IOCTL_SET_POSITION: + return ad5820_set_position(info, (u32) arg); + default: + return -EINVAL; + } + + return 0; +} + +struct ad5820_info *info; + +static int ad5820_open(struct inode *inode, struct file *file) +{ + file->private_data = info; + if (info->regulator) + regulator_enable(info->regulator); + return 0; +} + +int ad5820_release(struct inode *inode, struct file *file) +{ + if (info->regulator) + regulator_disable(info->regulator); + file->private_data = NULL; + return 0; +} + + +static const struct file_operations ad5820_fileops = { + .owner = THIS_MODULE, + .open = ad5820_open, + .unlocked_ioctl = ad5820_ioctl, + .release = ad5820_release, +}; + +static struct miscdevice ad5820_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "ad5820", + .fops = &ad5820_fileops, +}; + +static int ad5820_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int err; + + pr_info("ad5820: probing sensor.\n"); + + info = kzalloc(sizeof(struct ad5820_info), GFP_KERNEL); + if (!info) { + pr_err("ad5820: Unable to allocate memory!\n"); + return -ENOMEM; + } + + err = misc_register(&ad5820_device); + if (err) { + pr_err("ad5820: Unable to register misc device!\n"); + kfree(info); + return err; + } + + info->regulator = regulator_get(&client->dev, "vdd_vcore_af"); + if (IS_ERR_OR_NULL(info->regulator)) { + dev_err(&client->dev, "unable to get regulator %s\n", + dev_name(&client->dev)); + info->regulator = NULL; + } else { + regulator_enable(info->regulator); + } + + 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; + i2c_set_clientdata(client, info); + return 0; +} + +static int ad5820_remove(struct i2c_client *client) +{ + struct ad5820_info *info; + info = i2c_get_clientdata(client); + misc_deregister(&ad5820_device); + kfree(info); + return 0; +} + +static const struct i2c_device_id ad5820_id[] = { + { "ad5820", 0 }, + { }, +}; + +MODULE_DEVICE_TABLE(i2c, ad5820_id); + +static struct i2c_driver ad5820_i2c_driver = { + .driver = { + .name = "ad5820", + .owner = THIS_MODULE, + }, + .probe = ad5820_probe, + .remove = ad5820_remove, + .id_table = ad5820_id, +}; + +static int __init ad5820_init(void) +{ + pr_info("ad5820 sensor driver loading\n"); + return i2c_add_driver(&ad5820_i2c_driver); +} + +static void __exit ad5820_exit(void) +{ + i2c_del_driver(&ad5820_i2c_driver); +} + +module_init(ad5820_init); +module_exit(ad5820_exit); + diff --git a/include/media/ad5820.h b/include/media/ad5820.h new file mode 100644 index 000000000000..c3e710113402 --- /dev/null +++ b/include/media/ad5820.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2010-2011 NVIDIA Corporation. + * + * Contributors: + * Sachin Nikam <snikam@nvidia.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA + */ + +#ifndef __AD5820_H__ +#define __AD5820_H__ + +#include <linux/ioctl.h> /* For IOCTL macros */ + +#define AD5820_IOCTL_GET_CONFIG _IOR('o', 1, struct ad5820_config) +#define AD5820_IOCTL_SET_POSITION _IOW('o', 2, u32) + +struct ad5820_config { + __u32 settle_time; + __u32 actuator_range; + __u32 pos_low; + __u32 pos_high; + float focal_length; + float fnumber; + float max_aperture; +}; + +#endif /* __AD5820_H__ */ + |