From: Andrei Warkentin Date: Fri, 3 Sep 2010 01:26:33 +0000 (-0700) Subject: media: video: tegra: Add dw9714l focuser driver X-Git-Tag: firefly_0821_release~9834^2~602 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=c063995751537bc9f4d93be85c0f55fd2e3381f4;p=firefly-linux-kernel-4.4.55.git media: video: tegra: Add dw9714l focuser driver Change-Id: I4e3c690c782ea25c50fec25bf6252acd32a64242 Signed-off-by: Rebecca Schultz Zavin --- diff --git a/drivers/media/video/tegra/Kconfig b/drivers/media/video/tegra/Kconfig index b2926322b7f8..6c3972c1365b 100644 --- a/drivers/media/video/tegra/Kconfig +++ b/drivers/media/video/tegra/Kconfig @@ -12,3 +12,9 @@ config VIDEO_SOC2030 This is a driver for the SOC2030 2MP camera sensor for use with the tegra isp. +config VIDEO_DW9714L + tristate "DW9714L focuser support" + depends on I2C && ARCH_TEGRA + ---help--- + This is a driver for the the dw9714l focuser. + diff --git a/drivers/media/video/tegra/Makefile b/drivers/media/video/tegra/Makefile index 7709f16f2269..2c80cff939a1 100644 --- a/drivers/media/video/tegra/Makefile +++ b/drivers/media/video/tegra/Makefile @@ -4,3 +4,4 @@ obj-y += tegra_camera.o obj-$(CONFIG_VIDEO_OV5650) += ov5650.o obj-$(CONFIG_VIDEO_SOC2030) += soc2030.o +obj-$(CONFIG_VIDEO_DW9714L) += dw9714l.o \ No newline at end of file diff --git a/drivers/media/video/tegra/dw9714l.c b/drivers/media/video/tegra/dw9714l.c new file mode 100644 index 000000000000..7ac4f3c13fa8 --- /dev/null +++ b/drivers/media/video/tegra/dw9714l.c @@ -0,0 +1,213 @@ +/* + * DW9714L focuser driver. + * + * Copyright (C) 2010 Motorola Inc. + * + * Contributors: + * Andrei Warkentin + * + * 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 +#include +#include +#include +#include +#include +#include + +#define DW9714L_MAX_RETRIES (3) + +#define POS_PER_STEP (3) + +struct dw9714l_info { + struct i2c_client *i2c_client; + struct regulator *regulator; +}; + +static int dw9714l_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[0] = (u8) (value >> 8); + data[1] = (u8) (value & 0xFF); + + 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("dw9714l: i2c transfer failed, retrying %x\n", + value); + msleep(3); + } while (retry <= DW9714L_MAX_RETRIES); + return -EIO; +} + +static int dw9714l_set_position(struct dw9714l_info *info, u32 position) +{ + int ret; + + /* Protection off. */ + ret = dw9714l_write(info->i2c_client, 0xECA3); + if (ret) + return ret; + + ret = dw9714l_write(info->i2c_client, 0xF200 | (0x0F << 3)); + if (ret) + return ret; + + /* Protection on. */ + ret = dw9714l_write(info->i2c_client, 0xDC51); + if (ret) + return ret; + + ret = dw9714l_write(info->i2c_client, + (position << 4) | + (POS_PER_STEP << 2)); + if (ret) + return ret; + + return 0; +} + +static int dw9714l_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct dw9714l_info *info = file->private_data; + + switch (cmd) { + case DW9714L_IOCTL_SET_POSITION: + return dw9714l_set_position(info, (u32) arg); + default: + return -EINVAL; + } + return 0; +} + +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); + return 0; +} + +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; + return 0; +} + + +static const struct file_operations dw9714l_fileops = { + .owner = THIS_MODULE, + .open = dw9714l_open, + .ioctl = dw9714l_ioctl, + .release = dw9714l_release, +}; + +static struct miscdevice dw9714l_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "dw9714l", + .fops = &dw9714l_fileops, +}; + +static int dw9714l_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int err; + + pr_info("dw9714l: probing sensor.\n"); + + info = kzalloc(sizeof(struct dw9714l_info), GFP_KERNEL); + if (!info) { + pr_err("dw9714l: Unable to allocate memory!\n"); + return -ENOMEM; + } + + err = misc_register(&dw9714l_device); + if (err) { + pr_err("dw9714l: Unable to register misc device!\n"); + kfree(info); + return err; + } + + info->regulator = regulator_get(&client->dev, "vcc"); + 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; + i2c_set_clientdata(client, info); + return 0; +} + +static int dw9714l_remove(struct i2c_client *client) +{ + struct dw9714l_info *info; + info = i2c_get_clientdata(client); + misc_deregister(&dw9714l_device); + kfree(info); + return 0; +} + +static const struct i2c_device_id dw9714l_id[] = { + { "dw9714l", 0 }, + { }, +}; + +MODULE_DEVICE_TABLE(i2c, dw9714l_id); + +static struct i2c_driver dw9714l_i2c_driver = { + .driver = { + .name = "dw9714l", + .owner = THIS_MODULE, + }, + .probe = dw9714l_probe, + .remove = dw9714l_remove, + .id_table = dw9714l_id, +}; + +static int __init dw9714l_init(void) +{ + pr_info("dw9714l sensor driver loading\n"); + return i2c_add_driver(&dw9714l_i2c_driver); +} + +static void __exit dw9714l_exit(void) +{ + i2c_del_driver(&dw9714l_i2c_driver); +} + +module_init(dw9714l_init); +module_exit(dw9714l_exit); + diff --git a/include/media/dw9714l.h b/include/media/dw9714l.h new file mode 100644 index 000000000000..3d91140dd37f --- /dev/null +++ b/include/media/dw9714l.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2010 Motorola, Inc. + * + * Contributors: + * Andrei Warkentin + * + * 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 __DW9714L_H__ +#define __DW9714L_H__ + +#include /* For IOCTL macros */ + +#define DW9714L_IOCTL_SET_POSITION _IOW('o', 1, u32) + +#endif /* __DW9714L_H__ */ +