Loading drivers/cam_sensor_module/cam_cci/cam_cci_core.c +5 −4 Original line number Diff line number Diff line Loading @@ -26,7 +26,7 @@ static int32_t cam_cci_convert_type_to_num_bytes( num_bytes = 4; break; default: CAM_ERR(CAM_CCI, "failed: %d", type); CAM_ERR(CAM_CCI, "Wrong Sensor I2c Type: %d", type); num_bytes = 0; break; } Loading Loading @@ -1648,14 +1648,15 @@ static int32_t cam_cci_i2c_set_sync_prms(struct v4l2_subdev *sd, return rc; } static int32_t cam_cci_release(struct v4l2_subdev *sd) static int32_t cam_cci_release(struct v4l2_subdev *sd, enum cci_i2c_master_t master) { uint8_t rc = 0; struct cci_device *cci_dev; cci_dev = v4l2_get_subdevdata(sd); rc = cam_cci_soc_release(cci_dev); rc = cam_cci_soc_release(cci_dev, master); if (rc < 0) { CAM_ERR(CAM_CCI, "Failed in releasing the cci: %d", rc); return rc; Loading Loading @@ -1766,7 +1767,7 @@ int32_t cam_cci_core_cfg(struct v4l2_subdev *sd, break; case MSM_CCI_RELEASE: mutex_lock(&cci_dev->init_mutex); rc = cam_cci_release(sd); rc = cam_cci_release(sd, master); mutex_unlock(&cci_dev->init_mutex); break; case MSM_CCI_I2C_READ: Loading drivers/cam_sensor_module/cam_cci/cam_cci_dev.h +7 −5 Original line number Diff line number Diff line Loading @@ -39,7 +39,6 @@ #define CCI_TIMEOUT msecs_to_jiffies(1500) #define NUM_MASTERS 2 #define NUM_QUEUES 2 #define CCI_PINCTRL_STATE_DEFAULT "cci_default" Loading Loading @@ -122,7 +121,7 @@ struct cam_cci_i2c_queue_info { }; struct cam_cci_master_info { uint32_t status; int32_t status; atomic_t q_free[NUM_QUEUES]; uint8_t q_lock[NUM_QUEUES]; uint8_t reset_pending; Loading @@ -138,6 +137,7 @@ struct cam_cci_master_info { struct semaphore master_sem; bool is_first_req; uint16_t freq_ref_cnt; bool is_initilized; }; struct cam_cci_clk_params_t { Loading Loading @@ -172,6 +172,7 @@ enum cam_cci_state_t { * @cci_clk_info: CCI clock information * @cam_cci_i2c_queue_info: CCI queue information * @i2c_freq_mode: I2C frequency of operations * @master_active_slave: Number of active/connected slaves for master * @cci_clk_params: CCI hw clk params * @cci_gpio_tbl: CCI GPIO table * @cci_gpio_tbl_size: GPIO table size Loading Loading @@ -204,9 +205,10 @@ struct cci_device { uint8_t ref_count; enum cam_cci_state_t cci_state; struct cam_cci_i2c_queue_info cci_i2c_queue_info[NUM_MASTERS][NUM_QUEUES]; struct cam_cci_master_info cci_master_info[NUM_MASTERS]; enum i2c_freq_mode i2c_freq_mode[NUM_MASTERS]; cci_i2c_queue_info[MASTER_MAX][NUM_QUEUES]; struct cam_cci_master_info cci_master_info[MASTER_MAX]; enum i2c_freq_mode i2c_freq_mode[MASTER_MAX]; uint8_t master_active_slave[MASTER_MAX]; struct cam_cci_clk_params_t cci_clk_params[I2C_MAX_MODES]; struct msm_pinctrl_info cci_pinctrl; uint8_t cci_pinctrl_status; Loading drivers/cam_sensor_module/cam_cci/cam_cci_soc.c +144 −123 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include "cam_cci_dev.h" #include "cam_cci_core.h" static int cam_cci_init_master(struct cci_device *cci_dev, enum cci_i2c_master_t master) { int i = 0, rc = 0; void __iomem *base = NULL; struct cam_hw_soc_info *soc_info = NULL; uint32_t max_queue_0_size = 0, max_queue_1_size = 0; soc_info = &cci_dev->soc_info; base = soc_info->reg_map[0].mem_base; max_queue_0_size = CCI_I2C_QUEUE_0_SIZE; max_queue_1_size = CCI_I2C_QUEUE_1_SIZE; cci_dev->master_active_slave[master]++; if (!cci_dev->cci_master_info[master].is_initilized) { /* Re-initialize the completion */ reinit_completion( &cci_dev->cci_master_info[master].reset_complete); reinit_completion(&cci_dev->cci_master_info[master].rd_done); /* reinit the reports for the queue */ for (i = 0; i < NUM_QUEUES; i++) reinit_completion( &cci_dev->cci_master_info[master].report_q[i]); /* Set reset pending flag to true */ cci_dev->cci_master_info[master].reset_pending = true; cci_dev->cci_master_info[master].status = 0; if (cci_dev->ref_count == 1) { cam_io_w_mb(CCI_RESET_CMD_RMSK, base + CCI_RESET_CMD_ADDR); cam_io_w_mb(0x1, base + CCI_RESET_CMD_ADDR); } else { cam_io_w_mb((master == MASTER_0) ? CCI_M0_RESET_RMSK : CCI_M1_RESET_RMSK, base + CCI_RESET_CMD_ADDR); } if (!wait_for_completion_timeout( &cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT)) { CAM_ERR(CAM_CCI, "Failed: reset complete timeout for master: %d", master); rc = -ETIMEDOUT; cci_dev->master_active_slave[master]--; return rc; } flush_workqueue(cci_dev->write_wq[master]); /* Setting up the queue size for master */ cci_dev->cci_i2c_queue_info[master][QUEUE_0].max_queue_size = max_queue_0_size; cci_dev->cci_i2c_queue_info[master][QUEUE_1].max_queue_size = max_queue_1_size; CAM_DBG(CAM_CCI, "CCI Master[%d] :: Q0: %d Q1: %d", master, cci_dev->cci_i2c_queue_info[master][QUEUE_0] .max_queue_size, cci_dev->cci_i2c_queue_info[master][QUEUE_1] .max_queue_size); cci_dev->cci_master_info[master].status = 0; cci_dev->cci_master_info[master].is_initilized = true; } return 0; } int cam_cci_init(struct v4l2_subdev *sd, struct cam_cci_ctrl *c_ctrl) { uint8_t i = 0, j = 0; uint8_t i = 0; int32_t rc = 0; struct cci_device *cci_dev; enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master; Loading @@ -20,7 +90,8 @@ int cam_cci_init(struct v4l2_subdev *sd, cci_dev = v4l2_get_subdevdata(sd); if (!cci_dev || !c_ctrl) { CAM_ERR(CAM_CCI, "failed: invalid params %pK %pK", CAM_ERR(CAM_CCI, "failed: invalid params cci_dev:%pK, c_ctrl:%pK", cci_dev, c_ctrl); rc = -EINVAL; return rc; Loading @@ -30,144 +101,83 @@ int cam_cci_init(struct v4l2_subdev *sd, base = soc_info->reg_map[0].mem_base; if (!soc_info || !base) { CAM_ERR(CAM_CCI, "failed: invalid params %pK %pK", CAM_ERR(CAM_CCI, "failed: invalid params soc_info:%pK, base:%pK", soc_info, base); rc = -EINVAL; return rc; } CAM_DBG(CAM_CCI, "Base address %pK", base); if (master >= MASTER_MAX || master < 0) { CAM_ERR(CAM_CCI, "Incorrect Master: %d", master); return -EINVAL; } if (!cci_dev->write_wq[master]) { CAM_ERR(CAM_CCI, "Null memory for write wq[:%d]", master); rc = -ENOMEM; return rc; } if (cci_dev->ref_count++) { CAM_DBG(CAM_CCI, "ref_count %d", cci_dev->ref_count); CAM_DBG(CAM_CCI, "master %d", master); if (master < MASTER_MAX && master >= 0) { mutex_lock(&cci_dev->cci_master_info[master].mutex); flush_workqueue(cci_dev->write_wq[master]); /* Re-initialize the completion */ reinit_completion( &cci_dev->cci_master_info[master].reset_complete); reinit_completion( &cci_dev->cci_master_info[master].rd_done); for (i = 0; i < NUM_QUEUES; i++) reinit_completion( &cci_dev->cci_master_info[master].report_q[i]); /* Set reset pending flag to true */ cci_dev->cci_master_info[master].reset_pending = true; cci_dev->cci_master_info[master].status = 0; /* Set proper mask to RESET CMD address */ if (master == MASTER_0) cam_io_w_mb(CCI_M0_RESET_RMSK, base + CCI_RESET_CMD_ADDR); else cam_io_w_mb(CCI_M1_RESET_RMSK, base + CCI_RESET_CMD_ADDR); /* wait for reset done irq */ rc = wait_for_completion_timeout( &cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT); if (rc <= 0) CAM_ERR(CAM_CCI, "wait failed %d", rc); cci_dev->cci_master_info[master].status = 0; mutex_unlock(&cci_dev->cci_master_info[master].mutex); rc = cam_cci_init_master(cci_dev, master); if (rc) { CAM_ERR(CAM_CCI, "Failed to init: Master: %d: rc: %d", master, rc); cci_dev->ref_count--; } return 0; CAM_DBG(CAM_CCI, "ref_count %d, master: %d", cci_dev->ref_count, master); return rc; } ahb_vote.type = CAM_VOTE_ABSOLUTE; ahb_vote.vote.level = CAM_LOWSVS_VOTE; axi_vote.num_paths = 1; axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_WRITE; axi_vote.axi_path[0].camnoc_bw = CAM_CPAS_DEFAULT_AXI_BW; axi_vote.axi_path[0].mnoc_ab_bw = CAM_CPAS_DEFAULT_AXI_BW; axi_vote.axi_path[0].mnoc_ib_bw = CAM_CPAS_DEFAULT_AXI_BW; rc = cam_cpas_start(cci_dev->cpas_handle, &ahb_vote, &axi_vote); if (rc != 0) CAM_ERR(CAM_CCI, "CPAS start failed"); axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_WRITE; axi_vote.axi_path[0].camnoc_bw = CAM_CPAS_DEFAULT_AXI_BW; axi_vote.axi_path[0].mnoc_ab_bw = CAM_CPAS_DEFAULT_AXI_BW; axi_vote.axi_path[0].mnoc_ib_bw = CAM_CPAS_DEFAULT_AXI_BW; cam_cci_get_clk_rates(cci_dev, c_ctrl); rc = cam_cpas_start(cci_dev->cpas_handle, &ahb_vote, &axi_vote); if (rc) { CAM_ERR(CAM_CCI, "CPAS start failed rc= %d", rc); return rc; } /* Re-initialize the completion */ reinit_completion(&cci_dev->cci_master_info[master].reset_complete); reinit_completion(&cci_dev->cci_master_info[master].rd_done); for (i = 0; i < NUM_QUEUES; i++) reinit_completion( &cci_dev->cci_master_info[master].report_q[i]); cam_cci_get_clk_rates(cci_dev, c_ctrl); /* Enable Regulators and IRQ*/ rc = cam_soc_util_enable_platform_resource(soc_info, true, CAM_LOWSVS_VOTE, true); if (rc < 0) { CAM_DBG(CAM_CCI, "request platform resources failed"); CAM_DBG(CAM_CCI, "request platform resources failed, rc: %d", rc); goto platform_enable_failed; } cci_dev->hw_version = cam_io_r_mb(base + CCI_HW_VERSION_ADDR); cci_dev->hw_version = cam_io_r_mb(base + CCI_HW_VERSION_ADDR); CAM_DBG(CAM_CCI, "hw_version = 0x%x", cci_dev->hw_version); cci_dev->payload_size = MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11; cci_dev->payload_size = MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11; cci_dev->support_seq_write = 1; for (i = 0; i < NUM_MASTERS; i++) { for (j = 0; j < NUM_QUEUES; j++) { if (j == QUEUE_0) cci_dev->cci_i2c_queue_info[i][j].max_queue_size = CCI_I2C_QUEUE_0_SIZE; else cci_dev->cci_i2c_queue_info[i][j].max_queue_size = CCI_I2C_QUEUE_1_SIZE; CAM_DBG(CAM_CCI, "CCI Master[%d] :: Q0 : %d Q1 : %d", i, cci_dev->cci_i2c_queue_info[i][j].max_queue_size, cci_dev->cci_i2c_queue_info[i][j].max_queue_size); } } cci_dev->cci_master_info[master].reset_pending = true; cci_dev->cci_master_info[master].status = 0; cam_io_w_mb(CCI_RESET_CMD_RMSK, base + CCI_RESET_CMD_ADDR); cam_io_w_mb(0x1, base + CCI_RESET_CMD_ADDR); rc = wait_for_completion_timeout( &cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT); if (rc <= 0) { CAM_ERR(CAM_CCI, "wait_for_completion_timeout"); if (rc == 0) rc = -ETIMEDOUT; rc = cam_cci_init_master(cci_dev, master); if (rc) { CAM_ERR(CAM_CCI, "Failed to init: Master: %d, rc: %d", master, rc); goto reset_complete_failed; } for (i = 0; i < MASTER_MAX; i++) cci_dev->i2c_freq_mode[i] = I2C_MAX_MODES; cam_io_w_mb(CCI_IRQ_MASK_0_RMSK, base + CCI_IRQ_MASK_0_ADDR); cam_io_w_mb(CCI_IRQ_MASK_0_RMSK, base + CCI_IRQ_CLEAR_0_ADDR); cam_io_w_mb(CCI_IRQ_MASK_1_RMSK, base + CCI_IRQ_MASK_1_ADDR); cam_io_w_mb(CCI_IRQ_MASK_1_RMSK, base + CCI_IRQ_CLEAR_1_ADDR); cam_io_w_mb(0x1, base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR); for (i = 0; i < MASTER_MAX; i++) { if (!cci_dev->write_wq[i]) { CAM_ERR(CAM_CCI, "Failed to flush write wq"); rc = -ENOMEM; goto reset_complete_failed; } else { flush_workqueue(cci_dev->write_wq[i]); } } cam_io_w_mb(CCI_IRQ_MASK_0_RMSK, base + CCI_IRQ_MASK_0_ADDR); cam_io_w_mb(CCI_IRQ_MASK_0_RMSK, base + CCI_IRQ_CLEAR_0_ADDR); cam_io_w_mb(CCI_IRQ_MASK_1_RMSK, base + CCI_IRQ_MASK_1_ADDR); cam_io_w_mb(CCI_IRQ_MASK_1_RMSK, base + CCI_IRQ_CLEAR_1_ADDR); cam_io_w_mb(0x1, base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR); /* Set RD FIFO threshold for M0 & M1 */ cam_io_w_mb(CCI_I2C_RD_THRESHOLD_VALUE, Loading @@ -181,7 +191,6 @@ int cam_cci_init(struct v4l2_subdev *sd, reset_complete_failed: cam_soc_util_disable_platform_resource(soc_info, 1, 1); platform_enable_failed: cci_dev->ref_count--; cam_cpas_stop(cci_dev->cpas_handle); Loading @@ -201,9 +210,10 @@ static void cam_cci_init_cci_params(struct cci_device *new_cci_dev) { uint8_t i = 0, j = 0; for (i = 0; i < NUM_MASTERS; i++) { for (i = 0; i < MASTER_MAX; i++) { new_cci_dev->cci_master_info[i].status = 0; new_cci_dev->cci_master_info[i].is_first_req = true; new_cci_dev->cci_master_info[i].is_initilized = false; mutex_init(&new_cci_dev->cci_master_info[i].mutex); sema_init(&new_cci_dev->cci_master_info[i].master_sem, 1); spin_lock_init(&new_cci_dev->cci_master_info[i].freq_cnt); Loading Loading @@ -382,27 +392,38 @@ int cam_cci_parse_dt_info(struct platform_device *pdev, return 0; } int cam_cci_soc_release(struct cci_device *cci_dev) int cam_cci_soc_release(struct cci_device *cci_dev, enum cci_i2c_master_t master) { uint8_t i = 0, rc = 0; struct cam_hw_soc_info *soc_info = &cci_dev->soc_info; struct cam_hw_soc_info *soc_info = &cci_dev->soc_info; if (!cci_dev->ref_count || cci_dev->cci_state != CCI_STATE_ENABLED) { CAM_ERR(CAM_CCI, "invalid ref count %d / cci state %d", cci_dev->ref_count, cci_dev->cci_state); if (!cci_dev->ref_count || cci_dev->cci_state != CCI_STATE_ENABLED || !cci_dev->master_active_slave[master]) { CAM_ERR(CAM_CCI, "invalid cci_dev_ref count %u | cci state %d | master_ref_count %u", cci_dev->ref_count, cci_dev->cci_state, cci_dev->master_active_slave[master]); return -EINVAL; } if (!(--cci_dev->master_active_slave[master])) { cci_dev->cci_master_info[master].is_initilized = false; CAM_DBG(CAM_CCI, "All submodules are released for master: %d", master); } if (--cci_dev->ref_count) { CAM_DBG(CAM_CCI, "ref_count Exit %d", cci_dev->ref_count); CAM_DBG(CAM_CCI, "Submodule release: Ref_count: %d", cci_dev->ref_count); return 0; } for (i = 0; i < MASTER_MAX; i++) for (i = 0; i < MASTER_MAX; i++) { if (cci_dev->write_wq[i]) flush_workqueue(cci_dev->write_wq[i]); for (i = 0; i < MASTER_MAX; i++) cci_dev->i2c_freq_mode[i] = I2C_MAX_MODES; } rc = cam_soc_util_disable_platform_resource(soc_info, true, true); if (rc) { Loading drivers/cam_sensor_module/cam_cci/cam_cci_soc.h +3 −2 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CCI_SOC_H_ Loading @@ -23,7 +23,8 @@ int cam_cci_init(struct v4l2_subdev *sd, * * This API releases the CCI and its SOC resources */ int cam_cci_soc_release(struct cci_device *cci_dev); int cam_cci_soc_release(struct cci_device *cci_dev, enum cci_i2c_master_t master); /** * @pdev: Platform device Loading Loading
drivers/cam_sensor_module/cam_cci/cam_cci_core.c +5 −4 Original line number Diff line number Diff line Loading @@ -26,7 +26,7 @@ static int32_t cam_cci_convert_type_to_num_bytes( num_bytes = 4; break; default: CAM_ERR(CAM_CCI, "failed: %d", type); CAM_ERR(CAM_CCI, "Wrong Sensor I2c Type: %d", type); num_bytes = 0; break; } Loading Loading @@ -1648,14 +1648,15 @@ static int32_t cam_cci_i2c_set_sync_prms(struct v4l2_subdev *sd, return rc; } static int32_t cam_cci_release(struct v4l2_subdev *sd) static int32_t cam_cci_release(struct v4l2_subdev *sd, enum cci_i2c_master_t master) { uint8_t rc = 0; struct cci_device *cci_dev; cci_dev = v4l2_get_subdevdata(sd); rc = cam_cci_soc_release(cci_dev); rc = cam_cci_soc_release(cci_dev, master); if (rc < 0) { CAM_ERR(CAM_CCI, "Failed in releasing the cci: %d", rc); return rc; Loading Loading @@ -1766,7 +1767,7 @@ int32_t cam_cci_core_cfg(struct v4l2_subdev *sd, break; case MSM_CCI_RELEASE: mutex_lock(&cci_dev->init_mutex); rc = cam_cci_release(sd); rc = cam_cci_release(sd, master); mutex_unlock(&cci_dev->init_mutex); break; case MSM_CCI_I2C_READ: Loading
drivers/cam_sensor_module/cam_cci/cam_cci_dev.h +7 −5 Original line number Diff line number Diff line Loading @@ -39,7 +39,6 @@ #define CCI_TIMEOUT msecs_to_jiffies(1500) #define NUM_MASTERS 2 #define NUM_QUEUES 2 #define CCI_PINCTRL_STATE_DEFAULT "cci_default" Loading Loading @@ -122,7 +121,7 @@ struct cam_cci_i2c_queue_info { }; struct cam_cci_master_info { uint32_t status; int32_t status; atomic_t q_free[NUM_QUEUES]; uint8_t q_lock[NUM_QUEUES]; uint8_t reset_pending; Loading @@ -138,6 +137,7 @@ struct cam_cci_master_info { struct semaphore master_sem; bool is_first_req; uint16_t freq_ref_cnt; bool is_initilized; }; struct cam_cci_clk_params_t { Loading Loading @@ -172,6 +172,7 @@ enum cam_cci_state_t { * @cci_clk_info: CCI clock information * @cam_cci_i2c_queue_info: CCI queue information * @i2c_freq_mode: I2C frequency of operations * @master_active_slave: Number of active/connected slaves for master * @cci_clk_params: CCI hw clk params * @cci_gpio_tbl: CCI GPIO table * @cci_gpio_tbl_size: GPIO table size Loading Loading @@ -204,9 +205,10 @@ struct cci_device { uint8_t ref_count; enum cam_cci_state_t cci_state; struct cam_cci_i2c_queue_info cci_i2c_queue_info[NUM_MASTERS][NUM_QUEUES]; struct cam_cci_master_info cci_master_info[NUM_MASTERS]; enum i2c_freq_mode i2c_freq_mode[NUM_MASTERS]; cci_i2c_queue_info[MASTER_MAX][NUM_QUEUES]; struct cam_cci_master_info cci_master_info[MASTER_MAX]; enum i2c_freq_mode i2c_freq_mode[MASTER_MAX]; uint8_t master_active_slave[MASTER_MAX]; struct cam_cci_clk_params_t cci_clk_params[I2C_MAX_MODES]; struct msm_pinctrl_info cci_pinctrl; uint8_t cci_pinctrl_status; Loading
drivers/cam_sensor_module/cam_cci/cam_cci_soc.c +144 −123 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include "cam_cci_dev.h" #include "cam_cci_core.h" static int cam_cci_init_master(struct cci_device *cci_dev, enum cci_i2c_master_t master) { int i = 0, rc = 0; void __iomem *base = NULL; struct cam_hw_soc_info *soc_info = NULL; uint32_t max_queue_0_size = 0, max_queue_1_size = 0; soc_info = &cci_dev->soc_info; base = soc_info->reg_map[0].mem_base; max_queue_0_size = CCI_I2C_QUEUE_0_SIZE; max_queue_1_size = CCI_I2C_QUEUE_1_SIZE; cci_dev->master_active_slave[master]++; if (!cci_dev->cci_master_info[master].is_initilized) { /* Re-initialize the completion */ reinit_completion( &cci_dev->cci_master_info[master].reset_complete); reinit_completion(&cci_dev->cci_master_info[master].rd_done); /* reinit the reports for the queue */ for (i = 0; i < NUM_QUEUES; i++) reinit_completion( &cci_dev->cci_master_info[master].report_q[i]); /* Set reset pending flag to true */ cci_dev->cci_master_info[master].reset_pending = true; cci_dev->cci_master_info[master].status = 0; if (cci_dev->ref_count == 1) { cam_io_w_mb(CCI_RESET_CMD_RMSK, base + CCI_RESET_CMD_ADDR); cam_io_w_mb(0x1, base + CCI_RESET_CMD_ADDR); } else { cam_io_w_mb((master == MASTER_0) ? CCI_M0_RESET_RMSK : CCI_M1_RESET_RMSK, base + CCI_RESET_CMD_ADDR); } if (!wait_for_completion_timeout( &cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT)) { CAM_ERR(CAM_CCI, "Failed: reset complete timeout for master: %d", master); rc = -ETIMEDOUT; cci_dev->master_active_slave[master]--; return rc; } flush_workqueue(cci_dev->write_wq[master]); /* Setting up the queue size for master */ cci_dev->cci_i2c_queue_info[master][QUEUE_0].max_queue_size = max_queue_0_size; cci_dev->cci_i2c_queue_info[master][QUEUE_1].max_queue_size = max_queue_1_size; CAM_DBG(CAM_CCI, "CCI Master[%d] :: Q0: %d Q1: %d", master, cci_dev->cci_i2c_queue_info[master][QUEUE_0] .max_queue_size, cci_dev->cci_i2c_queue_info[master][QUEUE_1] .max_queue_size); cci_dev->cci_master_info[master].status = 0; cci_dev->cci_master_info[master].is_initilized = true; } return 0; } int cam_cci_init(struct v4l2_subdev *sd, struct cam_cci_ctrl *c_ctrl) { uint8_t i = 0, j = 0; uint8_t i = 0; int32_t rc = 0; struct cci_device *cci_dev; enum cci_i2c_master_t master = c_ctrl->cci_info->cci_i2c_master; Loading @@ -20,7 +90,8 @@ int cam_cci_init(struct v4l2_subdev *sd, cci_dev = v4l2_get_subdevdata(sd); if (!cci_dev || !c_ctrl) { CAM_ERR(CAM_CCI, "failed: invalid params %pK %pK", CAM_ERR(CAM_CCI, "failed: invalid params cci_dev:%pK, c_ctrl:%pK", cci_dev, c_ctrl); rc = -EINVAL; return rc; Loading @@ -30,144 +101,83 @@ int cam_cci_init(struct v4l2_subdev *sd, base = soc_info->reg_map[0].mem_base; if (!soc_info || !base) { CAM_ERR(CAM_CCI, "failed: invalid params %pK %pK", CAM_ERR(CAM_CCI, "failed: invalid params soc_info:%pK, base:%pK", soc_info, base); rc = -EINVAL; return rc; } CAM_DBG(CAM_CCI, "Base address %pK", base); if (master >= MASTER_MAX || master < 0) { CAM_ERR(CAM_CCI, "Incorrect Master: %d", master); return -EINVAL; } if (!cci_dev->write_wq[master]) { CAM_ERR(CAM_CCI, "Null memory for write wq[:%d]", master); rc = -ENOMEM; return rc; } if (cci_dev->ref_count++) { CAM_DBG(CAM_CCI, "ref_count %d", cci_dev->ref_count); CAM_DBG(CAM_CCI, "master %d", master); if (master < MASTER_MAX && master >= 0) { mutex_lock(&cci_dev->cci_master_info[master].mutex); flush_workqueue(cci_dev->write_wq[master]); /* Re-initialize the completion */ reinit_completion( &cci_dev->cci_master_info[master].reset_complete); reinit_completion( &cci_dev->cci_master_info[master].rd_done); for (i = 0; i < NUM_QUEUES; i++) reinit_completion( &cci_dev->cci_master_info[master].report_q[i]); /* Set reset pending flag to true */ cci_dev->cci_master_info[master].reset_pending = true; cci_dev->cci_master_info[master].status = 0; /* Set proper mask to RESET CMD address */ if (master == MASTER_0) cam_io_w_mb(CCI_M0_RESET_RMSK, base + CCI_RESET_CMD_ADDR); else cam_io_w_mb(CCI_M1_RESET_RMSK, base + CCI_RESET_CMD_ADDR); /* wait for reset done irq */ rc = wait_for_completion_timeout( &cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT); if (rc <= 0) CAM_ERR(CAM_CCI, "wait failed %d", rc); cci_dev->cci_master_info[master].status = 0; mutex_unlock(&cci_dev->cci_master_info[master].mutex); rc = cam_cci_init_master(cci_dev, master); if (rc) { CAM_ERR(CAM_CCI, "Failed to init: Master: %d: rc: %d", master, rc); cci_dev->ref_count--; } return 0; CAM_DBG(CAM_CCI, "ref_count %d, master: %d", cci_dev->ref_count, master); return rc; } ahb_vote.type = CAM_VOTE_ABSOLUTE; ahb_vote.vote.level = CAM_LOWSVS_VOTE; axi_vote.num_paths = 1; axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_WRITE; axi_vote.axi_path[0].camnoc_bw = CAM_CPAS_DEFAULT_AXI_BW; axi_vote.axi_path[0].mnoc_ab_bw = CAM_CPAS_DEFAULT_AXI_BW; axi_vote.axi_path[0].mnoc_ib_bw = CAM_CPAS_DEFAULT_AXI_BW; rc = cam_cpas_start(cci_dev->cpas_handle, &ahb_vote, &axi_vote); if (rc != 0) CAM_ERR(CAM_CCI, "CPAS start failed"); axi_vote.axi_path[0].path_data_type = CAM_AXI_PATH_DATA_ALL; axi_vote.axi_path[0].transac_type = CAM_AXI_TRANSACTION_WRITE; axi_vote.axi_path[0].camnoc_bw = CAM_CPAS_DEFAULT_AXI_BW; axi_vote.axi_path[0].mnoc_ab_bw = CAM_CPAS_DEFAULT_AXI_BW; axi_vote.axi_path[0].mnoc_ib_bw = CAM_CPAS_DEFAULT_AXI_BW; cam_cci_get_clk_rates(cci_dev, c_ctrl); rc = cam_cpas_start(cci_dev->cpas_handle, &ahb_vote, &axi_vote); if (rc) { CAM_ERR(CAM_CCI, "CPAS start failed rc= %d", rc); return rc; } /* Re-initialize the completion */ reinit_completion(&cci_dev->cci_master_info[master].reset_complete); reinit_completion(&cci_dev->cci_master_info[master].rd_done); for (i = 0; i < NUM_QUEUES; i++) reinit_completion( &cci_dev->cci_master_info[master].report_q[i]); cam_cci_get_clk_rates(cci_dev, c_ctrl); /* Enable Regulators and IRQ*/ rc = cam_soc_util_enable_platform_resource(soc_info, true, CAM_LOWSVS_VOTE, true); if (rc < 0) { CAM_DBG(CAM_CCI, "request platform resources failed"); CAM_DBG(CAM_CCI, "request platform resources failed, rc: %d", rc); goto platform_enable_failed; } cci_dev->hw_version = cam_io_r_mb(base + CCI_HW_VERSION_ADDR); cci_dev->hw_version = cam_io_r_mb(base + CCI_HW_VERSION_ADDR); CAM_DBG(CAM_CCI, "hw_version = 0x%x", cci_dev->hw_version); cci_dev->payload_size = MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11; cci_dev->payload_size = MSM_CCI_WRITE_DATA_PAYLOAD_SIZE_11; cci_dev->support_seq_write = 1; for (i = 0; i < NUM_MASTERS; i++) { for (j = 0; j < NUM_QUEUES; j++) { if (j == QUEUE_0) cci_dev->cci_i2c_queue_info[i][j].max_queue_size = CCI_I2C_QUEUE_0_SIZE; else cci_dev->cci_i2c_queue_info[i][j].max_queue_size = CCI_I2C_QUEUE_1_SIZE; CAM_DBG(CAM_CCI, "CCI Master[%d] :: Q0 : %d Q1 : %d", i, cci_dev->cci_i2c_queue_info[i][j].max_queue_size, cci_dev->cci_i2c_queue_info[i][j].max_queue_size); } } cci_dev->cci_master_info[master].reset_pending = true; cci_dev->cci_master_info[master].status = 0; cam_io_w_mb(CCI_RESET_CMD_RMSK, base + CCI_RESET_CMD_ADDR); cam_io_w_mb(0x1, base + CCI_RESET_CMD_ADDR); rc = wait_for_completion_timeout( &cci_dev->cci_master_info[master].reset_complete, CCI_TIMEOUT); if (rc <= 0) { CAM_ERR(CAM_CCI, "wait_for_completion_timeout"); if (rc == 0) rc = -ETIMEDOUT; rc = cam_cci_init_master(cci_dev, master); if (rc) { CAM_ERR(CAM_CCI, "Failed to init: Master: %d, rc: %d", master, rc); goto reset_complete_failed; } for (i = 0; i < MASTER_MAX; i++) cci_dev->i2c_freq_mode[i] = I2C_MAX_MODES; cam_io_w_mb(CCI_IRQ_MASK_0_RMSK, base + CCI_IRQ_MASK_0_ADDR); cam_io_w_mb(CCI_IRQ_MASK_0_RMSK, base + CCI_IRQ_CLEAR_0_ADDR); cam_io_w_mb(CCI_IRQ_MASK_1_RMSK, base + CCI_IRQ_MASK_1_ADDR); cam_io_w_mb(CCI_IRQ_MASK_1_RMSK, base + CCI_IRQ_CLEAR_1_ADDR); cam_io_w_mb(0x1, base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR); for (i = 0; i < MASTER_MAX; i++) { if (!cci_dev->write_wq[i]) { CAM_ERR(CAM_CCI, "Failed to flush write wq"); rc = -ENOMEM; goto reset_complete_failed; } else { flush_workqueue(cci_dev->write_wq[i]); } } cam_io_w_mb(CCI_IRQ_MASK_0_RMSK, base + CCI_IRQ_MASK_0_ADDR); cam_io_w_mb(CCI_IRQ_MASK_0_RMSK, base + CCI_IRQ_CLEAR_0_ADDR); cam_io_w_mb(CCI_IRQ_MASK_1_RMSK, base + CCI_IRQ_MASK_1_ADDR); cam_io_w_mb(CCI_IRQ_MASK_1_RMSK, base + CCI_IRQ_CLEAR_1_ADDR); cam_io_w_mb(0x1, base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR); /* Set RD FIFO threshold for M0 & M1 */ cam_io_w_mb(CCI_I2C_RD_THRESHOLD_VALUE, Loading @@ -181,7 +191,6 @@ int cam_cci_init(struct v4l2_subdev *sd, reset_complete_failed: cam_soc_util_disable_platform_resource(soc_info, 1, 1); platform_enable_failed: cci_dev->ref_count--; cam_cpas_stop(cci_dev->cpas_handle); Loading @@ -201,9 +210,10 @@ static void cam_cci_init_cci_params(struct cci_device *new_cci_dev) { uint8_t i = 0, j = 0; for (i = 0; i < NUM_MASTERS; i++) { for (i = 0; i < MASTER_MAX; i++) { new_cci_dev->cci_master_info[i].status = 0; new_cci_dev->cci_master_info[i].is_first_req = true; new_cci_dev->cci_master_info[i].is_initilized = false; mutex_init(&new_cci_dev->cci_master_info[i].mutex); sema_init(&new_cci_dev->cci_master_info[i].master_sem, 1); spin_lock_init(&new_cci_dev->cci_master_info[i].freq_cnt); Loading Loading @@ -382,27 +392,38 @@ int cam_cci_parse_dt_info(struct platform_device *pdev, return 0; } int cam_cci_soc_release(struct cci_device *cci_dev) int cam_cci_soc_release(struct cci_device *cci_dev, enum cci_i2c_master_t master) { uint8_t i = 0, rc = 0; struct cam_hw_soc_info *soc_info = &cci_dev->soc_info; struct cam_hw_soc_info *soc_info = &cci_dev->soc_info; if (!cci_dev->ref_count || cci_dev->cci_state != CCI_STATE_ENABLED) { CAM_ERR(CAM_CCI, "invalid ref count %d / cci state %d", cci_dev->ref_count, cci_dev->cci_state); if (!cci_dev->ref_count || cci_dev->cci_state != CCI_STATE_ENABLED || !cci_dev->master_active_slave[master]) { CAM_ERR(CAM_CCI, "invalid cci_dev_ref count %u | cci state %d | master_ref_count %u", cci_dev->ref_count, cci_dev->cci_state, cci_dev->master_active_slave[master]); return -EINVAL; } if (!(--cci_dev->master_active_slave[master])) { cci_dev->cci_master_info[master].is_initilized = false; CAM_DBG(CAM_CCI, "All submodules are released for master: %d", master); } if (--cci_dev->ref_count) { CAM_DBG(CAM_CCI, "ref_count Exit %d", cci_dev->ref_count); CAM_DBG(CAM_CCI, "Submodule release: Ref_count: %d", cci_dev->ref_count); return 0; } for (i = 0; i < MASTER_MAX; i++) for (i = 0; i < MASTER_MAX; i++) { if (cci_dev->write_wq[i]) flush_workqueue(cci_dev->write_wq[i]); for (i = 0; i < MASTER_MAX; i++) cci_dev->i2c_freq_mode[i] = I2C_MAX_MODES; } rc = cam_soc_util_disable_platform_resource(soc_info, true, true); if (rc) { Loading
drivers/cam_sensor_module/cam_cci/cam_cci_soc.h +3 −2 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CCI_SOC_H_ Loading @@ -23,7 +23,8 @@ int cam_cci_init(struct v4l2_subdev *sd, * * This API releases the CCI and its SOC resources */ int cam_cci_soc_release(struct cci_device *cci_dev); int cam_cci_soc_release(struct cci_device *cci_dev, enum cci_i2c_master_t master); /** * @pdev: Platform device Loading