From 137b5f5720ba61efe92f1c7cf26926b7b2c67a4e Mon Sep 17 00:00:00 2001 From: Subramanian Ananthanarayanan Date: Tue, 5 Nov 2019 14:38:25 +0530 Subject: [PATCH] i3c: i3c-master-qcom-geni: Support for OD,PUSH-PULL mode frequency switch This change is to support both OD,PUSH-PULL mode frequency upto 12.5 Mhz. Also to make use of same source frequency during both the operations. Change-Id: I48ecd4a48f11de466b8b15d8454b8e7e8acc6825 Signed-off-by: Subramanian Ananthanarayanan --- drivers/i3c/master/i3c-master-qcom-geni.c | 48 +++++++++++++++++------ 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/drivers/i3c/master/i3c-master-qcom-geni.c b/drivers/i3c/master/i3c-master-qcom-geni.c index ee0f4a81782e..7d3e7c5866af 100644 --- a/drivers/i3c/master/i3c-master-qcom-geni.c +++ b/drivers/i3c/master/i3c-master-qcom-geni.c @@ -199,12 +199,18 @@ enum geni_i3c_err_code { #define TLMM_I3C_MODE 0x24 #define IBI_SW_RESET_MIN_SLEEP 1000 #define IBI_SW_RESET_MAX_SLEEP 2000 +#define I3C_OD_CLK_RATE 370000 enum i3c_trans_dir { WRITE_TRANSACTION = 0, READ_TRANSACTION = 1 }; +enum i3c_bus_phase { + OPEN_DRAIN_MODE = 0, + PUSH_PULL_MODE = 1 +}; + struct geni_se { void __iomem *base; void __iomem *ibi_base; @@ -262,6 +268,7 @@ struct geni_i3c_dev { int cur_idx; unsigned long newaddrslots[(I3C_ADDR_MASK + 1) / BITS_PER_LONG]; const struct geni_i3c_clk_fld *clk_fld; + const struct geni_i3c_clk_fld *clk_od_fld; struct geni_ibi ibi; }; @@ -302,9 +309,9 @@ struct geni_i3c_clk_fld { u8 clk_div; u8 i2c_t_high_cnt; u8 i2c_t_low_cnt; - u8 i2c_t_cycle_cnt; u8 i3c_t_high_cnt; u8 i3c_t_cycle_cnt; + u32 i2c_t_cycle_cnt; }; static struct geni_i3c_dev* @@ -332,11 +339,12 @@ to_geni_i3c_master(struct i3c_master_controller *master) * clk_freq_out = t / t_cycle */ static const struct geni_i3c_clk_fld geni_i3c_clk_map[] = { - { KHZ(100), 19200, 7, 10, 11, 26, 0, 0 }, - { KHZ(400), 19200, 2, 5, 12, 24, 0, 0 }, - { KHZ(1000), 19200, 1, 3, 9, 18, 7, 0 }, - { KHZ(1920), 19200, 1, 4, 9, 19, 7, 8 }, - { KHZ(12500), 100000, 1, 60, 140, 250, 8, 16 }, + { KHZ(100), 19200, 7, 10, 11, 0, 0, 26}, + { KHZ(400), 19200, 2, 5, 12, 0, 0, 24}, + { KHZ(1000), 19200, 1, 3, 9, 7, 0, 18}, + { KHZ(1920), 19200, 1, 4, 9, 7, 8, 19}, + { KHZ(370), 100000, 20, 4, 7, 8, 14, 14}, + { KHZ(12500), 100000, 1, 72, 168, 6, 7, 300}, }; static int geni_i3c_clk_map_idx(struct geni_i3c_dev *gi3c) @@ -351,11 +359,19 @@ static int geni_i3c_clk_map_idx(struct geni_i3c_dev *gi3c) itr->clk_freq_out == bus->scl_rate.i3c) && KHZ(itr->clk_src_freq) == gi3c->clk_src_freq) { gi3c->clk_fld = itr; - return 0; } + + if (itr->clk_freq_out == I3C_OD_CLK_RATE) + gi3c->clk_od_fld = itr; } - return -EINVAL; + if ((!gi3c->clk_fld) || (!gi3c->clk_od_fld)) { + GENI_SE_ERR(gi3c->ipcl, true, gi3c->se.dev, + "%s : clk mapping failed", __func__); + return -EINVAL; + } + + return 0; } static void set_new_addr_slot(unsigned long *addrslot, u8 addr) @@ -391,13 +407,17 @@ static bool is_new_addr_slot_set(unsigned long *addrslot, u8 addr) return ((*ptr & (1 << (addr % BITS_PER_LONG))) != 0); } -static void qcom_geni_i3c_conf(struct geni_i3c_dev *gi3c) +static void qcom_geni_i3c_conf(struct geni_i3c_dev *gi3c, + enum i3c_bus_phase bus_phase) { const struct geni_i3c_clk_fld *itr = gi3c->clk_fld; u32 val; unsigned long freq; int ret = 0; + if (bus_phase == OPEN_DRAIN_MODE) + itr = gi3c->clk_od_fld; + if (gi3c->dfs_idx > DFS_INDEX_MAX) ret = geni_se_clk_freq_match(&gi3c->se.i3c_rsc, KHZ(itr->clk_src_freq), @@ -673,8 +693,6 @@ static int i3c_geni_runtime_get_mutex_lock(struct geni_i3c_dev *gi3c) return ret; } - qcom_geni_i3c_conf(gi3c); - return 0; /* return 0 to indicate SUCCESS */ } @@ -923,6 +941,8 @@ static int geni_i3c_master_send_ccc_cmd if (ret) return ret; + qcom_geni_i3c_conf(gi3c, OPEN_DRAIN_MODE); + for (i = 0; i < cmd->ndests; i++) { int stall = (i < (cmd->ndests - 1)) || (cmd->id == I3C_CCC_ENTDAA); @@ -1000,6 +1020,8 @@ static int geni_i3c_master_priv_xfers if (ret) return ret; + qcom_geni_i3c_conf(gi3c, PUSH_PULL_MODE); + for (i = 0; i < nxfers; i++) { bool stall = (i < (nxfers - 1)); struct i3c_xfer_params xfer = { FIFO_MODE }; @@ -1051,6 +1073,8 @@ static int geni_i3c_master_i2c_xfers if (ret) return ret; + qcom_geni_i3c_conf(gi3c, PUSH_PULL_MODE); + GENI_SE_DBG(gi3c->ipcl, false, gi3c->se.dev, "i2c xfer:num:%d, msgs:len:%d,flg:%d\n", num, msgs[0].len, msgs[0].flags); @@ -1193,7 +1217,7 @@ static int geni_i3c_master_bus_init(struct i3c_master_controller *m) goto err_cleanup; } - qcom_geni_i3c_conf(gi3c); + qcom_geni_i3c_conf(gi3c, OPEN_DRAIN_MODE); /* Get an address for the master. */ ret = i3c_master_get_free_addr(m, 0);