1852 lines
50 KiB
C
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");
|