alistair23-linux/drivers/staging/dream/camera/mt9t013.c
Tejun Heo 5a0e3ad6af include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files.  percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.

percpu.h -> slab.h dependency is about to be removed.  Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability.  As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.

  http://userweb.kernel.org/~tj/misc/slabh-sweep.py

The script does the followings.

* Scan files for gfp and slab usages and update includes such that
  only the necessary includes are there.  ie. if only gfp is used,
  gfp.h, if slab is used, slab.h.

* When the script inserts a new include, it looks at the include
  blocks and try to put the new include such that its order conforms
  to its surrounding.  It's put in the include block which contains
  core kernel includes, in the same order that the rest are ordered -
  alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
  doesn't seem to be any matching order.

* If the script can't find a place to put a new include (mostly
  because the file doesn't have fitting include block), it prints out
  an error message indicating which .h file needs to be added to the
  file.

The conversion was done in the following steps.

1. The initial automatic conversion of all .c files updated slightly
   over 4000 files, deleting around 700 includes and adding ~480 gfp.h
   and ~3000 slab.h inclusions.  The script emitted errors for ~400
   files.

2. Each error was manually checked.  Some didn't need the inclusion,
   some needed manual addition while adding it to implementation .h or
   embedding .c file was more appropriate for others.  This step added
   inclusions to around 150 files.

3. The script was run again and the output was compared to the edits
   from #2 to make sure no file was left behind.

4. Several build tests were done and a couple of problems were fixed.
   e.g. lib/decompress_*.c used malloc/free() wrappers around slab
   APIs requiring slab.h to be added manually.

5. The script was run on all .h files but without automatically
   editing them as sprinkling gfp.h and slab.h inclusions around .h
   files could easily lead to inclusion dependency hell.  Most gfp.h
   inclusion directives were ignored as stuff from gfp.h was usually
   wildly available and often used in preprocessor macros.  Each
   slab.h inclusion directive was examined and added manually as
   necessary.

6. percpu.h was updated not to include slab.h.

7. Build test were done on the following configurations and failures
   were fixed.  CONFIG_GCOV_KERNEL was turned off for all tests (as my
   distributed build env didn't work with gcov compiles) and a few
   more options had to be turned off depending on archs to make things
   build (like ipr on powerpc/64 which failed due to missing writeq).

   * x86 and x86_64 UP and SMP allmodconfig and a custom test config.
   * powerpc and powerpc64 SMP allmodconfig
   * sparc and sparc64 SMP allmodconfig
   * ia64 SMP allmodconfig
   * s390 SMP allmodconfig
   * alpha SMP allmodconfig
   * um on x86_64 SMP allmodconfig

8. percpu.h modifications were reverted so that it could be applied as
   a separate patch and serve as bisection point.

Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.

Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-30 22:02:32 +09:00

1498 lines
32 KiB
C

/*
* Copyright (C) 2008-2009 QUALCOMM Incorporated.
*/
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <media/msm_camera.h>
#include <mach/gpio.h>
#include <mach/camera.h>
#include <asm/mach-types.h>
#include "mt9t013.h"
/*=============================================================
SENSOR REGISTER DEFINES
==============================================================*/
#define MT9T013_REG_MODEL_ID 0x0000
#define MT9T013_MODEL_ID 0x2600
#define REG_GROUPED_PARAMETER_HOLD 0x0104
#define GROUPED_PARAMETER_HOLD 0x0100
#define GROUPED_PARAMETER_UPDATE 0x0000
#define REG_COARSE_INT_TIME 0x3012
#define REG_VT_PIX_CLK_DIV 0x0300
#define REG_VT_SYS_CLK_DIV 0x0302
#define REG_PRE_PLL_CLK_DIV 0x0304
#define REG_PLL_MULTIPLIER 0x0306
#define REG_OP_PIX_CLK_DIV 0x0308
#define REG_OP_SYS_CLK_DIV 0x030A
#define REG_SCALE_M 0x0404
#define REG_FRAME_LENGTH_LINES 0x300A
#define REG_LINE_LENGTH_PCK 0x300C
#define REG_X_ADDR_START 0x3004
#define REG_Y_ADDR_START 0x3002
#define REG_X_ADDR_END 0x3008
#define REG_Y_ADDR_END 0x3006
#define REG_X_OUTPUT_SIZE 0x034C
#define REG_Y_OUTPUT_SIZE 0x034E
#define REG_FINE_INT_TIME 0x3014
#define REG_ROW_SPEED 0x3016
#define MT9T013_REG_RESET_REGISTER 0x301A
#define MT9T013_RESET_REGISTER_PWON 0x10CC
#define MT9T013_RESET_REGISTER_PWOFF 0x1008 /* 0x10C8 stop streaming*/
#define REG_READ_MODE 0x3040
#define REG_GLOBAL_GAIN 0x305E
#define REG_TEST_PATTERN_MODE 0x3070
enum mt9t013_test_mode {
TEST_OFF,
TEST_1,
TEST_2,
TEST_3
};
enum mt9t013_resolution {
QTR_SIZE,
FULL_SIZE,
INVALID_SIZE
};
enum mt9t013_reg_update {
REG_INIT, /* registers that need to be updated during initialization */
UPDATE_PERIODIC, /* registers that needs periodic I2C writes */
UPDATE_ALL, /* all registers will be updated */
UPDATE_INVALID
};
enum mt9t013_setting {
RES_PREVIEW,
RES_CAPTURE
};
/* actuator's Slave Address */
#define MT9T013_AF_I2C_ADDR 0x18
/*
* AF Total steps parameters
*/
#define MT9T013_TOTAL_STEPS_NEAR_TO_FAR 30
/*
* Time in milisecs for waiting for the sensor to reset.
*/
#define MT9T013_RESET_DELAY_MSECS 66
/* for 30 fps preview */
#define MT9T013_DEFAULT_CLOCK_RATE 24000000
#define MT9T013_DEFAULT_MAX_FPS 26
/* FIXME: Changes from here */
struct mt9t013_work {
struct work_struct work;
};
static struct mt9t013_work *mt9t013_sensorw;
static struct i2c_client *mt9t013_client;
struct mt9t013_ctrl {
const struct msm_camera_sensor_info *sensordata;
int sensormode;
uint32_t fps_divider; /* init to 1 * 0x00000400 */
uint32_t pict_fps_divider; /* init to 1 * 0x00000400 */
uint16_t curr_lens_pos;
uint16_t init_curr_lens_pos;
uint16_t my_reg_gain;
uint32_t my_reg_line_count;
enum mt9t013_resolution prev_res;
enum mt9t013_resolution pict_res;
enum mt9t013_resolution curr_res;
enum mt9t013_test_mode set_test;
unsigned short imgaddr;
};
static struct mt9t013_ctrl *mt9t013_ctrl;
static DECLARE_WAIT_QUEUE_HEAD(mt9t013_wait_queue);
DECLARE_MUTEX(mt9t013_sem);
extern struct mt9t013_reg mt9t013_regs; /* from mt9t013_reg.c */
static int mt9t013_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 = length,
.buf = rxdata,
},
};
if (i2c_transfer(mt9t013_client->adapter, msgs, 2) < 0) {
pr_err("mt9t013_i2c_rxdata failed!\n");
return -EIO;
}
return 0;
}
static int32_t mt9t013_i2c_read_w(unsigned short saddr,
unsigned short raddr, unsigned short *rdata)
{
int32_t rc = 0;
unsigned char buf[4];
if (!rdata)
return -EIO;
memset(buf, 0, sizeof(buf));
buf[0] = (raddr & 0xFF00)>>8;
buf[1] = (raddr & 0x00FF);
rc = mt9t013_i2c_rxdata(saddr, buf, 2);
if (rc < 0)
return rc;
*rdata = buf[0] << 8 | buf[1];
if (rc < 0)
pr_err("mt9t013_i2c_read failed!\n");
return rc;
}
static int32_t mt9t013_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(mt9t013_client->adapter, msg, 1) < 0) {
pr_err("mt9t013_i2c_txdata failed\n");
return -EIO;
}
return 0;
}
static int32_t mt9t013_i2c_write_b(unsigned short saddr,
unsigned short waddr, unsigned short wdata)
{
int32_t rc = -EIO;
unsigned char buf[2];
memset(buf, 0, sizeof(buf));
buf[0] = waddr;
buf[1] = wdata;
rc = mt9t013_i2c_txdata(saddr, buf, 2);
if (rc < 0)
pr_err("i2c_write failed, addr = 0x%x, val = 0x%x!\n",
waddr, wdata);
return rc;
}
static int32_t mt9t013_i2c_write_w(unsigned short saddr,
unsigned short waddr, unsigned short wdata)
{
int32_t rc = -EIO;
unsigned char buf[4];
memset(buf, 0, sizeof(buf));
buf[0] = (waddr & 0xFF00)>>8;
buf[1] = (waddr & 0x00FF);
buf[2] = (wdata & 0xFF00)>>8;
buf[3] = (wdata & 0x00FF);
rc = mt9t013_i2c_txdata(saddr, buf, 4);
if (rc < 0)
pr_err("i2c_write_w failed, addr = 0x%x, val = 0x%x!\n",
waddr, wdata);
return rc;
}
static int32_t mt9t013_i2c_write_w_table(
struct mt9t013_i2c_reg_conf *reg_conf_tbl, int num_of_items_in_table)
{
int i;
int32_t rc = -EIO;
for (i = 0; i < num_of_items_in_table; i++) {
rc = mt9t013_i2c_write_w(mt9t013_client->addr,
reg_conf_tbl->waddr, reg_conf_tbl->wdata);
if (rc < 0)
break;
reg_conf_tbl++;
}
return rc;
}
static int32_t mt9t013_test(enum mt9t013_test_mode mo)
{
int32_t rc = 0;
rc = mt9t013_i2c_write_w(mt9t013_client->addr,
REG_GROUPED_PARAMETER_HOLD,
GROUPED_PARAMETER_HOLD);
if (rc < 0)
return rc;
if (mo == TEST_OFF)
return 0;
else {
rc = mt9t013_i2c_write_w_table(mt9t013_regs.ttbl,
mt9t013_regs.ttbl_size);
if (rc < 0)
return rc;
rc = mt9t013_i2c_write_w(mt9t013_client->addr,
REG_TEST_PATTERN_MODE, (uint16_t)mo);
if (rc < 0)
return rc;
}
rc = mt9t013_i2c_write_w(mt9t013_client->addr,
REG_GROUPED_PARAMETER_HOLD,
GROUPED_PARAMETER_UPDATE);
if (rc < 0)
return rc;
return rc;
}
static int32_t mt9t013_set_lc(void)
{
int32_t rc;
rc = mt9t013_i2c_write_w_table(mt9t013_regs.lctbl, mt9t013_regs.lctbl_size);
if (rc < 0)
return rc;
return rc;
}
static int32_t mt9t013_set_default_focus(uint8_t af_step)
{
int32_t rc = 0;
uint8_t code_val_msb, code_val_lsb;
code_val_msb = 0x01;
code_val_lsb = af_step;
/* Write the digital code for current to the actuator */
rc = mt9t013_i2c_write_b(MT9T013_AF_I2C_ADDR>>1,
code_val_msb, code_val_lsb);
mt9t013_ctrl->curr_lens_pos = 0;
mt9t013_ctrl->init_curr_lens_pos = 0;
return rc;
}
static void mt9t013_get_pict_fps(uint16_t fps, uint16_t *pfps)
{
/* input fps is preview fps in Q8 format */
uint32_t divider; /*Q10 */
uint32_t pclk_mult; /*Q10 */
if (mt9t013_ctrl->prev_res == QTR_SIZE) {
divider =
(uint32_t)(
((mt9t013_regs.reg_pat[RES_PREVIEW].frame_length_lines *
mt9t013_regs.reg_pat[RES_PREVIEW].line_length_pck) *
0x00000400) /
(mt9t013_regs.reg_pat[RES_CAPTURE].frame_length_lines *
mt9t013_regs.reg_pat[RES_CAPTURE].line_length_pck));
pclk_mult =
(uint32_t) ((mt9t013_regs.reg_pat[RES_CAPTURE].pll_multiplier *
0x00000400) /
(mt9t013_regs.reg_pat[RES_PREVIEW].pll_multiplier));
} else {
/* full size resolution used for preview. */
divider = 0x00000400; /*1.0 */
pclk_mult = 0x00000400; /*1.0 */
}
/* Verify PCLK settings and frame sizes. */
*pfps =
(uint16_t) (fps * divider * pclk_mult /
0x00000400 / 0x00000400);
}
static uint16_t mt9t013_get_prev_lines_pf(void)
{
if (mt9t013_ctrl->prev_res == QTR_SIZE)
return mt9t013_regs.reg_pat[RES_PREVIEW].frame_length_lines;
else
return mt9t013_regs.reg_pat[RES_CAPTURE].frame_length_lines;
}
static uint16_t mt9t013_get_prev_pixels_pl(void)
{
if (mt9t013_ctrl->prev_res == QTR_SIZE)
return mt9t013_regs.reg_pat[RES_PREVIEW].line_length_pck;
else
return mt9t013_regs.reg_pat[RES_CAPTURE].line_length_pck;
}
static uint16_t mt9t013_get_pict_lines_pf(void)
{
return mt9t013_regs.reg_pat[RES_CAPTURE].frame_length_lines;
}
static uint16_t mt9t013_get_pict_pixels_pl(void)
{
return mt9t013_regs.reg_pat[RES_CAPTURE].line_length_pck;
}
static uint32_t mt9t013_get_pict_max_exp_lc(void)
{
uint16_t snapshot_lines_per_frame;
if (mt9t013_ctrl->pict_res == QTR_SIZE) {
snapshot_lines_per_frame =
mt9t013_regs.reg_pat[RES_PREVIEW].frame_length_lines - 1;
} else {
snapshot_lines_per_frame =
mt9t013_regs.reg_pat[RES_CAPTURE].frame_length_lines - 1;
}
return snapshot_lines_per_frame * 24;
}
static int32_t mt9t013_set_fps(struct fps_cfg *fps)
{
/* input is new fps in Q8 format */
int32_t rc = 0;
mt9t013_ctrl->fps_divider = fps->fps_div;
mt9t013_ctrl->pict_fps_divider = fps->pict_fps_div;
rc = mt9t013_i2c_write_w(mt9t013_client->addr,
REG_GROUPED_PARAMETER_HOLD,
GROUPED_PARAMETER_HOLD);
if (rc < 0)
return -EBUSY;
CDBG("mt9t013_set_fps: fps_div is %d, frame_rate is %d\n",
fps->fps_div,
(uint16_t) (mt9t013_regs.reg_pat[RES_PREVIEW].
frame_length_lines *
fps->fps_div/0x00000400));
CDBG("mt9t013_set_fps: fps_mult is %d, frame_rate is %d\n",
fps->f_mult,
(uint16_t)(mt9t013_regs.reg_pat[RES_PREVIEW].
line_length_pck *
fps->f_mult / 0x00000400));
rc = mt9t013_i2c_write_w(mt9t013_client->addr,
REG_LINE_LENGTH_PCK,
(uint16_t) (
mt9t013_regs.reg_pat[RES_PREVIEW].line_length_pck *
fps->f_mult / 0x00000400));
if (rc < 0)
return rc;
rc = mt9t013_i2c_write_w(mt9t013_client->addr,
REG_GROUPED_PARAMETER_HOLD,
GROUPED_PARAMETER_UPDATE);
if (rc < 0)
return rc;
return rc;
}
static int32_t mt9t013_write_exp_gain(uint16_t gain, uint32_t line)
{
const uint16_t max_legal_gain = 0x01FF;
uint32_t line_length_ratio = 0x00000400;
enum mt9t013_setting setting;
int32_t rc = 0;
if (mt9t013_ctrl->sensormode == SENSOR_PREVIEW_MODE) {
mt9t013_ctrl->my_reg_gain = gain;
mt9t013_ctrl->my_reg_line_count = (uint16_t) line;
}
if (gain > max_legal_gain)
gain = max_legal_gain;
/* Verify no overflow */
if (mt9t013_ctrl->sensormode != SENSOR_SNAPSHOT_MODE) {
line = (uint32_t) (line * mt9t013_ctrl->fps_divider /
0x00000400);
setting = RES_PREVIEW;
} else {
line = (uint32_t) (line * mt9t013_ctrl->pict_fps_divider /
0x00000400);
setting = RES_CAPTURE;
}
/*Set digital gain to 1 */
gain |= 0x0200;
if ((mt9t013_regs.reg_pat[setting].frame_length_lines - 1) < line) {
line_length_ratio =
(uint32_t) (line * 0x00000400) /
(mt9t013_regs.reg_pat[setting].frame_length_lines - 1);
} else
line_length_ratio = 0x00000400;
/* There used to be PARAMETER_HOLD register write before and
* after REG_GLOBAL_GAIN & REG_COARSE_INIT_TIME. This causes
* aec oscillation. Hence removed. */
rc = mt9t013_i2c_write_w(mt9t013_client->addr, REG_GLOBAL_GAIN, gain);
if (rc < 0)
return rc;
rc = mt9t013_i2c_write_w(mt9t013_client->addr,
REG_COARSE_INT_TIME,
(uint16_t)((uint32_t) line * 0x00000400 /
line_length_ratio));
if (rc < 0)
return rc;
return rc;
}
static int32_t mt9t013_set_pict_exp_gain(uint16_t gain, uint32_t line)
{
int32_t rc = 0;
rc = mt9t013_write_exp_gain(gain, line);
if (rc < 0)
return rc;
rc = mt9t013_i2c_write_w(mt9t013_client->addr,
MT9T013_REG_RESET_REGISTER,
0x10CC | 0x0002);
mdelay(5);
/* camera_timed_wait(snapshot_wait*exposure_ratio); */
return rc;
}
static int32_t mt9t013_setting(enum mt9t013_reg_update rupdate,
enum mt9t013_setting rt)
{
int32_t rc = 0;
switch (rupdate) {
case UPDATE_PERIODIC: {
if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
#if 0
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
MT9T013_REG_RESET_REGISTER,
MT9T013_RESET_REGISTER_PWOFF);
if (rc < 0)
return rc;
#endif
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_VT_PIX_CLK_DIV,
mt9t013_regs.reg_pat[rt].vt_pix_clk_div);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_VT_SYS_CLK_DIV,
mt9t013_regs.reg_pat[rt].vt_sys_clk_div);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_PRE_PLL_CLK_DIV,
mt9t013_regs.reg_pat[rt].pre_pll_clk_div);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_PLL_MULTIPLIER,
mt9t013_regs.reg_pat[rt].pll_multiplier);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_OP_PIX_CLK_DIV,
mt9t013_regs.reg_pat[rt].op_pix_clk_div);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_OP_SYS_CLK_DIV,
mt9t013_regs.reg_pat[rt].op_sys_clk_div);
if (rc < 0)
return rc;
mdelay(5);
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_GROUPED_PARAMETER_HOLD,
GROUPED_PARAMETER_HOLD);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_ROW_SPEED,
mt9t013_regs.reg_pat[rt].row_speed);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_X_ADDR_START,
mt9t013_regs.reg_pat[rt].x_addr_start);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_X_ADDR_END,
mt9t013_regs.reg_pat[rt].x_addr_end);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_Y_ADDR_START,
mt9t013_regs.reg_pat[rt].y_addr_start);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_Y_ADDR_END,
mt9t013_regs.reg_pat[rt].y_addr_end);
if (rc < 0)
return rc;
if (machine_is_sapphire()) {
if (rt == 0)
rc = mt9t013_i2c_write_w(mt9t013_client->addr,
REG_READ_MODE,
0x046F);
else
rc = mt9t013_i2c_write_w(mt9t013_client->addr,
REG_READ_MODE,
0x0027);
} else
rc = mt9t013_i2c_write_w(mt9t013_client->addr,
REG_READ_MODE,
mt9t013_regs.reg_pat[rt].read_mode);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_SCALE_M,
mt9t013_regs.reg_pat[rt].scale_m);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_X_OUTPUT_SIZE,
mt9t013_regs.reg_pat[rt].x_output_size);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_Y_OUTPUT_SIZE,
mt9t013_regs.reg_pat[rt].y_output_size);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_LINE_LENGTH_PCK,
mt9t013_regs.reg_pat[rt].line_length_pck);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_FRAME_LENGTH_LINES,
(mt9t013_regs.reg_pat[rt].frame_length_lines *
mt9t013_ctrl->fps_divider / 0x00000400));
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_COARSE_INT_TIME,
mt9t013_regs.reg_pat[rt].coarse_int_time);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_FINE_INT_TIME,
mt9t013_regs.reg_pat[rt].fine_int_time);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_GROUPED_PARAMETER_HOLD,
GROUPED_PARAMETER_UPDATE);
if (rc < 0)
return rc;
rc = mt9t013_test(mt9t013_ctrl->set_test);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
MT9T013_REG_RESET_REGISTER,
MT9T013_RESET_REGISTER_PWON);
if (rc < 0)
return rc;
mdelay(5);
return rc;
}
}
break;
/*CAMSENSOR_REG_UPDATE_PERIODIC */
case REG_INIT: {
if (rt == RES_PREVIEW || rt == RES_CAPTURE) {
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
MT9T013_REG_RESET_REGISTER,
MT9T013_RESET_REGISTER_PWOFF);
if (rc < 0)
/* MODE_SELECT, stop streaming */
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_VT_PIX_CLK_DIV,
mt9t013_regs.reg_pat[rt].vt_pix_clk_div);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_VT_SYS_CLK_DIV,
mt9t013_regs.reg_pat[rt].vt_sys_clk_div);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_PRE_PLL_CLK_DIV,
mt9t013_regs.reg_pat[rt].pre_pll_clk_div);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_PLL_MULTIPLIER,
mt9t013_regs.reg_pat[rt].pll_multiplier);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_OP_PIX_CLK_DIV,
mt9t013_regs.reg_pat[rt].op_pix_clk_div);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_OP_SYS_CLK_DIV,
mt9t013_regs.reg_pat[rt].op_sys_clk_div);
if (rc < 0)
return rc;
mdelay(5);
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_GROUPED_PARAMETER_HOLD,
GROUPED_PARAMETER_HOLD);
if (rc < 0)
return rc;
/* additional power saving mode ok around 38.2MHz */
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
0x3084, 0x2409);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
0x3092, 0x0A49);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
0x3094, 0x4949);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
0x3096, 0x4949);
if (rc < 0)
return rc;
/* Set preview or snapshot mode */
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_ROW_SPEED,
mt9t013_regs.reg_pat[rt].row_speed);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_X_ADDR_START,
mt9t013_regs.reg_pat[rt].x_addr_start);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_X_ADDR_END,
mt9t013_regs.reg_pat[rt].x_addr_end);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_Y_ADDR_START,
mt9t013_regs.reg_pat[rt].y_addr_start);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_Y_ADDR_END,
mt9t013_regs.reg_pat[rt].y_addr_end);
if (rc < 0)
return rc;
if (machine_is_sapphire()) {
if (rt == 0)
rc = mt9t013_i2c_write_w(mt9t013_client->addr,
REG_READ_MODE,
0x046F);
else
rc = mt9t013_i2c_write_w(mt9t013_client->addr,
REG_READ_MODE,
0x0027);
} else
rc = mt9t013_i2c_write_w(mt9t013_client->addr,
REG_READ_MODE,
mt9t013_regs.reg_pat[rt].read_mode);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_SCALE_M,
mt9t013_regs.reg_pat[rt].scale_m);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_X_OUTPUT_SIZE,
mt9t013_regs.reg_pat[rt].x_output_size);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_Y_OUTPUT_SIZE,
mt9t013_regs.reg_pat[rt].y_output_size);
if (rc < 0)
return 0;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_LINE_LENGTH_PCK,
mt9t013_regs.reg_pat[rt].line_length_pck);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_FRAME_LENGTH_LINES,
mt9t013_regs.reg_pat[rt].frame_length_lines);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_COARSE_INT_TIME,
mt9t013_regs.reg_pat[rt].coarse_int_time);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_FINE_INT_TIME,
mt9t013_regs.reg_pat[rt].fine_int_time);
if (rc < 0)
return rc;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_GROUPED_PARAMETER_HOLD,
GROUPED_PARAMETER_UPDATE);
if (rc < 0)
return rc;
/* load lens shading */
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_GROUPED_PARAMETER_HOLD,
GROUPED_PARAMETER_HOLD);
if (rc < 0)
return rc;
/* most likely needs to be written only once. */
rc = mt9t013_set_lc();
if (rc < 0)
return -EBUSY;
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
REG_GROUPED_PARAMETER_HOLD,
GROUPED_PARAMETER_UPDATE);
if (rc < 0)
return rc;
rc = mt9t013_test(mt9t013_ctrl->set_test);
if (rc < 0)
return rc;
mdelay(5);
rc =
mt9t013_i2c_write_w(mt9t013_client->addr,
MT9T013_REG_RESET_REGISTER,
MT9T013_RESET_REGISTER_PWON);
if (rc < 0)
/* MODE_SELECT, stop streaming */
return rc;
CDBG("!!! mt9t013 !!! PowerOn is done!\n");
mdelay(5);
return rc;
}
} /* case CAMSENSOR_REG_INIT: */
break;
/*CAMSENSOR_REG_INIT */
default:
rc = -EINVAL;
break;
} /* switch (rupdate) */
return rc;
}
static int32_t mt9t013_video_config(int mode, int res)
{
int32_t rc;
switch (res) {
case QTR_SIZE:
rc = mt9t013_setting(UPDATE_PERIODIC, RES_PREVIEW);
if (rc < 0)
return rc;
CDBG("sensor configuration done!\n");
break;
case FULL_SIZE:
rc = mt9t013_setting(UPDATE_PERIODIC, RES_CAPTURE);
if (rc < 0)
return rc;
break;
default:
return -EINVAL;
} /* switch */
mt9t013_ctrl->prev_res = res;
mt9t013_ctrl->curr_res = res;
mt9t013_ctrl->sensormode = mode;
return mt9t013_write_exp_gain(mt9t013_ctrl->my_reg_gain,
mt9t013_ctrl->my_reg_line_count);
}
static int32_t mt9t013_snapshot_config(int mode)
{
int32_t rc = 0;
rc = mt9t013_setting(UPDATE_PERIODIC, RES_CAPTURE);
if (rc < 0)
return rc;
mt9t013_ctrl->curr_res = mt9t013_ctrl->pict_res;
mt9t013_ctrl->sensormode = mode;
return rc;
}
static int32_t mt9t013_raw_snapshot_config(int mode)
{
int32_t rc = 0;
rc = mt9t013_setting(UPDATE_PERIODIC, RES_CAPTURE);
if (rc < 0)
return rc;
mt9t013_ctrl->curr_res = mt9t013_ctrl->pict_res;
mt9t013_ctrl->sensormode = mode;
return rc;
}
static int32_t mt9t013_power_down(void)
{
int32_t rc = 0;
rc = mt9t013_i2c_write_w(mt9t013_client->addr,
MT9T013_REG_RESET_REGISTER,
MT9T013_RESET_REGISTER_PWOFF);
if (rc >= 0)
mdelay(5);
return rc;
}
static int32_t mt9t013_move_focus(int direction, int32_t num_steps)
{
int16_t step_direction;
int16_t actual_step;
int16_t next_position;
int16_t break_steps[4];
uint8_t code_val_msb, code_val_lsb;
int16_t i;
if (num_steps > MT9T013_TOTAL_STEPS_NEAR_TO_FAR)
num_steps = MT9T013_TOTAL_STEPS_NEAR_TO_FAR;
else if (num_steps == 0)
return -EINVAL;
if (direction == MOVE_NEAR)
step_direction = 4;
else if (direction == MOVE_FAR)
step_direction = -4;
else
return -EINVAL;
if (mt9t013_ctrl->curr_lens_pos < mt9t013_ctrl->init_curr_lens_pos)
mt9t013_ctrl->curr_lens_pos = mt9t013_ctrl->init_curr_lens_pos;
actual_step =
(int16_t) (step_direction *
(int16_t) num_steps);
for (i = 0; i < 4; i++)
break_steps[i] =
actual_step / 4 * (i + 1) - actual_step / 4 * i;
for (i = 0; i < 4; i++) {
next_position =
(int16_t)
(mt9t013_ctrl->curr_lens_pos + break_steps[i]);
if (next_position > 255)
next_position = 255;
else if (next_position < 0)
next_position = 0;
code_val_msb =
((next_position >> 4) << 2) |
((next_position << 4) >> 6);
code_val_lsb =
((next_position & 0x03) << 6);
/* Writing the digital code for current to the actuator */
if (mt9t013_i2c_write_b(MT9T013_AF_I2C_ADDR>>1,
code_val_msb, code_val_lsb) < 0)
return -EBUSY;
/* Storing the current lens Position */
mt9t013_ctrl->curr_lens_pos = next_position;
if (i < 3)
mdelay(1);
} /* for */
return 0;
}
static int mt9t013_sensor_init_done(const struct msm_camera_sensor_info *data)
{
gpio_direction_output(data->sensor_reset, 0);
gpio_free(data->sensor_reset);
return 0;
}
static int mt9t013_probe_init_sensor(const struct msm_camera_sensor_info *data)
{
int rc;
uint16_t chipid;
rc = gpio_request(data->sensor_reset, "mt9t013");
if (!rc)
gpio_direction_output(data->sensor_reset, 1);
else
goto init_probe_done;
mdelay(20);
/* RESET the sensor image part via I2C command */
rc = mt9t013_i2c_write_w(mt9t013_client->addr,
MT9T013_REG_RESET_REGISTER, 0x1009);
if (rc < 0)
goto init_probe_fail;
/* 3. Read sensor Model ID: */
rc = mt9t013_i2c_read_w(mt9t013_client->addr,
MT9T013_REG_MODEL_ID, &chipid);
if (rc < 0)
goto init_probe_fail;
CDBG("mt9t013 model_id = 0x%x\n", chipid);
/* 4. Compare sensor ID to MT9T012VC ID: */
if (chipid != MT9T013_MODEL_ID) {
rc = -ENODEV;
goto init_probe_fail;
}
rc = mt9t013_i2c_write_w(mt9t013_client->addr,
0x3064, 0x0805);
if (rc < 0)
goto init_probe_fail;
mdelay(MT9T013_RESET_DELAY_MSECS);
goto init_probe_done;
/* sensor: output enable */
#if 0
rc = mt9t013_i2c_write_w(mt9t013_client->addr,
MT9T013_REG_RESET_REGISTER,
MT9T013_RESET_REGISTER_PWON);
/* if this fails, the sensor is not the MT9T013 */
rc = mt9t013_set_default_focus(0);
#endif
init_probe_fail:
gpio_direction_output(data->sensor_reset, 0);
gpio_free(data->sensor_reset);
init_probe_done:
return rc;
}
static int32_t mt9t013_poweron_af(void)
{
int32_t rc = 0;
/* enable AF actuator */
CDBG("enable AF actuator, gpio = %d\n",
mt9t013_ctrl->sensordata->vcm_pwd);
rc = gpio_request(mt9t013_ctrl->sensordata->vcm_pwd, "mt9t013");
if (!rc) {
gpio_direction_output(mt9t013_ctrl->sensordata->vcm_pwd, 0);
mdelay(20);
rc = mt9t013_set_default_focus(0);
} else
pr_err("%s, gpio_request failed (%d)!\n", __func__, rc);
return rc;
}
static void mt9t013_poweroff_af(void)
{
gpio_direction_output(mt9t013_ctrl->sensordata->vcm_pwd, 1);
gpio_free(mt9t013_ctrl->sensordata->vcm_pwd);
}
int mt9t013_sensor_open_init(const struct msm_camera_sensor_info *data)
{
int32_t rc;
mt9t013_ctrl = kzalloc(sizeof(struct mt9t013_ctrl), GFP_KERNEL);
if (!mt9t013_ctrl) {
pr_err("mt9t013_init failed!\n");
rc = -ENOMEM;
goto init_done;
}
mt9t013_ctrl->fps_divider = 1 * 0x00000400;
mt9t013_ctrl->pict_fps_divider = 1 * 0x00000400;
mt9t013_ctrl->set_test = TEST_OFF;
mt9t013_ctrl->prev_res = QTR_SIZE;
mt9t013_ctrl->pict_res = FULL_SIZE;
if (data)
mt9t013_ctrl->sensordata = data;
/* enable mclk first */
msm_camio_clk_rate_set(MT9T013_DEFAULT_CLOCK_RATE);
mdelay(20);
msm_camio_camif_pad_reg_reset();
mdelay(20);
rc = mt9t013_probe_init_sensor(data);
if (rc < 0)
goto init_fail;
if (mt9t013_ctrl->prev_res == QTR_SIZE)
rc = mt9t013_setting(REG_INIT, RES_PREVIEW);
else
rc = mt9t013_setting(REG_INIT, RES_CAPTURE);
if (rc >= 0)
rc = mt9t013_poweron_af();
if (rc < 0)
goto init_fail;
else
goto init_done;
init_fail:
kfree(mt9t013_ctrl);
init_done:
return rc;
}
static int mt9t013_init_client(struct i2c_client *client)
{
/* Initialize the MSM_CAMI2C Chip */
init_waitqueue_head(&mt9t013_wait_queue);
return 0;
}
static int32_t mt9t013_set_sensor_mode(int mode, int res)
{
int32_t rc = 0;
rc = mt9t013_i2c_write_w(mt9t013_client->addr,
REG_GROUPED_PARAMETER_HOLD,
GROUPED_PARAMETER_HOLD);
if (rc < 0)
return rc;
switch (mode) {
case SENSOR_PREVIEW_MODE:
rc = mt9t013_video_config(mode, res);
break;
case SENSOR_SNAPSHOT_MODE:
rc = mt9t013_snapshot_config(mode);
break;
case SENSOR_RAW_SNAPSHOT_MODE:
rc = mt9t013_raw_snapshot_config(mode);
break;
default:
return -EINVAL;
}
/* FIXME: what should we do if rc < 0? */
if (rc >= 0)
return mt9t013_i2c_write_w(mt9t013_client->addr,
REG_GROUPED_PARAMETER_HOLD,
GROUPED_PARAMETER_UPDATE);
return rc;
}
int mt9t013_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;
down(&mt9t013_sem);
CDBG("mt9t013_sensor_config: cfgtype = %d\n", cdata.cfgtype);
switch (cdata.cfgtype) {
case CFG_GET_PICT_FPS:
mt9t013_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 = mt9t013_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 = mt9t013_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 = mt9t013_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 =
mt9t013_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 =
mt9t013_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 = mt9t013_set_fps(&(cdata.cfg.fps));
break;
case CFG_SET_EXP_GAIN:
rc = mt9t013_write_exp_gain(cdata.cfg.exp_gain.gain,
cdata.cfg.exp_gain.line);
break;
case CFG_SET_PICT_EXP_GAIN:
rc = mt9t013_set_pict_exp_gain(cdata.cfg.exp_gain.gain,
cdata.cfg.exp_gain.line);
break;
case CFG_SET_MODE:
rc = mt9t013_set_sensor_mode(cdata.mode, cdata.rs);
break;
case CFG_PWR_DOWN:
rc = mt9t013_power_down();
break;
case CFG_MOVE_FOCUS:
rc = mt9t013_move_focus(cdata.cfg.focus.dir,
cdata.cfg.focus.steps);
break;
case CFG_SET_DEFAULT_FOCUS:
rc = mt9t013_set_default_focus(cdata.cfg.focus.steps);
break;
case CFG_GET_AF_MAX_STEPS:
cdata.max_steps = MT9T013_TOTAL_STEPS_NEAR_TO_FAR;
if (copy_to_user((void *)argp,
&cdata,
sizeof(struct sensor_cfg_data)))
rc = -EFAULT;
break;
case CFG_SET_EFFECT:
default:
rc = -EINVAL;
break;
}
up(&mt9t013_sem);
return rc;
}
int mt9t013_sensor_release(void)
{
int rc = -EBADF;
down(&mt9t013_sem);
mt9t013_poweroff_af();
mt9t013_power_down();
gpio_direction_output(mt9t013_ctrl->sensordata->sensor_reset,
0);
gpio_free(mt9t013_ctrl->sensordata->sensor_reset);
kfree(mt9t013_ctrl);
up(&mt9t013_sem);
CDBG("mt9t013_release completed!\n");
return rc;
}
static int mt9t013_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int rc = 0;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
rc = -ENOTSUPP;
goto probe_failure;
}
mt9t013_sensorw =
kzalloc(sizeof(struct mt9t013_work), GFP_KERNEL);
if (!mt9t013_sensorw) {
rc = -ENOMEM;
goto probe_failure;
}
i2c_set_clientdata(client, mt9t013_sensorw);
mt9t013_init_client(client);
mt9t013_client = client;
mt9t013_client->addr = mt9t013_client->addr >> 1;
mdelay(50);
CDBG("i2c probe ok\n");
return 0;
probe_failure:
kfree(mt9t013_sensorw);
mt9t013_sensorw = NULL;
pr_err("i2c probe failure %d\n", rc);
return rc;
}
static const struct i2c_device_id mt9t013_i2c_id[] = {
{ "mt9t013", 0},
{ }
};
static struct i2c_driver mt9t013_i2c_driver = {
.id_table = mt9t013_i2c_id,
.probe = mt9t013_i2c_probe,
.remove = __exit_p(mt9t013_i2c_remove),
.driver = {
.name = "mt9t013",
},
};
static int mt9t013_sensor_probe(
const struct msm_camera_sensor_info *info,
struct msm_sensor_ctrl *s)
{
/* We expect this driver to match with the i2c device registered
* in the board file immediately. */
int rc = i2c_add_driver(&mt9t013_i2c_driver);
if (rc < 0 || mt9t013_client == NULL) {
rc = -ENOTSUPP;
goto probe_done;
}
/* enable mclk first */
msm_camio_clk_rate_set(MT9T013_DEFAULT_CLOCK_RATE);
mdelay(20);
rc = mt9t013_probe_init_sensor(info);
if (rc < 0) {
i2c_del_driver(&mt9t013_i2c_driver);
goto probe_done;
}
s->s_init = mt9t013_sensor_open_init;
s->s_release = mt9t013_sensor_release;
s->s_config = mt9t013_sensor_config;
mt9t013_sensor_init_done(info);
probe_done:
return rc;
}
static int __mt9t013_probe(struct platform_device *pdev)
{
return msm_camera_drv_start(pdev, mt9t013_sensor_probe);
}
static struct platform_driver msm_camera_driver = {
.probe = __mt9t013_probe,
.driver = {
.name = "msm_camera_mt9t013",
.owner = THIS_MODULE,
},
};
static int __init mt9t013_init(void)
{
return platform_driver_register(&msm_camera_driver);
}
module_init(mt9t013_init);