mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-02 01:37:17 -04:00
Merge branch 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/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
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 | \
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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));
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user