diff options
| -rw-r--r-- | drivers/i2c/busses/i2c-i801.c | 200 |
1 files changed, 102 insertions, 98 deletions
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 73bd8552734c..46aa41f73fdd 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>, | 4 | Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>, |
| 5 | Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker | 5 | Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker |
| 6 | <mdsxyz123@yahoo.com> | 6 | <mdsxyz123@yahoo.com> |
| 7 | Copyright (C) 2007 Jean Delvare <khali@linux-fr.org> | 7 | Copyright (C) 2007, 2008 Jean Delvare <khali@linux-fr.org> |
| 8 | 8 | ||
| 9 | 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 |
| 10 | 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 |
| @@ -121,6 +121,10 @@ | |||
| 121 | #define SMBHSTSTS_INTR 0x02 | 121 | #define SMBHSTSTS_INTR 0x02 |
| 122 | #define SMBHSTSTS_HOST_BUSY 0x01 | 122 | #define SMBHSTSTS_HOST_BUSY 0x01 |
| 123 | 123 | ||
| 124 | #define STATUS_FLAGS (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_FAILED | \ | ||
| 125 | SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | \ | ||
| 126 | SMBHSTSTS_INTR) | ||
| 127 | |||
| 124 | static unsigned long i801_smba; | 128 | static unsigned long i801_smba; |
| 125 | static unsigned char i801_original_hstcfg; | 129 | static unsigned char i801_original_hstcfg; |
| 126 | static struct pci_driver i801_driver; | 130 | static struct pci_driver i801_driver; |
| @@ -132,72 +136,114 @@ static struct pci_dev *I801_dev; | |||
| 132 | #define FEATURE_I2C_BLOCK_READ (1 << 3) | 136 | #define FEATURE_I2C_BLOCK_READ (1 << 3) |
| 133 | static unsigned int i801_features; | 137 | static unsigned int i801_features; |
| 134 | 138 | ||
| 135 | static int i801_transaction(int xact) | 139 | /* Make sure the SMBus host is ready to start transmitting. |
| 140 | Return 0 if it is, -EBUSY if it is not. */ | ||
| 141 | static int i801_check_pre(void) | ||
| 136 | { | 142 | { |
| 137 | int status; | 143 | int status; |
| 138 | int result = 0; | ||
| 139 | int timeout = 0; | ||
| 140 | 144 | ||
| 141 | /* Make sure the SMBus host is ready to start transmitting */ | 145 | status = inb_p(SMBHSTSTS); |
| 142 | /* 0x1f = Failed, Bus_Err, Dev_Err, Intr, Host_Busy */ | 146 | if (status & SMBHSTSTS_HOST_BUSY) { |
| 143 | if ((status = (0x1f & inb_p(SMBHSTSTS))) != 0x00) { | 147 | dev_err(&I801_dev->dev, "SMBus is busy, can't use it!\n"); |
| 144 | dev_dbg(&I801_dev->dev, "SMBus busy (%02x). Resetting...\n", | 148 | return -EBUSY; |
| 149 | } | ||
| 150 | |||
| 151 | status &= STATUS_FLAGS; | ||
| 152 | if (status) { | ||
| 153 | dev_dbg(&I801_dev->dev, "Clearing status flags (%02x)\n", | ||
| 145 | status); | 154 | status); |
| 146 | outb_p(status, SMBHSTSTS); | 155 | outb_p(status, SMBHSTSTS); |
| 147 | if ((status = (0x1f & inb_p(SMBHSTSTS))) != 0x00) { | 156 | status = inb_p(SMBHSTSTS) & STATUS_FLAGS; |
| 148 | dev_dbg(&I801_dev->dev, "Failed! (%02x)\n", status); | 157 | if (status) { |
| 158 | dev_err(&I801_dev->dev, | ||
| 159 | "Failed clearing status flags (%02x)\n", | ||
| 160 | status); | ||
| 149 | return -EBUSY; | 161 | return -EBUSY; |
| 150 | } else { | ||
| 151 | dev_dbg(&I801_dev->dev, "Successful!\n"); | ||
| 152 | } | 162 | } |
| 153 | } | 163 | } |
| 154 | 164 | ||
| 155 | /* the current contents of SMBHSTCNT can be overwritten, since PEC, | 165 | return 0; |
| 156 | * INTREN, SMBSCMD are passed in xact */ | 166 | } |
| 157 | outb_p(xact | I801_START, SMBHSTCNT); | ||
| 158 | 167 | ||
| 159 | /* We will always wait for a fraction of a second! */ | 168 | /* Convert the status register to an error code, and clear it. */ |
| 160 | do { | 169 | static int i801_check_post(int status, int timeout) |
| 161 | msleep(1); | 170 | { |
| 162 | status = inb_p(SMBHSTSTS); | 171 | int result = 0; |
| 163 | } while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_TIMEOUT)); | ||
| 164 | 172 | ||
| 165 | /* If the SMBus is still busy, we give up */ | 173 | /* If the SMBus is still busy, we give up */ |
| 166 | if (timeout >= MAX_TIMEOUT) { | 174 | if (timeout) { |
| 167 | dev_dbg(&I801_dev->dev, "SMBus Timeout!\n"); | 175 | dev_err(&I801_dev->dev, "Transaction timeout\n"); |
| 168 | result = -ETIMEDOUT; | ||
| 169 | /* try to stop the current command */ | 176 | /* try to stop the current command */ |
| 170 | dev_dbg(&I801_dev->dev, "Terminating the current operation\n"); | 177 | dev_dbg(&I801_dev->dev, "Terminating the current operation\n"); |
| 171 | outb_p(inb_p(SMBHSTCNT) | SMBHSTCNT_KILL, SMBHSTCNT); | 178 | outb_p(inb_p(SMBHSTCNT) | SMBHSTCNT_KILL, SMBHSTCNT); |
| 172 | msleep(1); | 179 | msleep(1); |
| 173 | outb_p(inb_p(SMBHSTCNT) & (~SMBHSTCNT_KILL), SMBHSTCNT); | 180 | outb_p(inb_p(SMBHSTCNT) & (~SMBHSTCNT_KILL), SMBHSTCNT); |
| 181 | |||
| 182 | /* Check if it worked */ | ||
| 183 | status = inb_p(SMBHSTSTS); | ||
| 184 | if ((status & SMBHSTSTS_HOST_BUSY) || | ||
| 185 | !(status & SMBHSTSTS_FAILED)) | ||
| 186 | dev_err(&I801_dev->dev, | ||
| 187 | "Failed terminating the transaction\n"); | ||
| 188 | outb_p(STATUS_FLAGS, SMBHSTSTS); | ||
| 189 | return -ETIMEDOUT; | ||
| 174 | } | 190 | } |
| 175 | 191 | ||
| 176 | if (status & SMBHSTSTS_FAILED) { | 192 | if (status & SMBHSTSTS_FAILED) { |
| 177 | result = -EIO; | 193 | result = -EIO; |
| 178 | dev_dbg(&I801_dev->dev, "Error: Failed bus transaction\n"); | 194 | dev_err(&I801_dev->dev, "Transaction failed\n"); |
| 195 | } | ||
| 196 | if (status & SMBHSTSTS_DEV_ERR) { | ||
| 197 | result = -ENXIO; | ||
| 198 | dev_dbg(&I801_dev->dev, "No response\n"); | ||
| 179 | } | 199 | } |
| 180 | |||
| 181 | if (status & SMBHSTSTS_BUS_ERR) { | 200 | if (status & SMBHSTSTS_BUS_ERR) { |
| 182 | result = -EAGAIN; | 201 | result = -EAGAIN; |
| 183 | dev_dbg(&I801_dev->dev, "Lost arbitration\n"); | 202 | dev_dbg(&I801_dev->dev, "Lost arbitration\n"); |
| 184 | } | 203 | } |
| 185 | 204 | ||
| 186 | if (status & SMBHSTSTS_DEV_ERR) { | 205 | if (result) { |
| 187 | result = -ENXIO; | 206 | /* Clear error flags */ |
| 188 | dev_dbg(&I801_dev->dev, "Error: no response!\n"); | 207 | outb_p(status & STATUS_FLAGS, SMBHSTSTS); |
| 208 | status = inb_p(SMBHSTSTS) & STATUS_FLAGS; | ||
| 209 | if (status) { | ||
| 210 | dev_warn(&I801_dev->dev, "Failed clearing status " | ||
| 211 | "flags at end of transaction (%02x)\n", | ||
| 212 | status); | ||
| 213 | } | ||
| 189 | } | 214 | } |
| 190 | 215 | ||
| 191 | if ((inb_p(SMBHSTSTS) & 0x1f) != 0x00) | ||
| 192 | outb_p(inb(SMBHSTSTS), SMBHSTSTS); | ||
| 193 | |||
| 194 | if ((status = (0x1f & inb_p(SMBHSTSTS))) != 0x00) { | ||
| 195 | dev_dbg(&I801_dev->dev, "Failed reset at end of transaction " | ||
| 196 | "(%02x)\n", status); | ||
| 197 | } | ||
| 198 | return result; | 216 | return result; |
| 199 | } | 217 | } |
| 200 | 218 | ||
| 219 | static int i801_transaction(int xact) | ||
| 220 | { | ||
| 221 | int status; | ||
| 222 | int result; | ||
| 223 | int timeout = 0; | ||
| 224 | |||
| 225 | result = i801_check_pre(); | ||
| 226 | if (result < 0) | ||
| 227 | return result; | ||
| 228 | |||
| 229 | /* the current contents of SMBHSTCNT can be overwritten, since PEC, | ||
| 230 | * INTREN, SMBSCMD are passed in xact */ | ||
| 231 | outb_p(xact | I801_START, SMBHSTCNT); | ||
| 232 | |||
| 233 | /* We will always wait for a fraction of a second! */ | ||
| 234 | do { | ||
| 235 | msleep(1); | ||
| 236 | status = inb_p(SMBHSTSTS); | ||
| 237 | } while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_TIMEOUT)); | ||
| 238 | |||
| 239 | result = i801_check_post(status, timeout >= MAX_TIMEOUT); | ||
| 240 | if (result < 0) | ||
| 241 | return result; | ||
| 242 | |||
| 243 | outb_p(SMBHSTSTS_INTR, SMBHSTSTS); | ||
| 244 | return 0; | ||
| 245 | } | ||
| 246 | |||
| 201 | /* wait for INTR bit as advised by Intel */ | 247 | /* wait for INTR bit as advised by Intel */ |
| 202 | static void i801_wait_hwpec(void) | 248 | static void i801_wait_hwpec(void) |
| 203 | { | 249 | { |
| @@ -256,9 +302,12 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data, | |||
| 256 | int i, len; | 302 | int i, len; |
| 257 | int smbcmd; | 303 | int smbcmd; |
| 258 | int status; | 304 | int status; |
| 259 | int result = 0; | 305 | int result; |
| 260 | int timeout; | 306 | int timeout; |
| 261 | unsigned char errmask; | 307 | |
| 308 | result = i801_check_pre(); | ||
| 309 | if (result < 0) | ||
| 310 | return result; | ||
| 262 | 311 | ||
| 263 | len = data->block[0]; | 312 | len = data->block[0]; |
| 264 | 313 | ||
| @@ -282,31 +331,6 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data, | |||
| 282 | } | 331 | } |
| 283 | outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT); | 332 | outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT); |
| 284 | 333 | ||
| 285 | /* Make sure the SMBus host is ready to start transmitting */ | ||
| 286 | status = inb_p(SMBHSTSTS); | ||
| 287 | if (i == 1) { | ||
| 288 | /* Erroneous conditions before transaction: | ||
| 289 | * Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */ | ||
| 290 | errmask = 0x9f; | ||
| 291 | } else { | ||
| 292 | /* Erroneous conditions during transaction: | ||
| 293 | * Failed, Bus_Err, Dev_Err, Intr */ | ||
| 294 | errmask = 0x1e; | ||
| 295 | } | ||
| 296 | if (status & errmask) { | ||
| 297 | dev_dbg(&I801_dev->dev, "SMBus busy (%02x). " | ||
| 298 | "Resetting...\n", status); | ||
| 299 | outb_p(status, SMBHSTSTS); | ||
| 300 | if (((status = inb_p(SMBHSTSTS)) & errmask) != 0x00) { | ||
| 301 | dev_err(&I801_dev->dev, | ||
| 302 | "Reset failed! (%02x)\n", status); | ||
| 303 | return -EBUSY; | ||
| 304 | } | ||
| 305 | if (i != 1) | ||
| 306 | /* if die in middle of block transaction, fail */ | ||
| 307 | return -EIO; | ||
| 308 | } | ||
| 309 | |||
| 310 | if (i == 1) | 334 | if (i == 1) |
| 311 | outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT); | 335 | outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT); |
| 312 | 336 | ||
| @@ -319,36 +343,23 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data, | |||
| 319 | while ((!(status & SMBHSTSTS_BYTE_DONE)) | 343 | while ((!(status & SMBHSTSTS_BYTE_DONE)) |
| 320 | && (timeout++ < MAX_TIMEOUT)); | 344 | && (timeout++ < MAX_TIMEOUT)); |
| 321 | 345 | ||
| 322 | /* If the SMBus is still busy, we give up */ | 346 | result = i801_check_post(status, timeout >= MAX_TIMEOUT); |
| 323 | if (timeout >= MAX_TIMEOUT) { | 347 | if (result < 0) |
| 324 | /* try to stop the current command */ | 348 | return result; |
| 325 | dev_dbg(&I801_dev->dev, "Terminating the current " | ||
| 326 | "operation\n"); | ||
| 327 | outb_p(inb_p(SMBHSTCNT) | SMBHSTCNT_KILL, SMBHSTCNT); | ||
| 328 | msleep(1); | ||
| 329 | outb_p(inb_p(SMBHSTCNT) & (~SMBHSTCNT_KILL), | ||
| 330 | SMBHSTCNT); | ||
| 331 | result = -ETIMEDOUT; | ||
| 332 | dev_dbg(&I801_dev->dev, "SMBus Timeout!\n"); | ||
| 333 | } | ||
| 334 | |||
| 335 | if (status & SMBHSTSTS_FAILED) { | ||
| 336 | result = -EIO; | ||
| 337 | dev_dbg(&I801_dev->dev, | ||
| 338 | "Error: Failed bus transaction\n"); | ||
| 339 | } else if (status & SMBHSTSTS_BUS_ERR) { | ||
| 340 | result = -EAGAIN; | ||
| 341 | dev_dbg(&I801_dev->dev, "Lost arbitration\n"); | ||
| 342 | } else if (status & SMBHSTSTS_DEV_ERR) { | ||
| 343 | result = -ENXIO; | ||
| 344 | dev_dbg(&I801_dev->dev, "Error: no response!\n"); | ||
| 345 | } | ||
| 346 | 349 | ||
| 347 | if (i == 1 && read_write == I2C_SMBUS_READ | 350 | if (i == 1 && read_write == I2C_SMBUS_READ |
| 348 | && command != I2C_SMBUS_I2C_BLOCK_DATA) { | 351 | && command != I2C_SMBUS_I2C_BLOCK_DATA) { |
| 349 | len = inb_p(SMBHSTDAT0); | 352 | len = inb_p(SMBHSTDAT0); |
| 350 | if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) | 353 | if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) { |
| 354 | dev_err(&I801_dev->dev, | ||
| 355 | "Illegal SMBus block read size %d\n", | ||
| 356 | len); | ||
| 357 | /* Recover */ | ||
| 358 | while (inb_p(SMBHSTSTS) & SMBHSTSTS_HOST_BUSY) | ||
| 359 | outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS); | ||
| 360 | outb_p(SMBHSTSTS_INTR, SMBHSTSTS); | ||
| 351 | return -EPROTO; | 361 | return -EPROTO; |
| 362 | } | ||
| 352 | data->block[0] = len; | 363 | data->block[0] = len; |
| 353 | } | 364 | } |
| 354 | 365 | ||
| @@ -357,19 +368,12 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data, | |||
| 357 | data->block[i] = inb_p(SMBBLKDAT); | 368 | data->block[i] = inb_p(SMBBLKDAT); |
| 358 | if (read_write == I2C_SMBUS_WRITE && i+1 <= len) | 369 | if (read_write == I2C_SMBUS_WRITE && i+1 <= len) |
| 359 | outb_p(data->block[i+1], SMBBLKDAT); | 370 | outb_p(data->block[i+1], SMBBLKDAT); |
| 360 | if ((status & 0x9e) != 0x00) | ||
| 361 | outb_p(status, SMBHSTSTS); /* signals SMBBLKDAT ready */ | ||
| 362 | 371 | ||
| 363 | if ((status = (0x1e & inb_p(SMBHSTSTS))) != 0x00) { | 372 | /* signals SMBBLKDAT ready */ |
| 364 | dev_dbg(&I801_dev->dev, | 373 | outb_p(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR, SMBHSTSTS); |
| 365 | "Bad status (%02x) at end of transaction\n", | ||
| 366 | status); | ||
| 367 | } | ||
| 368 | |||
| 369 | if (result < 0) | ||
| 370 | return result; | ||
| 371 | } | 374 | } |
| 372 | return result; | 375 | |
| 376 | return 0; | ||
| 373 | } | 377 | } |
| 374 | 378 | ||
| 375 | static int i801_set_block_buffer_mode(void) | 379 | static int i801_set_block_buffer_mode(void) |
