drivers/i2c/busses/i2c-riic.c | 100 ++++++++++++++++++++++++++++++---- 1 file changed, 90 insertions(+), 10 deletions(-)
From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Implement bus recovery by reinitializing the hardware to reset the bus
state and generating 9 clock cycles (and a stop condition) to release
the SDA line.
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Tested-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Reviewed-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Reviewed-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
Reviewed-by: Andy Shevchenko <andy@kernel.org>
---
v7->v8
- Included Acks from Andy and Fabrizio.
v6->v7
- https://lore.kernel.org/all/20250203143511.629140-1-prabhakar.mahadev-lad.rj@bp.renesas.com/
v2->v6
- Included RB and TB from Claudiu.
v1->v2
- Used single register read to check SDA/SCL lines
---
drivers/i2c/busses/i2c-riic.c | 100 ++++++++++++++++++++++++++++++----
1 file changed, 90 insertions(+), 10 deletions(-)
diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c
index d7dddd6c296a..888825423d94 100644
--- a/drivers/i2c/busses/i2c-riic.c
+++ b/drivers/i2c/busses/i2c-riic.c
@@ -51,6 +51,7 @@
#define ICCR1_ICE BIT(7)
#define ICCR1_IICRST BIT(6)
+#define ICCR1_CLO BIT(5)
#define ICCR1_SOWP BIT(4)
#define ICCR1_SCLI BIT(1)
#define ICCR1_SDAI BIT(0)
@@ -69,6 +70,7 @@
#define ICMR3_ACKBT BIT(3)
#define ICFER_FMPE BIT(7)
+#define ICFER_MALE BIT(1)
#define ICIER_TIE BIT(7)
#define ICIER_TEIE BIT(6)
@@ -82,6 +84,8 @@
#define RIIC_INIT_MSG -1
+#define RIIC_RECOVERY_CLK_CNT 9
+
enum riic_reg_list {
RIIC_ICCR1 = 0,
RIIC_ICCR2,
@@ -151,13 +155,16 @@ static int riic_bus_barrier(struct riic_dev *riic)
ret = readb_poll_timeout(riic->base + riic->info->regs[RIIC_ICCR2], val,
!(val & ICCR2_BBSY), 10, riic->adapter.timeout);
if (ret)
- return ret;
+ goto i2c_recover;
if ((riic_readb(riic, RIIC_ICCR1) & (ICCR1_SDAI | ICCR1_SCLI)) !=
(ICCR1_SDAI | ICCR1_SCLI))
- return -EBUSY;
+ goto i2c_recover;
return 0;
+
+i2c_recover:
+ return i2c_recover_bus(&riic->adapter);
}
static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
@@ -332,7 +339,7 @@ static const struct i2c_algorithm riic_algo = {
.functionality = riic_func,
};
-static int riic_init_hw(struct riic_dev *riic)
+static int riic_init_hw(struct riic_dev *riic, bool recover)
{
int ret;
unsigned long rate;
@@ -414,9 +421,11 @@ static int riic_init_hw(struct riic_dev *riic)
rate / total_ticks, ((brl + 3) * 100) / (brl + brh + 6),
t->scl_fall_ns / ns_per_tick, t->scl_rise_ns / ns_per_tick, cks, brl, brh);
- ret = pm_runtime_resume_and_get(dev);
- if (ret)
- return ret;
+ if (!recover) {
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ return ret;
+ }
/* Changing the order of accessing IICRST and ICE may break things! */
riic_writeb(riic, ICCR1_IICRST | ICCR1_SOWP, RIIC_ICCR1);
@@ -434,8 +443,74 @@ static int riic_init_hw(struct riic_dev *riic)
riic_clear_set_bit(riic, ICCR1_IICRST, 0, RIIC_ICCR1);
- pm_runtime_mark_last_busy(dev);
- pm_runtime_put_autosuspend(dev);
+ if (!recover) {
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+ }
+ return 0;
+}
+
+static int riic_recover_bus(struct i2c_adapter *adap)
+{
+ struct riic_dev *riic = i2c_get_adapdata(adap);
+ struct device *dev = riic->adapter.dev.parent;
+ int ret;
+ u8 val;
+
+ ret = riic_init_hw(riic, true);
+ if (ret)
+ return ret;
+
+ /* output extra SCL clock cycles with master arbitration-lost detection disabled */
+ riic_clear_set_bit(riic, ICFER_MALE, 0, RIIC_ICFER);
+
+ for (unsigned int i = 0; i < RIIC_RECOVERY_CLK_CNT; i++) {
+ riic_clear_set_bit(riic, 0, ICCR1_CLO, RIIC_ICCR1);
+ ret = readb_poll_timeout(riic->base + riic->info->regs[RIIC_ICCR1], val,
+ !(val & ICCR1_CLO), 0, 100);
+ if (ret) {
+ dev_err(dev, "SCL clock cycle timeout\n");
+ return ret;
+ }
+ }
+
+ /*
+ * The last clock cycle may have driven the SDA line high, so add a
+ * short delay to allow the line to stabilize before checking the status.
+ */
+ udelay(5);
+
+ /*
+ * If an incomplete byte write occurs, the SDA line may remain low
+ * even after 9 clock pulses, indicating the bus is not released.
+ * To resolve this, send an additional clock pulse to simulate a STOP
+ * condition and ensure proper bus release.
+ */
+ if ((riic_readb(riic, RIIC_ICCR1) & (ICCR1_SDAI | ICCR1_SCLI)) !=
+ (ICCR1_SDAI | ICCR1_SCLI)) {
+ riic_clear_set_bit(riic, 0, ICCR1_CLO, RIIC_ICCR1);
+ ret = readb_poll_timeout(riic->base + riic->info->regs[RIIC_ICCR1], val,
+ !(val & ICCR1_CLO), 0, 100);
+ if (ret) {
+ dev_err(dev, "SCL clock cycle timeout occurred while issuing the STOP condition\n");
+ return ret;
+ }
+ /* delay to make sure SDA line goes back HIGH again */
+ udelay(5);
+ }
+
+ /* clear any flags set */
+ riic_writeb(riic, 0, RIIC_ICSR2);
+ /* read back register to confirm writes */
+ riic_readb(riic, RIIC_ICSR2);
+
+ /* restore back ICFER_MALE */
+ riic_clear_set_bit(riic, 0, ICFER_MALE, RIIC_ICFER);
+
+ if ((riic_readb(riic, RIIC_ICCR1) & (ICCR1_SDAI | ICCR1_SCLI)) !=
+ (ICCR1_SDAI | ICCR1_SCLI))
+ return -EINVAL;
+
return 0;
}
@@ -447,6 +522,10 @@ static const struct riic_irq_desc riic_irqs[] = {
{ .res_num = 5, .isr = riic_tend_isr, .name = "riic-nack" },
};
+static struct i2c_bus_recovery_info riic_bri = {
+ .recover_bus = riic_recover_bus,
+};
+
static int riic_i2c_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -493,6 +572,7 @@ static int riic_i2c_probe(struct platform_device *pdev)
strscpy(adap->name, "Renesas RIIC adapter", sizeof(adap->name));
adap->owner = THIS_MODULE;
adap->algo = &riic_algo;
+ adap->bus_recovery_info = &riic_bri;
adap->dev.parent = dev;
adap->dev.of_node = dev->of_node;
@@ -505,7 +585,7 @@ static int riic_i2c_probe(struct platform_device *pdev)
pm_runtime_use_autosuspend(dev);
pm_runtime_enable(dev);
- ret = riic_init_hw(riic);
+ ret = riic_init_hw(riic, false);
if (ret)
goto out;
@@ -613,7 +693,7 @@ static int riic_i2c_resume(struct device *dev)
if (ret)
return ret;
- ret = riic_init_hw(riic);
+ ret = riic_init_hw(riic, false);
if (ret) {
/*
* In case this happens there is no way to recover from this
--
2.49.0
On Mon, Apr 07, 2025 at 01:18:59PM +0100, Prabhakar wrote: > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com> > > Implement bus recovery by reinitializing the hardware to reset the bus > state and generating 9 clock cycles (and a stop condition) to release > the SDA line. > > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com> > Tested-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com> > Reviewed-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com> > Reviewed-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com> > Reviewed-by: Andy Shevchenko <andy@kernel.org> As I wrote in the other thread: I took your generic_scl approach and replaced bus_free() with get_sda(). Works fine here with my G3S: # echo 0x1a > /sys/kernel/debug/i2c/i2c-2/incomplete_address_phase ; i2cget -f -y 0 0x1a 3 0x0c And I see 9 pulses in the scope. Can you try this with your setup please?
Hi Wolfram,
Thank you for the review.
Finally I got my setup out for this.
On Thu, Apr 17, 2025 at 9:32 AM Wolfram Sang
<wsa+renesas@sang-engineering.com> wrote:
>
> On Mon, Apr 07, 2025 at 01:18:59PM +0100, Prabhakar wrote:
> > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> >
> > Implement bus recovery by reinitializing the hardware to reset the bus
> > state and generating 9 clock cycles (and a stop condition) to release
> > the SDA line.
> >
> > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> > Tested-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> > Reviewed-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> > Reviewed-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> > Reviewed-by: Andy Shevchenko <andy@kernel.org>
>
> As I wrote in the other thread: I took your generic_scl approach and
> replaced bus_free() with get_sda(). Works fine here with my G3S:
>
As suggested I have the below now, (are there any changes Ive missed?)
+static int riic_get_sda(struct i2c_adapter *adap)
+{
+ struct riic_dev *riic = i2c_get_adapdata(adap);
+
+ /* Check if the bus is busy or SDA is not high */
+ if ((riic_readb(riic, RIIC_ICCR2) & ICCR2_BBSY) ||
+ !(riic_readb(riic, RIIC_ICCR1) & ICCR1_SDAI))
+ return -EBUSY;
+
+ return 1;
+}
+
static const struct riic_irq_desc riic_irqs[] = {
{ .res_num = 0, .isr = riic_tend_isr, .name = "riic-tend" },
{ .res_num = 1, .isr = riic_rdrf_isr, .name = "riic-rdrf" },
@@ -523,7 +568,11 @@ static const struct riic_irq_desc riic_irqs[] = {
};
static struct i2c_bus_recovery_info riic_bri = {
- .recover_bus = riic_recover_bus,
+ .get_scl = riic_get_scl,
+ .set_scl = riic_set_scl,
+ .set_sda = riic_set_sda,
+ .get_sda = riic_get_sda,
+ .recover_bus = i2c_generic_scl_recovery,
}
> # echo 0x1a > /sys/kernel/debug/i2c/i2c-2/incomplete_address_phase ; i2cget -f -y 0 0x1a 3
> 0x0c
>
> And I see 9 pulses in the scope. Can you try this with your setup
> please?
>
This seems to be unreliable on my side below are my test results.
root@smarc-rzg2l:~/i2c# cat ./incomplete_address_phase.sh
cd /sys/kernel/debug/i2c/i2c-4/
for i in {1..1}; do
echo 0x68 > incomplete_address_phase;
val=$(i2cget -y -f 3 0x68 8)
if [ "$?" != "0" ] || [ "${val}" != "0x83" ]; then
echo "I2C Read error (ret:$?) ${val}!!"
exit 1
fi
echo "Read val:${val}"
done
root@smarc-rzg2l:~/i2c#
root@smarc-rzg2l:~/i2c# ./incomplete_address_phase.sh
Read val:0x83
root@smarc-rzg2l:~/i2c# ./incomplete_address_phase.sh
Error: Read failed
I2C Read error (ret:0) !!
root@smarc-rzg2l:~/i2c# ./incomplete_address_phase.sh
Read val:0x83
root@smarc-rzg2l:~/i2c# ./incomplete_address_phase.sh
Error: Read failed
I2C Read error (ret:0) !!
root@smarc-rzg2l:~/i2c#
root@smarc-rzg2l:~/i2c# ./incomplete_address_phase.sh
Read val:0x83
root@smarc-rzg2l:~/i2c# ./incomplete_address_phase.sh
Error: Read failed
I2C Read error (ret:0) !!
root@smarc-rzg2l:~/i2c#
root@smarc-rzg2l:~/i2c#
Cheers,
Prabhakar
> As suggested I have the below now, (are there any changes Ive missed?)
Well, get_sda should really only get SDA :)
>
> +static int riic_get_sda(struct i2c_adapter *adap)
> +{
> + struct riic_dev *riic = i2c_get_adapdata(adap);
> +
> + /* Check if the bus is busy or SDA is not high */
> + if ((riic_readb(riic, RIIC_ICCR2) & ICCR2_BBSY) ||
> + !(riic_readb(riic, RIIC_ICCR1) & ICCR1_SDAI))
> + return -EBUSY;
> +
> + return 1;
> +}
I have
+static int riic_get_sda(struct i2c_adapter *adap)
+{
+ struct riic_dev *riic = i2c_get_adapdata(adap);
+
+ return !!(riic_readb(riic, RIIC_ICCR1) & ICCR1_SDAI);
+}
I believe the BBSY handling could be why it does not work.
Hi Wolfram,
On Thu, Apr 17, 2025 at 9:12 PM Wolfram Sang
<wsa+renesas@sang-engineering.com> wrote:
>
>
> > As suggested I have the below now, (are there any changes Ive missed?)
>
> Well, get_sda should really only get SDA :)
> >
> > +static int riic_get_sda(struct i2c_adapter *adap)
> > +{
> > + struct riic_dev *riic = i2c_get_adapdata(adap);
> > +
> > + /* Check if the bus is busy or SDA is not high */
> > + if ((riic_readb(riic, RIIC_ICCR2) & ICCR2_BBSY) ||
> > + !(riic_readb(riic, RIIC_ICCR1) & ICCR1_SDAI))
> > + return -EBUSY;
> > +
> > + return 1;
> > +}
>
> I have
>
> +static int riic_get_sda(struct i2c_adapter *adap)
> +{
> + struct riic_dev *riic = i2c_get_adapdata(adap);
> +
> + return !!(riic_readb(riic, RIIC_ICCR1) & ICCR1_SDAI);
> +}
>
> I believe the BBSY handling could be why it does not work.
>
Thanks, that did the trick. The incomplete_write_byte test case is
passing for me. Now moving onto the incomplete_address_phase case this
seems to be failing on my side. Did you test this on your side?
root@smarc-rzg2l:~/i2c# cat incomplete_address_phase.sh
cd /sys/kernel/debug/i2c/i2c-4/
for i in {1..1}; do
echo 0x68 > incomplete_address_phase;
val=$(i2cget -y -f 3 0x68 8)
if [ "$?" != "0" ] || [ "${val}" != "0x83" ]; then
echo "I2C Read error (ret:$?) ${val}!!"
exit 1
fi
echo "Read val:${val}"
done
root@smarc-rzg2l:~/i2c# ./incomplete_address_phase.sh
Error: Read failed
I2C Read error (ret:0) !!
root@smarc-rzg2l:~/i2c# ./incomplete_address_phase.sh
Read val:0x83
root@smarc-rzg2l:~/i2c# ./incomplete_address_phase.sh
Error: Read failed
I2C Read error (ret:0) !!
root@smarc-rzg2l:~/i2c# ./incomplete_address_phase.sh
Read val:0x83
root@smarc-rzg2l:~/i2c# ./incomplete_address_phase.sh
Error: Read failed
I2C Read error (ret:0) !!
root@smarc-rzg2l:~/i2c#
root@smarc-rzg2l:~/i2c#
Cheers,
Prabhakar
> Thanks, that did the trick. The incomplete_write_byte test case is > passing for me. Now moving onto the incomplete_address_phase case this > seems to be failing on my side. Did you test this on your side? Well, frankly, this is the only test I tried and, yes, it did work for me. Will check 'incomplete_write_byte' later today. I will also check if I need to run the tests more often. I did not do an endless loop.
> Well, frankly, this is the only test I tried and, yes, it did work for > me. Will check 'incomplete_write_byte' later today. I will also check if > I need to run the tests more often. I did not do an endless loop. Both tests work for me, even in an endless loop. I also get the desired signal outputs checking with the logic analyzer. Here is the branch I used: git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git renesas/g3s/riic-recovery-experimental
Hi Wolfram,
On Wed, Apr 23, 2025 at 9:26 AM Wolfram Sang
<wsa+renesas@sang-engineering.com> wrote:
>
>
> > Well, frankly, this is the only test I tried and, yes, it did work for
> > me. Will check 'incomplete_write_byte' later today. I will also check if
> > I need to run the tests more often. I did not do an endless loop.
>
> Both tests work for me, even in an endless loop. I also get the desired
> signal outputs checking with the logic analyzer.
>
> Here is the branch I used:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git renesas/g3s/riic-recovery-experimental
>
I prepared a setup on SMARC2 RZ/G3S and I can confirm it is working
(but this is failing on SMARC RZ/G2L I'll look further into this)
For the SMARC2 RZ/G3S to make sure the I2C GPIO pins behave as
opendrain I have the below patch for pinctrl
drivers/pinctrl/renesas/pinctrl-rzg2l.c | 24 +++++++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)
diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c
b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
index 78fa08ff0faa..04bbc7499ce9 100644
--- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c
+++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
@@ -167,6 +167,7 @@
#define NOD_MASK 0x01
#define SMT_MASK 0x01
+#define PM_HI_Z 0x0
#define PM_INPUT 0x1
#define PM_OUTPUT 0x2
@@ -176,6 +177,9 @@
#define RZG2L_TINT_MAX_INTERRUPT 32
#define RZG2L_PACK_HWIRQ(t, i) (((t) << 16) | (i))
+#define GPIO8_P8_2 66
+#define GPIO8_P8_3 67
+
/* Custom pinconf parameters */
#define RENESAS_RZV2H_PIN_CONFIG_OUTPUT_IMPEDANCE (PIN_CONFIG_END + 1)
@@ -1703,6 +1707,10 @@ static int rzg2l_gpio_request(struct gpio_chip
*chip, unsigned int offset)
pctrl->data->pmc_writeb(pctrl, reg8, PMC(off));
spin_unlock_irqrestore(&pctrl->lock, flags);
+ if (offset == GPIO8_P8_2 || offset == GPIO8_P8_3) {
+ rzg2l_rmw_pin_config(pctrl, PUPD(off), bit, PUPD_MASK, 1);
+ rzg2l_rmw_pin_config(pctrl, IOLH(off), bit, IOLH_MASK, 0x3);
+ }
return 0;
}
@@ -1722,7 +1730,10 @@ static void rzg2l_gpio_set_direction(struct
rzg2l_pinctrl *pctrl, u32 offset,
reg16 = readw(pctrl->base + PM(off));
reg16 &= ~(PM_MASK << (bit * 2));
- reg16 |= (output ? PM_OUTPUT : PM_INPUT) << (bit * 2);
+ if (offset == GPIO8_P8_2 || offset == GPIO8_P8_3)
+ reg16 |= (output ? PM_OUTPUT : PM_HI_Z) << (bit * 2);
+ else
+ reg16 |= (output ? PM_OUTPUT : PM_INPUT) << (bit * 2);
writew(reg16, pctrl->base + PM(off));
spin_unlock_irqrestore(&pctrl->lock, flags);
@@ -1769,6 +1780,11 @@ static void rzg2l_gpio_set(struct gpio_chip
*chip, unsigned int offset,
unsigned long flags;
u8 reg8;
+ if (offset == GPIO8_P8_2 || offset == GPIO8_P8_3) {
+ rzg2l_gpio_set_direction(pctrl, offset, value ? 0 : 1);
+ return;
+ }
+
spin_lock_irqsave(&pctrl->lock, flags);
reg8 = readb(pctrl->base + P(off));
@@ -1804,6 +1820,12 @@ static int rzg2l_gpio_get(struct gpio_chip
*chip, unsigned int offset)
reg16 = readw(pctrl->base + PM(off));
reg16 = (reg16 >> (bit * 2)) & PM_MASK;
+ if (offset == GPIO8_P8_2 || offset == GPIO8_P8_3) {
+ if (reg16 == PM_HI_Z)
+ return 1;
+ return 0;
+ }
+
if (reg16 == PM_INPUT)
return !!(readb(pctrl->base + PIN(off)) & BIT(bit));
else if (reg16 == PM_OUTPUT)
--
2.49.0
Below is my loop tests for SMARC2 RZ/G3S which worked without any issues:
root@smarc-rzg3s:~/i2c# cat ./i2c-inject-error.sh
DEFAULT_LOOP_COUNT=500
incomplete_address_phase() {
cd /sys/kernel/debug/i2c/i2c-2/
for i in {1..1}; do
echo 0x1a > incomplete_address_phase;
val=$(i2cget -y -f 0 0x1a 3)
if [ "$?" != "0" ] || [ "${val}" != "0x0c" ]; then
echo "I2C Read error (ret:$?) ${val}!!"
exit 1
fi
echo "Read val:${val}"
i2cget -y -f 0 0x1a 3;
if [ "$?" != "0" ]; then
echo "I2C Read error when no error injection!!"
exit 1
fi
done
}
incomplete_write_byte() {
cd /sys/kernel/debug/i2c/i2c-2/
for i in {1..1}; do
val1=$(printf "0x%02x" $((RANDOM & 0xff)))
val2=$(printf "0x%02x" $((RANDOM & 0xff)))
i2cset -y -f 0 0x57 0 ${val1}
i2cset -y -f 0 0x57 8 ${val2}
r1=$(i2cget -y -f 0 0x57 0x0)
if [ "$?" != "0" ] || [ "${r1}" != "${val1}" ]; then
echo "1: I2C Read error (ret:$?) ${r1}!!"
exit 1
fi
echo 0x57 > incomplete_write_byte
r1=$(i2cget -y -f 0 0x57 0x8)
if [ "$?" != "0" ] || [ "${r1}" != "${val2}" ]; then
echo "2: I2C Read error (ret:$?) ${r1}!!"
exit 1
fi
r1=$(i2cget -y -f 0 0x57 0x0)
if [ "$?" != "0" ] || [ "${r1}" != "${val1}" ]; then
echo "3: I2C Read error (ret:$?) ${r1}!!"
exit 1
fi
done
}
if [ ! -z "${1}" ];then
DEFAULT_LOOP_COUNT=$1
fi
for i in $(seq 0 $DEFAULT_LOOP_COUNT);do
echo "Loop count: "$i;
incomplete_address_phase
incomplete_write_byte
done
root@smarc-rzg3s:~/i2c#
Ive attached the analyzer for SMARC RZ/G2L where it is failing for
`incomplete_address_phase`.
Cheers,
Prabhakar
Hi Prabhakar, > I prepared a setup on SMARC2 RZ/G3S and I can confirm it is working This is good news! > (but this is failing on SMARC RZ/G2L I'll look further into this) This not so much. Hmmm, are you verifying against the same I2C device on the carrier board? If you compare against different I2C devices on the module board, the culprit might be the I2C device. > For the SMARC2 RZ/G3S to make sure the I2C GPIO pins behave as > opendrain I have the below patch for pinctrl Do you really need this patch? The GPIO lines are wired to SCL/SDA which are already pulled up. Search for R118 in the module schematics. All the best, Wolfram
Hi Wolfram, On Fri, Apr 25, 2025 at 10:14 AM Wolfram Sang <wsa+renesas@sang-engineering.com> wrote: > > Hi Prabhakar, > > > I prepared a setup on SMARC2 RZ/G3S and I can confirm it is working > > This is good news! > > > (but this is failing on SMARC RZ/G2L I'll look further into this) > > This not so much. Hmmm, are you verifying against the same I2C device > on the carrier board? If you compare against different I2C devices on > the module board, the culprit might be the I2C device. > You were right, it was the slave indeed. After recovery from the generic algorithm during the transfer I am seeing arbitration lost due to which there was a timeout during transmission. So for now we can conclude the generic I2C recovery algo works for RIIC. I have tested with two slaves: - PMOD RTC on SMARC RZ/G2L - PMOD RTC + Audio codec on SMARC RZ/G3S After tidying up, I'll resping a new version of the patch. > > For the SMARC2 RZ/G3S to make sure the I2C GPIO pins behave as > > opendrain I have the below patch for pinctrl > > Do you really need this patch? The GPIO lines are wired to SCL/SDA which > are already pulled up. Search for R118 in the module schematics. > Agreed the pullup isn't needed. This was needed on SMARC RZ/G2L as there were spikes. Cheers, Prabhakar
© 2016 - 2026 Red Hat, Inc.