aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorDaniel Kurtz <djkurtz@chromium.org>2012-07-24 08:13:58 -0400
committerJean Delvare <khali@endymion.delvare>2012-07-24 08:13:58 -0400
commit636752bcb5177a301d0266270661581de8624828 (patch)
tree6277793c24520d0f08a126554e773605a4b4f2ac /drivers/i2c
parent6cad93c4bbd62ecfa2e1b3a95c1ac4f6f27764c7 (diff)
i2c-i801: Enable IRQ for SMBus transactions
Add a new 'feature' to i2c-i801 to enable using PCI interrupts. When the feature is enabled, then an isr is installed for the device's PCI IRQ. An I2C/SMBus transaction is always terminated by one of the following interrupt sources: FAILED, BUS_ERR, DEV_ERR, or on success: INTR. When the isr fires for one of these cases, it sets the ->status variable and wakes up the waitq. The waitq then saves off the status code, and clears ->status (in preparation for some future transaction). The SMBus controller generates an INTR irq at the end of each transaction where INTREN was set in the HST_CNT register. No locking is needed around accesses to priv->status since all writes to it are serialized: it is only ever set once in the isr at the end of a transaction, and cleared while no interrupts can occur. In addition, the I2C adapter lock guarantees that entire I2C transactions for a single adapter are always serialized. For this patch, the INTREN bit is set only for SMBus block, byte and word transactions, but not for I2C reads or writes. The use of the DS (BYTE_DONE) interrupt with byte-by-byte I2C transactions is implemented in a subsequent patch. The interrupt feature has only been enabled for COUGARPOINT hardware. In addition, it is disabled if SMBus is using the SMI# interrupt. Signed-off-by: Daniel Kurtz <djkurtz@chromium.org> Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-i801.c99
1 files changed, 95 insertions, 4 deletions
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index a1ce4e68b49a..bcce18dfcc39 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -60,10 +60,12 @@
60 Block process call transaction no 60 Block process call transaction no
61 I2C block read transaction yes (doesn't use the block buffer) 61 I2C block read transaction yes (doesn't use the block buffer)
62 Slave mode no 62 Slave mode no
63 Interrupt processing yes
63 64
64 See the file Documentation/i2c/busses/i2c-i801 for details. 65 See the file Documentation/i2c/busses/i2c-i801 for details.
65*/ 66*/
66 67
68#include <linux/interrupt.h>
67#include <linux/module.h> 69#include <linux/module.h>
68#include <linux/pci.h> 70#include <linux/pci.h>
69#include <linux/kernel.h> 71#include <linux/kernel.h>
@@ -76,6 +78,7 @@
76#include <linux/io.h> 78#include <linux/io.h>
77#include <linux/dmi.h> 79#include <linux/dmi.h>
78#include <linux/slab.h> 80#include <linux/slab.h>
81#include <linux/wait.h>
79 82
80/* I801 SMBus address offsets */ 83/* I801 SMBus address offsets */
81#define SMBHSTSTS(p) (0 + (p)->smba) 84#define SMBHSTSTS(p) (0 + (p)->smba)
@@ -91,8 +94,12 @@
91 94
92/* PCI Address Constants */ 95/* PCI Address Constants */
93#define SMBBAR 4 96#define SMBBAR 4
97#define SMBPCISTS 0x006
94#define SMBHSTCFG 0x040 98#define SMBHSTCFG 0x040
95 99
100/* Host status bits for SMBPCISTS */
101#define SMBPCISTS_INTS 0x08
102
96/* Host configuration bits for SMBHSTCFG */ 103/* Host configuration bits for SMBHSTCFG */
97#define SMBHSTCFG_HST_EN 1 104#define SMBHSTCFG_HST_EN 1
98#define SMBHSTCFG_SMB_SMI_EN 2 105#define SMBHSTCFG_SMB_SMI_EN 2
@@ -155,6 +162,10 @@ struct i801_priv {
155 unsigned char original_hstcfg; 162 unsigned char original_hstcfg;
156 struct pci_dev *pci_dev; 163 struct pci_dev *pci_dev;
157 unsigned int features; 164 unsigned int features;
165
166 /* isr processing */
167 wait_queue_head_t waitq;
168 u8 status;
158}; 169};
159 170
160static struct pci_driver i801_driver; 171static struct pci_driver i801_driver;
@@ -163,6 +174,7 @@ static struct pci_driver i801_driver;
163#define FEATURE_BLOCK_BUFFER (1 << 1) 174#define FEATURE_BLOCK_BUFFER (1 << 1)
164#define FEATURE_BLOCK_PROC (1 << 2) 175#define FEATURE_BLOCK_PROC (1 << 2)
165#define FEATURE_I2C_BLOCK_READ (1 << 3) 176#define FEATURE_I2C_BLOCK_READ (1 << 3)
177#define FEATURE_IRQ (1 << 4)
166/* Not really a feature, but it's convenient to handle it as such */ 178/* Not really a feature, but it's convenient to handle it as such */
167#define FEATURE_IDF (1 << 15) 179#define FEATURE_IDF (1 << 15)
168 180
@@ -171,6 +183,7 @@ static const char *i801_feature_names[] = {
171 "Block buffer", 183 "Block buffer",
172 "Block process call", 184 "Block process call",
173 "I2C block read", 185 "I2C block read",
186 "Interrupt",
174}; 187};
175 188
176static unsigned int disable_features; 189static unsigned int disable_features;
@@ -215,7 +228,12 @@ static int i801_check_post(struct i801_priv *priv, int status)
215{ 228{
216 int result = 0; 229 int result = 0;
217 230
218 /* If the SMBus is still busy, we give up */ 231 /*
232 * If the SMBus is still busy, we give up
233 * Note: This timeout condition only happens when using polling
234 * transactions. For interrupt operation, NAK/timeout is indicated by
235 * DEV_ERR.
236 */
219 if (unlikely(status < 0)) { 237 if (unlikely(status < 0)) {
220 dev_err(&priv->pci_dev->dev, "Transaction timeout\n"); 238 dev_err(&priv->pci_dev->dev, "Transaction timeout\n");
221 /* try to stop the current command */ 239 /* try to stop the current command */
@@ -305,6 +323,14 @@ static int i801_transaction(struct i801_priv *priv, int xact)
305 if (result < 0) 323 if (result < 0)
306 return result; 324 return result;
307 325
326 if (priv->features & FEATURE_IRQ) {
327 outb_p(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START,
328 SMBHSTCNT(priv));
329 wait_event(priv->waitq, (status = priv->status));
330 priv->status = 0;
331 return i801_check_post(priv, status);
332 }
333
308 /* the current contents of SMBHSTCNT can be overwritten, since PEC, 334 /* the current contents of SMBHSTCNT can be overwritten, since PEC,
309 * SMBSCMD are passed in xact */ 335 * SMBSCMD are passed in xact */
310 outb_p(xact | SMBHSTCNT_START, SMBHSTCNT(priv)); 336 outb_p(xact | SMBHSTCNT_START, SMBHSTCNT(priv));
@@ -348,6 +374,44 @@ static int i801_block_transaction_by_block(struct i801_priv *priv,
348} 374}
349 375
350/* 376/*
377 * i801 signals transaction completion with one of these interrupts:
378 * INTR - Success
379 * DEV_ERR - Invalid command, NAK or communication timeout
380 * BUS_ERR - SMI# transaction collision
381 * FAILED - transaction was canceled due to a KILL request
382 * When any of these occur, update ->status and wake up the waitq.
383 * ->status must be cleared before kicking off the next transaction.
384 */
385static irqreturn_t i801_isr(int irq, void *dev_id)
386{
387 struct i801_priv *priv = dev_id;
388 u16 pcists;
389 u8 status;
390
391 /* Confirm this is our interrupt */
392 pci_read_config_word(priv->pci_dev, SMBPCISTS, &pcists);
393 if (!(pcists & SMBPCISTS_INTS))
394 return IRQ_NONE;
395
396 status = inb_p(SMBHSTSTS(priv));
397 if (status != 0x42)
398 dev_dbg(&priv->pci_dev->dev, "irq: status = %02x\n", status);
399
400 /*
401 * Clear irq sources and report transaction result.
402 * ->status must be cleared before the next transaction is started.
403 */
404 status &= SMBHSTSTS_INTR | STATUS_ERROR_FLAGS;
405 if (status) {
406 outb_p(status, SMBHSTSTS(priv));
407 priv->status |= status;
408 wake_up(&priv->waitq);
409 }
410
411 return IRQ_HANDLED;
412}
413
414/*
351 * For "byte-by-byte" block transactions: 415 * For "byte-by-byte" block transactions:
352 * I2C write uses cmd=I801_BLOCK_DATA, I2C_EN=1 416 * I2C write uses cmd=I801_BLOCK_DATA, I2C_EN=1
353 * I2C read uses cmd=I801_I2C_BLOCK_DATA 417 * I2C read uses cmd=I801_I2C_BLOCK_DATA
@@ -799,6 +863,10 @@ static int __devinit i801_probe(struct pci_dev *dev,
799 break; 863 break;
800 } 864 }
801 865
866 /* IRQ processing only tested on CougarPoint PCH */
867 if (dev->device == PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS)
868 priv->features |= FEATURE_IRQ;
869
802 /* Disable features on user request */ 870 /* Disable features on user request */
803 for (i = 0; i < ARRAY_SIZE(i801_feature_names); i++) { 871 for (i = 0; i < ARRAY_SIZE(i801_feature_names); i++) {
804 if (priv->features & disable_features & (1 << i)) 872 if (priv->features & disable_features & (1 << i))
@@ -846,16 +914,31 @@ static int __devinit i801_probe(struct pci_dev *dev,
846 } 914 }
847 pci_write_config_byte(priv->pci_dev, SMBHSTCFG, temp); 915 pci_write_config_byte(priv->pci_dev, SMBHSTCFG, temp);
848 916
849 if (temp & SMBHSTCFG_SMB_SMI_EN) 917 if (temp & SMBHSTCFG_SMB_SMI_EN) {
850 dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n"); 918 dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n");
851 else 919 /* Disable SMBus interrupt feature if SMBus using SMI# */
920 priv->features &= ~FEATURE_IRQ;
921 } else {
852 dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n"); 922 dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n");
923 }
853 924
854 /* Clear special mode bits */ 925 /* Clear special mode bits */
855 if (priv->features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER)) 926 if (priv->features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER))
856 outb_p(inb_p(SMBAUXCTL(priv)) & 927 outb_p(inb_p(SMBAUXCTL(priv)) &
857 ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv)); 928 ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
858 929
930 if (priv->features & FEATURE_IRQ) {
931 init_waitqueue_head(&priv->waitq);
932
933 err = request_irq(dev->irq, i801_isr, IRQF_SHARED,
934 i801_driver.name, priv);
935 if (err) {
936 dev_err(&dev->dev, "Failed to allocate irq %d: %d\n",
937 dev->irq, err);
938 goto exit_release;
939 }
940 }
941
859 /* set up the sysfs linkage to our parent device */ 942 /* set up the sysfs linkage to our parent device */
860 priv->adapter.dev.parent = &dev->dev; 943 priv->adapter.dev.parent = &dev->dev;
861 944
@@ -867,14 +950,18 @@ static int __devinit i801_probe(struct pci_dev *dev,
867 err = i2c_add_adapter(&priv->adapter); 950 err = i2c_add_adapter(&priv->adapter);
868 if (err) { 951 if (err) {
869 dev_err(&dev->dev, "Failed to add SMBus adapter\n"); 952 dev_err(&dev->dev, "Failed to add SMBus adapter\n");
870 goto exit_release; 953 goto exit_free_irq;
871 } 954 }
872 955
873 i801_probe_optional_slaves(priv); 956 i801_probe_optional_slaves(priv);
874 957
875 pci_set_drvdata(dev, priv); 958 pci_set_drvdata(dev, priv);
959
876 return 0; 960 return 0;
877 961
962exit_free_irq:
963 if (priv->features & FEATURE_IRQ)
964 free_irq(dev->irq, priv);
878exit_release: 965exit_release:
879 pci_release_region(dev, SMBBAR); 966 pci_release_region(dev, SMBBAR);
880exit: 967exit:
@@ -888,7 +975,11 @@ static void __devexit i801_remove(struct pci_dev *dev)
888 975
889 i2c_del_adapter(&priv->adapter); 976 i2c_del_adapter(&priv->adapter);
890 pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); 977 pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
978
979 if (priv->features & FEATURE_IRQ)
980 free_irq(dev->irq, priv);
891 pci_release_region(dev, SMBBAR); 981 pci_release_region(dev, SMBBAR);
982
892 pci_set_drvdata(dev, NULL); 983 pci_set_drvdata(dev, NULL);
893 kfree(priv); 984 kfree(priv);
894 /* 985 /*