Loading drivers/i2c/busses/i2c-msm-v2.c +61 −75 Original line number Diff line number Diff line Loading @@ -1073,26 +1073,65 @@ bool i2c_msm_xfer_is_high_speed(struct i2c_msm_ctrl *ctrl) } /* * i2c_msm_qup_xfer_init_run_state: set qup regs which must be set *after* reset * i2c_msm_clk_div_fld: * @clk_freq_out output clock frequency * @fs_div fs divider value * @ht_div high time divider value */ static void i2c_msm_qup_xfer_init_run_state(struct i2c_msm_ctrl *ctrl) struct i2c_msm_clk_div_fld { u32 clk_freq_out; u8 fs_div; u8 ht_div; }; /* * divider values as per HW Designers */ static struct i2c_msm_clk_div_fld i2c_msm_clk_div_map[] = { {KHz(100), 124, 62}, {KHz(400), 28, 14}, {KHz(1000), 8, 5}, }; /* @return zero on success */ static int i2c_msm_set_mstr_clk_ctl(struct i2c_msm_ctrl *ctrl) { void __iomem *base = ctrl->rsrcs.base; u32 val = 0; int fs_div = 0; int ht_div = 0; bool match = false; int i; u32 reg_val = 0; struct i2c_msm_clk_div_fld *itr = i2c_msm_clk_div_map; /* set noise rejection values for scl and sda */ reg_val = I2C_MSM_SCL_NOISE_REJECTION(reg_val, ctrl->noise_rjct_scl); reg_val = I2C_MSM_SDA_NOISE_REJECTION(reg_val, ctrl->noise_rjct_sda); /* set divider values */ for (i = 0; i < ARRAY_SIZE(i2c_msm_clk_div_map); ++i, ++itr) { if (ctrl->rsrcs.clk_freq_out == itr->clk_freq_out) { fs_div = itr->fs_div; ht_div = itr->ht_div; match = true; break; } } ctrl->mstr_clk_ctl = (reg_val & (~0xff07ff)) | ((ht_div & 0xff) << 16) |(fs_div & 0xff); if (i2c_msm_xfer_is_high_speed(ctrl)) { val = I2C_MSM_SCL_NOISE_REJECTION(val, ctrl->noise_rjct_scl); val = I2C_MSM_SDA_NOISE_REJECTION(val, ctrl->noise_rjct_sda); val = I2C_MSM_CLK_DIV(val, ctrl->rsrcs.clk_freq_in, ctrl->rsrcs.clk_freq_out, true); } else { val = I2C_MSM_SCL_NOISE_REJECTION(val, ctrl->noise_rjct_scl); val = I2C_MSM_SDA_NOISE_REJECTION(val, ctrl->noise_rjct_sda); val = I2C_MSM_CLK_DIV(val, ctrl->rsrcs.clk_freq_in, ctrl->rsrcs.clk_freq_out, false); if (!match) dev_err(ctrl->dev, "error clock frequency %dKHz is not supported\n" , (ctrl->rsrcs.clk_freq_out / 1000)); return !match; } writel_relaxed(val, base + QUP_I2C_MASTER_CLK_CTL); /* * i2c_msm_qup_xfer_init_run_state: set qup regs which must be set *after* reset */ static void i2c_msm_qup_xfer_init_run_state(struct i2c_msm_ctrl *ctrl) { void __iomem *base = ctrl->rsrcs.base; writel_relaxed(ctrl->mstr_clk_ctl, base + QUP_I2C_MASTER_CLK_CTL); /* Ensure that QUP configuration is written before leaving this func */ wmb(); Loading Loading @@ -2156,6 +2195,7 @@ static void i2c_msm_bam_teardown(struct i2c_msm_ctrl *ctrl) dma_free_coherent(ctrl->dev, I2C_MSM_BAM_TAG_MEM_SZ, tags_space_virt_addr, tags_space_phy_addr); iounmap(bam->base); bam->is_init = false; bam->is_core_init = false; } Loading Loading @@ -3644,60 +3684,6 @@ static void i2c_msm_rsrcs_clk_teardown(struct i2c_msm_ctrl *ctrl) } #ifdef CONFIG_DEBUG_FS static int i2c_msm_dbgfs_noise_scl_read(void *data, u64 *val) { struct i2c_msm_ctrl *ctrl = data; *val = ctrl->noise_rjct_scl; return 0; } static int i2c_msm_dbgfs_noise_scl_write(void *data, u64 val) { struct i2c_msm_ctrl *ctrl = data; if (val < 0 || val > 3) { dev_err(ctrl->dev, "error dbgfs attempt to set invalid value for noise" " reject. Should be 0..3\n"); return -EINVAL; } ctrl->noise_rjct_scl = val; return 0; } DEFINE_SIMPLE_ATTRIBUTE(i2c_msm_dbgfs_noise_scl_fops, i2c_msm_dbgfs_noise_scl_read, i2c_msm_dbgfs_noise_scl_write, "0x%llx"); static int i2c_msm_dbgfs_noise_sda_read(void *data, u64 *val) { struct i2c_msm_ctrl *ctrl = data; *val = ctrl->noise_rjct_sda; return 0; } static int i2c_msm_dbgfs_noise_sda_write(void *data, u64 val) { struct i2c_msm_ctrl *ctrl = data; if (val < 0 || val > 3) { dev_err(ctrl->dev, "error dbgfs attempt to set invalid value for noise" " reject. Should be 0..3\n"); return -EINVAL; } ctrl->noise_rjct_sda = val; return 0; } DEFINE_SIMPLE_ATTRIBUTE(i2c_msm_dbgfs_noise_sda_fops, i2c_msm_dbgfs_noise_sda_read, i2c_msm_dbgfs_noise_sda_write, "0x%llx"); /* * i2c_msm_dbgfs_clk_wrapper: take care of clocks before calling func * Loading Loading @@ -3828,16 +3814,10 @@ static void i2c_msm_dbgfs_init(struct i2c_msm_ctrl *ctrl) NULL, &ctrl->dbgfs.dbg_lvl}, {"xfer-force-mode", I2C_MSM_DFS_MD_RW, I2C_MSM_DFS_U8, NULL, &ctrl->dbgfs.force_xfer_mode}, {"noise-rjct-scl", I2C_MSM_DFS_MD_RW, I2C_MSM_DFS_FILE, &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}, {"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, &i2c_msm_dbgfs_do_bus_clear_fops, NULL}, {"freq-out-hz", I2C_MSM_DFS_MD_RW, I2C_MSM_DFS_U32, NULL, &ctrl->rsrcs.clk_freq_out}, {NULL, 0, 0, NULL , NULL}, /* null terminator */ }; return i2c_msm_dbgfs_create(ctrl, i2c_msm_dbgfs_map); Loading Loading @@ -4061,6 +4041,12 @@ static int i2c_msm_probe(struct platform_device *pdev) dev_err(ctrl->dev, "error in enabling clocks:%d\n", ret); goto clk_err; } /* set divider and noise reject values */ ret = i2c_msm_set_mstr_clk_ctl(ctrl); if (ret) goto clk_err; ret = i2c_msm_ctrl_ver_detect_and_set(ctrl); if (ret) { i2c_msm_pm_clk_disable_unprepare(ctrl); Loading drivers/i2c/busses/i2c-msm-v2.h +3 −19 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ enum msm_i2_debug_level { #define BITS_AT(val, idx, n_bits)(((val) & (((1 << n_bits) - 1) << idx)) >> idx) #define MASK_IS_SET(val, mask) ((val & mask) == mask) #define MASK_IS_SET_BOOL(val, mask) (MASK_IS_SET(val, mask) ? 1 : 0) #define KHz(freq) (1000 * freq) /* QUP Registers */ enum { Loading Loading @@ -142,7 +143,6 @@ enum { }; enum { I2C_MSM_CLK_FAST_FREQ_HS = 400000, I2C_MSM_CLK_FAST_MAX_FREQ = 1000000, I2C_MSM_CLK_HIGH_MAX_FREQ = 3400000, }; Loading @@ -152,24 +152,6 @@ enum { (((reg_val) & ~(0x3 << 24)) | (((noise_rej_val) & 0x3) << 24)) #define I2C_MSM_SDA_NOISE_REJECTION(reg_val, noise_rej_val) \ (((reg_val) & ~(0x3 << 26)) | (((noise_rej_val) & 0x3) << 26)) static inline u32 I2C_MSM_CLK_DIV(u32 reg_val, u32 clk_freq_in, u32 clk_freq_out, bool is_high_speed) { int fs_div; int hs_div; if (is_high_speed) { fs_div = I2C_MSM_CLK_FAST_FREQ_HS; hs_div = (clk_freq_in / (clk_freq_out * 3)); } else { fs_div = (clk_freq_in / (clk_freq_out * 2)) - 3; hs_div = 0; } /* Protect hs_div from overflow (it is represented in HW by 3 bits */ hs_div = min_t(int, hs_div, 0x7); return (reg_val & (~0x7ff)) | ((hs_div & 0x7) << 8) | (fs_div & 0xff); } /* Register:QUP_ERROR_FLAGS_EN flags */ enum { Loading Loading @@ -674,6 +656,7 @@ struct i2c_msm_xfer { * @noise_rjct_sda noise rejection value for the sda line (a field of * I2C_MASTER_CLK_CTL). * @pdata the platform data (values from board-file or from device-tree) * @mstr_clk_ctl cached value for programming to mstr_clk_ctl register */ struct i2c_msm_ctrl { struct device *dev; Loading @@ -684,6 +667,7 @@ struct i2c_msm_ctrl { struct i2c_msm_resources rsrcs; int noise_rjct_scl; int noise_rjct_sda; u32 mstr_clk_ctl; struct i2c_msm_v2_platform_data *pdata; enum msm_i2c_power_state pwr_state; }; Loading Loading
drivers/i2c/busses/i2c-msm-v2.c +61 −75 Original line number Diff line number Diff line Loading @@ -1073,26 +1073,65 @@ bool i2c_msm_xfer_is_high_speed(struct i2c_msm_ctrl *ctrl) } /* * i2c_msm_qup_xfer_init_run_state: set qup regs which must be set *after* reset * i2c_msm_clk_div_fld: * @clk_freq_out output clock frequency * @fs_div fs divider value * @ht_div high time divider value */ static void i2c_msm_qup_xfer_init_run_state(struct i2c_msm_ctrl *ctrl) struct i2c_msm_clk_div_fld { u32 clk_freq_out; u8 fs_div; u8 ht_div; }; /* * divider values as per HW Designers */ static struct i2c_msm_clk_div_fld i2c_msm_clk_div_map[] = { {KHz(100), 124, 62}, {KHz(400), 28, 14}, {KHz(1000), 8, 5}, }; /* @return zero on success */ static int i2c_msm_set_mstr_clk_ctl(struct i2c_msm_ctrl *ctrl) { void __iomem *base = ctrl->rsrcs.base; u32 val = 0; int fs_div = 0; int ht_div = 0; bool match = false; int i; u32 reg_val = 0; struct i2c_msm_clk_div_fld *itr = i2c_msm_clk_div_map; /* set noise rejection values for scl and sda */ reg_val = I2C_MSM_SCL_NOISE_REJECTION(reg_val, ctrl->noise_rjct_scl); reg_val = I2C_MSM_SDA_NOISE_REJECTION(reg_val, ctrl->noise_rjct_sda); /* set divider values */ for (i = 0; i < ARRAY_SIZE(i2c_msm_clk_div_map); ++i, ++itr) { if (ctrl->rsrcs.clk_freq_out == itr->clk_freq_out) { fs_div = itr->fs_div; ht_div = itr->ht_div; match = true; break; } } ctrl->mstr_clk_ctl = (reg_val & (~0xff07ff)) | ((ht_div & 0xff) << 16) |(fs_div & 0xff); if (i2c_msm_xfer_is_high_speed(ctrl)) { val = I2C_MSM_SCL_NOISE_REJECTION(val, ctrl->noise_rjct_scl); val = I2C_MSM_SDA_NOISE_REJECTION(val, ctrl->noise_rjct_sda); val = I2C_MSM_CLK_DIV(val, ctrl->rsrcs.clk_freq_in, ctrl->rsrcs.clk_freq_out, true); } else { val = I2C_MSM_SCL_NOISE_REJECTION(val, ctrl->noise_rjct_scl); val = I2C_MSM_SDA_NOISE_REJECTION(val, ctrl->noise_rjct_sda); val = I2C_MSM_CLK_DIV(val, ctrl->rsrcs.clk_freq_in, ctrl->rsrcs.clk_freq_out, false); if (!match) dev_err(ctrl->dev, "error clock frequency %dKHz is not supported\n" , (ctrl->rsrcs.clk_freq_out / 1000)); return !match; } writel_relaxed(val, base + QUP_I2C_MASTER_CLK_CTL); /* * i2c_msm_qup_xfer_init_run_state: set qup regs which must be set *after* reset */ static void i2c_msm_qup_xfer_init_run_state(struct i2c_msm_ctrl *ctrl) { void __iomem *base = ctrl->rsrcs.base; writel_relaxed(ctrl->mstr_clk_ctl, base + QUP_I2C_MASTER_CLK_CTL); /* Ensure that QUP configuration is written before leaving this func */ wmb(); Loading Loading @@ -2156,6 +2195,7 @@ static void i2c_msm_bam_teardown(struct i2c_msm_ctrl *ctrl) dma_free_coherent(ctrl->dev, I2C_MSM_BAM_TAG_MEM_SZ, tags_space_virt_addr, tags_space_phy_addr); iounmap(bam->base); bam->is_init = false; bam->is_core_init = false; } Loading Loading @@ -3644,60 +3684,6 @@ static void i2c_msm_rsrcs_clk_teardown(struct i2c_msm_ctrl *ctrl) } #ifdef CONFIG_DEBUG_FS static int i2c_msm_dbgfs_noise_scl_read(void *data, u64 *val) { struct i2c_msm_ctrl *ctrl = data; *val = ctrl->noise_rjct_scl; return 0; } static int i2c_msm_dbgfs_noise_scl_write(void *data, u64 val) { struct i2c_msm_ctrl *ctrl = data; if (val < 0 || val > 3) { dev_err(ctrl->dev, "error dbgfs attempt to set invalid value for noise" " reject. Should be 0..3\n"); return -EINVAL; } ctrl->noise_rjct_scl = val; return 0; } DEFINE_SIMPLE_ATTRIBUTE(i2c_msm_dbgfs_noise_scl_fops, i2c_msm_dbgfs_noise_scl_read, i2c_msm_dbgfs_noise_scl_write, "0x%llx"); static int i2c_msm_dbgfs_noise_sda_read(void *data, u64 *val) { struct i2c_msm_ctrl *ctrl = data; *val = ctrl->noise_rjct_sda; return 0; } static int i2c_msm_dbgfs_noise_sda_write(void *data, u64 val) { struct i2c_msm_ctrl *ctrl = data; if (val < 0 || val > 3) { dev_err(ctrl->dev, "error dbgfs attempt to set invalid value for noise" " reject. Should be 0..3\n"); return -EINVAL; } ctrl->noise_rjct_sda = val; return 0; } DEFINE_SIMPLE_ATTRIBUTE(i2c_msm_dbgfs_noise_sda_fops, i2c_msm_dbgfs_noise_sda_read, i2c_msm_dbgfs_noise_sda_write, "0x%llx"); /* * i2c_msm_dbgfs_clk_wrapper: take care of clocks before calling func * Loading Loading @@ -3828,16 +3814,10 @@ static void i2c_msm_dbgfs_init(struct i2c_msm_ctrl *ctrl) NULL, &ctrl->dbgfs.dbg_lvl}, {"xfer-force-mode", I2C_MSM_DFS_MD_RW, I2C_MSM_DFS_U8, NULL, &ctrl->dbgfs.force_xfer_mode}, {"noise-rjct-scl", I2C_MSM_DFS_MD_RW, I2C_MSM_DFS_FILE, &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}, {"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, &i2c_msm_dbgfs_do_bus_clear_fops, NULL}, {"freq-out-hz", I2C_MSM_DFS_MD_RW, I2C_MSM_DFS_U32, NULL, &ctrl->rsrcs.clk_freq_out}, {NULL, 0, 0, NULL , NULL}, /* null terminator */ }; return i2c_msm_dbgfs_create(ctrl, i2c_msm_dbgfs_map); Loading Loading @@ -4061,6 +4041,12 @@ static int i2c_msm_probe(struct platform_device *pdev) dev_err(ctrl->dev, "error in enabling clocks:%d\n", ret); goto clk_err; } /* set divider and noise reject values */ ret = i2c_msm_set_mstr_clk_ctl(ctrl); if (ret) goto clk_err; ret = i2c_msm_ctrl_ver_detect_and_set(ctrl); if (ret) { i2c_msm_pm_clk_disable_unprepare(ctrl); Loading
drivers/i2c/busses/i2c-msm-v2.h +3 −19 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ enum msm_i2_debug_level { #define BITS_AT(val, idx, n_bits)(((val) & (((1 << n_bits) - 1) << idx)) >> idx) #define MASK_IS_SET(val, mask) ((val & mask) == mask) #define MASK_IS_SET_BOOL(val, mask) (MASK_IS_SET(val, mask) ? 1 : 0) #define KHz(freq) (1000 * freq) /* QUP Registers */ enum { Loading Loading @@ -142,7 +143,6 @@ enum { }; enum { I2C_MSM_CLK_FAST_FREQ_HS = 400000, I2C_MSM_CLK_FAST_MAX_FREQ = 1000000, I2C_MSM_CLK_HIGH_MAX_FREQ = 3400000, }; Loading @@ -152,24 +152,6 @@ enum { (((reg_val) & ~(0x3 << 24)) | (((noise_rej_val) & 0x3) << 24)) #define I2C_MSM_SDA_NOISE_REJECTION(reg_val, noise_rej_val) \ (((reg_val) & ~(0x3 << 26)) | (((noise_rej_val) & 0x3) << 26)) static inline u32 I2C_MSM_CLK_DIV(u32 reg_val, u32 clk_freq_in, u32 clk_freq_out, bool is_high_speed) { int fs_div; int hs_div; if (is_high_speed) { fs_div = I2C_MSM_CLK_FAST_FREQ_HS; hs_div = (clk_freq_in / (clk_freq_out * 3)); } else { fs_div = (clk_freq_in / (clk_freq_out * 2)) - 3; hs_div = 0; } /* Protect hs_div from overflow (it is represented in HW by 3 bits */ hs_div = min_t(int, hs_div, 0x7); return (reg_val & (~0x7ff)) | ((hs_div & 0x7) << 8) | (fs_div & 0xff); } /* Register:QUP_ERROR_FLAGS_EN flags */ enum { Loading Loading @@ -674,6 +656,7 @@ struct i2c_msm_xfer { * @noise_rjct_sda noise rejection value for the sda line (a field of * I2C_MASTER_CLK_CTL). * @pdata the platform data (values from board-file or from device-tree) * @mstr_clk_ctl cached value for programming to mstr_clk_ctl register */ struct i2c_msm_ctrl { struct device *dev; Loading @@ -684,6 +667,7 @@ struct i2c_msm_ctrl { struct i2c_msm_resources rsrcs; int noise_rjct_scl; int noise_rjct_sda; u32 mstr_clk_ctl; struct i2c_msm_v2_platform_data *pdata; enum msm_i2c_power_state pwr_state; }; Loading