Add support for 32MHz GENI SE clocks through dedicated timing tables selected via the qcom,geni-se-clk-32mhz DT property. Also add chip probing support.
Depends on: misc: qcom_geni: Add minicore support Link: https://lore.kernel.org/u-boot/[email protected]/ Signed-off-by: Gurumoorthy Santhakumar <[email protected]> --- drivers/i2c/geni_i2c.c | 76 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 10 deletions(-) diff --git a/drivers/i2c/geni_i2c.c b/drivers/i2c/geni_i2c.c index 7498cbcb41a..9edba3dd551 100644 --- a/drivers/i2c/geni_i2c.c +++ b/drivers/i2c/geni_i2c.c @@ -96,18 +96,35 @@ struct geni_i2c_priv { * clk_freq_out = t / t_cycle * source_clock = 19.2 MHz */ -static const struct geni_i2c_clk_fld geni_i2c_clk_map[] = { - {I2C_SPEED_STANDARD_RATE, 7, 10, 11, 26}, - {I2C_SPEED_FAST_RATE, 2, 5, 12, 24}, - {I2C_SPEED_FAST_PLUS_RATE, 1, 3, 9, 18}, +static const struct geni_i2c_clk_fld geni_i2c_clk_map_19p2mhz[] = { + {I2C_SPEED_STANDARD_RATE, 7, 10, 12, 26}, + {I2C_SPEED_FAST_RATE, 2, 5, 11, 22}, + {I2C_SPEED_FAST_PLUS_RATE, 1, 2, 8, 18}, }; -static int geni_i2c_clk_map_idx(struct geni_i2c_priv *geni, unsigned int clk_freq) +/* source_clock = 32 MHz */ +static const struct geni_i2c_clk_fld geni_i2c_clk_map_32mhz[] = { + {I2C_SPEED_STANDARD_RATE, 12, 9, 10, 26}, + {I2C_SPEED_FAST_RATE, 4, 3, 9, 19}, + {I2C_SPEED_FAST_PLUS_RATE, 2, 3, 5, 15}, +}; + +static int geni_i2c_clk_map_idx(struct geni_i2c_priv *geni, + unsigned int clk_freq, bool use_32mhz) { - const struct geni_i2c_clk_fld *itr = geni_i2c_clk_map; + const struct geni_i2c_clk_fld *itr; + int array_size; int i; - for (i = 0; i < ARRAY_SIZE(geni_i2c_clk_map); i++, itr++) { + if (use_32mhz) { + itr = geni_i2c_clk_map_32mhz; + array_size = ARRAY_SIZE(geni_i2c_clk_map_32mhz); + } else { + itr = geni_i2c_clk_map_19p2mhz; + array_size = ARRAY_SIZE(geni_i2c_clk_map_19p2mhz); + } + + for (i = 0; i < array_size; i++, itr++) { if (itr->clk_freq_out == clk_freq) { geni->clk_fld = itr; return 0; @@ -262,6 +279,38 @@ static int geni_i2c_xfer_rx(struct geni_i2c_priv *geni, struct i2c_msg *msg, u32 return geni_i2c_fifo_rx_drain(geni, msg); } +/* Probe to see if a chip is present. */ +static int geni_i2c_probe_chip(struct udevice *dev, uint chip_addr, + uint chip_flags) +{ + struct geni_i2c_priv *geni = dev_get_priv(dev); + u32 m_param = (chip_addr << SLV_ADDR_SHFT) & SLV_ADDR_MSK; + u32 status; + ulong start; + + (void)chip_flags; + + /* Add delay before chip detect to prevent the bus going undefined. */ + mdelay(1); + + qcom_geni_i2c_conf(geni); + writel(0, geni->base + SE_I2C_TX_TRANS_LEN); + geni_i2c_setup_m_cmd(geni, I2C_ADDR_ONLY, m_param); + writel(1, geni->base + SE_GENI_TX_WATERMARK_REG); + + start = get_timer(0); + while (get_timer(start) < I2C_TIMEOUT_MS) { + status = readl(geni->base + SE_GENI_M_IRQ_STATUS); + if (status & M_CMD_DONE_EN) { + writel(status, geni->base + SE_GENI_M_IRQ_CLEAR); + return (status & SE_I2C_ERR) ? -ENODEV : 0; + } + udelay(10); + } + + return -ETIMEDOUT; +} + static int geni_i2c_xfer(struct udevice *bus, struct i2c_msg msgs[], int num) { struct geni_i2c_priv *geni = dev_get_priv(bus); @@ -468,6 +517,8 @@ static int geni_i2c_probe(struct udevice *dev) ofnode parent_node = ofnode_get_parent(dev_ofnode(dev)); struct geni_i2c_priv *geni = dev_get_priv(dev); u32 proto, tx_depth, fifo_disable; + u32 clk_freq; + bool use_32mhz; int ret; geni->is_master_hub = dev_get_driver_data(dev) & GENI_I2C_IS_MASTER_HUB; @@ -538,19 +589,24 @@ static int geni_i2c_probe(struct udevice *dev) geni_i2c_config_packing(geni, BITS_PER_BYTE, PACKING_BYTES_PW, true, true, true); - /* Setup for standard rate */ - return geni_i2c_clk_map_idx(geni, I2C_SPEED_STANDARD_RATE); + clk_freq = dev_read_u32_default(dev, "clock-frequency", + I2C_SPEED_STANDARD_RATE); + use_32mhz = dev_read_bool(dev, "qcom,geni-se-clk-32mhz"); + + return geni_i2c_clk_map_idx(geni, clk_freq, use_32mhz); } static int geni_i2c_set_bus_speed(struct udevice *dev, unsigned int clk_freq) { struct geni_i2c_priv *geni = dev_get_priv(dev); + bool use_32mhz = dev_read_bool(dev, "qcom,geni-se-clk-32mhz"); - return geni_i2c_clk_map_idx(geni, clk_freq); + return geni_i2c_clk_map_idx(geni, clk_freq, use_32mhz); } static const struct dm_i2c_ops geni_i2c_ops = { .xfer = geni_i2c_xfer, + .probe_chip = geni_i2c_probe_chip, .set_bus_speed = geni_i2c_set_bus_speed, }; -- 2.34.1
