diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2025-01-17 20:14:47 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2025-01-17 20:14:47 +0100 |
commit | 5e74b9bf263f5ab7b65e5553c9844c8197b73004 (patch) | |
tree | ceadc417148512c6648e77fee288437f6cff7c07 | |
parent | Merge tag 'pmdomain-v6.13-rc2-2' of git://git.kernel.org/pub/scm/linux/kernel... (diff) | |
parent | i2c: testunit: on errors, repeat NACK until STOP (diff) | |
download | linux-5e74b9bf263f5ab7b65e5553c9844c8197b73004.tar.xz linux-5e74b9bf263f5ab7b65e5553c9844c8197b73004.zip |
Merge tag 'i2c-for-6.13-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c fixes from Wolfram Sang:
- fix ref leak in the I2C core
- fix remove notification in the address translator
- missing error check in the pinctrl demuxer (plus a typo fix)
- fix NAK handling when Linux is testunit target
- fix NAK handling for the Renesas R-Car controller when it is a target
* tag 'i2c-for-6.13-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux:
i2c: testunit: on errors, repeat NACK until STOP
i2c: rcar: fix NACK handling when being a target
i2c: mux: demux-pinctrl: correct comment
i2c: mux: demux-pinctrl: check initial mux selection, too
i2c: atr: Fix client detach
i2c: core: fix reference leak in i2c_register_adapter()
-rw-r--r-- | drivers/i2c/busses/i2c-rcar.c | 20 | ||||
-rw-r--r-- | drivers/i2c/i2c-atr.c | 2 | ||||
-rw-r--r-- | drivers/i2c/i2c-core-base.c | 1 | ||||
-rw-r--r-- | drivers/i2c/i2c-slave-testunit.c | 19 | ||||
-rw-r--r-- | drivers/i2c/muxes/i2c-demux-pinctrl.c | 6 |
5 files changed, 36 insertions, 12 deletions
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index a7b77d14ee86..5693a38da7b5 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -130,6 +130,8 @@ #define ID_P_PM_BLOCKED BIT(31) #define ID_P_MASK GENMASK(31, 27) +#define ID_SLAVE_NACK BIT(0) + enum rcar_i2c_type { I2C_RCAR_GEN1, I2C_RCAR_GEN2, @@ -166,6 +168,7 @@ struct rcar_i2c_priv { int irq; struct i2c_client *host_notify_client; + u8 slave_flags; }; #define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent) @@ -655,6 +658,7 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv) { u32 ssr_raw, ssr_filtered; u8 value; + int ret; ssr_raw = rcar_i2c_read(priv, ICSSR) & 0xff; ssr_filtered = ssr_raw & rcar_i2c_read(priv, ICSIER); @@ -670,7 +674,10 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv) rcar_i2c_write(priv, ICRXTX, value); rcar_i2c_write(priv, ICSIER, SDE | SSR | SAR); } else { - i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_REQUESTED, &value); + ret = i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_REQUESTED, &value); + if (ret) + priv->slave_flags |= ID_SLAVE_NACK; + rcar_i2c_read(priv, ICRXTX); /* dummy read */ rcar_i2c_write(priv, ICSIER, SDR | SSR | SAR); } @@ -683,18 +690,21 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv) if (ssr_filtered & SSR) { i2c_slave_event(priv->slave, I2C_SLAVE_STOP, &value); rcar_i2c_write(priv, ICSCR, SIE | SDBS); /* clear our NACK */ + priv->slave_flags &= ~ID_SLAVE_NACK; rcar_i2c_write(priv, ICSIER, SAR); rcar_i2c_write(priv, ICSSR, ~SSR & 0xff); } /* master wants to write to us */ if (ssr_filtered & SDR) { - int ret; - value = rcar_i2c_read(priv, ICRXTX); ret = i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_RECEIVED, &value); - /* Send NACK in case of error */ - rcar_i2c_write(priv, ICSCR, SIE | SDBS | (ret < 0 ? FNA : 0)); + if (ret) + priv->slave_flags |= ID_SLAVE_NACK; + + /* Send NACK in case of error, but it will come 1 byte late :( */ + rcar_i2c_write(priv, ICSCR, SIE | SDBS | + (priv->slave_flags & ID_SLAVE_NACK ? FNA : 0)); rcar_i2c_write(priv, ICSSR, ~SDR & 0xff); } diff --git a/drivers/i2c/i2c-atr.c b/drivers/i2c/i2c-atr.c index b7c10ced5a43..8fe9ddff8e96 100644 --- a/drivers/i2c/i2c-atr.c +++ b/drivers/i2c/i2c-atr.c @@ -412,7 +412,7 @@ static int i2c_atr_bus_notifier_call(struct notifier_block *nb, dev_name(dev), ret); break; - case BUS_NOTIFY_DEL_DEVICE: + case BUS_NOTIFY_REMOVED_DEVICE: i2c_atr_detach_client(client->adapter, client); break; diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 7c810893bfa3..75d30861ffe2 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -1562,6 +1562,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap) res = device_add(&adap->dev); if (res) { pr_err("adapter '%s': can't register device (%d)\n", adap->name, res); + put_device(&adap->dev); goto out_list; } diff --git a/drivers/i2c/i2c-slave-testunit.c b/drivers/i2c/i2c-slave-testunit.c index 0d6fbaa48248..6de4307050dd 100644 --- a/drivers/i2c/i2c-slave-testunit.c +++ b/drivers/i2c/i2c-slave-testunit.c @@ -38,6 +38,7 @@ enum testunit_regs { enum testunit_flags { TU_FLAG_IN_PROCESS, + TU_FLAG_NACK, }; struct testunit_data { @@ -90,8 +91,10 @@ static int i2c_slave_testunit_slave_cb(struct i2c_client *client, switch (event) { case I2C_SLAVE_WRITE_REQUESTED: - if (test_bit(TU_FLAG_IN_PROCESS, &tu->flags)) - return -EBUSY; + if (test_bit(TU_FLAG_IN_PROCESS | TU_FLAG_NACK, &tu->flags)) { + ret = -EBUSY; + break; + } memset(tu->regs, 0, TU_NUM_REGS); tu->reg_idx = 0; @@ -99,8 +102,10 @@ static int i2c_slave_testunit_slave_cb(struct i2c_client *client, break; case I2C_SLAVE_WRITE_RECEIVED: - if (test_bit(TU_FLAG_IN_PROCESS, &tu->flags)) - return -EBUSY; + if (test_bit(TU_FLAG_IN_PROCESS | TU_FLAG_NACK, &tu->flags)) { + ret = -EBUSY; + break; + } if (tu->reg_idx < TU_NUM_REGS) tu->regs[tu->reg_idx] = *val; @@ -129,6 +134,8 @@ static int i2c_slave_testunit_slave_cb(struct i2c_client *client, * here because we still need them in the workqueue! */ tu->reg_idx = 0; + + clear_bit(TU_FLAG_NACK, &tu->flags); break; case I2C_SLAVE_READ_PROCESSED: @@ -151,6 +158,10 @@ static int i2c_slave_testunit_slave_cb(struct i2c_client *client, break; } + /* If an error occurred somewhen, we NACK everything until next STOP */ + if (ret) + set_bit(TU_FLAG_NACK, &tu->flags); + return ret; } diff --git a/drivers/i2c/muxes/i2c-demux-pinctrl.c b/drivers/i2c/muxes/i2c-demux-pinctrl.c index dce18f763a09..77a740561fd7 100644 --- a/drivers/i2c/muxes/i2c-demux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-demux-pinctrl.c @@ -68,7 +68,7 @@ static int i2c_demux_activate_master(struct i2c_demux_pinctrl_priv *priv, u32 ne } /* - * Check if there are pinctrl states at all. Note: we cant' use + * Check if there are pinctrl states at all. Note: we can't use * devm_pinctrl_get_select() because we need to distinguish between * the -ENODEV from devm_pinctrl_get() and pinctrl_lookup_state(). */ @@ -261,7 +261,9 @@ static int i2c_demux_pinctrl_probe(struct platform_device *pdev) pm_runtime_no_callbacks(&pdev->dev); /* switch to first parent as active master */ - i2c_demux_activate_master(priv, 0); + err = i2c_demux_activate_master(priv, 0); + if (err) + goto err_rollback; err = device_create_file(&pdev->dev, &dev_attr_available_masters); if (err) |