aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/i2c/busses/i2c-i801.c319
1 files changed, 175 insertions, 144 deletions
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 1fe30da653c3..56883f48c2e4 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -3,6 +3,8 @@
3 Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker 3 Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
4 <mdsxyz123@yahoo.com> 4 <mdsxyz123@yahoo.com>
5 Copyright (C) 2007, 2008 Jean Delvare <khali@linux-fr.org> 5 Copyright (C) 2007, 2008 Jean Delvare <khali@linux-fr.org>
6 Copyright (C) 2010 Intel Corporation,
7 David Woodhouse <dwmw2@infradead.org>
6 8
7 This program is free software; you can redistribute it and/or modify 9 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by 10 it under the terms of the GNU General Public License as published by
@@ -55,8 +57,6 @@
55 See the file Documentation/i2c/busses/i2c-i801 for details. 57 See the file Documentation/i2c/busses/i2c-i801 for details.
56*/ 58*/
57 59
58/* Note: we assume there can only be one I801, with one SMBus interface */
59
60#include <linux/module.h> 60#include <linux/module.h>
61#include <linux/pci.h> 61#include <linux/pci.h>
62#include <linux/kernel.h> 62#include <linux/kernel.h>
@@ -70,16 +70,16 @@
70#include <linux/dmi.h> 70#include <linux/dmi.h>
71 71
72/* I801 SMBus address offsets */ 72/* I801 SMBus address offsets */
73#define SMBHSTSTS (0 + i801_smba) 73#define SMBHSTSTS(p) (0 + (p)->smba)
74#define SMBHSTCNT (2 + i801_smba) 74#define SMBHSTCNT(p) (2 + (p)->smba)
75#define SMBHSTCMD (3 + i801_smba) 75#define SMBHSTCMD(p) (3 + (p)->smba)
76#define SMBHSTADD (4 + i801_smba) 76#define SMBHSTADD(p) (4 + (p)->smba)
77#define SMBHSTDAT0 (5 + i801_smba) 77#define SMBHSTDAT0(p) (5 + (p)->smba)
78#define SMBHSTDAT1 (6 + i801_smba) 78#define SMBHSTDAT1(p) (6 + (p)->smba)
79#define SMBBLKDAT (7 + i801_smba) 79#define SMBBLKDAT(p) (7 + (p)->smba)
80#define SMBPEC (8 + i801_smba) /* ICH3 and later */ 80#define SMBPEC(p) (8 + (p)->smba) /* ICH3 and later */
81#define SMBAUXSTS (12 + i801_smba) /* ICH4 and later */ 81#define SMBAUXSTS(p) (12 + (p)->smba) /* ICH4 and later */
82#define SMBAUXCTL (13 + i801_smba) /* ICH4 and later */ 82#define SMBAUXCTL(p) (13 + (p)->smba) /* ICH4 and later */
83 83
84/* PCI Address Constants */ 84/* PCI Address Constants */
85#define SMBBAR 4 85#define SMBBAR 4
@@ -128,16 +128,20 @@
128 SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | \ 128 SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | \
129 SMBHSTSTS_INTR) 129 SMBHSTSTS_INTR)
130 130
131static unsigned long i801_smba; 131struct i801_priv {
132static unsigned char i801_original_hstcfg; 132 struct i2c_adapter adapter;
133 unsigned long smba;
134 unsigned char original_hstcfg;
135 struct pci_dev *pci_dev;
136 unsigned int features;
137};
138
133static struct pci_driver i801_driver; 139static struct pci_driver i801_driver;
134static struct pci_dev *I801_dev;
135 140
136#define FEATURE_SMBUS_PEC (1 << 0) 141#define FEATURE_SMBUS_PEC (1 << 0)
137#define FEATURE_BLOCK_BUFFER (1 << 1) 142#define FEATURE_BLOCK_BUFFER (1 << 1)
138#define FEATURE_BLOCK_PROC (1 << 2) 143#define FEATURE_BLOCK_PROC (1 << 2)
139#define FEATURE_I2C_BLOCK_READ (1 << 3) 144#define FEATURE_I2C_BLOCK_READ (1 << 3)
140static unsigned int i801_features;
141 145
142static const char *i801_feature_names[] = { 146static const char *i801_feature_names[] = {
143 "SMBus PEC", 147 "SMBus PEC",
@@ -152,24 +156,24 @@ MODULE_PARM_DESC(disable_features, "Disable selected driver features");
152 156
153/* Make sure the SMBus host is ready to start transmitting. 157/* Make sure the SMBus host is ready to start transmitting.
154 Return 0 if it is, -EBUSY if it is not. */ 158 Return 0 if it is, -EBUSY if it is not. */
155static int i801_check_pre(void) 159static int i801_check_pre(struct i801_priv *priv)
156{ 160{
157 int status; 161 int status;
158 162
159 status = inb_p(SMBHSTSTS); 163 status = inb_p(SMBHSTSTS(priv));
160 if (status & SMBHSTSTS_HOST_BUSY) { 164 if (status & SMBHSTSTS_HOST_BUSY) {
161 dev_err(&I801_dev->dev, "SMBus is busy, can't use it!\n"); 165 dev_err(&priv->pci_dev->dev, "SMBus is busy, can't use it!\n");
162 return -EBUSY; 166 return -EBUSY;
163 } 167 }
164 168
165 status &= STATUS_FLAGS; 169 status &= STATUS_FLAGS;
166 if (status) { 170 if (status) {
167 dev_dbg(&I801_dev->dev, "Clearing status flags (%02x)\n", 171 dev_dbg(&priv->pci_dev->dev, "Clearing status flags (%02x)\n",
168 status); 172 status);
169 outb_p(status, SMBHSTSTS); 173 outb_p(status, SMBHSTSTS(priv));
170 status = inb_p(SMBHSTSTS) & STATUS_FLAGS; 174 status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS;
171 if (status) { 175 if (status) {
172 dev_err(&I801_dev->dev, 176 dev_err(&priv->pci_dev->dev,
173 "Failed clearing status flags (%02x)\n", 177 "Failed clearing status flags (%02x)\n",
174 status); 178 status);
175 return -EBUSY; 179 return -EBUSY;
@@ -180,48 +184,50 @@ static int i801_check_pre(void)
180} 184}
181 185
182/* Convert the status register to an error code, and clear it. */ 186/* Convert the status register to an error code, and clear it. */
183static int i801_check_post(int status, int timeout) 187static int i801_check_post(struct i801_priv *priv, int status, int timeout)
184{ 188{
185 int result = 0; 189 int result = 0;
186 190
187 /* If the SMBus is still busy, we give up */ 191 /* If the SMBus is still busy, we give up */
188 if (timeout) { 192 if (timeout) {
189 dev_err(&I801_dev->dev, "Transaction timeout\n"); 193 dev_err(&priv->pci_dev->dev, "Transaction timeout\n");
190 /* try to stop the current command */ 194 /* try to stop the current command */
191 dev_dbg(&I801_dev->dev, "Terminating the current operation\n"); 195 dev_dbg(&priv->pci_dev->dev, "Terminating the current operation\n");
192 outb_p(inb_p(SMBHSTCNT) | SMBHSTCNT_KILL, SMBHSTCNT); 196 outb_p(inb_p(SMBHSTCNT(priv)) | SMBHSTCNT_KILL,
197 SMBHSTCNT(priv));
193 msleep(1); 198 msleep(1);
194 outb_p(inb_p(SMBHSTCNT) & (~SMBHSTCNT_KILL), SMBHSTCNT); 199 outb_p(inb_p(SMBHSTCNT(priv)) & (~SMBHSTCNT_KILL),
200 SMBHSTCNT(priv));
195 201
196 /* Check if it worked */ 202 /* Check if it worked */
197 status = inb_p(SMBHSTSTS); 203 status = inb_p(SMBHSTSTS(priv));
198 if ((status & SMBHSTSTS_HOST_BUSY) || 204 if ((status & SMBHSTSTS_HOST_BUSY) ||
199 !(status & SMBHSTSTS_FAILED)) 205 !(status & SMBHSTSTS_FAILED))
200 dev_err(&I801_dev->dev, 206 dev_err(&priv->pci_dev->dev,
201 "Failed terminating the transaction\n"); 207 "Failed terminating the transaction\n");
202 outb_p(STATUS_FLAGS, SMBHSTSTS); 208 outb_p(STATUS_FLAGS, SMBHSTSTS(priv));
203 return -ETIMEDOUT; 209 return -ETIMEDOUT;
204 } 210 }
205 211
206 if (status & SMBHSTSTS_FAILED) { 212 if (status & SMBHSTSTS_FAILED) {
207 result = -EIO; 213 result = -EIO;
208 dev_err(&I801_dev->dev, "Transaction failed\n"); 214 dev_err(&priv->pci_dev->dev, "Transaction failed\n");
209 } 215 }
210 if (status & SMBHSTSTS_DEV_ERR) { 216 if (status & SMBHSTSTS_DEV_ERR) {
211 result = -ENXIO; 217 result = -ENXIO;
212 dev_dbg(&I801_dev->dev, "No response\n"); 218 dev_dbg(&priv->pci_dev->dev, "No response\n");
213 } 219 }
214 if (status & SMBHSTSTS_BUS_ERR) { 220 if (status & SMBHSTSTS_BUS_ERR) {
215 result = -EAGAIN; 221 result = -EAGAIN;
216 dev_dbg(&I801_dev->dev, "Lost arbitration\n"); 222 dev_dbg(&priv->pci_dev->dev, "Lost arbitration\n");
217 } 223 }
218 224
219 if (result) { 225 if (result) {
220 /* Clear error flags */ 226 /* Clear error flags */
221 outb_p(status & STATUS_FLAGS, SMBHSTSTS); 227 outb_p(status & STATUS_FLAGS, SMBHSTSTS(priv));
222 status = inb_p(SMBHSTSTS) & STATUS_FLAGS; 228 status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS;
223 if (status) { 229 if (status) {
224 dev_warn(&I801_dev->dev, "Failed clearing status " 230 dev_warn(&priv->pci_dev->dev, "Failed clearing status "
225 "flags at end of transaction (%02x)\n", 231 "flags at end of transaction (%02x)\n",
226 status); 232 status);
227 } 233 }
@@ -230,86 +236,88 @@ static int i801_check_post(int status, int timeout)
230 return result; 236 return result;
231} 237}
232 238