i2c-for-6.11-final-but-missed-it

These are only fixes originally meant for 6.11 final. Because of serious
 travel problems, I could not send them in time and so this is my first
 PR for 6.12.
 
 The Aspeed driver tracks the controller's state (stop, pending,
 start, etc.). Previously, when the stop command was sent, the
 state was not updated. The fix in this pull request ensures the
 driver's state is aligned with the device status.
 
 The Intel SCH driver receives a new look, and among the cleanups,
 there is a fix where, due to an oversight, an if/else statement
 was missing the else, causing it to move forward instead of
 exiting the function in case of an error.
 
 The Qualcomm GENI I2C driver adds the IRQF_NO_AUTOEN flag to the
 IRQ setup to prevent unwanted interrupts during probe.
 
 The Xilinx XPS controller fixes TX FIFO handling to avoid missed
 NAKs. Another fix ensures the controller is reinitialized when
 the bus appears busy.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEOZGx6rniZ1Gk92RdFA3kzBSgKbYFAmbr7nAACgkQFA3kzBSg
 KbbdRA/9Ft8+rQNlUH8oZ90qMjAu99ktwgLS99putSRtnnRClodLCafDskgYan5e
 H+UAr2LsolwWkG6Py47LRlghX1+lg/S6ZmWqsNQitJqeGc0FShO8KYDRx/kJDWU6
 wsielpFlzMvdLMcGtSAjbXHOxHKn2XX679MLpPQyLX4nbqcg0D82wWiLXjDVG21q
 BzUD0Ihgu4knX1uKPJjnoD9/aS+a97GbwPxGeMgQe03tZPZptkjnNvOilxbJp+cp
 Rne66N81/ztfdsJyvFsGtNAHLlpu8JsnhQjH6RkUYrXgiM2ezp6UkiSmkPaVMvJJ
 tDkZXlr5HNLZYHj48AeGAmZ7Y/GuP7iB6YfrCBe5G0bxB25M6dVGqeEZCtbuaBd+
 HBn3twG6Mv+fcPrgT2+poM4zUF3yRF8y5jcCCNeenA1srib//fPc3aS0eCZjeEHT
 MhZ6VUiEMcS//S0yO/2zDfzoCvPOxBns8ofoYrTEsfntg/3CDnmGTv9UO0Fqnlmo
 uIIMljIxhfAKF7qMWuHtXjzxsLnmGqG3KrrvNY0ZUY+IgkiXCzvQwXo7ooO9TJby
 mJowUROYwcylD2F29+MSrXZ0Vxh0PeZFj9bZA9nPdfaSOpXO9/ZSbvDwocfBioC8
 utqqR68IqLUUTJZIhk/S4CqkcL48P0ayOyQVgcKUiwJhJ5WHZqI=
 =KRVy
 -----END PGP SIGNATURE-----

Merge tag 'i2c-for-6.11-final-but-missed-it' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux

Pull i2c fixes from Wolfram Sang:
 "The Aspeed driver tracks the controller's state (stop, pending, start,
  etc.). Previously, when the stop command was sent, the state was not
  updated. The fix ensures the driver's state is aligned with the device
  status.

  The Intel SCH driver receives a new look, and among the cleanups,
  there is a fix where, due to an oversight, an if/else statement was
  missing the else, causing it to move forward instead of exiting the
  function in case of an error.

  The Qualcomm GENI I2C driver adds the IRQF_NO_AUTOEN flag to the IRQ
  setup to prevent unwanted interrupts during probe.

  The Xilinx XPS controller fixes TX FIFO handling to avoid missed NAKs.
  Another fix ensures the controller is reinitialized when the bus
  appears busy"

* tag 'i2c-for-6.11-final-but-missed-it' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux:
  i2c: qcom-geni: Use IRQF_NO_AUTOEN flag in request_irq()
  i2c: isch: Add missed 'else'
  i2c: xiic: Try re-initialization on bus busy timeout
  i2c: xiic: Wait for TX empty to avoid missed TX NAKs
  i2c: aspeed: Update the stop sw state when the bus recovery occurs
This commit is contained in:
Linus Torvalds 2024-09-19 12:52:23 +02:00
commit 7f52bb9de5
4 changed files with 45 additions and 38 deletions

View File

@ -170,6 +170,13 @@ struct aspeed_i2c_bus {
static int aspeed_i2c_reset(struct aspeed_i2c_bus *bus);
/* precondition: bus.lock has been acquired. */
static void aspeed_i2c_do_stop(struct aspeed_i2c_bus *bus)
{
bus->master_state = ASPEED_I2C_MASTER_STOP;
writel(ASPEED_I2CD_M_STOP_CMD, bus->base + ASPEED_I2C_CMD_REG);
}
static int aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus)
{
unsigned long time_left, flags;
@ -187,7 +194,7 @@ static int aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus)
command);
reinit_completion(&bus->cmd_complete);
writel(ASPEED_I2CD_M_STOP_CMD, bus->base + ASPEED_I2C_CMD_REG);
aspeed_i2c_do_stop(bus);
spin_unlock_irqrestore(&bus->lock, flags);
time_left = wait_for_completion_timeout(
@ -390,13 +397,6 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus)
writel(command, bus->base + ASPEED_I2C_CMD_REG);
}
/* precondition: bus.lock has been acquired. */
static void aspeed_i2c_do_stop(struct aspeed_i2c_bus *bus)
{
bus->master_state = ASPEED_I2C_MASTER_STOP;
writel(ASPEED_I2CD_M_STOP_CMD, bus->base + ASPEED_I2C_CMD_REG);
}
/* precondition: bus.lock has been acquired. */
static void aspeed_i2c_next_msg_or_stop(struct aspeed_i2c_bus *bus)
{

View File

@ -99,8 +99,7 @@ static int sch_transaction(void)
if (retries > MAX_RETRIES) {
dev_err(&sch_adapter.dev, "SMBus Timeout!\n");
result = -ETIMEDOUT;
}
if (temp & 0x04) {
} else if (temp & 0x04) {
result = -EIO;
dev_dbg(&sch_adapter.dev, "Bus collision! SMBus may be "
"locked until next hard reset. (sorry!)\n");

View File

@ -818,15 +818,13 @@ static int geni_i2c_probe(struct platform_device *pdev)
init_completion(&gi2c->done);
spin_lock_init(&gi2c->lock);
platform_set_drvdata(pdev, gi2c);
ret = devm_request_irq(dev, gi2c->irq, geni_i2c_irq, 0,
ret = devm_request_irq(dev, gi2c->irq, geni_i2c_irq, IRQF_NO_AUTOEN,
dev_name(dev), gi2c);
if (ret) {
dev_err(dev, "Request_irq failed:%d: err:%d\n",
gi2c->irq, ret);
return ret;
}
/* Disable the interrupt so that the system can enter low-power mode */
disable_irq(gi2c->irq);
i2c_set_adapdata(&gi2c->adap, gi2c);
gi2c->adap.dev.parent = dev;
gi2c->adap.dev.of_node = dev->of_node;

View File

@ -772,14 +772,17 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
goto out;
}
xiic_fill_tx_fifo(i2c);
/* current message sent and there is space in the fifo */
if (!xiic_tx_space(i2c) && xiic_tx_fifo_space(i2c) >= 2) {
if (xiic_tx_space(i2c)) {
xiic_fill_tx_fifo(i2c);
} else {
/* current message fully written */
dev_dbg(i2c->adap.dev.parent,
"%s end of message sent, nmsgs: %d\n",
__func__, i2c->nmsgs);
if (i2c->nmsgs > 1) {
/* Don't move onto the next message until the TX FIFO empties,
* to ensure that a NAK is not missed.
*/
if (i2c->nmsgs > 1 && (pend & XIIC_INTR_TX_EMPTY_MASK)) {
i2c->nmsgs--;
i2c->tx_msg++;
xfer_more = 1;
@ -790,11 +793,7 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
"%s Got TX IRQ but no more to do...\n",
__func__);
}
} else if (!xiic_tx_space(i2c) && (i2c->nmsgs == 1))
/* current frame is sent and is last,
* make sure to disable tx half
*/
xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK);
}
}
if (pend & XIIC_INTR_BNB_MASK) {
@ -844,23 +843,11 @@ static int xiic_bus_busy(struct xiic_i2c *i2c)
return (sr & XIIC_SR_BUS_BUSY_MASK) ? -EBUSY : 0;
}
static int xiic_busy(struct xiic_i2c *i2c)
static int xiic_wait_not_busy(struct xiic_i2c *i2c)
{
int tries = 3;
int err;
if (i2c->tx_msg || i2c->rx_msg)
return -EBUSY;
/* In single master mode bus can only be busy, when in use by this
* driver. If the register indicates bus being busy for some reason we
* should ignore it, since bus will never be released and i2c will be
* stuck forever.
*/
if (i2c->singlemaster) {
return 0;
}
/* for instance if previous transfer was terminated due to TX error
* it might be that the bus is on it's way to become available
* give it at most 3 ms to wake
@ -1104,13 +1091,36 @@ static int xiic_start_xfer(struct xiic_i2c *i2c, struct i2c_msg *msgs, int num)
mutex_lock(&i2c->lock);
ret = xiic_busy(i2c);
if (ret) {
if (i2c->tx_msg || i2c->rx_msg) {
dev_err(i2c->adap.dev.parent,
"cannot start a transfer while busy\n");
ret = -EBUSY;
goto out;
}
/* In single master mode bus can only be busy, when in use by this
* driver. If the register indicates bus being busy for some reason we
* should ignore it, since bus will never be released and i2c will be
* stuck forever.
*/
if (!i2c->singlemaster) {
ret = xiic_wait_not_busy(i2c);
if (ret) {
/* If the bus is stuck in a busy state, such as due to spurious low
* pulses on the bus causing a false start condition to be detected,
* then try to recover by re-initializing the controller and check
* again if the bus is still busy.
*/
dev_warn(i2c->adap.dev.parent, "I2C bus busy timeout, reinitializing\n");
ret = xiic_reinit(i2c);
if (ret)
goto out;
ret = xiic_wait_not_busy(i2c);
if (ret)
goto out;
}
}
i2c->tx_msg = msgs;
i2c->rx_msg = NULL;
i2c->nmsgs = num;