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

657 lines
15 KiB
C

/* Copyright (c) 2011, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/slab.h>
#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 "mt9d113.h"
/* Micron MT9D113 Registers and their values */
#define REG_MT9D113_MODEL_ID 0x0000
#define MT9D113_MODEL_ID 0x2580
#define Q8 0x00000100
struct mt9d113_work {
struct work_struct work;
};
static struct mt9d113_work *mt9d113_sensorw;
static struct i2c_client *mt9d113_client;
struct mt9d113_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;
uint16_t curr_step_pos;
uint16_t my_reg_gain;
uint32_t my_reg_line_count;
uint16_t total_lines_per_frame;
uint16_t config_csi;
enum mt9d113_resolution_t prev_res;
enum mt9d113_resolution_t pict_res;
enum mt9d113_resolution_t curr_res;
enum mt9d113_test_mode_t set_test;
};
static struct mt9d113_ctrl *mt9d113_ctrl;
static DECLARE_WAIT_QUEUE_HEAD(mt9d113_wait_queue);
DEFINE_MUTEX(mt9d113_mut);
static int mt9d113_i2c_rxdata(unsigned short saddr,
unsigned char *rxdata, int length)
{
struct i2c_msg msgs[] = {
{
.addr = saddr,
.flags = 0,
.len = 2,
.buf = rxdata,
},
{
.addr = saddr,
.flags = I2C_M_RD,
.len = length,
.buf = rxdata,
},
};
if (i2c_transfer(mt9d113_client->adapter, msgs, 2) < 0) {
CDBG("mt9d113_i2c_rxdata failed!\n");
return -EIO;
}
return 0;
}
static int32_t mt9d113_i2c_read(unsigned short saddr,
unsigned short raddr,
unsigned short *rdata,
enum mt9d113_width width)
{
int32_t rc = 0;
unsigned char buf[4];
if (!rdata)
return -EIO;
memset(buf, 0, sizeof(buf));
switch (width) {
case WORD_LEN: {
buf[0] = (raddr & 0xFF00)>>8;
buf[1] = (raddr & 0x00FF);
rc = mt9d113_i2c_rxdata(saddr, buf, 2);
if (rc < 0)
return rc;
*rdata = buf[0] << 8 | buf[1];
}
break;
default:
break;
}
if (rc < 0)
CDBG("mt9d113_i2c_read failed !\n");
return rc;
}
static int32_t mt9d113_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(mt9d113_client->adapter, msg, 1) < 0) {
CDBG("mt9d113_i2c_txdata failed\n");
return -EIO;
}
return 0;
}
static int32_t mt9d113_i2c_write(unsigned short saddr,
unsigned short waddr,
unsigned short wdata,
enum mt9d113_width width)
{
int32_t 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 = mt9d113_i2c_txdata(saddr, buf, 4);
}
break;
case BYTE_LEN: {
buf[0] = waddr;
buf[1] = wdata;
rc = mt9d113_i2c_txdata(saddr, buf, 2);
}
break;
default:
break;
}
if (rc < 0)
printk(KERN_ERR
"i2c_write failed, addr = 0x%x, val = 0x%x!\n",
waddr, wdata);
return rc;
}
static int32_t mt9d113_i2c_write_table(
struct mt9d113_i2c_reg_conf
const *reg_conf_tbl,
int num_of_items_in_table)
{
int i;
int32_t rc = -EIO;
for (i = 0; i < num_of_items_in_table; i++) {
rc = mt9d113_i2c_write(mt9d113_client->addr,
reg_conf_tbl->waddr, reg_conf_tbl->wdata,
WORD_LEN);
if (rc < 0)
break;
reg_conf_tbl++;
}
return rc;
}
static long mt9d113_reg_init(void)
{
uint16_t data = 0;
int32_t rc = 0;
int count = 0;
struct msm_camera_csi_params mt9d113_csi_params;
if (!mt9d113_ctrl->config_csi) {
mt9d113_csi_params.lane_cnt = 1;
mt9d113_csi_params.data_format = CSI_8BIT;
mt9d113_csi_params.lane_assign = 0xe4;
mt9d113_csi_params.dpcm_scheme = 0;
mt9d113_csi_params.settle_cnt = 0x14;
rc = msm_camio_csi_config(&mt9d113_csi_params);
mt9d113_ctrl->config_csi = 1;
msleep(50);
}
/* Disable parallel and enable mipi*/
rc = mt9d113_i2c_write(mt9d113_client->addr,
0x001A,
0x0051, WORD_LEN);
rc = mt9d113_i2c_write(mt9d113_client->addr,
0x001A,
0x0050,
WORD_LEN);
msleep(20);
rc = mt9d113_i2c_write(mt9d113_client->addr,
0x001A,
0x0058,
WORD_LEN);
/* Preset pll settings begin*/
rc = mt9d113_i2c_write_table(&mt9d113_regs.pll_tbl[0],
mt9d113_regs.pll_tbl_size);
if (rc < 0)
return rc;
rc = mt9d113_i2c_read(mt9d113_client->addr,
0x0014, &data, WORD_LEN);
data = data&0x8000;
/* Poll*/
while (data == 0x0000) {
data = 0;
rc = mt9d113_i2c_read(mt9d113_client->addr,
0x0014, &data, WORD_LEN);
data = data & 0x8000;
usleep_range(11000, 12000);
count++;
if (count == 100) {
CDBG(" Timeout:1\n");
break;
}
}
rc = mt9d113_i2c_write(mt9d113_client->addr,
0x0014,
0x20FA,
WORD_LEN);
/*Preset pll Ends*/
mt9d113_i2c_write(mt9d113_client->addr,
0x0018,
0x402D,
WORD_LEN);
mt9d113_i2c_write(mt9d113_client->addr,
0x0018,
0x402C,
WORD_LEN);
/*POLL_REG=0x0018,0x4000,!=0x0000,DELAY=10,TIMEOUT=100*/
data = 0;
rc = mt9d113_i2c_read(mt9d113_client->addr,
0x0018, &data, WORD_LEN);
data = data & 0x4000;
count = 0;
while (data != 0x0000) {
rc = mt9d113_i2c_read(mt9d113_client->addr,
0x0018, &data, WORD_LEN);
data = data & 0x4000;
CDBG(" data is %d\n" , data);
usleep_range(11000, 12000);
count++;
if (count == 100) {
CDBG(" Loop2 timeout: MT9D113\n");
break;
}
CDBG(" Not streaming\n");
}
CDBG("MT9D113: Start stream\n");
/*Preset Register Wizard Conf*/
rc = mt9d113_i2c_write_table(&mt9d113_regs.register_tbl[0],
mt9d113_regs.register_tbl_size);
if (rc < 0)
return rc;
rc = mt9d113_i2c_write_table(&mt9d113_regs.err_tbl[0],
mt9d113_regs.err_tbl_size);
if (rc < 0)
return rc;
rc = mt9d113_i2c_write_table(&mt9d113_regs.eeprom_tbl[0],
mt9d113_regs.eeprom_tbl_size);
if (rc < 0)
return rc;
rc = mt9d113_i2c_write_table(&mt9d113_regs.low_light_tbl[0],
mt9d113_regs.low_light_tbl_size);
if (rc < 0)
return rc;
rc = mt9d113_i2c_write_table(&mt9d113_regs.awb_tbl[0],
mt9d113_regs.awb_tbl_size);
if (rc < 0)
return rc;
rc = mt9d113_i2c_write_table(&mt9d113_regs.patch_tbl[0],
mt9d113_regs.patch_tbl_size);
if (rc < 0)
return rc;
/*check patch load*/
mt9d113_i2c_write(mt9d113_client->addr,
0x098C,
0xA024,
WORD_LEN);
count = 0;
/*To check if patch is loaded properly
poll the register 0x990 till the condition is
met or till the timeout*/
data = 0;
rc = mt9d113_i2c_read(mt9d113_client->addr,
0x0990, &data, WORD_LEN);
while (data == 0) {
data = 0;
rc = mt9d113_i2c_read(mt9d113_client->addr,
0x0990, &data, WORD_LEN);
usleep_range(11000, 12000);
count++;
if (count == 100) {
CDBG("Timeout in patch loading\n");
break;
}
}
/*BITFIELD=0x0018, 0x0004, 0*/
/*Preset continue begin */
rc = mt9d113_i2c_write(mt9d113_client->addr, 0x0018, 0x0028,
WORD_LEN);
CDBG(" mt9d113 wait for seq done\n");
/* syncronize the FW with the sensor
MCU_ADDRESS [SEQ_CMD]*/
rc = mt9d113_i2c_write(mt9d113_client->addr,
0x098C, 0xA103, WORD_LEN);
rc = mt9d113_i2c_write(mt9d113_client->addr,
0x0990, 0x0006, WORD_LEN);
/*mt9d113 wait for seq done
syncronize the FW with the sensor */
msleep(20);
/*Preset continue end */
CDBG(" MT9D113: Preset continue end\n");
rc = mt9d113_i2c_write(mt9d113_client->addr,
0x0012,
0x00F5,
WORD_LEN);
/*continue begin */
CDBG(" MT9D113: Preset continue begin\n");
rc = mt9d113_i2c_write(mt9d113_client->addr, 0x0018, 0x0028 ,
WORD_LEN);
/*mt9d113 wait for seq done
syncronize the FW with the sensor
MCU_ADDRESS [SEQ_CMD]*/
msleep(20);
rc = mt9d113_i2c_write(mt9d113_client->addr,
0x098C, 0xA103, WORD_LEN);
/* MCU DATA */
rc = mt9d113_i2c_write(mt9d113_client->addr, 0x0990,
0x0006, WORD_LEN);
/*mt9d113 wait for seq done
syncronize the FW with the sensor */
/* MCU_ADDRESS [SEQ_CMD]*/
msleep(20);
/*Preset continue end*/
return rc;
}
static long mt9d113_set_sensor_mode(int mode)
{
long rc = 0;
switch (mode) {
case SENSOR_PREVIEW_MODE:
rc = mt9d113_reg_init();
CDBG("MT9D113: configure to preview begin\n");
rc =
mt9d113_i2c_write(mt9d113_client->addr,
0x098C, 0xA115, WORD_LEN);
if (rc < 0)
return rc;
rc =
mt9d113_i2c_write(mt9d113_client->addr,
0x0990, 0x0000, WORD_LEN);
if (rc < 0)
return rc;
rc =
mt9d113_i2c_write(mt9d113_client->addr,
0x098C, 0xA103, WORD_LEN);
if (rc < 0)
return rc;
rc =
mt9d113_i2c_write(mt9d113_client->addr,
0x0990, 0x0001, WORD_LEN);
if (rc < 0)
return rc;
break;
case SENSOR_SNAPSHOT_MODE:
case SENSOR_RAW_SNAPSHOT_MODE:
rc =
mt9d113_i2c_write(mt9d113_client->addr,
0x098C, 0xA115, WORD_LEN);
rc =
mt9d113_i2c_write(mt9d113_client->addr,
0x0990, 0x0002, WORD_LEN);
rc =
mt9d113_i2c_write(mt9d113_client->addr,
0x098C, 0xA103, WORD_LEN);
rc =
mt9d113_i2c_write(mt9d113_client->addr,
0x0990, 0x0002, WORD_LEN);
break;
default:
return -EINVAL;
}
return 0;
}
static int mt9d113_sensor_init_probe(const struct
msm_camera_sensor_info * data)
{
uint16_t model_id = 0;
int rc = 0;
/* Read the Model ID of the sensor */
rc = mt9d113_i2c_read(mt9d113_client->addr,
REG_MT9D113_MODEL_ID,
&model_id, WORD_LEN);
if (rc < 0)
goto init_probe_fail;
/* Check if it matches it with the value in Datasheet */
if (model_id != MT9D113_MODEL_ID)
printk(KERN_INFO "mt9d113 model_id = 0x%x\n", model_id);
if (rc < 0)
goto init_probe_fail;
return rc;
init_probe_fail:
printk(KERN_INFO "probe fail\n");
return rc;
}
static int mt9d113_init_client(struct i2c_client *client)
{
/* Initialize the MSM_CAMI2C Chip */
init_waitqueue_head(&mt9d113_wait_queue);
return 0;
}
int mt9d113_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;
mutex_lock(&mt9d113_mut);
CDBG("mt9d113_ioctl, cfgtype = %d, mode = %d\n",
cfg_data.cfgtype, cfg_data.mode);
switch (cfg_data.cfgtype) {
case CFG_SET_MODE:
rc = mt9d113_set_sensor_mode(
cfg_data.mode);
break;
case CFG_SET_EFFECT:
return rc;
case CFG_GET_AF_MAX_STEPS:
default:
rc = -EINVAL;
break;
}
mutex_unlock(&mt9d113_mut);
return rc;
}
int mt9d113_sensor_release(void)
{
int rc = 0;
mutex_lock(&mt9d113_mut);
gpio_set_value_cansleep(mt9d113_ctrl->sensordata->sensor_reset, 0);
msleep(20);
gpio_free(mt9d113_ctrl->sensordata->sensor_reset);
kfree(mt9d113_ctrl);
mutex_unlock(&mt9d113_mut);
return rc;
}
static int mt9d113_probe_init_done(const struct msm_camera_sensor_info
*data)
{
gpio_free(data->sensor_reset);
return 0;
}
static int mt9d113_probe_init_sensor(const struct msm_camera_sensor_info
*data)
{
int32_t rc = 0;
uint16_t chipid = 0;
rc = gpio_request(data->sensor_reset, "mt9d113");
printk(KERN_INFO " mt9d113_probe_init_sensor\n");
if (!rc) {
printk(KERN_INFO "sensor_reset = %d\n", rc);
gpio_direction_output(data->sensor_reset, 0);
usleep_range(11000, 12000);
gpio_set_value_cansleep(data->sensor_reset, 1);
usleep_range(11000, 12000);
} else
goto init_probe_done;
printk(KERN_INFO " mt9d113_probe_init_sensor called\n");
rc = mt9d113_i2c_read(mt9d113_client->addr, REG_MT9D113_MODEL_ID,
&chipid, WORD_LEN);
if (rc < 0)
goto init_probe_fail;
/*Compare sensor ID to MT9D113 ID: */
if (chipid != MT9D113_MODEL_ID) {
printk(KERN_INFO "mt9d113_probe_init_sensor chip id is%d\n",
chipid);
}
CDBG("mt9d113_probe_init_sensor Success\n");
goto init_probe_done;
init_probe_fail:
CDBG(" ov2720_probe_init_sensor fails\n");
gpio_set_value_cansleep(data->sensor_reset, 0);
mt9d113_probe_init_done(data);
init_probe_done:
printk(KERN_INFO " mt9d113_probe_init_sensor finishes\n");
return rc;
}
static int mt9d113_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;
}
mt9d113_sensorw =
kzalloc(sizeof(struct mt9d113_work), GFP_KERNEL);
if (!mt9d113_sensorw) {
rc = -ENOMEM;
goto probe_failure;
}
i2c_set_clientdata(client, mt9d113_sensorw);
mt9d113_init_client(client);
mt9d113_client = client;
CDBG("mt9d113_probe succeeded!\n");
return 0;
probe_failure:
kfree(mt9d113_sensorw);
mt9d113_sensorw = NULL;
CDBG("mt9d113_probe failed!\n");
return rc;
}
static const struct i2c_device_id mt9d113_i2c_id[] = {
{ "mt9d113", 0},
{},
};
static struct i2c_driver mt9d113_i2c_driver = {
.id_table = mt9d113_i2c_id,
.probe = mt9d113_i2c_probe,
.remove = __exit_p(mt9d113_i2c_remove),
.driver = {
.name = "mt9d113",
},
};
int mt9d113_sensor_open_init(const struct msm_camera_sensor_info *data)
{
int32_t rc = 0;
mt9d113_ctrl = kzalloc(sizeof(struct mt9d113_ctrl), GFP_KERNEL);
if (!mt9d113_ctrl) {
printk(KERN_INFO "mt9d113_init failed!\n");
rc = -ENOMEM;
goto init_done;
}
mt9d113_ctrl->fps_divider = 1 * 0x00000400;
mt9d113_ctrl->pict_fps_divider = 1 * 0x00000400;
mt9d113_ctrl->set_test = TEST_OFF;
mt9d113_ctrl->config_csi = 0;
mt9d113_ctrl->prev_res = QTR_SIZE;
mt9d113_ctrl->pict_res = FULL_SIZE;
mt9d113_ctrl->curr_res = INVALID_SIZE;
if (data)
mt9d113_ctrl->sensordata = data;
if (rc < 0) {
printk(KERN_INFO "mt9d113_sensor_open_init fail\n");
return rc;
}
/* enable mclk first */
msm_camio_clk_rate_set(24000000);
msleep(20);
rc = mt9d113_probe_init_sensor(data);
if (rc < 0)
goto init_fail;
mt9d113_ctrl->fps = 30*Q8;
rc = mt9d113_sensor_init_probe(data);
if (rc < 0) {
gpio_set_value_cansleep(data->sensor_reset, 0);
goto init_fail;
} else
printk(KERN_ERR "%s: %d\n", __func__, __LINE__);
goto init_done;
init_fail:
printk(KERN_INFO "init_fail\n");
mt9d113_probe_init_done(data);
init_done:
CDBG("init_done\n");
return rc;
}
static int mt9d113_sensor_probe(const struct msm_camera_sensor_info
*info,
struct msm_sensor_ctrl *s)
{
int rc = 0;
rc = i2c_add_driver(&mt9d113_i2c_driver);
if (rc < 0 || mt9d113_client == NULL) {
rc = -ENOTSUPP;
goto probe_fail;
}
msm_camio_clk_rate_set(24000000);
usleep_range(5000, 6000);
rc = mt9d113_probe_init_sensor(info);
if (rc < 0)
goto probe_fail;
s->s_init = mt9d113_sensor_open_init;
s->s_release = mt9d113_sensor_release;
s->s_config = mt9d113_sensor_config;
s->s_camera_type = FRONT_CAMERA_2D;
s->s_mount_angle = 0;
gpio_set_value_cansleep(info->sensor_reset, 0);
mt9d113_probe_init_done(info);
return rc;
probe_fail:
printk(KERN_INFO "mt9d113_sensor_probe: SENSOR PROBE FAILS!\n");
return rc;
}
static int __mt9d113_probe(struct platform_device *pdev)
{
return msm_camera_drv_start(pdev, mt9d113_sensor_probe);
}
static struct platform_driver msm_camera_driver = {
.probe = __mt9d113_probe,
.driver = {
.name = "msm_cam_mt9d113",
.owner = THIS_MODULE,
},
};
static int __init mt9d113_init(void)
{
return platform_driver_register(&msm_camera_driver);
}
module_init(mt9d113_init);
MODULE_DESCRIPTION("Micron 2MP YUV sensor driver");
MODULE_LICENSE("GPL v2");