/* * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define SIZEOF_I2C_TRANSBUF 128 #define OV7695_TABLE_START 0x01 #define OV7695_TABLE_END 0x02 #define OV7695_WAIT_MS 0xFFFF struct ov7695_reg { u16 addr; u16 val; }; static struct ov7695_reg mode_640x480_30fps[] = { {OV7695_TABLE_START, 0x01}, {0x0100, 0x00}, {OV7695_WAIT_MS, 0x0a}, {0x0103, 0x01}, {0x3620, 0x2f}, {0x3623, 0x12}, {0x3718, 0x88}, {0x3703, 0x80}, {0x3712, 0x40}, {0x3706, 0x40}, {0x3631, 0x44}, {0x3632, 0x05}, {0x3013, 0xd0}, {0x3705, 0x1d}, {0x3713, 0x0e}, {0x3012, 0x0a}, {0x3717, 0x18}, {0x3621, 0x47}, {0x0309, 0x24}, {0x4803, 0x08}, {0x0101, 0x02}, {0x3002, 0x09}, {0x3024, 0x00}, {0x3630, 0x69}, {0x5090, 0x00}, {0x3820, 0x90}, {0x4500, 0x24}, {0x4008, 0x02}, {0x4009, 0x09}, {0x3811, 0x07}, {0x3813, 0x06}, /* YUV order 0x4300 * 3F : YUYV(default) * 33 : YVYU * 31 : VYUY * 30 : UYVY */ {0x4300, 0x30}, {0x5000, 0xff}, {0x5001, 0x3f}, {0x5002, 0x48}, {0x5910, 0x00}, {0x3a0f, 0x38}, {0x3a10, 0x30}, {0x3a1b, 0x3a}, {0x3a1e, 0x2e}, {0x3a11, 0x90}, {0x3a1f, 0x12}, {0x3a18, 0x00}, {0x3a19, 0xf8}, {0x3503, 0x00}, {0x5100, 0x01}, {0x5101, 0xbf}, {0x5102, 0x00}, {0x5103, 0xaa}, {0x5104, 0x3f}, {0x5105, 0x05}, {0x5106, 0xff}, {0x5107, 0x0f}, {0x5108, 0x01}, {0x5109, 0xff}, {0x510a, 0x00}, {0x510b, 0x72}, {0x510c, 0x45}, {0x510d, 0x06}, {0x510e, 0xff}, {0x510f, 0x0f}, {0x5110, 0x01}, {0x5111, 0xfe}, {0x5112, 0x00}, {0x5113, 0x70}, {0x5114, 0x21}, {0x5115, 0x05}, {0x5116, 0xff}, {0x5117, 0x0f}, {0x520a, 0xf4}, {0x520b, 0xf4}, {0x520c, 0xf4}, {0x5301, 0x05}, {0x5302, 0x0c}, {0x5303, 0x1c}, {0x5304, 0x2a}, {0x5305, 0x39}, {0x5306, 0x45}, {0x5307, 0x53}, {0x5308, 0x5d}, {0x5309, 0x68}, {0x530a, 0x7f}, {0x530b, 0x91}, {0x530c, 0xa5}, {0x530d, 0xc6}, {0x530e, 0xde}, {0x530f, 0xef}, {0x5310, 0x16}, {0x5003, 0x80}, {0x5500, 0x08}, {0x5501, 0x48}, {0x5502, 0x18}, {0x5503, 0x04}, {0x5504, 0x08}, {0x5505, 0x48}, {0x5506, 0x03}, {0x5507, 0x18}, {0x5508, 0x2d}, {0x5509, 0x08}, {0x550a, 0x48}, {0x550b, 0x06}, {0x550c, 0x04}, {0x550d, 0x01}, {0x5600, 0x00}, {0x5601, 0x31}, {0x5602, 0x3A}, {0x5603, 0x16}, {0x5604, 0x0A}, {0x5605, 0x61}, {0x5606, 0x6B}, {0x5607, 0x65}, {0x5608, 0x4F}, {0x5609, 0x16}, {0x560a, 0x01}, {0x560b, 0x98}, {0x5800, 0x02}, {0x5803, 0x40}, {0x5804, 0x34}, {0x0100, 0x01}, {OV7695_TABLE_END, 0x01}, }; struct ov7695_info { struct miscdevice miscdev_info; struct ov7695_power_rail power; struct ov7695_sensordata sensor_data; struct i2c_client *i2c_client; struct ov7695_platform_data *pdata; atomic_t in_use; const struct ov7695_reg *mode; #ifdef CONFIG_DEBUG_FS struct dentry *debugfs_root; u32 debug_i2c_offset; #endif u8 i2c_trans_buf[SIZEOF_I2C_TRANSBUF]; }; struct ov7695_mode_desc { u16 xres; u16 yres; const struct ov7695_reg *mode_tbl; struct ov7695_modeinfo mode_info; }; static struct ov7695_mode_desc mode_table[] = { { .xres = 640, .yres = 480, .mode_tbl = mode_640x480_30fps, }, { }, }; static long ov7695_ioctl(struct file *file, unsigned int cmd, unsigned long arg); static inline void ov7695_msleep(u32 t) { usleep_range(t*1000, t*1000 + 500); } static int ov7695_read_reg(struct i2c_client *client, u16 addr, u8 *val) { int err; struct i2c_msg msg[2]; unsigned char data[3]; if (!client->adapter) return -ENODEV; msg[0].addr = client->addr; msg[0].flags = 0; msg[0].len = 2; msg[0].buf = data; data[0] = (u8) (addr >> 8); data[1] = (u8) (addr & 0xff); msg[1].addr = client->addr; msg[1].flags = I2C_M_RD; msg[1].len = 1; msg[1].buf = data + 2; err = i2c_transfer(client->adapter, msg, 2); if (err != 2) return -EINVAL; *val = data[2]; return 0; } static int ov7695_write_bulk_reg(struct i2c_client *client, u8 *data, int len) { int err; struct i2c_msg msg; if (!client->adapter) return -ENODEV; msg.addr = client->addr; msg.flags = 0; msg.len = len; msg.buf = data; dev_dbg(&client->dev, "%s {0x%04x,", __func__, (int)data[0] << 8 | data[1]); for (err = 2; err < len; err++) dev_dbg(&client->dev, " 0x%02x", data[err]); dev_dbg(&client->dev, "},\n"); err = i2c_transfer(client->adapter, &msg, 1); if (err == 1) return 0; dev_err(&client->dev, "ov7695: i2c bulk transfer failed at %x\n", (int)data[0] << 8 | data[1]); return err; } static int ov7695_write_reg8(struct i2c_client *client, u16 addr, u8 val) { unsigned char data[3]; if (!client->adapter) return -ENODEV; data[0] = (u8) (addr >> 8); data[1] = (u8) (addr & 0xff); data[2] = (u8) (val & 0xff); dev_dbg(&client->dev, "0x%x = 0x%x\n", addr, val); return ov7695_write_bulk_reg(client, data, sizeof(data)); } static int ov7695_write_reg16(struct i2c_client *client, u16 addr, u16 val) { unsigned char data[4]; if (!client->adapter) return -ENODEV; data[0] = (u8) (addr >> 8); data[1] = (u8) (addr & 0xff); data[2] = (u8) (val >> 8); data[3] = (u8) (val & 0xff); dev_dbg(&client->dev, "0x%x = 0x%x\n", addr, val); return ov7695_write_bulk_reg(client, data, sizeof(data)); } static int ov7695_write_table( struct ov7695_info *info, const struct ov7695_reg table[]) { int err; const struct ov7695_reg *next; u16 val; for (next = table; next->addr != OV7695_TABLE_END; next++) { if (next->addr == OV7695_WAIT_MS) { msleep(next->val); continue; } val = next->val; err = ov7695_write_reg8(info->i2c_client, next->addr, val); if (err) return err; } return 0; } static int ov7695_open(struct inode *inode, struct file *file) { struct miscdevice *miscdev = file->private_data; struct ov7695_info *info = dev_get_drvdata(miscdev->parent); dev_dbg(&info->i2c_client->dev, "ov7695: open.\n"); info = container_of(miscdev, struct ov7695_info, miscdev_info); /* check if the device is in use */ if (atomic_xchg(&info->in_use, 1)) { dev_err(&info->i2c_client->dev, "%s:BUSY!\n", __func__); return -EBUSY; } file->private_data = info; if (info->pdata && info->pdata->power_on) info->pdata->power_on(&info->power); else { dev_err(&info->i2c_client->dev, "%s:no valid power_on function.\n", __func__); return -EFAULT; } return 0; } int ov7695_release(struct inode *inode, struct file *file) { struct ov7695_info *info = file->private_data; if (info->pdata && info->pdata->power_off) info->pdata->power_off(&info->power); file->private_data = NULL; /* warn if device is already released */ WARN_ON(!atomic_xchg(&info->in_use, 0)); return 0; } static int ov7695_regulator_get(struct ov7695_info *info, struct regulator **vreg, char vreg_name[]) { struct regulator *reg = NULL; int err = 0; reg = devm_regulator_get(&info->i2c_client->dev, vreg_name); if (unlikely(IS_ERR(reg))) { dev_err(&info->i2c_client->dev, "%s %s ERR: %d\n", __func__, vreg_name, (int)reg); err = PTR_ERR(reg); reg = NULL; } else { dev_dbg(&info->i2c_client->dev, "%s: %s\n", __func__, vreg_name); } *vreg = reg; return err; } static int ov7695_power_get(struct ov7695_info *info) { struct ov7695_power_rail *pw = &info->power; int err; /* note: ov7695 uses i2c address 0x42, * * This needs us to define a new vif2 as 2-0021 * for platform board file that uses ov7695 * otherwise below could not get the regulator * * This rails of "vif2" and "vana" can be modified as needed * for a new platform. * * ov7695: need to get 1.8v first */ /* interface 1.8v */ err = ov7695_regulator_get(info, &pw->iovdd, "vif2"); if (unlikely(IS_ERR(ERR_PTR(err)))) return err; /* ananlog 2.7v */ err = ov7695_regulator_get(info, &pw->avdd, "vana"); if (unlikely(IS_ERR(ERR_PTR(err)))) return err; return 0; } static const struct file_operations ov7695_fileops = { .owner = THIS_MODULE, .open = ov7695_open, .unlocked_ioctl = ov7695_ioctl, .release = ov7695_release, }; static struct miscdevice ov7695_device = { .minor = MISC_DYNAMIC_MINOR, .name = "ov7695", .fops = &ov7695_fileops, }; #ifdef CONFIG_DEBUG_FS static int ov7695_stats_show(struct seq_file *s, void *data) { static struct ov7695_info *info; seq_printf(s, "%-20s : %-20s\n", "Name", "ov7695-debugfs-testing"); seq_printf(s, "%-20s : 0x%X\n", "Current i2c-offset Addr", info->debug_i2c_offset); return 0; } static int ov7695_stats_open(struct inode *inode, struct file *file) { return single_open(file, ov7695_stats_show, inode->i_private); } static const struct file_operations ov7695_stats_fops = { .open = ov7695_stats_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int debug_i2c_offset_w(void *data, u64 val) { struct ov7695_info *info = (struct ov7695_info *)(data); dev_info(&info->i2c_client->dev, "ov7695:%s setting i2c offset to 0x%X\n", __func__, (u32)val); info->debug_i2c_offset = (u32)val; dev_info(&info->i2c_client->dev, "ov7695:%s new i2c offset is 0x%X\n", __func__, info->debug_i2c_offset); return 0; } static int debug_i2c_offset_r(void *data, u64 *val) { struct ov7695_info *info = (struct ov7695_info *)(data); *val = (u64)info->debug_i2c_offset; dev_info(&info->i2c_client->dev, "ov7695:%s reading i2c offset is 0x%X\n", __func__, info->debug_i2c_offset); return 0; } static int debug_i2c_read(void *data, u64 *val) { struct ov7695_info *info = (struct ov7695_info *)(data); u8 temp1 = 0; u8 temp2 = 0; dev_info(&info->i2c_client->dev, "ov7695:%s reading offset 0x%X\n", __func__, info->debug_i2c_offset); if (ov7695_read_reg(info->i2c_client, info->debug_i2c_offset, &temp1) || ov7695_read_reg(info->i2c_client, info->debug_i2c_offset+1, &temp2)) { dev_err(&info->i2c_client->dev, "ov7695:%s failed\n", __func__); return -EIO; } dev_info(&info->i2c_client->dev, "ov7695:%s read value is 0x%X\n", __func__, temp1<<8 | temp2); *val = (u64)(temp1<<8 | temp2); return 0; } static int debug_i2c_write(void *data, u64 val) { struct ov7695_info *info = (struct ov7695_info *)(data); dev_info(&info->i2c_client->dev, "ov7695:%s writing 0x%X to offset 0x%X\n", __func__, (u16)val, info->debug_i2c_offset); if (ov7695_write_reg16(info->i2c_client, info->debug_i2c_offset, (u16)val)) { dev_err(&info->i2c_client->dev, "ov7695:%s failed\n", __func__); return -EIO; } return 0; } DEFINE_SIMPLE_ATTRIBUTE(i2c_offset_fops, debug_i2c_offset_r, debug_i2c_offset_w, "0x%llx\n"); DEFINE_SIMPLE_ATTRIBUTE(i2c_read_fops, debug_i2c_read, /*debug_i2c_dummy_w*/ NULL, "0x%llx\n"); DEFINE_SIMPLE_ATTRIBUTE(i2c_write_fops, /*debug_i2c_dummy_r*/NULL, debug_i2c_write, "0x%llx\n"); static int ov7695_debug_init(struct ov7695_info *info) { dev_dbg(&info->i2c_client->dev, "%s", __func__); info->debugfs_root = debugfs_create_dir(ov7695_device.name, NULL); if (!info->debugfs_root) goto err_out; if (!debugfs_create_file("stats", S_IRUGO, info->debugfs_root, info, &ov7695_stats_fops)) goto err_out; if (!debugfs_create_file("i2c_offset", S_IRUGO | S_IWUSR, info->debugfs_root, info, &i2c_offset_fops)) goto err_out; if (!debugfs_create_file("i2c_read", S_IRUGO, info->debugfs_root, info, &i2c_read_fops)) goto err_out; if (!debugfs_create_file("i2c_write", S_IWUSR, info->debugfs_root, info, &i2c_write_fops)) goto err_out; return 0; err_out: dev_err(&info->i2c_client->dev, "ERROR:%s failed", __func__); if (info->debugfs_root) debugfs_remove_recursive(info->debugfs_root); return -ENOMEM; } #endif /* CONFIG_DEBUG_FS */ static struct ov7695_modeinfo def_modeinfo = { .xres = 640, .yres = 480, }; static struct ov7695_mode_desc *ov7695_get_mode( struct ov7695_info *info, struct ov7695_mode *mode) { struct ov7695_mode_desc *mt = mode_table; while (mt->xres) { if ((mt->xres == mode->xres) && (mt->yres == mode->yres)) break; mt++; } if (!mt->xres) mt = NULL; return mt; } static int ov7695_mode_info_init(struct ov7695_info *info) { struct ov7695_mode_desc *md = mode_table; const struct ov7695_reg *mt; struct ov7695_modeinfo *mi; dev_dbg(&info->i2c_client->dev, "%s", __func__); while (md->xres) { mi = &md->mode_info; mt = md->mode_tbl; memcpy(mi, &def_modeinfo, sizeof(*mi)); dev_dbg(&info->i2c_client->dev, "mode %d x %d ", md->xres, md->yres); mi->xres = md->xres; mi->yres = md->yres; md++; } return 0; } static int ov7695_set_mode(struct ov7695_info *info, struct ov7695_mode *mode) { struct ov7695_mode_desc *sensor_mode; int err; dev_info(&info->i2c_client->dev, "%s: xres %u yres %u\n", __func__, mode->xres, mode->yres); sensor_mode = ov7695_get_mode(info, mode); if (sensor_mode == NULL) { dev_err(&info->i2c_client->dev, "%s: invalid params supplied to set mode %d %d\n", __func__, mode->xres, mode->yres); return -EINVAL; } err = ov7695_write_table( info, sensor_mode->mode_tbl); if (err) return err; info->mode = sensor_mode->mode_tbl; return 0; } static long ov7695_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int err = 0; struct ov7695_info *info = file->private_data; switch (cmd) { case OV7695_SENSOR_IOCTL_SET_MODE: { struct ov7695_mode mode; dev_dbg(&info->i2c_client->dev, "OV7695_IOCTL_SET_MODE\n"); if (copy_from_user(&mode, (const void __user *)arg, sizeof(struct ov7695_mode))) { err = -EFAULT; break; } err = ov7695_set_mode(info, &mode); break; } default: dev_dbg(&info->i2c_client->dev, "INVALID IOCTL\n"); err = -EINVAL; } if (err) dev_err(&info->i2c_client->dev, "%s - %x: ERR = %d\n", __func__, cmd, err); return err; } static int ov7695_probe(struct i2c_client *client, const struct i2c_device_id *id) { int err; struct ov7695_info *info; dev_dbg(&client->dev, "ov7695: probing sensor.\n"); info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL); if (info == NULL) { dev_err(&client->dev, "%s: kzalloc error\n", __func__); return -ENOMEM; } info->pdata = client->dev.platform_data; info->i2c_client = client; atomic_set(&info->in_use, 0); info->mode = NULL; i2c_set_clientdata(client, info); err = ov7695_power_get(info); if (err) { dev_err(&info->i2c_client->dev, "ov7695: Unable to get regulators\n"); return err; } ov7695_mode_info_init(info); memcpy(&info->miscdev_info, &ov7695_device, sizeof(struct miscdevice)); err = misc_register(&info->miscdev_info); if (err) { dev_err(&info->i2c_client->dev, "ov7695: Unable to register misc device!\n"); return err; } #ifdef CONFIG_DEBUG_FS ov7695_debug_init(info); #endif return 0; } static int ov7695_remove(struct i2c_client *client) { struct ov7695_info *info; info = i2c_get_clientdata(client); misc_deregister(&ov7695_device); kfree(info); #ifdef CONFIG_DEBUG_FS if (info->debugfs_root) debugfs_remove_recursive(info->debugfs_root); #endif return 0; } static const struct i2c_device_id ov7695_id[] = { { "ov7695", 0 }, { }, }; MODULE_DEVICE_TABLE(i2c, ov7695_id); static struct i2c_driver ov7695_i2c_driver = { .driver = { .name = "ov7695", .owner = THIS_MODULE, }, .probe = ov7695_probe, .remove = ov7695_remove, .id_table = ov7695_id, }; static int __init ov7695_init(void) { pr_info("ov7695 sensor driver loading\n"); return i2c_add_driver(&ov7695_i2c_driver); } static void __exit ov7695_exit(void) { i2c_del_driver(&ov7695_i2c_driver); } module_init(ov7695_init); module_exit(ov7695_exit); MODULE_LICENSE("GPL v2");