2010-08-27 11:19:57 +02:00

1127 lines
29 KiB
C

/* Copyright (c) 2009, Code Aurora Forum. 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.
*
* 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.
*
*/
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/i2c.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <media/msm_camera.h>
#include <mach/gpio.h>
#include "ov9665.h"
/* OV9665 Registers and their values */
/* Sensor Core Registers */
#define REG_OV9665_MODEL_ID_H 0x0A
#define REG_OV9665_MODEL_ID_L 0x0B
#define OV9665_MODEL_ID 0x9663
/* SOC Registers Page 1 */
#define REG_OV9665_SENSOR_RESET 0x301A
#define REG_OV9665_STANDBY_CONTROL 0x3202
#define REG_OV9665_MCU_BOOT 0x3386
struct ov9665_work {
struct work_struct work;
};
static struct ov9665_work *ov9665_sensorw;
static struct i2c_client *ov9665_client;
struct ov9665_ctrl {
const struct msm_camera_sensor_info *sensordata;
};
static struct ov9665_ctrl *ov9665_ctrl;
static int op_mode;
static DECLARE_WAIT_QUEUE_HEAD(ov9665_wait_queue);
DECLARE_MUTEX(ov9665_sem);
static int sensor_probe_node = 0;
#define MAX_I2C_RETRIES 20
static int i2c_transfer_retry(struct i2c_adapter *adap,
struct i2c_msg *msgs,
int len)
{
int i2c_retry = 0;
int ns; /* number sent */
while (i2c_retry++ < MAX_I2C_RETRIES) {
ns = i2c_transfer(adap, msgs, len);
if (ns == len)
break;
pr_err("%s: try %d/%d: i2c_transfer sent: %d, len %d\n",
__func__,
i2c_retry, MAX_I2C_RETRIES, ns, len);
msleep(10);
}
return ns == len ? 0 : -EIO;
}
static int ov9665_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_retry(ov9665_client->adapter, msg, 1) < 0) {
pr_info("ov9665_i2c_txdata failed\n");
return -EIO;
}
return 0;
}
static int ov9665_i2c_write(unsigned short saddr,
unsigned char waddr, unsigned char wdata,
enum ov9665_width width)
{
int rc = -EIO;
unsigned char buf[4];
memset(buf, 0, sizeof(buf));
switch (width) {
case WORD_LEN:{
buf[0] = (waddr & 0xFF00) >> 8;
buf[1] = (waddr & 0x00FF);
buf[2] = (wdata & 0xFF00) >> 8;
buf[3] = (wdata & 0x00FF);
rc = ov9665_i2c_txdata(saddr, buf, 4);
}
break;
case BYTE_LEN:{
buf[0] = waddr;
buf[1] = wdata;
rc = ov9665_i2c_txdata(saddr, buf, 2);
}
break;
default:
break;
}
if (rc < 0)
pr_info("i2c_write failed, addr = 0x%x, val = 0x%x!\n",
waddr, wdata);
return rc;
}
static int ov9665_i2c_write_table(struct ov9665_i2c_reg_conf const
*reg_conf_tbl, int num_of_items_in_table)
{
int i;
int rc = -EIO;
for (i = 0; i < num_of_items_in_table; i++) {
rc = ov9665_i2c_write(ov9665_client->addr,
reg_conf_tbl->waddr, reg_conf_tbl->wdata,
reg_conf_tbl->width);
if (rc < 0)
break;
if (reg_conf_tbl->mdelay_time != 0)
mdelay(reg_conf_tbl->mdelay_time);
reg_conf_tbl++;
}
return rc;
}
static int ov9665_i2c_rxdata(unsigned short saddr,
unsigned char *rxdata, int length)
{
struct i2c_msg msgs[] = {
{
.addr = saddr,
.flags = 0,
.len = 1,
.buf = rxdata,
},
{
.addr = saddr,
.flags = I2C_M_RD,
.len = length,
.buf = rxdata,
},
};
if (i2c_transfer_retry(ov9665_client->adapter, msgs, 2) < 0) {
pr_info("ov9665_i2c_rxdata failed!\n");
return -EIO;
}
return 0;
}
static int ov9665_i2c_read(unsigned short saddr,
unsigned short raddr, unsigned char *rdata)
{
int rc = 0;
unsigned char buf[1];
if (!rdata)
return -EIO;
memset(buf, 0, sizeof(buf));
buf[0] = raddr;
rc = ov9665_i2c_rxdata(saddr, buf,1);
if (rc < 0)
return rc;
*rdata = buf[0];
if (rc < 0)
pr_info("ov9665_i2c_read failed!\n");
return rc;
}
static int ov9665_i2c_write_mask(
unsigned char addr,unsigned char Data, unsigned char Mask)
{
int rc = 0;
unsigned char temp;
rc = ov9665_i2c_read(ov9665_client->addr, addr, &temp);
if(rc < 0){
pr_err("ov9665 error : read i2c error\n");
return rc;
}
temp = (temp&(~Mask))|Data;
rc = ov9665_i2c_write(ov9665_client->addr, addr, temp, BYTE_LEN);
if(rc < 0){
pr_err("ov9665 error : write i2c error\n");
return rc;
}
return rc;
}
static int ov9665_pwd(const struct msm_camera_sensor_info *info){
int rc=0;
rc = gpio_request(info->sensor_pwd, "ov9665");
if (!rc)
gpio_direction_output(info->sensor_pwd, 0);
else
pr_err("GPIO(%d) request faile",info->sensor_pwd);
gpio_free(info->sensor_pwd);
return rc;
}
static int ov9665_reset(const struct msm_camera_sensor_info *dev)
{
int rc = 0;
rc = gpio_request(dev->sensor_reset, "ov9665");
if (!rc)
rc = gpio_direction_output(dev->sensor_reset, 1);
else
pr_err("GPIO(%d) request faile",dev->sensor_reset);
gpio_free(dev->sensor_reset);
return rc;
}
static int ov9665_reg_init(void)
{
int rc = 0;
rc = ov9665_i2c_write_table(&ov9665_regs.register_init[0],
ov9665_regs.register_init_size);
return rc;
}
static int ov9665_init_done(const struct msm_camera_sensor_info *info)
{
int rc = 0;
rc = gpio_request(info->sensor_pwd, "ov9665");
if (!rc)
gpio_direction_output(info->sensor_pwd, 1);
else
pr_err("GPIO(%d) request faile",info->sensor_pwd);
gpio_free(info->sensor_pwd);
return rc;
}
static int ov9665_set_sensor_mode(int mode)
{
unsigned char shading, gain;
switch (mode) {
case SENSOR_PREVIEW_MODE:
op_mode = SENSOR_PREVIEW_MODE;
pr_info("ov9665:sensor set mode: preview\n");
ov9665_i2c_write(ov9665_client->addr, 0x63, 0x00, BYTE_LEN);
/*Windowing*/
ov9665_i2c_write(ov9665_client->addr, 0x12, 0x40, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0x4d, 0x09, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0x17, 0x0c, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0x18, 0x5d, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0x19, 0x02, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0x1a, 0x3f, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0x03, 0x83, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0x32, 0xad, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0x2b, 0x00, BYTE_LEN);
/*scaling*/
ov9665_i2c_write(ov9665_client->addr, 0x64, 0xa4, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xab, 0xe7, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xb9, 0x50, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xba, 0x3c, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xbb, 0x50, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xbc, 0x3c, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0x85, 0xe7, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0x0d, 0x92, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0x0d, 0x90, BYTE_LEN);
/*enable 3A*/
ov9665_i2c_write(ov9665_client->addr, 0x13, 0xe7, BYTE_LEN);
/*VGA 30fps*/
ov9665_i2c_write(ov9665_client->addr, 0x11, 0x80, BYTE_LEN);
//ov9665_i2c_write(ov9665_client->addr, 0x09, 0x01, BYTE_LEN);
mdelay(400);/*skip 2 break frame */
break;
case SENSOR_SNAPSHOT_MODE:
pr_info("ov9665:sensor set mode: snapshot\n");
op_mode = SENSOR_SNAPSHOT_MODE;
/*disable 3A*/
ov9665_i2c_write(ov9665_client->addr, 0x13, 0xe0, BYTE_LEN);
/*SXGA 7.5fps*/
ov9665_i2c_write(ov9665_client->addr, 0x11, 0x81, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0x63, 0x01, BYTE_LEN);
/*Windowing*/
ov9665_i2c_write(ov9665_client->addr, 0x12, 0x00, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0x4d, 0x11, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0x17, 0x0c, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0x18, 0x5d, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0x19, 0x01, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0x1a, 0x82, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0x03, 0x83, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0x32, 0x24, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0x2b, 0x00, BYTE_LEN);
/*scaling*/
ov9665_i2c_write(ov9665_client->addr, 0x64, 0x24, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xab, 0xe7, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xb9, 0xa0, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xba, 0x80, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xbb, 0xa0, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xbc, 0x80, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0x85, 0xe7, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0x0d, 0x82, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0x0d, 0x80, BYTE_LEN);
mdelay(400); /*wait for AE stable*/
break;
case SENSOR_GET_EXP:
ov9665_i2c_read(ov9665_client->addr, 0x83, &shading);
ov9665_i2c_read(ov9665_client->addr, 0x00, &gain);
if (gain >= 0x36) //5.5xgain
ov9665_i2c_write
(ov9665_client->addr, 0x83, 0x06, BYTE_LEN);
else if (gain < 0x34) //5x gain
ov9665_i2c_write
(ov9665_client->addr, 0x83, 0x07, BYTE_LEN);
break;
default:
return -EINVAL;
}
return 0;
}
static int ov9665_set_effect(int effect)
{
if (op_mode == SENSOR_SNAPSHOT_MODE)
return 0;
switch (effect) {
case CAMERA_EFFECT_OFF:
#if 1/*color matrix*/
ov9665_i2c_write(ov9665_client->addr, 0xbd, 0x04, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xbe, 0x1f, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xbf, 0x03, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xc0, 0x0d, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xc1, 0x24, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xc2, 0x30, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xc3, 0x34, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xc4, 0x34, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xc5, 0x01, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xc6, 0x9c, BYTE_LEN);
#endif
#if 0/*control by SDE*/
ov9665_i2c_write(ov9665_client->addr, 0xc7, 0x80, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xc8, 0x00, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xcd, 0x80, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xce, 0x80, BYTE_LEN);
#endif
break;
case CAMERA_EFFECT_MONO:
#if 1/*color matrix*/
ov9665_i2c_write(ov9665_client->addr, 0xbd, 0x09, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xbe, 0x12, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xbf, 0x03, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xc0, 0x00, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xc1, 0x00, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xc2, 0x00, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xc3, 0x00, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xc4, 0x00, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xc5, 0x00, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xc6, 0x00, BYTE_LEN);
#endif
#if 0/*control by SDE*/
ov9665_i2c_write_mask(0xc7, 0x10, 0x10);
ov9665_i2c_write_mask(0xc8, 0x18, 0x18);
ov9665_i2c_write(ov9665_client->addr, 0xCD, 0x80, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xCE, 0x80, BYTE_LEN);
#endif
break;
case CAMERA_EFFECT_NEGATIVE:
#if 0/*control by SDE*/
ov9665_i2c_write_mask(0xc7, 0x10, 0x10);
ov9665_i2c_write_mask(0xc8, 0x40, 0x58);
/*ov9665_i2c_write(ov9665_client->addr, 0xC7, 0x90, BYTE_LEN);*/
#endif
break;
case CAMERA_EFFECT_SEPIA:
#if 1/*user color matrix*/
ov9665_i2c_write(ov9665_client->addr, 0xbd, 0x09, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xbe, 0x09, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xbf, 0x00, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xc0, 0x06, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xc1, 0x08, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xc2, 0x07, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xc3, 0x0a, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xc4, 0x04, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xc5, 0x00, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xc6, 0x98, BYTE_LEN);
#endif
#if 0/*control by SDE*/
ov9665_i2c_write(ov9665_client->addr, 0xc7, 0x90, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xc8, 0x18, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xCD, 0x40, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr, 0xCE, 0xa0, BYTE_LEN);
#endif
break;
default:
return -EINVAL;
}
return 0;
}
static int ov9665_set_antibanding(enum antibanding_mode antibanding_value)
{
if (op_mode == SENSOR_SNAPSHOT_MODE)
return 0;
switch (antibanding_value) {
case CAMERA_ANTI_BANDING_50HZ:
ov9665_i2c_write_mask(0x0c, 0x00, 0x02);
ov9665_i2c_write_mask(0x0c, 0x04, 0x04);
break;
case CAMERA_ANTI_BANDING_60HZ:
ov9665_i2c_write_mask(0x0c, 0x00, 0x02);
ov9665_i2c_write_mask(0x0c, 0x00, 0x04);
break;
case CAMERA_ANTI_BANDING_AUTO:
ov9665_i2c_write_mask(0x0c, 0x02, 0x02);
break;
}
return 0;
}
static int ov9665_set_brightness(enum brightness_t brightness_value)
{
if (op_mode == SENSOR_SNAPSHOT_MODE)
return 0;
ov9665_i2c_write_mask(0xc8, 0x04, 0x04);
switch (brightness_value) {
case CAMERA_BRIGHTNESS_N4:
ov9665_i2c_write_mask(0xc7, 0x18, 0x18);
ov9665_i2c_write(ov9665_client->addr,
0xd1, 0x40, BYTE_LEN);
break;
case CAMERA_BRIGHTNESS_N3:
ov9665_i2c_write_mask(0xc7, 0x18, 0x18);
ov9665_i2c_write(ov9665_client->addr,
0xd1, 0x30, BYTE_LEN);
break;
case CAMERA_BRIGHTNESS_N2:
ov9665_i2c_write_mask(0xc7, 0x18, 0x18);
ov9665_i2c_write(ov9665_client->addr,
0xd1, 0x20, BYTE_LEN);
break;
case CAMERA_BRIGHTNESS_N1:
ov9665_i2c_write_mask(0xc7, 0x18, 0x18);
ov9665_i2c_write(ov9665_client->addr,
0xd1, 0x10, BYTE_LEN);
break;
case CAMERA_BRIGHTNESS_D:
ov9665_i2c_write_mask(0xc7, 0x10, 0x18);
ov9665_i2c_write(ov9665_client->addr,
0xd1, 0x00, BYTE_LEN);
break;
case CAMERA_BRIGHTNESS_P1:
ov9665_i2c_write_mask(0xc7, 0x10, 0x18);
ov9665_i2c_write(ov9665_client->addr,
0xd1, 0x10, BYTE_LEN);
break;
case CAMERA_BRIGHTNESS_P2:
ov9665_i2c_write_mask(0xc7, 0x10, 0x18);
ov9665_i2c_write(ov9665_client->addr,
0xd1, 0x20, BYTE_LEN);
break;
case CAMERA_BRIGHTNESS_P3:
ov9665_i2c_write_mask(0xc7, 0x10, 0x18);
ov9665_i2c_write(ov9665_client->addr,
0xd1, 0x30, BYTE_LEN);
break;
case CAMERA_BRIGHTNESS_P4:
ov9665_i2c_write_mask(0xc7, 0x10, 0x18);
ov9665_i2c_write(ov9665_client->addr,
0xd1, 0x40, BYTE_LEN);
break;
default:
break;
}
return 0;
}
static int ov9665_set_wb(enum wb_mode wb_value)
{
if (op_mode == SENSOR_SNAPSHOT_MODE)
return 0;
switch (wb_value) {
case CAMERA_AWB_AUTO:
ov9665_i2c_write(ov9665_client->addr,
0x13, 0xe7, BYTE_LEN);
break;
case CAMERA_AWB_CLOUDY:
ov9665_i2c_write(ov9665_client->addr,
0x13, 0xe5, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0x01, 0x40, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0x02, 0x68, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0x16, 0x46, BYTE_LEN);
break;
case CAMERA_AWB_INDOOR_HOME:
ov9665_i2c_write(ov9665_client->addr,
0x13, 0xe5, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0x01, 0x62, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0x02, 0x3c, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0x16, 0x41, BYTE_LEN);
break;
case CAMERA_AWB_INDOOR_OFFICE:
ov9665_i2c_write(ov9665_client->addr,
0x13, 0xe5, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0x01, 0x50, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0x02, 0x40, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0x16, 0x40, BYTE_LEN);
break;
case CAMERA_AWB_SUNNY:
ov9665_i2c_write(ov9665_client->addr,
0x13, 0xe5, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0x01, 0x35, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0x02, 0x52, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0x16, 0x40, BYTE_LEN);
break;
default:
break;
}
return 0;
}
static int ov9665_set_sharpness(enum sharpness_mode sharpness_value)
{
if (op_mode == SENSOR_SNAPSHOT_MODE)
return 0;
ov9665_i2c_write_mask(0xab, 0x04, 0x04);
switch (sharpness_value) {
case CAMERA_SHARPNESS_X0:
ov9665_i2c_write(ov9665_client->addr,
0xad, 0x20, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0xd9, 0x00, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0xda, 0x00, BYTE_LEN);
break;
case CAMERA_SHARPNESS_X1:
ov9665_i2c_write(ov9665_client->addr,
0xad, 0x22, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0xd9, 0x01, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0xda, 0x00, BYTE_LEN);
break;
case CAMERA_SHARPNESS_X2:
ov9665_i2c_write(ov9665_client->addr,
0xad, 0x24, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0xd9, 0x13, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0xda, 0x00, BYTE_LEN);
break;
case CAMERA_SHARPNESS_X3:
ov9665_i2c_write(ov9665_client->addr,
0xad, 0x28, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0xd9, 0x26, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0xda, 0x22, BYTE_LEN);
break;
case CAMERA_SHARPNESS_X4:
ov9665_i2c_write(ov9665_client->addr,
0xad, 0x2c, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0xd9, 0x6a, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0xda, 0x66, BYTE_LEN);
break;
default:
break;
}
return 0;
}
static int ov9665_set_saturation(enum saturation_mode saturation_value)
{
if (op_mode == SENSOR_SNAPSHOT_MODE)
return 0;
switch (saturation_value) {
case CAMERA_SATURATION_X0:
ov9665_i2c_write_mask(0xc7, 0x10, 0x10);
ov9665_i2c_write_mask(0xc8, 0x02, 0x02);
ov9665_i2c_write(ov9665_client->addr,
0xcb, 0x00, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0xcc, 0x00, BYTE_LEN);
break;
case CAMERA_SATURATION_X05:
ov9665_i2c_write_mask(0xc7, 0x10, 0x10);
ov9665_i2c_write_mask(0xc8, 0x02, 0x02);
ov9665_i2c_write(ov9665_client->addr,
0xcb, 0x20, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0xcc, 0x20, BYTE_LEN);
break;
case CAMERA_SATURATION_X1:
ov9665_i2c_write_mask(0xc7, 0x10, 0x10);
ov9665_i2c_write_mask(0xc8, 0x02, 0x02);
ov9665_i2c_write(ov9665_client->addr,
0xcb, 0x40, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0xcc, 0x40, BYTE_LEN);
break;
case CAMERA_SATURATION_X15:
ov9665_i2c_write_mask(0xc7, 0x10, 0x10);
ov9665_i2c_write_mask(0xc8, 0x02, 0x02);
ov9665_i2c_write(ov9665_client->addr,
0xcb, 0x60, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0xcc, 0x60, BYTE_LEN);
break;
case CAMERA_SATURATION_X2:
ov9665_i2c_write_mask(0xc7, 0x10, 0x10);
ov9665_i2c_write_mask(0xc8, 0x02, 0x02);
ov9665_i2c_write(ov9665_client->addr,
0xcb, 0x80, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0xcc, 0x80, BYTE_LEN);
break;
default:
break;
}
return 0;
}
static int ov9665_set_contrast(enum contrast_mode contrast_value)
{
if (op_mode == SENSOR_SNAPSHOT_MODE)
return 0;
ov9665_i2c_write_mask(0xc7, 0x34, 0x34);
ov9665_i2c_write_mask(0xc8, 0x04, 0x04);
ov9665_i2c_write_mask(0x64, 0x02, 0x02);
switch (contrast_value) {
case CAMERA_CONTRAST_N2:
ov9665_i2c_write(ov9665_client->addr,
0xd0, 0x08, BYTE_LEN);
break;
case CAMERA_CONTRAST_N1:
ov9665_i2c_write(ov9665_client->addr,
0xd0, 0x10, BYTE_LEN);
break;
case CAMERA_CONTRAST_D:
ov9665_i2c_write(ov9665_client->addr,
0xd0, 0x20, BYTE_LEN);
break;
case CAMERA_CONTRAST_P1:
ov9665_i2c_write(ov9665_client->addr,
0xd0, 0x30, BYTE_LEN);
break;
case CAMERA_CONTRAST_P2:
ov9665_i2c_write(ov9665_client->addr,
0xd0, 0x40, BYTE_LEN);
break;
default:
break;
}
return 0;
}
static int ov9665_set_front_camera_mode(enum frontcam_t frontcam_value)
{
if (op_mode == SENSOR_SNAPSHOT_MODE)
return 0;
switch (frontcam_value) {
case CAMERA_MIRROR:
/*mirror and flip*/
ov9665_i2c_write(ov9665_client->addr,
0x04, 0xa8, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0x33, 0xc8, BYTE_LEN);
break;
case CAMERA_REVERSE:
/*reverse mode*/
ov9665_i2c_write(ov9665_client->addr,
0x04, 0x28, BYTE_LEN);
ov9665_i2c_write(ov9665_client->addr,
0x33, 0xc0, BYTE_LEN);
break;
default:
break;
}
return 0;
}
static int ov9665_sensor_init(const struct msm_camera_sensor_info *data)
{
uint8_t model_id_h = 0,model_id_l = 0;
uint16_t model_id;
int rc = 0;
pr_info("ov9665_sensor_init_probe \n");
/* Read the Model ID of the sensor */
rc = ov9665_i2c_read(ov9665_client->addr,
REG_OV9665_MODEL_ID_H, &model_id_h);
if (rc < 0)
goto init_probe_fail;
rc = ov9665_i2c_read(ov9665_client->addr,
REG_OV9665_MODEL_ID_L, &model_id_l);
if (rc < 0)
goto init_probe_fail;
model_id = (((model_id_h << 8) & 0xFF00) +(model_id_l));
pr_info("ov9665: model_id = 0x%x\n", model_id);
/* Check if it matches it with the value in Datasheet */
if (model_id != OV9665_MODEL_ID) {
rc = -EINVAL;
goto init_probe_fail;
}
return rc;
init_probe_fail:
return rc;
}
int ov9665_sensor_open_init(struct msm_camera_sensor_info *data)
{
int rc = 0;
ov9665_ctrl = kzalloc(sizeof(struct ov9665_ctrl), GFP_KERNEL);
if (!ov9665_ctrl) {
pr_info("ov9665_init failed!\n");
rc = -ENOMEM;
goto init_done;
}
if (data == NULL) {
pr_err("%s sensor data is NULL\n", __func__);
return -EINVAL;
}
ov9665_ctrl->sensordata = data;
/*switch PCLK and MCLK to 2nd cam*/
pr_info("ov9665: ov9665_sensor_probe switch clk\n");
if(data->camera_clk_switch != NULL)
data->camera_clk_switch();
/* Config power down */
rc = gpio_request(data->sensor_pwd, "ov9665");
if (!rc)
gpio_direction_output(data->sensor_pwd, 0);
else
pr_info("GPIO(%d) request faile",data->sensor_pwd);
gpio_free(data->sensor_pwd);
mdelay(3);
/* Input MCLK = 24MHz */
msm_camio_clk_rate_set(24000000);
mdelay(5);
msm_camio_camif_pad_reg_reset();
rc = ov9665_i2c_write_table(&ov9665_regs.plltbl[0],
ov9665_regs.plltbl_size);
/*read ID*/
rc = ov9665_sensor_init(data);
if (rc < 0) {
pr_info("ov9665_sensor_init failed!\n");
goto init_fail;
}
/*set initial register*/
rc = ov9665_reg_init();
if (rc < 0) {
pr_info("ov9665_sensor_reg_init failed!\n");
goto init_fail;
}
init_done:
return rc;
init_fail:
if (ov9665_ctrl) {
kfree(ov9665_ctrl);
ov9665_ctrl = NULL;
}
return rc;
}
static int ov9665_init_client(struct i2c_client *client)
{
/* Initialize the MSM_CAMI2C Chip */
init_waitqueue_head(&ov9665_wait_queue);
return 0;
}
int ov9665_sensor_config(void __user *argp)
{
struct sensor_cfg_data cfg_data;
long rc = 0;
if (copy_from_user(&cfg_data,
(void *)argp, sizeof(struct sensor_cfg_data)))
return -EFAULT;
switch (cfg_data.cfgtype) {
case CFG_SET_MODE:
rc = ov9665_set_sensor_mode(cfg_data.mode);
break;
case CFG_SET_EFFECT:
rc = ov9665_set_effect(cfg_data.cfg.effect);
if(rc < 0)
return rc;
break;
case CFG_SET_ANTIBANDING:
rc = ov9665_set_antibanding
(cfg_data.cfg.antibanding_value);
break;
case CFG_SET_BRIGHTNESS:
rc = ov9665_set_brightness
(cfg_data.cfg.brightness_value);
break;
case CFG_SET_WB:
rc = ov9665_set_wb(cfg_data.cfg.wb_value);
break;
case CFG_SET_SHARPNESS:
rc = ov9665_set_sharpness
(cfg_data.cfg.sharpness_value);
break;
case CFG_SET_SATURATION:
rc = ov9665_set_saturation
(cfg_data.cfg.saturation_value);
break;
case CFG_SET_CONTRAST:
rc = ov9665_set_contrast(cfg_data.cfg.contrast_value);
break;
case CFG_SET_FRONT_CAMERA_MODE:
rc = ov9665_set_front_camera_mode(cfg_data.cfg.frontcam_value);
break;
default:
rc = -EINVAL;
break;
}
return rc;
}
int ov9665_sensor_release(void)
{
int rc = 0;
down(&ov9665_sem);
rc = gpio_request(ov9665_ctrl->sensordata->sensor_pwd, "ov9665");
if (!rc)
gpio_direction_output(ov9665_ctrl->sensordata->sensor_pwd, 1);
else
pr_info("GPIO(%d) request faile",
ov9665_ctrl->sensordata->sensor_pwd);
gpio_free(ov9665_ctrl->sensordata->sensor_pwd);
if (ov9665_ctrl) {
kfree(ov9665_ctrl);
ov9665_ctrl = NULL;
}
up(&ov9665_sem);
return rc;
}
static const char *Ov9665Vendor = "OmniVision";
static const char *Ov9665NAME = "ov9665";
static const char *Ov9665Size = "1M";
static uint32_t htcwc_value;
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", Ov9665Vendor, Ov9665NAME, Ov9665Size);
ret = strlen(buf) + 1;
return ret;
}
static ssize_t htcwc_get(struct device *dev,
struct device_attribute *attr, char *buf)
{
ssize_t length;
length = sprintf(buf, "%d\n", htcwc_value);
return length;
}
static ssize_t htcwc_set(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
uint32_t tmp = 0;
tmp = buf[0] - 0x30; /* only get the first char */
#if 0
if (strcmp(current->comm,"com.android.camera")!=0){
pr_info("No permission : not camera ap\n");
return -EINVAL;
}
#endif
htcwc_value = tmp;
//pr_info("current_comm = %s\n", current->comm);
pr_info("htcwc_value = %d\n", htcwc_value);
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(htcwc, 0777, htcwc_get, htcwc_set);
static DEVICE_ATTR(node, 0444, sensor_read_node, NULL);
static struct kobject *android_ov9665;
static int ov9665_sysfs_init(void)
{
int ret ;
pr_info("ov9665:kobject creat and add\n");
android_ov9665 = kobject_create_and_add("android_camera2", NULL);
if (android_ov9665 == NULL) {
pr_info("ov9665_sysfs_init: subsystem_register " \
"failed\n");
ret = -ENOMEM;
return ret ;
}
pr_info("ov9665:sysfs_create_file\n");
ret = sysfs_create_file(android_ov9665, &dev_attr_sensor.attr);
if (ret) {
pr_info("ov9665_sysfs_init: sysfs_create_file " \
"failed\n");
kobject_del(android_ov9665);
}
ret = sysfs_create_file(android_ov9665, &dev_attr_htcwc.attr);
if (ret) {
pr_info("ov9665_sysfs_init: sysfs_create_file htcwc failed\n");
kobject_del(android_ov9665);
}
ret = sysfs_create_file(android_ov9665, &dev_attr_node.attr);
if (ret) {
pr_info("ov9665_sysfs_init: dev_attr_node failed\n");
kobject_del(android_ov9665);
}
return 0 ;
}
static int ov9665_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int rc = 0;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
rc = -ENOTSUPP;
goto probe_failure;
}
ov9665_sensorw = kzalloc(sizeof(struct ov9665_work), GFP_KERNEL);
if (!ov9665_sensorw) {
rc = -ENOMEM;
goto probe_failure;
}
i2c_set_clientdata(client, ov9665_sensorw);
ov9665_init_client(client);
ov9665_client = client;
pr_info("ov9665_probe succeeded!\n");
return 0;
probe_failure:
kfree(ov9665_sensorw);
ov9665_sensorw = NULL;
pr_info("ov9665_probe failed!\n");
return rc;
}
static const struct i2c_device_id ov9665_i2c_id[] = {
{"ov9665", 0},
{},
};
static struct i2c_driver ov9665_i2c_driver = {
.id_table = ov9665_i2c_id,
.probe = ov9665_i2c_probe,
.remove = __exit_p(ov9665_i2c_remove),
.driver = {
.name = "ov9665",
},
};
static int ov9665_sensor_probe(struct msm_camera_sensor_info *info,
struct msm_sensor_ctrl *s)
{
int rc = i2c_add_driver(&ov9665_i2c_driver);
if (rc < 0 || ov9665_client == NULL) {
rc = -ENOTSUPP;
goto probe_done;
}
pr_info("ov9665 s->node %d\n", s->node);
sensor_probe_node = s->node;
/*switch clk source*/
pr_info("ov9665: ov9665_sensor_probe switch clk\n");
if(info->camera_clk_switch != NULL)
info->camera_clk_switch();
/* Config power down */
if(ov9665_pwd(info)<0)
goto probe_fail;
mdelay(3);
/*Config reset */
if(ov9665_reset(info)<0)
goto probe_fail;
mdelay(5);
/*MCLK enable*/
pr_info("ov9665: MCLK enable clk\n");
msm_camio_clk_rate_set(24000000);
mdelay(100);
/* PLL Setup Start */
rc = ov9665_i2c_write_table(&ov9665_regs.plltbl[0],
ov9665_regs.plltbl_size);
rc = ov9665_sensor_init(info);
if (rc < 0)
goto probe_fail;
/*set initial register*/
rc = ov9665_reg_init();
if (rc < 0)
goto probe_fail;
s->s_init = ov9665_sensor_open_init;
s->s_release = ov9665_sensor_release;
s->s_config = ov9665_sensor_config;
/*init done*/
mdelay(800);
ov9665_init_done(info);
ov9665_sysfs_init();
probe_done:
pr_info("%s %s:%d\n", __FILE__, __func__, __LINE__);
return rc;
probe_fail:
pr_err("OV9665 probe faile\n");
return rc;
}
static int __ov9665_probe(struct platform_device *pdev)
{
return msm_camera_drv_start(pdev, ov9665_sensor_probe);
}
static struct platform_driver msm_camera_driver = {
.probe = __ov9665_probe,
.driver = {
.name = "msm_camera_ov9665",
.owner = THIS_MODULE,
},
};
static int __init ov9665_init(void)
{
return platform_driver_register(&msm_camera_driver);
}
module_init(ov9665_init);