M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions
@@ -0,0 +1,17 @@
GCC_VERSION := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
ccflags-y += -Idrivers/media/platform/msm/camera_v1 -Idrivers/media/platform/msm/camera_v1/cci
obj-$(CONFIG_MSM_CAMERA) += msm_camera_io_util.o msm_camera_i2c.o
ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
obj-$(CONFIG_MSM_CAMERA) += msm_camera_i2c_mux.o
obj-$(CONFIG_ARCH_MSM7X27A) += msm_io_7x27a_v4l2.o
obj-$(CONFIG_ARCH_MSM8X60) += msm_io_vfe31_v4l2.o
obj-$(CONFIG_ARCH_MSM7X30) += msm_io_vfe31_v4l2.o
else
obj-$(CONFIG_ARCH_MSM7X27A) += msm_io_7x27a.o
obj-$(CONFIG_ARCH_MSM8X60) += msm_io_8x60.o
obj-$(CONFIG_ARCH_MSM7X30) += msm_io_vfe31.o
endif
obj-$(CONFIG_ARCH_MSM_ARM11) += msm_io7x.o
obj-$(CONFIG_ARCH_QSD8X50) += msm_io8x.o
obj-$(CONFIG_ARCH_MSM8960) += msm_io_8960.o
@@ -0,0 +1,606 @@
/* Copyright (c) 2011, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <mach/camera.h>
#include "msm_camera_i2c.h"
#include "msm.h"
#include "msm_cci.h"
int32_t msm_camera_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_i2c_rxdata failed 0x%x\n", saddr);
return rc;
}
int32_t msm_camera_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_i2c_txdata faild 0x%x\n", saddr);
return 0;
}
int32_t msm_camera_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->cci_client) {
struct msm_camera_cci_ctrl cci_ctrl;
struct msm_camera_i2c_reg_conf reg_conf_tbl;
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);
CDBG("%s line %d rc = %d\n", __func__, __LINE__, rc);
rc = cci_ctrl.status;
} else {
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_i2c_txdata(client, buf, len);
if (rc < 0)
S_I2C_DBG("%s fail\n", __func__);
}
return rc;
}
int32_t msm_camera_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->cci_client) {
struct msm_camera_cci_ctrl cci_ctrl;
struct msm_camera_i2c_reg_conf reg_conf_tbl[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;
} else {
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_i2c_txdata(client, buf, len+num_byte);
if (rc < 0)
S_I2C_DBG("%s fail\n", __func__);
}
return rc;
}
int32_t msm_camera_i2c_set_mask(struct msm_camera_i2c_client *client,
uint16_t addr, uint16_t mask,
enum msm_camera_i2c_data_type data_type, uint16_t set_mask)
{
int32_t rc;
uint16_t reg_data;
rc = msm_camera_i2c_read(client, addr, &reg_data, data_type);
if (rc < 0) {
S_I2C_DBG("%s read fail\n", __func__);
return rc;
}
S_I2C_DBG("%s addr: 0x%x data: 0x%x setmask: 0x%x\n",
__func__, addr, reg_data, mask);
if (set_mask)
reg_data |= mask;
else
reg_data &= ~mask;
S_I2C_DBG("%s write: 0x%x\n", __func__, reg_data);
rc = msm_camera_i2c_write(client, addr, reg_data, data_type);
if (rc < 0)
S_I2C_DBG("%s write fail\n", __func__);
return rc;
}
int32_t msm_camera_i2c_set_write_mask_data(struct msm_camera_i2c_client *client,
uint16_t addr, uint16_t data, int16_t mask,
enum msm_camera_i2c_data_type data_type)
{
int32_t rc;
uint16_t reg_data;
CDBG("%s\n", __func__);
if (mask == -1)
return 0;
if (mask == 0)
rc = msm_camera_i2c_write(client, addr, data, data_type);
else{
rc = msm_camera_i2c_read(client, addr, &reg_data, data_type);
if (rc < 0) {
CDBG("%s read fail\n", __func__);
return rc;
}
reg_data = reg_data & mask;
reg_data = (reg_data | (data & (~mask)));
rc = msm_camera_i2c_write(client, addr, reg_data, data_type);
if (rc < 0)
CDBG("%s write fail\n", __func__);
}
return rc;
}
int32_t msm_camera_i2c_compare(struct msm_camera_i2c_client *client,
uint16_t addr, uint16_t data,
enum msm_camera_i2c_data_type data_type)
{
int32_t rc = -EIO;
uint16_t reg_data = 0;
int data_len = 0;
switch (data_type) {
case MSM_CAMERA_I2C_BYTE_DATA:
case MSM_CAMERA_I2C_WORD_DATA:
data_len = data_type;
break;
case MSM_CAMERA_I2C_SET_BYTE_MASK:
case MSM_CAMERA_I2C_UNSET_BYTE_MASK:
data_len = MSM_CAMERA_I2C_BYTE_DATA;
break;
case MSM_CAMERA_I2C_SET_WORD_MASK:
case MSM_CAMERA_I2C_UNSET_WORD_MASK:
data_len = MSM_CAMERA_I2C_WORD_DATA;
break;
default:
pr_err("%s: Unsupport data type: %d\n", __func__, data_type);
break;
}
rc = msm_camera_i2c_read(client,
addr, &reg_data, data_len);
if (rc < 0)
return rc;
rc = 0;
switch (data_type) {
case MSM_CAMERA_I2C_BYTE_DATA:
case MSM_CAMERA_I2C_WORD_DATA:
if (data == reg_data)
return rc;
break;
case MSM_CAMERA_I2C_SET_BYTE_MASK:
case MSM_CAMERA_I2C_SET_WORD_MASK:
if ((reg_data & data) == data)
return rc;
break;
case MSM_CAMERA_I2C_UNSET_BYTE_MASK:
case MSM_CAMERA_I2C_UNSET_WORD_MASK:
if (!(reg_data & data))
return rc;
break;
default:
pr_err("%s: Unsupport data type: %d\n", __func__, data_type);
break;
}
S_I2C_DBG("%s: Register and data does not match\n", __func__);
rc = 1;
return rc;
}
int32_t msm_camera_i2c_poll(struct msm_camera_i2c_client *client,
uint16_t addr, uint16_t data,
enum msm_camera_i2c_data_type data_type)
{
int32_t rc = -EIO;
int i;
S_I2C_DBG("%s: addr: 0x%x data: 0x%x dt: %d\n",
__func__, addr, data, data_type);
for (i = 0; i < 20; i++) {
rc = msm_camera_i2c_compare(client,
addr, data, data_type);
if (rc == 0 || rc < 0)
break;
usleep_range(10000, 11000);
}
return rc;
}
int32_t msm_camera_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_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;
}
int32_t msm_camera_i2c_write_bayer_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;
if (!client || !write_setting)
return rc;
reg_setting = write_setting->reg_setting;
client->addr_type = write_setting->addr_type;
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;
for (i = 0; i < write_setting->size; i++) {
rc = msm_camera_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);
return rc;
}
int32_t msm_camera_i2c_write_tbl(struct msm_camera_i2c_client *client,
struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size,
enum msm_camera_i2c_data_type data_type)
{
int i;
int32_t rc = -EFAULT;
for (i = 0; i < size; i++) {
enum msm_camera_i2c_data_type dt;
if (reg_conf_tbl->cmd_type == MSM_CAMERA_I2C_CMD_POLL) {
rc = msm_camera_i2c_poll(client,
reg_conf_tbl->reg_addr,
reg_conf_tbl->reg_data,
reg_conf_tbl->dt);
} else {
if (reg_conf_tbl->dt == 0)
dt = data_type;
else
dt = reg_conf_tbl->dt;
switch (dt) {
case MSM_CAMERA_I2C_BYTE_DATA:
case MSM_CAMERA_I2C_WORD_DATA:
rc = msm_camera_i2c_write(
client,
reg_conf_tbl->reg_addr,
reg_conf_tbl->reg_data, dt);
break;
case MSM_CAMERA_I2C_SET_BYTE_MASK:
rc = msm_camera_i2c_set_mask(client,
reg_conf_tbl->reg_addr,
reg_conf_tbl->reg_data,
MSM_CAMERA_I2C_BYTE_DATA, 1);
break;
case MSM_CAMERA_I2C_UNSET_BYTE_MASK:
rc = msm_camera_i2c_set_mask(client,
reg_conf_tbl->reg_addr,
reg_conf_tbl->reg_data,
MSM_CAMERA_I2C_BYTE_DATA, 0);
break;
case MSM_CAMERA_I2C_SET_WORD_MASK:
rc = msm_camera_i2c_set_mask(client,
reg_conf_tbl->reg_addr,
reg_conf_tbl->reg_data,
MSM_CAMERA_I2C_WORD_DATA, 1);
break;
case MSM_CAMERA_I2C_UNSET_WORD_MASK:
rc = msm_camera_i2c_set_mask(client,
reg_conf_tbl->reg_addr,
reg_conf_tbl->reg_data,
MSM_CAMERA_I2C_WORD_DATA, 0);
break;
case MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA:
rc = msm_camera_i2c_set_write_mask_data(
client,
reg_conf_tbl->reg_addr,
reg_conf_tbl->reg_data,
reg_conf_tbl->mask,
MSM_CAMERA_I2C_BYTE_DATA);
break;
default:
pr_err("%s: Unsupport data type: %d\n",
__func__, dt);
break;
}
}
if (rc < 0)
break;
reg_conf_tbl++;
}
return rc;
}
int32_t msm_camera_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->cci_client) {
struct msm_camera_cci_ctrl cci_ctrl;
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);
CDBG("%s line %d rc = %d\n", __func__, __LINE__, rc);
rc = cci_ctrl.status;
} else {
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_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_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->cci_client) {
struct msm_camera_cci_ctrl cci_ctrl;
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;
} else {
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_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_sensor_write_conf_array(struct msm_camera_i2c_client *client,
struct msm_camera_i2c_conf_array *array, uint16_t index)
{
int32_t rc;
rc = msm_camera_i2c_write_tbl(client,
(struct msm_camera_i2c_reg_conf *) array[index].conf,
array[index].size, array[index].data_type);
if (array[index].delay > 20)
msleep(array[index].delay);
else
usleep_range(array[index].delay*1000,
(array[index].delay+1)*1000);
return rc;
}
int32_t msm_sensor_write_enum_conf_array(struct msm_camera_i2c_client *client,
struct msm_camera_i2c_enum_conf_array *conf,
uint16_t enum_val)
{
int32_t rc = -1, i;
for (i = 0; i < conf->num_enum; i++) {
if (conf->conf_enum[i] == enum_val)
break;
if (conf->conf_enum[i] > enum_val)
break;
}
if (i == conf->num_enum)
i = conf->num_enum - 1;
if (i >= conf->num_index)
return rc;
rc = msm_sensor_write_all_conf_array(client,
&conf->conf[i*conf->num_conf], conf->num_conf);
if (conf->delay > 20)
msleep(conf->delay);
else
usleep_range(conf->delay*1000,
(conf->delay+1)*1000);
return rc;
}
int32_t msm_sensor_write_all_conf_array(struct msm_camera_i2c_client *client,
struct msm_camera_i2c_conf_array *array, uint16_t size)
{
int32_t rc = 0, i;
for (i = 0; i < size; i++) {
rc = msm_sensor_write_conf_array(client, array, i);
if (rc < 0)
break;
}
return rc;
}
int32_t msm_sensor_cci_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);
CDBG("%s line %d rc = %d\n", __func__, __LINE__, rc);
return cci_ctrl.status;
}
@@ -0,0 +1,115 @@
/* 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_CAMERA_I2C_H
#define MSM_CAMERA_I2C_H
#include <linux/i2c.h>
#include <linux/delay.h>
#include <mach/camera.h>
#include <media/v4l2-subdev.h>
#include <media/msm_camera.h>
#define CONFIG_MSM_CAMERA_I2C_DBG 0
#if CONFIG_MSM_CAMERA_I2C_DBG
#define S_I2C_DBG(fmt, args...) printk(fmt, ##args)
#else
#define S_I2C_DBG(fmt, args...) CDBG(fmt, ##args)
#endif
struct msm_camera_i2c_client {
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_conf_array {
struct msm_camera_i2c_reg_conf *conf;
uint16_t size;
uint16_t delay;
enum msm_camera_i2c_data_type data_type;
};
struct msm_camera_i2c_enum_conf_array {
struct msm_camera_i2c_conf_array *conf;
int *conf_enum;
uint16_t num_enum;
uint16_t num_index;
uint16_t num_conf;
uint16_t delay;
enum msm_camera_i2c_data_type data_type;
};
int32_t msm_camera_i2c_rxdata(struct msm_camera_i2c_client *client,
unsigned char *rxdata, int data_length);
int32_t msm_camera_i2c_txdata(struct msm_camera_i2c_client *client,
unsigned char *txdata, int length);
int32_t msm_camera_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_i2c_read_seq(struct msm_camera_i2c_client *client,
uint16_t addr, uint8_t *data, uint16_t num_byte);
int32_t msm_camera_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_i2c_write_seq(struct msm_camera_i2c_client *client,
uint16_t addr, uint8_t *data, uint16_t num_byte);
int32_t msm_camera_i2c_set_mask(struct msm_camera_i2c_client *client,
uint16_t addr, uint16_t mask,
enum msm_camera_i2c_data_type data_type, uint16_t flag);
int32_t msm_camera_i2c_compare(struct msm_camera_i2c_client *client,
uint16_t addr, uint16_t data,
enum msm_camera_i2c_data_type data_type);
int32_t msm_camera_i2c_poll(struct msm_camera_i2c_client *client,
uint16_t addr, uint16_t data,
enum msm_camera_i2c_data_type data_type);
int32_t msm_camera_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_camera_i2c_write_bayer_table(
struct msm_camera_i2c_client *client,
struct msm_camera_i2c_reg_setting *write_setting);
int32_t msm_camera_i2c_write_tbl(struct msm_camera_i2c_client *client,
struct msm_camera_i2c_reg_conf *reg_conf_tbl, uint16_t size,
enum msm_camera_i2c_data_type data_type);
int32_t msm_sensor_write_conf_array(struct msm_camera_i2c_client *client,
struct msm_camera_i2c_conf_array *array, uint16_t index);
int32_t msm_sensor_write_enum_conf_array(struct msm_camera_i2c_client *client,
struct msm_camera_i2c_enum_conf_array *conf, uint16_t enum_val);
int32_t msm_sensor_write_all_conf_array(struct msm_camera_i2c_client *client,
struct msm_camera_i2c_conf_array *array, uint16_t size);
int32_t msm_sensor_cci_util(struct msm_camera_i2c_client *client,
uint16_t cci_cmd);
#endif
@@ -0,0 +1,187 @@
/* 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.
*/
#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.h"
#include "msm_camera_i2c_mux.h"
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 __devinit 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");
@@ -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
@@ -0,0 +1,535 @@
/* Copyright (c) 2011-2012, 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 <mach/board.h>
#include <mach/camera.h>
#include <mach/gpiomux.h>
#define BUFF_SIZE_128 128
static int gpio_ref_count;
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++) {
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) {
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 failed\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;
}
static int config_gpio_table(struct msm_camera_gpio_conf *gpio)
{
int rc = 0, i = 0;
uint32_t *table_on;
uint32_t *table_off;
uint32_t len;
table_on = gpio->camera_on_table;
table_off = gpio->camera_off_table;
len = gpio->camera_on_table_size;
for (i = 0; i < len; i++) {
rc = gpio_tlmm_config(table_on[i], GPIO_CFG_ENABLE);
if (rc) {
pr_err("%s not able to get gpio\n", __func__);
for (i--; i >= 0; i--)
gpio_tlmm_config(table_off[i],
GPIO_CFG_ENABLE);
break;
}
}
return rc;
}
int msm_camera_request_gpio_table(struct msm_camera_sensor_info *sinfo,
int gpio_en)
{
int rc = 0;
struct msm_camera_gpio_conf *gpio_conf =
sinfo->sensor_platform_info->gpio_conf;
if (!gpio_conf->gpio_no_mux) {
if (gpio_conf->cam_gpio_req_tbl == NULL ||
gpio_conf->cam_gpio_common_tbl == NULL) {
pr_err("%s: NULL camera gpio table\n", __func__);
return -EFAULT;
}
}
if (gpio_conf->gpio_no_mux)
config_gpio_table(gpio_conf);
if (gpio_en) {
if (!gpio_conf->gpio_no_mux && !gpio_ref_count) {
if (gpio_conf->cam_gpiomux_conf_tbl != NULL) {
msm_gpiomux_install(
(struct msm_gpiomux_config *)
gpio_conf->cam_gpiomux_conf_tbl,
gpio_conf->cam_gpiomux_conf_tbl_size);
}
rc = gpio_request_array(gpio_conf->cam_gpio_common_tbl,
gpio_conf->cam_gpio_common_tbl_size);
if (rc < 0) {
pr_err("%s common gpio request failed\n"
, __func__);
return rc;
}
}
gpio_ref_count++;
if (gpio_conf->cam_gpio_req_tbl_size) {
rc = gpio_request_array(gpio_conf->cam_gpio_req_tbl,
gpio_conf->cam_gpio_req_tbl_size);
if (rc < 0) {
pr_err("%s camera gpio"
"request failed\n", __func__);
gpio_free_array(gpio_conf->cam_gpio_common_tbl,
gpio_conf->cam_gpio_common_tbl_size);
return rc;
}
}
} else {
gpio_ref_count--;
gpio_free_array(gpio_conf->cam_gpio_req_tbl,
gpio_conf->cam_gpio_req_tbl_size);
if (!gpio_conf->gpio_no_mux && !gpio_ref_count)
gpio_free_array(gpio_conf->cam_gpio_common_tbl,
gpio_conf->cam_gpio_common_tbl_size);
}
return rc;
}
int msm_camera_config_gpio_table(struct msm_camera_sensor_info *sinfo,
int gpio_en)
{
struct msm_camera_gpio_conf *gpio_conf =
sinfo->sensor_platform_info->gpio_conf;
int rc = 0, i;
if (gpio_en) {
for (i = 0; i < gpio_conf->cam_gpio_set_tbl_size; i++) {
gpio_set_value_cansleep(
gpio_conf->cam_gpio_set_tbl[i].gpio,
gpio_conf->cam_gpio_set_tbl[i].flags);
usleep_range(gpio_conf->cam_gpio_set_tbl[i].delay,
gpio_conf->cam_gpio_set_tbl[i].delay + 1000);
}
} else {
for (i = gpio_conf->cam_gpio_set_tbl_size - 1; i >= 0; i--) {
if (gpio_conf->cam_gpio_set_tbl[i].flags)
gpio_set_value_cansleep(
gpio_conf->cam_gpio_set_tbl[i].gpio,
GPIOF_OUT_INIT_LOW);
}
}
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_init_gpio_table(struct gpio *gpio_tbl, uint8_t gpio_tbl_size,
int gpio_en)
{
int rc = 0;
if (gpio_en) {
rc = gpio_request_array(gpio_tbl, gpio_tbl_size);
if (rc < 0) {
pr_err("%s:%d failed\n" , __func__, __LINE__);
return rc;
}
} else {
gpio_free_array(gpio_tbl, gpio_tbl_size);
}
return rc;
}
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;
}
@@ -0,0 +1,318 @@
/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <mach/gpio.h>
#include <mach/board.h>
#include <mach/camera.h>
#include <mach/clk.h>
#define CAMIF_CFG_RMSK 0x1fffff
#define CAM_SEL_BMSK 0x2
#define CAM_PCLK_SRC_SEL_BMSK 0x60000
#define CAM_PCLK_INVERT_BMSK 0x80000
#define CAM_PAD_REG_SW_RESET_BMSK 0x100000
#define EXT_CAM_HSYNC_POL_SEL_BMSK 0x10000
#define EXT_CAM_VSYNC_POL_SEL_BMSK 0x8000
#define MDDI_CLK_CHICKEN_BIT_BMSK 0x80
#define CAM_SEL_SHFT 0x1
#define CAM_PCLK_SRC_SEL_SHFT 0x11
#define CAM_PCLK_INVERT_SHFT 0x13
#define CAM_PAD_REG_SW_RESET_SHFT 0x14
#define EXT_CAM_HSYNC_POL_SEL_SHFT 0x10
#define EXT_CAM_VSYNC_POL_SEL_SHFT 0xF
#define MDDI_CLK_CHICKEN_BIT_SHFT 0x7
#define APPS_RESET_OFFSET 0x00000210
static struct clk *camio_vfe_mdc_clk;
static struct clk *camio_mdc_clk;
static struct clk *camio_vfe_clk;
static struct msm_camera_io_ext camio_ext;
static struct resource *appio, *mdcio;
void __iomem *appbase, *mdcbase;
static struct resource *appio, *mdcio;
void __iomem *appbase, *mdcbase;
int msm_camio_clk_enable(enum msm_camio_clk_type clktype)
{
int rc = -1;
struct clk *clk = NULL;
switch (clktype) {
case CAMIO_VFE_MDC_CLK:
clk = camio_vfe_mdc_clk = clk_get(NULL, "vfe_mdc_clk");
break;
case CAMIO_MDC_CLK:
clk = camio_mdc_clk = clk_get(NULL, "mdc_clk");
break;
case CAMIO_VFE_CLK:
clk = camio_vfe_clk = clk_get(NULL, "vfe_clk");
break;
default:
break;
}
if (!IS_ERR(clk)) {
clk_enable(clk);
rc = 0;
}
return rc;
}
int msm_camio_clk_disable(enum msm_camio_clk_type clktype)
{
int rc = -1;
struct clk *clk = NULL;
switch (clktype) {
case CAMIO_VFE_MDC_CLK:
clk = camio_vfe_mdc_clk;
break;
case CAMIO_MDC_CLK:
clk = camio_mdc_clk;
break;
case CAMIO_VFE_CLK:
clk = camio_vfe_clk;
break;
default:
break;
}
if (!IS_ERR(clk)) {
clk_disable(clk);
clk_put(clk);
rc = 0;
}
return rc;
}
void msm_camio_clk_rate_set(int rate)
{
struct clk *clk = camio_vfe_clk;
if (clk != ERR_PTR(-ENOENT))
clk_set_rate(clk, rate);
}
int msm_camio_enable(struct platform_device *pdev)
{
int rc = 0;
struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
struct msm_camera_device_platform_data *camdev = sinfo->pdata;
camio_ext = camdev->ioext;
appio = request_mem_region(camio_ext.appphy,
camio_ext.appsz, pdev->name);
if (!appio) {
rc = -EBUSY;
goto enable_fail;
}
appbase = ioremap(camio_ext.appphy,
camio_ext.appsz);
if (!appbase) {
rc = -ENOMEM;
goto apps_no_mem;
}
msm_camio_clk_enable(CAMIO_VFE_CLK);
msm_camio_clk_enable(CAMIO_MDC_CLK);
return 0;
apps_no_mem:
release_mem_region(camio_ext.appphy, camio_ext.appsz);
enable_fail:
return rc;
}
int msm_camio_sensor_clk_on(struct platform_device *pdev)
{
struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
struct msm_camera_device_platform_data *camdev = sinfo->pdata;
int32_t rc = 0;
camio_ext = camdev->ioext;
mdcio = request_mem_region(camio_ext.mdcphy,
camio_ext.mdcsz, pdev->name);
if (!mdcio)
rc = -EBUSY;
mdcbase = ioremap(camio_ext.mdcphy,
camio_ext.mdcsz);
if (!mdcbase) {
rc = -EINVAL;
goto mdc_no_mem;
}
camdev->camera_gpio_on();
return msm_camio_clk_enable(CAMIO_VFE_MDC_CLK);
mdc_no_mem:
release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz);
return rc;
}
int msm_camio_sensor_clk_off(struct platform_device *pdev)
{
struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
struct msm_camera_device_platform_data *camdev = sinfo->pdata;
camdev->camera_gpio_off();
iounmap(mdcbase);
release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz);
return msm_camio_clk_disable(CAMIO_VFE_MDC_CLK);
}
void msm_camio_disable(struct platform_device *pdev)
{
iounmap(appbase);
release_mem_region(camio_ext.appphy, camio_ext.appsz);
msm_camio_clk_disable(CAMIO_VFE_CLK);
msm_camio_clk_disable(CAMIO_MDC_CLK);
}
void msm_disable_io_gpio_clk(struct platform_device *pdev)
{
return;
}
void msm_camio_camif_pad_reg_reset(void)
{
uint32_t reg;
uint32_t mask, value;
/* select CLKRGM_VFE_SRC_CAM_VFE_SRC: internal source */
msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_INTERNAL);
reg = (msm_camera_io_r_mb(mdcbase)) & CAMIF_CFG_RMSK;
mask = CAM_SEL_BMSK |
CAM_PCLK_SRC_SEL_BMSK |
CAM_PCLK_INVERT_BMSK;
value = 1 << CAM_SEL_SHFT |
3 << CAM_PCLK_SRC_SEL_SHFT |
0 << CAM_PCLK_INVERT_SHFT;
msm_camera_io_w_mb((reg & (~mask)) | (value & mask), mdcbase);
usleep_range(10000, 11000);
reg = (msm_camera_io_r_mb(mdcbase)) & CAMIF_CFG_RMSK;
mask = CAM_PAD_REG_SW_RESET_BMSK;
value = 1 << CAM_PAD_REG_SW_RESET_SHFT;
msm_camera_io_w_mb((reg & (~mask)) | (value & mask), mdcbase);
usleep_range(10000, 11000);
reg = (msm_camera_io_r_mb(mdcbase)) & CAMIF_CFG_RMSK;
mask = CAM_PAD_REG_SW_RESET_BMSK;
value = 0 << CAM_PAD_REG_SW_RESET_SHFT;
msm_camera_io_w_mb((reg & (~mask)) | (value & mask), mdcbase);
usleep_range(10000, 11000);
msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_EXTERNAL);
usleep_range(10000, 11000);
}
void msm_camio_vfe_blk_reset(void)
{
uint32_t val;
/* do apps reset */
val = msm_camera_io_r_mb(appbase + 0x00000210);
val |= 0x1;
msm_camera_io_w_mb(val, appbase + 0x00000210);
usleep_range(10000, 11000);
val = msm_camera_io_r_mb(appbase + 0x00000210);
val &= ~0x1;
msm_camera_io_w_mb(val, appbase + 0x00000210);
usleep_range(10000, 11000);
/* do axi reset */
val = msm_camera_io_r_mb(appbase + 0x00000208);
val |= 0x1;
msm_camera_io_w_mb(val, appbase + 0x00000208);
usleep_range(10000, 11000);
val = msm_camera_io_r_mb(appbase + 0x00000208);
val &= ~0x1;
msm_camera_io_w_mb(val, appbase + 0x00000208);
usleep_range(10000, 11000);
}
void msm_camio_camif_pad_reg_reset_2(void)
{
uint32_t reg;
uint32_t mask, value;
reg = (msm_camera_io_r_mb(mdcbase)) & CAMIF_CFG_RMSK;
mask = CAM_PAD_REG_SW_RESET_BMSK;
value = 1 << CAM_PAD_REG_SW_RESET_SHFT;
msm_camera_io_w_mb((reg & (~mask)) | (value & mask), mdcbase);
usleep_range(10000, 11000);
reg = (msm_camera_io_r_mb(mdcbase)) & CAMIF_CFG_RMSK;
mask = CAM_PAD_REG_SW_RESET_BMSK;
value = 0 << CAM_PAD_REG_SW_RESET_SHFT;
msm_camera_io_w_mb((reg & (~mask)) | (value & mask), mdcbase);
usleep_range(10000, 11000);
}
void msm_camio_clk_sel(enum msm_camio_clk_src_type srctype)
{
struct clk *clk = NULL;
clk = camio_vfe_clk;
if (clk != NULL && clk != ERR_PTR(-ENOENT)) {
switch (srctype) {
case MSM_CAMIO_CLK_SRC_INTERNAL:
clk_set_flags(clk, 0x00000100 << 1);
break;
case MSM_CAMIO_CLK_SRC_EXTERNAL:
clk_set_flags(clk, 0x00000100);
break;
default:
break;
}
}
}
int msm_camio_probe_on(struct platform_device *pdev)
{
struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
struct msm_camera_device_platform_data *camdev = sinfo->pdata;
camdev->camera_gpio_on();
return msm_camio_clk_enable(CAMIO_VFE_CLK);
}
int msm_camio_probe_off(struct platform_device *pdev)
{
struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
struct msm_camera_device_platform_data *camdev = sinfo->pdata;
camdev->camera_gpio_off();
return msm_camio_clk_disable(CAMIO_VFE_CLK);
}
@@ -0,0 +1,331 @@
/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <mach/gpio.h>
#include <mach/board.h>
#include <mach/camera.h>
#include <mach/clk.h>
#define CAMIF_CFG_RMSK 0x1fffff
#define CAM_SEL_BMSK 0x2
#define CAM_PCLK_SRC_SEL_BMSK 0x60000
#define CAM_PCLK_INVERT_BMSK 0x80000
#define CAM_PAD_REG_SW_RESET_BMSK 0x100000
#define EXT_CAM_HSYNC_POL_SEL_BMSK 0x10000
#define EXT_CAM_VSYNC_POL_SEL_BMSK 0x8000
#define MDDI_CLK_CHICKEN_BIT_BMSK 0x80
#define CAM_SEL_SHFT 0x1
#define CAM_PCLK_SRC_SEL_SHFT 0x11
#define CAM_PCLK_INVERT_SHFT 0x13
#define CAM_PAD_REG_SW_RESET_SHFT 0x14
#define EXT_CAM_HSYNC_POL_SEL_SHFT 0x10
#define EXT_CAM_VSYNC_POL_SEL_SHFT 0xF
#define MDDI_CLK_CHICKEN_BIT_SHFT 0x7
#define APPS_RESET_OFFSET 0x00000214
static struct clk *camio_vfe_mdc_clk;
static struct clk *camio_mdc_clk;
static struct clk *camio_vfe_clk;
static struct clk *camio_vfe_axi_clk;
static struct msm_camera_io_ext camio_ext;
static struct resource *appio, *mdcio;
void __iomem *appbase, *mdcbase;
int msm_camio_clk_enable(enum msm_camio_clk_type clktype)
{
int rc = 0;
struct clk *clk = NULL;
switch (clktype) {
case CAMIO_VFE_MDC_CLK:
camio_vfe_mdc_clk = clk = clk_get(NULL, "vfe_mdc_clk");
break;
case CAMIO_MDC_CLK:
camio_mdc_clk = clk = clk_get(NULL, "mdc_clk");
break;
case CAMIO_VFE_CLK:
camio_vfe_clk = clk = clk_get(NULL, "vfe_clk");
break;
case CAMIO_VFE_AXI_CLK:
camio_vfe_axi_clk = clk = clk_get(NULL, "vfe_axi_clk");
break;
default:
break;
}
if (!IS_ERR(clk))
clk_enable(clk);
else
rc = -1;
return rc;
}
int msm_camio_clk_disable(enum msm_camio_clk_type clktype)
{
int rc = 0;
struct clk *clk = NULL;
switch (clktype) {
case CAMIO_VFE_MDC_CLK:
clk = camio_vfe_mdc_clk;
break;
case CAMIO_MDC_CLK:
clk = camio_mdc_clk;
break;
case CAMIO_VFE_CLK:
clk = camio_vfe_clk;
break;
case CAMIO_VFE_AXI_CLK:
clk = camio_vfe_axi_clk;
break;
default:
break;
}
if (!IS_ERR(clk)) {
clk_disable(clk);
clk_put(clk);
} else
rc = -1;
return rc;
}
void msm_camio_clk_rate_set(int rate)
{
struct clk *clk = camio_vfe_mdc_clk;
/* TODO: check return */
clk_set_rate(clk, rate);
}
int msm_camio_enable(struct platform_device *pdev)
{
int rc = 0;
appio = request_mem_region(camio_ext.appphy,
camio_ext.appsz, pdev->name);
if (!appio) {
rc = -EBUSY;
goto enable_fail;
}
appbase = ioremap(camio_ext.appphy, camio_ext.appsz);
if (!appbase) {
rc = -ENOMEM;
goto apps_no_mem;
}
msm_camio_clk_enable(CAMIO_MDC_CLK);
msm_camio_clk_enable(CAMIO_VFE_AXI_CLK);
return 0;
apps_no_mem:
release_mem_region(camio_ext.appphy, camio_ext.appsz);
enable_fail:
return rc;
}
void msm_camio_disable(struct platform_device *pdev)
{
iounmap(appbase);
release_mem_region(camio_ext.appphy, camio_ext.appsz);
msm_camio_clk_disable(CAMIO_MDC_CLK);
msm_camio_clk_disable(CAMIO_VFE_AXI_CLK);
}
int msm_camio_sensor_clk_on(struct platform_device *pdev)
{
struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
struct msm_camera_device_platform_data *camdev = sinfo->pdata;
int32_t rc = 0;
camio_ext = camdev->ioext;
mdcio = request_mem_region(camio_ext.mdcphy,
camio_ext.mdcsz, pdev->name);
if (!mdcio)
rc = -EBUSY;
mdcbase = ioremap(camio_ext.mdcphy,
camio_ext.mdcsz);
if (!mdcbase)
goto mdc_no_mem;
camdev->camera_gpio_on();
msm_camio_clk_enable(CAMIO_VFE_CLK);
msm_camio_clk_enable(CAMIO_VFE_MDC_CLK);
return rc;
mdc_no_mem:
release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz);
return -EINVAL;
}
int msm_camio_sensor_clk_off(struct platform_device *pdev)
{
struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
struct msm_camera_device_platform_data *camdev = sinfo->pdata;
camdev->camera_gpio_off();
iounmap(mdcbase);
release_mem_region(camio_ext.mdcphy, camio_ext.mdcsz);
msm_camio_clk_disable(CAMIO_VFE_CLK);
return msm_camio_clk_disable(CAMIO_VFE_MDC_CLK);
}
void msm_disable_io_gpio_clk(struct platform_device *pdev)
{
return;
}
void msm_camio_camif_pad_reg_reset(void)
{
uint32_t reg;
uint32_t mask, value;
/* select CLKRGM_VFE_SRC_CAM_VFE_SRC: internal source */
msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_INTERNAL);
reg = (msm_camera_io_r_mb(mdcbase)) & CAMIF_CFG_RMSK;
mask = CAM_SEL_BMSK |
CAM_PCLK_SRC_SEL_BMSK |
CAM_PCLK_INVERT_BMSK |
EXT_CAM_HSYNC_POL_SEL_BMSK |
EXT_CAM_VSYNC_POL_SEL_BMSK | MDDI_CLK_CHICKEN_BIT_BMSK;
value = 1 << CAM_SEL_SHFT |
3 << CAM_PCLK_SRC_SEL_SHFT |
0 << CAM_PCLK_INVERT_SHFT |
0 << EXT_CAM_HSYNC_POL_SEL_SHFT |
0 << EXT_CAM_VSYNC_POL_SEL_SHFT | 0 << MDDI_CLK_CHICKEN_BIT_SHFT;
msm_camera_io_w_mb((reg & (~mask)) | (value & mask), mdcbase);
usleep_range(10000, 11000);
reg = (msm_camera_io_r_mb(mdcbase)) & CAMIF_CFG_RMSK;
mask = CAM_PAD_REG_SW_RESET_BMSK;
value = 1 << CAM_PAD_REG_SW_RESET_SHFT;
msm_camera_io_w_mb((reg & (~mask)) | (value & mask), mdcbase);
usleep_range(10000, 11000);
reg = (msm_camera_io_r_mb(mdcbase)) & CAMIF_CFG_RMSK;
mask = CAM_PAD_REG_SW_RESET_BMSK;
value = 0 << CAM_PAD_REG_SW_RESET_SHFT;
msm_camera_io_w_mb((reg & (~mask)) | (value & mask), mdcbase);
usleep_range(10000, 11000);
msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_EXTERNAL);
usleep_range(10000, 11000);
/* todo: check return */
if (camio_vfe_clk)
clk_set_rate(camio_vfe_clk, 96000000);
}
void msm_camio_vfe_blk_reset(void)
{
uint32_t val;
val = msm_camera_io_r_mb(appbase + APPS_RESET_OFFSET);
val |= 0x1;
msm_camera_io_w_mb(val, appbase + APPS_RESET_OFFSET);
usleep_range(10000, 11000);
val = msm_camera_io_r_mb(appbase + APPS_RESET_OFFSET);
val &= ~0x1;
msm_camera_io_w_mb(val, appbase + APPS_RESET_OFFSET);
usleep_range(10000, 11000);
}
void msm_camio_camif_pad_reg_reset_2(void)
{
uint32_t reg;
uint32_t mask, value;
reg = (msm_camera_io_r_mb(mdcbase)) & CAMIF_CFG_RMSK;
mask = CAM_PAD_REG_SW_RESET_BMSK;
value = 1 << CAM_PAD_REG_SW_RESET_SHFT;
msm_camera_io_w_mb((reg & (~mask)) | (value & mask), mdcbase);
usleep_range(10000, 11000);
reg = (msm_camera_io_r_mb(mdcbase)) & CAMIF_CFG_RMSK;
mask = CAM_PAD_REG_SW_RESET_BMSK;
value = 0 << CAM_PAD_REG_SW_RESET_SHFT;
msm_camera_io_w_mb((reg & (~mask)) | (value & mask), mdcbase);
usleep_range(10000, 11000);
}
void msm_camio_clk_sel(enum msm_camio_clk_src_type srctype)
{
struct clk *clk = NULL;
clk = camio_vfe_clk;
if (clk != NULL) {
switch (srctype) {
case MSM_CAMIO_CLK_SRC_INTERNAL:
clk_set_flags(clk, 0x00000100 << 1);
break;
case MSM_CAMIO_CLK_SRC_EXTERNAL:
clk_set_flags(clk, 0x00000100);
break;
default:
break;
}
}
}
void msm_camio_clk_axi_rate_set(int rate)
{
struct clk *clk = camio_vfe_axi_clk;
/* todo: check return */
clk_set_rate(clk, rate);
}
int msm_camio_probe_on(struct platform_device *pdev)
{
struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
struct msm_camera_device_platform_data *camdev = sinfo->pdata;
camdev->camera_gpio_on();
return msm_camio_clk_enable(CAMIO_VFE_MDC_CLK);
}
int msm_camio_probe_off(struct platform_device *pdev)
{
struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
struct msm_camera_device_platform_data *camdev = sinfo->pdata;
camdev->camera_gpio_off();
return msm_camio_clk_disable(CAMIO_VFE_MDC_CLK);
}
@@ -0,0 +1,595 @@
/* 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.
*/
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/pm_qos.h>
#include <mach/board.h>
#include <mach/camera.h>
#include <mach/camera.h>
#include <mach/clk.h>
#include <mach/msm_bus.h>
#include <mach/msm_bus_board.h>
/* MIPI CSI controller registers */
#define MIPI_PHY_CONTROL 0x00000000
#define MIPI_PROTOCOL_CONTROL 0x00000004
#define MIPI_INTERRUPT_STATUS 0x00000008
#define MIPI_INTERRUPT_MASK 0x0000000C
#define MIPI_CAMERA_CNTL 0x00000024
#define MIPI_CALIBRATION_CONTROL 0x00000018
#define MIPI_PHY_D0_CONTROL2 0x00000038
#define MIPI_PHY_D1_CONTROL2 0x0000003C
#define MIPI_PHY_D2_CONTROL2 0x00000040
#define MIPI_PHY_D3_CONTROL2 0x00000044
#define MIPI_PHY_CL_CONTROL 0x00000048
#define MIPI_PHY_D0_CONTROL 0x00000034
#define MIPI_PHY_D1_CONTROL 0x00000020
#define MIPI_PHY_D2_CONTROL 0x0000002C
#define MIPI_PHY_D3_CONTROL 0x00000030
#define MIPI_PWR_CNTL 0x00000054
/*
* MIPI_PROTOCOL_CONTROL register bits to enable/disable the features of
* CSI Rx Block
*/
/* DPCM scheme */
#define MIPI_PROTOCOL_CONTROL_DPCM_SCHEME_SHFT 0x1e
/* SW_RST to issue a SW reset to the CSI core */
#define MIPI_PROTOCOL_CONTROL_SW_RST_BMSK 0x8000000
/* To Capture Long packet Header Info in MIPI_PROTOCOL_STATUS register */
#define MIPI_PROTOCOL_CONTROL_LONG_PACKET_HEADER_CAPTURE_BMSK 0x200000
/* Data format for unpacking purpose */
#define MIPI_PROTOCOL_CONTROL_DATA_FORMAT_SHFT 0x13
/* Enable decoding of payload based on data type filed of packet hdr */
#define MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK 0x00000
/* Enable error correction on packet headers */
#define MIPI_PROTOCOL_CONTROL_ECC_EN_BMSK 0x20000
/*
* MIPI_CALIBRATION_CONTROL register contains control info for
* calibration impledence controller
*/
/* Enable bit for calibration pad */
#define MIPI_CALIBRATION_CONTROL_SWCAL_CAL_EN_SHFT 0x16
/* With SWCAL_STRENGTH_OVERRIDE_EN, SW_CAL_EN and MANUAL_OVERRIDE_EN
* the hardware calibration circuitry associated with CAL_SW_HW_MODE
* is bypassed
*/
#define MIPI_CALIBRATION_CONTROL_SWCAL_STRENGTH_OVERRIDE_EN_SHFT 0x15
/* To indicate the Calibration process is in the control of HW/SW */
#define MIPI_CALIBRATION_CONTROL_CAL_SW_HW_MODE_SHFT 0x14
/* When this is set the strength value of the data and clk lane impedence
* termination is updated with MANUAL_STRENGTH settings and calibration
* sensing logic is idle.
*/
#define MIPI_CALIBRATION_CONTROL_MANUAL_OVERRIDE_EN_SHFT 0x7
/* Data lane0 control */
/* T-hs Settle count value for Rx */
#define MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT 0x18
/* Rx termination control */
#define MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT 0x10
/* LP Rx enable */
#define MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT 0x4
/*
* Enable for error in sync sequence
* 1 - one bit error in sync seq
* 0 - requires all 8 bit correct seq
*/
#define MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3
/* Comments are same as D0 */
#define MIPI_PHY_D1_CONTROL2_SETTLE_COUNT_SHFT 0x18
#define MIPI_PHY_D1_CONTROL2_HS_TERM_IMP_SHFT 0x10
#define MIPI_PHY_D1_CONTROL2_LP_REC_EN_SHFT 0x4
#define MIPI_PHY_D1_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3
/* Comments are same as D0 */
#define MIPI_PHY_D2_CONTROL2_SETTLE_COUNT_SHFT 0x18
#define MIPI_PHY_D2_CONTROL2_HS_TERM_IMP_SHFT 0x10
#define MIPI_PHY_D2_CONTROL2_LP_REC_EN_SHFT 0x4
#define MIPI_PHY_D2_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3
/* Comments are same as D0 */
#define MIPI_PHY_D3_CONTROL2_SETTLE_COUNT_SHFT 0x18
#define MIPI_PHY_D3_CONTROL2_HS_TERM_IMP_SHFT 0x10
#define MIPI_PHY_D3_CONTROL2_LP_REC_EN_SHFT 0x4
#define MIPI_PHY_D3_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3
/* PHY_CL_CTRL programs the parameters of clk lane of CSIRXPHY */
/* HS Rx termination control */
#define MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT 0x18
/* Start signal for T-hs delay */
#define MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT 0x2
/* PHY DATA lane 0 control */
/*
* HS RX equalizer strength control
* 00 - 0db 01 - 3db 10 - 5db 11 - 7db
*/
#define MIPI_PHY_D0_CONTROL_HS_REC_EQ_SHFT 0x1c
/* PHY DATA lane 1 control */
/* Shutdown signal for MIPI clk phy line */
#define MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT 0x9
/* Shutdown signal for MIPI data phy line */
#define MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT 0x8
#define MSM_AXI_QOS_PREVIEW 200000
#define MSM_AXI_QOS_SNAPSHOT 200000
#define MSM_AXI_QOS_RECORDING 200000
#define MIPI_PWR_CNTL_ENA 0x07
#define MIPI_PWR_CNTL_DIS 0x0
static struct clk *camio_cam_clk;
static struct clk *camio_vfe_clk;
static struct clk *camio_csi_src_clk;
static struct clk *camio_csi0_vfe_clk;
static struct clk *camio_csi1_vfe_clk;
static struct clk *camio_csi0_clk;
static struct clk *camio_csi1_clk;
static struct clk *camio_csi0_pclk;
static struct clk *camio_csi1_pclk;
static struct msm_camera_io_ext camio_ext;
static struct msm_camera_io_clk camio_clk;
static struct platform_device *camio_dev;
void __iomem *csibase;
void __iomem *appbase;
int msm_camio_vfe_clk_rate_set(int rate)
{
int rc = 0;
struct clk *clk = camio_vfe_clk;
if (rate > clk_get_rate(clk))
rc = clk_set_rate(clk, rate);
return rc;
}
int msm_camio_clk_enable(enum msm_camio_clk_type clktype)
{
int rc = 0;
struct clk *clk = NULL;
switch (clktype) {
case CAMIO_CAM_MCLK_CLK:
clk = clk_get(NULL, "cam_m_clk");
camio_cam_clk = clk;
msm_camio_clk_rate_set_2(clk, camio_clk.mclk_clk_rate);
break;
case CAMIO_VFE_CLK:
clk = clk_get(NULL, "vfe_clk");
camio_vfe_clk = clk;
msm_camio_clk_rate_set_2(clk, camio_clk.vfe_clk_rate);
break;
case CAMIO_CSI0_VFE_CLK:
clk = clk_get(&camio_dev->dev, "csi_vfe_clk");
camio_csi0_vfe_clk = clk;
break;
case CAMIO_CSI1_VFE_CLK:
clk = clk_get(NULL, "csi_vfe_clk");
camio_csi1_vfe_clk = clk;
break;
case CAMIO_CSI_SRC_CLK:
clk = clk_get(NULL, "csi_src_clk");
camio_csi_src_clk = clk;
break;
case CAMIO_CSI0_CLK:
clk = clk_get(&camio_dev->dev, "csi_clk");
camio_csi0_clk = clk;
msm_camio_clk_rate_set_2(clk, 400000000);
break;
case CAMIO_CSI1_CLK:
clk = clk_get(NULL, "csi_clk");
camio_csi1_clk = clk;
break;
case CAMIO_CSI0_PCLK:
clk = clk_get(&camio_dev->dev, "csi_pclk");
camio_csi0_pclk = clk;
break;
case CAMIO_CSI1_PCLK:
clk = clk_get(NULL, "csi_pclk");
camio_csi1_pclk = clk;
break;
default:
break;
}
if (!IS_ERR(clk))
clk_enable(clk);
else
rc = -1;
return rc;
}
int msm_camio_clk_disable(enum msm_camio_clk_type clktype)
{
int rc = 0;
struct clk *clk = NULL;
switch (clktype) {
case CAMIO_CAM_MCLK_CLK:
clk = camio_cam_clk;
break;
case CAMIO_VFE_CLK:
clk = camio_vfe_clk;
break;
case CAMIO_CSI_SRC_CLK:
clk = camio_csi_src_clk;
break;
case CAMIO_CSI0_VFE_CLK:
clk = camio_csi0_vfe_clk;
break;
case CAMIO_CSI1_VFE_CLK:
clk = camio_csi1_vfe_clk;
break;
case CAMIO_CSI0_CLK:
clk = camio_csi0_clk;
break;
case CAMIO_CSI1_CLK:
clk = camio_csi1_clk;
break;
case CAMIO_CSI0_PCLK:
clk = camio_csi0_pclk;
break;
case CAMIO_CSI1_PCLK:
clk = camio_csi1_pclk;
break;
default:
break;
}
if (!IS_ERR(clk)) {
clk_disable(clk);
clk_put(clk);
} else
rc = -1;
return rc;
}
void msm_camio_clk_rate_set(int rate)
{
struct clk *clk = camio_cam_clk;
clk_set_rate(clk, rate);
}
void msm_camio_clk_rate_set_2(struct clk *clk, int rate)
{
clk_set_rate(clk, rate);
}
static irqreturn_t msm_io_csi_irq(int irq_num, void *data)
{
uint32_t irq;
irq = msm_camera_io_r(csibase + MIPI_INTERRUPT_STATUS);
CDBG("%s MIPI_INTERRUPT_STATUS = 0x%x\n", __func__, irq);
msm_camera_io_w(irq, csibase + MIPI_INTERRUPT_STATUS);
/* TODO: Needs to send this info to upper layers */
if ((irq >> 19) & 0x1)
pr_info("Unsupported packet format is received\n");
return IRQ_HANDLED;
}
int msm_camio_enable(struct platform_device *pdev)
{
int rc = 0;
const struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
struct msm_camera_device_platform_data *camdev = sinfo->pdata;
uint32_t val;
camio_dev = pdev;
camio_ext = camdev->ioext;
camio_clk = camdev->ioclk;
msm_camio_clk_enable(CAMIO_VFE_CLK);
msm_camio_clk_enable(CAMIO_CSI0_VFE_CLK);
msm_camio_clk_enable(CAMIO_CSI1_VFE_CLK);
msm_camio_clk_enable(CAMIO_CSI0_CLK);
msm_camio_clk_enable(CAMIO_CSI1_CLK);
msm_camio_clk_enable(CAMIO_CSI0_PCLK);
msm_camio_clk_enable(CAMIO_CSI1_PCLK);
csibase = ioremap(camio_ext.csiphy, camio_ext.csisz);
if (!csibase) {
rc = -ENOMEM;
goto csi_busy;
}
rc = request_irq(camio_ext.csiirq, msm_io_csi_irq,
IRQF_TRIGGER_RISING, "csi", 0);
if (rc < 0)
goto csi_irq_fail;
msleep(20);
val = (20 <<
MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) |
(0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) |
(0x0 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) |
(0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT);
CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
msm_camera_io_w(val, csibase + MIPI_PHY_D0_CONTROL2);
msm_camera_io_w(val, csibase + MIPI_PHY_D1_CONTROL2);
msm_camera_io_w(val, csibase + MIPI_PHY_D2_CONTROL2);
msm_camera_io_w(val, csibase + MIPI_PHY_D3_CONTROL2);
val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) |
(0x0 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT);
CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
msm_camera_io_w(val, csibase + MIPI_PHY_CL_CONTROL);
appbase = ioremap(camio_ext.appphy,
camio_ext.appsz);
if (!appbase) {
rc = -ENOMEM;
goto csi_irq_fail;
}
return 0;
csi_irq_fail:
iounmap(csibase);
csi_busy:
msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
msm_camio_clk_disable(CAMIO_VFE_CLK);
msm_camio_clk_disable(CAMIO_CSI0_VFE_CLK);
msm_camio_clk_disable(CAMIO_CSI1_VFE_CLK);
msm_camio_clk_disable(CAMIO_CSI0_CLK);
msm_camio_clk_disable(CAMIO_CSI1_CLK);
msm_camio_clk_disable(CAMIO_CSI0_PCLK);
msm_camio_clk_disable(CAMIO_CSI1_PCLK);
camdev->camera_gpio_off();
return rc;
}
void msm_camio_disable(struct platform_device *pdev)
{
uint32_t val;
val = (20 <<
MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) |
(0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) |
(0x0 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) |
(0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT);
CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
msm_camera_io_w(val, csibase + MIPI_PHY_D0_CONTROL2);
msm_camera_io_w(val, csibase + MIPI_PHY_D1_CONTROL2);
msm_camera_io_w(val, csibase + MIPI_PHY_D2_CONTROL2);
msm_camera_io_w(val, csibase + MIPI_PHY_D3_CONTROL2);
val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) |
(0x0 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT);
CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
msm_camera_io_w(val, csibase + MIPI_PHY_CL_CONTROL);
msleep(20);
free_irq(camio_ext.csiirq, 0);
iounmap(csibase);
iounmap(appbase);
CDBG("disable clocks\n");
msm_camio_clk_disable(CAMIO_VFE_CLK);
msm_camio_clk_disable(CAMIO_CSI0_CLK);
msm_camio_clk_disable(CAMIO_CSI1_CLK);
msm_camio_clk_disable(CAMIO_CSI0_VFE_CLK);
msm_camio_clk_disable(CAMIO_CSI1_VFE_CLK);
msm_camio_clk_disable(CAMIO_CSI0_PCLK);
msm_camio_clk_disable(CAMIO_CSI1_PCLK);
}
int msm_camio_sensor_clk_on(struct platform_device *pdev)
{
int rc = 0;
const struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
struct msm_camera_device_platform_data *camdev = sinfo->pdata;
camio_dev = pdev;
camio_ext = camdev->ioext;
camio_clk = camdev->ioclk;
rc = camdev->camera_gpio_on();
if (rc < 0)
return rc;
return msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK);
}
int msm_camio_sensor_clk_off(struct platform_device *pdev)
{
const struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
struct msm_camera_device_platform_data *camdev = sinfo->pdata;
camdev->camera_gpio_off();
return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
}
void msm_camio_vfe_blk_reset(void)
{
uint32_t val;
/* do apps reset */
val = msm_camera_io_r(appbase + 0x00000210);
val |= 0x1;
msm_camera_io_w(val, appbase + 0x00000210);
usleep_range(10000, 11000);
val = msm_camera_io_r(appbase + 0x00000210);
val &= ~0x1;
msm_camera_io_w(val, appbase + 0x00000210);
usleep_range(10000, 11000);
/* do axi reset */
val = msm_camera_io_r(appbase + 0x00000208);
val |= 0x1;
msm_camera_io_w(val, appbase + 0x00000208);
usleep_range(10000, 11000);
val = msm_camera_io_r(appbase + 0x00000208);
val &= ~0x1;
msm_camera_io_w(val, appbase + 0x00000208);
mb();
usleep_range(10000, 11000);
return;
}
int msm_camio_probe_on(struct platform_device *pdev)
{
int rc = 0;
const struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
struct msm_camera_device_platform_data *camdev = sinfo->pdata;
camio_dev = pdev;
camio_ext = camdev->ioext;
camio_clk = camdev->ioclk;
msm_camio_clk_enable(CAMIO_CSI0_PCLK);
msm_camio_clk_enable(CAMIO_CSI1_PCLK);
rc = camdev->camera_gpio_on();
if (rc < 0)
return rc;
return msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK);
}
int msm_camio_probe_off(struct platform_device *pdev)
{
const struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
struct msm_camera_device_platform_data *camdev = sinfo->pdata;
camdev->camera_gpio_off();
csibase = ioremap(camdev->ioext.csiphy, camdev->ioext.csisz);
if (!csibase) {
pr_err("ioremap failed for CSIBASE\n");
goto ioremap_fail;
}
msm_camera_io_w(MIPI_PWR_CNTL_DIS, csibase + MIPI_PWR_CNTL);
iounmap(csibase);
ioremap_fail:
msm_camio_clk_disable(CAMIO_CSI0_PCLK);
msm_camio_clk_disable(CAMIO_CSI1_PCLK);
return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
}
int msm_camio_csi_config(struct msm_camera_csi_params *csi_params)
{
int rc = 0;
uint32_t val = 0;
CDBG("msm_camio_csi_config\n");
/* Enable error correction for DATA lane. Applies to all data lanes */
msm_camera_io_w(0x4, csibase + MIPI_PHY_CONTROL);
msm_camera_io_w(MIPI_PROTOCOL_CONTROL_SW_RST_BMSK,
csibase + MIPI_PROTOCOL_CONTROL);
val = MIPI_PROTOCOL_CONTROL_LONG_PACKET_HEADER_CAPTURE_BMSK |
MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK |
MIPI_PROTOCOL_CONTROL_ECC_EN_BMSK;
val |= (uint32_t)(csi_params->data_format) <<
MIPI_PROTOCOL_CONTROL_DATA_FORMAT_SHFT;
val |= csi_params->dpcm_scheme <<
MIPI_PROTOCOL_CONTROL_DPCM_SCHEME_SHFT;
CDBG("%s MIPI_PROTOCOL_CONTROL val=0x%x\n", __func__, val);
msm_camera_io_w(val, csibase + MIPI_PROTOCOL_CONTROL);
val = (0x1 << MIPI_CALIBRATION_CONTROL_SWCAL_CAL_EN_SHFT) |
(0x1 <<
MIPI_CALIBRATION_CONTROL_SWCAL_STRENGTH_OVERRIDE_EN_SHFT) |
(0x1 << MIPI_CALIBRATION_CONTROL_CAL_SW_HW_MODE_SHFT) |
(0x1 << MIPI_CALIBRATION_CONTROL_MANUAL_OVERRIDE_EN_SHFT);
CDBG("%s MIPI_CALIBRATION_CONTROL val=0x%x\n", __func__, val);
msm_camera_io_w(val, csibase + MIPI_CALIBRATION_CONTROL);
val = (csi_params->settle_cnt <<
MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) |
(0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) |
(0x1 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) |
(0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT);
CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
msm_camera_io_w(val, csibase + MIPI_PHY_D0_CONTROL2);
msm_camera_io_w(val, csibase + MIPI_PHY_D1_CONTROL2);
msm_camera_io_w(val, csibase + MIPI_PHY_D2_CONTROL2);
msm_camera_io_w(val, csibase + MIPI_PHY_D3_CONTROL2);
val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) |
(0x1 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT);
CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
msm_camera_io_w(val, csibase + MIPI_PHY_CL_CONTROL);
val = 0 << MIPI_PHY_D0_CONTROL_HS_REC_EQ_SHFT;
msm_camera_io_w(val, csibase + MIPI_PHY_D0_CONTROL);
val = (0x1 << MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT) |
(0x1 << MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT);
CDBG("%s MIPI_PHY_D1_CONTROL val=0x%x\n", __func__, val);
msm_camera_io_w(val, csibase + MIPI_PHY_D1_CONTROL);
msm_camera_io_w(0x00000000, csibase + MIPI_PHY_D2_CONTROL);
msm_camera_io_w(0x00000000, csibase + MIPI_PHY_D3_CONTROL);
/* program number of lanes and lane mapping */
switch (csi_params->lane_cnt) {
case 1:
msm_camera_io_w(csi_params->lane_assign << 8 | 0x4,
csibase + MIPI_CAMERA_CNTL);
break;
case 2:
msm_camera_io_w(csi_params->lane_assign << 8 | 0x5,
csibase + MIPI_CAMERA_CNTL);
break;
case 3:
msm_camera_io_w(csi_params->lane_assign << 8 | 0x6,
csibase + MIPI_CAMERA_CNTL);
break;
case 4:
msm_camera_io_w(csi_params->lane_assign << 8 | 0x7,
csibase + MIPI_CAMERA_CNTL);
break;
}
msm_camera_io_w(0xFFFFF3FF, csibase + MIPI_INTERRUPT_MASK);
/*clear IRQ bits - write 1 clears the status*/
msm_camera_io_w(0xFFFFF3FF, csibase + MIPI_INTERRUPT_STATUS);
return rc;
}
void msm_camio_set_perf_lvl(enum msm_bus_perf_setting perf_setting)
{
switch (perf_setting) {
case S_INIT:
add_axi_qos();
break;
case S_PREVIEW:
update_axi_qos(MSM_AXI_QOS_PREVIEW);
break;
case S_VIDEO:
update_axi_qos(MSM_AXI_QOS_RECORDING);
break;
case S_CAPTURE:
update_axi_qos(MSM_AXI_QOS_SNAPSHOT);
break;
case S_DEFAULT:
update_axi_qos(PM_QOS_DEFAULT_VALUE);
break;
case S_EXIT:
release_axi_qos();
break;
default:
CDBG("%s: INVALID CASE\n", __func__);
}
}
@@ -0,0 +1,218 @@
/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/pm_qos.h>
#include <linux/module.h>
#include <mach/board.h>
#include <mach/camera.h>
#include <mach/camera.h>
#include <mach/clk.h>
#include <mach/msm_bus.h>
#include <mach/msm_bus_board.h>
#include <mach/dal_axi.h>
#define MSM_AXI_QOS_PREVIEW 200000
#define MSM_AXI_QOS_SNAPSHOT 200000
#define MSM_AXI_QOS_RECORDING 200000
static struct clk *camio_cam_clk;
static struct resource *clk_ctrl_mem;
static struct msm_camera_io_clk camio_clk;
static int apps_reset;
void __iomem *appbase;
void msm_camio_clk_rate_set_2(struct clk *clk, int rate)
{
clk_set_rate(clk, rate);
}
int msm_camio_clk_enable(enum msm_camio_clk_type clktype)
{
int rc = 0;
struct clk *clk = NULL;
switch (clktype) {
case CAMIO_CAM_MCLK_CLK:
clk = clk_get(NULL, "cam_m_clk");
camio_cam_clk = clk;
msm_camio_clk_rate_set_2(clk, camio_clk.mclk_clk_rate);
break;
default:
break;
}
if (!IS_ERR(clk))
clk_enable(clk);
else
rc = -1;
return rc;
}
int msm_camio_clk_disable(enum msm_camio_clk_type clktype)
{
int rc = 0;
struct clk *clk = NULL;
switch (clktype) {
case CAMIO_CAM_MCLK_CLK:
clk = camio_cam_clk;
break;
default:
break;
}
if (!IS_ERR(clk)) {
clk_disable(clk);
clk_put(clk);
} else
rc = -1;
return rc;
}
void msm_camio_clk_rate_set(int rate)
{
struct clk *clk = camio_cam_clk;
clk_set_rate(clk, rate);
}
void msm_camio_vfe_blk_reset_2(void)
{
uint32_t val;
/* do apps reset */
val = readl_relaxed(appbase + 0x00000210);
val |= 0x1;
writel_relaxed(val, appbase + 0x00000210);
usleep_range(10000, 11000);
val = readl_relaxed(appbase + 0x00000210);
val &= ~0x1;
writel_relaxed(val, appbase + 0x00000210);
usleep_range(10000, 11000);
/* do axi reset */
val = readl_relaxed(appbase + 0x00000208);
val |= 0x1;
writel_relaxed(val, appbase + 0x00000208);
usleep_range(10000, 11000);
val = readl_relaxed(appbase + 0x00000208);
val &= ~0x1;
writel_relaxed(val, appbase + 0x00000208);
mb();
usleep_range(10000, 11000);
}
void msm_camio_vfe_blk_reset_3(void)
{
uint32_t val;
if (!apps_reset)
return;
/* do apps reset */
val = readl_relaxed(appbase + 0x00000210);
val |= 0x10A0000;
writel_relaxed(val, appbase + 0x00000210);
usleep_range(10000, 11000);
val = readl_relaxed(appbase + 0x00000210);
val &= ~(0x10A0000);
writel_relaxed(val, appbase + 0x00000210);
usleep_range(10000, 11000);
mb();
}
void msm_camio_set_perf_lvl(enum msm_bus_perf_setting perf_setting)
{
switch (perf_setting) {
case S_INIT:
add_axi_qos();
update_axi_qos(MSM_AXI_QOS_PREVIEW);
axi_allocate(AXI_FLOW_VIEWFINDER_HI);
break;
case S_PREVIEW:
break;
case S_VIDEO:
break;
case S_CAPTURE:
break;
case S_DEFAULT:
break;
case S_EXIT:
axi_free(AXI_FLOW_VIEWFINDER_HI);
release_axi_qos();
break;
default:
CDBG("%s: INVALID CASE\n", __func__);
}
}
static int __devinit clkctl_probe(struct platform_device *pdev)
{
int rc = 0;
apps_reset = *(int *)pdev->dev.platform_data;
clk_ctrl_mem = platform_get_resource_byname(pdev,
IORESOURCE_MEM, "clk_ctl");
if (!clk_ctrl_mem) {
pr_err("%s: no mem resource:3?\n", __func__);
return -ENODEV;
}
appbase = ioremap(clk_ctrl_mem->start,
resource_size(clk_ctrl_mem));
if (!appbase) {
pr_err("clkctl_probe: appbase:err\n");
rc = -ENOMEM;
goto ioremap_fail;
}
return 0;
ioremap_fail:
msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
return rc;
}
static int clkctl_remove(struct platform_device *pdev)
{
if (clk_ctrl_mem)
iounmap(clk_ctrl_mem);
return 0;
}
static struct platform_driver clkctl_driver = {
.probe = clkctl_probe,
.remove = clkctl_remove,
.driver = {
.name = "msm_clk_ctl",
.owner = THIS_MODULE,
},
};
static int __init msm_clkctl_init_module(void)
{
return platform_driver_register(&clkctl_driver);
}
static void __exit msm_clkctl_exit_module(void)
{
platform_driver_unregister(&clkctl_driver);
}
module_init(msm_clkctl_init_module);
module_exit(msm_clkctl_exit_module);
MODULE_DESCRIPTION("CAM IO driver");
MODULE_LICENSE("GPL v2");
@@ -0,0 +1,119 @@
/* 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.
*/
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/regulator/consumer.h>
#include <linux/mfd/pm8xxx/pm8921.h>
#include <mach/gpio.h>
#include <mach/gpiomux.h>
#include <mach/board.h>
#include <mach/camera.h>
#include <mach/vreg.h>
#include <mach/camera.h>
#include <mach/clk.h>
#include <mach/msm_bus.h>
#include <mach/msm_bus_board.h>
#define BUFF_SIZE_128 128
void msm_camio_clk_rate_set_2(struct clk *clk, int rate)
{
clk_set_rate(clk, rate);
}
void msm_camio_bus_scale_cfg(struct msm_bus_scale_pdata *cam_bus_scale_table,
enum msm_bus_perf_setting perf_setting)
{
static uint32_t bus_perf_client;
int rc = 0;
switch (perf_setting) {
case S_INIT:
bus_perf_client =
msm_bus_scale_register_client(cam_bus_scale_table);
if (!bus_perf_client) {
CDBG("%s: Registration Failed!!!\n", __func__);
bus_perf_client = 0;
return;
}
CDBG("%s: S_INIT rc = %u\n", __func__, bus_perf_client);
break;
case S_EXIT:
if (bus_perf_client) {
CDBG("%s: S_EXIT\n", __func__);
msm_bus_scale_unregister_client(bus_perf_client);
} else
CDBG("%s: Bus Client NOT Registered!!!\n", __func__);
break;
case S_PREVIEW:
if (bus_perf_client) {
rc = msm_bus_scale_client_update_request(
bus_perf_client, 1);
CDBG("%s: S_PREVIEW rc = %d\n", __func__, rc);
} else
CDBG("%s: Bus Client NOT Registered!!!\n", __func__);
break;
case S_VIDEO:
if (bus_perf_client) {
rc = msm_bus_scale_client_update_request(
bus_perf_client, 2);
CDBG("%s: S_VIDEO rc = %d\n", __func__, rc);
} else
CDBG("%s: Bus Client NOT Registered!!!\n", __func__);
break;
case S_CAPTURE:
if (bus_perf_client) {
rc = msm_bus_scale_client_update_request(
bus_perf_client, 3);
CDBG("%s: S_CAPTURE rc = %d\n", __func__, rc);
} else
CDBG("%s: Bus Client NOT Registered!!!\n", __func__);
break;
case S_ZSL:
if (bus_perf_client) {
rc = msm_bus_scale_client_update_request(
bus_perf_client, 4);
CDBG("%s: S_ZSL rc = %d\n", __func__, rc);
} else
CDBG("%s: Bus Client NOT Registered!!!\n", __func__);
break;
case S_LIVESHOT:
if (bus_perf_client) {
rc = msm_bus_scale_client_update_request(
bus_perf_client, 5);
CDBG("%s: S_LIVESHOT rc = %d\n", __func__, rc);
} else
CDBG("%s: Bus Client NOT Registered!!!\n", __func__);
break;
case S_DUAL:
if (bus_perf_client) {
rc = msm_bus_scale_client_update_request(
bus_perf_client, 6);
CDBG("%s: S_DUAL rc = %d\n", __func__, rc);
} else
CDBG("%s: Bus Client NOT Registered!!!\n", __func__);
break;
case S_ADV_VIDEO:
if (bus_perf_client) {
rc = msm_bus_scale_client_update_request(
bus_perf_client, 7);
CDBG("%s: S_ADV_VIDEO rc = %d\n", __func__, rc);
} else
CDBG("%s: Bus Client NOT Registered!!!\n", __func__);
break;
case S_DEFAULT:
break;
default:
pr_warning("%s: INVALID CASE\n", __func__);
}
}
@@ -0,0 +1,820 @@
/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/regulator/consumer.h>
#include <mach/gpio.h>
#include <mach/board.h>
#include <mach/camera.h>
#include <mach/vreg.h>
#include <mach/camera.h>
#include <mach/clk.h>
#include <mach/msm_bus.h>
#include <mach/msm_bus_board.h>
/* MIPI CSI controller registers */
#define MIPI_PHY_CONTROL 0x00000000
#define MIPI_PROTOCOL_CONTROL 0x00000004
#define MIPI_INTERRUPT_STATUS 0x00000008
#define MIPI_INTERRUPT_MASK 0x0000000C
#define MIPI_CAMERA_CNTL 0x00000024
#define MIPI_CALIBRATION_CONTROL 0x00000018
#define MIPI_PHY_D0_CONTROL2 0x00000038
#define MIPI_PHY_D1_CONTROL2 0x0000003C
#define MIPI_PHY_D2_CONTROL2 0x00000040
#define MIPI_PHY_D3_CONTROL2 0x00000044
#define MIPI_PHY_CL_CONTROL 0x00000048
#define MIPI_PHY_D0_CONTROL 0x00000034
#define MIPI_PHY_D1_CONTROL 0x00000020
#define MIPI_PHY_D2_CONTROL 0x0000002C
#define MIPI_PHY_D3_CONTROL 0x00000030
#define MIPI_PROTOCOL_CONTROL_SW_RST_BMSK 0x8000000
#define MIPI_PROTOCOL_CONTROL_LONG_PACKET_HEADER_CAPTURE_BMSK 0x200000
#define MIPI_PROTOCOL_CONTROL_DATA_FORMAT_BMSK 0x180000
#define MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK 0x40000
#define MIPI_PROTOCOL_CONTROL_ECC_EN_BMSK 0x20000
#define MIPI_CALIBRATION_CONTROL_SWCAL_CAL_EN_SHFT 0x16
#define MIPI_CALIBRATION_CONTROL_SWCAL_STRENGTH_OVERRIDE_EN_SHFT 0x15
#define MIPI_CALIBRATION_CONTROL_CAL_SW_HW_MODE_SHFT 0x14
#define MIPI_CALIBRATION_CONTROL_MANUAL_OVERRIDE_EN_SHFT 0x7
#define MIPI_PROTOCOL_CONTROL_DATA_FORMAT_SHFT 0x13
#define MIPI_PROTOCOL_CONTROL_DPCM_SCHEME_SHFT 0x1e
#define MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT 0x18
#define MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT 0x10
#define MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT 0x4
#define MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3
#define MIPI_PHY_D1_CONTROL2_SETTLE_COUNT_SHFT 0x18
#define MIPI_PHY_D1_CONTROL2_HS_TERM_IMP_SHFT 0x10
#define MIPI_PHY_D1_CONTROL2_LP_REC_EN_SHFT 0x4
#define MIPI_PHY_D1_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3
#define MIPI_PHY_D2_CONTROL2_SETTLE_COUNT_SHFT 0x18
#define MIPI_PHY_D2_CONTROL2_HS_TERM_IMP_SHFT 0x10
#define MIPI_PHY_D2_CONTROL2_LP_REC_EN_SHFT 0x4
#define MIPI_PHY_D2_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3
#define MIPI_PHY_D3_CONTROL2_SETTLE_COUNT_SHFT 0x18
#define MIPI_PHY_D3_CONTROL2_HS_TERM_IMP_SHFT 0x10
#define MIPI_PHY_D3_CONTROL2_LP_REC_EN_SHFT 0x4
#define MIPI_PHY_D3_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3
#define MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT 0x18
#define MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT 0x2
#define MIPI_PHY_D0_CONTROL_HS_REC_EQ_SHFT 0x1c
#define MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT 0x9
#define MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT 0x8
#define DBG_CSI 0
static struct clk *camio_cam_clk;
static struct clk *camio_vfe_clk;
static struct clk *camio_csi_src_clk;
static struct clk *camio_csi0_vfe_clk;
static struct clk *camio_csi1_vfe_clk;
static struct clk *camio_csi0_clk;
static struct clk *camio_csi1_clk;
static struct clk *camio_csi0_pclk;
static struct clk *camio_csi1_pclk;
static struct clk *camio_vfe_pclk;
static struct clk *camio_vpe_clk;
static struct clk *camio_vpe_pclk;
static struct regulator *fs_vfe;
static struct regulator *fs_vpe;
static struct regulator *ldo15;
static struct regulator *lvs0;
static struct regulator *ldo25;
static struct msm_camera_io_ext camio_ext;
static struct msm_camera_io_clk camio_clk;
static struct platform_device *camio_dev;
static struct resource *csiio;
void __iomem *csibase;
static int vpe_clk_rate;
struct msm_bus_scale_pdata *cam_bus_scale_table;
static void msm_camera_vreg_enable(void)
{
ldo15 = regulator_get(NULL, "8058_l15");
if (IS_ERR(ldo15)) {
pr_err("%s: VREG LDO15 get failed\n", __func__);
ldo15 = NULL;
return;
}
if (regulator_set_voltage(ldo15, 2850000, 2850000)) {
pr_err("%s: VREG LDO15 set voltage failed\n", __func__);
goto ldo15_disable;
}
if (regulator_enable(ldo15)) {
pr_err("%s: VREG LDO15 enable failed\n", __func__);
goto ldo15_put;
}
lvs0 = regulator_get(NULL, "8058_lvs0");
if (IS_ERR(lvs0)) {
pr_err("%s: VREG LVS0 get failed\n", __func__);
lvs0 = NULL;
goto ldo15_disable;
}
if (regulator_enable(lvs0)) {
pr_err("%s: VREG LVS0 enable failed\n", __func__);
goto lvs0_put;
}
ldo25 = regulator_get(NULL, "8058_l25");
if (IS_ERR(ldo25)) {
pr_err("%s: VREG LDO25 get failed\n", __func__);
ldo25 = NULL;
goto lvs0_disable;
}
if (regulator_set_voltage(ldo25, 1200000, 1200000)) {
pr_err("%s: VREG LDO25 set voltage failed\n", __func__);
goto ldo25_disable;
}
if (regulator_enable(ldo25)) {
pr_err("%s: VREG LDO25 enable failed\n", __func__);
goto ldo25_put;
}
fs_vfe = regulator_get(NULL, "fs_vfe");
if (IS_ERR(fs_vfe)) {
CDBG("%s: Regulator FS_VFE get failed %ld\n", __func__,
PTR_ERR(fs_vfe));
fs_vfe = NULL;
} else if (regulator_enable(fs_vfe)) {
CDBG("%s: Regulator FS_VFE enable failed\n", __func__);
regulator_put(fs_vfe);
}
return;
ldo25_disable:
regulator_disable(ldo25);
ldo25_put:
regulator_put(ldo25);
lvs0_disable:
regulator_disable(lvs0);
lvs0_put:
regulator_put(lvs0);
ldo15_disable:
regulator_disable(ldo15);
ldo15_put:
regulator_put(ldo15);
}
static void msm_camera_vreg_disable(void)
{
if (ldo15) {
regulator_disable(ldo15);
regulator_put(ldo15);
}
if (lvs0) {
regulator_disable(lvs0);
regulator_put(lvs0);
}
if (ldo25) {
regulator_disable(ldo25);
regulator_put(ldo25);
}
if (fs_vfe) {
regulator_disable(fs_vfe);
regulator_put(fs_vfe);
}
}
int msm_camio_clk_enable(enum msm_camio_clk_type clktype)
{
int rc = 0;
struct clk *clk = NULL;
switch (clktype) {
case CAMIO_CAM_MCLK_CLK:
camio_cam_clk =
clk = clk_get(NULL, "cam_clk");
msm_camio_clk_rate_set_2(clk, camio_clk.mclk_clk_rate);
break;
case CAMIO_VFE_CLK:
camio_vfe_clk =
clk = clk_get(NULL, "vfe_clk");
msm_camio_clk_rate_set_2(clk, camio_clk.vfe_clk_rate);
break;
case CAMIO_CSI0_VFE_CLK:
camio_csi0_vfe_clk =
clk = clk_get(NULL, "csi_vfe_clk");
break;
case CAMIO_CSI1_VFE_CLK:
camio_csi1_vfe_clk =
clk = clk_get(&camio_dev->dev, "csi_vfe_clk");
break;
case CAMIO_CSI_SRC_CLK:
camio_csi_src_clk =
clk = clk_get(NULL, "csi_src_clk");
msm_camio_clk_rate_set_2(clk, 384000000);
break;
case CAMIO_CSI0_CLK:
camio_csi0_clk =
clk = clk_get(NULL, "csi_clk");
break;
case CAMIO_CSI1_CLK:
camio_csi1_clk =
clk = clk_get(&camio_dev->dev, "csi_clk");
break;
case CAMIO_VFE_PCLK:
camio_vfe_pclk =
clk = clk_get(NULL, "vfe_pclk");
break;
case CAMIO_CSI0_PCLK:
camio_csi0_pclk =
clk = clk_get(NULL, "csi_pclk");
break;
case CAMIO_CSI1_PCLK:
camio_csi1_pclk =
clk = clk_get(&camio_dev->dev, "csi_pclk");
break;
case CAMIO_VPE_CLK:
camio_vpe_clk =
clk = clk_get(NULL, "vpe_clk");
vpe_clk_rate = clk_round_rate(camio_vpe_clk, vpe_clk_rate);
clk_set_rate(camio_vpe_clk, vpe_clk_rate);
break;
case CAMIO_VPE_PCLK:
camio_vpe_pclk =
clk = clk_get(NULL, "vpe_pclk");
break;
default:
break;
}
if (!IS_ERR(clk))
clk_enable(clk);
else
rc = -1;
return rc;
}
int msm_camio_clk_disable(enum msm_camio_clk_type clktype)
{
int rc = 0;
struct clk *clk = NULL;
switch (clktype) {
case CAMIO_CAM_MCLK_CLK:
clk = camio_cam_clk;
break;
case CAMIO_VFE_CLK:
clk = camio_vfe_clk;
break;
case CAMIO_CSI_SRC_CLK:
clk = camio_csi_src_clk;
break;
case CAMIO_CSI0_VFE_CLK:
clk = camio_csi0_vfe_clk;
break;
case CAMIO_CSI1_VFE_CLK:
clk = camio_csi1_vfe_clk;
break;
case CAMIO_CSI0_CLK:
clk = camio_csi0_clk;
break;
case CAMIO_CSI1_CLK:
clk = camio_csi1_clk;
break;
case CAMIO_VFE_PCLK:
clk = camio_vfe_pclk;
break;
case CAMIO_CSI0_PCLK:
clk = camio_csi0_pclk;
break;
case CAMIO_CSI1_PCLK:
clk = camio_csi1_pclk;
break;
case CAMIO_VPE_CLK:
clk = camio_vpe_clk;
break;
case CAMIO_VPE_PCLK:
clk = camio_vpe_pclk;
break;
default:
break;
}
if (!IS_ERR(clk)) {
clk_disable(clk);
clk_put(clk);
} else
rc = -1;
return rc;
}
int msm_camio_vfe_clk_rate_set(int rate)
{
int rc = 0;
struct clk *clk = camio_vfe_clk;
if (rate > clk_get_rate(clk))
rc = clk_set_rate(clk, rate);
return rc;
}
void msm_camio_clk_rate_set(int rate)
{
struct clk *clk = camio_cam_clk;
clk_set_rate(clk, rate);
}
void msm_camio_clk_rate_set_2(struct clk *clk, int rate)
{
clk_set_rate(clk, rate);
}
static irqreturn_t msm_io_csi_irq(int irq_num, void *data)
{
uint32_t irq = 0;
if (csibase != NULL)
irq = msm_camera_io_r(csibase + MIPI_INTERRUPT_STATUS);
CDBG("%s MIPI_INTERRUPT_STATUS = 0x%x\n", __func__, irq);
if (csibase != NULL)
msm_camera_io_w(irq, csibase + MIPI_INTERRUPT_STATUS);
return IRQ_HANDLED;
}
int msm_camio_vpe_clk_disable(void)
{
int rc = 0;
if (fs_vpe) {
regulator_disable(fs_vpe);
regulator_put(fs_vpe);
}
rc = msm_camio_clk_disable(CAMIO_VPE_CLK);
if (rc < 0)
return rc;
rc = msm_camio_clk_disable(CAMIO_VPE_PCLK);
return rc;
}
int msm_camio_vpe_clk_enable(uint32_t clk_rate)
{
int rc = 0;
fs_vpe = regulator_get(NULL, "fs_vpe");
if (IS_ERR(fs_vpe)) {
CDBG("%s: Regulator FS_VPE get failed %ld\n", __func__,
PTR_ERR(fs_vpe));
fs_vpe = NULL;
} else if (regulator_enable(fs_vpe)) {
CDBG("%s: Regulator FS_VPE enable failed\n", __func__);
regulator_put(fs_vpe);
}
vpe_clk_rate = clk_rate;
rc = msm_camio_clk_enable(CAMIO_VPE_CLK);
if (rc < 0)
return rc;
rc = msm_camio_clk_enable(CAMIO_VPE_PCLK);
return rc;
}
#ifdef DBG_CSI
static int csi_request_irq(void)
{
return request_irq(camio_ext.csiirq, msm_io_csi_irq,
IRQF_TRIGGER_HIGH, "csi", 0);
}
#else
static int csi_request_irq(void) { return 0; }
#endif
#ifdef DBG_CSI
static void csi_free_irq(void)
{
free_irq(camio_ext.csiirq, 0);
}
#else
static void csi_free_irq(void) { return 0; }
#endif
int msm_camio_enable(struct platform_device *pdev)
{
int rc = 0;
struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
struct msm_camera_device_platform_data *camdev = sinfo->pdata;
camio_dev = pdev;
camio_ext = camdev->ioext;
camio_clk = camdev->ioclk;
cam_bus_scale_table = camdev->cam_bus_scale_table;
msm_camio_clk_enable(CAMIO_VFE_CLK);
msm_camio_clk_enable(CAMIO_CSI0_VFE_CLK);
msm_camio_clk_enable(CAMIO_CSI1_VFE_CLK);
msm_camio_clk_enable(CAMIO_CSI_SRC_CLK);
msm_camio_clk_enable(CAMIO_CSI0_CLK);
msm_camio_clk_enable(CAMIO_CSI1_CLK);
msm_camio_clk_enable(CAMIO_VFE_PCLK);
msm_camio_clk_enable(CAMIO_CSI0_PCLK);
msm_camio_clk_enable(CAMIO_CSI1_PCLK);
csiio = request_mem_region(camio_ext.csiphy,
camio_ext.csisz, pdev->name);
if (!csiio) {
rc = -EBUSY;
goto common_fail;
}
csibase = ioremap(camio_ext.csiphy,
camio_ext.csisz);
if (!csibase) {
rc = -ENOMEM;
goto csi_busy;
}
rc = csi_request_irq();
if (rc < 0)
goto csi_irq_fail;
return 0;
csi_irq_fail:
iounmap(csibase);
csibase = NULL;
csi_busy:
release_mem_region(camio_ext.csiphy, camio_ext.csisz);
csibase = NULL;
common_fail:
msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
msm_camio_clk_disable(CAMIO_CSI0_VFE_CLK);
msm_camio_clk_disable(CAMIO_CSI0_CLK);
msm_camio_clk_disable(CAMIO_CSI1_VFE_CLK);
msm_camio_clk_disable(CAMIO_CSI1_CLK);
msm_camio_clk_disable(CAMIO_VFE_PCLK);
msm_camio_clk_disable(CAMIO_CSI0_PCLK);
msm_camio_clk_disable(CAMIO_CSI1_PCLK);
msm_camera_vreg_disable();
camdev->camera_gpio_off();
return rc;
}
static void msm_camio_csi_disable(void)
{
uint32_t val;
val = 0x0;
if (csibase != NULL) {
CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
msm_camera_io_w(val, csibase + MIPI_PHY_D0_CONTROL2);
msm_camera_io_w(val, csibase + MIPI_PHY_D1_CONTROL2);
msm_camera_io_w(val, csibase + MIPI_PHY_D2_CONTROL2);
msm_camera_io_w(val, csibase + MIPI_PHY_D3_CONTROL2);
CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
msm_camera_io_w(val, csibase + MIPI_PHY_CL_CONTROL);
msleep(20);
val = msm_camera_io_r(csibase + MIPI_PHY_D1_CONTROL);
val &=
~((0x1 << MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT)
|(0x1 << MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT));
CDBG("%s MIPI_PHY_D1_CONTROL val=0x%x\n", __func__, val);
msm_camera_io_w(val, csibase + MIPI_PHY_D1_CONTROL);
usleep_range(5000, 6000);
msm_camera_io_w(0x0, csibase + MIPI_INTERRUPT_MASK);
msm_camera_io_w(0x0, csibase + MIPI_INTERRUPT_STATUS);
csi_free_irq();
iounmap(csibase);
csibase = NULL;
release_mem_region(camio_ext.csiphy, camio_ext.csisz);
}
}
void msm_camio_disable(struct platform_device *pdev)
{
CDBG("disable mipi\n");
msm_camio_csi_disable();
CDBG("disable clocks\n");
msm_camio_clk_disable(CAMIO_CSI0_VFE_CLK);
msm_camio_clk_disable(CAMIO_CSI0_CLK);
msm_camio_clk_disable(CAMIO_CSI1_VFE_CLK);
msm_camio_clk_disable(CAMIO_CSI1_CLK);
msm_camio_clk_disable(CAMIO_VFE_PCLK);
msm_camio_clk_disable(CAMIO_CSI0_PCLK);
msm_camio_clk_disable(CAMIO_CSI1_PCLK);
msm_camio_clk_disable(CAMIO_CSI_SRC_CLK);
msm_camio_clk_disable(CAMIO_VFE_CLK);
}
int msm_camio_sensor_clk_on(struct platform_device *pdev)
{
int rc = 0;
struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
struct msm_camera_device_platform_data *camdev = sinfo->pdata;
camio_dev = pdev;
camio_ext = camdev->ioext;
camio_clk = camdev->ioclk;
msm_camera_vreg_enable();
usleep_range(10000, 11000);
rc = camdev->camera_gpio_on();
if (rc < 0)
return rc;
return msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK);
}
int msm_camio_sensor_clk_off(struct platform_device *pdev)
{
struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
struct msm_camera_device_platform_data *camdev = sinfo->pdata;
msm_camera_vreg_disable();
camdev->camera_gpio_off();
return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
}
void msm_camio_vfe_blk_reset(void)
{
return;
}
int msm_camio_probe_on(struct platform_device *pdev)
{
int rc = 0;
struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
struct msm_camera_device_platform_data *camdev = sinfo->pdata;
camio_dev = pdev;
camio_ext = camdev->ioext;
camio_clk = camdev->ioclk;
rc = camdev->camera_gpio_on();
if (rc < 0)
return rc;
msm_camera_vreg_enable();
return msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK);
}
int msm_camio_probe_off(struct platform_device *pdev)
{
struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
struct msm_camera_device_platform_data *camdev = sinfo->pdata;
msm_camera_vreg_disable();
camdev->camera_gpio_off();
return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
}
int msm_camio_csi_config(struct msm_camera_csi_params *csi_params)
{
int rc = 0;
uint32_t val = 0;
int i;
CDBG("msm_camio_csi_config\n");
if (csibase != NULL) {
/* SOT_ECC_EN enable error correction for SYNC (data-lane) */
msm_camera_io_w(0x4, csibase + MIPI_PHY_CONTROL);
/* SW_RST to the CSI core */
msm_camera_io_w(MIPI_PROTOCOL_CONTROL_SW_RST_BMSK,
csibase + MIPI_PROTOCOL_CONTROL);
/* PROTOCOL CONTROL */
val = MIPI_PROTOCOL_CONTROL_LONG_PACKET_HEADER_CAPTURE_BMSK |
MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK |
MIPI_PROTOCOL_CONTROL_ECC_EN_BMSK;
val |= (uint32_t)(csi_params->data_format) <<
MIPI_PROTOCOL_CONTROL_DATA_FORMAT_SHFT;
val |= csi_params->dpcm_scheme <<
MIPI_PROTOCOL_CONTROL_DPCM_SCHEME_SHFT;
CDBG("%s MIPI_PROTOCOL_CONTROL val=0x%x\n", __func__, val);
msm_camera_io_w(val, csibase + MIPI_PROTOCOL_CONTROL);
/* settle_cnt is very sensitive to speed!
increase this value to run at higher speeds */
val = (csi_params->settle_cnt <<
MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) |
(0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) |
(0x1 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) |
(0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT);
CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
for (i = 0; i < csi_params->lane_cnt; i++)
msm_camera_io_w(val,
csibase + MIPI_PHY_D0_CONTROL2 + i * 4);
val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) |
(0x1 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT);
CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
msm_camera_io_w(val, csibase + MIPI_PHY_CL_CONTROL);
val = 0 << MIPI_PHY_D0_CONTROL_HS_REC_EQ_SHFT;
msm_camera_io_w(val, csibase + MIPI_PHY_D0_CONTROL);
val =
(0x1 << MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT)
|(0x1 << MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT);
CDBG("%s MIPI_PHY_D1_CONTROL val=0x%x\n", __func__, val);
msm_camera_io_w(val, csibase + MIPI_PHY_D1_CONTROL);
msm_camera_io_w(0x00000000, csibase + MIPI_PHY_D2_CONTROL);
msm_camera_io_w(0x00000000, csibase + MIPI_PHY_D3_CONTROL);
/* halcyon only supports 1 or 2 lane */
switch (csi_params->lane_cnt) {
case 1:
msm_camera_io_w(csi_params->lane_assign << 8 | 0x4,
csibase + MIPI_CAMERA_CNTL);
break;
case 2:
msm_camera_io_w(csi_params->lane_assign << 8 | 0x5,
csibase + MIPI_CAMERA_CNTL);
break;
case 3:
msm_camera_io_w(csi_params->lane_assign << 8 | 0x6,
csibase + MIPI_CAMERA_CNTL);
break;
case 4:
msm_camera_io_w(csi_params->lane_assign << 8 | 0x7,
csibase + MIPI_CAMERA_CNTL);
break;
}
/* mask out ID_ERROR[19], DATA_CMM_ERR[11]
and CLK_CMM_ERR[10] - de-featured */
msm_camera_io_w(0xF017F3C0, csibase + MIPI_INTERRUPT_MASK);
/*clear IRQ bits*/
msm_camera_io_w(0xF017F3C0, csibase + MIPI_INTERRUPT_STATUS);
} else {
pr_info("CSIBASE is NULL");
}
return rc;
}
void msm_camio_set_perf_lvl(enum msm_bus_perf_setting perf_setting)
{
static uint32_t bus_perf_client;
int rc = 0;
switch (perf_setting) {
case S_INIT:
bus_perf_client =
msm_bus_scale_register_client(cam_bus_scale_table);
if (!bus_perf_client) {
pr_err("%s: Registration Failed!!!\n", __func__);
bus_perf_client = 0;
return;
}
CDBG("%s: S_INIT rc = %u\n", __func__, bus_perf_client);
break;
case S_EXIT:
if (bus_perf_client) {
CDBG("%s: S_EXIT\n", __func__);
msm_bus_scale_unregister_client(bus_perf_client);
} else
pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
break;
case S_PREVIEW:
if (bus_perf_client) {
rc = msm_bus_scale_client_update_request(
bus_perf_client, 1);
CDBG("%s: S_PREVIEW rc = %d\n", __func__, rc);
} else
pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
break;
case S_VIDEO:
if (bus_perf_client) {
rc = msm_bus_scale_client_update_request(
bus_perf_client, 2);
CDBG("%s: S_VIDEO rc = %d\n", __func__, rc);
} else
pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
break;
case S_CAPTURE:
if (bus_perf_client) {
rc = msm_bus_scale_client_update_request(
bus_perf_client, 3);
CDBG("%s: S_CAPTURE rc = %d\n", __func__, rc);
} else
pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
break;
case S_ZSL:
if (bus_perf_client) {
rc = msm_bus_scale_client_update_request(
bus_perf_client, 4);
CDBG("%s: S_ZSL rc = %d\n", __func__, rc);
} else
pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
break;
case S_STEREO_VIDEO:
if (bus_perf_client) {
rc = msm_bus_scale_client_update_request(
bus_perf_client, 5);
CDBG("%s: S_STEREO_VIDEO rc = %d\n", __func__, rc);
} else
pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
break;
case S_STEREO_CAPTURE:
if (bus_perf_client) {
rc = msm_bus_scale_client_update_request(
bus_perf_client, 6);
CDBG("%s: S_STEREO_VIDEO rc = %d\n", __func__, rc);
} else
pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
break;
case S_DEFAULT:
break;
default:
pr_warning("%s: INVALID CASE\n", __func__);
}
}
int msm_cam_core_reset(void)
{
struct clk *clk1;
int rc = 0;
clk1 = clk_get(&camio_dev->dev, "csi_vfe_clk");
if (IS_ERR(clk1)) {
pr_err("%s: did not get csi_vfe_clk\n", __func__);
return PTR_ERR(clk1);
}
rc = clk_reset(clk1, CLK_RESET_ASSERT);
if (rc) {
pr_err("%s:csi_vfe_clk assert failed\n", __func__);
clk_put(clk1);
return rc;
}
usleep_range(1000, 1200);
rc = clk_reset(clk1, CLK_RESET_DEASSERT);
if (rc) {
pr_err("%s:csi_vfe_clk deassert failed\n", __func__);
clk_put(clk1);
return rc;
}
clk_put(clk1);
clk1 = clk_get(&camio_dev->dev, "csi_clk");
if (IS_ERR(clk1)) {
pr_err("%s: did not get csi_clk\n", __func__);
return PTR_ERR(clk1);
}
rc = clk_reset(clk1, CLK_RESET_ASSERT);
if (rc) {
pr_err("%s:csi_clk assert failed\n", __func__);
clk_put(clk1);
return rc;
}
usleep_range(1000, 1200);
rc = clk_reset(clk1, CLK_RESET_DEASSERT);
if (rc) {
pr_err("%s:csi_clk deassert failed\n", __func__);
clk_put(clk1);
return rc;
}
clk_put(clk1);
clk1 = clk_get(&camio_dev->dev, "csi_pclk");
if (IS_ERR(clk1)) {
pr_err("%s: did not get csi_pclk\n", __func__);
return PTR_ERR(clk1);
}
rc = clk_reset(clk1, CLK_RESET_ASSERT);
if (rc) {
pr_err("%s:csi_pclk assert failed\n", __func__);
clk_put(clk1);
return rc;
}
usleep_range(1000, 1200);
rc = clk_reset(clk1, CLK_RESET_DEASSERT);
if (rc) {
pr_err("%s:csi_pclk deassert failed\n", __func__);
clk_put(clk1);
return rc;
}
clk_put(clk1);
return rc;
}
@@ -0,0 +1,776 @@
/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/pm_qos.h>
#include <linux/regulator/consumer.h>
#include <mach/gpio.h>
#include <mach/board.h>
#include <mach/camera.h>
#include <mach/vreg.h>
#include <mach/clk.h>
#define CAMIF_CFG_RMSK 0x1fffff
#define CAM_SEL_BMSK 0x2
#define CAM_PCLK_SRC_SEL_BMSK 0x60000
#define CAM_PCLK_INVERT_BMSK 0x80000
#define CAM_PAD_REG_SW_RESET_BMSK 0x100000
#define EXT_CAM_HSYNC_POL_SEL_BMSK 0x10000
#define EXT_CAM_VSYNC_POL_SEL_BMSK 0x8000
#define MDDI_CLK_CHICKEN_BIT_BMSK 0x80
#define CAM_SEL_SHFT 0x1
#define CAM_PCLK_SRC_SEL_SHFT 0x11
#define CAM_PCLK_INVERT_SHFT 0x13
#define CAM_PAD_REG_SW_RESET_SHFT 0x14
#define EXT_CAM_HSYNC_POL_SEL_SHFT 0x10
#define EXT_CAM_VSYNC_POL_SEL_SHFT 0xF
#define MDDI_CLK_CHICKEN_BIT_SHFT 0x7
/* MIPI CSI controller registers */
#define MIPI_PHY_CONTROL 0x00000000
#define MIPI_PROTOCOL_CONTROL 0x00000004
#define MIPI_INTERRUPT_STATUS 0x00000008
#define MIPI_INTERRUPT_MASK 0x0000000C
#define MIPI_CAMERA_CNTL 0x00000024
#define MIPI_CALIBRATION_CONTROL 0x00000018
#define MIPI_PHY_D0_CONTROL2 0x00000038
#define MIPI_PHY_D1_CONTROL2 0x0000003C
#define MIPI_PHY_D2_CONTROL2 0x00000040
#define MIPI_PHY_D3_CONTROL2 0x00000044
#define MIPI_PHY_CL_CONTROL 0x00000048
#define MIPI_PHY_D0_CONTROL 0x00000034
#define MIPI_PHY_D1_CONTROL 0x00000020
#define MIPI_PHY_D2_CONTROL 0x0000002C
#define MIPI_PHY_D3_CONTROL 0x00000030
#define MIPI_PROTOCOL_CONTROL_SW_RST_BMSK 0x8000000
#define MIPI_PROTOCOL_CONTROL_LONG_PACKET_HEADER_CAPTURE_BMSK 0x200000
#define MIPI_PROTOCOL_CONTROL_DATA_FORMAT_BMSK 0x180000
#define MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK 0x40000
#define MIPI_PROTOCOL_CONTROL_ECC_EN_BMSK 0x20000
#define MIPI_CALIBRATION_CONTROL_SWCAL_CAL_EN_SHFT 0x16
#define MIPI_CALIBRATION_CONTROL_SWCAL_STRENGTH_OVERRIDE_EN_SHFT 0x15
#define MIPI_CALIBRATION_CONTROL_CAL_SW_HW_MODE_SHFT 0x14
#define MIPI_CALIBRATION_CONTROL_MANUAL_OVERRIDE_EN_SHFT 0x7
#define MIPI_PROTOCOL_CONTROL_DATA_FORMAT_SHFT 0x13
#define MIPI_PROTOCOL_CONTROL_DPCM_SCHEME_SHFT 0x1e
#define MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT 0x18
#define MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT 0x10
#define MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT 0x4
#define MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3
#define MIPI_PHY_D1_CONTROL2_SETTLE_COUNT_SHFT 0x18
#define MIPI_PHY_D1_CONTROL2_HS_TERM_IMP_SHFT 0x10
#define MIPI_PHY_D1_CONTROL2_LP_REC_EN_SHFT 0x4
#define MIPI_PHY_D1_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3
#define MIPI_PHY_D2_CONTROL2_SETTLE_COUNT_SHFT 0x18
#define MIPI_PHY_D2_CONTROL2_HS_TERM_IMP_SHFT 0x10
#define MIPI_PHY_D2_CONTROL2_LP_REC_EN_SHFT 0x4
#define MIPI_PHY_D2_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3
#define MIPI_PHY_D3_CONTROL2_SETTLE_COUNT_SHFT 0x18
#define MIPI_PHY_D3_CONTROL2_HS_TERM_IMP_SHFT 0x10
#define MIPI_PHY_D3_CONTROL2_LP_REC_EN_SHFT 0x4
#define MIPI_PHY_D3_CONTROL2_ERR_SOT_HS_EN_SHFT 0x3
#define MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT 0x18
#define MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT 0x2
#define MIPI_PHY_D0_CONTROL_HS_REC_EQ_SHFT 0x1c
#define MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT 0x9
#define MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT 0x8
#define CAMIO_VFE_CLK_SNAP 122880000
#define CAMIO_VFE_CLK_PREV 122880000
/* AXI rates in KHz */
#define MSM_AXI_QOS_PREVIEW 192000
#define MSM_AXI_QOS_SNAPSHOT 192000
#define MSM_AXI_QOS_RECORDING 192000
static struct clk *camio_vfe_mdc_clk;
static struct clk *camio_mdc_clk;
static struct clk *camio_vfe_clk;
static struct clk *camio_vfe_camif_clk;
static struct clk *camio_vfe_pbdg_clk;
static struct clk *camio_cam_m_clk;
static struct clk *camio_camif_pad_pbdg_clk;
static struct clk *camio_csi_clk;
static struct clk *camio_csi_pclk;
static struct clk *camio_csi_vfe_clk;
static struct clk *camio_vpe_clk;
static struct regulator *fs_vpe;
static struct msm_camera_io_ext camio_ext;
static struct msm_camera_io_clk camio_clk;
static struct resource *camifpadio, *csiio;
void __iomem *camifpadbase, *csibase;
static uint32_t vpe_clk_rate;
static struct regulator_bulk_data regs[] = {
{ .supply = "gp2", .min_uV = 2600000, .max_uV = 2600000 },
{ .supply = "lvsw1" },
{ .supply = "fs_vfe" },
/* sn12m0pz regulators */
{ .supply = "gp6", .min_uV = 3050000, .max_uV = 3100000 },
{ .supply = "gp16", .min_uV = 1200000, .max_uV = 1200000 },
};
static int reg_count;
static void msm_camera_vreg_enable(struct platform_device *pdev)
{
int count, rc;
struct device *dev = &pdev->dev;
/* Use gp6 and gp16 if and only if dev name matches. */
if (!strncmp(pdev->name, "msm_camera_sn12m0pz", 20))
count = ARRAY_SIZE(regs);
else
count = ARRAY_SIZE(regs) - 2;
rc = regulator_bulk_get(dev, count, regs);
if (rc) {
dev_err(dev, "%s: could not get regulators: %d\n",
__func__, rc);
return;
}
rc = regulator_bulk_set_voltage(count, regs);
if (rc) {
dev_err(dev, "%s: could not set voltages: %d\n",
__func__, rc);
goto reg_free;
}
rc = regulator_bulk_enable(count, regs);
if (rc) {
dev_err(dev, "%s: could not enable regulators: %d\n",
__func__, rc);
goto reg_free;
}
reg_count = count;
return;
reg_free:
regulator_bulk_free(count, regs);
return;
}
static void msm_camera_vreg_disable(void)
{
regulator_bulk_disable(reg_count, regs);
regulator_bulk_free(reg_count, regs);
reg_count = 0;
}
int msm_camio_clk_enable(enum msm_camio_clk_type clktype)
{
int rc = 0;
struct clk *clk = NULL;
switch (clktype) {
case CAMIO_VFE_MDC_CLK:
camio_vfe_mdc_clk =
clk = clk_get(NULL, "vfe_mdc_clk");
break;
case CAMIO_MDC_CLK:
camio_mdc_clk =
clk = clk_get(NULL, "mdc_clk");
break;
case CAMIO_VFE_CLK:
camio_vfe_clk =
clk = clk_get(NULL, "vfe_clk");
msm_camio_clk_rate_set_2(clk, camio_clk.vfe_clk_rate);
break;
case CAMIO_VFE_CAMIF_CLK:
camio_vfe_camif_clk =
clk = clk_get(NULL, "vfe_camif_clk");
break;
case CAMIO_VFE_PBDG_CLK:
camio_vfe_pbdg_clk =
clk = clk_get(NULL, "vfe_pclk");
break;
case CAMIO_CAM_MCLK_CLK:
camio_cam_m_clk =
clk = clk_get(NULL, "cam_m_clk");
msm_camio_clk_rate_set_2(clk, camio_clk.mclk_clk_rate);
break;
case CAMIO_CAMIF_PAD_PBDG_CLK:
camio_camif_pad_pbdg_clk =
clk = clk_get(NULL, "camif_pad_pclk");
break;
case CAMIO_CSI0_CLK:
camio_csi_clk =
clk = clk_get(NULL, "csi_clk");
msm_camio_clk_rate_set_2(clk, 153600000);
break;
case CAMIO_CSI0_VFE_CLK:
camio_csi_vfe_clk =
clk = clk_get(NULL, "csi_vfe_clk");
break;
case CAMIO_CSI0_PCLK:
camio_csi_pclk =
clk = clk_get(NULL, "csi_pclk");
break;
case CAMIO_VPE_CLK:
camio_vpe_clk =
clk = clk_get(NULL, "vpe_clk");
vpe_clk_rate = clk_round_rate(clk, vpe_clk_rate);
clk_set_rate(clk, vpe_clk_rate);
break;
default:
break;
}
if (!IS_ERR(clk))
clk_prepare_enable(clk);
else
rc = -1;
return rc;
}
int msm_camio_clk_disable(enum msm_camio_clk_type clktype)
{
int rc = 0;
struct clk *clk = NULL;
switch (clktype) {
case CAMIO_VFE_MDC_CLK:
clk = camio_vfe_mdc_clk;
break;
case CAMIO_MDC_CLK:
clk = camio_mdc_clk;
break;
case CAMIO_VFE_CLK:
clk = camio_vfe_clk;
break;
case CAMIO_VFE_CAMIF_CLK:
clk = camio_vfe_camif_clk;
break;
case CAMIO_VFE_PBDG_CLK:
clk = camio_vfe_pbdg_clk;
break;
case CAMIO_CAM_MCLK_CLK:
clk = camio_cam_m_clk;
break;
case CAMIO_CAMIF_PAD_PBDG_CLK:
clk = camio_camif_pad_pbdg_clk;
break;
case CAMIO_CSI0_CLK:
clk = camio_csi_clk;
break;
case CAMIO_CSI0_VFE_CLK:
clk = camio_csi_vfe_clk;
break;
case CAMIO_CSI0_PCLK:
clk = camio_csi_pclk;
break;
case CAMIO_VPE_CLK:
clk = camio_vpe_clk;
break;
default:
break;
}
if (!IS_ERR(clk)) {
clk_disable_unprepare(clk);
clk_put(clk);
} else {
rc = -1;
}
return rc;
}
void msm_camio_clk_rate_set(int rate)
{
struct clk *clk = camio_cam_m_clk;
clk_set_rate(clk, rate);
}
int msm_camio_vfe_clk_rate_set(int rate)
{
struct clk *clk = camio_vfe_clk;
return clk_set_rate(clk, rate);
}
void msm_camio_clk_rate_set_2(struct clk *clk, int rate)
{
clk_set_rate(clk, rate);
}
static irqreturn_t msm_io_csi_irq(int irq_num, void *data)
{
uint32_t irq;
irq = msm_camera_io_r(csibase + MIPI_INTERRUPT_STATUS);
CDBG("%s MIPI_INTERRUPT_STATUS = 0x%x\n", __func__, irq);
msm_camera_io_w(irq, csibase + MIPI_INTERRUPT_STATUS);
return IRQ_HANDLED;
}
int msm_camio_vpe_clk_disable(void)
{
msm_camio_clk_disable(CAMIO_VPE_CLK);
if (fs_vpe) {
regulator_disable(fs_vpe);
regulator_put(fs_vpe);
}
return 0;
}
int msm_camio_vpe_clk_enable(uint32_t clk_rate)
{
fs_vpe = regulator_get(NULL, "fs_vpe");
if (IS_ERR(fs_vpe)) {
pr_err("%s: Regulator FS_VPE get failed %ld\n", __func__,
PTR_ERR(fs_vpe));
fs_vpe = NULL;
} else if (regulator_enable(fs_vpe)) {
pr_err("%s: Regulator FS_VPE enable failed\n", __func__);
regulator_put(fs_vpe);
}
vpe_clk_rate = clk_rate;
msm_camio_clk_enable(CAMIO_VPE_CLK);
return 0;
}
int msm_camio_enable(struct platform_device *pdev)
{
int rc = 0;
struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
msm_camio_clk_enable(CAMIO_VFE_PBDG_CLK);
if (!sinfo->csi_if)
msm_camio_clk_enable(CAMIO_VFE_CAMIF_CLK);
else {
msm_camio_clk_enable(CAMIO_VFE_CLK);
csiio = request_mem_region(camio_ext.csiphy,
camio_ext.csisz, pdev->name);
if (!csiio) {
rc = -EBUSY;
goto common_fail;
}
csibase = ioremap(camio_ext.csiphy,
camio_ext.csisz);
if (!csibase) {
rc = -ENOMEM;
goto csi_busy;
}
rc = request_irq(camio_ext.csiirq, msm_io_csi_irq,
IRQF_TRIGGER_RISING, "csi", 0);
if (rc < 0)
goto csi_irq_fail;
/* enable required clocks for CSI */
msm_camio_clk_enable(CAMIO_CSI0_PCLK);
msm_camio_clk_enable(CAMIO_CSI0_VFE_CLK);
msm_camio_clk_enable(CAMIO_CSI0_CLK);
}
return 0;
csi_irq_fail:
iounmap(csibase);
csi_busy:
release_mem_region(camio_ext.csiphy, camio_ext.csisz);
common_fail:
msm_camio_clk_disable(CAMIO_VFE_PBDG_CLK);
msm_camio_clk_disable(CAMIO_VFE_CLK);
return rc;
}
static void msm_camio_csi_disable(void)
{
uint32_t val;
val = 0x0;
CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
msm_camera_io_w(val, csibase + MIPI_PHY_D0_CONTROL2);
msm_camera_io_w(val, csibase + MIPI_PHY_D1_CONTROL2);
msm_camera_io_w(val, csibase + MIPI_PHY_D2_CONTROL2);
msm_camera_io_w(val, csibase + MIPI_PHY_D3_CONTROL2);
CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
msm_camera_io_w(val, csibase + MIPI_PHY_CL_CONTROL);
usleep_range(9000, 10000);
free_irq(camio_ext.csiirq, 0);
iounmap(csibase);
release_mem_region(camio_ext.csiphy, camio_ext.csisz);
}
void msm_camio_disable(struct platform_device *pdev)
{
struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
if (!sinfo->csi_if) {
msm_camio_clk_disable(CAMIO_VFE_CAMIF_CLK);
} else {
CDBG("disable mipi\n");
msm_camio_csi_disable();
CDBG("disable clocks\n");
msm_camio_clk_disable(CAMIO_CSI0_PCLK);
msm_camio_clk_disable(CAMIO_CSI0_VFE_CLK);
msm_camio_clk_disable(CAMIO_CSI0_CLK);
msm_camio_clk_disable(CAMIO_VFE_CLK);
}
msm_camio_clk_disable(CAMIO_VFE_PBDG_CLK);
}
void msm_camio_camif_pad_reg_reset(void)
{
uint32_t reg;
msm_camio_clk_sel(MSM_CAMIO_CLK_SRC_INTERNAL);
usleep_range(10000, 11000);
reg = (msm_camera_io_r(camifpadbase)) & CAMIF_CFG_RMSK;
reg |= 0x3;
msm_camera_io_w(reg, camifpadbase);
usleep_range(10000, 11000);
reg = (msm_camera_io_r(camifpadbase)) & CAMIF_CFG_RMSK;
reg |= 0x10;
msm_camera_io_w(reg, camifpadbase);
usleep_range(10000, 11000);
reg = (msm_camera_io_r(camifpadbase)) & CAMIF_CFG_RMSK;
/* Need to be uninverted*/
reg &= 0x03;
msm_camera_io_w(reg, camifpadbase);
usleep_range(10000, 11000);
}
void msm_camio_vfe_blk_reset(void)
{
return;
}
void msm_camio_camif_pad_reg_reset_2(void)
{
uint32_t reg;
uint32_t mask, value;
reg = (msm_camera_io_r(camifpadbase)) & CAMIF_CFG_RMSK;
mask = CAM_PAD_REG_SW_RESET_BMSK;
value = 1 << CAM_PAD_REG_SW_RESET_SHFT;
msm_camera_io_w((reg & (~mask)) | (value & mask), camifpadbase);
usleep_range(10000, 11000);
reg = (msm_camera_io_r(camifpadbase)) & CAMIF_CFG_RMSK;
mask = CAM_PAD_REG_SW_RESET_BMSK;
value = 0 << CAM_PAD_REG_SW_RESET_SHFT;
msm_camera_io_w((reg & (~mask)) | (value & mask), camifpadbase);
usleep_range(10000, 11000);
}
void msm_camio_clk_sel(enum msm_camio_clk_src_type srctype)
{
struct clk *clk = NULL;
clk = camio_vfe_clk;
if (clk != NULL) {
switch (srctype) {
case MSM_CAMIO_CLK_SRC_INTERNAL:
clk_set_flags(clk, 0x00000100 << 1);
break;
case MSM_CAMIO_CLK_SRC_EXTERNAL:
clk_set_flags(clk, 0x00000100);
break;
default:
break;
}
}
}
int msm_camio_probe_on(struct platform_device *pdev)
{
struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
struct msm_camera_device_platform_data *camdev = sinfo->pdata;
camio_clk = camdev->ioclk;
camio_ext = camdev->ioext;
camdev->camera_gpio_on();
msm_camera_vreg_enable(pdev);
return msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK);
}
int msm_camio_probe_off(struct platform_device *pdev)
{
struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
struct msm_camera_device_platform_data *camdev = sinfo->pdata;
msm_camera_vreg_disable();
camdev->camera_gpio_off();
return msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
}
int msm_camio_sensor_clk_on(struct platform_device *pdev)
{
int rc = 0;
struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
struct msm_camera_device_platform_data *camdev = sinfo->pdata;
camio_clk = camdev->ioclk;
camio_ext = camdev->ioext;
camdev->camera_gpio_on();
msm_camera_vreg_enable(pdev);
msm_camio_clk_enable(CAMIO_CAM_MCLK_CLK);
msm_camio_clk_enable(CAMIO_CAMIF_PAD_PBDG_CLK);
if (!sinfo->csi_if) {
camifpadio = request_mem_region(camio_ext.camifpadphy,
camio_ext.camifpadsz, pdev->name);
msm_camio_clk_enable(CAMIO_VFE_CLK);
if (!camifpadio) {
rc = -EBUSY;
goto common_fail;
}
camifpadbase = ioremap(camio_ext.camifpadphy,
camio_ext.camifpadsz);
if (!camifpadbase) {
CDBG("msm_camio_sensor_clk_on fail\n");
rc = -ENOMEM;
goto parallel_busy;
}
}
return rc;
parallel_busy:
release_mem_region(camio_ext.camifpadphy, camio_ext.camifpadsz);
goto common_fail;
common_fail:
msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
msm_camio_clk_disable(CAMIO_VFE_CLK);
msm_camio_clk_disable(CAMIO_CAMIF_PAD_PBDG_CLK);
msm_camera_vreg_disable();
camdev->camera_gpio_off();
return rc;
}
int msm_camio_sensor_clk_off(struct platform_device *pdev)
{
uint32_t rc = 0;
struct msm_camera_sensor_info *sinfo = pdev->dev.platform_data;
struct msm_camera_device_platform_data *camdev = sinfo->pdata;
camdev->camera_gpio_off();
msm_camera_vreg_disable();
rc = msm_camio_clk_disable(CAMIO_CAM_MCLK_CLK);
rc = msm_camio_clk_disable(CAMIO_CAMIF_PAD_PBDG_CLK);
if (!sinfo->csi_if) {
iounmap(camifpadbase);
release_mem_region(camio_ext.camifpadphy, camio_ext.camifpadsz);
rc = msm_camio_clk_disable(CAMIO_VFE_CLK);
}
return rc;
}
int msm_camio_csi_config(struct msm_camera_csi_params *csi_params)
{
int rc = 0;
uint32_t val = 0;
int i;
CDBG("msm_camio_csi_config\n");
/* SOT_ECC_EN enable error correction for SYNC (data-lane) */
msm_camera_io_w(0x4, csibase + MIPI_PHY_CONTROL);
/* SW_RST to the CSI core */
msm_camera_io_w(MIPI_PROTOCOL_CONTROL_SW_RST_BMSK,
csibase + MIPI_PROTOCOL_CONTROL);
/* PROTOCOL CONTROL */
val = MIPI_PROTOCOL_CONTROL_LONG_PACKET_HEADER_CAPTURE_BMSK |
MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK |
MIPI_PROTOCOL_CONTROL_ECC_EN_BMSK;
val |= (uint32_t)(csi_params->data_format) <<
MIPI_PROTOCOL_CONTROL_DATA_FORMAT_SHFT;
val |= csi_params->dpcm_scheme <<
MIPI_PROTOCOL_CONTROL_DPCM_SCHEME_SHFT;
CDBG("%s MIPI_PROTOCOL_CONTROL val=0x%x\n", __func__, val);
msm_camera_io_w(val, csibase + MIPI_PROTOCOL_CONTROL);
/* SW CAL EN */
val = (0x1 << MIPI_CALIBRATION_CONTROL_SWCAL_CAL_EN_SHFT) |
(0x1 <<
MIPI_CALIBRATION_CONTROL_SWCAL_STRENGTH_OVERRIDE_EN_SHFT) |
(0x1 << MIPI_CALIBRATION_CONTROL_CAL_SW_HW_MODE_SHFT) |
(0x1 << MIPI_CALIBRATION_CONTROL_MANUAL_OVERRIDE_EN_SHFT);
CDBG("%s MIPI_CALIBRATION_CONTROL val=0x%x\n", __func__, val);
msm_camera_io_w(val, csibase + MIPI_CALIBRATION_CONTROL);
/* settle_cnt is very sensitive to speed!
increase this value to run at higher speeds */
val = (csi_params->settle_cnt <<
MIPI_PHY_D0_CONTROL2_SETTLE_COUNT_SHFT) |
(0x0F << MIPI_PHY_D0_CONTROL2_HS_TERM_IMP_SHFT) |
(0x1 << MIPI_PHY_D0_CONTROL2_LP_REC_EN_SHFT) |
(0x1 << MIPI_PHY_D0_CONTROL2_ERR_SOT_HS_EN_SHFT);
CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
for (i = 0; i < csi_params->lane_cnt; i++)
msm_camera_io_w(val, csibase + MIPI_PHY_D0_CONTROL2 + i * 4);
val = (0x0F << MIPI_PHY_CL_CONTROL_HS_TERM_IMP_SHFT) |
(0x1 << MIPI_PHY_CL_CONTROL_LP_REC_EN_SHFT);
CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
msm_camera_io_w(val, csibase + MIPI_PHY_CL_CONTROL);
val = 0 << MIPI_PHY_D0_CONTROL_HS_REC_EQ_SHFT;
msm_camera_io_w(val, csibase + MIPI_PHY_D0_CONTROL);
val = (0x1 << MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT) |
(0x1 << MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT);
CDBG("%s MIPI_PHY_D1_CONTROL val=0x%x\n", __func__, val);
msm_camera_io_w(val, csibase + MIPI_PHY_D1_CONTROL);
msm_camera_io_w(0x00000000, csibase + MIPI_PHY_D2_CONTROL);
msm_camera_io_w(0x00000000, csibase + MIPI_PHY_D3_CONTROL);
/* halcyon only supports 1 or 2 lane */
switch (csi_params->lane_cnt) {
case 1:
msm_camera_io_w(csi_params->lane_assign << 8 | 0x4,
csibase + MIPI_CAMERA_CNTL);
break;
case 2:
msm_camera_io_w(csi_params->lane_assign << 8 | 0x5,
csibase + MIPI_CAMERA_CNTL);
break;
case 3:
msm_camera_io_w(csi_params->lane_assign << 8 | 0x6,
csibase + MIPI_CAMERA_CNTL);
break;
case 4:
msm_camera_io_w(csi_params->lane_assign << 8 | 0x7,
csibase + MIPI_CAMERA_CNTL);
break;
}
/* mask out ID_ERROR[19], DATA_CMM_ERR[11]
and CLK_CMM_ERR[10] - de-featured */
msm_camera_io_w(0xFFF7F3FF, csibase + MIPI_INTERRUPT_MASK);
/*clear IRQ bits*/
msm_camera_io_w(0xFFF7F3FF, csibase + MIPI_INTERRUPT_STATUS);
return rc;
}
void msm_camio_set_perf_lvl(enum msm_bus_perf_setting perf_setting)
{
switch (perf_setting) {
case S_INIT:
add_axi_qos();
break;
case S_PREVIEW:
update_axi_qos(MSM_AXI_QOS_PREVIEW);
break;
case S_VIDEO:
update_axi_qos(MSM_AXI_QOS_RECORDING);
break;
case S_CAPTURE:
update_axi_qos(MSM_AXI_QOS_SNAPSHOT);
break;
case S_DEFAULT:
update_axi_qos(PM_QOS_DEFAULT_VALUE);
break;
case S_EXIT:
release_axi_qos();
break;
default:
CDBG("%s: INVALID CASE\n", __func__);
}
}
int msm_cam_core_reset(void)
{
struct clk *clk1;
int rc = 0;
clk1 = clk_get(NULL, "csi_vfe_clk");
if (IS_ERR(clk1)) {
pr_err("%s: did not get csi_vfe_clk\n", __func__);
return PTR_ERR(clk1);
}
rc = clk_reset(clk1, CLK_RESET_ASSERT);
if (rc) {
pr_err("%s:csi_vfe_clk assert failed\n", __func__);
clk_put(clk1);
return rc;
}
usleep_range(1000, 1200);
rc = clk_reset(clk1, CLK_RESET_DEASSERT);
if (rc) {
pr_err("%s:csi_vfe_clk deassert failed\n", __func__);
clk_put(clk1);
return rc;
}
clk_put(clk1);
clk1 = clk_get(NULL, "csi_clk");
if (IS_ERR(clk1)) {
pr_err("%s: did not get csi_clk\n", __func__);
return PTR_ERR(clk1);
}
rc = clk_reset(clk1, CLK_RESET_ASSERT);
if (rc) {
pr_err("%s:csi_clk assert failed\n", __func__);
clk_put(clk1);
return rc;
}
usleep_range(1000, 1200);
rc = clk_reset(clk1, CLK_RESET_DEASSERT);
if (rc) {
pr_err("%s:csi_clk deassert failed\n", __func__);
clk_put(clk1);
return rc;
}
clk_put(clk1);
clk1 = clk_get(NULL, "csi_pclk");
if (IS_ERR(clk1)) {
pr_err("%s: did not get csi_pclk\n", __func__);
return PTR_ERR(clk1);
}
rc = clk_reset(clk1, CLK_RESET_ASSERT);
if (rc) {
pr_err("%s:csi_pclk assert failed\n", __func__);
clk_put(clk1);
return rc;
}
usleep_range(1000, 1200);
rc = clk_reset(clk1, CLK_RESET_DEASSERT);
if (rc) {
pr_err("%s:csi_pclk deassert failed\n", __func__);
clk_put(clk1);
return rc;
}
clk_put(clk1);
return rc;
}
@@ -0,0 +1,274 @@
/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/regulator/consumer.h>
#include <linux/export.h>
#include <mach/gpio.h>
#include <mach/board.h>
#include <mach/camera.h>
#include <mach/vreg.h>
#include <mach/camera.h>
#include <mach/clk.h>
#include <mach/msm_bus.h>
#include <mach/msm_bus_board.h>
#include <linux/pm_qos.h>
/* AXI rates in KHz */
#define MSM_AXI_QOS_PREVIEW 192000
#define MSM_AXI_QOS_SNAPSHOT 192000
#define MSM_AXI_QOS_RECORDING 192000
#define BUFF_SIZE_128 128
static struct clk *camio_vfe_clk;
static struct clk *camio_vpe_clk;
static struct clk *camio_vpe_pclk;
static struct regulator *fs_vpe;
static int vpe_clk_rate;
int msm_camio_clk_enable(enum msm_camio_clk_type clktype)
{
int rc = 0;
struct clk *clk = NULL;
switch (clktype) {
case CAMIO_VPE_CLK:
camio_vpe_clk =
clk = clk_get(NULL, "vpe_clk");
vpe_clk_rate = clk_round_rate(camio_vpe_clk, vpe_clk_rate);
clk_set_rate(camio_vpe_clk, vpe_clk_rate);
break;
case CAMIO_VPE_PCLK:
camio_vpe_pclk =
clk = clk_get(NULL, "vpe_pclk");
break;
default:
break;
}
if (!IS_ERR(clk)) {
clk_prepare(clk);
clk_enable(clk);
} else {
rc = -1;
}
return rc;
}
int msm_camio_clk_disable(enum msm_camio_clk_type clktype)
{
int rc = 0;
struct clk *clk = NULL;
switch (clktype) {
case CAMIO_VPE_CLK:
clk = camio_vpe_clk;
break;
case CAMIO_VPE_PCLK:
clk = camio_vpe_pclk;
break;
default:
break;
}
if (!IS_ERR(clk)) {
clk_disable(clk);
clk_unprepare(clk);
clk_put(clk);
} else {
rc = -1;
}
return rc;
}
int msm_camio_vfe_clk_rate_set(int rate)
{
int rc = 0;
struct clk *clk = camio_vfe_clk;
if (rate > clk_get_rate(clk))
rc = clk_set_rate(clk, rate);
return rc;
}
void msm_camio_clk_rate_set_2(struct clk *clk, int rate)
{
clk_set_rate(clk, rate);
}
int msm_camio_vpe_clk_disable(void)
{
int rc = 0;
if (fs_vpe) {
regulator_disable(fs_vpe);
regulator_put(fs_vpe);
}
rc = msm_camio_clk_disable(CAMIO_VPE_CLK);
if (rc < 0)
return rc;
rc = msm_camio_clk_disable(CAMIO_VPE_PCLK);
return rc;
}
int msm_camio_vpe_clk_enable(uint32_t clk_rate)
{
int rc = 0;
fs_vpe = regulator_get(NULL, "fs_vpe");
if (IS_ERR(fs_vpe)) {
CDBG("%s: Regulator FS_VPE get failed %ld\n", __func__,
PTR_ERR(fs_vpe));
fs_vpe = NULL;
} else if (regulator_enable(fs_vpe)) {
CDBG("%s: Regulator FS_VPE enable failed\n", __func__);
regulator_put(fs_vpe);
}
vpe_clk_rate = clk_rate;
rc = msm_camio_clk_enable(CAMIO_VPE_CLK);
if (rc < 0)
return rc;
rc = msm_camio_clk_enable(CAMIO_VPE_PCLK);
return rc;
}
void msm_camio_vfe_blk_reset(void)
{
return;
}
void msm_camio_vfe_blk_reset_3(void)
{
return;
}
static void msm_camio_axi_cfg(enum msm_bus_perf_setting perf_setting)
{
switch (perf_setting) {
case S_INIT:
add_axi_qos();
break;
case S_PREVIEW:
update_axi_qos(MSM_AXI_QOS_PREVIEW);
break;
case S_VIDEO:
update_axi_qos(MSM_AXI_QOS_RECORDING);
break;
case S_CAPTURE:
update_axi_qos(MSM_AXI_QOS_SNAPSHOT);
break;
case S_DEFAULT:
update_axi_qos(PM_QOS_DEFAULT_VALUE);
break;
case S_EXIT:
release_axi_qos();
break;
default:
CDBG("%s: INVALID CASE\n", __func__);
}
}
void msm_camio_bus_scale_cfg(struct msm_bus_scale_pdata *cam_bus_scale_table,
enum msm_bus_perf_setting perf_setting)
{
static uint32_t bus_perf_client;
int rc = 0;
if (cam_bus_scale_table == NULL) {
msm_camio_axi_cfg(perf_setting);
return;
}
switch (perf_setting) {
case S_INIT:
bus_perf_client =
msm_bus_scale_register_client(cam_bus_scale_table);
if (!bus_perf_client) {
pr_err("%s: Registration Failed!!!\n", __func__);
bus_perf_client = 0;
return;
}
CDBG("%s: S_INIT rc = %u\n", __func__, bus_perf_client);
break;
case S_EXIT:
if (bus_perf_client) {
CDBG("%s: S_EXIT\n", __func__);
msm_bus_scale_unregister_client(bus_perf_client);
} else
pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
break;
case S_PREVIEW:
if (bus_perf_client) {
rc = msm_bus_scale_client_update_request(
bus_perf_client, 1);
CDBG("%s: S_PREVIEW rc = %d\n", __func__, rc);
} else
pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
break;
case S_VIDEO:
if (bus_perf_client) {
rc = msm_bus_scale_client_update_request(
bus_perf_client, 2);
CDBG("%s: S_VIDEO rc = %d\n", __func__, rc);
} else
pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
break;
case S_CAPTURE:
if (bus_perf_client) {
rc = msm_bus_scale_client_update_request(
bus_perf_client, 3);
CDBG("%s: S_CAPTURE rc = %d\n", __func__, rc);
} else
pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
break;
case S_ZSL:
if (bus_perf_client) {
rc = msm_bus_scale_client_update_request(
bus_perf_client, 4);
CDBG("%s: S_ZSL rc = %d\n", __func__, rc);
} else
pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
break;
case S_STEREO_VIDEO:
if (bus_perf_client) {
rc = msm_bus_scale_client_update_request(
bus_perf_client, 5);
CDBG("%s: S_STEREO_VIDEO rc = %d\n", __func__, rc);
} else
pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
break;
case S_STEREO_CAPTURE:
if (bus_perf_client) {
rc = msm_bus_scale_client_update_request(
bus_perf_client, 6);
CDBG("%s: S_STEREO_VIDEO rc = %d\n", __func__, rc);
} else
pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
break;
case S_DEFAULT:
break;
default:
pr_warning("%s: INVALID CASE\n", __func__);
}
}