Loading Documentation/devicetree/bindings/i2c/i2c-msm-v2.txt +0 −4 Original line number Diff line number Diff line Loading @@ -28,10 +28,6 @@ Optional property: When missing default to 0. - qcom,bam-disable : disables BAM transfer mode. - qcom,master-id : Master-port value used on voting for the clock path. - qcom,clk-ctl-xfer : When present, the clocks's state (prepare_enable/ unprepare_disable) is controlled by i2c-transaction's begining and ending. When missing, the clock's state is controlled by runtime-pm events. Example: aliases { Loading drivers/i2c/busses/i2c-msm-v2.c +168 −173 Original line number Diff line number Diff line Loading @@ -69,14 +69,12 @@ static int i2c_msm_xfer_wait_for_completion(struct i2c_msm_ctrl *ctrl, static int i2c_msm_bam_xfer(struct i2c_msm_ctrl *ctrl); static int i2c_msm_fifo_xfer(struct i2c_msm_ctrl *ctrl); static int i2c_msm_blk_xfer(struct i2c_msm_ctrl *ctrl); static void i2c_msm_pm_resume_adptr(struct i2c_msm_ctrl *ctrl); static void i2c_msm_pm_suspend_adptr(struct i2c_msm_ctrl *ctrl); static int i2c_msm_qup_init(struct i2c_msm_ctrl *ctrl); static int i2c_msm_pm_resume_impl(struct device *dev); static int i2c_msm_pm_resume(struct device *dev); static void i2c_msm_pm_suspend(struct device *dev); static int i2c_msm_fifo_create_struct(struct i2c_msm_ctrl *ctrl); static int i2c_msm_bam_create_struct(struct i2c_msm_ctrl *ctrl); static int i2c_msm_blk_create_struct(struct i2c_msm_ctrl *ctrl); static void i2c_msm_clk_path_init(struct i2c_msm_ctrl *ctrl); /* i2c_msm_bam_get_struct: return the bam structure * if not created, call i2c_msm_bam_create_struct to create it Loading Loading @@ -396,7 +394,7 @@ static const struct i2c_msm_qup_reg_dump i2c_msm_qup_reg_dump_map[] = { /* * see: struct i2c_msm_qup_reg_dump for more */ static void i2c_msm_dbg_qup_reg_dump(struct i2c_msm_ctrl *ctrl) static int i2c_msm_dbg_qup_reg_dump(struct i2c_msm_ctrl *ctrl) { u32 val; char buf[I2C_MSM_REG_2_STR_BUF_SZ]; Loading @@ -414,6 +412,7 @@ static void i2c_msm_dbg_qup_reg_dump(struct i2c_msm_ctrl *ctrl) dev_info(ctrl->dev, "%-12s:0x%08x %s\n", itr->name, val, buf); }; return 0; } static void i2c_msm_dbg_xfer_dump(struct i2c_msm_ctrl *ctrl) Loading Loading @@ -2481,6 +2480,8 @@ poll_active_end: static void i2c_msm_clk_path_vote(struct i2c_msm_ctrl *ctrl) { i2c_msm_clk_path_init(ctrl); if (ctrl->rsrcs.clk_path_vote.client_hdl) msm_bus_scale_client_update_request( ctrl->rsrcs.clk_path_vote.client_hdl, Loading Loading @@ -2661,17 +2662,9 @@ static irqreturn_t i2c_msm_qup_isr(int irq, void *devid) i2c_msm_prof_evnt_add(ctrl, MSM_PROF, i2c_msm_prof_dump_irq_begn, irq, 0, 0); if (!atomic_read(&ctrl->is_ctrl_active)) { dev_info(ctrl->dev, "irq:%d when PM suspended\n", irq); return IRQ_NONE; } if (!ctrl->xfer.msgs) { if (!atomic_read(&ctrl->xfer.is_active)) { dev_info(ctrl->dev, "irq:%d when no active transfer\n", irq); writel_relaxed(QUP_STATE_RESET, base + QUP_STATE); /* Ensure that state is written before ISR exits */ wmb(); goto isr_end; return IRQ_HANDLED; } i2c_status = readl_relaxed(base + QUP_I2C_STATUS); Loading Loading @@ -2784,7 +2777,6 @@ static irqreturn_t i2c_msm_qup_isr(int irq, void *devid) i2c_msm_dbg_qup_reg_dump(ctrl); } isr_end: if (dump_details || log_event || (ctrl->dbgfs.dbg_lvl >= MSM_DBG)) i2c_msm_prof_evnt_add(ctrl, MSM_PROF, i2c_msm_prof_dump_irq_end, Loading Loading @@ -2863,7 +2855,7 @@ static int i2c_msm_qup_init(struct i2c_msm_ctrl *ctrl) /* * i2c_msm_qup_do_bus_clear: issue QUP bus clear command */ static bool i2c_msm_qup_do_bus_clear(struct i2c_msm_ctrl *ctrl) static int i2c_msm_qup_do_bus_clear(struct i2c_msm_ctrl *ctrl) { int ret; ulong min_sleep_usec; Loading Loading @@ -3172,6 +3164,91 @@ static bool i2c_msm_xfer_next_buf(struct i2c_msm_ctrl *ctrl) return true; } static void i2c_msm_pm_clk_disable_unprepare(struct i2c_msm_ctrl *ctrl) { clk_disable_unprepare(ctrl->rsrcs.core_clk); clk_disable_unprepare(ctrl->rsrcs.iface_clk); } static int i2c_msm_pm_clk_prepare_enable(struct i2c_msm_ctrl *ctrl) { int ret; ret = clk_prepare_enable(ctrl->rsrcs.iface_clk); if (ret) { dev_err(ctrl->dev, "error on clk_prepare_enable(iface_clk):%d\n", ret); return ret; } ret = clk_prepare_enable(ctrl->rsrcs.core_clk); if (ret) { clk_disable_unprepare(ctrl->rsrcs.iface_clk); dev_err(ctrl->dev, "error clk_prepare_enable(core_clk):%d\n", ret); } return ret; } static int i2c_msm_pm_xfer_start(struct i2c_msm_ctrl *ctrl) { int ret; struct i2c_msm_xfer *xfer = &ctrl->xfer; mutex_lock(&ctrl->xfer.mtx); /* if system is suspended just bail out */ if (ctrl->pwr_state == MSM_I2C_PM_SYS_SUSPENDED) { struct i2c_msg *msgs = xfer->msgs + xfer->cur_buf.msg_idx; dev_err(ctrl->dev, "slave:0x%x is calling xfer when system is suspended\n", msgs->addr); mutex_unlock(&ctrl->xfer.mtx); return -EIO; } pm_runtime_get_sync(ctrl->dev); /* * if runtime PM callback was not invoked (when both runtime-pm * and systme-pm are in transition concurrently) */ if (ctrl->pwr_state != MSM_I2C_PM_ACTIVE) { dev_info(ctrl->dev, "Runtime PM-callback was not invoked.\n"); i2c_msm_pm_resume(ctrl->dev); } ret = i2c_msm_pm_clk_prepare_enable(ctrl); if (ret) { mutex_unlock(&ctrl->xfer.mtx); return ret; } ctrl->ver.init(ctrl); /* Set xfer to active state (efectively enabling our ISR)*/ atomic_set(&ctrl->xfer.is_active, 1); if (xfer->mode_id == I2C_MSM_XFER_MODE_BAM) i2c_msm_bam_init(ctrl); enable_irq(ctrl->rsrcs.irq); return 0; } static void i2c_msm_pm_xfer_end(struct i2c_msm_ctrl *ctrl) { /* efectively disabling our ISR */ atomic_set(&ctrl->xfer.is_active, 0); i2c_msm_pm_clk_disable_unprepare(ctrl); if (pm_runtime_enabled(ctrl->dev)) { pm_runtime_mark_last_busy(ctrl->dev); pm_runtime_put_autosuspend(ctrl->dev); } else { i2c_msm_pm_suspend(ctrl->dev); } disable_irq(ctrl->rsrcs.irq); if (ctrl->xfer.mode_id == I2C_MSM_XFER_MODE_BAM) i2c_msm_bam_teardown(ctrl); mutex_unlock(&ctrl->xfer.mtx); } /* * i2c_msm_xfer_scan: initial input scan */ Loading Loading @@ -3205,14 +3282,9 @@ i2c_msm_frmwrk_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) struct i2c_msm_xfer *xfer = &ctrl->xfer; struct i2c_msm_xfer_mode *xfer_mode; mutex_lock(&ctrl->mlock); if (ctrl->pwr_state == MSM_I2C_PM_SYS_SUSPENDED) { dev_err(ctrl->dev, "slave:0x%x is calling xfer when system is suspended\n", msgs->addr); mutex_unlock(&ctrl->mlock); return -EIO; } ret = i2c_msm_pm_xfer_start(ctrl); if (ret) return ret; /* init xfer */ xfer->msgs = msgs; Loading @@ -3231,13 +3303,6 @@ i2c_msm_frmwrk_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) i2c_msm_prof_evnt_add(ctrl, MSM_PROF, i2c_msm_prof_dump_xfer_beg, num, msgs->addr, 0); i2c_msm_pm_resume_adptr(ctrl); /* if runtime PM callback was not invoked */ if (ctrl->pwr_state != MSM_I2C_PM_ACTIVE) { dev_info(ctrl->dev, "Runtime PM-callback was not invoked.\n"); i2c_msm_pm_resume_impl(ctrl->dev); } i2c_msm_xfer_scan(ctrl); i2c_msm_xfer_calc_timeout(ctrl); xfer->mode_id = (*ctrl->ver.choose_mode)(ctrl); Loading @@ -3251,8 +3316,6 @@ i2c_msm_frmwrk_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ret = (*xfer_mode->xfer)(ctrl); ret = (*ctrl->ver.post_xfer)(ctrl, ret); i2c_msm_pm_suspend_adptr(ctrl); /* on success, return number of messages sent (which is index + 1)*/ if (!ret) ret = xfer->cur_buf.msg_idx + 1; Loading @@ -3263,10 +3326,7 @@ i2c_msm_frmwrk_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) if (xfer->err || (ctrl->dbgfs.dbg_lvl >= MSM_PROF)) i2c_msm_prof_evnt_dump(ctrl); /* mark end of transfer */ xfer->msg_cnt = 0; xfer->msgs = NULL; mutex_unlock(&ctrl->mlock); i2c_msm_pm_xfer_end(ctrl); return ret; } Loading Loading @@ -3367,8 +3427,6 @@ static int i2c_msm_rsrcs_dt_to_pdata(struct i2c_msm_ctrl *ctrl, DT_OPT, DT_BOOL, 0}, {"qcom,master-id", &(ctrl->rsrcs.clk_path_vote.mstr_id), DT_SGST, DT_U32, 0}, {"qcom,clk-ctl-xfer", &(ctrl->rsrcs.clk_ctl_xfer), DT_OPT, DT_BOOL, 0}, {"qcom,noise-rjct-scl", &(ctrl->noise_rjct_scl), DT_OPT, DT_U32, 0}, {"qcom,noise-rjct-sda", &(ctrl->noise_rjct_sda), Loading Loading @@ -3628,23 +3686,45 @@ DEFINE_SIMPLE_ATTRIBUTE(i2c_msm_dbgfs_noise_sda_fops, i2c_msm_dbgfs_noise_sda_write, "0x%llx"); static int i2c_msm_dbgfs_reset(void *data, u64 val) /* * i2c_msm_dbgfs_clk_wrapper: take care of clocks before calling func * * this function will verify that clocks are voted for the func if that they are * not. This is required for functionality which touches registers from debugfs. */ static int i2c_msm_dbgfs_clk_wrapper(struct i2c_msm_ctrl *ctrl, int (*func)(struct i2c_msm_ctrl *)) { struct i2c_msm_ctrl *ctrl = data; (ctrl->ver.teardown)(ctrl); return 0; int ret; pm_runtime_get_sync(ctrl->dev); /* * if runtime PM callback was not invoked (when both runtime-pm * and systme-pm are in transition concurrently) */ if (ctrl->pwr_state != MSM_I2C_PM_ACTIVE) { dev_info(ctrl->dev, "Runtime PM-callback was not invoked.\n"); i2c_msm_pm_resume(ctrl->dev); } ret = i2c_msm_pm_clk_prepare_enable(ctrl); if (ret) return ret; DEFINE_SIMPLE_ATTRIBUTE(i2c_msm_dbgfs_reset_fops, NULL, i2c_msm_dbgfs_reset, "0x%llx"); ret = func(ctrl); i2c_msm_pm_clk_disable_unprepare(ctrl); if (pm_runtime_enabled(ctrl->dev)) { pm_runtime_mark_last_busy(ctrl->dev); pm_runtime_put_autosuspend(ctrl->dev); } else { i2c_msm_pm_suspend(ctrl->dev); } return ret; } static int i2c_msm_dbgfs_reg_dump(void *data, u64 val) { struct i2c_msm_ctrl *ctrl = data; i2c_msm_dbg_qup_reg_dump(ctrl); return 0; return i2c_msm_dbgfs_clk_wrapper(ctrl, i2c_msm_dbg_qup_reg_dump); } DEFINE_SIMPLE_ATTRIBUTE(i2c_msm_dbgfs_reg_dump_fops, Loading @@ -3655,8 +3735,7 @@ DEFINE_SIMPLE_ATTRIBUTE(i2c_msm_dbgfs_reg_dump_fops, static int i2c_msm_dbgfs_do_bus_clear(void *data, u64 val) { struct i2c_msm_ctrl *ctrl = data; i2c_msm_qup_do_bus_clear(ctrl); return 0; return i2c_msm_dbgfs_clk_wrapper(ctrl, i2c_msm_qup_do_bus_clear); } DEFINE_SIMPLE_ATTRIBUTE(i2c_msm_dbgfs_do_bus_clear_fops, Loading Loading @@ -3741,8 +3820,6 @@ static void i2c_msm_dbgfs_init(struct i2c_msm_ctrl *ctrl) &i2c_msm_dbgfs_noise_scl_fops, NULL}, {"noise-rjct-sda", I2C_MSM_DFS_MD_RW, I2C_MSM_DFS_FILE, &i2c_msm_dbgfs_noise_sda_fops, NULL}, {"reset", I2C_MSM_DFS_MD_W, I2C_MSM_DFS_FILE, &i2c_msm_dbgfs_reset_fops, NULL}, {"dump-regs", I2C_MSM_DFS_MD_W, I2C_MSM_DFS_FILE, &i2c_msm_dbgfs_reg_dump_fops, NULL}, {"bus-clear", I2C_MSM_DFS_MD_W, I2C_MSM_DFS_FILE, Loading @@ -3764,63 +3841,22 @@ static void i2c_msm_dbgfs_init(struct i2c_msm_ctrl *ctrl) {} static void i2c_msm_dbgfs_teardown(struct i2c_msm_ctrl *ctrl) {} #endif static void i2c_msm_pm_suspend_clk(struct i2c_msm_ctrl *ctrl) { clk_disable_unprepare(ctrl->rsrcs.core_clk); clk_disable_unprepare(ctrl->rsrcs.iface_clk); } static void i2c_msm_pm_clk_unvote(struct i2c_msm_ctrl *ctrl) { if (!ctrl->rsrcs.clk_ctl_xfer) i2c_msm_pm_suspend_clk(ctrl); i2c_msm_clk_path_unvote(ctrl); } static void i2c_msm_pm_resume_clk(struct i2c_msm_ctrl *ctrl) { int ret; ret = clk_prepare_enable(ctrl->rsrcs.iface_clk); if (ret) { dev_err(ctrl->dev, "error on clk_prepare_enable(iface_clk):%d\n", ret); return; } ret = clk_prepare_enable(ctrl->rsrcs.core_clk); if (ret) dev_err(ctrl->dev, "error clk_prepare_enable(core_clk):%d\n", ret); } static void i2c_msm_pm_clk_vote(struct i2c_msm_ctrl *ctrl) { i2c_msm_clk_path_init(ctrl); i2c_msm_clk_path_vote(ctrl); if (!ctrl->rsrcs.clk_ctl_xfer) i2c_msm_pm_resume_clk(ctrl); } static int i2c_msm_pm_suspend_impl(struct device *dev) static void i2c_msm_pm_suspend(struct device *dev) { struct i2c_msm_ctrl *ctrl = dev_get_drvdata(dev); if (ctrl->pwr_state == MSM_I2C_PM_SUSPENDED) { dev_err(ctrl->dev, "attempt to suspend when suspended\n"); return 0; return; } i2c_msm_dbg(ctrl, MSM_DBG, "suspending..."); disable_irq(ctrl->rsrcs.irq); i2c_msm_pm_clk_unvote(ctrl); i2c_msm_pm_pinctrl_state(ctrl, false); return 0; i2c_msm_clk_path_unvote(ctrl); ctrl->pwr_state = MSM_I2C_PM_SUSPENDED; return; } static int i2c_msm_pm_resume_impl(struct device *dev) static int i2c_msm_pm_resume(struct device *dev) { struct i2c_msm_ctrl *ctrl = dev_get_drvdata(dev); Loading @@ -3829,12 +3865,9 @@ static int i2c_msm_pm_resume_impl(struct device *dev) i2c_msm_dbg(ctrl, MSM_DBG, "resuming..."); i2c_msm_clk_path_vote(ctrl); i2c_msm_pm_pinctrl_state(ctrl, true); i2c_msm_pm_clk_vote(ctrl); enable_irq(ctrl->rsrcs.irq); (*ctrl->ver.init)(ctrl); ctrl->pwr_state = MSM_I2C_PM_ACTIVE; atomic_set(&ctrl->is_ctrl_active, 1); return 0; } Loading @@ -3846,17 +3879,16 @@ static int i2c_msm_pm_sys_suspend_noirq(struct device *dev) { int ret = 0; struct i2c_msm_ctrl *ctrl = dev_get_drvdata(dev); enum msm_i2c_power_state curr_state = ctrl->pwr_state; enum msm_i2c_power_state prev_state = ctrl->pwr_state; i2c_msm_dbg(ctrl, MSM_DBG, "pm_sys_noirq: suspending..."); /* Acquire mutex to ensure current transaction is over */ mutex_lock(&ctrl->mlock); mutex_lock(&ctrl->xfer.mtx); ctrl->pwr_state = MSM_I2C_PM_SYS_SUSPENDED; mutex_unlock(&ctrl->mlock); atomic_set(&ctrl->is_ctrl_active, 0); mutex_unlock(&ctrl->xfer.mtx); if (curr_state == MSM_I2C_PM_ACTIVE) { ret = i2c_msm_pm_suspend_impl(dev); if (prev_state == MSM_I2C_PM_ACTIVE) { i2c_msm_pm_suspend(dev); /* * Synchronize runtime-pm and system-pm states: * at this point we are already suspended. However, the Loading @@ -3874,18 +3906,15 @@ static int i2c_msm_pm_sys_suspend_noirq(struct device *dev) /* * i2c_msm_pm_sys_resume: system power management callback * shifts the controller's power state from system suspend to runtime suspend */ static int i2c_msm_pm_sys_resume_noirq(struct device *dev) { struct i2c_msm_ctrl *ctrl = dev_get_drvdata(dev); /* * Rely on runtime-PM to call resume in case it is enabled * Even if it's not enabled, rely on 1st client transaction to do * clock ON and gpio configuration */ i2c_msm_dbg(ctrl, MSM_DBG, "pm_sys_noirq: resuming..."); mutex_lock(&ctrl->xfer.mtx); ctrl->pwr_state = MSM_I2C_PM_SUSPENDED; atomic_set(&ctrl->is_ctrl_active, 0); mutex_unlock(&ctrl->xfer.mtx); return 0; } #endif Loading @@ -3905,13 +3934,10 @@ static void i2c_msm_pm_rt_init(struct device *dev) static int i2c_msm_pm_rt_suspend(struct device *dev) { struct i2c_msm_ctrl *ctrl = dev_get_drvdata(dev); int ret = 0; i2c_msm_dbg(ctrl, MSM_DBG, "pm_runtime: suspending..."); ret = i2c_msm_pm_suspend_impl(dev); ctrl->pwr_state = MSM_I2C_PM_SUSPENDED; atomic_set(&ctrl->is_ctrl_active, 0); return ret; i2c_msm_pm_suspend(dev); return 0; } /* Loading @@ -3922,43 +3948,13 @@ static int i2c_msm_pm_rt_resume(struct device *dev) struct i2c_msm_ctrl *ctrl = dev_get_drvdata(dev); i2c_msm_dbg(ctrl, MSM_DBG, "pm_runtime: resuming..."); return i2c_msm_pm_resume_impl(dev); return i2c_msm_pm_resume(dev); } static void i2c_msm_pm_resume_adptr(struct i2c_msm_ctrl *ctrl) { pm_runtime_get_sync(ctrl->dev); if (ctrl->rsrcs.clk_ctl_xfer) i2c_msm_pm_resume_clk(ctrl); } static void i2c_msm_pm_suspend_adptr(struct i2c_msm_ctrl *ctrl) { if (ctrl->rsrcs.clk_ctl_xfer) i2c_msm_pm_suspend_clk(ctrl); pm_runtime_mark_last_busy(ctrl->dev); pm_runtime_put_autosuspend(ctrl->dev); } #else static void i2c_msm_pm_rt_init(struct device *dev) {} #define i2c_msm_pm_rt_suspend NULL #define i2c_msm_pm_rt_resume NULL static void i2c_msm_pm_resume_adptr(struct i2c_msm_ctrl *ctrl) { i2c_msm_pm_resume_impl(ctrl->dev); if (ctrl->rsrcs.clk_ctl_xfer) i2c_msm_pm_resume_clk(ctrl); } static void i2c_msm_pm_suspend_adptr(struct i2c_msm_ctrl *ctrl) { if (ctrl->rsrcs.clk_ctl_xfer) i2c_msm_pm_suspend_clk(ctrl); i2c_msm_pm_suspend_impl(ctrl->dev); ctrl->pwr_state = MSM_I2C_PM_SUSPENDED; atomic_set(&ctrl->is_ctrl_active, 0); } #endif static const struct dev_pm_ops i2c_msm_pm_ops = { Loading Loading @@ -4025,9 +4021,8 @@ static int i2c_msm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ctrl); ctrl->dbgfs.dbg_lvl = DEFAULT_DBG_LVL; ctrl->dbgfs.force_xfer_mode = I2C_MSM_XFER_MODE_NONE; mutex_init(&ctrl->mlock); mutex_init(&ctrl->xfer.mtx); ctrl->pwr_state = MSM_I2C_PM_SUSPENDED; atomic_set(&ctrl->is_ctrl_active, 0); if (!pdev->dev.of_node) { dev_err(&pdev->dev, "error: null device-tree node"); Loading @@ -4047,14 +4042,17 @@ static int i2c_msm_probe(struct platform_device *pdev) goto clk_err; /* vote for clock to enable reading the version number off the HW */ i2c_msm_pm_clk_vote(ctrl); if (ctrl->rsrcs.clk_ctl_xfer) i2c_msm_pm_resume_clk(ctrl); i2c_msm_clk_path_vote(ctrl); ret = i2c_msm_pm_clk_prepare_enable(ctrl); if (ret) { dev_err(ctrl->dev, "error in enabling clocks:%d\n", ret); goto clk_err; } ret = i2c_msm_ctrl_ver_detect_and_set(ctrl); if (ret) { if (ctrl->rsrcs.clk_ctl_xfer) i2c_msm_pm_suspend_clk(ctrl); i2c_msm_pm_clk_unvote(ctrl); i2c_msm_pm_clk_disable_unprepare(ctrl); i2c_msm_clk_path_unvote(ctrl); goto ver_err; } Loading @@ -4066,9 +4064,8 @@ static int i2c_msm_probe(struct platform_device *pdev) if (ret) dev_err(ctrl->dev, "error error on qup software reset\n"); if (ctrl->rsrcs.clk_ctl_xfer) i2c_msm_pm_suspend_clk(ctrl); i2c_msm_pm_clk_unvote(ctrl); i2c_msm_pm_clk_disable_unprepare(ctrl); i2c_msm_clk_path_unvote(ctrl); ret = i2c_msm_rsrcs_gpio_pinctrl_init(ctrl); if (ret) Loading Loading @@ -4115,15 +4112,13 @@ static int i2c_msm_remove(struct platform_device *pdev) struct i2c_msm_ctrl *ctrl = platform_get_drvdata(pdev); /* Grab mutex to ensure ongoing transaction is over */ mutex_lock(&ctrl->mlock); mutex_lock(&ctrl->xfer.mtx); ctrl->pwr_state = MSM_I2C_PM_SYS_SUSPENDED; mutex_unlock(&ctrl->mlock); atomic_set(&ctrl->is_ctrl_active, 0); i2c_msm_pm_suspend_impl(ctrl->dev); mutex_destroy(&ctrl->mlock); /* no one can call a xfer after the next line */ i2c_msm_frmwrk_unreg(ctrl); mutex_unlock(&ctrl->xfer.mtx); mutex_destroy(&ctrl->xfer.mtx); /* * free version related resources. * Currently only BAM resources need to be freed Loading drivers/i2c/busses/i2c-msm-v2.h +6 −5 Original line number Diff line number Diff line Loading @@ -553,7 +553,6 @@ struct i2c_msm_resources { bool disable_dma; u32 bam_pipe_idx_cons; u32 bam_pipe_idx_prod; bool clk_ctl_xfer; struct pinctrl *pinctrl; struct pinctrl_state *gpio_state_active; struct pinctrl_state *gpio_state_suspend; Loading Loading @@ -637,6 +636,8 @@ enum i2c_msm_err_bit_field { * @tx_ovrhd_cnt number of output bytes due to tags. * @event profiling data. An array of timestamps of transfer events * @event_cnt number of items in event array. * @is_active true during xfer process and false after xfer end * @mtx mutex to solve multithreaded problem in xfer */ struct i2c_msm_xfer { struct i2c_msg *msgs; Loading @@ -653,6 +654,8 @@ struct i2c_msm_xfer { enum i2c_msm_err_bit_field err; struct i2c_msm_prof_event event[I2C_MSM_PROF_MAX_EVNTS]; atomic_t event_cnt; atomic_t is_active; struct mutex mtx; }; /* Loading Loading @@ -682,8 +685,6 @@ struct i2c_msm_ctrl { int noise_rjct_sda; struct i2c_msm_v2_platform_data *pdata; enum msm_i2c_power_state pwr_state; atomic_t is_ctrl_active; struct mutex mlock; }; #endif /* _I2C_MSM_V2_H */ Loading
Documentation/devicetree/bindings/i2c/i2c-msm-v2.txt +0 −4 Original line number Diff line number Diff line Loading @@ -28,10 +28,6 @@ Optional property: When missing default to 0. - qcom,bam-disable : disables BAM transfer mode. - qcom,master-id : Master-port value used on voting for the clock path. - qcom,clk-ctl-xfer : When present, the clocks's state (prepare_enable/ unprepare_disable) is controlled by i2c-transaction's begining and ending. When missing, the clock's state is controlled by runtime-pm events. Example: aliases { Loading
drivers/i2c/busses/i2c-msm-v2.c +168 −173 Original line number Diff line number Diff line Loading @@ -69,14 +69,12 @@ static int i2c_msm_xfer_wait_for_completion(struct i2c_msm_ctrl *ctrl, static int i2c_msm_bam_xfer(struct i2c_msm_ctrl *ctrl); static int i2c_msm_fifo_xfer(struct i2c_msm_ctrl *ctrl); static int i2c_msm_blk_xfer(struct i2c_msm_ctrl *ctrl); static void i2c_msm_pm_resume_adptr(struct i2c_msm_ctrl *ctrl); static void i2c_msm_pm_suspend_adptr(struct i2c_msm_ctrl *ctrl); static int i2c_msm_qup_init(struct i2c_msm_ctrl *ctrl); static int i2c_msm_pm_resume_impl(struct device *dev); static int i2c_msm_pm_resume(struct device *dev); static void i2c_msm_pm_suspend(struct device *dev); static int i2c_msm_fifo_create_struct(struct i2c_msm_ctrl *ctrl); static int i2c_msm_bam_create_struct(struct i2c_msm_ctrl *ctrl); static int i2c_msm_blk_create_struct(struct i2c_msm_ctrl *ctrl); static void i2c_msm_clk_path_init(struct i2c_msm_ctrl *ctrl); /* i2c_msm_bam_get_struct: return the bam structure * if not created, call i2c_msm_bam_create_struct to create it Loading Loading @@ -396,7 +394,7 @@ static const struct i2c_msm_qup_reg_dump i2c_msm_qup_reg_dump_map[] = { /* * see: struct i2c_msm_qup_reg_dump for more */ static void i2c_msm_dbg_qup_reg_dump(struct i2c_msm_ctrl *ctrl) static int i2c_msm_dbg_qup_reg_dump(struct i2c_msm_ctrl *ctrl) { u32 val; char buf[I2C_MSM_REG_2_STR_BUF_SZ]; Loading @@ -414,6 +412,7 @@ static void i2c_msm_dbg_qup_reg_dump(struct i2c_msm_ctrl *ctrl) dev_info(ctrl->dev, "%-12s:0x%08x %s\n", itr->name, val, buf); }; return 0; } static void i2c_msm_dbg_xfer_dump(struct i2c_msm_ctrl *ctrl) Loading Loading @@ -2481,6 +2480,8 @@ poll_active_end: static void i2c_msm_clk_path_vote(struct i2c_msm_ctrl *ctrl) { i2c_msm_clk_path_init(ctrl); if (ctrl->rsrcs.clk_path_vote.client_hdl) msm_bus_scale_client_update_request( ctrl->rsrcs.clk_path_vote.client_hdl, Loading Loading @@ -2661,17 +2662,9 @@ static irqreturn_t i2c_msm_qup_isr(int irq, void *devid) i2c_msm_prof_evnt_add(ctrl, MSM_PROF, i2c_msm_prof_dump_irq_begn, irq, 0, 0); if (!atomic_read(&ctrl->is_ctrl_active)) { dev_info(ctrl->dev, "irq:%d when PM suspended\n", irq); return IRQ_NONE; } if (!ctrl->xfer.msgs) { if (!atomic_read(&ctrl->xfer.is_active)) { dev_info(ctrl->dev, "irq:%d when no active transfer\n", irq); writel_relaxed(QUP_STATE_RESET, base + QUP_STATE); /* Ensure that state is written before ISR exits */ wmb(); goto isr_end; return IRQ_HANDLED; } i2c_status = readl_relaxed(base + QUP_I2C_STATUS); Loading Loading @@ -2784,7 +2777,6 @@ static irqreturn_t i2c_msm_qup_isr(int irq, void *devid) i2c_msm_dbg_qup_reg_dump(ctrl); } isr_end: if (dump_details || log_event || (ctrl->dbgfs.dbg_lvl >= MSM_DBG)) i2c_msm_prof_evnt_add(ctrl, MSM_PROF, i2c_msm_prof_dump_irq_end, Loading Loading @@ -2863,7 +2855,7 @@ static int i2c_msm_qup_init(struct i2c_msm_ctrl *ctrl) /* * i2c_msm_qup_do_bus_clear: issue QUP bus clear command */ static bool i2c_msm_qup_do_bus_clear(struct i2c_msm_ctrl *ctrl) static int i2c_msm_qup_do_bus_clear(struct i2c_msm_ctrl *ctrl) { int ret; ulong min_sleep_usec; Loading Loading @@ -3172,6 +3164,91 @@ static bool i2c_msm_xfer_next_buf(struct i2c_msm_ctrl *ctrl) return true; } static void i2c_msm_pm_clk_disable_unprepare(struct i2c_msm_ctrl *ctrl) { clk_disable_unprepare(ctrl->rsrcs.core_clk); clk_disable_unprepare(ctrl->rsrcs.iface_clk); } static int i2c_msm_pm_clk_prepare_enable(struct i2c_msm_ctrl *ctrl) { int ret; ret = clk_prepare_enable(ctrl->rsrcs.iface_clk); if (ret) { dev_err(ctrl->dev, "error on clk_prepare_enable(iface_clk):%d\n", ret); return ret; } ret = clk_prepare_enable(ctrl->rsrcs.core_clk); if (ret) { clk_disable_unprepare(ctrl->rsrcs.iface_clk); dev_err(ctrl->dev, "error clk_prepare_enable(core_clk):%d\n", ret); } return ret; } static int i2c_msm_pm_xfer_start(struct i2c_msm_ctrl *ctrl) { int ret; struct i2c_msm_xfer *xfer = &ctrl->xfer; mutex_lock(&ctrl->xfer.mtx); /* if system is suspended just bail out */ if (ctrl->pwr_state == MSM_I2C_PM_SYS_SUSPENDED) { struct i2c_msg *msgs = xfer->msgs + xfer->cur_buf.msg_idx; dev_err(ctrl->dev, "slave:0x%x is calling xfer when system is suspended\n", msgs->addr); mutex_unlock(&ctrl->xfer.mtx); return -EIO; } pm_runtime_get_sync(ctrl->dev); /* * if runtime PM callback was not invoked (when both runtime-pm * and systme-pm are in transition concurrently) */ if (ctrl->pwr_state != MSM_I2C_PM_ACTIVE) { dev_info(ctrl->dev, "Runtime PM-callback was not invoked.\n"); i2c_msm_pm_resume(ctrl->dev); } ret = i2c_msm_pm_clk_prepare_enable(ctrl); if (ret) { mutex_unlock(&ctrl->xfer.mtx); return ret; } ctrl->ver.init(ctrl); /* Set xfer to active state (efectively enabling our ISR)*/ atomic_set(&ctrl->xfer.is_active, 1); if (xfer->mode_id == I2C_MSM_XFER_MODE_BAM) i2c_msm_bam_init(ctrl); enable_irq(ctrl->rsrcs.irq); return 0; } static void i2c_msm_pm_xfer_end(struct i2c_msm_ctrl *ctrl) { /* efectively disabling our ISR */ atomic_set(&ctrl->xfer.is_active, 0); i2c_msm_pm_clk_disable_unprepare(ctrl); if (pm_runtime_enabled(ctrl->dev)) { pm_runtime_mark_last_busy(ctrl->dev); pm_runtime_put_autosuspend(ctrl->dev); } else { i2c_msm_pm_suspend(ctrl->dev); } disable_irq(ctrl->rsrcs.irq); if (ctrl->xfer.mode_id == I2C_MSM_XFER_MODE_BAM) i2c_msm_bam_teardown(ctrl); mutex_unlock(&ctrl->xfer.mtx); } /* * i2c_msm_xfer_scan: initial input scan */ Loading Loading @@ -3205,14 +3282,9 @@ i2c_msm_frmwrk_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) struct i2c_msm_xfer *xfer = &ctrl->xfer; struct i2c_msm_xfer_mode *xfer_mode; mutex_lock(&ctrl->mlock); if (ctrl->pwr_state == MSM_I2C_PM_SYS_SUSPENDED) { dev_err(ctrl->dev, "slave:0x%x is calling xfer when system is suspended\n", msgs->addr); mutex_unlock(&ctrl->mlock); return -EIO; } ret = i2c_msm_pm_xfer_start(ctrl); if (ret) return ret; /* init xfer */ xfer->msgs = msgs; Loading @@ -3231,13 +3303,6 @@ i2c_msm_frmwrk_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) i2c_msm_prof_evnt_add(ctrl, MSM_PROF, i2c_msm_prof_dump_xfer_beg, num, msgs->addr, 0); i2c_msm_pm_resume_adptr(ctrl); /* if runtime PM callback was not invoked */ if (ctrl->pwr_state != MSM_I2C_PM_ACTIVE) { dev_info(ctrl->dev, "Runtime PM-callback was not invoked.\n"); i2c_msm_pm_resume_impl(ctrl->dev); } i2c_msm_xfer_scan(ctrl); i2c_msm_xfer_calc_timeout(ctrl); xfer->mode_id = (*ctrl->ver.choose_mode)(ctrl); Loading @@ -3251,8 +3316,6 @@ i2c_msm_frmwrk_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ret = (*xfer_mode->xfer)(ctrl); ret = (*ctrl->ver.post_xfer)(ctrl, ret); i2c_msm_pm_suspend_adptr(ctrl); /* on success, return number of messages sent (which is index + 1)*/ if (!ret) ret = xfer->cur_buf.msg_idx + 1; Loading @@ -3263,10 +3326,7 @@ i2c_msm_frmwrk_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) if (xfer->err || (ctrl->dbgfs.dbg_lvl >= MSM_PROF)) i2c_msm_prof_evnt_dump(ctrl); /* mark end of transfer */ xfer->msg_cnt = 0; xfer->msgs = NULL; mutex_unlock(&ctrl->mlock); i2c_msm_pm_xfer_end(ctrl); return ret; } Loading Loading @@ -3367,8 +3427,6 @@ static int i2c_msm_rsrcs_dt_to_pdata(struct i2c_msm_ctrl *ctrl, DT_OPT, DT_BOOL, 0}, {"qcom,master-id", &(ctrl->rsrcs.clk_path_vote.mstr_id), DT_SGST, DT_U32, 0}, {"qcom,clk-ctl-xfer", &(ctrl->rsrcs.clk_ctl_xfer), DT_OPT, DT_BOOL, 0}, {"qcom,noise-rjct-scl", &(ctrl->noise_rjct_scl), DT_OPT, DT_U32, 0}, {"qcom,noise-rjct-sda", &(ctrl->noise_rjct_sda), Loading Loading @@ -3628,23 +3686,45 @@ DEFINE_SIMPLE_ATTRIBUTE(i2c_msm_dbgfs_noise_sda_fops, i2c_msm_dbgfs_noise_sda_write, "0x%llx"); static int i2c_msm_dbgfs_reset(void *data, u64 val) /* * i2c_msm_dbgfs_clk_wrapper: take care of clocks before calling func * * this function will verify that clocks are voted for the func if that they are * not. This is required for functionality which touches registers from debugfs. */ static int i2c_msm_dbgfs_clk_wrapper(struct i2c_msm_ctrl *ctrl, int (*func)(struct i2c_msm_ctrl *)) { struct i2c_msm_ctrl *ctrl = data; (ctrl->ver.teardown)(ctrl); return 0; int ret; pm_runtime_get_sync(ctrl->dev); /* * if runtime PM callback was not invoked (when both runtime-pm * and systme-pm are in transition concurrently) */ if (ctrl->pwr_state != MSM_I2C_PM_ACTIVE) { dev_info(ctrl->dev, "Runtime PM-callback was not invoked.\n"); i2c_msm_pm_resume(ctrl->dev); } ret = i2c_msm_pm_clk_prepare_enable(ctrl); if (ret) return ret; DEFINE_SIMPLE_ATTRIBUTE(i2c_msm_dbgfs_reset_fops, NULL, i2c_msm_dbgfs_reset, "0x%llx"); ret = func(ctrl); i2c_msm_pm_clk_disable_unprepare(ctrl); if (pm_runtime_enabled(ctrl->dev)) { pm_runtime_mark_last_busy(ctrl->dev); pm_runtime_put_autosuspend(ctrl->dev); } else { i2c_msm_pm_suspend(ctrl->dev); } return ret; } static int i2c_msm_dbgfs_reg_dump(void *data, u64 val) { struct i2c_msm_ctrl *ctrl = data; i2c_msm_dbg_qup_reg_dump(ctrl); return 0; return i2c_msm_dbgfs_clk_wrapper(ctrl, i2c_msm_dbg_qup_reg_dump); } DEFINE_SIMPLE_ATTRIBUTE(i2c_msm_dbgfs_reg_dump_fops, Loading @@ -3655,8 +3735,7 @@ DEFINE_SIMPLE_ATTRIBUTE(i2c_msm_dbgfs_reg_dump_fops, static int i2c_msm_dbgfs_do_bus_clear(void *data, u64 val) { struct i2c_msm_ctrl *ctrl = data; i2c_msm_qup_do_bus_clear(ctrl); return 0; return i2c_msm_dbgfs_clk_wrapper(ctrl, i2c_msm_qup_do_bus_clear); } DEFINE_SIMPLE_ATTRIBUTE(i2c_msm_dbgfs_do_bus_clear_fops, Loading Loading @@ -3741,8 +3820,6 @@ static void i2c_msm_dbgfs_init(struct i2c_msm_ctrl *ctrl) &i2c_msm_dbgfs_noise_scl_fops, NULL}, {"noise-rjct-sda", I2C_MSM_DFS_MD_RW, I2C_MSM_DFS_FILE, &i2c_msm_dbgfs_noise_sda_fops, NULL}, {"reset", I2C_MSM_DFS_MD_W, I2C_MSM_DFS_FILE, &i2c_msm_dbgfs_reset_fops, NULL}, {"dump-regs", I2C_MSM_DFS_MD_W, I2C_MSM_DFS_FILE, &i2c_msm_dbgfs_reg_dump_fops, NULL}, {"bus-clear", I2C_MSM_DFS_MD_W, I2C_MSM_DFS_FILE, Loading @@ -3764,63 +3841,22 @@ static void i2c_msm_dbgfs_init(struct i2c_msm_ctrl *ctrl) {} static void i2c_msm_dbgfs_teardown(struct i2c_msm_ctrl *ctrl) {} #endif static void i2c_msm_pm_suspend_clk(struct i2c_msm_ctrl *ctrl) { clk_disable_unprepare(ctrl->rsrcs.core_clk); clk_disable_unprepare(ctrl->rsrcs.iface_clk); } static void i2c_msm_pm_clk_unvote(struct i2c_msm_ctrl *ctrl) { if (!ctrl->rsrcs.clk_ctl_xfer) i2c_msm_pm_suspend_clk(ctrl); i2c_msm_clk_path_unvote(ctrl); } static void i2c_msm_pm_resume_clk(struct i2c_msm_ctrl *ctrl) { int ret; ret = clk_prepare_enable(ctrl->rsrcs.iface_clk); if (ret) { dev_err(ctrl->dev, "error on clk_prepare_enable(iface_clk):%d\n", ret); return; } ret = clk_prepare_enable(ctrl->rsrcs.core_clk); if (ret) dev_err(ctrl->dev, "error clk_prepare_enable(core_clk):%d\n", ret); } static void i2c_msm_pm_clk_vote(struct i2c_msm_ctrl *ctrl) { i2c_msm_clk_path_init(ctrl); i2c_msm_clk_path_vote(ctrl); if (!ctrl->rsrcs.clk_ctl_xfer) i2c_msm_pm_resume_clk(ctrl); } static int i2c_msm_pm_suspend_impl(struct device *dev) static void i2c_msm_pm_suspend(struct device *dev) { struct i2c_msm_ctrl *ctrl = dev_get_drvdata(dev); if (ctrl->pwr_state == MSM_I2C_PM_SUSPENDED) { dev_err(ctrl->dev, "attempt to suspend when suspended\n"); return 0; return; } i2c_msm_dbg(ctrl, MSM_DBG, "suspending..."); disable_irq(ctrl->rsrcs.irq); i2c_msm_pm_clk_unvote(ctrl); i2c_msm_pm_pinctrl_state(ctrl, false); return 0; i2c_msm_clk_path_unvote(ctrl); ctrl->pwr_state = MSM_I2C_PM_SUSPENDED; return; } static int i2c_msm_pm_resume_impl(struct device *dev) static int i2c_msm_pm_resume(struct device *dev) { struct i2c_msm_ctrl *ctrl = dev_get_drvdata(dev); Loading @@ -3829,12 +3865,9 @@ static int i2c_msm_pm_resume_impl(struct device *dev) i2c_msm_dbg(ctrl, MSM_DBG, "resuming..."); i2c_msm_clk_path_vote(ctrl); i2c_msm_pm_pinctrl_state(ctrl, true); i2c_msm_pm_clk_vote(ctrl); enable_irq(ctrl->rsrcs.irq); (*ctrl->ver.init)(ctrl); ctrl->pwr_state = MSM_I2C_PM_ACTIVE; atomic_set(&ctrl->is_ctrl_active, 1); return 0; } Loading @@ -3846,17 +3879,16 @@ static int i2c_msm_pm_sys_suspend_noirq(struct device *dev) { int ret = 0; struct i2c_msm_ctrl *ctrl = dev_get_drvdata(dev); enum msm_i2c_power_state curr_state = ctrl->pwr_state; enum msm_i2c_power_state prev_state = ctrl->pwr_state; i2c_msm_dbg(ctrl, MSM_DBG, "pm_sys_noirq: suspending..."); /* Acquire mutex to ensure current transaction is over */ mutex_lock(&ctrl->mlock); mutex_lock(&ctrl->xfer.mtx); ctrl->pwr_state = MSM_I2C_PM_SYS_SUSPENDED; mutex_unlock(&ctrl->mlock); atomic_set(&ctrl->is_ctrl_active, 0); mutex_unlock(&ctrl->xfer.mtx); if (curr_state == MSM_I2C_PM_ACTIVE) { ret = i2c_msm_pm_suspend_impl(dev); if (prev_state == MSM_I2C_PM_ACTIVE) { i2c_msm_pm_suspend(dev); /* * Synchronize runtime-pm and system-pm states: * at this point we are already suspended. However, the Loading @@ -3874,18 +3906,15 @@ static int i2c_msm_pm_sys_suspend_noirq(struct device *dev) /* * i2c_msm_pm_sys_resume: system power management callback * shifts the controller's power state from system suspend to runtime suspend */ static int i2c_msm_pm_sys_resume_noirq(struct device *dev) { struct i2c_msm_ctrl *ctrl = dev_get_drvdata(dev); /* * Rely on runtime-PM to call resume in case it is enabled * Even if it's not enabled, rely on 1st client transaction to do * clock ON and gpio configuration */ i2c_msm_dbg(ctrl, MSM_DBG, "pm_sys_noirq: resuming..."); mutex_lock(&ctrl->xfer.mtx); ctrl->pwr_state = MSM_I2C_PM_SUSPENDED; atomic_set(&ctrl->is_ctrl_active, 0); mutex_unlock(&ctrl->xfer.mtx); return 0; } #endif Loading @@ -3905,13 +3934,10 @@ static void i2c_msm_pm_rt_init(struct device *dev) static int i2c_msm_pm_rt_suspend(struct device *dev) { struct i2c_msm_ctrl *ctrl = dev_get_drvdata(dev); int ret = 0; i2c_msm_dbg(ctrl, MSM_DBG, "pm_runtime: suspending..."); ret = i2c_msm_pm_suspend_impl(dev); ctrl->pwr_state = MSM_I2C_PM_SUSPENDED; atomic_set(&ctrl->is_ctrl_active, 0); return ret; i2c_msm_pm_suspend(dev); return 0; } /* Loading @@ -3922,43 +3948,13 @@ static int i2c_msm_pm_rt_resume(struct device *dev) struct i2c_msm_ctrl *ctrl = dev_get_drvdata(dev); i2c_msm_dbg(ctrl, MSM_DBG, "pm_runtime: resuming..."); return i2c_msm_pm_resume_impl(dev); return i2c_msm_pm_resume(dev); } static void i2c_msm_pm_resume_adptr(struct i2c_msm_ctrl *ctrl) { pm_runtime_get_sync(ctrl->dev); if (ctrl->rsrcs.clk_ctl_xfer) i2c_msm_pm_resume_clk(ctrl); } static void i2c_msm_pm_suspend_adptr(struct i2c_msm_ctrl *ctrl) { if (ctrl->rsrcs.clk_ctl_xfer) i2c_msm_pm_suspend_clk(ctrl); pm_runtime_mark_last_busy(ctrl->dev); pm_runtime_put_autosuspend(ctrl->dev); } #else static void i2c_msm_pm_rt_init(struct device *dev) {} #define i2c_msm_pm_rt_suspend NULL #define i2c_msm_pm_rt_resume NULL static void i2c_msm_pm_resume_adptr(struct i2c_msm_ctrl *ctrl) { i2c_msm_pm_resume_impl(ctrl->dev); if (ctrl->rsrcs.clk_ctl_xfer) i2c_msm_pm_resume_clk(ctrl); } static void i2c_msm_pm_suspend_adptr(struct i2c_msm_ctrl *ctrl) { if (ctrl->rsrcs.clk_ctl_xfer) i2c_msm_pm_suspend_clk(ctrl); i2c_msm_pm_suspend_impl(ctrl->dev); ctrl->pwr_state = MSM_I2C_PM_SUSPENDED; atomic_set(&ctrl->is_ctrl_active, 0); } #endif static const struct dev_pm_ops i2c_msm_pm_ops = { Loading Loading @@ -4025,9 +4021,8 @@ static int i2c_msm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ctrl); ctrl->dbgfs.dbg_lvl = DEFAULT_DBG_LVL; ctrl->dbgfs.force_xfer_mode = I2C_MSM_XFER_MODE_NONE; mutex_init(&ctrl->mlock); mutex_init(&ctrl->xfer.mtx); ctrl->pwr_state = MSM_I2C_PM_SUSPENDED; atomic_set(&ctrl->is_ctrl_active, 0); if (!pdev->dev.of_node) { dev_err(&pdev->dev, "error: null device-tree node"); Loading @@ -4047,14 +4042,17 @@ static int i2c_msm_probe(struct platform_device *pdev) goto clk_err; /* vote for clock to enable reading the version number off the HW */ i2c_msm_pm_clk_vote(ctrl); if (ctrl->rsrcs.clk_ctl_xfer) i2c_msm_pm_resume_clk(ctrl); i2c_msm_clk_path_vote(ctrl); ret = i2c_msm_pm_clk_prepare_enable(ctrl); if (ret) { dev_err(ctrl->dev, "error in enabling clocks:%d\n", ret); goto clk_err; } ret = i2c_msm_ctrl_ver_detect_and_set(ctrl); if (ret) { if (ctrl->rsrcs.clk_ctl_xfer) i2c_msm_pm_suspend_clk(ctrl); i2c_msm_pm_clk_unvote(ctrl); i2c_msm_pm_clk_disable_unprepare(ctrl); i2c_msm_clk_path_unvote(ctrl); goto ver_err; } Loading @@ -4066,9 +4064,8 @@ static int i2c_msm_probe(struct platform_device *pdev) if (ret) dev_err(ctrl->dev, "error error on qup software reset\n"); if (ctrl->rsrcs.clk_ctl_xfer) i2c_msm_pm_suspend_clk(ctrl); i2c_msm_pm_clk_unvote(ctrl); i2c_msm_pm_clk_disable_unprepare(ctrl); i2c_msm_clk_path_unvote(ctrl); ret = i2c_msm_rsrcs_gpio_pinctrl_init(ctrl); if (ret) Loading Loading @@ -4115,15 +4112,13 @@ static int i2c_msm_remove(struct platform_device *pdev) struct i2c_msm_ctrl *ctrl = platform_get_drvdata(pdev); /* Grab mutex to ensure ongoing transaction is over */ mutex_lock(&ctrl->mlock); mutex_lock(&ctrl->xfer.mtx); ctrl->pwr_state = MSM_I2C_PM_SYS_SUSPENDED; mutex_unlock(&ctrl->mlock); atomic_set(&ctrl->is_ctrl_active, 0); i2c_msm_pm_suspend_impl(ctrl->dev); mutex_destroy(&ctrl->mlock); /* no one can call a xfer after the next line */ i2c_msm_frmwrk_unreg(ctrl); mutex_unlock(&ctrl->xfer.mtx); mutex_destroy(&ctrl->xfer.mtx); /* * free version related resources. * Currently only BAM resources need to be freed Loading
drivers/i2c/busses/i2c-msm-v2.h +6 −5 Original line number Diff line number Diff line Loading @@ -553,7 +553,6 @@ struct i2c_msm_resources { bool disable_dma; u32 bam_pipe_idx_cons; u32 bam_pipe_idx_prod; bool clk_ctl_xfer; struct pinctrl *pinctrl; struct pinctrl_state *gpio_state_active; struct pinctrl_state *gpio_state_suspend; Loading Loading @@ -637,6 +636,8 @@ enum i2c_msm_err_bit_field { * @tx_ovrhd_cnt number of output bytes due to tags. * @event profiling data. An array of timestamps of transfer events * @event_cnt number of items in event array. * @is_active true during xfer process and false after xfer end * @mtx mutex to solve multithreaded problem in xfer */ struct i2c_msm_xfer { struct i2c_msg *msgs; Loading @@ -653,6 +654,8 @@ struct i2c_msm_xfer { enum i2c_msm_err_bit_field err; struct i2c_msm_prof_event event[I2C_MSM_PROF_MAX_EVNTS]; atomic_t event_cnt; atomic_t is_active; struct mutex mtx; }; /* Loading Loading @@ -682,8 +685,6 @@ struct i2c_msm_ctrl { int noise_rjct_sda; struct i2c_msm_v2_platform_data *pdata; enum msm_i2c_power_state pwr_state; atomic_t is_ctrl_active; struct mutex mlock; }; #endif /* _I2C_MSM_V2_H */