1415 lines
36 KiB
C
1415 lines
36 KiB
C
/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 and
|
|
* only version 2 as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#include <linux/delay.h>
|
|
#include <linux/types.h>
|
|
#include <linux/i2c.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/miscdevice.h>
|
|
#include <linux/slab.h>
|
|
#include <media/msm_camera.h>
|
|
#include <mach/gpio.h>
|
|
#include <mach/camera.h>
|
|
#include <asm/mach-types.h>
|
|
#include "imx074.h"
|
|
|
|
/*SENSOR REGISTER DEFINES*/
|
|
#define IMX074_EEPROM_SLAVE_ADDR 0x52
|
|
#define REG_GROUPED_PARAMETER_HOLD 0x0104
|
|
#define GROUPED_PARAMETER_HOLD_OFF 0x00
|
|
#define GROUPED_PARAMETER_HOLD 0x01
|
|
#define REG_MODE_SELECT 0x100
|
|
#define MODE_SELECT_STANDBY_MODE 0x00
|
|
#define MODE_SELECT_STREAM 0x01
|
|
/* Integration Time */
|
|
#define REG_COARSE_INTEGRATION_TIME_HI 0x0202
|
|
#define REG_COARSE_INTEGRATION_TIME_LO 0x0203
|
|
/* Gain */
|
|
#define REG_ANALOGUE_GAIN_CODE_GLOBAL_HI 0x0204
|
|
#define REG_ANALOGUE_GAIN_CODE_GLOBAL_LO 0x0205
|
|
/* PLL registers */
|
|
#define REG_PLL_MULTIPLIER 0x0307
|
|
#define REG_PRE_PLL_CLK_DIV 0x0305
|
|
#define REG_PLSTATIM 0x302b
|
|
#define REG_3024 0x3024
|
|
#define REG_IMAGE_ORIENTATION 0x0101
|
|
#define REG_VNDMY_ABLMGSHLMT 0x300a
|
|
#define REG_Y_OPBADDR_START_DI 0x3014
|
|
#define REG_3015 0x3015
|
|
#define REG_301C 0x301C
|
|
#define REG_302C 0x302C
|
|
#define REG_3031 0x3031
|
|
#define REG_3041 0x3041
|
|
#define REG_3051 0x3051
|
|
#define REG_3053 0x3053
|
|
#define REG_3057 0x3057
|
|
#define REG_305C 0x305C
|
|
#define REG_305D 0x305D
|
|
#define REG_3060 0x3060
|
|
#define REG_3065 0x3065
|
|
#define REG_30AA 0x30AA
|
|
#define REG_30AB 0x30AB
|
|
#define REG_30B0 0x30B0
|
|
#define REG_30B2 0x30B2
|
|
#define REG_30D3 0x30D3
|
|
#define REG_3106 0x3106
|
|
#define REG_310C 0x310C
|
|
#define REG_3304 0x3304
|
|
#define REG_3305 0x3305
|
|
#define REG_3306 0x3306
|
|
#define REG_3307 0x3307
|
|
#define REG_3308 0x3308
|
|
#define REG_3309 0x3309
|
|
#define REG_330A 0x330A
|
|
#define REG_330B 0x330B
|
|
#define REG_330C 0x330C
|
|
#define REG_330D 0x330D
|
|
#define REG_330F 0x330F
|
|
#define REG_3381 0x3381
|
|
|
|
/* mode setting */
|
|
#define REG_FRAME_LENGTH_LINES_HI 0x0340
|
|
#define REG_FRAME_LENGTH_LINES_LO 0x0341
|
|
#define REG_YADDR_START 0x0347
|
|
#define REG_YAAAR_END 0x034b
|
|
#define REG_X_OUTPUT_SIZE_MSB 0x034c
|
|
#define REG_X_OUTPUT_SIZE_LSB 0x034d
|
|
#define REG_Y_OUTPUT_SIZE_MSB 0x034e
|
|
#define REG_Y_OUTPUT_SIZE_LSB 0x034f
|
|
#define REG_X_EVEN_INC 0x0381
|
|
#define REG_X_ODD_INC 0x0383
|
|
#define REG_Y_EVEN_INC 0x0385
|
|
#define REG_Y_ODD_INC 0x0387
|
|
#define REG_HMODEADD 0x3001
|
|
#define REG_VMODEADD 0x3016
|
|
#define REG_VAPPLINE_START 0x3069
|
|
#define REG_VAPPLINE_END 0x306b
|
|
#define REG_SHUTTER 0x3086
|
|
#define REG_HADDAVE 0x30e8
|
|
#define REG_LANESEL 0x3301
|
|
/* Test Pattern */
|
|
#define REG_TEST_PATTERN_MODE 0x0601
|
|
|
|
#define REG_LINE_LENGTH_PCK_HI 0x0342
|
|
#define REG_LINE_LENGTH_PCK_LO 0x0343
|
|
/*..... TYPE DECLARATIONS.....*/
|
|
#define IMX074_OFFSET 3
|
|
#define IMX074_DEFAULT_MASTER_CLK_RATE 24000000
|
|
/* Full Size */
|
|
#define IMX074_FULL_SIZE_WIDTH 4208
|
|
#define IMX074_FULL_SIZE_HEIGHT 3120
|
|
#define IMX074_FULL_SIZE_DUMMY_PIXELS 0
|
|
#define IMX074_FULL_SIZE_DUMMY_LINES 0
|
|
/* Quarter Size */
|
|
#define IMX074_QTR_SIZE_WIDTH 2104
|
|
#define IMX074_QTR_SIZE_HEIGHT 1560
|
|
#define IMX074_QTR_SIZE_DUMMY_PIXELS 0
|
|
#define IMX074_QTR_SIZE_DUMMY_LINES 0
|
|
/* Blanking as measured on the scope */
|
|
/* Full Size */
|
|
#define IMX074_HRZ_FULL_BLK_PIXELS 264
|
|
#define IMX074_VER_FULL_BLK_LINES 96
|
|
/* Quarter Size */
|
|
#define IMX074_HRZ_QTR_BLK_PIXELS 2368
|
|
#define IMX074_VER_QTR_BLK_LINES 21
|
|
#define Q8 0x100
|
|
#define Q10 0x400
|
|
#define IMX074_AF_I2C_SLAVE_ID 0x72
|
|
#define IMX074_STEPS_NEAR_TO_CLOSEST_INF 52
|
|
#define IMX074_TOTAL_STEPS_NEAR_TO_FAR 52
|
|
static uint32_t imx074_l_region_code_per_step = 2;
|
|
|
|
struct imx074_work_t {
|
|
struct work_struct work;
|
|
};
|
|
|
|
static struct imx074_work_t *imx074_sensorw;
|
|
static struct i2c_client *imx074_client;
|
|
|
|
struct imx074_ctrl_t {
|
|
const struct msm_camera_sensor_info *sensordata;
|
|
uint32_t sensormode;
|
|
uint32_t fps_divider;/* init to 1 * 0x00000400 */
|
|
uint32_t pict_fps_divider;/* init to 1 * 0x00000400 */
|
|
uint16_t fps;
|
|
int16_t curr_lens_pos;
|
|
uint16_t curr_step_pos;
|
|
uint16_t my_reg_gain;
|
|
uint32_t my_reg_line_count;
|
|
uint16_t total_lines_per_frame;
|
|
enum imx074_resolution_t prev_res;
|
|
enum imx074_resolution_t pict_res;
|
|
enum imx074_resolution_t curr_res;
|
|
enum imx074_test_mode_t set_test;
|
|
unsigned short imgaddr;
|
|
};
|
|
static uint8_t imx074_delay_msecs_stdby = 5;
|
|
static uint16_t imx074_delay_msecs_stream = 5;
|
|
static int32_t config_csi;
|
|
|
|
static struct imx074_ctrl_t *imx074_ctrl;
|
|
static DECLARE_WAIT_QUEUE_HEAD(imx074_wait_queue);
|
|
DEFINE_MUTEX(imx074_mut);
|
|
|
|
/*=============================================================*/
|
|
|
|
static int imx074_i2c_rxdata(unsigned short saddr,
|
|
unsigned char *rxdata, int length)
|
|
{
|
|
struct i2c_msg msgs[] = {
|
|
{
|
|
.addr = saddr,
|
|
.flags = 0,
|
|
.len = 2,
|
|
.buf = rxdata,
|
|
},
|
|
{
|
|
.addr = saddr,
|
|
.flags = I2C_M_RD,
|
|
.len = 2,
|
|
.buf = rxdata,
|
|
},
|
|
};
|
|
if (i2c_transfer(imx074_client->adapter, msgs, 2) < 0) {
|
|
CDBG("imx074_i2c_rxdata failed!\n");
|
|
return -EIO;
|
|
}
|
|
return 0;
|
|
}
|
|
static int32_t imx074_i2c_txdata(unsigned short saddr,
|
|
unsigned char *txdata, int length)
|
|
{
|
|
struct i2c_msg msg[] = {
|
|
{
|
|
.addr = saddr,
|
|
.flags = 0,
|
|
.len = length,
|
|
.buf = txdata,
|
|
},
|
|
};
|
|
if (i2c_transfer(imx074_client->adapter, msg, 1) < 0) {
|
|
CDBG("imx074_i2c_txdata faild 0x%x\n", imx074_client->addr);
|
|
return -EIO;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int32_t imx074_i2c_read(unsigned short raddr,
|
|
unsigned short *rdata, int rlen)
|
|
{
|
|
int32_t rc = 0;
|
|
unsigned char buf[2];
|
|
if (!rdata)
|
|
return -EIO;
|
|
memset(buf, 0, sizeof(buf));
|
|
buf[0] = (raddr & 0xFF00) >> 8;
|
|
buf[1] = (raddr & 0x00FF);
|
|
rc = imx074_i2c_rxdata(imx074_client->addr, buf, rlen);
|
|
if (rc < 0) {
|
|
CDBG("imx074_i2c_read 0x%x failed!\n", raddr);
|
|
return rc;
|
|
}
|
|
*rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]);
|
|
return rc;
|
|
}
|
|
|
|
static int imx074_af_i2c_rxdata_b(unsigned short saddr,
|
|
unsigned char *rxdata, int length)
|
|
{
|
|
struct i2c_msg msgs[] = {
|
|
{
|
|
.addr = saddr,
|
|
.flags = 0,
|
|
.len = 1,
|
|
.buf = rxdata,
|
|
},
|
|
{
|
|
.addr = saddr,
|
|
.flags = I2C_M_RD,
|
|
.len = 1,
|
|
.buf = rxdata,
|
|
},
|
|
};
|
|
|
|
if (i2c_transfer(imx074_client->adapter, msgs, 2) < 0) {
|
|
CDBG("imx074_i2c_rxdata_b failed!\n");
|
|
return -EIO;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int32_t imx074_i2c_read_w_eeprom(unsigned short raddr,
|
|
unsigned short *rdata)
|
|
{
|
|
int32_t rc;
|
|
unsigned char buf;
|
|
if (!rdata)
|
|
return -EIO;
|
|
/* Read 2 bytes in sequence */
|
|
buf = (raddr & 0x00FF);
|
|
rc = imx074_af_i2c_rxdata_b(IMX074_EEPROM_SLAVE_ADDR, &buf, 1);
|
|
if (rc < 0) {
|
|
CDBG("imx074_i2c_read_eeprom 0x%x failed!\n", raddr);
|
|
return rc;
|
|
}
|
|
*rdata = buf<<8;
|
|
|
|
/* Read Second byte of data */
|
|
buf = (raddr & 0x00FF) + 1;
|
|
rc = imx074_af_i2c_rxdata_b(IMX074_EEPROM_SLAVE_ADDR, &buf, 1);
|
|
if (rc < 0) {
|
|
CDBG("imx074_i2c_read_eeprom 0x%x failed!\n", raddr);
|
|
return rc;
|
|
}
|
|
*rdata |= buf;
|
|
return rc;
|
|
}
|
|
|
|
static int32_t imx074_i2c_write_b_sensor(unsigned short waddr, uint8_t bdata)
|
|
{
|
|
int32_t rc = -EFAULT;
|
|
unsigned char buf[3];
|
|
memset(buf, 0, sizeof(buf));
|
|
buf[0] = (waddr & 0xFF00) >> 8;
|
|
buf[1] = (waddr & 0x00FF);
|
|
buf[2] = bdata;
|
|
CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata);
|
|
rc = imx074_i2c_txdata(imx074_client->addr, buf, 3);
|
|
if (rc < 0) {
|
|
CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
|
|
waddr, bdata);
|
|
}
|
|
return rc;
|
|
}
|
|
static int16_t imx074_i2c_write_b_af(unsigned short saddr,
|
|
unsigned short baddr, unsigned short bdata)
|
|
{
|
|
int32_t rc;
|
|
unsigned char buf[2];
|
|
memset(buf, 0, sizeof(buf));
|
|
buf[0] = baddr;
|
|
buf[1] = bdata;
|
|
rc = imx074_i2c_txdata(saddr, buf, 2);
|
|
if (rc < 0)
|
|
CDBG("AFi2c_write failed, saddr = 0x%x addr = 0x%x, val =0x%x!",
|
|
saddr, baddr, bdata);
|
|
return rc;
|
|
}
|
|
|
|
static int32_t imx074_i2c_write_w_table(struct imx074_i2c_reg_conf const
|
|
*reg_conf_tbl, int num)
|
|
{
|
|
int i;
|
|
int32_t rc = -EIO;
|
|
for (i = 0; i < num; i++) {
|
|
rc = imx074_i2c_write_b_sensor(reg_conf_tbl->waddr,
|
|
reg_conf_tbl->wdata);
|
|
if (rc < 0)
|
|
break;
|
|
reg_conf_tbl++;
|
|
}
|
|
return rc;
|
|
}
|
|
static int16_t imx074_af_init(void)
|
|
{
|
|
int32_t rc;
|
|
/* Initialize waveform */
|
|
rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x01, 0xA9);
|
|
rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x02, 0xD2);
|
|
rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x03, 0x0C);
|
|
rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x04, 0x14);
|
|
rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x05, 0xB6);
|
|
rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x06, 0x4F);
|
|
return rc;
|
|
}
|
|
|
|
static void imx074_get_pict_fps(uint16_t fps, uint16_t *pfps)
|
|
{
|
|
/* input fps is preview fps in Q8 format */
|
|
uint16_t preview_frame_length_lines, snapshot_frame_length_lines;
|
|
uint32_t divider, d1;
|
|
uint32_t pclk_mult;/*Q10 */
|
|
/* Total frame_length_lines and line_length_pck for preview */
|
|
preview_frame_length_lines = IMX074_QTR_SIZE_HEIGHT +
|
|
IMX074_VER_QTR_BLK_LINES;
|
|
/* Total frame_length_lines and line_length_pck for snapshot */
|
|
snapshot_frame_length_lines = IMX074_FULL_SIZE_HEIGHT +
|
|
IMX074_VER_FULL_BLK_LINES;
|
|
d1 = preview_frame_length_lines * 0x00010000 /
|
|
snapshot_frame_length_lines;
|
|
pclk_mult =
|
|
(uint32_t) ((imx074_regs.reg_pat[RES_CAPTURE].pll_multiplier *
|
|
0x00010000) /
|
|
(imx074_regs.reg_pat[RES_PREVIEW].pll_multiplier));
|
|
divider = d1 * pclk_mult / 0x00010000;
|
|
*pfps = (uint16_t) (fps * divider / 0x00010000);
|
|
}
|
|
|
|
static uint16_t imx074_get_prev_lines_pf(void)
|
|
{
|
|
if (imx074_ctrl->prev_res == QTR_SIZE)
|
|
return IMX074_QTR_SIZE_HEIGHT + IMX074_VER_QTR_BLK_LINES;
|
|
else
|
|
return IMX074_FULL_SIZE_HEIGHT + IMX074_VER_FULL_BLK_LINES;
|
|
|
|
}
|
|
|
|
static uint16_t imx074_get_prev_pixels_pl(void)
|
|
{
|
|
if (imx074_ctrl->prev_res == QTR_SIZE)
|
|
return IMX074_QTR_SIZE_WIDTH + IMX074_HRZ_QTR_BLK_PIXELS;
|
|
else
|
|
return IMX074_FULL_SIZE_WIDTH + IMX074_HRZ_FULL_BLK_PIXELS;
|
|
}
|
|
|
|
static uint16_t imx074_get_pict_lines_pf(void)
|
|
{
|
|
if (imx074_ctrl->pict_res == QTR_SIZE)
|
|
return IMX074_QTR_SIZE_HEIGHT +
|
|
IMX074_VER_QTR_BLK_LINES;
|
|
else
|
|
return IMX074_FULL_SIZE_HEIGHT +
|
|
IMX074_VER_FULL_BLK_LINES;
|
|
}
|
|
|
|
static uint16_t imx074_get_pict_pixels_pl(void)
|
|
{
|
|
if (imx074_ctrl->pict_res == QTR_SIZE)
|
|
return IMX074_QTR_SIZE_WIDTH +
|
|
IMX074_HRZ_QTR_BLK_PIXELS;
|
|
else
|
|
return IMX074_FULL_SIZE_WIDTH +
|
|
IMX074_HRZ_FULL_BLK_PIXELS;
|
|
}
|
|
|
|
static uint32_t imx074_get_pict_max_exp_lc(void)
|
|
{
|
|
if (imx074_ctrl->pict_res == QTR_SIZE)
|
|
return (IMX074_QTR_SIZE_HEIGHT +
|
|
IMX074_VER_QTR_BLK_LINES)*24;
|
|
else
|
|
return (IMX074_FULL_SIZE_HEIGHT +
|
|
IMX074_VER_FULL_BLK_LINES)*24;
|
|
}
|
|
|
|
static int32_t imx074_set_fps(struct fps_cfg *fps)
|
|
{
|
|
uint16_t total_lines_per_frame;
|
|
int32_t rc = 0;
|
|
imx074_ctrl->fps_divider = fps->fps_div;
|
|
imx074_ctrl->pict_fps_divider = fps->pict_fps_div;
|
|
if (imx074_ctrl->curr_res == QTR_SIZE) {
|
|
total_lines_per_frame = (uint16_t)(((IMX074_QTR_SIZE_HEIGHT +
|
|
IMX074_VER_QTR_BLK_LINES) *
|
|
imx074_ctrl->fps_divider) / 0x400);
|
|
} else {
|
|
total_lines_per_frame = (uint16_t)(((IMX074_FULL_SIZE_HEIGHT +
|
|
IMX074_VER_FULL_BLK_LINES) *
|
|
imx074_ctrl->pict_fps_divider) / 0x400);
|
|
}
|
|
if (imx074_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_HI,
|
|
((total_lines_per_frame & 0xFF00) >> 8)) < 0)
|
|
return rc;
|
|
if (imx074_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_LO,
|
|
(total_lines_per_frame & 0x00FF)) < 0)
|
|
return rc;
|
|
return rc;
|
|
}
|
|
|
|
static int32_t imx074_write_exp_gain(uint16_t gain, uint32_t line)
|
|
{
|
|
static uint16_t max_legal_gain = 0x00E0;
|
|
uint8_t gain_msb, gain_lsb;
|
|
uint8_t intg_time_msb, intg_time_lsb;
|
|
uint8_t frame_length_line_msb, frame_length_line_lsb;
|
|
uint16_t frame_length_lines;
|
|
int32_t rc = -1;
|
|
|
|
CDBG("imx074_write_exp_gain : gain = %d line = %d", gain, line);
|
|
if (imx074_ctrl->curr_res == QTR_SIZE) {
|
|
frame_length_lines = IMX074_QTR_SIZE_HEIGHT +
|
|
IMX074_VER_QTR_BLK_LINES;
|
|
frame_length_lines = frame_length_lines *
|
|
imx074_ctrl->fps_divider / 0x400;
|
|
} else {
|
|
frame_length_lines = IMX074_FULL_SIZE_HEIGHT +
|
|
IMX074_VER_FULL_BLK_LINES;
|
|
frame_length_lines = frame_length_lines *
|
|
imx074_ctrl->pict_fps_divider / 0x400;
|
|
}
|
|
if (line > (frame_length_lines - IMX074_OFFSET))
|
|
frame_length_lines = line + IMX074_OFFSET;
|
|
|
|
CDBG("imx074 setting line = %d\n", line);
|
|
|
|
|
|
CDBG("imx074 setting frame_length_lines = %d\n",
|
|
frame_length_lines);
|
|
|
|
if (gain > max_legal_gain)
|
|
/* range: 0 to 224 */
|
|
gain = max_legal_gain;
|
|
|
|
/* update gain registers */
|
|
gain_msb = (uint8_t) ((gain & 0xFF00) >> 8);
|
|
gain_lsb = (uint8_t) (gain & 0x00FF);
|
|
|
|
frame_length_line_msb = (uint8_t) ((frame_length_lines & 0xFF00) >> 8);
|
|
frame_length_line_lsb = (uint8_t) (frame_length_lines & 0x00FF);
|
|
|
|
/* update line count registers */
|
|
intg_time_msb = (uint8_t) ((line & 0xFF00) >> 8);
|
|
intg_time_lsb = (uint8_t) (line & 0x00FF);
|
|
|
|
rc = imx074_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
|
|
GROUPED_PARAMETER_HOLD);
|
|
if (rc < 0)
|
|
return rc;
|
|
CDBG("imx074 setting REG_ANALOGUE_GAIN_CODE_GLOBAL_HI = 0x%X\n",
|
|
gain_msb);
|
|
rc = imx074_i2c_write_b_sensor(REG_ANALOGUE_GAIN_CODE_GLOBAL_HI,
|
|
gain_msb);
|
|
if (rc < 0)
|
|
return rc;
|
|
CDBG("imx074 setting REG_ANALOGUE_GAIN_CODE_GLOBAL_LO = 0x%X\n",
|
|
gain_lsb);
|
|
rc = imx074_i2c_write_b_sensor(REG_ANALOGUE_GAIN_CODE_GLOBAL_LO,
|
|
gain_lsb);
|
|
if (rc < 0)
|
|
return rc;
|
|
|
|
CDBG("imx074 setting REG_FRAME_LENGTH_LINES_HI = 0x%X\n",
|
|
frame_length_line_msb);
|
|
rc = imx074_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_HI,
|
|
frame_length_line_msb);
|
|
if (rc < 0)
|
|
return rc;
|
|
|
|
CDBG("imx074 setting REG_FRAME_LENGTH_LINES_LO = 0x%X\n",
|
|
frame_length_line_lsb);
|
|
rc = imx074_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_LO,
|
|
frame_length_line_lsb);
|
|
if (rc < 0)
|
|
return rc;
|
|
|
|
CDBG("imx074 setting REG_COARSE_INTEGRATION_TIME_HI = 0x%X\n",
|
|
intg_time_msb);
|
|
rc = imx074_i2c_write_b_sensor(REG_COARSE_INTEGRATION_TIME_HI,
|
|
intg_time_msb);
|
|
if (rc < 0)
|
|
return rc;
|
|
|
|
CDBG("imx074 setting REG_COARSE_INTEGRATION_TIME_LO = 0x%X\n",
|
|
intg_time_lsb);
|
|
rc = imx074_i2c_write_b_sensor(REG_COARSE_INTEGRATION_TIME_LO,
|
|
intg_time_lsb);
|
|
if (rc < 0)
|
|
return rc;
|
|
|
|
rc = imx074_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
|
|
GROUPED_PARAMETER_HOLD_OFF);
|
|
if (rc < 0)
|
|
return rc;
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int32_t imx074_set_pict_exp_gain(uint16_t gain, uint32_t line)
|
|
{
|
|
int32_t rc = 0;
|
|
rc = imx074_write_exp_gain(gain, line);
|
|
return rc;
|
|
}
|
|
|
|
static int32_t imx074_move_focus(int direction,
|
|
int32_t num_steps)
|
|
{
|
|
int32_t step_direction, dest_step_position, bit_mask;
|
|
int32_t rc = 0;
|
|
|
|
if (num_steps == 0)
|
|
return rc;
|
|
|
|
if (direction == MOVE_NEAR) {
|
|
step_direction = 1;
|
|
bit_mask = 0x80;
|
|
} else if (direction == MOVE_FAR) {
|
|
step_direction = -1;
|
|
bit_mask = 0x00;
|
|
} else {
|
|
CDBG("imx074_move_focus: Illegal focus direction");
|
|
return -EINVAL;
|
|
}
|
|
dest_step_position = imx074_ctrl->curr_step_pos +
|
|
(step_direction * num_steps);
|
|
if (dest_step_position < 0)
|
|
dest_step_position = 0;
|
|
else if (dest_step_position > IMX074_TOTAL_STEPS_NEAR_TO_FAR)
|
|
dest_step_position = IMX074_TOTAL_STEPS_NEAR_TO_FAR;
|
|
rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x00,
|
|
((num_steps * imx074_l_region_code_per_step) | bit_mask));
|
|
CDBG("%s: Index: %d\n", __func__, dest_step_position);
|
|
imx074_ctrl->curr_step_pos = dest_step_position;
|
|
return rc;
|
|
}
|
|
|
|
|
|
static int32_t imx074_set_default_focus(uint8_t af_step)
|
|
{
|
|
int32_t rc;
|
|
/* Initialize to infinity */
|
|
rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x00, 0x7F);
|
|
rc = imx074_i2c_write_b_af(IMX074_AF_I2C_SLAVE_ID, 0x00, 0x7F);
|
|
imx074_ctrl->curr_step_pos = 0;
|
|
return rc;
|
|
}
|
|
static int32_t imx074_test(enum imx074_test_mode_t mo)
|
|
{
|
|
int32_t rc = 0;
|
|
if (mo == TEST_OFF)
|
|
return rc;
|
|
else {
|
|
/* Set mo to 2 inorder to enable test pattern*/
|
|
if (imx074_i2c_write_b_sensor(REG_TEST_PATTERN_MODE,
|
|
(uint8_t) mo) < 0) {
|
|
return rc;
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
static int32_t imx074_sensor_setting(int update_type, int rt)
|
|
{
|
|
int32_t rc = 0;
|
|
struct msm_camera_csi_params imx074_csi_params;
|
|
switch (update_type) {
|
|
case REG_INIT:
|
|
if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
|
|
struct imx074_i2c_reg_conf init_tbl[] = {
|
|
{REG_PRE_PLL_CLK_DIV,
|
|
imx074_regs.reg_pat_init[0].
|
|
pre_pll_clk_div},
|
|
{REG_PLSTATIM,
|
|
imx074_regs.reg_pat_init[0].
|
|
plstatim},
|
|
{REG_3024,
|
|
imx074_regs.reg_pat_init[0].
|
|
reg_3024},
|
|
{REG_IMAGE_ORIENTATION,
|
|
imx074_regs.reg_pat_init[0].
|
|
image_orientation},
|
|
{REG_VNDMY_ABLMGSHLMT,
|
|
imx074_regs.reg_pat_init[0].
|
|
vndmy_ablmgshlmt},
|
|
{REG_Y_OPBADDR_START_DI,
|
|
imx074_regs.reg_pat_init[0].
|
|
y_opbaddr_start_di},
|
|
{REG_3015,
|
|
imx074_regs.reg_pat_init[0].
|
|
reg_0x3015},
|
|
{REG_301C,
|
|
imx074_regs.reg_pat_init[0].
|
|
reg_0x301c},
|
|
{REG_302C,
|
|
imx074_regs.reg_pat_init[0].
|
|
reg_0x302c},
|
|
{REG_3031,
|
|
imx074_regs.reg_pat_init[0].reg_0x3031},
|
|
{REG_3041,
|
|
imx074_regs.reg_pat_init[0].reg_0x3041},
|
|
{REG_3051,
|
|
imx074_regs.reg_pat_init[0].reg_0x3051},
|
|
{REG_3053,
|
|
imx074_regs.reg_pat_init[0].reg_0x3053},
|
|
{REG_3057,
|
|
imx074_regs.reg_pat_init[0].reg_0x3057},
|
|
{REG_305C,
|
|
imx074_regs.reg_pat_init[0].reg_0x305c},
|
|
{REG_305D,
|
|
imx074_regs.reg_pat_init[0].reg_0x305d},
|
|
{REG_3060,
|
|
imx074_regs.reg_pat_init[0].reg_0x3060},
|
|
{REG_3065,
|
|
imx074_regs.reg_pat_init[0].reg_0x3065},
|
|
{REG_30AA,
|
|
imx074_regs.reg_pat_init[0].reg_0x30aa},
|
|
{REG_30AB,
|
|
imx074_regs.reg_pat_init[0].reg_0x30ab},
|
|
{REG_30B0,
|
|
imx074_regs.reg_pat_init[0].reg_0x30b0},
|
|
{REG_30B2,
|
|
imx074_regs.reg_pat_init[0].reg_0x30b2},
|
|
{REG_30D3,
|
|
imx074_regs.reg_pat_init[0].reg_0x30d3},
|
|
{REG_3106,
|
|
imx074_regs.reg_pat_init[0].reg_0x3106},
|
|
{REG_310C,
|
|
imx074_regs.reg_pat_init[0].reg_0x310c},
|
|
{REG_3304,
|
|
imx074_regs.reg_pat_init[0].reg_0x3304},
|
|
{REG_3305,
|
|
imx074_regs.reg_pat_init[0].reg_0x3305},
|
|
{REG_3306,
|
|
imx074_regs.reg_pat_init[0].reg_0x3306},
|
|
{REG_3307,
|
|
imx074_regs.reg_pat_init[0].reg_0x3307},
|
|
{REG_3308,
|
|
imx074_regs.reg_pat_init[0].reg_0x3308},
|
|
{REG_3309,
|
|
imx074_regs.reg_pat_init[0].reg_0x3309},
|
|
{REG_330A,
|
|
imx074_regs.reg_pat_init[0].reg_0x330a},
|
|
{REG_330B,
|
|
imx074_regs.reg_pat_init[0].reg_0x330b},
|
|
{REG_330C,
|
|
imx074_regs.reg_pat_init[0].reg_0x330c},
|
|
{REG_330D,
|
|
imx074_regs.reg_pat_init[0].reg_0x330d},
|
|
{REG_330F,
|
|
imx074_regs.reg_pat_init[0].reg_0x330f},
|
|
{REG_3381,
|
|
imx074_regs.reg_pat_init[0].reg_0x3381},
|
|
};
|
|
struct imx074_i2c_reg_conf init_mode_tbl[] = {
|
|
{REG_GROUPED_PARAMETER_HOLD,
|
|
GROUPED_PARAMETER_HOLD},
|
|
{REG_PLL_MULTIPLIER,
|
|
imx074_regs.reg_pat[rt].
|
|
pll_multiplier},
|
|
{REG_FRAME_LENGTH_LINES_HI,
|
|
imx074_regs.reg_pat[rt].
|
|
frame_length_lines_hi},
|
|
{REG_FRAME_LENGTH_LINES_LO,
|
|
imx074_regs.reg_pat[rt].
|
|
frame_length_lines_lo},
|
|
{REG_YADDR_START ,
|
|
imx074_regs.reg_pat[rt].
|
|
y_addr_start},
|
|
{REG_YAAAR_END,
|
|
imx074_regs.reg_pat[rt].
|
|
y_add_end},
|
|
{REG_X_OUTPUT_SIZE_MSB,
|
|
imx074_regs.reg_pat[rt].
|
|
x_output_size_msb},
|
|
{REG_X_OUTPUT_SIZE_LSB,
|
|
imx074_regs.reg_pat[rt].
|
|
x_output_size_lsb},
|
|
{REG_Y_OUTPUT_SIZE_MSB,
|
|
imx074_regs.reg_pat[rt].
|
|
y_output_size_msb},
|
|
{REG_Y_OUTPUT_SIZE_LSB ,
|
|
imx074_regs.reg_pat[rt].
|
|
y_output_size_lsb},
|
|
{REG_X_EVEN_INC,
|
|
imx074_regs.reg_pat[rt].
|
|
x_even_inc},
|
|
{REG_X_ODD_INC,
|
|
imx074_regs.reg_pat[rt].
|
|
x_odd_inc},
|
|
{REG_Y_EVEN_INC,
|
|
imx074_regs.reg_pat[rt].
|
|
y_even_inc},
|
|
{REG_Y_ODD_INC,
|
|
imx074_regs.reg_pat[rt].
|
|
y_odd_inc},
|
|
{REG_HMODEADD,
|
|
imx074_regs.reg_pat[rt].
|
|
hmodeadd},
|
|
{REG_VMODEADD,
|
|
imx074_regs.reg_pat[rt].
|
|
vmodeadd},
|
|
{REG_VAPPLINE_START,
|
|
imx074_regs.reg_pat[rt].
|
|
vapplinepos_start},
|
|
{REG_VAPPLINE_END,
|
|
imx074_regs.reg_pat[rt].
|
|
vapplinepos_end},
|
|
{REG_SHUTTER,
|
|
imx074_regs.reg_pat[rt].
|
|
shutter},
|
|
{REG_HADDAVE,
|
|
imx074_regs.reg_pat[rt].
|
|
haddave},
|
|
{REG_LANESEL,
|
|
imx074_regs.reg_pat[rt].
|
|
lanesel},
|
|
{REG_GROUPED_PARAMETER_HOLD,
|
|
GROUPED_PARAMETER_HOLD_OFF},
|
|
|
|
};
|
|
/* reset fps_divider */
|
|
imx074_ctrl->fps = 30 * Q8;
|
|
imx074_ctrl->fps_divider = 1 * 0x400;
|
|
/* stop streaming */
|
|
rc = imx074_i2c_write_b_sensor(REG_MODE_SELECT,
|
|
MODE_SELECT_STANDBY_MODE);
|
|
if (rc < 0)
|
|
return rc;
|
|
msleep(imx074_delay_msecs_stdby);
|
|
rc = imx074_i2c_write_w_table(&init_tbl[0],
|
|
ARRAY_SIZE(init_tbl));
|
|
if (rc < 0)
|
|
return rc;
|
|
rc = imx074_i2c_write_w_table(&init_mode_tbl[0],
|
|
ARRAY_SIZE(init_mode_tbl));
|
|
if (rc < 0)
|
|
return rc;
|
|
rc = imx074_test(imx074_ctrl->set_test);
|
|
return rc;
|
|
}
|
|
break;
|
|
case UPDATE_PERIODIC:
|
|
if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
|
|
struct imx074_i2c_reg_conf mode_tbl[] = {
|
|
{REG_GROUPED_PARAMETER_HOLD,
|
|
GROUPED_PARAMETER_HOLD},
|
|
{REG_PLL_MULTIPLIER,
|
|
imx074_regs.reg_pat[rt].
|
|
pll_multiplier},
|
|
{REG_FRAME_LENGTH_LINES_HI,
|
|
imx074_regs.reg_pat[rt].
|
|
frame_length_lines_hi},
|
|
{REG_FRAME_LENGTH_LINES_LO,
|
|
imx074_regs.reg_pat[rt].
|
|
frame_length_lines_lo},
|
|
{REG_YADDR_START ,
|
|
imx074_regs.reg_pat[rt].
|
|
y_addr_start},
|
|
{REG_YAAAR_END,
|
|
imx074_regs.reg_pat[rt].
|
|
y_add_end},
|
|
{REG_X_OUTPUT_SIZE_MSB,
|
|
imx074_regs.reg_pat[rt].
|
|
x_output_size_msb},
|
|
{REG_X_OUTPUT_SIZE_LSB,
|
|
imx074_regs.reg_pat[rt].
|
|
x_output_size_lsb},
|
|
{REG_Y_OUTPUT_SIZE_MSB,
|
|
imx074_regs.reg_pat[rt].
|
|
y_output_size_msb},
|
|
{REG_Y_OUTPUT_SIZE_LSB ,
|
|
imx074_regs.reg_pat[rt].
|
|
y_output_size_lsb},
|
|
{REG_X_EVEN_INC,
|
|
imx074_regs.reg_pat[rt].
|
|
x_even_inc},
|
|
{REG_X_ODD_INC,
|
|
imx074_regs.reg_pat[rt].
|
|
x_odd_inc},
|
|
{REG_Y_EVEN_INC,
|
|
imx074_regs.reg_pat[rt].
|
|
y_even_inc},
|
|
{REG_Y_ODD_INC,
|
|
imx074_regs.reg_pat[rt].
|
|
y_odd_inc},
|
|
{REG_HMODEADD,
|
|
imx074_regs.reg_pat[rt].
|
|
hmodeadd},
|
|
{REG_VMODEADD,
|
|
imx074_regs.reg_pat[rt].
|
|
vmodeadd},
|
|
{REG_VAPPLINE_START,
|
|
imx074_regs.reg_pat[rt].
|
|
vapplinepos_start},
|
|
{REG_VAPPLINE_END,
|
|
imx074_regs.reg_pat[rt].
|
|
vapplinepos_end},
|
|
{REG_SHUTTER,
|
|
imx074_regs.reg_pat[rt].
|
|
shutter},
|
|
{REG_HADDAVE,
|
|
imx074_regs.reg_pat[rt].
|
|
haddave},
|
|
{REG_LANESEL,
|
|
imx074_regs.reg_pat[rt].
|
|
lanesel},
|
|
{REG_GROUPED_PARAMETER_HOLD,
|
|
GROUPED_PARAMETER_HOLD_OFF},
|
|
};
|
|
|
|
/* stop streaming */
|
|
rc = imx074_i2c_write_b_sensor(REG_MODE_SELECT,
|
|
MODE_SELECT_STANDBY_MODE);
|
|
msleep(imx074_delay_msecs_stdby);
|
|
if (config_csi == 0) {
|
|
imx074_csi_params.lane_cnt = 4;
|
|
imx074_csi_params.data_format = CSI_10BIT;
|
|
imx074_csi_params.lane_assign = 0xe4;
|
|
imx074_csi_params.dpcm_scheme = 0;
|
|
imx074_csi_params.settle_cnt = 0x14;
|
|
rc = msm_camio_csi_config(&imx074_csi_params);
|
|
/*imx074_delay_msecs_stdby*/
|
|
msleep(imx074_delay_msecs_stream);
|
|
config_csi = 1;
|
|
}
|
|
rc = imx074_i2c_write_w_table(&mode_tbl[0],
|
|
ARRAY_SIZE(mode_tbl));
|
|
if (rc < 0)
|
|
return rc;
|
|
rc = imx074_i2c_write_b_sensor(REG_MODE_SELECT,
|
|
MODE_SELECT_STREAM);
|
|
if (rc < 0)
|
|
return rc;
|
|
msleep(imx074_delay_msecs_stream);
|
|
}
|
|
break;
|
|
default:
|
|
rc = -EINVAL;
|
|
break;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
static int32_t imx074_video_config(int mode)
|
|
{
|
|
|
|
int32_t rc = 0;
|
|
int rt;
|
|
/* change sensor resolution if needed */
|
|
if (imx074_ctrl->prev_res == QTR_SIZE) {
|
|
rt = RES_PREVIEW;
|
|
} else {
|
|
rt = RES_CAPTURE;
|
|
}
|
|
if (imx074_sensor_setting(UPDATE_PERIODIC, rt) < 0)
|
|
return rc;
|
|
imx074_ctrl->curr_res = imx074_ctrl->prev_res;
|
|
imx074_ctrl->sensormode = mode;
|
|
return rc;
|
|
}
|
|
|
|
static int32_t imx074_snapshot_config(int mode)
|
|
{
|
|
int32_t rc = 0;
|
|
int rt = RES_PREVIEW; /* TODO: Used without initialization, guessing. */
|
|
/* change sensor resolution if needed */
|
|
if (imx074_ctrl->curr_res != imx074_ctrl->pict_res) {
|
|
if (imx074_ctrl->pict_res == QTR_SIZE) {
|
|
rt = RES_PREVIEW;
|
|
} else {
|
|
rt = RES_CAPTURE;
|
|
}
|
|
}
|
|
if (imx074_sensor_setting(UPDATE_PERIODIC, rt) < 0)
|
|
return rc;
|
|
imx074_ctrl->curr_res = imx074_ctrl->pict_res;
|
|
imx074_ctrl->sensormode = mode;
|
|
return rc;
|
|
}
|
|
static int32_t imx074_raw_snapshot_config(int mode)
|
|
{
|
|
int32_t rc = 0;
|
|
int rt = RES_PREVIEW; /* TODO: Used without initialization, guessing. */
|
|
/* change sensor resolution if needed */
|
|
if (imx074_ctrl->curr_res != imx074_ctrl->pict_res) {
|
|
if (imx074_ctrl->pict_res == QTR_SIZE) {
|
|
rt = RES_PREVIEW;
|
|
} else {
|
|
rt = RES_CAPTURE;
|
|
}
|
|
}
|
|
if (imx074_sensor_setting(UPDATE_PERIODIC, rt) < 0)
|
|
return rc;
|
|
imx074_ctrl->curr_res = imx074_ctrl->pict_res;
|
|
imx074_ctrl->sensormode = mode;
|
|
return rc;
|
|
}
|
|
static int32_t imx074_set_sensor_mode(int mode,
|
|
int res)
|
|
{
|
|
int32_t rc = 0;
|
|
switch (mode) {
|
|
case SENSOR_PREVIEW_MODE:
|
|
rc = imx074_video_config(mode);
|
|
break;
|
|
case SENSOR_SNAPSHOT_MODE:
|
|
rc = imx074_snapshot_config(mode);
|
|
break;
|
|
case SENSOR_RAW_SNAPSHOT_MODE:
|
|
rc = imx074_raw_snapshot_config(mode);
|
|
break;
|
|
default:
|
|
rc = -EINVAL;
|
|
break;
|
|
}
|
|
return rc;
|
|
}
|
|
static int32_t imx074_power_down(void)
|
|
{
|
|
imx074_i2c_write_b_sensor(REG_MODE_SELECT,
|
|
MODE_SELECT_STANDBY_MODE);
|
|
msleep(imx074_delay_msecs_stdby);
|
|
return 0;
|
|
}
|
|
static int imx074_probe_init_done(const struct msm_camera_sensor_info *data)
|
|
{
|
|
gpio_set_value_cansleep(data->sensor_reset, 0);
|
|
gpio_direction_input(data->sensor_reset);
|
|
gpio_free(data->sensor_reset);
|
|
return 0;
|
|
}
|
|
|
|
static int imx074_read_eeprom_data(struct sensor_cfg_data *cfg)
|
|
{
|
|
int32_t rc = 0;
|
|
uint16_t eepromdata = 0;
|
|
uint8_t addr = 0;
|
|
|
|
addr = 0x10;
|
|
rc = imx074_i2c_read_w_eeprom(addr, &eepromdata);
|
|
if (rc < 0) {
|
|
CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr);
|
|
return rc;
|
|
}
|
|
cfg->cfg.calib_info.r_over_g = eepromdata;
|
|
|
|
addr = 0x12;
|
|
rc = imx074_i2c_read_w_eeprom(addr, &eepromdata);
|
|
if (rc < 0) {
|
|
CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr);
|
|
return rc;
|
|
}
|
|
cfg->cfg.calib_info.b_over_g = eepromdata;
|
|
|
|
addr = 0x14;
|
|
rc = imx074_i2c_read_w_eeprom(addr, &eepromdata);
|
|
if (rc < 0) {
|
|
CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr);
|
|
return rc;
|
|
}
|
|
cfg->cfg.calib_info.gr_over_gb = eepromdata;
|
|
|
|
addr = 0x1A;
|
|
rc = imx074_i2c_read_w_eeprom(addr, &eepromdata);
|
|
if (rc < 0) {
|
|
CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr);
|
|
return rc;
|
|
}
|
|
cfg->cfg.calib_info.macro_2_inf = eepromdata;
|
|
|
|
addr = 0x1C;
|
|
rc = imx074_i2c_read_w_eeprom(addr, &eepromdata);
|
|
if (rc < 0) {
|
|
CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr);
|
|
return rc;
|
|
}
|
|
cfg->cfg.calib_info.inf_2_macro = eepromdata;
|
|
|
|
addr = 0x1E;
|
|
rc = imx074_i2c_read_w_eeprom(addr, &eepromdata);
|
|
if (rc < 0) {
|
|
CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr);
|
|
return rc;
|
|
}
|
|
cfg->cfg.calib_info.stroke_amt = eepromdata;
|
|
|
|
addr = 0x20;
|
|
rc = imx074_i2c_read_w_eeprom(addr, &eepromdata);
|
|
if (rc < 0) {
|
|
CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr);
|
|
return rc;
|
|
}
|
|
cfg->cfg.calib_info.af_pos_1m = eepromdata;
|
|
|
|
addr = 0x22;
|
|
rc = imx074_i2c_read_w_eeprom(addr, &eepromdata);
|
|
if (rc < 0) {
|
|
CDBG("%s: Error Reading EEPROM @ 0x%x\n", __func__, addr);
|
|
return rc;
|
|
}
|
|
cfg->cfg.calib_info.af_pos_inf = eepromdata;
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int imx074_probe_init_sensor(const struct msm_camera_sensor_info *data)
|
|
{
|
|
int32_t rc = 0;
|
|
unsigned short chipidl, chipidh;
|
|
CDBG("%s: %d\n", __func__, __LINE__);
|
|
rc = gpio_request(data->sensor_reset, "imx074");
|
|
CDBG(" imx074_probe_init_sensor \n");
|
|
if (!rc) {
|
|
CDBG("sensor_reset = %d\n", rc);
|
|
gpio_direction_output(data->sensor_reset, 0);
|
|
usleep_range(5000, 6000);
|
|
gpio_set_value_cansleep(data->sensor_reset, 1);
|
|
usleep_range(5000, 6000);
|
|
} else {
|
|
CDBG("gpio reset fail");
|
|
goto init_probe_done;
|
|
}
|
|
CDBG("imx074_probe_init_sensor is called\n");
|
|
/* 3. Read sensor Model ID: */
|
|
rc = imx074_i2c_read(0x0000, &chipidh, 1);
|
|
if (rc < 0) {
|
|
CDBG("Model read failed\n");
|
|
goto init_probe_fail;
|
|
}
|
|
rc = imx074_i2c_read(0x0001, &chipidl, 1);
|
|
if (rc < 0) {
|
|
CDBG("Model read failed\n");
|
|
goto init_probe_fail;
|
|
}
|
|
CDBG("imx074 model_id = 0x%x 0x%x\n", chipidh, chipidl);
|
|
/* 4. Compare sensor ID to IMX074 ID: */
|
|
if (chipidh != 0x00 || chipidl != 0x74) {
|
|
rc = -ENODEV;
|
|
CDBG("imx074_probe_init_sensor fail chip id doesnot match\n");
|
|
goto init_probe_fail;
|
|
}
|
|
goto init_probe_done;
|
|
init_probe_fail:
|
|
CDBG("imx074_probe_init_sensor fails\n");
|
|
imx074_probe_init_done(data);
|
|
init_probe_done:
|
|
CDBG(" imx074_probe_init_sensor finishes\n");
|
|
return rc;
|
|
}
|
|
static int32_t imx074_poweron_af(void)
|
|
{
|
|
int32_t rc = 0;
|
|
CDBG("imx074 enable AF actuator, gpio = %d\n",
|
|
imx074_ctrl->sensordata->vcm_pwd);
|
|
rc = gpio_request(imx074_ctrl->sensordata->vcm_pwd, "imx074");
|
|
if (!rc) {
|
|
gpio_direction_output(imx074_ctrl->sensordata->vcm_pwd, 1);
|
|
msleep(20);
|
|
rc = imx074_af_init();
|
|
if (rc < 0)
|
|
CDBG("imx074 AF initialisation failed\n");
|
|
} else {
|
|
CDBG("%s: AF PowerON gpio_request failed %d\n", __func__, rc);
|
|
}
|
|
return rc;
|
|
}
|
|
static void imx074_poweroff_af(void)
|
|
{
|
|
gpio_set_value_cansleep(imx074_ctrl->sensordata->vcm_pwd, 0);
|
|
gpio_free(imx074_ctrl->sensordata->vcm_pwd);
|
|
}
|
|
/* camsensor_iu060f_imx074_reset */
|
|
int imx074_sensor_open_init(const struct msm_camera_sensor_info *data)
|
|
{
|
|
int32_t rc = 0;
|
|
CDBG("%s: %d\n", __func__, __LINE__);
|
|
CDBG("Calling imx074_sensor_open_init\n");
|
|
imx074_ctrl = kzalloc(sizeof(struct imx074_ctrl_t), GFP_KERNEL);
|
|
if (!imx074_ctrl) {
|
|
CDBG("imx074_init failed!\n");
|
|
rc = -ENOMEM;
|
|
goto init_done;
|
|
}
|
|
imx074_ctrl->fps_divider = 1 * 0x00000400;
|
|
imx074_ctrl->pict_fps_divider = 1 * 0x00000400;
|
|
imx074_ctrl->fps = 30 * Q8;
|
|
imx074_ctrl->set_test = TEST_OFF;
|
|
imx074_ctrl->prev_res = QTR_SIZE;
|
|
imx074_ctrl->pict_res = FULL_SIZE;
|
|
imx074_ctrl->curr_res = INVALID_SIZE;
|
|
config_csi = 0;
|
|
|
|
if (data)
|
|
imx074_ctrl->sensordata = data;
|
|
|
|
/* enable mclk first */
|
|
msm_camio_clk_rate_set(IMX074_DEFAULT_MASTER_CLK_RATE);
|
|
usleep_range(1000, 2000);
|
|
rc = imx074_probe_init_sensor(data);
|
|
if (rc < 0) {
|
|
CDBG("Calling imx074_sensor_open_init fail\n");
|
|
goto probe_fail;
|
|
}
|
|
|
|
rc = imx074_sensor_setting(REG_INIT, RES_PREVIEW);
|
|
if (rc < 0) {
|
|
CDBG("imx074_sensor_setting failed\n");
|
|
goto init_fail;
|
|
}
|
|
if (machine_is_msm8x60_fluid())
|
|
rc = imx074_poweron_af();
|
|
else
|
|
rc = imx074_af_init();
|
|
if (rc < 0) {
|
|
CDBG("AF initialisation failed\n");
|
|
goto init_fail;
|
|
} else
|
|
goto init_done;
|
|
probe_fail:
|
|
CDBG(" imx074_sensor_open_init probe fail\n");
|
|
kfree(imx074_ctrl);
|
|
return rc;
|
|
init_fail:
|
|
CDBG(" imx074_sensor_open_init fail\n");
|
|
imx074_probe_init_done(data);
|
|
kfree(imx074_ctrl);
|
|
init_done:
|
|
CDBG("imx074_sensor_open_init done\n");
|
|
return rc;
|
|
}
|
|
static int imx074_init_client(struct i2c_client *client)
|
|
{
|
|
/* Initialize the MSM_CAMI2C Chip */
|
|
init_waitqueue_head(&imx074_wait_queue);
|
|
return 0;
|
|
}
|
|
|
|
static const struct i2c_device_id imx074_i2c_id[] = {
|
|
{"imx074", 0},
|
|
{ }
|
|
};
|
|
|
|
static int imx074_i2c_probe(struct i2c_client *client,
|
|
const struct i2c_device_id *id)
|
|
{
|
|
int rc = 0;
|
|
CDBG("imx074_probe called!\n");
|
|
|
|
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
|
CDBG("i2c_check_functionality failed\n");
|
|
goto probe_failure;
|
|
}
|
|
|
|
imx074_sensorw = kzalloc(sizeof(struct imx074_work_t), GFP_KERNEL);
|
|
if (!imx074_sensorw) {
|
|
CDBG("kzalloc failed.\n");
|
|
rc = -ENOMEM;
|
|
goto probe_failure;
|
|
}
|
|
|
|
i2c_set_clientdata(client, imx074_sensorw);
|
|
imx074_init_client(client);
|
|
imx074_client = client;
|
|
|
|
|
|
CDBG("imx074_probe successed! rc = %d\n", rc);
|
|
return 0;
|
|
|
|
probe_failure:
|
|
CDBG("imx074_probe failed! rc = %d\n", rc);
|
|
return rc;
|
|
}
|
|
|
|
static int __exit imx074_remove(struct i2c_client *client)
|
|
{
|
|
struct imx074_work_t_t *sensorw = i2c_get_clientdata(client);
|
|
free_irq(client->irq, sensorw);
|
|
imx074_client = NULL;
|
|
kfree(sensorw);
|
|
return 0;
|
|
}
|
|
|
|
static struct i2c_driver imx074_i2c_driver = {
|
|
.id_table = imx074_i2c_id,
|
|
.probe = imx074_i2c_probe,
|
|
.remove = __exit_p(imx074_i2c_remove),
|
|
.driver = {
|
|
.name = "imx074",
|
|
},
|
|
};
|
|
|
|
int imx074_sensor_config(void __user *argp)
|
|
{
|
|
struct sensor_cfg_data cdata;
|
|
long rc = 0;
|
|
if (copy_from_user(&cdata,
|
|
(void *)argp,
|
|
sizeof(struct sensor_cfg_data)))
|
|
return -EFAULT;
|
|
mutex_lock(&imx074_mut);
|
|
CDBG("imx074_sensor_config: cfgtype = %d\n",
|
|
cdata.cfgtype);
|
|
switch (cdata.cfgtype) {
|
|
case CFG_GET_PICT_FPS:
|
|
imx074_get_pict_fps(
|
|
cdata.cfg.gfps.prevfps,
|
|
&(cdata.cfg.gfps.pictfps));
|
|
if (copy_to_user((void *)argp,
|
|
&cdata,
|
|
sizeof(struct sensor_cfg_data)))
|
|
rc = -EFAULT;
|
|
break;
|
|
case CFG_GET_PREV_L_PF:
|
|
cdata.cfg.prevl_pf =
|
|
imx074_get_prev_lines_pf();
|
|
if (copy_to_user((void *)argp,
|
|
&cdata,
|
|
sizeof(struct sensor_cfg_data)))
|
|
rc = -EFAULT;
|
|
break;
|
|
case CFG_GET_PREV_P_PL:
|
|
cdata.cfg.prevp_pl =
|
|
imx074_get_prev_pixels_pl();
|
|
if (copy_to_user((void *)argp,
|
|
&cdata,
|
|
sizeof(struct sensor_cfg_data)))
|
|
rc = -EFAULT;
|
|
break;
|
|
|
|
case CFG_GET_PICT_L_PF:
|
|
cdata.cfg.pictl_pf =
|
|
imx074_get_pict_lines_pf();
|
|
if (copy_to_user((void *)argp,
|
|
&cdata,
|
|
sizeof(struct sensor_cfg_data)))
|
|
rc = -EFAULT;
|
|
break;
|
|
case CFG_GET_PICT_P_PL:
|
|
cdata.cfg.pictp_pl =
|
|
imx074_get_pict_pixels_pl();
|
|
if (copy_to_user((void *)argp,
|
|
&cdata,
|
|
sizeof(struct sensor_cfg_data)))
|
|
rc = -EFAULT;
|
|
break;
|
|
case CFG_GET_PICT_MAX_EXP_LC:
|
|
cdata.cfg.pict_max_exp_lc =
|
|
imx074_get_pict_max_exp_lc();
|
|
if (copy_to_user((void *)argp,
|
|
&cdata,
|
|
sizeof(struct sensor_cfg_data)))
|
|
rc = -EFAULT;
|
|
break;
|
|
case CFG_SET_FPS:
|
|
case CFG_SET_PICT_FPS:
|
|
rc = imx074_set_fps(&(cdata.cfg.fps));
|
|
break;
|
|
case CFG_SET_EXP_GAIN:
|
|
rc =
|
|
imx074_write_exp_gain(
|
|
cdata.cfg.exp_gain.gain,
|
|
cdata.cfg.exp_gain.line);
|
|
break;
|
|
case CFG_SET_PICT_EXP_GAIN:
|
|
rc =
|
|
imx074_set_pict_exp_gain(
|
|
cdata.cfg.exp_gain.gain,
|
|
cdata.cfg.exp_gain.line);
|
|
break;
|
|
case CFG_SET_MODE:
|
|
rc = imx074_set_sensor_mode(cdata.mode,
|
|
cdata.rs);
|
|
break;
|
|
case CFG_PWR_DOWN:
|
|
rc = imx074_power_down();
|
|
break;
|
|
case CFG_GET_CALIB_DATA:
|
|
rc = imx074_read_eeprom_data(&cdata);
|
|
if (rc < 0)
|
|
break;
|
|
if (copy_to_user((void *)argp,
|
|
&cdata,
|
|
sizeof(cdata)))
|
|
rc = -EFAULT;
|
|
break;
|
|
case CFG_MOVE_FOCUS:
|
|
rc =
|
|
imx074_move_focus(
|
|
cdata.cfg.focus.dir,
|
|
cdata.cfg.focus.steps);
|
|
break;
|
|
case CFG_SET_DEFAULT_FOCUS:
|
|
rc =
|
|
imx074_set_default_focus(
|
|
cdata.cfg.focus.steps);
|
|
break;
|
|
case CFG_GET_AF_MAX_STEPS:
|
|
cdata.max_steps = IMX074_STEPS_NEAR_TO_CLOSEST_INF;
|
|
if (copy_to_user((void *)argp,
|
|
&cdata,
|
|
sizeof(struct sensor_cfg_data)))
|
|
rc = -EFAULT;
|
|
break;
|
|
case CFG_SET_EFFECT:
|
|
default:
|
|
rc = -EFAULT;
|
|
break;
|
|
}
|
|
|
|
mutex_unlock(&imx074_mut);
|
|
|
|
return rc;
|
|
}
|
|
static int imx074_sensor_release(void)
|
|
{
|
|
int rc = -EBADF;
|
|
mutex_lock(&imx074_mut);
|
|
if (machine_is_msm8x60_fluid())
|
|
imx074_poweroff_af();
|
|
imx074_power_down();
|
|
gpio_set_value_cansleep(imx074_ctrl->sensordata->sensor_reset, 0);
|
|
msleep(5);
|
|
gpio_direction_input(imx074_ctrl->sensordata->sensor_reset);
|
|
gpio_free(imx074_ctrl->sensordata->sensor_reset);
|
|
kfree(imx074_ctrl);
|
|
imx074_ctrl = NULL;
|
|
CDBG("imx074_release completed\n");
|
|
mutex_unlock(&imx074_mut);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int imx074_sensor_probe(const struct msm_camera_sensor_info *info,
|
|
struct msm_sensor_ctrl *s)
|
|
{
|
|
int rc = 0;
|
|
rc = i2c_add_driver(&imx074_i2c_driver);
|
|
if (rc < 0 || imx074_client == NULL) {
|
|
rc = -ENOTSUPP;
|
|
goto probe_fail;
|
|
}
|
|
msm_camio_clk_rate_set(IMX074_DEFAULT_MASTER_CLK_RATE);
|
|
rc = imx074_probe_init_sensor(info);
|
|
if (rc < 0)
|
|
goto probe_fail;
|
|
s->s_init = imx074_sensor_open_init;
|
|
s->s_release = imx074_sensor_release;
|
|
s->s_config = imx074_sensor_config;
|
|
s->s_mount_angle = info->sensor_platform_info->mount_angle;
|
|
imx074_probe_init_done(info);
|
|
return rc;
|
|
|
|
probe_fail:
|
|
CDBG("imx074_sensor_probe: SENSOR PROBE FAILS!\n");
|
|
i2c_del_driver(&imx074_i2c_driver);
|
|
return rc;
|
|
}
|
|
|
|
static int __imx074_probe(struct platform_device *pdev)
|
|
{
|
|
|
|
return msm_camera_drv_start(pdev, imx074_sensor_probe);
|
|
}
|
|
|
|
static struct platform_driver msm_camera_driver = {
|
|
.probe = __imx074_probe,
|
|
.driver = {
|
|
.name = "msm_camera_imx074",
|
|
.owner = THIS_MODULE,
|
|
},
|
|
};
|
|
|
|
static int __init imx074_init(void)
|
|
{
|
|
return platform_driver_register(&msm_camera_driver);
|
|
}
|
|
|
|
module_init(imx074_init);
|
|
|
|
MODULE_DESCRIPTION("Sony 13 MP Bayer sensor driver");
|
|
MODULE_LICENSE("GPL v2");
|
|
|