M7350/kernel/drivers/media/platform/msm/camera_v1/sn12m0pz.c
2024-09-09 08:52:07 +00:00

1852 lines
50 KiB
C

/* Copyright (c) 2010-2012, 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/kernel.h>
#include <linux/module.h>
#include <media/msm_camera.h>
#include <mach/gpio.h>
#include <mach/camera.h>
#include <linux/slab.h>
#include "sn12m0pz.h"
#define Q8 0x00000100
#define REG_GROUPED_PARAMETER_HOLD 0x0104
#define GROUPED_PARAMETER_HOLD_OFF 0x00
#define GROUPED_PARAMETER_HOLD 0x01
#define REG_MODE_SELECT 0x0100
#define MODE_SELECT_STANDBY_MODE 0x00
#define MODE_SELECT_STREAM 0x01
/* Integration Time */
#define REG_COARSE_INTEGRATION_TIME_MSB 0x0202
#define REG_COARSE_INTEGRATION_TIME_LSB 0x0203
/* Gain */
#define REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB 0x0204
#define REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB 0x0205
/* PLL Register Defines */
#define REG_PLL_MULTIPLIER 0x0307
#define REG_0x302B 0x302B
/* MIPI Enable Settings */
#define REG_0x30E5 0x30E5
#define REG_0x3300 0x3300
/* Global Setting */
#define REG_IMAGE_ORIENTATION 0x0101
#define REG_0x300A 0x300A
#define REG_0x3014 0x3014
#define REG_0x3015 0x3015
#define REG_0x3017 0x3017
#define REG_0x301C 0x301C
#define REG_0x3031 0x3031
#define REG_0x3040 0x3040
#define REG_0x3041 0x3041
#define REG_0x3051 0x3051
#define REG_0x3053 0x3053
#define REG_0x3055 0x3055
#define REG_0x3057 0x3057
#define REG_0x3060 0x3060
#define REG_0x3065 0x3065
#define REG_0x30AA 0x30AA
#define REG_0x30AB 0x30AB
#define REG_0x30B0 0x30B0
#define REG_0x30B2 0x30B2
#define REG_0x30D3 0x30D3
#define REG_0x3106 0x3106
#define REG_0x3108 0x3108
#define REG_0x310A 0x310A
#define REG_0x310C 0x310C
#define REG_0x310E 0x310E
#define REG_0x3126 0x3126
#define REG_0x312E 0x312E
#define REG_0x313C 0x313C
#define REG_0x313E 0x313E
#define REG_0x3140 0x3140
#define REG_0x3142 0x3142
#define REG_0x3144 0x3144
#define REG_0x3148 0x3148
#define REG_0x314A 0x314A
#define REG_0x3166 0x3166
#define REG_0x3168 0x3168
#define REG_0x316F 0x316F
#define REG_0x3171 0x3171
#define REG_0x3173 0x3173
#define REG_0x3175 0x3175
#define REG_0x3177 0x3177
#define REG_0x3179 0x3179
#define REG_0x317B 0x317B
#define REG_0x317D 0x317D
#define REG_0x317F 0x317F
#define REG_0x3181 0x3181
#define REG_0x3184 0x3184
#define REG_0x3185 0x3185
#define REG_0x3187 0x3187
#define REG_0x31A4 0x31A4
#define REG_0x31A6 0x31A6
#define REG_0x31AC 0x31AC
#define REG_0x31AE 0x31AE
#define REG_0x31B4 0x31B4
#define REG_0x31B6 0x31B6
#define REG_0x3254 0x3254
#define REG_0x3256 0x3256
#define REG_0x3258 0x3258
#define REG_0x325A 0x325A
#define REG_0x3260 0x3260
#define REG_0x3262 0x3262
#define REG_0x3304 0x3304
#define REG_0x3305 0x3305
#define REG_0x3306 0x3306
#define REG_0x3307 0x3307
#define REG_0x3308 0x3308
#define REG_0x3309 0x3309
#define REG_0x330A 0x330A
#define REG_0x330B 0x330B
#define REG_0x330C 0x330C
#define REG_0x330D 0x330D
/* Mode Setting */
#define REG_FRAME_LENGTH_LINES_MSB 0x0340
#define REG_FRAME_LENGTH_LINES_LSB 0x0341
#define REG_LINE_LENGTH_PCK_MSB 0x0342
#define REG_LINE_LENGTH_PCK_LSB 0x0343
#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_LSB 0x0381
#define REG_X_ODD_INC_LSB 0x0383
#define REG_Y_EVEN_INC_LSB 0x0385
#define REG_Y_ODD_INC_LSB 0x0387
#define REG_0x3016 0x3016
#define REG_0x30E8 0x30E8
#define REG_0x3301 0x3301
/* for 120fps support */
#define REG_0x0344 0x0344
#define REG_0x0345 0x0345
#define REG_0x0346 0x0346
#define REG_0x0347 0x0347
#define REG_0x0348 0x0348
#define REG_0x0349 0x0349
#define REG_0x034A 0x034A
#define REG_0x034B 0x034B
/* Test Pattern */
#define REG_0x30D8 0x30D8
#define REG_TEST_PATTERN_MODE 0x0601
/* Solid Color Test Pattern */
#define REG_TEST_DATA_RED_MSB 0x0603
#define REG_TEST_DATA_RED_LSB 0x0603
#define REG_TEST_DATA_GREENR_MSB 0x0604
#define REG_TEST_DATA_GREENR_LSB 0x0605
#define REG_TEST_DATA_BLUE_MSB 0x0606
#define REG_TEST_DATA_BLUE_LSB 0x0607
#define REG_TEST_DATA_GREENB_MSB 0x0608
#define REG_TEST_DATA_GREENB_LSB 0x0609
#define SN12M0PZ_AF_I2C_SLAVE_ID 0xE4
#define SN12M0PZ_STEPS_NEAR_TO_CLOSEST_INF 42
#define SN12M0PZ_TOTAL_STEPS_NEAR_TO_FAR 42
/* TYPE DECLARATIONS */
enum mipi_config_type {
IU060F_SN12M0PZ_STMIPID01,
IU060F_SN12M0PZ_STMIPID02
};
enum sn12m0pz_test_mode_t {
TEST_OFF,
TEST_1,
TEST_2,
TEST_3
};
enum sn12m0pz_resolution_t {
QTR_SIZE,
FULL_SIZE,
INVALID_SIZE,
QVGA_SIZE,
};
enum sn12m0pz_setting {
RES_PREVIEW,
RES_CAPTURE,
RES_VIDEO_120FPS,
};
enum mt9p012_reg_update {
/* Sensor egisters that need to be updated during initialization */
REG_INIT,
/* Sensor egisters that needs periodic I2C writes */
UPDATE_PERIODIC,
/* All the sensor Registers will be updated */
UPDATE_ALL,
/* Not valid update */
UPDATE_INVALID
};
/* 816x612, 24MHz MCLK 96MHz PCLK */
#define IU060F_SN12M0PZ_OFFSET 3
/* Time in milisecs for waiting for the sensor to reset.*/
#define SN12M0PZ_RESET_DELAY_MSECS 66
#define SN12M0PZ_WIDTH 4032
#define SN12M0PZ_HEIGHT 3024
#define SN12M0PZ_FULL_SIZE_WIDTH 4032
#define SN12M0PZ_FULL_SIZE_HEIGHT 3024
#define SN12M0PZ_HRZ_FULL_BLK_PIXELS 176
#define SN12M0PZ_VER_FULL_BLK_LINES 50
#define SN12M0PZ_QTR_SIZE_WIDTH 2016
#define SN12M0PZ_QTR_SIZE_HEIGHT 1512
#define SN12M0PZ_HRZ_QTR_BLK_PIXELS 2192
#define SN12M0PZ_VER_QTR_BLK_LINES 26
/* 120fps mode */
#define SN12M0PZ_QVGA_SIZE_WIDTH 4032
#define SN12M0PZ_QVGA_SIZE_HEIGHT 249
#define SN12M0PZ_HRZ_QVGA_BLK_PIXELS 176
#define SN12M0PZ_VER_QVGA_BLK_LINES 9
#define SN12M0PZ_DEFAULT_CLOCK_RATE 24000000
static uint32_t IU060F_SN12M0PZ_DELAY_MSECS = 30;
static enum mipi_config_type mipi_config = IU060F_SN12M0PZ_STMIPID02;
/* AF Tuning Parameters */
static int16_t enable_single_D02_lane;
static int16_t fullsize_cropped_at_8mp;
struct sn12m0pz_work_t {
struct work_struct work;
};
static struct sn12m0pz_work_t *sn12m0pz_sensorw;
static struct i2c_client *sn12m0pz_client;
struct sn12m0pz_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 sn12m0pz_resolution_t prev_res;
enum sn12m0pz_resolution_t pict_res;
enum sn12m0pz_resolution_t curr_res;
enum sn12m0pz_test_mode_t set_test;
unsigned short imgaddr;
};
static struct sn12m0pz_ctrl_t *sn12m0pz_ctrl;
static DECLARE_WAIT_QUEUE_HEAD(sn12m0pz_wait_queue);
DEFINE_MUTEX(sn12m0pz_mut);
static int sn12m0pz_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(sn12m0pz_client->adapter, msgs, 2) < 0) {
CDBG("sn12m0pz_i2c_rxdata failed!");
return -EIO;
}
return 0;
}
static int32_t sn12m0pz_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(sn12m0pz_client->adapter, msg, 1) < 0) {
CDBG("sn12m0pz_i2c_txdata faild 0x%x", sn12m0pz_client->addr);
return -EIO;
}
return 0;
}
static int32_t sn12m0pz_i2c_read(unsigned short raddr,
unsigned short *rdata, int rlen)
{
int32_t rc;
unsigned char buf[2];
if (!rdata)
return -EIO;
memset(buf, 0, sizeof(buf));
buf[0] = (raddr & 0xFF00) >> 8;
buf[1] = (raddr & 0x00FF);
rc = sn12m0pz_i2c_rxdata(sn12m0pz_client->addr, buf, rlen);
if (rc < 0) {
CDBG("sn12m0pz_i2c_read 0x%x failed!", raddr);
return rc;
}
*rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]);
return rc;
}
static int32_t sn12m0pz_i2c_write_b_sensor(unsigned short waddr, uint8_t bdata)
{
int32_t rc;
unsigned char buf[3];
memset(buf, 0, sizeof(buf));
buf[0] = (waddr & 0xFF00) >> 8;
buf[1] = (waddr & 0x00FF);
buf[2] = bdata;
udelay(90);
CDBG("i2c_write_b addr = %x, val = %x\n", waddr, bdata);
rc = sn12m0pz_i2c_txdata(sn12m0pz_client->addr, buf, 3);
if (rc < 0) {
CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!",
waddr, bdata);
}
return rc;
}
static int16_t sn12m0pz_i2c_write_b_af(unsigned short saddr,
unsigned short baddr, unsigned short bdata)
{
int16_t rc;
unsigned char buf[2];
memset(buf, 0, sizeof(buf));
buf[0] = baddr;
buf[1] = bdata;
rc = sn12m0pz_i2c_txdata(saddr, buf, 2);
if (rc < 0)
CDBG("i2c_write failed, saddr = 0x%x addr = 0x%x, val =0x%x!",
saddr, baddr, bdata);
return rc;
}
static int32_t sn12m0pz_i2c_write_byte_bridge(unsigned short saddr,
unsigned short waddr, uint8_t bdata)
{
int32_t rc;
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 = %x, val = %x", waddr, bdata);
rc = sn12m0pz_i2c_txdata(saddr, buf, 3);
if (rc < 0)
CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!",
waddr, bdata);
return rc;
}
static int32_t sn12m0pz_stmipid01_config(void)
{
int32_t rc = 0;
/* Initiate I2C for D01: */
/* MIPI Bridge configuration */
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0002, 0x19) < 0)
return rc; /* enable clock lane*/
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0003, 0x00) < 0)
return rc;
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0004, 0x3E) < 0)
return rc; /* mipi mode clock*/
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0005, 0x01) < 0)
return rc; /* enable data line*/
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0006, 0x0F) < 0)
return rc; /* mipi mode data 0x01*/
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0009, 0x00) < 0)
return rc; /* Data_Lane1_Reg1*/
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x000D, 0x92) < 0)
return rc; /* CCPRxRegisters*/
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x000E, 0x28) < 0)
return rc; /* 10 bits for pixel width input for CCP rx.*/
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0014, 0xC0) < 0)
return rc; /* no bypass, no decomp, 1Lane System,CSIstreaming*/
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0015, 0x48) < 0)
return rc; /* ModeControlRegisters-- Don't reset error flag*/
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0017, 0x2B) < 0)
return rc; /* Data_ID_Rreg*/
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0018, 0x2B) < 0)
return rc; /* Data_ID_Rreg_emb*/
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0019, 0x0C) < 0)
return rc;
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x001E, 0x0A) < 0)
return rc;
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x001F, 0x0A) < 0)
return rc;
return rc;
}
static int32_t sn12m0pz_stmipid02_config(void)
{
int32_t rc = 0;
/* Main Camera Clock Lane 1 (CLHP1, CLKN1)*/
/* Enable Clock Lane 1 (CLHP1, CLKN1), 0x15 for 400MHz */
if (enable_single_D02_lane) {
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0002, 0x19) < 0)
return rc;
/* Main Camera Data Lane 1.1 (DATA2P1, DATA2N1) */
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0009, 0x00) < 0)
return rc;/* Enable Data Lane 1.2 (DATA2P1, DATA2N1) */
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x000A, 0x00) < 0)
return rc; /*CSIMode on Data Lane1.2(DATA2P1,DATA2N1)*/
/* Mode Control */
/* Enable single lane for qtr preview */
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0014, 0xC0) < 0)
return rc; /*set 0xC0 - left justified on upper bits)*/
/* bit 1 set to 0 i.e. 1 lane system for qtr size preview */
} else {
if (sn12m0pz_ctrl->prev_res == QVGA_SIZE) {
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1,
0x0002, 0x19) < 0)
return rc;
} else {
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1,
0x0002, 0x21) < 0)
return rc;
}
/* Main Camera Data Lane 1.1 (DATA2P1, DATA2N1) */
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0009, 0x01) < 0)
return rc; /* Enable Data Lane 1.2 (DATA2P1, DATA2N1) */
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x000A, 0x01) < 0)
return rc; /* CSI Mode Data Lane1.2(DATA2P1, DATA2N1)*/
/* Mode Control */
/* Enable two lanes for full size preview/ snapshot */
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0014, 0xC2) < 0)
return rc; /* No decompression, CSI dual lane */
}
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0004, 0x1E) < 0)
return rc;
/* Main Camera Data Lane 1.1 (DATA1P1, DATA1N1) */
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0005, 0x03) < 0)
return rc; /* Enable Data Lane 1.1 (DATA1P1, DATA1N1) */
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0006, 0x0f) < 0)
return rc; /* CSI Mode on Data Lane 1.1 (DATA1P1, DATA1N1) */
/* Tristated Output, continuous clock, */
/*polarity of clock is inverted and sync signals not inverted*/
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0015, 0x08) < 0)
return rc;
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0036, 0x20) < 0)
return rc; /* Enable compensation macro, main camera */
/* Data type: 0x2B Raw 10 */
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0017, 0x2B) < 0)
return rc;
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0018, 0x2B) < 0)
return rc; /* Data type of embedded data: 0x2B Raw 10 */
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x0019, 0x0C) < 0)
return rc; /* Data type and pixel width programmed 0x0C*/
/* Decompression Mode */
/* Pixel Width and Decompression ON/OFF */
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x001E, 0x0A) < 0)
return rc; /* Image data not compressed: 0x0A for 10 bits */
if (sn12m0pz_i2c_write_byte_bridge(0x28>>1, 0x001F, 0x0A) < 0)
return rc; /* Embedded data not compressed: 0x0A for 10 bits */
return rc;
}
static int16_t sn12m0pz_af_init(void)
{
int16_t rc;
/* Initialize waveform */
rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x01, 0xA9);
rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x02, 0xD2);
rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x03, 0x0C);
rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x04, 0x14);
rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x05, 0xB6);
rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x06, 0x4F);
rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x07, 0x00);
return rc;
}
static int32_t sn12m0pz_move_focus(int direction,
int32_t num_steps)
{
int8_t step_direction, dest_step_position, bit_mask;
int32_t rc = 0;
uint16_t sn12m0pz_l_region_code_per_step = 3;
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("sn12m0pz_move_focus: Illegal focus direction");
return -EINVAL;
}
dest_step_position = sn12m0pz_ctrl->curr_step_pos +
(step_direction * num_steps);
if (dest_step_position < 0)
dest_step_position = 0;
else if (dest_step_position > SN12M0PZ_TOTAL_STEPS_NEAR_TO_FAR)
dest_step_position = SN12M0PZ_TOTAL_STEPS_NEAR_TO_FAR;
rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x00,
((num_steps * sn12m0pz_l_region_code_per_step) | bit_mask));
sn12m0pz_ctrl->curr_step_pos = dest_step_position;
return rc;
}
static int32_t sn12m0pz_set_default_focus(uint8_t af_step)
{
int32_t rc;
/* Initialize to infinity */
rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x00, 0x7F);
rc = sn12m0pz_i2c_write_b_af(SN12M0PZ_AF_I2C_SLAVE_ID >> 1, 0x00, 0x7F);
sn12m0pz_ctrl->curr_step_pos = 0;
return rc;
}
static void sn12m0pz_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;
uint16_t preview_line_length_pck, snapshot_line_length_pck;
uint32_t divider, pclk_mult, d1, d2;
/* Total frame_length_lines and line_length_pck for preview */
CDBG("sn12m0pz_get_pict_fps prev_res %d", sn12m0pz_ctrl->prev_res);
if (sn12m0pz_ctrl->prev_res == QVGA_SIZE) {
preview_frame_length_lines = SN12M0PZ_QVGA_SIZE_HEIGHT +
SN12M0PZ_VER_QVGA_BLK_LINES;
preview_line_length_pck = SN12M0PZ_QVGA_SIZE_WIDTH +
SN12M0PZ_HRZ_QVGA_BLK_PIXELS;
} else {
preview_frame_length_lines = SN12M0PZ_QTR_SIZE_HEIGHT +
SN12M0PZ_VER_QTR_BLK_LINES;
preview_line_length_pck = SN12M0PZ_QTR_SIZE_WIDTH +
SN12M0PZ_HRZ_QTR_BLK_PIXELS;
}
/* Total frame_length_lines and line_length_pck for snapshot */
snapshot_frame_length_lines = SN12M0PZ_FULL_SIZE_HEIGHT
+ SN12M0PZ_HRZ_FULL_BLK_PIXELS;
snapshot_line_length_pck = SN12M0PZ_FULL_SIZE_WIDTH
+ SN12M0PZ_HRZ_FULL_BLK_PIXELS;
d1 = preview_frame_length_lines *
0x00000400 / snapshot_frame_length_lines;
d2 = preview_line_length_pck *
0x00000400/snapshot_line_length_pck;
divider = d1 * d2 / 0x400;
pclk_mult =
(uint32_t)
(sn12m0pz_regs.reg_pat[RES_CAPTURE].pll_multiplier_lsb *
0x400) / (uint32_t)
sn12m0pz_regs.reg_pat[RES_PREVIEW].pll_multiplier_lsb;
*pfps = (uint16_t) (((fps * divider) / 0x400 * pclk_mult) / 0x400);
}
static uint16_t sn12m0pz_get_prev_lines_pf(void)
{
if (sn12m0pz_ctrl->prev_res == QTR_SIZE)
return SN12M0PZ_QTR_SIZE_HEIGHT +
SN12M0PZ_VER_QTR_BLK_LINES;
else if (sn12m0pz_ctrl->prev_res == QVGA_SIZE)
return SN12M0PZ_QVGA_SIZE_HEIGHT +
SN12M0PZ_VER_QVGA_BLK_LINES;
else
return SN12M0PZ_FULL_SIZE_HEIGHT +
SN12M0PZ_VER_FULL_BLK_LINES;
}
static uint16_t sn12m0pz_get_prev_pixels_pl(void)
{
if (sn12m0pz_ctrl->prev_res == QTR_SIZE)
return SN12M0PZ_QTR_SIZE_WIDTH +
SN12M0PZ_HRZ_QTR_BLK_PIXELS;
else
return SN12M0PZ_FULL_SIZE_WIDTH +
SN12M0PZ_HRZ_FULL_BLK_PIXELS;
}
static uint16_t sn12m0pz_get_pict_lines_pf(void)
{
if (sn12m0pz_ctrl->pict_res == QTR_SIZE)
return SN12M0PZ_QTR_SIZE_HEIGHT +
SN12M0PZ_VER_QTR_BLK_LINES;
else
return SN12M0PZ_FULL_SIZE_HEIGHT +
SN12M0PZ_VER_FULL_BLK_LINES;
}
static uint16_t sn12m0pz_get_pict_pixels_pl(void)
{
if (sn12m0pz_ctrl->pict_res == QTR_SIZE)
return SN12M0PZ_QTR_SIZE_WIDTH +
SN12M0PZ_HRZ_QTR_BLK_PIXELS;
else
return SN12M0PZ_FULL_SIZE_WIDTH +
SN12M0PZ_HRZ_FULL_BLK_PIXELS;
}
static uint32_t sn12m0pz_get_pict_max_exp_lc(void)
{
if (sn12m0pz_ctrl->pict_res == QTR_SIZE)
return (SN12M0PZ_QTR_SIZE_HEIGHT +
SN12M0PZ_VER_QTR_BLK_LINES) * 24;
else
return (SN12M0PZ_FULL_SIZE_HEIGHT +
SN12M0PZ_VER_FULL_BLK_LINES) * 24;
}
static int32_t sn12m0pz_set_fps(struct fps_cfg *fps)
{
uint16_t total_lines_per_frame;
int32_t rc = 0;
total_lines_per_frame = (uint16_t)((SN12M0PZ_QTR_SIZE_HEIGHT +
SN12M0PZ_VER_QTR_BLK_LINES) *
sn12m0pz_ctrl->fps_divider / 0x400);
if (sn12m0pz_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_MSB,
((total_lines_per_frame & 0xFF00) >> 8)) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_FRAME_LENGTH_LINES_LSB,
(total_lines_per_frame & 0x00FF)) < 0)
return rc;
return rc;
}
static int32_t sn12m0pz_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 line_length_pck_msb, line_length_pck_lsb;
uint16_t line_length_pck, frame_length_lines, temp_lines;
uint32_t line_length_ratio = 1 * Q8;
int32_t rc = 0;
CDBG("sn12m0pz_write_exp_gain : gain = %d line = %d", gain, line);
if (sn12m0pz_ctrl->sensormode != SENSOR_SNAPSHOT_MODE) {
if (sn12m0pz_ctrl->prev_res == QVGA_SIZE) {
frame_length_lines = SN12M0PZ_QVGA_SIZE_HEIGHT +
SN12M0PZ_VER_QVGA_BLK_LINES;
line_length_pck = SN12M0PZ_QVGA_SIZE_WIDTH +
SN12M0PZ_HRZ_QVGA_BLK_PIXELS;
if (line > (frame_length_lines -
IU060F_SN12M0PZ_OFFSET))
line = frame_length_lines -
IU060F_SN12M0PZ_OFFSET;
sn12m0pz_ctrl->fps = (uint16_t) (120 * Q8);
} else {
if (sn12m0pz_ctrl->curr_res == QTR_SIZE) {
frame_length_lines = SN12M0PZ_QTR_SIZE_HEIGHT +
SN12M0PZ_VER_QTR_BLK_LINES;
line_length_pck = SN12M0PZ_QTR_SIZE_WIDTH +
SN12M0PZ_HRZ_QTR_BLK_PIXELS;
} else {
frame_length_lines = SN12M0PZ_HEIGHT +
SN12M0PZ_VER_FULL_BLK_LINES;
line_length_pck = SN12M0PZ_WIDTH +
SN12M0PZ_HRZ_FULL_BLK_PIXELS;
}
if (line > (frame_length_lines -
IU060F_SN12M0PZ_OFFSET))
sn12m0pz_ctrl->fps = (uint16_t) (30 * Q8 *
(frame_length_lines - IU060F_SN12M0PZ_OFFSET) / line);
else
sn12m0pz_ctrl->fps = (uint16_t) (30 * Q8);
}
} else {
if (sn12m0pz_ctrl->curr_res == QTR_SIZE) {
frame_length_lines = SN12M0PZ_QTR_SIZE_HEIGHT +
SN12M0PZ_VER_QTR_BLK_LINES;
line_length_pck = SN12M0PZ_QTR_SIZE_WIDTH +
SN12M0PZ_HRZ_QTR_BLK_PIXELS;
} else {
frame_length_lines = SN12M0PZ_HEIGHT +
SN12M0PZ_VER_FULL_BLK_LINES;
line_length_pck = SN12M0PZ_WIDTH +
SN12M0PZ_HRZ_FULL_BLK_PIXELS;
}
}
if (gain > max_legal_gain)
/* range: 0 to 224 */
gain = max_legal_gain;
temp_lines = line;
/* calculate line_length_ratio */
if (line > (frame_length_lines - IU060F_SN12M0PZ_OFFSET)) {
line_length_ratio = (line * Q8) / (frame_length_lines -
IU060F_SN12M0PZ_OFFSET);
temp_lines = frame_length_lines - IU060F_SN12M0PZ_OFFSET;
if (line_length_ratio == 0)
line_length_ratio = 1 * Q8;
} else
line_length_ratio = 1 * Q8;
line = (uint32_t) (line * sn12m0pz_ctrl->fps_divider/0x400);
/* update gain registers */
gain_msb = (uint8_t) ((gain & 0xFF00) >> 8);
gain_lsb = (uint8_t) (gain & 0x00FF);
/* linear AFR horizontal stretch */
line_length_pck = (uint16_t) (line_length_pck * line_length_ratio / Q8);
line_length_pck_msb = (uint8_t) ((line_length_pck & 0xFF00) >> 8);
line_length_pck_lsb = (uint8_t) (line_length_pck & 0x00FF);
/* update line count registers */
intg_time_msb = (uint8_t) ((temp_lines & 0xFF00) >> 8);
intg_time_lsb = (uint8_t) (temp_lines & 0x00FF);
if (sn12m0pz_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
GROUPED_PARAMETER_HOLD) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_ANALOGUE_GAIN_CODE_GLOBAL_MSB,
gain_msb) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_ANALOGUE_GAIN_CODE_GLOBAL_LSB,
gain_lsb) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_LINE_LENGTH_PCK_MSB,
line_length_pck_msb) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_LINE_LENGTH_PCK_LSB,
line_length_pck_lsb) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_COARSE_INTEGRATION_TIME_MSB,
intg_time_msb) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_COARSE_INTEGRATION_TIME_LSB,
intg_time_lsb) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_GROUPED_PARAMETER_HOLD,
GROUPED_PARAMETER_HOLD_OFF) < 0)
return rc;
return rc;
}
static int32_t sn12m0pz_set_pict_exp_gain(uint16_t gain, uint32_t line)
{
int32_t rc;
rc = sn12m0pz_write_exp_gain(gain, line);
return rc;
}
static int32_t sn12m0pz_test(enum sn12m0pz_test_mode_t mo)
{
uint8_t test_data_val_msb = 0x07;
uint8_t test_data_val_lsb = 0xFF;
int32_t rc = 0;
if (mo == TEST_OFF)
return rc;
else {
/* REG_0x30D8[4] is TESBYPEN: 0: Normal Operation,
1: Bypass Signal Processing. REG_0x30D8[5] is EBDMASK:
0: Output Embedded data, 1: No output embedded data */
if (sn12m0pz_i2c_write_b_sensor(REG_0x30D8, 0x10) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_TEST_PATTERN_MODE,
(uint8_t) mo) < 0)
return rc;
/* Solid Color Test Pattern */
if (mo == TEST_1) {
if (sn12m0pz_i2c_write_b_sensor(REG_TEST_DATA_RED_MSB,
test_data_val_msb) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_TEST_DATA_RED_LSB,
test_data_val_lsb) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(
REG_TEST_DATA_GREENR_MSB,
test_data_val_msb) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(
REG_TEST_DATA_GREENR_LSB,
test_data_val_lsb) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_TEST_DATA_BLUE_MSB,
test_data_val_msb) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_TEST_DATA_BLUE_LSB,
test_data_val_lsb) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(
REG_TEST_DATA_GREENB_MSB,
test_data_val_msb) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(
REG_TEST_DATA_GREENB_LSB,
test_data_val_lsb) < 0)
return rc;
}
}
return rc;
}
static int32_t sn12m0pz_reset(void)
{
int32_t rc = 0;
/* register 0x0002 is Port 2, CAM_XCLRO */
gpio_direction_output(sn12m0pz_ctrl->
sensordata->sensor_reset,
0);
msleep(50);
gpio_direction_output(sn12m0pz_ctrl->
sensordata->sensor_reset,
1);
msleep(13);
return rc;
}
static int32_t sn12m0pz_sensor_setting(int update_type, int rt)
{
uint16_t total_lines_per_frame;
int32_t rc = 0;
switch (update_type) {
case UPDATE_PERIODIC:
/* Put Sensor into sofware standby mode */
if (sn12m0pz_i2c_write_b_sensor(REG_MODE_SELECT,
MODE_SELECT_STANDBY_MODE) < 0)
return rc;
msleep(5);
/* Hardware reset D02, lane config between full size/qtr size*/
rc = sn12m0pz_reset();
if (rc < 0)
return rc;
if (sn12m0pz_stmipid02_config() < 0)
return rc;
case REG_INIT:
if (rt == RES_PREVIEW || rt == RES_CAPTURE
|| rt == RES_VIDEO_120FPS) {
/* reset fps_divider */
sn12m0pz_ctrl->fps_divider = 1 * 0x400;
/* PLL settings */
if (sn12m0pz_i2c_write_b_sensor(REG_PLL_MULTIPLIER,
sn12m0pz_regs.reg_pat[rt].pll_multiplier_lsb) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x302B,
sn12m0pz_regs.reg_pat_init[0].reg_0x302B) < 0)
return rc;
/* MIPI Enable Settings */
if (sn12m0pz_i2c_write_b_sensor(REG_0x30E5,
sn12m0pz_regs.reg_pat_init[0].reg_0x30E5) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3300,
sn12m0pz_regs.reg_pat_init[0].reg_0x3300) < 0)
return rc;
/* Global Setting */
if (
sn12m0pz_i2c_write_b_sensor(
REG_IMAGE_ORIENTATION,
sn12m0pz_regs.reg_pat_init[0].image_orient) < 0)
return rc;
if (
sn12m0pz_i2c_write_b_sensor(
REG_COARSE_INTEGRATION_TIME_MSB,
sn12m0pz_regs.reg_pat[rt].coarse_integ_time_msb)
< 0)
return rc;
if (
sn12m0pz_i2c_write_b_sensor(
REG_COARSE_INTEGRATION_TIME_LSB,
sn12m0pz_regs.reg_pat[rt].coarse_integ_time_lsb)
< 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x300A,
sn12m0pz_regs.reg_pat_init[0].reg_0x300A) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3014,
sn12m0pz_regs.reg_pat_init[0].reg_0x3014) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3015,
sn12m0pz_regs.reg_pat_init[0].reg_0x3015) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3017,
sn12m0pz_regs.reg_pat_init[0].reg_0x3017) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x301C,
sn12m0pz_regs.reg_pat_init[0].reg_0x301C) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3031,
sn12m0pz_regs.reg_pat_init[0].reg_0x3031) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3040,
sn12m0pz_regs.reg_pat_init[0].reg_0x3040) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3041,
sn12m0pz_regs.reg_pat_init[0].reg_0x3041) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3051,
sn12m0pz_regs.reg_pat_init[0].reg_0x3051) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3053,
sn12m0pz_regs.reg_pat_init[0].reg_0x3053) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3055,
sn12m0pz_regs.reg_pat_init[0].reg_0x3055) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3057,
sn12m0pz_regs.reg_pat_init[0].reg_0x3057) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3060,
sn12m0pz_regs.reg_pat_init[0].reg_0x3060) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3065,
sn12m0pz_regs.reg_pat_init[0].reg_0x3065) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x30AA,
sn12m0pz_regs.reg_pat_init[0].reg_0x30AA) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x30AB,
sn12m0pz_regs.reg_pat_init[0].reg_0x30AB) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x30B0,
sn12m0pz_regs.reg_pat_init[0].reg_0x30B0) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x30B2,
sn12m0pz_regs.reg_pat_init[0].reg_0x30B2) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x30D3,
sn12m0pz_regs.reg_pat_init[0].reg_0x30D3) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x30D8,
sn12m0pz_regs.reg_pat_init[0].reg_0x30D8) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3106,
sn12m0pz_regs.reg_pat_init[0].reg_0x3106) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3108,
sn12m0pz_regs.reg_pat_init[0].reg_0x3108) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x310A,
sn12m0pz_regs.reg_pat_init[0].reg_0x310A) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x310C,
sn12m0pz_regs.reg_pat_init[0].reg_0x310C) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x310E,
sn12m0pz_regs.reg_pat_init[0].reg_0x310E) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3126,
sn12m0pz_regs.reg_pat_init[0].reg_0x3126) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x312E,
sn12m0pz_regs.reg_pat_init[0].reg_0x312E) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x313C,
sn12m0pz_regs.reg_pat_init[0].reg_0x313C) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x313E,
sn12m0pz_regs.reg_pat_init[0].reg_0x313E) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3140,
sn12m0pz_regs.reg_pat_init[0].reg_0x3140) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3142,
sn12m0pz_regs.reg_pat_init[0].reg_0x3142) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3144,
sn12m0pz_regs.reg_pat_init[0].reg_0x3144) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3148,
sn12m0pz_regs.reg_pat_init[0].reg_0x3148) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x314A,
sn12m0pz_regs.reg_pat_init[0].reg_0x314A) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3166,
sn12m0pz_regs.reg_pat_init[0].reg_0x3166) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3168,
sn12m0pz_regs.reg_pat_init[0].reg_0x3168) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x316F,
sn12m0pz_regs.reg_pat_init[0].reg_0x316F) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3171,
sn12m0pz_regs.reg_pat_init[0].reg_0x3171) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3173,
sn12m0pz_regs.reg_pat_init[0].reg_0x3173) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3175,
sn12m0pz_regs.reg_pat_init[0].reg_0x3175) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3177,
sn12m0pz_regs.reg_pat_init[0].reg_0x3177) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3179,
sn12m0pz_regs.reg_pat_init[0].reg_0x3179) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x317B,
sn12m0pz_regs.reg_pat_init[0].reg_0x317B) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x317D,
sn12m0pz_regs.reg_pat_init[0].reg_0x317D) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x317F,
sn12m0pz_regs.reg_pat_init[0].reg_0x317F) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3181,
sn12m0pz_regs.reg_pat_init[0].reg_0x3181) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3184,
sn12m0pz_regs.reg_pat_init[0].reg_0x3184) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3185,
sn12m0pz_regs.reg_pat_init[0].reg_0x3185) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3187,
sn12m0pz_regs.reg_pat_init[0].reg_0x3187) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x31A4,
sn12m0pz_regs.reg_pat_init[0].reg_0x31A4) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x31A6,
sn12m0pz_regs.reg_pat_init[0].reg_0x31A6) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x31AC,
sn12m0pz_regs.reg_pat_init[0].reg_0x31AC) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x31AE,
sn12m0pz_regs.reg_pat_init[0].reg_0x31AE) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x31B4,
sn12m0pz_regs.reg_pat_init[0].reg_0x31B4) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x31B6,
sn12m0pz_regs.reg_pat_init[0].reg_0x31B6) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3254,
sn12m0pz_regs.reg_pat_init[0].reg_0x3254) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3256,
sn12m0pz_regs.reg_pat_init[0].reg_0x3256) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3258,
sn12m0pz_regs.reg_pat_init[0].reg_0x3258) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x325A,
sn12m0pz_regs.reg_pat_init[0].reg_0x325A) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3260,
sn12m0pz_regs.reg_pat_init[0].reg_0x3260) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3262,
sn12m0pz_regs.reg_pat_init[0].reg_0x3262) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3304,
sn12m0pz_regs.reg_pat_init[0].reg_0x3304) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3305,
sn12m0pz_regs.reg_pat_init[0].reg_0x3305) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3306,
sn12m0pz_regs.reg_pat_init[0].reg_0x3306) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3307,
sn12m0pz_regs.reg_pat_init[0].reg_0x3307) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3308,
sn12m0pz_regs.reg_pat_init[0].reg_0x3308) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3309,
sn12m0pz_regs.reg_pat_init[0].reg_0x3309) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x330A,
sn12m0pz_regs.reg_pat_init[0].reg_0x330A) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x330B,
sn12m0pz_regs.reg_pat_init[0].reg_0x330B) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x330C,
sn12m0pz_regs.reg_pat_init[0].reg_0x330C) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x330D,
sn12m0pz_regs.reg_pat_init[0].reg_0x330D) < 0)
return rc;
/* Mode setting */
/* Update registers with correct
frame_length_line value for AFR */
total_lines_per_frame = (uint16_t)(
(sn12m0pz_regs.reg_pat[rt].frame_length_lines_msb << 8)
& 0xFF00) +
sn12m0pz_regs.reg_pat[rt].frame_length_lines_lsb;
total_lines_per_frame = total_lines_per_frame *
sn12m0pz_ctrl->fps_divider / 0x400;
if (sn12m0pz_i2c_write_b_sensor(
REG_FRAME_LENGTH_LINES_MSB,
(total_lines_per_frame & 0xFF00) >> 8)
< 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(
REG_FRAME_LENGTH_LINES_LSB,
(total_lines_per_frame & 0x00FF)) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_LINE_LENGTH_PCK_MSB,
sn12m0pz_regs.reg_pat[rt].line_length_pck_msb) <
0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_LINE_LENGTH_PCK_LSB,
sn12m0pz_regs.reg_pat[rt].line_length_pck_lsb) <
0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_X_OUTPUT_SIZE_MSB,
sn12m0pz_regs.reg_pat[rt].x_output_size_msb) <
0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_X_OUTPUT_SIZE_LSB,
sn12m0pz_regs.reg_pat[rt].x_output_size_lsb) <
0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_Y_OUTPUT_SIZE_MSB,
sn12m0pz_regs.reg_pat[rt].y_output_size_msb) <
0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_Y_OUTPUT_SIZE_LSB,
sn12m0pz_regs.reg_pat[rt].y_output_size_lsb) <
0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_X_EVEN_INC_LSB,
sn12m0pz_regs.reg_pat[rt].x_even_inc_lsb) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_X_ODD_INC_LSB,
sn12m0pz_regs.reg_pat[rt].x_odd_inc_lsb) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_Y_EVEN_INC_LSB,
sn12m0pz_regs.reg_pat[rt].y_even_inc_lsb) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_Y_ODD_INC_LSB,
sn12m0pz_regs.reg_pat[rt].y_odd_inc_lsb) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3016,
sn12m0pz_regs.reg_pat[rt].reg_0x3016) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x30E8,
sn12m0pz_regs.reg_pat[rt].reg_0x30E8) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x3301,
sn12m0pz_regs.reg_pat[rt].reg_0x3301) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x0344,
sn12m0pz_regs.reg_pat[rt].reg_0x0344) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x0345,
sn12m0pz_regs.reg_pat[rt].reg_0x0345) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x0346,
sn12m0pz_regs.reg_pat[rt].reg_0x0346) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x0347,
sn12m0pz_regs.reg_pat[rt].reg_0x0347) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x0348,
sn12m0pz_regs.reg_pat[rt].reg_0x0348) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x0349,
sn12m0pz_regs.reg_pat[rt].reg_0x0349) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x034A,
sn12m0pz_regs.reg_pat[rt].reg_0x034A) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(REG_0x034B,
sn12m0pz_regs.reg_pat[rt].reg_0x034B) < 0)
return rc;
if ((rt == RES_CAPTURE) && fullsize_cropped_at_8mp) {
/* x address end */
if (sn12m0pz_i2c_write_b_sensor(0x0348,
0x0C) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(0x0349,
0x0CF) < 0)
return rc;
/* y address end */
if (sn12m0pz_i2c_write_b_sensor(0x034A,
0x09) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(0x034B,
0x9F) < 0)
return rc;
}
if (mipi_config == IU060F_SN12M0PZ_STMIPID01) {
if (sn12m0pz_i2c_write_b_sensor(
REG_PLL_MULTIPLIER, 0x43) < 0)
return rc;
if (rt == RES_CAPTURE) {
if (sn12m0pz_i2c_write_b_sensor(
REG_0x3301, 0x01) < 0)
return rc;
if (sn12m0pz_i2c_write_b_sensor(
REG_0x3017, 0xE0) < 0)
return rc;
}
}
if (sn12m0pz_i2c_write_b_sensor(REG_MODE_SELECT,
MODE_SELECT_STREAM) < 0)
return rc;
msleep(IU060F_SN12M0PZ_DELAY_MSECS);
if (sn12m0pz_test(sn12m0pz_ctrl->set_test) < 0)
return rc;
if (mipi_config == IU060F_SN12M0PZ_STMIPID02)
CDBG("%s,%d", __func__, __LINE__);
return rc;
}
default:
return rc;
}
}
static int32_t sn12m0pz_video_config(int mode)
{
int32_t rc = 0;
int rt;
if (mode == SENSOR_HFR_120FPS_MODE)
sn12m0pz_ctrl->prev_res = QVGA_SIZE;
/* change sensor resolution if needed */
if (sn12m0pz_ctrl->curr_res != sn12m0pz_ctrl->prev_res) {
if (sn12m0pz_ctrl->prev_res == QTR_SIZE) {
rt = RES_PREVIEW;
IU060F_SN12M0PZ_DELAY_MSECS = 35; /*measured on scope*/
enable_single_D02_lane = 1;
} else if (sn12m0pz_ctrl->prev_res == QVGA_SIZE) {
rt = RES_VIDEO_120FPS;
IU060F_SN12M0PZ_DELAY_MSECS = 35; /*measured on scope*/
enable_single_D02_lane = 0;
} else {
rt = RES_CAPTURE;
enable_single_D02_lane = 0;
}
if (sn12m0pz_sensor_setting(UPDATE_PERIODIC, rt) < 0)
return rc;
}
sn12m0pz_ctrl->curr_res = sn12m0pz_ctrl->prev_res;
sn12m0pz_ctrl->sensormode = mode;
return rc;
}
static int32_t sn12m0pz_snapshot_config(int mode)
{
int32_t rc = 0;
int rt;
/* change sensor resolution if needed */
if (sn12m0pz_ctrl->curr_res != sn12m0pz_ctrl->pict_res) {
if (sn12m0pz_ctrl->pict_res == QTR_SIZE) {
rt = RES_PREVIEW;
enable_single_D02_lane = 1;
} else {
rt = RES_CAPTURE;
IU060F_SN12M0PZ_DELAY_MSECS = 100;/*measured on scope*/
enable_single_D02_lane = 0;
}
if (sn12m0pz_sensor_setting(UPDATE_PERIODIC, rt) < 0)
return rc;
}
sn12m0pz_ctrl->curr_res = sn12m0pz_ctrl->pict_res;
sn12m0pz_ctrl->sensormode = mode;
return rc;
}
static int32_t sn12m0pz_raw_snapshot_config(int mode)
{
int32_t rc = 0;
int rt;
/* change sensor resolution if needed */
if (sn12m0pz_ctrl->curr_res != sn12m0pz_ctrl->pict_res) {
if (sn12m0pz_ctrl->pict_res == QTR_SIZE) {
rt = RES_PREVIEW;
enable_single_D02_lane = 1;
} else {
rt = RES_CAPTURE;
IU060F_SN12M0PZ_DELAY_MSECS = 100;/*measured on scope*/
enable_single_D02_lane = 0;
}
if (sn12m0pz_sensor_setting(UPDATE_PERIODIC, rt) < 0)
return rc;
}
sn12m0pz_ctrl->curr_res = sn12m0pz_ctrl->pict_res;
sn12m0pz_ctrl->sensormode = mode;
return rc;
}
static int32_t sn12m0pz_set_sensor_mode(int mode,
int res)
{
int32_t rc;
switch (mode) {
case SENSOR_PREVIEW_MODE:
case SENSOR_HFR_120FPS_MODE:
rc = sn12m0pz_video_config(mode);
break;
case SENSOR_SNAPSHOT_MODE:
rc = sn12m0pz_snapshot_config(mode);
break;
case SENSOR_RAW_SNAPSHOT_MODE:
rc = sn12m0pz_raw_snapshot_config(mode);
break;
default:
rc = -EINVAL;
break;
}
return rc;
}
static int32_t sn12m0pz_power_down(void)
{
return 0;
}
static int sn12m0pz_probe_init_done(const struct msm_camera_sensor_info *data)
{
gpio_direction_output(data->sensor_reset, 0);
gpio_free(data->sensor_reset);
gpio_direction_output(data->vcm_pwd, 0);
gpio_free(data->vcm_pwd);
return 0;
}
static int sn12m0pz_probe_init_sensor(const struct msm_camera_sensor_info *data)
{
int32_t rc;
unsigned short chipidl, chipidh;
CDBG("Requesting gpio");
rc = gpio_request(data->sensor_reset, "sn12m0pz");
CDBG(" sn12m0pz_probe_init_sensor");
if (!rc) {
gpio_direction_output(data->sensor_reset, 0);
msleep(20);
gpio_direction_output(data->sensor_reset, 1);
msleep(13);
} else {
goto init_probe_done;
}
CDBG("Requestion gpio");
rc = gpio_request(data->vcm_pwd, "sn12m0pz");
CDBG(" sn12m0pz_probe_init_sensor");
if (!rc) {
gpio_direction_output(data->vcm_pwd, 0);
msleep(20);
gpio_direction_output(data->vcm_pwd, 1);
msleep(13);
} else {
gpio_direction_output(data->sensor_reset, 0);
gpio_free(data->sensor_reset);
goto init_probe_done;
}
msleep(20);
/* 3. Read sensor Model ID: */
rc = sn12m0pz_i2c_read(0x0000, &chipidh, 1);
if (rc < 0) {
CDBG(" sn12m0pz_probe_init_sensor3");
goto init_probe_fail;
}
rc = sn12m0pz_i2c_read(0x0001, &chipidl, 1);
if (rc < 0) {
CDBG(" sn12m0pz_probe_init_sensor4");
goto init_probe_fail;
}
/* 4. Compare sensor ID to SN12M0PZ ID: */
if (chipidh != 0x00 || chipidl != 0x60) {
rc = -ENODEV;
CDBG("sn12m0pz_probe_init_sensor fail chip id doesnot match");
goto init_probe_fail;
}
msleep(SN12M0PZ_RESET_DELAY_MSECS);
goto init_probe_done;
init_probe_fail:
CDBG(" sn12m0pz_probe_init_sensor fails");
sn12m0pz_probe_init_done(data);
init_probe_done:
CDBG(" sn12m0pz_probe_init_sensor finishes");
return rc;
}
int sn12m0pz_sensor_open_init(const struct msm_camera_sensor_info *data)
{
int32_t rc = 0;
CDBG("Calling sn12m0pz_sensor_open_init");
sn12m0pz_ctrl = kzalloc(sizeof(struct sn12m0pz_ctrl_t), GFP_KERNEL);
if (!sn12m0pz_ctrl) {
CDBG("sn12m0pz_init failed!");
rc = -ENOMEM;
goto init_done;
}
sn12m0pz_ctrl->fps_divider = 1 * 0x00000400;
sn12m0pz_ctrl->pict_fps_divider = 1 * 0x00000400;
sn12m0pz_ctrl->set_test = TEST_OFF;
sn12m0pz_ctrl->prev_res = QTR_SIZE;
sn12m0pz_ctrl->pict_res = FULL_SIZE;
sn12m0pz_ctrl->curr_res = INVALID_SIZE;
if (data)
sn12m0pz_ctrl->sensordata = data;
if (rc < 0)
return rc;
/* enable mclk first */
msm_camio_clk_rate_set(SN12M0PZ_DEFAULT_CLOCK_RATE);
msleep(20);
msm_camio_camif_pad_reg_reset();
msleep(20);
CDBG("Calling sn12m0pz_sensor_open_init");
rc = sn12m0pz_probe_init_sensor(data);
if (rc < 0)
goto init_fail;
/* send reset signal */
if (mipi_config == IU060F_SN12M0PZ_STMIPID01) {
if (sn12m0pz_stmipid01_config() < 0) {
CDBG("Calling sn12m0pz_sensor_open_init fail");
return rc;
}
} else {
if (sn12m0pz_ctrl->prev_res == QTR_SIZE)
enable_single_D02_lane = 1;
else /* FULL_SIZE */
enable_single_D02_lane = 0;
if (sn12m0pz_stmipid02_config() < 0) {
CDBG("Calling sn12m0pz_sensor_open_init fail");
return rc;
}
}
if (sn12m0pz_ctrl->prev_res == QTR_SIZE) {
if (sn12m0pz_sensor_setting(REG_INIT, RES_PREVIEW) < 0)
return rc;
} else if (sn12m0pz_ctrl->prev_res == QVGA_SIZE) {
if (sn12m0pz_sensor_setting(REG_INIT, RES_VIDEO_120FPS) < 0)
return rc;
} else {
if (sn12m0pz_sensor_setting(REG_INIT, RES_CAPTURE) < 0)
return rc;
}
if (sn12m0pz_af_init() < 0)
return rc;
sn12m0pz_ctrl->fps = 30*Q8;
if (rc < 0)
goto init_fail;
else
goto init_done;
init_fail:
CDBG(" init_fail");
sn12m0pz_probe_init_done(data);
kfree(sn12m0pz_ctrl);
init_done:
CDBG("init_done");
return rc;
}
static int __devinit sn12m0pz_init_client(struct i2c_client *client)
{
/* Initialize the MSM_CAMI2C Chip */
init_waitqueue_head(&sn12m0pz_wait_queue);
return 0;
}
static const struct i2c_device_id sn12m0pz_i2c_id[] = {
{ "sn12m0pz", 0},
{ }
};
static int __devinit sn12m0pz_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int rc = 0;
CDBG("sn12m0pz_probe called!");
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
CDBG("i2c_check_functionality failed");
goto probe_failure;
}
sn12m0pz_sensorw = kzalloc(sizeof(struct sn12m0pz_work_t), GFP_KERNEL);
if (!sn12m0pz_sensorw) {
CDBG("kzalloc failed");
rc = -ENOMEM;
goto probe_failure;
}
i2c_set_clientdata(client, sn12m0pz_sensorw);
sn12m0pz_init_client(client);
sn12m0pz_client = client;
msleep(50);
CDBG("sn12m0pz_probe successed! rc = %d", rc);
return 0;
probe_failure:
CDBG("sn12m0pz_probe failed! rc = %d", rc);
return rc;
}
static int __exit sn12m0pz_remove(struct i2c_client *client)
{
struct sn12m0pz_work_t_t *sensorw = i2c_get_clientdata(client);
free_irq(client->irq, sensorw);
sn12m0pz_client = NULL;
kfree(sensorw);
return 0;
}
static struct i2c_driver sn12m0pz_i2c_driver = {
.id_table = sn12m0pz_i2c_id,
.probe = sn12m0pz_i2c_probe,
.remove = __exit_p(sn12m0pz_i2c_remove),
.driver = {
.name = "sn12m0pz",
},
};
int sn12m0pz_sensor_config(void __user *argp)
{
struct sensor_cfg_data cdata;
int32_t rc = 0;
if (copy_from_user(&cdata,
(void *)argp,
sizeof(struct sensor_cfg_data)))
return -EFAULT;
mutex_lock(&sn12m0pz_mut);
CDBG("sn12m0pz_sensor_config: cfgtype = %d",
cdata.cfgtype);
switch (cdata.cfgtype) {
case CFG_GET_PICT_FPS:
sn12m0pz_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 =
sn12m0pz_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 =
sn12m0pz_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 =
sn12m0pz_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 =
sn12m0pz_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 =
sn12m0pz_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 = sn12m0pz_set_fps(&(cdata.cfg.fps));
break;
case CFG_SET_EXP_GAIN:
rc =
sn12m0pz_write_exp_gain(
cdata.cfg.exp_gain.gain,
cdata.cfg.exp_gain.line);
break;
case CFG_SET_PICT_EXP_GAIN:
rc =
sn12m0pz_set_pict_exp_gain(
cdata.cfg.exp_gain.gain,
cdata.cfg.exp_gain.line);
break;
case CFG_SET_MODE:
rc = sn12m0pz_set_sensor_mode(cdata.mode,
cdata.rs);
break;
case CFG_PWR_DOWN:
rc = sn12m0pz_power_down();
break;
case CFG_MOVE_FOCUS:
rc = sn12m0pz_move_focus(cdata.cfg.focus.dir,
cdata.cfg.focus.steps);
break;
case CFG_SET_DEFAULT_FOCUS:
rc = sn12m0pz_set_default_focus(cdata.cfg.focus.steps);
break;
case CFG_SET_EFFECT:
rc = 0;
break;
case CFG_SET_LENS_SHADING:
rc = 0;
break;
default:
rc = -EFAULT;
break;
}
mutex_unlock(&sn12m0pz_mut);
return rc;
}
static int sn12m0pz_sensor_release(void)
{
int rc = -EBADF;
mutex_lock(&sn12m0pz_mut);
sn12m0pz_power_down();
gpio_direction_output(sn12m0pz_ctrl->sensordata->sensor_reset,
0);
gpio_free(sn12m0pz_ctrl->sensordata->sensor_reset);
gpio_direction_output(sn12m0pz_ctrl->sensordata->vcm_pwd,
0);
gpio_free(sn12m0pz_ctrl->sensordata->vcm_pwd);
kfree(sn12m0pz_ctrl);
sn12m0pz_ctrl = NULL;
CDBG("sn12m0pz_release completed");
mutex_unlock(&sn12m0pz_mut);
return rc;
}
static int sn12m0pz_sensor_probe(const struct msm_camera_sensor_info *info,
struct msm_sensor_ctrl *s)
{
int rc;
rc = i2c_add_driver(&sn12m0pz_i2c_driver);
if (rc < 0 || sn12m0pz_client == NULL) {
rc = -ENOTSUPP;
goto probe_fail;
}
msm_camio_clk_rate_set(SN12M0PZ_DEFAULT_CLOCK_RATE);
msleep(20);
rc = sn12m0pz_probe_init_sensor(info);
if (rc < 0)
goto probe_fail;
s->s_init = sn12m0pz_sensor_open_init;
s->s_release = sn12m0pz_sensor_release;
s->s_config = sn12m0pz_sensor_config;
s->s_mount_angle = 0;
sn12m0pz_probe_init_done(info);
return rc;
probe_fail:
CDBG("SENSOR PROBE FAILS!");
i2c_del_driver(&sn12m0pz_i2c_driver);
return rc;
}
static int __sn12m0pz_probe(struct platform_device *pdev)
{
return msm_camera_drv_start(pdev, sn12m0pz_sensor_probe);
}
static struct platform_driver msm_camera_driver = {
.probe = __sn12m0pz_probe,
.driver = {
.name = "msm_camera_sn12m0pz",
.owner = THIS_MODULE,
},
};
static int __init sn12m0pz_init(void)
{
return platform_driver_register(&msm_camera_driver);
}
module_init(sn12m0pz_init);
MODULE_DESCRIPTION("Sony 12M MP Bayer sensor driver");
MODULE_LICENSE("GPL v2");