diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-piix4.c')
-rw-r--r-- | drivers/i2c/busses/i2c-piix4.c | 73 |
1 files changed, 33 insertions, 40 deletions
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index ac9165968587..eaa9b387543e 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c | |||
@@ -1,6 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | piix4.c - Part of lm_sensors, Linux kernel modules for hardware | ||
3 | monitoring | ||
4 | Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl> and | 2 | Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl> and |
5 | Philip Edelbrock <phil@netroedge.com> | 3 | Philip Edelbrock <phil@netroedge.com> |
6 | 4 | ||
@@ -39,16 +37,10 @@ | |||
39 | #include <linux/i2c.h> | 37 | #include <linux/i2c.h> |
40 | #include <linux/init.h> | 38 | #include <linux/init.h> |
41 | #include <linux/dmi.h> | 39 | #include <linux/dmi.h> |
40 | #include <linux/acpi.h> | ||
42 | #include <asm/io.h> | 41 | #include <asm/io.h> |
43 | 42 | ||
44 | 43 | ||
45 | struct sd { | ||
46 | const unsigned short mfr; | ||
47 | const unsigned short dev; | ||
48 | const unsigned char fn; | ||
49 | const char *name; | ||
50 | }; | ||
51 | |||
52 | /* PIIX4 SMBus address offsets */ | 44 | /* PIIX4 SMBus address offsets */ |
53 | #define SMBHSTSTS (0 + piix4_smba) | 45 | #define SMBHSTSTS (0 + piix4_smba) |
54 | #define SMBHSLVSTS (1 + piix4_smba) | 46 | #define SMBHSLVSTS (1 + piix4_smba) |
@@ -101,8 +93,6 @@ MODULE_PARM_DESC(force_addr, | |||
101 | "Forcibly enable the PIIX4 at the given address. " | 93 | "Forcibly enable the PIIX4 at the given address. " |
102 | "EXTREMELY DANGEROUS!"); | 94 | "EXTREMELY DANGEROUS!"); |
103 | 95 | ||
104 | static int piix4_transaction(void); | ||
105 | |||
106 | static unsigned short piix4_smba; | 96 | static unsigned short piix4_smba; |
107 | static int srvrworks_csb5_delay; | 97 | static int srvrworks_csb5_delay; |
108 | static struct pci_driver piix4_driver; | 98 | static struct pci_driver piix4_driver; |
@@ -141,8 +131,6 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev, | |||
141 | { | 131 | { |
142 | unsigned char temp; | 132 | unsigned char temp; |
143 | 133 | ||
144 | dev_info(&PIIX4_dev->dev, "Found %s device\n", pci_name(PIIX4_dev)); | ||
145 | |||
146 | if ((PIIX4_dev->vendor == PCI_VENDOR_ID_SERVERWORKS) && | 134 | if ((PIIX4_dev->vendor == PCI_VENDOR_ID_SERVERWORKS) && |
147 | (PIIX4_dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5)) | 135 | (PIIX4_dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5)) |
148 | srvrworks_csb5_delay = 1; | 136 | srvrworks_csb5_delay = 1; |
@@ -172,17 +160,20 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev, | |||
172 | pci_read_config_word(PIIX4_dev, SMBBA, &piix4_smba); | 160 | pci_read_config_word(PIIX4_dev, SMBBA, &piix4_smba); |
173 | piix4_smba &= 0xfff0; | 161 | piix4_smba &= 0xfff0; |
174 | if(piix4_smba == 0) { | 162 | if(piix4_smba == 0) { |
175 | dev_err(&PIIX4_dev->dev, "SMB base address " | 163 | dev_err(&PIIX4_dev->dev, "SMBus base address " |
176 | "uninitialized - upgrade BIOS or use " | 164 | "uninitialized - upgrade BIOS or use " |
177 | "force_addr=0xaddr\n"); | 165 | "force_addr=0xaddr\n"); |
178 | return -ENODEV; | 166 | return -ENODEV; |
179 | } | 167 | } |
180 | } | 168 | } |
181 | 169 | ||
170 | if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) | ||
171 | return -EBUSY; | ||
172 | |||
182 | if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) { | 173 | if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) { |
183 | dev_err(&PIIX4_dev->dev, "SMB region 0x%x already in use!\n", | 174 | dev_err(&PIIX4_dev->dev, "SMBus region 0x%x already in use!\n", |
184 | piix4_smba); | 175 | piix4_smba); |
185 | return -ENODEV; | 176 | return -EBUSY; |
186 | } | 177 | } |
187 | 178 | ||
188 | pci_read_config_byte(PIIX4_dev, SMBHSTCFG, &temp); | 179 | pci_read_config_byte(PIIX4_dev, SMBHSTCFG, &temp); |
@@ -228,13 +219,13 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev, | |||
228 | "(or code out of date)!\n"); | 219 | "(or code out of date)!\n"); |
229 | 220 | ||
230 | pci_read_config_byte(PIIX4_dev, SMBREV, &temp); | 221 | pci_read_config_byte(PIIX4_dev, SMBREV, &temp); |
231 | dev_dbg(&PIIX4_dev->dev, "SMBREV = 0x%X\n", temp); | 222 | dev_info(&PIIX4_dev->dev, |
232 | dev_dbg(&PIIX4_dev->dev, "SMBA = 0x%X\n", piix4_smba); | 223 | "SMBus Host Controller at 0x%x, revision %d\n", |
224 | piix4_smba, temp); | ||
233 | 225 | ||
234 | return 0; | 226 | return 0; |
235 | } | 227 | } |
236 | 228 | ||
237 | /* Another internally used function */ | ||
238 | static int piix4_transaction(void) | 229 | static int piix4_transaction(void) |
239 | { | 230 | { |
240 | int temp; | 231 | int temp; |
@@ -253,7 +244,7 @@ static int piix4_transaction(void) | |||
253 | outb_p(temp, SMBHSTSTS); | 244 | outb_p(temp, SMBHSTSTS); |
254 | if ((temp = inb_p(SMBHSTSTS)) != 0x00) { | 245 | if ((temp = inb_p(SMBHSTSTS)) != 0x00) { |
255 | dev_err(&piix4_adapter.dev, "Failed! (%02x)\n", temp); | 246 | dev_err(&piix4_adapter.dev, "Failed! (%02x)\n", temp); |
256 | return -1; | 247 | return -EBUSY; |
257 | } else { | 248 | } else { |
258 | dev_dbg(&piix4_adapter.dev, "Successful!\n"); | 249 | dev_dbg(&piix4_adapter.dev, "Successful!\n"); |
259 | } | 250 | } |
@@ -275,23 +266,23 @@ static int piix4_transaction(void) | |||
275 | /* If the SMBus is still busy, we give up */ | 266 | /* If the SMBus is still busy, we give up */ |
276 | if (timeout >= MAX_TIMEOUT) { | 267 | if (timeout >= MAX_TIMEOUT) { |
277 | dev_err(&piix4_adapter.dev, "SMBus Timeout!\n"); | 268 | dev_err(&piix4_adapter.dev, "SMBus Timeout!\n"); |
278 | result = -1; | 269 | result = -ETIMEDOUT; |
279 | } | 270 | } |
280 | 271 | ||
281 | if (temp & 0x10) { | 272 | if (temp & 0x10) { |
282 | result = -1; | 273 | result = -EIO; |
283 | dev_err(&piix4_adapter.dev, "Error: Failed bus transaction\n"); | 274 | dev_err(&piix4_adapter.dev, "Error: Failed bus transaction\n"); |
284 | } | 275 | } |
285 | 276 | ||
286 | if (temp & 0x08) { | 277 | if (temp & 0x08) { |
287 | result = -1; | 278 | result = -EIO; |
288 | dev_dbg(&piix4_adapter.dev, "Bus collision! SMBus may be " | 279 | dev_dbg(&piix4_adapter.dev, "Bus collision! SMBus may be " |
289 | "locked until next hard reset. (sorry!)\n"); | 280 | "locked until next hard reset. (sorry!)\n"); |
290 | /* Clock stops and slave is stuck in mid-transmission */ | 281 | /* Clock stops and slave is stuck in mid-transmission */ |
291 | } | 282 | } |
292 | 283 | ||
293 | if (temp & 0x04) { | 284 | if (temp & 0x04) { |
294 | result = -1; | 285 | result = -ENXIO; |
295 | dev_dbg(&piix4_adapter.dev, "Error: no response!\n"); | 286 | dev_dbg(&piix4_adapter.dev, "Error: no response!\n"); |
296 | } | 287 | } |
297 | 288 | ||
@@ -309,31 +300,29 @@ static int piix4_transaction(void) | |||
309 | return result; | 300 | return result; |
310 | } | 301 | } |
311 | 302 | ||
312 | /* Return -1 on error. */ | 303 | /* Return negative errno on error. */ |
313 | static s32 piix4_access(struct i2c_adapter * adap, u16 addr, | 304 | static s32 piix4_access(struct i2c_adapter * adap, u16 addr, |
314 | unsigned short flags, char read_write, | 305 | unsigned short flags, char read_write, |
315 | u8 command, int size, union i2c_smbus_data * data) | 306 | u8 command, int size, union i2c_smbus_data * data) |
316 | { | 307 | { |
317 | int i, len; | 308 | int i, len; |
309 | int status; | ||
318 | 310 | ||
319 | switch (size) { | 311 | switch (size) { |
320 | case I2C_SMBUS_PROC_CALL: | ||
321 | dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n"); | ||
322 | return -1; | ||
323 | case I2C_SMBUS_QUICK: | 312 | case I2C_SMBUS_QUICK: |
324 | outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), | 313 | outb_p((addr << 1) | read_write, |
325 | SMBHSTADD); | 314 | SMBHSTADD); |
326 | size = PIIX4_QUICK; | 315 | size = PIIX4_QUICK; |
327 | break; | 316 | break; |
328 | case I2C_SMBUS_BYTE: | 317 | case I2C_SMBUS_BYTE: |
329 | outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), | 318 | outb_p((addr << 1) | read_write, |
330 | SMBHSTADD); | 319 | SMBHSTADD); |
331 | if (read_write == I2C_SMBUS_WRITE) | 320 | if (read_write == I2C_SMBUS_WRITE) |
332 | outb_p(command, SMBHSTCMD); | 321 | outb_p(command, SMBHSTCMD); |
333 | size = PIIX4_BYTE; | 322 | size = PIIX4_BYTE; |
334 | break; | 323 | break; |
335 | case I2C_SMBUS_BYTE_DATA: | 324 | case I2C_SMBUS_BYTE_DATA: |
336 | outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), | 325 | outb_p((addr << 1) | read_write, |
337 | SMBHSTADD); | 326 | SMBHSTADD); |
338 | outb_p(command, SMBHSTCMD); | 327 | outb_p(command, SMBHSTCMD); |
339 | if (read_write == I2C_SMBUS_WRITE) | 328 | if (read_write == I2C_SMBUS_WRITE) |
@@ -341,7 +330,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr, | |||
341 | size = PIIX4_BYTE_DATA; | 330 | size = PIIX4_BYTE_DATA; |
342 | break; | 331 | break; |
343 | case I2C_SMBUS_WORD_DATA: | 332 | case I2C_SMBUS_WORD_DATA: |
344 | outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), | 333 | outb_p((addr << 1) | read_write, |
345 | SMBHSTADD); | 334 | SMBHSTADD); |
346 | outb_p(command, SMBHSTCMD); | 335 | outb_p(command, SMBHSTCMD); |
347 | if (read_write == I2C_SMBUS_WRITE) { | 336 | if (read_write == I2C_SMBUS_WRITE) { |
@@ -351,15 +340,13 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr, | |||
351 | size = PIIX4_WORD_DATA; | 340 | size = PIIX4_WORD_DATA; |
352 | break; | 341 | break; |
353 | case I2C_SMBUS_BLOCK_DATA: | 342 | case I2C_SMBUS_BLOCK_DATA: |
354 | outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), | 343 | outb_p((addr << 1) | read_write, |
355 | SMBHSTADD); | 344 | SMBHSTADD); |
356 | outb_p(command, SMBHSTCMD); | 345 | outb_p(command, SMBHSTCMD); |
357 | if (read_write == I2C_SMBUS_WRITE) { | 346 | if (read_write == I2C_SMBUS_WRITE) { |
358 | len = data->block[0]; | 347 | len = data->block[0]; |
359 | if (len < 0) | 348 | if (len == 0 || len > I2C_SMBUS_BLOCK_MAX) |
360 | len = 0; | 349 | return -EINVAL; |
361 | if (len > 32) | ||
362 | len = 32; | ||
363 | outb_p(len, SMBHSTDAT0); | 350 | outb_p(len, SMBHSTDAT0); |
364 | i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ | 351 | i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ |
365 | for (i = 1; i <= len; i++) | 352 | for (i = 1; i <= len; i++) |
@@ -367,12 +354,16 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr, | |||
367 | } | 354 | } |
368 | size = PIIX4_BLOCK_DATA; | 355 | size = PIIX4_BLOCK_DATA; |
369 | break; | 356 | break; |
357 | default: | ||
358 | dev_warn(&adap->dev, "Unsupported transaction %d\n", size); | ||
359 | return -EOPNOTSUPP; | ||
370 | } | 360 | } |
371 | 361 | ||
372 | outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT); | 362 | outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT); |
373 | 363 | ||
374 | if (piix4_transaction()) /* Error in transaction */ | 364 | status = piix4_transaction(); |
375 | return -1; | 365 | if (status) |
366 | return status; | ||
376 | 367 | ||
377 | if ((read_write == I2C_SMBUS_WRITE) || (size == PIIX4_QUICK)) | 368 | if ((read_write == I2C_SMBUS_WRITE) || (size == PIIX4_QUICK)) |
378 | return 0; | 369 | return 0; |
@@ -388,6 +379,8 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr, | |||
388 | break; | 379 | break; |
389 | case PIIX4_BLOCK_DATA: | 380 | case PIIX4_BLOCK_DATA: |
390 | data->block[0] = inb_p(SMBHSTDAT0); | 381 | data->block[0] = inb_p(SMBHSTDAT0); |
382 | if (data->block[0] == 0 || data->block[0] > I2C_SMBUS_BLOCK_MAX) | ||
383 | return -EPROTO; | ||
391 | i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ | 384 | i = inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */ |
392 | for (i = 1; i <= data->block[0]; i++) | 385 | for (i = 1; i <= data->block[0]; i++) |
393 | data->block[i] = inb_p(SMBBLKDAT); | 386 | data->block[i] = inb_p(SMBBLKDAT); |
@@ -411,7 +404,7 @@ static const struct i2c_algorithm smbus_algorithm = { | |||
411 | static struct i2c_adapter piix4_adapter = { | 404 | static struct i2c_adapter piix4_adapter = { |
412 | .owner = THIS_MODULE, | 405 | .owner = THIS_MODULE, |
413 | .id = I2C_HW_SMBUS_PIIX4, | 406 | .id = I2C_HW_SMBUS_PIIX4, |
414 | .class = I2C_CLASS_HWMON, | 407 | .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, |
415 | .algo = &smbus_algorithm, | 408 | .algo = &smbus_algorithm, |
416 | }; | 409 | }; |
417 | 410 | ||