diff --git a/drivers/i2c/busses/i2c-qcom-cci.c b/drivers/i2c/busses/i2c-qcom-cci.c index 6716c7f730fb..ed26f4acfd9a 100644 --- a/drivers/i2c/busses/i2c-qcom-cci.c +++ b/drivers/i2c/busses/i2c-qcom-cci.c @@ -82,6 +82,13 @@ enum { I2C_MODE_STANDARD, I2C_MODE_FAST, I2C_MODE_FAST_PLUS, + NUM_I2C_MODES, +}; + +enum { + CCI_CLK_RATE_19_2MHZ, + CCI_CLK_RATE_37_5MHZ, + NUM_CCI_CLK_RATES, }; enum cci_i2c_queue_t { @@ -117,7 +124,7 @@ struct cci_data { unsigned int num_masters; struct i2c_adapter_quirks quirks; u16 queue_size[NUM_QUEUES]; - struct hw_params params[3]; + struct hw_params params[NUM_CCI_CLK_RATES][NUM_I2C_MODES]; }; struct cci { @@ -127,6 +134,7 @@ struct cci { const struct cci_data *data; struct clk_bulk_data *clocks; int nclocks; + struct clk *cci_clk; struct cci_master master[NUM_MASTERS]; }; @@ -225,7 +233,34 @@ static int cci_halt(struct cci *cci, u8 master_num) return 0; } -static void cci_init(struct cci *cci) +static const unsigned long cci_clk_rates[NUM_CCI_CLK_RATES] = { + [CCI_CLK_RATE_19_2MHZ] = 19200000, + [CCI_CLK_RATE_37_5MHZ] = 37500000, +}; + +static int cci_clk_rate_idx(unsigned long rate) +{ + int i; + + for (i = 0; i < NUM_CCI_CLK_RATES; i++) + if (cci_clk_rates[i] == rate) + return i; + + return -EINVAL; +} + +static const struct hw_params *cci_get_hw_params(struct cci *cci, int mode) +{ + unsigned long rate = clk_get_rate(cci->cci_clk); + int ri = cci_clk_rate_idx(rate); + + if (ri >= 0 && cci->data->params[ri][mode].thigh) + return &cci->data->params[ri][mode]; + + return NULL; +} + +static int cci_init(struct cci *cci) { u32 val = CCI_IRQ_MASK_0_I2C_M0_RD_DONE | CCI_IRQ_MASK_0_I2C_M0_Q0_REPORT | @@ -249,7 +284,12 @@ static void cci_init(struct cci *cci) if (!cci->master[i].cci) continue; - hw = &cci->data->params[mode]; + hw = cci_get_hw_params(cci, mode); + if (!hw) { + dev_err(cci->dev, "no timing for mode %d at CCI clock %lu Hz\n", + mode, clk_get_rate(cci->cci_clk)); + return -EOPNOTSUPP; + } val = hw->thigh << 16 | hw->tlow; writel(val, cci->base + CCI_I2C_Mm_SCL_CTL(i)); @@ -266,6 +306,8 @@ static void cci_init(struct cci *cci) val = hw->scl_stretch_en << 8 | hw->trdhld << 4 | hw->tsp; writel(val, cci->base + CCI_I2C_Mm_MISC_CTL(i)); } + + return 0; } static int cci_reset(struct cci *cci) @@ -283,9 +325,7 @@ static int cci_reset(struct cci *cci) return -ETIMEDOUT; } - cci_init(cci); - - return 0; + return cci_init(cci); } static int cci_run_queue(struct cci *cci, u8 master, u8 queue) @@ -488,8 +528,7 @@ static int __maybe_unused cci_resume_runtime(struct device *dev) if (ret) return ret; - cci_init(cci); - return 0; + return cci_init(cci); } static const struct dev_pm_ops qcom_cci_pm = { @@ -570,6 +609,11 @@ static int cci_probe(struct platform_device *pdev) return dev_err_probe(dev, -EINVAL, "not enough clocks in DT\n"); cci->nclocks = ret; + cci->cci_clk = devm_clk_get(dev, "cci"); + if (IS_ERR(cci->cci_clk)) + return dev_err_probe(dev, PTR_ERR(cci->cci_clk), + "failed to get CCI clock\n"); + ret = cci_enable_clocks(cci); if (ret < 0) return ret; @@ -649,7 +693,7 @@ static const struct cci_data cci_v1_data = { .max_write_len = 10, .max_read_len = 12, }, - .params[I2C_MODE_STANDARD] = { + .params[CCI_CLK_RATE_19_2MHZ][I2C_MODE_STANDARD] = { .thigh = 78, .tlow = 114, .tsu_sto = 28, @@ -661,7 +705,7 @@ static const struct cci_data cci_v1_data = { .trdhld = 6, .tsp = 1 }, - .params[I2C_MODE_FAST] = { + .params[CCI_CLK_RATE_19_2MHZ][I2C_MODE_FAST] = { .thigh = 20, .tlow = 28, .tsu_sto = 21, @@ -682,7 +726,7 @@ static const struct cci_data cci_v1_5_data = { .max_write_len = 10, .max_read_len = 12, }, - .params[I2C_MODE_STANDARD] = { + .params[CCI_CLK_RATE_19_2MHZ][I2C_MODE_STANDARD] = { .thigh = 78, .tlow = 114, .tsu_sto = 28, @@ -694,7 +738,7 @@ static const struct cci_data cci_v1_5_data = { .trdhld = 6, .tsp = 1 }, - .params[I2C_MODE_FAST] = { + .params[CCI_CLK_RATE_19_2MHZ][I2C_MODE_FAST] = { .thigh = 20, .tlow = 28, .tsu_sto = 21, @@ -715,7 +759,7 @@ static const struct cci_data cci_v2_data = { .max_write_len = 11, .max_read_len = 12, }, - .params[I2C_MODE_STANDARD] = { + .params[CCI_CLK_RATE_37_5MHZ][I2C_MODE_STANDARD] = { .thigh = 201, .tlow = 174, .tsu_sto = 204, @@ -727,7 +771,7 @@ static const struct cci_data cci_v2_data = { .trdhld = 6, .tsp = 3 }, - .params[I2C_MODE_FAST] = { + .params[CCI_CLK_RATE_37_5MHZ][I2C_MODE_FAST] = { .thigh = 38, .tlow = 56, .tsu_sto = 40, @@ -739,7 +783,7 @@ static const struct cci_data cci_v2_data = { .trdhld = 6, .tsp = 3 }, - .params[I2C_MODE_FAST_PLUS] = { + .params[CCI_CLK_RATE_37_5MHZ][I2C_MODE_FAST_PLUS] = { .thigh = 16, .tlow = 22, .tsu_sto = 17,