msm: camera: reimplement camera sensor driver

Camera sensor driver architecture is redesigned to have move control
at user space. The current kernel driver has provision for probing
to find whether a particular camera sensor is connected. A video node
is created for every successful camera probe. This request consists of
samsung S5K3L1YX 12 MP sensor driver, CCI (Camera Control Interface)
driver to perform I2C calls on I2C master bus, I2C MUX driver to select
2D / 3D MUX, QUP driver to perform legacy I2C calls and other utility
functions (msm_sensor) that can be reused by kernel sensor drivers.

Change-Id: I057e3a36b9e08e5b57eb7b90cb0643c84777d0bc
Signed-off-by: Hody Hung <hhung@codeaurora.org>
Signed-off-by: Shuzhen Wang <shuzhenw@codeaurora.org>
This commit is contained in:
Shuzhen Wang 2013-01-08 14:32:08 -08:00 committed by Stephen Boyd
parent 9d281dd01f
commit 923b49a7d4
22 changed files with 4969 additions and 12 deletions

View File

@ -1,7 +1,7 @@
/* arch/arm/mach-msm/include/mach/board.h
*
* Copyright (C) 2007 Google, Inc.
* Copyright (c) 2008-2012, The Linux Foundation. All rights reserved.
* Copyright (c) 2008-2013, The Linux Foundation. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@ -182,9 +182,8 @@ struct msm_gpio_set_tbl {
uint32_t delay;
};
struct msm_camera_csi_lane_params {
uint16_t csi_lane_assign;
uint16_t csi_lane_mask;
struct msm_camera_gpio_num_info {
uint16_t gpio_num[2];
};
struct msm_camera_gpio_conf {
@ -201,6 +200,7 @@ struct msm_camera_gpio_conf {
uint8_t camera_off_table_size;
uint32_t *camera_on_table;
uint8_t camera_on_table_size;
struct msm_camera_gpio_num_info *gpio_num_info;
};
enum msm_camera_i2c_mux_mode {
@ -215,13 +215,6 @@ struct msm_camera_i2c_conf {
enum msm_camera_i2c_mux_mode i2c_mux_mode;
};
enum msm_camera_vreg_name_t {
CAM_VDIG,
CAM_VIO,
CAM_VANA,
CAM_VAF,
};
struct msm_camera_sensor_platform_info {
int mount_angle;
int sensor_reset;

View File

@ -0,0 +1,91 @@
/* Copyright (c) 2011-2013, 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.
*
*/
#ifndef __CAMERA2_H__
#define __CAMERA2_H__
#include <media/msm_cam_sensor.h>
#include <mach/board.h>
enum msm_sensor_device_type_t {
MSM_SENSOR_I2C_DEVICE,
MSM_SENSOR_PLATFORM_DEVICE,
};
enum msm_bus_perf_setting {
S_INIT,
S_PREVIEW,
S_VIDEO,
S_CAPTURE,
S_ZSL,
S_STEREO_VIDEO,
S_STEREO_CAPTURE,
S_DEFAULT,
S_LIVESHOT,
S_DUAL,
S_EXIT
};
struct msm_camera_slave_info {
uint16_t sensor_slave_addr;
uint16_t sensor_id_reg_addr;
uint16_t sensor_id;
};
struct msm_cam_clk_info {
const char *clk_name;
long clk_rate;
uint32_t delay;
};
struct msm_cam_clk_setting {
struct msm_cam_clk_info *clk_info;
uint16_t num_clk_info;
uint8_t enable;
};
struct v4l2_subdev_info {
enum v4l2_mbus_pixelcode code;
enum v4l2_colorspace colorspace;
uint16_t fmt;
uint16_t order;
};
struct msm_camera_sensor_board_info {
const char *sensor_name;
struct msm_camera_slave_info *slave_info;
struct msm_camera_csi_lane_params *csi_lane_params;
struct camera_vreg_t *cam_vreg;
int num_vreg;
struct msm_camera_sensor_strobe_flash_data *strobe_flash_data;
struct msm_camera_gpio_conf *gpio_conf;
struct msm_actuator_info *actuator_info;
struct msm_camera_i2c_conf *i2c_conf;
struct msm_sensor_info_t *sensor_info;
struct msm_sensor_init_params *sensor_init_params;
};
enum msm_camera_i2c_cmd_type {
MSM_CAMERA_I2C_CMD_WRITE,
MSM_CAMERA_I2C_CMD_POLL,
};
struct msm_camera_i2c_reg_conf {
uint16_t reg_addr;
uint16_t reg_data;
enum msm_camera_i2c_data_type dt;
enum msm_camera_i2c_cmd_type cmd_type;
int16_t mask;
};
#endif

View File

@ -0,0 +1,3 @@
ccflags-y += -Idrivers/media/platform/msm/camera_v2
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
obj-$(CONFIG_MSM_CCI) += msm_cci.o

View File

@ -0,0 +1,61 @@
/* Copyright (c) 2012-2013, 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.
*/
#ifndef __MSM_CAM_CCI_HWREG__
#define __MSM_CAM_CCI_HWREG__
#define CCI_HW_VERSION_ADDR 0x00000000
#define CCI_RESET_CMD_ADDR 0x00000004
#define CCI_RESET_CMD_RMSK 0xcf73f3f7
#define CCI_M0_RESET_RMSK 0x3F1
#define CCI_M1_RESET_RMSK 0x3F001
#define CCI_QUEUE_START_ADDR 0x00000008
#define CCI_SET_CID_SYNC_TIMER_0_ADDR 0x00000010
#define CCI_I2C_M0_SCL_CTL_ADDR 0x00000100
#define CCI_I2C_M0_SDA_CTL_0_ADDR 0x00000104
#define CCI_I2C_M0_SDA_CTL_1_ADDR 0x00000108
#define CCI_I2C_M0_SDA_CTL_2_ADDR 0x0000010c
#define CCI_I2C_M0_READ_DATA_ADDR 0x00000118
#define CCI_I2C_M0_MISC_CTL_ADDR 0x00000110
#define CCI_I2C_M0_READ_BUF_LEVEL_ADDR 0x0000011C
#define CCI_HALT_REQ_ADDR 0x00000034
#define CCI_M0_HALT_REQ_RMSK 0x1
#define CCI_M1_HALT_REQ_RMSK 0x01
#define CCI_HALT_REQ_ADDR 0x00000034
#define CCI_I2C_M1_SCL_CTL_ADDR 0x00000200
#define CCI_I2C_M1_SDA_CTL_0_ADDR 0x00000204
#define CCI_I2C_M1_SDA_CTL_1_ADDR 0x00000208
#define CCI_I2C_M1_SDA_CTL_2_ADDR 0x0000020c
#define CCI_I2C_M1_MISC_CTL_ADDR 0x00000210
#define CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR 0x00000304
#define CCI_I2C_M0_Q0_CUR_CMD_ADDR 0x00000308
#define CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR 0x00000300
#define CCI_I2C_M0_Q0_LOAD_DATA_ADDR 0x00000310
#define CCI_IRQ_MASK_0_ADDR 0x00000c04
#define CCI_IRQ_MASK_0_RMSK 0x7fff7ff7
#define CCI_IRQ_CLEAR_0_ADDR 0x00000c08
#define CCI_IRQ_STATUS_0_ADDR 0x00000c0c
#define CCI_IRQ_STATUS_0_I2C_M1_Q1_NACK_ERR_BMSK 0x40000000
#define CCI_IRQ_STATUS_0_I2C_M1_Q0_NACK_ERR_BMSK 0x20000000
#define CCI_IRQ_STATUS_0_I2C_M0_Q1_NACK_ERR_BMSK 0x10000000
#define CCI_IRQ_STATUS_0_I2C_M0_Q0_NACK_ERR_BMSK 0x8000000
#define CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK 0x4000000
#define CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK 0x2000000
#define CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK 0x1000000
#define CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK 0x100000
#define CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK 0x10000
#define CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK 0x1000
#define CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK 0x100
#define CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK 0x10
#define CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK 0x1
#define CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR 0x00000c00
#endif /* __MSM_CAM_CCI_HWREG__ */

View File

@ -0,0 +1,969 @@
/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#include <media/msm_isp.h>
#include "msm_sd.h"
#include "msm_cci.h"
#include "msm_cam_cci_hwreg.h"
#include "msm_camera_io_util.h"
#define V4L2_IDENT_CCI 50005
#define CCI_I2C_QUEUE_0_SIZE 64
#define CCI_I2C_QUEUE_1_SIZE 16
#define CCI_TIMEOUT msecs_to_jiffies(100)
/* TODO move this somewhere else */
#define MSM_CCI_DRV_NAME "msm_cci"
#define CONFIG_MSMB_CAMERA_DEBUG
#undef CDBG
#ifdef CONFIG_MSMB_CAMERA_DEBUG
#define CDBG(fmt, args...) pr_debug(fmt, ##args)
#else
#define CDBG(fmt, args...) do { } while (0)
#endif
static struct v4l2_subdev *g_cci_subdev;
static void msm_cci_set_clk_param(struct cci_device *cci_dev)
{
struct msm_cci_clk_params_t *clk_params = &cci_dev->cci_clk_params;
msm_camera_io_w(clk_params->hw_thigh << 16 | clk_params->hw_tlow,
cci_dev->base + CCI_I2C_M0_SCL_CTL_ADDR);
msm_camera_io_w(clk_params->hw_tsu_sto << 16 | clk_params->hw_tsu_sta,
cci_dev->base + CCI_I2C_M0_SDA_CTL_0_ADDR);
msm_camera_io_w(clk_params->hw_thd_dat << 16 | clk_params->hw_thd_sta,
cci_dev->base + CCI_I2C_M0_SDA_CTL_1_ADDR);
msm_camera_io_w(clk_params->hw_tbuf,
cci_dev->base + CCI_I2C_M0_SDA_CTL_2_ADDR);
msm_camera_io_w(clk_params->hw_scl_stretch_en << 8 |
clk_params->hw_trdhld << 4 | clk_params->hw_tsp,
cci_dev->base + CCI_I2C_M0_MISC_CTL_ADDR);
msm_camera_io_w(clk_params->hw_thigh << 16 | clk_params->hw_tlow,
cci_dev->base + CCI_I2C_M1_SCL_CTL_ADDR);
msm_camera_io_w(clk_params->hw_tsu_sto << 16 | clk_params->hw_tsu_sta,
cci_dev->base + CCI_I2C_M1_SDA_CTL_0_ADDR);
msm_camera_io_w(clk_params->hw_thd_dat << 16 | clk_params->hw_thd_sta,
cci_dev->base + CCI_I2C_M1_SDA_CTL_1_ADDR);
msm_camera_io_w(clk_params->hw_tbuf,
cci_dev->base + CCI_I2C_M1_SDA_CTL_2_ADDR);
msm_camera_io_w(clk_params->hw_scl_stretch_en << 8 |
clk_params->hw_trdhld << 4 | clk_params->hw_tsp,
cci_dev->base + CCI_I2C_M1_MISC_CTL_ADDR);
return;
}
static int32_t msm_cci_i2c_config_sync_timer(struct v4l2_subdev *sd,
struct msm_camera_cci_ctrl *c_ctrl)
{
struct cci_device *cci_dev;
cci_dev = v4l2_get_subdevdata(sd);
msm_camera_io_w(c_ctrl->cci_info->cid, cci_dev->base +
CCI_SET_CID_SYNC_TIMER_0_ADDR + (c_ctrl->cci_info->cid * 0x4));
return 0;
}
static int32_t msm_cci_i2c_set_freq(struct v4l2_subdev *sd,
struct msm_camera_cci_ctrl *c_ctrl)
{
struct cci_device *cci_dev;
uint32_t val;
cci_dev = v4l2_get_subdevdata(sd);
val = c_ctrl->cci_info->freq;
msm_camera_io_w(val, cci_dev->base + CCI_I2C_M0_SCL_CTL_ADDR +
c_ctrl->cci_info->cci_i2c_master*0x100);
msm_camera_io_w(val, cci_dev->base + CCI_I2C_M0_SDA_CTL_0_ADDR +
c_ctrl->cci_info->cci_i2c_master*0x100);
msm_camera_io_w(val, cci_dev->base + CCI_I2C_M0_SDA_CTL_1_ADDR +
c_ctrl->cci_info->cci_i2c_master*0x100);
msm_camera_io_w(val, cci_dev->base + CCI_I2C_M0_SDA_CTL_2_ADDR +
c_ctrl->cci_info->cci_i2c_master*0x100);
msm_camera_io_w(val, cci_dev->base + CCI_I2C_M0_MISC_CTL_ADDR +
c_ctrl->cci_info->cci_i2c_master*0x100);
return 0;
}
static int32_t msm_cci_validate_queue(struct cci_device *cci_dev,
uint32_t len,
enum cci_i2c_master_t master,
enum cci_i2c_queue_t queue)
{
int32_t rc = 0;
uint32_t read_val = 0;
uint32_t reg_offset = master * 0x200 + queue * 0x100;
read_val = msm_camera_io_r(cci_dev->base +
CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR + reg_offset);
CDBG("%s line %d CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR %d len %d max %d\n",
__func__, __LINE__, read_val, len,
cci_dev->cci_i2c_queue_info[master][queue].max_queue_size);
if ((read_val + len + 1) > cci_dev->
cci_i2c_queue_info[master][queue].max_queue_size) {
uint32_t reg_val = 0;
uint32_t report_val = CCI_I2C_REPORT_CMD | (1 << 8);
CDBG("%s:%d CCI_I2C_REPORT_CMD\n", __func__, __LINE__);
msm_camera_io_w(report_val,
cci_dev->base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
reg_offset);
read_val++;
CDBG("%s:%d CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR %d\n",
__func__, __LINE__, read_val);
msm_camera_io_w(read_val, cci_dev->base +
CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset);
reg_val = 1 << ((master * 2) + queue);
CDBG("%s:%d CCI_QUEUE_START_ADDR\n", __func__, __LINE__);
msm_camera_io_w(reg_val, cci_dev->base + CCI_QUEUE_START_ADDR);
CDBG("%s line %d wait_for_completion_interruptible\n",
__func__, __LINE__);
rc = wait_for_completion_interruptible_timeout(&cci_dev->
cci_master_info[master].reset_complete, CCI_TIMEOUT);
if (rc <= 0) {
pr_err("%s: wait_for_completion_interruptible_timeout %d\n",
__func__, __LINE__);
if (rc == 0)
rc = -ETIMEDOUT;
return rc;
}
rc = cci_dev->cci_master_info[master].status;
if (rc < 0)
pr_err("%s failed rc %d\n", __func__, rc);
}
return rc;
}
static int32_t msm_cci_data_queue(struct cci_device *cci_dev,
struct msm_camera_cci_ctrl *c_ctrl, enum cci_i2c_queue_t queue)
{
uint16_t i = 0, j = 0, k = 0, h = 0, len = 0;
int32_t rc = 0;
uint32_t cmd = 0;
uint8_t data[10];
uint16_t reg_addr = 0;
struct msm_camera_cci_i2c_write_cfg *i2c_msg =
&c_ctrl->cfg.cci_i2c_write_cfg;
uint16_t cmd_size = i2c_msg->size;
struct msm_camera_i2c_reg_conf *i2c_cmd = i2c_msg->reg_conf_tbl;
enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master;
CDBG("%s addr type %d data type %d\n", __func__,
i2c_msg->addr_type, i2c_msg->data_type);
/* assume total size within the max queue */
while (cmd_size) {
CDBG("%s cmd_size %d addr 0x%x data 0x%x", __func__,
cmd_size, i2c_cmd->reg_addr, i2c_cmd->reg_data);
data[i++] = CCI_I2C_WRITE_CMD;
if (i2c_cmd->reg_addr)
reg_addr = i2c_cmd->reg_addr;
/* either byte or word addr */
if (i2c_msg->addr_type == MSM_CAMERA_I2C_BYTE_ADDR)
data[i++] = reg_addr;
else {
data[i++] = (reg_addr & 0xFF00) >> 8;
data[i++] = reg_addr & 0x00FF;
}
/* max of 10 data bytes */
do {
if (i2c_msg->data_type == MSM_CAMERA_I2C_BYTE_DATA) {
data[i++] = i2c_cmd->reg_data;
reg_addr++;
} else {
if ((i + 1) <= 10) {
data[i++] = (i2c_cmd->reg_data &
0xFF00) >> 8; /* MSB */
data[i++] = i2c_cmd->reg_data &
0x00FF; /* LSB */
reg_addr += 2;
} else
break;
}
i2c_cmd++;
} while (--cmd_size && !i2c_cmd->reg_addr && (i <= 10));
data[0] |= ((i-1) << 4);
len = ((i-1)/4) + 1;
rc = msm_cci_validate_queue(cci_dev, len, master, queue);
if (rc < 0) {
pr_err("%s: failed %d", __func__, __LINE__);
return rc;
}
for (h = 0, k = 0; h < len; h++) {
cmd = 0;
for (j = 0; (j < 4 && k < i); j++)
cmd |= (data[k++] << (j * 8));
CDBG("%s CCI_I2C_M0_Q0_LOAD_DATA_ADDR 0x%x\n",
__func__, cmd);
msm_camera_io_w(cmd, cci_dev->base +
CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
master * 0x200 + queue * 0x100);
}
i = 0;
}
return rc;
}
static int32_t msm_cci_write_i2c_queue(struct cci_device *cci_dev,
uint32_t val,
enum cci_i2c_master_t master,
enum cci_i2c_queue_t queue)
{
int32_t rc = 0;
uint32_t reg_offset = master * 0x200 + queue * 0x100;
CDBG("%s:%d called\n", __func__, __LINE__);
rc = msm_cci_validate_queue(cci_dev, 1, master, queue);
if (rc < 0) {
pr_err("%s: failed %d", __func__, __LINE__);
return rc;
}
CDBG("%s CCI_I2C_M0_Q0_LOAD_DATA_ADDR:val %x:%x\n",
__func__, CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
reg_offset, val);
msm_camera_io_w(val, cci_dev->base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
reg_offset);
return rc;
}
static int32_t msm_cci_i2c_read(struct v4l2_subdev *sd,
struct msm_camera_cci_ctrl *c_ctrl)
{
uint32_t rc = 0;
uint32_t val = 0;
int32_t read_words = 0, exp_words = 0;
int32_t index = 0, first_byte = 0;
uint32_t i = 0;
enum cci_i2c_master_t master;
enum cci_i2c_queue_t queue = QUEUE_1;
struct cci_device *cci_dev = NULL;
struct msm_camera_cci_i2c_read_cfg *read_cfg = NULL;
CDBG("%s line %d\n", __func__, __LINE__);
cci_dev = v4l2_get_subdevdata(sd);
master = c_ctrl->cci_info->cci_i2c_master;
read_cfg = &c_ctrl->cfg.cci_i2c_read_cfg;
mutex_lock(&cci_dev->cci_master_info[master].mutex);
CDBG("%s master %d, queue %d\n", __func__, master, queue);
CDBG("%s set param sid 0x%x retries %d id_map %d\n", __func__,
c_ctrl->cci_info->sid, c_ctrl->cci_info->retries,
c_ctrl->cci_info->id_map);
val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 |
c_ctrl->cci_info->retries << 16 |
c_ctrl->cci_info->id_map << 18;
rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
if (rc < 0) {
CDBG("%s failed line %d\n", __func__, __LINE__);
goto ERROR;
}
val = CCI_I2C_LOCK_CMD;
rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
if (rc < 0) {
CDBG("%s failed line %d\n", __func__, __LINE__);
goto ERROR;
}
if (read_cfg->addr_type == MSM_CAMERA_I2C_BYTE_ADDR)
val = CCI_I2C_WRITE_CMD | (read_cfg->addr_type << 4) |
((read_cfg->addr & 0xFF) << 8);
if (read_cfg->addr_type == MSM_CAMERA_I2C_WORD_ADDR)
val = CCI_I2C_WRITE_CMD | (read_cfg->addr_type << 4) |
(((read_cfg->addr & 0xFF00) >> 8) << 8) |
((read_cfg->addr & 0xFF) << 16);
rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
if (rc < 0) {
CDBG("%s failed line %d\n", __func__, __LINE__);
goto ERROR;
}
val = CCI_I2C_READ_CMD | (read_cfg->num_byte << 4);
rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
if (rc < 0) {
CDBG("%s failed line %d\n", __func__, __LINE__);
goto ERROR;
}
val = CCI_I2C_UNLOCK_CMD;
rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
if (rc < 0) {
CDBG("%s failed line %d\n", __func__, __LINE__);
goto ERROR;
}
val = msm_camera_io_r(cci_dev->base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR +
master * 0x200 + queue * 0x100);
CDBG("%s cur word cnt %x\n", __func__, val);
msm_camera_io_w(val, cci_dev->base + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR +
master * 0x200 + queue * 0x100);
val = 1 << ((master * 2) + queue);
msm_camera_io_w(val, cci_dev->base + CCI_QUEUE_START_ADDR);
CDBG("%s:%d E wait_for_completion_interruptible_timeout\n", __func__,
__LINE__);
rc = wait_for_completion_interruptible_timeout(&cci_dev->
cci_master_info[master].reset_complete, CCI_TIMEOUT);
if (rc <= 0) {
pr_err("%s: wait_for_completion_interruptible_timeout %d\n",
__func__, __LINE__);
if (rc == 0)
rc = -ETIMEDOUT;
return rc;
} else {
rc = 0;
}
CDBG("%s:%d E wait_for_completion_interruptible_timeout\n", __func__,
__LINE__);
read_words = msm_camera_io_r(cci_dev->base +
CCI_I2C_M0_READ_BUF_LEVEL_ADDR + master * 0x100);
exp_words = ((read_cfg->num_byte / 4) + 1);
if (read_words != exp_words) {
pr_err("%s:%d read_words = %d, exp words = %d\n", __func__,
__LINE__, read_words, exp_words);
memset(read_cfg->data, 0, read_cfg->num_byte);
rc = -EINVAL;
goto ERROR;
}
index = 0;
CDBG("%s index %d num_type %d\n", __func__, index,
read_cfg->num_byte);
first_byte = 0;
do {
val = msm_camera_io_r(cci_dev->base +
CCI_I2C_M0_READ_DATA_ADDR + master * 0x100);
CDBG("%s read val %x\n", __func__, val);
for (i = 0; (i < 4) && (index < read_cfg->num_byte); i++) {
CDBG("%s i %d index %d\n", __func__, i, index);
if (!first_byte) {
CDBG("%s sid %x\n", __func__, val & 0xFF);
first_byte++;
} else {
read_cfg->data[index] =
(val >> (i * 8)) & 0xFF;
CDBG("%s data[%d] %x\n", __func__, index,
read_cfg->data[index]);
index++;
}
}
} while (--read_words > 0);
ERROR:
mutex_unlock(&cci_dev->cci_master_info[master].mutex);
return rc;
}
static int32_t msm_cci_i2c_write(struct v4l2_subdev *sd,
struct msm_camera_cci_ctrl *c_ctrl)
{
int32_t rc = 0;
struct cci_device *cci_dev;
uint32_t val;
enum cci_i2c_master_t master;
enum cci_i2c_queue_t queue = QUEUE_0;
cci_dev = v4l2_get_subdevdata(sd);
master = c_ctrl->cci_info->cci_i2c_master;
CDBG("%s master %d, queue %d\n", __func__, master, queue);
CDBG("%s set param sid 0x%x retries %d id_map %d\n", __func__,
c_ctrl->cci_info->sid, c_ctrl->cci_info->retries,
c_ctrl->cci_info->id_map);
mutex_lock(&cci_dev->cci_master_info[master].mutex);
val = CCI_I2C_SET_PARAM_CMD | c_ctrl->cci_info->sid << 4 |
c_ctrl->cci_info->retries << 16 |
c_ctrl->cci_info->id_map << 18;
CDBG("%s:%d CCI_I2C_SET_PARAM_CMD\n", __func__, __LINE__);
rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
if (rc < 0) {
CDBG("%s failed line %d\n", __func__, __LINE__);
goto ERROR;
}
val = CCI_I2C_LOCK_CMD;
CDBG("%s:%d CCI_I2C_LOCK_CMD\n", __func__, __LINE__);
rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
if (rc < 0) {
CDBG("%s failed line %d\n", __func__, __LINE__);
goto ERROR;
}
msm_cci_data_queue(cci_dev, c_ctrl, queue);
val = CCI_I2C_UNLOCK_CMD;
CDBG("%s:%d CCI_I2C_UNLOCK_CMD\n", __func__, __LINE__);
rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
if (rc < 0) {
CDBG("%s failed line %d\n", __func__, __LINE__);
goto ERROR;
}
val = CCI_I2C_REPORT_CMD | (1 << 8);
CDBG("%s:%d CCI_I2C_REPORT_CMD\n", __func__, __LINE__);
rc = msm_cci_write_i2c_queue(cci_dev, val, master, queue);
if (rc < 0) {
CDBG("%s failed line %d\n", __func__, __LINE__);
goto ERROR;
}
val = msm_camera_io_r(cci_dev->base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR +
master * 0x200 + queue * 0x100);
CDBG("%s:%d cur word count %d\n", __func__, __LINE__, val);
CDBG("%s:%d CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR\n", __func__, __LINE__);
msm_camera_io_w(val, cci_dev->base + CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR +
master * 0x200 + queue * 0x100);
val = 1 << ((master * 2) + queue);
CDBG("%s:%d CCI_QUEUE_START_ADDR\n", __func__, __LINE__);
msm_camera_io_w(val, cci_dev->base + CCI_QUEUE_START_ADDR +
master*0x200 + queue * 0x100);
CDBG("%s:%d E wait_for_completion_interruptible\n",
__func__, __LINE__);
rc = wait_for_completion_interruptible_timeout(&cci_dev->
cci_master_info[master].reset_complete, CCI_TIMEOUT);
if (rc <= 0) {
pr_err("%s: wait_for_completion_interruptible_timeout %d\n",
__func__, __LINE__);
if (rc == 0)
rc = -ETIMEDOUT;
return rc;
} else {
rc = 0;
}
CDBG("%s:%d X wait_for_completion_interruptible\n", __func__,
__LINE__);
ERROR:
mutex_unlock(&cci_dev->cci_master_info[master].mutex);
return rc;
}
static int msm_cci_subdev_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *chip)
{
BUG_ON(!chip);
chip->ident = V4L2_IDENT_CCI;
chip->revision = 0;
return 0;
}
static struct msm_cam_clk_info cci_clk_info[] = {
{"camss_top_ahb_clk", -1},
{"cci_src_clk", 19200000},
{"cci_ahb_clk", -1},
{"cci_clk", -1},
};
static int32_t msm_cci_init(struct v4l2_subdev *sd)
{
int rc = 0;
struct cci_device *cci_dev;
cci_dev = v4l2_get_subdevdata(sd);
CDBG("%s line %d\n", __func__, __LINE__);
if (!cci_dev) {
pr_err("%s cci device NULL\n", __func__);
rc = -ENOMEM;
return rc;
}
if (cci_dev->ref_count++) {
CDBG("%s ref_count %d\n", __func__, cci_dev->ref_count);
return 0;
}
rc = msm_camera_request_gpio_table(cci_dev->cci_gpio_tbl,
cci_dev->cci_gpio_tbl_size, 1);
if (rc < 0) {
cci_dev->ref_count--;
CDBG("%s: request gpio failed\n", __func__);
goto clk_enable_failed;
}
rc = msm_cam_clk_enable(&cci_dev->pdev->dev, cci_clk_info,
cci_dev->cci_clk, ARRAY_SIZE(cci_clk_info), 1);
if (rc < 0) {
cci_dev->ref_count--;
CDBG("%s: clk enable failed\n", __func__);
goto clk_enable_failed;
}
enable_irq(cci_dev->irq->start);
cci_dev->hw_version = msm_camera_io_r(cci_dev->base +
CCI_HW_VERSION_ADDR);
cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE;
msm_camera_io_w(CCI_RESET_CMD_RMSK, cci_dev->base + CCI_RESET_CMD_ADDR);
msm_camera_io_w(0x1, cci_dev->base + CCI_RESET_CMD_ADDR);
rc = wait_for_completion_interruptible_timeout(
&cci_dev->cci_master_info[MASTER_0].reset_complete,
CCI_TIMEOUT);
if (rc <= 0) {
pr_err("%s: wait_for_completion_interruptible_timeout %d\n",
__func__, __LINE__);
if (rc == 0)
rc = -ETIMEDOUT;
return rc;
}
msm_cci_set_clk_param(cci_dev);
msm_camera_io_w(CCI_IRQ_MASK_0_RMSK,
cci_dev->base + CCI_IRQ_MASK_0_ADDR);
msm_camera_io_w(CCI_IRQ_MASK_0_RMSK,
cci_dev->base + CCI_IRQ_CLEAR_0_ADDR);
msm_camera_io_w(0x1, cci_dev->base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR);
cci_dev->cci_state = CCI_STATE_ENABLED;
return 0;
clk_enable_failed:
return rc;
}
static int32_t msm_cci_release(struct v4l2_subdev *sd)
{
struct cci_device *cci_dev;
cci_dev = v4l2_get_subdevdata(sd);
if (!cci_dev->ref_count || cci_dev->cci_state != CCI_STATE_ENABLED) {
pr_err("%s invalid ref count %d / cci state %d\n",
__func__, cci_dev->ref_count, cci_dev->cci_state);
return -EINVAL;
}
if (--cci_dev->ref_count) {
CDBG("%s ref_count %d\n", __func__, cci_dev->ref_count);
return 0;
}
disable_irq(cci_dev->irq->start);
msm_cam_clk_enable(&cci_dev->pdev->dev, cci_clk_info,
cci_dev->cci_clk, ARRAY_SIZE(cci_clk_info), 0);
msm_camera_request_gpio_table(cci_dev->cci_gpio_tbl,
cci_dev->cci_gpio_tbl_size, 0);
cci_dev->cci_state = CCI_STATE_DISABLED;
return 0;
}
static int32_t msm_cci_config(struct v4l2_subdev *sd,
struct msm_camera_cci_ctrl *cci_ctrl)
{
int32_t rc = 0;
CDBG("%s line %d cmd %d\n", __func__, __LINE__,
cci_ctrl->cmd);
switch (cci_ctrl->cmd) {
case MSM_CCI_INIT:
rc = msm_cci_init(sd);
break;
case MSM_CCI_RELEASE:
rc = msm_cci_release(sd);
break;
case MSM_CCI_SET_SID:
break;
case MSM_CCI_SET_FREQ:
rc = msm_cci_i2c_set_freq(sd, cci_ctrl);
break;
case MSM_CCI_SET_SYNC_CID:
rc = msm_cci_i2c_config_sync_timer(sd, cci_ctrl);
break;
case MSM_CCI_I2C_READ:
rc = msm_cci_i2c_read(sd, cci_ctrl);
break;
case MSM_CCI_I2C_WRITE:
rc = msm_cci_i2c_write(sd, cci_ctrl);
break;
case MSM_CCI_GPIO_WRITE:
break;
default:
rc = -ENOIOCTLCMD;
}
CDBG("%s line %d rc %d\n", __func__, __LINE__, rc);
cci_ctrl->status = rc;
return rc;
}
static irqreturn_t msm_cci_irq(int irq_num, void *data)
{
uint32_t irq;
struct cci_device *cci_dev = data;
irq = msm_camera_io_r(cci_dev->base + CCI_IRQ_STATUS_0_ADDR);
msm_camera_io_w(irq, cci_dev->base + CCI_IRQ_CLEAR_0_ADDR);
msm_camera_io_w(0x1, cci_dev->base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR);
msm_camera_io_w(0x0, cci_dev->base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR);
CDBG("%s CCI_I2C_M0_STATUS_ADDR = 0x%x\n", __func__, irq);
if (irq & CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK) {
if (cci_dev->cci_master_info[MASTER_0].reset_pending == TRUE) {
cci_dev->cci_master_info[MASTER_0].reset_pending =
FALSE;
complete(&cci_dev->cci_master_info[MASTER_0].
reset_complete);
}
if (cci_dev->cci_master_info[MASTER_1].reset_pending == TRUE) {
cci_dev->cci_master_info[MASTER_1].reset_pending =
FALSE;
complete(&cci_dev->cci_master_info[MASTER_1].
reset_complete);
}
} else if ((irq & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK) ||
(irq & CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK) ||
(irq & CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK)) {
cci_dev->cci_master_info[MASTER_0].status = 0;
complete(&cci_dev->cci_master_info[MASTER_0].reset_complete);
} else if ((irq & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) ||
(irq & CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK) ||
(irq & CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK)) {
cci_dev->cci_master_info[MASTER_1].status = 0;
complete(&cci_dev->cci_master_info[MASTER_1].reset_complete);
} else if ((irq & CCI_IRQ_STATUS_0_I2C_M0_Q0_NACK_ERR_BMSK) ||
(irq & CCI_IRQ_STATUS_0_I2C_M0_Q1_NACK_ERR_BMSK)) {
cci_dev->cci_master_info[MASTER_0].status = -EINVAL;
msm_camera_io_w(CCI_M0_HALT_REQ_RMSK,
cci_dev->base + CCI_HALT_REQ_ADDR);
} else if ((irq & CCI_IRQ_STATUS_0_I2C_M1_Q0_NACK_ERR_BMSK) ||
(irq & CCI_IRQ_STATUS_0_I2C_M1_Q1_NACK_ERR_BMSK)) {
cci_dev->cci_master_info[MASTER_1].status = -EINVAL;
msm_camera_io_w(CCI_M1_HALT_REQ_RMSK,
cci_dev->base + CCI_HALT_REQ_ADDR);
} else if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK) {
cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE;
msm_camera_io_w(CCI_M0_RESET_RMSK,
cci_dev->base + CCI_RESET_CMD_ADDR);
} else if (irq & CCI_IRQ_STATUS_0_I2C_M1_Q0Q1_HALT_ACK_BMSK) {
cci_dev->cci_master_info[MASTER_1].reset_pending = TRUE;
msm_camera_io_w(CCI_M1_RESET_RMSK,
cci_dev->base + CCI_RESET_CMD_ADDR);
} else {
pr_err("%s unhandled irq 0x%x\n", __func__, irq);
cci_dev->cci_master_info[MASTER_0].status = 0;
complete(&cci_dev->cci_master_info[MASTER_0].reset_complete);
cci_dev->cci_master_info[MASTER_1].status = 0;
complete(&cci_dev->cci_master_info[MASTER_1].reset_complete);
}
return IRQ_HANDLED;
}
static int msm_cci_irq_routine(struct v4l2_subdev *sd, u32 status,
bool *handled)
{
struct cci_device *cci_dev = v4l2_get_subdevdata(sd);
irqreturn_t ret;
CDBG("%s line %d\n", __func__, __LINE__);
ret = msm_cci_irq(cci_dev->irq->start, cci_dev);
CDBG("%s: msm_cci_irq return %d\n", __func__, ret);
*handled = TRUE;
return 0;
}
static long msm_cci_subdev_ioctl(struct v4l2_subdev *sd,
unsigned int cmd, void *arg)
{
int32_t rc = 0;
CDBG("%s line %d\n", __func__, __LINE__);
switch (cmd) {
case VIDIOC_MSM_CCI_CFG:
rc = msm_cci_config(sd, arg);
break;
default:
rc = -ENOIOCTLCMD;
}
CDBG("%s line %d rc %d\n", __func__, __LINE__, rc);
return rc;
}
static struct v4l2_subdev_core_ops msm_cci_subdev_core_ops = {
.g_chip_ident = &msm_cci_subdev_g_chip_ident,
.ioctl = &msm_cci_subdev_ioctl,
.interrupt_service_routine = msm_cci_irq_routine,
};
static const struct v4l2_subdev_ops msm_cci_subdev_ops = {
.core = &msm_cci_subdev_core_ops,
};
static const struct v4l2_subdev_internal_ops msm_cci_internal_ops;
static void msm_cci_init_cci_params(struct cci_device *new_cci_dev)
{
uint8_t i = 0, j = 0;
for (i = 0; i < NUM_MASTERS; i++) {
new_cci_dev->cci_master_info[i].status = 0;
mutex_init(&new_cci_dev->cci_master_info[i].mutex);
init_completion(&new_cci_dev->
cci_master_info[i].reset_complete);
for (j = 0; j < NUM_QUEUES; j++) {
if (j == QUEUE_0)
new_cci_dev->cci_i2c_queue_info[i][j].
max_queue_size = CCI_I2C_QUEUE_0_SIZE;
else
new_cci_dev->cci_i2c_queue_info[i][j].
max_queue_size = CCI_I2C_QUEUE_1_SIZE;
}
}
return;
}
static int32_t msm_cci_init_gpio_params(struct cci_device *cci_dev)
{
int32_t rc = 0, i = 0;
uint32_t *val_array = NULL;
uint8_t tbl_size = 0;
struct device_node *of_node = cci_dev->pdev->dev.of_node;
struct gpio *gpio_tbl = NULL;
cci_dev->cci_gpio_tbl_size = tbl_size = of_gpio_count(of_node);
CDBG("%s gpio count %d\n", __func__, tbl_size);
if (!tbl_size) {
pr_err("%s:%d gpio count 0\n", __func__, __LINE__);
return 0;
}
gpio_tbl = cci_dev->cci_gpio_tbl =
kzalloc(sizeof(struct gpio) * tbl_size, GFP_KERNEL);
if (!gpio_tbl) {
pr_err("%s failed %d\n", __func__, __LINE__);
return 0;
}
for (i = 0; i < tbl_size; i++) {
gpio_tbl[i].gpio = of_get_gpio(of_node, i);
CDBG("%s gpio_tbl[%d].gpio = %d\n", __func__, i,
gpio_tbl[i].gpio);
}
val_array = kzalloc(sizeof(uint32_t) * tbl_size, GFP_KERNEL);
if (!val_array) {
pr_err("%s failed %d\n", __func__, __LINE__);
rc = -ENOMEM;
goto ERROR1;
}
rc = of_property_read_u32_array(of_node, "qcom,gpio-tbl-flags",
val_array, tbl_size);
if (rc < 0) {
pr_err("%s failed %d\n", __func__, __LINE__);
goto ERROR2;
}
for (i = 0; i < tbl_size; i++) {
gpio_tbl[i].flags = val_array[i];
CDBG("%s gpio_tbl[%d].flags = %ld\n", __func__, i,
gpio_tbl[i].flags);
}
for (i = 0; i < tbl_size; i++) {
rc = of_property_read_string_index(of_node,
"qcom,gpio-tbl-label", i, &gpio_tbl[i].label);
CDBG("%s gpio_tbl[%d].label = %s\n", __func__, i,
gpio_tbl[i].label);
if (rc < 0) {
pr_err("%s failed %d\n", __func__, __LINE__);
goto ERROR2;
}
}
kfree(val_array);
return rc;
ERROR2:
kfree(val_array);
ERROR1:
kfree(cci_dev->cci_gpio_tbl);
cci_dev->cci_gpio_tbl = NULL;
cci_dev->cci_gpio_tbl_size = 0;
return rc;
}
static void msm_cci_init_clk_params(struct cci_device *cci_dev)
{
int32_t rc = 0;
uint32_t val = 0;
struct device_node *of_node = cci_dev->pdev->dev.of_node;
rc = of_property_read_u32(of_node, "qcom,hw-thigh", &val);
CDBG("%s qcom,hw-thigh %d, rc %d\n", __func__, val, rc);
if (!rc)
cci_dev->cci_clk_params.hw_thigh = val;
rc = of_property_read_u32(of_node, "qcom,hw-tlow", &val);
CDBG("%s qcom,hw-tlow %d, rc %d\n", __func__, val, rc);
if (!rc)
cci_dev->cci_clk_params.hw_tlow = val;
rc = of_property_read_u32(of_node, "qcom,hw-tsu-sto", &val);
CDBG("%s qcom,hw-tsu-sto %d, rc %d\n", __func__, val, rc);
if (!rc)
cci_dev->cci_clk_params.hw_tsu_sto = val;
rc = of_property_read_u32(of_node, "qcom,hw-tsu-sta", &val);
CDBG("%s qcom,hw-tsu-sta %d, rc %d\n", __func__, val, rc);
if (!rc)
cci_dev->cci_clk_params.hw_tsu_sta = val;
rc = of_property_read_u32(of_node, "qcom,hw-thd-dat", &val);
CDBG("%s qcom,hw-thd-dat %d, rc %d\n", __func__, val, rc);
if (!rc)
cci_dev->cci_clk_params.hw_thd_dat = val;
rc = of_property_read_u32(of_node, "qcom,hw-thd-sta", &val);
CDBG("%s qcom,hwthd-sta %d, rc %d\n", __func__, val, rc);
if (!rc)
cci_dev->cci_clk_params.hw_thd_sta = val;
rc = of_property_read_u32(of_node, "qcom,hw-tbuf", &val);
CDBG("%s qcom,hw-tbuf %d, rc %d\n", __func__, val, rc);
if (!rc)
cci_dev->cci_clk_params.hw_tbuf = val;
rc = of_property_read_u32(of_node, "qcom,hw-scl-stretch-en", &val);
CDBG("%s qcom,hw-scl-stretch-en %d, rc %d\n", __func__, val, rc);
if (!rc)
cci_dev->cci_clk_params.hw_scl_stretch_en = val;
rc = of_property_read_u32(of_node, "qcom,hw-trdhld", &val);
CDBG("%s qcom,hw-trdhld %d, rc %d\n", __func__, val, rc);
if (!rc)
cci_dev->cci_clk_params.hw_trdhld = val;
rc = of_property_read_u32(of_node, "qcom,hw-tsp", &val);
CDBG("%s qcom,hw-tsp %d, rc %d\n", __func__, val, rc);
if (!rc)
cci_dev->cci_clk_params.hw_tsp = val;
return;
}
struct v4l2_subdev *msm_cci_get_subdev(void)
{
return g_cci_subdev;
}
static int msm_cci_probe(struct platform_device *pdev)
{
struct cci_device *new_cci_dev;
int rc = 0;
pr_err("%s: pdev %p device id = %d\n", __func__, pdev, pdev->id);
new_cci_dev = kzalloc(sizeof(struct cci_device), GFP_KERNEL);
if (!new_cci_dev) {
CDBG("%s: no enough memory\n", __func__);
return -ENOMEM;
}
v4l2_subdev_init(&new_cci_dev->msm_sd.sd, &msm_cci_subdev_ops);
new_cci_dev->msm_sd.sd.internal_ops = &msm_cci_internal_ops;
snprintf(new_cci_dev->msm_sd.sd.name,
ARRAY_SIZE(new_cci_dev->msm_sd.sd.name), "msm_cci");
v4l2_set_subdevdata(&new_cci_dev->msm_sd.sd, new_cci_dev);
platform_set_drvdata(pdev, &new_cci_dev->msm_sd.sd);
CDBG("%s sd %p\n", __func__, &new_cci_dev->msm_sd.sd);
if (pdev->dev.of_node)
of_property_read_u32((&pdev->dev)->of_node,
"cell-index", &pdev->id);
new_cci_dev->mem = platform_get_resource_byname(pdev,
IORESOURCE_MEM, "cci");
if (!new_cci_dev->mem) {
CDBG("%s: no mem resource?\n", __func__);
rc = -ENODEV;
goto cci_no_resource;
}
new_cci_dev->irq = platform_get_resource_byname(pdev,
IORESOURCE_IRQ, "cci");
CDBG("%s line %d cci irq start %d end %d\n", __func__,
__LINE__,
new_cci_dev->irq->start,
new_cci_dev->irq->end);
if (!new_cci_dev->irq) {
CDBG("%s: no irq resource?\n", __func__);
rc = -ENODEV;
goto cci_no_resource;
}
new_cci_dev->io = request_mem_region(new_cci_dev->mem->start,
resource_size(new_cci_dev->mem), pdev->name);
if (!new_cci_dev->io) {
CDBG("%s: no valid mem region\n", __func__);
rc = -EBUSY;
goto cci_no_resource;
}
new_cci_dev->base = ioremap(new_cci_dev->mem->start,
resource_size(new_cci_dev->mem));
if (!new_cci_dev->base) {
rc = -ENOMEM;
goto cci_release_mem;
}
rc = request_irq(new_cci_dev->irq->start, msm_cci_irq,
IRQF_TRIGGER_RISING, "cci", new_cci_dev);
if (rc < 0) {
CDBG("%s: irq request fail\n", __func__);
rc = -EBUSY;
goto cci_release_mem;
}
disable_irq(new_cci_dev->irq->start);
msm_sd_register(&new_cci_dev->msm_sd);
new_cci_dev->pdev = pdev;
msm_cci_init_cci_params(new_cci_dev);
msm_cci_init_clk_params(new_cci_dev);
msm_cci_init_gpio_params(new_cci_dev);
rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
if (rc)
pr_err("%s: failed to add child nodes, rc=%d\n", __func__, rc);
new_cci_dev->cci_state = CCI_STATE_DISABLED;
g_cci_subdev = &new_cci_dev->msm_sd.sd;
CDBG("%s cci subdev %p\n", __func__, &new_cci_dev->msm_sd.sd);
CDBG("%s line %d\n", __func__, __LINE__);
return 0;
cci_release_mem:
release_mem_region(new_cci_dev->mem->start,
resource_size(new_cci_dev->mem));
cci_no_resource:
kfree(new_cci_dev);
return 0;
}
static int __exit msm_cci_exit(struct platform_device *pdev)
{
struct v4l2_subdev *subdev = platform_get_drvdata(pdev);
struct cci_device *cci_dev =
v4l2_get_subdevdata(subdev);
release_mem_region(cci_dev->mem->start, resource_size(cci_dev->mem));
kfree(cci_dev);
return 0;
}
static const struct of_device_id msm_cci_dt_match[] = {
{.compatible = "qcom,cci"},
{}
};
MODULE_DEVICE_TABLE(of, msm_cci_dt_match);
static struct platform_driver cci_driver = {
.probe = msm_cci_probe,
.remove = msm_cci_exit,
.driver = {
.name = MSM_CCI_DRV_NAME,
.owner = THIS_MODULE,
.of_match_table = msm_cci_dt_match,
},
};
static int __init msm_cci_init_module(void)
{
return platform_driver_register(&cci_driver);
}
static void __exit msm_cci_exit_module(void)
{
platform_driver_unregister(&cci_driver);
}
module_init(msm_cci_init_module);
module_exit(msm_cci_exit_module);
MODULE_DESCRIPTION("MSM CCI driver");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,189 @@
/* Copyright (c) 2012-2013, 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.
*/
#ifndef MSM_CCI_H
#define MSM_CCI_H
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <media/v4l2-subdev.h>
#include <media/msm_cam_sensor.h>
#include "msm_sd.h"
#define NUM_MASTERS 2
#define NUM_QUEUES 2
#define TRUE 1
#define FALSE 0
enum cci_i2c_master_t {
MASTER_0,
MASTER_1,
};
enum cci_i2c_queue_t {
QUEUE_0,
QUEUE_1,
};
struct msm_camera_cci_client {
struct v4l2_subdev *cci_subdev;
uint32_t freq;
enum cci_i2c_master_t cci_i2c_master;
uint16_t sid;
uint16_t cid;
uint32_t timeout;
uint16_t retries;
uint16_t id_map;
};
enum msm_cci_cmd_type {
MSM_CCI_INIT,
MSM_CCI_RELEASE,
MSM_CCI_SET_SID,
MSM_CCI_SET_FREQ,
MSM_CCI_SET_SYNC_CID,
MSM_CCI_I2C_READ,
MSM_CCI_I2C_WRITE,
MSM_CCI_GPIO_WRITE,
};
struct msm_camera_cci_wait_sync_cfg {
uint16_t line;
uint16_t delay;
};
struct msm_camera_cci_gpio_cfg {
uint16_t gpio_queue;
uint16_t i2c_queue;
};
struct msm_camera_cci_i2c_write_cfg {
struct msm_camera_i2c_reg_conf *reg_conf_tbl;
enum msm_camera_i2c_reg_addr_type addr_type;
enum msm_camera_i2c_data_type data_type;
uint16_t size;
};
struct msm_camera_cci_i2c_read_cfg {
uint16_t addr;
enum msm_camera_i2c_reg_addr_type addr_type;
uint8_t *data;
uint16_t num_byte;
};
struct msm_camera_cci_i2c_queue_info {
uint32_t max_queue_size;
uint32_t report_id;
uint32_t irq_en;
uint32_t capture_rep_data;
};
struct msm_camera_cci_ctrl {
int32_t status;
struct msm_camera_cci_client *cci_info;
enum msm_cci_cmd_type cmd;
union {
struct msm_camera_cci_i2c_write_cfg cci_i2c_write_cfg;
struct msm_camera_cci_i2c_read_cfg cci_i2c_read_cfg;
struct msm_camera_cci_wait_sync_cfg cci_wait_sync_cfg;
struct msm_camera_cci_gpio_cfg gpio_cfg;
} cfg;
};
struct msm_camera_cci_master_info {
uint32_t status;
uint8_t reset_pending;
struct mutex mutex;
struct completion reset_complete;
};
struct msm_cci_clk_params_t {
uint16_t hw_thigh;
uint16_t hw_tlow;
uint16_t hw_tsu_sto;
uint16_t hw_tsu_sta;
uint16_t hw_thd_dat;
uint16_t hw_thd_sta;
uint16_t hw_tbuf;
uint8_t hw_scl_stretch_en;
uint8_t hw_trdhld;
uint8_t hw_tsp;
};
enum msm_cci_state_t {
CCI_STATE_ENABLED,
CCI_STATE_DISABLED,
};
struct cci_device {
struct platform_device *pdev;
struct msm_sd_subdev msm_sd;
struct v4l2_subdev subdev;
struct resource *mem;
struct resource *irq;
struct resource *io;
void __iomem *base;
uint32_t hw_version;
uint8_t ref_count;
enum msm_cci_state_t cci_state;
struct clk *cci_clk[5];
struct msm_camera_cci_i2c_queue_info
cci_i2c_queue_info[NUM_MASTERS][NUM_QUEUES];
struct msm_camera_cci_master_info cci_master_info[NUM_MASTERS];
struct msm_cci_clk_params_t cci_clk_params;
struct gpio *cci_gpio_tbl;
uint8_t cci_gpio_tbl_size;
};
enum msm_cci_i2c_cmd_type {
CCI_I2C_SET_PARAM_CMD = 1,
CCI_I2C_WAIT_CMD,
CCI_I2C_WAIT_SYNC_CMD,
CCI_I2C_WAIT_GPIO_EVENT_CMD,
CCI_I2C_TRIG_I2C_EVENT_CMD,
CCI_I2C_LOCK_CMD,
CCI_I2C_UNLOCK_CMD,
CCI_I2C_REPORT_CMD,
CCI_I2C_WRITE_CMD,
CCI_I2C_READ_CMD,
CCI_I2C_WRITE_DISABLE_P_CMD,
CCI_I2C_READ_DISABLE_P_CMD,
CCI_I2C_WRITE_CMD2,
CCI_I2C_WRITE_CMD3,
CCI_I2C_REPEAT_CMD,
CCI_I2C_INVALID_CMD,
};
enum msm_cci_gpio_cmd_type {
CCI_GPIO_SET_PARAM_CMD = 1,
CCI_GPIO_WAIT_CMD,
CCI_GPIO_WAIT_SYNC_CMD,
CCI_GPIO_WAIT_GPIO_IN_EVENT_CMD,
CCI_GPIO_WAIT_I2C_Q_TRIG_EVENT_CMD,
CCI_GPIO_OUT_CMD,
CCI_GPIO_TRIG_EVENT_CMD,
CCI_GPIO_REPORT_CMD,
CCI_GPIO_REPEAT_CMD,
CCI_GPIO_CONTINUE_CMD,
CCI_GPIO_INVALID_CMD,
};
struct v4l2_subdev *msm_cci_get_subdev(void);
#define VIDIOC_MSM_CCI_CFG \
_IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct msm_camera_cci_ctrl *)
#endif

View File

@ -0,0 +1,3 @@
ccflags-y += -Idrivers/media/platform/msm/camera_v2/
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci
obj-$(CONFIG_MSMB_CAMERA) += msm_camera_io_util.o msm_camera_cci_i2c.o msm_camera_qup_i2c.o msm_camera_i2c_mux.o

View File

@ -0,0 +1,284 @@
/* Copyright (c) 2011-2013, 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 <mach/camera2.h>
#include "msm_camera_i2c.h"
#include "msm_cci.h"
#define CONFIG_MSMB_CAMERA_DEBUG
#undef CDBG
#ifdef CONFIG_MSMB_CAMERA_DEBUG
#define CDBG(fmt, args...) pr_debug(fmt, ##args)
#define S_I2C_DBG(fmt, args...) pr_debug(fmt, ##args)
#else
#define CDBG(fmt, args...) do { } while (0)
#define S_I2C_DBG(fmt, args...) do { } while (0)
#endif
int32_t msm_camera_cci_i2c_read(struct msm_camera_i2c_client *client,
uint16_t addr, uint16_t *data,
enum msm_camera_i2c_data_type data_type)
{
int32_t rc = -EFAULT;
unsigned char buf[client->addr_type+data_type];
struct msm_camera_cci_ctrl cci_ctrl;
if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
|| (data_type != MSM_CAMERA_I2C_BYTE_DATA
&& data_type != MSM_CAMERA_I2C_WORD_DATA))
return rc;
cci_ctrl.cmd = MSM_CCI_I2C_READ;
cci_ctrl.cci_info = client->cci_client;
cci_ctrl.cfg.cci_i2c_read_cfg.addr = addr;
cci_ctrl.cfg.cci_i2c_read_cfg.addr_type = client->addr_type;
cci_ctrl.cfg.cci_i2c_read_cfg.data = buf;
cci_ctrl.cfg.cci_i2c_read_cfg.num_byte = data_type;
rc = v4l2_subdev_call(client->cci_client->cci_subdev,
core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
if (rc < 0) {
pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc);
return rc;
}
rc = cci_ctrl.status;
if (data_type == MSM_CAMERA_I2C_BYTE_DATA)
*data = buf[0];
else
*data = buf[0] << 8 | buf[1];
S_I2C_DBG("%s addr = 0x%x data: 0x%x\n", __func__, addr, *data);
return rc;
}
int32_t msm_camera_cci_i2c_read_seq(struct msm_camera_i2c_client *client,
uint16_t addr, uint8_t *data, uint16_t num_byte)
{
int32_t rc = -EFAULT;
unsigned char buf[client->addr_type+num_byte];
int i;
struct msm_camera_cci_ctrl cci_ctrl;
if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
|| num_byte == 0)
return rc;
cci_ctrl.cmd = MSM_CCI_I2C_READ;
cci_ctrl.cci_info = client->cci_client;
cci_ctrl.cfg.cci_i2c_read_cfg.addr = addr;
cci_ctrl.cfg.cci_i2c_read_cfg.addr_type = client->addr_type;
cci_ctrl.cfg.cci_i2c_read_cfg.data = buf;
cci_ctrl.cfg.cci_i2c_read_cfg.num_byte = num_byte;
rc = v4l2_subdev_call(client->cci_client->cci_subdev,
core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
CDBG("%s line %d rc = %d\n", __func__, __LINE__, rc);
rc = cci_ctrl.status;
S_I2C_DBG("%s addr = 0x%x", __func__, addr);
for (i = 0; i < num_byte; i++) {
data[i] = buf[i];
S_I2C_DBG("Byte %d: 0x%x\n", i, buf[i]);
S_I2C_DBG("Data: 0x%x\n", data[i]);
}
return rc;
}
int32_t msm_camera_cci_i2c_write(struct msm_camera_i2c_client *client,
uint16_t addr, uint16_t data,
enum msm_camera_i2c_data_type data_type)
{
int32_t rc = -EFAULT;
struct msm_camera_cci_ctrl cci_ctrl;
struct msm_camera_i2c_reg_conf reg_conf_tbl;
if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
|| (data_type != MSM_CAMERA_I2C_BYTE_DATA
&& data_type != MSM_CAMERA_I2C_WORD_DATA))
return rc;
CDBG("%s:%d reg addr = 0x%x data type: %d\n",
__func__, __LINE__, addr, data_type);
reg_conf_tbl.reg_addr = addr;
reg_conf_tbl.reg_data = data;
cci_ctrl.cmd = MSM_CCI_I2C_WRITE;
cci_ctrl.cci_info = client->cci_client;
cci_ctrl.cfg.cci_i2c_write_cfg.reg_conf_tbl = &reg_conf_tbl;
cci_ctrl.cfg.cci_i2c_write_cfg.data_type = data_type;
cci_ctrl.cfg.cci_i2c_write_cfg.addr_type = client->addr_type;
cci_ctrl.cfg.cci_i2c_write_cfg.size = 1;
rc = v4l2_subdev_call(client->cci_client->cci_subdev,
core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
if (rc < 0) {
pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc);
return rc;
}
rc = cci_ctrl.status;
return rc;
}
int32_t msm_camera_cci_i2c_write_seq(struct msm_camera_i2c_client *client,
uint16_t addr, uint8_t *data, uint16_t num_byte)
{
int32_t rc = -EFAULT;
uint8_t i = 0;
struct msm_camera_cci_ctrl cci_ctrl;
struct msm_camera_i2c_reg_conf reg_conf_tbl[num_byte];
if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
|| num_byte == 0)
return rc;
S_I2C_DBG("%s reg addr = 0x%x num bytes: %d\n",
__func__, addr, num_byte);
reg_conf_tbl[0].reg_addr = addr;
for (i = 0; i < num_byte; i++)
reg_conf_tbl[i].reg_data = data[i];
cci_ctrl.cmd = MSM_CCI_I2C_WRITE;
cci_ctrl.cci_info = client->cci_client;
cci_ctrl.cfg.cci_i2c_write_cfg.reg_conf_tbl = reg_conf_tbl;
cci_ctrl.cfg.cci_i2c_write_cfg.size = num_byte;
rc = v4l2_subdev_call(client->cci_client->cci_subdev,
core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
CDBG("%s line %d rc = %d\n", __func__, __LINE__, rc);
rc = cci_ctrl.status;
return rc;
}
int32_t msm_camera_cci_i2c_write_table(
struct msm_camera_i2c_client *client,
struct msm_camera_i2c_reg_setting *write_setting)
{
int i;
int32_t rc = -EFAULT;
struct msm_camera_i2c_reg_array *reg_setting;
uint16_t client_addr_type;
if (!client || !write_setting)
return rc;
if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
&& write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
|| (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA
&& write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA))
return rc;
reg_setting = write_setting->reg_setting;
client_addr_type = client->addr_type;
client->addr_type = write_setting->addr_type;
for (i = 0; i < write_setting->size; i++) {
rc = msm_camera_cci_i2c_write(client, reg_setting->reg_addr,
reg_setting->reg_data, write_setting->data_type);
if (rc < 0)
return rc;
reg_setting++;
}
if (write_setting->delay > 20)
msleep(write_setting->delay);
else if (write_setting->delay)
usleep_range(write_setting->delay * 1000, (write_setting->delay
* 1000) + 1000);
client->addr_type = client_addr_type;
return rc;
}
int32_t msm_camera_cci_i2c_write_seq_table(
struct msm_camera_i2c_client *client,
struct msm_camera_i2c_seq_reg_setting *write_setting)
{
int i;
int32_t rc = -EFAULT;
struct msm_camera_i2c_seq_reg_array *reg_setting;
uint16_t client_addr_type;
if (!client || !write_setting)
return rc;
if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
&& write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR)) {
pr_err("%s Invalide addr type %d\n", __func__,
write_setting->addr_type);
return rc;
}
reg_setting = write_setting->reg_setting;
client_addr_type = client->addr_type;
client->addr_type = write_setting->addr_type;
for (i = 0; i < write_setting->size; i++) {
rc = msm_camera_cci_i2c_write_seq(client, reg_setting->reg_addr,
reg_setting->reg_data, reg_setting->reg_data_size);
if (rc < 0)
return rc;
reg_setting++;
}
if (write_setting->delay > 20)
msleep(write_setting->delay);
else if (write_setting->delay)
usleep_range(write_setting->delay * 1000, (write_setting->delay
* 1000) + 1000);
client->addr_type = client_addr_type;
return rc;
}
int32_t msm_camera_cci_i2c_write_table_w_microdelay(
struct msm_camera_i2c_client *client,
struct msm_camera_i2c_reg_tbl *reg_tbl, uint16_t size,
enum msm_camera_i2c_data_type data_type)
{
int i;
int32_t rc = -EFAULT;
if (!client || !reg_tbl)
return rc;
if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
|| (data_type != MSM_CAMERA_I2C_BYTE_DATA
&& data_type != MSM_CAMERA_I2C_WORD_DATA))
return rc;
for (i = 0; i < size; i++) {
rc = msm_camera_cci_i2c_write(client, reg_tbl->reg_addr,
reg_tbl->reg_data, data_type);
if (rc < 0)
return rc;
if (reg_tbl->delay)
usleep_range(reg_tbl->delay, reg_tbl->delay + 1000);
reg_tbl++;
}
return rc;
}
int32_t msm_sensor_cci_i2c_util(struct msm_camera_i2c_client *client,
uint16_t cci_cmd)
{
int32_t rc = 0;
struct msm_camera_cci_ctrl cci_ctrl;
CDBG("%s line %d\n", __func__, __LINE__);
cci_ctrl.cmd = cci_cmd;
cci_ctrl.cci_info = client->cci_client;
rc = v4l2_subdev_call(client->cci_client->cci_subdev,
core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl);
if (rc < 0) {
pr_err("%s line %d rc = %d\n", __func__, __LINE__, rc);
return rc;
}
return cci_ctrl.status;
}

View File

@ -0,0 +1,108 @@
/* Copyright (c) 2011-2013, 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.
*/
#ifndef MSM_CAMERA_CCI_I2C_H
#define MSM_CAMERA_CCI_I2C_H
#include <linux/delay.h>
#include <media/v4l2-subdev.h>
#include <media/msm_cam_sensor.h>
struct msm_camera_i2c_client {
struct msm_camera_i2c_fn_t *i2c_func_tbl;
struct i2c_client *client;
struct msm_camera_cci_client *cci_client;
enum msm_camera_i2c_reg_addr_type addr_type;
};
struct msm_camera_i2c_reg_tbl {
uint16_t reg_addr;
uint16_t reg_data;
uint16_t delay;
};
struct msm_camera_i2c_fn_t {
int (*i2c_read) (struct msm_camera_i2c_client *, uint16_t, uint16_t *,
enum msm_camera_i2c_data_type);
int32_t (*i2c_read_seq)(struct msm_camera_i2c_client *, uint16_t,
uint8_t *, uint16_t);
int (*i2c_write) (struct msm_camera_i2c_client *, uint16_t, uint16_t,
enum msm_camera_i2c_data_type);
int (*i2c_write_seq) (struct msm_camera_i2c_client *, uint16_t ,
uint8_t *, uint16_t);
int32_t (*i2c_write_table)(struct msm_camera_i2c_client *,
struct msm_camera_i2c_reg_setting *);
int32_t (*i2c_write_seq_table)(struct msm_camera_i2c_client *,
struct msm_camera_i2c_seq_reg_setting *);
int32_t (*i2c_write_table_w_microdelay)
(struct msm_camera_i2c_client *,
struct msm_camera_i2c_reg_tbl *, uint16_t,
enum msm_camera_i2c_data_type);
int32_t (*i2c_util)(struct msm_camera_i2c_client *, uint16_t);
};
int32_t msm_camera_cci_i2c_read(struct msm_camera_i2c_client *client,
uint16_t addr, uint16_t *data,
enum msm_camera_i2c_data_type data_type);
int32_t msm_camera_cci_i2c_read_seq(struct msm_camera_i2c_client *client,
uint16_t addr, uint8_t *data, uint16_t num_byte);
int32_t msm_camera_cci_i2c_write(struct msm_camera_i2c_client *client,
uint16_t addr, uint16_t data,
enum msm_camera_i2c_data_type data_type);
int32_t msm_camera_cci_i2c_write_seq(struct msm_camera_i2c_client *client,
uint16_t addr, uint8_t *data, uint16_t num_byte);
int32_t msm_camera_cci_i2c_write_table(
struct msm_camera_i2c_client *client,
struct msm_camera_i2c_reg_setting *write_setting);
int32_t msm_camera_cci_i2c_write_seq_table(
struct msm_camera_i2c_client *client,
struct msm_camera_i2c_seq_reg_setting *write_setting);
int32_t msm_camera_cci_i2c_write_table_w_microdelay(
struct msm_camera_i2c_client *client,
struct msm_camera_i2c_reg_tbl *reg_tbl, uint16_t size,
enum msm_camera_i2c_data_type data_type);
int32_t msm_sensor_cci_i2c_util(struct msm_camera_i2c_client *client,
uint16_t cci_cmd);
int32_t msm_camera_qup_i2c_read(struct msm_camera_i2c_client *client,
uint16_t addr, uint16_t *data,
enum msm_camera_i2c_data_type data_type);
int32_t msm_camera_qup_i2c_read_seq(struct msm_camera_i2c_client *client,
uint16_t addr, uint8_t *data, uint16_t num_byte);
int32_t msm_camera_qup_i2c_write(struct msm_camera_i2c_client *client,
uint16_t addr, uint16_t data,
enum msm_camera_i2c_data_type data_type);
int32_t msm_camera_qup_i2c_write_seq(struct msm_camera_i2c_client *client,
uint16_t addr, uint8_t *data, uint16_t num_byte);
int32_t msm_camera_qup_i2c_write_table(struct msm_camera_i2c_client *client,
struct msm_camera_i2c_reg_setting *write_setting);
int32_t msm_camera_qup_i2c_write_seq_table(struct msm_camera_i2c_client *client,
struct msm_camera_i2c_seq_reg_setting *write_setting);
int32_t msm_camera_qup_i2c_write_table_w_microdelay(
struct msm_camera_i2c_client *client,
struct msm_camera_i2c_reg_tbl *reg_tbl, uint16_t size,
enum msm_camera_i2c_data_type data_type);
#endif

View File

@ -0,0 +1,188 @@
/* Copyright (c) 2011-2013, The Linux Foundatation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
#include <mach/board.h>
#include <mach/camera.h>
#include "msm_camera_i2c_mux.h"
/* TODO move this somewhere else */
#define MSM_I2C_MUX_DRV_NAME "msm_cam_i2c_mux"
static int msm_i2c_mux_config(struct i2c_mux_device *mux_device, uint8_t *mode)
{
uint32_t val;
val = msm_camera_io_r(mux_device->ctl_base);
if (*mode == MODE_DUAL) {
msm_camera_io_w(val | 0x3, mux_device->ctl_base);
} else if (*mode == MODE_L) {
msm_camera_io_w(((val | 0x2) & ~(0x1)), mux_device->ctl_base);
val = msm_camera_io_r(mux_device->ctl_base);
CDBG("the camio mode config left value is %d\n", val);
} else {
msm_camera_io_w(((val | 0x1) & ~(0x2)), mux_device->ctl_base);
val = msm_camera_io_r(mux_device->ctl_base);
CDBG("the camio mode config right value is %d\n", val);
}
return 0;
}
static int msm_i2c_mux_init(struct i2c_mux_device *mux_device)
{
int rc = 0, val = 0;
if (mux_device->use_count == 0) {
mux_device->ctl_base = ioremap(mux_device->ctl_mem->start,
resource_size(mux_device->ctl_mem));
if (!mux_device->ctl_base) {
rc = -ENOMEM;
return rc;
}
mux_device->rw_base = ioremap(mux_device->rw_mem->start,
resource_size(mux_device->rw_mem));
if (!mux_device->rw_base) {
rc = -ENOMEM;
iounmap(mux_device->ctl_base);
return rc;
}
val = msm_camera_io_r(mux_device->rw_base);
msm_camera_io_w((val | 0x200), mux_device->rw_base);
}
mux_device->use_count++;
return 0;
};
static int msm_i2c_mux_release(struct i2c_mux_device *mux_device)
{
int val = 0;
mux_device->use_count--;
if (mux_device->use_count == 0) {
val = msm_camera_io_r(mux_device->rw_base);
msm_camera_io_w((val & ~0x200), mux_device->rw_base);
iounmap(mux_device->rw_base);
iounmap(mux_device->ctl_base);
}
return 0;
}
static long msm_i2c_mux_subdev_ioctl(struct v4l2_subdev *sd,
unsigned int cmd, void *arg)
{
struct i2c_mux_device *mux_device;
int rc = 0;
mux_device = v4l2_get_subdevdata(sd);
if (mux_device == NULL) {
rc = -ENOMEM;
return rc;
}
mutex_lock(&mux_device->mutex);
switch (cmd) {
case VIDIOC_MSM_I2C_MUX_CFG:
rc = msm_i2c_mux_config(mux_device, (uint8_t *) arg);
break;
case VIDIOC_MSM_I2C_MUX_INIT:
rc = msm_i2c_mux_init(mux_device);
break;
case VIDIOC_MSM_I2C_MUX_RELEASE:
rc = msm_i2c_mux_release(mux_device);
break;
default:
rc = -ENOIOCTLCMD;
}
mutex_unlock(&mux_device->mutex);
return rc;
}
static struct v4l2_subdev_core_ops msm_i2c_mux_subdev_core_ops = {
.ioctl = &msm_i2c_mux_subdev_ioctl,
};
static const struct v4l2_subdev_ops msm_i2c_mux_subdev_ops = {
.core = &msm_i2c_mux_subdev_core_ops,
};
static int i2c_mux_probe(struct platform_device *pdev)
{
struct i2c_mux_device *mux_device;
int rc = 0;
CDBG("%s: device id = %d\n", __func__, pdev->id);
mux_device = kzalloc(sizeof(struct i2c_mux_device), GFP_KERNEL);
if (!mux_device) {
pr_err("%s: no enough memory\n", __func__);
return -ENOMEM;
}
v4l2_subdev_init(&mux_device->subdev, &msm_i2c_mux_subdev_ops);
v4l2_set_subdevdata(&mux_device->subdev, mux_device);
platform_set_drvdata(pdev, &mux_device->subdev);
mutex_init(&mux_device->mutex);
mux_device->ctl_mem = platform_get_resource_byname(pdev,
IORESOURCE_MEM, "i2c_mux_ctl");
if (!mux_device->ctl_mem) {
pr_err("%s: no mem resource?\n", __func__);
rc = -ENODEV;
goto i2c_mux_no_resource;
}
mux_device->ctl_io = request_mem_region(mux_device->ctl_mem->start,
resource_size(mux_device->ctl_mem), pdev->name);
if (!mux_device->ctl_io) {
pr_err("%s: no valid mem region\n", __func__);
rc = -EBUSY;
goto i2c_mux_no_resource;
}
mux_device->rw_mem = platform_get_resource_byname(pdev,
IORESOURCE_MEM, "i2c_mux_rw");
if (!mux_device->rw_mem) {
pr_err("%s: no mem resource?\n", __func__);
rc = -ENODEV;
goto i2c_mux_no_resource;
}
mux_device->rw_io = request_mem_region(mux_device->rw_mem->start,
resource_size(mux_device->rw_mem), pdev->name);
if (!mux_device->rw_io) {
pr_err("%s: no valid mem region\n", __func__);
rc = -EBUSY;
goto i2c_mux_no_resource;
}
mux_device->pdev = pdev;
return 0;
i2c_mux_no_resource:
mutex_destroy(&mux_device->mutex);
kfree(mux_device);
return 0;
}
static struct platform_driver i2c_mux_driver = {
.probe = i2c_mux_probe,
.driver = {
.name = MSM_I2C_MUX_DRV_NAME,
.owner = THIS_MODULE,
},
};
static int __init msm_camera_i2c_mux_init_module(void)
{
return platform_driver_register(&i2c_mux_driver);
}
static void __exit msm_camera_i2c_mux_exit_module(void)
{
platform_driver_unregister(&i2c_mux_driver);
}
module_init(msm_camera_i2c_mux_init_module);
module_exit(msm_camera_i2c_mux_exit_module);
MODULE_DESCRIPTION("MSM Camera I2C mux driver");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,46 @@
/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef MSM_I2C_MUX_H
#define MSM_I2C_MUX_H
#include <linux/io.h>
#include <media/v4l2-subdev.h>
struct i2c_mux_device {
struct platform_device *pdev;
struct v4l2_subdev subdev;
struct resource *ctl_mem;
struct resource *ctl_io;
void __iomem *ctl_base;
struct resource *rw_mem;
struct resource *rw_io;
void __iomem *rw_base;
struct mutex mutex;
unsigned use_count;
};
struct i2c_mux_cfg_params {
struct v4l2_subdev *subdev;
void *parms;
};
#define VIDIOC_MSM_I2C_MUX_CFG \
_IOWR('V', BASE_VIDIOC_PRIVATE + 13, struct i2c_mux_cfg_params)
#define VIDIOC_MSM_I2C_MUX_INIT \
_IOWR('V', BASE_VIDIOC_PRIVATE + 14, struct v4l2_subdev*)
#define VIDIOC_MSM_I2C_MUX_RELEASE \
_IOWR('V', BASE_VIDIOC_PRIVATE + 15, struct v4l2_subdev*)
#endif

View File

@ -0,0 +1,523 @@
/* Copyright (c) 2011-2013, The Linux Foundataion. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/io.h>
#include <linux/err.h>
#include <mach/camera2.h>
#include <mach/gpiomux.h>
#include <mach/msm_bus.h>
#include "msm_camera_io_util.h"
#define BUFF_SIZE_128 128
#define CONFIG_MSMB_CAMERA_DEBUG
#undef CDBG
#ifdef CONFIG_MSMB_CAMERA_DEBUG
#define CDBG(fmt, args...) pr_debug(fmt, ##args)
#else
#define CDBG(fmt, args...) do { } while (0)
#endif
void msm_camera_io_w(u32 data, void __iomem *addr)
{
CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
writel_relaxed((data), (addr));
}
void msm_camera_io_w_mb(u32 data, void __iomem *addr)
{
CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
wmb();
writel_relaxed((data), (addr));
wmb();
}
u32 msm_camera_io_r(void __iomem *addr)
{
uint32_t data = readl_relaxed(addr);
CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
return data;
}
u32 msm_camera_io_r_mb(void __iomem *addr)
{
uint32_t data;
rmb();
data = readl_relaxed(addr);
rmb();
CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
return data;
}
void msm_camera_io_memcpy_toio(void __iomem *dest_addr,
void __iomem *src_addr, u32 len)
{
int i;
u32 *d = (u32 *) dest_addr;
u32 *s = (u32 *) src_addr;
for (i = 0; i < len; i++)
writel_relaxed(*s++, d++);
}
void msm_camera_io_dump(void __iomem *addr, int size)
{
char line_str[BUFF_SIZE_128], *p_str;
int i;
u32 *p = (u32 *) addr;
u32 data;
CDBG("%s: %p %d\n", __func__, addr, size);
line_str[0] = '\0';
p_str = line_str;
for (i = 0; i < size/4; i++) {
if (i % 4 == 0) {
snprintf(p_str, 12, "%08x: ", (u32) p);
p_str += 10;
}
data = readl_relaxed(p++);
snprintf(p_str, 12, "%08x ", data);
p_str += 9;
if ((i + 1) % 4 == 0) {
CDBG("%s\n", line_str);
line_str[0] = '\0';
p_str = line_str;
}
}
if (line_str[0] != '\0')
CDBG("%s\n", line_str);
}
void msm_camera_io_memcpy(void __iomem *dest_addr,
void __iomem *src_addr, u32 len)
{
CDBG("%s: %p %p %d\n", __func__, dest_addr, src_addr, len);
msm_camera_io_memcpy_toio(dest_addr, src_addr, len / 4);
msm_camera_io_dump(dest_addr, len);
}
int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info,
struct clk **clk_ptr, int num_clk, int enable)
{
int i;
int rc = 0;
if (enable) {
for (i = 0; i < num_clk; i++) {
CDBG("%s enable %s\n", __func__,
clk_info[i].clk_name);
clk_ptr[i] = clk_get(dev, clk_info[i].clk_name);
if (IS_ERR(clk_ptr[i])) {
pr_err("%s get failed\n", clk_info[i].clk_name);
rc = PTR_ERR(clk_ptr[i]);
goto cam_clk_get_err;
}
if (clk_info[i].clk_rate >= 0) {
rc = clk_set_rate(clk_ptr[i],
clk_info[i].clk_rate);
if (rc < 0) {
pr_err("%s set failed\n",
clk_info[i].clk_name);
goto cam_clk_set_err;
}
}
rc = clk_prepare(clk_ptr[i]);
if (rc < 0) {
pr_err("%s prepare failed\n",
clk_info[i].clk_name);
goto cam_clk_prepare_err;
}
rc = clk_enable(clk_ptr[i]);
if (rc < 0) {
pr_err("%s enable failed\n",
clk_info[i].clk_name);
goto cam_clk_enable_err;
}
if (clk_info[i].delay > 20) {
msleep(clk_info[i].delay);
} else if (clk_info[i].delay) {
usleep_range(clk_info[i].delay * 1000,
(clk_info[i].delay * 1000) + 1000);
}
}
} else {
for (i = num_clk - 1; i >= 0; i--) {
if (clk_ptr[i] != NULL) {
CDBG("%s disable %s\n", __func__,
clk_info[i].clk_name);
clk_disable(clk_ptr[i]);
clk_unprepare(clk_ptr[i]);
clk_put(clk_ptr[i]);
}
}
}
return rc;
cam_clk_enable_err:
clk_unprepare(clk_ptr[i]);
cam_clk_prepare_err:
cam_clk_set_err:
clk_put(clk_ptr[i]);
cam_clk_get_err:
for (i--; i >= 0; i--) {
if (clk_ptr[i] != NULL) {
clk_disable(clk_ptr[i]);
clk_unprepare(clk_ptr[i]);
clk_put(clk_ptr[i]);
}
}
return rc;
}
int msm_camera_config_vreg(struct device *dev, struct camera_vreg_t *cam_vreg,
int num_vreg, enum msm_camera_vreg_name_t *vreg_seq,
int num_vreg_seq, struct regulator **reg_ptr, int config)
{
int i = 0, j = 0;
int rc = 0;
struct camera_vreg_t *curr_vreg;
if (num_vreg_seq > num_vreg) {
pr_err("%s:%d vreg sequence invalid\n", __func__, __LINE__);
return -EINVAL;
}
if (!num_vreg_seq)
num_vreg_seq = num_vreg;
if (config) {
for (i = 0; i < num_vreg_seq; i++) {
if (vreg_seq) {
j = vreg_seq[i];
if (j >= num_vreg)
continue;
} else
j = i;
curr_vreg = &cam_vreg[j];
reg_ptr[j] = regulator_get(dev,
curr_vreg->reg_name);
if (IS_ERR(reg_ptr[j])) {
pr_err("%s: %s get failed\n",
__func__,
curr_vreg->reg_name);
reg_ptr[j] = NULL;
goto vreg_get_fail;
}
if (curr_vreg->type == REG_LDO) {
rc = regulator_set_voltage(
reg_ptr[j],
curr_vreg->min_voltage,
curr_vreg->max_voltage);
if (rc < 0) {
pr_err("%s: %s set voltage failed\n",
__func__,
curr_vreg->reg_name);
goto vreg_set_voltage_fail;
}
if (curr_vreg->op_mode >= 0) {
rc = regulator_set_optimum_mode(
reg_ptr[j],
curr_vreg->op_mode);
if (rc < 0) {
pr_err(
"%s:%s set optimum mode fail\n",
__func__,
curr_vreg->reg_name);
goto vreg_set_opt_mode_fail;
}
}
}
}
} else {
for (i = num_vreg_seq-1; i >= 0; i--) {
if (vreg_seq) {
j = vreg_seq[i];
if (j >= num_vreg)
continue;
} else
j = i;
curr_vreg = &cam_vreg[j];
if (reg_ptr[j]) {
if (curr_vreg->type == REG_LDO) {
if (curr_vreg->op_mode >= 0) {
regulator_set_optimum_mode(
reg_ptr[j], 0);
}
regulator_set_voltage(
reg_ptr[j], 0, curr_vreg->
max_voltage);
}
regulator_put(reg_ptr[j]);
reg_ptr[j] = NULL;
}
}
}
return 0;
vreg_unconfig:
if (curr_vreg->type == REG_LDO)
regulator_set_optimum_mode(reg_ptr[j], 0);
vreg_set_opt_mode_fail:
if (curr_vreg->type == REG_LDO)
regulator_set_voltage(reg_ptr[j], 0,
curr_vreg->max_voltage);
vreg_set_voltage_fail:
regulator_put(reg_ptr[j]);
reg_ptr[j] = NULL;
vreg_get_fail:
for (i--; i >= 0; i--) {
if (vreg_seq) {
j = vreg_seq[i];
if (j >= num_vreg)
continue;
} else
j = i;
curr_vreg = &cam_vreg[j];
goto vreg_unconfig;
}
return -ENODEV;
}
int msm_camera_enable_vreg(struct device *dev, struct camera_vreg_t *cam_vreg,
int num_vreg, enum msm_camera_vreg_name_t *vreg_seq,
int num_vreg_seq, struct regulator **reg_ptr, int enable)
{
int i = 0, j = 0, rc = 0;
if (num_vreg_seq > num_vreg) {
pr_err("%s:%d vreg sequence invalid\n", __func__, __LINE__);
return -EINVAL;
}
if (!num_vreg_seq)
num_vreg_seq = num_vreg;
if (enable) {
for (i = 0; i < num_vreg_seq; i++) {
if (vreg_seq) {
j = vreg_seq[i];
if (j >= num_vreg)
continue;
} else
j = i;
if (IS_ERR(reg_ptr[j])) {
pr_err("%s: %s null regulator\n",
__func__, cam_vreg[j].reg_name);
goto disable_vreg;
}
rc = regulator_enable(reg_ptr[j]);
if (rc < 0) {
pr_err("%s: %s enable failed\n",
__func__, cam_vreg[j].reg_name);
goto disable_vreg;
}
if (cam_vreg[j].delay > 20)
msleep(cam_vreg[j].delay);
else if (cam_vreg[j].delay)
usleep_range(cam_vreg[j].delay * 1000,
(cam_vreg[j].delay * 1000) + 1000);
}
} else {
for (i = num_vreg_seq-1; i >= 0; i--) {
if (vreg_seq) {
j = vreg_seq[i];
if (j >= num_vreg)
continue;
} else
j = i;
regulator_disable(reg_ptr[j]);
if (cam_vreg[j].delay > 20)
msleep(cam_vreg[j].delay);
else if (cam_vreg[j].delay)
usleep_range(cam_vreg[j].delay * 1000,
(cam_vreg[j].delay * 1000) + 1000);
}
}
return rc;
disable_vreg:
for (i--; i >= 0; i--) {
if (vreg_seq) {
j = vreg_seq[i];
if (j >= num_vreg)
continue;
} else
j = i;
regulator_disable(reg_ptr[j]);
if (cam_vreg[j].delay > 20)
msleep(cam_vreg[j].delay);
else if (cam_vreg[j].delay)
usleep_range(cam_vreg[j].delay * 1000,
(cam_vreg[j].delay * 1000) + 1000);
}
return rc;
}
void msm_camera_bus_scale_cfg(uint32_t bus_perf_client,
enum msm_bus_perf_setting perf_setting)
{
int rc = 0;
if (!bus_perf_client) {
pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
return;
}
switch (perf_setting) {
case S_EXIT:
rc = msm_bus_scale_client_update_request(bus_perf_client, 1);
msm_bus_scale_unregister_client(bus_perf_client);
break;
case S_PREVIEW:
rc = msm_bus_scale_client_update_request(bus_perf_client, 1);
break;
case S_VIDEO:
rc = msm_bus_scale_client_update_request(bus_perf_client, 2);
break;
case S_CAPTURE:
rc = msm_bus_scale_client_update_request(bus_perf_client, 3);
break;
case S_ZSL:
rc = msm_bus_scale_client_update_request(bus_perf_client, 4);
break;
case S_LIVESHOT:
rc = msm_bus_scale_client_update_request(bus_perf_client, 5);
break;
case S_DEFAULT:
break;
default:
pr_warning("%s: INVALID CASE\n", __func__);
}
}
int msm_camera_set_gpio_table(struct msm_gpio_set_tbl *gpio_tbl,
uint8_t gpio_tbl_size, int gpio_en)
{
int rc = 0, i;
if (gpio_en) {
for (i = 0; i < gpio_tbl_size; i++) {
gpio_set_value_cansleep(gpio_tbl[i].gpio,
gpio_tbl[i].flags);
usleep_range(gpio_tbl[i].delay,
gpio_tbl[i].delay + 1000);
}
} else {
for (i = gpio_tbl_size - 1; i >= 0; i--) {
if (gpio_tbl[i].flags)
gpio_set_value_cansleep(gpio_tbl[i].gpio,
GPIOF_OUT_INIT_LOW);
}
}
return rc;
}
int msm_camera_config_single_vreg(struct device *dev,
struct camera_vreg_t *cam_vreg, struct regulator **reg_ptr, int config)
{
int rc = 0;
if (config) {
CDBG("%s enable %s\n", __func__, cam_vreg->reg_name);
*reg_ptr = regulator_get(dev, cam_vreg->reg_name);
if (IS_ERR(*reg_ptr)) {
pr_err("%s: %s get failed\n", __func__,
cam_vreg->reg_name);
*reg_ptr = NULL;
goto vreg_get_fail;
}
if (cam_vreg->type == REG_LDO) {
rc = regulator_set_voltage(
*reg_ptr, cam_vreg->min_voltage,
cam_vreg->max_voltage);
if (rc < 0) {
pr_err("%s: %s set voltage failed\n",
__func__, cam_vreg->reg_name);
goto vreg_set_voltage_fail;
}
if (cam_vreg->op_mode >= 0) {
rc = regulator_set_optimum_mode(*reg_ptr,
cam_vreg->op_mode);
if (rc < 0) {
pr_err(
"%s: %s set optimum mode failed\n",
__func__, cam_vreg->reg_name);
goto vreg_set_opt_mode_fail;
}
}
}
rc = regulator_enable(*reg_ptr);
if (rc < 0) {
pr_err("%s: %s enable failed\n",
__func__, cam_vreg->reg_name);
goto vreg_unconfig;
}
} else {
if (*reg_ptr) {
CDBG("%s disable %s\n", __func__, cam_vreg->reg_name);
regulator_disable(*reg_ptr);
if (cam_vreg->type == REG_LDO) {
if (cam_vreg->op_mode >= 0)
regulator_set_optimum_mode(*reg_ptr, 0);
regulator_set_voltage(
*reg_ptr, 0, cam_vreg->max_voltage);
}
regulator_put(*reg_ptr);
*reg_ptr = NULL;
}
}
return 0;
vreg_unconfig:
if (cam_vreg->type == REG_LDO)
regulator_set_optimum_mode(*reg_ptr, 0);
vreg_set_opt_mode_fail:
if (cam_vreg->type == REG_LDO)
regulator_set_voltage(*reg_ptr, 0, cam_vreg->max_voltage);
vreg_set_voltage_fail:
regulator_put(*reg_ptr);
*reg_ptr = NULL;
vreg_get_fail:
return -ENODEV;
}
int msm_camera_request_gpio_table(struct gpio *gpio_tbl, uint8_t size,
int gpio_en)
{
int rc = 0, i = 0;
if (!gpio_tbl || !size) {
pr_err("%s:%d invalid gpio_tbl %p / size %d\n", __func__,
__LINE__, gpio_tbl, size);
return -EINVAL;
}
for (i = 0; i < size; i++) {
CDBG("%s:%d i %d, gpio %d dir %ld\n", __func__, __LINE__, i,
gpio_tbl[i].gpio, gpio_tbl[i].flags);
}
if (gpio_en) {
rc = gpio_request_array(gpio_tbl, size);
if (rc < 0) {
pr_err("%s:%d camera gpio request failed\n", __func__,
__LINE__);
return rc;
}
} else {
gpio_free_array(gpio_tbl, size);
}
return rc;
}

View File

@ -0,0 +1,54 @@
/* Copyright (c) 2011-2013, The Linux Foundataion. 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.
*/
#ifndef __MSM_CAMERA_IO_UTIL_H
#define __MSM_CAMERA_IO_UTIL_H
#include <linux/regulator/consumer.h>
#include <linux/gpio.h>
#include <mach/camera2.h>
#include <media/msm_cam_sensor.h>
void msm_camera_io_w(u32 data, void __iomem *addr);
void msm_camera_io_w_mb(u32 data, void __iomem *addr);
u32 msm_camera_io_r(void __iomem *addr);
u32 msm_camera_io_r_mb(void __iomem *addr);
void msm_camera_io_dump(void __iomem *addr, int size);
void msm_camera_io_memcpy(void __iomem *dest_addr,
void __iomem *src_addr, u32 len);
int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info,
struct clk **clk_ptr, int num_clk, int enable);
int msm_camera_config_vreg(struct device *dev, struct camera_vreg_t *cam_vreg,
int num_vreg, enum msm_camera_vreg_name_t *vreg_seq,
int num_vreg_seq, struct regulator **reg_ptr, int config);
int msm_camera_enable_vreg(struct device *dev, struct camera_vreg_t *cam_vreg,
int num_vreg, enum msm_camera_vreg_name_t *vreg_seq,
int num_vreg_seq, struct regulator **reg_ptr, int enable);
void msm_camera_bus_scale_cfg(uint32_t bus_perf_client,
enum msm_bus_perf_setting perf_setting);
int msm_camera_set_gpio_table(struct msm_gpio_set_tbl *gpio_tbl,
uint8_t gpio_tbl_size, int gpio_en);
void msm_camera_config_single_gpio(uint16_t gpio, unsigned long flags,
int gpio_en);
int msm_camera_config_single_vreg(struct device *dev,
struct camera_vreg_t *cam_vreg, struct regulator **reg_ptr, int config);
int msm_camera_request_gpio_table(struct gpio *gpio_tbl, uint8_t size,
int gpio_en);
#endif

View File

@ -0,0 +1,333 @@
/* Copyright (c) 2011, 2013, 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 <mach/camera2.h>
#include "msm_camera_i2c.h"
#define CONFIG_MSMB_CAMERA_DEBUG
#undef CDBG
#ifdef CONFIG_MSMB_CAMERA_DEBUG
#define CDBG(fmt, args...) pr_debug(fmt, ##args)
#define S_I2C_DBG(fmt, args...) pr_debug(fmt, ##args)
#else
#define CDBG(fmt, args...) do { } while (0)
#define S_I2C_DBG(fmt, args...) do { } while (0)
#endif
static int32_t msm_camera_qup_i2c_rxdata(
struct msm_camera_i2c_client *dev_client, unsigned char *rxdata,
int data_length)
{
int32_t rc = 0;
uint16_t saddr = dev_client->client->addr >> 1;
struct i2c_msg msgs[] = {
{
.addr = saddr,
.flags = 0,
.len = dev_client->addr_type,
.buf = rxdata,
},
{
.addr = saddr,
.flags = I2C_M_RD,
.len = data_length,
.buf = rxdata,
},
};
rc = i2c_transfer(dev_client->client->adapter, msgs, 2);
if (rc < 0)
S_I2C_DBG("msm_camera_qup_i2c_rxdata failed 0x%x\n", saddr);
return rc;
}
static int32_t msm_camera_qup_i2c_txdata(
struct msm_camera_i2c_client *dev_client, unsigned char *txdata,
int length)
{
int32_t rc = 0;
uint16_t saddr = dev_client->client->addr >> 1;
struct i2c_msg msg[] = {
{
.addr = saddr,
.flags = 0,
.len = length,
.buf = txdata,
},
};
rc = i2c_transfer(dev_client->client->adapter, msg, 1);
if (rc < 0)
S_I2C_DBG("msm_camera_qup_i2c_txdata faild 0x%x\n", saddr);
return 0;
}
int32_t msm_camera_qup_i2c_read(struct msm_camera_i2c_client *client,
uint16_t addr, uint16_t *data,
enum msm_camera_i2c_data_type data_type)
{
int32_t rc = -EFAULT;
unsigned char buf[client->addr_type+data_type];
if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
|| (data_type != MSM_CAMERA_I2C_BYTE_DATA
&& data_type != MSM_CAMERA_I2C_WORD_DATA))
return rc;
if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) {
buf[0] = addr;
} else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) {
buf[0] = addr >> BITS_PER_BYTE;
buf[1] = addr;
}
rc = msm_camera_qup_i2c_rxdata(client, buf, data_type);
if (rc < 0) {
S_I2C_DBG("%s fail\n", __func__);
return rc;
}
if (data_type == MSM_CAMERA_I2C_BYTE_DATA)
*data = buf[0];
else
*data = buf[0] << 8 | buf[1];
S_I2C_DBG("%s addr = 0x%x data: 0x%x\n", __func__, addr, *data);
return rc;
}
int32_t msm_camera_qup_i2c_read_seq(struct msm_camera_i2c_client *client,
uint16_t addr, uint8_t *data, uint16_t num_byte)
{
int32_t rc = -EFAULT;
unsigned char buf[client->addr_type+num_byte];
int i;
if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
|| num_byte == 0)
return rc;
if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) {
buf[0] = addr;
} else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) {
buf[0] = addr >> BITS_PER_BYTE;
buf[1] = addr;
}
rc = msm_camera_qup_i2c_rxdata(client, buf, num_byte);
if (rc < 0) {
S_I2C_DBG("%s fail\n", __func__);
return rc;
}
S_I2C_DBG("%s addr = 0x%x", __func__, addr);
for (i = 0; i < num_byte; i++) {
data[i] = buf[i];
S_I2C_DBG("Byte %d: 0x%x\n", i, buf[i]);
S_I2C_DBG("Data: 0x%x\n", data[i]);
}
return rc;
}
int32_t msm_camera_qup_i2c_write(struct msm_camera_i2c_client *client,
uint16_t addr, uint16_t data,
enum msm_camera_i2c_data_type data_type)
{
int32_t rc = -EFAULT;
unsigned char buf[client->addr_type+data_type];
uint8_t len = 0;
if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
|| (data_type != MSM_CAMERA_I2C_BYTE_DATA
&& data_type != MSM_CAMERA_I2C_WORD_DATA))
return rc;
S_I2C_DBG("%s reg addr = 0x%x data type: %d\n",
__func__, addr, data_type);
if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) {
buf[0] = addr;
S_I2C_DBG("%s byte %d: 0x%x\n", __func__,
len, buf[len]);
len = 1;
} else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) {
buf[0] = addr >> BITS_PER_BYTE;
buf[1] = addr;
S_I2C_DBG("%s byte %d: 0x%x\n", __func__,
len, buf[len]);
S_I2C_DBG("%s byte %d: 0x%x\n", __func__,
len+1, buf[len+1]);
len = 2;
}
S_I2C_DBG("Data: 0x%x\n", data);
if (data_type == MSM_CAMERA_I2C_BYTE_DATA) {
buf[len] = data;
S_I2C_DBG("Byte %d: 0x%x\n", len, buf[len]);
len += 1;
} else if (data_type == MSM_CAMERA_I2C_WORD_DATA) {
buf[len] = data >> BITS_PER_BYTE;
buf[len+1] = data;
S_I2C_DBG("Byte %d: 0x%x\n", len, buf[len]);
S_I2C_DBG("Byte %d: 0x%x\n", len+1, buf[len+1]);
len += 2;
}
rc = msm_camera_qup_i2c_txdata(client, buf, len);
if (rc < 0)
S_I2C_DBG("%s fail\n", __func__);
return rc;
}
int32_t msm_camera_qup_i2c_write_seq(struct msm_camera_i2c_client *client,
uint16_t addr, uint8_t *data, uint16_t num_byte)
{
int32_t rc = -EFAULT;
unsigned char buf[client->addr_type+num_byte];
uint8_t len = 0, i = 0;
if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
|| num_byte == 0)
return rc;
S_I2C_DBG("%s reg addr = 0x%x num bytes: %d\n",
__func__, addr, num_byte);
if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) {
buf[0] = addr;
S_I2C_DBG("%s byte %d: 0x%x\n", __func__,
len, buf[len]);
len = 1;
} else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) {
buf[0] = addr >> BITS_PER_BYTE;
buf[1] = addr;
S_I2C_DBG("%s byte %d: 0x%x\n", __func__,
len, buf[len]);
S_I2C_DBG("%s byte %d: 0x%x\n", __func__,
len+1, buf[len+1]);
len = 2;
}
for (i = 0; i < num_byte; i++) {
buf[i+len] = data[i];
S_I2C_DBG("Byte %d: 0x%x\n", i+len, buf[i+len]);
S_I2C_DBG("Data: 0x%x\n", data[i]);
}
rc = msm_camera_qup_i2c_txdata(client, buf, len+num_byte);
if (rc < 0)
S_I2C_DBG("%s fail\n", __func__);
return rc;
}
int32_t msm_camera_qup_i2c_write_table(struct msm_camera_i2c_client *client,
struct msm_camera_i2c_reg_setting *write_setting)
{
int i;
int32_t rc = -EFAULT;
struct msm_camera_i2c_reg_array *reg_setting;
uint16_t client_addr_type;
if (!client || !write_setting)
return rc;
if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
&& write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
|| (write_setting->data_type != MSM_CAMERA_I2C_BYTE_DATA
&& write_setting->data_type != MSM_CAMERA_I2C_WORD_DATA))
return rc;
reg_setting = write_setting->reg_setting;
client_addr_type = client->addr_type;
client->addr_type = write_setting->addr_type;
for (i = 0; i < write_setting->size; i++) {
CDBG("%s addr %x data %x\n", __func__,
reg_setting->reg_addr, reg_setting->reg_data);
rc = msm_camera_qup_i2c_write(client, reg_setting->reg_addr,
reg_setting->reg_data, write_setting->data_type);
if (rc < 0)
break;
reg_setting++;
}
if (write_setting->delay > 20)
msleep(write_setting->delay);
else if (write_setting->delay)
usleep_range(write_setting->delay * 1000, (write_setting->delay
* 1000) + 1000);
client->addr_type = client_addr_type;
return rc;
}
int32_t msm_camera_qup_i2c_write_seq_table(struct msm_camera_i2c_client *client,
struct msm_camera_i2c_seq_reg_setting *write_setting)
{
int i;
int32_t rc = -EFAULT;
struct msm_camera_i2c_seq_reg_array *reg_setting;
uint16_t client_addr_type;
if (!client || !write_setting)
return rc;
if ((write_setting->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
&& write_setting->addr_type != MSM_CAMERA_I2C_WORD_ADDR)) {
pr_err("%s Invalide addr type %d\n", __func__,
write_setting->addr_type);
return rc;
}
reg_setting = write_setting->reg_setting;
client_addr_type = client->addr_type;
client->addr_type = write_setting->addr_type;
for (i = 0; i < write_setting->size; i++) {
rc = msm_camera_qup_i2c_write_seq(client, reg_setting->reg_addr,
reg_setting->reg_data, reg_setting->reg_data_size);
if (rc < 0)
break;
reg_setting++;
}
if (write_setting->delay > 20)
msleep(write_setting->delay);
else if (write_setting->delay)
usleep_range(write_setting->delay * 1000, (write_setting->delay
* 1000) + 1000);
client->addr_type = client_addr_type;
return rc;
}
int32_t msm_camera_qup_i2c_write_table_w_microdelay(
struct msm_camera_i2c_client *client,
struct msm_camera_i2c_reg_tbl *reg_tbl, uint16_t size,
enum msm_camera_i2c_data_type data_type)
{
int i;
int32_t rc = -EFAULT;
if (!client || !reg_tbl)
return rc;
if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR
&& client->addr_type != MSM_CAMERA_I2C_WORD_ADDR)
|| (data_type != MSM_CAMERA_I2C_BYTE_DATA
&& data_type != MSM_CAMERA_I2C_WORD_DATA))
return rc;
for (i = 0; i < size; i++) {
rc = msm_camera_qup_i2c_write(client, reg_tbl->reg_addr,
reg_tbl->reg_data, data_type);
if (rc < 0)
break;
if (reg_tbl->delay)
usleep_range(reg_tbl->delay, reg_tbl->delay + 1000);
reg_tbl++;
}
return rc;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,86 @@
/* Copyright (c) 2011-2013, 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.
*/
#ifndef MSM_SENSOR_H
#define MSM_SENSOR_H
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <mach/camera2.h>
#include <media/msm_cam_sensor.h>
#include <media/v4l2-subdev.h>
#include "msm_camera_i2c.h"
#include "msm_sd.h"
#define DEFINE_MSM_MUTEX(mutexname) \
static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
struct msm_sensor_ctrl_t;
struct msm_sensor_fn_t {
int (*sensor_config) (struct msm_sensor_ctrl_t *, void __user *);
int (*sensor_power_down)
(struct msm_sensor_ctrl_t *);
int (*sensor_power_up) (struct msm_sensor_ctrl_t *);
int32_t (*sensor_match_id)(struct msm_sensor_ctrl_t *s_ctrl);
};
struct msm_sensor_ctrl_t {
struct platform_device *pdev;
enum msm_sensor_device_type_t sensor_device_type;
struct msm_camera_sensor_board_info *sensordata;
struct msm_sensor_power_setting_array power_setting_array;
struct mutex *msm_sensor_mutex;
struct msm_camera_i2c_client *sensor_i2c_client;
struct device *dev;
struct msm_sd_subdev msm_sd;
struct v4l2_subdev_info *sensor_v4l2_subdev_info;
uint8_t sensor_v4l2_subdev_info_size;
struct v4l2_subdev_ops *sensor_v4l2_subdev_ops;
struct msm_sensor_fn_t *func_tbl;
struct msm_camera_i2c_reg_setting stop_setting;
bool free_power_setting;
struct msm_cam_clk_info *clk_info;
uint16_t clk_info_size;
};
int32_t msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl,
void __user *argp);
int32_t msm_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl);
int32_t msm_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl);
int32_t msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl);
int32_t msm_sensor_platform_probe(struct platform_device *pdev,
const void *data);
int32_t msm_sensor_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id);
int32_t msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl);
#endif

View File

@ -0,0 +1,155 @@
/* Copyright (c) 2012-2013, 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 "msm_sensor.h"
#define S5K3L1YX_SENSOR_NAME "s5k3l1yx"
DEFINE_MSM_MUTEX(s5k3l1yx_mut);
static struct msm_sensor_ctrl_t s5k3l1yx_s_ctrl;
static struct msm_sensor_power_setting s5k3l1yx_power_setting[] = {
{
.seq_type = SENSOR_VREG,
.seq_val = CAM_VDIG,
.config_val = 0,
.delay = 0,
},
{
.seq_type = SENSOR_VREG,
.seq_val = CAM_VANA,
.config_val = 0,
.delay = 0,
},
{
.seq_type = SENSOR_VREG,
.seq_val = CAM_VIO,
.config_val = 0,
.delay = 0,
},
{
.seq_type = SENSOR_VREG,
.seq_val = CAM_VAF,
.config_val = 0,
.delay = 0,
},
{
.seq_type = SENSOR_GPIO,
.seq_val = SENSOR_GPIO_RESET,
.config_val = GPIO_OUT_LOW,
.delay = 1,
},
{
.seq_type = SENSOR_GPIO,
.seq_val = SENSOR_GPIO_RESET,
.config_val = GPIO_OUT_HIGH,
.delay = 30,
},
{
.seq_type = SENSOR_CLK,
.seq_val = SENSOR_CAM_MCLK,
.config_val = 0,
.delay = 1,
},
{
.seq_type = SENSOR_I2C_MUX,
.seq_val = 0,
.config_val = 0,
.delay = 0,
},
};
static struct v4l2_subdev_info s5k3l1yx_subdev_info[] = {
{
.code = V4L2_MBUS_FMT_SBGGR10_1X10,
.colorspace = V4L2_COLORSPACE_JPEG,
.fmt = 1,
.order = 0,
},
};
static const struct i2c_device_id s5k3l1yx_i2c_id[] = {
{S5K3L1YX_SENSOR_NAME, (kernel_ulong_t)&s5k3l1yx_s_ctrl},
{ }
};
static struct i2c_driver s5k3l1yx_i2c_driver = {
.id_table = s5k3l1yx_i2c_id,
.probe = msm_sensor_i2c_probe,
.driver = {
.name = S5K3L1YX_SENSOR_NAME,
},
};
static struct msm_camera_i2c_client s5k3l1yx_sensor_i2c_client = {
.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
};
static const struct of_device_id s5k3l1yx_dt_match[] = {
{.compatible = "qcom,s5k3l1yx", .data = &s5k3l1yx_s_ctrl},
{}
};
MODULE_DEVICE_TABLE(of, s5k3l1yx_dt_match);
static struct platform_driver s5k3l1yx_platform_driver = {
.driver = {
.name = "qcom,s5k3l1yx",
.owner = THIS_MODULE,
.of_match_table = s5k3l1yx_dt_match,
},
};
static int32_t s5k3l1yx_platform_probe(struct platform_device *pdev)
{
int32_t rc = 0;
const struct of_device_id *match;
match = of_match_device(s5k3l1yx_dt_match, &pdev->dev);
rc = msm_sensor_platform_probe(pdev, match->data);
return rc;
}
static int __init s5k3l1yx_init_module(void)
{
int32_t rc = 0;
pr_info("%s:%d\n", __func__, __LINE__);
rc = platform_driver_probe(&s5k3l1yx_platform_driver,
s5k3l1yx_platform_probe);
if (!rc)
return rc;
pr_err("%s:%d rc %d\n", __func__, __LINE__, rc);
return i2c_add_driver(&s5k3l1yx_i2c_driver);
}
static void __exit s5k3l1yx_exit_module(void)
{
pr_info("%s:%d\n", __func__, __LINE__);
if (s5k3l1yx_s_ctrl.pdev) {
msm_sensor_free_sensor_data(&s5k3l1yx_s_ctrl);
platform_driver_unregister(&s5k3l1yx_platform_driver);
} else
i2c_del_driver(&s5k3l1yx_i2c_driver);
return;
}
static struct msm_sensor_ctrl_t s5k3l1yx_s_ctrl = {
.sensor_i2c_client = &s5k3l1yx_sensor_i2c_client,
.power_setting_array.power_setting = s5k3l1yx_power_setting,
.power_setting_array.size = ARRAY_SIZE(s5k3l1yx_power_setting),
.msm_sensor_mutex = &s5k3l1yx_mut,
.sensor_v4l2_subdev_info = s5k3l1yx_subdev_info,
.sensor_v4l2_subdev_info_size = ARRAY_SIZE(s5k3l1yx_subdev_info),
};
module_init(s5k3l1yx_init_module);
module_exit(s5k3l1yx_exit_module);
MODULE_DESCRIPTION("s5k3l1yx");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,303 @@
#ifndef __LINUX_MSM_CAM_SENSOR_H
#define __LINUX_MSM_CAM_SENSOR_H
#ifdef MSM_CAMERA_BIONIC
#include <sys/types.h>
#endif
#include <linux/types.h>
#include <linux/v4l2-mediabus.h>
#include <linux/i2c.h>
#define I2C_SEQ_REG_SETTING_MAX 5
#define I2C_SEQ_REG_DATA_MAX 20
#define MAX_CID 16
#define MSM_SENSOR_MCLK_8HZ 8000000
#define MSM_SENSOR_MCLK_16HZ 16000000
#define MSM_SENSOR_MCLK_24HZ 24000000
#define GPIO_OUT_LOW (0 << 1)
#define GPIO_OUT_HIGH (1 << 1)
#define CSI_EMBED_DATA 0x12
#define CSI_RESERVED_DATA_0 0x13
#define CSI_YUV422_8 0x1E
#define CSI_RAW8 0x2A
#define CSI_RAW10 0x2B
#define CSI_RAW12 0x2C
#define CSI_DECODE_6BIT 0
#define CSI_DECODE_8BIT 1
#define CSI_DECODE_10BIT 2
#define CSI_DECODE_DPCM_10_8_10 5
#define MAX_SENSOR_NAME 32
enum msm_camera_i2c_reg_addr_type {
MSM_CAMERA_I2C_BYTE_ADDR = 1,
MSM_CAMERA_I2C_WORD_ADDR,
};
enum msm_camera_i2c_data_type {
MSM_CAMERA_I2C_BYTE_DATA = 1,
MSM_CAMERA_I2C_WORD_DATA,
MSM_CAMERA_I2C_SET_BYTE_MASK,
MSM_CAMERA_I2C_UNSET_BYTE_MASK,
MSM_CAMERA_I2C_SET_WORD_MASK,
MSM_CAMERA_I2C_UNSET_WORD_MASK,
MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA,
};
enum msm_sensor_power_seq_type_t {
SENSOR_CLK,
SENSOR_GPIO,
SENSOR_VREG,
SENSOR_I2C_MUX,
};
enum msm_sensor_clk_type_t {
SENSOR_CAM_MCLK,
SENSOR_CAM_CLK,
SENSOR_CAM_CLK_MAX,
};
enum msm_sensor_power_seq_gpio_t {
SENSOR_GPIO_RESET,
SENSOR_GPIO_STANDBY,
SENSOR_GPIO_MAX,
};
enum msm_camera_vreg_name_t {
CAM_VDIG,
CAM_VIO,
CAM_VANA,
CAM_VAF,
CAM_VREG_MAX,
};
enum msm_sensor_resolution_t {
MSM_SENSOR_RES_FULL,
MSM_SENSOR_RES_QTR,
MSM_SENSOR_RES_2,
MSM_SENSOR_RES_3,
MSM_SENSOR_RES_4,
MSM_SENSOR_RES_5,
MSM_SENSOR_RES_6,
MSM_SENSOR_RES_7,
MSM_SENSOR_INVALID_RES,
};
enum sensor_sub_module_t {
SUB_MODULE_SENSOR,
SUB_MODULE_CHROMATIX,
SUB_MODULE_ACTUATOR,
SUB_MODULE_EEPROM,
SUB_MODULE_LED_FLASH,
SUB_MODULE_STROBE_FLASH,
SUB_MODULE_CSIPHY,
SUB_MODULE_CSIPHY_3D,
SUB_MODULE_CSID,
SUB_MODULE_CSID_3D,
SUB_MODULE_MAX,
};
enum csid_cfg_type_t {
CSID_INIT,
CSID_CFG,
CSID_RELEASE,
};
enum csiphy_cfg_type_t {
CSIPHY_INIT,
CSIPHY_CFG,
CSIPHY_RELEASE,
};
enum camera_vreg_type {
REG_LDO,
REG_VS,
REG_GPIO,
};
struct msm_sensor_power_setting {
enum msm_sensor_power_seq_type_t seq_type;
uint16_t seq_val;
long config_val;
uint16_t delay;
void *data[10];
};
struct msm_sensor_power_setting_array {
struct msm_sensor_power_setting *power_setting;
uint16_t size;
};
struct msm_sensor_id_info_t {
uint16_t sensor_id_reg_addr;
uint16_t sensor_id;
};
struct msm_camera_sensor_slave_info {
uint16_t slave_addr;
enum msm_camera_i2c_reg_addr_type addr_type;
struct msm_sensor_id_info_t sensor_id_info;
struct msm_sensor_power_setting_array power_setting_array;
};
struct msm_camera_i2c_reg_array {
uint16_t reg_addr;
uint16_t reg_data;
};
struct msm_camera_i2c_reg_setting {
struct msm_camera_i2c_reg_array *reg_setting;
uint16_t size;
enum msm_camera_i2c_reg_addr_type addr_type;
enum msm_camera_i2c_data_type data_type;
uint16_t delay;
};
struct msm_camera_i2c_seq_reg_array {
uint16_t reg_addr;
uint8_t reg_data[I2C_SEQ_REG_DATA_MAX];
uint16_t reg_data_size;
};
struct msm_camera_i2c_seq_reg_setting {
struct msm_camera_i2c_seq_reg_array *reg_setting;
uint16_t size;
enum msm_camera_i2c_reg_addr_type addr_type;
uint16_t delay;
};
struct msm_camera_csid_vc_cfg {
uint8_t cid;
uint8_t dt;
uint8_t decode_format;
};
struct msm_camera_csid_lut_params {
uint8_t num_cid;
struct msm_camera_csid_vc_cfg *vc_cfg[MAX_CID];
};
struct msm_camera_csid_params {
uint8_t lane_cnt;
uint16_t lane_assign;
uint8_t phy_sel;
struct msm_camera_csid_lut_params lut_params;
};
struct msm_camera_csiphy_params {
uint8_t lane_cnt;
uint8_t settle_cnt;
uint16_t lane_mask;
uint8_t combo_mode;
};
struct msm_camera_csi2_params {
struct msm_camera_csid_params csid_params;
struct msm_camera_csiphy_params csiphy_params;
};
struct msm_camera_csi_lane_params {
uint16_t csi_lane_assign;
uint16_t csi_lane_mask;
};
struct csi_lane_params_t {
uint16_t csi_lane_assign;
uint8_t csi_lane_mask;
uint8_t csi_if;
uint8_t csid_core[2];
uint8_t csi_phy_sel;
};
struct msm_sensor_info_t {
char sensor_name[MAX_SENSOR_NAME];
int32_t session_id;
int32_t subdev_id[SUB_MODULE_MAX];
};
struct camera_vreg_t {
const char *reg_name;
enum camera_vreg_type type;
int min_voltage;
int max_voltage;
int op_mode;
uint32_t delay;
};
enum camb_position_t {
BACK_CAMERA_B,
FRONT_CAMERA_B,
};
enum camerab_mode_t {
CAMERA_MODE_2D_B = (1<<0),
CAMERA_MODE_3D_B = (1<<1)
};
struct msm_sensor_init_params {
/* mask of modes supported: 2D, 3D */
int modes_supported;
/* sensor position: front, back */
enum camb_position_t position;
/* sensor mount angle */
uint32_t sensor_mount_angle;
};
struct sensorb_cfg_data {
int cfgtype;
union {
struct msm_sensor_info_t sensor_info;
struct msm_sensor_init_params sensor_init_params;
void *setting;
} cfg;
};
struct csid_cfg_data {
enum csid_cfg_type_t cfgtype;
union {
uint32_t csid_version;
struct msm_camera_csid_params *csid_params;
} cfg;
};
struct csiphy_cfg_data {
enum csiphy_cfg_type_t cfgtype;
union {
struct msm_camera_csiphy_params *csiphy_params;
struct msm_camera_csi_lane_params *csi_lane_params;
} cfg;
};
enum msm_sensor_cfg_type_t {
CFG_SET_SLAVE_INFO,
CFG_WRITE_I2C_ARRAY,
CFG_WRITE_I2C_SEQ_ARRAY,
CFG_POWER_UP,
CFG_POWER_DOWN,
CFG_SET_STOP_STREAM_SETTING,
CFG_GET_SENSOR_INFO,
CFG_GET_SENSOR_INIT_PARAMS,
};
#define VIDIOC_MSM_SENSOR_CFG \
_IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct sensorb_cfg_data)
#define VIDIOC_MSM_SENSOR_RELEASE \
_IO('V', BASE_VIDIOC_PRIVATE + 2)
#define VIDIOC_MSM_SENSOR_GET_SUBDEV_ID \
_IOWR('V', BASE_VIDIOC_PRIVATE + 3, uint32_t)
#define VIDIOC_MSM_CSIPHY_IO_CFG \
_IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct csid_cfg_data)
#define VIDIOC_MSM_CSID_IO_CFG \
_IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct csiphy_cfg_data)
#define MSM_V4L2_PIX_FMT_META v4l2_fourcc('M', 'E', 'T', 'A') /* META */
#endif /* __LINUX_MSM_CAM_SENSOR_H */

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
/* Copyright (c) 2009-2013, 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

View File

@ -19,6 +19,22 @@
#define MSM_CAMERA_NAME "msm_camera"
#define MSM_CONFIGURATION_NAME "msm_config"
#define MSM_CAMERA_SUBDEV_CSIPHY 0
#define MSM_CAMERA_SUBDEV_CSID 1
#define MSM_CAMERA_SUBDEV_ISPIF 2
#define MSM_CAMERA_SUBDEV_VFE 3
#define MSM_CAMERA_SUBDEV_AXI 4
#define MSM_CAMERA_SUBDEV_VPE 5
#define MSM_CAMERA_SUBDEV_SENSOR 6
#define MSM_CAMERA_SUBDEV_ACTUATOR 7
#define MSM_CAMERA_SUBDEV_EEPROM 8
#define MSM_CAMERA_SUBDEV_CPP 9
#define MSM_CAMERA_SUBDEV_CCI 10
#define MSM_CAMERA_SUBDEV_LED_FLASH 11
#define MSM_CAMERA_SUBDEV_STROBE_FLASH 12
#define MSM_MAX_CAMERA_SENSORS 5
/* featur base */
#define MSM_CAMERA_FEATURE_BASE 0x00010000
#define MSM_CAMERA_FEATURE_SHUTDOWN (MSM_CAMERA_FEATURE_BASE + 1)

View File

@ -11,3 +11,4 @@ header-y += msm_jpeg.h
header-y += msm_media_info.h
header-y += msm_vidc.h
header-y += msmb_camera.h
header-y += msm_cam_sensor.h

View File

@ -1592,6 +1592,19 @@ enum camera_vreg_type {
REG_GPIO,
};
enum msm_camera_vreg_name_t {
CAM_VDIG,
CAM_VIO,
CAM_VANA,
CAM_VAF,
CAM_VREG_MAX,
};
struct msm_camera_csi_lane_params {
uint16_t csi_lane_assign;
uint16_t csi_lane_mask;
};
struct camera_vreg_t {
const char *reg_name;
enum camera_vreg_type type;