On 10/7/26 19:41, Gurumoorthy Santhakumar wrote:
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;
+}
This probe_chip callback is unrelated to this change, move it to a separate
commit.
Neil
+
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,
};