blob: 7971b79d741735b3cd96712bea477eb43d89193f [file] [log] [blame]
/* Copyright (c) 2017, 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/module.h>
#include <linux/firmware.h>
#include <cam_sensor_cmn_header.h>
#include "cam_ois_core.h"
#include "cam_ois_soc.h"
#include "cam_sensor_util.h"
#include "cam_debug_util.h"
/**
* cam_ois_get_dev_handle - get device handle
* @o_ctrl: ctrl structure
* @arg: Camera control command argument
*
* Returns success or failure
*/
static int cam_ois_get_dev_handle(struct cam_ois_ctrl_t *o_ctrl,
void *arg)
{
struct cam_sensor_acquire_dev ois_acq_dev;
struct cam_create_dev_hdl bridge_params;
struct cam_control *cmd = (struct cam_control *)arg;
if (o_ctrl->bridge_intf.device_hdl != -1) {
CAM_ERR(CAM_OIS, "Device is already acquired");
return -EFAULT;
}
if (copy_from_user(&ois_acq_dev, (void __user *) cmd->handle,
sizeof(ois_acq_dev)))
return -EFAULT;
bridge_params.session_hdl = ois_acq_dev.session_handle;
bridge_params.ops = &o_ctrl->bridge_intf.ops;
bridge_params.v4l2_sub_dev_flag = 0;
bridge_params.media_entity_flag = 0;
bridge_params.priv = o_ctrl;
ois_acq_dev.device_handle =
cam_create_device_hdl(&bridge_params);
o_ctrl->bridge_intf.device_hdl = ois_acq_dev.device_handle;
o_ctrl->bridge_intf.session_hdl = ois_acq_dev.session_handle;
CAM_DBG(CAM_OIS, "Device Handle: %d", ois_acq_dev.device_handle);
if (copy_to_user((void __user *) cmd->handle, &ois_acq_dev,
sizeof(struct cam_sensor_acquire_dev))) {
CAM_ERR(CAM_OIS, "ACQUIRE_DEV: copy to user failed");
return -EFAULT;
}
return 0;
}
static int cam_ois_vreg_control(struct cam_ois_ctrl_t *o_ctrl,
int config)
{
int rc = 0, cnt;
struct cam_hw_soc_info *soc_info;
soc_info = &o_ctrl->soc_info;
cnt = soc_info->num_rgltr;
if (!cnt)
return 0;
if (cnt >= CAM_SOC_MAX_REGULATOR) {
CAM_ERR(CAM_OIS, "Regulators more than supported %d", cnt);
return -EINVAL;
}
if (config) {
rc = cam_soc_util_request_platform_resource(soc_info,
NULL, NULL);
rc = cam_soc_util_enable_platform_resource(soc_info, false, 0,
false);
} else {
rc = cam_soc_util_disable_platform_resource(soc_info, false,
false);
rc = cam_soc_util_release_platform_resource(soc_info);
}
return rc;
}
static int cam_ois_power_up(struct cam_ois_ctrl_t *o_ctrl)
{
int rc = 0;
struct cam_hw_soc_info *soc_info =
&o_ctrl->soc_info;
struct msm_camera_gpio_num_info *gpio_num_info = NULL;
rc = cam_ois_vreg_control(o_ctrl, 1);
if (rc < 0) {
CAM_ERR(CAM_OIS, "OIS Reg Failed %d", rc);
return rc;
}
gpio_num_info = o_ctrl->gpio_num_info;
if (soc_info->gpio_data &&
gpio_num_info &&
gpio_num_info->valid[SENSOR_VAF] == 1) {
gpio_set_value_cansleep(
gpio_num_info->gpio_num[SENSOR_VAF],
1);
}
/* VREG needs some delay to power up */
usleep_range(2000, 2050);
return rc;
}
static int cam_ois_power_down(struct cam_ois_ctrl_t *o_ctrl)
{
int32_t rc = 0;
struct cam_hw_soc_info *soc_info =
&o_ctrl->soc_info;
struct msm_camera_gpio_num_info *gpio_num_info = NULL;
gpio_num_info = o_ctrl->gpio_num_info;
if (soc_info->gpio_data &&
gpio_num_info &&
gpio_num_info->valid[SENSOR_VAF] == 1) {
gpio_set_value_cansleep(
gpio_num_info->gpio_num[SENSOR_VAF],
GPIOF_OUT_INIT_LOW);
}
rc = cam_ois_vreg_control(o_ctrl, 0);
if (rc < 0)
CAM_ERR(CAM_OIS, "Disable regualtor Failed %d", rc);
return rc;
}
static int cam_ois_apply_settings(struct cam_ois_ctrl_t *o_ctrl,
struct i2c_settings_array *i2c_set)
{
struct i2c_settings_list *i2c_list;
int32_t rc = 0;
uint32_t i, size;
if (o_ctrl == NULL || i2c_set == NULL) {
CAM_ERR(CAM_OIS, "Invalid Args");
return -EINVAL;
}
if (i2c_set->is_settings_valid != 1) {
CAM_ERR(CAM_OIS, " Invalid settings");
return -EINVAL;
}
list_for_each_entry(i2c_list,
&(i2c_set->list_head), list) {
if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_RANDOM) {
rc = camera_io_dev_write(&(o_ctrl->io_master_info),
&(i2c_list->i2c_settings));
if (rc < 0) {
CAM_ERR(CAM_OIS,
"Failed in Applying i2c wrt settings");
return rc;
}
} else if (i2c_list->op_code == CAM_SENSOR_I2C_POLL) {
size = i2c_list->i2c_settings.size;
for (i = 0; i < size; i++) {
rc = camera_io_dev_poll(
&(o_ctrl->io_master_info),
i2c_list->i2c_settings.
reg_setting[i].reg_addr,
i2c_list->i2c_settings.
reg_setting[i].reg_data,
i2c_list->i2c_settings.
reg_setting[i].data_mask,
i2c_list->i2c_settings.addr_type,
i2c_list->i2c_settings.data_type,
i2c_list->i2c_settings.
reg_setting[i].delay);
if (rc < 0) {
CAM_ERR(CAM_OIS,
"i2c poll apply setting Fail");
return rc;
}
}
}
}
return rc;
}
static int cam_ois_slaveInfo_pkt_parser(struct cam_ois_ctrl_t *o_ctrl,
uint32_t *cmd_buf)
{
int32_t rc = 0;
struct cam_cmd_ois_info *ois_info;
if (!o_ctrl || !cmd_buf) {
CAM_ERR(CAM_OIS, "Invalid Args");
return -EINVAL;
}
ois_info = (struct cam_cmd_ois_info *)cmd_buf;
if (o_ctrl->io_master_info.master_type == CCI_MASTER) {
o_ctrl->io_master_info.cci_client->i2c_freq_mode =
ois_info->i2c_freq_mode;
o_ctrl->io_master_info.cci_client->sid =
ois_info->slave_addr >> 1;
o_ctrl->ois_fw_flag = ois_info->ois_fw_flag;
o_ctrl->is_ois_calib = ois_info->is_ois_calib;
memcpy(o_ctrl->ois_name, ois_info->ois_name, 32);
o_ctrl->io_master_info.cci_client->retries = 3;
o_ctrl->io_master_info.cci_client->id_map = 0;
memcpy(&(o_ctrl->opcode), &(ois_info->opcode),
sizeof(struct cam_ois_opcode));
CAM_DBG(CAM_OIS, "Slave addr: 0x%x Freq Mode: %d",
ois_info->slave_addr, ois_info->i2c_freq_mode);
} else if (o_ctrl->io_master_info.master_type == I2C_MASTER) {
o_ctrl->io_master_info.client->addr = ois_info->slave_addr;
CAM_DBG(CAM_OIS, "Slave addr: 0x%x", ois_info->slave_addr);
} else {
CAM_ERR(CAM_OIS, "Invalid Master type : %d",
o_ctrl->io_master_info.master_type);
rc = -EINVAL;
}
return rc;
}
static int cam_ois_fw_download(struct cam_ois_ctrl_t *o_ctrl)
{
uint16_t total_bytes = 0;
uint8_t *ptr = NULL;
int32_t rc = 0, cnt;
const struct firmware *fw = NULL;
const char *fw_name_prog = NULL;
const char *fw_name_coeff = NULL;
char name_prog[32] = {0};
char name_coeff[32] = {0};
struct device *dev = &(o_ctrl->pdev->dev);
struct cam_sensor_i2c_reg_setting i2c_reg_setting;
if (!o_ctrl) {
CAM_ERR(CAM_OIS, "Invalid Args");
return -EINVAL;
}
snprintf(name_coeff, 32, "%s.coeff", o_ctrl->ois_name);
snprintf(name_prog, 32, "%s.prog", o_ctrl->ois_name);
/* cast pointer as const pointer*/
fw_name_prog = name_prog;
fw_name_coeff = name_coeff;
/* Load FW */
rc = request_firmware(&fw, fw_name_prog, dev);
if (rc) {
CAM_ERR(CAM_OIS, "Failed to locate %s", fw_name_prog);
return rc;
}
total_bytes = fw->size;
i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE;
i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE;
i2c_reg_setting.size = total_bytes;
i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *)
kzalloc(sizeof(struct cam_sensor_i2c_reg_array) * total_bytes,
GFP_KERNEL);
if (!i2c_reg_setting.reg_setting) {
CAM_ERR(CAM_OIS, "Failed in allocating i2c_array");
release_firmware(fw);
return -ENOMEM;
}
for (cnt = 0, ptr = (uint8_t *)fw->data; cnt < total_bytes;
cnt++, ptr++) {
i2c_reg_setting.reg_setting[cnt].reg_addr =
o_ctrl->opcode.prog;
i2c_reg_setting.reg_setting[cnt].reg_data = *ptr;
i2c_reg_setting.reg_setting[cnt].delay = 0;
i2c_reg_setting.reg_setting[cnt].data_mask = 0;
}
rc = camera_io_dev_write_continuous(&(o_ctrl->io_master_info),
&i2c_reg_setting, 1);
if (rc < 0) {
CAM_ERR(CAM_OIS, "OIS FW download failed %d", rc);
goto release_firmware;
}
kfree(i2c_reg_setting.reg_setting);
release_firmware(fw);
rc = request_firmware(&fw, fw_name_coeff, dev);
if (rc) {
CAM_ERR(CAM_OIS, "Failed to locate %s", fw_name_coeff);
return rc;
}
total_bytes = fw->size;
i2c_reg_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE;
i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE;
i2c_reg_setting.size = total_bytes;
i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *)
kzalloc(sizeof(struct cam_sensor_i2c_reg_array) * total_bytes,
GFP_KERNEL);
if (!i2c_reg_setting.reg_setting) {
CAM_ERR(CAM_OIS, "Failed in allocating i2c_array");
release_firmware(fw);
return -ENOMEM;
}
for (cnt = 0, ptr = (uint8_t *)fw->data; cnt < total_bytes;
cnt++, ptr++) {
i2c_reg_setting.reg_setting[cnt].reg_addr =
o_ctrl->opcode.coeff;
i2c_reg_setting.reg_setting[cnt].reg_data = *ptr;
i2c_reg_setting.reg_setting[cnt].delay = 0;
i2c_reg_setting.reg_setting[cnt].data_mask = 0;
}
rc = camera_io_dev_write_continuous(&(o_ctrl->io_master_info),
&i2c_reg_setting, 1);
if (rc < 0)
CAM_ERR(CAM_OIS, "OIS FW download failed %d", rc);
release_firmware:
kfree(i2c_reg_setting.reg_setting);
release_firmware(fw);
return rc;
}
/**
* cam_ois_pkt_parse - Parse csl packet
* @o_ctrl: ctrl structure
* @arg: Camera control command argument
*
* Returns success or failure
*/
static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg)
{
int32_t rc = 0;
uint64_t generic_ptr;
struct cam_control *ioctl_ctrl = NULL;
struct cam_config_dev_cmd dev_config;
struct i2c_settings_array *i2c_reg_settings = NULL;
struct cam_cmd_buf_desc *cmd_desc = NULL;
uint64_t generic_pkt_addr;
size_t pkt_len;
struct cam_packet *csl_packet = NULL;
size_t len_of_buff = 0;
uint32_t *offset = NULL, *cmd_buf;
ioctl_ctrl = (struct cam_control *)arg;
if (copy_from_user(&dev_config, (void __user *) ioctl_ctrl->handle,
sizeof(dev_config)))
return -EFAULT;
rc = cam_mem_get_cpu_buf(dev_config.packet_handle,
(uint64_t *)&generic_pkt_addr, &pkt_len);
if (rc) {
CAM_ERR(CAM_OIS,
"error in converting command Handle Error: %d", rc);
return rc;
}
if (dev_config.offset > pkt_len) {
CAM_ERR(CAM_OIS,
"offset is out of bound: off: %lld len: %zu",
dev_config.offset, pkt_len);
return -EINVAL;
}
csl_packet = (struct cam_packet *)
(generic_pkt_addr + dev_config.offset);
switch (csl_packet->header.op_code & 0xFFFFFF) {
case CAM_OIS_PACKET_OPCODE_INIT:
offset = (uint32_t *)&csl_packet->payload;
offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t));
cmd_desc = (struct cam_cmd_buf_desc *)(offset);
if ((csl_packet->num_cmd_buf < 2) &&
(csl_packet->num_cmd_buf > 3)) {
CAM_ERR(CAM_OIS, "wrong cmd Buffer count: %d",
csl_packet->num_cmd_buf);
return -EINVAL;
}
rc = cam_mem_get_cpu_buf(cmd_desc[0].mem_handle,
(uint64_t *)&generic_ptr, &len_of_buff);
if (rc < 0) {
CAM_ERR(CAM_OIS, "Failed to get cpu buf");
return rc;
}
cmd_buf = (uint32_t *)generic_ptr;
cmd_buf += cmd_desc->offset / sizeof(uint32_t);
rc = cam_ois_slaveInfo_pkt_parser(o_ctrl, cmd_buf);
if (rc < 0) {
CAM_ERR(CAM_OIS, "Failed in parsing the pkt");
return rc;
}
cmd_buf += (sizeof(struct cam_cmd_i2c_info)/sizeof(uint32_t));
i2c_reg_settings = &(o_ctrl->i2c_init_data);
i2c_reg_settings->is_settings_valid = 1;
i2c_reg_settings->request_id = 0;
rc = cam_sensor_i2c_command_parser(i2c_reg_settings,
&cmd_desc[1], 1);
if (rc < 0) {
CAM_ERR(CAM_OIS, "OIS pkt parsing failed: %d",
rc);
return rc;
}
if (o_ctrl->is_ois_calib) {
i2c_reg_settings = &(o_ctrl->i2c_calib_data);
i2c_reg_settings->is_settings_valid = 1;
i2c_reg_settings->request_id = 0;
rc = cam_sensor_i2c_command_parser(i2c_reg_settings,
&cmd_desc[2], 1);
if (rc < 0) {
CAM_ERR(CAM_OIS,
"OIS pkt parsing failed: %d", rc);
return rc;
}
}
break;
case CAM_OIS_PACKET_OPCODE_OIS_CONTROL:
offset = (uint32_t *)&csl_packet->payload;
offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t));
cmd_desc = (struct cam_cmd_buf_desc *)(offset);
i2c_reg_settings = &(o_ctrl->i2c_mode_data);
i2c_reg_settings->is_settings_valid = 1;
i2c_reg_settings->request_id = 0;
rc = cam_sensor_i2c_command_parser(i2c_reg_settings,
cmd_desc, 1);
if (rc < 0) {
CAM_ERR(CAM_OIS, "OIS pkt parsing failed: %d", rc);
return rc;
}
rc = cam_ois_apply_settings(o_ctrl, i2c_reg_settings);
if (rc < 0)
CAM_ERR(CAM_OIS, "Cannot apply mode settings");
break;
default:
break;
}
return rc;
}
/**
* cam_ois_driver_cmd - Handle ois cmds
* @e_ctrl: ctrl structure
* @arg: Camera control command argument
*
* Returns success or failure
*/
int cam_ois_driver_cmd(struct cam_ois_ctrl_t *o_ctrl, void *arg)
{
int rc = 0;
struct cam_ois_query_cap_t ois_cap = {0};
struct cam_control *cmd = (struct cam_control *)arg;
if (!o_ctrl) {
CAM_ERR(CAM_OIS, "e_ctrl is NULL");
return -EINVAL;
}
mutex_lock(&(o_ctrl->ois_mutex));
switch (cmd->op_code) {
case CAM_QUERY_CAP:
ois_cap.slot_info = o_ctrl->soc_info.index;
if (copy_to_user((void __user *) cmd->handle,
&ois_cap,
sizeof(struct cam_ois_query_cap_t))) {
CAM_ERR(CAM_OIS, "Failed Copy to User");
return -EFAULT;
goto release_mutex;
}
CAM_DBG(CAM_OIS, "ois_cap: ID: %d", ois_cap.slot_info);
break;
case CAM_ACQUIRE_DEV:
rc = cam_ois_get_dev_handle(o_ctrl, arg);
if (rc) {
CAM_ERR(CAM_OIS, "Failed to acquire dev");
goto release_mutex;
}
break;
case CAM_START_DEV:
rc = cam_ois_power_up(o_ctrl);
if (rc) {
CAM_ERR(CAM_OIS, " OIS Power up failed");
goto release_mutex;
}
rc = camera_io_init(&o_ctrl->io_master_info);
if (rc) {
CAM_ERR(CAM_OIS, "cci_init failed");
goto pwr_dwn;
}
if (o_ctrl->ois_fw_flag) {
rc = cam_ois_fw_download(o_ctrl);
if (rc) {
CAM_ERR(CAM_OIS, "Failed OIS FW Download");
goto pwr_dwn;
}
}
rc = cam_ois_apply_settings(o_ctrl, &o_ctrl->i2c_init_data);
if (rc < 0) {
CAM_ERR(CAM_OIS, "Cannot apply Init settings");
goto pwr_dwn;
}
if (o_ctrl->is_ois_calib) {
rc = cam_ois_apply_settings(o_ctrl,
&o_ctrl->i2c_calib_data);
if (rc) {
CAM_ERR(CAM_OIS, "Cannot apply calib data");
goto pwr_dwn;
}
}
break;
case CAM_CONFIG_DEV:
rc = cam_ois_pkt_parse(o_ctrl, arg);
if (rc) {
CAM_ERR(CAM_OIS, "Failed in ois pkt Parsing");
goto release_mutex;
}
break;
case CAM_RELEASE_DEV:
if (o_ctrl->bridge_intf.device_hdl == -1) {
CAM_ERR(CAM_OIS, "link hdl: %d device hdl: %d",
o_ctrl->bridge_intf.device_hdl,
o_ctrl->bridge_intf.link_hdl);
rc = -EINVAL;
goto release_mutex;
}
rc = cam_destroy_device_hdl(o_ctrl->bridge_intf.device_hdl);
if (rc < 0)
CAM_ERR(CAM_OIS, "destroying the device hdl");
o_ctrl->bridge_intf.device_hdl = -1;
o_ctrl->bridge_intf.link_hdl = -1;
o_ctrl->bridge_intf.session_hdl = -1;
break;
case CAM_STOP_DEV:
rc = camera_io_release(&o_ctrl->io_master_info);
if (rc < 0)
CAM_ERR(CAM_OIS, "Failed in releasing CCI");
rc = cam_ois_power_down(o_ctrl);
if (rc < 0) {
CAM_ERR(CAM_OIS, "OIS Power down failed");
goto release_mutex;
}
break;
default:
CAM_ERR(CAM_OIS, "invalid opcode");
goto release_mutex;
}
pwr_dwn:
cam_ois_power_down(o_ctrl);
release_mutex:
mutex_unlock(&(o_ctrl->ois_mutex));
return rc;
}