| /* 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 <cam_sensor_cmn_header.h> |
| #include "cam_sensor_core.h" |
| #include <cam_sensor_util.h> |
| #include "cam_soc_util.h" |
| |
| static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, |
| void *arg) |
| { |
| int32_t rc = 0; |
| uint64_t generic_ptr; |
| struct cam_control *ioctl_ctrl = NULL; |
| struct cam_packet *csl_packet = NULL; |
| struct cam_cmd_buf_desc *cmd_desc = NULL; |
| struct i2c_settings_array *i2c_reg_settings = NULL; |
| size_t len_of_buff = 0; |
| uint32_t *offset = NULL; |
| struct cam_config_dev_cmd config; |
| struct i2c_data_settings *i2c_data = NULL; |
| struct cam_req_mgr_add_request add_req; |
| |
| ioctl_ctrl = (struct cam_control *)arg; |
| |
| if (ioctl_ctrl->handle_type != CAM_HANDLE_USER_POINTER) { |
| pr_err("%s:%d :Error: Invalid Handle Type\n", |
| __func__, __LINE__); |
| return -EINVAL; |
| } |
| |
| if (copy_from_user(&config, (void __user *) ioctl_ctrl->handle, |
| sizeof(config))) |
| return -EFAULT; |
| |
| rc = cam_mem_get_cpu_buf( |
| config.packet_handle, |
| (uint64_t *)&generic_ptr, |
| &len_of_buff); |
| if (rc < 0) { |
| pr_err("%s:%d :Error: Failed in getting the buffer: %d\n", |
| __func__, __LINE__, rc); |
| return rc; |
| } |
| |
| csl_packet = (struct cam_packet *)(generic_ptr + |
| config.offset); |
| if (config.offset > len_of_buff) { |
| pr_err("%s: %d offset is out of bounds: off: %lld len: %zu\n", |
| __func__, __LINE__, config.offset, len_of_buff); |
| return -EINVAL; |
| } |
| |
| i2c_data = &(s_ctrl->i2c_data); |
| CDBG("%s:%d Header OpCode: %d\n", |
| __func__, __LINE__, csl_packet->header.op_code); |
| if ((csl_packet->header.op_code & 0xFFFFFF) == |
| CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG) { |
| i2c_reg_settings = &i2c_data->init_settings; |
| i2c_reg_settings->request_id = 0; |
| i2c_reg_settings->is_settings_valid = 1; |
| } else if ((csl_packet->header.op_code & 0xFFFFFF) == |
| CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE) { |
| i2c_reg_settings = |
| &i2c_data-> |
| per_frame[csl_packet->header.request_id % |
| MAX_PER_FRAME_ARRAY]; |
| CDBG("%s:%d Received Packet: %lld\n", __func__, __LINE__, |
| csl_packet->header.request_id % MAX_PER_FRAME_ARRAY); |
| if (i2c_reg_settings->is_settings_valid == 1) { |
| pr_err("%s:%d :Error: Already some pkt in offset req : %lld\n", |
| __func__, __LINE__, |
| csl_packet->header.request_id); |
| rc = delete_request(i2c_reg_settings); |
| if (rc < 0) { |
| pr_err("%s: %d :Error: Failed in Deleting the err: %d\n", |
| __func__, __LINE__, rc); |
| return rc; |
| } |
| } |
| |
| i2c_reg_settings->request_id = |
| csl_packet->header.request_id; |
| i2c_reg_settings->is_settings_valid = 1; |
| } else if ((csl_packet->header.op_code & 0xFFFFFF) == |
| CAM_PKT_NOP_OPCODE) { |
| goto update_req_mgr; |
| } else { |
| pr_err("%s:%d Invalid Packet Header\n", __func__, __LINE__); |
| return -EINVAL; |
| } |
| |
| offset = (uint32_t *)&csl_packet->payload; |
| offset += csl_packet->cmd_buf_offset / 4; |
| cmd_desc = (struct cam_cmd_buf_desc *)(offset); |
| |
| rc = cam_sensor_i2c_pkt_parser(i2c_reg_settings, cmd_desc, 1); |
| if (rc < 0) { |
| pr_err("%s:%d :Error: Fail parsing I2C Pkt: %d\n", |
| __func__, __LINE__, rc); |
| return rc; |
| } |
| |
| update_req_mgr: |
| if (((csl_packet->header.op_code & 0xFFFFFF) == |
| CAM_PKT_NOP_OPCODE) || (csl_packet->header.op_code == |
| CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE)) { |
| add_req.link_hdl = s_ctrl->bridge_intf.link_hdl; |
| add_req.req_id = csl_packet->header.request_id; |
| CDBG("%s:%d Rxed Req Id: %lld\n", |
| __func__, __LINE__, csl_packet->header.request_id); |
| add_req.dev_hdl = s_ctrl->bridge_intf.device_hdl; |
| if (s_ctrl->bridge_intf.crm_cb && |
| s_ctrl->bridge_intf.crm_cb->add_req) |
| s_ctrl->bridge_intf.crm_cb->add_req(&add_req); |
| CDBG("%s:%d add req to req mgr: %lld\n", |
| __func__, __LINE__, add_req.req_id); |
| } |
| return rc; |
| } |
| |
| int32_t cam_sensor_update_i2c_info(struct cam_cmd_i2c_info *i2c_info, |
| struct cam_sensor_ctrl_t *s_ctrl) |
| { |
| int32_t rc = 0; |
| struct cam_sensor_cci_client *cci_client = NULL; |
| |
| if (s_ctrl->io_master_info.master_type == CCI_MASTER) { |
| cci_client = s_ctrl->io_master_info.cci_client; |
| if (!cci_client) { |
| pr_err("failed: cci_client %pK", cci_client); |
| return -EINVAL; |
| } |
| cci_client->cci_i2c_master = s_ctrl->cci_i2c_master; |
| cci_client->sid = i2c_info->slave_addr >> 1; |
| cci_client->retries = 3; |
| cci_client->id_map = 0; |
| cci_client->i2c_freq_mode = i2c_info->i2c_freq_mode; |
| CDBG("%s:%d Master: %d sid: %d freq_mode: %d\n", |
| __func__, __LINE__, |
| cci_client->cci_i2c_master, i2c_info->slave_addr, |
| i2c_info->i2c_freq_mode); |
| } |
| |
| return rc; |
| } |
| |
| int32_t cam_sensor_update_slave_info(struct cam_cmd_probe *probe_info, |
| struct cam_sensor_ctrl_t *s_ctrl) |
| { |
| int32_t rc = 0; |
| |
| s_ctrl->sensordata->slave_info.sensor_id_reg_addr = |
| probe_info->reg_addr; |
| s_ctrl->sensordata->slave_info.sensor_id = |
| probe_info->expected_data; |
| s_ctrl->sensordata->slave_info.sensor_id_mask = |
| probe_info->data_mask; |
| |
| s_ctrl->sensor_probe_addr_type = probe_info->addr_type; |
| s_ctrl->sensor_probe_data_type = probe_info->data_type; |
| CDBG("%s:%d Sensor Addr: 0x%x sensor_id: 0x%x sensor_mask: 0x%x\n", |
| __func__, __LINE__, |
| s_ctrl->sensordata->slave_info.sensor_id_reg_addr, |
| s_ctrl->sensordata->slave_info.sensor_id, |
| s_ctrl->sensordata->slave_info.sensor_id_mask); |
| return rc; |
| } |
| |
| int32_t cam_sensor_update_power_settings(void *cmd_buf, |
| int cmd_length, struct cam_sensor_ctrl_t *s_ctrl) |
| { |
| int32_t rc = 0, tot_size = 0, last_cmd_type = 0; |
| int32_t i = 0, pwr_up = 0, pwr_down = 0; |
| void *ptr = cmd_buf, *scr; |
| struct cam_cmd_power *pwr_cmd = (struct cam_cmd_power *)cmd_buf; |
| struct common_header *cmm_hdr = (struct common_header *)cmd_buf; |
| struct cam_sensor_power_ctrl_t *power_info = |
| &s_ctrl->sensordata->power_info; |
| |
| if (!pwr_cmd || !cmd_length) { |
| pr_err("%s:%d Invalid Args: pwr_cmd %pK, cmd_length: %d\n", |
| __func__, __LINE__, pwr_cmd, cmd_length); |
| return -EINVAL; |
| } |
| |
| power_info->power_setting_size = 0; |
| power_info->power_setting = |
| (struct cam_sensor_power_setting *) |
| kzalloc(sizeof(struct cam_sensor_power_setting) * |
| MAX_POWER_CONFIG, GFP_KERNEL); |
| if (!power_info->power_setting) |
| return -ENOMEM; |
| |
| power_info->power_down_setting = |
| (struct cam_sensor_power_setting *) |
| kzalloc(sizeof(struct cam_sensor_power_setting) * |
| MAX_POWER_CONFIG, GFP_KERNEL); |
| if (!power_info->power_down_setting) { |
| rc = -ENOMEM; |
| goto free_power_settings; |
| } |
| |
| while (tot_size < cmd_length) { |
| if (cmm_hdr->cmd_type == |
| CAMERA_SENSOR_CMD_TYPE_PWR_UP) { |
| struct cam_cmd_power *pwr_cmd = |
| (struct cam_cmd_power *)ptr; |
| |
| power_info-> |
| power_setting_size += |
| pwr_cmd->count; |
| scr = ptr + sizeof(struct cam_cmd_power); |
| tot_size = tot_size + sizeof(struct cam_cmd_power); |
| |
| if (pwr_cmd->count == 0) |
| CDBG("%s:%d Un expected Command\n", |
| __func__, __LINE__); |
| |
| for (i = 0; i < pwr_cmd->count; i++, pwr_up++) { |
| power_info-> |
| power_setting[pwr_up].seq_type = |
| pwr_cmd->power_settings[i]. |
| power_seq_type; |
| power_info-> |
| power_setting[pwr_up].config_val = |
| pwr_cmd->power_settings[i]. |
| config_val_low; |
| power_info->power_setting[pwr_up].delay = 0; |
| if (i) { |
| scr = scr + |
| sizeof( |
| struct cam_power_settings); |
| tot_size = tot_size + |
| sizeof( |
| struct cam_power_settings); |
| } |
| if (tot_size > cmd_length) { |
| pr_err("%s:%d :Error: Command Buffer is wrong\n", |
| __func__, __LINE__); |
| rc = -EINVAL; |
| goto free_power_down_settings; |
| } |
| CDBG("Seq Type[%d]: %d Config_val: %ldn", |
| pwr_up, |
| power_info-> |
| power_setting[pwr_up].seq_type, |
| power_info-> |
| power_setting[pwr_up]. |
| config_val); |
| } |
| last_cmd_type = CAMERA_SENSOR_CMD_TYPE_PWR_UP; |
| ptr = (void *) scr; |
| cmm_hdr = (struct common_header *)ptr; |
| } else if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_WAIT) { |
| struct cam_cmd_unconditional_wait *wait_cmd = |
| (struct cam_cmd_unconditional_wait *)ptr; |
| if (wait_cmd->op_code == |
| CAMERA_SENSOR_WAIT_OP_SW_UCND) { |
| if (last_cmd_type == |
| CAMERA_SENSOR_CMD_TYPE_PWR_UP) { |
| if (pwr_up > 0) |
| power_info-> |
| power_setting |
| [pwr_up - 1].delay += |
| wait_cmd->delay; |
| else |
| pr_err("%s:%d Delay is expected only after valid power up setting\n", |
| __func__, __LINE__); |
| } else if (last_cmd_type == |
| CAMERA_SENSOR_CMD_TYPE_PWR_DOWN) { |
| if (pwr_down > 0) |
| power_info-> |
| power_down_setting |
| [pwr_down - 1].delay += |
| wait_cmd->delay; |
| else |
| pr_err("%s:%d Delay is expected only after valid power down setting\n", |
| __func__, __LINE__); |
| } |
| } else |
| CDBG("%s:%d Invalid op code: %d\n", |
| __func__, __LINE__, wait_cmd->op_code); |
| tot_size = tot_size + |
| sizeof(struct cam_cmd_unconditional_wait); |
| if (tot_size > cmd_length) { |
| pr_err("Command Buffer is wrong\n"); |
| return -EINVAL; |
| } |
| scr = (void *) (wait_cmd); |
| ptr = (void *) |
| (scr + |
| sizeof(struct cam_cmd_unconditional_wait)); |
| CDBG("%s:%d ptr: %pK sizeof: %d Next: %pK\n", |
| __func__, __LINE__, scr, |
| (int32_t)sizeof( |
| struct cam_cmd_unconditional_wait), ptr); |
| |
| cmm_hdr = (struct common_header *)ptr; |
| } else if (cmm_hdr->cmd_type == |
| CAMERA_SENSOR_CMD_TYPE_PWR_DOWN) { |
| struct cam_cmd_power *pwr_cmd = |
| (struct cam_cmd_power *)ptr; |
| |
| scr = ptr + sizeof(struct cam_cmd_power); |
| tot_size = tot_size + sizeof(struct cam_cmd_power); |
| power_info->power_down_setting_size += pwr_cmd->count; |
| |
| if (pwr_cmd->count == 0) |
| pr_err("%s:%d Invalid Command\n", |
| __func__, __LINE__); |
| |
| for (i = 0; i < pwr_cmd->count; i++, pwr_down++) { |
| power_info-> |
| power_down_setting[pwr_down]. |
| seq_type = |
| pwr_cmd->power_settings[i]. |
| power_seq_type; |
| power_info-> |
| power_down_setting[pwr_down]. |
| config_val = |
| pwr_cmd->power_settings[i]. |
| config_val_low; |
| power_info-> |
| power_down_setting[pwr_down].delay = 0; |
| if (i) { |
| scr = scr + |
| sizeof( |
| struct cam_power_settings); |
| tot_size = |
| tot_size + |
| sizeof( |
| struct cam_power_settings); |
| } |
| if (tot_size > cmd_length) { |
| pr_err("Command Buffer is wrong\n"); |
| rc = -EINVAL; |
| goto free_power_down_settings; |
| } |
| CDBG("%s:%d Seq Type[%d]: %d Config_val: %ldn", |
| __func__, __LINE__, |
| pwr_down, |
| power_info-> |
| power_down_setting[pwr_down]. |
| seq_type, |
| power_info-> |
| power_down_setting[pwr_down]. |
| config_val); |
| } |
| last_cmd_type = CAMERA_SENSOR_CMD_TYPE_PWR_DOWN; |
| ptr = (void *) scr; |
| cmm_hdr = (struct common_header *)ptr; |
| } else { |
| pr_err("%s:%d: :Error: Un expected Header Type: %d\n", |
| __func__, __LINE__, cmm_hdr->cmd_type); |
| } |
| } |
| |
| return rc; |
| free_power_down_settings: |
| kfree(power_info->power_down_setting); |
| free_power_settings: |
| kfree(power_info->power_setting); |
| return rc; |
| } |
| |
| int32_t cam_handle_cmd_buffers_for_probe(void *cmd_buf, |
| struct cam_sensor_ctrl_t *s_ctrl, |
| int32_t cmd_buf_num, int cmd_buf_length) |
| { |
| int32_t rc = 0; |
| |
| switch (cmd_buf_num) { |
| case 0: { |
| struct cam_cmd_i2c_info *i2c_info = NULL; |
| struct cam_cmd_probe *probe_info; |
| |
| i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; |
| rc = cam_sensor_update_i2c_info(i2c_info, s_ctrl); |
| if (rc < 0) { |
| pr_err("%s:%d Failed in Updating the i2c Info\n", |
| __func__, __LINE__); |
| return rc; |
| } |
| probe_info = (struct cam_cmd_probe *) |
| (cmd_buf + sizeof(struct cam_cmd_i2c_info)); |
| rc = cam_sensor_update_slave_info(probe_info, s_ctrl); |
| if (rc < 0) { |
| pr_err("%s:%d :Error: Updating the slave Info\n", |
| __func__, __LINE__); |
| return rc; |
| } |
| cmd_buf = probe_info; |
| } |
| break; |
| case 1: { |
| rc = cam_sensor_update_power_settings(cmd_buf, |
| cmd_buf_length, s_ctrl); |
| if (rc < 0) { |
| pr_err("Failed in updating power settings\n"); |
| return rc; |
| } |
| } |
| break; |
| default: |
| pr_err("%s:%d Invalid command buffer\n", |
| __func__, __LINE__); |
| break; |
| } |
| return rc; |
| } |
| |
| int32_t cam_handle_mem_ptr(uint64_t handle, struct cam_sensor_ctrl_t *s_ctrl) |
| { |
| int rc = 0, i; |
| void *packet = NULL, *cmd_buf1 = NULL; |
| uint32_t *cmd_buf; |
| void *ptr; |
| size_t len; |
| struct cam_packet *pkt; |
| struct cam_cmd_buf_desc *cmd_desc; |
| |
| rc = cam_mem_get_cpu_buf(handle, |
| (uint64_t *)&packet, &len); |
| if (rc < 0) { |
| pr_err("%s: %d Failed to get the command Buffer\n", |
| __func__, __LINE__); |
| return -EINVAL; |
| } |
| pkt = (struct cam_packet *)packet; |
| cmd_desc = (struct cam_cmd_buf_desc *) |
| ((uint32_t *)&pkt->payload + pkt->cmd_buf_offset/4); |
| if (cmd_desc == NULL) { |
| pr_err("%s: %d command descriptor pos is invalid\n", |
| __func__, __LINE__); |
| return -EINVAL; |
| } |
| if (pkt->num_cmd_buf != 2) { |
| pr_err("%s: %d Expected More Command Buffers : %d\n", |
| __func__, __LINE__, pkt->num_cmd_buf); |
| return -EINVAL; |
| } |
| for (i = 0; i < pkt->num_cmd_buf; i++) { |
| if (!(cmd_desc[i].length)) |
| continue; |
| rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, |
| (uint64_t *)&cmd_buf1, &len); |
| if (rc < 0) { |
| pr_err("%s: %d Failed to parse the command Buffer Header\n", |
| __func__, __LINE__); |
| return -EINVAL; |
| } |
| cmd_buf = (uint32_t *)cmd_buf1; |
| cmd_buf += cmd_desc[i].offset/4; |
| ptr = (void *) cmd_buf; |
| |
| rc = cam_handle_cmd_buffers_for_probe(ptr, s_ctrl, |
| i, cmd_desc[i].length); |
| if (rc < 0) { |
| pr_err("%s: %d Failed to parse the command Buffer Header\n", |
| __func__, __LINE__); |
| return -EINVAL; |
| } |
| } |
| return rc; |
| } |
| |
| void cam_sensor_query_cap(struct cam_sensor_ctrl_t *s_ctrl, |
| struct cam_sensor_query_cap *query_cap) |
| { |
| query_cap->pos_roll = s_ctrl->sensordata->pos_roll; |
| query_cap->pos_pitch = s_ctrl->sensordata->pos_pitch; |
| query_cap->pos_yaw = s_ctrl->sensordata->pos_yaw; |
| query_cap->secure_camera = 0; |
| query_cap->actuator_slot_id = |
| s_ctrl->sensordata->subdev_id[SUB_MODULE_ACTUATOR]; |
| query_cap->csiphy_slot_id = |
| s_ctrl->sensordata->subdev_id[SUB_MODULE_CSIPHY]; |
| query_cap->eeprom_slot_id = |
| s_ctrl->sensordata->subdev_id[SUB_MODULE_EEPROM]; |
| query_cap->flash_slot_id = |
| s_ctrl->sensordata->subdev_id[SUB_MODULE_LED_FLASH]; |
| query_cap->ois_slot_id = |
| s_ctrl->sensordata->subdev_id[SUB_MODULE_OIS]; |
| query_cap->slot_info = |
| s_ctrl->soc_info.index; |
| } |
| |
| static uint16_t cam_sensor_id_by_mask(struct cam_sensor_ctrl_t *s_ctrl, |
| uint32_t chipid) |
| { |
| uint16_t sensor_id = (uint16_t)(chipid & 0xFFFF); |
| int16_t sensor_id_mask = s_ctrl->sensordata->slave_info.sensor_id_mask; |
| |
| if (!sensor_id_mask) |
| sensor_id_mask = ~sensor_id_mask; |
| |
| sensor_id &= sensor_id_mask; |
| sensor_id_mask &= -sensor_id_mask; |
| sensor_id_mask -= 1; |
| while (sensor_id_mask) { |
| sensor_id_mask >>= 1; |
| sensor_id >>= 1; |
| } |
| return sensor_id; |
| } |
| |
| int cam_sensor_match_id(struct cam_sensor_ctrl_t *s_ctrl) |
| { |
| int rc = 0; |
| uint32_t chipid = 0; |
| struct cam_camera_slave_info *slave_info; |
| |
| slave_info = &(s_ctrl->sensordata->slave_info); |
| |
| if (!slave_info) { |
| pr_err("%s:%d failed: %pK\n", |
| __func__, __LINE__, slave_info); |
| return -EINVAL; |
| } |
| |
| rc = camera_io_dev_read( |
| &(s_ctrl->io_master_info), |
| slave_info->sensor_id_reg_addr, |
| &chipid, CAMERA_SENSOR_I2C_TYPE_WORD, |
| CAMERA_SENSOR_I2C_TYPE_WORD); |
| |
| CDBG("%s:%d read id: 0x%x expected id 0x%x:\n", |
| __func__, __LINE__, chipid, slave_info->sensor_id); |
| if (cam_sensor_id_by_mask(s_ctrl, chipid) != slave_info->sensor_id) { |
| pr_err("%s: chip id %x does not match %x\n", |
| __func__, chipid, slave_info->sensor_id); |
| return -ENODEV; |
| } |
| return rc; |
| } |
| |
| int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, |
| void *arg) |
| { |
| int rc = 0; |
| struct cam_control *cmd = (struct cam_control *)arg; |
| struct cam_sensor_power_setting *pu = NULL; |
| struct cam_sensor_power_setting *pd = NULL; |
| struct cam_sensor_power_ctrl_t *power_info = |
| &s_ctrl->sensordata->power_info; |
| |
| if (!s_ctrl || !arg) { |
| pr_err("%s: %d s_ctrl is NULL\n", |
| __func__, __LINE__); |
| return -EINVAL; |
| } |
| |
| mutex_lock(&(s_ctrl->cam_sensor_mutex)); |
| switch (cmd->op_code) { |
| case CAM_SENSOR_PROBE_CMD: { |
| if (s_ctrl->is_probe_succeed == 1) { |
| pr_err("Already Sensor Probed in the slot\n"); |
| break; |
| } |
| /* Allocate memory for power up setting */ |
| pu = kzalloc(sizeof(struct cam_sensor_power_setting) * |
| MAX_POWER_CONFIG, GFP_KERNEL); |
| if (!pu) { |
| rc = -ENOMEM; |
| goto release_mutex; |
| } |
| |
| pd = kzalloc(sizeof(struct cam_sensor_power_setting) * |
| MAX_POWER_CONFIG, GFP_KERNEL); |
| if (!pd) { |
| kfree(pu); |
| rc = -ENOMEM; |
| goto release_mutex; |
| } |
| |
| power_info->power_setting = pu; |
| power_info->power_down_setting = pd; |
| |
| if (cmd->handle_type == |
| CAM_HANDLE_MEM_HANDLE) { |
| rc = cam_handle_mem_ptr(cmd->handle, s_ctrl); |
| if (rc < 0) { |
| pr_err("%s: %d Get Buffer Handle Failed\n", |
| __func__, __LINE__); |
| kfree(pu); |
| kfree(pd); |
| goto release_mutex; |
| } |
| } else { |
| pr_err("%s:%d :Error: Invalid Command Type: %d", |
| __func__, __LINE__, cmd->handle_type); |
| } |
| |
| /* Parse and fill vreg params for powerup settings */ |
| rc = msm_camera_fill_vreg_params( |
| &s_ctrl->soc_info, |
| s_ctrl->sensordata->power_info.power_setting, |
| s_ctrl->sensordata->power_info.power_setting_size); |
| if (rc < 0) { |
| pr_err("%s:%d :Error: Fail in filling vreg params for PUP rc %d", |
| __func__, __LINE__, rc); |
| kfree(pu); |
| kfree(pd); |
| goto release_mutex; |
| } |
| |
| /* Parse and fill vreg params for powerdown settings*/ |
| rc = msm_camera_fill_vreg_params( |
| &s_ctrl->soc_info, |
| s_ctrl->sensordata->power_info.power_down_setting, |
| s_ctrl->sensordata->power_info.power_down_setting_size); |
| if (rc < 0) { |
| pr_err("%s:%d :Error: Fail in filling vreg params for PDOWN rc %d", |
| __func__, __LINE__, rc); |
| kfree(pu); |
| kfree(pd); |
| goto release_mutex; |
| } |
| |
| /* Power up and probe sensor */ |
| rc = cam_sensor_power_up(s_ctrl); |
| if (rc < 0) { |
| pr_err("power up failed"); |
| cam_sensor_power_down(s_ctrl); |
| kfree(pu); |
| kfree(pd); |
| goto release_mutex; |
| } |
| |
| /* Match sensor ID */ |
| rc = cam_sensor_match_id(s_ctrl); |
| if (rc < 0) { |
| cam_sensor_power_down(s_ctrl); |
| msleep(20); |
| kfree(pu); |
| kfree(pd); |
| goto release_mutex; |
| } |
| |
| CDBG("%s:%d Probe Succeeded on the slot: %d\n", |
| __func__, __LINE__, |
| s_ctrl->soc_info.index); |
| rc = cam_sensor_power_down(s_ctrl); |
| if (rc < 0) { |
| pr_err("%s:%d :Error: fail in Sensor Power Down\n", |
| __func__, __LINE__); |
| kfree(pu); |
| kfree(pd); |
| goto release_mutex; |
| } |
| /* |
| * Set probe succeeded flag to 1 so that no other camera shall |
| * probed on this slot |
| */ |
| s_ctrl->is_probe_succeed = 1; |
| } |
| break; |
| case CAM_ACQUIRE_DEV: { |
| struct cam_sensor_acquire_dev sensor_acq_dev; |
| struct cam_create_dev_hdl bridge_params; |
| |
| if (s_ctrl->bridge_intf.device_hdl != -1) { |
| pr_err("%s:%d Device is already acquired\n", |
| __func__, __LINE__); |
| rc = -EINVAL; |
| goto release_mutex; |
| } |
| rc = copy_from_user(&sensor_acq_dev, |
| (void __user *) cmd->handle, sizeof(sensor_acq_dev)); |
| if (rc < 0) { |
| pr_err("Failed Copying from user\n"); |
| goto release_mutex; |
| } |
| |
| bridge_params.session_hdl = sensor_acq_dev.session_handle; |
| bridge_params.ops = &s_ctrl->bridge_intf.ops; |
| bridge_params.v4l2_sub_dev_flag = 0; |
| bridge_params.media_entity_flag = 0; |
| bridge_params.priv = s_ctrl; |
| |
| sensor_acq_dev.device_handle = |
| cam_create_device_hdl(&bridge_params); |
| s_ctrl->bridge_intf.device_hdl = sensor_acq_dev.device_handle; |
| s_ctrl->bridge_intf.session_hdl = sensor_acq_dev.session_handle; |
| |
| CDBG("%s:%d Device Handle: %d\n", __func__, __LINE__, |
| sensor_acq_dev.device_handle); |
| if (copy_to_user((void __user *) cmd->handle, &sensor_acq_dev, |
| sizeof(struct cam_sensor_acquire_dev))) { |
| pr_err("Failed Copy to User\n"); |
| rc = -EFAULT; |
| goto release_mutex; |
| } |
| } |
| break; |
| case CAM_RELEASE_DEV: { |
| if (s_ctrl->bridge_intf.device_hdl == -1) { |
| pr_err("%s:%d Invalid Handles: link hdl: %d device hdl: %d\n", |
| __func__, __LINE__, |
| s_ctrl->bridge_intf.device_hdl, |
| s_ctrl->bridge_intf.link_hdl); |
| rc = -EINVAL; |
| goto release_mutex; |
| } |
| rc = cam_destroy_device_hdl(s_ctrl->bridge_intf.device_hdl); |
| if (rc < 0) |
| pr_err("%s:%d Failed in destroying the device hdl\n", |
| __func__, __LINE__); |
| s_ctrl->bridge_intf.device_hdl = -1; |
| s_ctrl->bridge_intf.link_hdl = -1; |
| s_ctrl->bridge_intf.session_hdl = -1; |
| } |
| break; |
| case CAM_QUERY_CAP: { |
| struct cam_sensor_query_cap sensor_cap; |
| |
| cam_sensor_query_cap(s_ctrl, &sensor_cap); |
| if (copy_to_user((void __user *) cmd->handle, &sensor_cap, |
| sizeof(struct cam_sensor_query_cap))) { |
| pr_err("Failed Copy to User\n"); |
| rc = -EFAULT; |
| goto release_mutex; |
| } |
| break; |
| } |
| case CAM_START_DEV: { |
| rc = cam_sensor_power_up(s_ctrl); |
| if (rc < 0) { |
| pr_err("%s:%d :Error: Sensor Power up failed\n", |
| __func__, __LINE__); |
| goto release_mutex; |
| } |
| rc = cam_sensor_apply_settings(s_ctrl, 0); |
| if (rc < 0) { |
| pr_err("cannot apply settings\n"); |
| goto release_mutex; |
| } |
| rc = delete_request(&s_ctrl->i2c_data.init_settings); |
| if (rc < 0) { |
| pr_err("%s:%d Fail in deleting the Init settings\n", |
| __func__, __LINE__); |
| rc = -EINVAL; |
| goto release_mutex; |
| } |
| } |
| break; |
| case CAM_STOP_DEV: { |
| rc = cam_sensor_power_down(s_ctrl); |
| if (rc < 0) { |
| pr_err("%s:%d Sensor Power Down failed\n", |
| __func__, __LINE__); |
| goto release_mutex; |
| } |
| } |
| break; |
| case CAM_CONFIG_DEV: { |
| rc = cam_sensor_i2c_pkt_parse(s_ctrl, arg); |
| if (rc < 0) { |
| pr_err("%s:%d :Error: Failed CCI Config: %d\n", |
| __func__, __LINE__, rc); |
| goto release_mutex; |
| } |
| } |
| break; |
| case CAM_SD_SHUTDOWN: |
| break; |
| default: |
| pr_err("%s:%d :Error: Invalid Opcode: %d\n", |
| __func__, __LINE__, cmd->op_code); |
| rc = -EINVAL; |
| goto release_mutex; |
| } |
| |
| release_mutex: |
| mutex_unlock(&(s_ctrl->cam_sensor_mutex)); |
| return rc; |
| } |
| |
| int cam_sensor_publish_dev_info(struct cam_req_mgr_device_info *info) |
| { |
| int rc = 0; |
| |
| if (!info) |
| return -EINVAL; |
| |
| info->dev_id = CAM_REQ_MGR_DEVICE_SENSOR; |
| strlcpy(info->name, CAM_SENSOR_NAME, sizeof(info->name)); |
| info->p_delay = 2; |
| |
| return rc; |
| } |
| |
| int cam_sensor_establish_link(struct cam_req_mgr_core_dev_link_setup *link) |
| { |
| struct cam_sensor_ctrl_t *s_ctrl = NULL; |
| |
| if (!link) |
| return -EINVAL; |
| |
| s_ctrl = (struct cam_sensor_ctrl_t *) |
| cam_get_device_priv(link->dev_hdl); |
| if (!s_ctrl) { |
| pr_err("%s: Device data is NULL\n", __func__); |
| return -EINVAL; |
| } |
| if (link->link_enable) { |
| s_ctrl->bridge_intf.link_hdl = link->link_hdl; |
| s_ctrl->bridge_intf.crm_cb = link->crm_cb; |
| } else { |
| s_ctrl->bridge_intf.link_hdl = -1; |
| s_ctrl->bridge_intf.crm_cb = NULL; |
| } |
| |
| return 0; |
| } |
| |
| int cam_sensor_power(struct v4l2_subdev *sd, int on) |
| { |
| struct cam_sensor_ctrl_t *s_ctrl = v4l2_get_subdevdata(sd); |
| |
| mutex_lock(&(s_ctrl->cam_sensor_mutex)); |
| if (!on && s_ctrl->sensor_state == CAM_SENSOR_POWER_UP) { |
| cam_sensor_power_down(s_ctrl); |
| s_ctrl->sensor_state = CAM_SENSOR_POWER_DOWN; |
| } |
| mutex_unlock(&(s_ctrl->cam_sensor_mutex)); |
| |
| return 0; |
| } |
| |
| int cam_sensor_power_up(struct cam_sensor_ctrl_t *s_ctrl) |
| { |
| int rc; |
| struct cam_sensor_power_ctrl_t *power_info; |
| struct cam_camera_slave_info *slave_info; |
| struct cam_hw_soc_info *soc_info = |
| &s_ctrl->soc_info; |
| |
| if (!s_ctrl) { |
| pr_err("%s:%d failed: %pK\n", |
| __func__, __LINE__, s_ctrl); |
| return -EINVAL; |
| } |
| |
| power_info = &s_ctrl->sensordata->power_info; |
| slave_info = &(s_ctrl->sensordata->slave_info); |
| |
| if (!power_info || !slave_info) { |
| pr_err("%s:%d failed: %pK %pK\n", |
| __func__, __LINE__, power_info, |
| slave_info); |
| return -EINVAL; |
| } |
| |
| rc = cam_sensor_core_power_up(power_info, soc_info); |
| if (rc < 0) { |
| pr_err("%s:%d power up the core is failed:%d\n", |
| __func__, __LINE__, rc); |
| return rc; |
| } |
| |
| if (s_ctrl->io_master_info.master_type == CCI_MASTER) { |
| rc = camera_io_init(&(s_ctrl->io_master_info)); |
| if (rc < 0) { |
| pr_err("%s cci_init failed\n", __func__); |
| return -EINVAL; |
| } |
| } |
| |
| s_ctrl->sensor_state = CAM_SENSOR_POWER_UP; |
| |
| return rc; |
| } |
| |
| int cam_sensor_power_down(struct cam_sensor_ctrl_t *s_ctrl) |
| { |
| struct cam_sensor_power_ctrl_t *power_info; |
| struct cam_hw_soc_info *soc_info; |
| int rc = 0; |
| |
| if (!s_ctrl) { |
| pr_err("%s:%d failed: s_ctrl %pK\n", |
| __func__, __LINE__, s_ctrl); |
| return -EINVAL; |
| } |
| |
| power_info = &s_ctrl->sensordata->power_info; |
| soc_info = &s_ctrl->soc_info; |
| |
| if (!power_info) { |
| pr_err("%s:%d failed: power_info %pK\n", |
| __func__, __LINE__, power_info); |
| return -EINVAL; |
| } |
| rc = msm_camera_power_down(power_info, soc_info); |
| if (rc < 0) { |
| pr_err("%s:%d power down the core is failed:%d\n", |
| __func__, __LINE__, rc); |
| return rc; |
| } |
| |
| if (s_ctrl->io_master_info.master_type == CCI_MASTER) |
| camera_io_release(&(s_ctrl->io_master_info)); |
| |
| s_ctrl->sensor_state = CAM_SENSOR_POWER_DOWN; |
| |
| return rc; |
| } |
| |
| int cam_sensor_apply_settings(struct cam_sensor_ctrl_t *s_ctrl, |
| int64_t req_id) |
| { |
| int rc = 0, offset, del_req_id; |
| struct i2c_settings_array *i2c_set = NULL; |
| struct i2c_settings_list *i2c_list; |
| |
| if (req_id == 0) { |
| i2c_set = &s_ctrl->i2c_data.init_settings; |
| if (i2c_set->is_settings_valid == 1) { |
| list_for_each_entry(i2c_list, |
| &(i2c_set->list_head), list) { |
| rc = camera_io_dev_write( |
| &(s_ctrl->io_master_info), |
| &(i2c_list->i2c_settings)); |
| if (rc < 0) { |
| pr_err("Failed to write the I2C settings\n"); |
| return rc; |
| } |
| } |
| rc = delete_request(&(s_ctrl->i2c_data.init_settings)); |
| i2c_set->is_settings_valid = 0; |
| if (rc < 0) { |
| pr_err("%s:%d :Error: Failed in deleting the Init request: %d\n", |
| __func__, __LINE__, rc); |
| } |
| } |
| } else { |
| offset = req_id % MAX_PER_FRAME_ARRAY; |
| i2c_set = &(s_ctrl->i2c_data.per_frame[offset]); |
| if (i2c_set->is_settings_valid == 1 && |
| i2c_set->request_id == req_id) { |
| list_for_each_entry(i2c_list, |
| &(i2c_set->list_head), list) { |
| rc = camera_io_dev_write( |
| &(s_ctrl->io_master_info), |
| &(i2c_list->i2c_settings)); |
| if (rc < 0) { |
| pr_err("%s:%d :Error: Fail to write the I2C settings: %d\n", |
| __func__, __LINE__, rc); |
| return rc; |
| } |
| } |
| del_req_id = (req_id + |
| MAX_PER_FRAME_ARRAY - |
| MAX_SYSTEM_PIPELINE_DELAY) % |
| MAX_PER_FRAME_ARRAY; |
| CDBG("%s:%d Deleting the Request: %d\n", |
| __func__, __LINE__, del_req_id); |
| if (req_id > |
| s_ctrl->i2c_data.per_frame[del_req_id]. |
| request_id) { |
| s_ctrl->i2c_data.per_frame[del_req_id]. |
| request_id = 0; |
| rc = delete_request( |
| &(s_ctrl->i2c_data. |
| per_frame[del_req_id])); |
| if (rc < 0) |
| pr_err("%s:%d :Error: Failed in deleting the request: %d rc: %d\n", |
| __func__, __LINE__, |
| del_req_id, rc); |
| } |
| } else { |
| CDBG("%s:%d Invalid/NOP request to apply: %lld\n", |
| __func__, __LINE__, req_id); |
| } |
| } |
| return rc; |
| } |
| |
| int32_t cam_sensor_apply_request(struct cam_req_mgr_apply_request *apply) |
| { |
| int32_t rc = 0; |
| struct cam_sensor_ctrl_t *s_ctrl = NULL; |
| |
| if (!apply) |
| return -EINVAL; |
| |
| s_ctrl = (struct cam_sensor_ctrl_t *) |
| cam_get_device_priv(apply->dev_hdl); |
| if (!s_ctrl) { |
| pr_err("%s: Device data is NULL\n", __func__); |
| return -EINVAL; |
| } |
| CDBG("%s:%d Req Id: %lld\n", __func__, __LINE__, |
| apply->request_id); |
| rc = cam_sensor_apply_settings(s_ctrl, apply->request_id); |
| return rc; |
| } |
| |
| int32_t cam_sensor_flush_request(struct cam_req_mgr_flush_request *flush_req) |
| { |
| int32_t rc = 0, i; |
| uint32_t cancel_req_id_found = 0; |
| struct cam_sensor_ctrl_t *s_ctrl = NULL; |
| struct i2c_settings_array *i2c_set = NULL; |
| |
| if (!flush_req) |
| return -EINVAL; |
| |
| s_ctrl = (struct cam_sensor_ctrl_t *) |
| cam_get_device_priv(flush_req->dev_hdl); |
| if (!s_ctrl) { |
| pr_err("%s: Device data is NULL\n", __func__); |
| return -EINVAL; |
| } |
| |
| for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { |
| i2c_set = &(s_ctrl->i2c_data.per_frame[i]); |
| |
| if ((flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) |
| && (i2c_set->request_id != flush_req->req_id)) |
| continue; |
| |
| if (i2c_set->is_settings_valid == 1) { |
| rc = delete_request(i2c_set); |
| if (rc < 0) |
| pr_err("%s:%d :Error: delete request: %lld rc: %d\n", |
| __func__, __LINE__, |
| i2c_set->request_id, rc); |
| |
| if (flush_req->type == |
| CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) { |
| cancel_req_id_found = 1; |
| break; |
| } |
| } |
| } |
| |
| if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ && |
| !cancel_req_id_found) |
| CDBG("%s:Flush request id:%lld not found in the pending list\n", |
| __func__, flush_req->req_id); |
| return rc; |
| } |