diff --git a/techpack/camera/config/holicameraconf.h b/techpack/camera/config/holicameraconf.h index 958fe154c124..72c6202e0338 100644 --- a/techpack/camera/config/holicameraconf.h +++ b/techpack/camera/config/holicameraconf.h @@ -8,3 +8,4 @@ #define CONFIG_SPECTRA_OPE 1 #define CONFIG_SPECTRA_TFE 1 #define CONFIG_SPECTRA_SENSOR 1 + diff --git a/techpack/camera/drivers/Makefile b/techpack/camera/drivers/Makefile index 7a7b0250f03f..214817f9aa25 100644 --- a/techpack/camera/drivers/Makefile +++ b/techpack/camera/drivers/Makefile @@ -162,6 +162,9 @@ camera-$(CONFIG_SPECTRA_SENSOR) += \ cam_sensor_module/cam_ois/cam_ois_dev.o \ cam_sensor_module/cam_ois/cam_ois_core.o \ cam_sensor_module/cam_ois/cam_ois_soc.o \ + cam_sensor_module/cam_ois/cam_ois_dw9781.o \ + cam_sensor_module/cam_ois/cam_ois_dw9784.o \ + cam_sensor_module/cam_ois/cam_ois_aw86006.o \ cam_sensor_module/cam_sensor/cam_sensor_dev.o \ cam_sensor_module/cam_sensor/cam_sensor_core.o \ cam_sensor_module/cam_sensor/cam_sensor_soc.o \ @@ -170,8 +173,15 @@ camera-$(CONFIG_SPECTRA_SENSOR) += \ cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.o \ cam_sensor_module/cam_sensor_io/cam_sensor_spi.o \ cam_sensor_module/cam_sensor_utils/cam_sensor_util.o \ + cam_sensor_module/cam_flash_pm6125_gpio/pm6125_flash_gpio.o \ cam_sensor_module/cam_res_mgr/cam_res_mgr.o +ifneq (,$(filter $(CONFIG_AF_NOISE_ELIMINATION), y m)) +camera-$(CONFIG_SPECTRA_SENSOR) += \ + cam_sensor_module/cam_actuator/mot_actuator.o \ + cam_sensor_module/cam_actuator/mot_actuator_policy.o +endif + camera-$(CONFIG_LEDS_QPNP_FLASH_V2) += \ cam_sensor_module/cam_flash/cam_flash_dev.o \ cam_sensor_module/cam_flash/cam_flash_core.o \ diff --git a/techpack/camera/drivers/cam_core/cam_hw_mgr_intf.h b/techpack/camera/drivers/cam_core/cam_hw_mgr_intf.h index 2b56d21b20be..22864250ca67 100644 --- a/techpack/camera/drivers/cam_core/cam_hw_mgr_intf.h +++ b/techpack/camera/drivers/cam_core/cam_hw_mgr_intf.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022. Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CAM_HW_MGR_INTF_H_ @@ -26,6 +27,12 @@ /* Maximum reg dump cmd buffer entries in a context */ #define CAM_REG_DUMP_MAX_BUF_ENTRIES 10 +/* + * This value should align with MAX requests supported by + * hw modules like ICP, IFE, JPEG etc. + */ +#define CAM_MAX_FLUSH_REQS 40 + /** * enum cam_context_dump_id - * context dump type @@ -289,9 +296,9 @@ struct cam_hw_config_args { struct cam_hw_flush_args { void *ctxt_to_hw_map; uint32_t num_req_pending; - void *flush_req_pending[20]; + void *flush_req_pending[CAM_MAX_FLUSH_REQS]; uint32_t num_req_active; - void *flush_req_active[20]; + void *flush_req_active[CAM_MAX_FLUSH_REQS]; enum flush_type_t flush_type; uint32_t last_flush_req; }; diff --git a/techpack/camera/drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c b/techpack/camera/drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c index 5d385f6b9840..137f126caedf 100644 --- a/techpack/camera/drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c +++ b/techpack/camera/drivers/cam_ope/ope_hw_mgr/cam_ope_hw_mgr.c @@ -3350,7 +3350,7 @@ static int cam_ope_mgr_prepare_hw_update(void *hw_priv, prepare_args->priv = ctx_data->req_list[request_idx]; prepare_args->pf_data->packet = packet; prepare_args->pf_data->req = ope_req; - CAM_INFO(CAM_REQ, "OPE req %x num_batch %d", ope_req, ope_req->num_batch); + CAM_DBG(CAM_REQ, "OPE req %x num_batch %d", ope_req, ope_req->num_batch); ope_req->hang_data.packet = packet; ktime_get_boottime_ts64(&ts); ctx_data->last_req_time = (uint64_t)((ts.tv_sec * 1000000000) + diff --git a/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c b/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c index 6d3c7a50207b..6d325961680c 100644 --- a/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c +++ b/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_core.c @@ -11,6 +11,15 @@ #include "cam_trace.h" #include "cam_common_util.h" #include "cam_packet_util.h" +#ifdef CONFIG_AF_NOISE_ELIMINATION +#include "mot_actuator_policy.h" +#include "mot_actuator.h" +#endif + +#ifdef CONFIG_MOT_DONGWOON_OIS_AF_DRIFT +extern int cam_ois_get_init_info(void); +extern int cam_ois_write_af_drift(uint32_t dac); +#endif int32_t cam_actuator_construct_default_power_setting( struct cam_sensor_power_ctrl_t *power_info) @@ -160,8 +169,17 @@ static int32_t cam_actuator_i2c_modes_util( uint32_t i, size; if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_RANDOM) { - rc = camera_io_dev_write(io_master_info, - &(i2c_list->i2c_settings)); + // if meet cci fail, retry 5 times, each time dealy 1.5ms. + for (i = 0; i < 5; i++) { + rc = camera_io_dev_write(io_master_info, + &(i2c_list->i2c_settings)); + + if (rc >= 0) + break; + + usleep_range(1000, 1500); + } + if (rc < 0) { CAM_ERR(CAM_ACTUATOR, "Failed to random write I2C settings: %d", @@ -251,6 +269,11 @@ int32_t cam_actuator_apply_settings(struct cam_actuator_ctrl_t *a_ctrl, struct i2c_settings_list *i2c_list; int32_t rc = 0; +#ifdef CONFIG_MOT_DONGWOON_OIS_AF_DRIFT + struct cam_sensor_i2c_reg_setting * i2c_reg = NULL; + uint32_t dac = 0; +#endif + if (a_ctrl == NULL || i2c_set == NULL) { CAM_ERR(CAM_ACTUATOR, "Invalid Args"); return -EINVAL; @@ -260,7 +283,13 @@ int32_t cam_actuator_apply_settings(struct cam_actuator_ctrl_t *a_ctrl, CAM_ERR(CAM_ACTUATOR, " Invalid settings"); return -EINVAL; } - +#ifdef CONFIG_AF_NOISE_ELIMINATION + /*Usually actuator initial setting will execute power down reset(PD), actuator can't respond + CCI access for a while after PD. Add lock to avoid access actuator while PD operation.*/ + if (a_ctrl->is_multi_user_supported) { + mot_actuator_lock(); + } +#endif list_for_each_entry(i2c_list, &(i2c_set->list_head), list) { rc = cam_actuator_i2c_modes_util( @@ -274,9 +303,47 @@ int32_t cam_actuator_apply_settings(struct cam_actuator_ctrl_t *a_ctrl, CAM_DBG(CAM_ACTUATOR, "Success:request ID: %d", i2c_set->request_id); +#ifdef CONFIG_MOT_DONGWOON_OIS_AF_DRIFT + if (a_ctrl->af_drift_supported == true && + (cam_ois_get_init_info() == 1) && + i2c_list != NULL) { + + #define ADDR_ACTUATOR 0x18 + #define REG_ACTUATOR 0x00 + #define DATA_SHIFT 4 + + i2c_reg = &(i2c_list->i2c_settings); + + if (i2c_reg != NULL && + i2c_reg->reg_setting != NULL && + a_ctrl->io_master_info.cci_client != NULL && + a_ctrl->io_master_info.cci_client->sid == (ADDR_ACTUATOR >> 1) && + i2c_reg->addr_type == CAMERA_SENSOR_I2C_TYPE_BYTE && + i2c_reg->data_type == CAMERA_SENSOR_I2C_TYPE_WORD && + i2c_reg->reg_setting[0].reg_data != 0 && + i2c_reg->reg_setting[0].reg_addr == REG_ACTUATOR) + { + dac = i2c_reg->reg_setting[0].reg_data >> DATA_SHIFT; + + rc = cam_ois_write_af_drift(dac); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, "Failed to apply af drift settings: %d", rc); + rc = 0; // avoid broken actuator function + } + } + } +#endif } } +#ifdef CONFIG_AF_NOISE_ELIMINATION + /*Usually actuator initial setting will execute power down reset(PD), actuator can't respond + CCI access for a while after PD. Add lock to avoid access actuator while PD operation.*/ + if (a_ctrl->is_multi_user_supported) { + mot_actuator_unlock(); + } +#endif + return rc; } @@ -593,6 +660,15 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, cam_mem_put_cpu_buf(cmd_desc[i].mem_handle); } +#ifdef CONFIG_AF_NOISE_ELIMINATION + if (a_ctrl->cam_act_state == CAM_ACTUATOR_ACQUIRE && + a_ctrl->is_multi_user_supported == true) { + /*exile vibrator when camera want to take control of actuator*/ + mot_actuator_handle_exile(); + mot_actuator_get(ACTUATOR_CLIENT_CAMERA); + } +#endif + if (a_ctrl->cam_act_state == CAM_ACTUATOR_ACQUIRE) { rc = cam_actuator_power_up(a_ctrl); if (rc < 0) { @@ -606,6 +682,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, rc = cam_actuator_apply_settings(a_ctrl, &a_ctrl->i2c_data.init_settings); if (rc < 0) { + delete_request(&a_ctrl->i2c_data.init_settings); CAM_ERR(CAM_ACTUATOR, "Cannot apply Init settings"); goto end; } @@ -902,6 +979,11 @@ int32_t cam_actuator_driver_cmd(struct cam_actuator_ctrl_t *a_ctrl, } if (a_ctrl->cam_act_state == CAM_ACTUATOR_CONFIG) { +#ifdef CONFIG_AF_NOISE_ELIMINATION + if (a_ctrl->is_multi_user_supported == true) { + mot_actuator_put(ACTUATOR_CLIENT_CAMERA); + } +#endif rc = cam_actuator_power_down(a_ctrl); if (rc < 0) { CAM_ERR(CAM_ACTUATOR, diff --git a/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h b/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h index 1ec575301cfc..6ed2d19a97f1 100644 --- a/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h +++ b/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_dev.h @@ -115,6 +115,12 @@ struct cam_actuator_ctrl_t { struct cam_actuator_query_cap act_info; struct actuator_intf_params bridge_intf; uint32_t last_flush_req; +#ifdef CONFIG_AF_NOISE_ELIMINATION + bool is_multi_user_supported; +#endif +#ifdef CONFIG_MOT_DONGWOON_OIS_AF_DRIFT + bool af_drift_supported; +#endif }; /** diff --git a/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_soc.c b/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_soc.c index cb852423a228..f664633fd865 100644 --- a/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_soc.c +++ b/techpack/camera/drivers/cam_sensor_module/cam_actuator/cam_actuator_soc.c @@ -34,6 +34,24 @@ int32_t cam_actuator_parse_dt(struct cam_actuator_ctrl_t *a_ctrl, of_node = soc_info->dev->of_node; +#ifdef CONFIG_AF_NOISE_ELIMINATION + if (!of_property_read_bool(of_node, "multi-user-support")) { + a_ctrl->is_multi_user_supported = false; + } else { + a_ctrl->is_multi_user_supported = true; + } + CAM_DBG(CAM_ACTUATOR, "multi-user-support %d", a_ctrl->is_multi_user_supported); +#endif + +#ifdef CONFIG_MOT_DONGWOON_OIS_AF_DRIFT + if (!of_property_read_bool(of_node, "af-drift-support")) { + a_ctrl->af_drift_supported = false; + } else { + a_ctrl->af_drift_supported = true; + } + CAM_DBG(CAM_ACTUATOR, "af-drift-support %d", a_ctrl->af_drift_supported); +#endif + if (a_ctrl->io_master_info.master_type == CCI_MASTER) { rc = of_property_read_u32(of_node, "cci-master", &(a_ctrl->cci_i2c_master)); diff --git a/techpack/camera/drivers/cam_sensor_module/cam_actuator/mot_actuator.c b/techpack/camera/drivers/cam_sensor_module/cam_actuator/mot_actuator.c new file mode 100644 index 000000000000..8311d5ff639a --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_actuator/mot_actuator.c @@ -0,0 +1,1713 @@ +/* + * Copyright (C) 2020 Motorola Mobility LLC. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_debug_util.h" +#include "cam_cci_dev.h" +#include "mot_actuator.h" +#include "mot_actuator_policy.h" +#include "cam_sensor_io.h" +#include "cam_req_mgr_dev.h" +#include "linux/pm_wakeup.h" + +/*=================ACTUATOR HW INFO====================*/ +#define DEVICE_NAME_LEN 32 +#define MAX_ACTUATOR_NUM 3 +#define REGULATOR_NAME_MAX_LEN 32 +#define ANDROIDBOOT_DEVICE_MAX_LEN 32 +#define LENS_MAX_STAGES 10 + +typedef enum { + MOT_ACTUATOR_INVALID, + MOT_ACTUATOR_FIRST, + MOT_ACTUATOR_GT9767 = MOT_ACTUATOR_FIRST, + MOT_ACTUATOR_GT9764, + MOT_ACTUATOR_GT9772, + MOT_ACTUATOR_DW9714, + MOT_ACTUATOR_DW9800V, + MOT_ACTUATOR_NUM, +} mot_actuator_type; + +typedef enum { + REGULATOR_IOVDD, + REGULATOR_AFVDD, + REGULATOR_NUM, +} mot_regulator_type; + +typedef enum { + MOT_DEVICE_NIO, + MOT_DEVICE_BERLNA, + MOT_DEVICE_BERLIN, + MOT_DEVICE_CYPFG, + MOT_DEVICE_CYPFQ, + MOT_DEVICE_CYPFR, + MOT_DEVICE_CORFUP, + MOT_DEVICE_CORFUQ, + MOT_DEVICE_CORFUR, + MOT_DEVICE_RHODEC, + MOT_DEVICE_RHODEI, + MOT_DEVICE_PENANG, + MOT_DEVICE_FOGOS, + MOT_DEVICE_NUM, +} mot_dev_type; + +typedef struct { + uint16_t kneePoint; + uint16_t step; +} mot_park_lens_step; + +typedef struct { + uint16_t kneePoint; + uint16_t step; +} mot_reset_lens_step; + +typedef struct { + uint16_t kneePoint; + uint16_t step; +} mot_launch_lens_step; + +typedef struct { + struct cam_sensor_i2c_reg_setting *init_setting; + struct cam_sensor_i2c_reg_setting *dac_setting; +} mot_actuator_settings; +typedef struct { + bool launch_lens_needed; + mot_launch_lens_step launch_lens_step[LENS_MAX_STAGES]; +} mot_launch_lens; + +typedef struct { + mot_actuator_type actuator_type; + uint16_t dac_pos; + uint16_t init_pos; + uint16_t cci_addr; + uint16_t cci_dev; + uint16_t cci_master; + char *regulator_list[REGULATOR_NUM]; + uint32_t regulator_volt_uv[REGULATOR_NUM]; + bool park_lens_needed; + bool reset_lens_needed; + mot_launch_lens launch_lens; + bool pmic_load_needed; + uint32_t regulator_load_ua[REGULATOR_NUM]; +} mot_actuator_hw_info; + +typedef struct { + mot_dev_type dev_type; + uint16_t actuator_num; + char dev_name[DEVICE_NAME_LEN]; + mot_actuator_hw_info actuator_info[MAX_ACTUATOR_NUM]; +} mot_dev_info; + +/*Register settings of GT9767*/ +static struct cam_sensor_i2c_reg_array mot_gt9767_init_setting[] ={ + {0x02, 0x00, 300}, + {0x06, 0x0A, 0}, + {0x07, 0x01, 0}, + {0x08, 0x43, 0}, +}; + +static struct cam_sensor_i2c_reg_array mot_gt9767_dac_setting[] ={ + {0x03, 0x3ff, 0} +}; + +static struct cam_sensor_i2c_reg_setting mot_gt9767_init_settings = { + .reg_setting = mot_gt9767_init_setting, + .size = ARRAY_SIZE(mot_gt9767_init_setting), + .addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, +}; + +static struct cam_sensor_i2c_reg_setting mot_gt9767_dac_settings = { + .reg_setting = mot_gt9767_dac_setting, + .size = ARRAY_SIZE(mot_gt9767_dac_setting), + .addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .data_type = CAMERA_SENSOR_I2C_TYPE_WORD, +}; + +/*Register settings of GT9764*/ +static struct cam_sensor_i2c_reg_array mot_gt9764_init_setting[] ={ + {0x02, 0x00, 1000}, + {0x02, 0x02, 0}, + {0x06, 0x80, 0}, + {0x07, 0x62, 0}, +}; + +static struct cam_sensor_i2c_reg_array mot_gt9764_dac_setting[] ={ + {0x03, 0x3ff, 0} +}; +static struct cam_sensor_i2c_reg_setting mot_gt9764_init_settings = { + .reg_setting = mot_gt9764_init_setting, + .size = ARRAY_SIZE(mot_gt9764_init_setting), + .addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, +}; + +static struct cam_sensor_i2c_reg_setting mot_gt9764_dac_settings = { + .reg_setting = mot_gt9764_dac_setting, + .size = ARRAY_SIZE(mot_gt9764_dac_setting), + .addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .data_type = CAMERA_SENSOR_I2C_TYPE_WORD, +}; + +/*Register settings of GT9772*/ +static struct cam_sensor_i2c_reg_array mot_gt9772_init_setting[] ={ + {0xED, 0xAB, 0}, + {0x02, 0x01, 0}, + {0x02, 0x00, 300}, + {0x06, 0x84, 0}, + {0x07, 0x01, 0}, + {0x08, 0x62, 0}, +}; + +static struct cam_sensor_i2c_reg_array mot_gt9772_dac_setting[] ={ + {0x03, 0x3ff, 0} +}; + +static struct cam_sensor_i2c_reg_setting mot_gt9772_init_settings = { + .reg_setting = mot_gt9772_init_setting, + .size = ARRAY_SIZE(mot_gt9772_init_setting), + .addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, +}; + +static struct cam_sensor_i2c_reg_setting mot_gt9772_dac_settings = { + .reg_setting = mot_gt9772_dac_setting, + .size = ARRAY_SIZE(mot_gt9772_dac_setting), + .addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .data_type = CAMERA_SENSOR_I2C_TYPE_WORD, +}; + +/*Register settings of DW9714*/ +static struct cam_sensor_i2c_reg_array mot_dw9714_init_setting[] ={ + {0xED, 0xAB, 0}, + {0x02, 0x01, 0}, + {0x02, 0x00, 1000}, + {0x06, 0x84, 0}, + {0x07, 0x01, 0}, + {0x08, 0x78, 0}, +}; + +static struct cam_sensor_i2c_reg_array mot_dw9714_dac_setting[] ={ + {0x03, 0x3ff, 0} +}; + +static struct cam_sensor_i2c_reg_setting mot_dw9714_init_settings = { + .reg_setting = mot_dw9714_init_setting, + .size = ARRAY_SIZE(mot_dw9714_init_setting), + .addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, +}; + +static struct cam_sensor_i2c_reg_setting mot_dw9714_dac_settings = { + .reg_setting = mot_dw9714_dac_setting, + .size = ARRAY_SIZE(mot_dw9714_dac_setting), + .addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .data_type = CAMERA_SENSOR_I2C_TYPE_WORD, +}; + +/*Register settings of DW9800V*/ +static struct cam_sensor_i2c_reg_array mot_dw9800v_init_setting[] ={ + {0x02, 0x02, 300}, + {0x06, 0x80, 0}, + {0x07, 0x62, 0}, +}; + +static struct cam_sensor_i2c_reg_array mot_dw9800v_dac_setting[] ={ + {0x03, 0x3ff, 0} +}; + +static struct cam_sensor_i2c_reg_setting mot_dw9800v_init_settings = { + .reg_setting = mot_dw9800v_init_setting, + .size = ARRAY_SIZE(mot_dw9800v_init_setting), + .addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, +}; + +static struct cam_sensor_i2c_reg_setting mot_dw9800v_dac_settings = { + .reg_setting = mot_dw9800v_dac_setting, + .size = ARRAY_SIZE(mot_dw9800v_dac_setting), + .addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .data_type = CAMERA_SENSOR_I2C_TYPE_WORD, +}; + +/*Register settings of all supported actuator types*/ +static mot_actuator_settings mot_actuator_list[MOT_ACTUATOR_NUM-1] = { + //MUST be sorted as definition order in above structure: mot_actuator_type + {&mot_gt9767_init_settings, &mot_gt9767_dac_settings}, + {&mot_gt9764_init_settings, &mot_gt9764_dac_settings}, + {&mot_gt9772_init_settings, &mot_gt9772_dac_settings}, + {&mot_dw9714_init_settings, &mot_dw9714_dac_settings}, + {&mot_dw9800v_init_settings, &mot_dw9800v_dac_settings}, +}; + +static const mot_dev_info mot_dev_list[MOT_DEVICE_NUM] = { + { + .dev_type = MOT_DEVICE_NIO, + .actuator_num = 1, + .dev_name = "nio", + .actuator_info = { + [0] = { + .actuator_type = MOT_ACTUATOR_GT9772, + .dac_pos = 400, + .cci_addr = 0x0c, + .cci_dev = 0x01, + .cci_master = 0x0, + .regulator_list = {"ldo7", "ldo5"}, + .regulator_volt_uv = {1800000, 2800000}, + .park_lens_needed = true, + }, + }, + }, + { + .dev_type = MOT_DEVICE_BERLNA, + .actuator_num = 1, + .dev_name = "berlna", + .actuator_info = { + [0] = { + .actuator_type = MOT_ACTUATOR_DW9714, + .dac_pos = 480, + .cci_addr = 0x0c, + .cci_dev = 0x01, + .cci_master = 0x01, + .regulator_list = {"ldo7", "ldo5"}, + .regulator_volt_uv = {1800000, 2800000}, + .park_lens_needed = true, + }, + }, + }, + { + .dev_type = MOT_DEVICE_BERLIN, + .actuator_num = 1, + .dev_name = "berlin", + .actuator_info = { + [0] = { + .actuator_type = MOT_ACTUATOR_GT9772, + .dac_pos = 900, + .cci_addr = 0x0c, + .cci_dev = 0x01, + .cci_master = 0x1, + .regulator_list = {"ldo7", "ldo5"}, + .regulator_volt_uv = {1800000, 2800000}, + .park_lens_needed = true, + .reset_lens_needed = true, + .launch_lens = { + .launch_lens_needed = true, + .launch_lens_step = { + {300, 300}, + {700, 100}, + {820, 60}, + {900, 40}, + }, + }, + }, + }, + }, + { + .dev_type = MOT_DEVICE_CYPFG, + .actuator_num = 1, + .dev_name = "cypfg", + .actuator_info = { + [0] = { + .actuator_type = MOT_ACTUATOR_DW9800V, + .dac_pos = 0, + .init_pos = 512, + .cci_addr = 0x0c, + .cci_dev = 0x00, + .cci_master = 0x0, + .regulator_list = {"ldo7", "ldo5"}, + .regulator_volt_uv = {1800000, 2800000}, + .launch_lens = { + .launch_lens_needed = true, + .launch_lens_step = { + {200, 100}, + {100, 60}, + {50, 30}, + }, + }, + }, + }, + }, + + { + .dev_type = MOT_DEVICE_CYPFQ, + .actuator_num = 1, + .dev_name = "cypfq", + .actuator_info = { + [0] = { + .actuator_type = MOT_ACTUATOR_DW9800V, + .dac_pos = 0, + .init_pos = 512, + .cci_addr = 0x0c, + .cci_dev = 0x00, + .cci_master = 0x0, + .regulator_list = {"ldo7", "ldo5"}, + .regulator_volt_uv = {1800000, 2800000}, + .launch_lens = { + .launch_lens_needed = true, + .launch_lens_step = { + {200, 100}, + {100, 60}, + {50, 30}, + }, + }, + }, + }, + }, + + { + .dev_type = MOT_DEVICE_CYPFR, + .actuator_num = 1, + .dev_name = "cypfr", + .actuator_info = { + [0] = { + .actuator_type = MOT_ACTUATOR_DW9800V, + .dac_pos = 0, + .init_pos = 512, + .cci_addr = 0x0c, + .cci_dev = 0x00, + .cci_master = 0x0, + .regulator_list = {"ldo7", "ldo5"}, + .regulator_volt_uv = {1800000, 2800000}, + .launch_lens = { + .launch_lens_needed = true, + .launch_lens_step = { + {200, 100}, + {100, 60}, + {50, 30}, + }, + }, + }, + }, + }, + + { + .dev_type = MOT_DEVICE_CORFUP, + .actuator_num = 1, + .dev_name = "corfup", + .actuator_info = { + [0] = { + .actuator_type = MOT_ACTUATOR_DW9800V, + .dac_pos = 0, + .init_pos = 512, + .cci_addr = 0x0c, + .cci_dev = 0x00, + .cci_master = 0x1, + .regulator_list = {"ldo7", "ldo5"}, + .regulator_volt_uv = {1800000, 2800000}, + .launch_lens = { + .launch_lens_needed = true, + .launch_lens_step = { + {200, 100}, + {100, 60}, + {50, 30}, + }, + }, + }, + }, + }, + + { + .dev_type = MOT_DEVICE_CORFUQ, + .actuator_num = 1, + .dev_name = "corfuq", + .actuator_info = { + [0] = { + .actuator_type = MOT_ACTUATOR_DW9800V, + .dac_pos = 0, + .init_pos = 512, + .cci_addr = 0x0c, + .cci_dev = 0x00, + .cci_master = 0x1, + .regulator_list = {"ldo7", "ldo5"}, + .regulator_volt_uv = {1800000, 2800000}, + .launch_lens = { + .launch_lens_needed = true, + .launch_lens_step = { + {200, 100}, + {100, 60}, + {50, 30}, + }, + }, + }, + }, + }, + + { + .dev_type = MOT_DEVICE_CORFUR, + .actuator_num = 1, + .dev_name = "corfur", + .actuator_info = { + [0] = { + .actuator_type = MOT_ACTUATOR_DW9800V, + .dac_pos = 0, + .init_pos = 512, + .cci_addr = 0x0c, + .cci_dev = 0x00, + .cci_master = 0x1, + .regulator_list = {"ldo7", "ldo5"}, + .regulator_volt_uv = {1800000, 2800000}, + .launch_lens = { + .launch_lens_needed = true, + .launch_lens_step = { + {200, 100}, + {100, 60}, + {50, 30}, + }, + }, + }, + }, + }, + + { + .dev_type = MOT_DEVICE_RHODEC, + .actuator_num = 1, + .dev_name = "rhodec", + .actuator_info = { + [0] = { + .actuator_type = MOT_ACTUATOR_DW9800V, + .dac_pos = 0, + .init_pos = 512, + .cci_addr = 0x0c, + .cci_dev = 0x00, + .cci_master = 0x1, + .regulator_list = {"pm6125_l9", "cam_rear_af"}, + .regulator_volt_uv = {1800000, 2800000}, + .launch_lens = { + .launch_lens_needed = true, + .launch_lens_step = { + {200, 100}, + {100, 60}, + {50, 30}, + }, + }, + }, + }, + }, + + { + .dev_type = MOT_DEVICE_RHODEI, + .actuator_num = 1, + .dev_name = "rhodei", + .actuator_info = { + [0] = { + .actuator_type = MOT_ACTUATOR_DW9800V, + .dac_pos = 0, + .init_pos = 512, + .cci_addr = 0x0c, + .cci_dev = 0x00, + .cci_master = 0x1, + .regulator_list = {"pm6125_l9", "cam_rear_af"}, + .regulator_volt_uv = {1800000, 2800000}, + .launch_lens = { + .launch_lens_needed = true, + .launch_lens_step = { + {200, 100}, + {100, 60}, + {50, 30}, + }, + }, + }, + }, + }, + + { + .dev_type = MOT_DEVICE_PENANG, + .actuator_num = 1, + .dev_name = "penang", + .actuator_info = { + [0] = { + .actuator_type = MOT_ACTUATOR_DW9800V, + .dac_pos = 0, + .init_pos = 512, + .cci_addr = 0x0c, + .cci_dev = 0x00, + .cci_master = 0x1, + .regulator_list = {"camera_ldo_dovdd", "pm6125_l21"}, + .regulator_volt_uv = {1800000, 2800000}, + .launch_lens = { + .launch_lens_needed = true, + .launch_lens_step = { + {200, 100}, + {100, 60}, + {50, 30}, + }, + }, + .pmic_load_needed = true, + .regulator_load_ua = {120000, 120000}, + }, + }, + }, + + { + .dev_type = MOT_DEVICE_FOGOS, + .actuator_num = 1, + .dev_name = "fogos", + .actuator_info = { + [0] = { + .actuator_type = MOT_ACTUATOR_GT9764, + .dac_pos = 0, + .init_pos = 512, + .cci_addr = 0x0c, + .cci_dev = 0x00, + .cci_master = 0x0, + .regulator_list = {"pm6125_l13", "camera_ldo_50m_afvdd"}, + .regulator_volt_uv = {1800000, 2800000}, + .launch_lens = { + .launch_lens_needed = true, + .launch_lens_step = { + {200, 100}, + {100, 60}, + {50, 30}, + }, + }, + .pmic_load_needed = true, + .regulator_load_ua = {120000, 120000}, + }, + }, + }, + +}; + +static uint32_t mot_device_index = MOT_DEVICE_NUM; + +static char *bootargs_str; +static char androidboot_device[ANDROIDBOOT_DEVICE_MAX_LEN]; +int mot_actuator_get_bootarg(char *key, char **value) +{ + const char *bootargs_tmp = NULL; + char *idx = NULL; + char *kvpair = NULL; + int err = 1; + struct device_node *n = of_find_node_by_path("/chosen"); + size_t bootargs_tmp_len = 0; + + if (n == NULL) + goto err; + + if (of_property_read_string(n, "bootargs", &bootargs_tmp) != 0) + goto putnode; + + bootargs_tmp_len = strlen(bootargs_tmp); + if (!bootargs_str) { + /* The following operations need a non-const + * version of bootargs + */ + bootargs_str = kzalloc(bootargs_tmp_len + 1, GFP_KERNEL); + if (!bootargs_str) + goto putnode; + } + strlcpy(bootargs_str, bootargs_tmp, bootargs_tmp_len + 1); + + idx = strnstr(bootargs_str, key, strlen(bootargs_str)); + if (idx) { + kvpair = strsep(&idx, " "); + if (kvpair) + if (strsep(&kvpair, "=")) { + *value = strsep(&kvpair, " "); + if (*value) + err = 0; + } + } + +putnode: + of_node_put(n); +err: + return err; +} + +static int cam_select_actuator_by_device_name(void) +{ + char *str; + uint32_t i; + if (mot_actuator_get_bootarg("androidboot.device=", &str) == 0) + strlcpy(androidboot_device, str, ANDROIDBOOT_DEVICE_MAX_LEN); + + for (i=0; i= MOT_DEVICE_NUM) { + CAM_ERR(CAM_ACTUATOR, "UNKNOWN DEVICE:%s", str); + } + return 1; +} + +/*=================ACTUATOR RUNTIME====================*/ +#define VIBRATING_MAX_INTERVAL 2000//ms +#define PARK_LENS_MAX_STAGES 10 +#define RESET_LENS_MAX_STAGES 10 +#define LAUNCH_LENS_MAX_STAGES LENS_MAX_STAGES + +struct mot_actuator_ctrl_t { + struct cam_subdev v4l2_dev_str; + struct platform_device *pdev; + char device_name[20]; + struct workqueue_struct *mot_actuator_wq; + struct delayed_work delay_work; + struct mutex actuator_lock; + struct wakeup_source actuator_wakelock; +}; + +enum mot_actuator_state_e { + MOT_ACTUATOR_IDLE, + MOT_ACTUATOR_INITED, + MOT_ACTUATOR_STARTED, + MOT_ACTUATOR_RELEASED +}; + +typedef struct { + struct cam_sensor_cci_client client; + struct camera_io_master io_master; + struct regulator * regulators[REGULATOR_NUM]; + uint32_t safe_dac_pos; +} mot_actuator_runtime_type; + +static struct mot_actuator_ctrl_t mot_actuator_fctrl; +static enum mot_actuator_state_e mot_actuator_state = MOT_ACTUATOR_IDLE; +static mot_actuator_runtime_type mot_actuator_runtime[MAX_ACTUATOR_NUM]; +static uint32_t lens_safe_pos_dac = 0; +static uint32_t lens_park_pos = 100; +static mot_park_lens_step lens_park_table[PARK_LENS_MAX_STAGES] = { + {300, 60}, + {200, 40}, +}; +static mot_reset_lens_step lens_reset_table[RESET_LENS_MAX_STAGES] = { + {400, 0}, + {100, 100}, +}; + +static bool runtime_inited = 0; + +static int mot_actuator_init_runtime(void) +{ + int i; + int regIdx; + + if (runtime_inited == true) { + CAM_DBG(CAM_ACTUATOR, "Runtime has been inited!!!"); + return 0; + } + + if (mot_device_index >= MOT_DEVICE_NUM) { + CAM_ERR(CAM_ACTUATOR, "INVALID DEVICE!!!"); + return -1; + } + + for (i = 0; i < mot_dev_list[mot_device_index].actuator_num; i++) { + if (mot_dev_list[mot_device_index].actuator_info[i].actuator_type == MOT_ACTUATOR_INVALID) { + CAM_DBG(CAM_ACTUATOR, "NO. %d actuator type is %d", + i, mot_dev_list[mot_device_index].actuator_info[i].actuator_type); + continue; + } + + /*Init actuators' CCI data*/ + mot_actuator_runtime[i].io_master.master_type = CCI_MASTER; + mot_actuator_runtime[i].io_master.cci_client = &mot_actuator_runtime[i].client; + mot_actuator_runtime[i].client.sid = mot_dev_list[mot_device_index].actuator_info[i].cci_addr; + mot_actuator_runtime[i].client.cci_device = mot_dev_list[mot_device_index].actuator_info[i].cci_dev; + mot_actuator_runtime[i].client.cci_i2c_master = mot_dev_list[mot_device_index].actuator_info[i].cci_master; + CAM_DBG(CAM_ACTUATOR, "NO. %d ACTUATOR sid:%x, cci_device:%d, cci_i2c_master:%d", + i, mot_actuator_runtime[i].client.sid, mot_actuator_runtime[i].client.cci_device, + mot_actuator_runtime[i].client.cci_i2c_master); + + /*Init actuators' DAC pos*/ + if (lens_safe_pos_dac != 0) { + mot_actuator_runtime[i].safe_dac_pos = lens_safe_pos_dac; + } else { + mot_actuator_runtime[i].safe_dac_pos = mot_dev_list[mot_device_index].actuator_info[i].dac_pos; + } + CAM_DBG(CAM_ACTUATOR, "ACTUATOR NO. %d, DAC pos: %d", i, mot_actuator_runtime[i].safe_dac_pos); + + /*Init actuators' regulators*/ + for (regIdx = 0; regIdx < REGULATOR_NUM; regIdx++) { + char *reg_name = mot_dev_list[mot_device_index].actuator_info[i].regulator_list[regIdx]; + if (reg_name[0] != '\0' && mot_actuator_runtime[i].regulators[regIdx] == NULL) { + mot_actuator_runtime[i].regulators[regIdx] = regulator_get(&mot_actuator_fctrl.v4l2_dev_str.pdev->dev, reg_name); + if (mot_actuator_runtime[i].regulators[regIdx] == NULL) { + CAM_DBG(CAM_ACTUATOR, "REGULATOR NO. %d of actuator %d IS NULL!", regIdx, i); + } else { + CAM_DBG(CAM_ACTUATOR, "REGULATOR GET SUCCESS:%p", mot_actuator_runtime[i].regulators[regIdx]); + regulator_set_voltage(mot_actuator_runtime[i].regulators[regIdx], + mot_dev_list[mot_device_index].actuator_info[i].regulator_volt_uv[regIdx], + mot_dev_list[mot_device_index].actuator_info[i].regulator_volt_uv[regIdx]); + /*change current to 120ma avoid current exceeds pmic linit just for penang*/ + if(mot_dev_list[mot_device_index].actuator_info[i].pmic_load_needed == true){ + regulator_set_load(mot_actuator_runtime[i].regulators[regIdx], + mot_dev_list[mot_device_index].actuator_info[i].regulator_load_ua[regIdx]); + CAM_WARN(CAM_ACTUATOR, "REGULATOR use custom load %d !", + mot_dev_list[mot_device_index].actuator_info[i].regulator_load_ua[regIdx]); + } + else{ + CAM_DBG(CAM_ACTUATOR, "REGULATOR Use default load !"); + } + } + } + } + } + + runtime_inited = true; + + return 0; +} + +static int32_t mot_actuator_apply_settings(struct camera_io_master *io_master_info, + struct cam_sensor_i2c_reg_setting *write_setting) +{ + /*Usually actuator initial setting will execute power down reset(PD), actuator can't respond + CCI access for a while after PD. Add lock to avoid access actuator while PD operation.*/ + int32_t ret = 0; + mot_actuator_lock(); + ret = camera_io_dev_write(io_master_info, write_setting); + mot_actuator_unlock(); + return ret; +} + +static struct cam_sensor_i2c_reg_setting *mot_actuator_get_init_settings(uint32_t index) +{ + uint32_t actuator_index = mot_dev_list[mot_device_index].actuator_info[index].actuator_type - MOT_ACTUATOR_FIRST; + return mot_actuator_list[actuator_index].init_setting; +} + +static struct cam_sensor_i2c_reg_setting *mot_actuator_get_dac_settings(uint32_t index) +{ + uint32_t actuator_index = mot_dev_list[mot_device_index].actuator_info[index].actuator_type - MOT_ACTUATOR_FIRST; + return mot_actuator_list[actuator_index].dac_setting; +} + +static int32_t mot_actuator_move_lens_by_dac(uint32_t index, uint32_t dac_value) +{ + struct cam_sensor_i2c_reg_setting *dac_setting = mot_actuator_get_dac_settings(index); + /*Fill the DAC value*/ + dac_setting->reg_setting[0].reg_data = dac_value; + CAM_DBG(CAM_ACTUATOR, "move lens to DAC pos: %d", dac_value); + return mot_actuator_apply_settings(&mot_actuator_runtime[index].io_master, dac_setting); +} + +static int32_t mot_actuator_power_on(uint32_t index) +{ + int i; + int ret = 0; + + for (i = 0; i < REGULATOR_NUM; i++) { + if (mot_actuator_runtime[index].regulators[i] != NULL) { + ret = regulator_enable(mot_actuator_runtime[index].regulators[i]); + if(ret){ + CAM_ERR(CAM_ACTUATOR, "power on regulators[%d] failed, ret:%d", i,ret); + } + } + } + + return ret; +} + +static int32_t mot_actuator_power_off(uint32_t index) +{ + int i; + int ret = 0; + + for (i = 0; i < REGULATOR_NUM; i++) { + if (mot_actuator_runtime[index].regulators[i] != NULL) { + ret = regulator_disable(mot_actuator_runtime[index].regulators[i]); + CAM_DBG(CAM_ACTUATOR, "power off ret %d", ret); + } + } + + return ret; +} + +int32_t mot_actuator_init_cci(uint32_t index) +{ + int32_t ret = 0,rc = 0; + + CAM_DBG(CAM_ACTUATOR, "init cci."); + ret = camera_io_init(&mot_actuator_runtime[index].io_master); + if (ret != 0) { + rc = camera_io_release(&mot_actuator_runtime[index].io_master); + CAM_ERR(CAM_ACTUATOR, "init cci failed!!! ret=%d,release rc=%d. try again!", ret, rc); + /*delay 100ms and try again*/ + usleep_range(100000, 100100); + ret = camera_io_init(&mot_actuator_runtime[index].io_master); + if (ret != 0) { + rc = camera_io_release(&mot_actuator_runtime[index].io_master); + CAM_ERR(CAM_ACTUATOR, "try again init cci failed!!! ret=%d, release rc=%d", ret, rc); + } + } + return ret; +} + +int32_t mot_actuator_release_cci(uint32_t index) +{ + int32_t ret = 0; + + CAM_DBG(CAM_ACTUATOR, "release cci."); + ret = camera_io_release(&mot_actuator_runtime[index].io_master); + if (ret != 0) { + CAM_ERR(CAM_ACTUATOR, "release cci failed, ret=%d!!!", ret); + } + return ret; +} + +static int32_t mot_actuator_launch_lens(uint32_t index, uint32_t dac_value) +{ + uint32_t init_len_pos = mot_dev_list[mot_device_index].actuator_info[0].init_pos; + uint32_t cur_len_pos = init_len_pos; + uint32_t last_len_pos = 0; + int stageIndex; + unsigned int consumers = 0; + int32_t ret = 0; + uint32_t lens_launch_pos = dac_value; + mot_launch_lens_step const *lens_launch_table = mot_dev_list[mot_device_index].actuator_info[index].launch_lens.launch_lens_step; + + if (mot_dev_list[mot_device_index].actuator_info[index].launch_lens.launch_lens_needed == false) { + CAM_DBG(CAM_ACTUATOR, "Launch lens is not needed."); + return 0; + } + + // from 0 to safe_dac_pos + while (cur_len_pos < lens_launch_pos) { + consumers = mot_actuator_get_consumers(); + if ((consumers & (~CLINET_VIBRATOR_MASK)) != 0) { + CAM_WARN(CAM_ACTUATOR, "Launch lens was broken by other actuator requests."); + break; + } + + for (stageIndex=0; stageIndex 0) { + cur_len_pos += lens_launch_table[stageIndex].step; + break; + } + } + + if (stageIndex == LAUNCH_LENS_MAX_STAGES && cur_len_pos < lens_launch_pos) { + cur_len_pos += 10; + } + + if(last_len_pos == cur_len_pos) + /*break the cycle when cur_len_pos didn't update*/ + break; + else + last_len_pos = cur_len_pos; + + ret = mot_actuator_move_lens_by_dac(index, cur_len_pos); + + if (ret < 0 ) { + CAM_ERR(CAM_ACTUATOR, "Launch Lens encounter CCI error, break now."); + break; + } + + if (cur_len_pos >= lens_launch_pos) { + /*For skipping the last delay*/ + CAM_WARN(CAM_ACTUATOR, "Launch lens done."); + break; + } + + usleep_range(10000, 12000); + } + + // from 512 to 0 + while ((cur_len_pos > lens_launch_pos) && init_len_pos) { + consumers = mot_actuator_get_consumers(); + if ((consumers & (~CLINET_VIBRATOR_MASK)) != 0) { + CAM_WARN(CAM_ACTUATOR, "Launch lens was broken by other actuator requests."); + break; + } + + for (stageIndex = 0; stageIndex < LENS_MAX_STAGES; stageIndex++) { + if (lens_launch_table[stageIndex].kneePoint == 0 && lens_launch_table[stageIndex].step == 0) { + break; + } + + if (cur_len_pos >= lens_launch_table[stageIndex].kneePoint && lens_launch_table[stageIndex].step > 0) { + cur_len_pos -= lens_launch_table[stageIndex].step; + break; + } + } + + if (lens_launch_table[stageIndex].step == 0 && cur_len_pos > lens_launch_pos) { + cur_len_pos -= 10; + if (cur_len_pos < 10) + cur_len_pos = 0; + } + + ret = mot_actuator_move_lens_by_dac(index, cur_len_pos); + + if (ret < 0 ) { + CAM_ERR(CAM_ACTUATOR, "Launch Lens encounter CCI error, break now."); + break; + } + + if (cur_len_pos <= lens_launch_pos) { + /*For skipping the last delay*/ + CAM_DBG(CAM_ACTUATOR, "Launch lens done."); + break; + } + + usleep_range(10000, 12000); + } + + return ret; +} + +static int32_t mot_actuator_vib_move_lens(uint32_t index) +{ + int32_t ret = 0; + unsigned int consumers = 0; + + if (mot_device_index >= MOT_DEVICE_NUM || index > mot_dev_list[mot_device_index].actuator_num) { + CAM_ERR(CAM_ACTUATOR, "INVALID device!!!"); + return -1; + } + + consumers = mot_actuator_get_consumers(); + CAM_DBG(CAM_ACTUATOR, "consumers=%d",consumers); + if (consumers & CLINET_CAMERA_MASK) { + /*Don't init actuator when camera on*/ + CAM_WARN(CAM_ACTUATOR, "Camera is holding actuator,don't init actuator for vibrator,consumers=%d",consumers); + } else if (mot_actuator_state <= MOT_ACTUATOR_IDLE || mot_actuator_state >= MOT_ACTUATOR_RELEASED) { + mot_actuator_init_runtime(); + mot_actuator_power_on(index); + ret = mot_actuator_init_cci(index); + if (ret == 0) { + ret = mot_actuator_apply_settings(&mot_actuator_runtime[index].io_master, mot_actuator_get_init_settings(index)); + if (ret == 0) { + CAM_WARN(CAM_ACTUATOR, "init acutator sucess", ret); + mot_actuator_state = MOT_ACTUATOR_INITED; + } else { + mot_actuator_release_cci(index); + CAM_ERR(CAM_ACTUATOR, "init acutator failed, ret=%d!!!", ret); + } + } else { + CAM_ERR(CAM_ACTUATOR, "init cci device failed, ret=%d!!!", ret); + } + + if (ret != 0) { + CAM_ERR(CAM_ACTUATOR, "init actuator encountered error, power off now. ret=%d", ret); + mot_actuator_power_off(index); + } + } + + if (ret == 0 && mot_actuator_state == MOT_ACTUATOR_INITED) { + /*Move lens to the specified position.*/ + CAM_WARN(CAM_ACTUATOR, "actuator consumers: %d", consumers); + + if ((consumers & CLINET_VIBRATOR_MASK) == 0) { + mot_actuator_get(ACTUATOR_CLIENT_VIBRATOR); + } + + if (consumers == 0) { + /*Just move lens when camera off and before first vibrating*/ + /*use launch_lens to move lens step-by-step,reduce TICK noise*/ + if (mot_dev_list[mot_device_index].actuator_info[index].launch_lens.launch_lens_needed == true) { + ret = mot_actuator_launch_lens(index, mot_actuator_runtime[index].safe_dac_pos); + }else { + ret = mot_actuator_move_lens_by_dac(index, mot_actuator_runtime[index].safe_dac_pos); + /*delay 10~12ms to wait lens move to specify location*/ + usleep_range(10000, 12000); + } + if (ret == 0) { + CAM_WARN(CAM_ACTUATOR, "actuator is safe now, safe_dac_pos:%d, please start vibrating.", + mot_actuator_runtime[index].safe_dac_pos); + } else { + CAM_ERR(CAM_ACTUATOR, "write dac failed, ret=%d!!!", ret); + } + } else { + CAM_WARN(CAM_ACTUATOR, "actuator is already in position."); + } + + mot_actuator_state = MOT_ACTUATOR_STARTED; + } else { + CAM_WARN(CAM_ACTUATOR, "May be already in position. state: %d ret=%d.", mot_actuator_state, ret); + } + + return ret; +} + +static int32_t mot_actuator_park_lens(uint32_t index) +{ + uint32_t cur_len_pos = mot_actuator_runtime[index].safe_dac_pos; + int stageIndex; + unsigned int consumers = 0; + int32_t ret = 0; + + if (mot_dev_list[mot_device_index].actuator_info[index].park_lens_needed == false) { + CAM_DBG(CAM_ACTUATOR, "Park lens is not needed."); + return 0; + } + + while (cur_len_pos > lens_park_pos) { + consumers = mot_actuator_get_consumers(); + if ((consumers & (~CLINET_VIBRATOR_MASK)) != 0) { + CAM_WARN(CAM_ACTUATOR, "Park lens was broken by other actuator requests."); + break; + } + + for (stageIndex=0; stageIndex= lens_park_table[stageIndex].kneePoint && lens_park_table[stageIndex].step > 0) { + cur_len_pos -= lens_park_table[stageIndex].step; + break; + } + } + + if (lens_park_table[stageIndex].step <= 0 && cur_len_pos > lens_park_pos) { + cur_len_pos -= 10; + } + + ret = mot_actuator_move_lens_by_dac(index, cur_len_pos); + + if (ret < 0 ) { + CAM_ERR(CAM_ACTUATOR, "Park Lens encounter CCI error, break now."); + break; + } + + if (cur_len_pos <= lens_park_pos) { + /*For skipping the last delay*/ + CAM_DBG(CAM_ACTUATOR, "Park lens done."); + break; + } + + usleep_range(10000, 12000); + } + + return 0; +} + +int mot_actuator_on_vibrate_start(void) +{ + bool is_exiting = false; + ktime_t start,end,duration; + start = ktime_get(); + __pm_stay_awake(&mot_actuator_fctrl.actuator_wakelock); + cancel_delayed_work(&mot_actuator_fctrl.delay_work); + if (mutex_is_locked(&mot_actuator_fctrl.actuator_lock)) { + is_exiting = true; + } + mutex_lock(&mot_actuator_fctrl.actuator_lock); + if (is_exiting) { + CAM_WARN(CAM_ACTUATOR, "Wait 20~30us to let CCI release done."); + usleep_range(20, 30); + } + mot_actuator_vib_move_lens(0); + mutex_unlock(&mot_actuator_fctrl.actuator_lock); + end = ktime_get(); + duration = ktime_sub(end, start); + duration /= 1000; + CAM_WARN(CAM_ACTUATOR, "Move lens delay: %dus", duration); + return 0; +} +EXPORT_SYMBOL(mot_actuator_on_vibrate_start); + +int mot_actuator_on_vibrate_stop(void) +{ + if (mot_actuator_fctrl.mot_actuator_wq != NULL) { + queue_delayed_work(mot_actuator_fctrl.mot_actuator_wq, + &mot_actuator_fctrl.delay_work, msecs_to_jiffies(VIBRATING_MAX_INTERVAL)); + } else { + //Dedicated work queue may create failed, use default one. + schedule_delayed_work(&mot_actuator_fctrl.delay_work, msecs_to_jiffies(VIBRATING_MAX_INTERVAL)); + } + return 0; +} +EXPORT_SYMBOL(mot_actuator_on_vibrate_stop); + +static int32_t mot_actuator_handle_exit(uint32_t arg) +{ + int rc = 0; + + return rc; +} + +static int32_t mot_actuator_handle_write(uint32_t arg) +{ + int rc = 0; + + if (mot_actuator_state != MOT_ACTUATOR_INITED) { + pr_err("%s: mot actuator is not initiated!!", __func__); + return -EINVAL; + } + + return rc; +} + +static void mot_actuator_handle_release(void) +{ + if (mot_actuator_state == MOT_ACTUATOR_RELEASED) { + pr_err("%s: Already released.", __func__); + return; + } + + if (mot_actuator_state == MOT_ACTUATOR_INITED) { + pr_debug("Disable AF power!"); + //regulator_disable(afVdd); + //regulator_disable(ioVdd); + } + pr_debug("%s: Vsync released.", __func__); + mot_actuator_state = MOT_ACTUATOR_RELEASED; + return; +} + +static int32_t mot_actuator_handle_cmd( + struct v4l2_subdev *sd, + uint32_t arg, + unsigned int cmd) +{ + int32_t rc=0; + + switch (cmd) { + case MOT_ACTUATOR_INIT: + /* init */ + mot_actuator_init_runtime(); + pr_debug("%s: MOT_ACTUATOR_INIT ret:%d", __func__, rc); + break; + case MOT_ACTUATOR_READ: + /* read */ + pr_debug("%s: MOT_ACTUATOR_READ ret:%d", __func__, rc); + break; + case MOT_ACTUATOR_WRITE: + /* write */ + mot_actuator_handle_write(arg); + pr_debug("%s: MOT_ACTUATOR_WRITE ret:%d", __func__, rc); + break; + case MOT_ACTUATOR_EXIT: + /* exit */ + mot_actuator_handle_exit(arg); + pr_debug("%s: MOT_ACTUATOR_EXIT ret:%d", __func__, rc); + break; + case MOT_ACTUATOR_RELEASE: + /* release */ + mot_actuator_handle_release(); + pr_debug("%s: MOT_ACTUATOR_RELEASE ret:%d", __func__, rc); + break; + default: + pr_err("%s: Unknown command (%d)\n", __func__, cmd); + rc = -EINVAL; + break; + } + + return rc; +} + +static long mot_actuator_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + pr_debug("%s cmd=%x, arg=%x\n", __func__, cmd, *(int *)arg); + + switch (cmd) { + case MOT_ACTUATOR_READ: + case MOT_ACTUATOR_WRITE: + case MOT_ACTUATOR_INIT: + case MOT_ACTUATOR_EXIT: + case MOT_ACTUATOR_RELEASE: + return mot_actuator_handle_cmd(sd, *(int *)arg, cmd); + default: + pr_err("%s Unsupported cmd=%x, arg=%x\n", __func__, cmd, arg); + pr_debug("%s supported cmd: %x, %x, %x, %x, %x\n", __func__, + MOT_ACTUATOR_READ, + MOT_ACTUATOR_WRITE, + MOT_ACTUATOR_INIT, + MOT_ACTUATOR_EXIT, + MOT_ACTUATOR_RELEASE); + return -ENOIOCTLCMD; + } +} + +#ifdef CONFIG_COMPAT +static long mot_actuator_ioctl32(struct v4l2_subdev *sd, + unsigned int cmd, unsigned long arg) +{ + int cmd_data; + int32_t rc = 0; + + if (copy_from_user(&cmd_data, (void __user *)arg, + sizeof(cmd_data))) { + pr_err("Failed to copy from user_ptr=%pK size=%zu", (void __user *)arg, sizeof(cmd_data)); + return -EFAULT; + } + + pr_debug("%s cmd=%x, arg=%x\n", __func__, cmd, arg); + + switch (cmd) { + case MOT_ACTUATOR_READ32: + cmd = MOT_ACTUATOR_READ; + break; + case MOT_ACTUATOR_WRITE32: + cmd = MOT_ACTUATOR_WRITE; + break; + case MOT_ACTUATOR_INIT32: + cmd = MOT_ACTUATOR_INIT; + break; + case MOT_ACTUATOR_EXIT32: + cmd = MOT_ACTUATOR_EXIT; + break; + case MOT_ACTUATOR_RELEASE32: + cmd = MOT_ACTUATOR_RELEASE; + break; + default: + pr_err("%s Unsupported cmd=%x, arg=%x\n", __func__, cmd, arg); + pr_debug("%s supported cmd: %x, %x, %x, %x, %x\n", __func__, + MOT_ACTUATOR_READ32, + MOT_ACTUATOR_WRITE32, + MOT_ACTUATOR_INIT32, + MOT_ACTUATOR_EXIT32, + MOT_ACTUATOR_RELEASE32); + return -ENOIOCTLCMD; + } + + rc = mot_actuator_ioctl(sd, cmd, (void *)&cmd_data); + + return rc; +} +#endif + +static struct v4l2_subdev_core_ops mot_actuator_subdev_core_ops = { + .ioctl = mot_actuator_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = mot_actuator_ioctl32, +#endif +}; + +static struct v4l2_subdev_ops mot_actuator_subdev_ops = { + .core = &mot_actuator_subdev_core_ops, +}; + +static const struct v4l2_subdev_internal_ops mot_actuator_internal_ops; + +static int32_t mot_actuator_reset_lens(uint32_t index) +{ + uint32_t cur_len_pos = mot_actuator_runtime[index].safe_dac_pos; + int stageIndex; + unsigned int consumers = 0; + int32_t ret = 0; + + if (mot_dev_list[mot_device_index].actuator_info[index].reset_lens_needed == false) { + CAM_DBG(CAM_ACTUATOR, "reset lens is not needed."); + return 0; + } + /*The first step is to get back to a specify position,regardless of the step size*/ + if(cur_len_pos > lens_reset_table[0].kneePoint) + { + cur_len_pos = lens_reset_table[0].kneePoint; + ret = mot_actuator_move_lens_by_dac(index, cur_len_pos); + usleep_range(10000, 12000); + } + while (cur_len_pos > lens_park_pos) { + consumers = mot_actuator_get_consumers(); + if ((consumers & (~CLINET_VIBRATOR_MASK)) != 0) { + CAM_WARN(CAM_ACTUATOR, "reset lens was broken by other actuator requests."); + break; + } + + for (stageIndex=1; stageIndex= lens_reset_table[stageIndex].kneePoint && lens_reset_table[stageIndex].step > 0) { + cur_len_pos -= lens_reset_table[stageIndex].step; + break; + } + } + + if (lens_reset_table[stageIndex].step <= 0 && cur_len_pos > lens_park_pos) { + cur_len_pos -= 10; + } + + ret = mot_actuator_move_lens_by_dac(index, cur_len_pos); + if (ret < 0 ) { + CAM_ERR(CAM_ACTUATOR, "reset Lens encounter CCI error, break now."); + break; + } + + if (cur_len_pos <= lens_park_pos) { + /*For skipping the last delay*/ + CAM_DBG(CAM_ACTUATOR, "reset lens done."); + break; + } + usleep_range(10000, 12000); + } + return 0; +} + +void mot_actuator_handle_exile(void) +{ + unsigned int consumers = 0,ret = 0; + int actuatorUsers = 0; + ktime_t start,end,duration; + mutex_lock(&mot_actuator_fctrl.actuator_lock); + consumers = mot_actuator_get_consumers(); + /*Only reset lens when vibrator in consumer list*/ + if ((consumers & CLINET_VIBRATOR_MASK) != 0) { + actuatorUsers = mot_actuator_put(ACTUATOR_CLIENT_VIBRATOR); + start = ktime_get(); + if (mot_actuator_state >= MOT_ACTUATOR_INITED && mot_actuator_state < MOT_ACTUATOR_RELEASED) { + if ((consumers & (~CLINET_VIBRATOR_MASK)) == 0) { + //Only reset lens when there's no other user holding actuator. + CAM_DBG(CAM_ACTUATOR, "reset _lens_now"); + ret = mot_actuator_reset_lens(0); + } + mot_actuator_power_off(0); + mot_actuator_release_cci(0); + } + mot_actuator_state = MOT_ACTUATOR_RELEASED; + end = ktime_get(); + duration = ktime_sub(end, start); + duration /= 1000; + CAM_WARN(CAM_ACTUATOR, "reset lens delay: %dus", duration); + } + mutex_unlock(&mot_actuator_fctrl.actuator_lock); +} + +EXPORT_SYMBOL(mot_actuator_handle_exile); +static void mot_actuator_delayed_process(struct work_struct *work) +{ + struct mot_actuator_ctrl_t *actuator_fctrl = container_of(work, + struct mot_actuator_ctrl_t, delay_work.work); + unsigned int consumers = 0; + int actuatorUsers = 0; + + mutex_lock(&actuator_fctrl->actuator_lock); + consumers = mot_actuator_get_consumers(); + if ((consumers & CLINET_VIBRATOR_MASK) != 0) { + actuatorUsers = mot_actuator_put(ACTUATOR_CLIENT_VIBRATOR); + } + if (mot_actuator_state >= MOT_ACTUATOR_INITED && mot_actuator_state < MOT_ACTUATOR_RELEASED) { + if ((consumers & (~CLINET_VIBRATOR_MASK)) == 0) { + //Only park lens when there's no other user holding actuator. + mot_actuator_park_lens(0); + } + mot_actuator_power_off(0); + mot_actuator_release_cci(0); + } + mot_actuator_state = MOT_ACTUATOR_RELEASED; + mutex_unlock(&actuator_fctrl->actuator_lock); + __pm_relax(&actuator_fctrl->actuator_wakelock); +} + +static inline ssize_t msm_actuator_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t count = 0; + count = sprintf(buf, "\nmot_actuator_state: %d, device index: %d\n", mot_actuator_state, mot_device_index); + return count; +} + +static ssize_t msm_actuator_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int retval; + unsigned int input; + + if (kstrtouint(buf, 10, &input) != 0) { + retval = -EINVAL; + goto exit; + } + + if (input) { + CAM_DBG(CAM_ACTUATOR, "start actuator"); + mot_actuator_on_vibrate_start(); + } else { + CAM_DBG(CAM_ACTUATOR, "stop actuator"); + mot_actuator_on_vibrate_stop(); + } + retval = count; +exit: + return retval; +} + +//Tuning interface +static inline ssize_t mot_actuator_lens_park_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t count = 0; + count = sprintf(buf, "\n lens park pos: %d\n", lens_park_pos); + return count; +} + +static ssize_t mot_actuator_lens_park_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int retval; + unsigned int input; + + if (kstrtouint(buf, 10, &input) != 0) { + retval = -EINVAL; + goto exit; + } + + lens_park_pos = input; + + retval = count; +exit: + return retval; +} + +static inline ssize_t mot_actuator_safe_pos_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t count = 0; + count = sprintf(buf, "\n safe dac value steps: %d\n", lens_safe_pos_dac); + return count; +} + +static ssize_t mot_actuator_safe_pos_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int retval; + unsigned int input; + + if (kstrtouint(buf, 10, &input) != 0) { + retval = -EINVAL; + goto exit; + } + + lens_safe_pos_dac = input; + //reinitialize when the safe_pos parameter is manually configured. + runtime_inited = false; + retval = count; +exit: + return retval; +} + +static inline ssize_t mot_actuator_dump_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t count = 0; + count = mot_actuator_dump(buf); + return count; +} + +static ssize_t mot_actuator_dump_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return count; +} + + +static inline ssize_t mot_actuator_park_lens_table_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t count = 0; + int i; + count += sprintf(buf, "\n knee point step\n"); + for (i=0; i 0) { + for (index=0; indexv4l2_dev_str.internal_ops = &mot_actuator_internal_ops; + f_ctrl->v4l2_dev_str.ops = &mot_actuator_subdev_ops; + strlcpy(f_ctrl->device_name, MOT_ACTUATOR_NAME, sizeof(f_ctrl->device_name)); + f_ctrl->v4l2_dev_str.name = f_ctrl->device_name; + f_ctrl->v4l2_dev_str.sd_flags = + (V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS); + f_ctrl->v4l2_dev_str.ent_function = CAM_MOT_ACTUATOR_TYPE; + f_ctrl->v4l2_dev_str.token = f_ctrl; + + f_ctrl->v4l2_dev_str.pdev = pdev; + + f_ctrl->mot_actuator_wq = NULL; + f_ctrl->mot_actuator_wq = create_singlethread_workqueue("mot_actuator_wq"); + if (f_ctrl->mot_actuator_wq == NULL) { + CAM_ERR(CAM_ACTUATOR, "create work queue failed!!!"); + } + + INIT_DELAYED_WORK(&f_ctrl->delay_work, mot_actuator_delayed_process); + mutex_init(&f_ctrl->actuator_lock); + memset(&f_ctrl->actuator_wakelock, 0, sizeof(f_ctrl->actuator_wakelock)); + f_ctrl->actuator_wakelock.name = "actuator_hold_wl"; + wakeup_source_add(&f_ctrl->actuator_wakelock); + + {//Debug/tuning interfaces + int i; + for (i=0; iv4l2_dev_str.pdev->dev.kobj, + &mot_actuator_attrs[i].attr); + } + } + + rc = cam_register_subdev(&(f_ctrl->v4l2_dev_str)); + if (rc) + CAM_ERR(CAM_ACTUATOR, "Fail with cam_register_subdev rc: %d", rc); + + return rc; +} + +static int mot_actuator_component_bind(struct device *dev, + struct device *master_dev, void *data) +{ + CAM_WARN(CAM_ACTUATOR,"enter"); + + (void)master_dev; + (void)data; + + mot_actuator_init_subdev(dev, &mot_actuator_fctrl); + cam_select_actuator_by_device_name(); + + CAM_WARN(CAM_ACTUATOR,"exit"); + + return 0; +} + +static void mot_actuator_component_unbind(struct device *dev, + struct device *master_dev, void *data) +{ + CAM_WARN(CAM_ACTUATOR,"enter"); + + (void)dev; + (void)master_dev; + (void)data; + + cancel_delayed_work_sync(&mot_actuator_fctrl.delay_work); + if (mot_actuator_fctrl.mot_actuator_wq != NULL) { + flush_workqueue(mot_actuator_fctrl.mot_actuator_wq); + destroy_workqueue(mot_actuator_fctrl.mot_actuator_wq); + mot_actuator_fctrl.mot_actuator_wq = NULL; + } + cam_unregister_subdev(&mot_actuator_fctrl.v4l2_dev_str); + __pm_relax(&mot_actuator_fctrl.actuator_wakelock); + wakeup_source_remove(&mot_actuator_fctrl.actuator_wakelock); + + CAM_WARN(CAM_ACTUATOR,"exit"); +} + +const static struct component_ops mot_actuator_component_ops = { + .bind = mot_actuator_component_bind, + .unbind = mot_actuator_component_unbind, +}; + +static int32_t mot_actuator_platform_remove( + struct platform_device *pdev) +{ + component_del(&pdev->dev, &mot_actuator_component_ops); + return 0; +} + +static const struct of_device_id mot_actuator_driver_dt_match[] = { + {.compatible = "mot,actuator"}, + {} +}; + +static int32_t mot_actuator_driver_platform_probe( + struct platform_device *pdev) +{ + int rc = 0; + + CAM_DBG(CAM_ACTUATOR, "Adding sensor actuator component"); + rc = component_add(&pdev->dev, &mot_actuator_component_ops); + if (rc) + CAM_ERR(CAM_ICP, "failed to add component rc: %d", rc); + + return rc; +} + +MODULE_DEVICE_TABLE(of, mot_actuator_driver_dt_match); + +struct platform_driver mot_actuator_platform_driver = { + .probe = mot_actuator_driver_platform_probe, + .driver = { + .name = "mot,actuator", + .owner = THIS_MODULE, + .of_match_table = mot_actuator_driver_dt_match, + .suppress_bind_attrs = true, + }, + .remove = mot_actuator_platform_remove, +}; + +int mot_actuator_driver_init(void) +{ + int32_t rc = 0; + + rc = platform_driver_register(&mot_actuator_platform_driver); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "platform_driver_register failed rc = %d", rc); + return rc; + } + + return rc; +} + +void mot_actuator_driver_exit(void) +{ + platform_driver_unregister(&mot_actuator_platform_driver); +} + +MODULE_DESCRIPTION("mot_actuator_driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_sensor_module/cam_actuator/mot_actuator.h b/techpack/camera/drivers/cam_sensor_module/cam_actuator/mot_actuator.h new file mode 100644 index 000000000000..d6d1699799a0 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_actuator/mot_actuator.h @@ -0,0 +1,36 @@ +#ifndef __MOT_ACTUATOR_H__ +#define __MOT_ACTUATOR_H__ + +#include +#include +#define MOT_ACTUATOR_NAME "mot_actuator" + +#define MOT_ACTUATOR_READ \ + _IOWR('X', BASE_VIDIOC_PRIVATE + 50, int) +#define MOT_ACTUATOR_READ32 \ + _IOWR('X', BASE_VIDIOC_PRIVATE + 50, int) + +#define MOT_ACTUATOR_WRITE \ + _IOWR('X', BASE_VIDIOC_PRIVATE + 51, int) +#define MOT_ACTUATOR_WRITE32 \ + _IOWR('X', BASE_VIDIOC_PRIVATE + 51, int) + +#define MOT_ACTUATOR_INIT \ + _IOWR('X', BASE_VIDIOC_PRIVATE + 52, int) +#define MOT_ACTUATOR_INIT32 \ + _IOWR('X', BASE_VIDIOC_PRIVATE + 52, int) + +#define MOT_ACTUATOR_RELEASE \ + _IOWR('X', BASE_VIDIOC_PRIVATE + 53, int) +#define MOT_ACTUATOR_RELEASE32 \ + _IOWR('X', BASE_VIDIOC_PRIVATE + 53, int) + +#define MOT_ACTUATOR_EXIT \ + _IOWR('X', BASE_VIDIOC_PRIVATE + 54, int) +#define MOT_ACTUATOR_EXIT32 \ + _IOWR('X', BASE_VIDIOC_PRIVATE + 54, int) + +void mot_actuator_handle_exile(void); +int mot_actuator_driver_init(void); +void mot_actuator_driver_exit(void); +#endif /*__MOT_ACTUATOR_H__*/ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_actuator/mot_actuator_policy.c b/techpack/camera/drivers/cam_sensor_module/cam_actuator/mot_actuator_policy.c new file mode 100644 index 000000000000..b979927c1c9b --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_actuator/mot_actuator_policy.c @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2020 Motorola Mobility LLC. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 +#include +#include "cam_debug_util.h" +#include "mot_actuator_policy.h" + +extern int mot_actuator_on_vibrate_start(void); +extern int mot_actuator_on_vibrate_stop(void); + +static atomic_t mot_actuator_ref_count = ATOMIC_INIT(0); +static unsigned long mot_actuator_consumers = ATOMIC_INIT(0); +static struct mutex actuator_res_lock = __MUTEX_INITIALIZER(actuator_res_lock); + +int mot_actuator_get(mot_actuator_client user) +{ + if (user <= ACTUATOR_CLIENT_INVALID || user >= ACTUATOR_CLIENT_MAX) { + CAM_ERR(CAM_ACTUATOR, "INVALID CLIENT!!!"); + return 0; + } + + CAM_DBG(CAM_ACTUATOR, "Obtain actuator from: %d", user); + + test_and_set_bit(user, &mot_actuator_consumers); + + return atomic_add_return(1, &mot_actuator_ref_count); +} +EXPORT_SYMBOL(mot_actuator_get); + +int mot_actuator_put(mot_actuator_client user) +{ + unsigned long consumers = 0; + if (user <= ACTUATOR_CLIENT_INVALID || user >= ACTUATOR_CLIENT_MAX) { + CAM_ERR(CAM_ACTUATOR, "INVALID CLIENT!!!"); + return 0; + } + + CAM_DBG(CAM_ACTUATOR, "Release actuator from: %d", user); + + test_and_clear_bit(user, &mot_actuator_consumers); + + consumers = mot_actuator_get_consumers(); + if (((consumers & CLINET_VIBRATOR_MASK) == CLINET_VIBRATOR_MASK) && + (user != ACTUATOR_CLIENT_VIBRATOR)) { + //If only vibrator noise eliminator exists, move lens to required position + CAM_DBG(CAM_ACTUATOR, "Set actuator pos for vibrator"); + mot_actuator_on_vibrate_start(); + if ((mot_actuator_get_consumers() & CLINET_VIBRATOR_MASK) == 0) { + mot_actuator_on_vibrate_stop(); + } + } + + return atomic_sub_return(1, &mot_actuator_ref_count); +} +EXPORT_SYMBOL(mot_actuator_put); + +int mot_actuator_get_ref_count(void) +{ + return atomic_read(&mot_actuator_ref_count); +} +EXPORT_SYMBOL(mot_actuator_get_ref_count); + +unsigned int mot_actuator_get_consumers(void) +{ + return mot_actuator_consumers; +} +EXPORT_SYMBOL(mot_actuator_get_consumers); + +void mot_actuator_lock(void) +{ + mutex_lock(&actuator_res_lock); +} +EXPORT_SYMBOL(mot_actuator_lock); + +void mot_actuator_unlock(void) +{ + mutex_unlock(&actuator_res_lock); +} +EXPORT_SYMBOL(mot_actuator_unlock); + +ssize_t mot_actuator_dump(char *buf) +{ + int item_len = 0; + unsigned int consumers = mot_actuator_get_consumers(); + + item_len += sprintf(buf+item_len, "refCount: %d\n", mot_actuator_get_ref_count()); + item_len += sprintf(buf+item_len, "Consumers (0x%x):\n", consumers); + + if (consumers & CLINET_CAMERA_MASK) { + item_len += sprintf(buf+item_len, "camera"); + } + + if (consumers & CLINET_VIBRATOR_MASK) { + item_len += sprintf(buf+item_len, " vibrator"); + } + + item_len += sprintf(buf+item_len, "\n"); + + CAM_DBG(CAM_ACTUATOR, "ref cnt:%d, consumers:0x%x", mot_actuator_get_ref_count(), mot_actuator_get_consumers()); + return item_len; +} +EXPORT_SYMBOL(mot_actuator_dump); diff --git a/techpack/camera/drivers/cam_sensor_module/cam_actuator/mot_actuator_policy.h b/techpack/camera/drivers/cam_sensor_module/cam_actuator/mot_actuator_policy.h new file mode 100644 index 000000000000..3278546e0e3a --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_actuator/mot_actuator_policy.h @@ -0,0 +1,20 @@ +#ifndef __MOT_ACTUATOR_POLICY_H__ +#define __MOT_ACTUATOR_POLICY_H__ + +typedef enum { + ACTUATOR_CLIENT_INVALID, + ACTUATOR_CLIENT_CAMERA, + ACTUATOR_CLIENT_VIBRATOR, + ACTUATOR_CLIENT_MAX +} mot_actuator_client; + +#define CLINET_CAMERA_MASK (0x01 << ACTUATOR_CLIENT_CAMERA) +#define CLINET_VIBRATOR_MASK (0x01 << ACTUATOR_CLIENT_VIBRATOR) + +int mot_actuator_get(mot_actuator_client user); +int mot_actuator_put(mot_actuator_client user); +void mot_actuator_lock(void); +void mot_actuator_unlock(void); +ssize_t mot_actuator_dump(char *buf); +unsigned int mot_actuator_get_consumers(void); +#endif /*__MOT_ACTUATOR_POLICY_H__*/ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_core.c b/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_core.c index bf4a2b975121..bfeef7b381f2 100644 --- a/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_core.c @@ -212,7 +212,7 @@ void cam_cci_dump_registers(struct cci_device *cci_dev, uint32_t reg_offset = 0; void __iomem *base = cci_dev->soc_info.reg_map[0].mem_base; - dump_en = cci_dev->dump_en; + dump_en = cci_dev->dump_en = 6; if (!(dump_en & CAM_CCI_NACK_DUMP_EN) && !(dump_en & CAM_CCI_TIMEOUT_DUMP_EN)) { CAM_DBG(CAM_CCI, diff --git a/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c b/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c index 28b76aef1c12..3508ba9402ef 100644 --- a/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/techpack/camera/drivers/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -28,6 +28,8 @@ struct v4l2_subdev *cam_cci_get_subdev(int cci_dev_index) return sub_device; } +EXPORT_SYMBOL(cam_cci_get_subdev); + static long cam_cci_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { diff --git a/techpack/camera/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c index 59946e481246..534a05cb82f0 100644 --- a/techpack/camera/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -37,6 +37,10 @@ /* Mask to enable skew calibration registers */ #define SKEW_CAL_MASK 0x2 +#ifdef CONFIG_MOT_SECURE_CAMERA +#define QCOM_SCM_EBUSY_MAX_RETRY 5 +#endif + static DEFINE_MUTEX(active_csiphy_cnt_mutex); static int csiphy_dump; @@ -1097,6 +1101,10 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, struct cam_control *cmd = (struct cam_control *)arg; int32_t rc = 0; +#ifdef CONFIG_MOT_SECURE_CAMERA + int32_t retry_count = 0; +#endif + if (!csiphy_dev || !cmd) { CAM_ERR(CAM_CSIPHY, "Invalid input args"); return -EINVAL; @@ -1293,7 +1301,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, cam_csiphy_update_lane(csiphy_dev, offset, false); goto release_mutex; } - +#ifndef CONFIG_MOT_SECURE_CAMERA if (csiphy_dev->csiphy_info[offset].secure_mode) cam_csiphy_notify_secure_mode( csiphy_dev, @@ -1301,6 +1309,28 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, csiphy_dev->csiphy_info[offset].secure_mode = CAM_SECURE_MODE_NON_SECURE; +#else + retry_count = 0; +retry_a: + retry_count++; + + if (csiphy_dev->csiphy_info[offset].secure_mode) { + rc = cam_csiphy_notify_secure_mode( + csiphy_dev, + CAM_SECURE_MODE_NON_SECURE, offset); + if (rc <0 && retry_count <= QCOM_SCM_EBUSY_MAX_RETRY) { + CAM_INFO(CAM_CSIPHY, "CAM_STOP_PHYDEV: scm call with count: %d,",retry_count); + goto retry_a; + } else if (rc <0 && retry_count > QCOM_SCM_EBUSY_MAX_RETRY){ + CAM_INFO(CAM_CSIPHY, "CAM_STOP_PHYDEV: notify secure mode finally failed scm call with count: %d,",retry_count); + } + + } + + csiphy_dev->csiphy_info[offset].secure_mode = + CAM_SECURE_MODE_NON_SECURE; + +#endif csiphy_dev->csiphy_info[offset].csiphy_cpas_cp_reg_mask = 0x0; @@ -1356,6 +1386,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, goto release_mutex; } +#ifndef CONFIG_MOT_SECURE_CAMERA if (csiphy_dev->csiphy_info[offset].secure_mode) cam_csiphy_notify_secure_mode( csiphy_dev, @@ -1363,6 +1394,26 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, csiphy_dev->csiphy_info[offset].secure_mode = CAM_SECURE_MODE_NON_SECURE; +#else + retry_count = 0; +retry_b: + retry_count++; + + if (csiphy_dev->csiphy_info[offset].secure_mode) { + rc = cam_csiphy_notify_secure_mode( + csiphy_dev, + CAM_SECURE_MODE_NON_SECURE, offset); + if (rc <0 && retry_count <= QCOM_SCM_EBUSY_MAX_RETRY) { + CAM_INFO(CAM_CSIPHY, "CAM_RELEASE_PHYDEV: scm call with count: %d,",retry_count); + goto retry_b; + } else if (rc <0 && retry_count > QCOM_SCM_EBUSY_MAX_RETRY){ + CAM_INFO(CAM_CSIPHY, "CAM_RELEASE_PHYDEV: notify secure mode finally failed scm call with count: %d,",retry_count); + } + } + + csiphy_dev->csiphy_info[offset].secure_mode = + CAM_SECURE_MODE_NON_SECURE; +#endif csiphy_dev->csiphy_cpas_cp_reg_mask[offset] = 0x0; diff --git a/techpack/camera/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h index aaa8bae0b667..7dddef775129 100644 --- a/techpack/camera/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h +++ b/techpack/camera/drivers/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_3_hwreg.h @@ -376,12 +376,22 @@ struct data_rate_settings_t data_rate_delta_table_1_2_3 = { { .lane_identifier = CPHY_LANE_0, .csiphy_data_rate_regs = { +#ifdef CONFIG_CAM_CTLE_ENABLE + {0x144, 0xB2, 0x00, + CSIPHY_DEFAULT_PARAMS}, +#else {0x144, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, +#endif {0x988, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, +#ifdef CONFIG_CAM_CTLE_ENABLE + {0x980, 0x60, 0x00, + CSIPHY_DEFAULT_PARAMS}, +#else {0x980, 0x61, 0x00, CSIPHY_DEFAULT_PARAMS}, +#endif {0x9B4, 0x08, 0x0A, CSIPHY_DEFAULT_PARAMS}, }, @@ -389,12 +399,22 @@ struct data_rate_settings_t data_rate_delta_table_1_2_3 = { { .lane_identifier = CPHY_LANE_1, .csiphy_data_rate_regs = { +#ifdef CONFIG_CAM_CTLE_ENABLE + {0x344, 0xB2, 0x00, + CSIPHY_DEFAULT_PARAMS}, +#else {0x344, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, +#endif {0xA88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, +#ifdef CONFIG_CAM_CTLE_ENABLE + {0xA80, 0x60, 0x00, + CSIPHY_DEFAULT_PARAMS}, +#else {0xA80, 0x61, 0x00, CSIPHY_DEFAULT_PARAMS}, +#endif {0xAB4, 0x08, 0x0A, CSIPHY_DEFAULT_PARAMS}, }, @@ -402,12 +422,22 @@ struct data_rate_settings_t data_rate_delta_table_1_2_3 = { { .lane_identifier = CPHY_LANE_2, .csiphy_data_rate_regs = { +#ifdef CONFIG_CAM_CTLE_ENABLE + {0x544, 0xB2, 0x00, + CSIPHY_DEFAULT_PARAMS}, +#else {0x544, 0xA2, 0x00, CSIPHY_DEFAULT_PARAMS}, +#endif {0xB88, 0x05, 0x00, CSIPHY_DEFAULT_PARAMS}, +#ifdef CONFIG_CAM_CTLE_ENABLE + {0xB80, 0x60, 0x00, + CSIPHY_DEFAULT_PARAMS}, +#else {0xB80, 0x61, 0x00, CSIPHY_DEFAULT_PARAMS}, +#endif {0xBB4, 0x08, 0x0A, CSIPHY_DEFAULT_PARAMS}, }, diff --git a/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_core.c b/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_core.c index cbe33b043a51..1eae8295cdb2 100644 --- a/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_core.c @@ -13,9 +13,58 @@ #include "cam_packet_util.h" #include +#ifdef CONFIG_CAMERA_FLASH_PWM +#include "cam_sensor_util.h" +#include "../cam_flash_pm6125_gpio/pm6125_flash_gpio.h" +#endif + static uint default_on_timer = 2; module_param(default_on_timer, uint, 0644); +static int flash_initstate = 0; +static struct i2c_settings_list* i2c_flash_off = NULL; +static struct i2c_settings_list* + cam_flash_get_i2c_ptr(struct i2c_settings_list *pi2c_list) +{ + struct i2c_settings_list *tmp; + struct cam_sensor_i2c_reg_array *i2c_reg_settings = + pi2c_list->i2c_settings.reg_setting; + uint32_t size = pi2c_list->i2c_settings.size; + int i = 0; + + tmp = kzalloc(sizeof(struct i2c_settings_list), GFP_KERNEL); + if (tmp == NULL) { + CAM_WARN(CAM_FLASH, "kzalloc failed"); + return NULL; + } + + tmp->i2c_settings.reg_setting = (struct cam_sensor_i2c_reg_array *) + vzalloc(size * sizeof(struct cam_sensor_i2c_reg_array)); + if (tmp->i2c_settings.reg_setting == NULL) { + kfree(tmp); + CAM_WARN(CAM_FLASH, "vzalloc failed"); + return NULL; + } + + tmp->i2c_settings.size = size; + tmp->op_code = pi2c_list->op_code; + tmp->i2c_settings.addr_type = pi2c_list->i2c_settings.addr_type; + tmp->i2c_settings.data_type = pi2c_list->i2c_settings.data_type; + + for( i = 0; i < size ; i++ ) { + tmp->i2c_settings.reg_setting[i].reg_addr = + i2c_reg_settings[i].reg_addr; + tmp->i2c_settings.reg_setting[i].reg_data = + i2c_reg_settings[i].reg_data; + tmp->i2c_settings.reg_setting[i].data_mask = + i2c_reg_settings[i].data_mask; + tmp->i2c_settings.reg_setting[i].delay = + i2c_reg_settings[i].delay; + } + + return tmp; +} + int cam_flash_led_prepare(struct led_trigger *trigger, int options, int *max_current, bool is_wled) { @@ -290,6 +339,7 @@ int cam_flash_i2c_flush_request(struct cam_flash_ctrl *fctrl, int i = 0; uint32_t cancel_req_id_found = 0; struct i2c_settings_array *i2c_set = NULL; + struct i2c_settings_list *i2c_list = NULL; if (!fctrl) { CAM_ERR(CAM_FLASH, "Device data is NULL"); @@ -310,6 +360,17 @@ int cam_flash_i2c_flush_request(struct cam_flash_ctrl *fctrl, continue; if (i2c_set->is_settings_valid == 1) { + list_for_each_entry(i2c_list, + &(i2c_set->list_head), list) { + rc = cam_sensor_util_i2c_apply_setting( + &(fctrl->io_master_info), + i2c_list); + if (rc) { + CAM_ERR(CAM_FLASH, + "Failed to apply settings: %d", + rc); + } + } rc = delete_request(i2c_set); if (rc < 0) CAM_ERR(CAM_FLASH, @@ -462,6 +523,11 @@ int cam_flash_off(struct cam_flash_ctrl *flash_ctrl) { int rc = 0; +#ifdef CONFIG_CAMERA_FLASH_PWM + struct cam_hw_soc_info soc_info = flash_ctrl->soc_info; + struct cam_flash_private_soc *soc_private = (struct cam_flash_private_soc *)soc_info.soc_private; +#endif + if (!flash_ctrl) { CAM_ERR(CAM_FLASH, "Flash control Null"); return -EINVAL; @@ -480,6 +546,19 @@ int cam_flash_off(struct cam_flash_ctrl *flash_ctrl) "cannot apply streamoff settings"); } } + + if(i2c_flash_off) + { + CAM_DBG(CAM_FLASH, "i2c Flash OFF Triggered"); + cam_sensor_util_i2c_apply_setting(&(flash_ctrl->io_master_info), + i2c_flash_off); + } +#ifdef CONFIG_CAMERA_FLASH_PWM + CAM_ERR(CAM_SENSOR,"cam_flash_off"); + cam_res_mgr_gpio_set_value(soc_private->flash_gpio_enable, 0); + cam_res_mgr_gpio_free(soc_info.dev, soc_private->flash_gpio_enable); + pm6125_flash_gpio_select_state(PM6125_FLASH_GPIO_STATE_SUSPEND, CAMERA_SENSOR_FLASH_OP_OFF, 0); +#endif return 0; } @@ -489,6 +568,11 @@ static int cam_flash_low( { int i = 0, rc = 0; +#ifdef CONFIG_CAMERA_FLASH_PWM + struct cam_hw_soc_info soc_info = flash_ctrl->soc_info; + struct cam_flash_private_soc *soc_private = (struct cam_flash_private_soc *)soc_info.soc_private; +#endif + if (!flash_data) { CAM_ERR(CAM_FLASH, "Flash Data Null"); return -EINVAL; @@ -505,6 +589,19 @@ static int cam_flash_low( if (rc) CAM_ERR(CAM_FLASH, "Fire Torch failed: %d", rc); +#ifdef CONFIG_CAMERA_FLASH_PWM + CAM_DBG(CAM_FLASH, "Flash low Triggered flash_data->led_current_ma[0] = %u", flash_data->led_current_ma[0]); + rc = cam_res_mgr_gpio_request(soc_info.dev, soc_private->flash_gpio_enable, 0, "CUSTOM_GPIO1"); + if(rc) { + CAM_ERR(CAM_FLASH, "gpio %d request fails", soc_private->flash_gpio_enable); + return rc; + } + cam_res_mgr_gpio_set_value(soc_private->flash_gpio_enable, 0); + pm6125_flash_gpio_select_state(PM6125_FLASH_GPIO_STATE_ACTIVE, CAMERA_SENSOR_FLASH_OP_FIRELOW, FLASH_FIRE_LOW_MAXCURRENT); + usleep_range(5000,6000); + pm6125_flash_gpio_select_state(PM6125_FLASH_GPIO_STATE_ACTIVE, CAMERA_SENSOR_FLASH_OP_FIRELOW, flash_data->led_current_ma[0]); +#endif + return rc; } @@ -514,6 +611,11 @@ static int cam_flash_high( { int i = 0, rc = 0; +#ifdef CONFIG_CAMERA_FLASH_PWM + struct cam_hw_soc_info soc_info = flash_ctrl->soc_info; + struct cam_flash_private_soc *soc_private = (struct cam_flash_private_soc *)soc_info.soc_private; +#endif + if (!flash_data) { CAM_ERR(CAM_FLASH, "Flash Data Null"); return -EINVAL; @@ -530,6 +632,17 @@ static int cam_flash_high( if (rc) CAM_ERR(CAM_FLASH, "Fire Flash Failed: %d", rc); +#ifdef CONFIG_CAMERA_FLASH_PWM + CAM_DBG(CAM_FLASH, "Flash high Triggered flash_data->led_current_ma[0] = %u", flash_data->led_current_ma[0]); + rc = cam_res_mgr_gpio_request(soc_info.dev, soc_private->flash_gpio_enable, 0, "CUSTOM_GPIO1"); + if(rc) { + CAM_ERR(CAM_FLASH, "gpio %d request fails", soc_private->flash_gpio_enable); + return rc; + } + cam_res_mgr_gpio_set_value(soc_private->flash_gpio_enable, 1); + pm6125_flash_gpio_select_state(PM6125_FLASH_GPIO_STATE_ACTIVE, CAMERA_SENSOR_FLASH_OP_FIREHIGH, flash_data->led_current_ma[0]); +#endif + return rc; } @@ -706,6 +819,8 @@ int cam_flash_i2c_apply_setting(struct cam_flash_ctrl *fctrl, CAM_DBG(CAM_FLASH, "req_id=%llu", req_id); if (req_id == 0) { /* NonRealTime Init settings*/ + + if (fctrl->apply_streamoff == true) { fctrl->apply_streamoff = false; i2c_set = &fctrl->i2c_data.streamoff_settings; @@ -722,6 +837,9 @@ int cam_flash_i2c_apply_setting(struct cam_flash_ctrl *fctrl, break; } } else if (fctrl->i2c_data.init_settings.is_settings_valid == true) { + if(flash_initstate) + goto config_setting; + list_for_each_entry(i2c_list, &(fctrl->i2c_data.init_settings.list_head), list) { @@ -743,8 +861,14 @@ int cam_flash_i2c_apply_setting(struct cam_flash_ctrl *fctrl, rc); return rc; } + + if((NULL != i2c_list) && (NULL == i2c_flash_off)) { + i2c_flash_off = cam_flash_get_i2c_ptr(i2c_list); + } } + flash_initstate = CAM_FLASH_STATE_CONFIG; } +config_setting: /* NonRealTime (Widget/RER/INIT_FIRE settings) */ if (fctrl->i2c_data.config_settings.is_settings_valid == true) { list_for_each_entry(i2c_list, @@ -1258,7 +1382,12 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) CAM_DBG(CAM_FLASH, "settings already valid"); i2c_reg_settings->request_id = 0; i2c_reg_settings->is_settings_valid = false; - goto update_req_mgr; + //goto update_req_mgr; + rc = delete_request(i2c_reg_settings); + if (rc) { + CAM_ERR(CAM_FLASH, "Error deleting req: %d", rc); + return rc; + } } i2c_reg_settings->is_settings_valid = true; i2c_reg_settings->request_id = @@ -2009,6 +2138,18 @@ int cam_flash_release_dev(struct cam_flash_ctrl *fctrl) } } + if(i2c_flash_off != NULL) + { + if(i2c_flash_off->i2c_settings.reg_setting != NULL) { + vfree(i2c_flash_off->i2c_settings.reg_setting); + i2c_flash_off->i2c_settings.reg_setting = NULL; + } + + kfree(i2c_flash_off); + i2c_flash_off = NULL; + flash_initstate = 0; + } + if (fctrl->bridge_intf.device_hdl != 1) { rc = cam_destroy_device_hdl(fctrl->bridge_intf.device_hdl); if (rc) @@ -2078,3 +2219,98 @@ int cam_flash_apply_request(struct cam_req_mgr_apply_request *apply) return rc; } + +#ifdef CONFIG_CAMERA_FLASH_IIC_COMPATIBLE +static int cam_flash_construct_power_vio_setting( + struct cam_sensor_power_ctrl_t *power_info) +{ + int rc = 0; + + power_info->power_setting_size = 2; + power_info->power_setting = + kzalloc(sizeof(struct cam_sensor_power_setting) * 2, + GFP_KERNEL); + if (!power_info->power_setting) + return -ENOMEM; + + power_info->power_setting[0].seq_type = SENSOR_VIO; + power_info->power_setting[0].seq_val = CAM_VIO; + power_info->power_setting[0].config_val = 1; + power_info->power_setting[0].delay = 2; + power_info->power_setting[1].seq_type = SENSOR_CUSTOM_REG2; + power_info->power_setting[1].seq_val = 0; + power_info->power_setting[1].config_val = 1; + power_info->power_setting[1].delay = 0; + + power_info->power_down_setting_size = 2; + power_info->power_down_setting = + kzalloc(sizeof(struct cam_sensor_power_setting) * 2, + GFP_KERNEL); + if (!power_info->power_down_setting) { + rc = -ENOMEM; + goto free_power_settings; + } + + power_info->power_down_setting[0].seq_type = SENSOR_CUSTOM_REG2; + power_info->power_down_setting[0].seq_val = 0; + power_info->power_down_setting[0].config_val = 0; + power_info->power_down_setting[1].seq_type = SENSOR_VIO; + power_info->power_down_setting[1].seq_val = CAM_VIO; + power_info->power_down_setting[1].config_val = 0; + + return rc; + +free_power_settings: + kfree(power_info->power_setting); + power_info->power_setting = NULL; + power_info->power_setting_size = 0; + return rc; +} + +int cam_flash_fill_vreg_setting(struct cam_flash_ctrl *fctrl) +{ + int rc = 0; + + rc = cam_flash_construct_power_vio_setting( + &fctrl->power_info); + if (rc) { + CAM_ERR(CAM_FLASH, "Failed Flash Power VIO Setting: rc=%d\n", rc); + return rc; + } + rc = msm_camera_fill_vreg_params(&fctrl->soc_info, + fctrl->power_info.power_setting, + fctrl->power_info.power_setting_size); + if(rc) + { + CAM_ERR(CAM_FLASH, "Failed Flash Fill Power Up Params: rc=%d\n", rc); + return rc; + } + rc = msm_camera_fill_vreg_params(&fctrl->soc_info, + fctrl->power_info.power_down_setting, + fctrl->power_info.power_down_setting_size); + if(rc) + { + CAM_ERR(CAM_FLASH, "Failed Flash Fill Power Down Params: rc=%d\n", rc); + return rc; + } + return rc; +} + +int cam_flash_fill_i2c_default_setting(struct cam_flash_ctrl *fctrl, uint32_t slave_addr) +{ + int rc = 0; + + struct cam_cmd_i2c_info i2c_info={0}; + i2c_info.slave_addr = slave_addr; + i2c_info.i2c_freq_mode = I2C_STANDARD_MODE; + + rc = cam_flash_slaveInfo_pkt_parser( + fctrl, (uint32_t *)&i2c_info, sizeof(struct cam_cmd_i2c_info)); + if (rc < 0) { + CAM_ERR(CAM_FLASH, + "Failed parsing slave info: rc: %d", + rc); + } + return rc; +} +#endif diff --git a/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c b/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c index cc57a7124ae9..80d2bd4382dd 100644 --- a/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c +++ b/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_dev.c @@ -9,6 +9,9 @@ #include "cam_flash_core.h" #include "cam_common_util.h" #include "camera_main.h" +#ifdef CONFIG_CAMERA_FLASH_PWM +#include "pm6125_flash_gpio.h" +#endif static int32_t cam_flash_driver_cmd(struct cam_flash_ctrl *fctrl, void *arg, struct cam_flash_private_soc *soc_private) @@ -138,10 +141,17 @@ static int32_t cam_flash_driver_cmd(struct cam_flash_ctrl *fctrl, } case CAM_QUERY_CAP: { struct cam_flash_query_cap_info flash_cap = {0}; - +#ifdef CONFIG_CAMERA_FLASH_IIC_COMPATIBLE + uint32_t flash_iic_supplier[3]; + uint32_t flashid=0; +#endif CAM_DBG(CAM_FLASH, "CAM_QUERY_CAP"); flash_cap.slot_info = fctrl->soc_info.index; flash_cap.flash_type = soc_private->flash_type; + CAM_DBG(CAM_FLASH, "dts flash_type is %d, it should same with camx&chi flash_type", soc_private->flash_type); +#ifdef CONFIG_CAMERA_FLASH_PWM + CAM_DBG(CAM_FLASH, "get flash_enabel_gpio %d", soc_private->flash_gpio_enable); +#endif for (i = 0; i < fctrl->flash_num_sources; i++) { flash_cap.max_current_flash[i] = soc_private->flash_max_current[i]; @@ -152,7 +162,39 @@ static int32_t cam_flash_driver_cmd(struct cam_flash_ctrl *fctrl, for (i = 0; i < fctrl->torch_num_sources; i++) flash_cap.max_current_torch[i] = soc_private->torch_max_current[i]; - +#ifdef CONFIG_CAMERA_FLASH_IIC_COMPATIBLE + rc = of_property_read_u32_array(fctrl->of_node, "distinguish-flash-supplier", + flash_iic_supplier, 3); + if (!rc) { + CAM_DBG(CAM_FLASH, "Distinguish IIC Flash Supplier dev:0x%x addr:0x%x data:0x%x", + flash_iic_supplier[0],flash_iic_supplier[1],flash_iic_supplier[2]); + if (cam_flash_fill_vreg_setting(fctrl)){ + CAM_ERR(CAM_FLASH, "Flash Fill Vreg Failed"); + goto release_mutex; + } + if (cam_flash_fill_i2c_default_setting(fctrl, flash_iic_supplier[0])){ + CAM_ERR(CAM_FLASH, "Failed Flash Fill I2C Setting rc =%d",rc); + goto release_mutex; + } + if (fctrl->func_tbl.power_ops(fctrl, true)){ + CAM_ERR(CAM_FLASH, "Power Up Failed"); + goto release_mutex; + } + rc = camera_io_dev_read(&(fctrl->io_master_info), + flash_iic_supplier[1],&flashid, + CAMERA_SENSOR_I2C_TYPE_BYTE, + CAMERA_SENSOR_I2C_TYPE_BYTE); + CAM_DBG(CAM_FLASH, "flashid=%d",flashid); + if ((!rc) && (flashid == flash_iic_supplier[2])) + flash_cap.flash_supplier = 1; + else + flash_cap.flash_supplier = 0; + if (fctrl->func_tbl.power_ops(fctrl, false)){ + CAM_ERR(CAM_FLASH, "Power Down Failed"); + goto release_mutex; + } + } +#endif if (copy_to_user(u64_to_user_ptr(cmd->handle), &flash_cap, sizeof(struct cam_flash_query_cap_info))) { CAM_ERR(CAM_FLASH, "Failed Copy to User"); @@ -440,6 +482,9 @@ static int cam_flash_component_bind(struct device *dev, fctrl->soc_info.dev_name = pdev->name; platform_set_drvdata(pdev, fctrl); +#ifdef CONFIG_CAMERA_FLASH_PWM + dev_set_drvdata(&pdev->dev, fctrl); +#endif rc = cam_flash_get_dt_data(fctrl, &fctrl->soc_info); if (rc) { @@ -482,8 +527,9 @@ static int cam_flash_component_bind(struct device *dev, rc = cam_sensor_util_init_gpio_pin_tbl(soc_info, &fctrl->power_info.gpio_num_info); if ((rc < 0) || (!fctrl->power_info.gpio_num_info)) { - CAM_ERR(CAM_FLASH, "No/Error Flash GPIOs"); - return -EINVAL; + //CAM_ERR(CAM_FLASH, "No/Error Flash GPIOs"); + //return -EINVAL; + CAM_WARN(CAM_FLASH, "No/Error Flash GPIOs"); } rc = cam_sensor_util_regulator_powerup(soc_info); if (rc < 0) { @@ -539,6 +585,9 @@ static int cam_flash_component_bind(struct device *dev, fctrl->flash_state = CAM_FLASH_STATE_INIT; CAM_DBG(CAM_FLASH, "Component bound successfully"); +#ifdef CONFIG_CAMERA_FLASH_PWM + pm6125_flash_control_create_device(&pdev->dev); +#endif return rc; free_cci_resource: @@ -561,6 +610,10 @@ static void cam_flash_component_unbind(struct device *dev, struct cam_flash_ctrl *fctrl; struct platform_device *pdev = to_platform_device(dev); +#ifdef CONFIG_CAMERA_FLASH_PWM + pm6125_flash_control_remove_device(&pdev->dev); +#endif + fctrl = platform_get_drvdata(pdev); if (!fctrl) { CAM_ERR(CAM_FLASH, "Flash device is NULL"); @@ -573,6 +626,9 @@ static void cam_flash_component_unbind(struct device *dev, cam_unregister_subdev(&(fctrl->v4l2_dev_str)); cam_flash_put_source_node_data(fctrl); platform_set_drvdata(pdev, NULL); +#ifdef CONFIG_CAMERA_FLASH_PWM + dev_set_drvdata(&pdev->dev, NULL); +#endif v4l2_set_subdevdata(&fctrl->v4l2_dev_str.sd, NULL); kfree(fctrl); CAM_INFO(CAM_FLASH, "Flash Sensor component unbind"); diff --git a/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h b/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h index f5437c93a843..59af237869c4 100644 --- a/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h +++ b/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_dev.h @@ -153,6 +153,9 @@ struct cam_flash_private_soc { uint32_t torch_max_current[CAM_FLASH_MAX_LED_TRIGGERS]; bool is_wled_flash; uint32_t flash_type; +#ifdef CONFIG_CAMERA_FLASH_PWM + uint32_t flash_gpio_enable; +#endif }; struct cam_flash_func_tbl { @@ -239,7 +242,10 @@ int cam_flash_pmic_flush_request(struct cam_flash_ctrl *fctrl, enum cam_flash_flush_type, uint64_t req_id); void cam_flash_shutdown(struct cam_flash_ctrl *fctrl); int cam_flash_release_dev(struct cam_flash_ctrl *fctrl); - +#ifdef CONFIG_CAMERA_FLASH_IIC_COMPATIBLE +int cam_flash_fill_i2c_default_setting(struct cam_flash_ctrl *fctrl, uint32_t slave_addr); +int cam_flash_fill_vreg_setting(struct cam_flash_ctrl *fctrl); +#endif /** * @brief : API to register FLASH hw to platform framework. * @return struct platform_device pointer on on success, or ERR_PTR() on error. diff --git a/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_soc.c b/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_soc.c index 9eac7a8b8aaf..d5f3f1ca6572 100644 --- a/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_soc.c +++ b/techpack/camera/drivers/cam_sensor_module/cam_flash/cam_flash_soc.c @@ -70,6 +70,10 @@ static int32_t cam_get_source_node_info( struct device_node *flash_src_node = NULL; struct device_node *torch_src_node = NULL; struct device_node *switch_src_node = NULL; +#ifdef CONFIG_CAMERA_FLASH_PWM + int16_t gpio_array_size = 0; + uint16_t *gpio_array = NULL; +#endif soc_private->is_wled_flash = of_property_read_bool(of_node, "wled-flash-support"); @@ -79,7 +83,29 @@ static int32_t cam_get_source_node_info( CAM_ERR(CAM_FLASH, "flash-type read failed rc=%d", rc); soc_private->flash_type = CAM_FLASH_TYPE_PMIC; // default to PMIC flash +#ifdef CONFIG_CAMERA_FLASH_PWM + } else if(soc_private->flash_type == CAM_FLASH_TYPE_GPIO) { + gpio_array_size = of_gpio_count(of_node); + if (gpio_array_size == 1){ + gpio_array = kcalloc(gpio_array_size, sizeof(uint16_t), GFP_KERNEL); + if (!gpio_array) { + CAM_ERR(CAM_FLASH, "flash gpio array alloc fail"); + } else { + for (i = 0; i < gpio_array_size; i++) { + gpio_array[i] = of_get_gpio(of_node, i); + CAM_DBG(CAM_FLASH, "flash dts gpio_array[%d] = %d name is %s %s", i, gpio_array[i], of_node->name, of_node->full_name); + } + soc_private->flash_gpio_enable = gpio_array[0]; + CAM_DBG(CAM_FLASH, "flash gpio enable %d",soc_private->flash_gpio_enable); + kfree(gpio_array); + } + } else { + CAM_ERR(CAM_FLASH, "flash should have two gpio, first is enable in flash dts, second control by flash pm6125"); + } } +#else + } +#endif switch_src_node = of_parse_phandle(of_node, "switch-source", 0); if (!switch_src_node) { diff --git a/techpack/camera/drivers/cam_sensor_module/cam_flash_pm6125_gpio/pm6125_flash_gpio.c b/techpack/camera/drivers/cam_sensor_module/cam_flash_pm6125_gpio/pm6125_flash_gpio.c new file mode 100644 index 000000000000..413f6b73bfc1 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_flash_pm6125_gpio/pm6125_flash_gpio.c @@ -0,0 +1,302 @@ +/* + *Copyright (C) 2021 Motorola Mobility LLC, + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pm6125_flash_gpio.h" +#ifdef CONFIG_CAMERA_FLASH_PWM +#include "cam_flash_dev.h" +#include "cam_flash_soc.h" +#include "cam_flash_core.h" +#include "cam_common_util.h" +#include "cam_res_mgr_api.h" +#endif + + +/***************************************************************************** + * Data Structure + *****************************************************************************/ + +struct pwm_device *pwm; +#ifdef CONFIG_CAMERA_FLASH_PWM +static unsigned int flashlight_enable = CAMERA_SENSOR_FLASH_STATUS_OFF; +static unsigned int flashlight_brightness = 0; +#endif/***************************************************************************** + * Function + *****************************************************************************/ + +void pm6125_flash_gpio_select_state(PM6125_FLASH_GPIO_STATE s, enum camera_flash_opcode opcode, u64 flash_current){ + struct pwm_state pstate; + int rc = 0; + u64 real_current = 0; + + pwm_get_state(pwm, &pstate); + PM6125_FLASH_PRINT("[pm6125_flash_gpio]Status duty_cycle = %u, period = %u\n", + pstate.duty_cycle, pstate.period); + pstate.period = PM6125_PWM_PERIOD; + switch (s) { + case PM6125_FLASH_GPIO_STATE_ACTIVE: + + switch (opcode) + { + case CAMERA_SENSOR_FLASH_OP_FIRELOW: + real_current = (flash_current > FLASH_FIRE_LOW_MAXCURRENT?FLASH_FIRE_LOW_MAXCURRENT:flash_current); + pstate.duty_cycle = PM6125_PWM_PERIOD * real_current / FLASH_FIRE_LOW_MAXCURRENT; + break; + case CAMERA_SENSOR_FLASH_OP_FIREHIGH: + real_current = (flash_current > FLASH_FIRE_HIGH_MAXCURRENT?FLASH_FIRE_HIGH_MAXCURRENT:flash_current); + pstate.duty_cycle = PM6125_PWM_PERIOD * real_current / FLASH_FIRE_HIGH_MAXCURRENT; + break; + default: + pstate.duty_cycle = PM6125_PWM_PERIOD; + break; + } + + pstate.enabled = true; + rc = pwm_apply_state(pwm, &pstate); + + PM6125_FLASH_PRINT("[pm6125_flash_gpio]Active duty_cycle = %u, period = %u, opcode = %u, real_current = %u\n", + pstate.duty_cycle, pstate.period, opcode, real_current); + break; + case PM6125_FLASH_GPIO_STATE_SUSPEND: + pstate.enabled = false; + rc = pwm_apply_state(pwm, &pstate); + PM6125_FLASH_PRINT("[pm6125_flash_gpio]Suspend"); + break; + default: + PM6125_FLASH_PRINT("[pm6125_flash_gpio]Failed to control PWM use a err state!\n"); + } + + if(rc < 0) { + PM6125_FLASH_PRINT("[pm6125_flash_gpio]Apply PWM state fail, rc = %d", rc); + } +} +#ifdef CONFIG_CAMERA_FLASH_PWM +static ssize_t flashlight_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", flashlight_enable); +} + +static ssize_t flashlight_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct cam_flash_ctrl *fctrl = dev_get_drvdata(dev); + struct cam_flash_private_soc *soc_private = fctrl->soc_info.soc_private; + unsigned long state_to_set; + ssize_t ret = -EINVAL; + + CAM_INFO(CAM_FLASH, "Flash Enable Command: %s", buf); + ret = kstrtoul(buf, 10, &state_to_set); + if (ret) + return ret; + + if (CAMERA_SENSOR_FLASH_STATUS_OFF != state_to_set) { + // enable flash + if (CAMERA_SENSOR_FLASH_STATUS_OFF == flashlight_enable) { + ret = cam_res_mgr_gpio_request( + fctrl->soc_info.dev, + soc_private->flash_gpio_enable, 0, + "CUSTOM_GPIO1"); + if (ret) { + CAM_ERR(CAM_FLASH, "gpio %d request fails", + soc_private->flash_gpio_enable); + return ret; + } + } + + flashlight_enable = state_to_set; + cam_res_mgr_gpio_set_value( + soc_private->flash_gpio_enable, + flashlight_enable == CAMERA_SENSOR_FLASH_STATUS_HIGH); + if (flashlight_enable == CAMERA_SENSOR_FLASH_STATUS_LOW) { + pm6125_flash_gpio_select_state( + PM6125_FLASH_GPIO_STATE_ACTIVE, + CAMERA_SENSOR_FLASH_OP_FIRELOW, + FLASH_FIRE_LOW_MAXCURRENT); + usleep_range(5000, 6000); + } + pm6125_flash_gpio_select_state( + PM6125_FLASH_GPIO_STATE_ACTIVE, + flashlight_enable == CAMERA_SENSOR_FLASH_STATUS_HIGH ? + CAMERA_SENSOR_FLASH_OP_FIREHIGH : + CAMERA_SENSOR_FLASH_OP_FIRELOW, + (u64)flashlight_brightness); + } + else { + // disable flash + if (CAMERA_SENSOR_FLASH_STATUS_OFF != flashlight_enable) { + cam_res_mgr_gpio_set_value( + soc_private->flash_gpio_enable, 0); + cam_res_mgr_gpio_free(fctrl->soc_info.dev, + soc_private->flash_gpio_enable); + } + flashlight_enable = CAMERA_SENSOR_FLASH_STATUS_OFF; + pm6125_flash_gpio_select_state(PM6125_FLASH_GPIO_STATE_SUSPEND, + CAMERA_SENSOR_FLASH_OP_OFF, 0); + } + return size; +} + +static ssize_t flashlight_brightness_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", flashlight_brightness); +} + +static ssize_t flashlight_brightness_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct cam_flash_ctrl *fctrl = dev_get_drvdata(dev); + struct cam_flash_private_soc *soc_private = fctrl->soc_info.soc_private; + unsigned long brightness_to_set; + ssize_t ret = -EINVAL; + + CAM_INFO(CAM_FLASH, "Flash Brightness Command: %s", buf); + ret = kstrtoul(buf, 10, &brightness_to_set); + if (ret) + return ret; + + flashlight_brightness = brightness_to_set; + + switch (flashlight_enable) + { + case CAMERA_SENSOR_FLASH_STATUS_LOW: // CAMERA_SENSOR_FLASH_OP_FIRELOW + case CAMERA_SENSOR_FLASH_STATUS_HIGH: // CAMERA_SENSOR_FLASH_OP_FIREHIGH + + CAM_INFO(CAM_FLASH, "Flash Mode %s: %d", + flashlight_enable == CAMERA_SENSOR_FLASH_STATUS_HIGH ? + "High" : + "Low", + flashlight_brightness); + + // disable first + cam_res_mgr_gpio_set_value( + soc_private->flash_gpio_enable, 0); + cam_res_mgr_gpio_free(fctrl->soc_info.dev, + soc_private->flash_gpio_enable); + pm6125_flash_gpio_select_state(PM6125_FLASH_GPIO_STATE_SUSPEND, CAMERA_SENSOR_FLASH_OP_OFF, 0); + + // get handle + ret = cam_res_mgr_gpio_request( + fctrl->soc_info.dev, + soc_private->flash_gpio_enable, 0, + "CUSTOM_GPIO1"); + if (ret) { + CAM_ERR(CAM_FLASH, "gpio %d request fails", + soc_private->flash_gpio_enable); + return ret; + } + + cam_res_mgr_gpio_set_value( + soc_private->flash_gpio_enable, + flashlight_enable == CAMERA_SENSOR_FLASH_STATUS_HIGH); + if (flashlight_enable == CAMERA_SENSOR_FLASH_STATUS_LOW) { + pm6125_flash_gpio_select_state( + PM6125_FLASH_GPIO_STATE_ACTIVE, + CAMERA_SENSOR_FLASH_OP_FIRELOW, + FLASH_FIRE_LOW_MAXCURRENT); + usleep_range(5000, 6000); + } + pm6125_flash_gpio_select_state( + PM6125_FLASH_GPIO_STATE_ACTIVE, + flashlight_enable == CAMERA_SENSOR_FLASH_STATUS_HIGH ? + CAMERA_SENSOR_FLASH_OP_FIREHIGH : + CAMERA_SENSOR_FLASH_OP_FIRELOW, + (u64)flashlight_brightness); + break; + default: + CAM_INFO(CAM_FLASH, "flashlight had not been enable yet."); + break; + } + + return size; +} +static DEVICE_ATTR_RW(flashlight_enable); +static DEVICE_ATTR_RW(flashlight_brightness); +struct device_attribute *flashlight_attributes[] = { + &dev_attr_flashlight_enable, + &dev_attr_flashlight_brightness, +}; +int pm6125_flash_control_create_device(struct device* dev) +{ + int i, ret = 0; + for (i = 0; i < ARRAY_SIZE(flashlight_attributes); i++) { + ret = device_create_file(dev, + flashlight_attributes[i]); + if (ret) { + dev_err(dev, "failed: sysfs file %s\n", + flashlight_attributes[i]->attr.name); + pm6125_flash_control_remove_device(dev); + return ret; + } + } + return 0; +} + +int pm6125_flash_control_remove_device(struct device* dev) +{ + int i; + for (i = 0; i < ARRAY_SIZE(flashlight_attributes); i++) { + device_remove_file(dev, flashlight_attributes[i]); + } + return 0; +} +#endif +static int pm6125_flash_pwm_probe(struct platform_device *pdev) +{ + int rc = 0; + pwm = devm_pwm_get(&pdev->dev, NULL); + if (IS_ERR(pwm)) + return PTR_ERR(pwm); + return rc; +} + +static const struct of_device_id gpio_of_match[] = { + { .compatible = "qualcomm,pm6125_flash_gpio", }, + {}, +}; + +static struct platform_driver pm6125_flash_gpio_platform_driver = { + .probe = pm6125_flash_pwm_probe, + .driver = { + .name = "PM6125_FLASH_GPIO_DTS", + .of_match_table = gpio_of_match, + }, +}; + +int pm6125_flash_gpio_init_module(void) +{ + if (platform_driver_register(&pm6125_flash_gpio_platform_driver)) { + PM6125_FLASH_PRINT("[pm6125_flash_gpio]Failed to register pm6125_flash_gpio_platform_driver!\n"); + return -1; + } + return 0; +} + +void pm6125_flash_gpio_exit_module(void) +{ + platform_driver_unregister(&pm6125_flash_gpio_platform_driver); +} + +MODULE_AUTHOR("liyang "); +MODULE_DESCRIPTION("CONTROL PM6125 FLASH GPIO Driver"); +MODULE_LICENSE("GPL"); \ No newline at end of file diff --git a/techpack/camera/drivers/cam_sensor_module/cam_flash_pm6125_gpio/pm6125_flash_gpio.h b/techpack/camera/drivers/cam_sensor_module/cam_flash_pm6125_gpio/pm6125_flash_gpio.h new file mode 100644 index 000000000000..97b19ea341a6 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_flash_pm6125_gpio/pm6125_flash_gpio.h @@ -0,0 +1,38 @@ +#ifndef _PM6125_FLASH_GPIO_H_ +#define _PM6125_FLASH_GPIO_H_ + +#include "../cam_sensor_utils/cam_sensor_cmn_header.h" + +#define PM6125_FLASH_PRINT pr_info //printk + +/* DTS state */ +typedef enum { + PM6125_FLASH_GPIO_STATE_ACTIVE, + PM6125_FLASH_GPIO_STATE_SUSPEND, + PM6125_FLASH_GPIO_STATE_MAX, /* for array size */ +} PM6125_FLASH_GPIO_STATE; + +#ifdef CONFIG_CAMERA_FLASH_PWM +enum{ + CAMERA_SENSOR_FLASH_STATUS_OFF, + CAMERA_SENSOR_FLASH_STATUS_LOW, + CAMERA_SENSOR_FLASH_STATUS_HIGH +}; +#endif + + +#define PM6125_PWM_PERIOD 50000 +#define FLASH_FIRE_HIGH_MAXCURRENT 1200 +#define FLASH_FIRE_LOW_MAXCURRENT 150 + +/***************************************************************************** + * Function Prototype + *****************************************************************************/ +extern void pm6125_flash_gpio_select_state(PM6125_FLASH_GPIO_STATE s, enum camera_flash_opcode opcode, u64 flash_current); +#ifdef CONFIG_CAMERA_FLASH_PWM +extern int pm6125_flash_control_create_device(struct device* dev); +extern int pm6125_flash_control_remove_device(struct device* dev); +#endif +int pm6125_flash_gpio_init_module(void); +void pm6125_flash_gpio_exit_module(void); +#endif /* _PM6125_FLASH_GPIO_H_*/ diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_aw86006.c b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_aw86006.c new file mode 100644 index 000000000000..5c2fcbc1d719 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_aw86006.c @@ -0,0 +1,2385 @@ +/* + * File: cam_ois_aw86006.c + * + * Author: hushanping + * + * Copyright (c) 2021 AWINIC Technology CO., LTD + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_ois_core.h" +#include "cam_ois_soc.h" +#include "cam_ois_dev.h" +#include "cam_cci_dev.h" +#include "cam_sensor_util.h" +#include "cam_debug_util.h" +#include "cam_res_mgr_api.h" +#include "cam_common_util.h" +#include "cam_packet_util.h" +#include "cam_ois_aw86006.h" + +#define AW86006_DRIVER_VERSION "v0.5.0.9" +#define AW86006_FW_NAME "mot_aw86006.prog" + +const char fw_check_str[] = { 'A', 'W', 'I', 'N', 'I', 'C', 0, 0 }; +struct cam_ois_ctrl_t *g_o_ctrl; +static struct class *ois_debug_class; +struct aw86006_info g_aw86006_info = { + .already_update = 0, + .checkinfo_fw = { 0 }, + .checkinfo_rd = { 0 }, + .fw = { 0 }, +}; + +static int ois_block_read_addr8_data8(struct cam_ois_ctrl_t *o_ctrl, + uint32_t addr, uint32_t addr_type, uint8_t *data, uint32_t num_byte) +{ + enum i2c_freq_mode temp_freq; + int ret = OIS_ERROR; + + if (o_ctrl == NULL || data == NULL) { + AW_LOGE("Invalid Args o_ctrl: %pK, data: %pK", o_ctrl, data); + return -EINVAL; + } + if (o_ctrl->cam_ois_state < CAM_OIS_CONFIG) { + AW_LOGE("Not in right state to start soc reads: %d", + o_ctrl->cam_ois_state); + return -EINVAL; + } + temp_freq = o_ctrl->io_master_info.cci_client->i2c_freq_mode; + /* Modify i2c freq to 100K */ + o_ctrl->io_master_info.cci_client->i2c_freq_mode = I2C_STANDARD_MODE; + ret = camera_io_dev_read_seq(&(o_ctrl->io_master_info), addr, data, + addr_type, CAMERA_SENSOR_I2C_TYPE_BYTE, num_byte); + if (ret < 0) + AW_LOGE("err! ret:%d", ret); + o_ctrl->io_master_info.cci_client->i2c_freq_mode = temp_freq; + + return ret; +} + +static int ois_block_write_addr8_data8(struct cam_ois_ctrl_t *o_ctrl, + uint32_t addr, uint32_t addr_type, uint8_t *data, uint32_t num_byte) +{ + int ret = OIS_ERROR; + int cnt; + enum i2c_freq_mode temp_freq; + struct cam_sensor_i2c_reg_setting i2c_reg_setting; + + + if (o_ctrl == NULL || data == NULL) { + AW_LOGE("Invalid Args o_ctrl: %pK, data: %pK", o_ctrl, data); + return -EINVAL; + } + if (o_ctrl->cam_ois_state < CAM_OIS_CONFIG) { + AW_LOGE("Not in right state to start soc writes: %d", + o_ctrl->cam_ois_state); + return -EINVAL; + } + temp_freq = o_ctrl->io_master_info.cci_client->i2c_freq_mode; + o_ctrl->io_master_info.cci_client->i2c_freq_mode = I2C_FAST_PLUS_MODE; + i2c_reg_setting.addr_type = addr_type; + i2c_reg_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + i2c_reg_setting.size = num_byte; + i2c_reg_setting.delay = 0; + i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) + kzalloc(sizeof(struct cam_sensor_i2c_reg_array) * + num_byte, GFP_KERNEL); + if (i2c_reg_setting.reg_setting == NULL) { + AW_LOGE("kzalloc failed"); + return OIS_ERROR; + } + i2c_reg_setting.reg_setting[0].reg_addr = addr; + i2c_reg_setting.reg_setting[0].reg_data = data[0]; + i2c_reg_setting.reg_setting[0].delay = 0; + i2c_reg_setting.reg_setting[0].data_mask = 0; + for (cnt = 1; cnt < num_byte; cnt++) { + i2c_reg_setting.reg_setting[cnt].reg_addr = 0; + i2c_reg_setting.reg_setting[cnt].reg_data = data[cnt]; + i2c_reg_setting.reg_setting[cnt].delay = 0; + i2c_reg_setting.reg_setting[cnt].data_mask = 0; + } + ret = camera_io_dev_write_continuous(&(o_ctrl->io_master_info), + &i2c_reg_setting, 0); + if (ret < 0) + AW_LOGE("err! ret:%d", ret); + o_ctrl->io_master_info.cci_client->i2c_freq_mode = temp_freq; + kfree(i2c_reg_setting.reg_setting); + + return ret; +} + +static int aw86006_reset(struct cam_ois_ctrl_t *o_ctrl) +{ + int ret = OIS_ERROR; + uint16_t temp_addr; + uint8_t boot_cmd_1[] = { 0xFF, 0xF0, 0x20, 0x20, 0x02, 0x02, 0x19, 0x29, + 0x19, 0x29 }; + uint8_t boot_cmd_2[] = { 0xFF, 0xC4, 0xC4 }; + uint8_t boot_cmd_3[] = { 0xFF, 0xC4, 0x00 }; + uint8_t boot_cmd_4[] = { 0xFF, 0x10, 0xC3 }; + + AW_LOGI("enter"); + + /* first: shutdown */ + temp_addr = o_ctrl->io_master_info.cci_client->sid; + o_ctrl->io_master_info.cci_client->sid = AW_SHUTDOWN_I2C_ADDR; + ret = ois_block_write_addr8_data8(o_ctrl, boot_cmd_1[0], + CAMERA_SENSOR_I2C_TYPE_BYTE, + &boot_cmd_1[1], sizeof(boot_cmd_1) - 1); + if (ret < 0) { + AW_LOGE("boot_cmd_1 write error!"); + goto err_exit; + } + ret = ois_block_write_addr8_data8(o_ctrl, boot_cmd_2[0], + CAMERA_SENSOR_I2C_TYPE_BYTE, + &boot_cmd_2[1], sizeof(boot_cmd_2) - 1); + if (ret < 0) { + AW_LOGE("boot_cmd_2 write error!"); + goto err_exit; + } + usleep_range(AW_SHUTDOWN_DELAY, AW_SHUTDOWN_DELAY + 50); /* 2 ms */ + /* second: wake up */ + o_ctrl->io_master_info.cci_client->sid = AW_WAKEUP_I2C_ADDR; + ret = ois_block_write_addr8_data8(o_ctrl, boot_cmd_3[0], + CAMERA_SENSOR_I2C_TYPE_BYTE, + &boot_cmd_3[1], sizeof(boot_cmd_3) - 1); + if (ret < 0) { + AW_LOGE("boot_cmd_3 write error!"); + goto err_exit; + } + ret = ois_block_write_addr8_data8(o_ctrl, boot_cmd_4[0], + CAMERA_SENSOR_I2C_TYPE_BYTE, + &boot_cmd_4[1], sizeof(boot_cmd_4) - 1); + if (ret < 0) { + AW_LOGE("boot_cmd_4 write error!"); + goto err_exit; + } + + o_ctrl->io_master_info.cci_client->sid = temp_addr; + + AW_LOGD("end"); + + return OIS_SUCCESS; + + err_exit: + o_ctrl->io_master_info.cci_client->sid = temp_addr; + return OIS_ERROR; +} + +static int aw86006_runtime_check(struct cam_ois_ctrl_t *o_ctrl) +{ + int ret = OIS_ERROR; + uint32_t version = 0; + uint8_t reg_val[4] = { 0 }; + uint8_t chip_id = 0; + + AW_LOGI("enter"); + + ret = ois_block_read_addr8_data8(o_ctrl, REG_CHIPID, + CAMERA_SENSOR_I2C_TYPE_WORD, &chip_id, 1); + if (ret < 0) { + AW_LOGE("read chipid error!"); + return ret; + } + + ret = ois_block_read_addr8_data8(o_ctrl, REG_VERSION, + CAMERA_SENSOR_I2C_TYPE_WORD, ®_val[0], 4); + if (ret < 0) { + AW_LOGE("read version error!"); + return ret; + } + version = (reg_val[3] << AW_DATA_SHIFT_24_BIT) | + (reg_val[2] << AW_DATA_SHIFT_16_BIT) | + (reg_val[1] << AW_DATA_SHIFT_8_BIT) | + (reg_val[0] << AW_DATA_SHIFT_0_BIT); + + AW_LOGI("Chip_ID: 0x%02X, Version: v%d.%d.%d.%d", chip_id, reg_val[3], + reg_val[2], reg_val[1], reg_val[0]); + + if ((chip_id != g_aw86006_info.fw.app_id) || + (version != g_aw86006_info.fw.app_version)) { + AW_LOGE("Chip_ID or Version not match!"); + return OIS_ERROR; + } + AW_LOGI("pass!"); + + return OIS_SUCCESS; +} + +static int aw86006_soc_buf_build(struct cam_ois_ctrl_t *o_ctrl, uint8_t *buf, + struct soc_protocol *soc_struct) +{ + int i = 0; + uint8_t *p_head = (uint8_t *) soc_struct; + uint8_t checksum = 0; + uint8_t data_sum = 0; + + if ((buf == NULL) || ((soc_struct == NULL))) + return OIS_ERROR; + if (soc_struct->p_data == NULL) + soc_struct->len[0] = 0; + soc_struct->protocol_ver = SOC_VERSION; + soc_struct->ack = SOC_ACK; + soc_struct->addr = + ((soc_struct->ack_juge == SOC_CTL) ? SOC_ADDR : SOC_READ_ADDR); + for (i = 0; i < soc_struct->len[0]; i++) { + data_sum += soc_struct->p_data[i]; + buf[i + SOC_PROTOCAL_HEAD] = soc_struct->p_data[i]; + } + soc_struct->sum = data_sum; + for (i = 1; i < SOC_PROTOCAL_HEAD; i++) { + checksum += p_head[i]; + buf[i] = p_head[i]; + } + soc_struct->checksum = checksum; + buf[0] = p_head[0]; + + return OIS_SUCCESS; +} + +static int aw86006_soc_connect_check(struct cam_ois_ctrl_t *o_ctrl) +{ + struct soc_protocol soc_struct = { 0 }; + int ret = OIS_ERROR; + uint8_t w_buf[14] = { 0 }; + uint8_t r_buf[14] = { 0 }; + uint8_t cmp_buf[5] = {0x00, 0x01, 0x00, 0x00, 0x00}; + + soc_struct.module = SOC_HANK; + + soc_struct.event = SOC_HANK_CONNECT; + soc_struct.len[0] = 0; + soc_struct.p_data = NULL; + soc_struct.ack_juge = SOC_CTL; + + memset(w_buf, 0, sizeof(w_buf)); + aw86006_soc_buf_build(o_ctrl, w_buf, &soc_struct); + ret = ois_block_write_addr8_data8(o_ctrl, w_buf[0], + CAMERA_SENSOR_I2C_TYPE_BYTE, &w_buf[1], + SOC_CONNECT_WRITE_LEN - 1); + if (ret < 0) { + AW_LOGE("write connect w_buf error!"); + return ret; + } + + usleep_range(SOC_CONNECT_DELAY, SOC_CONNECT_DELAY + 50); + + memset(r_buf, 0, sizeof(r_buf)); + ret = ois_block_read_addr8_data8(o_ctrl, AW_I2C_WRITE_BYTE_ZERO, + CAMERA_SENSOR_I2C_TYPE_BYTE, &r_buf[0], 14); + if (ret < 0) { + AW_LOGE("read connect r_buf error!"); + return ret; + } + /* regroup w_buf */ + soc_struct.event = SOC_HANK_CONNECT_ACK; + soc_struct.ack_juge = SOC_ACK; + soc_struct.len[0] = 5; + soc_struct.p_data = cmp_buf; + + memset(w_buf, 0, sizeof(w_buf)); + aw86006_soc_buf_build(o_ctrl, w_buf, &soc_struct); + + ret = memcmp(w_buf, r_buf, sizeof(r_buf)); + if (ret != 0) { + AW_LOGE("connect memcmp error!"); + return OIS_ERROR; + } + + return OIS_SUCCESS; +} + +static int aw86006_soc_flash_read_check(struct cam_ois_ctrl_t *o_ctrl, + uint32_t addr, uint8_t *bin_buf, uint32_t len) +{ + struct soc_protocol soc_struct = { 0 }; + int i = 0; + int ret = OIS_ERROR; + int loop = 0; + uint8_t temp_buf[SOC_READ_STRUCT_LEN] = { 0 }; + uint8_t w_buf[SOC_READ_WRITE_LEN] = { 0 }; + uint8_t r_buf[80] = { 0 }; + uint8_t checksum = 0; + + temp_buf[0] = len; + temp_buf[1] = 0; + for (i = 0; i < 4; i++) + temp_buf[i + 2] = (uint8_t) (addr >> (i * 8)); + soc_struct.module = SOC_FLASH; + + do { + soc_struct.event = SOC_FLASH_READ; + soc_struct.len[0] = SOC_READ_STRUCT_LEN; + soc_struct.p_data = temp_buf; + soc_struct.ack_juge = SOC_CTL; + + memset(w_buf, 0, sizeof(w_buf)); + aw86006_soc_buf_build(o_ctrl, w_buf, &soc_struct); + ret = ois_block_write_addr8_data8(o_ctrl, w_buf[0], + CAMERA_SENSOR_I2C_TYPE_BYTE, + &w_buf[1], sizeof(w_buf) - 1); + if (ret < 0) { + AW_LOGE("i2c write w_buf error, loop: %d", loop); + continue; + } + usleep_range(SOC_READ_BLOCK_DELAY, SOC_READ_BLOCK_DELAY + 50); + + memset(r_buf, 0, sizeof(r_buf)); + ret = ois_block_read_addr8_data8(o_ctrl, AW_I2C_WRITE_BYTE_ZERO, + CAMERA_SENSOR_I2C_TYPE_BYTE, &r_buf[0], 14 + len); + if (ret < 0) { + AW_LOGE("i2c read r_buf error, loop: %d", loop); + continue; + } + /* check error flag */ + if (r_buf[9] != OIS_SUCCESS) { + AW_LOGE("flag error: %d, loop: %d", r_buf[10], loop); + continue; + } + checksum = 0; + /* compute data checksum */ + for (i = 0; i < len + 5; i++) + checksum += r_buf[9 + i]; + if (checksum != r_buf[8]) { + AW_LOGE("data checksum error: 0x%02x != 0x%02x", + checksum, r_buf[8]); + continue; + } + checksum = 0; + /* compute head checksum */ + for (i = 1; i < 9; i++) + checksum += r_buf[i]; + if (checksum != r_buf[0]) { + AW_LOGE("head checksum error: 0x%02x != 0x%02x", + checksum, r_buf[0]); + continue; + } + memcpy(bin_buf, (uint8_t *)&r_buf[14], len); + break; /* Check pass */ + } while ((++loop) < AW_FLASH_READ_ERROR_LOOP); + if (loop >= AW_FLASH_READ_ERROR_LOOP) + return OIS_ERROR; + + return OIS_SUCCESS; +} + +static int aw86006_soc_flash_write_check(struct cam_ois_ctrl_t *o_ctrl, + uint32_t addr, uint32_t block_num, + uint8_t *bin_buf, uint32_t len) +{ + struct soc_protocol soc_struct = { 0 }; + int i = 0; + int ret = OIS_ERROR; + int loop = 0; + +#ifdef AW_FLASH_WRITE_CONNECT + int connect_loop = 0; +#endif + + uint8_t temp_buf[68] = { 0 }; + uint8_t w_buf[77] = { 0 }; + uint8_t r_buf[10] = { 0 }; + uint8_t cmp_buf[1] = { 0 }; + + for (i = 0; i < 4; i++) + temp_buf[i] = (uint8_t) ((addr + + block_num * AW_FLASH_WRITE_LEN) >> (i * 8)); + for (i = 0; i < len; i++) + temp_buf[i + 4] = (bin_buf + block_num * AW_FLASH_WRITE_LEN)[i]; + + soc_struct.module = SOC_FLASH; + +#ifdef AW_FLASH_WRITE_CONNECT + do { + ret = aw86006_soc_connect_check(o_ctrl); + if (ret == OIS_SUCCESS) + break; + AW_LOGE("connect_loop error ret: %d, connect_loop: %d", ret, + connect_loop); + } while ((++connect_loop) < AW_ERROR_LOOP); + if (connect_loop >= AW_ERROR_LOOP) + return OIS_ERROR; +#endif + + do { + soc_struct.event = SOC_FLASH_WRITE; + soc_struct.len[0] = (uint8_t) (4 + len); + soc_struct.p_data = temp_buf; + soc_struct.ack_juge = SOC_CTL; + + memset(w_buf, 0, sizeof(w_buf)); + aw86006_soc_buf_build(o_ctrl, w_buf, &soc_struct); + ret = ois_block_write_addr8_data8(o_ctrl, w_buf[0], + CAMERA_SENSOR_I2C_TYPE_BYTE, &w_buf[1], + SOC_WRITE_BLOCK_HEAD - 1 + len); + if (ret < 0) { + AW_LOGE("i2c write w_buf error, loop: %d", loop); + continue; + } + usleep_range(SOC_WRITE_BLOCK_DELAY, SOC_WRITE_BLOCK_DELAY + 50); + + memset(r_buf, 0, sizeof(r_buf)); + ret = ois_block_read_addr8_data8(o_ctrl, AW_I2C_WRITE_BYTE_ZERO, + CAMERA_SENSOR_I2C_TYPE_BYTE, &r_buf[0], 10); + if (ret < 0) { + AW_LOGE("i2c read r_buf error, loop: %d", loop); + continue; + } + /* regroup w_buf */ + soc_struct.event = SOC_FLASH_WRITE_ACK; + soc_struct.len[0] = 1; + soc_struct.p_data = cmp_buf; + soc_struct.ack_juge = SOC_ACK; + + memset(w_buf, 0, sizeof(w_buf)); + aw86006_soc_buf_build(o_ctrl, w_buf, &soc_struct); + ret = memcmp(w_buf, r_buf, sizeof(r_buf)); + if (ret == 0) + break; + + AW_LOGI("memcmp error, try again, loop: %d", loop); + } while ((++loop) < AW_FLASH_WRITE_ERROR_LOOP); + if (loop >= AW_FLASH_WRITE_ERROR_LOOP) + return OIS_ERROR; + + return OIS_SUCCESS; +} + +static int aw86006_soc_flash_erase_check(struct cam_ois_ctrl_t *o_ctrl, + uint32_t addr, uint32_t len) +{ + struct soc_protocol soc_struct = { 0 }; + uint32_t erase_block = 0; + int i = 0; + int ret = OIS_ERROR; + int loop = 0; + uint8_t temp_buf[6] = { 0 }; + uint8_t cmp_buf[1] = { 0 }; + uint8_t w_buf[15] = { 0 }; + uint8_t r_buf[10] = { 0 }; + + erase_block = len / AW_FLASH_ERASE_LEN + + ((len % AW_FLASH_ERASE_LEN) ? 1 : 0); + + temp_buf[0] = (uint8_t) erase_block; + temp_buf[1] = 0x00; + for (i = 0; i < 4; i++) + temp_buf[i + 2] = (uint8_t) (addr >> (i * 8)); + + soc_struct.module = SOC_FLASH; + + do { + soc_struct.event = SOC_FLASH_ERASE_BLOCK; + soc_struct.len[0] = SOC_ERASE_STRUCT_LEN; + soc_struct.p_data = temp_buf; + soc_struct.ack_juge = SOC_CTL; + + memset(w_buf, 0, sizeof(w_buf)); + aw86006_soc_buf_build(o_ctrl, w_buf, &soc_struct); + ret = ois_block_write_addr8_data8(o_ctrl, w_buf[0], + CAMERA_SENSOR_I2C_TYPE_BYTE, &w_buf[1], + SOC_ERASE_WRITE_LEN - 1); + if (ret < 0) { + AW_LOGE("i2c write w_buf error, loop: %d", loop); + continue; + } + msleep(erase_block * SOC_ERASE_BLOCK_DELAY); + + memset(r_buf, 0, sizeof(r_buf)); + ret = ois_block_read_addr8_data8(o_ctrl, AW_I2C_WRITE_BYTE_ZERO, + CAMERA_SENSOR_I2C_TYPE_BYTE, &r_buf[0], 10); + if (ret < 0) { + AW_LOGE("i2c read r_buf error, loop: %d", loop); + continue; + } + soc_struct.event = SOC_FLASH_ERASE_BLOCK_ACK; + soc_struct.len[0] = 1; + soc_struct.ack_juge = SOC_ACK; + soc_struct.p_data = cmp_buf; + + memset(w_buf, 0, sizeof(w_buf)); + aw86006_soc_buf_build(o_ctrl, w_buf, &soc_struct); + ret = memcmp(w_buf, r_buf, sizeof(r_buf)); + if (ret == 0) + break; + + AW_LOGI("memcmp error, try again, loop: %d", loop); + } while ((++loop) < AW_FLASH_ERASE_ERROR_LOOP); + if (loop >= AW_FLASH_ERASE_ERROR_LOOP) + return OIS_ERROR; + + AW_LOGI("flash erase success!, addr: 0x%08x, len: 0x%08x", addr, len); + + return OIS_SUCCESS; +} + +static int aw86006_soc_flash_download_check(struct cam_ois_ctrl_t *o_ctrl, + uint32_t addr, uint8_t *bin_buf, size_t len) +{ + uint32_t flash_block = 0; + uint32_t flash_tail = 0; + uint32_t flash_checkinfo = 0; + int i = 0; + int ret = OIS_ERROR; + + flash_block = len / AW_FLASH_WRITE_LEN; + flash_tail = len % AW_FLASH_WRITE_LEN; + + if (addr == AW_FLASH_BASE_ADDR) { + flash_checkinfo = AW_FLASH_MOVE_LENGTH / AW_FLASH_WRITE_LEN; + /* first erase app+info data */ + ret = aw86006_soc_flash_erase_check(o_ctrl, AW_FLASH_APP_ADDR, + len - AW_FLASH_MOVE_LENGTH); + if (ret != OIS_SUCCESS) { + AW_LOGE("Failed to erase app+checkinfo"); + return OIS_ERROR; + } + /* then erase move data */ + ret = aw86006_soc_flash_erase_check(o_ctrl, AW_FLASH_BASE_ADDR, + AW_FLASH_MOVE_LENGTH); + if (ret != OIS_SUCCESS) { + AW_LOGE("Failed to erase move"); + return OIS_ERROR; + } + /* write move data */ + for (i = 0; i < flash_checkinfo; i++) { + ret = aw86006_soc_flash_write_check(o_ctrl, addr, i, + bin_buf, AW_FLASH_WRITE_LEN); + if (ret != OIS_SUCCESS) { + AW_LOGE("Failed to write flash block: %d", i); + return OIS_ERROR; + } + } + /* write app block data */ + for (i = flash_checkinfo + 1; i < flash_block; i++) { + ret = aw86006_soc_flash_write_check(o_ctrl, addr, i, + bin_buf, AW_FLASH_WRITE_LEN); + if (ret != OIS_SUCCESS) { + AW_LOGE("Failed to write flash block: %d", i); + return OIS_ERROR; + } + } + /* write app tail data */ + if ((flash_tail != 0) && (len > AW_FLASH_MOVE_LENGTH)) { + ret = aw86006_soc_flash_write_check(o_ctrl, addr, i, + bin_buf, flash_tail); + if (ret != OIS_SUCCESS) { + AW_LOGE("Failed to write flash app tail"); + return OIS_ERROR; + } + } + } else if (addr == AW_FLASH_APP_ADDR) { + flash_checkinfo = 0; + /* erase app+info data */ + ret = aw86006_soc_flash_erase_check(o_ctrl, AW_FLASH_APP_ADDR, + len); + if (ret != OIS_SUCCESS) { + AW_LOGE("Failed to erase app+checkinfo!"); + return OIS_ERROR; + } + /* write app block data */ + for (i = 1; i < flash_block; i++) { + ret = aw86006_soc_flash_write_check(o_ctrl, addr, i, + bin_buf, AW_FLASH_WRITE_LEN); + if (ret != OIS_SUCCESS) { + AW_LOGE("Failed to write flash block: %d", i); + return OIS_ERROR; + } + } + /* write app tail data */ + if (flash_tail != 0) { + ret = aw86006_soc_flash_write_check(o_ctrl, addr, i, + bin_buf, flash_tail); + if (ret != OIS_SUCCESS) { + AW_LOGE("Failed to write flash tail"); + return OIS_ERROR; + } + } + } else { + AW_LOGE("wrong addr!"); + return OIS_ERROR; + } + + /* Write checkinfo data */ + ret = aw86006_soc_flash_write_check(o_ctrl, AW_FLASH_APP_ADDR, 0, + g_aw86006_info.checkinfo_fw, + AW_FLASH_WRITE_LEN); + if (ret != OIS_SUCCESS) { + AW_LOGE("Failed to write checkinfo!"); + return OIS_ERROR; + } + + return OIS_SUCCESS; +} + +static int aw86006_jump_move_check(struct cam_ois_ctrl_t *o_ctrl) +{ + ktime_t kstart; + ktime_t kend; + uint32_t move_version = 0; + uint32_t ms_count_reset = 0; + uint32_t ms_count_stop = 0; + uint32_t ms_first_f0 = 0; + int ret = OIS_ERROR; + int i = 0; + int jump_loop = 0; + uint8_t move_cmd[] = {0xF0, 0xF0, 0xF0}; + uint8_t version_cmd[] = {0x00, 0x55}; + uint8_t version_ack[5] = {0x00}; + + do { + ret = aw86006_reset(o_ctrl); + if (ret != OIS_SUCCESS) { + AW_LOGE("aw86006_reset error, ret: %d, loop: %d", ret, + jump_loop); + continue; + } + /* delay: 9ms */ + kstart = ktime_get(); + for (i = 0; i < AW_JUMP_MOVE_DELAY_MAX; i++) { + mdelay(1); + kend = ktime_get(); + ms_count_reset = ktime_to_ms(ktime_sub(kend, kstart)); + if (ms_count_reset >= AW_JUMP_MOVE_DELAY) + break; + } + if (ms_count_reset >= AW_JUMP_MOVE_DELAY_MAX) { + AW_LOGE("ms_count_reset timeout: %d, loop: %d", + ms_count_reset, jump_loop); + continue; + } + /* send jump cmd */ + for (i = 0; i < AW_STAY_ON_MOVE_LOOP; i++) { /* loop 20 */ + ois_block_write_addr8_data8(o_ctrl, move_cmd[0], + CAMERA_SENSOR_I2C_TYPE_BYTE, &move_cmd[1], + sizeof(move_cmd) - 1); + if (i == 0) { + kend = ktime_get(); + ms_first_f0 = + ktime_to_ms(ktime_sub(kend, kstart)); + } + } + + kend = ktime_get(); + ms_count_stop = ktime_to_ms(ktime_sub(kend, kstart)); + AW_LOGD("ms_count_reset: %u, ms_count_stop: %u", ms_count_reset, + ms_count_stop); + + if (ms_first_f0 > AW_JUMP_MOVE_DELAY_MAX) { + AW_LOGI("first 0xF0: %d ms", ms_first_f0); + continue; + } + + /* send read move version cmd */ + ret = ois_block_write_addr8_data8(o_ctrl, version_cmd[0], + CAMERA_SENSOR_I2C_TYPE_BYTE, &version_cmd[1], + sizeof(version_cmd) - 1); + if (ret < 0) { + AW_LOGE("write version_cmd failed! loop:%d", jump_loop); + continue; + } + usleep_range(ISP_READ_VERSION_DELAY, + ISP_READ_VERSION_DELAY + 50); + ret = ois_block_read_addr8_data8(o_ctrl, ISP_VERS_CONNECT_ACK, + CAMERA_SENSOR_I2C_TYPE_BYTE, + &version_ack[0], ISP_VERSION_ACK_LEN); + if (ret < 0) { + AW_LOGE("read version error, loop: %d", jump_loop); + continue; + } + + if (version_ack[0] != ISP_EVENT_OK) { + AW_LOGE("wrong version_ack: %d, loop: %d", + version_ack[0], jump_loop); + continue; + } + move_version = (version_ack[4] << AW_DATA_SHIFT_24_BIT) | + (version_ack[3] << AW_DATA_SHIFT_16_BIT) | + (version_ack[2] << AW_DATA_SHIFT_8_BIT) | + (version_ack[1] << AW_DATA_SHIFT_0_BIT); + + if (move_version == g_aw86006_info.fw.move_version) + break; + + AW_LOGE("move_version not match: 0x%08X != 0x%08X, loop: %d", + move_version, g_aw86006_info.fw.move_version, + jump_loop); + } while ((++jump_loop) < AW_JUMP_MOVE_LOOP); + if (jump_loop >= AW_JUMP_MOVE_LOOP) + return OIS_ERROR; + + AW_LOGI("Jump move success! move_version: 0x%08X", move_version); + return OIS_SUCCESS; +} + +static int aw86006_jump_boot_check(struct cam_ois_ctrl_t *o_ctrl) +{ + ktime_t kend; + ktime_t kstart; + uint32_t ms_count_reset = 0; + uint32_t ms_count_stop = 0; + uint32_t ms_first_ac = 0; + int ret = OIS_ERROR; + int i = 0; + int jump_loop = 0; + uint8_t boot_cmd[] = {0xAC, 0xAC, 0xAC}; + + do { + ret = aw86006_reset(o_ctrl); + if (ret != OIS_SUCCESS) { + AW_LOGE("aw86006_reset error, ret: %d, loop: %d", ret, + jump_loop); + continue; + } + /* delay: 2ms */ + kstart = ktime_get(); + for (i = 0; i < AW_JUMP_BOOT_DELAY_MAX; i++) { + mdelay(1); + kend = ktime_get(); + ms_count_reset = ktime_to_ms(ktime_sub(kend, kstart)); + if (ms_count_reset >= AW_JUMP_BOOT_DELAY) + break; + } + if (ms_count_reset >= AW_JUMP_BOOT_DELAY_MAX) { + AW_LOGE("ms_count_reset timeout: %d, loop: %d", + ms_count_reset, jump_loop); + continue; + } + /* send jump boot cmd */ + for (i = 0; i < AW_STAY_ON_BOOT_LOOP; i++) { + ois_block_write_addr8_data8(o_ctrl, boot_cmd[0], + CAMERA_SENSOR_I2C_TYPE_BYTE, + &boot_cmd[1], sizeof(boot_cmd) - 1); + if (i == 0) { + kend = ktime_get(); + ms_first_ac = + ktime_to_ms(ktime_sub(kend, kstart)); + } + } + /* get the end time of send boot cmd */ + kend = ktime_get(); + ms_count_stop = ktime_to_ms(ktime_sub(kend, kstart)); + AW_LOGD("ms_count_reset: %u, ms_count_stop: %u", + ms_count_reset, ms_count_stop); + if (ms_first_ac > AW_JUMP_BOOT_DELAY_MAX) { + AW_LOGI("first 0xAC: %d ms", ms_first_ac); + continue; + } + + ret = aw86006_soc_connect_check(o_ctrl); + if (ret == OIS_SUCCESS) + break; + + AW_LOGE("soc connect failed, ret:%d, loop: %d", ret, jump_loop); + } while ((++jump_loop) < AW_JUMP_BOOT_LOOP); + if (jump_loop >= AW_JUMP_BOOT_LOOP) + return OIS_ERROR; + + AW_LOGI("success"); + + return OIS_SUCCESS; +} + +static int aw86006_soc_flash_update(struct cam_ois_ctrl_t *o_ctrl, + uint32_t addr, uint8_t *data_p, size_t fw_size) +{ + int ret = OIS_ERROR; + int loop = 0; + + if (!data_p) { + AW_LOGE("data_p is NULL"); + return OIS_ERROR; + } + /* enter boot mode */ + ret = aw86006_jump_boot_check(o_ctrl); + if (ret != OIS_SUCCESS) { + AW_LOGE("jump boot failed!"); + return OIS_ERROR; + } + /* update flash */ + do { + ret = aw86006_soc_flash_download_check(o_ctrl, addr, data_p, + fw_size); + if (ret == OIS_SUCCESS) + break; + AW_LOGE("soc_flash_download_check failed! loop: %d", loop); + } while ((++loop) < AW_ERROR_LOOP); + if (loop >= AW_ERROR_LOOP) + return OIS_ERROR; + + ret = aw86006_reset(o_ctrl); + if (ret != OIS_SUCCESS) { + AW_LOGE("aw86006_reset failed!"); + return OIS_ERROR; + } + msleep(AW_RESET_DELAY); + + AW_LOGI("success!"); + + return OIS_SUCCESS; +} + +static int aw86006_firmware_check(struct cam_ois_ctrl_t *o_ctrl, + const struct firmware *fw) +{ + uint32_t temp = 0; + uint32_t *check_ptr = NULL; + int i = 0; + int ret = OIS_ERROR; + char *identify = (char *)fw->data + AW_FW_SHIFT_IDENTIFY; + + if (fw == NULL) { + AW_LOGE("FW Empty!!!"); + return OIS_ERROR; + } + + ret = memcmp(fw_check_str, identify, 8); /* AWINIC00 8bytes */ + if (ret != 0) { + AW_LOGE("loaded wrong firmware!"); + return OIS_ERROR; + } + + /* get fw info */ + g_aw86006_info.fw.size = fw->size; + g_aw86006_info.fw.checksum = + *(uint32_t *) (&fw->data[AW_FW_SHIFT_CHECKSUM]); + g_aw86006_info.fw.app_checksum = + *(uint32_t *) (&fw->data[AW_FW_SHIFT_APP_CHECKSUM]); + /* app_length: app + check_info */ + g_aw86006_info.fw.app_length = + *(uint32_t *) (&fw->data[AW_FW_SHIFT_APP_LENGTH]) + + AW_FW_INFO_LENGTH; + g_aw86006_info.fw.app_version = + *(uint32_t *) (&fw->data[AW_FW_SHIFT_APP_VERSION]); + g_aw86006_info.fw.app_id = + *(uint32_t *) (&fw->data[AW_FW_SHIFT_APP_ID]); + g_aw86006_info.fw.move_checksum = + *(uint32_t *) (&fw->data[AW_FW_SHIFT_MOVE_CHECKSUM]); + g_aw86006_info.fw.move_version = + *(uint32_t *) (&fw->data[AW_FW_SHIFT_MOVE_VERSION]); + g_aw86006_info.fw.move_length = + *(uint32_t *) (&fw->data[AW_FW_SHIFT_MOVE_LENGTH]); + + AW_LOGI("fw->size:0x%04X, app_length:0x%04X, app_version:0x%08X", + g_aw86006_info.fw.size, + g_aw86006_info.fw.app_length, + g_aw86006_info.fw.app_version); + AW_LOGI("app_id:0x%02X, move_version:0x%08X, move_length:0x%04X", + g_aw86006_info.fw.app_id, + g_aw86006_info.fw.move_version, + g_aw86006_info.fw.move_length); + + /* length check */ + temp = g_aw86006_info.fw.move_length + g_aw86006_info.fw.app_length; + if (g_aw86006_info.fw.size != temp) { + AW_LOGE("fw->size error: 0x%X != 0x%X", g_aw86006_info.fw.size, + temp); + return OIS_ERROR; + } + + /* move checksum check */ + check_ptr = (uint32_t *) &fw->data[0]; + temp = 0; + for (i = 0; i < (g_aw86006_info.fw.move_length / sizeof(uint32_t)); i++) + temp += check_ptr[i]; + if (temp != g_aw86006_info.fw.move_checksum) { + AW_LOGE("move checksum error:0x%08X != 0x%08X", + g_aw86006_info.fw.move_checksum, temp); + return OIS_ERROR; + } + + /* info checksum check */ + check_ptr = (uint32_t *) &fw->data[AW_FW_SHIFT_CHECKSUM_ADDR]; + temp = 0; + /* identify length:8bytes; info_checksum length:4byes */ + for (i = 0; i < ((AW_FW_INFO_LENGTH - 8 - 4) / sizeof(uint32_t)); i++) + temp += check_ptr[i]; + if (temp != g_aw86006_info.fw.checksum) { + AW_LOGE("check_info checksum error:0x%08X != 0x%08X", + g_aw86006_info.fw.checksum, temp); + return OIS_ERROR; + } + + /* app checksum check */ + check_ptr = (uint32_t *) &fw->data[AW_FLASH_MOVE_LENGTH + + AW_FW_INFO_LENGTH]; + temp = 0; + for (i = 0; i < ((g_aw86006_info.fw.app_length - AW_FW_INFO_LENGTH) / + sizeof(uint32_t)); i++) + temp += check_ptr[i]; + + if (temp != g_aw86006_info.fw.app_checksum) { + AW_LOGE("app checksum error:0x%08X != 0x%08X", + g_aw86006_info.fw.app_checksum, temp); + return OIS_ERROR; + } + /* Save firmware checkinfo */ + memcpy(&g_aw86006_info.checkinfo_fw[0], + fw->data + AW_FLASH_MOVE_LENGTH, AW_FW_INFO_LENGTH); + + AW_LOGI("Pass!"); + + return OIS_SUCCESS; +} + +static int aw86006_checkinfo_analyse(struct cam_ois_ctrl_t *o_ctrl, + uint8_t *checkinfo_rd, struct aw86006_fw *info) +{ + uint32_t temp = 0; + uint32_t *check_ptr = NULL; + int i = 0; + int ret = OIS_ERROR; + + if ((checkinfo_rd == NULL) || (info == NULL)) { + AW_LOGE("checkinfo empty!"); + return OIS_ERROR; + } + /* compare identify: AWINIC00 */ + ret = memcmp(fw_check_str, (char *)checkinfo_rd, 8); + if (ret != 0) { + AW_LOGE("checkinfo not match!"); + return OIS_ERROR; + } + + info->checksum = *(uint32_t *) (&checkinfo_rd[AW_FW_SHIFT_CHECKSUM - + AW_FLASH_MOVE_LENGTH]); + info->app_checksum = + *(uint32_t *) (&checkinfo_rd[AW_FW_SHIFT_APP_CHECKSUM - + AW_FLASH_MOVE_LENGTH]); + info->app_length = *(uint32_t *) (&checkinfo_rd[AW_FW_SHIFT_APP_LENGTH - + AW_FLASH_MOVE_LENGTH]) + AW_FW_INFO_LENGTH; + info->app_version = + *(uint32_t *) (&checkinfo_rd[AW_FW_SHIFT_APP_VERSION - + AW_FLASH_MOVE_LENGTH]); + info->app_id = *(uint32_t *) (&checkinfo_rd[AW_FW_SHIFT_APP_ID - + AW_FLASH_MOVE_LENGTH]); + info->move_checksum = + *(uint32_t *) (&checkinfo_rd[AW_FW_SHIFT_MOVE_CHECKSUM - + AW_FLASH_MOVE_LENGTH]); + info->move_version = + *(uint32_t *) (&checkinfo_rd[AW_FW_SHIFT_MOVE_VERSION - + AW_FLASH_MOVE_LENGTH]); + info->move_length = + *(uint32_t *) (&checkinfo_rd[AW_FW_SHIFT_MOVE_LENGTH - + AW_FLASH_MOVE_LENGTH]); + + AW_LOGI("app_length: 0x%04X, app_version: 0x%08X, app_id: 0x%02X", + info->app_length, + info->app_version, + info->app_id); + AW_LOGI("move_version:0x%08X, move_length:0x%04X", info->move_version, + info->move_length); + + /* info checksum check */ + check_ptr = (uint32_t *) &checkinfo_rd[AW_FW_SHIFT_CHECKSUM_ADDR - + AW_FLASH_MOVE_LENGTH]; + temp = 0; + for (i = 0; i < ((AW_FW_INFO_LENGTH - 8 - 4) / sizeof(uint32_t)); i++) + temp += check_ptr[i]; + if (temp != info->checksum) { + AW_LOGE("checkinfo_rd checksum error:0x%08X != 0x%08X", + info->checksum, temp); + return OIS_ERROR; + } + AW_LOGI("pass!"); + return OIS_SUCCESS; +} + +static int aw86006_get_standby_flag(struct cam_ois_ctrl_t *o_ctrl, + uint8_t *pflag) +{ + int ret = OIS_ERROR; + uint8_t flag = 0; + uint8_t temp_addr = 0; + + AW_LOGI("enter"); + + temp_addr = o_ctrl->io_master_info.cci_client->sid; + o_ctrl->io_master_info.cci_client->sid = AW_SHUTDOWN_I2C_ADDR; + ret = ois_block_read_addr8_data8(o_ctrl, 0xFF11, + CAMERA_SENSOR_I2C_TYPE_WORD, &flag, 1); + o_ctrl->io_master_info.cci_client->sid = temp_addr; + if (ret < 0) { + AW_LOGE("read standby flag error, ret: %d", ret); + return ret; + } + + *pflag = flag; + + AW_LOGI("standby flag: %d", flag); + + return OIS_SUCCESS; +} + +static int aw86006_mem_download(struct cam_ois_ctrl_t *o_ctrl, + const struct firmware *fw) +{ + struct aw86006_fw info_rd; + size_t all_buf_size = g_aw86006_info.fw.app_length + + AW_FLASH_MOVE_LENGTH; + size_t app_buf_size = g_aw86006_info.fw.app_length; + int i = 0; + int ret = OIS_ERROR; + uint8_t *all_buf_ptr = (uint8_t *) fw->data; + uint8_t *app_buf_ptr = (uint8_t *) fw->data + AW_FLASH_MOVE_LENGTH; + + AW_LOGI("enter"); + + if (fw == NULL) { + AW_LOGE("error, FW Empty!!!"); + return OIS_ERROR; + } + + /* enter boot mode */ + ret = aw86006_jump_boot_check(o_ctrl); + if (ret != OIS_SUCCESS) { + AW_LOGE("jump boot failed!"); + return OIS_ERROR; + } + +#ifdef AW_SOC_FLASH_READ_FLAG + /* get check_info data */ + ret = aw86006_soc_flash_read_check(o_ctrl, AW_FLASH_APP_ADDR, + &g_aw86006_info.checkinfo_rd[0], AW_FLASH_READ_LEN); + if (ret != OIS_SUCCESS) + AW_LOGE("read checkinfo error!"); +#endif + + g_aw86006_info.fw.update_flag = + g_aw86006_info.checkinfo_rd[AW_ARRAY_SHIFT_UPDATE_FLAG]; + + if (g_aw86006_info.fw.update_flag != 0x01) { + AW_LOGI("update_flag not match, update all!"); + ret = aw86006_soc_flash_update(o_ctrl, AW_FLASH_BASE_ADDR, + all_buf_ptr, all_buf_size); + if (ret != OIS_SUCCESS) { + AW_LOGE("update all failed!"); + return OIS_ERROR; + } + } else { + AW_LOGI("update_flag match!"); + ret = memcmp(g_aw86006_info.checkinfo_rd, + g_aw86006_info.checkinfo_fw, AW_FW_INFO_LENGTH); + if (ret != 0) { + ret = aw86006_checkinfo_analyse(o_ctrl, + g_aw86006_info.checkinfo_rd, &info_rd); + if ((ret != OIS_SUCCESS) || (info_rd.move_version != + g_aw86006_info.fw.move_version)) { + AW_LOGE("checkinfo/move not match, update all"); + ret = aw86006_soc_flash_update(o_ctrl, + AW_FLASH_BASE_ADDR, all_buf_ptr, + all_buf_size); + if (ret != OIS_SUCCESS) { + AW_LOGE("update all failed!"); + return OIS_ERROR; + } + } else if ((info_rd.app_version != + g_aw86006_info.fw.app_version) || + (info_rd.app_id != + g_aw86006_info.fw.app_id)) { + AW_LOGE("app not match, update app!"); + ret = aw86006_soc_flash_update(o_ctrl, + AW_FLASH_APP_ADDR, app_buf_ptr, + app_buf_size); + if (ret != OIS_SUCCESS) { + AW_LOGE("update app failed!"); + return OIS_ERROR; + } + } else { + AW_LOGE("other error, update all!"); + ret = aw86006_soc_flash_update(o_ctrl, + AW_FLASH_BASE_ADDR, all_buf_ptr, + all_buf_size); + if (ret != OIS_SUCCESS) { + AW_LOGE("update all failed!"); + return OIS_ERROR; + } + } + } else { + ret = aw86006_jump_move_check(o_ctrl); + if (ret != OIS_SUCCESS) { + AW_LOGE("jump_move_check fail, update all!"); + ret = aw86006_soc_flash_update(o_ctrl, + AW_FLASH_BASE_ADDR, all_buf_ptr, + all_buf_size); + if (ret != OIS_SUCCESS) { + AW_LOGE("update all failed!"); + return OIS_ERROR; + } + } else { + ret = aw86006_reset(o_ctrl); + if (ret != OIS_SUCCESS) { + AW_LOGE("reset failed!"); + return OIS_ERROR; + } + msleep(AW_RESET_DELAY); + } + } + } + + for (i = 0; i <= AW_ERROR_LOOP; i++) { + ret = aw86006_runtime_check(o_ctrl); + if (ret == OIS_SUCCESS) { + AW_LOGI("runtime_check pass, no need to update fw!"); + break; + } + AW_LOGE("runtime_check failed, update app! loop: %d", i); + if (i == AW_ERROR_LOOP) + break; + + ret = aw86006_soc_flash_update(o_ctrl, AW_FLASH_APP_ADDR, + app_buf_ptr, app_buf_size); + if (ret != OIS_SUCCESS) { + AW_LOGE("update app failed!"); + break; + } + } + + return ret; +} + +int aw86006_firmware_update(struct cam_ois_ctrl_t *o_ctrl, + const struct firmware *fw) +{ + int ret = OIS_ERROR; + int i = 0; + int j = 0; + uint8_t standby_flag = 0; + + AW_LOGI("enter"); + + /* fw check */ + AW_LOGI("Load:%s size:%zu", AW86006_FW_NAME, fw->size); + ret = aw86006_firmware_check(o_ctrl, fw); + if (ret != OIS_SUCCESS) { + AW_LOGE("fw check failed!"); + goto err_fw_check; + } + /* reset */ + ret = aw86006_reset(o_ctrl); + if (ret != OIS_SUCCESS) { + AW_LOGE("reset failed"); + goto err_reset; + } + mdelay(AW_RESET_DELAY); /* run app after reset */ + /* Get standby flag */ + for (j = 0; j < AW_ERROR_LOOP; j++) { + for (i = 0; i < AW_ERROR_LOOP; i++) { + aw86006_get_standby_flag(o_ctrl, &standby_flag); + if (standby_flag == AW_IC_STANDBY) + break; + mdelay(AW_RESET_DELAY); + } + //Retry reset + if((i == AW_ERROR_LOOP) && (standby_flag != AW_IC_STANDBY)){ + aw86006_reset(o_ctrl); + mdelay(AW_RESET_DELAY); + } + if (standby_flag == AW_IC_STANDBY) + break; + } + + if (standby_flag == AW_IC_STANDBY) { + ret = aw86006_runtime_check(o_ctrl); + if (ret == OIS_SUCCESS) + AW_LOGI("runtime_check pass, no need to update fw!"); + } + /* update flash */ + if ((standby_flag != AW_IC_STANDBY) || (ret != OIS_SUCCESS)) { + /* update flash */ + ret = aw86006_mem_download(o_ctrl, fw); + if (ret == OIS_SUCCESS) + AW_LOGI("fw update success!"); + else + AW_LOGE("fw update failed, ret: %d", ret); + } + +err_reset: +err_fw_check: + release_firmware(fw); + return ret; +} + +static void aw86006_firmware_update_work_routine(struct work_struct *work) +{ + struct cam_ois_ctrl_t *o_ctrl = container_of(work, + struct cam_ois_ctrl_t, aw_fw_update_work); + const struct firmware *fw = NULL; + int loop = 0; + int ret = OIS_ERROR; + + AW_LOGI("enter"); + + /* load firmware */ + do { + ret = request_firmware(&fw, AW86006_FW_NAME, + &o_ctrl->pdev->dev); + if (ret == 0) + break; + } while ((++loop) < AW_ERROR_LOOP); + if (loop >= AW_ERROR_LOOP) { + AW_LOGE("request_firmware [%s] failed!", AW86006_FW_NAME); + return; + } + mutex_lock(&o_ctrl->aw_ois_mutex); + aw86006_firmware_update(o_ctrl, fw); + mutex_unlock(&o_ctrl->aw_ois_mutex); + + AW_LOGI("End"); +} + +/******************************************************************************* + * adb debug interface + ******************************************************************************/ +static ssize_t reg_show(struct class *class, struct class_attribute *attr, + char *buf) +{ + struct cam_ois_ctrl_t *o_ctrl = g_o_ctrl; + ssize_t len = 0; + int i = 0; + uint8_t reg_val[20] = { 0 }; + + AW_LOGI("Start"); + + mutex_lock(&o_ctrl->aw_ois_mutex); + for (i = 0; i < 20; i++) { + ois_block_read_addr8_data8(o_ctrl, i, CAMERA_SENSOR_I2C_TYPE_WORD, + ®_val[i], 1); + len += snprintf(buf + len, PAGE_SIZE - len, + "reg[0x%04X]:0x%02X\n", i, reg_val[i]); + AW_LOGD("reg[0x%04X]:0x%02X", i, reg_val[i]); + } + mutex_unlock(&o_ctrl->aw_ois_mutex); + + AW_LOGI("End"); + + return len; +} + +static ssize_t reg_store(struct class *class, struct class_attribute *attr, + const char *buf, size_t count) +{ + struct cam_ois_ctrl_t *o_ctrl = g_o_ctrl; + uint32_t databuf[2] = { 0 }; + + AW_LOGI("Start"); + + mutex_lock(&o_ctrl->aw_ois_mutex); + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) == 2) { + AW_LOGD("reg[0x%04X]:0x%02X", databuf[0], databuf[1]); + ois_block_write_addr8_data8(o_ctrl, databuf[0], + CAMERA_SENSOR_I2C_TYPE_WORD, (uint8_t *) &databuf[1], + CAMERA_SENSOR_I2C_TYPE_BYTE); + } else { + AW_LOGE("Number of parameters"); + mutex_unlock(&o_ctrl->aw_ois_mutex); + return -EPERM; + } + mutex_unlock(&o_ctrl->aw_ois_mutex); + + AW_LOGI("End"); + + return count; +} + +static int aw86006_parse_reg_data(struct awrw_ctrl *awrw_ctrl, const char *buf) +{ + int ret = OIS_ERROR; + int i = 0; + char data_buf[5] = { 0 }; + uint8_t temp = 0; + + AW_LOGI("Start"); + + for (i = 0; i < awrw_ctrl->reg_num; i++) { + if ((i * 5 + 5) > (strlen(buf) - 2 * (4 + 1) - (6 + 1))) { + AW_LOGE("buf length error"); + return -ERANGE; + } + memcpy(data_buf, &buf[17 + i * 5], 4); + data_buf[4] = '\0'; + /* char convert to unsigned char */ + ret = kstrtou8(data_buf, 0, &temp); + if (ret < 0) { + AW_LOGE("Parse reg_data[%d] error", i); + return ret; + } + awrw_ctrl->reg_data[i] = temp; + + AW_LOGD("reg_data[%d]: 0x%02x", i, awrw_ctrl->reg_data[i]); + } + + return 0; +} + +static ssize_t awrw_show(struct class *class, struct class_attribute *attr, + char *buf) +{ + struct awrw_ctrl *awrw_ctrl = g_o_ctrl->awrw_ctrl; + int i = 0; + ssize_t len = 0; + uint16_t reg_num = awrw_ctrl->reg_num; + uint8_t flag = awrw_ctrl->flag; + uint8_t *reg_data = awrw_ctrl->reg_data; + + AW_LOGI("Start"); + + if (!reg_num) { + AW_LOGE("Reg_nums parameter error"); + return -ERANGE; + } + + if (reg_data == NULL) { + AW_LOGE("reg_data empty!"); + return -ERANGE; + } + + if (flag == AW_SEQ_READ) { + for (i = 0; i < reg_num; i++) { + AW_LOGD("reg_data[%d]: 0x%02x", i, reg_data[i]); + len += snprintf(buf + len, PAGE_SIZE - len, "0x%02x,", + reg_data[i]); + } + len += snprintf(buf + len - 1, PAGE_SIZE - len, "\n"); + } else { + AW_LOGE("Need to read awrw before show"); + return -EPERM; + } + + AW_LOGI("End"); + + return len; +} + +static ssize_t awrw_store(struct class *class, struct class_attribute *attr, + const char *buf, size_t count) +{ + struct cam_ois_ctrl_t *o_ctrl = g_o_ctrl; + struct awrw_ctrl *awrw_ctrl = g_o_ctrl->awrw_ctrl; + int ret = OIS_ERROR; + uint32_t flag = 0; + uint32_t reg_num = 0; + uint32_t reg_addr = 0; + + AW_LOGI("Start"); + + if (sscanf(buf, "%x %x %x", &flag, ®_num, ®_addr) == 3) { + if (!reg_num) { + AW_LOGE("awrw parameter error"); + return -ERANGE; + } + mutex_lock(&o_ctrl->aw_ois_mutex); + awrw_ctrl->flag = (uint8_t)flag; + awrw_ctrl->reg_num = (uint16_t)reg_num; + /* clear old reg_data */ + if (awrw_ctrl->reg_data != NULL) + kfree(awrw_ctrl->reg_data); + /* Request memory space for reg_data; Unit: byte */ + awrw_ctrl->reg_data = kzalloc(reg_num, GFP_KERNEL); + + if (awrw_ctrl->flag == AW_SEQ_WRITE) { + /* parse reg data */ + ret = aw86006_parse_reg_data(awrw_ctrl, buf); + if (ret < 0) { + AW_LOGE("Parse reg_data error"); + mutex_unlock(&o_ctrl->aw_ois_mutex); + return ret; + } + AW_LOGD("Parse reg_data OK"); + /* writes reg_data */ + ois_block_write_addr8_data8(o_ctrl, reg_addr, + CAMERA_SENSOR_I2C_TYPE_WORD, + awrw_ctrl->reg_data, + awrw_ctrl->reg_num); + } else if (awrw_ctrl->flag == AW_SEQ_READ) /* read data */ + ois_block_read_addr8_data8(o_ctrl, reg_addr, + CAMERA_SENSOR_I2C_TYPE_WORD, + awrw_ctrl->reg_data, + awrw_ctrl->reg_num); + + mutex_unlock(&o_ctrl->aw_ois_mutex); + } else { + AW_LOGE("Number of parameters"); + } + + AW_LOGI("End"); + + return count; +} + +static ssize_t update_show(struct class *class, struct class_attribute *attr, + char *buf) +{ + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, + "update ois: echo 1 > update\n"); + + return len; +} + +static ssize_t update_store(struct class *class, struct class_attribute *attr, + const char *buf, size_t count) +{ + struct cam_ois_ctrl_t *o_ctrl = g_o_ctrl; + uint32_t databuf = 0; + int ret = OIS_ERROR; + + AW_LOGI("Start"); + + ret = kstrtouint(buf, 0, &databuf); + if (ret < 0) { + AW_LOGE("Number of parameters error"); + return ret; + } + + /* fw update */ + if (databuf != 1) { + AW_LOGE("flag error: %d", databuf); + return -EPERM; + } + + schedule_work(&o_ctrl->aw_fw_update_work); + + AW_LOGI("End"); + + return count; +} + +static ssize_t erase_show(struct class *class, struct class_attribute *attr, + char *buf) +{ + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, + "erase app flash: echo app > erase\n"); + len += snprintf(buf + len, PAGE_SIZE - len, + "erase all flash: echo all > erase\n"); + len += snprintf(buf + len, PAGE_SIZE - len, + "read checkinfo: echo read > erase\n"); + len += snprintf(buf + len, PAGE_SIZE - len, + "ois reset: echo reset > erase\n"); + + return len; +} + +static ssize_t erase_store(struct class *class, struct class_attribute *attr, + const char *buf, size_t count) +{ + struct cam_ois_ctrl_t *o_ctrl = g_o_ctrl; + int ret = OIS_ERROR; + char databuf[10] = {0}; + char readbuf[64] = {0}; + + if (sscanf(buf, "%s", databuf) == 1) { + mutex_lock(&o_ctrl->aw_ois_mutex); + if (strcmp(databuf, "app") == 0) { + AW_LOGI("aw86006 will erase app!"); + ret = aw86006_jump_boot_check(o_ctrl); + if (ret != OIS_SUCCESS) { + AW_LOGE("Jump boot failed"); + goto err_exit; + } + ret = aw86006_soc_flash_erase_check(o_ctrl, + AW_FLASH_APP_ADDR, AW_FLASH_FULL_SIZE - + AW_FLASH_MOVE_LENGTH); + if (ret != OIS_SUCCESS) { + AW_LOGE("Erase app failed"); + goto err_exit; + } + } else if (strcmp(databuf, "all") == 0) { + AW_LOGI("aw86006 will erase all!"); + ret = aw86006_jump_boot_check(o_ctrl); + if (ret != OIS_SUCCESS) { + AW_LOGE("Jump boot failed"); + goto err_exit; + } + ret = aw86006_soc_flash_erase_check(o_ctrl, + AW_FLASH_BASE_ADDR, + AW_FLASH_FULL_SIZE); + if (ret != OIS_SUCCESS) { + AW_LOGE("Erase all failed"); + goto err_exit; + } + } else if (strcmp(databuf, "read") == 0) { + ret = aw86006_jump_boot_check(o_ctrl); + if (ret != OIS_SUCCESS) { + AW_LOGE("Jump boot failed"); + goto err_exit; + } + ret = aw86006_soc_flash_read_check(o_ctrl, + AW_FLASH_APP_ADDR, readbuf, + AW_FLASH_READ_LEN); + if (ret != OIS_SUCCESS) { + AW_LOGE("Read checkinfo failed"); + goto err_exit; + } + } else if (strcmp(databuf, "reset") == 0) { + AW_LOGI("aw86006 reset"); + ret = aw86006_reset(o_ctrl); + if (ret != OIS_SUCCESS) { + AW_LOGE("Reset failed"); + goto err_exit; + } + } else { + AW_LOGE("Erase: %s is not support!", databuf); + } + + mutex_unlock(&o_ctrl->aw_ois_mutex); + } + + return count; + +err_exit: + mutex_unlock(&o_ctrl->aw_ois_mutex); + return ret; +} + +static ssize_t mode_show(struct class *class, struct class_attribute *attr, + char *buf) +{ + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, + "OIS_ON: echo 1 > mode\n"); + len += snprintf(buf + len, PAGE_SIZE - len, + "OIS_OFF: echo 0 > mode\n"); + + return len; +} + +static ssize_t mode_store(struct class *class, struct class_attribute *attr, + const char *buf, size_t count) +{ + struct cam_ois_ctrl_t *o_ctrl = g_o_ctrl; + int ret = OIS_ERROR; + int loop = 0; + uint32_t ois_status = 0; + uint8_t temp = 0; + + AW_LOGI("enter"); + + ret = kstrtou32(buf, 0, &ois_status); + if (ret < 0) { + AW_LOGE("Number of parameters error"); + return ret; + } + if ((ois_status != OIS_DISABLE) && (ois_status != OIS_ENABLE)) { + AW_LOGE("ois_status error: %d", ois_status); + return -EPERM; + } + /* enable OIS mode */ + mutex_lock(&o_ctrl->aw_ois_mutex); + do { + temp = (uint8_t)ois_status; + AW_LOGD("set ois status: %d", temp); + + ret = ois_block_write_addr8_data8(o_ctrl, REG_OIS_ENABLE, + CAMERA_SENSOR_I2C_TYPE_WORD, &temp, 1); + if (ret < 0) { + AW_LOGE("Send OIS mode error"); + mutex_unlock(&o_ctrl->aw_ois_mutex); + return ret; + } + /* 1000 us */ + usleep_range(1000, 1500); + + /* check OIS enable status */ + temp = 0; + ret = ois_block_read_addr8_data8(o_ctrl, REG_OIS_ENABLE, + CAMERA_SENSOR_I2C_TYPE_WORD, &temp, 1); + if (ret < 0) { + AW_LOGE("Read OIS mode error"); + mutex_unlock(&o_ctrl->aw_ois_mutex); + return ret; + } + AW_LOGD("OIS enable value: 0x%02x", temp); + + if (temp == ois_status) { + AW_LOGI("Set OIS mode success!"); + break; + } + AW_LOGE("OIS mode check error! value: 0x%02x", temp); + } while ((++loop) < AW_ERROR_LOOP); + mutex_unlock(&o_ctrl->aw_ois_mutex); + if (loop >= AW_ERROR_LOOP) + return OIS_ERROR; + + return count; +} + +static ssize_t chipid_show(struct class *class, struct class_attribute *attr, + char *buf) +{ + struct cam_ois_ctrl_t *o_ctrl = g_o_ctrl; + ssize_t len = 0; + int ret = OIS_ERROR; + uint8_t chipid = 0; + + mutex_lock(&o_ctrl->aw_ois_mutex); + ret = ois_block_read_addr8_data8(o_ctrl, REG_CHIPID, + CAMERA_SENSOR_I2C_TYPE_WORD, &chipid, 1); + if (ret < 0) { + AW_LOGE("read chipid error"); + mutex_unlock(&o_ctrl->aw_ois_mutex); + return ret; + } + + AW_LOGD("Chipid: 0x%02X", chipid); + + len += snprintf(buf + len, PAGE_SIZE - len, "Chipid: 0x%02X\n", chipid); + mutex_unlock(&o_ctrl->aw_ois_mutex); + + return len; +} + +static ssize_t chipid_store(struct class *class, struct class_attribute *attr, + const char *buf, size_t count) +{ + return count; +} + +static ssize_t version_show(struct class *class, struct class_attribute *attr, + char *buf) +{ + struct cam_ois_ctrl_t *o_ctrl = g_o_ctrl; + ssize_t len = 0; + uint32_t version = 0; + int ret = OIS_ERROR; + uint8_t temp[4] = { 0 }; + + mutex_lock(&o_ctrl->aw_ois_mutex); + ret = ois_block_read_addr8_data8(o_ctrl, REG_VERSION, + CAMERA_SENSOR_I2C_TYPE_WORD, temp, 4); + if (ret < 0) { + AW_LOGE("read version error"); + mutex_unlock(&o_ctrl->aw_ois_mutex); + return ret; + } + + version = (temp[3] << 24) | (temp[2] << 16) | (temp[1] << 8) | temp[0]; + AW_LOGD("version:v%d.%d.%d.%d", temp[3], temp[2], temp[1], temp[0]); + + len += snprintf(buf + len, PAGE_SIZE - len, "version: v%d.%d.%d.%d\n", + temp[3], temp[2], temp[1], temp[0]); + mutex_unlock(&o_ctrl->aw_ois_mutex); + + return len; +} + +static ssize_t version_store(struct class *class, struct class_attribute *attr, + const char *buf, size_t count) +{ + return count; +} + +static ssize_t checkinfo_show(struct class *class, struct class_attribute *attr, + char *buf) +{ + ssize_t len = 0; + int i = 0; + + for (i = 0; i < 8; i++) { + len += snprintf(buf + len, PAGE_SIZE - len, + "checkinfo_rd_0x%x 0x%02X 0x%02X 0x%02X ", + i, g_aw86006_info.checkinfo_rd[i * 8 + 0], + g_aw86006_info.checkinfo_rd[i * 8 + 1], + g_aw86006_info.checkinfo_rd[i * 8 + 2]); + len += snprintf(buf + len, PAGE_SIZE - len, + "0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\n", + g_aw86006_info.checkinfo_rd[i * 8 + 3], + g_aw86006_info.checkinfo_rd[i * 8 + 4], + g_aw86006_info.checkinfo_rd[i * 8 + 5], + g_aw86006_info.checkinfo_rd[i * 8 + 6], + g_aw86006_info.checkinfo_rd[i * 8 + 7]); + len += snprintf(buf + len, PAGE_SIZE - len, + "checkinfo_fw_0x%x 0x%02X 0x%02X 0x%02X ", + i, g_aw86006_info.checkinfo_fw[i * 8 + 0], + g_aw86006_info.checkinfo_fw[i * 8 + 1], + g_aw86006_info.checkinfo_fw[i * 8 + 2]); + len += snprintf(buf + len, PAGE_SIZE - len, + "0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\n", + g_aw86006_info.checkinfo_fw[i * 8 + 3], + g_aw86006_info.checkinfo_fw[i * 8 + 4], + g_aw86006_info.checkinfo_fw[i * 8 + 5], + g_aw86006_info.checkinfo_fw[i * 8 + 6], + g_aw86006_info.checkinfo_fw[i * 8 + 7]); + } + + return len; +} + +static ssize_t checkinfo_store(struct class *class, + struct class_attribute *attr, + const char *buf, size_t count) +{ + return count; +} + +static ssize_t standby_show(struct class *class, struct class_attribute *attr, + char *buf) +{ + struct cam_ois_ctrl_t *o_ctrl = g_o_ctrl; + ssize_t len = 0; + int ret = OIS_ERROR; + uint8_t standby_flag = 0; + + mutex_lock(&o_ctrl->aw_ois_mutex); + ret = aw86006_get_standby_flag(o_ctrl, &standby_flag); + if (ret != OIS_SUCCESS) + len += snprintf(buf + len, PAGE_SIZE - len, + "aw_read_standby error!\n"); + else + len += snprintf(buf + len, PAGE_SIZE - len, + "standby_flag: %d\n", standby_flag); + mutex_unlock(&o_ctrl->aw_ois_mutex); + + return len; +} + +static ssize_t standby_store(struct class *class, struct class_attribute *attr, + const char *buf, size_t count) +{ + /* struct cam_ois_ctrl_t *o_ctrl = g_o_ctrl; */ + uint32_t databuf = 0; + int ret = OIS_ERROR; + + ret = kstrtouint(buf, 0, &databuf); + if (ret < 0) { + AW_LOGE("kstrtouint fail"); + return ret; + } + + return count; +} + +static ssize_t jump_show(struct class *class, struct class_attribute *attr, + char *buf) +{ + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, + "jump boot: echo boot > jump\n"); + len += snprintf(buf + len, PAGE_SIZE - len, + "jump move: echo move > jump\n"); + len += snprintf(buf + len, PAGE_SIZE - len, + "reset: echo reset > jump\n"); + + return len; +} + +static ssize_t jump_store(struct class *class, struct class_attribute *attr, + const char *buf, size_t count) +{ + struct cam_ois_ctrl_t *o_ctrl = g_o_ctrl; + char databuf[10] = {0}; + int ret = OIS_ERROR; + + if (sscanf(buf, "%s", databuf) == 1) { + mutex_lock(&o_ctrl->aw_ois_mutex); + if (strcmp(databuf, "boot") == 0) { + AW_LOGI("aw86006 will jump boot!"); + ret = aw86006_jump_boot_check(o_ctrl); + if (ret != OIS_SUCCESS) { + AW_LOGE("Jump boot failed"); + goto err_exit; + } + } else if (strcmp(databuf, "move") == 0) { + AW_LOGI("aw86006 will jump move!"); + ret = aw86006_jump_move_check(o_ctrl); + if (ret != OIS_SUCCESS) { + AW_LOGE("Jump boot failed"); + goto err_exit; + } + } else if (strcmp(databuf, "reset") == 0) { + AW_LOGI("aw86006 will reset!"); + ret = aw86006_reset(o_ctrl); + if (ret != OIS_SUCCESS) { + AW_LOGE("Jump boot failed"); + goto err_exit; + } + } else { + AW_LOGE("jump [%s] is not support!", databuf); + } + + mutex_unlock(&o_ctrl->aw_ois_mutex); + } + + return count; + +err_exit: + mutex_unlock(&o_ctrl->aw_ois_mutex); + return ret; +} + +static int aw86006_raw_data_check(uint8_t *pdata, uint8_t size) +{ + uint8_t cnt = 0; + + while (cnt < size) { + if (pdata != NULL && *pdata != 0xff) + break; + + pdata++; + cnt++; + } + + if (cnt == size) + return OIS_ERROR; + + return OIS_SUCCESS; +} + +static int aw86006_accelgyro_dift_raw_data_check(struct cam_ois_ctrl_t *o_ctrl) +{ + uint8_t dift_val[12] = { 0 }; + int ret = 0; + + ois_block_read_addr8_data8(o_ctrl, 0xf84c, CAMERA_SENSOR_I2C_TYPE_WORD, + dift_val, 12); + ret = aw86006_raw_data_check(dift_val, + sizeof(dift_val)/sizeof(dift_val[0])); + if (ret < 0) { + AW_LOGE("accelgyro_dift raw data is all 0xff\n"); + return OIS_ERROR; + } + + return OIS_SUCCESS; +} + +static int aw86006_get_accelgyro_dift(struct cam_ois_ctrl_t *o_ctrl, + struct accelgyro_dift *ag_dift) +{ + uint8_t dift_val[12] = { 0 }; + + ois_block_read_addr8_data8(o_ctrl, 0xf84c, CAMERA_SENSOR_I2C_TYPE_WORD, + dift_val, 12); + + ag_dift->gyro_dift[AXIS_X] = (int16_t)((dift_val[1] << 8) | dift_val[0]); + ag_dift->gyro_dift[AXIS_Y] = (int16_t)((dift_val[3] << 8) | dift_val[2]); + ag_dift->gyro_dift[AXIS_Z] = (int16_t)((dift_val[5] << 8) | dift_val[4]); + + ag_dift->accel_dift[AXIS_X] = (int16_t)((dift_val[7] << 8) | dift_val[6]); + ag_dift->accel_dift[AXIS_Y] = (int16_t)((dift_val[9] << 8) | dift_val[8]); + ag_dift->accel_dift[AXIS_Z] = (int16_t)((dift_val[11] << 8) | dift_val[10]); + + AW_LOGI("gyro_dift: 0x%hx(%d) 0x%hx(%d) 0x%hx(%d)", + ag_dift->gyro_dift[AXIS_X], ag_dift->gyro_dift[AXIS_X], + ag_dift->gyro_dift[AXIS_Y], ag_dift->gyro_dift[AXIS_Y], + ag_dift->gyro_dift[AXIS_Z], ag_dift->gyro_dift[AXIS_Z]); + + AW_LOGI("accel_dift: 0x%hx(%d) 0x%hx(%d) 0x%hx(%d)", + ag_dift->accel_dift[AXIS_X], ag_dift->accel_dift[AXIS_X], + ag_dift->accel_dift[AXIS_Y], ag_dift->accel_dift[AXIS_Y], + ag_dift->accel_dift[AXIS_Z], ag_dift->accel_dift[AXIS_Z]); + + /* check gyro x/y dift */ + if(CHECK_DIFF(ag_dift->gyro_dift[AXIS_X], AW_GYROACCEL_DIFT_LIMIT) > 0) { + AW_LOGE("gyro_dift_x error!!"); + return OIS_ERROR; + } + if(CHECK_DIFF(ag_dift->gyro_dift[AXIS_Y], AW_GYROACCEL_DIFT_LIMIT) > 0) { + AW_LOGE("gyro_dift_y error!!"); + return OIS_ERROR; + } + /* check accel x/y dift */ + if(CHECK_DIFF(ag_dift->accel_dift[AXIS_X], AW_GYROACCEL_DIFT_LIMIT) > 0) { + AW_LOGE("accel_dift_x error!!"); + return OIS_ERROR; + } + if(CHECK_DIFF(ag_dift->accel_dift[AXIS_Y], AW_GYROACCEL_DIFT_LIMIT) > 0) { + AW_LOGE("accel_dift_y error!!"); + return OIS_ERROR; + } + + return OIS_SUCCESS; +} + +static int aw86006_set_normal_mode(struct cam_ois_ctrl_t *o_ctrl) +{ + int i = 0; + uint8_t send_cmd[2] = { 0xae, 0x02 }; + uint8_t check_val = 0; + + /*unlock */ + do { + ois_block_write_addr8_data8(o_ctrl, 0xff1f, + CAMERA_SENSOR_I2C_TYPE_WORD, &send_cmd[0], 1); + ois_block_read_addr8_data8(o_ctrl, 0xff1f, + CAMERA_SENSOR_I2C_TYPE_WORD, &check_val, 1); + } while ((check_val != 0x01) && (i++ < AW_ERROR_LOOP)); + + if (check_val != 0x01) { + AW_LOGE("unlock error:, check_val: 0x%02x", check_val); + return OIS_ERROR; + } + + /* set normal mode */ + do { + ois_block_write_addr8_data8(o_ctrl, 0xff11, + CAMERA_SENSOR_I2C_TYPE_WORD, &send_cmd[1], 1); + msleep(2); + ois_block_read_addr8_data8(o_ctrl, 0xff10, + CAMERA_SENSOR_I2C_TYPE_WORD, &check_val, 1); + } while ((check_val != 0) && (i++ < AW_ERROR_LOOP)); + + if (check_val != 0) { + AW_LOGE("enter normal error:, check_val: 0x%02x", check_val); + return OIS_ERROR; + } + + return OIS_SUCCESS; +} + +static ssize_t gyro_offset_cali_show(struct class *class, + struct class_attribute *attr, char *buf) +{ + struct cam_ois_ctrl_t *o_ctrl = g_o_ctrl; + struct accelgyro_dift ag_dift = {0}; + ssize_t len = 0; + + aw86006_get_accelgyro_dift(o_ctrl, &ag_dift); + + len += snprintf(buf + len, PAGE_SIZE - len, + "gyro_dift: 0x%hx(%d) 0x%hx(%d) 0x%hx(%d)\n", + ag_dift.gyro_dift[AXIS_X], ag_dift.gyro_dift[AXIS_X], + ag_dift.gyro_dift[AXIS_Y], ag_dift.gyro_dift[AXIS_Y], + ag_dift.gyro_dift[AXIS_Z], ag_dift.gyro_dift[AXIS_Z]); + + len += snprintf(buf + len, PAGE_SIZE - len, + "accel_dift: 0x%hx(%d) 0x%hx(%d) 0x%hx(%d)\n", + ag_dift.accel_dift[AXIS_X], ag_dift.accel_dift[AXIS_X], + ag_dift.accel_dift[AXIS_Y], ag_dift.accel_dift[AXIS_Y], + ag_dift.accel_dift[AXIS_Z], ag_dift.accel_dift[AXIS_Z]); + + return len; +} + +static ssize_t gyro_offset_cali_store(struct class *class, + struct class_attribute *attr, + const char *buf, size_t count) +{ + struct cam_ois_ctrl_t *o_ctrl = g_o_ctrl; + struct accelgyro_dift ag_dift; + int i = 0; + int ret = 0; + uint8_t data_buf[5] = { 0 }; + uint8_t ois_mode = 0; + uint8_t unlock_val[2] = { 0xa4, 0xac }; + uint8_t lock_val[2] = { 0xdc, 0xd4 }; + uint8_t trigger_cmd[4] = { 0x01, 0x02, 0x01, 0x01 }; + uint8_t exit_cmd[4] = { 0x00, 0x00, 0x00, 0x02 }; + uint8_t check_val = 0; + + if (sscanf(buf, "%d", &data_buf[0]) != 1) { + AW_LOGE("input para error!"); + return OIS_ERROR; + } + + AW_LOGI("aw86006 gyro offset cali start!"); + + /* check accelgyro_diff */ + ret = aw86006_accelgyro_dift_raw_data_check(o_ctrl); + if (ret < 0) { + AW_LOGE("accelgyro_dift raw data error"); + return OIS_ERROR; + } + + /* OIS off */ + ois_mode = OIS_DISABLE; + do { + ois_block_write_addr8_data8(o_ctrl, REG_OIS_ENABLE, + CAMERA_SENSOR_I2C_TYPE_WORD, &ois_mode, 1); + ois_block_read_addr8_data8(o_ctrl, REG_OIS_ENABLE, + CAMERA_SENSOR_I2C_TYPE_WORD, &check_val, 1); + } while ((check_val != 0x00) && (i++ < AW_ERROR_LOOP)); + + if (check_val != 0x00) { + AW_LOGE("reg[0001]:0x%x != 0x00, i: %d", check_val, i); + return OIS_ERROR; + } + + /* enter normal mode */ + ret = aw86006_set_normal_mode(o_ctrl); + if (ret < 0) + return OIS_ERROR; + + /* unlock register */ + i = 0; + do { + ois_block_write_addr8_data8(o_ctrl, 0xf20f, + CAMERA_SENSOR_I2C_TYPE_WORD, &unlock_val[0], 1); + ois_block_read_addr8_data8(o_ctrl, 0xf20f, + CAMERA_SENSOR_I2C_TYPE_WORD, &check_val, 1); + } while ((check_val != 0x01) && (i++ < AW_ERROR_LOOP)); + + if (check_val != 0x01) { + AW_LOGE("reg[f20f]:0x%x != 0x01, i: %d", check_val, i); + return OIS_ERROR; + } + + /* unlock register */ + i = 0; + do { + ois_block_write_addr8_data8(o_ctrl, 0xf8ff, + CAMERA_SENSOR_I2C_TYPE_WORD, &unlock_val[1], 1); + ois_block_read_addr8_data8(o_ctrl, 0xf8ff, + CAMERA_SENSOR_I2C_TYPE_WORD, &check_val, 1); + } while ((check_val != 0x01) && (i++ < AW_ERROR_LOOP)); + + if (check_val != 0x01) { + AW_LOGE("reg[f8ff]:0x%x != 0x01, i: %d", check_val, i); + return OIS_ERROR; + } + + /* Read the data in the flash into the register, trigger_cmd[0]: 0x01 */ + ois_block_write_addr8_data8(o_ctrl, 0xf8e4, CAMERA_SENSOR_I2C_TYPE_WORD, + &trigger_cmd[0], 1); + msleep(5); /* delay 5ms at least */ + + /* Select the gyroscope zero drift calibration function, trigger_cmd[1]: 0x02 */ + ois_block_write_addr8_data8(o_ctrl, 0xf200, CAMERA_SENSOR_I2C_TYPE_WORD, + &trigger_cmd[1], 1); + + /* Enter mass production test mode, trigger_cmd[2]: 0x01 */ + i = 0; + do { + ois_block_write_addr8_data8(o_ctrl, 0xf203, + CAMERA_SENSOR_I2C_TYPE_WORD, &trigger_cmd[2], 1); + ois_block_read_addr8_data8(o_ctrl, 0xf203, + CAMERA_SENSOR_I2C_TYPE_WORD, &check_val, 1); + } while ((check_val != 0x01) && (i++ < AW_ERROR_LOOP)); + + if (check_val != 0x01) { + AW_LOGE("reg[f203]:0x%x != 0x01, i: %d", check_val, i); + return OIS_ERROR; + } + + /* Trigger zero drift calibration of gyroscope, trigger_cmd[3]:0x01 */ + i = 0; + do { + ois_block_write_addr8_data8(o_ctrl, 0xf202, + CAMERA_SENSOR_I2C_TYPE_WORD, &trigger_cmd[3], 1); + ois_block_read_addr8_data8(o_ctrl, 0xf201, + CAMERA_SENSOR_I2C_TYPE_WORD, &check_val, 1); + } while ((check_val != 0x11) && (i++ < AW_ERROR_LOOP)); + + if (check_val != 0x11) { + AW_LOGE("reg[f201]:0x%x != 0x11, i: %d", check_val, i); + return OIS_ERROR; + } + + msleep(1000); /* delay 1s at least */ + + /* Check if the calibration is complete */ + i = 0; + do { + ois_block_read_addr8_data8(o_ctrl, 0xf201, + CAMERA_SENSOR_I2C_TYPE_WORD, &check_val, 1); + msleep(20); + } while ((check_val != 0x21) && (i++ < AW_ERROR_LOOP)); + + if (check_val != 0x21) { + AW_LOGE("reg[f201]:0x%x != 0x21, i: %d", check_val, i); + return OIS_ERROR; + } + + /* Exit calibration mode */ + ois_block_write_addr8_data8(o_ctrl, 0xf200, CAMERA_SENSOR_I2C_TYPE_WORD, + &exit_cmd[0], 1); + + i = 0; + do { + /* exit_cmd[2]:0x00 */ + ois_block_write_addr8_data8(o_ctrl, 0xf203, + CAMERA_SENSOR_I2C_TYPE_WORD, &exit_cmd[2], 1); + ois_block_read_addr8_data8(o_ctrl, 0xf203, + CAMERA_SENSOR_I2C_TYPE_WORD, &check_val, 1); + } while ((check_val != 0x00) && (i++ < AW_ERROR_LOOP)); + + if (check_val != 0x00) { + AW_LOGE("reg[f203]:0x%x != 0, i: %d", check_val, i); + return OIS_ERROR; + } + + /* Data update to flash, exit_cmd[3]: 0x02 */ + ois_block_write_addr8_data8(o_ctrl, 0xf8e4, CAMERA_SENSOR_I2C_TYPE_WORD, + &exit_cmd[3], 1); + + msleep(20 * 2); /* 2: two sector */ + + /* Lock register */ + ois_block_write_addr8_data8(o_ctrl, 0xf8ff, CAMERA_SENSOR_I2C_TYPE_WORD, + &lock_val[0], 1); + ois_block_write_addr8_data8(o_ctrl, 0xf20f, CAMERA_SENSOR_I2C_TYPE_WORD, + &lock_val[1], 1); + + /* Read the zero drift value of the three-axis angular velocity and + * acceleration of the gyroscope */ + ret = aw86006_get_accelgyro_dift(o_ctrl, &ag_dift); + if (ret < 0) + AW_LOGE("aw86006 gyro offset cali error!"); + else + AW_LOGI("aw86006 gyro offset cali ok!"); + + return count; +} + +static ssize_t slave_var_show(struct class *class, struct class_attribute *attr, + char *buf) +{ + ssize_t len = 0; + return len; +} + +static ssize_t slave_var_store(struct class *class, + struct class_attribute *attr, + const char *buf, size_t count) +{ + struct cam_ois_ctrl_t *o_ctrl = g_o_ctrl; + uint32_t databuf[5] = { 0 }; + uint16_t temp_addr = 0; + uint32_t addr_type = 1; + + AW_LOGI("enter"); + + temp_addr = o_ctrl->io_master_info.cci_client->sid; + + if (sscanf(buf, "%x %x %x %x %x", &databuf[0], &databuf[1], &databuf[2], + &databuf[3], &databuf[4]) == 5) { + AW_LOGI("1.slave: 0x%02x, flag: 0x%02x, addr_type: 0x%02x", + databuf[0], databuf[1], databuf[2]); + AW_LOGI("reg: 0x%04x, val: 0x%02x", databuf[3], databuf[4]); + + o_ctrl->io_master_info.cci_client->sid = databuf[0]; + if (databuf[2] == 0x01) + addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + else if (databuf[2] == 0x02) + addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + + if (databuf[1] == AW_SEQ_WRITE) { + ois_block_write_addr8_data8(o_ctrl, databuf[3], + addr_type, (uint8_t *) &databuf[4], + CAMERA_SENSOR_I2C_TYPE_BYTE); + /* callback read */ + databuf[4] = 0; + ois_block_read_addr8_data8(o_ctrl, databuf[3], + addr_type, (uint8_t *) &databuf[4], + CAMERA_SENSOR_I2C_TYPE_BYTE); + } else if (databuf[1] == AW_SEQ_READ) { + databuf[4] = 0; + ois_block_read_addr8_data8(o_ctrl, databuf[3], + addr_type, (uint8_t *) &databuf[4], + CAMERA_SENSOR_I2C_TYPE_BYTE); + } + AW_LOGI("2.slave: 0x%02x, flag: 0x%02x, addr_type: 0x%02x", + databuf[0], databuf[1], databuf[2]); + AW_LOGI("reg: 0x%04x, val: 0x%02x", databuf[3], databuf[4]); + } + + o_ctrl->io_master_info.cci_client->sid = temp_addr; + + return count; +} + +/******************************************************************************* + * Debug node + * Path: /sys/class/aw86006_ois + * ****************************************************************************/ +static CLASS_ATTR_RW(reg); +static CLASS_ATTR_RW(awrw); +static CLASS_ATTR_RW(update); +static CLASS_ATTR_RW(erase); +static CLASS_ATTR_RW(mode); +static CLASS_ATTR_RW(chipid); +static CLASS_ATTR_RW(version); +static CLASS_ATTR_RW(checkinfo); +static CLASS_ATTR_RW(standby); +static CLASS_ATTR_RW(jump); +static CLASS_ATTR_RW(gyro_offset_cali); +static CLASS_ATTR_RW(slave_var); + +static int aw86006_create_sysfs(void) +{ + int ret = OIS_ERROR; + + AW_LOGI("Start"); + + if (!ois_debug_class) { + AW_LOGI("create aw86006_result_class!"); + ois_debug_class = class_create(THIS_MODULE, "aw86006_ois"); + + ret = class_create_file(ois_debug_class, &class_attr_reg); + if (ret < 0) { + AW_LOGE("Create reg failed, ret: %d", ret); + return ret; + } + ret = class_create_file(ois_debug_class, &class_attr_awrw); + if (ret < 0) { + AW_LOGE("Create awrw failed, ret: %d", ret); + return ret; + } + ret = class_create_file(ois_debug_class, &class_attr_update); + if (ret < 0) { + AW_LOGE("Create update failed, ret: %d", ret); + return ret; + } + ret = class_create_file(ois_debug_class, &class_attr_erase); + if (ret < 0) { + AW_LOGE("Create erase failed, ret: %d", ret); + return ret; + } + ret = class_create_file(ois_debug_class, &class_attr_mode); + if (ret < 0) { + AW_LOGE("Create mode failed, ret: %d", ret); + return ret; + } + ret = class_create_file(ois_debug_class, &class_attr_chipid); + if (ret < 0) { + AW_LOGE("Create chipid failed, ret: %d", ret); + return ret; + } + ret = class_create_file(ois_debug_class, &class_attr_version); + if (ret < 0) { + AW_LOGE("Create version failed, ret: %d", ret); + return ret; + } + ret = class_create_file(ois_debug_class, &class_attr_checkinfo); + if (ret < 0) { + AW_LOGE("Create checkinfo failed, ret: %d", ret); + return ret; + } + ret = class_create_file(ois_debug_class, &class_attr_standby); + if (ret < 0) { + AW_LOGE("Create standby failed, ret: %d", ret); + return ret; + } + ret = class_create_file(ois_debug_class, &class_attr_jump); + if (ret < 0) { + AW_LOGE("Create jump failed, ret: %d", ret); + return ret; + } + ret = class_create_file(ois_debug_class, + &class_attr_gyro_offset_cali); + if (ret < 0) { + AW_LOGE("Create gyro_offset_cali failed, ret: %d", ret); + return ret; + } + ret = class_create_file(ois_debug_class, &class_attr_slave_var); + if (ret < 0) { + AW_LOGE("Create slave_var failed, ret: %d", ret); + return ret; + } + } + + AW_LOGI("Creat sysfs debug success."); + + return 0; +} + +static void aw86006_destroy_sysfs(void) +{ + AW_LOGI("Start"); + + if (ois_debug_class) { + class_remove_file(ois_debug_class, &class_attr_reg); + class_remove_file(ois_debug_class, &class_attr_awrw); + class_remove_file(ois_debug_class, &class_attr_update); + class_remove_file(ois_debug_class, &class_attr_erase); + class_remove_file(ois_debug_class, &class_attr_mode); + class_remove_file(ois_debug_class, &class_attr_chipid); + class_remove_file(ois_debug_class, &class_attr_version); + class_remove_file(ois_debug_class, &class_attr_checkinfo); + class_remove_file(ois_debug_class, &class_attr_standby); + class_remove_file(ois_debug_class, &class_attr_jump); + class_remove_file(ois_debug_class, + &class_attr_gyro_offset_cali); + class_remove_file(ois_debug_class, &class_attr_slave_var); + class_destroy(ois_debug_class); + ois_debug_class = NULL; + AW_LOGD("destroy ois_debug_class done!"); + } + + AW_LOGI("End"); +} + +/******************************************************************************* + * aw86006 ois init + * Callback: Path: function + ******************************************************************************/ +int aw86006_ois_init(struct cam_ois_ctrl_t *o_ctrl) +{ + int loop = 0; + + AW_LOGI("enter, %s", AW86006_DRIVER_VERSION); + + /* awrw_ctrl: debug node awrw */ + do { + o_ctrl->awrw_ctrl = kzalloc(sizeof(struct awrw_ctrl), + GFP_KERNEL); + if (!o_ctrl->awrw_ctrl) { + AW_LOGE("Request memory for awrw_ctrl error"); + continue; + } + break; + } while ((++loop) < AW_ERROR_LOOP); + if (loop >= AW_ERROR_LOOP) + return -ENOMEM; + + INIT_WORK(&o_ctrl->aw_fw_update_work, + aw86006_firmware_update_work_routine); + mutex_init(&o_ctrl->aw_ois_mutex); + aw86006_create_sysfs(); /* adb debug node */ + + g_o_ctrl = o_ctrl; + + AW_LOGI("exit"); + + return OIS_SUCCESS; +} + +int aw86006_ois_exit(struct cam_ois_ctrl_t *o_ctrl) +{ + AW_LOGI("enter"); + + aw86006_destroy_sysfs(); + + kfree(o_ctrl->awrw_ctrl); + + return OIS_SUCCESS; +} + +MODULE_AUTHOR(""); +MODULE_DESCRIPTION("AWINIC OIS Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_aw86006.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_aw86006.h new file mode 100644 index 000000000000..62e2f429053a --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_aw86006.h @@ -0,0 +1,224 @@ +#ifndef AW86006_OIS_H +#define AW86006_OIS_H + +/* Log Format */ +#define AW_LOGI(format, ...) \ + CAM_INFO(CAM_OIS, format, ##__VA_ARGS__) +#define AW_LOGD(format, ...) \ + CAM_DBG(CAM_OIS, format, ##__VA_ARGS__) +#define AW_LOGE(format, ...) \ + CAM_ERR(CAM_OIS, format, ##__VA_ARGS__) + +/* I2c address */ +#define AW_SHUTDOWN_I2C_ADDR (0xC2 >> 1) /* 0x61 */ +#define AW_WAKEUP_I2C_ADDR (0xD2 >> 1) /* 0x69 */ + +/* Register detail */ +#define REG_CHIPID (0x0000) +#define REG_OIS_ENABLE (0x0001) +#define REG_OIS_STATUS (0x0002) +#define REG_PACKING_RST (0x0003) +#define REG_DATA_READY (0x0004) +#define REG_SAMPLE_TIME (0x0005) +#define REG_PACK_DATA (0x0006) +#define REG_SPI_GYRO (0x0007) +#define REG_SPI_CFG (0x0008) +#define REG_AF_CODE_H (0x0009) +#define REG_AF_CODE_L (0x000A) +#define REG_AF_ARCT (0x000B) +#define REG_AF_CFG (0x000C) +#define REG_AF_BUSY (0x000D) +#define REG_VERSION (0x0010) +#define REG_STANDBY (0xFF11) + +/* Flag */ +#define OIS_ENABLE (0x01) +#define OIS_DISABLE (0x00) +#define OIS_ERROR (-1) +#define OIS_SUCCESS (0) +#define AW_IC_STANDBY (1) +#define AW_FLASH_WRITE_CONNECT +/* #define AW_SOC_FLASH_READ_FLAG */ + +/* Loop */ +#define AW_STAY_ON_MOVE_LOOP (20) +#define AW_STAY_ON_BOOT_LOOP (20) +#define AW_ERROR_LOOP (3) +#define AW_FLASH_WRITE_ERROR_LOOP (2) +#define AW_FLASH_READ_ERROR_LOOP (2) +#define AW_FLASH_ERASE_ERROR_LOOP (2) +#define AW_JUMP_BOOT_LOOP (6) +#define AW_JUMP_MOVE_LOOP (6) + +/* Addr or data size */ +#define AW_SIZE_BYTE_0 (0) +#define AW_SIZE_BYTE_1 (1) +#define AW_SIZE_BYTE_2 (2) +#define AW_SIZE_BYTE_3 (3) +#define AW_SIZE_BYTE_4 (4) +#define AW_SIZE_BYTE_12 (12) +#define AW_SIZE_BYTE_20 (20) +#define AW_PROTOCOL_SIZE (14) +#define AW_DATA_SHIFT_0_BIT (0) +#define AW_DATA_SHIFT_8_BIT (8) +#define AW_DATA_SHIFT_16_BIT (16) +#define AW_DATA_SHIFT_24_BIT (24) +#define AW_I2C_WRITE_BYTE_ZERO (0x00) + +/* Delay */ +#define AW_RESET_DELAY (50) /* ms */ +#define AW_JUMP_MOVE_DELAY (9) /* ms */ +#define AW_JUMP_MOVE_DELAY_MAX (16) /* ms */ +#define AW_JUMP_BOOT_DELAY (2) /* ms */ +#define AW_JUMP_BOOT_DELAY_MAX (6) /* ms */ +#define AW_SHUTDOWN_DELAY (2000) /* us */ + +/* Flash and firmware */ +#define AW_FLASH_BASE_ADDR (0x01000000) +#define AW_FLASH_APP_ADDR (0x01002000) +#define AW_FLASH_MOVE_LENGTH (AW_FLASH_APP_ADDR - AW_FLASH_BASE_ADDR) +#define AW_FLASH_FULL_SIZE (0xB000) +#define AW_FLASH_TOP_ADDR (AW_FLASH_BASE_ADDR + AW_FLASH_FULL_SIZE) +#define AW_FLASH_ERASE_LEN (512) +#define AW_FLASH_WRITE_LEN (64) +#define AW_FLASH_READ_LEN (64) +#define AW_FW_INFO_LENGTH (64) +#define AW_FW_SHIFT_IDENTIFY (AW_FLASH_MOVE_LENGTH) +#define AW_FW_SHIFT_CHECKSUM (AW_FW_SHIFT_IDENTIFY + 8) +#define AW_FW_SHIFT_APP_CHECKSUM (AW_FW_SHIFT_CHECKSUM + 4) +#define AW_FW_SHIFT_CHECKSUM_ADDR (AW_FW_SHIFT_APP_CHECKSUM) +#define AW_FW_SHIFT_APP_LENGTH (AW_FW_SHIFT_APP_CHECKSUM + 4) +#define AW_FW_SHIFT_APP_VERSION (AW_FW_SHIFT_APP_LENGTH + 4) +#define AW_FW_SHIFT_APP_ID (AW_FW_SHIFT_APP_VERSION + 4) +#define AW_FW_SHIFT_MOVE_CHECKSUM (AW_FW_SHIFT_APP_ID + 4) +#define AW_FW_SHIFT_MOVE_VERSION (AW_FW_SHIFT_MOVE_CHECKSUM + 4) +#define AW_FW_SHIFT_MOVE_LENGTH (AW_FW_SHIFT_MOVE_VERSION + 4) +#define AW_FW_SHIFT_UPDATE_FLAG (AW_FW_SHIFT_MOVE_LENGTH + 8) +#define AW_ARRAY_SHIFT_UPDATE_FLAG (AW_FW_SHIFT_UPDATE_FLAG - AW_FLASH_MOVE_LENGTH) + +/* gyro and hall test */ +#define AW_GYROACCEL_DIFT_LIMIT 5000 +#define CHECK_DIFF(x, y) ((x > 0) ? (x - y) : (-x - y)) + +/* SOC */ +enum soc_status { + SOC_OK = 0, + SOC_ADDR_ERROR, + SOC_PBUF_ERROR, + SOC_HANK_ERROR, + SOC_JUMP_ERROR, + SOC_FLASH_ERROR, + SOC_SPACE_ERROR, +}; + +enum soc_module { + SOC_HANK = 0x01, + SOC_SRAM = 0x02, + SOC_FLASH = 0x03, + SOC_END = 0x04, +}; + +enum soc_enum { + SOC_VERSION = 0x01, + SOC_CTL = 0x00, + SOC_ACK = 0x01, + SOC_ADDR = 0x84, + SOC_READ_ADDR = 0x48, + SOC_ERASE_STRUCT_LEN = 6, + SOC_READ_STRUCT_LEN = 6, + SOC_PROTOCAL_HEAD = 9, + SOC_CONNECT_WRITE_LEN = 9, + SOC_ERASE_WRITE_LEN = 15, + SOC_READ_WRITE_LEN = 15, + SOC_ERASE_BLOCK_DELAY = 5, + SOC_WRITE_BLOCK_HEAD = 13, + SOC_WRITE_BLOCK_DELAY = 600, /* us */ + SOC_READ_BLOCK_DELAY = 200, /* us */ + SOC_CONNECT_DELAY = 100, /* us */ +}; + +enum soc_flash_event { + SOC_FLASH_WRITE = 0x01, + SOC_FLASH_WRITE_ACK = 0x02, + SOC_FLASH_READ = 0x11, + SOC_FLASH_READ_ACK = 0x12, + SOC_FLASH_ERASE_BLOCK = 0x21, + SOC_FLASH_ERASE_BLOCK_ACK = 0x22, + SOC_FLASH_ERASE_CHIP = 0x23, + SOC_FLASH_ERASE_CHIP_ACK = 0x24, +}; + +enum soc_hank_event { + SOC_HANK_CONNECT = 0x01, + SOC_HANK_CONNECT_ACK = 0x02, + SOC_HANK_PROTICOL = 0x11, + SOC_HANK_PROTICOL_ACK = 0x12, + SOC_HANK_VERSION = 0x21, + SOC_HANK_VERSION_ACK = 0x22, + SOC_HANK_ID = 0x31, + SOC_HANK_ID_ACK = 0x32, + SOC_HANK_DATE = 0x33, + SOC_HANK_DATA_ACK = 0x34, +}; + +/* ISP */ +enum isp_enum { + ISP_READ_VERSION_DELAY = 500, /* us */ + ISP_VERS_CONNECT_ACK = 0x01, + ISP_VERSION_ACK_LEN = 5, + ISP_EVENT_OK = 0x01, +}; + +enum awrw_flag { + AW_SEQ_WRITE = 0, + AW_SEQ_READ = 1, +}; + +enum axis_info { + AXIS_X, + AXIS_Y, + AXIS_Z, +}; + +struct accelgyro_dift { + int16_t gyro_dift[3]; + int16_t accel_dift[3]; +}; + +/* Struct */ +struct soc_protocol { + uint8_t checksum; + uint8_t protocol_ver; + uint8_t addr; + uint8_t module; + uint8_t event; + uint8_t len[2]; + uint8_t ack; + uint8_t sum; + uint8_t reserved[3]; + uint8_t ack_juge; + uint8_t *p_data; +}; + +struct aw86006_fw { + uint32_t checksum; + uint32_t app_checksum; + uint32_t app_length; + uint32_t app_version; + uint32_t app_id; + uint32_t move_checksum; + uint32_t move_version; + uint32_t move_length; + uint32_t update_flag; + uint32_t size; + uint8_t *data_p; +}; + +struct aw86006_info { + uint8_t already_update; + uint8_t checkinfo_fw[64]; + uint8_t checkinfo_rd[64]; + struct aw86006_fw fw; +}; + +#endif diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_core.c b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_core.c index d8766a225046..59e70c454811 100644 --- a/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_core.c @@ -16,6 +16,28 @@ #include "cam_common_util.h" #include "cam_packet_util.h" +#define DW9784_IF_SIZE (512) + +extern int dw9781c_check_fw_download(struct camera_io_master * io_master_info, const uint8_t *fwData, uint32_t fwSize); +extern void dw9781_post_firmware_download(struct camera_io_master * io_master_info, const uint8_t *fwData, uint32_t fwSize); +extern int aw86006_firmware_update(struct cam_ois_ctrl_t *o_ctrl, const struct firmware *fw); +extern int dw9784_check_fw_download(struct camera_io_master * io_master_info, const uint8_t *fwData, uint32_t fwSize); +extern void dw9784_post_firmware_download(struct camera_io_master * io_master_info); +extern int dw9784_check_if_download(struct camera_io_master * io_master_info); +#ifdef CONFIG_MOT_DONGWOON_OIS_AF_DRIFT +int m_ois_init = 0; + +int cam_ois_get_init_info(void) +{ + return m_ois_init; +} + +static void cam_ois_set_init_info(int value) +{ + m_ois_init = value; +} +#endif + int32_t cam_ois_construct_default_power_setting( struct cam_sensor_power_ctrl_t *power_info) { @@ -110,6 +132,13 @@ static int cam_ois_power_up(struct cam_ois_ctrl_t *o_ctrl) &o_ctrl->soc_info; struct cam_ois_soc_private *soc_private; struct cam_sensor_power_ctrl_t *power_info; + o_ctrl->prev_timestamp = 0; + o_ctrl->curr_timestamp = 0; + o_ctrl->is_first_vsync = 1; + o_ctrl->is_video_mode = false; + o_ctrl->is_need_eis_data = false; + o_ctrl->q_timer_cnt = QTIMER_SAMPLE_TIME*10*2; + o_ctrl->mono_timestamp = 0; soc_private = (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; @@ -157,6 +186,8 @@ static int cam_ois_power_up(struct cam_ois_ctrl_t *o_ctrl) return rc; } + CAM_INFO(CAM_OIS, "OIS Power up successfully"); + rc = camera_io_init(&o_ctrl->io_master_info); if (rc) { CAM_ERR(CAM_OIS, "cci_init failed: rc: %d", rc); @@ -206,6 +237,13 @@ static int cam_ois_power_down(struct cam_ois_ctrl_t *o_ctrl) return rc; } + CAM_INFO(CAM_OIS, "OIS power down successed"); + +#ifdef CONFIG_MOT_DONGWOON_OIS_AF_DRIFT + if (strstr(o_ctrl->ois_name, "dw9784")) + cam_ois_set_init_info(0); +#endif + camera_io_release(&o_ctrl->io_master_info); return rc; @@ -281,6 +319,20 @@ static int cam_ois_apply_settings(struct cam_ois_ctrl_t *o_ctrl, "Failed in Applying i2c wrt settings"); return rc; } + if (o_ctrl->ic_name != NULL && strstr(o_ctrl->ic_name, "aw86006")) { + if (i2c_list->i2c_settings.reg_setting[0].reg_addr == AW86006_PACKET_ENABLE && + i2c_list->i2c_settings.reg_setting[0].reg_data == 0x01) + o_ctrl->is_video_mode = true; + else + o_ctrl->is_video_mode = false; + } + if (o_ctrl->ic_name != NULL && strstr(o_ctrl->ic_name, "dw9781c")) { + if (i2c_list->i2c_settings.reg_setting[0].reg_addr == 0x7014 && + i2c_list->i2c_settings.reg_setting[0].reg_data == 0x00) + o_ctrl->is_video_mode = true; + else + o_ctrl->is_video_mode = false; + } } else if (i2c_list->op_code == CAM_SENSOR_I2C_WRITE_SEQ) { rc = camera_io_dev_write_continuous( &(o_ctrl->io_master_info), @@ -303,6 +355,13 @@ static int cam_ois_apply_settings(struct cam_ois_ctrl_t *o_ctrl, i2c_list->i2c_settings.addr_type, i2c_list->i2c_settings.data_type, i2c_list->i2c_settings.reg_setting[i].delay); + if (rc == 1) { + CAM_ERR(CAM_OIS, + "i2c poll fails addr:data %x:%x", + i2c_list->i2c_settings.reg_setting[i].reg_addr, + i2c_list->i2c_settings.reg_setting[i].reg_data); + return rc; + } if (rc < 0) { CAM_ERR(CAM_OIS, "i2c poll apply setting Fail"); @@ -333,7 +392,14 @@ static int cam_ois_slaveInfo_pkt_parser(struct cam_ois_ctrl_t *o_ctrl, 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->ois_preprog_flag = ois_info->ois_preprog_flag; + o_ctrl->ois_precoeff_flag = ois_info->ois_precoeff_flag; o_ctrl->is_ois_calib = ois_info->is_ois_calib; + o_ctrl->ois_postcalib_flag = ois_info->ois_postcalib_flag; + o_ctrl->ois_fw_txn_data_sz = ois_info->ois_fw_txn_data_sz; + o_ctrl->ois_fw_inc_addr = ois_info->ois_fw_inc_addr; + o_ctrl->ois_fw_addr_type = ois_info->ois_fw_addr_type; + o_ctrl->ois_fw_data_type = ois_info->ois_fw_data_type; memcpy(o_ctrl->ois_name, ois_info->ois_name, OIS_NAME_LEN); o_ctrl->ois_name[OIS_NAME_LEN - 1] = '\0'; o_ctrl->io_master_info.cci_client->retries = 3; @@ -354,16 +420,162 @@ static int cam_ois_slaveInfo_pkt_parser(struct cam_ois_ctrl_t *o_ctrl, return rc; } -static int cam_ois_fw_download(struct cam_ois_ctrl_t *o_ctrl) +static int cam_ois_fw_prog_download(struct cam_ois_ctrl_t *o_ctrl) { uint16_t total_bytes = 0; uint8_t *ptr = NULL; - int32_t rc = 0, cnt; - uint32_t fw_size; + int32_t rc = 0, total_idx, packet_idx; + uint32_t txn_data_size, txn_regsetting_size; const struct firmware *fw = NULL; const char *fw_name_prog = NULL; - const char *fw_name_coeff = NULL; char name_prog[32] = {0}; + struct device *dev = &(o_ctrl->pdev->dev); + struct cam_sensor_i2c_reg_setting i2c_reg_setting; + void *vaddr = NULL; + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return -EINVAL; + } + + snprintf(name_prog, 32, "%s.prog", o_ctrl->ois_name); + + /* cast pointer as const pointer*/ + fw_name_prog = name_prog; + + /* 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; + } + + if (strstr(o_ctrl->ois_name, "dw9781")) { + if (!dw9781c_check_fw_download(&(o_ctrl->io_master_info), fw->data, fw->size)) { + CAM_INFO(CAM_OIS, "Skip firmware download."); + release_firmware(fw); + return 0; + } + CAM_INFO(CAM_OIS, "Firmware download started."); + }else if (strstr(o_ctrl->ois_name, "dw9784")) { + if (!dw9784_check_fw_download(&(o_ctrl->io_master_info), fw->data, fw->size)) { + CAM_INFO(CAM_OIS, "Skip firmware download."); + release_firmware(fw); + return 0; + } + CAM_INFO(CAM_OIS, "Firmware download started."); + } + else if (strstr(o_ctrl->ois_name, "aw86006")) { + mutex_lock(&o_ctrl->aw_ois_mutex); + rc = aw86006_firmware_update(o_ctrl, fw); + mutex_unlock(&o_ctrl->aw_ois_mutex); + return rc; + } + + total_bytes = fw->size; + if(o_ctrl->ois_fw_txn_data_sz == 0) + txn_data_size = total_bytes; + else + txn_data_size = o_ctrl->ois_fw_txn_data_sz; + + i2c_reg_setting.addr_type = o_ctrl->ois_fw_addr_type; + i2c_reg_setting.data_type = o_ctrl->ois_fw_data_type; + i2c_reg_setting.delay = 0; + txn_regsetting_size = sizeof(struct cam_sensor_i2c_reg_array) * txn_data_size; + vaddr = vmalloc(txn_regsetting_size); + if (!vaddr) { + CAM_ERR(CAM_OIS, "Failed in allocating i2c_array"); + release_firmware(fw); + return -ENOMEM; + } + + CAM_DBG(CAM_OIS, "fw len: %d, addr_type: %d, data_type: %d, chunck: %d, ois_fw_data_type:%d", total_bytes, + i2c_reg_setting.addr_type, + i2c_reg_setting.data_type, + txn_data_size, + o_ctrl->ois_fw_data_type); + + i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) (vaddr); + + for (total_idx = 0, ptr = (uint8_t *)fw->data; total_idx < total_bytes;) { + for (packet_idx = 0; + (packet_idx < (txn_data_size/o_ctrl->ois_fw_data_type)) && (total_idx + (packet_idx*o_ctrl->ois_fw_data_type) < total_bytes); + packet_idx ++, ptr += o_ctrl->ois_fw_data_type) + { + int regAddrOffset = 0; + if(o_ctrl->ois_fw_inc_addr == 1) + regAddrOffset = total_idx/o_ctrl->ois_fw_data_type + packet_idx; + if (strstr(o_ctrl->ois_name, "dw9784") && total_idx >= total_bytes - DW9784_IF_SIZE) { + i2c_reg_setting.reg_setting[packet_idx].reg_addr = o_ctrl->opcode.prog + regAddrOffset - (total_bytes - DW9784_IF_SIZE)/2; + i2c_reg_setting.reg_setting[packet_idx].reg_data = (uint32_t)(*ptr << 8) | *(ptr+1); + i2c_reg_setting.reg_setting[packet_idx].delay = 0; + i2c_reg_setting.reg_setting[packet_idx].data_mask = 0; + CAM_DBG(CAM_OIS, "IF OIS_FW Reg:[0x%04x]: 0x%04x P:0x%x", + i2c_reg_setting.reg_setting[packet_idx].reg_addr, + i2c_reg_setting.reg_setting[packet_idx].reg_data, + (ptr-(uint8_t *)fw->data)); + } else { + i2c_reg_setting.reg_setting[packet_idx].reg_addr = + o_ctrl->opcode.prog + regAddrOffset; + if (o_ctrl->ois_fw_data_type == CAMERA_SENSOR_I2C_TYPE_WORD) { + i2c_reg_setting.reg_setting[packet_idx].reg_data = (uint32_t)(*ptr << 8) | *(ptr+1); + } else { + i2c_reg_setting.reg_setting[packet_idx].reg_data = *ptr; + } + i2c_reg_setting.reg_setting[packet_idx].delay = 0; + i2c_reg_setting.reg_setting[packet_idx].data_mask = 0; + CAM_DBG(CAM_OIS, "OIS_FW Reg:[0x%04x]: 0x%04x P:0x%x", + i2c_reg_setting.reg_setting[packet_idx].reg_addr, + i2c_reg_setting.reg_setting[packet_idx].reg_data, + (ptr-(uint8_t *)fw->data)); + } + } + i2c_reg_setting.size = packet_idx; + if (o_ctrl->ois_fw_inc_addr == 1) { + if (strstr(o_ctrl->ois_name, "dw9784") && total_idx == total_bytes - DW9784_IF_SIZE){ + rc = dw9784_check_if_download(&(o_ctrl->io_master_info)); + if (rc < 0) { + CAM_ERR(CAM_OIS, "dw9784 check if download fail"); + goto release_firmware; + } + } + rc = camera_io_dev_write_continuous(&(o_ctrl->io_master_info), + &i2c_reg_setting, 0); + } else { + 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; + } + total_idx += packet_idx*o_ctrl->ois_fw_data_type; + CAM_DBG(CAM_OIS, "packet_idx: %d, total_idx: %d", packet_idx, total_idx); + } + + if (strstr(o_ctrl->ois_name, "dw9781")) { + dw9781_post_firmware_download(&(o_ctrl->io_master_info), fw->data, fw->size); + } else if (strstr(o_ctrl->ois_name, "dw9784")) { + dw9784_post_firmware_download(&(o_ctrl->io_master_info)); + } + +release_firmware: + vfree(vaddr); + vaddr = NULL; + txn_regsetting_size = 0; + release_firmware(fw); + + return rc; +} + +static int cam_ois_fw_coeff_download(struct cam_ois_ctrl_t *o_ctrl) +{ + uint16_t total_bytes = 0; + uint8_t *ptr = NULL; + int32_t rc = 0, total_idx, packet_idx; + uint32_t txn_data_size, txn_regsetting_size; + const struct firmware *fw = NULL; + const char *fw_name_coeff = NULL; char name_coeff[32] = {0}; struct device *dev = &(o_ctrl->pdev->dev); struct cam_sensor_i2c_reg_setting i2c_reg_setting; @@ -374,58 +586,15 @@ static int cam_ois_fw_download(struct cam_ois_ctrl_t *o_ctrl) return -EINVAL; } + if (strstr(o_ctrl->ois_name, "dw9781") || strstr(o_ctrl->ois_name, "aw86006") || + strstr(o_ctrl->ois_name, "dw9784")) { + CAM_DBG(CAM_OIS, "not need download coeff fw for %s.", o_ctrl->ois_name); + return 0; + } + 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.delay = 0; - fw_size = (sizeof(struct cam_sensor_i2c_reg_array) * total_bytes); - vaddr = vmalloc(fw_size); - if (!vaddr) { - CAM_ERR(CAM_OIS, - "Failed in allocating i2c_array: fw_size: %u", fw_size); - release_firmware(fw); - return -ENOMEM; - } - - i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) ( - vaddr); - - 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; - } - vfree(vaddr); - vaddr = NULL; - fw_size = 0; - release_firmware(fw); - rc = request_firmware(&fw, fw_name_coeff, dev); if (rc) { CAM_ERR(CAM_OIS, "Failed to locate %s", fw_name_coeff); @@ -433,41 +602,90 @@ static int cam_ois_fw_download(struct cam_ois_ctrl_t *o_ctrl) } 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; + if(o_ctrl->ois_fw_txn_data_sz == 0) + txn_data_size = total_bytes; + else + txn_data_size = o_ctrl->ois_fw_txn_data_sz; + + i2c_reg_setting.addr_type = o_ctrl->ois_fw_addr_type; + i2c_reg_setting.data_type = o_ctrl->ois_fw_data_type; i2c_reg_setting.delay = 0; - fw_size = (sizeof(struct cam_sensor_i2c_reg_array) * total_bytes); - vaddr = vmalloc(fw_size); + txn_regsetting_size = sizeof(struct cam_sensor_i2c_reg_array) * txn_data_size; + vaddr = vmalloc(txn_regsetting_size); if (!vaddr) { - CAM_ERR(CAM_OIS, - "Failed in allocating i2c_array: fw_size: %u", fw_size); + CAM_ERR(CAM_OIS, "Failed in allocating i2c_array"); release_firmware(fw); return -ENOMEM; } - i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) ( - vaddr); + i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) (vaddr); - 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; + for (total_idx = 0, ptr = (uint8_t *)fw->data; total_idx < total_bytes;) { + for(packet_idx = 0; + (packet_idx < txn_data_size) && (total_idx + packet_idx < total_bytes); + packet_idx++, ptr++) + { + int regAddrOffset = 0; + if(o_ctrl->ois_fw_inc_addr == 1) + regAddrOffset = total_idx + packet_idx; + + i2c_reg_setting.reg_setting[packet_idx].reg_addr = + o_ctrl->opcode.coeff + regAddrOffset; + i2c_reg_setting.reg_setting[packet_idx].reg_data = *ptr; + i2c_reg_setting.reg_setting[packet_idx].delay = 0; + i2c_reg_setting.reg_setting[packet_idx].data_mask = 0; + } + i2c_reg_setting.size = packet_idx; + 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; + } + total_idx += packet_idx; } - 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: vfree(vaddr); vaddr = NULL; - fw_size = 0; + txn_regsetting_size = 0; release_firmware(fw); + + return rc; +} + +static int cam_ois_write_q_timer(struct cam_ois_ctrl_t *o_ctrl) +{ + struct cam_sensor_i2c_reg_setting i2c_reg_setting = {NULL,1,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD,0}; + struct cam_sensor_i2c_reg_array i2c_write_settings = {QTIMER_ADDR,0x0000,0,0}; + int32_t rc = 0; + uint32_t data = 0; + uint64_t mono_time_ns = 0; + struct timespec64 ts; + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return -EINVAL; + } + + if (o_ctrl->q_timer_cnt > 60000) + o_ctrl->q_timer_cnt = QTIMER_SAMPLE_TIME*10*2; + + data = ++o_ctrl->q_timer_cnt; + + i2c_write_settings.reg_data = data; + i2c_reg_setting.reg_setting = &(i2c_write_settings); + + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &(i2c_reg_setting)); + if (rc < 0) { + CAM_ERR(CAM_OIS, "Failed in Applying Q-timer settings"); + } else { + ktime_get_boottime_ts64(&ts); + mono_time_ns = (uint64_t)((ts.tv_sec * 1000000000) + ts.tv_nsec); + o_ctrl->mono_timestamp = mono_time_ns; + } + + CAM_DBG(CAM_OIS,"Write Q-timer %d, mono timestamp %lld", data, mono_time_ns); return rc; } @@ -638,6 +856,34 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) "init parsing failed: %d", rc); break; } + } else if (((o_ctrl->ois_preprog_flag) != 0) && + o_ctrl->i2c_preprog_data.is_settings_valid == 0) { + CAM_DBG(CAM_OIS, "Received PreProg Settings"); + i2c_reg_settings = &(o_ctrl->i2c_preprog_data); + i2c_reg_settings->request_id = 0; + rc = cam_sensor_i2c_command_parser( + &o_ctrl->io_master_info, + i2c_reg_settings, + &cmd_desc[i], 1, NULL); + if (rc < 0) { + CAM_ERR(CAM_OIS, + "preprog parsing failed: %d", rc); + return rc; + } + } else if (((o_ctrl->ois_precoeff_flag) != 0) && + o_ctrl->i2c_precoeff_data.is_settings_valid == 0) { + CAM_DBG(CAM_OIS, "Received PreCoeff Settings"); + i2c_reg_settings = &(o_ctrl->i2c_precoeff_data); + i2c_reg_settings->request_id = 0; + rc = cam_sensor_i2c_command_parser( + &o_ctrl->io_master_info, + i2c_reg_settings, + &cmd_desc[i], 1, NULL); + if (rc < 0) { + CAM_ERR(CAM_OIS, + "precoeff parsing failed: %d", rc); + return rc; + } } else if ((o_ctrl->is_ois_calib != 0) && (o_ctrl->i2c_calib_data.is_settings_valid == 0)) { @@ -655,6 +901,20 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) "Calib parsing failed: %d", rc); break; } + } else if (((o_ctrl->ois_postcalib_flag) != 0) && + o_ctrl->i2c_postcalib_data.is_settings_valid == 0) { + CAM_DBG(CAM_OIS, "Received PostCalib Settings"); + i2c_reg_settings = &(o_ctrl->i2c_postcalib_data); + i2c_reg_settings->request_id = 0; + rc = cam_sensor_i2c_command_parser( + &o_ctrl->io_master_info, + i2c_reg_settings, + &cmd_desc[i], 1, NULL); + if (rc < 0) { + CAM_ERR(CAM_OIS, + "postcalib parsing failed: %d", rc); + return rc; + } } break; } @@ -673,14 +933,40 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) o_ctrl->cam_ois_state = CAM_OIS_CONFIG; } + if (o_ctrl->ois_preprog_flag) { + rc = cam_ois_apply_settings(o_ctrl, + &o_ctrl->i2c_preprog_data); + if (rc) { + CAM_ERR(CAM_OIS, "Cannot apply preprog settings"); + goto pwr_dwn; + } + } + if (o_ctrl->ois_fw_flag) { - rc = cam_ois_fw_download(o_ctrl); + rc = cam_ois_fw_prog_download(o_ctrl); if (rc) { CAM_ERR(CAM_OIS, "Failed OIS FW Download"); goto pwr_dwn; } } + if (o_ctrl->ois_precoeff_flag) { + rc = cam_ois_apply_settings(o_ctrl, + &o_ctrl->i2c_precoeff_data); + if (rc) { + CAM_ERR(CAM_OIS, "Cannot apply precoeff settings"); + goto pwr_dwn; + } + } + + if (o_ctrl->ois_fw_flag) { + rc = cam_ois_fw_coeff_download(o_ctrl); + if (rc) { + CAM_ERR(CAM_OIS, "Failed OIS COEFF FW Download"); + goto pwr_dwn; + } + } + rc = cam_ois_apply_settings(o_ctrl, &o_ctrl->i2c_init_data); if ((rc == -EAGAIN) && (o_ctrl->io_master_info.master_type == CCI_MASTER)) { @@ -697,6 +983,10 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) goto pwr_dwn; } +#ifdef CONFIG_MOT_DONGWOON_OIS_AF_DRIFT + if (strstr(o_ctrl->ois_name, "dw9784")) + cam_ois_set_init_info(1); +#endif if (o_ctrl->is_ois_calib) { rc = cam_ois_apply_settings(o_ctrl, &o_ctrl->i2c_calib_data); @@ -706,18 +996,46 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) } } + if (o_ctrl->ois_postcalib_flag) { + CAM_DBG(CAM_OIS, "starting post calib data"); + rc = cam_ois_apply_settings(o_ctrl, + &o_ctrl->i2c_postcalib_data); + if (rc) { + CAM_ERR(CAM_OIS, "Cannot apply post calib data"); + goto pwr_dwn; + } + } + rc = delete_request(&o_ctrl->i2c_init_data); if (rc < 0) { CAM_WARN(CAM_OIS, "Fail deleting Init data: rc: %d", rc); rc = 0; } + rc = delete_request(&o_ctrl->i2c_preprog_data); + if (rc < 0) { + CAM_WARN(CAM_OIS, + "Fail deleting PreProg data: rc: %d", rc); + rc = 0; + } + rc = delete_request(&o_ctrl->i2c_precoeff_data); + if (rc < 0) { + CAM_WARN(CAM_OIS, + "Fail deleting PreCoeff data: rc: %d", rc); + rc = 0; + } rc = delete_request(&o_ctrl->i2c_calib_data); if (rc < 0) { CAM_WARN(CAM_OIS, "Fail deleting Calibration data: rc: %d", rc); rc = 0; } + rc = delete_request(&o_ctrl->i2c_postcalib_data); + if (rc < 0) { + CAM_WARN(CAM_OIS, + "Fail deleting PostCalib data: rc: %d", rc); + rc = 0; + } break; case CAM_OIS_PACKET_OPCODE_OIS_CONTROL: if (o_ctrl->cam_ois_state < CAM_OIS_CONFIG) { @@ -727,6 +1045,9 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) o_ctrl->cam_ois_state); goto end; } + + o_ctrl->is_need_eis_data = false; + offset = (uint32_t *)&csl_packet->payload; offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t)); cmd_desc = (struct cam_cmd_buf_desc *)(offset); @@ -754,6 +1075,41 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) goto end; } break; + case CAM_OIS_PACKET_OPCODE_OIS_GYRO_OFFSET: + if (o_ctrl->cam_ois_state < CAM_OIS_CONFIG) { + rc = -EINVAL; + CAM_WARN(CAM_OIS, + "Not in right state to control OIS: %d", + o_ctrl->cam_ois_state); + return rc; + } + 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_gyro_data); + i2c_reg_settings->is_settings_valid = 1; + i2c_reg_settings->request_id = 0; + rc = cam_sensor_i2c_command_parser(&o_ctrl->io_master_info, + i2c_reg_settings, + cmd_desc, 1, NULL); + 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 gyro offset settings"); + return rc; + } + + rc = delete_request(i2c_reg_settings); + if (rc < 0) { + CAM_ERR(CAM_OIS, + "Fail deleting gyro offset data: rc: %d", rc); + return rc; + } + break; case CAM_OIS_PACKET_OPCODE_READ: { struct cam_buf_io_cfg *io_cfg; struct i2c_settings_array i2c_read_settings; @@ -869,6 +1225,552 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) } break; } + case CAM_OIS_PACKET_OPCODE_ACTIVE_OIS_ROHM: { + struct cam_buf_io_cfg *io_cfg; + struct cam_buf_io_cfg *timestamp_io_cfg; + struct i2c_settings_array i2c_read_settings; + struct timespec64 ts; + uintptr_t buf_addr = 0x0; + size_t buf_size = 0; + uint64_t timestamp; + uint8_t *timestampBuf; + uint32_t timestampBufLen; + + if (o_ctrl->cam_ois_state < CAM_OIS_CONFIG) { + rc = -EINVAL; + CAM_WARN(CAM_OIS, + "Not in right state to read OIS: %d", + o_ctrl->cam_ois_state); + return rc; + } + CAM_DBG(CAM_OIS, "number of I/O configs: %d:", + csl_packet->num_io_configs); + if (csl_packet->num_io_configs < 2) { + CAM_ERR(CAM_OIS, "Not enough I/O Configs"); + rc = -EINVAL; + return rc; + } + + INIT_LIST_HEAD(&(i2c_read_settings.list_head)); + + io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *) + &csl_packet->payload + + csl_packet->io_configs_offset); + + if (io_cfg == NULL) { + CAM_ERR(CAM_OIS, "I/O config is invalid(NULL)"); + rc = -EINVAL; + return rc; + } + + timestamp_io_cfg = &io_cfg[1]; + + if (timestamp_io_cfg == NULL) { + CAM_ERR(CAM_OIS, "timestamp I/O config is invalid(NULL)"); + rc = -EINVAL; + return rc; + } + + offset = (uint32_t *)&csl_packet->payload; + offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t)); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + if (cmd_desc == NULL) { + CAM_ERR(CAM_OIS, "cmd desc is invalid(NULL)"); + rc = -EINVAL; + return rc; + } + + i2c_read_settings.is_settings_valid = 1; + i2c_read_settings.request_id = 0; + rc = cam_sensor_i2c_command_parser(&o_ctrl->io_master_info, + &i2c_read_settings, + cmd_desc, 1, io_cfg); + if (rc < 0) { + CAM_ERR(CAM_OIS, "OIS read pkt parsing failed: %d", rc); + return rc; + } + + rc = cam_sensor_i2c_read_data( + &i2c_read_settings, + &o_ctrl->io_master_info); + if (rc < 0) { + CAM_ERR(CAM_OIS, "cannot read data rc: %d", rc); + delete_request(&i2c_read_settings); + return rc; + } + + ktime_get_boottime_ts64(&ts); + timestamp = + (uint64_t)((ts.tv_sec * 1000000000) + ts.tv_nsec); + rc = cam_mem_get_cpu_buf(timestamp_io_cfg->mem_handle[0], + &buf_addr, &buf_size); + timestampBuf = (uint8_t *)buf_addr + timestamp_io_cfg->offsets[0]; + timestampBufLen = buf_size - timestamp_io_cfg->offsets[0]; + if(timestampBufLen < sizeof(uint64_t)) { + CAM_ERR(CAM_OIS, "Buffer not large enough for timestamp"); + return -EINVAL; + } + + memcpy((void *)timestampBuf, (void *)×tamp, sizeof(uint64_t)); + rc = delete_request(&i2c_read_settings); + if (rc < 0) { + CAM_ERR(CAM_OIS, + "Failed in deleting the read settings"); + return rc; + } + break; + } + case CAM_OIS_PACKET_OPCODE_ACTIVE_OIS_DONGWOON: { + struct cam_buf_io_cfg *io_cfg; + struct cam_buf_io_cfg *timestamp_io_cfg; + struct i2c_settings_array i2c_read_settings; + uintptr_t buf_addr = 0x0; + size_t buf_size = 0; + uint8_t *timestampBuf; + uint32_t timestampBufLen; + struct i2c_settings_list *i2c_list; + uint8_t *read_buff = NULL; + uint32_t buff_length = 0; + uint32_t read_length = 0; + uint32_t size; + unsigned long rem_jiffies = 0; + + o_ctrl->is_need_eis_data = true; + + if (o_ctrl->cam_ois_state < CAM_OIS_CONFIG) { + rc = -EINVAL; + CAM_WARN(CAM_OIS, + "Not in right state to read OIS: %d", + o_ctrl->cam_ois_state); + return rc; + } + CAM_DBG(CAM_OIS, "number of I/O configs: %d:", + csl_packet->num_io_configs); + if (csl_packet->num_io_configs < 2) { + CAM_ERR(CAM_OIS, "Not enough I/O Configs"); + rc = -EINVAL; + return rc; + } + + INIT_LIST_HEAD(&(i2c_read_settings.list_head)); + + io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *) + &csl_packet->payload + + csl_packet->io_configs_offset); + + if (io_cfg == NULL) { + CAM_ERR(CAM_OIS, "I/O config is invalid(NULL)"); + rc = -EINVAL; + return rc; + } + + timestamp_io_cfg = &io_cfg[1]; + + if (timestamp_io_cfg == NULL) { + CAM_ERR(CAM_OIS, "timestamp I/O config is invalid(NULL)"); + rc = -EINVAL; + return rc; + } + + offset = (uint32_t *)&csl_packet->payload; + offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t)); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + if (cmd_desc == NULL) { + CAM_ERR(CAM_OIS, "cmd desc is invalid(NULL)"); + rc = -EINVAL; + return rc; + } + + i2c_read_settings.is_settings_valid = 1; + i2c_read_settings.request_id = 0; + rc = cam_sensor_i2c_command_parser(&o_ctrl->io_master_info, + &i2c_read_settings, + cmd_desc, 1, io_cfg); + if (rc < 0) { + CAM_ERR(CAM_OIS, "OIS read pkt parsing failed: %d", rc); + return rc; + } + + list_for_each_entry(i2c_list, + &(i2c_read_settings.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"); + delete_request(&i2c_read_settings); + return rc; + } + } else if (i2c_list->op_code == CAM_SENSOR_I2C_READ_SEQ) { + read_buff = i2c_list->i2c_settings.read_buff; + buff_length = i2c_list->i2c_settings.read_buff_len; + read_length = i2c_list->i2c_settings.size; + + CAM_DBG(CAM_OIS, "buff_length = %d, read_length = %d", buff_length, read_length); + + if (read_length > buff_length || buff_length < PACKET_BYTE*MAX_PACKET) { + CAM_ERR(CAM_SENSOR, + "Invalid buffer size, readLen: %d, bufLen: %d", + read_length, buff_length); + delete_request(&i2c_read_settings); + return -EINVAL; + } + + rc = cam_mem_get_cpu_buf(timestamp_io_cfg->mem_handle[0], + &buf_addr, &buf_size); + timestampBuf = (uint8_t *)buf_addr + timestamp_io_cfg->offsets[0]; + timestampBufLen = buf_size - timestamp_io_cfg->offsets[0]; + + if(timestampBufLen < sizeof(uint64_t)) { + CAM_ERR(CAM_OIS, "Buffer not large enough for timestamp"); + delete_request(&i2c_read_settings); + return -EINVAL; + } + + rem_jiffies = wait_for_completion_timeout(&o_ctrl->ois_data_complete, + msecs_to_jiffies(120)); + if (rem_jiffies == 0) { + CAM_ERR(CAM_OIS, "Wait ois data completion timeout 120 ms"); + delete_request(&i2c_read_settings); + return -ETIMEDOUT; + } + + mutex_lock(&(o_ctrl->vsync_mutex)); + memcpy((void *)timestampBuf, (void *)&o_ctrl->prev_timestamp, sizeof(uint64_t)); + + if (o_ctrl->ois_data_size <= buff_length) + memcpy((void *)read_buff, (void *)o_ctrl->ois_data, o_ctrl->ois_data_size); + else + memcpy((void *)read_buff, (void *)o_ctrl->ois_data, buff_length); + + mutex_unlock(&(o_ctrl->vsync_mutex)); + } 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, + 0xFFFE, + i2c_list->i2c_settings.addr_type, + i2c_list->i2c_settings.data_type, + i2c_list->i2c_settings.reg_setting[i].delay); + } + if ((rc == 1) || (rc < 0)) { + CAM_ERR(CAM_OIS, + "i2c poll fails rc: %d",rc); + rc = -EINVAL; + break; + } + } + } + rc = delete_request(&i2c_read_settings); + if (rc < 0) { + CAM_ERR(CAM_OIS, + "Failed in deleting the read settings"); + return rc; + } + break; + } + case CAM_OIS_PACKET_OPCODE_ACTIVE_OIS_AW86006: { + struct cam_buf_io_cfg *io_cfg; + struct cam_buf_io_cfg *timestamp_io_cfg; + struct i2c_settings_array i2c_read_settings; + uintptr_t buf_addr = 0x0; + size_t buf_size = 0; + uint8_t *timestampBuf; + uint32_t timestampBufLen; + struct i2c_settings_list *i2c_list; + uint8_t *read_buff = NULL; + uint32_t buff_length = 0; + uint32_t read_length = 0; + unsigned long rem_jiffies = 0; + + o_ctrl->is_need_eis_data = true; + + if (o_ctrl->cam_ois_state < CAM_OIS_CONFIG) { + rc = -EINVAL; + CAM_WARN(CAM_OIS, + "Not in right state to read OIS: %d", + o_ctrl->cam_ois_state); + return rc; + } + CAM_DBG(CAM_OIS, "number of I/O configs: %d:", + csl_packet->num_io_configs); + if (csl_packet->num_io_configs < 2) { + CAM_ERR(CAM_OIS, "Not enough I/O Configs"); + rc = -EINVAL; + return rc; + } + + INIT_LIST_HEAD(&(i2c_read_settings.list_head)); + + io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *) + &csl_packet->payload + + csl_packet->io_configs_offset); + + if (io_cfg == NULL) { + CAM_ERR(CAM_OIS, "I/O config is invalid(NULL)"); + rc = -EINVAL; + return rc; + } + + timestamp_io_cfg = &io_cfg[1]; + + if (timestamp_io_cfg == NULL) { + CAM_ERR(CAM_OIS, "timestamp I/O config is invalid(NULL)"); + rc = -EINVAL; + return rc; + } + + offset = (uint32_t *)&csl_packet->payload; + offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t)); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + if (cmd_desc == NULL) { + CAM_ERR(CAM_OIS, "cmd desc is invalid(NULL)"); + rc = -EINVAL; + return rc; + } + + i2c_read_settings.is_settings_valid = 1; + i2c_read_settings.request_id = 0; + rc = cam_sensor_i2c_command_parser(&o_ctrl->io_master_info, + &i2c_read_settings, + cmd_desc, 1, io_cfg); + if (rc < 0) { + CAM_ERR(CAM_OIS, "OIS read pkt parsing failed: %d", rc); + return rc; + } + + list_for_each_entry(i2c_list, + &(i2c_read_settings.list_head), list) { + if (i2c_list->op_code == CAM_SENSOR_I2C_READ_SEQ) { + read_buff = i2c_list->i2c_settings.read_buff; + buff_length = i2c_list->i2c_settings.read_buff_len; + read_length = i2c_list->i2c_settings.size; + + CAM_DBG(CAM_OIS, "buff_length = %d, read_length = %d", buff_length, read_length); + + if (read_length > buff_length || buff_length < RING_BUFFER_LEN) { + CAM_ERR(CAM_SENSOR, + "Invalid buffer size, readLen: %d, bufLen: %d", + read_length, buff_length); + delete_request(&i2c_read_settings); + return -EINVAL; + } + + rc = cam_mem_get_cpu_buf(timestamp_io_cfg->mem_handle[0], + &buf_addr, &buf_size); + timestampBuf = (uint8_t *)buf_addr + timestamp_io_cfg->offsets[0]; + timestampBufLen = buf_size - timestamp_io_cfg->offsets[0]; + + if(timestampBufLen < sizeof(uint64_t)) { + CAM_ERR(CAM_OIS, "Buffer not large enough for timestamp"); + delete_request(&i2c_read_settings); + return -EINVAL; + } + + rem_jiffies = wait_for_completion_timeout(&o_ctrl->ois_data_complete, + msecs_to_jiffies(120)); + if (rem_jiffies == 0) { + CAM_ERR(CAM_OIS, "Wait ois data completion timeout 120 ms"); + delete_request(&i2c_read_settings); + return -ETIMEDOUT; + } + + mutex_lock(&(o_ctrl->vsync_mutex)); + memcpy((void *)timestampBuf, (void *)&o_ctrl->prev_timestamp, sizeof(uint64_t)); + + if (o_ctrl->ring_buff_size <= buff_length) + memcpy((void *)read_buff, (void *)o_ctrl->ring_buff, o_ctrl->ring_buff_size); + else + memcpy((void *)read_buff, (void *)o_ctrl->ring_buff, buff_length); + + mutex_unlock(&(o_ctrl->vsync_mutex)); + } + } + rc = delete_request(&i2c_read_settings); + if (rc < 0) { + CAM_ERR(CAM_OIS, + "Failed in deleting the read settings"); + return rc; + } + break; + } + case CAM_OIS_PACKET_OPCODE_ACTIVE_OIS_DONGWOON_QTIMER: { + struct cam_buf_io_cfg *io_cfg; + struct cam_buf_io_cfg *timestamp_io_cfg; + struct i2c_settings_array i2c_read_settings; + uintptr_t buf_addr = 0x0; + size_t buf_size = 0; + uint8_t *timestampBuf; + uint32_t timestampBufLen; + struct i2c_settings_list *i2c_list; + uint8_t *read_buff = NULL; + uint32_t buff_length = 0, read_length = 0; + uint16_t sample_cnt = 0, flag = 0, latest_data_ts = 0; + uint64_t delta_timestamp_ns = 0; + + if (o_ctrl->cam_ois_state < CAM_OIS_CONFIG) { + rc = -EINVAL; + CAM_WARN(CAM_OIS, + "Not in right state to read OIS: %d", + o_ctrl->cam_ois_state); + return rc; + } + CAM_DBG(CAM_OIS, "number of I/O configs: %d:", + csl_packet->num_io_configs); + if (csl_packet->num_io_configs < 2) { + CAM_ERR(CAM_OIS, "Not enough I/O Configs"); + rc = -EINVAL; + return rc; + } + + INIT_LIST_HEAD(&(i2c_read_settings.list_head)); + + io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *) + &csl_packet->payload + + csl_packet->io_configs_offset); + + if (io_cfg == NULL) { + CAM_ERR(CAM_OIS, "I/O config is invalid(NULL)"); + rc = -EINVAL; + return rc; + } + + timestamp_io_cfg = &io_cfg[1]; + + if (timestamp_io_cfg == NULL) { + CAM_ERR(CAM_OIS, "timestamp I/O config is invalid(NULL)"); + rc = -EINVAL; + return rc; + } + + offset = (uint32_t *)&csl_packet->payload; + offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t)); + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + if (cmd_desc == NULL) { + CAM_ERR(CAM_OIS, "cmd desc is invalid(NULL)"); + rc = -EINVAL; + return rc; + } + + i2c_read_settings.is_settings_valid = 1; + i2c_read_settings.request_id = 0; + rc = cam_sensor_i2c_command_parser(&o_ctrl->io_master_info, + &i2c_read_settings, + cmd_desc, 1, io_cfg); + if (rc < 0) { + CAM_ERR(CAM_OIS, "OIS read pkt parsing failed: %d", rc); + return rc; + } + + list_for_each_entry(i2c_list, + &(i2c_read_settings.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"); + delete_request(&i2c_read_settings); + return rc; + } + } else if (i2c_list->op_code == CAM_SENSOR_I2C_READ_SEQ) { + read_buff = i2c_list->i2c_settings.read_buff; + buff_length = i2c_list->i2c_settings.read_buff_len; + read_length = i2c_list->i2c_settings.size; + + CAM_DBG(CAM_OIS, "buff_length = %d, read_length = %d", buff_length, read_length); + + if (buff_length < read_length) { + CAM_ERR(CAM_SENSOR, "Invalid buffer size, readLen: %d, bufLen: %d", read_length, buff_length); + delete_request(&i2c_read_settings); + return -EINVAL; + } + + rc = cam_mem_get_cpu_buf(timestamp_io_cfg->mem_handle[0], + &buf_addr, &buf_size); + timestampBuf = (uint8_t *)buf_addr + timestamp_io_cfg->offsets[0]; + timestampBufLen = buf_size - timestamp_io_cfg->offsets[0]; + + if(timestampBufLen < sizeof(uint64_t)) { + CAM_ERR(CAM_OIS, "Buffer not large enough for timestamp"); + delete_request(&i2c_read_settings); + return -EINVAL; + } + + rc = cam_ois_write_q_timer(o_ctrl); + udelay(300); + + if (rc < 0) { + CAM_ERR(CAM_OIS,"Write Q-timer failed rc: %d", rc); + delete_request(&i2c_read_settings); + return -EINVAL; + } + + // SM7325 support burst read + rc = camera_io_dev_read_seq( + &o_ctrl->io_master_info, + i2c_list->i2c_settings.reg_setting[0].reg_addr, + read_buff, + i2c_list->i2c_settings.addr_type, + i2c_list->i2c_settings.data_type, + i2c_list->i2c_settings.size); + if (rc < 0) { + CAM_ERR(CAM_OIS, "Failed: seq read I2C settings: %d", rc); + delete_request(&i2c_read_settings); + return -EINVAL; + } + + flag = (read_buff[0] >> 4) & 0xF; + sample_cnt = ((read_buff[0] & 0xF) << 8) | read_buff[1]; + latest_data_ts = (read_buff[2] << 8) | read_buff[3]; + + CAM_DBG(CAM_OIS, "flag = %d, sample_cnt = %d, latest_data_ts = %d", + flag, sample_cnt, latest_data_ts); + + if (flag != 0x2 && flag != 0x3) { + CAM_ERR(CAM_OIS, "flag %d is not in correct status", flag); + delete_request(&i2c_read_settings); + return -EINVAL; + } + + if (sample_cnt == 0 || sample_cnt > QTIMER_MAX_SAMPLE) { + CAM_ERR(CAM_OIS, "sample_cnt %d is out of range", sample_cnt); + delete_request(&i2c_read_settings); + return -EINVAL; + } + + if (latest_data_ts == 0 || + latest_data_ts > o_ctrl->q_timer_cnt || + ((QTIMER_SAMPLE_TIME*10+3) + latest_data_ts) <= o_ctrl->q_timer_cnt) { + CAM_ERR(CAM_OIS, "latest_data_ts %d is out of range, q_timer_cnt %d", + latest_data_ts, o_ctrl->q_timer_cnt); + delete_request(&i2c_read_settings); + return -EINVAL; + } + + delta_timestamp_ns = (o_ctrl->q_timer_cnt - latest_data_ts)*100000; + o_ctrl->mono_timestamp -= delta_timestamp_ns; // latest ois data timestamp + + if (o_ctrl->mono_timestamp == 0) { + CAM_ERR(CAM_OIS, "mono_timestamp is zero."); + delete_request(&i2c_read_settings); + return -EINVAL; + } + + CAM_DBG(CAM_OIS,"latest ois data mono timestamp %lld", o_ctrl->mono_timestamp); + + memcpy((void *)timestampBuf, (void *)&o_ctrl->mono_timestamp, sizeof(uint64_t)); + } + } + rc = delete_request(&i2c_read_settings); + if (rc < 0) { + CAM_ERR(CAM_OIS, "Failed in deleting the read settings"); + return rc; + } + break; + } default: CAM_ERR(CAM_OIS, "Invalid Opcode: %d", (csl_packet->header.op_code & 0xFFFFFF)); @@ -880,7 +1782,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) goto end; pwr_dwn: - cam_ois_power_down(o_ctrl); + //cam_ois_power_down(o_ctrl); /* ois will pown down in CAM_RELEASE_DEV when closed camera */ end: cam_common_mem_free(csl_packet); put_ref: @@ -917,6 +1819,9 @@ void cam_ois_shutdown(struct cam_ois_ctrl_t *o_ctrl) if (o_ctrl->i2c_mode_data.is_settings_valid == 1) delete_request(&o_ctrl->i2c_mode_data); + if (o_ctrl->i2c_gyro_data.is_settings_valid == 1) + delete_request(&o_ctrl->i2c_gyro_data); + if (o_ctrl->i2c_calib_data.is_settings_valid == 1) delete_request(&o_ctrl->i2c_calib_data); @@ -1044,6 +1949,13 @@ int cam_ois_driver_cmd(struct cam_ois_ctrl_t *o_ctrl, void *arg) if (o_ctrl->i2c_mode_data.is_settings_valid == 1) delete_request(&o_ctrl->i2c_mode_data); +#ifdef CONFIG_MOT_OIS_AF_DRIFT + if (o_ctrl->i2c_af_drift_data.is_settings_valid == 1) + delete_request(&o_ctrl->i2c_af_drift_data); +#endif + if (o_ctrl->i2c_gyro_data.is_settings_valid == 1) + delete_request(&o_ctrl->i2c_gyro_data); + if (o_ctrl->i2c_calib_data.is_settings_valid == 1) delete_request(&o_ctrl->i2c_calib_data); diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c index a7616d4d19b1..bd8b1c0740db 100644 --- a/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -10,6 +10,63 @@ #include "cam_debug_util.h" #include "camera_main.h" +extern int aw86006_ois_init(struct cam_ois_ctrl_t *o_ctrl); /* awinic add */ +extern int aw86006_ois_exit(struct cam_ois_ctrl_t *o_ctrl); /* awinic add */ + +static int cam_ois_clear_data_ready(struct cam_ois_ctrl_t *o_ctrl) +{ + struct cam_sensor_i2c_reg_setting i2c_reg_setting = {NULL,1,CAMERA_SENSOR_I2C_TYPE_WORD,CAMERA_SENSOR_I2C_TYPE_WORD,0}; + struct cam_sensor_i2c_reg_array i2c_write_settings = {0x70DA,0x0000,0,0}; + int32_t rc = 0; + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return -EINVAL; + } + + i2c_reg_setting.reg_setting = &(i2c_write_settings); + + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &(i2c_reg_setting)); + if (rc < 0) { + CAM_ERR(CAM_OIS, "Failed in Applying i2c wrt settings"); + } + + CAM_DBG(CAM_OIS,"Clear data-ready success"); + return rc; +} +#ifdef CONFIG_MOT_DONGWOON_OIS_AF_DRIFT +static struct cam_ois_ctrl_t * g_o_ctrl = NULL; + +int cam_ois_write_af_drift(uint32_t dac) +{ + struct cam_ois_ctrl_t *o_ctrl = g_o_ctrl; + struct cam_sensor_i2c_reg_setting i2c_reg_setting = {NULL, 1, CAMERA_SENSOR_I2C_TYPE_WORD, CAMERA_SENSOR_I2C_TYPE_WORD, 0}; + struct cam_sensor_i2c_reg_array i2c_write_settings = {0x7070, dac, 0, 0}; + int rc = 0; + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "invalid args"); + return -EINVAL; + } + + if (o_ctrl->cam_ois_state < CAM_OIS_CONFIG) { + CAM_WARN(CAM_OIS, "Not in right state to write af drift: %d", o_ctrl->cam_ois_state); + return -EINVAL; + } + + i2c_reg_setting.reg_setting = &(i2c_write_settings); + + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &(i2c_reg_setting)); + if (rc < 0) { + CAM_ERR(CAM_OIS, "fail in applying i2c wrt settings"); + return -EINVAL; + } + + CAM_DBG(CAM_OIS,"write af-drift success 0x%x", dac); + return rc; +} +#endif + static int cam_ois_subdev_close_internal(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { @@ -271,6 +328,255 @@ static int cam_ois_i2c_driver_remove(struct i2c_client *client) return 0; } +static irqreturn_t cam_aw86006_ois_vsync_irq_thread(int irq, void *data) +{ + struct cam_ois_ctrl_t *o_ctrl = data; + int rc = -EINVAL, handled = IRQ_NONE, sample_cnt = 0, delay_time = 0; + uint64_t mono_time_ns; + struct timespec64 ts; + uint8_t *read_buff; + uint32_t k, read_len; + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return IRQ_NONE; + } + + if (o_ctrl->cam_ois_state < CAM_OIS_CONFIG) { + CAM_WARN(CAM_OIS, "Not in right state to read Eis data: %d", o_ctrl->cam_ois_state); + return IRQ_NONE; + } + + if (o_ctrl->is_video_mode == false || + o_ctrl->is_need_eis_data == false) { + CAM_DBG(CAM_OIS, "No need to read Eis data: %d %d", o_ctrl->is_video_mode, o_ctrl->is_need_eis_data); + return IRQ_NONE; + } + + if (!mutex_trylock(&o_ctrl->vsync_mutex)) { + CAM_WARN(CAM_OIS, "try to get mutex fail, skip this irq"); + return IRQ_NONE; + } + + ktime_get_boottime_ts64(&ts); + mono_time_ns = (uint64_t)((ts.tv_sec * 1000000000) + ts.tv_nsec); + + CAM_DBG(CAM_OIS, "aw86006 ois vsync sof mono timestamp is %lld", mono_time_ns); + + o_ctrl->prev_timestamp = o_ctrl->curr_timestamp; + o_ctrl->curr_timestamp = mono_time_ns; + + // when the first vsync arrived, return + if (o_ctrl->is_first_vsync) { + o_ctrl->is_first_vsync = 0; + rc = -EINVAL; + goto release_mutex; + } + + memset(o_ctrl->ring_buff, 0, o_ctrl->ring_buff_size); + read_buff = o_ctrl->ring_buff; + + for (k = 0; k < RING_BUFFER_LEN/READ_BYTE + 1; k++) { + if (k == RING_BUFFER_LEN/READ_BYTE) + read_len = RING_BUFFER_LEN%READ_BYTE; + else + read_len = READ_BYTE; + + if (read_len == 0) { + CAM_WARN(CAM_OIS, "read length is 0, break loop read"); + break; + } + + rc = camera_io_dev_ois_read_seq( + &o_ctrl->io_master_info, + AW86006_PACKET_ADDR, + read_buff + k*READ_BYTE, + CAMERA_SENSOR_I2C_TYPE_WORD, + CAMERA_SENSOR_I2C_TYPE_BYTE, + read_len); + + if (rc < 0) { + CAM_ERR(CAM_OIS, "failed to read ois data: %d", rc); + goto release_mutex; + } + } + + sample_cnt = read_buff[0]; + delay_time = read_buff[1]; + + CAM_DBG(CAM_OIS,"sample_cnt = %d, delay_time = %d (100 us)", sample_cnt, delay_time); + + if (sample_cnt == 0 || sample_cnt > AW86006_MAX_SAMPLE) { + CAM_WARN(CAM_OIS,"sample_cnt %d is invalid, skip the data", sample_cnt); + rc = -EINVAL; + goto release_mutex; + } + +release_mutex: + if (rc < 0) { + memset(o_ctrl->ring_buff, 0, o_ctrl->ring_buff_size); + handled = IRQ_NONE; + } else + handled = IRQ_HANDLED; + + mutex_unlock(&(o_ctrl->vsync_mutex)); + + if (rc >= 0) + complete(&o_ctrl->ois_data_complete); + + return handled; +} + +static irqreturn_t cam_ois_vsync_irq_thread(int irq, void *data) +{ + struct cam_ois_ctrl_t *o_ctrl = data; + int rc = 0, handled = IRQ_NONE, packet_cnt = 0, sample_cnt = 0; + uint64_t mono_time_ns; + struct timespec64 ts; + uint8_t *read_buff; + uint32_t k, read_len; + uint32_t data_ready = 0xFFFF; + int i = 0; + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "Invalid Args"); + return IRQ_NONE; + } + + if (o_ctrl->cam_ois_state < CAM_OIS_CONFIG) { + CAM_WARN(CAM_OIS, "Not in right state to read OIS: %d", o_ctrl->cam_ois_state); + goto release_mutex; + } + + if(o_ctrl->is_video_mode == false || + o_ctrl->is_need_eis_data == false) { + CAM_WARN(CAM_OIS, "No need to read Eis data %d %d", o_ctrl->is_video_mode, o_ctrl->is_need_eis_data); + return IRQ_NONE; + } + + if (!mutex_trylock(&o_ctrl->vsync_mutex)) { + CAM_ERR(CAM_OIS, "try lock fail, skip this irq"); + return IRQ_NONE; + } + + ktime_get_boottime_ts64(&ts); + mono_time_ns = (uint64_t)((ts.tv_sec * 1000000000) + ts.tv_nsec); + + CAM_DBG(CAM_OIS, "vsync sof mono timestamp is %lld", mono_time_ns); + + o_ctrl->prev_timestamp = o_ctrl->curr_timestamp; + o_ctrl->curr_timestamp = mono_time_ns; + + // when the first vsync arrived, clear data-ready, and return. + if (o_ctrl->is_first_vsync) { + o_ctrl->is_first_vsync = 0; + rc = cam_ois_clear_data_ready(o_ctrl); + udelay(1000); + goto release_mutex; + } + + memset(o_ctrl->ois_data, 0, o_ctrl->ois_data_size); + read_buff = o_ctrl->ois_data; + + for (i = 0; i < READ_COUNT; i++) { + rc = camera_io_dev_read( + &o_ctrl->io_master_info, + DATA_READY_ADDR, + &data_ready, + CAMERA_SENSOR_I2C_TYPE_WORD, + CAMERA_SENSOR_I2C_TYPE_WORD); + if (rc < 0) { + CAM_ERR(CAM_OIS, "failed to read OIS 0x70da reg rc: %d", rc); + goto release_mutex; + } + if (data_ready == DATA_READY) { + CAM_DBG(CAM_OIS, "data_ready == 0x0001 i = %d", i); + udelay(400); + break; + } else if (data_ready != DATA_READY && i < READ_COUNT - 1) { + CAM_ERR(CAM_OIS, "data_ready != 0x0001 i = %d", i); + udelay(1000); + } else { + CAM_ERR(CAM_OIS, "data_ready check fail i = %d", i); + goto release_mutex; + } + } + do { + if (packet_cnt > 0 && packet_cnt < MAX_PACKET) + read_buff += PACKET_BYTE; + + // SM6375: CCI_VERSION_1_2_9 can only support read 0xE bytes data one time. + for (k = 0; k < PACKET_BYTE/READ_BYTE + 1; k++) { + if (k == PACKET_BYTE/READ_BYTE) + read_len = PACKET_BYTE%READ_BYTE; + else + read_len = READ_BYTE; + + if (read_len == 0) { + CAM_WARN(CAM_OIS, "Read length is zero, break loop read"); + break; + } + + rc = camera_io_dev_ois_read_seq( + &o_ctrl->io_master_info, + PACKET_ADDR + k*READ_BYTE/2, + read_buff + k*READ_BYTE, + CAMERA_SENSOR_I2C_TYPE_WORD, + CAMERA_SENSOR_I2C_TYPE_WORD, + read_len); + + if (rc < 0) { + CAM_ERR(CAM_OIS, "Failed: seq read I2C settings: %d", rc); + goto release_mutex; + } + + if (k == 0 && packet_cnt == 0) { + sample_cnt = read_buff[1]; + if (sample_cnt != 0) { + packet_cnt = (sample_cnt + 9)/10; + CAM_DBG(CAM_OIS,"sample data = 0x%x, packet_cnt = %d", sample_cnt, packet_cnt); + + // we only need max 30 sample. + if (packet_cnt > MAX_PACKET || sample_cnt > MAX_SAMPLE) { + CAM_WARN(CAM_OIS,"Too many packet, skip this read"); + rc = -EINVAL; + goto release_mutex; + } + } else { + CAM_WARN(CAM_OIS,"No-fatal: sample data is zero, break the loop read"); + goto release_mutex; + } + } + } + + if (sample_cnt > 10 && packet_cnt > 1) { + CAM_WARN(CAM_OIS,"more than 1 packet, clear data-ready and read next packet"); + rc = cam_ois_clear_data_ready(o_ctrl); + udelay(1000); + + if (rc < 0) { + CAM_ERR(CAM_OIS,"Write failed rc: %d", rc); + goto release_mutex; + } + } + + packet_cnt--; + } while(packet_cnt > 0); + +release_mutex: + if (rc < 0) { + memset(o_ctrl->ois_data, 0, o_ctrl->ois_data_size); + handled = IRQ_NONE; + } else + handled = IRQ_HANDLED; + + mutex_unlock(&(o_ctrl->vsync_mutex)); + + complete(&o_ctrl->ois_data_complete); + + return handled; +} + static int cam_ois_component_bind(struct device *dev, struct device *master_dev, void *data) { @@ -290,11 +596,21 @@ static int cam_ois_component_bind(struct device *dev, o_ctrl->ois_device_type = MSM_CAMERA_PLATFORM_DEVICE; + o_ctrl->ring_buff_size = RING_BUFFER_LEN; + o_ctrl->ring_buff = kzalloc(o_ctrl->ring_buff_size, GFP_KERNEL); + if (!o_ctrl->ring_buff) + goto free_o_ctrl; + + o_ctrl->ois_data_size = PACKET_BYTE*MAX_PACKET; + o_ctrl->ois_data = kzalloc(o_ctrl->ois_data_size, GFP_KERNEL); + if (!o_ctrl->ois_data) + goto free_ring_buff; + o_ctrl->io_master_info.master_type = CCI_MASTER; o_ctrl->io_master_info.cci_client = kzalloc( sizeof(struct cam_sensor_cci_client), GFP_KERNEL); if (!o_ctrl->io_master_info.cci_client) - goto free_o_ctrl; + goto free_ois_data; soc_private = kzalloc(sizeof(struct cam_ois_soc_private), GFP_KERNEL); @@ -306,8 +622,12 @@ static int cam_ois_component_bind(struct device *dev, soc_private->power_info.dev = &pdev->dev; INIT_LIST_HEAD(&(o_ctrl->i2c_init_data.list_head)); + INIT_LIST_HEAD(&(o_ctrl->i2c_preprog_data.list_head)); + INIT_LIST_HEAD(&(o_ctrl->i2c_precoeff_data.list_head)); INIT_LIST_HEAD(&(o_ctrl->i2c_calib_data.list_head)); + INIT_LIST_HEAD(&(o_ctrl->i2c_postcalib_data.list_head)); INIT_LIST_HEAD(&(o_ctrl->i2c_mode_data.list_head)); + INIT_LIST_HEAD(&(o_ctrl->i2c_gyro_data.list_head)); mutex_init(&(o_ctrl->ois_mutex)); rc = cam_ois_driver_soc_init(o_ctrl); if (rc) { @@ -328,6 +648,48 @@ static int cam_ois_component_bind(struct device *dev, platform_set_drvdata(pdev, o_ctrl); o_ctrl->cam_ois_state = CAM_OIS_INIT; + +#ifdef CONFIG_MOT_DONGWOON_OIS_AF_DRIFT + g_o_ctrl = o_ctrl; +#endif + mutex_init(&(o_ctrl->vsync_mutex)); + init_completion(&o_ctrl->ois_data_complete); + + if (o_ctrl->ic_name != NULL && strstr(o_ctrl->ic_name, "aw86006")) + aw86006_ois_init(o_ctrl); + + if (o_ctrl->is_ois_vsync_irq_supported) { + o_ctrl->vsync_irq = platform_get_irq_optional(pdev, 0); + + if (o_ctrl->vsync_irq > 0) { + CAM_DBG(CAM_OIS, "get ois-vsync irq: %d", o_ctrl->vsync_irq); + + if (o_ctrl->ic_name != NULL && strstr(o_ctrl->ic_name, "aw86006")) { + rc = devm_request_threaded_irq(dev, + o_ctrl->vsync_irq, + NULL, + cam_aw86006_ois_vsync_irq_thread, + (IRQF_TRIGGER_RISING | IRQF_ONESHOT), + "aw86006-vsync-irq", + o_ctrl); + } else { + rc = devm_request_threaded_irq(dev, + o_ctrl->vsync_irq, + NULL, + cam_ois_vsync_irq_thread, + (IRQF_TRIGGER_RISING | IRQF_ONESHOT), + "ois-vsync-irq", + o_ctrl); + } + + if (rc != 0) + CAM_ERR(CAM_OIS, "failed: to request ois-vsync IRQ %d, rc %d", o_ctrl->vsync_irq, rc); + else + CAM_DBG(CAM_OIS, "request ois-vsync IRQ success"); + } else + CAM_ERR(CAM_OIS, "failed: to get ois-vsync IRQ"); + } + CAM_DBG(CAM_OIS, "Component bound successfully"); return rc; unreg_subdev: @@ -336,6 +698,10 @@ free_soc: kfree(soc_private); free_cci_client: kfree(o_ctrl->io_master_info.cci_client); +free_ois_data: + kfree(o_ctrl->ois_data); +free_ring_buff: + kfree(o_ctrl->ring_buff); free_o_ctrl: kfree(o_ctrl); return rc; @@ -358,6 +724,9 @@ static void cam_ois_component_unbind(struct device *dev, } CAM_INFO(CAM_OIS, "platform driver remove invoked"); + if (o_ctrl->ic_name != NULL && strstr(o_ctrl->ic_name, "aw86006")) + aw86006_ois_exit(o_ctrl); + soc_info = &o_ctrl->soc_info; for (i = 0; i < soc_info->num_clk; i++) devm_clk_put(soc_info->dev, soc_info->clk[i]); @@ -373,6 +742,8 @@ static void cam_ois_component_unbind(struct device *dev, kfree(o_ctrl->soc_info.soc_private); kfree(o_ctrl->io_master_info.cci_client); + kfree(o_ctrl->ois_data); + kfree(o_ctrl->ring_buff); platform_set_drvdata(pdev, NULL); v4l2_set_subdevdata(&o_ctrl->v4l2_dev_str.sd, NULL); kfree(o_ctrl); diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h index ddb585bc4f2b..28b35ec1738e 100644 --- a/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_dev.h @@ -25,6 +25,28 @@ #define DEFINE_MSM_MUTEX(mutexname) \ static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) +#define MODE_ADDR 0x7014 +#define ENABLE_ADDR 0x7015 +#define PACKET_ADDR 0x70B0 +#define DATA_READY_ADDR 0x70DA +#define DATA_READY 0x0001 +#define READ_COUNT 3 +#define PACKET_BYTE 62 +#define MAX_PACKET 5 +#define MAX_SAMPLE 30 +#define READ_BYTE 0xC + +#define QTIMER_ADDR 0x70DB +#define QTIMER_SAMPLE_TIME 2 +#define QTIMER_MAX_SAMPLE 20 + +/* AW86006 EIS */ +#define RING_BUFFER_LEN 42 +#define AW86006_PACKET_ENABLE 0x0003 +#define AW86006_PACKET_ADDR 0x0006 +#define AW86006_MAX_SAMPLE 10 + + enum cam_ois_state { CAM_OIS_INIT, CAM_OIS_ACQUIRE, @@ -82,6 +104,13 @@ struct cam_ois_intf_params { struct cam_req_mgr_crm_cb *crm_cb; }; +struct awrw_ctrl { + uint32_t addr[4]; + uint16_t reg_num; + uint8_t flag; + uint8_t *reg_data; +}; + /** * struct cam_ois_ctrl_t - OIS ctrl private data * @device_name : ois device_name @@ -95,12 +124,21 @@ struct cam_ois_intf_params { * @i2c_init_data : ois i2c init settings * @i2c_mode_data : ois i2c mode settings * @i2c_time_data : ois i2c time write settings + * @i2c_preprog_data : ois i2c preprog settings + * @i2c_precoeff_data : ois i2c precoeff settings + * @i2c_postcalib_data : ois i2c postcalib settings * @i2c_calib_data : ois i2c calib settings * @ois_device_type : ois device type * @cam_ois_state : ois_device_state * @ois_fw_flag : flag for firmware download + * @ois_preprog_flag : flag for preprog reg settings + * @ois_precoeff_flag : flag for precoeff reg settings * @is_ois_calib : flag for Calibration data + * @ois_postcalib_flag : flag for postcalib reg settings * @opcode : ois opcode + * @ois_fw_inc_addr : flag to increment address when sending fw + * @ois_fw_addr_type : address type of fw + * @ois_fw_txn_data_sz : num data bytes per i2c txn when sending fw * @device_name : Device name * */ @@ -115,15 +153,46 @@ struct cam_ois_ctrl_t { struct cam_subdev v4l2_dev_str; struct cam_ois_intf_params bridge_intf; struct i2c_settings_array i2c_init_data; + struct i2c_settings_array i2c_preprog_data; + struct i2c_settings_array i2c_precoeff_data; struct i2c_settings_array i2c_calib_data; + struct i2c_settings_array i2c_postcalib_data; struct i2c_settings_array i2c_mode_data; + struct i2c_settings_array i2c_gyro_data; struct i2c_settings_array i2c_time_data; enum msm_camera_device_type_t ois_device_type; enum cam_ois_state cam_ois_state; char ois_name[32]; uint8_t ois_fw_flag; + uint8_t ois_preprog_flag; + uint8_t ois_precoeff_flag; uint8_t is_ois_calib; + uint8_t ois_postcalib_flag; + uint8_t ois_fw_txn_data_sz; + uint8_t ois_fw_inc_addr; + uint8_t ois_fw_addr_type; + uint8_t ois_fw_data_type; + uint64_t prev_timestamp; + uint64_t curr_timestamp; struct cam_ois_opcode opcode; + bool is_ois_vsync_irq_supported; + int vsync_irq; + struct mutex vsync_mutex; + struct completion ois_data_complete; + bool is_first_vsync; + uint8_t *ois_data; + int ois_data_size; + uint16_t q_timer_cnt; + uint64_t mono_timestamp; + /* awinic_add */ + const char *ic_name; + struct work_struct aw_fw_update_work; + struct mutex aw_ois_mutex; + struct awrw_ctrl *awrw_ctrl; + uint8_t *ring_buff; + int ring_buff_size; + bool is_video_mode; + bool is_need_eis_data; }; /** diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_dw9781.c b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_dw9781.c new file mode 100644 index 000000000000..b977eef2fc71 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_dw9781.c @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2021 Motorola Mobility LLC. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 +#include "cam_ois_core.h" +#include "cam_ois_soc.h" +#include "cam_sensor_util.h" +#include "cam_debug_util.h" +#include "cam_common_util.h" + +#define DW9781C_CHIP_ID_ADDRESS 0x7000 +#define DW9781C_CHECKSUM_ADDRESS 0x7007 +#define DW9781C_CHIP_ID 0x9781 +#define FW_VER_CURR_ADDR 0x7001 +#define FW_TYPE_ADDR 0x700D +#define SET_FW 0x8001 + +#define EOK 0 + +#define FW_VERSION_OFFSET 10235 +#define FW_CHECKSUM_OFFSET 10234 + +typedef struct +{ + unsigned int driverIc; + unsigned int size; + const uint16_t *fwContentPtr; + uint16_t version; + uint16_t checksum; +} FirmwareContex; + +static FirmwareContex g_dw9781FirmwareContext; + +static int32_t dw9781_cci_write(struct camera_io_master * io_master_info, uint16_t reg, uint16_t val) +{ + int32_t rc = 0; + struct cam_sensor_i2c_reg_array reg_setting; + struct cam_sensor_i2c_reg_setting wr_setting; + + reg_setting.reg_addr = reg; + reg_setting.reg_data = val; + reg_setting.delay = 0; + reg_setting.data_mask = 0; + wr_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + wr_setting.data_type = CAMERA_SENSOR_I2C_TYPE_WORD; + wr_setting.reg_setting = ®_setting; + wr_setting.size = 1; + wr_setting.delay = 0; + rc = camera_io_dev_write(io_master_info, &wr_setting); + return rc; +} + +static int32_t dw9781_cci_read(struct camera_io_master * io_master_info, uint16_t reg, uint16_t *val) +{ + int32_t rc = 0; + uint32_t regVal = 0; + rc = camera_io_dev_read(io_master_info, reg, ®Val, CAMERA_SENSOR_I2C_TYPE_WORD, CAMERA_SENSOR_I2C_TYPE_WORD); + if (!rc) { + *val = (uint16_t)regVal; + } + return rc; +} + +static void dw9781_delay_ms(uint32_t ms) +{ + usleep_range(ms*1000, ms*1000+10); + return; +} + +void dw9781_ois_reset(struct camera_io_master * io_master_info) +{ + CAM_DBG(CAM_OIS, "[dw9781c_ois_reset] ois reset"); + dw9781_cci_write(io_master_info, 0xD002, 0x0001); /* DW9781_DBGc reset */ + dw9781_delay_ms(4); + dw9781_cci_write(io_master_info, 0xD001, 0x0001); /* Active mode (DSP ON) */ + dw9781_delay_ms(25); /* ST gyro - over wait 25ms, default Servo On */ + dw9781_cci_write(io_master_info, 0xEBF1, 0x56FA); /* User protection release */ +} + +void dw9781_ois_ready_check(struct camera_io_master * io_master_info) +{ + uint16_t fw_flag; + dw9781_cci_write(io_master_info, 0xD001, 0x0000); /* dsp off mode */ + dw9781_cci_write(io_master_info, 0xFAFA, 0x98AC); /* All protection(1) */ + dw9781_cci_write(io_master_info, 0xF053, 0x70BD); /* All protection(2) */ + dw9781_cci_read(io_master_info, 0xA7F9, &fw_flag); /* check checksum flag */ + CAM_DBG(CAM_OIS, "[dw9781c_ois_ready_check] checksum flag : 0x%04x", fw_flag); + if(fw_flag == 0xCC33) + { + CAM_DBG(CAM_OIS, "[dw9781c_ois_ready_check] checksum flag is ok"); + dw9781_ois_reset(io_master_info); /* ois reset */ + } else { + dw9781_cci_write(io_master_info, 0xD002, 0x0001); /* dw9781c reset */ + dw9781_delay_ms(4); + CAM_ERR(CAM_OIS, "[dw9781c_ois_ready_check] previous firmware download fail"); + } +} + +void dw9781_all_protection_release(struct camera_io_master * io_master_info) +{ + CAM_DBG(CAM_OIS, "[dw9781c_all_protection_release] execution"); + /* release all protection */ + dw9781_cci_write(io_master_info, 0xFAFA, 0x98AC); + dw9781_delay_ms(1); + dw9781_cci_write(io_master_info, 0xF053, 0x70BD); + dw9781_delay_ms(1); +} + +static uint16_t dw9781_fw_checksum_verify(struct camera_io_master * io_master_info) +{ + uint16_t data; + + /* FW checksum command */ + dw9781_cci_write(io_master_info, 0x7011, 0x2000); + /* command start */ + dw9781_cci_write(io_master_info, 0x7010, 0x8000); + dw9781_delay_ms(10); + /* calc the checksum to write the 0x7005 */ + dw9781_cci_read(io_master_info, 0x7005, &data); + CAM_DBG(CAM_OIS, "F/W Checksum calculated value : 0x%04X", data); + + return data; +} + +static int dw9781_erase_mtp_rewritefw(struct camera_io_master * io_master_info) +{ + CAM_DBG(CAM_OIS, "dw9781c erase for rewritefw starting.."); + + /* 512 byte page */ + dw9781_cci_write(io_master_info, 0xde03, 0x0027); + /* page erase */ + dw9781_cci_write(io_master_info, 0xde04, 0x0008); + dw9781_delay_ms(10); + + CAM_DBG(CAM_OIS, "dw9781c checksum flag erase : 0xCC33"); + return 0; +} + +static void dw9781_erase_mtp(struct camera_io_master * io_master_info) +{ + CAM_DBG(CAM_OIS, "[dw9781c_erase_mtp] start erasing firmware flash"); + /* 12c level adjust */ + dw9781_cci_write(io_master_info, 0xd005, 0x0001); + dw9781_cci_write(io_master_info, 0xdd03, 0x0002); + dw9781_cci_write(io_master_info, 0xdd04, 0x0002); + + /* 4k Sector_0 Erase*/ + dw9781_cci_write(io_master_info, 0xde03, 0x0000); + dw9781_cci_write(io_master_info, 0xde04, 0x0002); + dw9781_delay_ms(10); + /* 4k Sector_1 Erase*/ + dw9781_cci_write(io_master_info, 0xde03, 0x0008); + dw9781_cci_write(io_master_info, 0xde04, 0x0002); + dw9781_delay_ms(10); + /* 4k Sector_2 Erase*/ + dw9781_cci_write(io_master_info, 0xde03, 0x0010); + dw9781_cci_write(io_master_info, 0xde04, 0x0002); + dw9781_delay_ms(10); + /* 4k Sector_3 Erase*/ + dw9781_cci_write(io_master_info, 0xde03, 0x0018); + dw9781_cci_write(io_master_info, 0xde04, 0x0002); + dw9781_delay_ms(10); + /* 4k Sector_4 Erase*/ + dw9781_cci_write(io_master_info, 0xde03, 0x0020); + dw9781_cci_write(io_master_info, 0xde04, 0x0002); + dw9781_delay_ms(10); + CAM_DBG(CAM_OIS, "[dw9781c_erase_mtp] complete erasing firmware flash"); +} + +static int dw9781_prepare_fw_download(struct camera_io_master * io_master_info) +{ + /* step 1: MTP Erase and DSP Disable for firmware 0x8000 write */ + /* step 2: MTP setup */ + /* step 3: firmware sequential write to flash */ + /* step 4: firmware sequential read from flash */ + /* step 5: firmware verify */ + dw9781_cci_write(io_master_info, 0xd001, 0x0000); + dw9781_all_protection_release(io_master_info); + dw9781_erase_mtp(io_master_info); + CAM_DBG(CAM_OIS, "[dw9781c_download_fw] start firmware download"); + return 0; +} + +int dw9781c_check_fw_download(struct camera_io_master * io_master_info, const uint8_t *fwData, uint32_t fwSize) +{ + uint8_t ret; + uint8_t needDownload = 0; + uint16_t fwchecksum = 0; + uint16_t first_chip_id = 0; + uint16_t chip_checksum = 0; + uint16_t second_chip_id = 0; + uint16_t fw_version_current = 0; + uint16_t fw_version_latest = 0; + + if (io_master_info == NULL) { + printk("FATAL: OIS CCI context error!!!"); + return -1; + } + + if (fwData == NULL || fwSize < FW_VERSION_OFFSET*sizeof(uint16_t)) { + printk("FATAL: firmware buffer(%p) is NULL or size(%d) abnormal!!!", fwData, fwSize); + return -1; + } + + g_dw9781FirmwareContext.driverIc = 0x9781; + g_dw9781FirmwareContext.fwContentPtr = (const uint16_t *)fwData; + g_dw9781FirmwareContext.size = fwSize; + g_dw9781FirmwareContext.version = *(g_dw9781FirmwareContext.fwContentPtr+FW_VERSION_OFFSET); + g_dw9781FirmwareContext.version = ((g_dw9781FirmwareContext.version << 8) & 0xff00) | + ((g_dw9781FirmwareContext.version >> 8) & 0xff); + g_dw9781FirmwareContext.checksum = *(g_dw9781FirmwareContext.fwContentPtr+FW_CHECKSUM_OFFSET); + g_dw9781FirmwareContext.checksum = ((g_dw9781FirmwareContext.checksum << 8) & 0xff00) | + ((g_dw9781FirmwareContext.checksum >> 8) & 0xff); + + dw9781_ois_ready_check(io_master_info); + + dw9781_cci_read(io_master_info, DW9781C_CHIP_ID_ADDRESS, &first_chip_id); + dw9781_cci_read(io_master_info, 0x7001, &chip_checksum); + CAM_DBG(CAM_OIS, "[dw9781c] FW_VER_PHONE_MAKER : 0x%x", chip_checksum); + dw9781_cci_read(io_master_info, 0x7002, &chip_checksum); + CAM_DBG(CAM_OIS, "[dw9781c] FW_DATE_PHONE_MAKER : 0x%x", chip_checksum); + + CAM_DBG(CAM_OIS, "[dw9781c] first_chip_id : 0x%x", first_chip_id); + if (first_chip_id != DW9781C_CHIP_ID) { /* first_chip_id verification failed */ + dw9781_all_protection_release(io_master_info); + dw9781_cci_read(io_master_info, 0xd060, &second_chip_id); /* second_chip_id: 0x0020 */ + if ( second_chip_id == 0x0020 ) /* Check the second_chip_id*/ + { + CAM_DBG(CAM_OIS, "[dw9781c] start flash download:: size:%d, version:0x%x", + g_dw9781FirmwareContext.size, g_dw9781FirmwareContext.version); + needDownload = 1; + ret = dw9781_prepare_fw_download(io_master_info); /* Need to forced update OIS firmware again. */ + } else { + dw9781_cci_write(io_master_info, 0xd000, 0x0000); /* Shutdown mode */ + CAM_ERR(CAM_OIS, "[dw9781c] second_chip_id check fail"); + CAM_ERR(CAM_OIS, "[dw9781c] change dw9781c state to shutdown mode"); + return needDownload; + } + } else { + + + dw9781_cci_read(io_master_info, FW_VER_CURR_ADDR, &fw_version_current); + fw_version_latest = g_dw9781FirmwareContext.version; /*Firmware version read from file content.*/ + + CAM_DBG(CAM_OIS, "[dw9781c] fw_version_current = 0x%x, fw_version_latest = 0x%x", + fw_version_current, fw_version_latest); + + /* download firmware, check if need update, download firmware to flash */ + if (((fw_version_current & 0xFF) != (fw_version_latest & 0xFF))) { + + fwchecksum = dw9781_fw_checksum_verify(io_master_info); + if(fwchecksum != g_dw9781FirmwareContext.checksum) + { + needDownload = 1; + CAM_DBG(CAM_OIS, "[dw9781c] firmware checksum error 0x%04X, 0x%04X", + g_dw9781FirmwareContext.checksum, fwchecksum); + } + + if (needDownload) + { + CAM_DBG(CAM_OIS, "[dw9781c] start flash download:: size:%d, version:0x%x needDownload %d", + g_dw9781FirmwareContext.size, g_dw9781FirmwareContext.version, needDownload); + + ret = dw9781_prepare_fw_download(io_master_info); + CAM_DBG(CAM_OIS, "[dw9781c] flash download::vendor_dw9781c"); + if (ret != EOK) { + dw9781_erase_mtp_rewritefw(io_master_info); + dw9781_cci_write(io_master_info, 0xd000, 0x0000); /* Shut download mode */ + CAM_ERR(CAM_OIS, "[dw9781c] firmware download error, ret = 0x%x", ret); + CAM_ERR(CAM_OIS, "[dw9781c] change dw9781c state to shutdown mode"); + needDownload = 1; + } + } else { + CAM_DBG(CAM_OIS, "[dw9781c] ois firmware version is updated, skip download"); + } + } else { + CAM_DBG(CAM_OIS, "[dw9781c] ois firmware version is updated, skip download"); + } + } + return needDownload; +} +EXPORT_SYMBOL(dw9781c_check_fw_download); + +void dw9781_post_firmware_download(struct camera_io_master * io_master_info, const uint8_t *fwData, uint32_t fwSize) +{ + uint16_t fwchecksum = 0; + + g_dw9781FirmwareContext.checksum = *(g_dw9781FirmwareContext.fwContentPtr+FW_CHECKSUM_OFFSET); + g_dw9781FirmwareContext.checksum = ((g_dw9781FirmwareContext.checksum << 8) & 0xff00) | + ((g_dw9781FirmwareContext.checksum >> 8) & 0xff); + + dw9781_ois_ready_check(io_master_info); + + fwchecksum = dw9781_fw_checksum_verify(io_master_info); + if(fwchecksum != g_dw9781FirmwareContext.checksum) + { + CAM_ERR(CAM_OIS, "[dw9781c] firmware checksum error 0x%04X, 0x%04X", g_dw9781FirmwareContext.checksum, fwchecksum); + dw9781_cci_write(io_master_info, 0xd000, 0x0000); /* Shutdown mode */ + dw9781_delay_ms(100); + dw9781_cci_write(io_master_info, 0xd000, 0x0001); /* Standby mode */ + dw9781_delay_ms(100); + dw9781_all_protection_release(io_master_info); /* Disable write protect */ + dw9781_erase_mtp_rewritefw(io_master_info); + dw9781_cci_write(io_master_info, 0xd000, 0x0000); /* Shutdown mode */ + CAM_ERR(CAM_OIS, "[dw9781c] firmware download error"); + CAM_ERR(CAM_OIS, "[dw9781c] change dw9781c state to shutdown mode"); + } else { + CAM_DBG(CAM_OIS, "[dw9781c] Firmware download succes..."); + dw9781_ois_reset(io_master_info); + } + + return; +} + +EXPORT_SYMBOL(dw9781_post_firmware_download); diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_dw9784.c b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_dw9784.c new file mode 100644 index 000000000000..e79847778356 --- /dev/null +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_dw9784.c @@ -0,0 +1,406 @@ +/* + * Copyright (C) 2021 Motorola Mobility LLC. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 +#include "cam_ois_core.h" +#include "cam_ois_soc.h" +#include "cam_sensor_util.h" +#include "cam_debug_util.h" +#include "cam_common_util.h" + +#define DW9784_CHIP_ID_ADDRESS 0x7000 +#define DW9784_CHECKSUM_ADDRESS 0x700C +#define DW9784_CHIP_ID 0x9784 +#define FW_VER_CURR_ADDR 0x7001 + +#define EOK 0 + +#define FW_VERSION_OFFSET 10493 +#define FW_CHECKSUM_OFFSET 10495 + +typedef struct +{ + unsigned int driverIc; + unsigned int size; + const uint16_t *fwContentPtr; + uint16_t version; + uint16_t checksum; +} FirmwareContex; + +static FirmwareContex g_dw9784FirmwareContext; + +static int32_t dw9784_cci_write(struct camera_io_master * io_master_info, uint16_t reg, uint16_t val) +{ + int32_t rc = 0; + struct cam_sensor_i2c_reg_array reg_setting; + struct cam_sensor_i2c_reg_setting wr_setting; + + reg_setting.reg_addr = reg; + reg_setting.reg_data = val; + reg_setting.delay = 0; + reg_setting.data_mask = 0; + wr_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + wr_setting.data_type = CAMERA_SENSOR_I2C_TYPE_WORD; + wr_setting.reg_setting = ®_setting; + wr_setting.size = 1; + wr_setting.delay = 0; + rc = camera_io_dev_write(io_master_info, &wr_setting); + return rc; +} + +static int32_t dw9784_cci_read(struct camera_io_master * io_master_info, uint16_t reg, uint16_t *val) +{ + int32_t rc = 0; + uint32_t regVal = 0; + rc = camera_io_dev_read(io_master_info, reg, ®Val, CAMERA_SENSOR_I2C_TYPE_WORD, CAMERA_SENSOR_I2C_TYPE_WORD); + if (!rc) { + *val = (uint16_t)regVal; + } + return rc; +} + +static void dw9784_delay_ms(uint32_t ms) +{ + usleep_range(ms*1000, ms*1000+10); + return; +} + +void dw9784_ois_reset(struct camera_io_master * io_master_info) +{ + CAM_INFO(CAM_OIS, "[dw9784_ois_reset] ois reset"); + dw9784_cci_write(io_master_info, 0xD002, 0x0001); /* DW9784_DBGc reset */ + dw9784_delay_ms(4); + dw9784_cci_write(io_master_info, 0xD001, 0x0001); /* Active mode (DSP ON) */ + dw9784_delay_ms(25); /* ST gyro - over wait 25ms, default Servo On */ + dw9784_cci_write(io_master_info, 0xEBF1, 0x56FA); /* User protection release */ +} + +void dw9784_code_pt_off(struct camera_io_master * io_master_info) +{ + CAM_INFO(CAM_OIS, "[dw9784_code_pt_off] start"); + /* release all protection */ + dw9784_cci_write(io_master_info, 0xFD00, 0x5252); + dw9784_delay_ms(1); + CAM_INFO(CAM_OIS, "[dw9784_code_pt_off] finish"); +} + +void dw9784_pid_erase(struct camera_io_master * io_master_info) +{ + CAM_INFO(CAM_OIS, "[dw9784_pid_erase] start pid flash(IF) erase"); + dw9784_cci_write(io_master_info, 0xde03, 0x0000); // page 0 + dw9784_delay_ms(1); + dw9784_cci_write(io_master_info, 0xde04, 0x0008); // page erase + dw9784_delay_ms(10); // need to delay after erase + CAM_INFO(CAM_OIS, "[dw9784_pid_erase] finish"); +} + +void dw9784_fw_eflash_erase(struct camera_io_master * io_master_info) +{ + CAM_INFO(CAM_OIS, "[dw9784_fw_eflash_erase] start fw flash erase"); + dw9784_cci_write(io_master_info, 0xde03, 0x0000); // 4k Sector_0 + dw9784_delay_ms(1); + dw9784_cci_write(io_master_info, 0xde04, 0x0002); // 4k Sector Erase + dw9784_delay_ms(10); // need to delay after erase + + dw9784_cci_write(io_master_info, 0xde03, 0x0008); // 4k Sector_1 + dw9784_delay_ms(1); + dw9784_cci_write(io_master_info, 0xde04, 0x0002); // 4k Sector Erase + dw9784_delay_ms(10); // need to delay after erase + + dw9784_cci_write(io_master_info, 0xde03, 0x0010); // 4k Sector_2 + dw9784_delay_ms(1); + dw9784_cci_write(io_master_info, 0xde04, 0x0002); // 4k Sector Erase + dw9784_delay_ms(10); // need to delay after erase + + dw9784_cci_write(io_master_info, 0xde03, 0x0018); // 4k Sector_3 + dw9784_delay_ms(1); + dw9784_cci_write(io_master_info, 0xde04, 0x0002); // 4k Sector Erase + dw9784_delay_ms(10); // need to delay after erase + + dw9784_cci_write(io_master_info, 0xde03, 0x0020); // 4k Sector_4 + dw9784_delay_ms(1); + dw9784_cci_write(io_master_info, 0xde04, 0x0002); // 4k Sector Erase + dw9784_delay_ms(10); // need to delay after erase + CAM_INFO(CAM_OIS, "[dw9784_fw_eflash_erase] finish"); +} + +void dw9784_flash_acess(struct camera_io_master * io_master_info) +{ + CAM_INFO(CAM_OIS, "[dw9784_flash_acess] execution"); + /* release all protection */ + dw9784_cci_write(io_master_info, 0xFAFA, 0x98AC); + dw9784_delay_ms(1); + dw9784_cci_write(io_master_info, 0xF053, 0x70BD); + dw9784_delay_ms(1); +} + +int dw9784_whoami_chk(struct camera_io_master * io_master_info) +{ + uint16_t sec_chip_id; + dw9784_cci_write(io_master_info, 0xD000, 0x0001); /* chip enable */ + dw9784_delay_ms(4); + dw9784_cci_write(io_master_info, 0xD001, 0x0000); /* dsp off mode */ + dw9784_delay_ms(1); + + dw9784_flash_acess(io_master_info); /* All protection */ + + dw9784_cci_read(io_master_info, 0xD060, &sec_chip_id); /* 2nd chip id */ + CAM_INFO(CAM_OIS, "[dw9784_ois_ready_check] sec_chip_id : 0x%04x", sec_chip_id); + if(sec_chip_id != 0x0020) + { + CAM_ERR(CAM_OIS, "[dw9784] second_chip_id check fail : 0x%04X", sec_chip_id); + CAM_ERR(CAM_OIS, "[dw9784] second_enter shutdown mode"); + dw9784_cci_write(io_master_info, 0xD000, 0x0000); /* ic */ + return -1; + } + + dw9784_ois_reset(io_master_info); /* ois reset */ + return 0; +} + +int dw9784_checksum_fw_chk(struct camera_io_master * io_master_info) +{ + /* + Bit [0]: FW checksum error + Bit [1]: Module cal. checksum error + Bit [2]: Set cal. checksum error + */ + uint16_t reg_fw_checksum; // 0x700C + uint16_t reg_checksum_status; // 0x700D + + dw9784_cci_read(io_master_info, 0x700C, ®_fw_checksum); + dw9784_cci_read(io_master_info, 0x700D, ®_checksum_status); + + CAM_INFO(CAM_OIS, "[dw9784_checksum_fw_chk] reg_checksum_status : 0x%04X", reg_checksum_status); + CAM_INFO(CAM_OIS, "[dw9784_checksum_fw_chk] reg_fw_checksum : 0x%04X", reg_fw_checksum); + + if( (reg_checksum_status & 0x0001) == 0) + { + CAM_INFO(CAM_OIS, "[dw9784_checksum_fw_chk] fw checksum pass"); + return 0; + }else + { + CAM_ERR(CAM_OIS, "[dw9784_checksum_fw_chk] fw checksum error reg_fw_checksum : 0x%04X", reg_fw_checksum); + return -1; + } +} + +static int dw9784_erase_mtp_rewritefw(struct camera_io_master * io_master_info) +{ + uint16_t FMC; + CAM_INFO(CAM_OIS, "dw9784 erase for rewritefw starting.."); + dw9784_cci_write(io_master_info, 0xd001, 0x0000); + dw9784_delay_ms(1); + dw9784_flash_acess(io_master_info); + + dw9784_cci_write(io_master_info, 0xDE01, 0x0000); // FMC block FW select + dw9784_delay_ms(1); + dw9784_cci_read(io_master_info, 0xDE01, &FMC); + if (FMC != 0) + { + CAM_INFO(CAM_OIS, "[dw9784_download_fw] FMC register value 1st warning : %04x", FMC); + dw9784_cci_write(io_master_info, 0xDE01, 0x0000); + dw9784_delay_ms(1); + FMC = 0; // initialize FMC value + + dw9784_cci_read(io_master_info, 0xDE01, &FMC); + if (FMC != 0) + { + CAM_ERR(CAM_OIS, "[dw9784_download_fw] 2nd FMC register value 2nd warning : %04x", FMC); + CAM_ERR(CAM_OIS, "[dw9784_download_fw] stop f/w download"); + return -1; + } + } + + /* code protection off */ + dw9784_code_pt_off(io_master_info); + + /* 512 byte page */ + dw9784_cci_write(io_master_info, 0xde03, 0x0027); + /* page erase */ + dw9784_cci_write(io_master_info, 0xde04, 0x0008); + dw9784_delay_ms(10); + + dw9784_cci_write(io_master_info, 0xd000, 0x0000); /* Shut download mode */ + + return 0; +} + +static int dw9784_prepare_fw_download(struct camera_io_master * io_master_info) +{ + /* step 1: MTP Erase and DSP Disable for firmware 0x8000 write */ + /* step 2: MTP setup */ + /* step 3. FMC register check */ + /* step 4. code protection off */ + /* step 5. erase flash fw data */ + uint16_t FMC; + dw9784_cci_write(io_master_info, 0xd001, 0x0000); + dw9784_flash_acess(io_master_info); + + dw9784_cci_write(io_master_info, 0xDE01, 0x0000); // FMC block FW select + dw9784_delay_ms(1); + dw9784_cci_read(io_master_info, 0xDE01, &FMC); + if (FMC != 0) + { + CAM_INFO(CAM_OIS, "[dw9784_download_fw] FMC register value 1st warning : %04x", FMC); + dw9784_cci_write(io_master_info, 0xDE01, 0x0000); + dw9784_delay_ms(1); + FMC = 0; // initialize FMC value + + dw9784_cci_read(io_master_info, 0xDE01, &FMC); + if (FMC != 0) + { + CAM_ERR(CAM_OIS, "[dw9784_download_fw] 2nd FMC register value 2nd warning : %04x", FMC); + CAM_ERR(CAM_OIS, "[dw9784_download_fw] stop f/w download"); + return -1; + } + } + + dw9784_code_pt_off(io_master_info); + dw9784_fw_eflash_erase(io_master_info); + CAM_INFO(CAM_OIS, "[dw9784_download_fw] start firmware download"); + return 0; +} + +int dw9784_check_fw_download(struct camera_io_master * io_master_info, const uint8_t *fwData, uint32_t fwSize) +{ + uint8_t ret; + uint8_t needDownload = 0; + uint16_t fwchecksum = 0; + uint16_t first_chip_id = 0; + uint16_t chip_checksum = 0; + uint16_t fw_version_current = 0; + uint16_t fw_version_latest = 0; + + if (io_master_info == NULL) { + CAM_ERR(CAM_OIS, "FATAL: OIS CCI context error!!!"); + return -1; + } + + if (fwData == NULL || fwSize < FW_VERSION_OFFSET*sizeof(uint16_t)) { + CAM_ERR(CAM_OIS, "FATAL: firmware buffer(%p) is NULL or size(%d) abnormal!!!", fwData, fwSize); + return -1; + } + + g_dw9784FirmwareContext.driverIc = 0x9784; + g_dw9784FirmwareContext.fwContentPtr = (const uint16_t *)fwData; + g_dw9784FirmwareContext.size = fwSize; + g_dw9784FirmwareContext.version = *(g_dw9784FirmwareContext.fwContentPtr+FW_VERSION_OFFSET); + g_dw9784FirmwareContext.version = ((g_dw9784FirmwareContext.version << 8) & 0xff00) | + ((g_dw9784FirmwareContext.version >> 8) & 0xff); + g_dw9784FirmwareContext.checksum = *(g_dw9784FirmwareContext.fwContentPtr+FW_CHECKSUM_OFFSET); + g_dw9784FirmwareContext.checksum = ((g_dw9784FirmwareContext.checksum << 8) & 0xff00) | + ((g_dw9784FirmwareContext.checksum >> 8) & 0xff); + if (dw9784_whoami_chk(io_master_info) != 0) { + CAM_ERR(CAM_OIS, "[dw9784] second chip id check fail"); + return -1; + } + + dw9784_cci_read(io_master_info, DW9784_CHIP_ID_ADDRESS, &first_chip_id); + dw9784_cci_read(io_master_info, 0x7001, &chip_checksum); + CAM_INFO(CAM_OIS, "[dw9784] FW_VER_PHONE_MAKER : 0x%x", chip_checksum); + dw9784_cci_read(io_master_info, 0x7002, &chip_checksum); + CAM_INFO(CAM_OIS, "[dw9784] FW_DATE_PHONE_MAKER : 0x%x", chip_checksum); + + CAM_INFO(CAM_OIS, "[dw9784] first_chip_id : 0x%x", first_chip_id); + if (first_chip_id != DW9784_CHIP_ID) { /* first_chip_id verification failed */ + CAM_INFO(CAM_OIS, "[dw9784] start flash download:: size:%d, version:0x%x", + g_dw9784FirmwareContext.size, g_dw9784FirmwareContext.version); + needDownload = 1; + ret = dw9784_prepare_fw_download(io_master_info); /* Need to forced update OIS firmware again. */ + } else { + fwchecksum = dw9784_checksum_fw_chk(io_master_info); + if(fwchecksum != 0) + { + needDownload = 1; + CAM_INFO(CAM_OIS, "[dw9784] firmware checksum error"); + } + + dw9784_cci_read(io_master_info, FW_VER_CURR_ADDR, &fw_version_current); + fw_version_latest = g_dw9784FirmwareContext.version; /*Firmware version read from file content.*/ + + CAM_INFO(CAM_OIS, "[dw9784] fw_version_current = 0x%x, fw_version_latest = 0x%x", + fw_version_current, fw_version_latest); + + /* download firmware, check if need update, download firmware to flash */ + if (needDownload || ((fw_version_current & 0xFFFF) != (fw_version_latest & 0xFFFF))) { + needDownload = 1; + + CAM_INFO(CAM_OIS, "[dw9784] start flash download:: size:%d, version:0x%x needDownload %d", + g_dw9784FirmwareContext.size, g_dw9784FirmwareContext.version, needDownload); + + ret = dw9784_prepare_fw_download(io_master_info); + CAM_INFO(CAM_OIS, "[dw9784] flash download::vendor_dw9784"); + if (ret != EOK) { + dw9784_erase_mtp_rewritefw(io_master_info); + CAM_ERR(CAM_OIS, "[dw9784] firmware download error, ret = 0x%x", ret); + CAM_ERR(CAM_OIS, "[dw9784] change dw9784 state to shutdown mode"); + needDownload = 1; + } + } else { + CAM_INFO(CAM_OIS, "[dw9784] ois firmware version is updated, skip download"); + } + } + return needDownload; +} +EXPORT_SYMBOL(dw9784_check_fw_download); + +int dw9784_check_if_download(struct camera_io_master * io_master_info) +{ + uint16_t FMC; + + /* step 1. Writes 512Byte FW(PID) data to IF flash. (FMC register check) */ + dw9784_cci_write(io_master_info, 0xDE01, 0x1000); + dw9784_delay_ms(1); + dw9784_cci_read(io_master_info,0xDE01, &FMC); + dw9784_delay_ms(1); + if (FMC != 0x1000) + { + CAM_INFO(CAM_OIS, "[dw9784_download_fw] IF FMC register value 1st warning : %04x", FMC); + dw9784_cci_write(io_master_info, 0xDE01, 0x1000); + dw9784_delay_ms(1); + FMC = 0; // initialize FMC value + + dw9784_cci_read(io_master_info,0xDE01, &FMC); + if (FMC != 0x1000) + { + CAM_ERR(CAM_OIS, "[dw9784_download_fw] 2nd IF FMC register value 2nd fail : %04x", FMC); + CAM_ERR(CAM_OIS, "[dw9784_download_fw] stop firmware download"); + return -1; + } + } + + /* step 2. erease IF(FW/PID) eFLASH */ + dw9784_pid_erase(io_master_info); + + CAM_INFO(CAM_OIS, "[dw9784_download_fw] start firmware/pid download"); + return 0; +} +EXPORT_SYMBOL(dw9784_check_if_download); + +void dw9784_post_firmware_download(struct camera_io_master * io_master_info) +{ + uint16_t fwchecksum = 0; + + dw9784_ois_reset(io_master_info); + fwchecksum = dw9784_checksum_fw_chk(io_master_info); + if(fwchecksum != 0) + { + CAM_ERR(CAM_OIS, "[dw9784] firmware checksum error"); + dw9784_erase_mtp_rewritefw(io_master_info); + CAM_ERR(CAM_OIS, "[dw9784] change dw9784 state to shutdown mode"); + } + return; +} + +EXPORT_SYMBOL(dw9784_post_firmware_download); diff --git a/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c index 510c81d9e9f3..5b9619a1ead8 100644 --- a/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c +++ b/techpack/camera/drivers/cam_sensor_module/cam_ois/cam_ois_soc.c @@ -34,6 +34,25 @@ static int cam_ois_get_dt_data(struct cam_ois_ctrl_t *o_ctrl) o_ctrl->ois_device_type); return -EINVAL; } + + if (!of_property_read_bool(of_node, "vsync-irq-support")) { + o_ctrl->is_ois_vsync_irq_supported = false; + } else { + o_ctrl->is_ois_vsync_irq_supported = true; + } + + rc = of_property_read_string(of_node, "ois-name", &o_ctrl->ic_name); + if (rc) { + CAM_DBG(CAM_OIS, "ois-name is not available in the node: %d", rc); + o_ctrl->ic_name = NULL; + } + +#ifdef CONFIG_CAMERA_DISABLE_VSYNC_IRQ + o_ctrl->is_ois_vsync_irq_supported = false; + CAM_WARN(CAM_OIS, "disable ois vsync irq in factory build"); +#endif + CAM_DBG(CAM_OIS, "is_ois_vsync_irq_supported %d", o_ctrl->is_ois_vsync_irq_supported); + rc = cam_soc_util_get_dt_properties(soc_info); if (rc < 0) { CAM_ERR(CAM_OIS, "cam_soc_util_get_dt_properties rc %d", diff --git a/techpack/camera/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.c b/techpack/camera/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.c index 146967f076a9..1596f7db5634 100644 --- a/techpack/camera/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.c +++ b/techpack/camera/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.c @@ -459,6 +459,7 @@ int cam_res_mgr_gpio_request(struct device *dev, uint gpio, * from the gpio_res_list * These two situations both need request gpio. */ + CAM_DBG(CAM_RES, "shared gpio enable is %d shared gpio num is %d", cam_res->shared_gpio_enabled, cam_res->dt.num_shared_gpio); if (!gpio_found) { CAM_DBG(CAM_RES, "gpio: %u not found in gpio_res list", gpio); rc = gpio_request_one(gpio, flags, label); @@ -572,7 +573,7 @@ bool cam_res_mgr_util_check_if_gpio_is_shared( } EXPORT_SYMBOL(cam_res_mgr_util_check_if_gpio_is_shared); -static void cam_res_mgr_gpio_free(struct device *dev, uint gpio) +void cam_res_mgr_gpio_free(struct device *dev, uint gpio) { bool gpio_found = false; bool need_free = true; @@ -647,6 +648,7 @@ static void cam_res_mgr_gpio_free(struct device *dev, uint gpio) mutex_unlock(&cam_res->gpio_res_lock); } +EXPORT_SYMBOL(cam_res_mgr_gpio_free); void cam_res_mgr_gpio_free_arry(struct device *dev, const struct gpio *array, size_t num) diff --git a/techpack/camera/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr_api.h b/techpack/camera/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr_api.h index cb5022f482e5..9a4b2b8560b8 100644 --- a/techpack/camera/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr_api.h +++ b/techpack/camera/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr_api.h @@ -73,6 +73,18 @@ bool cam_res_mgr_util_check_if_gpio_is_shared( int cam_res_mgr_gpio_request(struct device *dev, unsigned int gpio, unsigned long flags, const char *label); +/** + * @brief: Free a GPIO + * + * Free the GPIO and release corresponding gpio_res. + * + * @dev : Pointer to the device + * @gpio : A GPIO number + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +void cam_res_mgr_gpio_free(struct device *dev, uint gpio); + /** * @brief: Free a array GPIO * diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c index d56068b766eb..51f6e58f0713 100644 --- a/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -155,7 +155,7 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, csl_packet = (struct cam_packet *)(generic_ptr + (uint32_t)config.offset); - if (cam_packet_util_validate_packet(csl_packet, + if ((csl_packet == NULL) || cam_packet_util_validate_packet(csl_packet, remain_len)) { CAM_ERR(CAM_SENSOR, "Invalid packet params"); rc = -EINVAL; @@ -446,15 +446,90 @@ int32_t cam_sensor_update_slave_info(struct cam_cmd_probe *probe_info, s_ctrl->sensor_probe_addr_type = probe_info->addr_type; s_ctrl->sensor_probe_data_type = probe_info->data_type; + + s_ctrl->probe_sub_device = probe_info->probe_sub_device; + s_ctrl->sub_device_addr = probe_info->sub_device_addr; + s_ctrl->sub_device_data_type = probe_info->sub_device_data_type; + s_ctrl->sub_device_addr_type = probe_info->sub_device_addr_type; + s_ctrl->sub_device_id_addr = probe_info->sub_device_id_addr; + s_ctrl->expected_sub_device_id = probe_info->expected_sub_device_id; + s_ctrl->sub_device_cci_master = probe_info->sub_device_cci_master; + s_ctrl->sub_device_cci_device = probe_info->sub_device_cci_device; + s_ctrl->sub_device_i2c_freq_mode = probe_info->sub_device_i2c_freq_mode; +#ifdef CONFIG_CAMERA_CCI_ADDR_SWITCH + s_ctrl->i2c_addr_switch = probe_info->i2c_addr_switch; + s_ctrl->second_i2c_address = probe_info->second_i2c_address; + s_ctrl->i2c_switch_reg_addr_Type = probe_info->i2c_switch_reg_addr_Type; + s_ctrl->i2c_switch_reg_data_Type = probe_info->i2c_switch_reg_data_Type; + s_ctrl->i2c_switch_reg_addr = probe_info->i2c_switch_reg_addr; + s_ctrl->i2c_switch_reg_data = probe_info->i2c_switch_reg_data; + s_ctrl->i2c_switch_reg_delayMs = probe_info->i2c_switch_reg_delayMs; + CAM_DBG(CAM_SENSOR, - "Sensor Addr: 0x%x sensor_id: 0x%x sensor_mask: 0x%x sensor_pipeline_delay:0x%x", + "Sensor Addr: 0x%x sensor_id: 0x%x sensor_mask: 0x%x sensor_pipeline_delay:0x%x i2c_addr_switch: 0x%x second_i2c_address: 0x%x i2c_switch_reg_addr: 0x%x", s_ctrl->sensordata->slave_info.sensor_id_reg_addr, s_ctrl->sensordata->slave_info.sensor_id, s_ctrl->sensordata->slave_info.sensor_id_mask, - s_ctrl->pipeline_delay); + s_ctrl->pipeline_delay, + s_ctrl->i2c_addr_switch , + s_ctrl->second_i2c_address , + s_ctrl->i2c_switch_reg_addr); +#endif return rc; } +#ifdef CONFIG_CAMERA_CCI_ADDR_SWITCH +int cam_sensor_set_i2c_addr_switch_reg(struct cam_sensor_ctrl_t *s_ctrl) +{ + int rc = 0; + uint16_t sensor_address = 0; + struct cam_sensor_i2c_reg_setting wr_setting; + struct cam_sensor_i2c_reg_array reg_setting; + + /* if hal doesn't config i2c_addr_switch parameter in sensor xml, return success immediately */ + if (!s_ctrl->i2c_addr_switch) { + return 0; + } + + /* save sensor i2c address */ + sensor_address = s_ctrl->io_master_info.cci_client->sid; + + /* set sub-device i2c address */ + if (s_ctrl->second_i2c_address) { + s_ctrl->io_master_info.cci_client->sid = s_ctrl->second_i2c_address >> 1; + } + + reg_setting.reg_addr = s_ctrl->i2c_switch_reg_addr; + reg_setting.reg_data = s_ctrl->i2c_switch_reg_data; + reg_setting.delay = s_ctrl->i2c_switch_reg_delayMs; /* delay after switch iic addr */ + reg_setting.data_mask = 0; + wr_setting.addr_type = s_ctrl->i2c_switch_reg_addr_Type; + wr_setting.data_type = s_ctrl->i2c_switch_reg_data_Type; + wr_setting.reg_setting = ®_setting; + wr_setting.size = 1; + wr_setting.delay = 0; + rc = camera_io_dev_write(&s_ctrl->io_master_info, &wr_setting); +CAM_ERR(CAM_SENSOR, + "cam_sensor_set_i2c_addr_switch_reg slot:%d, slave_addr:0x%x, sensor_id:0x%x, sensor_address:0x%x", + s_ctrl->soc_info.index, + s_ctrl->sensordata->slave_info.sensor_slave_addr, + s_ctrl->sensordata->slave_info.sensor_id, + sensor_address); + /* restore sensor i2c address */ + s_ctrl->io_master_info.cci_client->sid = sensor_address; + + if (rc == 0) { + CAM_ERR(CAM_SENSOR, "write i2c addr switch reg success"); + } + else { + CAM_ERR(CAM_SENSOR, "write i2c addr switch reg fail"); + rc = -EINVAL; + } + + return rc; +} +#endif + int32_t cam_handle_cmd_buffers_for_probe(void *cmd_buf, struct cam_sensor_ctrl_t *s_ctrl, int32_t cmd_buf_num, uint32_t cmd_buf_length, size_t remain_len) @@ -685,6 +760,10 @@ void cam_sensor_shutdown(struct cam_sensor_ctrl_t *s_ctrl) int cam_sensor_match_id(struct cam_sensor_ctrl_t *s_ctrl) { int rc = 0; +#ifdef CONFIG_CAM_SENSOR_PROBE_RETRY + int retries = 5; + bool matched = false; +#endif uint32_t chipid = 0; struct cam_camera_slave_info *slave_info; @@ -696,6 +775,28 @@ int cam_sensor_match_id(struct cam_sensor_ctrl_t *s_ctrl) return -EINVAL; } +#ifdef CONFIG_CAM_SENSOR_PROBE_RETRY + while (retries-- && !matched) { + rc = camera_io_dev_read( + &(s_ctrl->io_master_info), + slave_info->sensor_id_reg_addr, + &chipid, + s_ctrl->sensor_probe_addr_type, + s_ctrl->sensor_probe_data_type); + + CAM_INFO(CAM_SENSOR, "read id: 0x%x expected id 0x%x:", + chipid, slave_info->sensor_id); + + if (cam_sensor_id_by_mask(s_ctrl, chipid) == slave_info->sensor_id) + matched = true; + + if (!matched && !retries) { + CAM_ERR(CAM_SENSOR, "Failed read id: 0x%x expected id 0x%x:", + chipid, slave_info->sensor_id); + return -ENODEV; + } + } +#else rc = camera_io_dev_read( &(s_ctrl->io_master_info), slave_info->sensor_id_reg_addr, @@ -711,6 +812,114 @@ int cam_sensor_match_id(struct cam_sensor_ctrl_t *s_ctrl) chipid, slave_info->sensor_id); return -ENODEV; } +#endif + return rc; +} + +int cam_sensor_match_sub_device_id(struct cam_sensor_ctrl_t *s_ctrl) +{ + int rc = 0; + int ret = 0; + uint32_t sub_device_id = 0; + uint16_t sensor_address = 0; + uint16_t sensor_freq_mode = 0; + uint8_t sensor_cci_master = 0; + uint8_t sensor_cci_device = 0; + + /* if hal doesn't config ProbeSubDevice parameter in sensor xml, return success immediately */ + if (!s_ctrl->probe_sub_device) { + return 0; + } + + /* save sensor i2c address */ + sensor_address = s_ctrl->io_master_info.cci_client->sid; + + /* set sub-device i2c address */ + if (s_ctrl->sub_device_addr) { + s_ctrl->io_master_info.cci_client->sid = s_ctrl->sub_device_addr >> 1; + } + + /*if need change cci master*/ + if (s_ctrl->need_change_cci_master) { + sensor_cci_master = s_ctrl->io_master_info.cci_client->cci_i2c_master; + sensor_freq_mode = s_ctrl->io_master_info.cci_client->i2c_freq_mode; + sensor_cci_device = s_ctrl->io_master_info.cci_client->cci_device; + + ret = camera_io_release(&(s_ctrl->io_master_info)); + if (ret != 0) { + CAM_ERR(CAM_SENSOR, "release sensor cci failed!"); + } + + s_ctrl->io_master_info.cci_client->cci_i2c_master = s_ctrl->sub_device_cci_master; + s_ctrl->io_master_info.cci_client->i2c_freq_mode = s_ctrl->sub_device_i2c_freq_mode; + + if(s_ctrl->io_master_info.cci_client->cci_device != s_ctrl->sub_device_cci_device) + { + s_ctrl->io_master_info.cci_client->cci_device = s_ctrl->sub_device_cci_device; + } + rc = camera_io_init(&(s_ctrl->io_master_info)); + if(rc != 0) { + ret = camera_io_release(&(s_ctrl->io_master_info)); + CAM_ERR(CAM_SENSOR, "init sensor cci failed! rc=%d, release ret=%d, try again!", rc, ret); + usleep_range(100000, 100000); + rc = camera_io_init(&(s_ctrl->io_master_info)); + if (rc != 0) { + ret = camera_io_release(&(s_ctrl->io_master_info)); + CAM_ERR(CAM_SENSOR, "try again init sensor cci failed again! rc=%d, release ret=%d", rc, ret); + } + } + } + + rc = camera_io_dev_read( + &(s_ctrl->io_master_info), + s_ctrl->sub_device_id_addr, + &sub_device_id, + s_ctrl->sub_device_addr_type, + s_ctrl->sub_device_data_type); + + CAM_INFO(CAM_SENSOR, "Read sub device id: 0x%x expected sub device id 0x%x:", + sub_device_id, s_ctrl->expected_sub_device_id); + + /* restore sensor i2c address */ + s_ctrl->io_master_info.cci_client->sid = sensor_address; + + /* reset cci master */ + if (s_ctrl->need_change_cci_master) { + ret = camera_io_release(&(s_ctrl->io_master_info)); + if (ret != 0) { + CAM_ERR(CAM_SENSOR, "release flash cci failed! "); + } + + s_ctrl->io_master_info.cci_client->cci_i2c_master = sensor_cci_master; + s_ctrl->io_master_info.cci_client->i2c_freq_mode = sensor_freq_mode; + s_ctrl->io_master_info.cci_client->cci_device = sensor_cci_device; + + rc = camera_io_init(&(s_ctrl->io_master_info)); + if(rc != 0) { + ret = camera_io_release(&(s_ctrl->io_master_info)); + CAM_ERR(CAM_SENSOR, "init sensor cci failed! rc=%d, release ret=%d, try again!", rc, ret); + usleep_range(100000, 100000); + rc = camera_io_init(&(s_ctrl->io_master_info)); + if (rc != 0) { + ret = camera_io_release(&(s_ctrl->io_master_info)); + CAM_ERR(CAM_SENSOR, "try again init sensor cci failed again! rc=%d, release ret=%d", rc, ret); + } + } + } + + if (sub_device_id == s_ctrl->expected_sub_device_id) { + CAM_INFO(CAM_SENSOR, + "Probe sub device success,slot:%d,sub_device_addr:0x%x,sub_device_id:0x%x", + s_ctrl->soc_info.index, + s_ctrl->sub_device_addr, + s_ctrl->expected_sub_device_id); + rc = 0; + } + else { + CAM_ERR(CAM_SENSOR, "Probe sub device fail"); + rc = -EINVAL; + } + return rc; } @@ -789,6 +998,20 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, goto free_power_settings; } +#ifdef CONFIG_CAMERA_CCI_ADDR_SWITCH + /* load probe setting before read sensorID */ + rc = cam_sensor_set_i2c_addr_switch_reg(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "set i2c addr switch reg failed ! slot:%d, slave_addr:0x%x, sensor_id:0x%x", + s_ctrl->soc_info.index, + s_ctrl->sensordata->slave_info.sensor_slave_addr, + s_ctrl->sensordata->slave_info.sensor_id); + cam_sensor_power_down(s_ctrl); + msleep(20); + goto free_power_settings; + } +#endif /* Match sensor ID */ rc = cam_sensor_match_id(s_ctrl); if (rc < 0) { @@ -797,6 +1020,14 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, goto free_power_settings; } + /* Match sub-device ID */ + rc = cam_sensor_match_sub_device_id(s_ctrl); + if (rc < 0) { + cam_sensor_power_down(s_ctrl); + usleep_range(20000,20000); + goto free_power_settings; + } + CAM_INFO(CAM_SENSOR, "Probe success,slot:%d,slave_addr:0x%x,sensor_id:0x%x", s_ctrl->soc_info.index, @@ -814,6 +1045,9 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, */ s_ctrl->is_probe_succeed = 1; s_ctrl->sensor_state = CAM_SENSOR_INIT; +#ifdef CONFIG_MOT_SENSOR_PRE_POWERUP + s_ctrl->sensor_power_up_done = 0; +#endif } break; case CAM_ACQUIRE_DEV: { @@ -1103,6 +1337,69 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, } } break; +#ifdef CONFIG_MOT_SENSOR_PRE_POWERUP + case CAM_MOT_PRE_POWER_UP: { + if (!s_ctrl->sensor_power_up_done) + { + rc = cam_sensor_power_up(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "MotPreAct - Sensor Power up failed for sensor_id:0x%x, slave_addr:0x%x", + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_slave_addr); + goto release_mutex; + } + s_ctrl->sensor_power_up_done = 1; + CAM_DBG(CAM_SENSOR, "MotPreAct - Camera sensor_id:0x%x, slave_addr:0x%x, pre power on done = %d", + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_slave_addr, + s_ctrl->sensor_power_up_done); + } + } + break; + case CAM_MOT_PRE_POWER_DOWN: { + if (s_ctrl->sensor_power_up_done) + { + rc = cam_sensor_power_down(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Sensor Power Down failed sensor_id: 0x%x, slave_addr:0x%x", + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_slave_addr); + goto release_mutex; + } + CAM_DBG(CAM_SENSOR, "MotPreAct - Camera sensor_id:0x%x, slave_addr:0x%x, pre power on done = %d", + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_slave_addr, + s_ctrl->sensor_power_up_done); + } + } + break; + case CAM_MOT_QUERY_SENSOR_STATUS: { + uint32_t isSensorActive = 0; + + if (s_ctrl->sensor_power_up_done) + { + isSensorActive = 1; + } + else + { + isSensorActive = 0; + } + + if (copy_to_user(u64_to_user_ptr(cmd->handle), + &isSensorActive, sizeof(uint32_t))) { + CAM_ERR(CAM_SENSOR, "MotPreAct - Failed Copy to User"); + rc = -EFAULT; + goto release_mutex; + } + CAM_DBG(CAM_SENSOR, "MotPreAct - Query camera sensor_id:0x%x, slave_addr:0x%x, status = %d", + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_slave_addr, + isSensorActive); + } + break; +#endif default: CAM_ERR(CAM_SENSOR, "Invalid Opcode: %d", cmd->op_code); rc = -EINVAL; @@ -1205,6 +1502,16 @@ int cam_sensor_power_up(struct cam_sensor_ctrl_t *s_ctrl) return -EINVAL; } +#ifdef CONFIG_MOT_SENSOR_PRE_POWERUP + if (s_ctrl->sensor_power_up_done) + { + CAM_INFO(CAM_SENSOR, "MotPreAct - sensor has power on done for sensor_id:0x%x, slave_addr:0x%x", + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_slave_addr); + return 0; + } +#endif + power_info = &s_ctrl->sensordata->power_info; slave_info = &(s_ctrl->sensordata->slave_info); @@ -1279,6 +1586,9 @@ int cam_sensor_power_down(struct cam_sensor_ctrl_t *s_ctrl) } camera_io_release(&(s_ctrl->io_master_info)); +#ifdef CONFIG_MOT_SENSOR_PRE_POWERUP + s_ctrl->sensor_power_up_done = 0; +#endif return rc; } diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h b/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h index 8586ce51c87f..486574164f56 100644 --- a/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_dev.h @@ -111,6 +111,26 @@ struct cam_sensor_ctrl_t { bool bob_pwm_switch; uint32_t last_flush_req; uint16_t pipeline_delay; + uint8_t probe_sub_device; + uint16_t sub_device_addr; + uint8_t sub_device_data_type; + uint8_t sub_device_addr_type; + uint16_t sub_device_id_addr; + uint16_t expected_sub_device_id; + uint8_t sub_device_cci_master; + uint8_t sub_device_cci_device; + uint8_t sub_device_i2c_freq_mode; + bool need_change_cci_master; + uint8_t i2c_addr_switch; + uint16_t second_i2c_address; + uint8_t i2c_switch_reg_addr_Type; + uint8_t i2c_switch_reg_data_Type; + uint16_t i2c_switch_reg_addr; + uint16_t i2c_switch_reg_data; + uint16_t i2c_switch_reg_delayMs; +#ifdef CONFIG_MOT_SENSOR_PRE_POWERUP + bool sensor_power_up_done; +#endif }; /** diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_soc.c b/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_soc.c index d5cfe48223a5..dc41dacae0ea 100644 --- a/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_soc.c +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor/cam_sensor_soc.c @@ -187,6 +187,13 @@ static int32_t cam_sensor_driver_get_dt_data(struct cam_sensor_ctrl_t *s_ctrl) CAM_DBG(CAM_SENSOR, "cci-index %d", s_ctrl->cci_num); } + if (of_property_read_bool(of_node, "need-change-cci-master")) { + CAM_DBG(CAM_SENSOR, "need-change-cci-master found in this imgsensor"); + s_ctrl->need_change_cci_master = true; + } else { + s_ctrl->need_change_cci_master = false; + } + if (of_property_read_u32(of_node, "sensor-position-pitch", &sensordata->pos_pitch) < 0) { CAM_DBG(CAM_SENSOR, "Invalid sensor position"); diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c b/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c index a5e780a2e119..1400dc14b821 100644 --- a/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c @@ -93,6 +93,39 @@ int32_t cam_camera_cci_i2c_read_seq(struct cam_sensor_cci_client *cci_client, return rc; } +int32_t cam_camera_cci_i2c_ois_read_seq(struct cam_sensor_cci_client *cci_client, + uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type, + uint32_t num_byte) +{ + int32_t rc = -EFAULT; + struct cam_cci_ctrl cci_ctrl; + + if ((addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) + || (data_type >= CAMERA_SENSOR_I2C_TYPE_MAX) + || (num_byte > I2C_REG_DATA_MAX)) { + CAM_ERR(CAM_SENSOR, "addr_type %d num_byte %d", addr_type, + num_byte); + return rc; + } + + cci_ctrl.cmd = MSM_CCI_I2C_READ; + cci_ctrl.cci_info = cci_client; + cci_ctrl.cfg.cci_i2c_read_cfg.addr = addr; + cci_ctrl.cfg.cci_i2c_read_cfg.addr_type = addr_type; + cci_ctrl.cfg.cci_i2c_read_cfg.data_type = data_type; + cci_ctrl.cfg.cci_i2c_read_cfg.data = data; + cci_ctrl.cfg.cci_i2c_read_cfg.num_byte = num_byte; + cci_ctrl.status = -EFAULT; + rc = v4l2_subdev_call(cci_client->cci_subdev, + core, ioctl, VIDIOC_MSM_CCI_CFG, &cci_ctrl); + rc = cci_ctrl.status; + CAM_DBG(CAM_SENSOR, "addr = 0x%x, rc = %d", addr, rc); + + return rc; +} + static int32_t cam_cci_i2c_write_table_cmd( struct camera_io_master *client, struct cam_sensor_i2c_reg_setting *write_setting, diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h b/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h index 6cece10403c9..9c3c108437fe 100644 --- a/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h @@ -49,6 +49,12 @@ int32_t cam_camera_cci_i2c_read_seq(struct cam_sensor_cci_client *client, enum camera_sensor_i2c_type data_type, uint32_t num_byte); +int32_t cam_camera_cci_i2c_ois_read_seq(struct cam_sensor_cci_client *client, + uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type, + uint32_t num_byte); + /** * @client: CCI client structure * @write_setting: I2C register setting diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.c b/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.c index 108c47923eb7..3d8d48f295df 100644 --- a/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.c +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.c @@ -6,6 +6,27 @@ #include "cam_sensor_io.h" #include "cam_sensor_i2c.h" +#ifdef CONFIG_CAM_DISTINGUISH_SENSOR_VERSION + +#define SPECIAL_SENSOR_ID 0x5041 +#define SPECIAL_SENSOR_ADDR_ID 0x300B +#define SPECIAL_SENSOR_ADDR_VERSION 0x900E +#define SPECIAL_SENSOR_IIC_ADDR 0x10 + +static uint32_t s_r900e_val = 0; + +struct cam_sensor_i2c_reg_array special_on_write_settings = {0x0100, 0x01, 0x05, 0xFF}; +struct cam_sensor_i2c_reg_array special_off_write_settings = {0x0100, 0x00, 0x00, 0xFF}; + +struct cam_sensor_i2c_reg_array special_streamon_write_settings[] = +{ + {0x7278, 0x00, 0x00, 0xFF}, + {0x727a, 0x01, 0x00, 0xFF}, + {0x7280, 0x07, 0x00, 0xFF}, + {0x0100, 0x01, 0x00, 0xFF} +}; +#endif + int32_t camera_io_dev_poll(struct camera_io_master *io_master_info, uint32_t addr, uint16_t data, uint32_t data_mask, enum camera_sensor_i2c_type addr_type, @@ -68,14 +89,25 @@ int32_t camera_io_dev_read(struct camera_io_master *io_master_info, enum camera_sensor_i2c_type addr_type, enum camera_sensor_i2c_type data_type) { +#ifdef CONFIG_CAM_DISTINGUISH_SENSOR_VERSION + int32_t retval = 0; + uint32_t r900e = 0; + struct cam_sensor_i2c_reg_setting write_setting = {0}; +#endif + if (!io_master_info) { CAM_ERR(CAM_SENSOR, "Invalid Args"); return -EINVAL; } if (io_master_info->master_type == CCI_MASTER) { +#ifdef CONFIG_CAM_DISTINGUISH_SENSOR_VERSION + retval = cam_cci_i2c_read(io_master_info->cci_client, + addr, data, addr_type, data_type); +#else return cam_cci_i2c_read(io_master_info->cci_client, addr, data, addr_type, data_type); +#endif } else if (io_master_info->master_type == I2C_MASTER) { return cam_qup_i2c_read(io_master_info->client, addr, data, addr_type, data_type); @@ -87,7 +119,50 @@ int32_t camera_io_dev_read(struct camera_io_master *io_master_info, io_master_info->master_type); return -EINVAL; } + +#ifdef CONFIG_CAM_DISTINGUISH_SENSOR_VERSION + if (retval == 0 && + data != NULL && + *data == SPECIAL_SENSOR_ID && + addr == SPECIAL_SENSOR_ADDR_ID && + io_master_info->cci_client != NULL && + io_master_info->cci_client->cci_i2c_master == 0 && + io_master_info->cci_client->sid == SPECIAL_SENSOR_IIC_ADDR) + { + write_setting.size = 1; + write_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + write_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + write_setting.delay = 21; + write_setting.read_buff = NULL; + write_setting.read_buff_len = 0; + write_setting.reg_setting = &special_on_write_settings; + retval = cam_cci_i2c_write_table(io_master_info, &write_setting); + + retval = cam_cci_i2c_read(io_master_info->cci_client, + SPECIAL_SENSOR_ADDR_VERSION, + &r900e, + CAMERA_SENSOR_I2C_TYPE_WORD, + CAMERA_SENSOR_I2C_TYPE_BYTE); + + CAM_INFO(CAM_SENSOR, "retval = %d, r900e = %d", retval, r900e); + + if(retval == 0) + s_r900e_val = r900e; + + write_setting.size = 1; + write_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + write_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + write_setting.delay = 0; + write_setting.read_buff = NULL; + write_setting.read_buff_len = 0; + write_setting.reg_setting = &special_off_write_settings; + retval = cam_cci_i2c_write_table(io_master_info, &write_setting); + } + + return retval; +#else return 0; +#endif } int32_t camera_io_dev_read_seq(struct camera_io_master *io_master_info, @@ -115,9 +190,38 @@ int32_t camera_io_dev_read_seq(struct camera_io_master *io_master_info, return 0; } +int32_t camera_io_dev_ois_read_seq(struct camera_io_master *io_master_info, + uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type, int32_t num_bytes) +{ + if (io_master_info->master_type == CCI_MASTER) { + return cam_camera_cci_i2c_ois_read_seq(io_master_info->cci_client, + addr, data, addr_type, data_type, num_bytes); + } else if (io_master_info->master_type == I2C_MASTER) { + return cam_qup_i2c_read_seq(io_master_info->client, + addr, data, addr_type, num_bytes); + } else if (io_master_info->master_type == SPI_MASTER) { + return cam_spi_read_seq(io_master_info, + addr, data, addr_type, num_bytes); + } else if (io_master_info->master_type == SPI_MASTER) { + return cam_spi_write_seq(io_master_info, + addr, data, addr_type, num_bytes); + } else { + CAM_ERR(CAM_SENSOR, "Invalid Comm. Master:%d", + io_master_info->master_type); + return -EINVAL; + } + return 0; +} + int32_t camera_io_dev_write(struct camera_io_master *io_master_info, struct cam_sensor_i2c_reg_setting *write_setting) { +#ifdef CONFIG_CAM_DISTINGUISH_SENSOR_VERSION + int32_t retval = 0; +#endif + if (!write_setting || !io_master_info) { CAM_ERR(CAM_SENSOR, "Input parameters not valid ws: %pK ioinfo: %pK", @@ -130,6 +234,44 @@ int32_t camera_io_dev_write(struct camera_io_master *io_master_info, return -EINVAL; } +#ifdef CONFIG_CAM_DISTINGUISH_SENSOR_VERSION + if (io_master_info->cci_client != NULL && + io_master_info->cci_client->sid== SPECIAL_SENSOR_IIC_ADDR && + io_master_info->cci_client->cci_device == 1 && + io_master_info->cci_client->cci_i2c_master == 0 && + write_setting->reg_setting->reg_addr == 0x0100 && + write_setting->reg_setting->reg_data == 0x01) + { + CAM_INFO(CAM_SENSOR, "Detect stream on setting, r900e = %d", s_r900e_val); + + if (s_r900e_val == 0x02) + { + write_setting->reg_setting->reg_addr = special_streamon_write_settings[0].reg_addr; + write_setting->reg_setting->reg_data = special_streamon_write_settings[0].reg_data; + write_setting->reg_setting->delay = special_streamon_write_settings[0].delay; + write_setting->reg_setting->data_mask = special_streamon_write_settings[0].data_mask; + retval = cam_cci_i2c_write_table(io_master_info, write_setting); + + write_setting->reg_setting->reg_addr = special_streamon_write_settings[1].reg_addr; + write_setting->reg_setting->reg_data = special_streamon_write_settings[1].reg_data; + write_setting->reg_setting->delay = special_streamon_write_settings[1].delay; + write_setting->reg_setting->data_mask = special_streamon_write_settings[1].data_mask; + retval = cam_cci_i2c_write_table(io_master_info, write_setting); + + write_setting->reg_setting->reg_addr = special_streamon_write_settings[2].reg_addr; + write_setting->reg_setting->reg_data = special_streamon_write_settings[2].reg_data; + write_setting->reg_setting->delay = special_streamon_write_settings[2].delay; + write_setting->reg_setting->data_mask = special_streamon_write_settings[2].data_mask; + retval = cam_cci_i2c_write_table(io_master_info, write_setting); + + write_setting->reg_setting->reg_addr = special_streamon_write_settings[3].reg_addr; + write_setting->reg_setting->reg_data = special_streamon_write_settings[3].reg_data; + write_setting->reg_setting->delay = special_streamon_write_settings[3].delay; + write_setting->reg_setting->data_mask = special_streamon_write_settings[3].data_mask; + } + } +#endif + if (io_master_info->master_type == CCI_MASTER) { return cam_cci_i2c_write_table(io_master_info, write_setting); diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.h b/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.h index f70709997e69..7bd2457c2496 100644 --- a/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.h +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor_io/cam_sensor_io.h @@ -57,6 +57,12 @@ int32_t camera_io_dev_read_seq(struct camera_io_master *io_master_info, enum camera_sensor_i2c_type data_type, int32_t num_bytes); +int32_t camera_io_dev_ois_read_seq(struct camera_io_master *io_master_info, + uint32_t addr, uint8_t *data, + enum camera_sensor_i2c_type addr_type, + enum camera_sensor_i2c_type data_type, + int32_t num_bytes); + /** * @io_master_info: I2C/SPI master information * diff --git a/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h b/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h index 58a248f4c882..13131a75a94d 100644 --- a/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h +++ b/techpack/camera/drivers/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h @@ -174,7 +174,12 @@ enum cam_ois_packet_opcodes { CAM_OIS_PACKET_OPCODE_INIT, CAM_OIS_PACKET_OPCODE_OIS_CONTROL, CAM_OIS_PACKET_OPCODE_READ, - CAM_OIS_PACKET_OPCODE_WRITE_TIME + CAM_OIS_PACKET_OPCODE_WRITE_TIME, + CAM_OIS_PACKET_OPCODE_ACTIVE_OIS_ROHM, + CAM_OIS_PACKET_OPCODE_ACTIVE_OIS_DONGWOON, + CAM_OIS_PACKET_OPCODE_ACTIVE_OIS_DONGWOON_QTIMER, + CAM_OIS_PACKET_OPCODE_ACTIVE_OIS_AW86006, + CAM_OIS_PACKET_OPCODE_OIS_GYRO_OFFSET }; enum msm_bus_perf_setting { diff --git a/techpack/camera/drivers/cam_utils/cam_soc_util.c b/techpack/camera/drivers/cam_utils/cam_soc_util.c index c7cb0524f2de..c48f84e2a210 100644 --- a/techpack/camera/drivers/cam_utils/cam_soc_util.c +++ b/techpack/camera/drivers/cam_utils/cam_soc_util.c @@ -1231,6 +1231,11 @@ static int cam_soc_util_get_dt_regulator_info { int rc = 0, count = 0, i = 0; struct device_node *of_node = NULL; +#ifdef CONFIG_CAMERA_VOLTAGE_COMPATIBLE + int idpin_gpio = 0, idpin_value = 0; + unsigned int second_vol_range[2]; + const char *rgltr_name = ""; +#endif if (!soc_info || !soc_info->dev) { CAM_ERR(CAM_UTIL, "Invalid parameters"); @@ -1295,6 +1300,63 @@ static int cam_soc_util_get_dt_regulator_info return -EINVAL; } +#ifdef CONFIG_CAMERA_VOLTAGE_COMPATIBLE + idpin_gpio = of_get_named_gpio(of_node, "volt-compat-gpio",0); + if (idpin_gpio < 0) { + CAM_ERR(CAM_UTIL, "Not volt-compat-gpio found ,gpio=%d",idpin_gpio); + } else { + if(gpio_is_valid(idpin_gpio)) { + if(!gpio_request(idpin_gpio,"volt-compat-gpio")) { + gpio_direction_input(idpin_gpio); + CAM_DBG(CAM_UTIL, "volt-compat-gpio:%d =%d ", idpin_gpio, gpio_get_value(idpin_gpio)); + + rc = of_property_read_u32_array(of_node, "volt-compat-range", second_vol_range, 2); + if (rc) { + CAM_ERR(CAM_UTIL, "No volt-compat-range found, rc=%d", rc); + gpio_free(idpin_gpio); + idpin_gpio = 0; + return -EINVAL; + } + + rc = of_property_read_string(of_node,"volt-compat-rgltr-name",&rgltr_name); + if (rc) { + CAM_ERR(CAM_UTIL, "No volt-compat-rgltr-name found, rc=%d", rc); + gpio_free(idpin_gpio); + idpin_gpio = 0; + return -EINVAL; + } + + rc = of_property_read_u32(of_node,"volt-compat-gpio-value",&idpin_value); + if (rc) { + CAM_ERR(CAM_UTIL, "No volt-compat-gpio-value found, rc=%d", rc); + gpio_free(idpin_gpio); + idpin_gpio = 0; + return -EINVAL; + } + + if(soc_info->index == 0 && idpin_gpio > 0) { + for (i = 0; i < soc_info->num_rgltr; i++) { + if((strcmp(soc_info->rgltr_name[i], rgltr_name)== 0)) { + int val = 1; + val = gpio_get_value(idpin_gpio); + if(val == idpin_value) { + soc_info->rgltr_min_volt [i]= second_vol_range[0]; + soc_info->rgltr_max_volt[i]= second_vol_range[1]; + } + CAM_ERR(CAM_UTIL, "cam:%d, %s, voltage range: min:%d max:%d", + soc_info->index,soc_info->rgltr_name[i], soc_info->rgltr_min_volt [i],soc_info->rgltr_max_volt[i]); + } + } + } + }else{ + CAM_ERR(CAM_UTIL, "volt-compat-gpio request failed"); + } + }else{ + CAM_ERR(CAM_UTIL, "volt-compat-gpio is not vaild"); + } + } +#endif + return rc; } diff --git a/techpack/camera/drivers/camera_main.c b/techpack/camera/drivers/camera_main.c index f59be8dbe113..a49ba3b78018 100644 --- a/techpack/camera/drivers/camera_main.c +++ b/techpack/camera/drivers/camera_main.c @@ -20,9 +20,13 @@ #include "cam_cci_dev.h" #include "cam_sensor_dev.h" #include "cam_actuator_dev.h" +#ifdef CONFIG_AF_NOISE_ELIMINATION +#include "mot_actuator.h" +#endif #include "cam_csiphy_dev.h" #include "cam_eeprom_dev.h" #include "cam_ois_dev.h" +#include "pm6125_flash_gpio.h" #if IS_REACHABLE(CONFIG_LEDS_QPNP_FLASH_V2) || \ IS_REACHABLE(CONFIG_LEDS_QTI_FLASH) @@ -105,6 +109,9 @@ static const struct camera_submodule_component camera_sensor[] = { {&cam_cci_init_module, &cam_cci_exit_module}, {&cam_csiphy_init_module, &cam_csiphy_exit_module}, {&cam_actuator_driver_init, &cam_actuator_driver_exit}, +#ifdef CONFIG_AF_NOISE_ELIMINATION + {&mot_actuator_driver_init, &mot_actuator_driver_exit}, +#endif {&cam_sensor_driver_init, &cam_sensor_driver_exit}, {&cam_eeprom_driver_init, &cam_eeprom_driver_exit}, {&cam_ois_driver_init, &cam_ois_driver_exit}, @@ -112,6 +119,9 @@ static const struct camera_submodule_component camera_sensor[] = { IS_REACHABLE(CONFIG_LEDS_QTI_FLASH) {&cam_flash_init_module, &cam_flash_exit_module}, #endif +#if IS_REACHABLE(CONFIG_CAMERA_FLASH_PWM) + {&pm6125_flash_gpio_init_module, &pm6125_flash_gpio_exit_module}, +#endif #endif }; diff --git a/techpack/camera/drivers/camera_main.h b/techpack/camera/drivers/camera_main.h index 4cc6a6ae3e57..7bcd829d6df8 100644 --- a/techpack/camera/drivers/camera_main.h +++ b/techpack/camera/drivers/camera_main.h @@ -41,6 +41,9 @@ extern struct platform_driver cam_ois_platform_driver; IS_REACHABLE(CONFIG_LEDS_QTI_FLASH) extern struct platform_driver cam_flash_platform_driver; #endif +#ifdef CONFIG_AF_NOISE_ELIMINATION +extern struct platform_driver mot_actuator_platform_driver; +#endif #endif #ifdef CONFIG_SPECTRA_ICP extern struct platform_driver cam_a5_driver; @@ -102,6 +105,7 @@ static struct platform_driver *const cam_component_drivers[] = { &cci_driver, &csiphy_driver, &cam_actuator_platform_driver, + &cam_sensor_platform_driver, &cam_eeprom_platform_driver, &cam_ois_platform_driver, @@ -109,6 +113,10 @@ static struct platform_driver *const cam_component_drivers[] = { IS_REACHABLE(CONFIG_LEDS_QTI_FLASH) &cam_flash_platform_driver, #endif +#ifdef CONFIG_AF_NOISE_ELIMINATION + &mot_actuator_platform_driver, +#endif + #endif #ifdef CONFIG_SPECTRA_ICP &cam_a5_driver, diff --git a/techpack/camera/include/uapi/camera/media/cam_defs.h b/techpack/camera/include/uapi/camera/media/cam_defs.h index 9da3a636ab0e..b76d67e43028 100644 --- a/techpack/camera/include/uapi/camera/media/cam_defs.h +++ b/techpack/camera/include/uapi/camera/media/cam_defs.h @@ -32,6 +32,12 @@ #define CAM_EXT_OPCODE_BASE 0x200 #define CAM_CONFIG_DEV_EXTERNAL (CAM_EXT_OPCODE_BASE + 0x1) +/* CONFIG_MOT_SENSOR_PRE_POWERUP */ +#define CAM_MOT_OPCODE_BASE 0x250 +#define CAM_MOT_PRE_POWER_UP (CAM_MOT_OPCODE_BASE + 0x1) +#define CAM_MOT_PRE_POWER_DOWN (CAM_MOT_OPCODE_BASE + 0x2) +#define CAM_MOT_QUERY_SENSOR_STATUS (CAM_MOT_OPCODE_BASE + 0x3) + /* camera handle type */ #define CAM_HANDLE_USER_POINTER 1 #define CAM_HANDLE_MEM_HANDLE 2 diff --git a/techpack/camera/include/uapi/camera/media/cam_req_mgr.h b/techpack/camera/include/uapi/camera/media/cam_req_mgr.h index 2ce529fdf82b..5d0700529652 100644 --- a/techpack/camera/include/uapi/camera/media/cam_req_mgr.h +++ b/techpack/camera/include/uapi/camera/media/cam_req_mgr.h @@ -32,6 +32,7 @@ #define CAM_CUSTOM_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 14) #define CAM_OPE_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 15) #define CAM_TFE_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 16) +#define CAM_MOT_ACTUATOR_TYPE (CAM_DEVICE_TYPE_BASE + 17) /* cam_req_mgr hdl info */ #define CAM_REQ_MGR_HDL_IDX_POS 8 diff --git a/techpack/camera/include/uapi/camera/media/cam_sensor.h b/techpack/camera/include/uapi/camera/media/cam_sensor.h index f935a7a702b3..92d6672ba37d 100644 --- a/techpack/camera/include/uapi/camera/media/cam_sensor.h +++ b/techpack/camera/include/uapi/camera/media/cam_sensor.h @@ -137,6 +137,13 @@ struct cam_cmd_ois_info { __u8 cmd_type; __u8 ois_fw_flag; __u8 is_ois_calib; + __u8 ois_preprog_flag; + __u8 ois_precoeff_flag; + __u8 ois_postcalib_flag; + __u8 ois_fw_txn_data_sz; + __u8 ois_fw_inc_addr; + __u8 ois_fw_addr_type; + __u8 ois_fw_data_type; char ois_name[MAX_OIS_NAME_SIZE]; struct cam_ois_opcode opcode; } __attribute__((packed)); @@ -165,6 +172,22 @@ struct cam_cmd_probe { __u32 data_mask; __u16 camera_id; __u16 reserved; + __u8 probe_sub_device; + __u32 sub_device_addr; + __u8 sub_device_data_type; + __u8 sub_device_addr_type; + __u32 sub_device_id_addr; + __u32 expected_sub_device_id; + __u8 sub_device_cci_master; + __u8 sub_device_cci_device; + __u8 sub_device_i2c_freq_mode; + __u8 i2c_addr_switch; + __u32 second_i2c_address; + __u8 i2c_switch_reg_addr_Type; + __u8 i2c_switch_reg_data_Type; + __u32 i2c_switch_reg_addr; + __u32 i2c_switch_reg_data; + __u32 i2c_switch_reg_delayMs; } __attribute__((packed)); /** @@ -485,6 +508,7 @@ struct cam_flash_query_cap_info { __u32 max_duration_flash[CAM_FLASH_MAX_LED_TRIGGERS]; __u32 max_current_torch[CAM_FLASH_MAX_LED_TRIGGERS]; __u32 flash_type; + __u32 flash_supplier; } __attribute__ ((packed)); #endif