diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-14 23:54:40 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-14 23:54:40 +0300 |
commit | 96895199c8648db475b38aac5fe6a04ec14a49c4 (patch) | |
tree | 3cb2a2a68a4750de20cf3deddd4a897189164ea9 /drivers/i2c/busses/i2c-i801.c | |
parent | 8fd9589ced9a4ab1cf23296fa1c17d07e883f734 (diff) | |
parent | 6cf710d47633be388e831713738626d1911163c8 (diff) | |
download | linux-96895199c8648db475b38aac5fe6a04ec14a49c4.tar.xz |
Merge branch 'i2c/for-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang:
"For 3.19, the I2C subsystem has to offer special candy this time.
Right in time for Christmas :)
- I2C slave framework: finally, a generic mechanism for Linux being
an I2C slave (if the bus driver supports that). Docs are still
missing but will come later this cycle, the code is good enough to
go.
- I2C muxes represent their topology in sysfs much more detailed.
This will help users to navigate around much easier.
- irq population of i2c clients is now done at probe time, not device
creation time, to have better support for deferred probing.
- new drivers for Imagination SCB, Amlogic Meson
- DMA support added for Freescale IMX, Renesas SHMobile
- slightly bigger driver updates to OMAP, i801, AT91, and rk3x
(mostly quirk handling, timing updates, and using better kernel
interfaces)
- eeprom driver can now write with byte-access (very slow, but OK to
have)
- and the bunch of smaller fixes, cleanups, ID updates..."
* 'i2c/for-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (56 commits)
i2c: sh_mobile: remove unneeded DMA mask
i2c: rcar: add slave support
i2c: slave-eeprom: add eeprom simulator driver
i2c: core changes for slave support
MAINTAINERS: add I2C dt bindings also to I2C realm
i2c: designware: Fix falling time bindings doc
i2c: davinci: switch to use platform_get_irq
Documentation: i2c: Use PM ops instead of legacy suspend/resume
i2c: sh_mobile: optimize irq entry
i2c: pxa: add support for SCCB devices
omap: i2c: don't check bus state IP rev3.3 and earlier
i2c: s3c2410: Handle i2c sys_cfg register in i2c driver
i2c: rk3x: add Kconfig dependency on COMMON_CLK
i2c: omap: add notes related to i2c multimaster mode
i2c: omap: don't reset controller if Arbitration Lost detected
i2c: omap: implement workaround for handling invalid BB-bit values
i2c: omap: cleanup register definitions
i2c: rk3x: handle dynamic clock rate changes correctly
i2c: at91: enable probe deferring on dma channel request
i2c: at91: remove legacy DMA support
...
Diffstat (limited to 'drivers/i2c/busses/i2c-i801.c')
-rw-r--r-- | drivers/i2c/busses/i2c-i801.c | 57 |
1 files changed, 48 insertions, 9 deletions
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 6ab4f1cb21f3..8fafb254e42a 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -2,7 +2,7 @@ Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker <mdsxyz123@yahoo.com> - Copyright (C) 2007 - 2012 Jean Delvare <jdelvare@suse.de> + Copyright (C) 2007 - 2014 Jean Delvare <jdelvare@suse.de> Copyright (C) 2010 Intel Corporation, David Woodhouse <dwmw2@infradead.org> @@ -59,6 +59,7 @@ * Wildcat Point-LP (PCH) 0x9ca2 32 hard yes yes yes * BayTrail (SOC) 0x0f12 32 hard yes yes yes * Sunrise Point-H (PCH) 0xa123 32 hard yes yes yes + * Sunrise Point-LP (PCH) 0x9d23 32 hard yes yes yes * * Features supported by this driver: * Software PEC no @@ -109,12 +110,16 @@ /* PCI Address Constants */ #define SMBBAR 4 +#define SMBPCICTL 0x004 #define SMBPCISTS 0x006 #define SMBHSTCFG 0x040 /* Host status bits for SMBPCISTS */ #define SMBPCISTS_INTS 0x08 +/* Control bits for SMBPCICTL */ +#define SMBPCICTL_INTDIS 0x0400 + /* Host configuration bits for SMBHSTCFG */ #define SMBHSTCFG_HST_EN 1 #define SMBHSTCFG_SMB_SMI_EN 2 @@ -182,6 +187,7 @@ #define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS 0x9c22 #define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS 0x9ca2 #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS 0xa123 +#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS 0x9d23 struct i801_mux_config { char *gpio_chip; @@ -371,6 +377,7 @@ static int i801_transaction(struct i801_priv *priv, int xact) { int status; int result; + const struct i2c_adapter *adap = &priv->adapter; result = i801_check_pre(priv); if (result < 0) @@ -379,7 +386,14 @@ static int i801_transaction(struct i801_priv *priv, int xact) if (priv->features & FEATURE_IRQ) { outb_p(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START, SMBHSTCNT(priv)); - wait_event(priv->waitq, (status = priv->status)); + result = wait_event_timeout(priv->waitq, + (status = priv->status), + adap->timeout); + if (!result) { + status = -ETIMEDOUT; + dev_warn(&priv->pci_dev->dev, + "Timeout waiting for interrupt!\n"); + } priv->status = 0; return i801_check_post(priv, status); } @@ -493,9 +507,6 @@ static irqreturn_t i801_isr(int irq, void *dev_id) return IRQ_NONE; status = inb_p(SMBHSTSTS(priv)); - if (status != 0x42) - dev_dbg(&priv->pci_dev->dev, "irq: status = %02x\n", status); - if (status & SMBHSTSTS_BYTE_DONE) i801_isr_byte_done(priv); @@ -527,6 +538,7 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, int smbcmd; int status; int result; + const struct i2c_adapter *adap = &priv->adapter; result = i801_check_pre(priv); if (result < 0) @@ -555,7 +567,14 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, priv->data = &data->block[1]; outb_p(priv->cmd | SMBHSTCNT_START, SMBHSTCNT(priv)); - wait_event(priv->waitq, (status = priv->status)); + result = wait_event_timeout(priv->waitq, + (status = priv->status), + adap->timeout); + if (!result) { + status = -ETIMEDOUT; + dev_warn(&priv->pci_dev->dev, + "Timeout waiting for interrupt!\n"); + } priv->status = 0; return i801_check_post(priv, status); } @@ -829,6 +848,7 @@ static const struct pci_device_id i801_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS) }, { 0, } }; @@ -1212,6 +1232,25 @@ 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)); + /* Default timeout in interrupt mode: 200 ms */ + priv->adapter.timeout = HZ / 5; + + if (priv->features & FEATURE_IRQ) { + u16 pcictl, pcists; + + /* Complain if an interrupt is already pending */ + pci_read_config_word(priv->pci_dev, SMBPCISTS, &pcists); + if (pcists & SMBPCISTS_INTS) + dev_warn(&dev->dev, "An interrupt is pending!\n"); + + /* Check if interrupts have been disabled */ + pci_read_config_word(priv->pci_dev, SMBPCICTL, &pcictl); + if (pcictl & SMBPCICTL_INTDIS) { + dev_info(&dev->dev, "Interrupts are disabled\n"); + priv->features &= ~FEATURE_IRQ; + } + } + if (priv->features & FEATURE_IRQ) { init_waitqueue_head(&priv->waitq); @@ -1220,10 +1259,11 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) if (err) { dev_err(&dev->dev, "Failed to allocate irq %d: %d\n", dev->irq, err); - goto exit_release; + priv->features &= ~FEATURE_IRQ; } - dev_info(&dev->dev, "SMBus using PCI Interrupt\n"); } + dev_info(&dev->dev, "SMBus using %s\n", + priv->features & FEATURE_IRQ ? "PCI interrupt" : "polling"); /* set up the sysfs linkage to our parent device */ priv->adapter.dev.parent = &dev->dev; @@ -1250,7 +1290,6 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) exit_free_irq: if (priv->features & FEATURE_IRQ) free_irq(dev->irq, priv); -exit_release: pci_release_region(dev, SMBBAR); exit: kfree(priv); |