/* * ar0330.c - ar0330 sensor driver * * Copyright (c) 2014 - 2015, 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 #include #include #include "nvc_utilities.h" struct ar0330_reg { u16 addr; u16 val; }; struct ar0330_info { struct miscdevice miscdev_info; int mode; struct ar0330_power_rail power; struct ar0330_sensordata sensor_data; struct i2c_client *i2c_client; struct ar0330_platform_data *pdata; struct clk *mclk; struct regmap *regmap; struct mutex ar0330_camera_lock; atomic_t in_use; char devname[16]; }; static const struct regmap_config sensor_regmap_config = { .reg_bits = 16, .val_bits = 16, .cache_type = REGCACHE_RBTREE, }; #define AR0330_TABLE_WAIT_MS 0 #define AR0330_TABLE_END 1 #define AR0330_MAX_RETRIES 3 #define AR0330_WAIT_MS 100 #define MAX_BUFFER_SIZE 32 #define AR0330_FRAME_LENGTH_ADDR 0x300A #define AR0330_COARSE_TIME_ADDR 0x3012 #define AR0330_GAIN_ADDR 0x3060 static struct ar0330_reg mode_2304x1536[] = { {0x3052, 0xa114}, {0x304A, 0x0070}, {AR0330_TABLE_WAIT_MS, AR0330_WAIT_MS}, {0x301A, 0x0058}, {0x302A, 0x0005}, {0x302C, 0x0004}, {0x302E, 0x0003}, {0x3030, 0x005F}, {0x3036, 0x000A}, {0x3038, 0x0001}, {0x31AC, 0x0A0A}, {0x31AE, 0x0201}, {0x31B0, 0x003D}, {0x31B2, 0x0018}, {0x31B4, 0x4F56}, {0x31B6, 0x4214}, {0x31B8, 0x308B}, {0x31BA, 0x028A}, {0x31BC, 0x8008}, {0x3002, 0x0006}, {0x3004, 0x0006}, {0x3006, 0x0605}, {0x3008, 0x0905}, {0x300A, 0x0611}, {0x300C, 0x04E0}, {0x3012, 0x0610}, {0x3014, 0x0000}, {0x30A2, 0x0001}, {0x30A6, 0x0001}, {0x3040, 0x0000}, {0x3042, 0x0000}, {0x30BA, 0x006C}, {0x31E0, 0x0303}, {0x3064, 0x1802}, {0x3ED2, 0x0146}, {0x3ED4, 0x8F6C}, {0x3ED6, 0x66CC}, {0x3ED8, 0x8C42}, {0x3EDA, 0x88BC}, {0x3EDC, 0xAA63}, {0x305E, 0x00A0}, {0x3088, 0x80BA}, {0x3086, 0x0253}, {0x30CE, 0x0010}, {0x301A, 0x035C}, {AR0330_TABLE_END, 0x00} }; static struct ar0330_reg mode_1280x720[] = { {0x301A, 0x0059}, {AR0330_TABLE_WAIT_MS, AR0330_WAIT_MS}, {0x31AE, 0x0204}, {0x301A, 0x0059}, {AR0330_TABLE_WAIT_MS, AR0330_WAIT_MS}, {0x301A, 0x0058}, {0x3064, 0x1802}, {0x3078, 0x0001}, {0x30BA, 0x002C}, {0x30FE, 0x0080}, {0x31E0, 0x0003}, {0x3ECE, 0x09FF}, {0x3ED0, 0xE4F6}, {0x3ED2, 0x0146}, {0x3ED4, 0x8F6C}, {0x3ED6, 0x66CC}, {0x3ED8, 0x8C42}, {0x3EDA, 0x889B}, {0x3EDC, 0x8863}, {0x3EDE, 0xAA04}, {0x3EE0, 0x15F0}, {0x3EE6, 0x008C}, {0x3EE8, 0x2024}, {0x3EEA, 0xFF1F}, {0x3F06, 0x046A}, {0x3046, 0x4038}, {0x3048, 0x8480}, {0x31E0, 0x0003}, {0x301A, 0x0058}, {0x31AE, 0x0201}, {0x31AC, 0x0A0A}, {0x31B0, 0x0028}, {0x31B2, 0x000E}, {0x31B4, 0x2743}, {0x31B6, 0x114E}, {0x31B8, 0x2049}, {0x31BA, 0x0186}, {0x31BC, 0x8005}, {0x31BE, 0x2003}, {0x302A, 0x0005}, {0x302C, 0x0004}, {0x302E, 0x0004}, {0x3030, 0x0052}, {0x3036, 0x000A}, {0x3038, 0x0001}, {0x31AC, 0x0A0A}, {0x3004, 0x0200}, {0x3008, 0x06FF}, {0x3002, 0x019C}, {0x3006, 0x046B}, {0x30A2, 0x0001}, {0x30A6, 0x0001}, {0x3040, 0x0000}, {0x300C, 0x03F6}, {0x300A, 0x0328}, {0x3014, 0x0000}, {0x3012, 0x0327}, {0x3042, 0x02B0}, {0x30BA, 0x002C}, {0x301A, 0x0058}, {AR0330_TABLE_WAIT_MS, AR0330_WAIT_MS}, {0x3088, 0x8000}, {0x3086, 0x4A03}, {0x3086, 0x4316}, {0x3086, 0x0443}, {0x3086, 0x1645}, {0x3086, 0x4045}, {0x3086, 0x6017}, {0x3086, 0x2045}, {0x3086, 0x404B}, {0x3086, 0x1244}, {0x3086, 0x6134}, {0x3086, 0x4A31}, {0x3086, 0x4342}, {0x3086, 0x4560}, {0x3086, 0x2714}, {0x3086, 0x3DFF}, {0x3086, 0x3DFF}, {0x3086, 0x3DEA}, {0x3086, 0x2704}, {0x3086, 0x3D10}, {0x3086, 0x2705}, {0x3086, 0x3D10}, {0x3086, 0x2715}, {0x3086, 0x3527}, {0x3086, 0x053D}, {0x3086, 0x1045}, {0x3086, 0x4027}, {0x3086, 0x0427}, {0x3086, 0x143D}, {0x3086, 0xFF3D}, {0x3086, 0xFF3D}, {0x3086, 0xEA62}, {0x3086, 0x2728}, {0x3086, 0x3627}, {0x3086, 0x083D}, {0x3086, 0x6444}, {0x3086, 0x2C2C}, {0x3086, 0x2C2C}, {0x3086, 0x4B01}, {0x3086, 0x432D}, {0x3086, 0x4643}, {0x3086, 0x1647}, {0x3086, 0x435F}, {0x3086, 0x4F50}, {0x3086, 0x2604}, {0x3086, 0x2684}, {0x3086, 0x2027}, {0x3086, 0xFC53}, {0x3086, 0x0D5C}, {0x3086, 0x0D57}, {0x3086, 0x5417}, {0x3086, 0x0955}, {0x3086, 0x5649}, {0x3086, 0x5307}, {0x3086, 0x5302}, {0x3086, 0x4D28}, {0x3086, 0x6C4C}, {0x3086, 0x0928}, {0x3086, 0x2C28}, {0x3086, 0x294E}, {0x3086, 0x5C09}, {0x3086, 0x6045}, {0x3086, 0x0045}, {0x3086, 0x8026}, {0x3086, 0xA627}, {0x3086, 0xF817}, {0x3086, 0x0227}, {0x3086, 0xFA5C}, {0x3086, 0x0B17}, {0x3086, 0x1826}, {0x3086, 0xA25C}, {0x3086, 0x0317}, {0x3086, 0x4427}, {0x3086, 0xF25F}, {0x3086, 0x2809}, {0x3086, 0x1714}, {0x3086, 0x2808}, {0x3086, 0x1701}, {0x3086, 0x4D1A}, {0x3086, 0x2683}, {0x3086, 0x1701}, {0x3086, 0x27FA}, {0x3086, 0x45A0}, {0x3086, 0x1707}, {0x3086, 0x27FB}, {0x3086, 0x1729}, {0x3086, 0x4580}, {0x3086, 0x1708}, {0x3086, 0x27FA}, {0x3086, 0x1728}, {0x3086, 0x5D17}, {0x3086, 0x0E26}, {0x3086, 0x8153}, {0x3086, 0x0117}, {0x3086, 0xE653}, {0x3086, 0x0217}, {0x3086, 0x1026}, {0x3086, 0x8326}, {0x3086, 0x8248}, {0x3086, 0x4D4E}, {0x3086, 0x2809}, {0x3086, 0x4C0B}, {0x3086, 0x6017}, {0x3086, 0x2027}, {0x3086, 0xF217}, {0x3086, 0x535F}, {0x3086, 0x2808}, {0x3086, 0x164D}, {0x3086, 0x1A17}, {0x3086, 0x0127}, {0x3086, 0xFA26}, {0x3086, 0x035C}, {0x3086, 0x0145}, {0x3086, 0x4027}, {0x3086, 0x9817}, {0x3086, 0x2A4A}, {0x3086, 0x0A43}, {0x3086, 0x160B}, {0x3086, 0x4327}, {0x3086, 0x9C45}, {0x3086, 0x6017}, {0x3086, 0x0727}, {0x3086, 0x9D17}, {0x3086, 0x2545}, {0x3086, 0x4017}, {0x3086, 0x0827}, {0x3086, 0x985D}, {0x3086, 0x2645}, {0x3086, 0x4B17}, {0x3086, 0x0A28}, {0x3086, 0x0853}, {0x3086, 0x0D52}, {0x3086, 0x5112}, {0x3086, 0x4460}, {0x3086, 0x184A}, {0x3086, 0x0343}, {0x3086, 0x1604}, {0x3086, 0x4316}, {0x3086, 0x5843}, {0x3086, 0x1659}, {0x3086, 0x4316}, {0x3086, 0x5A43}, {0x3086, 0x165B}, {0x3086, 0x4327}, {0x3086, 0x9C45}, {0x3086, 0x6017}, {0x3086, 0x0727}, {0x3086, 0x9D17}, {0x3086, 0x2545}, {0x3086, 0x4017}, {0x3086, 0x1027}, {0x3086, 0x9817}, {0x3086, 0x2022}, {0x3086, 0x4B12}, {0x3086, 0x442C}, {0x3086, 0x2C2C}, {0x3086, 0x2C00}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, {0x3086, 0x0000}, /* stream on */ {0x301A, 0x0058}, {AR0330_TABLE_WAIT_MS, AR0330_WAIT_MS}, {0x3088, 0x80BA}, {0x3086, 0x0253}, {0x30CE, 0x0010}, {0x301A, 0x015C}, {AR0330_TABLE_END, 0x00} }; static struct ar0330_reg mode_1280x960[] = { {0x3052, 0xa114}, {0x304A, 0x0070}, {AR0330_TABLE_WAIT_MS, AR0330_WAIT_MS}, {0x301A, 0x0058}, {0x302A, 0x0005}, {0x302C, 0x0004}, {0x302E, 0x0003}, {0x3030, 0x005F}, {0x3036, 0x000A}, {0x3038, 0x0001}, {0x31AC, 0x0A0A}, {0x31AE, 0x0201}, {0x31B0, 0x003D}, {0x31B2, 0x0018}, {0x31B4, 0x4F56}, {0x31B6, 0x4214}, {0x31B8, 0x308B}, {0x31BA, 0x028A}, {0x31BC, 0x8008}, {0x3002, 0x0126}, {0x3004, 0x0206}, {0x3006, 0x04E5}, {0x3008, 0x0705}, {0x300A, 0x0449}, {0x300C, 0x0482}, {0x3012, 0x0448}, {0x3014, 0x0000}, {0x30A2, 0x0001}, {0x30A6, 0x0001}, {0x3040, 0x0000}, {0x3042, 0x0000}, {0x30BA, 0x006C}, {0x31E0, 0x0303}, {0x3064, 0x1802}, {0x3ED2, 0x0146}, {0x3ED4, 0x8F6C}, {0x3ED6, 0x66CC}, {0x3ED8, 0x8C42}, {0x3EDA, 0x88BC}, {0x3EDC, 0xAA63}, {0x305E, 0x00A0}, {0x3088, 0x80BA}, {0x3086, 0x0253}, {0x30CE, 0x0010}, {0x301A, 0x035C}, {AR0330_TABLE_END, 0x00} }; enum { AR0330_MODE_2304X1536, AR0330_MODE_1280X720, AR0330_MODE_1280X960, }; static struct ar0330_reg *mode_table[] = { [AR0330_MODE_2304X1536] = mode_2304x1536, [AR0330_MODE_1280X720] = mode_1280x720, [AR0330_MODE_1280X960] = mode_1280x960, }; static inline void msleep_range(unsigned int delay_base) { usleep_range(delay_base*1000, delay_base*1000+500); } static inline void ar0330_get_frame_length_regs(struct ar0330_reg *regs, u32 frame_length) { regs->addr = AR0330_FRAME_LENGTH_ADDR; regs->val = frame_length & 0xffff; } static inline void ar0330_get_coarse_time_regs(struct ar0330_reg *regs, u32 coarse_time) { regs->addr = AR0330_COARSE_TIME_ADDR; regs->val = coarse_time & 0xffff; } static inline void ar0330_get_gain_reg(struct ar0330_reg *regs, u16 gain) { regs->addr = AR0330_GAIN_ADDR; regs->val = gain; } static inline int ar0330_read_reg(struct ar0330_info *info, u16 addr, u16 *val) { return regmap_read(info->regmap, addr, (unsigned int *) val); } static int ar0330_write_reg(struct ar0330_info *info, u16 addr, u16 val) { int err; err = regmap_write(info->regmap, addr, val); if (err) pr_err("%s:i2c write failed, %x = %x\n", __func__, addr, val); return err; } static int ar0330_write_table(struct ar0330_info *info, const struct ar0330_reg table[], const struct ar0330_reg override_list[], int num_override_regs) { int err; const struct ar0330_reg *next; int i; u16 val; for (next = table; next->addr != AR0330_TABLE_END; next++) { if (next->addr == AR0330_TABLE_WAIT_MS) { msleep_range(next->val); 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; } } } err = ar0330_write_reg(info, next->addr, val); if (err) { pr_err("%s:ar0330_write_table:%d", __func__, err); return err; } } return 0; } static int ar0330_get_flash_cap(struct ar0330_info *info) { struct ar0330_flash_control *fctl; dev_dbg(&info->i2c_client->dev, "%s: %p\n", __func__, info->pdata); if (info->pdata) { fctl = &info->pdata->flash_cap; dev_dbg(&info->i2c_client->dev, "edg: %x, st: %x, rpt: %x, dl: %x\n", fctl->edge_trig_en, fctl->start_edge, fctl->repeat, fctl->delay_frm); if (fctl->enable) return 0; } return -ENODEV; } static inline int ar0330_set_flash_control( struct ar0330_info *info, struct ar0330_flash_control *fc) { dev_dbg(&info->i2c_client->dev, "%s\n", __func__); return 0; } static int ar0330_set_mode(struct ar0330_info *info, struct ar0330_mode *mode) { int sensor_mode; int err; struct ar0330_reg reg_list[8]; pr_info("%s: xres %u yres %u framelength %u coarsetime %u gain %u\n", __func__, mode->xres, mode->yres, mode->frame_length, mode->coarse_time, mode->gain); if (mode->xres == 2304 && mode->yres == 1520) { sensor_mode = AR0330_MODE_2304X1536; } else if (mode->xres == 1280 && mode->yres == 720) { sensor_mode = AR0330_MODE_1280X720; } else if (mode->xres == 1280 && mode->yres == 960) { sensor_mode = AR0330_MODE_1280X960; } else { pr_err("%s: invalid resolution supplied to set mode %d %d\n", __func__, mode->xres, mode->yres); return -EINVAL; } /* get a list of override regs for the asking frame length, */ /* coarse integration time, and gain. */ ar0330_get_frame_length_regs(reg_list, mode->frame_length); ar0330_get_coarse_time_regs(reg_list + 1, mode->coarse_time); ar0330_get_gain_reg(reg_list + 2, mode->gain); err = ar0330_write_table(info, mode_table[sensor_mode], reg_list, 3); if (err) return err; info->mode = sensor_mode; pr_info("[AR0330]: stream on.\n"); return 0; } static int ar0330_get_status(struct ar0330_info *info, u8 *dev_status) { *dev_status = 0; return 0; } static int ar0330_set_frame_length(struct ar0330_info *info, u32 frame_length, bool group_hold) { struct ar0330_reg reg_list[2]; int i = 0; int ret; ar0330_get_frame_length_regs(reg_list, frame_length); for (i = 0; i < 1; i++) { ret = ar0330_write_reg(info, reg_list[i].addr, reg_list[i].val); if (ret) return ret; } return 0; } static int ar0330_set_coarse_time(struct ar0330_info *info, u32 coarse_time, bool group_hold) { int ret; struct ar0330_reg reg_list[2]; int i = 0; ar0330_get_coarse_time_regs(reg_list, coarse_time); for (i = 0; i < 1; i++) { ret = ar0330_write_reg(info, reg_list[i].addr, reg_list[i].val); if (ret) return ret; } return 0; } static int ar0330_set_gain(struct ar0330_info *info, u16 gain, bool group_hold) { int ret; struct ar0330_reg reg_list; ar0330_get_gain_reg(®_list, gain); ret = ar0330_write_reg(info, reg_list.addr, reg_list.val); if (ret) return ret; return 0; } static int ar0330_set_group_hold(struct ar0330_info *info, struct ar0330_ae *ae) { int count = 0; bool group_hold_enabled = false; if (ae->gain_enable) count++; if (ae->coarse_time_enable) count++; if (ae->frame_length_enable) count++; if (count >= 2) group_hold_enabled = true; if (ae->gain_enable) ar0330_set_gain(info, ae->gain, false); if (ae->coarse_time_enable) ar0330_set_coarse_time(info, ae->coarse_time, false); if (ae->frame_length_enable) ar0330_set_frame_length(info, ae->frame_length, false); return 0; } static int ar0330_get_sensor_id(struct ar0330_info *info) { int ret = 0; pr_info("%s\n", __func__); if (info->sensor_data.fuse_id_size) return 0; /* Note 1: If the sensor does not have power at this point Need to supply the power, e.g. by calling power on function */ /*ret |= ar0330_write_reg(info, 0x3B02, 0x00); ret |= ar0330_write_reg(info, 0x3B00, 0x01); for (i = 0; i < 9; i++) { ret |= ar0330_read_reg(info, 0x3B24 + i, &bak); info->sensor_data.fuse_id[i] = bak; } if (!ret) info->sensor_data.fuse_id_size = i;*/ /* Note 2: Need to clean up any action carried out in Note 1 */ return ret; } static void ar0330_mclk_disable(struct ar0330_info *info) { dev_dbg(&info->i2c_client->dev, "%s: disable MCLK\n", __func__); clk_disable_unprepare(info->mclk); } static int ar0330_mclk_enable(struct ar0330_info *info) { int err; unsigned long mclk_init_rate = 24000000; dev_dbg(&info->i2c_client->dev, "%s: enable MCLK with %lu Hz\n", __func__, mclk_init_rate); err = clk_set_rate(info->mclk, mclk_init_rate); if (!err) err = clk_prepare_enable(info->mclk); return err; } static long ar0330_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int err = 0; struct ar0330_info *info = file->private_data; switch (cmd) { case AR0330_IOCTL_SET_POWER: if (!info->pdata) break; if (arg && info->pdata->power_on) { err = ar0330_mclk_enable(info); if (!err) err = info->pdata->power_on(&info->power); if (err < 0) ar0330_mclk_disable(info); } if (!arg && info->pdata->power_off) { info->pdata->power_off(&info->power); ar0330_mclk_disable(info); } break; case AR0330_IOCTL_SET_MODE: { struct ar0330_mode mode; if (copy_from_user(&mode, (const void __user *)arg, sizeof(struct ar0330_mode))) { pr_err("%s:Failed to get mode from user.\n", __func__); return -EFAULT; } return ar0330_set_mode(info, &mode); } case AR0330_IOCTL_SET_FRAME_LENGTH: return ar0330_set_frame_length(info, (u32)arg, true); case AR0330_IOCTL_SET_COARSE_TIME: return ar0330_set_coarse_time(info, (u32)arg, true); case AR0330_IOCTL_SET_GAIN: return ar0330_set_gain(info, (u16)arg, true); case AR0330_IOCTL_GET_STATUS: { u8 status; err = ar0330_get_status(info, &status); if (err) return err; if (copy_to_user((void __user *)arg, &status, 1)) { pr_err("%s:Failed to copy status to user\n", __func__); return -EFAULT; } return 0; } case AR0330_IOCTL_GET_SENSORDATA: { err = ar0330_get_sensor_id(info); if (err) { pr_err("%s:Failed to get fuse id info.\n", __func__); return err; } if (copy_to_user((void __user *)arg, &info->sensor_data, sizeof(struct ar0330_sensordata))) { pr_info("%s:Failed to copy fuse id to user space\n", __func__); return -EFAULT; } return 0; } case AR0330_IOCTL_SET_GROUP_HOLD: { struct ar0330_ae ae; if (copy_from_user(&ae, (const void __user *)arg, sizeof(struct ar0330_ae))) { pr_info("%s:fail group hold\n", __func__); return -EFAULT; } return ar0330_set_group_hold(info, &ae); } case AR0330_IOCTL_SET_FLASH_MODE: { struct ar0330_flash_control values; dev_dbg(&info->i2c_client->dev, "AR0330_IOCTL_SET_FLASH_MODE\n"); if (copy_from_user(&values, (const void __user *)arg, sizeof(struct ar0330_flash_control))) { err = -EFAULT; break; } err = ar0330_set_flash_control(info, &values); break; } case AR0330_IOCTL_GET_FLASH_CAP: err = ar0330_get_flash_cap(info); break; default: pr_err("%s:unknown cmd.\n", __func__); err = -EINVAL; } return err; } static int ar0330_power_on(struct ar0330_power_rail *pw) { int err; struct ar0330_info *info = container_of(pw, struct ar0330_info, power); if (unlikely(WARN_ON(!pw || !pw->iovdd || !pw->avdd || !pw->dvdd))) return -EFAULT; gpio_set_value(info->pdata->cam2_gpio, 0); usleep_range(10, 20); err = regulator_enable(pw->avdd); if (err) goto ar0330_avdd_fail; err = regulator_enable(pw->dvdd); if (err) goto ar0330_dvdd_fail; err = regulator_enable(pw->iovdd); if (err) goto ar0330_iovdd_fail; usleep_range(1, 2); gpio_set_value(info->pdata->cam2_gpio, 1); usleep_range(300, 310); return 1; ar0330_iovdd_fail: regulator_disable(pw->dvdd); ar0330_dvdd_fail: regulator_disable(pw->avdd); ar0330_avdd_fail: pr_err("%s failed.\n", __func__); return -ENODEV; } static int ar0330_power_off(struct ar0330_power_rail *pw) { struct ar0330_info *info = container_of(pw, struct ar0330_info, power); if (unlikely(WARN_ON(!pw || !pw->iovdd || !pw->avdd || !pw->dvdd))) return -EFAULT; usleep_range(1, 2); gpio_set_value(info->pdata->cam2_gpio, 0); usleep_range(1, 2); regulator_disable(pw->iovdd); regulator_disable(pw->dvdd); regulator_disable(pw->avdd); return 0; } static int ar0330_open(struct inode *inode, struct file *file) { struct miscdevice *miscdev = file->private_data; struct ar0330_info *info; info = container_of(miscdev, struct ar0330_info, miscdev_info); /* check if the device is in use */ if (atomic_xchg(&info->in_use, 1)) { pr_info("%s:BUSY!\n", __func__); return -EBUSY; } file->private_data = info; return 0; } static int ar0330_release(struct inode *inode, struct file *file) { struct ar0330_info *info = file->private_data; file->private_data = NULL; /* warn if device is already released */ WARN_ON(!atomic_xchg(&info->in_use, 0)); return 0; } static int ar0330_power_put(struct ar0330_power_rail *pw) { if (unlikely(!pw)) return -EFAULT; if (likely(pw->avdd)) regulator_put(pw->avdd); if (likely(pw->iovdd)) regulator_put(pw->iovdd); if (likely(pw->dvdd)) regulator_put(pw->dvdd); pw->avdd = NULL; pw->iovdd = NULL; pw->dvdd = NULL; return 0; } static int ar0330_regulator_get(struct ar0330_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 ar0330_power_get(struct ar0330_info *info) { struct ar0330_power_rail *pw = &info->power; int err = 0; err |= ar0330_regulator_get(info, &pw->avdd, "vana"); /* ananlog 2.7v */ err |= ar0330_regulator_get(info, &pw->dvdd, "vdig"); /* digital 1.2v */ err |= ar0330_regulator_get(info, &pw->iovdd, "vif"); /* IO 1.8v */ return err; } static const struct file_operations ar0330_fileops = { .owner = THIS_MODULE, .open = ar0330_open, .unlocked_ioctl = ar0330_ioctl, .release = ar0330_release, }; static struct miscdevice ar0330_device = { .minor = MISC_DYNAMIC_MINOR, .name = "ar0330", .fops = &ar0330_fileops, }; static struct of_device_id ar0330_of_match[] = { { .compatible = "nvidia,ar0330", }, { }, }; MODULE_DEVICE_TABLE(of, ar0330_of_match); static struct ar0330_platform_data *ar0330_parse_dt(struct i2c_client *client) { struct device_node *np = client->dev.of_node; struct ar0330_platform_data *board_info_pdata; const struct of_device_id *match; match = of_match_device(ar0330_of_match, &client->dev); if (!match) { dev_err(&client->dev, "Failed to find matching dt id\n"); return NULL; } board_info_pdata = devm_kzalloc(&client->dev, sizeof(*board_info_pdata), GFP_KERNEL); if (!board_info_pdata) { dev_err(&client->dev, "Failed to allocate pdata\n"); return NULL; } board_info_pdata->cam2_gpio = of_get_named_gpio(np, "cam1-gpios", 0); board_info_pdata->ext_reg = of_property_read_bool(np, "nvidia,ext_reg"); board_info_pdata->power_on = ar0330_power_on; board_info_pdata->power_off = ar0330_power_off; return board_info_pdata; } static int ar0330_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct ar0330_info *info; int err; const char *mclk_name; pr_err("[AR0330]: probing sensor.\n"); info = devm_kzalloc(&client->dev, sizeof(struct ar0330_info), GFP_KERNEL); if (!info) { pr_err("%s:Unable to allocate memory!\n", __func__); return -ENOMEM; } info->regmap = devm_regmap_init_i2c(client, &sensor_regmap_config); if (IS_ERR(info->regmap)) { dev_err(&client->dev, "regmap init failed: %ld\n", PTR_ERR(info->regmap)); return -ENODEV; } if (client->dev.of_node) info->pdata = ar0330_parse_dt(client); else info->pdata = client->dev.platform_data; if (!info->pdata) { pr_err("[AR0330]:%s:Unable to get platform data\n", __func__); return -EFAULT; } info->i2c_client = client; atomic_set(&info->in_use, 0); info->mode = -1; mclk_name = info->pdata->mclk_name ? info->pdata->mclk_name : "default_mclk"; info->mclk = devm_clk_get(&client->dev, mclk_name); if (IS_ERR(info->mclk)) { dev_err(&client->dev, "%s: unable to get clock %s\n", __func__, mclk_name); return PTR_ERR(info->mclk); } if (info->pdata->dev_name != NULL) strncpy(info->devname, info->pdata->dev_name, sizeof(info->devname) - 1); else strncpy(info->devname, "ar0330", sizeof(info->devname) - 1); ar0330_power_get(info); memcpy(&info->miscdev_info, &ar0330_device, sizeof(struct miscdevice)); info->miscdev_info.name = info->devname; err = misc_register(&info->miscdev_info); if (err) { pr_err("%s:Unable to register misc device!\n", __func__); goto ar0330_probe_fail; } i2c_set_clientdata(client, info); mutex_init(&info->ar0330_camera_lock); pr_err("[AR0330]: end of probing sensor.\n"); return 0; ar0330_probe_fail: ar0330_power_put(&info->power); return err; } static int ar0330_remove(struct i2c_client *client) { struct ar0330_info *info; info = i2c_get_clientdata(client); misc_deregister(&ar0330_device); mutex_destroy(&info->ar0330_camera_lock); ar0330_power_put(&info->power); return 0; } static const struct i2c_device_id ar0330_id[] = { { "ar0330", 0 }, { "ar0330.1", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, ar0330_id); static struct i2c_driver ar0330_i2c_driver = { .driver = { .name = "ar0330", .owner = THIS_MODULE, }, .probe = ar0330_probe, .remove = ar0330_remove, .id_table = ar0330_id, }; static int __init ar0330_init(void) { pr_info("[AR0330] sensor driver loading\n"); return i2c_add_driver(&ar0330_i2c_driver); } static void __exit ar0330_exit(void) { i2c_del_driver(&ar0330_i2c_driver); } module_init(ar0330_init); module_exit(ar0330_exit);