/* * ar0833.c - ar0833 sensor driver * * 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 struct ar0833_reg { u16 addr; u16 val; }; struct ar0833_reg_blob { u16 addr; u16 size; u8 *data; }; struct ar0833_info { struct miscdevice miscdev_info; struct ar0833_power_rail power; struct ar0833_sensordata sensor_data; struct i2c_client *i2c_client; struct ar0833_platform_data *pdata; atomic_t in_use; const struct ar0833_reg *mode; #ifdef CONFIG_DEBUG_FS struct dentry *debugfs_root; u32 debug_i2c_offset; int enableDCBLC; #endif u8 i2c_trans_buf[SIZEOF_I2C_TRANSBUF]; }; #define AR0833_TABLE_WAIT_MS 0xC000 #define AR0833_TABLE_NOP 0xC001 #define AR0833_TABLE_CALL 0xC002 #define AR0833_TABLE_BLOB 0xC003 #define AR0833_TABLE_END 0xC004 #define AR0833_TABLE_8BIT 0x8000 #include "ar0833_mode_tbls.c" struct ar0833_mode_desc { u16 xres; u16 yres; u8 hdr_en; const struct ar0833_reg *mode_tbl; struct ar0833_modeinfo mode_info; }; static struct ar0833_mode_desc mode_table[] = { { .xres = 3264, .yres = 2448, .hdr_en = 0, .mode_tbl = mode_3264x2448_30fps, }, { .xres = 3264, .yres = 2448, .hdr_en = 1, .mode_tbl = mode_3264x2448_HDR_30fps, }, { .xres = 1920, .yres = 1080, .hdr_en = 0, .mode_tbl = mode_1920x1080_30fps, }, { .xres = 1920, .yres = 1080, .hdr_en = 1, .mode_tbl = mode_1920x1080_HDR_30fps, }, { .xres = 3264, .yres = 1836, .hdr_en = 0, .mode_tbl = mode_3264x1836_30fps, }, { .xres = 3264, .yres = 1836, .hdr_en = 1, .mode_tbl = mode_3264x1836_HDR_30fps, }, { }, }; static long ar0833_ioctl(struct file *file, unsigned int cmd, unsigned long arg); static inline void ar0833_msleep(u32 t) { usleep_range(t*1000, t*1000 + 500); } static inline void ar0833_get_coarse_time_regs(struct ar0833_reg *regs, u32 coarse_time) { regs->addr = 0x0202; regs->val = coarse_time & 0xFFFF; } static inline void ar0833_get_coarse_time_short_regs(struct ar0833_reg *regs, u32 coarse_time) { regs->addr = 0x3088; regs->val = coarse_time & 0xFFFF; } static inline void ar0833_get_gain_reg(struct ar0833_reg *regs, u16 gain) { regs->addr = 0x305E; regs->val = gain & 0xFFFF; } static int ar0833_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; /* high byte goes out first */ 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 ar0833_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, "ar0833: i2c bulk transfer failed at %x\n", (int)data[0] << 8 | data[1]); return err; } static int ar0833_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 ar0833_write_bulk_reg(client, data, sizeof(data)); } static int ar0833_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 ar0833_write_bulk_reg(client, data, sizeof(data)); } /* flush and reset buffer */ static int ar0833_flash_buffer(struct ar0833_info *info, int *len) { int err; if (!(*len)) return 0; err = ar0833_write_bulk_reg(info->i2c_client, info->i2c_trans_buf, *len); *len = 0; return err; } static int ar0833_write_blob( struct ar0833_info *info, struct ar0833_reg_blob *pblob) { u8 *pdata = pblob->data; u16 addr = pblob->addr; u16 size = pblob->size; int err = 0; u16 blk; dev_dbg(&info->i2c_client->dev, "ar0833_write_blob ++\n"); while (size) { blk = size > sizeof(info->i2c_trans_buf) - 2 ? sizeof(info->i2c_trans_buf) - 2 : size; info->i2c_trans_buf[0] = addr >> 8; info->i2c_trans_buf[1] = (u8)addr; memcpy(info->i2c_trans_buf + 2, pdata, blk); err = ar0833_write_bulk_reg(info->i2c_client, info->i2c_trans_buf, blk + 2); if (err) break; size -= blk; pdata += blk; addr += blk; } dev_dbg(&info->i2c_client->dev, "ar0833_write_blob -- %d\n", err); return err; } static int ar0833_write_table( struct ar0833_info *info, const struct ar0833_reg table[], const struct ar0833_reg override_list[], int num_override_regs) { int err = 0; const struct ar0833_reg *next, *n_next; u8 *b_ptr = info->i2c_trans_buf; unsigned int buf_filled = 0; int i; u16 val; dev_dbg(&info->i2c_client->dev, "%s ++\n", __func__); for (next = table; !err; next++) { switch (next->addr) { case AR0833_TABLE_END: dev_dbg(&info->i2c_client->dev, "ar0833_table_end\n"); err = ar0833_flash_buffer(info, &buf_filled); return err; case AR0833_TABLE_NOP: continue; case AR0833_TABLE_WAIT_MS: dev_dbg(&info->i2c_client->dev, "ar0833_wait_ms %d\n", next->val); err = ar0833_flash_buffer(info, &buf_filled); if (err < 0) return err; ar0833_msleep(next->val); continue; case AR0833_TABLE_CALL: err = ar0833_flash_buffer(info, &buf_filled); if (next->val >= NUM_OF_SUBTBLS) { dev_err(&info->i2c_client->dev, "%s: invalid tbl index %d\n", __func__, next->val); return -EFAULT; } if (err < 0) return err; err = ar0833_write_table( info, sub_tbls[next->val], NULL, 0); if (err < 0) return err; continue; case AR0833_TABLE_BLOB: err = ar0833_flash_buffer(info, &buf_filled); if (next->val >= NUM_OF_SUBTBLS) { dev_err(&info->i2c_client->dev, "%s: invalid tbl index %d\n", __func__, next->val); return -EFAULT; } if (err < 0) return err; err = ar0833_write_blob(info, sub_tbls[next->val]); if (err < 0) return err; continue; } val = next->val; /* When an override list is passed in, replace the reg */ /* value to write if the reg is in the list */ if (override_list) for (i = 0; i < num_override_regs; i++) if (next->addr == override_list[i].addr) { val = override_list[i].val; break; } if (!buf_filled) { b_ptr = info->i2c_trans_buf; *b_ptr++ = (next->addr & ~AR0833_TABLE_8BIT) >> 8; *b_ptr++ = next->addr & 0xff; buf_filled = 2; } if (!(next->addr & AR0833_TABLE_8BIT)) { *b_ptr++ = (u8)(val >> 8); buf_filled++; } *b_ptr++ = (u8)val; buf_filled++; n_next = next + 1; if (buf_filled < (sizeof(info->i2c_trans_buf) & 0xFFFE) && n_next->addr == next->addr + 2) continue; err = ar0833_flash_buffer(info, &buf_filled); if (err < 0) return err; } dev_dbg(&info->i2c_client->dev, "%s --\n", __func__); return 0; } static int ar0833_set_coarse_time(struct ar0833_info *info, u32 coarse_time, bool group_hold) { int ret; struct ar0833_reg reg_list; ar0833_get_coarse_time_regs(®_list, coarse_time); if (group_hold) { ret = ar0833_write_reg16(info->i2c_client, 0x0104, 0x1); if (ret) return ret; } ret = ar0833_write_reg16(info->i2c_client, reg_list.addr, reg_list.val); if (ret) return ret; if (group_hold) { ret = ar0833_write_reg16(info->i2c_client, 0x0104, 0x0); if (ret) return ret; } return ret; } static int ar0833_set_hdr_coarse_time(struct ar0833_info *info, struct ar0833_hdr *values, bool group_hold) { int ret; struct ar0833_reg reg_list; struct ar0833_reg reg_list_short; ar0833_get_coarse_time_regs(®_list, values->coarse_time_long); ar0833_get_coarse_time_short_regs(®_list_short, values->coarse_time_short); if (group_hold) { ret = ar0833_write_reg16(info->i2c_client, 0x0104, 0x1); if (ret) return ret; } ret = ar0833_write_reg16(info->i2c_client, reg_list.addr, reg_list.val); if (ret) return ret; ret = ar0833_write_reg16(info->i2c_client, reg_list_short.addr, reg_list_short.val); if (ret) return ret; if (group_hold) { ret = ar0833_write_reg16(info->i2c_client, 0x0104, 0x0); if (ret) return ret; } return ret; } static int ar0833_set_gain(struct ar0833_info *info, u16 gain, bool group_hold) { int ret; struct ar0833_reg reg_list; ar0833_get_gain_reg(®_list, gain); if (group_hold) { ret = ar0833_write_reg16(info->i2c_client, 0x0104, 0x1); if (ret) return ret; } ret = ar0833_write_reg16(info->i2c_client, reg_list.addr, reg_list.val); if (ret) return ret; if (group_hold) { ret = ar0833_write_reg16(info->i2c_client, 0x0104, 0x0); if (ret) return ret; } return ret; } static int ar0833_set_group_hold(struct ar0833_info *info, struct ar0833_ae *ae) { int ret; int count = 0; bool groupHoldEnabled = false; struct ar0833_hdr values; values.coarse_time_long = ae->coarse_time; values.coarse_time_short = ae->coarse_time_short; if (ae->gain_enable) count++; if (ae->coarse_time_enable) count++; if (count >= 1) groupHoldEnabled = true; if (groupHoldEnabled) { ret = ar0833_write_reg16(info->i2c_client, 0x104, 0x1); if (ret) return ret; } if (ae->gain_enable) ar0833_set_gain(info, ae->gain, false); if (ae->coarse_time_enable) ar0833_set_hdr_coarse_time(info, &values, false); if (groupHoldEnabled) { ret = ar0833_write_reg16(info->i2c_client, 0x104, 0x0); if (ret) return ret; } return 0; } static int ar0833_get_status(struct ar0833_info *info, u8 *status) { int err; err = ar0833_read_reg(info->i2c_client, 0x380e, status); return err; } static int ar0833_open(struct inode *inode, struct file *file) { struct miscdevice *miscdev = file->private_data; struct ar0833_info *info; info = container_of(miscdev, struct ar0833_info, miscdev_info); /* check if the device is in use */ if (atomic_xchg(&info->in_use, 1)) { dev_info(&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 -EEXIST; } return 0; } int ar0833_release(struct inode *inode, struct file *file) { struct ar0833_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 ar0833_regulator_get(struct ar0833_info *info, struct regulator **vreg, char vreg_name[]) { struct regulator *reg = NULL; int err = 0; reg = 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 ar0833_power_get(struct ar0833_info *info) { struct ar0833_power_rail *pw = &info->power; ar0833_regulator_get(info, &pw->avdd, "vana"); /* ananlog 2.7v */ ar0833_regulator_get(info, &pw->dvdd, "vdig"); /* digital 1.2v */ ar0833_regulator_get(info, &pw->iovdd, "vif"); /* interface 1.8v */ return 0; } static const struct file_operations ar0833_fileops = { .owner = THIS_MODULE, .open = ar0833_open, .unlocked_ioctl = ar0833_ioctl, .release = ar0833_release, }; static struct miscdevice ar0833_device = { .minor = MISC_DYNAMIC_MINOR, .name = "ar0833", .fops = &ar0833_fileops, }; #ifdef CONFIG_DEBUG_FS int control_DC_BLC(struct ar0833_info *info) { u8 reg0x3d0a; u8 reg0x3d0b; u8 reg0x4006; if (info->enableDCBLC) { ar0833_write_reg8(info->i2c_client, 0x3d84, 0xdf); ar0833_write_reg8(info->i2c_client, 0x3d81, 0x01); ar0833_msleep(10); ar0833_read_reg(info->i2c_client, 0x3d0a, ®0x3d0a); ar0833_read_reg(info->i2c_client, 0x3d0b, ®0x3d0b); ar0833_write_reg8(info->i2c_client, 0x3d81, 0x00); if ((reg0x3d0b > 0x10 && reg0x3d0b < 0x20)) reg0x4006 = reg0x3d0b; else if ((reg0x3d0a > 0x10) && (reg0x3d0a < 0x20)) reg0x4006 = reg0x3d0a; else reg0x4006 = 0x20; ar0833_write_reg8(info->i2c_client, 0x4006, reg0x4006); dev_info(&info->i2c_client->dev, "ar0833: %s: wrote the DC BLC commands\n", __func__); } else { dev_info(&info->i2c_client->dev, "ar0833: %s: DID NOT do the DC BLC commands\n", __func__); } return 0; } static int ar0833_stats_show(struct seq_file *s, void *data) { static struct ar0833_info *info; seq_printf(s, "%-20s : %-20s\n", "Name", "ar0833-debugfs-testing"); seq_printf(s, "%-20s : 0x%X\n", "Current i2c-offset Addr", info->debug_i2c_offset); seq_printf(s, "%-20s : 0x%X\n", "DC BLC Enabled", info->debug_i2c_offset); return 0; } static int ar0833_stats_open(struct inode *inode, struct file *file) { return single_open(file, ar0833_stats_show, inode->i_private); } static const struct file_operations ar0833_stats_fops = { .open = ar0833_stats_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static int debug_i2c_offset_w(void *data, u64 val) { struct ar0833_info *info = (struct ar0833_info *)(data); dev_info(&info->i2c_client->dev, "ar0833:%s setting i2c offset to 0x%X\n", __func__, (u32)val); info->debug_i2c_offset = (u32)val; dev_info(&info->i2c_client->dev, "ar0833:%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 ar0833_info *info = (struct ar0833_info *)(data); *val = (u64)info->debug_i2c_offset; dev_info(&info->i2c_client->dev, "ar0833:%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 ar0833_info *info = (struct ar0833_info *)(data); u8 temp1 = 0; u8 temp2 = 0; dev_info(&info->i2c_client->dev, "ar0833:%s reading offset 0x%X\n", __func__, info->debug_i2c_offset); if (ar0833_read_reg(info->i2c_client, info->debug_i2c_offset, &temp1) || ar0833_read_reg(info->i2c_client, info->debug_i2c_offset+1, &temp2)) { dev_err(&info->i2c_client->dev, "ar0833:%s failed\n", __func__); return -EIO; } dev_info(&info->i2c_client->dev, "ar0833:%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 ar0833_info *info = (struct ar0833_info *)(data); dev_info(&info->i2c_client->dev, "ar0833:%s writing 0x%X to offset 0x%X\n", __func__, (u16)val, info->debug_i2c_offset); if (ar0833_write_reg16(info->i2c_client, info->debug_i2c_offset, (u16)val)) { dev_err(&info->i2c_client->dev, "ar0833:%s failed\n", __func__); return -EIO; } return 0; } static int debug_dcblc_r(void *data, u64 *val) { struct ar0833_info *info = (struct ar0833_info *)(data); *val = (u64)info->enableDCBLC; dev_info(&info->i2c_client->dev, "ar0833:%s read DC BLC [%d]\n", __func__, info->enableDCBLC); return 0; } static int debug_dcblc_w(void *data, u64 val) { struct ar0833_info *info = (struct ar0833_info *)(data); if (val != 0) { info->enableDCBLC = 1; dev_info(&info->i2c_client->dev, "ar0833:%s enabled DC BLC\n", __func__); } else { info->enableDCBLC = 0; dev_info(&info->i2c_client->dev, "ar0833:%s disabled DC BLC\n", __func__); } return 0; } DEFINE_SIMPLE_ATTRIBUTE(debug_dcblc_fops, debug_dcblc_r, debug_dcblc_w, "0x%llx\n"); 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 ar0833_debug_init(struct ar0833_info *info) { dev_dbg(&info->i2c_client->dev, "%s", __func__); info->debugfs_root = debugfs_create_dir(ar0833_device.name, NULL); if (!info->debugfs_root) goto err_out; if (!debugfs_create_file("stats", S_IRUGO, info->debugfs_root, info, &ar0833_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; if (!debugfs_create_file("DCBLC", S_IRUGO | S_IWUSR, info->debugfs_root, info, &debug_dcblc_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 static struct ar0833_modeinfo def_modeinfo = { .xres = 3264, .yres = 2448, .hdr = 0, .lanes = 4, .line_len = 0x0f68, .frame_len = 0x0a01, .coarse_time = 2400, .coarse_time_2nd = 300, .xstart = 8, .xend = 0x0cc7, .ystart = 8, .yend = 0x0997, .xsize = 0x0cc0, .ysize = 0x0990, .gain = 0x1000, .x_flip = 1, .y_flip = 0, .x_bin = 1, .y_bin = 1, .vt_pix_clk_div = 5, .vt_sys_clk_div = 1, .pre_pll_clk_div = 2, .pll_multi = 0x40, .op_pix_clk_div = 0x0a, .op_sys_clk_div = 1, }; static struct ar0833_mode_desc *ar0833_get_mode( struct ar0833_info *info, struct ar0833_mode *mode) { struct ar0833_mode_desc *mt = mode_table; while (mt->xres) { if ((mt->xres == mode->xres) && (mt->yres == mode->yres) && (mt->hdr_en == mode->hdr_en)) break; mt++; } if (!mt->xres) mt = NULL; return mt; } static int ar0833_mode_info_init(struct ar0833_info *info) { struct ar0833_mode_desc *md = mode_table; const struct ar0833_reg *mt; struct ar0833_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 %s", md->xres, md->yres, md->hdr_en ? "HDR" : "REG"); mi->xres = md->xres; mi->yres = md->yres; mi->hdr = md->hdr_en; while (mt->addr != AR0833_TABLE_END) { switch (mt->addr) { case 0x0300: mi->vt_pix_clk_div = mt->val; break; case 0x0302: mi->vt_sys_clk_div = mt->val; break; case 0x0304: mi->pre_pll_clk_div = mt->val; break; case 0x0306: mi->pll_multi = mt->val; break; case 0x0308: mi->op_pix_clk_div = mt->val; break; case 0x030a: mi->op_sys_clk_div = mt->val; break; case 0x0202: mi->coarse_time = mt->val; break; case 0x3088: mi->coarse_time_2nd = mt->val; break; case 0x0340: mi->frame_len = mt->val; break; case 0x0342: mi->line_len = mt->val; break; case 0x0344: mi->xstart = mt->val; break; case 0x0346: mi->ystart = mt->val; break; case 0x0348: mi->xend = mt->val; break; case 0x034a: mi->yend = mt->val; break; case 0x034c: mi->xsize = mt->val; break; case 0x034e: mi->ysize = mt->val; break; case 0x305e: mi->gain = mt->val; break; case 0x31ae: mi->lanes = mt->val & 0x7; break; case 0x3040: if (mt->val & 0x8000) mi->y_flip = 1; if (mt->val & 0x4000) mi->x_flip = 1; switch (mt->val & 0x1c0) { case 1: mi->x_bin = 1; break; case 3: mi->x_bin = 2; break; case 7: mi->x_bin = 4; break; default: dev_warn(&info->i2c_client->dev, "%s :Unrecognized x_odd_inc" "setting in mode %d x %d %s," " 0x3040 = 0x%x\n", __func__, md->xres, md->yres, md->hdr_en ? "HDR" : "REG", mt->val); break; } switch (mt->val & 0x3f) { case 1: mi->y_bin = 1; break; case 3: mi->y_bin = 2; break; case 7: mi->y_bin = 4; break; case 15: mi->y_bin = 8; break; case 31: mi->y_bin = 16; break; case 63: mi->y_bin = 32; break; default: dev_warn(&info->i2c_client->dev, "%s :Unrecognized y_odd_inc" "setting in mode %d x %d %s," " 0x3040 = 0x%x\n", __func__, md->xres, md->yres, md->hdr_en ? "HDR" : "REG", mt->val); break; } break; }; mt++; }; md++; } return 0; } static struct ar0833_modeinfo *ar0833_get_mode_info( struct ar0833_info *info, struct ar0833_modeinfo *mi) { struct ar0833_mode mode; struct ar0833_mode_desc *mode_desc; mode.xres = mi->xres; mode.yres = mi->yres; mode.hdr_en = mi->hdr; mode_desc = ar0833_get_mode(info, &mode); if (mode_desc == NULL) { dev_err(&info->i2c_client->dev, "%s: invalid params to get mode info %d %d %d\n", __func__, mi->xres, mi->yres, mi->hdr); return NULL; } return &mode_desc->mode_info; } static int ar0833_set_mode(struct ar0833_info *info, struct ar0833_mode *mode) { struct ar0833_mode_desc *sensor_mode; struct ar0833_reg reg_list[4]; int err; dev_info(&info->i2c_client->dev, "%s: xres %u yres %u hdr %d\n", __func__, mode->xres, mode->yres, mode->hdr_en); dev_info(&info->i2c_client->dev, "framelength %u coarsetime %u gain %x\n", mode->frame_length, mode->coarse_time, mode->gain); sensor_mode = ar0833_get_mode(info, mode); if (sensor_mode == NULL) { dev_err(&info->i2c_client->dev, "%s: invalid params supplied to set mode %d %d %d\n", __func__, mode->xres, mode->yres, mode->hdr_en); return -EINVAL; } if (mode->hdr_en == 1) /* if HDR is enabled */ dev_info(&info->i2c_client->dev, "ar0833 HDR enabled\n"); else dev_info(&info->i2c_client->dev, "ar0833 HDR disabled\n"); memset(reg_list, 0, sizeof(reg_list)); /* get a list of override regs for the asking frame length, */ /* coarse integration time, and gain. */ ar0833_get_coarse_time_regs(reg_list, mode->coarse_time); ar0833_get_gain_reg(reg_list + 1, mode->gain); if (mode->hdr_en == 1) /* if HDR is enabled */ ar0833_get_coarse_time_short_regs( reg_list + 2, mode->coarse_time_short); err = ar0833_write_table( info, sensor_mode->mode_tbl, reg_list, mode->hdr_en ? 3 : 2); if (err) return err; info->mode = sensor_mode->mode_tbl; #ifdef CONFIG_DEBUG_FS control_DC_BLC(info); #endif return 0; } static long ar0833_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int err = 0; struct ar0833_info *info = file->private_data; switch (cmd) { case AR0833_IOCTL_SET_MODE: { struct ar0833_mode mode; dev_dbg(&info->i2c_client->dev, "AR0833_IOCTL_SET_MODE\n"); if (copy_from_user(&mode, (const void __user *)arg, sizeof(struct ar0833_mode))) { err = -EFAULT; break; } err = ar0833_set_mode(info, &mode); break; } case AR0833_IOCTL_SET_FRAME_LENGTH: dev_dbg(&info->i2c_client->dev, "AR0833_IOCTL_SET_FRAME_LENGTH %x\n", (u32)arg); /* obsolete. we should not update frame length, it is done by sensor automatically */ break; case AR0833_IOCTL_SET_COARSE_TIME: dev_dbg(&info->i2c_client->dev, "AR0833_IOCTL_SET_COARSE_TIME %x\n", (u32)arg); err = ar0833_set_coarse_time(info, (u32)arg, true); break; case AR0833_IOCTL_SET_HDR_COARSE_TIME: { struct ar0833_hdr values; dev_dbg(&info->i2c_client->dev, "AR0833_IOCTL_SET_HDR_COARSE_TIME\n"); if (copy_from_user(&values, (const void __user *)arg, sizeof(struct ar0833_hdr))) { err = -EFAULT; break; } err = ar0833_set_hdr_coarse_time(info, &values, true); break; } case AR0833_IOCTL_SET_GAIN: dev_dbg(&info->i2c_client->dev, "AR0833_IOCTL_SET_GAIN %x\n", (u32)arg); err = ar0833_set_gain(info, (u16)arg, true); break; case AR0833_IOCTL_SET_GROUP_HOLD: { struct ar0833_ae ae; if (copy_from_user(&ae, (const void __user *)arg, sizeof(struct ar0833_ae))) { dev_err(&info->i2c_client->dev, "%s:fail group hold\n", __func__); return -EFAULT; } return ar0833_set_group_hold(info, &ae); } case AR0833_IOCTL_GET_STATUS: { u8 status; dev_dbg(&info->i2c_client->dev, "AR0833_IOCTL_GET_STATUS\n"); err = ar0833_get_status(info, &status); if (err) break; if (copy_to_user((void __user *)arg, &status, 2)) { err = -EFAULT; break; } break; } case AR0833_IOCTL_GET_MODE: { struct ar0833_modeinfo mode_info, *mi; dev_dbg(&info->i2c_client->dev, "AR0833_IOCTL_GET_MODE\n"); if (copy_from_user(&mode_info, (const void __user *)arg, sizeof(struct ar0833_mode))) { err = -EFAULT; break; } mi = ar0833_get_mode_info(info, &mode_info); if (mi == NULL) err = -EFAULT; else { if (copy_to_user((void __user *)arg, mi, sizeof(*mi))) { err = -EFAULT; break; } dev_dbg(&info->i2c_client->dev, "mode %d x %d %s:\n", mi->xres, mi->yres, mi->hdr ? "HDR" : "REG"); dev_dbg(&info->i2c_client->dev, "line_len = %d\n", mi->line_len); dev_dbg(&info->i2c_client->dev, "frame_len = %d\n", mi->frame_len); dev_dbg(&info->i2c_client->dev, "xsize = %d\n", mi->xsize); dev_dbg(&info->i2c_client->dev, "ysize = %d\n", mi->ysize); dev_dbg(&info->i2c_client->dev, "vt_pix_clk_div = %d\n", mi->vt_pix_clk_div); dev_dbg(&info->i2c_client->dev, "vt_sys_clk_div = %d\n", mi->vt_sys_clk_div); dev_dbg(&info->i2c_client->dev, "pre_pll_clk_div = %d\n", mi->pre_pll_clk_div); dev_dbg(&info->i2c_client->dev, "pll_multi = %d\n", mi->pll_multi); dev_dbg(&info->i2c_client->dev, "op_pix_clk_div = %d\n", mi->op_pix_clk_div); dev_dbg(&info->i2c_client->dev, "op_sys_clk_div = %d\n", mi->op_sys_clk_div); } break; } default: dev_dbg(&info->i2c_client->dev, "INVALID IOCTL\n"); err = -EINVAL; } if (err) dev_dbg(&info->i2c_client->dev, "%s - %x: ERR = %d\n", __func__, cmd, err); return err; } static int ar0833_probe(struct i2c_client *client, const struct i2c_device_id *id) { int err; struct ar0833_info *info; dev_info(&client->dev, "ar0833: 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); ar0833_power_get(info); ar0833_mode_info_init(info); memcpy(&info->miscdev_info, &ar0833_device, sizeof(struct miscdevice)); err = misc_register(&info->miscdev_info); if (err) { dev_err(&info->i2c_client->dev, "ar0833: Unable to register misc device!\n"); kfree(info); return err; } #ifdef CONFIG_DEBUG_FS ar0833_debug_init(info); info->enableDCBLC = 0; #endif return 0; } static int ar0833_remove(struct i2c_client *client) { struct ar0833_info *info; info = i2c_get_clientdata(client); misc_deregister(&info->miscdev_info); 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 ar0833_id[] = { { "ar0833", 0 }, { }, }; MODULE_DEVICE_TABLE(i2c, ar0833_id); static struct i2c_driver ar0833_i2c_driver = { .driver = { .name = "ar0833", .owner = THIS_MODULE, }, .probe = ar0833_probe, .remove = ar0833_remove, .id_table = ar0833_id, }; static int __init ar0833_init(void) { pr_info("ar0833 sensor driver loading\n"); return i2c_add_driver(&ar0833_i2c_driver); } static void __exit ar0833_exit(void) { i2c_del_driver(&ar0833_i2c_driver); } module_init(ar0833_init); module_exit(ar0833_exit); MODULE_LICENSE("GPL v2");