blob: 3fc4acd958a94a367ed0c45b3504179c5ec621b3 [file] [log] [blame]
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/i2c.h>
#include <linux/clk.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <media/ov5693.h>
#define OV5693_ID 0x5693
#define OV5693_SENSOR_TYPE NVC_IMAGER_TYPE_RAW
#define OV5693_RES_CHG_WAIT_TIME_MS 100
#define OV5693_SIZEOF_I2C_BUF 16
#define OV5693_TABLE_WAIT_MS 0
#define OV5693_TABLE_END 1
#define OV5693_TABLE_RESET 2
#define OV5693_TABLE_RESET_TIMEOUT 50
#define OV5693_LENS_MAX_APERTURE 0 /* _INT2FLOAT_DIVISOR */
#define OV5693_LENS_FNUMBER 0 /* _INT2FLOAT_DIVISOR */
#define OV5693_LENS_FOCAL_LENGTH 6120 /* _INT2FLOAT_DIVISOR */
#define OV5693_LENS_VIEW_ANGLE_H 60000 /* _INT2FLOAT_DIVISOR */
#define OV5693_LENS_VIEW_ANGLE_V 60000 /* _INT2FLOAT_DIVISOR */
static struct nvc_gpio_init ov5693_gpio[] = {
{ OV5693_GPIO_TYPE_PWRDN, GPIOF_OUT_INIT_LOW, "pwrdn", false, true, },
};
struct ov5693_info {
atomic_t in_use;
struct i2c_client *i2c_client;
struct ov5693_platform_data *pdata;
struct clk *mclk;
struct miscdevice miscdev;
int pwr_api;
int pwr_dev;
struct nvc_gpio gpio[ARRAY_SIZE(ov5693_gpio)];
struct ov5693_power_rail regulators;
bool power_on;
u32 mode_index;
bool mode_valid;
bool mode_enable;
unsigned test_pattern;
struct nvc_imager_static_nvc sdata;
u8 bin_en;
struct ov5693_fuseid fuseid;
struct regmap *regmap;
struct regulator *ext_vcm_vdd;
};
struct ov5693_reg {
u16 addr;
u16 val;
};
struct ov5693_mode_data {
struct nvc_imager_mode sensor_mode;
struct nvc_imager_dynamic_nvc sensor_dnvc;
struct ov5693_reg *p_mode_i2c;
};
static struct ov5693_platform_data ov5693_dflt_pdata = {
.cfg = 0,
.num = 0,
.dev_name = "camera",
};
/*
* NOTE: static vs dynamic
* If a member in the nvc_imager_static_nvc structure is not actually
* static data, then leave blank and add the parameter to the parameter
* read function that dynamically reads the data. The NVC user driver
* will call the parameter read for the data if the member data is 0.
* If the dynamic data becomes static during probe (a one time read
* such as device ID) then add the dynamic read to the _sdata_init
* function.
*/
static struct nvc_imager_static_nvc ov5693_dflt_sdata = {
.api_version = NVC_IMAGER_API_STATIC_VER,
.sensor_type = OV5693_SENSOR_TYPE,
.bits_per_pixel = 10,
.sensor_id = OV5693_ID,
.sensor_id_minor = 0,
.focal_len = OV5693_LENS_FOCAL_LENGTH,
.max_aperture = OV5693_LENS_MAX_APERTURE,
.fnumber = OV5693_LENS_FNUMBER,
.view_angle_h = OV5693_LENS_VIEW_ANGLE_H,
.view_angle_v = OV5693_LENS_VIEW_ANGLE_V,
.res_chg_wait_time = OV5693_RES_CHG_WAIT_TIME_MS,
};
static const struct ov5693_reg ov5693_2592x1944_i2c[] = {
{OV5693_TABLE_RESET, 0},/* Including sw reset */
{0x3001, 0x0a},
{0x3002, 0x80},
{0x3006, 0x00},
{0x3011, 0x21},
{0x3012, 0x09},
{0x3013, 0x10},
{0x3014, 0x00},
{0x3015, 0x08},
{0x3016, 0xf0},
{0x3017, 0xf0},
{0x3018, 0xf0},
{0x301b, 0xb4},
{0x301d, 0x02},
{0x3021, 0x00},
{0x3022, 0x01},
{0x3028, 0x44},
{0x3090, 0x02},
{0x3091, 0x0e},
{0x3092, 0x00},
{0x3093, 0x00},
{0x3098, 0x03},
{0x3099, 0x1e},
{0x309a, 0x02},
{0x309b, 0x01},
{0x309c, 0x00},
{0x30a0, 0xd2},
{0x30a2, 0x01},
{0x30b2, 0x00},
{0x30b3, 0x68},
{0x30b4, 0x03},
{0x30b5, 0x04},
{0x30b6, 0x01},
{0x3104, 0x21},
{0x3106, 0x00},
{0x3400, 0x04},
{0x3401, 0x00},
{0x3402, 0x04},
{0x3403, 0x00},
{0x3404, 0x04},
{0x3405, 0x00},
{0x3406, 0x01},
{0x3500, 0x00},
{0x3501, 0x7b},
{0x3502, 0x00},
{0x3503, 0x07},
{0x3504, 0x00},
{0x3505, 0x00},
{0x3506, 0x00},
{0x3507, 0x02},
{0x3508, 0x00},
{0x3509, 0x08},
{0x350a, 0x00},
{0x350b, 0x40},
{0x3601, 0x0a},
{0x3602, 0x18},
{0x3612, 0x80},
{0x3620, 0x54},
{0x3621, 0xc7},
{0x3622, 0x0f},
{0x3625, 0x10},
{0x3630, 0x55},
{0x3631, 0xf4},
{0x3632, 0x00},
{0x3633, 0x34},
{0x3634, 0x02},
{0x364d, 0x0d},
{0x364f, 0xdd},
{0x3660, 0x04},
{0x3662, 0x10},
{0x3663, 0xf1},
{0x3665, 0x00},
{0x3666, 0x20},
{0x3667, 0x00},
{0x366a, 0x80},
{0x3680, 0xe0},
{0x3681, 0x00},
{0x3700, 0x42},
{0x3701, 0x14},
{0x3702, 0xa0},
{0x3703, 0xd8},
{0x3704, 0x78},
{0x3705, 0x02},
{0x3708, 0xe2},
{0x3709, 0xc3},
{0x370a, 0x00},
{0x370b, 0x20},
{0x370c, 0x0c},
{0x370d, 0x11},
{0x370e, 0x00},
{0x370f, 0x40},
{0x3710, 0x00},
{0x371a, 0x1c},
{0x371b, 0x05},
{0x371c, 0x01},
{0x371e, 0xa1},
{0x371f, 0x0c},
{0x3721, 0x00},
{0x3726, 0x00},
{0x372a, 0x01},
{0x3730, 0x10},
{0x3738, 0x22},
{0x3739, 0xe5},
{0x373a, 0x50},
{0x373b, 0x02},
{0x373c, 0x41},
{0x373f, 0x02},
{0x3740, 0x42},
{0x3741, 0x02},
{0x3742, 0x18},
{0x3743, 0x01},
{0x3744, 0x02},
{0x3747, 0x10},
{0x374c, 0x04},
{0x3751, 0xf0},
{0x3752, 0x00},
{0x3753, 0x00},
{0x3754, 0xc0},
{0x3755, 0x00},
{0x3756, 0x1a},
{0x3758, 0x00},
{0x3759, 0x0f},
{0x376b, 0x44},
{0x375c, 0x04},
{0x3776, 0x00},
{0x377f, 0x08},
{0x3780, 0x22},
{0x3781, 0x0c},
{0x3784, 0x2c},
{0x3785, 0x1e},
{0x378f, 0xf5},
{0x3791, 0xb0},
{0x3795, 0x00},
{0x3796, 0x64},
{0x3797, 0x11},
{0x3798, 0x30},
{0x3799, 0x41},
{0x379a, 0x07},
{0x379b, 0xb0},
{0x379c, 0x0c},
{0x37c5, 0x00},
{0x37c6, 0x00},
{0x37c7, 0x00},
{0x37c9, 0x00},
{0x37ca, 0x00},
{0x37cb, 0x00},
{0x37de, 0x00},
{0x37df, 0x00},
{0x3800, 0x00},
{0x3801, 0x00},
{0x3802, 0x00},
{0x3803, 0x00},
{0x3804, 0x0a},
{0x3805, 0x3f},
{0x3806, 0x07},
{0x3807, 0xa3},
{0x3808, 0x0a},
{0x3809, 0x20},
{0x380a, 0x07},
{0x380b, 0x98},
{0x380c, 0x0a},
{0x380d, 0x80},
{0x380e, 0x07},
{0x380f, 0xc0},
{0x3810, 0x00},
{0x3811, 0x02},
{0x3812, 0x00},
{0x3813, 0x02},
{0x3814, 0x11},
{0x3815, 0x11},
{0x3820, 0x00},
{0x3821, 0x1e},
{0x3823, 0x00},
{0x3824, 0x00},
{0x3825, 0x00},
{0x3826, 0x00},
{0x3827, 0x00},
{0x382a, 0x04},
{0x3a04, 0x06},
{0x3a05, 0x14},
{0x3a06, 0x00},
{0x3a07, 0xfe},
{0x3b00, 0x00},
{0x3b02, 0x00},
{0x3b03, 0x00},
{0x3b04, 0x00},
{0x3b05, 0x00},
{0x3d00, 0x00},
{0x3d01, 0x00},
{0x3d02, 0x00},
{0x3d03, 0x00},
{0x3d04, 0x00},
{0x3d05, 0x00},
{0x3d06, 0x00},
{0x3d07, 0x00},
{0x3d08, 0x00},
{0x3d09, 0x00},
{0x3d0a, 0x00},
{0x3d0b, 0x00},
{0x3d0c, 0x00},
{0x3d0d, 0x00},
{0x3d0e, 0x00},
{0x3d0f, 0x00},
{0x3d80, 0x00},
{0x3d81, 0x00},
{0x3d84, 0x00},
{0x3e07, 0x20},
{0x4000, 0x08},
{0x4001, 0x04},
{0x4002, 0x45},
{0x4004, 0x08},
{0x4005, 0x18},
{0x4006, 0x20},
{0x4008, 0x24},
{0x4009, 0x10},
{0x400c, 0x00},
{0x400d, 0x00},
{0x4058, 0x00},
{0x4101, 0xb2},
{0x4303, 0x00},
{0x4304, 0x08},
{0x4307, 0x30},
{0x4311, 0x04},
{0x4315, 0x01},
{0x4511, 0x05},
{0x4512, 0x01},
{0x4806, 0x00},
{0x4816, 0x52},
{0x481f, 0x30},
{0x4826, 0x2c},
{0x4831, 0x64},
{0x4d00, 0x04},
{0x4d01, 0x71},
{0x4d02, 0xfd},
{0x4d03, 0xf5},
{0x4d04, 0x0c},
{0x4d05, 0xcc},
{0x4837, 0x09},
{0x5000, 0x06},
{0x5001, 0x01},
{0x5002, 0x00},
{0x5003, 0x20},
{0x5046, 0x0a},
{0x5013, 0x00},
{0x5046, 0x0a},
{0x5780, 0x1c},
{0x5786, 0x20},
{0x5787, 0x10},
{0x5788, 0x18},
{0x578a, 0x04},
{0x578b, 0x02},
{0x578c, 0x02},
{0x578e, 0x06},
{0x578f, 0x02},
{0x5790, 0x02},
{0x5791, 0xff},
{0x5842, 0x01},
{0x5843, 0x2b},
{0x5844, 0x01},
{0x5845, 0x92},
{0x5846, 0x01},
{0x5847, 0x8f},
{0x5848, 0x01},
{0x5849, 0x0c},
{0x5e00, 0x00},
{0x5e10, 0x0c},
{0x0100, 0x01},
{OV5693_TABLE_END, 0x0000}
};
static const struct ov5693_reg ov5693_1296x972_i2c[] = {
{OV5693_TABLE_RESET, 0},/* Including sw reset */
{0x0103, 0x01},
{0x3001, 0x0a},
{0x3002, 0x80},
{0x3006, 0x00},
{0x3011, 0x21},
{0x3012, 0x09},
{0x3013, 0x10},
{0x3014, 0x00},
{0x3015, 0x08},
{0x3016, 0xf0},
{0x3017, 0xf0},
{0x3018, 0xf0},
{0x301b, 0xb4},
{0x301d, 0x02},
{0x3021, 0x00},
{0x3022, 0x01},
{0x3028, 0x44},
{0x3098, 0x03},
{0x3099, 0x1e},
{0x309a, 0x02},
{0x309b, 0x01},
{0x309c, 0x00},
{0x30a0, 0xd2},
{0x30a2, 0x01},
{0x30b2, 0x00},
{0x30b3, 0x64},
{0x30b4, 0x03},
{0x30b5, 0x04},
{0x30b6, 0x01},
{0x3104, 0x21},
{0x3106, 0x00},
{0x3400, 0x04},
{0x3401, 0x00},
{0x3402, 0x04},
{0x3403, 0x00},
{0x3404, 0x04},
{0x3405, 0x00},
{0x3406, 0x01},
{0x3500, 0x00},
{0x3501, 0x7b},
{0x3502, 0x00},
{0x3503, 0x07},
{0x3504, 0x00},
{0x3505, 0x00},
{0x3506, 0x00},
{0x3507, 0x02},
{0x3508, 0x00},
{0x3509, 0x08},
{0x350a, 0x00},
{0x350b, 0x40},
{0x3601, 0x0a},
{0x3602, 0x38},
{0x3612, 0x80},
{0x3620, 0x54},
{0x3621, 0xc7},
{0x3622, 0x0f},
{0x3625, 0x10},
{0x3630, 0x55},
{0x3631, 0xf4},
{0x3632, 0x00},
{0x3633, 0x34},
{0x3634, 0x02},
{0x364d, 0x0d},
{0x364f, 0xdd},
{0x3660, 0x04},
{0x3662, 0x10},
{0x3663, 0xf1},
{0x3665, 0x00},
{0x3666, 0x20},
{0x3667, 0x00},
{0x366a, 0x80},
{0x3680, 0xe0},
{0x3681, 0x00},
{0x3700, 0x42},
{0x3701, 0x14},
{0x3702, 0xa0},
{0x3703, 0xd8},
{0x3704, 0x78},
{0x3705, 0x02},
{0x3708, 0xe6},
{0x3709, 0xc3},
{0x370a, 0x00},
{0x370b, 0x20},
{0x370c, 0x0c},
{0x370d, 0x11},
{0x370e, 0x00},
{0x370f, 0x40},
{0x3710, 0x00},
{0x371a, 0x1c},
{0x371b, 0x05},
{0x371c, 0x01},
{0x371e, 0xa1},
{0x371f, 0x0c},
{0x3721, 0x00},
{0x3724, 0x10},
{0x3726, 0x00},
{0x372a, 0x01},
{0x3730, 0x10},
{0x3738, 0x22},
{0x3739, 0xe5},
{0x373a, 0x50},
{0x373b, 0x02},
{0x373c, 0x41},
{0x373f, 0x02},
{0x3740, 0x42},
{0x3741, 0x02},
{0x3742, 0x18},
{0x3743, 0x01},
{0x3744, 0x02},
{0x3747, 0x10},
{0x374c, 0x04},
{0x3751, 0xf0},
{0x3752, 0x00},
{0x3753, 0x00},
{0x3754, 0xc0},
{0x3755, 0x00},
{0x3756, 0x1a},
{0x3758, 0x00},
{0x3759, 0x0f},
{0x376b, 0x44},
{0x375c, 0x04},
{0x3774, 0x10},
{0x3776, 0x00},
{0x377f, 0x08},
{0x3780, 0x22},
{0x3781, 0x0c},
{0x3784, 0x2c},
{0x3785, 0x1e},
{0x378f, 0xf5},
{0x3791, 0xb0},
{0x3795, 0x00},
{0x3796, 0x64},
{0x3797, 0x11},
{0x3798, 0x30},
{0x3799, 0x41},
{0x379a, 0x07},
{0x379b, 0xb0},
{0x379c, 0x0c},
{0x37c5, 0x00},
{0x37c6, 0x00},
{0x37c7, 0x00},
{0x37c9, 0x00},
{0x37ca, 0x00},
{0x37cb, 0x00},
{0x37de, 0x00},
{0x37df, 0x00},
{0x3800, 0x00},
{0x3801, 0x00},
{0x3802, 0x00},
{0x3803, 0x00},
{0x3804, 0x0a},
{0x3805, 0x3f},
{0x3806, 0x07},
{0x3807, 0xa3},
{0x3808, 0x05},
{0x3809, 0x10},
{0x380a, 0x03},
{0x380b, 0xcc},
{0x380c, 0x0a},
{0x380d, 0x80},
{0x380e, 0x07},
{0x380f, 0xc0},
{0x3810, 0x00},
{0x3811, 0x02},
{0x3812, 0x00},
{0x3813, 0x02},
{0x3814, 0x31},
{0x3815, 0x31},
{0x3820, 0x01},
{0x3821, 0x1f},
{0x3823, 0x00},
{0x3824, 0x00},
{0x3825, 0x00},
{0x3826, 0x00},
{0x3827, 0x00},
{0x382a, 0x04},
{0x3a04, 0x06},
{0x3a05, 0x14},
{0x3a06, 0x00},
{0x3a07, 0xfe},
{0x3b00, 0x00},
{0x3b02, 0x00},
{0x3b03, 0x00},
{0x3b04, 0x00},
{0x3b05, 0x00},
{0x3e07, 0x20},
{0x4000, 0x08},
{0x4001, 0x04},
{0x4002, 0x45},
{0x4004, 0x08},
{0x4005, 0x18},
{0x4006, 0x20},
{0x4008, 0x24},
{0x4009, 0x40},
{0x400c, 0x00},
{0x400d, 0x00},
{0x4058, 0x00},
{0x404e, 0x37},
{0x404f, 0x8f},
{0x4058, 0x00},
{0x4101, 0xb2},
{0x4303, 0x00},
{0x4304, 0x08},
{0x4307, 0x30},
{0x4311, 0x04},
{0x4315, 0x01},
{0x4511, 0x05},
{0x4512, 0x01},
{0x4806, 0x00},
{0x4816, 0x52},
{0x481f, 0x30},
{0x4826, 0x2c},
{0x4831, 0x64},
{0x4d00, 0x04},
{0x4d01, 0x71},
{0x4d02, 0xfd},
{0x4d03, 0xf5},
{0x4d04, 0x0c},
{0x4d05, 0xcc},
{0x4837, 0x0a},
{0x5000, 0x06},
{0x5001, 0x01},
{0x5002, 0x00},
{0x5003, 0x20},
{0x5046, 0x0a},
{0x5013, 0x00},
{0x5046, 0x0a},
{0x5780, 0x1c},
{0x5786, 0x20},
{0x5787, 0x10},
{0x5788, 0x18},
{0x578a, 0x04},
{0x578b, 0x02},
{0x578c, 0x02},
{0x578e, 0x06},
{0x578f, 0x02},
{0x5790, 0x02},
{0x5791, 0xff},
{0x5842, 0x01},
{0x5843, 0x2b},
{0x5844, 0x01},
{0x5845, 0x92},
{0x5846, 0x01},
{0x5847, 0x8f},
{0x5848, 0x01},
{0x5849, 0x0c},
{0x5e00, 0x00},
{0x5e10, 0x0c},
{0x0100, 0x01},
{OV5693_TABLE_END, 0x0000}
};
static const struct ov5693_reg ov5693_1920x1080_i2c[] = {
{OV5693_TABLE_RESET, 0x0},/*, 0xIncluding, 0xsw, 0xreset, 0x*/
{0x3001, 0x0a},
{0x3002, 0x80},
{0x3006, 0x00},
{0x3011, 0x21},
{0x3012, 0x09},
{0x3013, 0x10},
{0x3014, 0x00},
{0x3015, 0x08},
{0x3016, 0xf0},
{0x3017, 0xf0},
{0x3018, 0xf0},
{0x301b, 0xb4},
{0x301d, 0x02},
{0x3021, 0x00},
{0x3022, 0x01},
{0x3028, 0x44},
{0x3098, 0x03},
{0x3099, 0x1e},
{0x309a, 0x02},
{0x309b, 0x01},
{0x309c, 0x00},
{0x30a0, 0xd2},
{0x30a2, 0x01},
{0x30b2, 0x00},
{0x30b3, 0x64},
{0x30b4, 0x03},
{0x30b5, 0x04},
{0x30b6, 0x01},
{0x3104, 0x21},
{0x3106, 0x00},
{0x3400, 0x04},
{0x3401, 0x00},
{0x3402, 0x04},
{0x3403, 0x00},
{0x3404, 0x04},
{0x3405, 0x00},
{0x3406, 0x01},
{0x3500, 0x00},
{0x3501, 0x7b},
{0x3502, 0x00},
{0x3503, 0x07},
{0x3504, 0x00},
{0x3505, 0x00},
{0x3506, 0x00},
{0x3507, 0x02},
{0x3508, 0x00},
{0x3509, 0x08},
{0x350a, 0x00},
{0x350b, 0x40},
{0x3601, 0x0a},
{0x3602, 0x38},
{0x3612, 0x80},
{0x3620, 0x54},
{0x3621, 0xc7},
{0x3622, 0x0f},
{0x3625, 0x10},
{0x3630, 0x55},
{0x3631, 0xf4},
{0x3632, 0x00},
{0x3633, 0x34},
{0x3634, 0x02},
{0x364d, 0x0d},
{0x364f, 0xdd},
{0x3660, 0x04},
{0x3662, 0x10},
{0x3663, 0xf1},
{0x3665, 0x00},
{0x3666, 0x20},
{0x3667, 0x00},
{0x366a, 0x80},
{0x3680, 0xe0},
{0x3681, 0x00},
{0x3700, 0x42},
{0x3701, 0x14},
{0x3702, 0xa0},
{0x3703, 0xd8},
{0x3704, 0x78},
{0x3705, 0x02},
{0x3708, 0xe2},
{0x3709, 0xc3},
{0x370a, 0x00},
{0x370b, 0x20},
{0x370c, 0x0c},
{0x370d, 0x11},
{0x370e, 0x00},
{0x370f, 0x40},
{0x3710, 0x00},
{0x371a, 0x1c},
{0x371b, 0x05},
{0x371c, 0x01},
{0x371e, 0xa1},
{0x371f, 0x0c},
{0x3721, 0x00},
{0x3724, 0x10},
{0x3726, 0x00},
{0x372a, 0x01},
{0x3730, 0x10},
{0x3738, 0x22},
{0x3739, 0xe5},
{0x373a, 0x50},
{0x373b, 0x02},
{0x373c, 0x41},
{0x373f, 0x02},
{0x3740, 0x42},
{0x3741, 0x02},
{0x3742, 0x18},
{0x3743, 0x01},
{0x3744, 0x02},
{0x3747, 0x10},
{0x374c, 0x04},
{0x3751, 0xf0},
{0x3752, 0x00},
{0x3753, 0x00},
{0x3754, 0xc0},
{0x3755, 0x00},
{0x3756, 0x1a},
{0x3758, 0x00},
{0x3759, 0x0f},
{0x376b, 0x44},
{0x375c, 0x04},
{0x3774, 0x10},
{0x3776, 0x00},
{0x377f, 0x08},
{0x3780, 0x22},
{0x3781, 0x0c},
{0x3784, 0x2c},
{0x3785, 0x1e},
{0x378f, 0xf5},
{0x3791, 0xb0},
{0x3795, 0x00},
{0x3796, 0x64},
{0x3797, 0x11},
{0x3798, 0x30},
{0x3799, 0x41},
{0x379a, 0x07},
{0x379b, 0xb0},
{0x379c, 0x0c},
{0x37c5, 0x00},
{0x37c6, 0x00},
{0x37c7, 0x00},
{0x37c9, 0x00},
{0x37ca, 0x00},
{0x37cb, 0x00},
{0x37de, 0x00},
{0x37df, 0x00},
{0x3800, 0x00},
{0x3801, 0x00},
{0x3802, 0x00},
{0x3803, 0xf8},
{0x3804, 0x0a},
{0x3805, 0x3f},
{0x3806, 0x06},
{0x3807, 0xab},
{0x3808, 0x07},
{0x3809, 0x80},
{0x380a, 0x04},
{0x380b, 0x38},
{0x380c, 0x0a},
{0x380d, 0x80},
{0x380e, 0x07},
{0x380f, 0xc0},
{0x3810, 0x00},
{0x3811, 0x02},
{0x3812, 0x00},
{0x3813, 0x02},
{0x3814, 0x11},
{0x3815, 0x11},
{0x3820, 0x00},
{0x3821, 0x1e},
{0x3823, 0x00},
{0x3824, 0x00},
{0x3825, 0x00},
{0x3826, 0x00},
{0x3827, 0x00},
{0x382a, 0x04},
{0x3a04, 0x06},
{0x3a05, 0x14},
{0x3a06, 0x00},
{0x3a07, 0xfe},
{0x3b00, 0x00},
{0x3b02, 0x00},
{0x3b03, 0x00},
{0x3b04, 0x00},
{0x3b05, 0x00},
{0x3e07, 0x20},
{0x4000, 0x08},
{0x4001, 0x04},
{0x4002, 0x45},
{0x4004, 0x08},
{0x4005, 0x18},
{0x4006, 0x20},
{0x4008, 0x24},
{0x4009, 0x40},
{0x400c, 0x00},
{0x400d, 0x00},
{0x4058, 0x00},
{0x404e, 0x37},
{0x404f, 0x8f},
{0x4058, 0x00},
{0x4101, 0xb2},
{0x4303, 0x00},
{0x4304, 0x08},
{0x4307, 0x30},
{0x4311, 0x04},
{0x4315, 0x01},
{0x4511, 0x05},
{0x4512, 0x01},
{0x4806, 0x00},
{0x4816, 0x52},
{0x481f, 0x30},
{0x4826, 0x2c},
{0x4831, 0x64},
{0x4d00, 0x04},
{0x4d01, 0x71},
{0x4d02, 0xfd},
{0x4d03, 0xf5},
{0x4d04, 0x0c},
{0x4d05, 0xcc},
{0x4837, 0x0a},
{0x5000, 0x06},
{0x5001, 0x01},
{0x5002, 0x80},
{0x5003, 0x20},
{0x5046, 0x0a},
{0x5013, 0x00},
{0x5046, 0x0a},
{0x5780, 0x1c},
{0x5786, 0x20},
{0x5787, 0x10},
{0x5788, 0x18},
{0x578a, 0x04},
{0x578b, 0x02},
{0x578c, 0x02},
{0x578e, 0x06},
{0x578f, 0x02},
{0x5790, 0x02},
{0x5791, 0xff},
{0x5842, 0x01},
{0x5843, 0x2b},
{0x5844, 0x01},
{0x5845, 0x92},
{0x5846, 0x01},
{0x5847, 0x8f},
{0x5848, 0x01},
{0x5849, 0x0c},
{0x5e00, 0x00},
{0x5e10, 0x0c},
{0x0100, 0x01},
{OV5693_TABLE_END, 0x0000}
};
static const struct ov5693_reg ov5693_1280x720_120fps_i2c[] = {
{OV5693_TABLE_RESET, 0},/* Including sw reset */
{0x3001, 0x0a},
{0x3002, 0x80},
{0x3006, 0x00},
{0x3011, 0x21},
{0x3012, 0x09},
{0x3013, 0x10},
{0x3014, 0x00},
{0x3015, 0x08},
{0x3016, 0xf0},
{0x3017, 0xf0},
{0x3018, 0xf0},
{0x301b, 0xb4},
{0x301d, 0x02},
{0x3021, 0x00},
{0x3022, 0x01},
{0x3028, 0x44},
{0x3098, 0x03},
{0x3099, 0x1e},
{0x309a, 0x02},
{0x309b, 0x01},
{0x309c, 0x00},
{0x30a0, 0xd2},
{0x30a2, 0x01},
{0x30b2, 0x00},
{0x30b3, 0x64},
{0x30b4, 0x03},
{0x30b5, 0x04},
{0x30b6, 0x01},
{0x3104, 0x21},
{0x3106, 0x00},
{0x3400, 0x04},
{0x3401, 0x00},
{0x3402, 0x04},
{0x3403, 0x00},
{0x3404, 0x04},
{0x3405, 0x00},
{0x3406, 0x01},
{0x3500, 0x00},
{0x3501, 0x2e},
{0x3502, 0x80},
{0x3503, 0x07},
{0x3504, 0x00},
{0x3505, 0x00},
{0x3506, 0x00},
{0x3507, 0x02},
{0x3508, 0x00},
{0x3509, 0x08},
{0x350a, 0x00},
{0x350b, 0x40},
{0x3601, 0x0a},
{0x3602, 0x38},
{0x3612, 0x80},
{0x3620, 0x54},
{0x3621, 0xc7},
{0x3622, 0x0f},
{0x3625, 0x10},
{0x3630, 0x55},
{0x3631, 0xf4},
{0x3632, 0x00},
{0x3633, 0x34},
{0x3634, 0x02},
{0x364d, 0x0d},
{0x364f, 0xdd},
{0x3660, 0x04},
{0x3662, 0x10},
{0x3663, 0xf1},
{0x3665, 0x00},
{0x3666, 0x20},
{0x3667, 0x00},
{0x366a, 0x80},
{0x3680, 0xe0},
{0x3681, 0x00},
{0x3700, 0x42},
{0x3701, 0x14},
{0x3702, 0xa0},
{0x3703, 0xd8},
{0x3704, 0x78},
{0x3705, 0x02},
{0x3708, 0xe6},
{0x3709, 0xc7},
{0x370a, 0x00},
{0x370b, 0x20},
{0x370c, 0x0c},
{0x370d, 0x11},
{0x370e, 0x00},
{0x370f, 0x40},
{0x3710, 0x00},
{0x371a, 0x1c},
{0x371b, 0x05},
{0x371c, 0x01},
{0x371e, 0xa1},
{0x371f, 0x0c},
{0x3721, 0x00},
{0x3724, 0x10},
{0x3726, 0x00},
{0x372a, 0x01},
{0x3730, 0x10},
{0x3738, 0x22},
{0x3739, 0xe5},
{0x373a, 0x50},
{0x373b, 0x02},
{0x373c, 0x41},
{0x373f, 0x02},
{0x3740, 0x42},
{0x3741, 0x02},
{0x3742, 0x18},
{0x3743, 0x01},
{0x3744, 0x02},
{0x3747, 0x10},
{0x374c, 0x04},
{0x3751, 0xf0},
{0x3752, 0x00},
{0x3753, 0x00},
{0x3754, 0xc0},
{0x3755, 0x00},
{0x3756, 0x1a},
{0x3758, 0x00},
{0x3759, 0x0f},
{0x376b, 0x44},
{0x375c, 0x04},
{0x3774, 0x10},
{0x3776, 0x00},
{0x377f, 0x08},
{0x3780, 0x22},
{0x3781, 0x0c},
{0x3784, 0x2c},
{0x3785, 0x1e},
{0x378f, 0xf5},
{0x3791, 0xb0},
{0x3795, 0x00},
{0x3796, 0x64},
{0x3797, 0x11},
{0x3798, 0x30},
{0x3799, 0x41},
{0x379a, 0x07},
{0x379b, 0xb0},
{0x379c, 0x0c},
{0x37c5, 0x00},
{0x37c6, 0x00},
{0x37c7, 0x00},
{0x37c9, 0x00},
{0x37ca, 0x00},
{0x37cb, 0x00},
{0x37de, 0x00},
{0x37df, 0x00},
{0x3800, 0x00},
{0x3801, 0x00},
{0x3802, 0x00},
{0x3803, 0xf4},
{0x3804, 0x0a},
{0x3805, 0x3f},
{0x3806, 0x06},
{0x3807, 0xab},
{0x3808, 0x05},
{0x3809, 0x00},
{0x380a, 0x02},
{0x380b, 0xd0},
{0x380c, 0x06},
{0x380d, 0xd8},
{0x380e, 0x02},
{0x380f, 0xf8},
{0x3810, 0x00},
{0x3811, 0x02},
{0x3812, 0x00},
{0x3813, 0x02},
{0x3814, 0x31},
{0x3815, 0x31},
{0x3820, 0x04},
{0x3821, 0x1f},
{0x3823, 0x00},
{0x3824, 0x00},
{0x3825, 0x00},
{0x3826, 0x00},
{0x3827, 0x00},
{0x382a, 0x04},
{0x3a04, 0x06},
{0x3a05, 0x14},
{0x3a06, 0x00},
{0x3a07, 0xfe},
{0x3b00, 0x00},
{0x3b02, 0x00},
{0x3b03, 0x00},
{0x3b04, 0x00},
{0x3b05, 0x00},
{0x3e07, 0x20},
{0x4000, 0x08},
{0x4001, 0x04},
{0x4002, 0x45},
{0x4004, 0x08},
{0x4005, 0x18},
{0x4006, 0x20},
{0x4008, 0x24},
{0x4009, 0x40},
{0x400c, 0x00},
{0x400d, 0x00},
{0x4058, 0x00},
{0x404e, 0x37},
{0x404f, 0x8f},
{0x4058, 0x00},
{0x4101, 0xb2},
{0x4303, 0x00},
{0x4304, 0x08},
{0x4307, 0x30},
{0x4311, 0x04},
{0x4315, 0x01},
{0x4511, 0x05},
{0x4512, 0x01},
{0x4806, 0x00},
{0x4816, 0x52},
{0x481f, 0x30},
{0x4826, 0x2c},
{0x4831, 0x64},
{0x4d00, 0x04},
{0x4d01, 0x71},
{0x4d02, 0xfd},
{0x4d03, 0xf5},
{0x4d04, 0x0c},
{0x4d05, 0xcc},
{0x4837, 0x0a},
{0x5000, 0x06},
{0x5001, 0x01},
{0x5002, 0x00},
{0x5003, 0x20},
{0x5046, 0x0a},
{0x5013, 0x00},
{0x5046, 0x0a},
{0x5780, 0x1c},
{0x5786, 0x20},
{0x5787, 0x10},
{0x5788, 0x18},
{0x578a, 0x04},
{0x578b, 0x02},
{0x578c, 0x02},
{0x578e, 0x06},
{0x578f, 0x02},
{0x5790, 0x02},
{0x5791, 0xff},
{0x5842, 0x01},
{0x5843, 0x2b},
{0x5844, 0x01},
{0x5845, 0x92},
{0x5846, 0x01},
{0x5847, 0x8f},
{0x5848, 0x01},
{0x5849, 0x0c},
{0x5e00, 0x00},
{0x5e10, 0x0c},
{0x0100, 0x01},
{0x350b, 0xF8},
{OV5693_TABLE_END, 0x0000}
};
enum {
OV5693_MODE_2592x1944 = 0,
OV5693_MODE_1920x1080,
OV5693_MODE_1296x972,
OV5693_MODE_1280x720_120FPS,
};
static const struct ov5693_reg *mode_table[] = {
[OV5693_MODE_2592x1944] = ov5693_2592x1944_i2c,
[OV5693_MODE_1920x1080] = ov5693_1920x1080_i2c,
[OV5693_MODE_1296x972] = ov5693_1296x972_i2c,
[OV5693_MODE_1280x720_120FPS] = ov5693_1280x720_120fps_i2c,
};
static int ov5693_i2c_rd8(struct ov5693_info *info, u16 reg, u8 *val)
{
unsigned int data;
int ret = regmap_read(info->regmap, reg, &data);
*val = data;
return ret;
}
static int ov5693_i2c_wr_table(struct ov5693_info *info,
const struct ov5693_reg table[])
{
int err;
int buf_count = 0;
const struct ov5693_reg *next, *n_next;
u16 i2c_reg = 0;
u8 i2c_buf[OV5693_SIZEOF_I2C_BUF];
u8 *b_ptr = i2c_buf;
u8 reset_status = 1;
u8 reset_tries_left = OV5693_TABLE_RESET_TIMEOUT;
for (next = table; next->addr != OV5693_TABLE_END; next++) {
if (next->addr == OV5693_TABLE_WAIT_MS) {
msleep(next->val);
continue;
} else if (next->addr == OV5693_TABLE_RESET) {
err = regmap_write(info->regmap, 0x0103, 0x01);
if (err)
return err;
while (reset_status) {
usleep_range(200, 300);
if (reset_tries_left < 1)
return -EIO;
err = ov5693_i2c_rd8(info, 0x0103,
&reset_status);
if (err)
return err;
reset_status &= 0x01;
reset_tries_left -= 1;
}
continue;
}
if (buf_count == 0) {
b_ptr = i2c_buf;
i2c_reg = next->addr;
}
*b_ptr++ = next->val;
buf_count++;
n_next = next + 1;
if (n_next->addr == next->addr + 1 &&
n_next->addr != OV5693_TABLE_WAIT_MS &&
buf_count < OV5693_SIZEOF_I2C_BUF &&
n_next->addr != OV5693_TABLE_RESET &&
n_next->addr != OV5693_TABLE_END)
continue;
err = regmap_bulk_write(info->regmap, i2c_reg,
i2c_buf, buf_count);
if (err)
return err;
buf_count = 0;
}
return 0;
}
static inline int ov5693_frame_length_reg(struct ov5693_reg *regs,
u32 frame_length)
{
regs->addr = 0x380E;
regs->val = (frame_length >> 8) & 0xff;
(regs + 1)->addr = 0x380F;
(regs + 1)->val = (frame_length) & 0xff;
return 2;
}
static inline int ov5693_coarse_time_reg(struct ov5693_reg *regs,
u32 coarse_time)
{
regs->addr = 0x3500;
regs->val = (coarse_time >> 12) & 0xff;
(regs + 1)->addr = 0x3501;
(regs + 1)->val = (coarse_time >> 4) & 0xff;
(regs + 2)->addr = 0x3502;
(regs + 2)->val = (coarse_time & 0xf) << 4;
return 3;
}
#define OV5693_ENTER_GROUP_HOLD(group_hold) \
do { \
if (group_hold) { \
reg_list[offset].addr = 0x3208; \
reg_list[offset].val = 0x01;\
offset++; \
} \
} while (0)
#define OV5693_LEAVE_GROUP_HOLD(group_hold) \
do { \
if (group_hold) { \
reg_list[offset].addr = 0x3208; \
reg_list[offset].val = 0x11;\
offset++; \
reg_list[offset].addr = 0x3208; \
reg_list[offset].val = 0xe1;\
offset++; \
} \
} while (0)
static int ov5693_set_frame_length(struct ov5693_info *info,
u32 frame_length, bool group_hold)
{
struct ov5693_reg reg_list[9];
int err = 0;
int offset = 0;
OV5693_ENTER_GROUP_HOLD(group_hold);
offset += ov5693_frame_length_reg(reg_list + offset, frame_length);
OV5693_LEAVE_GROUP_HOLD(group_hold);
reg_list[offset].addr = OV5693_TABLE_END;
offset++;
err = ov5693_i2c_wr_table(info, reg_list);
return err;
}
static int ov5693_set_coarse_time(struct ov5693_info *info,
u32 coarse_time, bool group_hold)
{
struct ov5693_reg reg_list[16];
int err = 0;
int offset = 0;
OV5693_ENTER_GROUP_HOLD(group_hold);
offset += ov5693_coarse_time_reg(reg_list + offset, coarse_time);
OV5693_LEAVE_GROUP_HOLD(group_hold);
reg_list[offset].addr = OV5693_TABLE_END;
offset++;
err = ov5693_i2c_wr_table(info, reg_list);
return err;
}
static inline int ov5693_gain_reg(struct ov5693_reg *regs, u32 gain)
{
(regs)->addr = 0x350B;
(regs)->val = gain;
return 1;
}
static int ov5693_bin_wr(struct ov5693_info *info, u8 enable)
{
int err = 0;
if (enable == info->bin_en)
return 0;
if (!err)
info->bin_en = enable;
dev_dbg(&info->i2c_client->dev, "%s bin_en=%x err=%d\n",
__func__, info->bin_en, err);
return err;
}
static int ov5693_exposure_wr(struct ov5693_info *info,
struct ov5693_mode *mode)
{
struct ov5693_reg reg_list[16];
int err = 0;
int offset = 0;
bool group_hold = true; /* To use GROUP_HOLD macros */
OV5693_ENTER_GROUP_HOLD(group_hold);
offset += ov5693_coarse_time_reg(reg_list + offset, mode->coarse_time);
offset += ov5693_gain_reg(reg_list + offset, mode->gain);
OV5693_LEAVE_GROUP_HOLD(group_hold);
reg_list[offset].addr = OV5693_TABLE_END;
err = ov5693_i2c_wr_table(info, reg_list);
return err;
}
static int ov5693_set_gain(struct ov5693_info *info, u32 gain, bool group_hold)
{
struct ov5693_reg reg_list[9];
int err = 0;
int offset = 0;
OV5693_ENTER_GROUP_HOLD(group_hold);
offset += ov5693_gain_reg(reg_list + offset, gain);
OV5693_LEAVE_GROUP_HOLD(group_hold);
reg_list[offset].addr = OV5693_TABLE_END;
offset++;
err = ov5693_i2c_wr_table(info, reg_list);
return err;
}
static int ov5693_set_group_hold(struct ov5693_info *info,
struct ov5693_ae *ae)
{
int err = 0;
struct ov5693_reg reg_list[16];
int offset = 0;
bool group_hold = true; /* To use GROUP_HOLD macros */
OV5693_ENTER_GROUP_HOLD(group_hold);
if (ae->gain_enable)
offset += ov5693_gain_reg(reg_list + offset,
ae->gain);
if (ae->frame_length_enable)
offset += ov5693_frame_length_reg(reg_list + offset,
ae->frame_length);
if (ae->coarse_time_enable)
offset += ov5693_coarse_time_reg(reg_list + offset,
ae->coarse_time);
OV5693_LEAVE_GROUP_HOLD(group_hold);
reg_list[offset].addr = OV5693_TABLE_END;
err |= ov5693_i2c_wr_table(info, reg_list);
return err;
}
static int ov5693_gpio_rd(struct ov5693_info *info,
enum ov5693_gpio_type type)
{
int val = -EINVAL;
if (info->gpio[type].gpio) {
val = gpio_get_value_cansleep(info->gpio[type].gpio);
dev_dbg(&info->i2c_client->dev, "%s %u %d\n", __func__,
info->gpio[type].gpio, val);
if (!info->gpio[type].active_high)
val = !val;
val &= 1;
}
return val; /* return read value or error */
}
static int ov5693_gpio_wr(struct ov5693_info *info,
enum ov5693_gpio_type type,
int val) /* val: 0=deassert, 1=assert */
{
int err = -EINVAL;
if (info->gpio[type].gpio) {
if (!info->gpio[type].active_high)
val = !val;
val &= 1;
err = val;
gpio_set_value_cansleep(info->gpio[type].gpio, val);
dev_dbg(&info->i2c_client->dev, "%s %u %d\n", __func__,
info->gpio[type].gpio, val);
}
return err; /* return value written or error */
}
static void ov5693_gpio_pwrdn(struct ov5693_info *info, int val)
{
int prev_val;
prev_val = ov5693_gpio_rd(info, OV5693_GPIO_TYPE_PWRDN);
if ((prev_val < 0) || (val == prev_val))
return;
ov5693_gpio_wr(info, OV5693_GPIO_TYPE_PWRDN, val);
if (!val && prev_val)
/* if transition from assert to deassert then delay for I2C */
msleep(50);
}
static void ov5693_gpio_exit(struct ov5693_info *info)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(ov5693_gpio); i++) {
if (info->gpio[i].gpio && info->gpio[i].own)
gpio_free(info->gpio[i].gpio);
}
}
static void ov5693_gpio_init(struct ov5693_info *info)
{
char label[32];
unsigned long flags;
unsigned type;
unsigned i;
unsigned j;
int err;
if (!info->pdata->gpio_count || !info->pdata->gpio)
return;
for (i = 0; i < ARRAY_SIZE(ov5693_gpio); i++) {
type = ov5693_gpio[i].gpio_type;
for (j = 0; j < info->pdata->gpio_count; j++) {
if (type == info->pdata->gpio[j].gpio_type)
break;
}
if (j == info->pdata->gpio_count)
continue;
info->gpio[type].gpio = info->pdata->gpio[j].gpio;
if (ov5693_gpio[i].use_flags) {
flags = ov5693_gpio[i].flags;
info->gpio[type].active_high =
ov5693_gpio[i].active_high;
} else {
info->gpio[type].active_high =
info->pdata->gpio[j].active_high;
if (info->gpio[type].active_high)
flags = GPIOF_OUT_INIT_LOW;
else
flags = GPIOF_OUT_INIT_HIGH;
}
if (!info->pdata->gpio[j].init_en)
continue;
snprintf(label, sizeof(label), "ov5693_%u_%s",
info->pdata->num, ov5693_gpio[i].label);
err = gpio_request_one(info->gpio[type].gpio, flags, label);
if (err) {
dev_err(&info->i2c_client->dev,
"%s ERR %s %u\n", __func__, label,
info->gpio[type].gpio);
} else {
info->gpio[type].own = true;
dev_dbg(&info->i2c_client->dev,
"%s %s %u\n", __func__, label,
info->gpio[type].gpio);
}
}
}
static void ov5693_mclk_disable(struct ov5693_info *info)
{
dev_dbg(&info->i2c_client->dev, "%s: disable MCLK\n", __func__);
clk_disable_unprepare(info->mclk);
}
static int ov5693_mclk_enable(struct ov5693_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 int ov5693_power_off(struct ov5693_info *info)
{
struct ov5693_power_rail *pw = &info->regulators;
int err;
if (false == info->power_on)
return 0;
if (info->pdata && info->pdata->power_off) {
err = info->pdata->power_off(pw);
if (0 > err)
return err;
info->power_on = false;
ov5693_gpio_pwrdn(info, 1);
ov5693_mclk_disable(info);
} else {
dev_err(&info->i2c_client->dev,
"%s ERR: has no power_off function\n", __func__);
err = -EINVAL;
}
return err;
}
static int ov5693_power_on(struct ov5693_info *info, bool standby)
{
struct ov5693_power_rail *pw = &info->regulators;
int err;
if (true == info->power_on)
return 0;
err = ov5693_mclk_enable(info);
if (err)
return err;
if (info->pdata && info->pdata->power_on) {
err = info->pdata->power_on(pw);
if (err >= 0) {
info->power_on = true;
ov5693_gpio_pwrdn(info, standby ? 1 : 0);
msleep(100);
}
} else {
dev_err(&info->i2c_client->dev,
"%s ERR: has no power_on function\n", __func__);
err = -EINVAL;
}
if (err < 0)
ov5693_mclk_disable(info);
return err;
}
static int ov5693_pm_wr(struct ov5693_info *info, int pwr)
{
int err = 0;
if ((info->pdata->cfg & (NVC_CFG_OFF2STDBY | NVC_CFG_BOOT_INIT)) &&
(pwr == NVC_PWR_OFF ||
pwr == NVC_PWR_STDBY_OFF))
pwr = NVC_PWR_STDBY;
if (pwr == info->pwr_dev)
return 0;
switch (pwr) {
case NVC_PWR_OFF_FORCE:
case NVC_PWR_OFF:
case NVC_PWR_STDBY_OFF:
err = ov5693_power_off(info);
info->mode_valid = false;
info->bin_en = 0;
break;
case NVC_PWR_STDBY:
err = ov5693_power_on(info, true);
break;
case NVC_PWR_COMM:
case NVC_PWR_ON:
err = ov5693_power_on(info, false);
break;
default:
err = -EINVAL;
break;
}
if (err < 0) {
dev_err(&info->i2c_client->dev, "%s err %d\n", __func__, err);
pwr = NVC_PWR_ERR;
}
info->pwr_dev = pwr;
dev_dbg(&info->i2c_client->dev, "%s pwr_dev=%d\n",
__func__, info->pwr_dev);
if (err > 0)
return 0;
return err;
}
static int ov5693_pm_dev_wr(struct ov5693_info *info, int pwr)
{
if (info->mode_enable)
pwr = NVC_PWR_ON;
if (pwr < info->pwr_api)
pwr = info->pwr_api;
return ov5693_pm_wr(info, pwr);
}
static void ov5693_pm_exit(struct ov5693_info *info)
{
ov5693_pm_wr(info, NVC_PWR_OFF_FORCE);
ov5693_gpio_exit(info);
}
static void ov5693_regulator_get(struct ov5693_info *info,
struct regulator **vreg,
const char vreg_name[])
{
struct regulator *reg = NULL;
int err = 0;
reg = devm_regulator_get(&info->i2c_client->dev, vreg_name);
if (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;
}
static void ov5693_pm_init(struct ov5693_info *info)
{
struct ov5693_power_rail *pw = &info->regulators;
ov5693_gpio_init(info);
ov5693_regulator_get(info, &pw->dvdd, "dvdd");
ov5693_regulator_get(info, &pw->avdd, "avdd");
ov5693_regulator_get(info, &pw->dovdd, "dovdd");
info->power_on = false;
}
static int ov5693_mode_able(struct ov5693_info *info, bool mode_enable)
{
u8 val;
int err;
if (mode_enable)
val = 0x01;
else
val = 0x00;
err = regmap_write(info->regmap, 0x0100, val);
if (!err) {
info->mode_enable = mode_enable;
dev_dbg(&info->i2c_client->dev, "%s streaming=%x\n",
__func__, info->mode_enable);
if (!mode_enable)
ov5693_pm_dev_wr(info, NVC_PWR_STDBY);
}
return err;
}
static int ov5693_mode_wr_full(struct ov5693_info *info, u32 mode_index)
{
int err;
ov5693_pm_dev_wr(info, NVC_PWR_ON);
ov5693_bin_wr(info, 0);
err = ov5693_i2c_wr_table(info, mode_table[mode_index]);
if (!err) {
dev_dbg(&info->i2c_client->dev,
"init done(mode=%d)!!!\n", mode_index);
info->mode_index = mode_index;
info->mode_valid = true;
} else {
dev_dbg(&info->i2c_client->dev,
"init error(mode=%d)!!!\n", mode_index);
info->mode_valid = false;
}
return err;
}
static int ov5693_set_mode(struct ov5693_info *info,
struct ov5693_mode *mode)
{
u32 mode_index = 0;
int err = 0;
if (!mode->res_x && !mode->res_y) {
if (mode->frame_length || mode->coarse_time || mode->gain) {
/* write exposure only */
err = ov5693_exposure_wr(info, mode);
return err;
} else {
/* turn off streaming */
err = ov5693_mode_able(info, false);
return err;
}
}
if (mode->res_x == 2592 && mode->res_y == 1944)
mode_index = OV5693_MODE_2592x1944;
else if (mode->res_x == 1296 && mode->res_y == 972)
mode_index = OV5693_MODE_1296x972;
else if (mode->res_x == 1920 && mode->res_y == 1080)
mode_index = OV5693_MODE_1920x1080;
else if (mode->res_x == 1280 && mode->res_y == 720)
mode_index = OV5693_MODE_1280x720_120FPS;
if (!info->mode_valid || (info->mode_index != mode_index))
err = ov5693_mode_wr_full(info, mode_index);
else
dev_dbg(&info->i2c_client->dev, "%s short mode\n", __func__);
dev_dbg(&info->i2c_client->dev, "%s: mode #: %d\n",
__func__, mode_index);
dev_dbg(&info->i2c_client->dev, "%s: AE: %d, %d, %d\n",
__func__, mode->frame_length,
mode->coarse_time, mode->gain);
err |= ov5693_exposure_wr(info, mode);
if (err < 0) {
info->mode_valid = false;
dev_err(&info->i2c_client->dev,
"%s set_mode error\n", __func__);
goto ov5693_mode_wr_err;
}
return 0;
ov5693_mode_wr_err:
if (!info->mode_enable)
ov5693_pm_dev_wr(info, NVC_PWR_OFF);
return err;
}
static int ov5693_get_fuse_id(struct ov5693_info *info)
{
ov5693_i2c_rd8(info, 0x300A, &info->fuseid.id[0]);
ov5693_i2c_rd8(info, 0x300B, &info->fuseid.id[1]);
info->fuseid.size = 2;
dev_dbg(&info->i2c_client->dev, "ov5693 fuse_id: %x,%x\n",
info->fuseid.id[0], info->fuseid.id[1]);
return 0;
}
static long ov5693_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct ov5693_info *info = file->private_data;
int err;
switch (cmd) {
case OV5693_IOCTL_SET_MODE:
{
struct ov5693_mode mode;
if (copy_from_user(&mode,
(const void __user *)arg,
sizeof(struct ov5693_mode))) {
dev_err(&info->i2c_client->dev,
"%s:Failed to get mode from user.\n",
__func__);
return -EFAULT;
}
return ov5693_set_mode(info, &mode);
}
case OV5693_IOCTL_GET_STATUS: {
u8 status = 0;
if (copy_to_user((void __user *)arg, &status, sizeof(status))) {
dev_err(&info->i2c_client->dev,
"%s:Failed to copy status to user.\n",
__func__);
return -EFAULT;
}
return 0;
}
case OV5693_IOCTL_SET_GROUP_HOLD: {
struct ov5693_ae ae;
if (copy_from_user(&ae, (const void __user *)arg,
sizeof(struct ov5693_ae))) {
dev_dbg(&info->i2c_client->dev,
"%s:fail group hold\n", __func__);
return -EFAULT;
}
return ov5693_set_group_hold(info, &ae);
}
case OV5693_IOCTL_SET_FRAME_LENGTH:
return ov5693_set_frame_length(info, (u32)arg, true);
case OV5693_IOCTL_SET_COARSE_TIME:
return ov5693_set_coarse_time(info, (u32)arg, true);
case OV5693_IOCTL_SET_GAIN:
return ov5693_set_gain(info, (u32)arg, true);
case OV5693_IOCTL_GET_FUSEID:
{
err = ov5693_get_fuse_id(info);
if (err) {
dev_err(&info->i2c_client->dev, "%s:Failed to get fuse id info.\n",
__func__);
return err;
}
if (copy_to_user((void __user *)arg,
&info->fuseid,
sizeof(struct ov5693_fuseid))) {
dev_dbg(&info->i2c_client->dev, "%s:Fail copy fuse id to user space\n",
__func__);
return -EFAULT;
}
return 0;
}
default:
dev_err(&info->i2c_client->dev, "%s unsupported ioctl: %x\n",
__func__, cmd);
}
return -EINVAL;
}
static void ov5693_sdata_init(struct ov5693_info *info)
{
memcpy(&info->sdata, &ov5693_dflt_sdata, sizeof(info->sdata));
if (info->pdata->lens_focal_length)
info->sdata.focal_len = info->pdata->lens_focal_length;
if (info->pdata->lens_max_aperture)
info->sdata.max_aperture = info->pdata->lens_max_aperture;
if (info->pdata->lens_fnumber)
info->sdata.fnumber = info->pdata->lens_fnumber;
if (info->pdata->lens_view_angle_h)
info->sdata.view_angle_h = info->pdata->lens_view_angle_h;
if (info->pdata->lens_view_angle_v)
info->sdata.view_angle_v = info->pdata->lens_view_angle_v;
}
static int ov5693_open(struct inode *inode, struct file *file)
{
int err;
struct miscdevice *miscdev = file->private_data;
struct ov5693_info *info = dev_get_drvdata(miscdev->parent);
if (atomic_xchg(&info->in_use, 1))
return -EBUSY;
file->private_data = info;
dev_dbg(&info->i2c_client->dev, "%s\n", __func__);
err = ov5693_power_on(info, false);
return err;
}
int ov5693_release(struct inode *inode, struct file *file)
{
struct ov5693_info *info = file->private_data;
dev_dbg(&info->i2c_client->dev, "%s\n", __func__);
ov5693_pm_wr(info, NVC_PWR_OFF);
file->private_data = NULL;
WARN_ON(!atomic_xchg(&info->in_use, 0));
return 0;
}
static const struct file_operations ov5693_fileops = {
.owner = THIS_MODULE,
.open = ov5693_open,
.unlocked_ioctl = ov5693_ioctl,
.release = ov5693_release,
};
static void ov5693_del(struct ov5693_info *info)
{
ov5693_pm_exit(info);
synchronize_rcu();
}
static int ov5693_remove(struct i2c_client *client)
{
struct ov5693_info *info = i2c_get_clientdata(client);
dev_dbg(&info->i2c_client->dev, "%s\n", __func__);
misc_deregister(&info->miscdev);
ov5693_del(info);
return 0;
}
static struct of_device_id ov5693_of_match[] = {
{ .compatible = "nvidia,ov5693", },
{ },
};
MODULE_DEVICE_TABLE(of, ov5693_of_match);
static int ov5693_platform_power_on(struct ov5693_power_rail *pw)
{
int err;
struct ov5693_info *info = container_of(pw, struct ov5693_info,
regulators);
if (info->pdata->use_vcm_vdd) {
err = regulator_enable(info->ext_vcm_vdd);
if (unlikely(err))
goto ov5693_vcm_fail;
}
ov5693_gpio_wr(info, OV5693_GPIO_TYPE_PWRDN, 0);
usleep_range(10, 20);
err = regulator_enable(pw->avdd);
if (err)
goto ov5693_avdd_fail;
err = regulator_enable(pw->dovdd);
if (err)
goto ov5693_iovdd_fail;
usleep_range(1, 2);
ov5693_gpio_wr(info, OV5693_GPIO_TYPE_PWRDN, 1);
usleep_range(300, 310);
return 0;
ov5693_iovdd_fail:
regulator_disable(pw->avdd);
ov5693_avdd_fail:
if (info->pdata->use_vcm_vdd)
regulator_disable(info->ext_vcm_vdd);
ov5693_vcm_fail:
pr_err("%s FAILED\n", __func__);
return err;
}
static int ov5693_platform_power_off(struct ov5693_power_rail *pw)
{
struct ov5693_info *info = container_of(pw, struct ov5693_info,
regulators);
usleep_range(21, 25);
ov5693_gpio_wr(info, OV5693_GPIO_TYPE_PWRDN, 0);
usleep_range(1, 2);
regulator_disable(pw->dovdd);
regulator_disable(pw->avdd);
if (info->pdata->use_vcm_vdd)
regulator_disable(info->ext_vcm_vdd);
return 0;
}
static int ov5693_parse_dt_gpio(struct device_node *np, const char *name,
enum ov5693_gpio_type type,
struct nvc_gpio_pdata *pdata)
{
enum of_gpio_flags gpio_flags;
if (of_find_property(np, name, NULL)) {
pdata->gpio = of_get_named_gpio_flags(np, name, 0, &gpio_flags);
pdata->gpio_type = type;
pdata->init_en = true;
pdata->active_high = !(gpio_flags & OF_GPIO_ACTIVE_LOW);
return 1;
}
return 0;
}
static struct ov5693_platform_data *ov5693_parse_dt(struct i2c_client *client)
{
struct device_node *np = client->dev.of_node;
struct ov5693_platform_data *pdata;
struct nvc_gpio_pdata *gpio_pdata = NULL;
pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
dev_err(&client->dev, "Failed to allocate pdata\n");
return ERR_PTR(-ENOMEM);
}
gpio_pdata = devm_kzalloc(&client->dev,
sizeof(*gpio_pdata) * ARRAY_SIZE(ov5693_gpio), GFP_KERNEL);
if (!gpio_pdata) {
dev_err(&client->dev, "cannot allocate gpio data memory\n");
return ERR_PTR(-ENOMEM);
}
/* init with default platform data values */
memcpy(pdata, &ov5693_dflt_pdata, sizeof(*pdata));
/* extra regulators info */
pdata->use_vcm_vdd = of_property_read_bool(np, "nvidia,use-vcm-vdd");
/* generic info */
of_property_read_u32(np, "nvidia,num", &pdata->num);
of_property_read_string(np, "nvidia,dev-name", &pdata->dev_name);
/* ov5693 gpios */
pdata->gpio_count = 0;
pdata->gpio_count += ov5693_parse_dt_gpio(np,
"reset-gpios", OV5693_GPIO_TYPE_PWRDN,
&gpio_pdata[pdata->gpio_count]);
pdata->gpio = gpio_pdata;
/* MCLK clock info */
of_property_read_string(np, "nvidia,mclk_name",
&pdata->mclk_name);
/* ov5693 power functions */
pdata->power_on = ov5693_platform_power_on;
pdata->power_off = ov5693_platform_power_off;
return pdata;
}
static int ov5693_probe(
struct i2c_client *client,
const struct i2c_device_id *id)
{
struct ov5693_info *info;
char dname[16];
unsigned long clock_probe_rate;
int err;
const char *mclk_name;
static struct regmap_config ad5823_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
};
dev_dbg(&client->dev, "%s\n", __func__);
info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
if (info == NULL) {
dev_err(&client->dev, "%s: kzalloc error\n", __func__);
return -ENOMEM;
}
info->i2c_client = client;
if (client->dev.of_node) {
info->pdata = ov5693_parse_dt(client);
if (IS_ERR(info->pdata)) {
err = PTR_ERR(info->pdata);
dev_err(&client->dev,
"Failed to parse OF node: %d\n", err);
return err;
}
} else if (client->dev.platform_data)
info->pdata = client->dev.platform_data;
else {
info->pdata = &ov5693_dflt_pdata;
dev_dbg(&client->dev,
"%s No platform data. Using defaults.\n",
__func__);
}
if (info->pdata->use_vcm_vdd) {
info->ext_vcm_vdd = devm_regulator_get(&info->i2c_client->dev,
"ext_vcm_vdd");
if (WARN_ON(IS_ERR(info->ext_vcm_vdd))) {
err = PTR_ERR(info->ext_vcm_vdd);
dev_err(&client->dev,
"ext_vcm_vdd get failed %d\n", err);
info->ext_vcm_vdd = NULL;
return err;
}
}
info->regmap = devm_regmap_init_i2c(client, &ad5823_regmap_config);
if (IS_ERR(info->regmap)) {
err = PTR_ERR(info->regmap);
dev_err(&client->dev,
"Failed to allocate register map: %d\n", err);
return err;
}
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);
}
i2c_set_clientdata(client, info);
ov5693_pm_init(info);
if (!info->regulators.avdd || !info->regulators.dovdd)
return -EFAULT;
ov5693_sdata_init(info);
if (info->pdata->cfg & (NVC_CFG_NODEV | NVC_CFG_BOOT_INIT)) {
if (info->pdata->probe_clock) {
clock_probe_rate = 6000; /* initial_clcok*/
clock_probe_rate *= 1000;
info->pdata->probe_clock(clock_probe_rate);
}
ov5693_pm_dev_wr(info, NVC_PWR_COMM);
ov5693_pm_dev_wr(info, NVC_PWR_OFF);
if (info->pdata->probe_clock)
info->pdata->probe_clock(0);
}
if (info->pdata->dev_name != NULL)
strcpy(dname, info->pdata->dev_name);
else
strcpy(dname, "ov5693");
if (info->pdata->num)
snprintf(dname, sizeof(dname), "%s.%u",
dname, info->pdata->num);
info->miscdev.name = dname;
info->miscdev.fops = &ov5693_fileops;
info->miscdev.minor = MISC_DYNAMIC_MINOR;
info->miscdev.parent = &client->dev;
if (misc_register(&info->miscdev)) {
dev_err(&client->dev, "%s unable to register misc device %s\n",
__func__, dname);
ov5693_del(info);
return -ENODEV;
}
dev_dbg(&client->dev, "ov5693 sensor driver loading done\n");
return 0;
}
static const struct i2c_device_id ov5693_id[] = {
{ "ov5693", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, ov5693_id);
static struct i2c_driver ov5693_i2c_driver = {
.driver = {
.name = "ov5693",
.owner = THIS_MODULE,
.of_match_table = ov5693_of_match,
},
.id_table = ov5693_id,
.probe = ov5693_probe,
.remove = ov5693_remove,
};
module_i2c_driver(ov5693_i2c_driver);
MODULE_LICENSE("GPL v2");