Hello Gurumoorthy Santhakumar,
On 07.10.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},
value changes from 11 -> 12 ? Why?
+ {I2C_SPEED_FAST_RATE, 2, 5, 11, 22},
+ {I2C_SPEED_FAST_PLUS_RATE, 1, 2, 8, 18},
};
You change here the values for I2C_SPEED_FAST_PLUS_RATE.
Have you checked, that the frequency is still the same with this settings?
Ah, I found your settings also in the linux driver!
It came in through commit
"""
commit a815975cbaeb4ab29f45312ef23be2871b2e8b82
Author: Mukesh Kumar Savaliya <[email protected]>
Date: Wed Jan 22 12:16:34 2025 +0530
i2c: qcom-geni: Update i2c frequency table to match hardware guidance
"""
I see this as a seperate patch, and please refer to the above
linux commit ... sorry for this nitpick...
-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");
Hmm.. this property is not defined in linux code... do you plan to push this
to linux?
It seems to me, this is not needed in the linux driver at all!
Could you check, if you can adapt geni_i2c_clk_map_idx() to the one from linux?
They get the current clock from geni_se_clk_freq_match(). Is it possible to
port this to u-boot?
Thanks!
+
+ 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,
};
bye,
Heiko
--
Nabla Software Engineering
HRB 40522 Augsburg
Phone: +49 821 45592596
E-Mail: [email protected]
Geschäftsführer : Stefano Babic