android_kernel_cmhtcleo/drivers/media/video/msm/ov8810.c
2010-08-27 11:19:57 +02:00

2741 lines
74 KiB
C

/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Code Aurora Forum nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* Alternatively, provided that this notice is retained in full, this software
* may be relicensed by the recipient under the terms of the GNU General Public
* License version 2 ("GPL") and only version 2, in which case the provisions of
* the GPL apply INSTEAD OF those given above. If the recipient relicenses the
* software under the GPL, then the identification text in the MODULE_LICENSE
* macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
* recipient changes the license terms to the GPL, subsequent recipients shall
* not relicense under alternate licensing terms, including the BSD or dual
* BSD/GPL terms. In addition, the following license statement immediately
* below and between the words START and END shall also then apply when this
* software is relicensed under the GPL:
*
* START
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* END
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/i2c.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/earlysuspend.h>
#include <linux/wakelock.h>
#include <media/msm_camera.h>
#include <mach/gpio.h>
#include <mach/camera.h>
#include <mach/vreg.h>
#include <asm/mach-types.h>
#include "ov8810.h"
/* CAMIF output resolutions */
/* 816x612, 24MHz MCLK 96MHz PCLK */
#define OV8810_FULL_SIZE_DUMMY_PIXELS 0
#define OV8810_FULL_SIZE_DUMMY_LINES 0
#define OV8810_FULL_SIZE_WIDTH 3280
#define OV8810_FULL_SIZE_HEIGHT 2456
#define OV8810_QTR_SIZE_DUMMY_PIXELS 0
#define OV8810_QTR_SIZE_DUMMY_LINES 0
#define OV8810_QTR_SIZE_WIDTH 1632
#define OV8810_QTR_SIZE_HEIGHT 1224
#define OV8810_HRZ_FULL_BLK_PIXELS 696 /*stella 1203*/
#define OV8810_VER_FULL_BLK_LINES 44
#define OV8810_HRZ_QTR_BLK_PIXELS 890
#define OV8810_VER_QTR_BLK_LINES 44
static int cam_mode_sel = 0; /* 0: photo, 1: video@30fps, 2: video@24fps */
/* 240: 26, 365: 24, 589: 21 */
const int ov8810_ver_qtr_blk_lines_array[] = {44, 44, 365};
/*=============================================================
SENSOR REGISTER DEFINES
==============================================================*/
#define Q8 0x00000100
/* Omnivision8810 product ID register address */
#define OV8810_PIDH_REG 0x300A
#define OV8810_PIDL_REG 0x300B
/* Omnivision8810 product ID */
#define OV8810_PID 0x88
/* Omnivision8810 version */
#define OV8810_VER 0x10
/* Time in milisecs for waiting for the sensor to reset */
#define OV8810_RESET_DELAY_MSECS 66
#define OV8810_DEFAULT_CLOCK_RATE 24000000
/* Registers*/
/* PLL Registers */
#define REG_PRE_PLL_CLK_DIV 0x3011 /*0x0305*/
#define REG_PLL_MULTIPLIER 0x3010
#define REG_VT_CLK_DIV 0x300E /*[7:4]VT_SYS_DIV, [3-0]VT_PIX_DIV*/
#define REG_OP_CLK_DIV 0x300F /*[7:4]OP_SYS_DIV, [3-0]OP_PIX_DIV*/
/* ISP Enable Control */
#define REG_ISP_ENABLE_CONTROL_00 0x3302
#define REG_ISP_ENABLE_CONTROL_01 0x3301
/* AWB Control */
#define REG_AWB_CTRL_0 0x3320
#define REG_AWB_CTRL_1 0x3321
#define REG_AWB_CTRL_2 0x3322
#define REG_AWB_CTRL_8 0x3328
/* Output Size */
#define REG_X_OUTPUT_SIZE_MSB 0x302C
#define REG_X_OUTPUT_SIZE_LSB 0x302D
#define REG_Y_OUTPUT_SIZE_MSB 0x302E
#define REG_Y_OUTPUT_SIZE_LSB 0x302F
/*Reserved register */
#define REG_BINNING_CONTROL 0x3091
/* Frame Fotmat */
#define REG_FRAME_LENGTH_LINES_MSB 0x3020
#define REG_FRAME_LENGTH_LINES_LSB 0x3021
#define REG_LINE_LENGTH_PCK_MSB 0x3022
#define REG_LINE_LENGTH_PCK_LSB 0x3023
#define REG_EXTRA_VSYNC_WIDTH_MSB 0x301E
#define REG_EXTRA_VSYNC_WIDTH_LSB 0x301F
#define REG_X_ADDR_START_HIGH 0x3024
#define REG_X_ADDR_START_LOW 0x3025
#define REG_Y_ADDR_START_HIGH 0x3026
#define REG_Y_ADDR_START_LOW 0x3027
#define REG_X_ADDR_END_HIGH 0x3028
#define REG_X_ADDR_END_LOW 0x3029
#define REG_Y_ADDR_END_HIGH 0x302A
#define REG_Y_ADDR_END_LOW 0x302B
/* Gain setting register */
#define OV8810_GAIN 0x3000
#define OV8810_AEC_MSB 0x3002
#define OV8810_AEC_LSB 0x3003
/* additional gain function provided by OV8810,
* original gain can changed to 1x, 2x or 4x
* to increase the gain that OV8810 can provide */
#define OV8810_REG_MUL_GAIN 0x3006
#define MUL_GAIN_INIT_VALUE 0x00
#define OV8810_MAX_EXPOSURE_GAIN 0x1FF
/* Mode select register */
#define OV8810_REG_MODE_SELECT 0x30FA /* image system */
#define OV8810_MODE_SELECT_STREAM 0x01 /* start streaming */
#define OV8810_MODE_SELECT_SW_STANDBY 0x00 /* software standby */
#define OV8810_REG_SOFTWARE_RESET 0x3012 /* 0x0103 */
#define OV8810_SOFTWARE_RESET 0x80 /* 0x01 */
/* AF Total steps parameters */
#define OV8810_AF_MSB 0x30EC
#define OV8810_AF_LSB 0x30ED
#define OV8810_STEPS_NEAR_TO_CLOSEST_INF 42 /*43 stella0122 */
#define OV8810_TOTAL_STEPS_NEAR_TO_FAR 42 /*43 stella0122 */
/*Test pattern*/
/* Color bar pattern selection */
#define OV8810_COLOR_BAR_PATTERN_SEL_REG 0x307B
/* Color bar enabling control */
#define OV8810_COLOR_BAR_ENABLE_REG 0x307D
/* I2C Address of the Sensor */
#define OV8810_I2C_SLAVE_ID 0x6C
/*LSC table length*/
#define LSC_table_length 144
/*============================================================================
TYPE DECLARATIONS
============================================================================*/
/* 16bit address - 8 bit context register structure */
#if 0
typedef struct reg_addr_val_pair_struct {
uint16_t reg_addr;
uint8_t reg_val;
} reg_struct_type;
#endif
struct awb_lsc_struct_type {
unsigned int caBuff[8]; /*awb_calibartion*/
struct reg_addr_val_pair_struct LSC_table[150]; /*lsc_calibration*/
uint32_t LSC_table_CRC;
};
enum ov8810_test_mode_t {
TEST_OFF,
TEST_1,
TEST_2,
TEST_3
};
enum ov8810_resolution_t {
QTR_SIZE,
FULL_SIZE,
INVALID_SIZE
};
/*LSC calibration*/
int global_mode;
/*TODO: should be use a header file to reference this function*/
extern unsigned char *get_cam_awb_cal(void);
static int sensor_probe_node = 0;
static struct wake_lock ov8810_wake_lock;
static inline void init_suspend(void)
{
wake_lock_init(&ov8810_wake_lock, WAKE_LOCK_IDLE, "ov8810");
}
static inline void deinit_suspend(void)
{
wake_lock_destroy(&ov8810_wake_lock);
}
static inline void prevent_suspend(void)
{
wake_lock(&ov8810_wake_lock);
}
static inline void allow_suspend(void)
{
wake_unlock(&ov8810_wake_lock);
}
/*============================================================================
DATA DECLARATIONS
============================================================================*/
/* 96MHz PCLK @ 24MHz MCLK inc*/
/*stella1223 start*/
static struct reg_addr_val_pair_struct ov8810_init_settings_array[] =
{
/* Sensor clk setup */
{REG_OP_CLK_DIV, 0x04},
{REG_VT_CLK_DIV, 0x05},
#if 1 /* weiting0414 prevent capture hang restore CLK */
{REG_PLL_MULTIPLIER, 0x28}, /*0x28 96MHz PCLK 0x18 64MHz PCLK*/
{REG_PRE_PLL_CLK_DIV, 0x22},
#else
{REG_PLL_MULTIPLIER, 0x14}, /*Reduce internal clock to prevent hang Weiting0331*/
{REG_PRE_PLL_CLK_DIV, 0x21},
#endif
{OV8810_GAIN, 8}, /*0x30},*/
{OV8810_AEC_MSB, 0x04},
{OV8810_AEC_LSB, 0xc4}, /*stella 1203*/
{REG_ISP_ENABLE_CONTROL_00, 0x20},
{0x30b2, 0x13}, /*driving strength*/
{0x30a0, 0x40},
{0x3098, 0x24},
{0x3099, 0x81},
{0x309a, 0x64},
{0x309b, 0x00},
{0x309d, 0x64},
{0x309e, 0x2d},
{REG_AWB_CTRL_0, 0xc2}, /*set wb manual*/
{REG_AWB_CTRL_1, 0x02},
{REG_AWB_CTRL_2, 0x04},
{REG_AWB_CTRL_8, 0x40},
{0x3329, 0xe3}, /*00},*/ /*stella 1203*/
{0x3306, 0x00},
{0x3316, 0x03},
{0x3079, 0x0a},
/*stella 1203*/
{0x3058, 0x01},
{0x3059, 0xa0},
{0x306b, 0x00},
{0x3065, 0x50},
{0x3067, 0x40},
{0x3069, 0x80},
{0x3071, 0x40},/*50 BLC trigger by gain 40 BLC every frame */
{0x3300, 0xef},
{0x3334, 0x02},
{0x3331, 0x08}, /*BLC level 8813*/ /*stella 1203*/
{0x3332, 0x08}, /*8813*/
{0x3333, 0x41},
/*Stella1221 for adding init size */
{0x30f8, 0x45},
{REG_FRAME_LENGTH_LINES_MSB,
((OV8810_QTR_SIZE_HEIGHT + OV8810_VER_QTR_BLK_LINES) & 0xFF00) >> 8},
{REG_FRAME_LENGTH_LINES_LSB,
((OV8810_QTR_SIZE_HEIGHT + OV8810_VER_QTR_BLK_LINES) & 0x00FF)},
{REG_LINE_LENGTH_PCK_MSB,
((OV8810_QTR_SIZE_WIDTH + OV8810_HRZ_QTR_BLK_PIXELS) & 0xFF00) >> 8},
{REG_LINE_LENGTH_PCK_LSB,
((OV8810_QTR_SIZE_WIDTH + OV8810_HRZ_QTR_BLK_PIXELS) & 0x00FF)},
{REG_X_ADDR_START_HIGH, 0x00},
{REG_X_ADDR_START_LOW, 0x04}, /*stella 1203*/
{REG_Y_ADDR_START_HIGH, 0x00},
{REG_Y_ADDR_START_LOW, 0x00},
{REG_X_ADDR_END_HIGH, 0x0c},
{REG_X_ADDR_END_LOW, 0xdb}, /*stella 1203*/
{REG_Y_ADDR_END_HIGH, 0x09},
{REG_Y_ADDR_END_LOW, 0x9f},
{REG_X_OUTPUT_SIZE_MSB, (OV8810_QTR_SIZE_WIDTH & 0xFF00) >> 8},
{REG_X_OUTPUT_SIZE_LSB, (OV8810_QTR_SIZE_WIDTH & 0x00FF)},
{REG_Y_OUTPUT_SIZE_MSB, (OV8810_QTR_SIZE_HEIGHT & 0xFF00) >> 8},
{REG_Y_OUTPUT_SIZE_LSB, (OV8810_QTR_SIZE_HEIGHT & 0x00FF)},
/*Stella1221 for adding init size */
/* {REG_BINNING_CONTROL, 0x00},*/ /*stella 1203*/
{OV8810_REG_MUL_GAIN, MUL_GAIN_INIT_VALUE},
{0x3082, 0x80},
{0x331e, 0x94},
{0x331f, 0x6e},
{0x3092, 0x00},
{0x3094, 0x01},
{0x3090, 0x2b}, /* for AN version 8a */ /*changed by Stella for 8813*/
{0x30ab, 0x44},
{0x3095, 0x0a},
{0x308d, 0x00},
{0x3082, 0x00},
{0x3080, 0x40},
{0x30aa, 0x59},
{0x30a9, 0x00},
{0x30be, 0x08},
{0x309f, 0x23},
{0x3065, 0x40},
{0x3068, 0x00},
{0x30bf, 0x80},
{0x309c, 0x00},
{0x3084, 0x44}, /*added by stella for 8813*/
{0x3016, 0x03}, /*added by stella for 8813*/
{0x30e9, 0x09}, /*changed by stella for 8813*/
{0x3075, 0x29},
{0x3076, 0x29},
{0x3077, 0x29},
{0x3078, 0x29},
{0x306a, 0x05},
{0x3015, 0x33}, /*changed by stella for 8813*/
/*stella 1203 start*/
{0x3090, 0x36},
{0x333e, 0x00},
{0x306a, 0x05},
/*stella 1203 end*/
{0x3087, 0x41},
{0x3090, 0x97}, /*99, QCT=97*/
{0x309e, 0x1b},
{0x30e3, 0x0e},
{0x30f0, 0x00},
{0x30f2, 0x00},
{0x30f4, 0x90},
/*stella 1203 start*/
{0x3347, 0x00},
{0x3347, 0x00},
#if 0
{0x3092, 0x00}, //marked by QCT
{0x30f0, 0x10}, //marked by QCT
{0x30f1, 0x56}, //marked by QCT
{0x30fb, 0x8e}, //marked by QCT
{0x30f3, 0xa7}, //marked by QCT
#endif
{0x3091, 0x08}, /*QCT for 8813*/
{0x3090, 0x97}, /*QCT for 8813*/
{0x30fb, 0xc9}, /*QCT for 8813*/
{0x308d, 0x02},
{0x30e7, 0x41},
{0x30b3, 0x08},
{0x33e5, 0x00}, /*30e5*/
{0x350e, 0x40}, /*305e*/
{0x301f, 0x00},
{0x309f, 0x23},
{0x3013, 0xc0},
{0x30e1, 0x90},
{0x3058, 0x01},
{0x3500, 0x40}, /* vsync_new */
{REG_BINNING_CONTROL, 0x00}, /*stella 0126*/
/*stella 1203 end*/
};
/*Vincent for LSC calibration*/
static struct reg_addr_val_pair_struct lsc_table_array[] =
{
{0x3358, 0x1f },//{0x3358, 0x18},
{0x3359, 0x14 },//{0x3359, 0x0f},
{0x335a, 0x0f },//{0x335a, 0x0c},
{0x335b, 0x0d },//{0x335b, 0x0a},
{0x335c, 0x0d },//{0x335c, 0x0a},
{0x335d, 0x0f },//{0x335d, 0x0b},
{0x335e, 0x14 },//{0x335e, 0x0d},
{0x335f, 0x1d },//{0x335f, 0x15},
{0x3360, 0x0f },//{0x3360, 0x0b},
{0x3361, 0x0a },//{0x3361, 0x09},
{0x3362, 0x07 },//{0x3362, 0x06},
{0x3363, 0x06 },//{0x3363, 0x05},
{0x3364, 0x06 },//{0x3364, 0x05},
{0x3365, 0x07 },//{0x3365, 0x06},
{0x3366, 0x09 },//{0x3366, 0x08},
{0x3367, 0x0d },//{0x3367, 0x0b},
{0x3368, 0x09 },//{0x3368, 0x07},
{0x3369, 0x06 },//{0x3369, 0x05},
{0x336a, 0x04 },//{0x336a, 0x03},
{0x336b, 0x03 },//{0x336b, 0x02},
{0x336c, 0x03 },//{0x336c, 0x02},
{0x336d, 0x04 },//{0x336d, 0x03},
{0x336e, 0x06 },//{0x336e, 0x04},
{0x336f, 0x09 },//{0x336f, 0x06},
{0x3370, 0x07 },//{0x3370, 0x05},
{0x3371, 0x04 },//{0x3371, 0x04},
{0x3372, 0x01 },//{0x3372, 0x01},
{0x3373, 0x00 },//{0x3373, 0x00},
{0x3374, 0x00 },//{0x3374, 0x00},
{0x3375, 0x01 },//{0x3375, 0x01},
{0x3376, 0x04 },//{0x3376, 0x03},
{0x3377, 0x07 },//{0x3377, 0x05},
{0x3378, 0x08 },//{0x3378, 0x05},
{0x3379, 0x04 },//{0x3379, 0x03},
{0x337a, 0x01 },//{0x337a, 0x01},
{0x337b, 0x00 },//{0x337b, 0x00},
{0x337c, 0x00 },//{0x337c, 0x00},
{0x337d, 0x01 },//{0x337d, 0x00},
{0x337e, 0x04 },//{0x337e, 0x02},
{0x337f, 0x07 },//{0x337f, 0x05},
{0x3380, 0x09 },//{0x3380, 0x06},
{0x3381, 0x06 },//{0x3381, 0x04},
{0x3382, 0x04 },//{0x3382, 0x03},
{0x3383, 0x02 },//{0x3383, 0x02},
{0x3384, 0x02 },//{0x3384, 0x01},
{0x3385, 0x04 },//{0x3385, 0x02},
{0x3386, 0x06 },//{0x3386, 0x03},
{0x3387, 0x09 },//{0x3387, 0x05},
{0x3388, 0x0f },//{0x3388, 0x0a},
{0x3389, 0x0a },//{0x3389, 0x07},
{0x338a, 0x07 },//{0x338a, 0x05},
{0x338b, 0x07 },//{0x338b, 0x04},
{0x338c, 0x07 },//{0x338c, 0x04},
{0x338d, 0x07 },//{0x338d, 0x05},
{0x338e, 0x0a },//{0x338e, 0x06},
{0x338f, 0x0f },//{0x338f, 0x09},
{0x3390, 0x1d },//{0x3390, 0x12},
{0x3391, 0x12 },//{0x3391, 0x0d},
{0x3392, 0x0d },//{0x3392, 0x09},
{0x3393, 0x0b },//{0x3393, 0x08},
{0x3394, 0x0b },//{0x3394, 0x08},
{0x3395, 0x0d },//{0x3395, 0x09},
{0x3396, 0x12 },//{0x3396, 0x0c},
{0x3397, 0x1a },//{0x3397, 0x11},
{0x3398, 0x0f },//{0x3398, 0x10},
{0x3399, 0x0d },//{0x3399, 0x10},
{0x339a, 0x0e },//{0x339a, 0x10},
{0x339b, 0x0f },//{0x339b, 0x0e},
{0x339c, 0x11 },//{0x339c, 0x0e},
{0x339d, 0x0d },//{0x339d, 0x0f},
{0x339e, 0x12 },//{0x339e, 0x0e},
{0x339f, 0x0e },//{0x339f, 0x0f},
{0x33a0, 0x0f },//{0x33a0, 0x0f},
{0x33a1, 0x0f },//{0x33a1, 0x0f},
{0x33a2, 0x10 },//{0x33a2, 0x0f},
{0x33a3, 0x10 },//{0x33a3, 0x10},
{0x33a4, 0x0f },//{0x33a4, 0x0e},
{0x33a5, 0x0d },//{0x33a5, 0x10},
{0x33a6, 0x0f },//{0x33a6, 0x11},
{0x33a7, 0x10 },//{0x33a7, 0x10},
{0x33a8, 0x10 },//{0x33a8, 0x10},
{0x33a9, 0x0f },//{0x33a9, 0x0f},
{0x33aa, 0x10 },//{0x33aa, 0x0e},
{0x33ab, 0x0e },//{0x33ab, 0x0f},
{0x33ac, 0x10 },//{0x33ac, 0x10},
{0x33ad, 0x11 },//{0x33ad, 0x10},
{0x33ae, 0x11 },//{0x33ae, 0x10},
{0x33af, 0x0f },//{0x33af, 0x0f},
{0x33b0, 0x0f },//{0x33b0, 0x0e},
{0x33b1, 0x0d },//{0x33b1, 0x0f},
{0x33b2, 0x0d },//{0x33b2, 0x0f},
{0x33b3, 0x0e },//{0x33b3, 0x0f},
{0x33b4, 0x0f },//{0x33b4, 0x0f},
{0x33b5, 0x10 },//{0x33b5, 0x0f},
{0x33b6, 0x12 },//{0x33b6, 0x0e},
{0x33b7, 0x0d },//{0x33b7, 0x0d},
{0x33b8, 0x0c },//{0x33b8, 0x0c},
{0x33b9, 0x0c },//{0x33b9, 0x0c},
{0x33ba, 0x0c },//{0x33ba, 0x0d},
{0x33bb, 0x0b },//{0x33bb, 0x0f},
{0x33bc, 0x1b },//{0x33bc, 0x16},
{0x33bd, 0x1b },//{0x33bd, 0x17},
{0x33be, 0x1d },//{0x33be, 0x17},
{0x33bf, 0x1d },//{0x33bf, 0x17},
{0x33c0, 0x1e },//{0x33c0, 0x17},
{0x33c1, 0x1c },//{0x33c1, 0x14},
{0x33c2, 0x1a },//{0x33c2, 0x17},
{0x33c3, 0x17 },//{0x33c3, 0x14},
{0x33c4, 0x15 },//{0x33c4, 0x13},
{0x33c5, 0x16 },//{0x33c5, 0x13},
{0x33c6, 0x19 },//{0x33c6, 0x14},
{0x33c7, 0x1e },//{0x33c7, 0x15},
{0x33c8, 0x16 },//{0x33c8, 0x15},
{0x33c9, 0x12 },//{0x33c9, 0x12},
{0x33ca, 0x10 },//{0x33ca, 0x10},
{0x33cb, 0x10 },//{0x33cb, 0x10},
{0x33cc, 0x14 },//{0x33cc, 0x12},
{0x33cd, 0x19 },//{0x33cd, 0x14},
{0x33ce, 0x16 },//{0x33ce, 0x15},
{0x33cf, 0x12 },//{0x33cf, 0x12},
{0x33d0, 0x10 },//{0x33d0, 0x10},
{0x33d1, 0x11 },//{0x33d1, 0x10},
{0x33d2, 0x14 },//{0x33d2, 0x12},
{0x33d3, 0x1a },//{0x33d3, 0x14},
{0x33d4, 0x18 },//{0x33d4, 0x16},
{0x33d5, 0x15 },//{0x33d5, 0x13},
{0x33d6, 0x13 },//{0x33d6, 0x12},
{0x33d7, 0x14 },//{0x33d7, 0x12},
{0x33d8, 0x17 },//{0x33d8, 0x13},
{0x33d9, 0x1b },//{0x33d9, 0x15},
{0x33da, 0x18 },//{0x33da, 0x18},
{0x33db, 0x1a },//{0x33db, 0x15},
{0x33dc, 0x1b },//{0x33dc, 0x15},
{0x33dd, 0x1b },//{0x33dd, 0x15},
{0x33de, 0x1b },//{0x33de, 0x15},
{0x33df, 0x1c },//{0x33df, 0x14},
{0x3350, 0x06 },//{0x3350, 0x06},
{0x3351, 0xab },//{0x3351, 0xab},
{0x3352, 0x05 },//{0x3352, 0x05},
{0x3353, 0x00 },//{0x3353, 0x00},
{0x3354, 0x04 },//{0x3354, 0x04},
{0x3355, 0xf8 },//{0x3355, 0xf8},
{0x3356, 0x07 },//{0x3356, 0x07},
{0x3357, 0x74 },//{0x3357, 0x74},
/* lsc setting on sensor*/
{0x3300, 0xff}, /*enable lsc on sensor*/
/*move to the last*/
{OV8810_REG_MODE_SELECT, OV8810_MODE_SELECT_STREAM},
};
/*1632x1224; 24MHz MCLK 96MHz PCLK*/
static struct reg_addr_val_pair_struct ov8810_qtr_settings_array[] =
{
{0x30f8, 0x45},
{REG_FRAME_LENGTH_LINES_MSB,
((OV8810_QTR_SIZE_HEIGHT + OV8810_VER_QTR_BLK_LINES) & 0xFF00) >> 8},
{REG_FRAME_LENGTH_LINES_LSB,
((OV8810_QTR_SIZE_HEIGHT + OV8810_VER_QTR_BLK_LINES) & 0x00FF)},
{REG_LINE_LENGTH_PCK_MSB,
((OV8810_QTR_SIZE_WIDTH + OV8810_HRZ_QTR_BLK_PIXELS) & 0xFF00) >> 8},
{REG_LINE_LENGTH_PCK_LSB,
((OV8810_QTR_SIZE_WIDTH + OV8810_HRZ_QTR_BLK_PIXELS) & 0x00FF)},
{REG_X_ADDR_START_HIGH, 0x00},
{REG_X_ADDR_START_LOW, 0x04}, /*stella 1203*/
{REG_Y_ADDR_START_HIGH, 0x00},
{REG_Y_ADDR_START_LOW, 0x00},
{REG_X_ADDR_END_HIGH, 0x0c},
{REG_X_ADDR_END_LOW, 0xd8}, /*stella 1203=db*/ /*QCT:d8*/
{REG_Y_ADDR_END_HIGH, 0x09},
{REG_Y_ADDR_END_LOW, 0x9f},
{REG_X_OUTPUT_SIZE_MSB, (OV8810_QTR_SIZE_WIDTH & 0xFF00) >> 8},
{REG_X_OUTPUT_SIZE_LSB, (OV8810_QTR_SIZE_WIDTH & 0x00FF)},
{REG_Y_OUTPUT_SIZE_MSB, (OV8810_QTR_SIZE_HEIGHT & 0xFF00) >> 8},
{REG_Y_OUTPUT_SIZE_LSB, (OV8810_QTR_SIZE_HEIGHT & 0x00FF)},
/*stella1202 for capture over exposure issue due to user space use 2X line count*/
{0x3068, 0x00}, /*changed for color edge, stella 1203*/
{0x307e, 0x00},
{0x3071, 0x40},/*50 BLC trigger by gain 40 BLC every frame */
{REG_ISP_ENABLE_CONTROL_01, 0x0B},
{REG_BINNING_CONTROL, 0x00}, //stella0127
{0x331c, 0x00},
{0x331d, 0x00},
{0x308a, 0x02},
{0x3072, 0x0d},
{0x3319, 0x04},
{0x309e, 0x09},
{0x300e, 0x05},
{0x300f, 0x04},
{0x33e4, 0x07}, /*lsc for 2:1 down sampling*/
};
/*stella1223 end*/
/* 3280x2456 Sensor Raw; 24MHz MCLK 96MHz PCLK*/
static struct reg_addr_val_pair_struct ov8810_full_settings_array[] =
{
{0x30f8, 0x40},
{REG_FRAME_LENGTH_LINES_MSB,
((OV8810_FULL_SIZE_HEIGHT + OV8810_VER_FULL_BLK_LINES) & 0xFF00) >> 8},
{REG_FRAME_LENGTH_LINES_LSB,
((OV8810_FULL_SIZE_HEIGHT + OV8810_VER_FULL_BLK_LINES) & 0x00FF)},
{REG_LINE_LENGTH_PCK_MSB,
((OV8810_FULL_SIZE_WIDTH + OV8810_HRZ_FULL_BLK_PIXELS) & 0xFF00) >> 8},
{REG_LINE_LENGTH_PCK_LSB,
((OV8810_FULL_SIZE_WIDTH + OV8810_HRZ_FULL_BLK_PIXELS) & 0x00FF)},
{REG_X_ADDR_START_HIGH, 0x00},
{REG_X_ADDR_START_LOW, 0x02}, /*stella 1203*/
{REG_Y_ADDR_START_HIGH, 0x00},
{REG_Y_ADDR_START_LOW, 0x00},
{REG_X_ADDR_END_HIGH, 0x0c},
{REG_X_ADDR_END_LOW, 0xdd}, /*stella 1203*/
{REG_Y_ADDR_END_HIGH, 0x09},
{REG_Y_ADDR_END_LOW, 0x9f},
{REG_X_OUTPUT_SIZE_MSB, (OV8810_FULL_SIZE_WIDTH & 0xFF00) >> 8},
{REG_X_OUTPUT_SIZE_LSB, (OV8810_FULL_SIZE_WIDTH & 0x00FF)},
{REG_Y_OUTPUT_SIZE_MSB, (OV8810_FULL_SIZE_HEIGHT & 0xFF00) >> 8},
{REG_Y_OUTPUT_SIZE_LSB, (OV8810_FULL_SIZE_HEIGHT & 0x00FF)},
/*stella1202 for capture over exposure issue
due to user space use 2X line count */
{0x3068, 0x00}, /* changed for color edge stella 1203*/
{0x307e, 0x00},
{REG_ISP_ENABLE_CONTROL_01, 0x0B},
{REG_BINNING_CONTROL, 0x00}, //stella0127
{0x331c, 0x28},
{0x331d, 0x21},
{0x308a, 0x01},
{0x3072, 0x01},
{0x3319, 0x06},
{0x309e, 0x1b},
{0x300e, 0x05},
{0x300f, 0x04},
{0x33e4, 0x02}, /*lsc for full resolution*/
};
/* AF Tuning Parameters */
static uint16_t ov8810_step_position_table[OV8810_TOTAL_STEPS_NEAR_TO_FAR+1];
static uint8_t ov8810_damping_threshold = 10;
static uint8_t ov8810_damping_course_step = 4;
static uint8_t ov8810_damping_fine_step = 10;
static uint8_t ov8810_damping_time_wait;
static uint16_t ov8810_focus_debug; /*don't init to 0*/
static uint16_t ov8810_use_default_damping = 1;
static uint16_t ov8810_use_threshold_damping = 1; /*set to FALSE if too slow*/
/*static uint32_t stored_line_length_ratio = 1 * Q8;*/
/*Andy1217 write Line 1 frame ealier before Gain*/
struct backup_line_gain_struct {
uint32_t line;
uint8_t mul;
uint16_t gain;
uint32_t extra_line_length;
};
static struct backup_line_gain_struct backup_line_gain[2];
static uint16_t write_cnt;
static uint16_t updated_BLC; /* only set to 0x50 after 1st update again*/
uint8_t S3_to_0 = 0x1; /* 0x9 */
/* static Variables*/
static uint16_t step_position_table[OV8810_TOTAL_STEPS_NEAR_TO_FAR+1];
/* FIXME: Changes from here */
struct ov8810_work {
struct work_struct work;
};
static struct ov8810_work *ov8810_sensorw;
static struct i2c_client *ov8810_client;
static struct vreg *vreg_af_actuator;
struct ov8810_ctrl {
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 ov8810_resolution_t prev_res;
enum ov8810_resolution_t pict_res;
enum ov8810_resolution_t curr_res;
enum ov8810_test_mode_t set_test;
unsigned short imgaddr;
};
static struct ov8810_ctrl *ov8810_ctrl;
static struct platform_device *ov8810_pdev;
struct ov8810_waitevent{
uint32_t waked_up;
wait_queue_head_t event_wait;
};
static struct ov8810_waitevent ov8810_event;
static DECLARE_WAIT_QUEUE_HEAD(ov8810_wait_queue);
DECLARE_MUTEX(ov8810_sem);
/*=============================================================*/
static int ov8810_i2c_rxdata(unsigned short saddr,
unsigned char *rxdata, int length)
{
struct i2c_msg msgs[] = {
{
.addr = saddr,
.flags = 0,
.len = 2,
.buf = rxdata,
},
{
.addr = saddr,
.flags = I2C_M_RD,
.len = length,
.buf = rxdata,
},
};
CDBG("%s: saddr=0x%X\n", __func__, saddr);
CDBG("%s: raddr=0x%X\n", __func__, *rxdata);
if (i2c_transfer(ov8810_client->adapter, msgs, 2) < 0) {
pr_err("ov8810_i2c_rxdata failed!\n");
return -EIO;
}
CDBG("%s: rxdata=0x%X\n", __func__, *rxdata);
return 0;
}
static int32_t ov8810_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(ov8810_client->adapter, msg, 1) < 0) {
pr_err("ov8810_i2c_txdata faild 0x%x\n", ov8810_client->addr);
return -EIO;
}
return 0;
}
static int32_t ov8810_i2c_read(unsigned short raddr,
unsigned short *rdata, int rlen)
{
int32_t rc = 0;
unsigned char buf[2];
int count = 0;
if (!rdata)
return -EIO;
memset(buf, 0, sizeof(buf));
buf[0] = (raddr & 0xFF00) >> 8;
buf[1] = (raddr & 0x00FF);
retry:
rc = ov8810_i2c_rxdata(ov8810_client->addr, buf, rlen);
if (rc < 0) {
pr_err("ov8810_i2c_read 0x%x failed!\n", raddr);
printk(KERN_ERR "starting read retry policy count:%d\n", count);
udelay(10);
count++;
if (count < 20) {
if (count > 10)
udelay(100);
} else
return rc;
goto retry;
}
*rdata = (rlen == 2 ? buf[0] << 8 | buf[1] : buf[0]);
return rc;
}
static int32_t ov8810_i2c_write_b(unsigned short saddr,
unsigned short waddr, uint8_t bdata)
{
int32_t rc = -EFAULT;
unsigned char buf[3];
int count = 0;
CDBG("i2c_write_w_b, addr = 0x%x, val = 0x%x!\n", waddr, bdata);
memset(buf, 0, sizeof(buf));
buf[0] = (waddr & 0xFF00) >> 8;
buf[1] = (waddr & 0x00FF);
buf[2] = bdata;
retry:
CDBG("i2c_write_b addr = %d, val = %d\n", waddr, bdata);
rc = ov8810_i2c_txdata(saddr, buf, 3);
if (rc < 0) {
pr_err("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
waddr, bdata);
pr_err(KERN_ERR "starting read retry policy count:%d\n", count);
udelay(10);
count++;
if (count < 20) {
if (count > 10)
udelay(100);
} else
return rc;
goto retry;
}
return rc;
}
/*for LSC calibration*/
static int ov8810_update_lsc_table(struct sensor_cfg_data *cdata)
{
int i = 0;
pr_info("[LSC calibration]ov8810_update_lsc_table\n");
for (i = 0; i < 144; i++) {
ov8810_i2c_write_b(
ov8810_client->addr,
cdata->cfg.lsctable.lsc_table[i].reg_addr,
cdata->cfg.lsctable.lsc_table[i].reg_val);
pr_info("[LSC calibration]update_lsc_table: 0x%x, 0x%x\n",
cdata->cfg.lsctable.lsc_table[i].reg_addr,
cdata->cfg.lsctable.lsc_table[i].reg_val);
}
/*enable lsc on sensor*/
ov8810_i2c_write_b(ov8810_client->addr, 0x3300, 0xff);
/*mirror on*/
ov8810_i2c_write_b(ov8810_client->addr, 0x30f8, 0x45);
/*mirror on*/
ov8810_i2c_write_b(ov8810_client->addr, 0x3316, 0x03);
return 1;
}
/*20100330 vincent for LSC calibration*/
static int ov8810_LSC_calibration_set_rawflag(struct sensor_cfg_data *cdata)
{
global_mode = 1;
return 1;
}
#define MAX_FUSE_ID_INFO 11
static int ov8810_i2c_read_fuseid(struct sensor_cfg_data *cdata)
{
unsigned short fuse_id[MAX_FUSE_ID_INFO];
int count = 0;
ov8810_i2c_write_b(ov8810_client->addr, 0x30d5, 0xff);
ov8810_i2c_write_b(ov8810_client->addr, 0x30d6, 0xff);
ov8810_i2c_write_b(ov8810_client->addr, 0x30d7, 0xff);
ov8810_i2c_write_b(ov8810_client->addr, 0x30d8, 0xff);
ov8810_i2c_write_b(ov8810_client->addr, 0x30d9, 0xff);
ov8810_i2c_write_b(ov8810_client->addr, 0x30da, 0xff);
ov8810_i2c_write_b(ov8810_client->addr, 0x30db, 0xff);
ov8810_i2c_write_b(ov8810_client->addr, 0x30dc, 0xff);
ov8810_i2c_write_b(ov8810_client->addr, 0x30dd, 0xff);
ov8810_i2c_write_b(ov8810_client->addr, 0x30de, 0xff);
ov8810_i2c_write_b(ov8810_client->addr, 0x30df, 0xff);
ov8810_i2c_write_b(ov8810_client->addr, 0x303e, 0x55);
ov8810_i2c_read(0x30d5, &fuse_id[0], 2);
ov8810_i2c_read(0x30d6, &fuse_id[1], 2);
ov8810_i2c_read(0x30d7, &fuse_id[2], 2);
ov8810_i2c_read(0x30d8, &fuse_id[3], 2);
ov8810_i2c_read(0x30d9, &fuse_id[4], 2);
ov8810_i2c_read(0x30da, &fuse_id[5], 2);
ov8810_i2c_read(0x30db, &fuse_id[6], 2);
ov8810_i2c_read(0x30dc, &fuse_id[7], 2);
ov8810_i2c_read(0x30dd, &fuse_id[8], 2);
ov8810_i2c_read(0x30de, &fuse_id[9], 2);
ov8810_i2c_read(0x30df, &fuse_id[10], 2);
cdata->cfg.fuse.fuse_id_word1 = (uint32_t) fuse_id[0];
cdata->cfg.fuse.fuse_id_word2 = (uint32_t) fuse_id[1];
cdata->cfg.fuse.fuse_id_word3 = 0;
cdata->cfg.fuse.fuse_id_word4 = 0;
for (count = 0; count < MAX_FUSE_ID_INFO; count++)
pr_info("Ov8810 Get fuse: fuse_id[%d]: %x\n",
count, fuse_id[count]);
return 0;
}
static int32_t ov8810_af_i2c_write(uint16_t data)
{
uint8_t code_val_msb, code_val_lsb; /* S3_to_0; */
uint32_t rc = 0;
/* S3_to_0 = 0x9; S[3:0] */
code_val_msb = data >> 4; /* D[9:4] */
code_val_lsb = ((data & 0x000F) << 4) | S3_to_0;
CDBG("code value = %d ,D[9:4] = %d ,D[3:0] = %d\n",
data, code_val_msb, code_val_lsb);
rc = ov8810_i2c_write_b(ov8810_client->addr,
OV8810_AF_MSB, code_val_msb);
if (rc < 0) {
pr_err("Unable to write code_val_msb = %d\n", code_val_msb);
return rc;
}
rc = ov8810_i2c_write_b(ov8810_client->addr,
OV8810_AF_LSB, code_val_lsb);
if (rc < 0) {
pr_err("Unable to write code_val_lsb = %disclaimer\n",
code_val_lsb);
return rc;
}
return rc;
} /* ov8810_af_i2c_write */
static int32_t ov8810_move_focus(int direction, int32_t num_steps)
{
int8_t step_direction;
int8_t dest_step_position;
uint16_t dest_lens_position, target_dist, small_step;
int16_t next_lens_position;
int32_t rc = 0;
if (num_steps == 0) {
return rc;
}
if (direction == MOVE_NEAR) {
step_direction = 1;
} else if (direction == MOVE_FAR) {
step_direction = -1;
} else {
pr_err("Illegal focus direction\n");
return -EINVAL;; /* CAMERA_INVALID_PARM; */
}
CDBG("%s, interpolate\n", __func__);
dest_step_position =
ov8810_ctrl->curr_step_pos + (step_direction * num_steps);
if (dest_step_position < 0)
dest_step_position = 0;
else if (dest_step_position > OV8810_TOTAL_STEPS_NEAR_TO_FAR)
dest_step_position = OV8810_TOTAL_STEPS_NEAR_TO_FAR;
dest_lens_position = ov8810_step_position_table[dest_step_position];
/* Taking small damping steps */
target_dist = step_direction *
(dest_lens_position - ov8810_ctrl->curr_lens_pos);
if (target_dist == 0) {
return rc;
}
if (ov8810_use_threshold_damping &&
(step_direction < 0) &&
(target_dist >=
ov8810_step_position_table[ov8810_damping_threshold])) {
/* change to variable */
small_step = (uint16_t)(target_dist/ov8810_damping_fine_step);
ov8810_damping_time_wait = 1;
} else {
small_step = (uint16_t)(target_dist/ov8810_damping_course_step);
ov8810_damping_time_wait = 4;
}
for (next_lens_position =
ov8810_ctrl->curr_lens_pos + (step_direction * small_step);
(step_direction * next_lens_position) <=
(step_direction * dest_lens_position);
next_lens_position += (step_direction * small_step)) {
if (ov8810_af_i2c_write(next_lens_position) < 0)
return -EBUSY;
ov8810_ctrl->curr_lens_pos = next_lens_position;
if (ov8810_ctrl->curr_lens_pos != dest_lens_position) {
mdelay(ov8810_damping_time_wait);
}
}
if (ov8810_ctrl->curr_lens_pos != dest_lens_position) {
if (ov8810_af_i2c_write(dest_lens_position) < 0) {
return -EBUSY;
}
}
/* Storing the current lens Position */
ov8810_ctrl->curr_lens_pos = dest_lens_position;
ov8810_ctrl->curr_step_pos = dest_step_position;
CDBG("done\n");
return rc;
}
static int32_t ov8810_set_default_focus(uint8_t af_step)
{
int16_t position;
int32_t rc = 0;
ov8810_damping_time_wait = 4;
if (ov8810_use_default_damping) {
/* when lens is uninitialized */
if (ov8810_ctrl->curr_lens_pos == -1
|| (ov8810_focus_debug == 1)) {
position = ov8810_step_position_table[ov8810_damping_threshold];
rc = ov8810_af_i2c_write(position);
if (rc < 0) {
return rc;
}
ov8810_ctrl->curr_step_pos = ov8810_damping_threshold;
ov8810_ctrl->curr_lens_pos = position;
mdelay(ov8810_damping_time_wait);
}
rc = ov8810_move_focus(MOVE_FAR, ov8810_ctrl->curr_step_pos);
if (rc < 0)
return rc;
} else {
rc = ov8810_af_i2c_write(ov8810_step_position_table[0]);
if (rc < 0)
return rc;
ov8810_ctrl->curr_step_pos = 0;
ov8810_ctrl->curr_lens_pos = ov8810_step_position_table[0];
}
return rc;
}
static void ov8810_get_pict_fps(uint16_t fps, uint16_t *pfps)
{
/* input fps is preview fps in Q8 format */
uint32_t divider, d1, d2;
uint16_t snapshot_height, preview_height, preview_width, snapshot_width;
if (ov8810_ctrl->prev_res == QTR_SIZE) {
preview_width =
OV8810_QTR_SIZE_WIDTH + OV8810_HRZ_QTR_BLK_PIXELS ;
preview_height =
OV8810_QTR_SIZE_HEIGHT + ov8810_ver_qtr_blk_lines_array[cam_mode_sel] ;
} else {
/* full size resolution used for preview. */
preview_width =
OV8810_FULL_SIZE_WIDTH + OV8810_HRZ_FULL_BLK_PIXELS ;
preview_height =
OV8810_FULL_SIZE_HEIGHT + OV8810_VER_FULL_BLK_LINES ;
}
if (ov8810_ctrl->pict_res == QTR_SIZE) {
snapshot_width =
OV8810_QTR_SIZE_WIDTH + OV8810_HRZ_QTR_BLK_PIXELS ;
snapshot_height =
OV8810_QTR_SIZE_HEIGHT + ov8810_ver_qtr_blk_lines_array[cam_mode_sel] ;
} else {
snapshot_width =
OV8810_FULL_SIZE_WIDTH + OV8810_HRZ_FULL_BLK_PIXELS;
snapshot_height =
OV8810_FULL_SIZE_HEIGHT + OV8810_VER_FULL_BLK_LINES;
}
d1 = preview_height * 0x00000400 / snapshot_height;
d2 = preview_width * 0x00000400 / snapshot_width;
divider = (uint32_t) (d1 * d2) / 0x00000400;
*pfps = (uint16_t)(fps * divider / 0x00000400);
} /* endof ov8810_get_pict_fps */
static uint16_t ov8810_get_prev_lines_pf(void)
{
if (ov8810_ctrl->prev_res == QTR_SIZE) {
return (OV8810_QTR_SIZE_HEIGHT + ov8810_ver_qtr_blk_lines_array[cam_mode_sel]);
} else {
return (OV8810_FULL_SIZE_HEIGHT + OV8810_VER_FULL_BLK_LINES);
}
}
static uint16_t ov8810_get_prev_pixels_pl(void)
{
if (ov8810_ctrl->prev_res == QTR_SIZE) {
return (OV8810_QTR_SIZE_WIDTH + OV8810_HRZ_QTR_BLK_PIXELS);
} else {
return (OV8810_FULL_SIZE_WIDTH + OV8810_HRZ_FULL_BLK_PIXELS);
}
}
static uint16_t ov8810_get_pict_lines_pf(void)
{
if (ov8810_ctrl->pict_res == QTR_SIZE) {
return (OV8810_QTR_SIZE_HEIGHT + ov8810_ver_qtr_blk_lines_array[cam_mode_sel]);
} else {
return (OV8810_FULL_SIZE_HEIGHT + OV8810_VER_FULL_BLK_LINES);
}
}
static uint16_t ov8810_get_pict_pixels_pl(void)
{
if (ov8810_ctrl->pict_res == QTR_SIZE) {
return (OV8810_QTR_SIZE_WIDTH + OV8810_HRZ_QTR_BLK_PIXELS);
} else {
return (OV8810_FULL_SIZE_WIDTH + OV8810_HRZ_FULL_BLK_PIXELS);
}
}
static uint32_t ov8810_get_pict_max_exp_lc(void)
{
if (ov8810_ctrl->pict_res == QTR_SIZE) {
return (OV8810_QTR_SIZE_HEIGHT + ov8810_ver_qtr_blk_lines_array[cam_mode_sel]);
} else {
return (OV8810_FULL_SIZE_HEIGHT + OV8810_VER_FULL_BLK_LINES);
}
}
static int32_t ov8810_set_fps(struct fps_cfg *fps)
{
int32_t rc = 0;
ov8810_ctrl->fps_divider = fps->fps_div;
ov8810_ctrl->pict_fps_divider = fps->pict_fps_div;
ov8810_ctrl->fps = fps->f_mult;
return rc;
}
static int32_t ov8810_write_exp_gain
(uint16_t mul, uint16_t gain, uint32_t line)
{
uint16_t aec_msb;
uint16_t aec_lsb;
int32_t rc = 0;
uint32_t total_lines_per_frame;
uint32_t total_pixels_per_line;
/*uint32_t line_length_ratio = 1 * Q8;*/
/**uint8_t ov8810_offset = 2; */
uint32_t extra_line_length = 0;
uint16_t extra_line_msb = 0;
uint16_t extra_line_lsb = 0;
uint32_t phy_line = 0;
uint8_t phy_mul = MUL_GAIN_INIT_VALUE;
uint16_t phy_gain = 0;
uint32_t phy_extra_line_length = 0;
const uint16_t postpone_frames = 4;
uint16_t do_write = 1; /* assume do things */
uint16_t ori_reg_mul_gain;
uint8_t ori_reg_mul_gain_8bit;
CDBG("%s start, mul = %d gain = %d line = %d\n", __func__,
mul, gain, line);
if (ov8810_ctrl->curr_res == QTR_SIZE) {
total_lines_per_frame =
(OV8810_QTR_SIZE_HEIGHT + ov8810_ver_qtr_blk_lines_array[cam_mode_sel]);
total_pixels_per_line =
OV8810_QTR_SIZE_WIDTH + OV8810_HRZ_QTR_BLK_PIXELS;
} else {
total_lines_per_frame =
(OV8810_FULL_SIZE_HEIGHT + OV8810_VER_FULL_BLK_LINES);
total_pixels_per_line =
OV8810_FULL_SIZE_WIDTH + OV8810_HRZ_FULL_BLK_PIXELS;
}
if (line > total_lines_per_frame - 4) {
extra_line_length =
(uint32_t)(line - (total_lines_per_frame-4));
line = total_lines_per_frame - 4;
} else {
extra_line_length = (uint16_t)0;
}
phy_line = line;
phy_mul = mul;
phy_gain = gain;
phy_extra_line_length = extra_line_length;
/* postpone writing gain only apply to preview */
if (ov8810_ctrl->sensormode == SENSOR_PREVIEW_MODE) {
/* need time to wait for aec stable (prevent black preview) */
mdelay(6);
CDBG("Stella: write_cnt=%d, pre_line = %d, line = %d," \
"pre_mul = %d mul = %d," \
"pre_gain = %d gain = %d," \
"pre_extra_line_length =%d extra_line_length = %d\n",
write_cnt,
backup_line_gain[1].line, line,
backup_line_gain[1].mul, mul,
backup_line_gain[1].gain, gain,
backup_line_gain[1].extra_line_length, extra_line_length);
if (write_cnt == 0 && (
backup_line_gain[1].line != line ||
backup_line_gain[1].mul != mul ||
backup_line_gain[1].gain != gain ||
backup_line_gain[1].extra_line_length != extra_line_length)) {
backup_line_gain[1].line = line;
backup_line_gain[1].mul = mul;
backup_line_gain[1].gain = gain;
backup_line_gain[1].extra_line_length = extra_line_length;
phy_line = backup_line_gain[1].line;
phy_mul = backup_line_gain[0].mul;
phy_gain = backup_line_gain[0].gain;
phy_extra_line_length = backup_line_gain[0].extra_line_length;
write_cnt++;
} else if (write_cnt >= 1 && write_cnt < postpone_frames) {
phy_line = backup_line_gain[1].line;
phy_mul = backup_line_gain[1].mul;
phy_gain = backup_line_gain[1].gain;
phy_extra_line_length = backup_line_gain[1].extra_line_length;
CDBG("updated_BLC = %d\n", updated_BLC);
if (updated_BLC == 5) {
/*50 BLC trigger by gain 40 BLC every frame */
pr_info("### BLC to 0x50 ###\n");
#if 0
ov8810_i2c_write_b(ov8810_client->addr, 0x3071, 0x50);
#endif
}
if (updated_BLC <= 5)
updated_BLC++;
if (write_cnt > 1)
do_write = 0;
write_cnt++;
} else {
write_cnt = 0;
do_write = 0;
}
if (do_write) {
backup_line_gain[0].line = phy_line;
backup_line_gain[0].mul = phy_mul;
backup_line_gain[0].gain = phy_gain;
backup_line_gain[0].extra_line_length = phy_extra_line_length;
}
}
#if 0
pr_info("Stella: backup_line_gain[0].line = %d\n",
backup_line_gain[0].line);
pr_info("Stella: backup_line_gain[0].mul = %d\n",
backup_line_gain[0].mul);
pr_info("Stella: backup_line_gain[0].gain = %d\n",
backup_line_gain[0].gain);
pr_info("Stella: backup_line_gain[0].extra_line_length = %d\n",
backup_line_gain[0].extra_line_length);
pr_info("Stella: backup_line_gain[1].line = %d\n",
backup_line_gain[1].line);
pr_info("Stella: backup_line_gain[1].mul = %d\n",
backup_line_gain[1].mul);
pr_info("Stella: backup_line_gain[1].gain = %d\n",
backup_line_gain[1].gain);
pr_info("Stella: backup_line_gain[1].extra_line_length = %d\n",
backup_line_gain[1].extra_line_length);
pr_info("Stella: phy_line=%d\n", phy_line);
pr_info("Stella: phy_gain=%d\n", phy_gain);
pr_info("Stella: phy_extra_line_length=%d\n", phy_extra_line_length);
#endif
extra_line_msb = (uint16_t)(phy_extra_line_length & 0xFF00) >> 8;
extra_line_lsb = (uint16_t)(phy_extra_line_length & 0x00FF);
aec_msb = (uint16_t)(phy_line & 0xFF00) >> 8;
aec_lsb = (uint16_t)(phy_line & 0x00FF);
if (!do_write)
return rc;
/*Move the read function out of group update to prevent hang Weiting0331*/
rc = ov8810_i2c_read(OV8810_REG_MUL_GAIN,
&ori_reg_mul_gain, 2);
if (rc < 0) {
pr_err("read OV8810_REG_MUL_GAIN fail\n");
return rc;
}
/* since we do STREAM ON here, don't do group update for snapshot */
if (ov8810_ctrl->sensormode != SENSOR_SNAPSHOT_MODE) {
/*for group update top*/
/* weiting0414 prevent capture hang, enable 0x30b7[2] */
rc = ov8810_i2c_write_b(ov8810_client->addr, 0x30b7, 0x8c);
if (rc < 0)
return rc;
}
/* FIXME: prevent black preview by restoring 0x30bf -> 0x80 */
rc = ov8810_i2c_write_b(ov8810_client->addr, 0x30bf, 0x80);
if (rc < 0)
return rc;
rc = ov8810_i2c_write_b(ov8810_client->addr,
OV8810_AEC_MSB, (uint8_t)aec_msb);
if (rc < 0)
return rc;
rc = ov8810_i2c_write_b(ov8810_client->addr,
OV8810_AEC_LSB, (uint8_t)aec_lsb);
if (rc < 0)
return rc;
ori_reg_mul_gain_8bit =
(uint8_t)((ori_reg_mul_gain & 0xFF00) >> 8);
CDBG("%s, read OV8810_REG_MUL_GAIN ori_reg_mul_gain = %x\n",
__func__, ori_reg_mul_gain_8bit);
ori_reg_mul_gain_8bit =
(ori_reg_mul_gain_8bit & 0xFC) | (phy_mul & 0x03);
CDBG("%s, read OV8810_REG_MUL_GAIN ori_reg_mul_gain = %x\n",
__func__, ori_reg_mul_gain_8bit);
rc = ov8810_i2c_write_b(ov8810_client->addr,
OV8810_REG_MUL_GAIN, ori_reg_mul_gain_8bit);
if (rc < 0)
return rc;
rc = ov8810_i2c_write_b(ov8810_client->addr,
OV8810_GAIN, (uint8_t)phy_gain);
if (rc < 0)
return rc;
rc = ov8810_i2c_write_b(ov8810_client->addr,
REG_EXTRA_VSYNC_WIDTH_MSB, (uint8_t)extra_line_msb);
if (rc < 0)
return rc;
rc = ov8810_i2c_write_b(ov8810_client->addr,
REG_EXTRA_VSYNC_WIDTH_LSB, (uint8_t)extra_line_lsb);
if (rc < 0)
return rc;
if (ov8810_ctrl->sensormode != SENSOR_SNAPSHOT_MODE) {
/* for group update bottom */
/* weiting0414 prevent capture hang , enable 0x30b7[2] */
rc = ov8810_i2c_write_b(ov8810_client->addr, 0x30b7, 0x84);
if (rc < 0)
return rc;
/* for group update enable */
rc = ov8810_i2c_write_b(ov8810_client->addr, 0x30ff, 0xff);
if (rc < 0)
return rc;
/* weiting0414 prevent capture hang ,
retry I2C write to make sure enable */
rc = ov8810_i2c_write_b(ov8810_client->addr, 0x30ff, 0xff);
if (rc < 0)
return rc;
}
if (ov8810_ctrl->sensormode == SENSOR_RAW_SNAPSHOT_MODE) {
pr_info("sleep 500 ms for safety raw snapshot");
msleep(500);
}
/* STREAM ON for SNAPSHOT */
if (ov8810_ctrl->sensormode == SENSOR_SNAPSHOT_MODE) {
pr_info("ov8810_ctrl: STREAM ON for SNAPSHOT\n");
rc = ov8810_i2c_write_b(ov8810_client->addr,
OV8810_REG_MODE_SELECT,
OV8810_MODE_SELECT_STREAM);
if (rc < 0)
return rc;
msleep(50);
}
/*stored_line_length_ratio = line_length_ratio;*/
return rc;
} /* endof ov8810_write_exp_gain*/
/* ### this function is not called for userspace ### */
static int32_t ov8810_set_pict_exp_gain
(uint16_t mul, uint16_t gain, uint32_t line)
{
int32_t rc = 0;
rc = ov8810_write_exp_gain(mul, gain, line);
return rc;
} /* endof ov8810_set_pict_exp_gain*/
/* remove test code */
#if 0
static int32_t ov8810_test(enum ov8810_test_mode_t mo)
{
int32_t rc = 0;
if (mo == TEST_OFF) {
return rc;
}
/* Activate the Color bar test pattern */
if (mo == TEST_1) {
rc = ov8810_i2c_write_b(ov8810_client->addr,
OV8810_COLOR_BAR_ENABLE_REG, 0xa0);
if (rc < 0) {
return rc;
}
rc = ov8810_i2c_write_b(ov8810_client->addr,
0x3085, 0x20);
if (rc < 0) {
return rc;
}
rc = ov8810_i2c_write_b(ov8810_client->addr,
0x306c, 0x00);
if (rc < 0) {
return rc;
}
rc = ov8810_i2c_write_b(ov8810_client->addr,
OV8810_COLOR_BAR_PATTERN_SEL_REG, 0x02);
if (rc < 0) {
return rc;
}
}
return rc;
}
#endif
uint32_t Crc32CheckSumByte(uint8_t *pData, uint32_t uiLen, uint32_t preValue)
{
const uint32_t crc32table[256] = {
/* 0x00 */ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
/* 0x04 */ 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
/* 0x08 */ 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
/* 0x0C */ 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
/* 0x10 */ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
/* 0x14 */ 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
/* 0x18 */ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
/* 0x1C */ 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
/* 0x20 */ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
/* 0x24 */ 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
/* 0x28 */ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
/* 0x2C */ 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
/* 0x30 */ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
/* 0x34 */ 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
/* 0x38 */ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
/* 0x3C */ 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
/* 0x40 */ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
/* 0x44 */ 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
/* 0x48 */ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
/* 0x4C */ 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
/* 0x50 */ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
/* 0x54 */ 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
/* 0x58 */ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
/* 0x5C */ 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
/* 0x60 */ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
/* 0x64 */ 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
/* 0x68 */ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
/* 0x6C */ 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
/* 0x70 */ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
/* 0x74 */ 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
/* 0x78 */ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
/* 0x7C */ 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
/* 0x80 */ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
/* 0x84 */ 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
/* 0x88 */ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
/* 0x8C */ 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
/* 0x90 */ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
/* 0x94 */ 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
/* 0x98 */ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
/* 0x9C */ 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
/* 0xA0 */ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
/* 0xA4 */ 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
/* 0xA8 */ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
/* 0xAC */ 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
/* 0xB0 */ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
/* 0xB4 */ 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
/* 0xB8 */ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
/* 0xBC */ 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
/* 0xC0 */ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
/* 0xC4 */ 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
/* 0xC8 */ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
/* 0xCC */ 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
/* 0xD0 */ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
/* 0xD4 */ 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
/* 0xD8 */ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
/* 0xDC */ 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
/* 0xE0 */ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
/* 0xE4 */ 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
/* 0xE8 */ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
/* 0xEC */ 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
/* 0xF0 */ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
/* 0xF4 */ 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
/* 0xF8 */ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
/* 0xFC */ 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,};
uint32_t i, CheckSum, cvalue;
CheckSum = preValue;
for (i = 0; i < uiLen; i++) {
cvalue = *pData;
CheckSum =
(CheckSum>>8) ^
crc32table[(CheckSum & 0xFF) ^
(cvalue & 0xFF)];
pData++;
}
return CheckSum;
}
static int32_t HTC_update_ov8810_lsc_registers(void)
{
int i;
struct awb_lsc_struct_type *awb_lsc_data_ptr;
awb_lsc_data_ptr = (struct awb_lsc_struct_type *)get_cam_awb_cal();
for (i = 0; i < 8; i++) {
pr_info(KERN_INFO"[LSC calibration] read AWB table 0x%x\n",
awb_lsc_data_ptr->caBuff[i]);
}
for (i = 0; i < LSC_table_length; i++) {
pr_info("[LSC calibration] read LSC table 0x%x, 0x%x\n",
awb_lsc_data_ptr->LSC_table[i].reg_addr,
awb_lsc_data_ptr->LSC_table[i].reg_val);
}
if (awb_lsc_data_ptr->LSC_table_CRC ==
Crc32CheckSumByte(
(uint8_t *) awb_lsc_data_ptr->LSC_table,
150 * sizeof(struct reg_addr_val_pair_struct), 0) &&
awb_lsc_data_ptr->LSC_table_CRC != 0) {
pr_info("[LSC calibration]checksum pass,use calibrated LSC\n");
for (i = 0; i < LSC_table_length; i++) {
ov8810_i2c_write_b(ov8810_client->addr,
awb_lsc_data_ptr->LSC_table[i].reg_addr,
awb_lsc_data_ptr->LSC_table[i].reg_val);
}
/*enable lsc on sensor*/
ov8810_i2c_write_b(ov8810_client->addr, 0x3300, 0xff);
/*move to the last*/
ov8810_i2c_write_b(ov8810_client->addr,
OV8810_REG_MODE_SELECT, OV8810_MODE_SELECT_STREAM);
} else {/*use default LSC table*/
pr_info("[LSC calibration]checksum fail\n");
return false;
}
return true;
}
static int32_t initialize_ov8810_registers(void)
{
int32_t i, array_length;
int32_t rc = 0;
mdelay(5);
ov8810_i2c_write_b(
ov8810_client->addr,
OV8810_REG_SOFTWARE_RESET,
OV8810_SOFTWARE_RESET);
mdelay(5);
ov8810_i2c_write_b(
ov8810_client->addr,
OV8810_REG_MODE_SELECT,
OV8810_MODE_SELECT_SW_STANDBY);
mdelay(1);
array_length = sizeof(ov8810_init_settings_array) /
sizeof(ov8810_init_settings_array[0]);
/* Configure sensor for Preview mode and Snapshot mode */
for (i = 0; i < array_length; i++) {
rc = ov8810_i2c_write_b(ov8810_client->addr,
ov8810_init_settings_array[i].reg_addr,
ov8810_init_settings_array[i].reg_val);
if (rc < 0)
return rc;
}
/*use calibrated LSC table*/
if (HTC_update_ov8810_lsc_registers()) {
pr_info("[LSC calibration] use calibrated LSC table done!\n");
} else {/*use default LSC table*/
array_length =
sizeof(lsc_table_array) / sizeof(lsc_table_array[0]);
for (i = 0; i < array_length; i++) {
rc = ov8810_i2c_write_b(ov8810_client->addr,
lsc_table_array[i].reg_addr,
lsc_table_array[i].reg_val);
}
pr_info("[LSC calibration] use default LSC table done\n");
}
return rc;
} /* end of initialize_ov8810_ov8m0vc_registers. */
static int32_t ov8810_setting(int rt)
{
int32_t rc = 0;
int32_t i, array_length;
static int16_t did_snapshot;
uint16_t ori_reg_mul_gain;
uint8_t ori_reg_mul_gain_8bit;
uint16_t i2c_ret = 0;
write_cnt = 0;
pr_info("ov8810_setting rt = %d\n", rt);
if (rt == FULL_SIZE) {
ov8810_i2c_read(0x30b7, &i2c_ret, 1);
pr_info("0x30b7, i2c_ret = 0x%X\n", i2c_ret);
/*Retry writing group update bottom to ensure capture settings can be updated Weiting0331*/
while (i2c_ret != 0x84) {
/* for group update bottom */
rc = ov8810_i2c_write_b(ov8810_client->addr, 0x30b7, 0x84);
if (rc < 0)
return rc;
/* for group update enable */
rc = ov8810_i2c_write_b(ov8810_client->addr, 0x30ff, 0xff);
if (rc < 0)
return rc;
msleep(50);
ov8810_i2c_read(0x30b7, &i2c_ret, 1);
pr_info("retry 0x30b7, i2c_ret = 0x%X\n", i2c_ret);
};
}
rc = ov8810_i2c_write_b(ov8810_client->addr,
OV8810_REG_MODE_SELECT,
OV8810_MODE_SELECT_SW_STANDBY);
if (rc < 0) {
return rc;
}
ov8810_i2c_read(OV8810_REG_MODE_SELECT, &i2c_ret, 1);
pr_info("OV8810_REG_MODE_SELECT, i2c_ret = 0x%X\n", i2c_ret);
switch (rt) {
case QTR_SIZE:
array_length = sizeof(ov8810_qtr_settings_array) /
sizeof(ov8810_qtr_settings_array[0]);
/* Configure sensor for XGA preview mode */
for (i = 0; i < array_length; i++) {
rc = ov8810_i2c_write_b(ov8810_client->addr,
ov8810_qtr_settings_array[i].reg_addr,
ov8810_qtr_settings_array[i].reg_val);
if (rc < 0) {
return rc;
}
}
/* reconfigure the qtr height to adjust frame rate */
{
uint16_t fl_line = 0;
fl_line = OV8810_QTR_SIZE_HEIGHT +
ov8810_ver_qtr_blk_lines_array[cam_mode_sel];
rc = ov8810_i2c_write_b(ov8810_client->addr,
REG_FRAME_LENGTH_LINES_MSB,
(fl_line & 0xFF00) >> 8);
if (rc < 0)
return rc;
rc = ov8810_i2c_write_b(ov8810_client->addr,
REG_FRAME_LENGTH_LINES_LSB,
fl_line & 0x00FF);
if (rc < 0)
return rc;
#if 0
if (cam_mode_sel > 0) {
pr_info("andy write binning ctrl 0x00, cam_mode_sel %d\n", cam_mode_sel);
rc = ov8810_i2c_write_b(ov8810_client->addr, //weiting ori c0
REG_BINNING_CONTROL, 0x00);
if (rc < 0)
return rc;
}
#endif
}
#if 1 /* this is supposed to prevent abnormal color when restart preview */
if (!did_snapshot)
{
memset(&backup_line_gain, 0,
sizeof(struct backup_line_gain_struct));
backup_line_gain[0].line = 0x4c4;
backup_line_gain[0].mul = MUL_GAIN_INIT_VALUE;
backup_line_gain[0].gain = 8; /*0x30;*/
backup_line_gain[0].extra_line_length = 0;
}
CDBG("backup_line_gain[0].line = %d" \
"backup_line_gain[0].mul = %d" \
"backup_line_gain[0].gain = %d" \
"backup_line_gain[0].extra_line_length = %d",
backup_line_gain[0].line,
backup_line_gain[0].mul,
backup_line_gain[0].gain,
backup_line_gain[0].extra_line_length);
rc = ov8810_i2c_write_b(ov8810_client->addr,
OV8810_AEC_MSB,
(uint8_t)((backup_line_gain[0].line & 0xFF00) >> 8));
if (rc < 0)
return rc;
rc = ov8810_i2c_write_b(ov8810_client->addr,
OV8810_AEC_LSB,
(uint8_t)(backup_line_gain[0].line & 0x00FF));
if (rc < 0)
return rc;
rc = ov8810_i2c_read(OV8810_REG_MUL_GAIN, &ori_reg_mul_gain, 2);
if (rc < 0) {
pr_err("read OV8810_REG_MUL_GAIN fail\n");
return rc;
}
ori_reg_mul_gain_8bit =
(uint8_t)((ori_reg_mul_gain & 0xFF00)>>8);
CDBG("%s, read OV8810_REG_MUL_GAIN ori_reg_mul_gain = %x\n",
__func__, ori_reg_mul_gain_8bit);
ori_reg_mul_gain_8bit =
(ori_reg_mul_gain_8bit & 0xFC) |
(backup_line_gain[0].mul & 0x03);
CDBG("%s, read OV8810_REG_MUL_GAIN ori_reg_mul_gain = %x\n",
__func__, ori_reg_mul_gain_8bit);
rc = ov8810_i2c_write_b(ov8810_client->addr,
OV8810_REG_MUL_GAIN, ori_reg_mul_gain_8bit);
if (rc < 0)
return rc;
rc = ov8810_i2c_write_b(ov8810_client->addr,
OV8810_GAIN,
(uint8_t)(backup_line_gain[0].gain & 0x00FF));
if (rc < 0)
return rc;
rc = ov8810_i2c_write_b(ov8810_client->addr,
REG_EXTRA_VSYNC_WIDTH_MSB,
(uint8_t)((backup_line_gain[0].extra_line_length
& 0xFF00) >> 8));
if (rc < 0)
return rc;
rc = ov8810_i2c_write_b(ov8810_client->addr,
REG_EXTRA_VSYNC_WIDTH_LSB,
(uint8_t)(backup_line_gain[0].extra_line_length
& 0x00FF));
if (rc < 0)
return rc;
#endif
did_snapshot = 0;
ov8810_ctrl->curr_res = QTR_SIZE;
break;
case FULL_SIZE:
if (rc < 0)
return rc;
array_length = sizeof(ov8810_full_settings_array) /
sizeof(ov8810_full_settings_array[0]);
/* Configure sensor for QXGA capture mode */
for (i = 0; i < array_length; i++) {
rc = ov8810_i2c_write_b(ov8810_client->addr,
ov8810_full_settings_array[i].reg_addr,
ov8810_full_settings_array[i].reg_val);
if (rc < 0)
return rc;
}
did_snapshot = 1;
ov8810_ctrl->curr_res = FULL_SIZE;
break;
default:
rc = -EFAULT;
return rc;
}
/*disablt LSC for calibration*/
pr_info("[LSC calibration] global_mode=%d!!!!\n", global_mode);
/*take raw picture for LSC calibration*/
if (global_mode) {
/*disable sensor LSC*/
rc = ov8810_i2c_write_b(ov8810_client->addr, 0x3300, 0xef);
/*mirror off*/
rc = ov8810_i2c_write_b(ov8810_client->addr, 0x30f8, 0x00);
/*mirror off*/
rc = ov8810_i2c_write_b(ov8810_client->addr, 0x3316, 0x02);
pr_info("[LSC calibration]turn off LSC!Mirror On\n");
/*fix gain & linecount*/
/*Gain=0x9,exp=008d*/
/*so luma taget = 100 to mfg light source*/
rc = ov8810_i2c_write_b(ov8810_client->addr, 0x3000, 0x9);
/*AEC_MSB*/
rc = ov8810_i2c_write_b(ov8810_client->addr, 0x3002, 0x00);
/*AEC_LSB*/
rc = ov8810_i2c_write_b(ov8810_client->addr, 0x3003, 0x8d);
pr_info("[LSC calibration]fix gain & linecount\n");
global_mode = 0;
}
if (ov8810_ctrl->sensormode != SENSOR_SNAPSHOT_MODE) {
msleep(50);
rc = ov8810_i2c_write_b(ov8810_client->addr,
OV8810_REG_MODE_SELECT,
OV8810_MODE_SELECT_STREAM);
if (rc < 0)
return rc;
updated_BLC = 0;
}
/* remove test code
rc = ov8810_test(ov8810_ctrl->set_test);
if (rc < 0)
return rc;
*/
return rc;
} /*endof ov8810_setting*/
static int32_t ov8810_video_config(int mode)
{
int32_t rc = 0;
static int pre_sel = 0;
int cur_sel = (cam_mode_sel > 1)?1:0;
ov8810_ctrl->sensormode = mode;
pr_info("%s cam_mode_sel %d cur_sel %d \n", __func__, cam_mode_sel, cur_sel);
if (ov8810_ctrl->curr_res != ov8810_ctrl->prev_res
|| pre_sel != cur_sel
) {
rc = ov8810_setting(ov8810_ctrl->prev_res);
if (rc < 0)
return rc;
} else {
ov8810_ctrl->curr_res = ov8810_ctrl->prev_res;
}
pre_sel = cur_sel;
ov8810_ctrl->sensormode = mode;
return rc;
} /*end of ov354_video_config*/
static int32_t ov8810_snapshot_config(int mode)
{
int32_t rc = 0;
ov8810_ctrl->sensormode = mode;
if (ov8810_ctrl->curr_res != ov8810_ctrl->pict_res) {
rc = ov8810_setting(ov8810_ctrl->pict_res);
if (rc < 0)
return rc;
} else {
ov8810_ctrl->curr_res = ov8810_ctrl->pict_res;
}
ov8810_ctrl->sensormode = mode;
return rc;
} /*end of ov8810_snapshot_config*/
static int32_t ov8810_raw_snapshot_config(int mode)
{
int32_t rc = 0;
ov8810_ctrl->sensormode = mode;
if (ov8810_ctrl->curr_res != ov8810_ctrl->pict_res) {
rc = ov8810_setting(ov8810_ctrl->pict_res);
if (rc < 0)
return rc;
} else {
ov8810_ctrl->curr_res = ov8810_ctrl->pict_res;
} /* Update sensor resolution */
ov8810_ctrl->sensormode = mode;
return rc;
} /*end of ov8810_raw_snapshot_config*/
static int32_t ov8810_set_sensor_mode(int mode,
int res)
{
int32_t rc = 0;
struct msm_camera_sensor_info *sinfo = ov8810_pdev->dev.platform_data;
switch (mode) {
case SENSOR_PREVIEW_MODE:
rc = ov8810_video_config(mode);
break;
case SENSOR_SNAPSHOT_MODE:
pr_info("KPI PA: start sensor snapshot config: %d\n", __LINE__);
sinfo->kpi_sensor_start = ktime_to_ns(ktime_get());
rc = ov8810_snapshot_config(mode);
break;
case SENSOR_RAW_SNAPSHOT_MODE:
/*global_mode = 1; //20100330 vincent lsc calibration*/
pr_info("KPI PA: start sensor snapshot config: %d\n", __LINE__);
sinfo->kpi_sensor_start = ktime_to_ns(ktime_get());
rc = ov8810_raw_snapshot_config(mode);
break;
default:
rc = -EINVAL;
break;
}
return rc;
}
static int32_t ov8810_power_down(void)
{
return 0;
}
static int ov8810_probe_read_id(const struct msm_camera_sensor_info *data)
{
int32_t rc = 0;
uint16_t chipidh = 0; /*, chipidl;*/
uint16_t def_chipid = 0;
msleep(20);
pr_info("%s, ov8810_probe_init_sensor 1\n", __func__);
/* 3. Read sensor Model ID: */
if (ov8810_i2c_read(OV8810_PIDH_REG, &chipidh, 2) < 0) {
rc = -1;
pr_err("read sensor id fail\n");
}
pr_info("ov8810 model_id + ver = 0x%x\n", chipidh);
/* 4. Compare sensor ID to OV8810 ID: */
def_chipid = (((OV8810_PID << 8) & 0xFF00) + (OV8810_VER & 0x00FF));
pr_info("%s, Expected id=0x%x\n", __func__, def_chipid);
if (chipidh < def_chipid) {
rc = -ENODEV;
pr_err("read sensor id incorrect\n");
}
pr_info("%s, vreg_get vreg_af_actuator\n", __func__);
vreg_af_actuator = vreg_get(0, "gp5");
if (IS_ERR(vreg_af_actuator))
return PTR_ERR(vreg_af_actuator);
pr_info(" ov8810_probe_init_sensor finishes\n");
return rc;
}
static int ov8810_sensor_open_init(struct msm_camera_sensor_info *data)
{
int i;
int32_t rc = 0;
/*stella0122*/
uint16_t ov8810_nl_region_boundary = 5; /*3;*/
uint16_t ov8810_nl_region_code_per_step = 35; /*101;*/
uint16_t ov8810_l_region_code_per_step = 20; /*18;*/
int timeout;
pr_info("Calling ov8810_sensor_open_init\n");
down(&ov8810_sem);
if (data == NULL) {
pr_info("data is a NULL pointer\n");
return -EINVAL;
}
/*check whether resume done*/
timeout = wait_event_interruptible_timeout(
ov8810_event.event_wait,
ov8810_event.waked_up,
30*HZ);
pr_info("wait event : %d timeout:%d\n", ov8810_event.waked_up, timeout);
if (timeout == 0) {
up(&ov8810_sem);
return rc;
}
msm_camio_probe_on(ov8810_pdev);
ov8810_ctrl = kzalloc(sizeof(struct ov8810_ctrl), GFP_KERNEL);
if (!ov8810_ctrl) {
pr_err("ov8810_init failed!\n");
rc = -ENOMEM;
goto init_done;
}
ov8810_ctrl->curr_lens_pos = -1;
ov8810_ctrl->fps_divider = 1 * 0x00000400;
ov8810_ctrl->pict_fps_divider = 1 * 0x00000400;
ov8810_ctrl->set_test = TEST_OFF;
ov8810_ctrl->prev_res = QTR_SIZE;
ov8810_ctrl->pict_res = FULL_SIZE;
ov8810_ctrl->curr_res = INVALID_SIZE;
if (data)
ov8810_ctrl->sensordata = data;
/*switch pclk and mclk between main cam and 2nd cam*/
/*only for supersonic*/
pr_info("doing clk switch (ov8810)\n");
if(data->camera_clk_switch != NULL)
data->camera_clk_switch();
/* enable mclk first */
msm_camio_clk_rate_set(OV8810_DEFAULT_CLOCK_RATE);
msleep(20);
msm_camio_camif_pad_reg_reset();
msleep(20);
/*PWD and RST config*/
pr_info("%s, GPIO(%d) sensor_pwd 0\n", __func__, data->sensor_pwd);
rc = gpio_request(data->sensor_pwd, "ov8810");
if (!rc)
gpio_direction_output(data->sensor_pwd, 0);
else
pr_err("GPIO (%d) request faile\n", data->sensor_pwd);
gpio_free(data->sensor_pwd);
mdelay(5);
rc = gpio_request(data->sensor_reset, "ov8810");
if (!rc)
gpio_direction_output(data->sensor_reset, 1);
else
pr_err("GPIO (%d) request faile\n", data->sensor_reset);
gpio_free(data->sensor_reset);
/*read sensor id*/
rc = ov8810_probe_read_id(data);
ov8810_ctrl->sensormode = SENSOR_PREVIEW_MODE ;
pr_info("%s, initialize_ov8810_registers: %d\n", __func__, __LINE__);
if (rc < 0)
goto init_fail;
#if 0 /*move to probe up sensor*/
/* Initialize Sensor registers */
rc = initialize_ov8810_registers();
if (rc < 0)
return rc;
pr_info("%s, ov8810_setting preview %d\n", __func__, __LINE__);
if (ov8810_ctrl->curr_res != ov8810_ctrl->prev_res) {
rc = ov8810_setting(ov8810_ctrl->prev_res);
if (rc < 0)
goto init_fail;
} else {
ov8810_ctrl->curr_res = ov8810_ctrl->prev_res;
}
#endif
pr_info("%s, enable AF actuator %d\n", __func__, __LINE__);
/* enable AF actuator */
rc = vreg_enable(vreg_af_actuator);
if (!rc) {
rc = vreg_set_level(vreg_af_actuator, 2800); /*2v8*/
if (rc)
{
pr_err("vreg_af_actuator vreg_set_level 2v8 failed!\n");
goto init_fail;
}
}
else {
pr_err("vreg_af_actuator vreg_enable failed!\n");
goto init_fail;
}
msleep(20);
pr_info("%s, set step_position_table %d\n", __func__, __LINE__);
ov8810_ctrl->fps = 30*Q8;
step_position_table[0] = 0;
for (i = 1; i <= OV8810_TOTAL_STEPS_NEAR_TO_FAR; i++) {
if (i <= ov8810_nl_region_boundary) {
ov8810_step_position_table[i] =
ov8810_step_position_table[i-1] +
ov8810_nl_region_code_per_step;
} else {
ov8810_step_position_table[i] =
ov8810_step_position_table[i-1] +
ov8810_l_region_code_per_step;
}
}
/* generate test pattern */
pr_info("%s, generate test pattern, %d, rc=%d\n",
__func__, __LINE__, rc);
if (rc < 0)
goto init_fail;
else
goto init_done;
/* reset the driver state */
init_fail:
pr_err("%s: init_fail\n", __func__);
vreg_disable(vreg_af_actuator);
if (ov8810_ctrl) {
kfree(ov8810_ctrl);
ov8810_ctrl = NULL;
}
init_done:
up(&ov8810_sem);
pr_info("%s: init_done\n", __func__);
return rc;
} /*endof ov8810_sensor_open_init*/
static int ov8810_init_client(struct i2c_client *client)
{
/* Initialize the MSM_CAMI2C Chip */
init_waitqueue_head(&ov8810_wait_queue);
return 0;
}
static const struct i2c_device_id ov8810_i2c_id[] = {
{ "ov8810", 0},
{ }
};
static int ov8810_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int rc = 0;
pr_info("ov8810_probe called!\n");
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
pr_err("i2c_check_functionality failed\n");
goto probe_failure;
}
ov8810_sensorw = kzalloc(sizeof(struct ov8810_work), GFP_KERNEL);
if (!ov8810_sensorw) {
pr_err("kzalloc failed.\n");
rc = -ENOMEM;
goto probe_failure;
}
i2c_set_clientdata(client, ov8810_sensorw);
ov8810_init_client(client);
ov8810_client = client;
msleep(50);
pr_info("ov8810_probe successed! rc = %d\n", rc);
return 0;
probe_failure:
pr_err("ov8810_probe failed! rc = %d\n", rc);
return rc;
}
static int ov8810_probe_init_done(const struct msm_camera_sensor_info *data)
{
gpio_request(data->sensor_pwd, "ov8810");
gpio_direction_output(data->sensor_pwd, 1);
gpio_free(data->sensor_pwd);
mdelay(1);
return 0;
}
static int ov8810_suspend(struct platform_device *pdev, pm_message_t state)
{
int rc;
struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
if (!sinfo->need_suspend)
return 0;
ov8810_event.waked_up = 0;
pr_info("ov8810: camera suspend\n");
pr_info("%s, vreg_af_actuator vreg_disable\n", __func__);
vreg_disable(vreg_af_actuator);
rc = gpio_request(sinfo->sensor_reset, "ov8810");
if (!rc)
gpio_direction_output(sinfo->sensor_reset, 0);
else
pr_info("ov8810: request GPIO(sensor_reset) :%d faile\n",
sinfo->sensor_reset);
gpio_free(sinfo->sensor_reset);
msleep(10);
rc = gpio_request(sinfo->sensor_pwd, "ov8810");
if (!rc)
gpio_direction_output(sinfo->sensor_pwd, 0);
else
pr_info("ov8810: request GPIO(sensor_reset) :%d faile\n",
sinfo->sensor_pwd);
gpio_free(sinfo->sensor_pwd);
pr_info("ov8810:suspend done\n");
return rc;
}
static void ov8810_resume(struct early_suspend *handler)
{
int rc = 0;
struct msm_camera_sensor_info *sinfo = ov8810_pdev->dev.platform_data;
pr_info("ov8810_resume\n");
/*check whether need resume*/
if (!sinfo->need_suspend)
return;
/*check whether already suspend*/
if (ov8810_event.waked_up == 1) {
pr_info("Ov8810: No nesesary to do Resume\n");
return;
}
mdelay(5);
/*power down setup*/
pr_info("%s, sensor_pwd 0\n", __func__);
rc = gpio_request(sinfo->sensor_pwd, "ov8810");
if (!rc)
gpio_direction_output(sinfo->sensor_pwd, 0);
else
pr_err("GPIO (%d) request faile\n", sinfo->sensor_pwd);
gpio_free(sinfo->sensor_pwd);
mdelay(5);
/*reset setup */
rc = gpio_request(sinfo->sensor_reset, "ov8810");
if (!rc)
gpio_direction_output(sinfo->sensor_reset, 1);
else
pr_err("GPIO (%d) request faile\n", sinfo->sensor_reset);
gpio_free(sinfo->sensor_reset);
/*init msm,clk ,GPIO,enable*/
pr_info("%s, msm_camio_probe_on\n", __func__);
msm_camio_probe_on(ov8810_pdev);
msm_camio_clk_enable(CAMIO_MDC_CLK);
/*set MCLK*/
pr_info("%s, msm_camio_clk_rate_set = %d\n",
__func__, OV8810_DEFAULT_CLOCK_RATE);
msm_camio_clk_rate_set(OV8810_DEFAULT_CLOCK_RATE);
msleep(100);
/*read sensor id*/
rc = ov8810_probe_read_id(sinfo);
if (rc < 0)
pr_err("OV8810 resume faile :can not read sensor ID\n");
/* Initialize Sensor registers */
rc = initialize_ov8810_registers();
if (rc < 0)
return;
msleep(20);
/*resume done*/
ov8810_probe_init_done(sinfo);
/*turn off MCLK*/
msm_camio_probe_off(ov8810_pdev);
msm_camio_clk_disable(CAMIO_MDC_CLK);
ov8810_event.waked_up = 1;
pr_info("ov8810:resume done\n");
wake_up(&ov8810_event.event_wait);
return;
}
static int __exit ov8810_i2c_remove(struct i2c_client *client)
{
struct ov8810_work_t *sensorw = i2c_get_clientdata(client);
free_irq(client->irq, sensorw);
deinit_suspend();
ov8810_client = NULL;
kfree(sensorw);
return 0;
}
static struct i2c_driver ov8810_i2c_driver = {
.id_table = ov8810_i2c_id,
.probe = ov8810_i2c_probe,
.remove = __exit_p(ov8810_i2c_remove),
.driver = {
.name = "ov8810",
},
};
static struct early_suspend early_suspend_ov8810 = {
.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN+1,
.resume = ov8810_resume,
.suspend = NULL,
};
static const char *Ov8810Vendor = "OmniVision";
static const char *Ov8810NAME = "ov8810";
static const char *Ov8810Size = "8M";
static ssize_t sensor_vendor_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
ssize_t ret = 0;
sprintf(buf, "%s %s %s\n", Ov8810Vendor, Ov8810NAME, Ov8810Size);
ret = strlen(buf) + 1;
return ret;
}
DEFINE_MUTEX(cam_mode_lock);
static ssize_t sensor_read_cam_mode(struct device *dev,
struct device_attribute *attr, char *buf)
{
ssize_t length;
mutex_lock(&cam_mode_lock);
length = sprintf(buf, "%d\n", cam_mode_sel);
mutex_unlock(&cam_mode_lock);
return length;
}
static ssize_t sensor_set_cam_mode(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
uint32_t tmp = 0;
mutex_lock(&cam_mode_lock);
tmp = buf[0] - 0x30; /* only get the first char */
cam_mode_sel = tmp;
mutex_unlock(&cam_mode_lock);
return count;
}
static ssize_t sensor_read_node(struct device *dev,
struct device_attribute *attr, char *buf)
{
ssize_t length;
length = sprintf(buf, "%d\n", sensor_probe_node);
return length;
}
static DEVICE_ATTR(sensor, 0444, sensor_vendor_show, NULL);
static DEVICE_ATTR(cam_mode, 0644, sensor_read_cam_mode, sensor_set_cam_mode);
static DEVICE_ATTR(node, 0444, sensor_read_node, NULL);
static struct kobject *android_ov8810;
static int ov8810_sysfs_init(void)
{
int ret = 0;
pr_info("ov8810:kobject creat and add\n");
android_ov8810 = kobject_create_and_add("android_camera", NULL);
if (android_ov8810 == NULL) {
pr_info("ov8810_sysfs_init: subsystem_register failed\n");
ret = -ENOMEM;
return ret ;
}
pr_info("Ov8810:sysfs_create_file\n");
ret = sysfs_create_file(android_ov8810, &dev_attr_sensor.attr);
if (ret) {
pr_info("ov8810_sysfs_init: sysfs_create_file failed\n");
ret = -EFAULT;
goto error;
}
ret = sysfs_create_file(android_ov8810, &dev_attr_cam_mode.attr);
if (ret) {
pr_info("ov8810_sysfs_init: dev_attr_cam_mode failed\n");
ret = -EFAULT;
goto error;
}
ret = sysfs_create_file(android_ov8810, &dev_attr_node.attr);
if (ret) {
pr_info("ov8810_sysfs_init: dev_attr_node failed\n");
ret = -EFAULT;
goto error;
}
return ret;
error:
kobject_del(android_ov8810);
return ret;
}
int ov8810_sensor_config(void __user *argp)
{
struct sensor_cfg_data cdata;
long rc = 0;
if (copy_from_user(&cdata,
(void *)argp,
sizeof(struct sensor_cfg_data)))
return -EFAULT;
down(&ov8810_sem);
CDBG("ov8810_sensor_config: cfgtype = %d\n",
cdata.cfgtype);
switch (cdata.cfgtype) {
case CFG_GET_PICT_FPS:
ov8810_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 =
ov8810_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 =
ov8810_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 =
ov8810_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 =
ov8810_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 =
ov8810_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 = ov8810_set_fps(&(cdata.cfg.fps));
break;
case CFG_SET_EXP_GAIN:
rc =
ov8810_write_exp_gain(
cdata.cfg.exp_gain.mul,
cdata.cfg.exp_gain.gain,
cdata.cfg.exp_gain.line);
break;
case CFG_SET_PICT_EXP_GAIN:
rc =
ov8810_set_pict_exp_gain(
cdata.cfg.exp_gain.mul,
cdata.cfg.exp_gain.gain,
cdata.cfg.exp_gain.line);
break;
case CFG_SET_MODE:
rc = ov8810_set_sensor_mode(cdata.mode,
cdata.rs);
break;
case CFG_PWR_DOWN:
rc = ov8810_power_down();
break;
case CFG_MOVE_FOCUS:
rc =
ov8810_move_focus(
cdata.cfg.focus.dir,
cdata.cfg.focus.steps);
break;
case CFG_SET_DEFAULT_FOCUS:
rc =
ov8810_set_default_focus(
cdata.cfg.focus.steps);
break;
case CFG_SET_EFFECT:
rc = ov8810_set_default_focus(
cdata.cfg.effect);
break;
case CFG_I2C_IOCTL_R_OTP:{
rc = ov8810_i2c_read_fuseid(&cdata);
if (copy_to_user
(argp, &cdata, sizeof(struct sensor_cfg_data))
)
rc = -EFAULT;
}
break;
case CFG_SET_OV_LSC:
rc = ov8810_update_lsc_table(&cdata);
break;
/*20100330 vincent for lsc calibration*/
case CFG_SET_OV_LSC_RAW_CAPTURE:
rc = ov8810_LSC_calibration_set_rawflag(&cdata);
break;
default:
rc = -EFAULT;
break;
}
prevent_suspend();
up(&ov8810_sem);
return rc;
}
static int ov8810_sensor_release(void)
{
int rc = -EBADF;
down(&ov8810_sem);
msleep(35);
gpio_request(ov8810_ctrl->sensordata->sensor_pwd, "ov8810");
gpio_direction_output(ov8810_ctrl->sensordata->sensor_pwd, 1);
gpio_free(ov8810_ctrl->sensordata->sensor_pwd);
pr_info("vreg_af_actuator vreg_disable\n");
vreg_disable(vreg_af_actuator);
msleep(20);
pr_info("%s, %d\n", __func__, __LINE__);
msm_camio_probe_off(ov8810_pdev);
if (ov8810_ctrl) {
kfree(ov8810_ctrl);
ov8810_ctrl = NULL;
}
allow_suspend();
pr_info("ov8810_release completed\n");
up(&ov8810_sem);
return rc;
}
static int ov8810_sensor_probe(struct msm_camera_sensor_info *info,
struct msm_sensor_ctrl *s)
{
int rc = 0;
rc = i2c_add_driver(&ov8810_i2c_driver);
if (rc < 0 || ov8810_client == NULL) {
rc = -ENOTSUPP;
goto probe_fail;
}
pr_info("ov8810 s->node %d\n", s->node);
sensor_probe_node = s->node;
/*switch pclk and mclk between main cam and 2nd cam*/
/*only for supersonic*/
pr_info("Ov8810: doing clk switch (ov8810)\n");
if(info->camera_clk_switch != NULL)
info->camera_clk_switch();
mdelay(5);
/*power down setup*/
rc = gpio_request(info->sensor_pwd, "ov8810");
if (!rc)
gpio_direction_output(info->sensor_pwd, 0);
else
pr_err("GPIO (%d) request faile\n", info->sensor_pwd);
gpio_free(info->sensor_pwd);
mdelay(5);
/*reset setup */
rc = gpio_request(info->sensor_reset, "ov8810");
if (!rc)
gpio_direction_output(info->sensor_reset, 1);
else
pr_err("GPIO (%d) request faile\n", info->sensor_reset);
gpio_free(info->sensor_reset);
/*set MCLK*/
pr_info("%s, msm_camio_clk_rate_set %d\n",
__func__, OV8810_DEFAULT_CLOCK_RATE);
msm_camio_clk_rate_set(OV8810_DEFAULT_CLOCK_RATE);
msleep(100);
/*read sensor id*/
rc = ov8810_probe_read_id(info);
if (rc < 0)
goto probe_fail;
/* Initialize Sensor registers */
rc = initialize_ov8810_registers();
if (rc < 0)
return rc;
init_suspend();
s->s_init = ov8810_sensor_open_init;
s->s_release = ov8810_sensor_release;
s->s_config = ov8810_sensor_config;
msleep(20);
ov8810_probe_init_done(info);
/*register late resuem*/
register_early_suspend(&early_suspend_ov8810);
/*init wait event*/
init_waitqueue_head(&ov8810_event.event_wait);
/*init waked_up value*/
ov8810_event.waked_up = 1;
/*write sysfs*/
ov8810_sysfs_init();
pr_info("%s: ov8810_probe_init_done %d\n", __func__, __LINE__);
goto probe_done;
probe_fail:
pr_err("SENSOR PROBE FAILS!\n");
probe_done:
return rc;
}
static int ov8810_vreg_enable(struct platform_device *pdev)
{
struct msm_camera_sensor_info *sdata = pdev->dev.platform_data;
int rc;
pr_info("%s camera vreg on\n", __func__);
if (sdata->camera_power_on == NULL) {
pr_err("sensor platform_data didnt register\n");
return -EIO;
}
rc = sdata->camera_power_on();
return rc;
}
static int ov8810_vreg_disable(struct platform_device *pdev)
{
struct msm_camera_sensor_info *sdata = pdev->dev.platform_data;
int rc;
printk(KERN_INFO "%s camera vreg off\n", __func__);
if (sdata->camera_power_off == NULL) {
pr_err("sensor platform_data didnt register\n");
return -EIO;
}
rc = sdata->camera_power_off();
return rc;
}
static int __ov8810_probe(struct platform_device *pdev)
{
int rc;
printk("__ov8810_probe\n");
ov8810_pdev = pdev;
rc = ov8810_vreg_enable(pdev);
if (rc < 0)
pr_err("__ov8810_probe fail sensor power on error\n");
return msm_camera_drv_start(pdev, ov8810_sensor_probe);
}
static struct platform_driver msm_camera_driver = {
.probe = __ov8810_probe,
.driver = {
.name = "msm_camera_ov8810",
.owner = THIS_MODULE,
},
.suspend = ov8810_suspend,
};
static int __init ov8810_init(void)
{
return platform_driver_register(&msm_camera_driver);
}
module_init(ov8810_init);