blob: 94a30f5de776b02306c26b855e12fa74f18c6651 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Jean Delvare455f3322006-06-12 21:52:02 +02002 i2c-i801.c - Part of lm_sensors, Linux kernel modules for hardware
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 monitoring
4 Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>,
5 Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
6 <mdsxyz123@yahoo.com>
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21*/
22
23/*
24 SUPPORTED DEVICES PCI ID
25 82801AA 2413
26 82801AB 2423
27 82801BA 2443
28 82801CA/CAM 2483
29 82801DB 24C3 (HW PEC supported, 32 byte buffer not supported)
30 82801EB 24D3 (HW PEC supported, 32 byte buffer not supported)
31 6300ESB 25A4
32 ICH6 266A
33 ICH7 27DA
Jason Gastonb0a70b52005-04-16 15:24:45 -070034 ESB2 269B
Jason Gaston8254fc42006-01-09 10:58:08 -080035 ICH8 283E
Linus Torvalds1da177e2005-04-16 15:20:36 -070036 This driver supports several versions of Intel's I/O Controller Hubs (ICH).
37 For SMBus support, they are similar to the PIIX4 and are part
38 of Intel's '810' and other chipsets.
Jean Delvare455f3322006-06-12 21:52:02 +020039 See the file Documentation/i2c/busses/i2c-i801 for details.
Linus Torvalds1da177e2005-04-16 15:20:36 -070040 I2C Block Read and Process Call are not supported.
41*/
42
43/* Note: we assume there can only be one I801, with one SMBus interface */
44
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#include <linux/module.h>
46#include <linux/pci.h>
47#include <linux/kernel.h>
48#include <linux/stddef.h>
49#include <linux/delay.h>
50#include <linux/sched.h>
51#include <linux/ioport.h>
52#include <linux/init.h>
53#include <linux/i2c.h>
54#include <asm/io.h>
55
Linus Torvalds1da177e2005-04-16 15:20:36 -070056/* I801 SMBus address offsets */
57#define SMBHSTSTS (0 + i801_smba)
58#define SMBHSTCNT (2 + i801_smba)
59#define SMBHSTCMD (3 + i801_smba)
60#define SMBHSTADD (4 + i801_smba)
61#define SMBHSTDAT0 (5 + i801_smba)
62#define SMBHSTDAT1 (6 + i801_smba)
63#define SMBBLKDAT (7 + i801_smba)
64#define SMBPEC (8 + i801_smba) /* ICH4 only */
65#define SMBAUXSTS (12 + i801_smba) /* ICH4 only */
66#define SMBAUXCTL (13 + i801_smba) /* ICH4 only */
67
68/* PCI Address Constants */
Jean Delvare6dcc19d2006-06-12 21:53:02 +020069#define SMBBAR 4
Linus Torvalds1da177e2005-04-16 15:20:36 -070070#define SMBHSTCFG 0x040
71#define SMBREV 0x008
72
73/* Host configuration bits for SMBHSTCFG */
74#define SMBHSTCFG_HST_EN 1
75#define SMBHSTCFG_SMB_SMI_EN 2
76#define SMBHSTCFG_I2C_EN 4
77
78/* Other settings */
79#define MAX_TIMEOUT 100
80#define ENABLE_INT9 0 /* set to 0x01 to enable - untested */
81
82/* I801 command constants */
83#define I801_QUICK 0x00
84#define I801_BYTE 0x04
85#define I801_BYTE_DATA 0x08
86#define I801_WORD_DATA 0x0C
87#define I801_PROC_CALL 0x10 /* later chips only, unimplemented */
88#define I801_BLOCK_DATA 0x14
89#define I801_I2C_BLOCK_DATA 0x18 /* unimplemented */
90#define I801_BLOCK_LAST 0x34
91#define I801_I2C_BLOCK_LAST 0x38 /* unimplemented */
92#define I801_START 0x40
93#define I801_PEC_EN 0x80 /* ICH4 only */
94
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
96static int i801_transaction(void);
Jean Delvare585b3162005-10-26 21:31:15 +020097static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
98 int command, int hwpec);
Linus Torvalds1da177e2005-04-16 15:20:36 -070099
Jean Delvare6dcc19d2006-06-12 21:53:02 +0200100static unsigned long i801_smba;
Jean Delvared6072f82005-09-25 16:37:04 +0200101static struct pci_driver i801_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102static struct pci_dev *I801_dev;
103static int isich4;
104
Jean Delvare455f3322006-06-12 21:52:02 +0200105static int __devinit i801_setup(struct pci_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 unsigned char temp;
Jean Delvare6dcc19d2006-06-12 21:53:02 +0200108 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 I801_dev = dev;
111 if ((dev->device == PCI_DEVICE_ID_INTEL_82801DB_3) ||
112 (dev->device == PCI_DEVICE_ID_INTEL_82801EB_3) ||
113 (dev->device == PCI_DEVICE_ID_INTEL_ESB_4))
114 isich4 = 1;
115 else
116 isich4 = 0;
117
Jean Delvare6dcc19d2006-06-12 21:53:02 +0200118 err = pci_enable_device(dev);
119 if (err) {
120 dev_err(&dev->dev, "Failed to enable SMBus device (%d)\n",
121 err);
122 goto exit;
123 }
124
Jean Delvare455f3322006-06-12 21:52:02 +0200125 /* Determine the address of the SMBus area */
Jean Delvare6dcc19d2006-06-12 21:53:02 +0200126 i801_smba = pci_resource_start(dev, SMBBAR);
Jean Delvared8db8f92006-06-12 21:50:11 +0200127 if (!i801_smba) {
128 dev_err(&dev->dev, "SMBus base address uninitialized, "
129 "upgrade BIOS\n");
Jean Delvare6dcc19d2006-06-12 21:53:02 +0200130 err = -ENODEV;
131 goto exit_disable;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 }
133
Jean Delvare6dcc19d2006-06-12 21:53:02 +0200134 err = pci_request_region(dev, SMBBAR, i801_driver.name);
135 if (err) {
136 dev_err(&dev->dev, "Failed to request SMBus region "
137 "0x%lx-0x%lx\n", i801_smba,
138 pci_resource_end(dev, SMBBAR));
139 goto exit_disable;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 }
141
142 pci_read_config_byte(I801_dev, SMBHSTCFG, &temp);
143 temp &= ~SMBHSTCFG_I2C_EN; /* SMBus timing */
Jean Delvare455f3322006-06-12 21:52:02 +0200144 if (!(temp & SMBHSTCFG_HST_EN)) {
145 dev_warn(&dev->dev, "enabling SMBus device\n");
146 temp |= SMBHSTCFG_HST_EN;
147 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 pci_write_config_byte(I801_dev, SMBHSTCFG, temp);
149
Jean Delvare455f3322006-06-12 21:52:02 +0200150 if (temp & SMBHSTCFG_SMB_SMI_EN)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 dev_dbg(&dev->dev, "I801 using Interrupt SMI# for SMBus.\n");
152 else
153 dev_dbg(&dev->dev, "I801 using PCI Interrupt for SMBus.\n");
154
155 pci_read_config_byte(I801_dev, SMBREV, &temp);
156 dev_dbg(&dev->dev, "SMBREV = 0x%X\n", temp);
157 dev_dbg(&dev->dev, "I801_smba = 0x%X\n", i801_smba);
158
Jean Delvare455f3322006-06-12 21:52:02 +0200159 return 0;
Jean Delvare6dcc19d2006-06-12 21:53:02 +0200160
161exit_disable:
162 pci_disable_device(dev);
163exit:
164 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165}
166
167static int i801_transaction(void)
168{
169 int temp;
170 int result = 0;
171 int timeout = 0;
172
Jean Delvare368609c2005-07-29 12:15:07 -0700173 dev_dbg(&I801_dev->dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
175 inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
176 inb_p(SMBHSTDAT1));
177
178 /* Make sure the SMBus host is ready to start transmitting */
179 /* 0x1f = Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
180 if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
Jean Delvare541e6a02005-06-23 22:18:08 +0200181 dev_dbg(&I801_dev->dev, "SMBus busy (%02x). Resetting...\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 temp);
183 outb_p(temp, SMBHSTSTS);
184 if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
185 dev_dbg(&I801_dev->dev, "Failed! (%02x)\n", temp);
186 return -1;
187 } else {
188 dev_dbg(&I801_dev->dev, "Successfull!\n");
189 }
190 }
191
192 outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT);
193
194 /* We will always wait for a fraction of a second! */
195 do {
196 msleep(1);
197 temp = inb_p(SMBHSTSTS);
198 } while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT));
199
200 /* If the SMBus is still busy, we give up */
201 if (timeout >= MAX_TIMEOUT) {
202 dev_dbg(&I801_dev->dev, "SMBus Timeout!\n");
203 result = -1;
204 }
205
206 if (temp & 0x10) {
207 result = -1;
208 dev_dbg(&I801_dev->dev, "Error: Failed bus transaction\n");
209 }
210
211 if (temp & 0x08) {
212 result = -1;
213 dev_err(&I801_dev->dev, "Bus collision! SMBus may be locked "
214 "until next hard reset. (sorry!)\n");
215 /* Clock stops and slave is stuck in mid-transmission */
216 }
217
218 if (temp & 0x04) {
219 result = -1;
220 dev_dbg(&I801_dev->dev, "Error: no response!\n");
221 }
222
223 if ((inb_p(SMBHSTSTS) & 0x1f) != 0x00)
224 outb_p(inb(SMBHSTSTS), SMBHSTSTS);
225
226 if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
Jean Delvare368609c2005-07-29 12:15:07 -0700227 dev_dbg(&I801_dev->dev, "Failed reset at end of transaction "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 "(%02x)\n", temp);
229 }
230 dev_dbg(&I801_dev->dev, "Transaction (post): CNT=%02x, CMD=%02x, "
231 "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
232 inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
233 inb_p(SMBHSTDAT1));
234 return result;
235}
236
237/* All-inclusive block transaction function */
238static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
Jean Delvare585b3162005-10-26 21:31:15 +0200239 int command, int hwpec)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240{
241 int i, len;
242 int smbcmd;
243 int temp;
244 int result = 0;
245 int timeout;
246 unsigned char hostc, errmask;
247
248 if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
249 if (read_write == I2C_SMBUS_WRITE) {
250 /* set I2C_EN bit in configuration register */
251 pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc);
252 pci_write_config_byte(I801_dev, SMBHSTCFG,
253 hostc | SMBHSTCFG_I2C_EN);
254 } else {
255 dev_err(&I801_dev->dev,
256 "I2C_SMBUS_I2C_BLOCK_READ not DB!\n");
257 return -1;
258 }
259 }
260
261 if (read_write == I2C_SMBUS_WRITE) {
262 len = data->block[0];
263 if (len < 1)
264 len = 1;
265 if (len > 32)
266 len = 32;
267 outb_p(len, SMBHSTDAT0);
268 outb_p(data->block[1], SMBBLKDAT);
269 } else {
270 len = 32; /* max for reads */
271 }
272
273 if(isich4 && command != I2C_SMBUS_I2C_BLOCK_DATA) {
274 /* set 32 byte buffer */
275 }
276
277 for (i = 1; i <= len; i++) {
278 if (i == len && read_write == I2C_SMBUS_READ)
279 smbcmd = I801_BLOCK_LAST;
280 else
281 smbcmd = I801_BLOCK_DATA;
282 outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT);
283
284 dev_dbg(&I801_dev->dev, "Block (pre %d): CNT=%02x, CMD=%02x, "
285 "ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i,
286 inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
287 inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT));
288
289 /* Make sure the SMBus host is ready to start transmitting */
290 temp = inb_p(SMBHSTSTS);
291 if (i == 1) {
292 /* Erronenous conditions before transaction:
293 * Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
294 errmask=0x9f;
295 } else {
296 /* Erronenous conditions during transaction:
297 * Failed, Bus_Err, Dev_Err, Intr */
298 errmask=0x1e;
299 }
300 if (temp & errmask) {
301 dev_dbg(&I801_dev->dev, "SMBus busy (%02x). "
Jean Delvare541e6a02005-06-23 22:18:08 +0200302 "Resetting...\n", temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 outb_p(temp, SMBHSTSTS);
304 if (((temp = inb_p(SMBHSTSTS)) & errmask) != 0x00) {
305 dev_err(&I801_dev->dev,
306 "Reset failed! (%02x)\n", temp);
307 result = -1;
308 goto END;
309 }
310 if (i != 1) {
311 /* if die in middle of block transaction, fail */
312 result = -1;
313 goto END;
314 }
315 }
316
317 if (i == 1)
318 outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT);
319
320 /* We will always wait for a fraction of a second! */
321 timeout = 0;
322 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 msleep(1);
Jean Delvare397e2f62006-06-12 21:49:36 +0200324 temp = inb_p(SMBHSTSTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 }
326 while ((!(temp & 0x80))
327 && (timeout++ < MAX_TIMEOUT));
328
329 /* If the SMBus is still busy, we give up */
330 if (timeout >= MAX_TIMEOUT) {
331 result = -1;
332 dev_dbg(&I801_dev->dev, "SMBus Timeout!\n");
333 }
334
335 if (temp & 0x10) {
336 result = -1;
337 dev_dbg(&I801_dev->dev,
338 "Error: Failed bus transaction\n");
339 } else if (temp & 0x08) {
340 result = -1;
341 dev_err(&I801_dev->dev, "Bus collision!\n");
342 } else if (temp & 0x04) {
343 result = -1;
344 dev_dbg(&I801_dev->dev, "Error: no response!\n");
345 }
346
347 if (i == 1 && read_write == I2C_SMBUS_READ) {
348 len = inb_p(SMBHSTDAT0);
349 if (len < 1)
350 len = 1;
351 if (len > 32)
352 len = 32;
353 data->block[0] = len;
354 }
355
356 /* Retrieve/store value in SMBBLKDAT */
357 if (read_write == I2C_SMBUS_READ)
358 data->block[i] = inb_p(SMBBLKDAT);
359 if (read_write == I2C_SMBUS_WRITE && i+1 <= len)
360 outb_p(data->block[i+1], SMBBLKDAT);
361 if ((temp & 0x9e) != 0x00)
362 outb_p(temp, SMBHSTSTS); /* signals SMBBLKDAT ready */
363
364 if ((temp = (0x1e & inb_p(SMBHSTSTS))) != 0x00) {
365 dev_dbg(&I801_dev->dev,
366 "Bad status (%02x) at end of transaction\n",
367 temp);
368 }
369 dev_dbg(&I801_dev->dev, "Block (post %d): CNT=%02x, CMD=%02x, "
370 "ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i,
371 inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
372 inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT));
373
374 if (result < 0)
375 goto END;
376 }
377
Jean Delvaree8aac4a2005-10-26 21:34:42 +0200378 if (hwpec) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 /* wait for INTR bit as advised by Intel */
380 timeout = 0;
381 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 msleep(1);
Jean Delvare397e2f62006-06-12 21:49:36 +0200383 temp = inb_p(SMBHSTSTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 } while ((!(temp & 0x02))
385 && (timeout++ < MAX_TIMEOUT));
386
387 if (timeout >= MAX_TIMEOUT) {
388 dev_dbg(&I801_dev->dev, "PEC Timeout!\n");
389 }
390 outb_p(temp, SMBHSTSTS);
391 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 result = 0;
393END:
394 if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
395 /* restore saved configuration register value */
396 pci_write_config_byte(I801_dev, SMBHSTCFG, hostc);
397 }
398 return result;
399}
400
401/* Return -1 on error. */
402static s32 i801_access(struct i2c_adapter * adap, u16 addr,
403 unsigned short flags, char read_write, u8 command,
404 int size, union i2c_smbus_data * data)
405{
Jean Delvaree8aac4a2005-10-26 21:34:42 +0200406 int hwpec;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 int block = 0;
408 int ret, xact = 0;
409
Jean Delvaree8aac4a2005-10-26 21:34:42 +0200410 hwpec = isich4 && (flags & I2C_CLIENT_PEC)
411 && size != I2C_SMBUS_QUICK
412 && size != I2C_SMBUS_I2C_BLOCK_DATA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413
414 switch (size) {
415 case I2C_SMBUS_QUICK:
416 outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
417 SMBHSTADD);
418 xact = I801_QUICK;
419 break;
420 case I2C_SMBUS_BYTE:
421 outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
422 SMBHSTADD);
423 if (read_write == I2C_SMBUS_WRITE)
424 outb_p(command, SMBHSTCMD);
425 xact = I801_BYTE;
426 break;
427 case I2C_SMBUS_BYTE_DATA:
428 outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
429 SMBHSTADD);
430 outb_p(command, SMBHSTCMD);
431 if (read_write == I2C_SMBUS_WRITE)
432 outb_p(data->byte, SMBHSTDAT0);
433 xact = I801_BYTE_DATA;
434 break;
435 case I2C_SMBUS_WORD_DATA:
436 outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
437 SMBHSTADD);
438 outb_p(command, SMBHSTCMD);
439 if (read_write == I2C_SMBUS_WRITE) {
440 outb_p(data->word & 0xff, SMBHSTDAT0);
441 outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
442 }
443 xact = I801_WORD_DATA;
444 break;
445 case I2C_SMBUS_BLOCK_DATA:
446 case I2C_SMBUS_I2C_BLOCK_DATA:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
448 SMBHSTADD);
449 outb_p(command, SMBHSTCMD);
450 block = 1;
451 break;
452 case I2C_SMBUS_PROC_CALL:
453 default:
454 dev_err(&I801_dev->dev, "Unsupported transaction %d\n", size);
455 return -1;
456 }
457
Mark M. Hoffman2e3e13f2005-11-06 23:04:51 +0100458 outb_p(hwpec, SMBAUXCTL); /* enable/disable hardware PEC */
Jean Delvaree8aac4a2005-10-26 21:34:42 +0200459
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 if(block)
Jean Delvare585b3162005-10-26 21:31:15 +0200461 ret = i801_block_transaction(data, read_write, size, hwpec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 else {
463 outb_p(xact | ENABLE_INT9, SMBHSTCNT);
464 ret = i801_transaction();
465 }
466
Jean Delvarec79cfba2006-04-20 02:43:18 -0700467 /* Some BIOSes don't like it when PEC is enabled at reboot or resume
468 time, so we forcibly disable it after every transaction. */
469 if (hwpec)
470 outb_p(0, SMBAUXCTL);
471
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 if(block)
473 return ret;
474 if(ret)
475 return -1;
476 if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK))
477 return 0;
478
479 switch (xact & 0x7f) {
480 case I801_BYTE: /* Result put in SMBHSTDAT0 */
481 case I801_BYTE_DATA:
482 data->byte = inb_p(SMBHSTDAT0);
483 break;
484 case I801_WORD_DATA:
485 data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
486 break;
487 }
488 return 0;
489}
490
491
492static u32 i801_func(struct i2c_adapter *adapter)
493{
494 return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
495 I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
496 I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK
Jean Delvareb8095542005-10-26 21:25:04 +0200497 | (isich4 ? I2C_FUNC_SMBUS_HWPEC_CALC : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498}
499
500static struct i2c_algorithm smbus_algorithm = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 .smbus_xfer = i801_access,
502 .functionality = i801_func,
503};
504
505static struct i2c_adapter i801_adapter = {
506 .owner = THIS_MODULE,
507 .class = I2C_CLASS_HWMON,
508 .algo = &smbus_algorithm,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509};
510
511static struct pci_device_id i801_ids[] = {
512 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) },
513 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) },
514 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_2) },
515 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_3) },
516 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_3) },
517 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_3) },
518 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_4) },
519 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_16) },
520 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_17) },
Jason Gastonb0a70b52005-04-16 15:24:45 -0700521 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_17) },
Jason Gaston8254fc42006-01-09 10:58:08 -0800522 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_5) },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 { 0, }
524};
525
526MODULE_DEVICE_TABLE (pci, i801_ids);
527
528static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
529{
Jean Delvare455f3322006-06-12 21:52:02 +0200530 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531
Jean Delvare455f3322006-06-12 21:52:02 +0200532 if ((err = i801_setup(dev)))
533 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534
535 /* set up the driverfs linkage to our parent device */
536 i801_adapter.dev.parent = &dev->dev;
537
538 snprintf(i801_adapter.name, I2C_NAME_SIZE,
Jean Delvare6dcc19d2006-06-12 21:53:02 +0200539 "SMBus I801 adapter at %04lx", i801_smba);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 return i2c_add_adapter(&i801_adapter);
541}
542
543static void __devexit i801_remove(struct pci_dev *dev)
544{
545 i2c_del_adapter(&i801_adapter);
Jean Delvare6dcc19d2006-06-12 21:53:02 +0200546 pci_release_region(dev, SMBBAR);
547 pci_disable_device(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548}
549
550static struct pci_driver i801_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 .name = "i801_smbus",
552 .id_table = i801_ids,
553 .probe = i801_probe,
554 .remove = __devexit_p(i801_remove),
555};
556
557static int __init i2c_i801_init(void)
558{
559 return pci_register_driver(&i801_driver);
560}
561
562static void __exit i2c_i801_exit(void)
563{
564 pci_unregister_driver(&i801_driver);
565}
566
567MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, "
568 "Philip Edelbrock <phil@netroedge.com>, "
569 "and Mark D. Studebaker <mdsxyz123@yahoo.com>");
570MODULE_DESCRIPTION("I801 SMBus driver");
571MODULE_LICENSE("GPL");
572
573module_init(i2c_i801_init);
574module_exit(i2c_i801_exit);