| /* 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/crc32.h> |
| #include <media/cam_sensor.h> |
| |
| #include "cam_eeprom_core.h" |
| #include "cam_eeprom_soc.h" |
| #include "cam_debug_util.h" |
| |
| /** |
| * cam_eeprom_read_memory() - read map data into buffer |
| * @e_ctrl: eeprom control struct |
| * @block: block to be read |
| * |
| * This function iterates through blocks stored in block->map, reads each |
| * region and concatenate them into the pre-allocated block->mapdata |
| */ |
| static int cam_eeprom_read_memory(struct cam_eeprom_ctrl_t *e_ctrl, |
| struct cam_eeprom_memory_block_t *block) |
| { |
| int rc = 0; |
| int j; |
| struct cam_sensor_i2c_reg_setting i2c_reg_settings; |
| struct cam_sensor_i2c_reg_array i2c_reg_array; |
| struct cam_eeprom_memory_map_t *emap = block->map; |
| struct cam_eeprom_soc_private *eb_info; |
| uint8_t *memptr = block->mapdata; |
| |
| if (!e_ctrl) { |
| CAM_ERR(CAM_EEPROM, "e_ctrl is NULL"); |
| return -EINVAL; |
| } |
| |
| eb_info = (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; |
| |
| for (j = 0; j < block->num_map; j++) { |
| CAM_DBG(CAM_EEPROM, "slave-addr = 0x%X", emap[j].saddr); |
| if (emap[j].saddr) { |
| eb_info->i2c_info.slave_addr = emap[j].saddr; |
| rc = cam_eeprom_update_i2c_info(e_ctrl, |
| &eb_info->i2c_info); |
| if (rc) { |
| CAM_ERR(CAM_EEPROM, |
| "failed: to update i2c info rc %d", |
| rc); |
| return rc; |
| } |
| } |
| |
| if (emap[j].page.valid_size) { |
| i2c_reg_settings.addr_type = emap[j].page.addr_type; |
| i2c_reg_settings.data_type = emap[j].page.data_type; |
| i2c_reg_settings.size = 1; |
| i2c_reg_array.reg_addr = emap[j].page.addr; |
| i2c_reg_array.reg_data = emap[j].page.data; |
| i2c_reg_array.delay = emap[j].page.delay; |
| i2c_reg_settings.reg_setting = &i2c_reg_array; |
| rc = camera_io_dev_write(&e_ctrl->io_master_info, |
| &i2c_reg_settings); |
| if (rc) { |
| CAM_ERR(CAM_EEPROM, "page write failed rc %d", |
| rc); |
| return rc; |
| } |
| } |
| |
| if (emap[j].pageen.valid_size) { |
| i2c_reg_settings.addr_type = emap[j].pageen.addr_type; |
| i2c_reg_settings.data_type = emap[j].pageen.data_type; |
| i2c_reg_settings.size = 1; |
| i2c_reg_array.reg_addr = emap[j].pageen.addr; |
| i2c_reg_array.reg_data = emap[j].pageen.data; |
| i2c_reg_array.delay = emap[j].pageen.delay; |
| i2c_reg_settings.reg_setting = &i2c_reg_array; |
| rc = camera_io_dev_write(&e_ctrl->io_master_info, |
| &i2c_reg_settings); |
| if (rc) { |
| CAM_ERR(CAM_EEPROM, "page enable failed rc %d", |
| rc); |
| return rc; |
| } |
| } |
| |
| if (emap[j].poll.valid_size) { |
| rc = camera_io_dev_poll(&e_ctrl->io_master_info, |
| emap[j].poll.addr, emap[j].poll.data, |
| 0, emap[j].poll.addr_type, |
| emap[j].poll.data_type, |
| emap[j].poll.delay); |
| if (rc) { |
| CAM_ERR(CAM_EEPROM, "poll failed rc %d", |
| rc); |
| return rc; |
| } |
| } |
| |
| if (emap[j].mem.valid_size) { |
| rc = camera_io_dev_read_seq(&e_ctrl->io_master_info, |
| emap[j].mem.addr, memptr, |
| emap[j].mem.addr_type, |
| emap[j].mem.valid_size); |
| if (rc) { |
| CAM_ERR(CAM_EEPROM, "read failed rc %d", |
| rc); |
| return rc; |
| } |
| memptr += emap[j].mem.valid_size; |
| } |
| |
| if (emap[j].pageen.valid_size) { |
| i2c_reg_settings.addr_type = emap[j].pageen.addr_type; |
| i2c_reg_settings.data_type = emap[j].pageen.data_type; |
| i2c_reg_settings.size = 1; |
| i2c_reg_array.reg_addr = emap[j].pageen.addr; |
| i2c_reg_array.reg_data = 0; |
| i2c_reg_array.delay = emap[j].pageen.delay; |
| i2c_reg_settings.reg_setting = &i2c_reg_array; |
| rc = camera_io_dev_write(&e_ctrl->io_master_info, |
| &i2c_reg_settings); |
| |
| if (rc) { |
| CAM_ERR(CAM_EEPROM, |
| "page disable failed rc %d", |
| rc); |
| return rc; |
| } |
| } |
| } |
| return rc; |
| } |
| |
| /** |
| * cam_eeprom_power_up - Power up eeprom hardware |
| * @e_ctrl: ctrl structure |
| * @power_info: power up/down info for eeprom |
| * |
| * Returns success or failure |
| */ |
| static int cam_eeprom_power_up(struct cam_eeprom_ctrl_t *e_ctrl, |
| struct cam_sensor_power_ctrl_t *power_info) |
| { |
| int32_t rc = 0; |
| struct cam_hw_soc_info *soc_info = |
| &e_ctrl->soc_info; |
| |
| /* Parse and fill vreg params for power up settings */ |
| rc = msm_camera_fill_vreg_params( |
| &e_ctrl->soc_info, |
| power_info->power_setting, |
| power_info->power_setting_size); |
| if (rc) { |
| CAM_ERR(CAM_EEPROM, |
| "failed to fill vreg params for power up rc:%d", rc); |
| return rc; |
| } |
| |
| /* Parse and fill vreg params for power down settings*/ |
| rc = msm_camera_fill_vreg_params( |
| &e_ctrl->soc_info, |
| power_info->power_down_setting, |
| power_info->power_down_setting_size); |
| if (rc) { |
| CAM_ERR(CAM_EEPROM, |
| "failed to fill vreg params power down rc:%d", rc); |
| return rc; |
| } |
| |
| rc = cam_sensor_core_power_up(power_info, soc_info); |
| if (rc) { |
| CAM_ERR(CAM_EEPROM, "failed in eeprom power up rc %d", rc); |
| return rc; |
| } |
| |
| if (e_ctrl->io_master_info.master_type == CCI_MASTER) { |
| rc = camera_io_init(&(e_ctrl->io_master_info)); |
| if (rc) { |
| CAM_ERR(CAM_EEPROM, "cci_init failed"); |
| return -EINVAL; |
| } |
| } |
| return rc; |
| } |
| |
| /** |
| * cam_eeprom_power_down - Power down eeprom hardware |
| * @e_ctrl: ctrl structure |
| * |
| * Returns success or failure |
| */ |
| static int cam_eeprom_power_down(struct cam_eeprom_ctrl_t *e_ctrl) |
| { |
| struct cam_sensor_power_ctrl_t *power_info; |
| struct cam_hw_soc_info *soc_info; |
| struct cam_eeprom_soc_private *soc_private; |
| int rc = 0; |
| |
| if (!e_ctrl) { |
| CAM_ERR(CAM_EEPROM, "failed: e_ctrl %pK", e_ctrl); |
| return -EINVAL; |
| } |
| |
| soc_private = |
| (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; |
| power_info = &soc_private->power_info; |
| soc_info = &e_ctrl->soc_info; |
| |
| if (!power_info) { |
| CAM_ERR(CAM_EEPROM, "failed: power_info %pK", power_info); |
| return -EINVAL; |
| } |
| rc = msm_camera_power_down(power_info, soc_info); |
| if (rc) { |
| CAM_ERR(CAM_EEPROM, "power down the core is failed:%d", rc); |
| return rc; |
| } |
| |
| if (e_ctrl->io_master_info.master_type == CCI_MASTER) |
| camera_io_release(&(e_ctrl->io_master_info)); |
| |
| return rc; |
| } |
| |
| /** |
| * cam_eeprom_match_id - match eeprom id |
| * @e_ctrl: ctrl structure |
| * |
| * Returns success or failure |
| */ |
| static int cam_eeprom_match_id(struct cam_eeprom_ctrl_t *e_ctrl) |
| { |
| int rc; |
| struct camera_io_master *client = &e_ctrl->io_master_info; |
| uint8_t id[2]; |
| |
| rc = cam_spi_query_id(client, 0, CAMERA_SENSOR_I2C_TYPE_WORD, |
| &id[0], 2); |
| if (rc) |
| return rc; |
| CAM_DBG(CAM_EEPROM, "read 0x%x 0x%x, check 0x%x 0x%x", |
| id[0], id[1], client->spi_client->mfr_id0, |
| client->spi_client->device_id0); |
| if (id[0] != client->spi_client->mfr_id0 |
| || id[1] != client->spi_client->device_id0) |
| return -ENODEV; |
| return 0; |
| } |
| |
| /** |
| * cam_eeprom_parse_read_memory_map - Parse memory map |
| * @of_node: device node |
| * @e_ctrl: ctrl structure |
| * |
| * Returns success or failure |
| */ |
| int32_t cam_eeprom_parse_read_memory_map(struct device_node *of_node, |
| struct cam_eeprom_ctrl_t *e_ctrl) |
| { |
| int32_t rc = 0; |
| struct cam_eeprom_soc_private *soc_private; |
| struct cam_sensor_power_ctrl_t *power_info; |
| |
| if (!e_ctrl) { |
| CAM_ERR(CAM_EEPROM, "failed: e_ctrl is NULL"); |
| return -EINVAL; |
| } |
| |
| soc_private = |
| (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; |
| power_info = &soc_private->power_info; |
| |
| rc = cam_eeprom_parse_dt_memory_map(of_node, &e_ctrl->cal_data); |
| if (rc) { |
| CAM_ERR(CAM_EEPROM, "failed: eeprom dt parse rc %d", rc); |
| return rc; |
| } |
| rc = cam_eeprom_power_up(e_ctrl, power_info); |
| if (rc) { |
| CAM_ERR(CAM_EEPROM, "failed: eeprom power up rc %d", rc); |
| goto data_mem_free; |
| } |
| if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE) { |
| rc = cam_eeprom_match_id(e_ctrl); |
| if (rc) { |
| CAM_DBG(CAM_EEPROM, "eeprom not matching %d", rc); |
| goto power_down; |
| } |
| } |
| rc = cam_eeprom_read_memory(e_ctrl, &e_ctrl->cal_data); |
| if (rc) { |
| CAM_ERR(CAM_EEPROM, "read_eeprom_memory failed"); |
| goto power_down; |
| } |
| |
| rc = cam_eeprom_power_down(e_ctrl); |
| if (rc) |
| CAM_ERR(CAM_EEPROM, "failed: eeprom power down rc %d", rc); |
| return rc; |
| power_down: |
| cam_eeprom_power_down(e_ctrl); |
| data_mem_free: |
| kfree(e_ctrl->cal_data.mapdata); |
| kfree(e_ctrl->cal_data.map); |
| e_ctrl->cal_data.num_data = 0; |
| e_ctrl->cal_data.num_map = 0; |
| return rc; |
| } |
| |
| /** |
| * cam_eeprom_get_dev_handle - get device handle |
| * @e_ctrl: ctrl structure |
| * @arg: Camera control command argument |
| * |
| * Returns success or failure |
| */ |
| static int32_t cam_eeprom_get_dev_handle(struct cam_eeprom_ctrl_t *e_ctrl, |
| void *arg) |
| { |
| struct cam_sensor_acquire_dev eeprom_acq_dev; |
| struct cam_create_dev_hdl bridge_params; |
| struct cam_control *cmd = (struct cam_control *)arg; |
| |
| if (e_ctrl->bridge_intf.device_hdl != -1) { |
| CAM_ERR(CAM_EEPROM, "Device is already acquired"); |
| return -EFAULT; |
| } |
| if (copy_from_user(&eeprom_acq_dev, (void __user *) cmd->handle, |
| sizeof(eeprom_acq_dev))) { |
| CAM_ERR(CAM_EEPROM, |
| "EEPROM:ACQUIRE_DEV: copy from user failed"); |
| return -EFAULT; |
| } |
| |
| bridge_params.session_hdl = eeprom_acq_dev.session_handle; |
| bridge_params.ops = &e_ctrl->bridge_intf.ops; |
| bridge_params.v4l2_sub_dev_flag = 0; |
| bridge_params.media_entity_flag = 0; |
| bridge_params.priv = e_ctrl; |
| |
| eeprom_acq_dev.device_handle = |
| cam_create_device_hdl(&bridge_params); |
| e_ctrl->bridge_intf.device_hdl = eeprom_acq_dev.device_handle; |
| e_ctrl->bridge_intf.session_hdl = eeprom_acq_dev.session_handle; |
| |
| CAM_DBG(CAM_EEPROM, "Device Handle: %d", eeprom_acq_dev.device_handle); |
| if (copy_to_user((void __user *) cmd->handle, &eeprom_acq_dev, |
| sizeof(struct cam_sensor_acquire_dev))) { |
| CAM_ERR(CAM_EEPROM, "EEPROM:ACQUIRE_DEV: copy to user failed"); |
| return -EFAULT; |
| } |
| return 0; |
| } |
| |
| /** |
| * cam_eeprom_update_slaveInfo - Update slave info |
| * @e_ctrl: ctrl structure |
| * @cmd_buf: command buffer |
| * |
| * Returns success or failure |
| */ |
| static int32_t cam_eeprom_update_slaveInfo(struct cam_eeprom_ctrl_t *e_ctrl, |
| void *cmd_buf) |
| { |
| int32_t rc = 0; |
| struct cam_eeprom_soc_private *soc_private; |
| struct cam_cmd_i2c_info *cmd_i2c_info = NULL; |
| |
| soc_private = |
| (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; |
| cmd_i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; |
| soc_private->i2c_info.slave_addr = cmd_i2c_info->slave_addr; |
| soc_private->i2c_info.i2c_freq_mode = cmd_i2c_info->i2c_freq_mode; |
| |
| rc = cam_eeprom_update_i2c_info(e_ctrl, |
| &soc_private->i2c_info); |
| CAM_DBG(CAM_EEPROM, "Slave addr: 0x%x Freq Mode: %d", |
| soc_private->i2c_info.slave_addr, |
| soc_private->i2c_info.i2c_freq_mode); |
| |
| return rc; |
| } |
| |
| /** |
| * cam_eeprom_parse_memory_map - Parse memory map info |
| * @data: memory block data |
| * @cmd_buf: command buffer |
| * @cmd_length: command buffer length |
| * @num_map: memory map size |
| * @cmd_length_bytes: command length processed in this function |
| * |
| * Returns success or failure |
| */ |
| static int32_t cam_eeprom_parse_memory_map( |
| struct cam_eeprom_memory_block_t *data, |
| void *cmd_buf, int cmd_length, uint16_t *cmd_length_bytes, |
| int16_t num_map) |
| { |
| int32_t rc = 0; |
| int32_t processed_size = 0; |
| struct cam_eeprom_memory_map_t *map = data->map; |
| struct common_header *cmm_hdr = |
| (struct common_header *)cmd_buf; |
| uint16_t cmd_length_in_bytes = 0; |
| struct cam_cmd_i2c_random_wr *i2c_random_wr = NULL; |
| struct cam_cmd_i2c_continuous_rd *i2c_cont_rd = NULL; |
| struct cam_cmd_conditional_wait *i2c_poll = NULL; |
| |
| switch (cmm_hdr->cmd_type) { |
| case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR: |
| i2c_random_wr = (struct cam_cmd_i2c_random_wr *)cmd_buf; |
| cmd_length_in_bytes = sizeof(struct cam_cmd_i2c_random_wr); |
| |
| map[num_map].page.addr = |
| i2c_random_wr->random_wr_payload[0].reg_addr; |
| map[num_map].page.addr_type = i2c_random_wr->header.addr_type; |
| map[num_map].page.data = |
| i2c_random_wr->random_wr_payload[0].reg_data; |
| map[num_map].page.data_type = i2c_random_wr->header.data_type; |
| map[num_map].page.valid_size = 1; |
| cmd_buf += cmd_length_in_bytes / sizeof(int32_t); |
| processed_size += |
| cmd_length_in_bytes; |
| break; |
| case CAMERA_SENSOR_CMD_TYPE_I2C_CONT_RD: |
| i2c_cont_rd = (struct cam_cmd_i2c_continuous_rd *)cmd_buf; |
| cmd_length_in_bytes = sizeof(struct cam_cmd_i2c_continuous_rd); |
| |
| map[num_map].mem.addr = i2c_cont_rd->reg_addr; |
| map[num_map].mem.addr_type = i2c_cont_rd->header.addr_type; |
| map[num_map].mem.data_type = i2c_cont_rd->header.data_type; |
| map[num_map].mem.valid_size = |
| i2c_cont_rd->header.count; |
| cmd_buf += cmd_length_in_bytes / sizeof(int32_t); |
| processed_size += |
| cmd_length_in_bytes; |
| data->num_data += map[num_map].mem.valid_size; |
| break; |
| case CAMERA_SENSOR_CMD_TYPE_WAIT: |
| i2c_poll = (struct cam_cmd_conditional_wait *)cmd_buf; |
| cmd_length_in_bytes = sizeof(struct cam_cmd_conditional_wait); |
| |
| map[num_map].poll.addr = i2c_poll->reg_addr; |
| map[num_map].poll.addr_type = i2c_poll->addr_type; |
| map[num_map].poll.data = i2c_poll->reg_data; |
| map[num_map].poll.data_type = i2c_poll->data_type; |
| map[num_map].poll.delay = i2c_poll->timeout; |
| map[num_map].poll.valid_size = 1; |
| break; |
| default: |
| break; |
| } |
| *cmd_length_bytes = processed_size; |
| return rc; |
| } |
| |
| /** |
| * cam_eeprom_init_pkt_parser - Parse eeprom packet |
| * @e_ctrl: ctrl structure |
| * @csl_packet: csl packet received |
| * |
| * Returns success or failure |
| */ |
| static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl, |
| struct cam_packet *csl_packet) |
| { |
| int32_t rc = 0; |
| int i = 0; |
| struct cam_cmd_buf_desc *cmd_desc = NULL; |
| uint32_t *offset = NULL; |
| uint32_t *cmd_buf = NULL; |
| uint64_t generic_pkt_addr; |
| size_t pkt_len = 0; |
| uint32_t total_cmd_buf_in_bytes = 0; |
| uint32_t processed_cmd_buf_in_bytes = 0; |
| struct common_header *cmm_hdr = NULL; |
| uint16_t cmd_length_in_bytes = 0; |
| struct cam_cmd_i2c_info *i2c_info = NULL; |
| int num_map = -1; |
| struct cam_eeprom_memory_map_t *map = NULL; |
| struct cam_eeprom_soc_private *soc_private = |
| (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; |
| struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info; |
| |
| e_ctrl->cal_data.map = kcalloc((MSM_EEPROM_MEMORY_MAP_MAX_SIZE * |
| MSM_EEPROM_MAX_MEM_MAP_CNT), |
| (sizeof(struct cam_eeprom_memory_map_t)), GFP_KERNEL); |
| if (!e_ctrl->cal_data.map) { |
| rc = -ENOMEM; |
| CAM_ERR(CAM_EEPROM, "failed"); |
| return rc; |
| } |
| map = e_ctrl->cal_data.map; |
| |
| offset = (uint32_t *)&csl_packet->payload; |
| offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t)); |
| cmd_desc = (struct cam_cmd_buf_desc *)(offset); |
| |
| /* Loop through multiple command buffers */ |
| for (i = 0; i < csl_packet->num_cmd_buf; i++) { |
| total_cmd_buf_in_bytes = cmd_desc[i].length; |
| processed_cmd_buf_in_bytes = 0; |
| if (!total_cmd_buf_in_bytes) |
| continue; |
| rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, |
| (uint64_t *)&generic_pkt_addr, &pkt_len); |
| if (rc) { |
| CAM_ERR(CAM_EEPROM, "Failed to get cpu buf"); |
| return rc; |
| } |
| cmd_buf = (uint32_t *)generic_pkt_addr; |
| if (!cmd_buf) { |
| CAM_ERR(CAM_EEPROM, "invalid cmd buf"); |
| return -EINVAL; |
| } |
| cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); |
| /* Loop through multiple cmd formats in one cmd buffer */ |
| while (processed_cmd_buf_in_bytes < total_cmd_buf_in_bytes) { |
| cmm_hdr = (struct common_header *)cmd_buf; |
| switch (cmm_hdr->cmd_type) { |
| case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: |
| i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; |
| num_map++; |
| map[num_map].saddr = i2c_info->slave_addr; |
| rc = cam_eeprom_update_slaveInfo(e_ctrl, |
| cmd_buf); |
| cmd_length_in_bytes = |
| sizeof(struct cam_cmd_i2c_info); |
| processed_cmd_buf_in_bytes += |
| cmd_length_in_bytes; |
| cmd_buf += cmd_length_in_bytes/4; |
| e_ctrl->cal_data.num_map = num_map + 1; |
| break; |
| case CAMERA_SENSOR_CMD_TYPE_PWR_UP: |
| case CAMERA_SENSOR_CMD_TYPE_PWR_DOWN: |
| cmd_length_in_bytes = |
| sizeof(struct cam_cmd_power); |
| rc = cam_sensor_update_power_settings(cmd_buf, |
| cmd_length_in_bytes, power_info); |
| processed_cmd_buf_in_bytes += |
| total_cmd_buf_in_bytes; |
| cmd_buf += total_cmd_buf_in_bytes/4; |
| if (rc) { |
| CAM_ERR(CAM_EEPROM, "Failed"); |
| return rc; |
| } |
| break; |
| case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR: |
| case CAMERA_SENSOR_CMD_TYPE_I2C_CONT_RD: |
| case CAMERA_SENSOR_CMD_TYPE_WAIT: |
| rc = cam_eeprom_parse_memory_map( |
| &e_ctrl->cal_data, cmd_buf, |
| total_cmd_buf_in_bytes, |
| &cmd_length_in_bytes, num_map); |
| processed_cmd_buf_in_bytes += |
| cmd_length_in_bytes; |
| cmd_buf += cmd_length_in_bytes/4; |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| return rc; |
| } |
| |
| /** |
| * cam_eeprom_get_cal_data - parse the userspace IO config and |
| * copy read data to share with userspace |
| * @e_ctrl: ctrl structure |
| * @csl_packet: csl packet received |
| * |
| * Returns success or failure |
| */ |
| static int32_t cam_eeprom_get_cal_data(struct cam_eeprom_ctrl_t *e_ctrl, |
| struct cam_packet *csl_packet) |
| { |
| struct cam_buf_io_cfg *io_cfg; |
| uint32_t i = 0; |
| int rc = 0; |
| uint64_t buf_addr; |
| size_t buf_size; |
| uint8_t *read_buffer; |
| |
| io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *) |
| &csl_packet->payload + |
| csl_packet->io_configs_offset); |
| |
| CAM_DBG(CAM_EEPROM, "number of IO configs: %d:", |
| csl_packet->num_io_configs); |
| |
| for (i = 0; i < csl_packet->num_io_configs; i++) { |
| CAM_DBG(CAM_EEPROM, "Direction: %d:", io_cfg->direction); |
| if (io_cfg->direction == CAM_BUF_OUTPUT) { |
| rc = cam_mem_get_cpu_buf(io_cfg->mem_handle[0], |
| (uint64_t *)&buf_addr, &buf_size); |
| CAM_DBG(CAM_EEPROM, "buf_addr : %pK, buf_size : %zu\n", |
| (void *)buf_addr, buf_size); |
| |
| read_buffer = (uint8_t *)buf_addr; |
| if (!read_buffer) { |
| CAM_ERR(CAM_EEPROM, |
| "invalid buffer to copy data"); |
| return -EINVAL; |
| } |
| read_buffer += io_cfg->offsets[0]; |
| |
| if (buf_size < e_ctrl->cal_data.num_data) { |
| CAM_ERR(CAM_EEPROM, |
| "failed to copy, Invalid size"); |
| return -EINVAL; |
| } |
| |
| CAM_DBG(CAM_EEPROM, "copy the data, len:%d", |
| e_ctrl->cal_data.num_data); |
| memcpy(read_buffer, e_ctrl->cal_data.mapdata, |
| e_ctrl->cal_data.num_data); |
| |
| } else { |
| CAM_ERR(CAM_EEPROM, "Invalid direction"); |
| rc = -EINVAL; |
| } |
| } |
| return rc; |
| } |
| |
| /** |
| * cam_eeprom_pkt_parse - Parse csl packet |
| * @e_ctrl: ctrl structure |
| * @arg: Camera control command argument |
| * |
| * Returns success or failure |
| */ |
| static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) |
| { |
| int32_t rc = 0; |
| struct cam_control *ioctl_ctrl = NULL; |
| struct cam_config_dev_cmd dev_config; |
| uint64_t generic_pkt_addr; |
| size_t pkt_len; |
| struct cam_packet *csl_packet = NULL; |
| struct cam_eeprom_soc_private *soc_private = |
| (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; |
| |
| 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_EEPROM, |
| "error in converting command Handle Error: %d", rc); |
| return rc; |
| } |
| csl_packet = (struct cam_packet *) |
| (generic_pkt_addr + dev_config.offset); |
| switch (csl_packet->header.op_code & 0xFFFFFF) { |
| case CAM_EEPROM_PACKET_OPCODE_INIT: |
| if (e_ctrl->userspace_probe == false) { |
| rc = cam_eeprom_parse_read_memory_map( |
| e_ctrl->soc_info.dev->of_node, e_ctrl); |
| if (rc < 0) { |
| CAM_ERR(CAM_EEPROM, "Failed: rc : %d", rc); |
| return rc; |
| } |
| rc = cam_eeprom_get_cal_data(e_ctrl, csl_packet); |
| kfree(e_ctrl->cal_data.mapdata); |
| kfree(e_ctrl->cal_data.map); |
| e_ctrl->cal_data.num_data = 0; |
| e_ctrl->cal_data.num_map = 0; |
| CAM_DBG(CAM_EEPROM, |
| "Returning the data using kernel probe"); |
| break; |
| } |
| rc = cam_eeprom_init_pkt_parser(e_ctrl, csl_packet); |
| if (rc) { |
| CAM_ERR(CAM_EEPROM, |
| "Failed in parsing the pkt"); |
| return rc; |
| } |
| |
| e_ctrl->cal_data.mapdata = |
| kzalloc(e_ctrl->cal_data.num_data, GFP_KERNEL); |
| if (!e_ctrl->cal_data.mapdata) { |
| rc = -ENOMEM; |
| CAM_ERR(CAM_EEPROM, "failed"); |
| goto error; |
| } |
| |
| rc = cam_eeprom_power_up(e_ctrl, |
| &soc_private->power_info); |
| if (rc) { |
| CAM_ERR(CAM_EEPROM, "failed rc %d", rc); |
| goto memdata_free; |
| } |
| |
| rc = cam_eeprom_read_memory(e_ctrl, &e_ctrl->cal_data); |
| if (rc) { |
| CAM_ERR(CAM_EEPROM, |
| "read_eeprom_memory failed"); |
| goto power_down; |
| } |
| |
| rc = cam_eeprom_get_cal_data(e_ctrl, csl_packet); |
| rc = cam_eeprom_power_down(e_ctrl); |
| kfree(e_ctrl->cal_data.mapdata); |
| kfree(e_ctrl->cal_data.map); |
| e_ctrl->cal_data.num_data = 0; |
| e_ctrl->cal_data.num_map = 0; |
| break; |
| default: |
| break; |
| } |
| return rc; |
| power_down: |
| cam_eeprom_power_down(e_ctrl); |
| memdata_free: |
| kfree(e_ctrl->cal_data.mapdata); |
| error: |
| kfree(e_ctrl->cal_data.map); |
| e_ctrl->cal_data.num_data = 0; |
| e_ctrl->cal_data.num_map = 0; |
| return rc; |
| } |
| |
| void cam_eeprom_shutdown(struct cam_eeprom_ctrl_t *e_ctrl) |
| { |
| int rc; |
| |
| if (e_ctrl->cam_eeprom_state == CAM_EEPROM_INIT) |
| return; |
| |
| if (e_ctrl->cam_eeprom_state == CAM_EEPROM_START) { |
| rc = camera_io_release(&e_ctrl->io_master_info); |
| if (rc < 0) |
| CAM_ERR(CAM_EEPROM, "Failed in releasing CCI"); |
| rc = cam_eeprom_power_down(e_ctrl); |
| if (rc < 0) |
| CAM_ERR(CAM_EEPROM, "EEPROM Power down failed"); |
| e_ctrl->cam_eeprom_state = CAM_EEPROM_ACQUIRE; |
| } |
| |
| if (e_ctrl->cam_eeprom_state == CAM_EEPROM_ACQUIRE) { |
| rc = cam_destroy_device_hdl(e_ctrl->bridge_intf.device_hdl); |
| if (rc < 0) |
| CAM_ERR(CAM_EEPROM, "destroying the device hdl"); |
| e_ctrl->bridge_intf.device_hdl = -1; |
| e_ctrl->bridge_intf.link_hdl = -1; |
| e_ctrl->bridge_intf.session_hdl = -1; |
| } |
| |
| e_ctrl->cam_eeprom_state = CAM_EEPROM_INIT; |
| } |
| |
| /** |
| * cam_eeprom_driver_cmd - Handle eeprom cmds |
| * @e_ctrl: ctrl structure |
| * @arg: Camera control command argument |
| * |
| * Returns success or failure |
| */ |
| int32_t cam_eeprom_driver_cmd(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) |
| { |
| int rc = 0; |
| struct cam_eeprom_query_cap_t eeprom_cap = {0}; |
| struct cam_control *cmd = (struct cam_control *)arg; |
| |
| if (!e_ctrl) { |
| CAM_ERR(CAM_EEPROM, "e_ctrl is NULL"); |
| return -EINVAL; |
| } |
| |
| mutex_lock(&(e_ctrl->eeprom_mutex)); |
| switch (cmd->op_code) { |
| case CAM_QUERY_CAP: |
| eeprom_cap.slot_info = e_ctrl->soc_info.index; |
| if (e_ctrl->userspace_probe == false) |
| eeprom_cap.eeprom_kernel_probe = true; |
| else |
| eeprom_cap.eeprom_kernel_probe = false; |
| |
| if (copy_to_user((void __user *) cmd->handle, |
| &eeprom_cap, |
| sizeof(struct cam_eeprom_query_cap_t))) { |
| CAM_ERR(CAM_EEPROM, "Failed Copy to User"); |
| return -EFAULT; |
| goto release_mutex; |
| } |
| CAM_DBG(CAM_EEPROM, "eeprom_cap: ID: %d", eeprom_cap.slot_info); |
| break; |
| case CAM_ACQUIRE_DEV: |
| rc = cam_eeprom_get_dev_handle(e_ctrl, arg); |
| if (rc) { |
| CAM_ERR(CAM_EEPROM, "Failed to acquire dev"); |
| goto release_mutex; |
| } |
| e_ctrl->cam_eeprom_state = CAM_EEPROM_ACQUIRE; |
| break; |
| case CAM_RELEASE_DEV: |
| if (e_ctrl->bridge_intf.device_hdl == -1) { |
| CAM_ERR(CAM_EEPROM, |
| "Invalid Handles: link hdl: %d device hdl: %d", |
| e_ctrl->bridge_intf.device_hdl, |
| e_ctrl->bridge_intf.link_hdl); |
| rc = -EINVAL; |
| goto release_mutex; |
| } |
| rc = cam_destroy_device_hdl(e_ctrl->bridge_intf.device_hdl); |
| if (rc < 0) |
| CAM_ERR(CAM_EEPROM, |
| "failed in destroying the device hdl"); |
| e_ctrl->bridge_intf.device_hdl = -1; |
| e_ctrl->bridge_intf.link_hdl = -1; |
| e_ctrl->bridge_intf.session_hdl = -1; |
| e_ctrl->cam_eeprom_state = CAM_EEPROM_INIT; |
| break; |
| case CAM_CONFIG_DEV: |
| rc = cam_eeprom_pkt_parse(e_ctrl, arg); |
| if (rc) { |
| CAM_ERR(CAM_EEPROM, "Failed in eeprom pkt Parsing"); |
| goto release_mutex; |
| } |
| break; |
| default: |
| CAM_DBG(CAM_EEPROM, "invalid opcode"); |
| break; |
| } |
| |
| release_mutex: |
| mutex_unlock(&(e_ctrl->eeprom_mutex)); |
| |
| return rc; |
| } |
| |