Skip to content

Commit

Permalink
Merge branch 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/…
Browse files Browse the repository at this point in the history
…kernel/git/wsa/linux

Pull i2c fixes from Wolfram Sang:
 "I2C has an interrupt storm fix for the i801, better timeout handling
  for the new virtio driver, and some documentation fixes this time"

* 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux:
  docs: i2c: smbus-protocol: mention the repeated start condition
  i2c: virtio: disable timeout handling
  i2c: i801: Fix interrupt storm from SMB_ALERT signal
  i2c: i801: Restore INTREN on unload
  dt-bindings: i2c: imx-lpi2c: Fix i.MX 8QM compatible matching
  • Loading branch information
Linus Torvalds committed Nov 26, 2021
2 parents 6b54698 + bed68f4 commit 80d7520
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 24 deletions.
5 changes: 3 additions & 2 deletions Documentation/devicetree/bindings/i2c/i2c-imx-lpi2c.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ properties:
oneOf:
- enum:
- fsl,imx7ulp-lpi2c
- fsl,imx8qm-lpi2c
- items:
- const: fsl,imx8qxp-lpi2c
- enum:
- fsl,imx8qxp-lpi2c
- fsl,imx8qm-lpi2c
- const: fsl,imx7ulp-lpi2c

reg:
Expand Down
14 changes: 8 additions & 6 deletions Documentation/i2c/smbus-protocol.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ Key to symbols

=============== =============================================================
S Start condition
Sr Repeated start condition, used to switch from write to
read mode.
P Stop condition
Rd/Wr (1 bit) Read/Write bit. Rd equals 1, Wr equals 0.
A, NA (1 bit) Acknowledge (ACK) and Not Acknowledge (NACK) bit
Expand Down Expand Up @@ -100,7 +102,7 @@ Implemented by i2c_smbus_read_byte_data()
This reads a single byte from a device, from a designated register.
The register is specified through the Comm byte::

S Addr Wr [A] Comm [A] S Addr Rd [A] [Data] NA P
S Addr Wr [A] Comm [A] Sr Addr Rd [A] [Data] NA P

Functionality flag: I2C_FUNC_SMBUS_READ_BYTE_DATA

Expand All @@ -114,7 +116,7 @@ This operation is very like Read Byte; again, data is read from a
device, from a designated register that is specified through the Comm
byte. But this time, the data is a complete word (16 bits)::

S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P
S Addr Wr [A] Comm [A] Sr Addr Rd [A] [DataLow] A [DataHigh] NA P

Functionality flag: I2C_FUNC_SMBUS_READ_WORD_DATA

Expand Down Expand Up @@ -164,7 +166,7 @@ This command selects a device register (through the Comm byte), sends
16 bits of data to it, and reads 16 bits of data in return::

S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A]
S Addr Rd [A] [DataLow] A [DataHigh] NA P
Sr Addr Rd [A] [DataLow] A [DataHigh] NA P

Functionality flag: I2C_FUNC_SMBUS_PROC_CALL

Expand All @@ -181,7 +183,7 @@ of data is specified by the device in the Count byte.
::

S Addr Wr [A] Comm [A]
S Addr Rd [A] [Count] A [Data] A [Data] A ... A [Data] NA P
Sr Addr Rd [A] [Count] A [Data] A [Data] A ... A [Data] NA P

Functionality flag: I2C_FUNC_SMBUS_READ_BLOCK_DATA

Expand Down Expand Up @@ -212,7 +214,7 @@ This command selects a device register (through the Comm byte), sends
1 to 31 bytes of data to it, and reads 1 to 31 bytes of data in return::

S Addr Wr [A] Comm [A] Count [A] Data [A] ...
S Addr Rd [A] [Count] A [Data] ... A P
Sr Addr Rd [A] [Count] A [Data] ... A P

Functionality flag: I2C_FUNC_SMBUS_BLOCK_PROC_CALL

Expand Down Expand Up @@ -300,7 +302,7 @@ This command reads a block of bytes from a device, from a
designated register that is specified through the Comm byte::

S Addr Wr [A] Comm [A]
S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P
Sr Addr Rd [A] [Data] A [Data] A ... A [Data] NA P

Functionality flag: I2C_FUNC_SMBUS_READ_I2C_BLOCK

Expand Down
32 changes: 25 additions & 7 deletions drivers/i2c/busses/i2c-i801.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@
#define SMBSLVSTS_HST_NTFY_STS BIT(0)

/* Host Notify Command register bits */
#define SMBSLVCMD_SMBALERT_DISABLE BIT(2)
#define SMBSLVCMD_HST_NTFY_INTREN BIT(0)

#define STATUS_ERROR_FLAGS (SMBHSTSTS_FAILED | SMBHSTSTS_BUS_ERR | \
Expand Down Expand Up @@ -259,6 +260,7 @@ struct i801_priv {
struct i2c_adapter adapter;
unsigned long smba;
unsigned char original_hstcfg;
unsigned char original_hstcnt;
unsigned char original_slvcmd;
struct pci_dev *pci_dev;
unsigned int features;
Expand Down Expand Up @@ -641,12 +643,20 @@ static irqreturn_t i801_isr(int irq, void *dev_id)
i801_isr_byte_done(priv);

/*
* Clear irq sources and report transaction result.
* Clear remaining IRQ sources: Completion of last command, errors
* and the SMB_ALERT signal. SMB_ALERT status is set after signal
* assertion independently of the interrupt generation being blocked
* or not so clear it always when the status is set.
*/
status &= SMBHSTSTS_INTR | STATUS_ERROR_FLAGS | SMBHSTSTS_SMBALERT_STS;
if (status)
outb_p(status, SMBHSTSTS(priv));
status &= ~SMBHSTSTS_SMBALERT_STS; /* SMB_ALERT not reported */
/*
* Report transaction result.
* ->status must be cleared before the next transaction is started.
*/
status &= SMBHSTSTS_INTR | STATUS_ERROR_FLAGS;
if (status) {
outb_p(status, SMBHSTSTS(priv));
priv->status = status;
complete(&priv->done);
}
Expand Down Expand Up @@ -974,9 +984,13 @@ static void i801_enable_host_notify(struct i2c_adapter *adapter)
if (!(priv->features & FEATURE_HOST_NOTIFY))
return;

if (!(SMBSLVCMD_HST_NTFY_INTREN & priv->original_slvcmd))
outb_p(SMBSLVCMD_HST_NTFY_INTREN | priv->original_slvcmd,
SMBSLVCMD(priv));
/*
* Enable host notify interrupt and block the generation of interrupt
* from the SMB_ALERT signal because the driver does not support
* SMBus Alert.
*/
outb_p(SMBSLVCMD_HST_NTFY_INTREN | SMBSLVCMD_SMBALERT_DISABLE |
priv->original_slvcmd, SMBSLVCMD(priv));

/* clear Host Notify bit to allow a new notification */
outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv));
Expand Down Expand Up @@ -1805,7 +1819,8 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
outb_p(inb_p(SMBAUXCTL(priv)) &
~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));

/* Remember original Host Notify setting */
/* Remember original Interrupt and Host Notify settings */
priv->original_hstcnt = inb_p(SMBHSTCNT(priv)) & ~SMBHSTCNT_KILL;
if (priv->features & FEATURE_HOST_NOTIFY)
priv->original_slvcmd = inb_p(SMBSLVCMD(priv));

Expand Down Expand Up @@ -1869,6 +1884,7 @@ static void i801_remove(struct pci_dev *dev)
{
struct i801_priv *priv = pci_get_drvdata(dev);

outb_p(priv->original_hstcnt, SMBHSTCNT(priv));
i801_disable_host_notify(priv);
i801_del_mux(priv);
i2c_del_adapter(&priv->adapter);
Expand All @@ -1892,6 +1908,7 @@ static void i801_shutdown(struct pci_dev *dev)
struct i801_priv *priv = pci_get_drvdata(dev);

/* Restore config registers to avoid hard hang on some systems */
outb_p(priv->original_hstcnt, SMBHSTCNT(priv));
i801_disable_host_notify(priv);
pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
}
Expand All @@ -1901,6 +1918,7 @@ static int i801_suspend(struct device *dev)
{
struct i801_priv *priv = dev_get_drvdata(dev);

outb_p(priv->original_hstcnt, SMBHSTCNT(priv));
pci_write_config_byte(priv->pci_dev, SMBHSTCFG, priv->original_hstcfg);
return 0;
}
Expand Down
14 changes: 5 additions & 9 deletions drivers/i2c/busses/i2c-virtio.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,10 @@ static int virtio_i2c_prepare_reqs(struct virtqueue *vq,

static int virtio_i2c_complete_reqs(struct virtqueue *vq,
struct virtio_i2c_req *reqs,
struct i2c_msg *msgs, int num,
bool timedout)
struct i2c_msg *msgs, int num)
{
struct virtio_i2c_req *req;
bool failed = timedout;
bool failed = false;
unsigned int len;
int i, j = 0;

Expand All @@ -130,7 +129,7 @@ static int virtio_i2c_complete_reqs(struct virtqueue *vq,
j++;
}

return timedout ? -ETIMEDOUT : j;
return j;
}

static int virtio_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
Expand All @@ -139,7 +138,6 @@ static int virtio_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
struct virtio_i2c *vi = i2c_get_adapdata(adap);
struct virtqueue *vq = vi->vq;
struct virtio_i2c_req *reqs;
unsigned long time_left;
int count;

reqs = kcalloc(num, sizeof(*reqs), GFP_KERNEL);
Expand All @@ -162,11 +160,9 @@ static int virtio_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
reinit_completion(&vi->completion);
virtqueue_kick(vq);

time_left = wait_for_completion_timeout(&vi->completion, adap->timeout);
if (!time_left)
dev_err(&adap->dev, "virtio i2c backend timeout.\n");
wait_for_completion(&vi->completion);

count = virtio_i2c_complete_reqs(vq, reqs, msgs, count, !time_left);
count = virtio_i2c_complete_reqs(vq, reqs, msgs, count);

err_free:
kfree(reqs);
Expand Down

0 comments on commit 80d7520

Please sign in to comment.